Menu
popagent
publicLatest change c5c74dbdbdce2026200ca34f315ffbf4df7da967 - Fail model gateway requests fast when no response arrives within 90s by AkurAI Build
import { describe, expect, test } from "bun:test";
import { agentRuntimeSettings } from "./agent-runtime-settings";
import { createLocalModelFetch, FREE_MODEL_ROUTE, LOCAL_MODEL_ROUTE, listModelCatalog, normalizeChatRequest, runtimeModelId, resolveModel, trimDanglingAssistantWireTail } from "./models";
describe("resolveModel", () => {
test("requires an explicit model id", () => {
expect(resolveModel("test/model").modelId).toBe("test/model");
});
test("resolves an explicit model id", () => {
expect(resolveModel("cc/claude-sonnet-5").modelId).toBe("cc/claude-sonnet-5");
});
test("maps persisted runtime sources to the local and free routes", () => {
expect(runtimeModelId("ignored/model", "local")).toBe(LOCAL_MODEL_ROUTE);
expect(runtimeModelId("ignored/model", "openrouter-free")).toBe(FREE_MODEL_ROUTE);
expect(runtimeModelId("configured/model", "configured")).toBe("configured/model");
});
});
describe("normalizeChatRequest", () => {
test("merges leading system messages for the local Ornith chat template", () => {
const body = {
model: "titan/ornith-1.0-9b-mtp-q4_k_m",
messages: [
{ role: "system", content: "Agent instructions" },
{ role: "system", content: "Workspace instructions" },
{ role: "user", content: "hi" },
],
};
expect(normalizeChatRequest(body)).toEqual({
model: "titan/ornith-1.0-9b-mtp-q4_k_m",
messages: [
{ role: "system", content: "Agent instructions\n\nWorkspace instructions" },
{ role: "user", content: "hi" },
],
});
});
test("preserves multi-system requests for compatible models", () => {
const body = { model: "cx/gpt-5.6-sol", messages: [
{ role: "system", content: "One" },
{ role: "system", content: "Two" },
] };
expect(normalizeChatRequest(body)).toBe(body);
});
test("preserves a request that already ends on a non-assistant message", () => {
const body = { model: "cc/claude-sonnet-5", messages: [
{ role: "user", content: "Report status" },
{ role: "assistant", content: null, tool_calls: [{ id: "call-1", type: "function", function: { name: "read", arguments: "{}" } }] },
{ role: "tool", tool_call_id: "call-1", content: "ok" },
] };
expect(normalizeChatRequest(body)).toBe(body);
});
});
describe("trimDanglingAssistantWireTail", () => {
test("drops a trailing assistant message with unresolved tool calls", () => {
const body = { model: "cc/claude-sonnet-5", messages: [
{ role: "user", content: "Report status" },
{ role: "assistant", content: "Working on it" },
{ role: "assistant", content: null, tool_calls: [{ id: "call-1", type: "function", function: { name: "read", arguments: "{}" } }] },
] };
expect(trimDanglingAssistantWireTail(body)).toEqual({
model: "cc/claude-sonnet-5",
messages: [{ role: "user", content: "Report status" }],
});
});
test("returns the same request when it already ends on a non-assistant message", () => {
const body = { model: "any/model", messages: [
{ role: "user", content: "Hi" },
{ role: "assistant", content: "Hello" },
{ role: "user", content: "Continue" },
] };
expect(trimDanglingAssistantWireTail(body)).toBe(body);
});
test("ignores requests without a messages array", () => {
const body = { model: "any/model" };
expect(trimDanglingAssistantWireTail(body)).toBe(body);
});
});
describe("createLocalModelFetch", () => {
test("queues local streams FIFO and removes aborted waiters", async () => {
const gates = [
Promise.withResolvers<void>(),
Promise.withResolvers<void>(),
Promise.withResolvers<void>(),
];
const firstPairStarted = Promise.withResolvers<void>();
const thirdStarted = Promise.withResolvers<void>();
const started: string[] = [];
let active = 0;
let peak = 0;
const upstream = (async (_input: RequestInfo | URL, init?: RequestInit) => {
const body = JSON.parse(String(init?.body)) as { messages: Array<{ content: string }> };
const label = body.messages[0]!.content;
const gate = gates[started.length]!;
started.push(label);
active++;
peak = Math.max(peak, active);
if (started.length === 2) firstPairStarted.resolve();
if (started.length === 3) thirdStarted.resolve();
return new Response(new ReadableStream({
async pull(controller) {
await gate.promise;
active--;
controller.enqueue(new TextEncoder().encode(label));
controller.close();
},
}));
}) as typeof fetch;
const queuedFetch = createLocalModelFetch(upstream, 2);
const run = (label: string, signal?: AbortSignal) => queuedFetch("http://router/v1/chat/completions", {
method: "POST",
signal,
body: JSON.stringify({
model: LOCAL_MODEL_ROUTE,
messages: [{ role: "user", content: label }],
}),
}).then((response) => response.text());
const first = run("first");
const second = run("second");
const aborted = new AbortController();
const cancelled = run("cancelled", aborted.signal);
const third = run("third");
await firstPairStarted.promise;
expect(started).toEqual(["first", "second"]);
expect(peak).toBe(2);
aborted.abort();
await expect(cancelled).rejects.toBeInstanceOf(DOMException);
gates[0]!.resolve();
expect(await first).toBe("first");
await thirdStarted.promise;
expect(started).toEqual(["first", "second", "third"]);
expect(peak).toBe(2);
gates[1]!.resolve();
gates[2]!.resolve();
expect(await Promise.all([second, third])).toEqual(["second", "third"]);
});
});
describe("listModelCatalog", () => {
test("returns context windows for the configured default model", async () => {
const configured = await agentRuntimeSettings.get();
const catalog = await listModelCatalog();
expect(catalog.models).toContain(configured.defaultModel);
expect(catalog.contextWindows[configured.defaultModel]).toBeGreaterThan(0);
expect(catalog.models).toEqual([...new Set(catalog.models)]);
});
});
describe("createFirstByteTimeoutFetch", () => {
test("aborts a request whose headers never arrive and leaves fast responses alone", async () => {
const { createFirstByteTimeoutFetch } = await import("./models");
const hanging = createFirstByteTimeoutFetch(((_input: RequestInfo | URL, init?: RequestInit) => new Promise<Response>((_resolve, reject) => {
init?.signal?.addEventListener("abort", () => reject(init.signal!.reason), { once: true });
})) as unknown as typeof fetch, 30);
await expect(hanging("http://127.0.0.1:1/v1/chat/completions")).rejects.toThrow("first-byte timeout");
const quick = createFirstByteTimeoutFetch((async () => new Response("ok")) as unknown as typeof fetch, 30);
expect(await (await quick("http://127.0.0.1:1/v1/models")).text()).toBe("ok");
const outer = new AbortController();
const forwarded = createFirstByteTimeoutFetch(((_input: RequestInfo | URL, init?: RequestInit) => new Promise<Response>((_resolve, reject) => {
init?.signal?.addEventListener("abort", () => reject(new Error(String(init.signal!.reason))), { once: true });
})) as unknown as typeof fetch, 10_000);
const pending = forwarded("http://127.0.0.1:1/v1/chat/completions", { signal: outer.signal });
outer.abort("caller aborted");
await expect(pending).rejects.toThrow("caller aborted");
});
});