import { describe, it, expect } from 'vitest'; const fs = require('fs'); const path = require('path'); const student = require('../src/student.js'); /* * A Qwen3 adapter scored 35.31% on the exam and zero in front of a real job. The exam renders * every prompt with enable_thinking=False and strips any reasoning block before reading the * answer; the serving path did neither, so the model reasoned through the whole 320-token answer * budget and emitted no JSON at all. Two locks now, one per side of that gap. */ describe('Qwen3 is not allowed to think its answer away', () => { const server = fs.readFileSync(path.join(__dirname, '..', 'src', 'server.js'), 'utf8'); /* `templateFor` is module-private; the file is the surface the test has. */ const qwen3 = server.slice(server.indexOf("if (m.includes('qwen3'))"), server.indexOf("family: 'chatml'")); it('serves Qwen3 with the empty reasoning block enable_thinking=False would have written', () => { expect(qwen3).toBeTruthy(); expect(qwen3).toMatch(/family: 'qwen3'/); /* The block sits AFTER the assistant marker and BEFORE the response, which is the whole point - it is the pre-filled opening the model is made to continue from. */ const after = qwen3.slice(qwen3.indexOf('im_start|>assistant')); expect(after.indexOf('')).toBeGreaterThan(-1); expect(after.indexOf('')).toBeGreaterThan(after.indexOf('')); expect(after.indexOf('{{ .Response }}')).toBeGreaterThan(after.indexOf('')); }); it('and joins the template with a newline, not a line break in the source', () => { /* A real newline inside the join argument is a syntax error that only shows at require time, which on this path means after the image is built. */ expect(qwen3).toMatch(/\]\.join\('\\n'\)/); }); it('leaves Qwen2.5 and Gemma on their own templates', () => { expect(server).toMatch(/if \(m\.includes\('gemma'\)\)/); const chatml = server.slice(server.indexOf("family: 'chatml'")); expect(chatml.slice(0, 400)).not.toMatch(//); }); }); describe('the parser drops a reasoning block if one arrives anyway', () => { it('reads the call that follows the block, not a brace inside it', () => { const text = '' + String.fromCharCode(10) + 'I could say {"tool":"guess"} but no.' + String.fromCharCode(10) + '' + String.fromCharCode(10) + '{"tool":"open","args":{"url":"https://example.com"}}'; expect(student.parseCall(text)).toEqual({ name: 'open', args: { url: 'https://example.com' } }); }); it('leaves an unclosed block alone — an answer cut off mid-thought is no answer', () => { /* Removing the marker and reading on would turn "ran out of budget" into a guess. */ const text = '' + String.fromCharCode(10) + 'the page shows {"tool":"click"} maybe'; expect(student.parseCall(text)).toBe(null); }); it('does not touch an answer that never reasoned', () => { expect(student.unthink('{"tool":"read","args":{}}')).toBe('{"tool":"read","args":{}}'); }); });