const { test } = require('node:test'); const assert = require('node:assert/strict'); const path = require('node:path'); const { pathToFileURL } = require('node:url'); async function imagesModule() { return import(pathToFileURL(path.join(__dirname, '..', 'public/js/assistant/images.js')).href); } test('assistant image intent does not intercept table retrieval requests', async () => { const { isImageRequest } = await imagesModule(); assert.equal(isImageRequest('can you show me the table?'), false); assert.equal(isImageRequest('show me Table 13.1'), false); }); test('assistant image intent still handles explicit visual requests', async () => { const { isImageRequest } = await imagesModule(); assert.equal(isImageRequest('show me the diagram'), true); assert.equal(isImageRequest('create an infographic for asthma'), true); }); // A run of image turns used to make every acknowledgement produce another image: // the model saw its own "I'll generate an educational image…" in the history and // replayed it verbatim for "Окей" and "Nice". The fix is not a word list in the // route — the model already has the tool, the prompt and the conversation, so the // policy lives where the model reads it. test('the prompt states principles, not an enumerated list of cases', () => { const { DEFAULT_BEHAVIOR } = require('../src/utils/clinicalPrompts'); assert.match(DEFAULT_BEHAVIOR, /Respond to the user's latest message, not to an earlier one/); assert.match(DEFAULT_BEHAVIOR, /If it carries no question/, 'covers acknowledgements without naming any'); assert.match(DEFAULT_BEHAVIOR, /Never repeat a previous answer/); assert.match(DEFAULT_BEHAVIOR, /do not answer from your own knowledge/, 'grounded in retrieved context'); // No word list anywhere: the model reads the message in whatever language it // arrives in, so no vocabulary needs maintaining here. for (const word of ['ok', 'nice', 'thanks', 'okay']) { assert.doesNotMatch(DEFAULT_BEHAVIOR, new RegExp('"' + word + '"', 'i'), 'no example word list'); } }); test('the tool description says when to use it and when not', () => { const { tools } = require('../src/utils/imageTool'); const description = tools[0].function.description; assert.match(description, /asks for a picture, or for a change to one you just made/); assert.match(description, /and not otherwise/); assert.match(description, /grounded in the current clinical content/); }); test('no hand-maintained acknowledgement or language list is left in the route', () => { const fs = require('node:fs'); const src = fs.readFileSync(path.join(__dirname, '..', 'src/routes/clinicalAssistant.js'), 'utf8'); assert.doesNotMatch(src, /GREETING_RE/, 'greeting word list removed — the model decides'); assert.doesNotMatch(src, /IMAGE_NOUN_NON_LATIN|IMAGE_REPEAT_NON_LATIN/, 'no multilingual vocabulary lists'); assert.doesNotMatch(src, /suppressRepeatedImage/, 'no answer-inspection backstop'); // The one surviving pattern is the compatibility path for models that write // the prompt as text; it reads the USER's message only. const fallback = src.slice(src.indexOf('async function dispatchImageRequestFallback')); assert.match(fallback, /isExplicitImageRequest\(prepared\.message\)/, 'gated on the user, never on the answer'); });