// Choosing a chat model should not mean scrolling past rerankers, image models // and speech models. /v1/models carries no mode, so the list had everything the // gateway serves; /model/info does carry it, which is where every other // discovery endpoint already looks. const test = require('node:test'); const assert = require('node:assert/strict'); const fs = require('node:fs'); const path = require('node:path'); const route = fs.readFileSync(path.join(__dirname, '..', 'src/routes/adminConfig.js'), 'utf8'); test('every non-chat mode the gateway reports is excluded', () => { assert.match(route, /var NON_CHAT_MODES = /); for (const mode of ['image_generation', 'rerank', 'audio_speech', 'audio_transcription', 'embedding']) { assert.ok(route.includes("'" + mode + "'"), mode + ' is not excluded'); } }); test('a model with no mode is kept — unknown is not disqualified', () => { // Requiring a positive 'chat' would hide every model the gateway has no // metadata for, which on this roster is most of them. assert.match(route, /excludes what the\n\/\/ gateway says is something else, rather than requiring it to say 'chat'/); const fn = route.slice(route.indexOf('async function nonChatModelIds')); assert.match(fn.slice(0, 900), /NON_CHAT_MODES\.indexOf\(liteLLMModelMode\(m\)\) !== -1/); assert.doesNotMatch(fn.slice(0, 900), /mode === 'chat'/); }); test('unreachable metadata filters nothing rather than emptying the list', () => { const fn = route.slice(route.indexOf('async function nonChatModelIds')); assert.match(fn.slice(0, 1100), /catch \(e\) \{[\s\S]{0,160}return new Set\(\)/); assert.match(fn, /No metadata means no filtering, which is what it did before/); }); test('the filter runs before the search, so a search cannot reveal a hidden model', () => { const handler = route.slice(route.indexOf("router.get('/config/models/discover'")); const filter = handler.indexOf('exclude.has(m.id)'); const search = handler.indexOf('req.query.q'); assert.ok(filter > -1 && filter < search, 'exclusion must precede the search filter'); });