import test from 'brittle' import { readFileSync } from 'node:fs' import vm from 'node:vm' const SRC = readFileSync(new URL('../lib/agent/agent-models.js', import.meta.url), 'utf8') function load() { const sandbox = { console } vm.createContext(sandbox) vm.runInContext(SRC, sandbox, { filename: 'agent-models.js' }) return sandbox } test('QVAC catalog covers profiles and extra chat ids', async (t) => { const s = load() const ids = s.BARE_AGENT_QVAC_CHAT_MODELS.map((m) => m.id) t.ok(ids.includes('QWEN3_1_7B_INST_Q4')) t.ok(ids.includes('QWEN3_8B_INST_Q4_K_M')) t.ok(ids.includes('LLAMA_TOOL_CALLING_1B_INST_Q4_K')) t.ok(ids.includes('GEMMA4_2B_MULTIMODAL_Q4_K_M')) t.is(s.bareAgentQvacModelForProfile('recommended').id, 'QWEN3_1_7B_INST_Q4') t.is(s.bareAgentQvacModelForProfile('strong').id, 'QWEN3_4B_INST_Q4_K_M') for (const m of s.BARE_AGENT_QVAC_CHAT_MODELS) { t.ok(m.ctxSize >= 8192, m.id + ' missing ctxSize') } t.is(s.bareAgentQvacFindChatModel('QWEN3_5_4B_MULTIMODAL_Q4_K_M').ctxSize, 262144) t.is(s.bareAgentQvacFindChatModel('GEMMA4_2B_MULTIMODAL_Q4_K_M').ctxSize, 131072) }) test('parse OpenAI models skips embeddings and sorts', async (t) => { const s = load() const list = s.bareAgentParseOpenAiModels({ data: [ { id: 'llama-3.3-70b-versatile', owned_by: 'meta' }, { id: 'text-embedding-3-large', owned_by: 'openai' }, { id: 'whisper-large-v3', owned_by: 'openai' }, { id: 'gpt-4.1', owned_by: 'openai' } ] }) t.is(list.length, 2) t.is(list[0].id, 'gpt-4.1') t.is(list[1].id, 'llama-3.3-70b-versatile') }) test('fetch REST models uses /models and falls back on empty', async (t) => { const s = load() const live = await s.bareAgentFetchRestModels( async () => ({ ok: true, status: 200, json: async () => ({ data: [{ id: 'grok-4' }, { id: 'grok-3-mini' }] }) }), { baseUrl: 'https://api.x.ai/v1', apiKey: 'x' } ) t.is(live.length, 2) t.is(live[0].id, 'grok-3-mini') await t.exception(() => s.bareAgentFetchRestModels(async () => ({ ok: false, status: 401 }), { baseUrl: 'https://api.groq.com/openai/v1' }) ) t.ok(s.bareAgentRestModelsFallback('groq').some((m) => m.id === 'llama-3.3-70b-versatile')) }) test('honor explicit QVAC model does not fall back to profile default', async (t) => { const s = load() const next = s.bareAgentHonorExplicitQvacModel( { qvac_profile: 'recommended', qvac_model: 'QWEN3_8B_INST_Q4_K_M', model: 'QWEN3_8B_INST_Q4_K_M' }, { chatModel: 'QWEN3_1_7B_INST_Q4' } ) t.is(next.qvac_model, 'QWEN3_8B_INST_Q4_K_M') t.is(next.model, 'QWEN3_8B_INST_Q4_K_M') }) test('apply live model switches QVAC and REST independently', async (t) => { const s = load() const qvac = s.bareAgentApplyLiveModel( { backend: 'qvac', qvac_profile: 'recommended', qvac_model: 'QWEN3_1_7B_INST_Q4' }, 'QWEN3_600M_INST_Q4' ) t.is(qvac.qvac_model, 'QWEN3_600M_INST_Q4') t.is(qvac.qvac_profile, 'lite') const rest = s.bareAgentApplyLiveModel( { backend: 'rest', provider: 'groq', rest_api_key: 'gsk', rest_base_url: 'https://api.groq.com/openai/v1', model: 'old' }, 'llama-3.1-8b-instant' ) t.is(rest.backend, 'rest') t.is(rest.model, 'llama-3.1-8b-instant') })