import assert from "node:assert/strict"; import { test } from "node:test"; import { createZcodeModelGateway } from "@/lib/ai/zcode-agent/model-gateway"; import type { AgentModelEntry, AgentCircuitStore } from "@/lib/ai/runtime/agent-model-failover"; const body = { model: "primary", stream: true, messages: [{ role: "user", content: "request" }], tools: [{ type: "function", function: { name: "readCanvas", parameters: { type: "object" } } }] }; function entry(id: string, responses = false): AgentModelEntry { return { model: { id, modelId: id, capabilities: responses ? { vip98k: { invocation: { path: "/v1/responses", headers: { "X-Relay-Route-Option": "route-proof" } } } } : null }, provider: { type: responses ? "vip98k" : "openai", baseUrl: "https://fixture.invalid", apiKey: "synthetic-only" } } as AgentModelEntry; } function fixture() { const paused = new Set(); const calls: Array<{ url: string; request: any }> = []; const circuit: AgentCircuitStore = { isPaused: async e => paused.has(e.model.id), fail: async e => { paused.add(e.model.id); } }; return { paused, calls, circuit }; } test("a broken primary and a Responses-only backup work through one stable native protocol", async () => { const s = fixture(); const primary = entry("primary"); const backup = entry("backup", true); const original = global.fetch; global.fetch = async (url, init) => { const request = JSON.parse(String(init?.body)); s.calls.push({ url: String(url), request }); if (request.model === "primary") return new Response("invalid authentication", { status: 401 }); assert.equal(request.stream, false); assert.equal(request.tools[0].name, "readCanvas"); assert.equal((init?.headers as Record)["X-Relay-Route-Option"], "route-proof"); return Response.json({ status: "completed", output: [{ type: "function_call", call_id: "once", name: "readCanvas", arguments: "{}" }] }); }; try { const gateway = await createZcodeModelGateway(primary, undefined, [primary, backup], s.circuit); assert.equal(gateway.apiType, "openai-chat-completions"); const response = await gateway.forward(body, "/v1/chat/completions", new AbortController().signal); assert.equal(response.status, 200); assert.match(await response.text(), /"id":"once"/); assert.deepEqual([...s.paused], ["primary"]); const nextGateway = await createZcodeModelGateway(primary, undefined, [primary, backup], s.circuit); await nextGateway.forward(body, "/v1/chat/completions", new AbortController().signal); assert.deepEqual(s.calls.map(x => x.request.model), ["primary", "backup", "backup"]); assert.equal(s.calls[1].url, "https://fixture.invalid/v1/responses"); assert.deepEqual(body.messages, [{ role: "user", content: "request" }]); } finally { global.fetch = original; } }); test("truncated tool output cannot escape before fallback supplies a complete replacement", async () => { const s = fixture(); const primary = entry("primary"); const backup = entry("backup"); const original = global.fetch; global.fetch = async (_url, init) => { const request = JSON.parse(String(init?.body)); s.calls.push({ url: "", request }); return Response.json({ choices: [{ finish_reason: "tool_calls", message: { tool_calls: [{ id: "once", type: "function", function: { name: "readCanvas", arguments: request.model === "primary" ? "{bad" : "{}" } }] } }] }); }; try { const gateway = await createZcodeModelGateway(primary, undefined, [primary, backup], s.circuit); const response = await gateway.forward(body, "/v1/chat/completions", new AbortController().signal); const output = await response.text(); assert.equal(response.status, 200); assert(!output.includes("{bad")); assert.deepEqual(s.calls.map(x => x.request.model), ["primary", "backup"]); assert.deepEqual([...s.paused], ["primary"]); } finally { global.fetch = original; } }); test("already paused models receive no HTTP call even in a new gateway", async () => { const s = fixture(); s.paused.add("primary"); const original = global.fetch; global.fetch = async () => { throw new Error("must not contact paused model"); }; try { const gateway = await createZcodeModelGateway(entry("primary"), undefined, [entry("primary")], s.circuit); assert.equal((await gateway.forward(body, "/v1/chat/completions", new AbortController().signal)).status, 503); } finally { global.fetch = original; } });