Release v3.8.29 (#4126)

OmniRoute v3.8.29 — 115 commits since v3.8.28. Full CHANGELOG + 41 i18n mirrors. All content quality gates green (build, unit 8/8, vitest 188/188, PR test policy, quality gates extended, docs sync, quality ratchet). Remaining red CI checks are pre-existing release flakes (coverage-shard/integration/node-compat teardown), a new transitive undici advisory in electron devDeps, and a workflow-level CodeQL fail (0 open alerts). VPS-validated by the operator.
This commit is contained in:
Diego Rodrigues de Sa e Souza
2026-06-19 06:49:01 -03:00
committed by GitHub
parent dd5a3db55e
commit 3c9883bb73
497 changed files with 35580 additions and 5484 deletions

View File

@@ -5,7 +5,12 @@
"targetFormat": "gemini",
"input": {
"model": "gemini-2.5-flash",
"messages": [{ "role": "user", "content": "Hello Gemini!" }]
"messages": [
{
"role": "user",
"content": "Hello Gemini!"
}
]
}
},
{
@@ -15,10 +20,30 @@
"input": {
"model": "gemini-2.5-pro",
"messages": [
{ "role": "system", "content": "You are a helpful assistant." },
{ "role": "user", "content": "Tell me a joke." }
{
"role": "system",
"content": "You are a helpful assistant."
},
{
"role": "user",
"content": "Tell me a joke."
}
],
"temperature": 0.7
}
},
{
"name": "openai-to-gemini/modern-gemini-default-thinking",
"sourceFormat": "openai",
"targetFormat": "gemini",
"input": {
"model": "gemini-2.5-flash",
"messages": [
{
"role": "user",
"content": "Hello Gemini!"
}
]
}
}
]

View File

@@ -99,14 +99,29 @@ test("round-robin combo cycles through three providers", async () => {
return buildGeminiResponse("Gemini round-robin");
};
const first = await handleChat(buildRequest({ body: buildOpenAIChatBody("router-rr") }));
const second = await handleChat(buildRequest({ body: buildOpenAIChatBody("router-rr") }));
const third = await handleChat(buildRequest({ body: buildOpenAIChatBody("router-rr") }));
// `stickyRoundRobinLimit` defaults to 3 (src/lib/db/settings.ts), so a combo using the
// round-robin strategy serves 3 consecutive requests per target before advancing to the
// next one — batched rotation, not one-request-per-target. Nine requests therefore cover
// a full cycle: openai x3 -> claude x3 -> gemini x3.
const responses = [];
for (let i = 0; i < 9; i++) {
responses.push(await handleChat(buildRequest({ body: buildOpenAIChatBody("router-rr") })));
}
assert.equal(first.status, 200);
assert.equal(second.status, 200);
assert.equal(third.status, 200);
assert.deepEqual(seenProviders, ["openai", "claude", "gemini"]);
for (const response of responses) {
assert.equal(response.status, 200);
}
assert.deepEqual(seenProviders, [
"openai",
"openai",
"openai",
"claude",
"claude",
"claude",
"gemini",
"gemini",
"gemini",
]);
});
test("priority combo sticks to the primary model while healthy", async () => {
@@ -382,19 +397,23 @@ test("strategy updates take effect for later requests on the same combo name", a
strategy: "round-robin",
config: { maxRetries: 0, retryDelayMs: 0 },
});
const second = await handleChat(
buildRequest({
body: buildOpenAIChatBody("router-dynamic", "Route dynamic second"),
})
);
const third = await handleChat(
buildRequest({
body: buildOpenAIChatBody("router-dynamic", "Route dynamic third"),
})
);
// After the strategy flips to round-robin the new behavior must take effect. With the
// default stickyRoundRobinLimit of 3 the round-robin batch serves openai three times
// before advancing, so the 4th post-update request rotates to claude — a provider the
// previous "priority" strategy would never have reached. That rotation is the proof the
// updated strategy is live.
const postUpdate = [];
for (let i = 0; i < 4; i++) {
postUpdate.push(
await handleChat(
buildRequest({ body: buildOpenAIChatBody("router-dynamic", `Route dynamic ${i}`) })
)
);
}
assert.equal(initial.status, 200);
assert.equal(second.status, 200);
assert.equal(third.status, 200);
assert.deepEqual(seenProviders, ["openai", "openai", "claude"]);
for (const response of postUpdate) {
assert.equal(response.status, 200);
}
assert.deepEqual(seenProviders, ["openai", "openai", "openai", "openai", "claude"]);
});

View File

@@ -0,0 +1,115 @@
import { test, before, after, beforeEach } from "node:test";
import assert from "node:assert/strict";
import { createChatPipelineHarness } from "./_chatPipelineHarness.ts";
let h: Awaited<ReturnType<typeof createChatPipelineHarness>>;
before(async () => {
h = await createChatPipelineHarness("stream-recovery");
});
after(async () => {
await h.cleanup();
});
beforeEach(async () => {
await h.resetStorage();
delete process.env.STREAM_RECOVERY_ENABLED;
});
// A 200 SSE stream that ends WITHOUT a terminal `[DONE]` marker = silent truncation.
function truncatedOpenAIStream(): Response {
const chunk = JSON.stringify({
id: "chatcmpl_trunc",
object: "chat.completion.chunk",
choices: [{ index: 0, delta: { role: "assistant", content: "PARTIAL" } }],
});
return new Response(`data: ${chunk}\n\n`, {
status: 200,
headers: { "Content-Type": "text/event-stream" },
});
}
function completeOpenAIStream(): Response {
const chunk = JSON.stringify({
id: "chatcmpl_full",
object: "chat.completion.chunk",
choices: [{ index: 0, delta: { role: "assistant", content: "RECOVERED" } }],
});
return new Response([`data: ${chunk}`, "", "data: [DONE]", ""].join("\n"), {
status: 200,
headers: { "Content-Type": "text/event-stream" },
});
}
async function readSSE(response: Response): Promise<string> {
const reader = (response.body as ReadableStream<Uint8Array>).getReader();
const decoder = new TextDecoder();
let out = "";
for (;;) {
const { done, value } = await reader.read();
if (done) break;
if (value) out += decoder.decode(value, { stream: true });
}
return out;
}
test("stream recovery ON: a truncated opening stream is retried transparently", async () => {
await h.seedConnection("openai", { apiKey: "sk-openai-primary" });
const apiKey = await h.seedApiKey();
await h.settingsDb.updateSettings({
resilienceSettings: { streamRecovery: { enabled: true } },
});
let calls = 0;
globalThis.fetch = (async () => {
calls++;
return calls === 1 ? truncatedOpenAIStream() : completeOpenAIStream();
}) as typeof fetch;
const response = await h.handleChat(
h.buildRequest({
authKey: apiKey.key,
body: {
model: "openai/gpt-4o-mini",
stream: true,
messages: [{ role: "user", content: "hi" }],
},
})
);
assert.equal(response.status, 200);
const sse = await readSSE(response);
assert.equal(calls, 2, "should have re-opened the upstream exactly once");
assert.match(sse, /RECOVERED/, "client receives the recovered attempt");
assert.match(sse, /\[DONE\]/, "recovered stream carries its terminal marker");
assert.doesNotMatch(sse, /PARTIAL/, "the discarded first attempt must not leak to the client");
});
test("stream recovery OFF (default): a truncated stream is NOT retried", async () => {
await h.seedConnection("openai", { apiKey: "sk-openai-primary" });
const apiKey = await h.seedApiKey();
// No setting, no env → default OFF.
let calls = 0;
globalThis.fetch = (async () => {
calls++;
return truncatedOpenAIStream();
}) as typeof fetch;
const response = await h.handleChat(
h.buildRequest({
authKey: apiKey.key,
body: {
model: "openai/gpt-4o-mini",
stream: true,
messages: [{ role: "user", content: "hi" }],
},
})
);
assert.equal(response.status, 200);
await readSSE(response);
assert.equal(calls, 1, "default path calls upstream exactly once — zero behavior change");
});

View File

@@ -169,5 +169,8 @@ test("contract: /api/v1/messages/count_tokens computes token estimate from text
assert.equal(response.status, 200);
const body = (await response.json()) as any;
assert.equal(body.input_tokens, 3);
// Real tiktoken count (countTextTokens): "abcd" => 1, "12345678" => 3 (digits split).
// The previous expectation (3) was the old ceil(chars/4) heuristic, replaced by the
// tiktoken-based estimator; the accurate total for this payload is 4.
assert.equal(body.input_tokens, 4);
});

View File

@@ -10,7 +10,11 @@
}
],
"generationConfig": {
"maxOutputTokens": 65536
"maxOutputTokens": 65536,
"thinkingConfig": {
"includeThoughts": true,
"thinkingBudget": 24576
}
},
"model": "gemini-2.5-flash",
"safetySettings": [

View File

@@ -0,0 +1,42 @@
{
"contents": [
{
"parts": [
{
"text": "Hello Gemini!"
}
],
"role": "user"
}
],
"generationConfig": {
"maxOutputTokens": 65536,
"thinkingConfig": {
"includeThoughts": true,
"thinkingBudget": 24576
}
},
"model": "gemini-2.5-flash",
"safetySettings": [
{
"category": "HARM_CATEGORY_HATE_SPEECH",
"threshold": "OFF"
},
{
"category": "HARM_CATEGORY_DANGEROUS_CONTENT",
"threshold": "OFF"
},
{
"category": "HARM_CATEGORY_SEXUALLY_EXPLICIT",
"threshold": "OFF"
},
{
"category": "HARM_CATEGORY_HARASSMENT",
"threshold": "OFF"
},
{
"category": "HARM_CATEGORY_CIVIC_INTEGRITY",
"threshold": "OFF"
}
]
}

View File

@@ -11,7 +11,11 @@
],
"generationConfig": {
"maxOutputTokens": 8192,
"temperature": 0.7
"temperature": 0.7,
"thinkingConfig": {
"includeThoughts": true,
"thinkingBudget": 24576
}
},
"model": "gemini-2.5-pro",
"safetySettings": [

View File

@@ -0,0 +1,48 @@
import test from "node:test";
import assert from "node:assert/strict";
import { inferRequiredScope } from "../../src/server/authz/accessScopes.ts";
test("read methods default to read", () => {
assert.equal(inferRequiredScope("GET", "/api/v1/models"), "read");
assert.equal(inferRequiredScope("HEAD", "/api/health"), "read");
assert.equal(inferRequiredScope("OPTIONS", "/api/anything"), "read");
});
test("mutating methods default to write", () => {
assert.equal(inferRequiredScope("POST", "/api/keys"), "write");
assert.equal(inferRequiredScope("PUT", "/api/config"), "write");
assert.equal(inferRequiredScope("PATCH", "/api/combo/x"), "write");
assert.equal(inferRequiredScope("DELETE", "/api/keys/abc"), "write");
});
test("admin-prefix routes require admin for ANY method", () => {
assert.equal(inferRequiredScope("GET", "/api/cli/tokens"), "admin");
assert.equal(inferRequiredScope("POST", "/api/cli/tokens"), "admin");
assert.equal(inferRequiredScope("DELETE", "/api/cli/tokens/tok_1"), "admin");
assert.equal(inferRequiredScope("GET", "/api/oauth/start"), "admin");
assert.equal(inferRequiredScope("POST", "/api/auth/login"), "admin");
assert.equal(inferRequiredScope("POST", "/api/policy"), "admin");
assert.equal(inferRequiredScope("POST", "/api/services/foo/start"), "admin");
});
test("admin-mutation prefixes: GET stays read, mutations become admin", () => {
// providers: status is read, but creating/rotating is admin
assert.equal(inferRequiredScope("GET", "/api/providers/status"), "read");
assert.equal(inferRequiredScope("GET", "/api/providers"), "read");
assert.equal(inferRequiredScope("POST", "/api/providers"), "admin");
assert.equal(inferRequiredScope("DELETE", "/api/providers/openai"), "admin");
// cli-tools/apply writes to the host fs
assert.equal(inferRequiredScope("POST", "/api/cli-tools/apply"), "admin");
});
test("a brand-new mutating route is write by default (not admin)", () => {
assert.equal(inferRequiredScope("POST", "/api/some-future-route"), "write");
assert.equal(inferRequiredScope("GET", "/api/some-future-route"), "read");
});
test("prefix matching does not over-match unrelated paths", () => {
// "/api/authz-inventory" must NOT be caught by the "/api/auth" admin prefix
assert.equal(inferRequiredScope("GET", "/api/authz-inventory"), "read");
// "/api/services" itself and its children are admin, but a lookalike is not
assert.equal(inferRequiredScope("GET", "/api/services-catalog"), "read");
});

View File

@@ -0,0 +1,58 @@
import test from "node:test";
import assert from "node:assert/strict";
import {
ACCESS_SCOPES,
isAccessScope,
scopeSatisfies,
normalizeScope,
} from "../../src/lib/accessTokens/scopes.ts";
test("ACCESS_SCOPES are exactly read/write/admin", () => {
assert.deepEqual([...ACCESS_SCOPES], ["read", "write", "admin"]);
});
test("isAccessScope accepts valid scopes and rejects anything else", () => {
assert.equal(isAccessScope("read"), true);
assert.equal(isAccessScope("write"), true);
assert.equal(isAccessScope("admin"), true);
assert.equal(isAccessScope("superuser"), false);
assert.equal(isAccessScope(""), false);
assert.equal(isAccessScope(null), false);
assert.equal(isAccessScope(undefined), false);
assert.equal(isAccessScope(3), false);
});
test("scopeSatisfies enforces the admin ⊃ write ⊃ read hierarchy", () => {
// admin satisfies everything
assert.equal(scopeSatisfies("admin", "read"), true);
assert.equal(scopeSatisfies("admin", "write"), true);
assert.equal(scopeSatisfies("admin", "admin"), true);
// write satisfies read+write, not admin
assert.equal(scopeSatisfies("write", "read"), true);
assert.equal(scopeSatisfies("write", "write"), true);
assert.equal(scopeSatisfies("write", "admin"), false);
// read satisfies only read
assert.equal(scopeSatisfies("read", "read"), true);
assert.equal(scopeSatisfies("read", "write"), false);
assert.equal(scopeSatisfies("read", "admin"), false);
});
test("scopeSatisfies returns false for invalid `have` scopes (fail closed)", () => {
assert.equal(scopeSatisfies("bogus", "read"), false);
assert.equal(scopeSatisfies(null, "read"), false);
assert.equal(scopeSatisfies(undefined, "read"), false);
assert.equal(scopeSatisfies("", "read"), false);
});
test("normalizeScope falls back to read by default for invalid input", () => {
assert.equal(normalizeScope("write"), "write");
assert.equal(normalizeScope("admin"), "admin");
assert.equal(normalizeScope("bogus"), "read");
assert.equal(normalizeScope(undefined), "read");
assert.equal(normalizeScope(null), "read");
});
test("normalizeScope honors a custom fallback", () => {
assert.equal(normalizeScope("bogus", "write"), "write");
assert.equal(normalizeScope(undefined, "admin"), "admin");
});

View File

@@ -0,0 +1,104 @@
import test from "node:test";
import assert from "node:assert/strict";
import fs from "node:fs";
import os from "node:os";
import path from "node:path";
// DB-backed access-token store. Uses an isolated DATA_DIR + closes the handle in
// test.after (CLAUDE.md "Database Handles in Tests" — otherwise Node's runner hangs).
const TEST_DATA_DIR = fs.mkdtempSync(path.join(os.tmpdir(), "omniroute-access-tokens-"));
process.env.DATA_DIR = TEST_DATA_DIR;
process.env.DISABLE_SQLITE_AUTO_BACKUP = "true";
const core = await import("../../src/lib/db/core.ts");
const at = await import("../../src/lib/db/accessTokens.ts");
test.after(() => {
try {
core.resetDbInstance();
} catch {}
try {
fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true });
} catch {}
});
test("createAccessToken returns a secret prefixed oma_live_ and a masked record", () => {
const { record, secret } = at.createAccessToken({ name: "laptop", scope: "write" });
assert.match(secret, /^oma_live_/);
assert.equal(record.name, "laptop");
assert.equal(record.scope, "write");
assert.ok(record.id.startsWith("tok_"));
assert.ok(secret.startsWith(record.tokenPrefix), "prefix must be a prefix of the secret");
assert.equal(record.revokedAt, null);
});
test("createAccessToken defaults to the safest scope (read) for invalid input", () => {
const { record } = at.createAccessToken({ name: "x", scope: "bogus" });
assert.equal(record.scope, "read");
});
test("createAccessToken rejects an empty name", () => {
assert.throws(() => at.createAccessToken({ name: " ", scope: "read" }), /name is required/);
});
test("verifyAccessToken returns identity+scope for a valid secret, null for wrong", () => {
const { secret } = at.createAccessToken({ name: "verify-me", scope: "admin" });
const v = at.verifyAccessToken(secret);
assert.ok(v);
assert.equal(v?.scope, "admin");
assert.equal(v?.name, "verify-me");
assert.equal(at.verifyAccessToken("oma_live_wrong"), null);
assert.equal(at.verifyAccessToken(""), null);
assert.equal(at.verifyAccessToken(null), null);
});
test("only the hash is stored — the plaintext secret never lands in the DB", () => {
const { secret, record } = at.createAccessToken({ name: "secrecy", scope: "read" });
const db = core.getDbInstance();
const row = db
.prepare("SELECT token_hash, token_prefix FROM cli_access_tokens WHERE id = ?")
.get(record.id) as { token_hash: string; token_prefix: string };
assert.notEqual(row.token_hash, secret, "must store hash, not plaintext");
assert.equal(row.token_hash, at.hashAccessToken(secret));
assert.equal(row.token_hash.length, 64, "sha-256 hex");
});
test("verifyAccessToken stamps last_used_at", () => {
const { secret, record } = at.createAccessToken({ name: "touch", scope: "read" });
assert.equal(at.getAccessToken(record.id)?.lastUsedAt, null);
at.verifyAccessToken(secret);
assert.notEqual(at.getAccessToken(record.id)?.lastUsedAt, null);
});
test("revoked tokens fail verification", () => {
const { secret, record } = at.createAccessToken({ name: "to-revoke", scope: "write" });
assert.ok(at.verifyAccessToken(secret));
assert.equal(at.revokeAccessToken(record.id), true);
assert.equal(at.verifyAccessToken(secret), null);
// idempotent: revoking again is a no-op
assert.equal(at.revokeAccessToken(record.id), false);
});
test("revokeAccessToken works by display prefix too", () => {
const { secret, record } = at.createAccessToken({ name: "by-prefix", scope: "read" });
assert.equal(at.revokeAccessToken(record.tokenPrefix), true);
assert.equal(at.verifyAccessToken(secret), null);
});
test("expired tokens fail verification", () => {
const past = new Date(Date.now() - 60_000).toISOString();
const { secret } = at.createAccessToken({ name: "expired", scope: "admin", expiresAt: past });
assert.equal(at.verifyAccessToken(secret), null);
});
test("listAccessTokens returns masked records (no secret/hash field)", () => {
at.createAccessToken({ name: "listed", scope: "read" });
const list = at.listAccessTokens();
assert.ok(list.length >= 1);
for (const rec of list) {
assert.ok("tokenPrefix" in rec);
assert.ok(!("secret" in rec));
assert.ok(!("tokenHash" in rec));
assert.ok(!("token_hash" in rec));
}
});

View File

@@ -0,0 +1,123 @@
/**
* Client-side fetch helpers that the AgentBridge maintenance card uses to drive
* the already-shipped backend routes (#4084 repair + DELETE cert, #4093
* diagnose, #4094 config import/export). Pure integration logic — no DOM — so
* it is unit-testable by stubbing global.fetch: each helper must parse the
* success body and surface the sanitized server error message on !res.ok.
*/
import test from "node:test";
import assert from "node:assert/strict";
const {
runDiagnose,
removeCaCert,
repairMitmState,
fetchAgentBridgeConfig,
importAgentBridgeConfig,
} = await import("../../src/lib/inspector/agentBridgeMaintenanceApi.ts");
type FetchCall = { url: string; init?: RequestInit };
function stubFetch(handler: (call: FetchCall) => { ok: boolean; status?: number; body: unknown }) {
const calls: FetchCall[] = [];
const original = global.fetch;
global.fetch = (async (url: string, init?: RequestInit) => {
const call = { url: String(url), init };
calls.push(call);
const { ok, status = ok ? 200 : 500, body } = handler(call);
return {
ok,
status,
json: async () => body,
} as unknown as Response;
}) as typeof fetch;
return {
calls,
restore() {
global.fetch = original;
},
};
}
test("runDiagnose returns the report and hits GET /diagnose", async () => {
const report = { healthy: false, checks: [{ name: "cert-trusted", ok: false, hint: "trust it" }], port: 443 };
const f = stubFetch(() => ({ ok: true, body: report }));
try {
const result = await runDiagnose();
assert.equal(result.healthy, false);
assert.equal(result.port, 443);
assert.equal(result.checks[0].name, "cert-trusted");
assert.equal(f.calls[0].url, "/api/tools/agent-bridge/diagnose");
} finally {
f.restore();
}
});
test("removeCaCert DELETEs /cert and returns trusted flag", async () => {
const f = stubFetch(() => ({ ok: true, body: { ok: true, trusted: false } }));
try {
const result = await removeCaCert();
assert.equal(result.trusted, false);
assert.equal(f.calls[0].url, "/api/tools/agent-bridge/cert");
assert.equal(f.calls[0].init?.method, "DELETE");
} finally {
f.restore();
}
});
test("repairMitmState POSTs /repair and returns the repaired list", async () => {
const f = stubFetch(() => ({ ok: true, body: { ok: true, repaired: ["dns", "system-proxy"] } }));
try {
const result = await repairMitmState();
assert.deepEqual(result.repaired, ["dns", "system-proxy"]);
assert.equal(f.calls[0].url, "/api/tools/agent-bridge/repair");
assert.equal(f.calls[0].init?.method, "POST");
} finally {
f.restore();
}
});
test("fetchAgentBridgeConfig GETs /config and returns the portable blob", async () => {
const cfg = { version: 1, bypassPatterns: ["*.corp"], customHosts: [], agentMappings: {} };
const f = stubFetch(() => ({ ok: true, body: cfg }));
try {
const result = await fetchAgentBridgeConfig();
assert.equal(result.version, 1);
assert.deepEqual(result.bypassPatterns, ["*.corp"]);
assert.equal(f.calls[0].url, "/api/tools/agent-bridge/config");
} finally {
f.restore();
}
});
test("importAgentBridgeConfig POSTs the config and returns the counts", async () => {
const cfg = { version: 1 as const, bypassPatterns: ["*.corp"], customHosts: [], agentMappings: {} };
const f = stubFetch(() => ({ ok: true, body: { ok: true, bypassPatterns: 1, customHosts: 0, agents: 0 } }));
try {
const result = await importAgentBridgeConfig(cfg);
assert.equal(result.bypassPatterns, 1);
assert.equal(f.calls[0].url, "/api/tools/agent-bridge/config");
assert.equal(f.calls[0].init?.method, "POST");
assert.equal(JSON.parse(String(f.calls[0].init?.body)).version, 1);
} finally {
f.restore();
}
});
test("each helper surfaces the sanitized server error message on !res.ok", async () => {
const f = stubFetch(() => ({ ok: false, status: 400, body: { error: { message: "Invalid AgentBridge config" } } }));
try {
await assert.rejects(() => importAgentBridgeConfig({ version: 1, bypassPatterns: [], customHosts: [], agentMappings: {} }), /Invalid AgentBridge config/);
} finally {
f.restore();
}
});
test("helpers fall back to HTTP status when the error body has no message", async () => {
const f = stubFetch(() => ({ ok: false, status: 503, body: null }));
try {
await assert.rejects(() => repairMitmState(), /HTTP 503/);
} finally {
f.restore();
}
});

View File

@@ -48,6 +48,26 @@ test("normalizeAgentBridgeState falls back to safe defaults for empty/garbage in
}
});
test("normalizeAgentBridgeState maps orphanedStateDetected + dnsConfigured from getMitmStatus (Gap 7 repair banner)", () => {
// getMitmStatus() returns these two flags; the maintenance card needs them in
// serverState to decide whether to surface the "orphaned state — repair" banner.
const routeShape = {
server: { running: false, dnsConfigured: true, certExists: true, orphanedStateDetected: true },
agents: [],
};
const result = normalizeAgentBridgeState(routeShape);
assert.equal(result.serverState.orphanedStateDetected, true, "orphanedStateDetected maps through");
assert.equal(result.serverState.dnsConfigured, true, "dnsConfigured maps through");
});
test("normalizeAgentBridgeState defaults orphanedStateDetected + dnsConfigured to false", () => {
for (const bad of [null, undefined, {}, { server: {} }]) {
const result = normalizeAgentBridgeState(bad);
assert.equal(result.serverState.orphanedStateDetected, false);
assert.equal(result.serverState.dnsConfigured, false);
}
});
test("normalizeAgentBridgeState passes a correctly-shaped payload through intact", () => {
const correct = {
...DEFAULT_AGENT_BRIDGE_STATE,

View File

@@ -0,0 +1,63 @@
/**
* #4235 — Enhanced `auto/*` combos.
*
* Phase A: the README advertises `auto/cheap`, `auto/offline`, `auto/smart`
* (and they already resolve via parseAutoPrefix → createVirtualAutoCombo), but
* they were missing from AUTO_TEMPLATE_VARIANTS, so `/v1/models` and the
* dashboard never listed them — the catalog/UI drifted from the README.
*
* Later phases (suffix parser `auto/<category>:<tier>`, new categories, `:pro`)
* extend the assertions below.
*/
import test from "node:test";
import assert from "node:assert/strict";
import fs from "node:fs";
import os from "node:os";
import path from "node:path";
const TEST_DATA_DIR = fs.mkdtempSync(path.join(os.tmpdir(), "omniroute-4235-"));
process.env.DATA_DIR = TEST_DATA_DIR;
process.env.API_KEY_SECRET = process.env.API_KEY_SECRET || "auto-4235-test-secret";
const core = await import("../../src/lib/db/core.ts");
const builtinCatalog = await import("../../open-sse/services/autoCombo/builtinCatalog.ts");
function resetStorage() {
core.resetDbInstance();
fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true });
fs.mkdirSync(TEST_DATA_DIR, { recursive: true });
}
test.beforeEach(() => {
resetStorage();
});
test.after(() => {
core.resetDbInstance();
fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true });
});
test("#4235 Phase A: README-advertised cheap/offline/smart are in the built-in catalog", () => {
const ids = Object.keys(builtinCatalog.AUTO_TEMPLATE_VARIANTS);
for (const id of ["auto/cheap", "auto/offline", "auto/smart"]) {
assert.ok(
ids.includes(id),
`expected ${id} in AUTO_TEMPLATE_VARIANTS (advertised in /v1/models)`
);
}
});
test("#4235 Phase A: cheap/offline/smart map to their scoring variant", () => {
assert.equal(builtinCatalog.AUTO_TEMPLATE_VARIANTS["auto/cheap"], "cheap");
assert.equal(builtinCatalog.AUTO_TEMPLATE_VARIANTS["auto/offline"], "offline");
assert.equal(builtinCatalog.AUTO_TEMPLATE_VARIANTS["auto/smart"], "smart");
});
test("#4235 Phase A: each new entry materializes into a virtual auto-combo", async () => {
for (const id of ["auto/cheap", "auto/offline", "auto/smart"]) {
const suffix = id.slice("auto/".length);
const combo = await builtinCatalog.createBuiltinAutoCombo(id, suffix);
assert.equal(combo.id, id, `${id} combo id`);
assert.equal(combo.strategy, "auto", `${id} uses the auto strategy`);
}
});

View File

@@ -0,0 +1,120 @@
/**
* #4235 Phase B — OpenRouter-style `auto/<category>:<tier>` suffix combos.
*
* Covers the pure composition layer (parse + tier→weights + candidate filter) and
* the end-to-end advertisement of the curated suffix combos in `/v1/models`.
*/
import test from "node:test";
import assert from "node:assert/strict";
import fs from "node:fs";
import os from "node:os";
import path from "node:path";
const TEST_DATA_DIR = fs.mkdtempSync(path.join(os.tmpdir(), "omniroute-4235b-"));
process.env.DATA_DIR = TEST_DATA_DIR;
process.env.API_KEY_SECRET = process.env.API_KEY_SECRET || "auto-4235b-test-secret";
const core = await import("../../src/lib/db/core.ts");
const suffix = await import("../../open-sse/services/autoCombo/suffixComposition.ts");
const modePacks = await import("../../open-sse/services/autoCombo/modePacks.ts");
const builtinCatalog = await import("../../open-sse/services/autoCombo/builtinCatalog.ts");
const v1ModelsCatalog = await import("../../src/app/api/v1/models/catalog.ts");
function resetStorage() {
core.resetDbInstance();
fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true });
fs.mkdirSync(TEST_DATA_DIR, { recursive: true });
}
test.beforeEach(() => resetStorage());
test.after(() => {
core.resetDbInstance();
fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true });
});
test("#4235 parseAutoSuffix parses category and category:tier", () => {
assert.deepEqual(suffix.parseAutoSuffix("coding:fast"), {
valid: true,
category: "coding",
tier: "fast",
});
assert.deepEqual(suffix.parseAutoSuffix("vision"), { valid: true, category: "vision" });
assert.deepEqual(suffix.parseAutoSuffix("reasoning:pro"), {
valid: true,
category: "reasoning",
tier: "pro",
});
// floor is an accepted tier alias of cheap
assert.equal(suffix.parseAutoSuffix("coding:floor").valid, true);
});
test("#4235 parseAutoSuffix rejects unknown categories/tiers and malformed input", () => {
assert.equal(suffix.parseAutoSuffix("coding:bogus").valid, false);
assert.equal(suffix.parseAutoSuffix("bogus:fast").valid, false);
assert.equal(suffix.parseAutoSuffix("coding:fast:extra").valid, false);
// a bare flat-variant token (fast/cheap/smart) is NOT a category — left to parseAutoPrefix
assert.equal(suffix.parseAutoSuffix("fast").valid, false);
assert.equal(suffix.parseAutoSuffix("").valid, false);
});
test("#4235 tierToWeightVariant maps tiers to scoring profiles", () => {
assert.equal(suffix.tierToWeightVariant("fast"), "fast");
assert.equal(suffix.tierToWeightVariant("cheap"), "cheap");
assert.equal(suffix.tierToWeightVariant("floor"), "cheap");
assert.equal(suffix.tierToWeightVariant("reliable"), "reliability");
// free/pro carry no weight bias — the candidate filter does the work
assert.equal(suffix.tierToWeightVariant("free"), undefined);
assert.equal(suffix.tierToWeightVariant("pro"), undefined);
assert.equal(suffix.tierToWeightVariant(undefined), undefined);
});
test("#4235 buildAutoCandidateFilter only filters when a constraint applies", () => {
// coding/chat with no tier → no narrowing
assert.equal(suffix.buildAutoCandidateFilter("coding", undefined), null);
assert.equal(suffix.buildAutoCandidateFilter("chat", undefined), null);
// category constraints (vision/reasoning/multimodal) and tier constraints (free/pro) → a filter fn
assert.equal(typeof suffix.buildAutoCandidateFilter("vision", undefined), "function");
assert.equal(typeof suffix.buildAutoCandidateFilter("reasoning", undefined), "function");
assert.equal(typeof suffix.buildAutoCandidateFilter(undefined, "free"), "function");
assert.equal(typeof suffix.buildAutoCandidateFilter("coding", "pro"), "function");
});
test("#4235 reliability-first mode pack exists and is normalized", () => {
const pack = modePacks.MODE_PACKS["reliability-first"];
assert.ok(pack, "reliability-first pack registered");
const sum = Object.values(pack).reduce((a, b) => a + b, 0);
assert.ok(Math.abs(sum - 1.0) < 0.01, `reliability-first weights sum to ~1.0 (got ${sum})`);
// health + stability should dominate
assert.ok(pack.health >= 0.3, "reliability-first leans on circuit-breaker health");
});
test("#4235 createBuiltinAutoCombo composes tier weights for auto/coding:fast", async () => {
const combo = await builtinCatalog.createBuiltinAutoCombo("auto/coding:fast", "coding:fast");
assert.equal(combo.id, "auto/coding:fast");
assert.equal(combo.strategy, "auto");
// :fast → ship-fast weights (latency-dominant)
assert.deepEqual(combo.weights, modePacks.MODE_PACKS["ship-fast"]);
});
test("#4235 createBuiltinAutoCombo composes reliability weights for auto/coding:reliable", async () => {
const combo = await builtinCatalog.createBuiltinAutoCombo(
"auto/coding:reliable",
"coding:reliable"
);
assert.deepEqual(combo.weights, modePacks.MODE_PACKS["reliability-first"]);
});
test("#4235 /v1/models advertises the curated auto/<category>:<tier> combos", async () => {
const response = await v1ModelsCatalog.getUnifiedModelsResponse(
new Request("http://localhost/api/v1/models")
);
assert.equal(response.status, 200);
const body = (await response.json()) as { data: Array<{ id: string; owned_by?: string }> };
const ids = new Set(body.data.map((m) => m.id));
for (const autoId of builtinCatalog.AUTO_SUFFIX_VARIANTS) {
assert.ok(ids.has(autoId), `expected /v1/models to advertise ${autoId}`);
}
const codingFast = body.data.find((m) => m.id === "auto/coding:fast");
assert.equal(codingFast?.owned_by, "combo");
});

View File

@@ -248,12 +248,17 @@ test("ensureGitTagExists verifies refs/tags paths and throws a clear error when
test("auto update script builders generate npm, source, and docker-compose scripts with quoting and patch commits", () => {
const npmScript = autoUpdate.buildNpmUpdateScript("3.6.0");
assert.match(npmScript, /npm install -g omniroute@3.6.0/);
// Optional deps (better-sqlite3, keytar, tls-client, and the llmlingua SLM stack)
// must survive an update — install them explicitly so an `omit=optional` config
// cannot silently drop them.
assert.match(npmScript, /--include=optional/);
assert.match(npmScript, /pm2 restart omniroute \|\| true/);
assert.match(npmScript, /Successfully updated to v3.6.0/);
const sourceScript = autoUpdate.buildSourceUpdateScript("3.6.0", "upstream");
assert.match(sourceScript, /git fetch --tags 'upstream'/);
assert.match(sourceScript, /git stash --include-untracked/);
assert.match(sourceScript, /npm install --include=optional --legacy-peer-deps/);
assert.match(sourceScript, /node scripts\/dev\/sync-env\.mjs 2>\/dev\/null \|\| true/);
assert.match(sourceScript, /Successfully updated to v3\.6\.0/);

View File

@@ -337,3 +337,102 @@ test("sanitizeReasoningEffortForProvider: non-object body returns unchanged", ()
const arr: unknown[] = [];
assert.equal(sanitizeReasoningEffortForProvider(arr, "xiaomi-mimo", "x", null), arr);
});
// ── Native DeepSeek (api.deepseek.com) ───────────────────────────────────────
// DeepSeek V4 thinking mode accepts reasoning_effort ONLY as {high, max}. The
// internal OmniRoute scale (low|medium|high|xhigh, xhigh = top) must be mapped
// onto DeepSeek's native vocabulary so the client's requested effort is honored
// instead of silently dropped to the default. This is the INVERSE of the
// OpenRouter-DeepSeek path, whose normalized API expects xhigh, not max.
test("sanitizeReasoningEffortForProvider: native deepseek maps xhigh → max", () => {
const log = makeLog();
const body = {
model: "deepseek-v4-pro",
reasoning_effort: "xhigh",
messages: [{ role: "user", content: "hi" }],
};
const result = sanitizeReasoningEffortForProvider(body, "deepseek", "deepseek-v4-pro", log);
assert.notEqual(result, body, "must return a new object when mutating");
assert.equal((result as any).reasoning_effort, "max");
assert.equal((result as any).model, "deepseek-v4-pro", "other fields preserved");
assert.ok(
log.messages.some(([tag, m]) => tag === "REASONING_SANITIZE" && /xhigh → max/.test(m)),
"logs the xhigh → max mapping"
);
});
test("sanitizeReasoningEffortForProvider: native deepseek preserves max", () => {
const log = makeLog();
const body = {
model: "deepseek-v4-flash",
reasoning_effort: "max",
messages: [{ role: "user", content: "hi" }],
};
const result = sanitizeReasoningEffortForProvider(body, "deepseek", "deepseek-v4-flash", log);
assert.equal(result, body, "max is DeepSeek's native top tier — passes through unchanged");
assert.equal((result as any).reasoning_effort, "max");
assert.equal(log.messages.length, 0);
});
test("sanitizeReasoningEffortForProvider: native deepseek clamps low → high", () => {
const body = {
model: "deepseek-v4-pro",
reasoning_effort: "low",
messages: [{ role: "user", content: "hi" }],
};
const result = sanitizeReasoningEffortForProvider(body, "deepseek", "deepseek-v4-pro", null);
assert.notEqual(result, body, "must return a new object when mutating");
assert.equal((result as any).reasoning_effort, "high", "below the {high, max} floor → high");
});
test("sanitizeReasoningEffortForProvider: native deepseek clamps medium → high", () => {
const body = {
model: "deepseek-v4-pro",
reasoning_effort: "medium",
messages: [{ role: "user", content: "hi" }],
};
const result = sanitizeReasoningEffortForProvider(body, "deepseek", "deepseek-v4-pro", null);
assert.equal((result as any).reasoning_effort, "high");
});
test("sanitizeReasoningEffortForProvider: native deepseek preserves high unchanged", () => {
const body = {
model: "deepseek-v4-pro",
reasoning_effort: "high",
messages: [{ role: "user", content: "hi" }],
};
const result = sanitizeReasoningEffortForProvider(body, "deepseek", "deepseek-v4-pro", null);
assert.equal(result, body, "high is already valid — passes through unchanged");
assert.equal((result as any).reasoning_effort, "high");
});
test("sanitizeReasoningEffortForProvider: native deepseek maps nested reasoning.effort xhigh → max", () => {
const body = {
model: "deepseek-v4-pro",
reasoning: { effort: "xhigh", summary: "auto" },
input: [],
};
const result = sanitizeReasoningEffortForProvider(body, "deepseek", "deepseek-v4-pro", null);
assert.equal((result as any).reasoning.effort, "max");
assert.equal((result as any).reasoning.summary, "auto", "other reasoning fields preserved");
assert.equal((result as any).reasoning_effort, undefined);
});
test("sanitizeReasoningEffortForProvider: OpenRouter DeepSeek still preserves xhigh (not native)", () => {
// Regression guard: the native-deepseek mapping must NOT touch openrouter,
// whose normalized API expects xhigh (issue earendil-works/pi#4055).
const body = {
model: "deepseek/deepseek-v4-pro",
reasoning_effort: "xhigh",
messages: [{ role: "user", content: "hi" }],
};
const result = sanitizeReasoningEffortForProvider(
body,
"openrouter",
"deepseek/deepseek-v4-pro",
null
);
assert.equal(result, body);
assert.equal((result as any).reasoning_effort, "xhigh");
});

View File

@@ -107,6 +107,36 @@ test("resolveNextBuildEnv forces stable build worker mode unless already provide
assert.equal(preservedEnv.NODE_ENV, "production");
});
// Escalated bug (WhatsApp BR, cmqiuhd7600): a local `npm run build` stalls/OOMs
// during the webpack production pass ("Compiling instrumentation" bundles the whole
// server graph). #4076/#4104 raised the heap only in the Docker builder stage; the
// local/native path (build-next-isolated.mjs → resolveNextBuildEnv) was left on V8's
// default ~2 GB ceiling, so memory-constrained npm-global installs hit the same OOM.
test("resolveNextBuildEnv raises the Node heap for memory-constrained local builds", () => {
const env = resolveNextBuildEnv({ NODE_ENV: "production" });
const match = (env.NODE_OPTIONS ?? "").match(/--max-old-space-size=(\d+)/);
assert.ok(
match,
"local build must set NODE_OPTIONS --max-old-space-size to avoid the webpack-pass OOM"
);
assert.ok(
Number(match[1]) >= 4096,
`build heap default must be >= 4096 MB (the V8 default ~2 GB OOMed); got ${match[1]}`
);
});
test("resolveNextBuildEnv does not clobber an existing --max-old-space-size (Docker)", () => {
const env = resolveNextBuildEnv({ NODE_OPTIONS: "--max-old-space-size=8192" });
const occurrences = (env.NODE_OPTIONS.match(/--max-old-space-size=/g) || []).length;
assert.equal(occurrences, 1, "must not duplicate the heap flag when one is already set");
assert.match(env.NODE_OPTIONS, /--max-old-space-size=8192/);
});
test("resolveNextBuildEnv honors the OMNIROUTE_BUILD_MEMORY_MB override", () => {
const env = resolveNextBuildEnv({ OMNIROUTE_BUILD_MEMORY_MB: "6144" });
assert.match(env.NODE_OPTIONS, /--max-old-space-size=6144/);
});
test("getTransientBuildPaths leaves _tasks in place by default", () => {
const paths = getTransientBuildPaths("/repo", {});

View File

@@ -33,6 +33,7 @@ function seedSidecarSources(root: string) {
const files = [
"node_modules/wreq-js/rust/lib.so",
"node_modules/better-sqlite3/build/Release/better_sqlite3.node",
"src/mitm/tproxy/native/build/Release/transparent.node",
"node_modules/@swc/helpers/package.json",
"node_modules/pino-abstract-transport/index.js",
"node_modules/pino-pretty/index.js",
@@ -70,7 +71,13 @@ test("assembleStandalone copies standalone + static + public + sidecars into out
fs.mkdirSync(path.join(tmp, "public"), { recursive: true });
fs.writeFileSync(path.join(tmp, "public", "logo.svg"), "<svg/>");
assembleStandalone({ distDir, outDir, projectRoot: tmp, sanitizePaths: false, copyNatives: false });
assembleStandalone({
distDir,
outDir,
projectRoot: tmp,
sanitizePaths: false,
copyNatives: false,
});
assert.ok(fs.existsSync(path.join(outDir, "server.js")), "server.js copied");
// Static lands under the distDir path (.build/next/static), where the standalone
@@ -128,5 +135,27 @@ test("async and sync sidecar copy paths produce identical bundle trees", async (
asyncTree,
"sync (assembleStandalone) and async (sync*ToDir) must copy the same sidecar tree"
);
// The TPROXY native addon must land at the cwd-relative path the runtime loader
// (transparentSocket.ts) resolves in the standalone bundle.
assert.ok(
asyncTree.includes("src/mitm/tproxy/native/build/Release/transparent.node"),
"TPROXY transparent.node copied into the standalone bundle"
);
fs.rmSync(tmp, { recursive: true, force: true });
});
test("the TPROXY addon source is skipped gracefully when it was not built (non-Linux)", async () => {
const tmp = fs.mkdtempSync(path.join(os.tmpdir(), "assemble-skip-"));
const projectRoot = path.join(tmp, "src-root");
// Seed everything EXCEPT the tproxy addon (simulating a non-Linux build).
fs.mkdirSync(projectRoot, { recursive: true });
const out = path.join(tmp, "out");
fs.mkdirSync(out, { recursive: true });
// No throw even though src/mitm/tproxy/native/... is absent.
await syncStandaloneNativeAssets(projectRoot, fs.promises, { log() {} }, out);
assert.ok(
!fs.existsSync(path.join(out, "src/mitm/tproxy/native/build/Release/transparent.node")),
"absent addon is simply not copied (graceful skip)"
);
fs.rmSync(tmp, { recursive: true, force: true });
});

View File

@@ -0,0 +1,91 @@
import { test } from "node:test";
import assert from "node:assert";
import os from "node:os";
import fs from "node:fs";
import path from "node:path";
import {
evaluateMutationRatchet,
mutationScoreForFile,
measureMutationScores,
readBaselineMutationScores,
} from "../../../scripts/check/check-mutation-ratchet.mjs";
// ── evaluateMutationRatchet: direction UP (score can only improve) ───────────
test("mutation ratchet flags a drop (direction up)", () => {
assert.equal(evaluateMutationRatchet(72.0, 75.0).regressed, true);
assert.equal(evaluateMutationRatchet(76.0, 75.0).regressed, false);
assert.equal(evaluateMutationRatchet(76.0, 75.0).improved, true);
assert.equal(evaluateMutationRatchet(75.0, 75.0).regressed, false); // equal holds
assert.equal(evaluateMutationRatchet(75.0, 75.0).improved, false);
});
// ── mutationScoreForFile: covered score = detected/(detected+survived),
// NoCoverage EXCLUDED (it is a coverage gap, not a test-quality signal). ─────
test("mutationScoreForFile computes the covered score and excludes NoCoverage", () => {
const fileData = {
mutants: [
{ status: "Killed" },
{ status: "Killed" },
{ status: "Killed" },
{ status: "Timeout" }, // Timeout counts as detected
{ status: "Survived" },
{ status: "Survived" },
{ status: "NoCoverage" }, // excluded from denominator
{ status: "NoCoverage" },
{ status: "Ignored" }, // excluded (not a valid mutant)
],
};
// detected = 4 (3 Killed + 1 Timeout); denom = 6 (+2 Survived); NoCoverage/Ignored out.
assert.ok(Math.abs(mutationScoreForFile(fileData) - (4 / 6) * 100) < 1e-9);
});
test("mutationScoreForFile returns null when there are no covered mutants", () => {
assert.equal(mutationScoreForFile({ mutants: [{ status: "NoCoverage" }] }), null);
assert.equal(mutationScoreForFile({ mutants: [] }), null);
});
// ── measureMutationScores: per-file scores from a report (and merges batches) ─
test("measureMutationScores maps each mutated file to its score", () => {
const report = {
files: {
"src/a.ts": { mutants: [{ status: "Killed" }, { status: "Survived" }] }, // 50
"src/b.ts": { mutants: [{ status: "Killed" }, { status: "Killed" }] }, // 100
"src/empty.ts": { mutants: [{ status: "NoCoverage" }] }, // null -> omitted
},
};
const scores = measureMutationScores(report);
assert.equal(scores["src/a.ts"], 50);
assert.equal(scores["src/b.ts"], 100);
assert.equal("src/empty.ts" in scores, false);
});
test("measureMutationScores accepts several reports (per-batch) and unions them", () => {
const c = { files: { "src/a.ts": { mutants: [{ status: "Killed" }, { status: "Survived" }] } } };
const g = { files: { "src/b.ts": { mutants: [{ status: "Killed" }] } } };
const scores = measureMutationScores([c, g]);
assert.equal(scores["src/a.ts"], 50);
assert.equal(scores["src/b.ts"], 100);
});
// ── readBaselineMutationScores: graceful skip when the file/keys are absent ──
test("readBaselineMutationScores returns {} when the baseline file is missing", () => {
assert.deepEqual(readBaselineMutationScores("/no/such/baseline.json"), {});
});
test("readBaselineMutationScores extracts mutationScore.<path> metric values", () => {
// Write a tiny baseline to a temp file and read it back.
const tmp = path.join(os.tmpdir(), `mut-baseline-${process.pid}.json`);
fs.writeFileSync(
tmp,
JSON.stringify({
metrics: {
eslintWarnings: { value: 10, direction: "down" },
"mutationScore.src/a.ts": { value: 70, direction: "up", dedicatedGate: true },
"mutationScore.src/b.ts": { value: 80, direction: "up", dedicatedGate: true },
},
})
);
const base = readBaselineMutationScores(tmp);
assert.deepEqual(base, { "src/a.ts": 70, "src/b.ts": 80 });
fs.rmSync(tmp, { force: true });
});

View File

@@ -0,0 +1,119 @@
import { test } from "node:test";
import assert from "node:assert";
import {
classifyTestFiles,
aggregateRadiography,
classifyFromCounts,
} from "../../../scripts/quality/mutation-radiography.mjs";
// ── classifyTestFiles: the plan's canonical fixture ──────────────────────────
// 2 testFiles that kill mutants + 1 that kills nothing.
// m1 killed ONLY by A -> A gets a unique kill
// m2 killed by A AND B -> both get a shared kill
// m3 survived -> nobody
// Universe = [A, B, C]; C never appears in any killedBy -> empty.
test("classifies unique / redundant / empty test files from killedBy (file-name killedBy)", () => {
const report = {
files: {
"open-sse/utils/error.ts": {
mutants: [
{ id: "m1", status: "Killed", killedBy: ["A.test.ts"] },
{ id: "m2", status: "Killed", killedBy: ["A.test.ts", "B.test.ts"] },
{ id: "m3", status: "Survived", killedBy: [] },
],
},
},
};
const allTestFiles = ["A.test.ts", "B.test.ts", "C.test.ts"];
const r = classifyTestFiles(report, allTestFiles);
assert.equal(r["A.test.ts"].class, "unique"); // mata m1 sozinho
assert.equal(r["A.test.ts"].uniqueKills, 1);
assert.equal(r["A.test.ts"].sharedKills, 1);
assert.equal(r["B.test.ts"].class, "redundant"); // só m2 (compartilhado)
assert.equal(r["B.test.ts"].uniqueKills, 0);
assert.equal(r["C.test.ts"].class, "empty"); // não mata nada
});
// ── id resolution: real Stryker tap-runner reports use numeric test ids in
// killedBy and a testFiles{} section mapping id -> file name. ────────────────
test("resolves numeric killedBy ids to file names via the testFiles section", () => {
const report = {
testFiles: {
"tests/unit/x.test.ts": { tests: [{ id: "0", name: "tests/unit/x.test.ts" }] },
"tests/unit/y.test.ts": { tests: [{ id: "1", name: "tests/unit/y.test.ts" }] },
"tests/unit/z.test.ts": { tests: [{ id: "2", name: "tests/unit/z.test.ts" }] },
},
files: {
"src/m.ts": {
mutants: [
{ id: "m1", status: "Killed", killedBy: ["0"] }, // x alone -> unique
{ id: "m2", status: "Killed", killedBy: ["0", "1"] }, // x + y shared
],
},
},
};
// allTestFiles defaults to the testFiles keys when omitted.
const r = classifyTestFiles(report);
assert.equal(r["tests/unit/x.test.ts"].class, "unique");
assert.equal(r["tests/unit/y.test.ts"].class, "redundant");
assert.equal(r["tests/unit/z.test.ts"].class, "empty");
});
// ── overlapping (🟡): kills ≥1 unique but the majority of its kills are shared.
test("classifies overlapping when shared kills outnumber unique kills", () => {
const report = {
files: {
"src/m.ts": {
mutants: [
{ id: "m1", status: "Killed", killedBy: ["D"] }, // D unique
{ id: "m2", status: "Killed", killedBy: ["D", "E"] }, // D shared
{ id: "m3", status: "Killed", killedBy: ["D", "E", "F"] }, // D shared
],
},
},
};
const r = classifyTestFiles(report, ["D", "E", "F"]);
assert.equal(r["D"].uniqueKills, 1);
assert.equal(r["D"].sharedKills, 2);
assert.equal(r["D"].class, "overlapping"); // 2 shared > 1 unique
assert.equal(r["E"].class, "redundant");
assert.equal(r["F"].class, "redundant");
});
// ── classifyFromCounts: the pure threshold helper. ───────────────────────────
test("classifyFromCounts applies the threshold rules", () => {
assert.equal(classifyFromCounts(0, 0), "empty");
assert.equal(classifyFromCounts(0, 3), "redundant");
assert.equal(classifyFromCounts(2, 1), "unique"); // shared not > unique
assert.equal(classifyFromCounts(1, 1), "unique"); // tie -> unique
assert.equal(classifyFromCounts(1, 5), "overlapping"); // shared > unique
});
// ── aggregateRadiography: merge per-batch reports at the FILE level (ids are
// per-run, so each report is classified independently then summed). A file can
// be empty in one batch but unique in another -> unique overall. ─────────────
test("aggregateRadiography sums per-file kills across batches and reclassifies", () => {
const batchC = {
files: {
"src/routeGuard.ts": {
mutants: [{ id: "c1", status: "Killed", killedBy: ["A"] }], // A unique here
},
},
};
const batchG = {
files: {
"src/chatCore/x.ts": {
mutants: [
{ id: "g1", status: "Killed", killedBy: ["A", "B"] }, // A shared, B shared
],
},
},
};
// B only ever shares; A is unique in C and shared in G -> A unique overall.
const agg = aggregateRadiography([batchC, batchG], ["A", "B", "C"]);
assert.equal(agg["A"].uniqueKills, 1);
assert.equal(agg["A"].sharedKills, 1);
assert.equal(agg["A"].class, "unique");
assert.equal(agg["B"].class, "redundant");
assert.equal(agg["C"].class, "empty");
});

View File

@@ -0,0 +1,42 @@
import test from "node:test";
import assert from "node:assert/strict";
import { readFileSync } from "node:fs";
import { fileURLToPath } from "node:url";
// Regression guard: provider cards must have a *visible* hover state.
//
// Reported bug: hovering a provider card made it go "transparent / not
// highlighted". Root cause was a 1%-opacity hover (`hover:bg-black/[0.01]` /
// `hover:bg-white/[0.01]`) — effectively invisible. The fix switches both card
// surfaces to the dashboard's dominant, visible hover (`hover:bg-*/5`) plus a
// `hover:border-primary/40` highlight. This pins it so the near-invisible hover
// can't silently come back.
const ROOT = fileURLToPath(new URL("../../", import.meta.url));
const CARD_FILES = [
"src/app/(dashboard)/dashboard/providers/components/ProviderCard.tsx",
"src/app/(dashboard)/dashboard/media-providers/[kind]/page.tsx",
];
for (const rel of CARD_FILES) {
test(`${rel}: card hover is visible, not near-transparent`, () => {
const src = readFileSync(ROOT + rel, "utf8");
assert.ok(
!src.includes("hover:bg-black/[0.01]"),
`${rel} still uses the near-invisible 1% hover (light)`
);
assert.ok(
!src.includes("hover:bg-white/[0.01]"),
`${rel} still uses the near-invisible 1% hover (dark)`
);
assert.ok(
src.includes("hover:bg-black/5") && src.includes("hover:bg-white/5"),
`${rel} should use a visible hover background (hover:bg-*/5)`
);
assert.ok(
src.includes("hover:border-primary/40"),
`${rel} should add a visible hover border highlight`
);
});
}

View File

@@ -0,0 +1,116 @@
// Regression guard for two catalog fixes shipped in v3.8.29:
//
// 1. Task 1 — moonshotai/kimi-k2.7-code added to the kimi-coding-apikey (kmca)
// provider catalog (KIMI_CODING_SHARED.models in open-sse/config/providers/shared.ts).
// Requested by @hana189 in discussion #3737.
//
// 2. Bug #3 (issue #3931) — qwen-web missing from PROVIDER_MODELS_CONFIG in
// src/app/api/providers/[id]/models/route.ts, so the model discovery page for
// the web-cookie provider returned nothing. Identified by @thezukiru in #3895.
import test from "node:test";
import assert from "node:assert/strict";
import fs from "node:fs";
import path from "node:path";
import { getModelsByProviderId } from "../../open-sse/config/providerModels.ts";
// ── Task 1: kimi-k2.7-code in kmca (kimi-coding-apikey) ───────────────────────
test("kmca (kimi-coding-apikey) catalog includes moonshotai/kimi-k2.7-code", () => {
const models = getModelsByProviderId("kmca");
const ids = new Set(models.map((m) => m.id));
assert.ok(
ids.has("moonshotai/kimi-k2.7-code"),
"moonshotai/kimi-k2.7-code missing from kmca — add to KIMI_CODING_SHARED.models in shared.ts"
);
});
test("kmca kimi-k2.7-code has 262144 context length and maxOutputTokens", () => {
const models = getModelsByProviderId("kmca");
const model = models.find((m) => m.id === "moonshotai/kimi-k2.7-code");
assert.ok(model, "moonshotai/kimi-k2.7-code not found in kmca catalog");
assert.equal(model.contextLength, 262144, "kimi-k2.7-code contextLength must be 262144");
assert.equal(model.maxOutputTokens, 262144, "kimi-k2.7-code maxOutputTokens must be 262144");
});
test("kmca still exposes kimi-k2.6 and kimi-k2.6-thinking alongside the new model", () => {
const ids = new Set(getModelsByProviderId("kmca").map((m) => m.id));
assert.ok(ids.has("kimi-k2.6"), "kimi-k2.6 must still be present");
assert.ok(ids.has("kimi-k2.6-thinking"), "kimi-k2.6-thinking must still be present");
assert.ok(ids.has("moonshotai/kimi-k2.7-code"), "moonshotai/kimi-k2.7-code must be present");
});
// ── Bug #3 / issue #3931: qwen-web in PROVIDER_MODELS_CONFIG ──────────────────
const ROUTE_FILE = path.join("src", "app", "api", "providers", "[id]", "models", "route.ts");
test("PROVIDER_MODELS_CONFIG contains a qwen-web entry (issue #3931 bug #3)", () => {
const src = fs.readFileSync(ROUTE_FILE, "utf-8");
assert.match(
src,
/"qwen-web"\s*:/,
'"qwen-web" key missing from PROVIDER_MODELS_CONFIG in models/route.ts'
);
});
test("qwen-web PROVIDER_MODELS_CONFIG entry targets chat.qwen.ai/api/v2/models", () => {
const src = fs.readFileSync(ROUTE_FILE, "utf-8");
assert.match(
src,
/chat\.qwen\.ai\/api\/v2\/models/,
"qwen-web discovery URL must be https://chat.qwen.ai/api/v2/models"
);
});
test("qwen-web parseResponse handles Qwen nested data.data structure", () => {
const mockResponse = {
data: {
data: [
{ id: "qwen3.7-plus", name: "Qwen3.7-Plus", owned_by: "qwen" },
{ id: "qwen3-235b-a22b", name: "Qwen3-235B-A22B", owned_by: "qwen" },
{ id: "qwen3-coder-480b", name: "Qwen3-Coder-480B" },
],
},
};
// parseResponse logic matches PROVIDER_MODELS_CONFIG["qwen-web"].parseResponse
const innerData: Array<Record<string, unknown>> =
(mockResponse?.data?.data as Array<Record<string, unknown>>) ||
(mockResponse?.data as unknown as Array<Record<string, unknown>>) ||
[];
const models = innerData
.map((item) => ({
id: (item.id || item.name) as string,
name: (item.name || item.id) as string,
owned_by: (item.owned_by || "qwen") as string,
}))
.filter((m) => m.id);
assert.equal(models.length, 3);
assert.equal(models[0].id, "qwen3.7-plus");
assert.equal(models[0].name, "Qwen3.7-Plus");
assert.equal(models[0].owned_by, "qwen");
assert.equal(models[2].owned_by, "qwen", "owned_by defaults to 'qwen' when absent");
});
test("qwen-web parseResponse handles flat data array fallback", () => {
const mockResponse = {
data: [{ id: "qwen3.7-plus", name: "Qwen3.7-Plus" }],
};
const innerData: Array<Record<string, unknown>> =
(mockResponse?.data as unknown as { data?: Array<Record<string, unknown>> })?.data ||
(mockResponse?.data as unknown as Array<Record<string, unknown>>) ||
[];
const models = innerData
.map((item) => ({
id: (item.id || item.name) as string,
name: (item.name || item.id) as string,
owned_by: (item.owned_by || "qwen") as string,
}))
.filter((m) => m.id);
assert.equal(models.length, 1);
assert.equal(models[0].id, "qwen3.7-plus");
});

View File

@@ -0,0 +1,171 @@
import test from "node:test";
import assert from "node:assert/strict";
import {
resolveAccountSemaphoreKey,
resolveAccountSemaphoreAccountKey,
resolveAccountSemaphoreMaxConcurrency,
buildClaudePromptCacheLogMeta,
} from "../../open-sse/handlers/chatCore/executorHelpers.ts";
import { FORMATS } from "../../open-sse/translator/formats.ts";
test("resolveAccountSemaphoreAccountKey prefers an explicit non-blank connectionId", () => {
assert.equal(resolveAccountSemaphoreAccountKey("conn-1", { id: "ignored" }), "conn-1");
});
test("resolveAccountSemaphoreAccountKey falls back through credential candidates in order", () => {
// blank connectionId -> first non-blank candidate (connectionId field) wins
assert.equal(
resolveAccountSemaphoreAccountKey(" ", { connectionId: "cred-conn", id: "id-x" }),
"cred-conn"
);
// candidate order: connectionId, id, email, name, displayName
assert.equal(resolveAccountSemaphoreAccountKey(null, { id: " id-x " }), "id-x");
assert.equal(resolveAccountSemaphoreAccountKey(null, { email: "a@b.co" }), "a@b.co");
assert.equal(resolveAccountSemaphoreAccountKey(null, { name: "the-name" }), "the-name");
assert.equal(resolveAccountSemaphoreAccountKey(null, { displayName: "Disp" }), "Disp");
});
test("resolveAccountSemaphoreAccountKey returns null when nothing usable is present", () => {
assert.equal(resolveAccountSemaphoreAccountKey(null, null), null);
assert.equal(resolveAccountSemaphoreAccountKey(undefined, undefined), null);
assert.equal(resolveAccountSemaphoreAccountKey("", {}), null);
// non-string / blank candidates are all rejected
assert.equal(resolveAccountSemaphoreAccountKey("", { id: 123, email: " " } as unknown as Record<string, unknown>), null);
});
test("resolveAccountSemaphoreMaxConcurrency parses finite numbers and numeric strings", () => {
// number passthrough
assert.equal(resolveAccountSemaphoreMaxConcurrency({ maxConcurrent: 4 }), 4);
assert.equal(resolveAccountSemaphoreMaxConcurrency({ maxConcurrent: 0 }), 0);
assert.equal(resolveAccountSemaphoreMaxConcurrency({ maxConcurrent: -2 }), -2);
// numeric string is coerced
assert.equal(resolveAccountSemaphoreMaxConcurrency({ maxConcurrent: "8" }), 8);
assert.equal(resolveAccountSemaphoreMaxConcurrency({ maxConcurrent: " 3.5 " }), 3.5);
});
test("resolveAccountSemaphoreMaxConcurrency rejects non-finite / non-numeric / missing values", () => {
// exercises the private toFiniteNumberOrNull null branches indirectly
assert.equal(resolveAccountSemaphoreMaxConcurrency({ maxConcurrent: Infinity }), null);
assert.equal(resolveAccountSemaphoreMaxConcurrency({ maxConcurrent: NaN }), null);
assert.equal(resolveAccountSemaphoreMaxConcurrency({ maxConcurrent: "abc" }), null);
assert.equal(resolveAccountSemaphoreMaxConcurrency({ maxConcurrent: "" }), null);
assert.equal(resolveAccountSemaphoreMaxConcurrency({ maxConcurrent: " " }), null);
assert.equal(resolveAccountSemaphoreMaxConcurrency({ maxConcurrent: true } as unknown as Record<string, unknown>), null);
assert.equal(resolveAccountSemaphoreMaxConcurrency({}), null);
assert.equal(resolveAccountSemaphoreMaxConcurrency(null), null);
});
test("resolveAccountSemaphoreKey builds provider:accountKey when both resolve", () => {
assert.equal(
resolveAccountSemaphoreKey({
provider: "openai",
model: "gpt-4o",
connectionId: "conn-9",
credentials: null,
}),
"openai:conn-9"
);
// accountKey can come from credentials when connectionId is blank
assert.equal(
resolveAccountSemaphoreKey({
provider: "anthropic",
model: "claude",
connectionId: null,
credentials: { email: "user@x.io" },
}),
"anthropic:user@x.io"
);
});
test("resolveAccountSemaphoreKey returns null without a provider or account key", () => {
// no account key resolvable
assert.equal(
resolveAccountSemaphoreKey({ provider: "openai", model: "m", connectionId: null, credentials: null }),
null
);
// account key resolves but provider missing
assert.equal(
resolveAccountSemaphoreKey({ provider: null, model: "m", connectionId: "conn", credentials: null }),
null
);
assert.equal(
resolveAccountSemaphoreKey({ provider: "", model: "m", connectionId: "conn", credentials: null }),
null
);
});
test("buildClaudePromptCacheLogMeta returns null for non-Claude format or non-object body", () => {
assert.equal(buildClaudePromptCacheLogMeta(FORMATS.OPENAI, { system: [] }, null), null);
assert.equal(buildClaudePromptCacheLogMeta(FORMATS.CLAUDE, null, null), null);
assert.equal(
buildClaudePromptCacheLogMeta(FORMATS.CLAUDE, "x" as unknown as Record<string, unknown>, null),
null
);
});
test("buildClaudePromptCacheLogMeta returns null when there are no breakpoints and no beta header", () => {
const body = {
system: [{ text: "plain system, no cache_control" }],
tools: [{ name: "t1" }],
messages: [{ role: "user", content: [{ type: "text", text: "hi" }] }],
};
assert.equal(buildClaudePromptCacheLogMeta(FORMATS.CLAUDE, body, null), null);
});
test("buildClaudePromptCacheLogMeta counts cache_control breakpoints across system/tools/messages", () => {
const body = {
system: [
{ text: "billing", cache_control: { type: "ephemeral", ttl: "5m" } },
// billing header lines are skipped entirely
{ text: "x-anthropic-billing-header: abc", cache_control: { type: "ephemeral" } },
],
tools: [{ name: "lookup", cache_control: { type: "ephemeral" } }],
messages: [
{
role: "user",
content: [
{ type: "text", text: "q", cache_control: { type: "ephemeral" } },
{ type: "text", text: "no cache here" },
],
},
],
};
const meta = buildClaudePromptCacheLogMeta(FORMATS.CLAUDE, body, null);
assert.ok(meta);
// 1 system (the billing-header one is skipped) + 1 tool + 1 message = 3
assert.equal(meta.totalBreakpoints, 3);
assert.equal(meta.applied, true);
assert.equal(meta.systemBreakpoints.length, 1);
assert.equal(meta.systemBreakpoints[0].ttl, "5m");
assert.equal(meta.systemBreakpoints[0].index, 0);
assert.equal(meta.toolBreakpoints.length, 1);
assert.equal(meta.toolBreakpoints[0].name, "lookup");
assert.equal(meta.messageBreakpoints.length, 1);
assert.equal(meta.messageBreakpoints[0].role, "user");
assert.equal(meta.messageBreakpoints[0].blockType, "text");
// default type when cache_control.type missing/blank is "ephemeral"
assert.equal(meta.messageBreakpoints[0].type, "ephemeral");
});
test("buildClaudePromptCacheLogMeta surfaces the Anthropic-Beta header even with zero breakpoints", () => {
const body = { system: [{ text: "plain" }] };
// provider header present -> meta returned, applied=false (no breakpoints)
const fromProvider = buildClaudePromptCacheLogMeta(FORMATS.CLAUDE, body, {
"anthropic-beta": "prompt-caching-2024-07-31",
});
assert.ok(fromProvider);
assert.equal(fromProvider.applied, false);
assert.equal(fromProvider.totalBreakpoints, 0);
assert.equal(fromProvider.anthropicBeta, "prompt-caching-2024-07-31");
// falls back to client headers when provider header absent
const fromClient = buildClaudePromptCacheLogMeta(
FORMATS.CLAUDE,
body,
null,
new Headers({ "Anthropic-Beta": "client-beta" })
);
assert.ok(fromClient);
assert.equal(fromClient.anthropicBeta, "client-beta");
});

View File

@@ -0,0 +1,48 @@
import test from "node:test";
import assert from "node:assert/strict";
import { getHeaderValueCaseInsensitive } from "../../open-sse/handlers/chatCore/headers.ts";
test("getHeaderValueCaseInsensitive reads a Headers instance via .get()", () => {
const h = new Headers({ "Content-Type": "text/event-stream" });
// Headers.get is itself case-insensitive, so a lowercase lookup hits the value.
assert.equal(getHeaderValueCaseInsensitive(h, "content-type"), "text/event-stream");
assert.equal(getHeaderValueCaseInsensitive(h, "Content-Type"), "text/event-stream");
// Missing header on a Headers instance returns null (Headers.get contract).
assert.equal(getHeaderValueCaseInsensitive(h, "x-missing"), null);
});
test("getHeaderValueCaseInsensitive matches plain-object keys case-insensitively", () => {
const obj = { Accept: "text/event-stream", "X-Foo": "bar" };
assert.equal(getHeaderValueCaseInsensitive(obj, "accept"), "text/event-stream");
assert.equal(getHeaderValueCaseInsensitive(obj, "ACCEPT"), "text/event-stream");
assert.equal(getHeaderValueCaseInsensitive(obj, "x-foo"), "bar");
});
test("getHeaderValueCaseInsensitive trims plain-object string values", () => {
assert.equal(getHeaderValueCaseInsensitive({ Accept: " v " }, "accept"), "v");
});
test("getHeaderValueCaseInsensitive ignores blank and non-string plain-object values", () => {
// whitespace-only value: value.trim() is falsy -> skipped -> null
assert.equal(getHeaderValueCaseInsensitive({ Accept: " " }, "accept"), null);
// empty string -> skipped -> null
assert.equal(getHeaderValueCaseInsensitive({ Accept: "" }, "accept"), null);
// non-string values are not strings -> skipped -> null
assert.equal(getHeaderValueCaseInsensitive({ "Content-Length": 42 }, "content-length"), null);
assert.equal(getHeaderValueCaseInsensitive({ Flag: true }, "flag"), null);
});
test("getHeaderValueCaseInsensitive returns null for missing key on plain object", () => {
assert.equal(getHeaderValueCaseInsensitive({ Accept: "x" }, "missing"), null);
});
test("getHeaderValueCaseInsensitive returns null for null/undefined/non-object inputs", () => {
assert.equal(getHeaderValueCaseInsensitive(null, "accept"), null);
assert.equal(getHeaderValueCaseInsensitive(undefined, "accept"), null);
// a non-object (typeof !== "object") short-circuits to null
assert.equal(
getHeaderValueCaseInsensitive("text/event-stream" as unknown as Record<string, unknown>, "accept"),
null
);
});

View File

@@ -0,0 +1,151 @@
import test from "node:test";
import assert from "node:assert/strict";
import {
capMemoryExtractionText,
truncateChatLogText,
cloneBoundedChatLogPayload,
truncateForLog,
MEMORY_EXTRACTION_TEXT_LIMIT,
} from "../../open-sse/handlers/chatCore/logTruncation.ts";
import {
getChatLogTextLimit,
getChatLogArrayTailItems,
getChatLogMaxDepth,
getChatLogMaxObjectKeys,
} from "../../src/lib/logEnv.ts";
test("MEMORY_EXTRACTION_TEXT_LIMIT is the documented 64KB constant", () => {
assert.equal(MEMORY_EXTRACTION_TEXT_LIMIT, 64 * 1024);
});
test("capMemoryExtractionText returns short strings unchanged", () => {
assert.equal(capMemoryExtractionText("hello"), "hello");
// exactly at the limit is not truncated (<= limit)
const exact = "x".repeat(MEMORY_EXTRACTION_TEXT_LIMIT);
assert.equal(capMemoryExtractionText(exact), exact);
});
test("capMemoryExtractionText keeps the trailing window of over-limit strings", () => {
const long = "a".repeat(MEMORY_EXTRACTION_TEXT_LIMIT) + "TAIL";
const capped = capMemoryExtractionText(long);
assert.equal(capped.length, MEMORY_EXTRACTION_TEXT_LIMIT);
// slice(-LIMIT) keeps the end, so the appended TAIL survives.
assert.ok(capped.endsWith("TAIL"));
});
test("truncateChatLogText passes through strings up to the configured limit", () => {
const limit = getChatLogTextLimit();
const under = "y".repeat(limit);
assert.equal(truncateChatLogText(under), under);
});
test("truncateChatLogText builds head + marker + tail for over-limit strings", () => {
const limit = getChatLogTextLimit();
const head = "H".repeat(Math.floor(limit / 2));
const tail = "T".repeat(Math.ceil(limit / 2));
// make the total strictly larger than the limit by inserting a middle chunk
const middle = "M".repeat(500);
const value = head + middle + tail;
const out = truncateChatLogText(value);
const expectedHead = value.slice(0, Math.floor(limit / 2));
const expectedTail = value.slice(-Math.ceil(limit / 2));
assert.equal(
out,
`${expectedHead}\n[...truncated ${value.length - limit} chars...]\n${expectedTail}`
);
// sanity: the marker reports exactly the number of dropped chars
assert.ok(out.includes(`[...truncated ${value.length - limit} chars...]`));
});
test("cloneBoundedChatLogPayload returns null/undefined/primitives as-is", () => {
assert.equal(cloneBoundedChatLogPayload(null), null);
assert.equal(cloneBoundedChatLogPayload(undefined), undefined);
assert.equal(cloneBoundedChatLogPayload(42), 42);
assert.equal(cloneBoundedChatLogPayload(true), true);
});
test("cloneBoundedChatLogPayload truncates long string leaves via truncateChatLogText", () => {
const limit = getChatLogTextLimit();
const big = "z".repeat(limit + 1000);
const out = cloneBoundedChatLogPayload(big) as string;
assert.equal(out, truncateChatLogText(big));
assert.ok(out.includes("[...truncated"));
});
test("cloneBoundedChatLogPayload tail-truncates long arrays with a marker entry", () => {
const maxTail = getChatLogArrayTailItems();
const n = maxTail + 100;
const cloned = cloneBoundedChatLogPayload(new Array(n).fill("a")) as unknown[];
// marker prepended + the retained tail items
assert.equal(cloned.length, maxTail + 1);
const marker = cloned[0] as Record<string, unknown>;
assert.equal(marker._omniroute_truncated_array, true);
assert.equal(marker.originalLength, n);
assert.equal(marker.retainedTailItems, maxTail);
});
test("cloneBoundedChatLogPayload leaves short arrays unmarked", () => {
const cloned = cloneBoundedChatLogPayload(["a", "b", "c"]) as unknown[];
assert.deepEqual(cloned, ["a", "b", "c"]);
});
test("cloneBoundedChatLogPayload caps object keys and records the dropped count", () => {
const maxKeys = getChatLogMaxObjectKeys();
const obj: Record<string, number> = {};
for (let i = 0; i < maxKeys + 5; i += 1) obj[`k${i}`] = i;
const cloned = cloneBoundedChatLogPayload(obj) as Record<string, unknown>;
// first maxKeys keys retained + the synthetic _omniroute_truncated_keys field
assert.equal(cloned._omniroute_truncated_keys, 5);
assert.equal(cloned.k0, 0);
assert.equal(cloned[`k${maxKeys - 1}`], maxKeys - 1);
// a key beyond the cap is dropped
assert.equal(cloned[`k${maxKeys}`], undefined);
});
test("cloneBoundedChatLogPayload stops at max depth with a [MaxDepth] sentinel", () => {
const depth = getChatLogMaxDepth();
// build nesting that goes one level past the cap
let leaf: Record<string, unknown> = { deep: "value" };
for (let i = 0; i < depth + 1; i += 1) leaf = { nested: leaf };
const cloned = cloneBoundedChatLogPayload(leaf) as Record<string, unknown>;
// walk down `depth` levels; the level at >= maxDepth becomes the sentinel string
let cursor: unknown = cloned;
for (let i = 0; i < depth; i += 1) {
cursor = (cursor as Record<string, unknown>).nested;
}
assert.equal(cursor, "[MaxDepth]");
});
test("truncateForLog returns null/undefined and non-object primitives unchanged", () => {
assert.equal(truncateForLog(null), null);
assert.equal(truncateForLog(undefined), undefined);
assert.equal(truncateForLog("hi" as unknown), "hi" as unknown);
});
test("truncateForLog passes small objects through untouched", () => {
const small = { model: "gpt-4o", messages: [{ role: "user", content: "hi" }] };
assert.equal(truncateForLog(small), small);
});
test("truncateForLog summarizes oversized payloads instead of cloning", () => {
const huge = {
model: "gpt-4o",
provider: "openai",
stream: true,
// distinct object references so estimateSizeFast (WeakSet-dedup) counts each one
messages: Array.from({ length: 50000 }, () => ({ role: "user", content: "x".repeat(64) })),
contents: [{ a: 1 }],
};
const summary = truncateForLog(huge) as Record<string, unknown>;
assert.equal(summary._truncated, true);
assert.equal(typeof summary._originalBytes, "number");
assert.ok((summary._originalBytes as number) > 8 * 1024);
assert.equal(summary.model, "gpt-4o");
assert.equal(summary.provider, "openai");
assert.equal(summary.messageCount, 50000);
assert.equal(summary.contentCount, 1);
assert.equal(summary.stream, true);
// the original (huge) is NOT returned — it is a fresh summary object
assert.notEqual(summary, huge);
});

View File

@@ -0,0 +1,136 @@
import test from "node:test";
import assert from "node:assert/strict";
import {
extractMemoryTextFromResponse,
extractMemoryTextFromRequestBody,
resolveMemoryOwnerId,
} from "../../open-sse/handlers/chatCore/memoryExtraction.ts";
test("extractMemoryTextFromResponse reads OpenAI choices[0].message.content (trimmed)", () => {
assert.equal(
extractMemoryTextFromResponse({ choices: [{ message: { content: " hi " } }] }),
"hi"
);
});
test("extractMemoryTextFromResponse joins Claude content text blocks and skips non-text", () => {
assert.equal(
extractMemoryTextFromResponse({
content: [
{ type: "text", text: " a " },
{ type: "image" },
{ type: "text", text: "b" },
],
}),
"a\nb"
);
});
test("extractMemoryTextFromResponse falls back to Responses output_text", () => {
assert.equal(extractMemoryTextFromResponse({ output_text: " out " }), "out");
});
test("extractMemoryTextFromResponse returns empty string for null/empty/no-text shapes", () => {
assert.equal(extractMemoryTextFromResponse(null), "");
assert.equal(extractMemoryTextFromResponse(undefined), "");
assert.equal(extractMemoryTextFromResponse({}), "");
// content array with no text parts -> contentText is "" -> falls through to ""
assert.equal(extractMemoryTextFromResponse({ content: [{ type: "image" }] }), "");
});
test("extractMemoryTextFromResponse prefers OpenAI content over output_text", () => {
assert.equal(
extractMemoryTextFromResponse({
choices: [{ message: { content: "openai" } }],
output_text: "responses",
}),
"openai"
);
});
test("extractMemoryTextFromRequestBody returns the LAST user message (string content)", () => {
const body = {
messages: [
{ role: "user", content: "first" },
{ role: "assistant", content: "ignored" },
{ role: "user", content: "second" },
],
};
assert.equal(extractMemoryTextFromRequestBody(body), "second");
});
test("extractMemoryTextFromRequestBody joins array content parts of the last user message", () => {
const body = {
messages: [
{
role: "user",
content: [
{ type: "input_text", text: " a " },
{ text: "b" },
{ type: "image_url" },
],
},
],
};
assert.equal(extractMemoryTextFromRequestBody(body), "a\nb");
});
test("extractMemoryTextFromRequestBody reads Responses-style input items", () => {
const inputBody = {
input: [{ role: "user", type: "message", content: [{ type: "input_text", text: "hey" }] }],
};
assert.equal(extractMemoryTextFromRequestBody(inputBody), "hey");
});
test("extractMemoryTextFromRequestBody reads a string-content input item", () => {
const inputBody = {
input: [{ role: "user", type: "message", content: " plain " }],
};
assert.equal(extractMemoryTextFromRequestBody(inputBody), "plain");
});
test("extractMemoryTextFromRequestBody scans input items from the end and returns the last user text", () => {
// The primary input scan walks from the end and returns immediately on the
// last item whose role is user (or unset) and type is message (or unset).
const inputBody = {
input: [
{ type: "reasoning", content: "thinking" }, // itemType !== "message" -> skipped
{ role: "user", content: "alpha" }, // matches, but an earlier item from the end wins
{ role: "user", content: "beta" }, // last matching item -> returned
],
};
assert.equal(extractMemoryTextFromRequestBody(inputBody), "beta");
});
test("extractMemoryTextFromRequestBody skips assistant input items but accepts the prior user item", () => {
const inputBody = {
input: [
{ role: "user", type: "message", content: "the question" },
{ role: "assistant", type: "message", content: "the answer" }, // role !== user -> skipped
],
};
assert.equal(extractMemoryTextFromRequestBody(inputBody), "the question");
});
test("extractMemoryTextFromRequestBody returns empty for null/empty/no-user bodies", () => {
assert.equal(extractMemoryTextFromRequestBody(null), "");
assert.equal(extractMemoryTextFromRequestBody(undefined), "");
assert.equal(extractMemoryTextFromRequestBody({}), "");
// only an assistant message -> no user text
assert.equal(
extractMemoryTextFromRequestBody({ messages: [{ role: "assistant", content: "x" }] }),
""
);
});
test("resolveMemoryOwnerId returns the id when present, null otherwise", () => {
assert.equal(resolveMemoryOwnerId({ id: "key_123" }), "key_123");
// whitespace-only id is rejected
assert.equal(resolveMemoryOwnerId({ id: " " }), null);
// non-string id is rejected
assert.equal(resolveMemoryOwnerId({ id: 7 } as unknown as Record<string, unknown>), null);
// missing id / null info
assert.equal(resolveMemoryOwnerId({}), null);
assert.equal(resolveMemoryOwnerId(null), null);
});

View File

@@ -0,0 +1,128 @@
import test from "node:test";
import assert from "node:assert/strict";
import fs from "node:fs";
import os from "node:os";
import path from "node:path";
// Isolated DATA_DIR set BEFORE importing anything that touches the DB
// (injectMemoryAndSkills -> getMemorySettings / retrieveMemories / injectSkills).
const TEST_DATA_DIR = fs.mkdtempSync(path.join(os.tmpdir(), "omniroute-mem-skills-"));
process.env.DATA_DIR = TEST_DATA_DIR;
const { getSkillsProviderForFormat, injectMemoryAndSkills } = await import(
"../../open-sse/handlers/chatCore/memorySkillsInjection.ts"
);
const { FORMATS } = await import("../../open-sse/translator/formats.ts");
const core = await import("../../src/lib/db/core.ts");
test.after(() => {
core.resetDbInstance();
fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true });
});
// ─── getSkillsProviderForFormat (pure switch) ────────────────────────────────
test("getSkillsProviderForFormat maps CLAUDE -> anthropic", () => {
assert.equal(getSkillsProviderForFormat(FORMATS.CLAUDE), "anthropic");
});
test("getSkillsProviderForFormat maps GEMINI -> google", () => {
assert.equal(getSkillsProviderForFormat(FORMATS.GEMINI), "google");
});
test("getSkillsProviderForFormat maps OPENAI and any unknown format -> openai (default)", () => {
assert.equal(getSkillsProviderForFormat(FORMATS.OPENAI), "openai");
// any other / unknown format falls through to the default branch
assert.equal(getSkillsProviderForFormat("gemini-cli"), "openai");
assert.equal(getSkillsProviderForFormat("codex"), "openai");
assert.equal(getSkillsProviderForFormat("totally-unknown"), "openai");
assert.equal(getSkillsProviderForFormat(""), "openai");
});
// ─── injectMemoryAndSkills ───────────────────────────────────────────────────
test("injectMemoryAndSkills with memoryOwnerId=null skips both branches and returns the body unchanged", async () => {
// memoryOwnerId is null -> memorySettings stays null -> the memory guard is false
// (no getMemorySettings/retrieveMemories) AND the skills guard (memorySettings?.skillsEnabled)
// is false. The body is returned verbatim with memorySettings=null.
const body: Record<string, unknown> = {
model: "gpt-4o",
messages: [{ role: "user", content: "hello world" }],
};
const result = await injectMemoryAndSkills({
body,
memoryOwnerId: null,
provider: "openai",
effectiveModel: "gpt-4o",
sourceFormat: FORMATS.OPENAI,
targetFormat: FORMATS.OPENAI,
backgroundReason: null,
log: null,
});
assert.equal(result.memorySettings, null, "memorySettings is null when no owner is provided");
// body is returned as-is (same reference, no injection happened)
assert.equal(result.body, body);
assert.deepEqual(result.body.messages, [{ role: "user", content: "hello world" }]);
assert.equal("tools" in result.body, false, "no skills were injected");
});
test("injectMemoryAndSkills with an empty DB resolves settings, finds nothing to inject, returns body unchanged", async () => {
// memoryOwnerId is set -> getMemorySettings() resolves DB defaults (enabled, skillsEnabled).
// The body has NO `messages` array (only `input`), so shouldInjectMemory() returns false and
// the memory-retrieval branch is skipped. The skills branch runs injectSkills(), but the
// empty DB registry has no skills, so mergedTools.length == existingTools.length and the body
// is NOT cloned/mutated. This exercises the realistic "nothing to inject" path end-to-end.
const log = {
debug: (..._args: unknown[]) => {
/* swallow */
},
};
const body: Record<string, unknown> = {
model: "gpt-4o",
input: [{ role: "user", content: "no messages array here" }],
};
const result = await injectMemoryAndSkills({
body,
memoryOwnerId: "owner-empty-db",
provider: "openai",
effectiveModel: "gpt-4o",
sourceFormat: FORMATS.OPENAI,
targetFormat: FORMATS.OPENAI,
backgroundReason: null,
log,
});
// memorySettings was resolved (defaults) — it is a real object, not null.
assert.ok(result.memorySettings, "memorySettings resolved from DB defaults");
assert.equal(result.memorySettings.enabled, true);
assert.equal(result.memorySettings.skillsEnabled, true);
// No skills in the empty registry -> body returned unchanged (same reference).
assert.equal(result.body, body);
assert.equal("tools" in result.body, false, "no skills injected from an empty registry");
});
test("injectMemoryAndSkills resolves cleanly for a CLAUDE-format body with no owner (provider-mapping path)", async () => {
// Characterizes the no-owner short-circuit for a non-OpenAI source format. Nothing is
// injected; the function just returns the body untouched and memorySettings=null.
const body: Record<string, unknown> = {
model: "claude-3-5-sonnet",
messages: [{ role: "user", content: [{ type: "text", text: "hi" }] }],
};
const result = await injectMemoryAndSkills({
body,
memoryOwnerId: null,
provider: "claude",
effectiveModel: "claude-3-5-sonnet",
sourceFormat: FORMATS.CLAUDE,
targetFormat: FORMATS.CLAUDE,
backgroundReason: "background-task",
log: null,
});
assert.equal(result.memorySettings, null);
assert.equal(result.body, body);
});

View File

@@ -0,0 +1,72 @@
import test from "node:test";
import assert from "node:assert/strict";
import {
convertNDJSONToSSE,
normalizeNonStreamingEventPayload,
isTruthyStreamBody,
isEventStreamAccepted,
shouldTreatBufferedEventResponseAsExpected,
parseNonStreamingSSEPayload,
appendNonStreamingSseTerminalSignal,
type NonStreamingSseTerminalState,
} from "../../open-sse/handlers/chatCore/nonStreamingSse.ts";
import { FORMATS } from "../../open-sse/translator/formats.ts";
test("convertNDJSONToSSE wraps each non-empty line as a data: frame", () => {
const out = convertNDJSONToSSE('{"a":1}\n{"b":2}\n');
assert.ok(out.includes('data: {"a":1}\n'));
assert.ok(out.includes('data: {"b":2}\n'));
assert.equal(convertNDJSONToSSE(""), "");
});
test("normalizeNonStreamingEventPayload only converts x-ndjson content", () => {
const raw = '{"a":1}';
assert.equal(normalizeNonStreamingEventPayload(raw, "application/json"), raw);
assert.notEqual(normalizeNonStreamingEventPayload(raw, "application/x-ndjson"), raw);
});
test("stream-body and event-stream acceptance predicates", () => {
assert.equal(isTruthyStreamBody({ stream: true }), true);
assert.equal(isTruthyStreamBody({ stream: false }), false);
assert.equal(isTruthyStreamBody(null), false);
assert.equal(isEventStreamAccepted({ accept: "text/event-stream" }), true);
assert.equal(isEventStreamAccepted({ accept: "application/json" }), false);
assert.equal(
shouldTreatBufferedEventResponseAsExpected(
false,
{ accept: "application/json" },
{ stream: true }
),
true
);
assert.equal(
shouldTreatBufferedEventResponseAsExpected(false, { accept: "application/json" }, {}),
false
);
});
test("appendNonStreamingSseTerminalSignal detects [DONE] and terminal event types", () => {
const done: NonStreamingSseTerminalState = { currentEvent: "", pendingLine: "" };
assert.equal(appendNonStreamingSseTerminalSignal(done, "data: [DONE]\n"), true);
const stop: NonStreamingSseTerminalState = { currentEvent: "", pendingLine: "" };
assert.equal(appendNonStreamingSseTerminalSignal(stop, "event: message_stop\ndata: {}\n"), true);
const delta: NonStreamingSseTerminalState = { currentEvent: "", pendingLine: "" };
assert.equal(
appendNonStreamingSseTerminalSignal(delta, 'data: {"type":"content_block_delta"}\n'),
false
);
});
test("parseNonStreamingSSEPayload parses an OpenAI-format SSE buffer", () => {
const raw =
'data: {"id":"x","choices":[{"delta":{"content":"hi"},"finish_reason":"stop"}]}\n\ndata: [DONE]\n';
const result = parseNonStreamingSSEPayload(raw, FORMATS.OPENAI, "gpt-4o");
assert.ok(result !== null);
assert.equal(result?.format, FORMATS.OPENAI);
assert.equal(typeof result?.body, "object");
});

View File

@@ -0,0 +1,41 @@
import test from "node:test";
import assert from "node:assert/strict";
import {
buildClaudePassthroughToolNameMap,
restoreClaudePassthroughToolNames,
mergeResponseToolNameMap,
} from "../../open-sse/handlers/chatCore/passthroughToolNames.ts";
import { CLAUDE_OAUTH_TOOL_PREFIX } from "../../open-sse/translator/request/openai-to-claude.ts";
test("buildClaudePassthroughToolNameMap maps prefixed -> original names", () => {
const map = buildClaudePassthroughToolNameMap({
tools: [{ type: "function", function: { name: "get_weather" } }],
});
assert.ok(map);
assert.equal(map?.get(`${CLAUDE_OAUTH_TOOL_PREFIX}get_weather`), "get_weather");
assert.equal(buildClaudePassthroughToolNameMap({ tools: [] }), null);
assert.equal(buildClaudePassthroughToolNameMap(null), null);
});
test("restoreClaudePassthroughToolNames rewrites tool_use block names", () => {
const map = new Map([[`${CLAUDE_OAUTH_TOOL_PREFIX}x`, "x"]]);
const restored = restoreClaudePassthroughToolNames(
{ content: [{ type: "tool_use", name: `${CLAUDE_OAUTH_TOOL_PREFIX}x` }] },
map
) as { content: { name: string }[] };
assert.equal(restored.content[0].name, "x");
const body = { content: [{ type: "tool_use", name: "y" }] };
assert.equal(restoreClaudePassthroughToolNames(body, null), body);
});
test("mergeResponseToolNameMap unions base with executor _toolNameMap", () => {
const base = new Map([["a", "1"]]);
const merged = mergeResponseToolNameMap(base, { _toolNameMap: new Map([["b", "2"]]) }) as Map<
string,
string
>;
assert.equal(merged.get("a"), "1");
assert.equal(merged.get("b"), "2");
assert.equal(mergeResponseToolNameMap(base, {}), base);
});

View File

@@ -0,0 +1,307 @@
import test from "node:test";
import assert from "node:assert/strict";
import fs from "node:fs";
import os from "node:os";
import path from "node:path";
// Isolated DATA_DIR set BEFORE importing anything that touches the DB
// (checkSemanticCache -> getCachedResponse reads the semantic_cache SQLite table).
const TEST_DATA_DIR = fs.mkdtempSync(path.join(os.tmpdir(), "omniroute-sem-cache-"));
process.env.DATA_DIR = TEST_DATA_DIR;
const { checkSemanticCache } = await import("../../open-sse/handlers/chatCore/semanticCache.ts");
const core = await import("../../src/lib/db/core.ts");
// Seeding the real cache (no mock.module under the Stryker tap-runner) lets us drive the
// HIT branch deterministically: setCachedResponse populates the in-memory cache that
// getCachedResponse checks first, so the signature checkSemanticCache rebuilds resolves.
const { generateSignature, setCachedResponse, clearCache } = await import(
"../../src/lib/semanticCache.ts"
);
const { OMNIROUTE_RESPONSE_HEADERS } = await import("../../src/shared/constants/headers.ts");
test.after(() => {
core.resetDbInstance();
fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true });
});
// A reusable persistAttemptLogs spy + base args. The functions below should NEVER be
// invoked on the guard-false / cache-miss paths (those only run on a HIT).
function makeBaseArgs(overrides: Record<string, unknown> = {}) {
const persistCalls: unknown[] = [];
const args = {
semanticCacheEnabled: false,
body: { model: "gpt-4o", messages: [{ role: "user", content: "hi" }], temperature: 0 },
clientRawRequest: { headers: {} },
model: "gpt-4o",
provider: "openai",
stream: false,
reqLogger: {
logConvertedResponse: () => {
throw new Error("logConvertedResponse should not run on guard-false / miss paths");
},
},
effectiveServiceTier: undefined,
connectionId: null as string | null,
startTime: Date.now(),
log: {
debug: () => {
throw new Error("log.debug should only fire on a cache HIT");
},
},
persistAttemptLogs: (a: unknown) => {
persistCalls.push(a);
},
apiKeyId: null as string | null,
...overrides,
};
return { args, persistCalls };
}
// ─── checkSemanticCache ──────────────────────────────────────────────────────
test("checkSemanticCache returns null when semanticCacheEnabled is false (outer guard short-circuit)", async () => {
const { args, persistCalls } = makeBaseArgs({ semanticCacheEnabled: false });
const result = await checkSemanticCache(args as Parameters<typeof checkSemanticCache>[0]);
assert.equal(result, null, "disabled cache -> no-op null result");
assert.equal(persistCalls.length, 0, "no logging side effects when the guard is false");
});
test("checkSemanticCache returns null when enabled but the body is NOT cacheable (temperature != 0)", async () => {
// isCacheableForRead requires temperature === 0. A non-zero temperature makes the guard
// false even with semanticCacheEnabled=true, so it short-circuits to the null no-op.
const { args, persistCalls } = makeBaseArgs({
semanticCacheEnabled: true,
body: { model: "gpt-4o", messages: [{ role: "user", content: "hi" }], temperature: 0.7 },
});
const result = await checkSemanticCache(args as Parameters<typeof checkSemanticCache>[0]);
assert.equal(result, null, "non-cacheable body -> guard false -> null");
assert.equal(persistCalls.length, 0);
});
test("checkSemanticCache returns null when the x-omniroute-no-cache header forces a bypass", async () => {
// The no-cache header makes isCacheableForRead return false even with temperature:0.
const { args } = makeBaseArgs({
semanticCacheEnabled: true,
body: { model: "gpt-4o", messages: [{ role: "user", content: "hi" }], temperature: 0 },
clientRawRequest: { headers: { "x-omniroute-no-cache": "true" } },
});
const result = await checkSemanticCache(args as Parameters<typeof checkSemanticCache>[0]);
assert.equal(result, null, "explicit no-cache header bypasses the cache read");
});
test("checkSemanticCache returns null on a cache MISS (enabled + cacheable body + empty cache)", async () => {
// semanticCacheEnabled=true AND temperature:0 (cacheable) -> enters the guard -> builds a
// signature -> getCachedResponse() finds nothing in the empty (fresh DATA_DIR) cache ->
// the `if (cached)` block is skipped -> the function falls through to `return null`.
const { args, persistCalls } = makeBaseArgs({
semanticCacheEnabled: true,
body: {
model: "gpt-4o",
messages: [{ role: "user", content: "a unique miss query " + Date.now() }],
temperature: 0,
},
});
const result = await checkSemanticCache(args as Parameters<typeof checkSemanticCache>[0]);
assert.equal(result, null, "empty cache -> MISS -> null (no HIT-path side effects)");
assert.equal(persistCalls.length, 0, "persistAttemptLogs only runs on a HIT");
});
test("checkSemanticCache MISS also works for the Responses-API `input` body shape", async () => {
// generateSignature falls back to body.input when body.messages is absent; the empty cache
// still yields a MISS, so the result is null.
const { args, persistCalls } = makeBaseArgs({
semanticCacheEnabled: true,
body: {
model: "gpt-4o",
input: [{ role: "user", content: "responses api miss " + Date.now() }],
temperature: 0,
},
stream: true,
});
const result = await checkSemanticCache(args as Parameters<typeof checkSemanticCache>[0]);
assert.equal(result, null);
assert.equal(persistCalls.length, 0);
});
// ─── HIT path ────────────────────────────────────────────────────────────────
// The guard-false / miss tests above only exercise the `return null` branches. These
// seed the real cache so the `if (cached)` block actually runs end-to-end, killing
// mutants in the HIT body (status 200 / "semantic" / "HIT" / the stream + content-type
// ternaries / the cost fallback / the side-effect calls).
// Recording (non-throwing) spies — the HIT path DOES invoke log.debug + logConvertedResponse.
function makeHitArgs(overrides: Record<string, unknown> = {}) {
const persistCalls: Record<string, unknown>[] = [];
const convertedCalls: unknown[] = [];
const debugCalls: unknown[][] = [];
const args = {
semanticCacheEnabled: true,
body: { model: "gpt-4o", messages: [{ role: "user", content: "cached query" }], temperature: 0 },
clientRawRequest: { headers: {} },
model: "gpt-4o",
provider: "openai",
stream: false,
reqLogger: {
logConvertedResponse: (r: unknown) => {
convertedCalls.push(r);
},
},
effectiveServiceTier: undefined,
connectionId: null as string | null,
startTime: Date.now() - 5,
log: {
debug: (...a: unknown[]) => {
debugCalls.push(a);
},
},
persistAttemptLogs: (a: unknown) => {
persistCalls.push(a as Record<string, unknown>);
},
apiKeyId: null as string | null,
...overrides,
};
return { args, persistCalls, convertedCalls, debugCalls };
}
// Seed the cache under the EXACT signature checkSemanticCache rebuilds for `args`.
function seedHit(args: ReturnType<typeof makeHitArgs>["args"], response: unknown) {
const signature = generateSignature(
args.model,
args.body.messages ?? (args.body as Record<string, unknown>).input,
args.body.temperature,
(args.body as Record<string, unknown>).top_p,
args.apiKeyId ?? undefined
);
setCachedResponse(signature, args.model, response);
return signature;
}
test("checkSemanticCache returns a non-streaming JSON HIT with cache headers + logging side effects", async () => {
clearCache();
const cached = {
id: "chatcmpl-cached-1",
choices: [
{ index: 0, message: { role: "assistant", content: "cached answer" }, finish_reason: "stop" },
],
usage: { prompt_tokens: 10, completion_tokens: 5, total_tokens: 15 },
};
const { args, persistCalls, convertedCalls, debugCalls } = makeHitArgs({
body: { model: "gpt-4o", messages: [{ role: "user", content: "hit query one" }], temperature: 0 },
stream: false,
});
seedHit(args, cached);
const result = await checkSemanticCache(args as Parameters<typeof checkSemanticCache>[0]);
assert.ok(result, "HIT -> non-null result");
assert.equal(result.success, true, "HIT result.success is true");
const res = result.response as Response;
assert.equal(res.headers.get(OMNIROUTE_RESPONSE_HEADERS.cache), "HIT", "X-OmniRoute-Cache: HIT");
assert.equal(
res.headers.get(OMNIROUTE_RESPONSE_HEADERS.cacheHit),
"true",
"cacheHit meta header is true"
);
assert.equal(
res.headers.get("Content-Type"),
"application/json",
"non-streaming HIT -> application/json"
);
const bodyText = await res.text();
assert.equal(bodyText, JSON.stringify(cached), "non-streaming HIT body is the cached JSON");
assert.equal(persistCalls.length, 1, "persistAttemptLogs runs exactly once on a HIT");
const logged = persistCalls[0];
assert.equal(logged.status, 200, "persisted status is 200");
assert.equal(logged.cacheSource, "semantic", "persisted cacheSource is 'semantic'");
assert.deepEqual(logged.responseBody, cached, "persisted responseBody is the cached object");
assert.deepEqual(logged.clientResponse, cached, "persisted clientResponse is the cached object");
assert.deepEqual(logged.tokens, cached.usage, "persisted tokens come from cached.usage");
assert.equal(logged.providerRequest, null);
assert.equal(logged.providerResponse, null);
assert.equal(convertedCalls.length, 1, "logConvertedResponse called once with the cached body");
assert.deepEqual(convertedCalls[0], cached);
assert.equal(debugCalls.length, 1, "log.debug fires exactly once on a HIT");
});
test("checkSemanticCache returns a streaming SSE HIT (text/event-stream) when stream=true", async () => {
clearCache();
const cached = {
id: "chatcmpl-cached-stream",
choices: [
{
index: 0,
message: { role: "assistant", content: "streamed cached answer" },
finish_reason: "stop",
},
],
usage: { prompt_tokens: 3, completion_tokens: 4, total_tokens: 7 },
};
const { args, persistCalls } = makeHitArgs({
body: { model: "gpt-4o", messages: [{ role: "user", content: "hit query stream" }], temperature: 0 },
stream: true,
});
seedHit(args, cached);
const result = await checkSemanticCache(args as Parameters<typeof checkSemanticCache>[0]);
assert.ok(result, "streaming HIT -> non-null result");
assert.equal(result.success, true);
const res = result.response as Response;
assert.equal(
res.headers.get("Content-Type"),
"text/event-stream",
"streaming HIT -> text/event-stream"
);
assert.equal(res.headers.get(OMNIROUTE_RESPONSE_HEADERS.cache), "HIT");
const bodyText = await res.text();
assert.ok(bodyText.includes("data: "), "SSE body contains data frames");
assert.ok(bodyText.includes("streamed cached answer"), "SSE body carries the cached content");
assert.ok(bodyText.trimEnd().endsWith("data: [DONE]"), "SSE body terminates with [DONE]");
assert.equal(persistCalls.length, 1, "persistAttemptLogs runs once on a streaming HIT too");
});
test("checkSemanticCache HITs even when the cached body has no usage (cost falls back to 0)", async () => {
clearCache();
const cached = {
id: "chatcmpl-cached-no-usage",
choices: [
{ index: 0, message: { role: "assistant", content: "no-usage answer" }, finish_reason: "stop" },
],
};
const { args, persistCalls } = makeHitArgs({
body: {
model: "gpt-4o",
messages: [{ role: "user", content: "hit query no usage" }],
temperature: 0,
},
stream: false,
});
seedHit(args, cached);
const result = await checkSemanticCache(args as Parameters<typeof checkSemanticCache>[0]);
assert.ok(result, "HIT with no usage -> non-null result");
assert.equal(result.success, true);
const res = result.response as Response;
assert.equal(res.headers.get(OMNIROUTE_RESPONSE_HEADERS.cache), "HIT");
// cachedUsage resolves to undefined -> cachedCost = 0 -> the zero-cost sentinel header.
assert.equal(
res.headers.get(OMNIROUTE_RESPONSE_HEADERS.responseCost),
"0.0000000000",
"no usage -> zero responseCost header"
);
assert.equal(persistCalls.length, 1);
assert.equal(persistCalls[0].tokens, undefined, "no usage -> persisted tokens is undefined");
});

View File

@@ -0,0 +1,173 @@
import test from "node:test";
import assert from "node:assert/strict";
import fs from "node:fs";
import os from "node:os";
import path from "node:path";
// Isolated DATA_DIR set BEFORE importing anything that may touch the DB
// (maybeSyncClaudeExtraUsageState -> fetchLiveProviderLimits -> getProviderConnectionById).
const TEST_DATA_DIR = fs.mkdtempSync(path.join(os.tmpdir(), "omniroute-telemetry-"));
process.env.DATA_DIR = TEST_DATA_DIR;
const { forwardDashboardEventToLiveWs, maybeSyncClaudeExtraUsageState } = await import(
"../../open-sse/handlers/chatCore/telemetryHelpers.ts"
);
const core = await import("../../src/lib/db/core.ts");
const originalFetch = globalThis.fetch;
const originalLiveWsPort = process.env.LIVE_WS_PORT;
test.afterEach(() => {
globalThis.fetch = originalFetch;
if (originalLiveWsPort === undefined) {
delete process.env.LIVE_WS_PORT;
} else {
process.env.LIVE_WS_PORT = originalLiveWsPort;
}
});
test.after(() => {
globalThis.fetch = originalFetch;
core.resetDbInstance();
fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true });
});
// ─── forwardDashboardEventToLiveWs ───────────────────────────────────────────
test("forwardDashboardEventToLiveWs POSTs event+payload+timestamp as JSON to the default port", async () => {
delete process.env.LIVE_WS_PORT;
let capturedUrl: string | undefined;
let capturedInit: RequestInit | undefined;
globalThis.fetch = (async (url: string, init: RequestInit) => {
capturedUrl = url;
capturedInit = init;
return new Response("ok", { status: 200 });
}) as typeof fetch;
const before = Date.now();
await forwardDashboardEventToLiveWs("my-event", { foo: "bar" });
const after = Date.now();
// Default port is 20129 when LIVE_WS_PORT is unset.
assert.equal(capturedUrl, "http://127.0.0.1:20129/__omniroute_event");
assert.equal(capturedInit?.method, "POST");
assert.equal(
(capturedInit?.headers as Record<string, string>)["content-type"],
"application/json"
);
assert.ok(capturedInit?.signal, "an AbortSignal is attached for the 1.5s timeout");
const parsed = JSON.parse(capturedInit?.body as string);
assert.equal(parsed.event, "my-event");
assert.deepEqual(parsed.payload, { foo: "bar" });
assert.equal(typeof parsed.timestamp, "number");
assert.ok(
parsed.timestamp >= before && parsed.timestamp <= after,
"timestamp is Date.now() captured at call time"
);
});
test("forwardDashboardEventToLiveWs honors LIVE_WS_PORT override", async () => {
process.env.LIVE_WS_PORT = "31337";
let capturedUrl: string | undefined;
globalThis.fetch = (async (url: string) => {
capturedUrl = url;
return new Response("ok", { status: 200 });
}) as typeof fetch;
await forwardDashboardEventToLiveWs("e", null);
assert.equal(capturedUrl, "http://127.0.0.1:31337/__omniroute_event");
});
test("forwardDashboardEventToLiveWs swallows fetch rejection and still resolves", async () => {
globalThis.fetch = (async () => {
throw new Error("sidecar down");
}) as typeof fetch;
// Must not throw — best-effort sidecar bridge; the catch swallows.
await assert.doesNotReject(forwardDashboardEventToLiveWs("e", { a: 1 }));
});
// ─── maybeSyncClaudeExtraUsageState ──────────────────────────────────────────
test("maybeSyncClaudeExtraUsageState returns early when connectionId is falsy (no fetch)", async () => {
let fetchCalled = false;
globalThis.fetch = (async () => {
fetchCalled = true;
return new Response("", { status: 200 });
}) as typeof fetch;
await maybeSyncClaudeExtraUsageState({
provider: "claude",
connectionId: null,
providerSpecificData: {},
log: null,
});
assert.equal(fetchCalled, false, "guard short-circuits before any network/DB work");
});
test("maybeSyncClaudeExtraUsageState returns early for non-claude provider (block disabled)", async () => {
let fetchCalled = false;
globalThis.fetch = (async () => {
fetchCalled = true;
return new Response("", { status: 200 });
}) as typeof fetch;
await maybeSyncClaudeExtraUsageState({
provider: "openai",
connectionId: "some-conn",
providerSpecificData: {},
log: null,
});
assert.equal(fetchCalled, false, "isClaudeExtraUsageBlockEnabled is false for non-claude");
});
test("maybeSyncClaudeExtraUsageState returns early for claude with blockExtraUsage:false", async () => {
let fetchCalled = false;
globalThis.fetch = (async () => {
fetchCalled = true;
return new Response("", { status: 200 });
}) as typeof fetch;
await maybeSyncClaudeExtraUsageState({
provider: "claude",
connectionId: "some-conn",
providerSpecificData: { blockExtraUsage: false },
log: null,
});
assert.equal(fetchCalled, false, "explicit blockExtraUsage:false disables the block");
});
test("maybeSyncClaudeExtraUsageState enters the try for claude+enabled, swallows the error, and logs via log.debug", async () => {
// provider=claude, providerSpecificData={} (blockExtraUsage !== false), connectionId set
// -> passes the guard -> calls the REAL fetchLiveProviderLimits("bogus-conn") which
// looks the connection up in the (empty) DB, finds nothing, throws "Connection not found",
// and the function's internal try/catch swallows it while logging to log.debug.
const calls: unknown[][] = [];
const log = {
debug: (...args: unknown[]) => {
calls.push(args);
},
};
await assert.doesNotReject(
maybeSyncClaudeExtraUsageState({
provider: "claude",
connectionId: "bogus-conn-id",
providerSpecificData: {},
log,
})
);
assert.equal(calls.length, 1, "the swallowed error path logs exactly once");
assert.equal(calls[0][0], "CLAUDE_USAGE");
assert.match(
String(calls[0][1]),
/Failed to sync Claude extra-usage state:/,
"logs the sync-failure message with the underlying error text"
);
});

View File

@@ -433,14 +433,13 @@ test("chatCore times out upstream execution before provider response headers", a
userAgent: "unit-test",
} as any);
const pendingDetail = (await waitFor(
() =>
// details[connectionId] is Record<modelKey, PendingRequestDetail[]> —
// the original predicate tested each ARRAY's .providerRequest (always
// undefined), so the waitFor could never resolve. Flatten to the details.
Object.values(getPendingRequests().details[connectionId] || {})
.flat()
.find((detail: any) => detail?.providerRequest?.model === "gpt-4o-mini")
const pendingDetail = (await waitFor(() =>
// details[connectionId] is Record<modelKey, PendingRequestDetail[]> —
// the original predicate tested each ARRAY's .providerRequest (always
// undefined), so the waitFor could never resolve. Flatten to the details.
Object.values(getPendingRequests().details[connectionId] || {})
.flat()
.find((detail: any) => detail?.providerRequest?.model === "gpt-4o-mini")
)) as any;
assert.equal(pendingDetail?.providerRequest?.model, "gpt-4o-mini");
assert.deepEqual(pendingDetail?.providerRequest?.messages, body.messages);
@@ -2519,7 +2518,13 @@ test("chatCore returns streaming responses without waiting for upstream completi
const raceResult = await Promise.race([
invocation.then(() => "returned"),
new Promise((resolve) => setTimeout(() => resolve("blocked"), 1000)),
// 10s ceiling: a non-buffering streaming impl resolves the invocation as soon
// as the Response is returned (upstream still open), but on a starved CI event
// loop that legitimate early return can exceed a 1s wall-clock budget (flake
// repro: 5/8 runs returned at 1.32.2s under CPU contention → false "blocked").
// The ceiling only bounds the buffered-failure case: a buffering impl never
// resolves until closeUpstream() fires below, so it still trips "blocked".
new Promise((resolve) => setTimeout(() => resolve("blocked"), 10000)),
]);
if (raceResult !== "returned") {

View File

@@ -0,0 +1,51 @@
import test from "node:test";
import assert from "node:assert/strict";
import {
createBodyTimeoutError,
createUpstreamStartTimeoutError,
createAbortError,
computeBillableTokens,
getExecutorTimeoutMs,
normalizeExecutorResult,
} from "../../open-sse/handlers/chatCore/upstreamTimeouts.ts";
test("error factories set name and message", () => {
const body = createBodyTimeoutError(1234);
assert.equal(body.name, "BodyTimeoutError");
assert.match(body.message, /1234ms/);
const start = createUpstreamStartTimeoutError(500, "openai", "gpt-4o");
assert.equal(start.name, "TimeoutError");
assert.match(start.message, /openai\/gpt-4o/);
const ctrl = new AbortController();
ctrl.abort("nope");
const ab = createAbortError(ctrl.signal);
assert.equal(ab.name, "AbortError");
});
test("computeBillableTokens sums input+output+reasoning (no cache double-count)", () => {
const total = computeBillableTokens({
prompt_tokens: 10,
completion_tokens: 5,
reasoning_tokens: 2,
});
assert.equal(total, 17);
});
test("getExecutorTimeoutMs floors valid values and falls back to default", () => {
assert.equal(getExecutorTimeoutMs({ getTimeoutMs: () => 1234.9 }), 1234);
assert.equal(getExecutorTimeoutMs({ getTimeoutMs: () => NaN }), getExecutorTimeoutMs(null));
assert.ok(Number.isFinite(getExecutorTimeoutMs(null)));
});
test("normalizeExecutorResult wraps bare Response and passes through rich result", () => {
const r = new Response("x");
const wrapped = normalizeExecutorResult(r);
assert.equal(wrapped.response, r);
assert.equal(wrapped.url, "");
const rich = normalizeExecutorResult({ response: r, url: "u", headers: { a: "b" } });
assert.equal(rich.url, "u");
assert.equal(rich.headers.a, "b");
});

View File

@@ -122,9 +122,10 @@ test("INTENTIONALLY_INTERNAL is exported from check-db-rules.mjs", () => {
assert.ok(INTENTIONALLY_INTERNAL.size > 0, "INTENTIONALLY_INTERNAL must not be empty");
});
test("INTENTIONALLY_INTERNAL contains the expected 25 audited modules", () => {
test("INTENTIONALLY_INTERNAL contains the expected 26 audited modules", () => {
const expected = [
"_rowTypes",
"accessTokens",
"cleanup",
"cliToolState",
"comboForecast",

View File

@@ -9,6 +9,45 @@ import {
formatHumanReport,
} from "../../scripts/check/check-fabricated-docs.mjs";
// ── Fixture helpers ─────────────────────────────────────────────────────────
// The hardened checker accepts a `root` so we can run the full pipeline against a
// throwaway fixture repo (its own docs/, src/, .env.example) instead of the live
// tree. Each fixture is a minimal repo: a code surface to index + a single doc.
type Fixture = { docs?: Record<string, string>; files?: Record<string, string> };
function makeFixtureRoot(fx: Fixture): string {
const root = fs.mkdtempSync(path.join(os.tmpdir(), "fab-docs-"));
const write = (rel: string, content: string) => {
const abs = path.join(root, rel);
fs.mkdirSync(path.dirname(abs), { recursive: true });
fs.writeFileSync(abs, content);
};
// Always provide an AGENTS.md so allScanFiles() has at least one scan target.
write("AGENTS.md", fx.docs?.["AGENTS.md"] ?? "# Fixture\n");
for (const [rel, content] of Object.entries(fx.docs ?? {})) {
if (rel === "AGENTS.md") write(rel, content);
else write(path.join("docs", rel), content);
}
for (const [rel, content] of Object.entries(fx.files ?? {})) write(rel, content);
return root;
}
/** Returns the set of distinct `${kind}::${value}` findings for a fixture. */
function findingsFor(fx: Fixture): Set<string> {
const root = makeFixtureRoot(fx);
try {
const result = runFabricatedDocsCheck({ root });
const out = new Set<string>();
for (const f of result.files) {
for (const finding of f.findings) out.add(`${finding.kind}::${finding.value}`);
}
return out;
} finally {
fs.rmSync(root, { recursive: true, force: true });
}
}
// We can't easily mock the buildCodebaseIndex() which walks src/app/api etc.
// Instead, we test the report-formatting logic and the no-findings path on
// the real repo, which acts as a smoke test that the script runs end-to-end.
@@ -73,3 +112,236 @@ test("formatHumanReport: groups findings by kind", () => {
assert.match(out, /FAKE_VAR_X/);
assert.match(out, /onFake/);
});
// ─── Hardening: precision fixes (QG v2 Fase 9 T9) ───────────────────────────
//
// Each test runs the FULL pipeline (index + scan) over a fixture repo so it
// exercises the real heuristic, not a stubbed index.
test("env-var: an `export const` UPPER_SNAKE identifier in backticks is NOT flagged", () => {
const found = findingsFor({
files: {
"src/server/authz/routeGuard.ts":
"export const LOCAL_ONLY_API_PREFIXES: ReadonlyArray<string> = [];\n",
},
docs: {
"guide.md": "We expose `LOCAL_ONLY_API_PREFIXES` to gate loopback routes.\n",
},
});
assert.ok(
!found.has("env-var::LOCAL_ONLY_API_PREFIXES"),
"export const identifier must not be flagged as a fabricated env var"
);
});
test("env-var: an enum / object-literal member (HALF_OPEN) in backticks is NOT flagged", () => {
const found = findingsFor({
files: {
"src/shared/utils/circuitBreaker.ts":
'export const STATE = {\n CLOSED: "CLOSED",\n HALF_OPEN: "HALF_OPEN",\n} as const;\n',
},
docs: { "resilience.md": "After the reset window the breaker enters `HALF_OPEN`.\n" },
});
assert.ok(!found.has("env-var::HALF_OPEN"), "object-literal/enum key must not be flagged");
});
test('env-var: a var read via bracket notation process.env["X"] is NOT flagged', () => {
const found = findingsFor({
files: {
"src/lib/memory/vectorStore.ts": 'const k = Number(process.env["MEMORY_RRF_K"] ?? 60);\n',
},
docs: { "memory.md": "Tune ranking with `MEMORY_RRF_K`.\n" },
});
assert.ok(!found.has("env-var::MEMORY_RRF_K"), 'process.env["X"] read must be indexed');
});
test('env-var: a var read via an env helper (envInt("X")) is NOT flagged', () => {
const found = findingsFor({
files: {
"open-sse/config/constants.ts":
'const t = envInt("OMNIROUTE_CIRCUIT_BREAKER_OAUTH_THRESHOLD", 8);\n',
},
docs: { "cfg.md": "Override with `OMNIROUTE_CIRCUIT_BREAKER_OAUTH_THRESHOLD`.\n" },
});
assert.ok(
!found.has("env-var::OMNIROUTE_CIRCUIT_BREAKER_OAUTH_THRESHOLD"),
'envInt("X", …) helper read must be indexed'
);
});
test("env-var: a var read ONLY in tests/ (RUN_CHAOS_INT) is NOT flagged", () => {
const found = findingsFor({
files: {
"tests/integration/resilience-chaos.test.ts":
'const RUN = process.env.RUN_CHAOS_INT === "1";\n',
},
docs: { "testing.md": "Set `RUN_CHAOS_INT` to enable the chaos suite.\n" },
});
assert.ok(
!found.has("env-var::RUN_CHAOS_INT"),
"env vars read only in tests/ must be indexed, not flagged"
);
});
test("env-var: a var present only in .env.example is NOT flagged", () => {
const found = findingsFor({
files: { ".env.example": "# Contract\nSOME_DOCUMENTED_CONTRACT_VAR=value\n" },
docs: { "env.md": "Configure `SOME_DOCUMENTED_CONTRACT_VAR` in your environment.\n" },
});
assert.ok(
!found.has("env-var::SOME_DOCUMENTED_CONTRACT_VAR"),
".env.example is the env contract — its vars are documented, not fabricated"
);
});
test("api-path: a documented prefix with sub-routes (/api/cloud/) is NOT flagged", () => {
const found = findingsFor({
files: {
"src/app/api/cloud/auth/route.ts": "export async function GET() {}\n",
},
docs: { "cloud.md": "All cloud endpoints live under `/api/cloud/`.\n" },
});
assert.ok(
!found.has("api-path::/api/cloud/"),
"a prefix that is an ancestor of a real route.ts must resolve"
);
});
test("api-path: a dynamic-segment prefix (/api/services/{name}/) is NOT flagged", () => {
const found = findingsFor({
files: {
"src/app/api/services/[name]/status/route.ts": "export async function GET() {}\n",
},
docs: { "services.md": "Hit `/api/services/{name}/status` for health.\n" },
});
assert.ok(
!found.has("api-path::/api/services/{name}/status"),
"[name] dynamic segments must match the documented {name} convention"
);
});
test("hook: a real callback now in KNOWN_HOOKS (onChunk) is NOT flagged", () => {
const found = findingsFor({
docs: { "playground.md": "The stream invokes `onChunk` for each delta.\n" },
});
assert.ok(!found.has("hook::onChunk"), "onChunk is a real callback and must not be flagged");
});
test("file-ref: a tutorial placeholder (src/app/api/your-route/route.ts) is NOT flagged", () => {
const found = findingsFor({
docs: {
"scenario.md": "Create `src/app/api/your-route/route.ts` with GET/POST handlers.\n",
},
});
assert.ok(
!found.has("file-ref::src/app/api/your-route/route.ts"),
"your-* / my* placeholders in how-to scenarios must not be flagged"
);
});
// ─── ANTI-OVER-SUPPRESSION GUARD (the most important test) ──────────────────
//
// The hardening eliminates false positives by adding PRECISION, never by blinding
// the checker. A reference to something that genuinely does not exist MUST still be
// flagged — otherwise the gate is worthless.
test("ANTI-OVER-SUPPRESSION: a reference to a genuinely missing file IS still flagged", () => {
const found = findingsFor({
docs: { "bad.md": "See the handler in `src/nao/existe.ts` for details.\n" },
});
assert.ok(
found.has("file-ref::src/nao/existe.ts"),
"a non-existent file reference must remain flagged — precision must not blind detection"
);
});
test("ANTI-OVER-SUPPRESSION: a truly fabricated env var IS still flagged", () => {
const found = findingsFor({
// No code reads it, not a code identifier, not in .env.example.
docs: { "bad.md": "Set `TOTALLY_FABRICATED_ENV_VAR_XYZ` to enable nothing.\n" },
});
assert.ok(
found.has("env-var::TOTALLY_FABRICATED_ENV_VAR_XYZ"),
"a fabricated env var must remain flagged"
);
});
test("ANTI-OVER-SUPPRESSION: a fabricated API path with no backing route.ts IS still flagged", () => {
const found = findingsFor({
files: { "src/app/api/cloud/auth/route.ts": "export async function GET() {}\n" },
// /api/imaginary/* has no route.ts anywhere and is not an ancestor of one.
docs: { "bad.md": "Call `/api/imaginary/widget` to do magic.\n" },
});
assert.ok(
found.has("api-path::/api/imaginary/widget"),
"an API path with no backing route must remain flagged"
);
});
test("env-var: a doc explicitly stating a var does NOT exist is NOT flagged (documents absence)", () => {
const found = findingsFor({
docs: {
"memory.md":
"There are no env vars to tune weights (`MEMORY_RRF_VECTOR_WEIGHT` does not exist).\n",
},
});
assert.ok(
!found.has("env-var::MEMORY_RRF_VECTOR_WEIGHT"),
"documenting a var's absence is not fabricating it"
);
});
test("env-var: a doc saying an override is 'not yet implemented' is NOT flagged", () => {
const found = findingsFor({
docs: {
"zed.md": "A `ZED_CONFIG_PATH` environment variable override is not yet implemented.\n",
},
});
assert.ok(!found.has("env-var::ZED_CONFIG_PATH"), "not-yet-implemented is an absence statement");
});
test("ANTI-OVER-SUPPRESSION: a fabricated env var on a normal (non-negated) line IS still flagged", () => {
// Same shape as the negation cases above, but WITHOUT an absence statement —
// proves the negation skip is scoped to lines that disclaim the var, not a blanket
// suppression of every memory/config-looking name.
const found = findingsFor({
docs: { "bad.md": "Set `MADE_UP_TUNING_KNOB_FOR_NOTHING` to change behavior.\n" },
});
assert.ok(
found.has("env-var::MADE_UP_TUNING_KNOB_FOR_NOTHING"),
"a fabricated env var on a plain line must still be flagged"
);
});
test("cli-cmd: an arg-bearing `.command('connect <host>')` registration is NOT flagged", () => {
// The old extraction regex required the subcommand name to be immediately followed
// by the closing quote, so commander's arg-bearing forms (`connect <host>`,
// `chat [msg]`) were never indexed → a doc that referenced them was wrongly flagged.
const found = findingsFor({
files: {
"bin/cli/commands/connect.mjs":
'export function registerConnect(p) {\n p.command("connect <host>").action(() => {});\n}\n',
},
docs: { "guides/remote.md": "You log in once with `omniroute connect <host>`.\n" },
});
assert.ok(
!found.has("cli-cmd::omniroute connect"),
"a registered arg-bearing subcommand must be recognized and not flagged"
);
});
test("ANTI-OVER-SUPPRESSION: an unregistered subcommand IS still flagged", () => {
// Broadening the regex must add precision, not blind detection: a doc that invokes
// a subcommand with no `.command()` registration anywhere in bin/ must remain flagged.
const found = findingsFor({
files: {
"bin/cli/commands/connect.mjs":
'export function registerConnect(p) {\n p.command("connect <host>").action(() => {});\n}\n',
},
docs: { "guides/remote.md": "Then run `omniroute teleport <host>` to finish.\n" },
});
assert.ok(
found.has("cli-cmd::omniroute teleport"),
"an unregistered subcommand must remain flagged — precision must not blind detection"
);
});

View File

@@ -17,6 +17,7 @@ import { spawnSync } from "node:child_process";
import {
evaluateOpenapiRatchet,
readBaselineOpenapiValue,
releaseBranchForVersion,
// @ts-expect-error — .mjs helper has no type declarations; runtime shape is known.
} from "../../scripts/check/check-openapi-breaking.mjs";
@@ -26,11 +27,34 @@ const evaluate = evaluateOpenapiRatchet as (args: {
baseline: number | null;
}) => RatchetVerdict;
const readBaseline = readBaselineOpenapiValue as (p?: string) => number | null;
const releaseBranch = releaseBranchForVersion as (v: string | null | undefined) => string | null;
const SCRIPT_PATH = fileURLToPath(
new URL("../../scripts/check/check-openapi-breaking.mjs", import.meta.url)
);
// ---------------------------------------------------------------------------
// releaseBranchForVersion — the default base ref derives from the package
// version so it never goes stale across release cycles (was a hard-coded
// "origin/release/v3.8.27" that drifted into the v3.8.29 cycle).
// ---------------------------------------------------------------------------
test("releaseBranchForVersion: a clean semver derives the matching release branch", () => {
assert.equal(releaseBranch("3.8.29"), "origin/release/v3.8.29");
});
test("releaseBranchForVersion: a prerelease/build suffix is ignored", () => {
assert.equal(releaseBranch("3.8.29-dev.2"), "origin/release/v3.8.29");
assert.equal(releaseBranch("10.0.0+build.7"), "origin/release/v10.0.0");
});
test("releaseBranchForVersion: a non-semver value yields null (caller falls back)", () => {
assert.equal(releaseBranch(""), null);
assert.equal(releaseBranch(null), null);
assert.equal(releaseBranch(undefined), null);
assert.equal(releaseBranch("not-a-version"), null);
});
// ---------------------------------------------------------------------------
// evaluateOpenapiRatchet — the three contract cases from the plan
// ---------------------------------------------------------------------------

View File

@@ -0,0 +1,72 @@
/**
* Claude Opus 4.7+/Fable 5 sampling-param strip + adaptive-only flag.
*
* Anthropic's Opus 4.7+ generation rejects non-default `temperature`/`top_p`/`top_k` with a
* 400 (sampling is fixed; reasoning is steered by output_config.effort). These tests pin both
* the registry `unsupportedParams` that drive the strip at the chatCore dispatch point and
* the `isAdaptiveThinkingOnly` model flag — with regression guards that pre-4.7 models keep
* accepting sampling params and manual thinking.
*/
import test from "node:test";
import assert from "node:assert/strict";
import { getUnsupportedParams } from "../../open-sse/config/providerRegistry.ts";
import { isAdaptiveThinkingOnly } from "../../src/shared/constants/modelSpecs.ts";
const SAMPLING = ["temperature", "top_p", "top_k"];
test("claude registry strips temperature/top_p/top_k for Opus 4.7+/Fable 5", () => {
for (const model of ["claude-opus-4-8", "claude-opus-4-7", "claude-fable-5"]) {
const unsupported = getUnsupportedParams("claude", model);
for (const param of SAMPLING) {
assert.ok(
unsupported.includes(param),
`${model} must list ${param} as unsupported (400 on Anthropic otherwise)`
);
}
}
});
test("anthropic registry (dotted ids) strips sampling params for Opus 4.7", () => {
const unsupported = getUnsupportedParams("anthropic", "claude-opus-4.7");
for (const param of SAMPLING) {
assert.ok(unsupported.includes(param), `claude-opus-4.7 must list ${param} as unsupported`);
}
});
test("pre-4.7 Claude models still accept sampling params (regression guard)", () => {
for (const [provider, model] of [
["claude", "claude-opus-4-6"],
["claude", "claude-opus-4-5-20251101"],
["claude", "claude-sonnet-4-5-20250929"],
["claude", "claude-haiku-4-5-20251001"],
["anthropic", "claude-opus-4.6"],
] as const) {
const unsupported = getUnsupportedParams(provider, model);
for (const param of SAMPLING) {
assert.ok(
!unsupported.includes(param),
`${provider}/${model} must NOT strip ${param} — it still accepts sampling`
);
}
}
});
test("isAdaptiveThinkingOnly is true only for Opus 4.7+/Fable 5", () => {
for (const model of ["claude-opus-4-8", "claude-opus-4-7", "claude-fable-5"]) {
assert.equal(isAdaptiveThinkingOnly(model), true, `${model} is adaptive-only`);
}
for (const model of [
"claude-opus-4-6",
"claude-opus-4-5-20251101",
"claude-sonnet-4-6",
"claude-haiku-4-5-20251001",
]) {
assert.equal(isAdaptiveThinkingOnly(model), false, `${model} still supports manual thinking`);
}
assert.equal(isAdaptiveThinkingOnly(null), false);
assert.equal(isAdaptiveThinkingOnly(""), false);
});
test("isAdaptiveThinkingOnly resolves Bedrock/dated aliases", () => {
assert.equal(isAdaptiveThinkingOnly("anthropic.claude-opus-4-8"), true);
});

View File

@@ -0,0 +1,108 @@
/**
* Claude adaptive-thinking normalization — `normalizeClaudeAdaptiveThinking`.
*
* Claude Opus 4.7+/Fable 5 removed manual extended thinking: `thinking.type:"enabled"` and
* any `thinking.budget_tokens` return HTTP 400 (Anthropic migration guide, 2026-05-19).
* These tests pin the final guard that collapses any manual thinking that reached the
* dispatch point to `{type:"adaptive"}`, while leaving non-adaptive-only models and
* already-adaptive bodies untouched.
*/
import test from "node:test";
import assert from "node:assert/strict";
import { normalizeClaudeAdaptiveThinking } from "../../open-sse/services/claudeAdaptiveThinking.ts";
test("manual thinking:{type:'enabled', budget_tokens} → adaptive, budget dropped (Opus 4.8)", () => {
const body = {
model: "claude-opus-4-8",
messages: [],
thinking: { type: "enabled", budget_tokens: 131072 },
};
const result = normalizeClaudeAdaptiveThinking(body, "claude-opus-4-8");
assert.deepEqual(result.thinking, { type: "adaptive" });
});
test("Claude-shaped thinking:{type:'enabled', max_tokens} → adaptive, max_tokens dropped", () => {
const body = {
model: "claude-opus-4-7",
messages: [],
thinking: { type: "enabled", budget_tokens: 4096, max_tokens: 8000 },
};
const result = normalizeClaudeAdaptiveThinking(body, "claude-opus-4-7");
assert.deepEqual(result.thinking, { type: "adaptive" });
});
test("type:'enabled' with no budget still flips to adaptive (manual mode is gone)", () => {
const body = { model: "claude-fable-5", messages: [], thinking: { type: "enabled" } };
const result = normalizeClaudeAdaptiveThinking(body, "claude-fable-5");
assert.deepEqual(result.thinking, { type: "adaptive" });
});
test("thinking:{type:'adaptive'} is returned UNTOUCHED (same reference)", () => {
const body = { model: "claude-opus-4-8", messages: [], thinking: { type: "adaptive" } };
const result = normalizeClaudeAdaptiveThinking(body, "claude-opus-4-8");
assert.equal(result, body, "already-adaptive body must not be reallocated");
});
test("adaptive thinking carrying a stray budget_tokens has it stripped", () => {
const body = {
model: "claude-opus-4-8",
messages: [],
thinking: { type: "adaptive", budget_tokens: 5 },
};
const result = normalizeClaudeAdaptiveThinking(body, "claude-opus-4-8");
assert.deepEqual(result.thinking, { type: "adaptive" });
});
test("thinking:{type:'disabled'} is left untouched (handled by normalizeThinkingForModel)", () => {
const body = { model: "claude-opus-4-8", messages: [], thinking: { type: "disabled" } };
const result = normalizeClaudeAdaptiveThinking(body, "claude-opus-4-8");
assert.equal(result, body, "disabled is a separate concern; do not touch it here");
});
test("NON-adaptive-only model keeps its manual budget (regression guard for Opus 4.6)", () => {
const body = {
model: "claude-opus-4-6",
messages: [],
thinking: { type: "enabled", budget_tokens: 96000 },
};
const result = normalizeClaudeAdaptiveThinking(body, "claude-opus-4-6");
assert.equal(result, body, "Opus 4.6 still supports manual extended thinking");
assert.deepEqual(result.thinking, { type: "enabled", budget_tokens: 96000 });
});
test("body without a thinking object is returned UNTOUCHED (same reference)", () => {
const body = { model: "claude-opus-4-8", messages: [{ role: "user", content: "hi" }] };
const result = normalizeClaudeAdaptiveThinking(body, "claude-opus-4-8");
assert.equal(result, body);
});
test("non-object body / empty model are returned unchanged", () => {
const body = null as unknown as Record<string, unknown>;
assert.equal(normalizeClaudeAdaptiveThinking(body, "claude-opus-4-8"), body);
const ok = { model: "claude-opus-4-8", thinking: { type: "enabled" } };
assert.equal(normalizeClaudeAdaptiveThinking(ok, ""), ok, "empty model → no-op");
});
test("Bedrock/dated alias still resolves the adaptive-only spec", () => {
const body = { thinking: { type: "enabled", budget_tokens: 1000 } };
// BEDROCK_CLAUDE_ALIASES generates `anthropic.claude-opus-4-8` etc.; getModelSpec resolves it.
const result = normalizeClaudeAdaptiveThinking(body, "anthropic.claude-opus-4-8");
assert.deepEqual(result.thinking, { type: "adaptive" });
});
test("unrelated fields are preserved when collapsing thinking", () => {
const body = {
model: "claude-opus-4-8",
messages: [{ role: "user", content: "hi" }],
output_config: { effort: "high" },
thinking: { type: "enabled", budget_tokens: 32000 },
};
const result = normalizeClaudeAdaptiveThinking(body, "claude-opus-4-8") as Record<
string,
unknown
>;
assert.equal(result.model, "claude-opus-4-8");
assert.deepEqual(result.messages, [{ role: "user", content: "hi" }]);
assert.deepEqual(result.output_config, { effort: "high" });
assert.deepEqual(result.thinking, { type: "adaptive" });
});

View File

@@ -0,0 +1,35 @@
import test from "node:test";
import assert from "node:assert/strict";
import { normalizeBaseUrl, hostLabel } from "../../bin/cli/commands/connect.mjs";
import { profileNameFromModel } from "../../bin/cli/commands/configure.mjs";
test("normalizeBaseUrl: bare host gets http:// and the default port", () => {
assert.equal(normalizeBaseUrl("192.168.0.15", "20128"), "http://192.168.0.15:20128");
});
test("normalizeBaseUrl: host with explicit port keeps it", () => {
assert.equal(normalizeBaseUrl("192.168.0.15:9000", "20128"), "http://192.168.0.15:9000");
});
test("normalizeBaseUrl: full https URL is preserved as origin", () => {
assert.equal(normalizeBaseUrl("https://omni.example.com", "20128"), "https://omni.example.com");
assert.equal(normalizeBaseUrl("http://host:1234/path", "20128"), "http://host:1234");
});
test("normalizeBaseUrl: empty input returns empty string", () => {
assert.equal(normalizeBaseUrl("", "20128"), "");
});
test("hostLabel strips scheme and port", () => {
assert.equal(hostLabel("https://omni.example.com:20128"), "omni.example.com");
assert.equal(hostLabel("192.168.0.15:20128"), "192.168.0.15");
assert.equal(hostLabel("http://10.0.0.1"), "10.0.0.1");
});
test("profileNameFromModel strips the provider prefix and non-alphanumerics", () => {
assert.equal(profileNameFromModel("glm/glm-5.2"), "glm52");
assert.equal(profileNameFromModel("kmc/kimi-k2.7"), "kimik27");
assert.equal(profileNameFromModel("ollamacloud/gpt-oss:20b"), "gptoss20b");
assert.equal(profileNameFromModel("cx/gpt-5.5"), "gpt55");
assert.equal(profileNameFromModel("bare-model"), "baremodel");
});

View File

@@ -0,0 +1,178 @@
import test from "node:test";
import assert from "node:assert/strict";
import { mkdtempSync, rmSync, writeFileSync, mkdirSync } from "node:fs";
import { join } from "node:path";
import { tmpdir } from "node:os";
// Remote-mode core: the CLI must resolve BOTH baseUrl and auth from the active
// context (canonical `contexts`/`currentContext` schema, with legacy
// `profiles`/`activeProfile` fallback). Before this work, getBaseUrl read only
// the legacy `profiles` schema and buildHeaders never read the context's
// credential at all — so `omniroute contexts use <remote>` silently failed to
// route auth to the remote server.
let tmpDir: string;
let origDataDir: string | undefined;
let origBaseUrl: string | undefined;
let origApiKey: string | undefined;
let origContext: string | undefined;
function writeConfig(cfg: unknown): void {
mkdirSync(tmpDir, { recursive: true });
writeFileSync(join(tmpDir, "config.json"), JSON.stringify(cfg, null, 2));
}
test.before(() => {
tmpDir = mkdtempSync(join(tmpdir(), "omniroute-remote-test-"));
origDataDir = process.env.DATA_DIR;
origBaseUrl = process.env.OMNIROUTE_BASE_URL;
origApiKey = process.env.OMNIROUTE_API_KEY;
origContext = process.env.OMNIROUTE_CONTEXT;
process.env.DATA_DIR = tmpDir;
delete process.env.OMNIROUTE_BASE_URL;
delete process.env.OMNIROUTE_API_KEY;
delete process.env.OMNIROUTE_CONTEXT;
});
test.after(() => {
if (origDataDir === undefined) delete process.env.DATA_DIR;
else process.env.DATA_DIR = origDataDir;
if (origBaseUrl === undefined) delete process.env.OMNIROUTE_BASE_URL;
else process.env.OMNIROUTE_BASE_URL = origBaseUrl;
if (origApiKey === undefined) delete process.env.OMNIROUTE_API_KEY;
else process.env.OMNIROUTE_API_KEY = origApiKey;
if (origContext === undefined) delete process.env.OMNIROUTE_CONTEXT;
else process.env.OMNIROUTE_CONTEXT = origContext;
try {
rmSync(tmpDir, { recursive: true, force: true });
} catch {}
});
// ── getBaseUrl ────────────────────────────────────────────────────────────────
test("getBaseUrl reads baseUrl from the active context (canonical schema)", async () => {
writeConfig({
version: 1,
currentContext: "vps",
contexts: {
default: { baseUrl: "http://localhost:20128", apiKey: null },
vps: { baseUrl: "https://vps.example.com:20128", accessToken: "oma_live_x", scope: "write" },
},
});
const { getBaseUrl } = await import("../../bin/cli/api.mjs");
assert.equal(getBaseUrl(), "https://vps.example.com:20128");
});
test("getBaseUrl honors the --context override", async () => {
writeConfig({
version: 1,
currentContext: "default",
contexts: {
default: { baseUrl: "http://localhost:20128", apiKey: null },
staging: { baseUrl: "http://staging:20128", apiKey: null },
},
});
const { getBaseUrl } = await import("../../bin/cli/api.mjs");
assert.equal(getBaseUrl({ context: "staging" }), "http://staging:20128");
});
test("getBaseUrl is backward-compatible with the legacy profiles schema", async () => {
writeConfig({
version: 1,
activeProfile: "old",
profiles: { old: { baseUrl: "http://legacy:20128" } },
});
const { getBaseUrl } = await import("../../bin/cli/api.mjs");
assert.equal(getBaseUrl(), "http://legacy:20128");
});
test("getBaseUrl: opts.baseUrl wins over the active context", async () => {
writeConfig({
version: 1,
currentContext: "vps",
contexts: { vps: { baseUrl: "https://vps.example.com" } },
});
const { getBaseUrl } = await import("../../bin/cli/api.mjs");
assert.equal(getBaseUrl({ baseUrl: "http://override:1234" }), "http://override:1234");
});
// ── buildHeaders (auth resolution) ─────────────────────────────────────────────
test("buildHeaders injects Bearer from the active context accessToken", async () => {
writeConfig({
version: 1,
currentContext: "vps",
contexts: { vps: { baseUrl: "https://vps.example.com", accessToken: "oma_live_secret" } },
});
const { buildHeaders } = await import("../../bin/cli/api.mjs");
const headers = await buildHeaders({ cliToken: "" });
assert.equal(headers.get("authorization"), "Bearer oma_live_secret");
});
test("buildHeaders prefers accessToken over apiKey in the same context", async () => {
writeConfig({
version: 1,
currentContext: "vps",
contexts: {
vps: { baseUrl: "https://vps.example.com", accessToken: "oma_token", apiKey: "sk-legacy" },
},
});
const { buildHeaders } = await import("../../bin/cli/api.mjs");
const headers = await buildHeaders({ cliToken: "" });
assert.equal(headers.get("authorization"), "Bearer oma_token");
});
test("buildHeaders falls back to the context apiKey when no accessToken", async () => {
writeConfig({
version: 1,
currentContext: "vps",
contexts: { vps: { baseUrl: "https://vps.example.com", apiKey: "sk-ctx" } },
});
const { buildHeaders } = await import("../../bin/cli/api.mjs");
const headers = await buildHeaders({ cliToken: "" });
assert.equal(headers.get("authorization"), "Bearer sk-ctx");
});
test("buildHeaders: explicit opts.apiKey wins over the context credential", async () => {
writeConfig({
version: 1,
currentContext: "vps",
contexts: { vps: { baseUrl: "https://vps.example.com", accessToken: "oma_token" } },
});
const { buildHeaders } = await import("../../bin/cli/api.mjs");
const headers = await buildHeaders({ cliToken: "", apiKey: "sk-explicit" });
assert.equal(headers.get("authorization"), "Bearer sk-explicit");
});
// ── context current command ─────────────────────────────────────────────────────
test("commands/contexts.mjs registers a `current` subcommand", async () => {
const { registerContexts } = await import("../../bin/cli/commands/contexts.mjs");
// Minimal fake commander program to capture subcommand registration.
const sub: string[] = [];
const fakeCtx: any = {
command(name: string) {
sub.push(name.split(" ")[0]);
return this;
},
description() {
return this;
},
requiredOption() {
return this;
},
option() {
return this;
},
action() {
return this;
},
};
const fakeProgram: any = {
command() {
return fakeCtx;
},
};
registerContexts(fakeProgram);
assert.ok(sub.includes("current"), `expected a 'current' subcommand, got: ${sub.join(", ")}`);
});

View File

@@ -0,0 +1,149 @@
/**
* #4227 — Cursor Cloud Agent (REST adapter).
*
* Validates the adapter mapping between Cursor's Background/Cloud Agents REST API and
* OmniRoute's CloudAgentBase contract (status mapping, request shape, result extraction)
* with a mocked fetch. NOTE: this proves the adapter's internal mapping, NOT the live
* Cursor API shapes — those need a live validation run with a real Cursor API key before
* merge (Rule #18, external-API integration; see the PR description).
*/
import test from "node:test";
import assert from "node:assert/strict";
const cursorMod = await import("../../src/lib/cloudAgent/agents/cursor.ts");
const registry = await import("../../src/lib/cloudAgent/registry.ts");
const CREDS = { apiKey: "key_test_123" };
const SOURCE = { repoName: "org/repo", repoUrl: "https://github.com/org/repo", branch: "main" };
const OPTIONS = { autoCreatePr: true };
function mockFetch(handler: (url: string, init?: RequestInit) => Response | Promise<Response>) {
const original = globalThis.fetch;
// @ts-expect-error test shim
globalThis.fetch = async (url: string | URL | Request, init?: RequestInit) =>
handler(String(url), init);
return () => {
globalThis.fetch = original;
};
}
test("#4227 registry exposes cursor-cloud as a cloud-agent provider", () => {
assert.equal(registry.isCloudAgentProvider("cursor-cloud"), true);
const agent = registry.getAgent("cursor-cloud");
assert.ok(agent, "getAgent('cursor-cloud') returns an instance");
assert.equal(agent?.providerId, "cursor-cloud");
assert.ok(registry.getAvailableAgents().includes("cursor-cloud"));
});
test("#4227 createTask posts the prompt+repo and maps CREATING → queued", async () => {
const agent = new cursorMod.CursorCloudAgent();
let captured: { url: string; body: any } | null = null;
const restore = mockFetch((url, init) => {
captured = { url, body: init?.body ? JSON.parse(String(init.body)) : null };
return Response.json({ id: "bc-abc123", status: "CREATING", name: "agent-1" });
});
try {
const task = await agent.createTask({ prompt: "fix the bug", source: SOURCE, options: OPTIONS }, CREDS);
assert.equal(task.providerId, "cursor-cloud");
assert.equal(task.externalId, "bc-abc123");
assert.equal(task.status, "queued");
assert.equal(task.prompt, "fix the bug");
// request shape
assert.ok(captured, "fetch was called");
assert.match(captured!.url, /\/agents$/);
assert.equal(captured!.body.prompt.text, "fix the bug");
assert.equal(captured!.body.source.repository, "https://github.com/org/repo");
assert.equal(captured!.body.source.ref, "main");
assert.equal(captured!.body.autoCreatePr, true);
} finally {
restore();
}
});
test("#4227 createTask surfaces an upstream error instead of swallowing it", async () => {
const agent = new cursorMod.CursorCloudAgent();
const restore = mockFetch(() => new Response("nope", { status: 401 }));
try {
await assert.rejects(
agent.createTask({ prompt: "x", source: SOURCE, options: {} }, CREDS),
/Cursor create agent failed: 401/
);
} finally {
restore();
}
});
test("#4227 getStatus maps FINISHED → completed and extracts the PR url + conversation", async () => {
const agent = new cursorMod.CursorCloudAgent();
const restore = mockFetch(() =>
Response.json({
id: "bc-abc123",
status: "FINISHED",
target: { prUrl: "https://github.com/org/repo/pull/7", branchName: "cursor/fix" },
summary: "Fixed it",
conversation: [{ type: "assistant_message", text: "done", createdAt: "2026-06-19T00:00:00Z" }],
})
);
try {
const result = await agent.getStatus("bc-abc123", CREDS);
assert.equal(result.status, "completed");
assert.equal(result.result?.prUrl, "https://github.com/org/repo/pull/7");
assert.equal(result.result?.summary, "Fixed it");
assert.equal(result.activities.length, 1);
assert.equal(result.activities[0].content, "done");
} finally {
restore();
}
});
test("#4227 getStatus maps Cursor enums (RUNNING→running, ERROR→failed)", async () => {
const agent = new cursorMod.CursorCloudAgent();
let restore = mockFetch(() => Response.json({ status: "RUNNING" }));
try {
assert.equal((await agent.getStatus("id", CREDS)).status, "running");
} finally {
restore();
}
restore = mockFetch(() => Response.json({ status: "ERROR", error: "boom" }));
try {
const r = await agent.getStatus("id", CREDS);
assert.equal(r.status, "failed");
assert.equal(r.error, "boom");
} finally {
restore();
}
});
test("#4227 sendMessage posts a followup; approvePlan is unsupported", async () => {
const agent = new cursorMod.CursorCloudAgent();
let captured: { url: string; body: any } | null = null;
const restore = mockFetch((url, init) => {
captured = { url, body: init?.body ? JSON.parse(String(init.body)) : null };
return Response.json({ ok: true });
});
try {
const activity = await agent.sendMessage("bc-1", "also add tests", CREDS);
assert.equal(activity.type, "message");
assert.equal(activity.content, "also add tests");
assert.match(captured!.url, /\/agents\/bc-1\/followup$/);
assert.equal(captured!.body.prompt.text, "also add tests");
} finally {
restore();
}
await assert.rejects(agent.approvePlan("bc-1", CREDS), /do not support plan approval/);
});
test("#4227 listSources normalizes the repositories list", async () => {
const agent = new cursorMod.CursorCloudAgent();
const restore = mockFetch(() =>
Response.json({ repositories: [{ url: "https://github.com/org/repo", name: "org/repo" }] })
);
try {
const sources = await agent.listSources(CREDS);
assert.equal(sources.length, 1);
assert.equal(sources[0].url, "https://github.com/org/repo");
assert.equal(sources[0].name, "org/repo");
} finally {
restore();
}
});

View File

@@ -3,9 +3,9 @@ import { describe, test } from "node:test";
import { getAvailableAgents } from "../../src/lib/cloudAgent/registry.ts";
describe("cloud-agent health API — getAvailableAgents", () => {
test("returns exactly three agents", () => {
test("returns exactly four agents", () => {
const agents = getAvailableAgents();
assert.equal(agents.length, 3);
assert.equal(agents.length, 4);
});
test('includes "jules"', () => {
@@ -20,8 +20,12 @@ describe("cloud-agent health API — getAvailableAgents", () => {
assert.ok(getAvailableAgents().includes("codex-cloud"));
});
test('includes "cursor-cloud"', () => {
assert.ok(getAvailableAgents().includes("cursor-cloud"));
});
test("returns agents in expected order", () => {
assert.deepEqual(getAvailableAgents(), ["jules", "devin", "codex-cloud"]);
assert.deepEqual(getAvailableAgents(), ["jules", "devin", "codex-cloud", "cursor-cloud"]);
});
});
@@ -64,11 +68,13 @@ describe("cloud-agent health API — health check logic", () => {
jules: "Jules",
devin: "Devin",
"codex-cloud": "Codex Cloud",
"cursor-cloud": "Cursor Cloud",
};
assert.equal(PROVIDER_NAMES["jules"], "Jules");
assert.equal(PROVIDER_NAMES["devin"], "Devin");
assert.equal(PROVIDER_NAMES["codex-cloud"], "Codex Cloud");
assert.equal(PROVIDER_NAMES["cursor-cloud"], "Cursor Cloud");
assert.equal(PROVIDER_NAMES["nonexistent"], undefined);
});
});

View File

@@ -131,7 +131,8 @@ test("getAvailableAgents returns all registered agents", () => {
assert.strictEqual(agents.includes("jules"), true);
assert.strictEqual(agents.includes("devin"), true);
assert.strictEqual(agents.includes("codex-cloud"), true);
assert.strictEqual(agents.length, 3);
assert.strictEqual(agents.includes("cursor-cloud"), true);
assert.strictEqual(agents.length, 4);
});
test("getAgent returns correct agent for valid providerId", () => {

View File

@@ -4,6 +4,8 @@ import fs from "node:fs";
import os from "node:os";
import path from "node:path";
import { OMNIROUTE_RESPONSE_HEADERS } from "../../src/shared/constants/headers.ts";
const TEST_DATA_DIR = fs.mkdtempSync(path.join(os.tmpdir(), "omniroute-codex-stream-false-"));
process.env.DATA_DIR = TEST_DATA_DIR;
@@ -365,3 +367,49 @@ test("handleComboChat validates non-stream quality using the original client str
)
);
});
test("non-stream chat success carries cost-telemetry meta headers (cost/version/tokens)", async () => {
// Regression guard: the single non-stream success return in chatCore.ts routes
// through attachOmniRouteMetaHeaders, which must always emit the cost-telemetry
// headers. A usage-bearing JSON upstream body proves real usage flowed through.
const { result } = await invokeChatCore({
body: {
model: "gpt-4o-mini",
stream: false,
messages: [{ role: "user", content: "Qual a capital do Brasil?" }],
},
provider: "openai",
model: "gpt-4o-mini",
responseFactory: () =>
jsonResponse({
id: "chatcmpl-cost-header",
object: "chat.completion",
model: "gpt-4o-mini",
choices: [
{
index: 0,
message: { role: "assistant", content: "Brasilia" },
finish_reason: "stop",
},
],
usage: { prompt_tokens: 10, completion_tokens: 5, total_tokens: 15 },
}),
});
assert.equal(result.success, true);
const headers = result.response.headers;
const cost = headers.get(OMNIROUTE_RESPONSE_HEADERS.responseCost);
assert.equal(typeof cost, "string");
// 10-decimal cost format; 0.0000000000 is valid when no pricing is available.
assert.match(String(cost), /^\d+\.\d{10}$/);
const version = headers.get(OMNIROUTE_RESPONSE_HEADERS.version);
assert.equal(typeof version, "string");
assert.ok(String(version).length > 0);
// Real usage from the upstream body must surface as token-count headers.
assert.equal(headers.get(OMNIROUTE_RESPONSE_HEADERS.tokensIn), "10");
assert.equal(headers.get(OMNIROUTE_RESPONSE_HEADERS.tokensOut), "5");
});

View File

@@ -0,0 +1,57 @@
/**
* Codex verbosity normalization — `normalizeCodexVerbosity`.
*
* GPT-5 verbosity is `verbosity` on Chat Completions and `text.verbosity` on the Responses
* API. The CodexExecutor allowlist drops `text`, so translated requests lose the hint. These
* tests pin the fold into a single validated `text:{verbosity}` (or its removal when invalid),
* which — paired with `text` added to the allowlist — lets verbosity reach the Codex backend.
*/
import test from "node:test";
import assert from "node:assert/strict";
import { normalizeCodexVerbosity } from "../../open-sse/services/codexVerbosity.ts";
test("chat-style top-level verbosity is lifted to text.verbosity and dropped", () => {
const body: Record<string, unknown> = { model: "gpt-5.5", verbosity: "low", input: [] };
normalizeCodexVerbosity(body);
assert.deepEqual(body.text, { verbosity: "low" });
assert.equal(body.verbosity, undefined);
});
test("existing Responses text.verbosity is preserved", () => {
const body: Record<string, unknown> = { text: { verbosity: "high" }, input: [] };
normalizeCodexVerbosity(body);
assert.deepEqual(body.text, { verbosity: "high" });
});
test("chat-style verbosity takes precedence when both shapes are present", () => {
const body: Record<string, unknown> = { verbosity: "medium", text: { verbosity: "high" } };
normalizeCodexVerbosity(body);
assert.deepEqual(body.text, { verbosity: "medium" });
assert.equal(body.verbosity, undefined);
});
test("invalid verbosity is dropped and text removed", () => {
const body: Record<string, unknown> = { verbosity: "ultra", input: [] };
normalizeCodexVerbosity(body);
assert.equal(body.text, undefined);
assert.equal(body.verbosity, undefined);
});
test("no verbosity + stray non-verbosity text → text removed (status quo)", () => {
const body: Record<string, unknown> = { text: { format: { type: "json" } }, input: [] };
normalizeCodexVerbosity(body);
assert.equal(body.text, undefined);
});
test("verbosity is normalized case-insensitively", () => {
const body: Record<string, unknown> = { verbosity: "HIGH" };
normalizeCodexVerbosity(body);
assert.deepEqual(body.text, { verbosity: "high" });
});
test("body without any verbosity is left without a text field", () => {
const body: Record<string, unknown> = { model: "gpt-5.5", input: [] };
normalizeCodexVerbosity(body);
assert.equal(body.text, undefined);
assert.equal(body.model, "gpt-5.5");
});

View File

@@ -203,3 +203,41 @@ test("pre-screen: backward compatible with all targets available", async () => {
assert.equal(calls.length, 1);
assert.equal(calls[0], "p1/m1");
});
test("priority combo: quota 429 on passthrough provider does not skip another model on same provider", async () => {
const calls: string[] = [];
const combo = await combosDb.createCombo({
name: "passthrough-quota-scope",
strategy: "priority",
models: ["antigravity/claude-opus-4-6-thinking", "antigravity/gemini-3-flash-agent"],
});
const response = await handleComboChat({
body: { ...reqBody, model: combo.name },
combo,
allCombos: [combo],
isModelAvailable: async () => true,
relayOptions: undefined,
signal: undefined,
settings: {},
log: makeLog(),
handleSingleModel: async (_body: unknown, modelStr: string) => {
calls.push(modelStr);
if (modelStr.includes("claude-opus")) {
return Response.json(
{ error: { message: "quota exhausted for claude-opus-4-6-thinking" } },
{ status: 429 }
);
}
return okResponse(modelStr);
},
});
assert.equal(response.status, 200);
assert.equal(calls.at(-1), "antigravity/gemini-3-flash-agent");
assert.ok(
calls.includes("antigravity/claude-opus-4-6-thinking"),
"first passthrough model should be attempted before fallback"
);
});

View File

@@ -0,0 +1,76 @@
import { describe, it } from "node:test";
import assert from "node:assert/strict";
import { applyCompression } from "../../../open-sse/services/compression/strategySelector.ts";
import { registerCompressionEngine } from "../../../open-sse/services/compression/index.ts";
import type { CompressionEngine } from "../../../open-sse/services/compression/engines/types.ts";
import type { CompressionConfig } from "../../../open-sse/services/compression/types.ts";
// The combo proactive-fallback path calls applyCompression(stacked); a throwing engine there
// propagates and is swallowed as a "Speculative task error", silently dropping the target. The
// fix lets that caller opt into the TV1 bail-out (enabled, minGainPercent 0 = skip-on-throw
// without changing the min-gain advance behavior). This documents the opt-in contract.
const THROWING_ENGINE: CompressionEngine = {
id: "applycompress-bailout-throw",
name: "Throwing Test Engine",
description: "test fixture",
icon: "",
targets: ["messages"],
stackable: true,
stackPriority: 999,
metadata: {
id: "applycompress-bailout-throw",
name: "Throwing Test Engine",
description: "test",
inputScope: "messages",
targetLatencyMs: 1,
supportsPreview: false,
stable: false,
},
apply() {
throw new Error("boom from fallback engine");
},
compress() {
throw new Error("boom from fallback engine");
},
getConfigSchema() {
return [];
},
validateConfig() {
return { valid: true, errors: [] };
},
};
function stackedConfig(): CompressionConfig {
return {
stackedPipeline: [{ engine: "applycompress-bailout-throw" }],
} as unknown as CompressionConfig;
}
describe("applyCompression — combo fallback bail-out opt-in", () => {
it("opting into bail-out skips a throwing engine instead of propagating (no silent drop)", () => {
registerCompressionEngine(THROWING_ENGINE);
const body = { messages: [{ role: "user", content: "hello world" }] };
let result: ReturnType<typeof applyCompression> | undefined;
assert.doesNotThrow(() => {
result = applyCompression(body, "stacked", {
config: stackedConfig(),
bailout: { enabled: true, minGainPercent: 0 },
});
});
assert.ok(result, "returns a result instead of throwing");
assert.equal(result!.compressed, false, "a crashing engine compresses nothing");
});
it("without bail-out, a throwing engine still propagates (TV1 default unchanged)", () => {
registerCompressionEngine(THROWING_ENGINE);
const body = { messages: [{ role: "user", content: "hello world" }] };
assert.throws(
() => applyCompression(body, "stacked", { config: stackedConfig() }),
/boom from fallback engine/,
"the default (opt-out) path is unchanged — bail-out is strictly opt-in"
);
});
});

View File

@@ -11,7 +11,6 @@ import assert from "node:assert/strict";
import {
ccrEngine,
reconstructCcr,
retrieveBlock,
recordRetrieval,
shouldSkipCompression,
@@ -109,30 +108,6 @@ describe("ccr engine", () => {
assert.equal(retrieved, LARGE_TEXT, "retrieved block must equal the original verbatim text");
});
it("reconstructs the body to deep-equal the original (round-trip)", () => {
resetCcrStore();
const originalMessages = [
{ role: "user", content: LARGE_TEXT },
{ role: "assistant", content: "I understand your point." },
];
const body = makeBody(originalMessages);
const result = ccrEngine.apply(body as Record<string, unknown>);
assert.equal(result.compressed, true, "should be compressed");
const reconstructed = reconstructCcr(result.body);
const reconstructedMessages = reconstructed.messages as Array<{
role: string;
content: string;
}>;
assert.deepEqual(
reconstructedMessages,
originalMessages,
"reconstructed messages must deep-equal original messages"
);
});
it("does NOT compress small blocks (below minChars threshold)", () => {
resetCcrStore();
const body = makeBody([{ role: "user", content: SMALL_TEXT }]);
@@ -205,14 +180,6 @@ describe("ccr engine", () => {
assert.equal(result, null, "unknown hash must return null");
});
it("reconstructCcr is idempotent when no markers are present", () => {
const body = makeBody([{ role: "user", content: SMALL_TEXT }]);
const reconstructed = reconstructCcr(body as Record<string, unknown>);
assert.deepEqual(reconstructed.messages as Array<{ role: string; content: string }>, [
{ role: "user", content: SMALL_TEXT },
]);
});
it("handles multipart content (type:text parts)", () => {
resetCcrStore();
const body = {

View File

@@ -0,0 +1,49 @@
import { describe, it } from "node:test";
import assert from "node:assert/strict";
import {
BENCHMARK_CORPUS,
DEFAULT_BENCHMARK_ENGINES,
benchmarkEngines,
compareReports,
formatBenchmarkTable,
} from "../../../open-sse/services/compression/harness/benchmark.ts";
// F2.4: the benchmark harness existed but nothing invoked it and there was no report output.
// These cover the CLI's core: a markdown formatter + a default engine set that resolves and
// runs the corpus end-to-end, so `npm run bench:compression` produces a real A/B table.
describe("compression benchmark CLI core", () => {
it("formatBenchmarkTable renders a markdown table with the best engine bolded", () => {
const md = formatBenchmarkTable([
{ engine: "rtk", meanSavingsPercent: 42.5, meanRetention: 0.9, totalCompressedTokens: 100 },
{ engine: "lite", meanSavingsPercent: 10, meanRetention: 0.99, totalCompressedTokens: 200 },
]);
assert.match(md, /\| Engine \|/, "has a header row");
assert.match(md, /\*\*rtk\*\*/, "best (first) engine is bolded");
assert.match(md, /42\.5/, "renders the savings number");
assert.match(md, /\blite\b/, "renders the runner-up");
assert.ok(!md.includes("**lite**"), "only the best engine is bolded");
});
it("DEFAULT_BENCHMARK_ENGINES all resolve and run the corpus end-to-end", async () => {
assert.ok(DEFAULT_BENCHMARK_ENGINES.length > 0, "has a default engine set");
assert.ok(
!DEFAULT_BENCHMARK_ENGINES.includes("llmlingua"),
"excludes llmlingua (needs the ONNX model at runtime)"
);
const reports = await benchmarkEngines(BENCHMARK_CORPUS, DEFAULT_BENCHMARK_ENGINES);
const rows = compareReports(reports);
assert.equal(rows.length, DEFAULT_BENCHMARK_ENGINES.length);
for (const id of DEFAULT_BENCHMARK_ENGINES) {
assert.ok(
rows.some((r) => r.engine === id),
`${id} present in the comparison table`
);
}
// The formatted table is non-empty and lists every engine.
const md = formatBenchmarkTable(rows);
for (const id of DEFAULT_BENCHMARK_ENGINES) {
assert.ok(md.includes(id), `${id} appears in the markdown table`);
}
});
});

View File

@@ -0,0 +1,55 @@
import { describe, it } from "node:test";
import assert from "node:assert/strict";
import fs from "node:fs";
import path from "node:path";
import { fileURLToPath } from "node:url";
import {
BENCHMARK_CORPUS,
DEFAULT_BENCHMARK_ENGINES,
benchmarkEngines,
runBenchmarkGate,
} from "../../../open-sse/services/compression/harness/benchmark.ts";
import {
tokensPerTask,
type BudgetBaseline,
} from "../../../open-sse/services/compression/harness/budgetGate.ts";
const BASELINE_PATH = path.join(
path.dirname(fileURLToPath(import.meta.url)),
"../../../scripts/check/compression-budget-baseline.json"
);
describe("compression budget gate (F2.4 / N4 ratchet)", () => {
it("the committed baseline matches the current benchmark (not stale, no regression)", async () => {
const baselines = JSON.parse(fs.readFileSync(BASELINE_PATH, "utf8")) as Record<
string,
BudgetBaseline
>;
const reports = await benchmarkEngines(BENCHMARK_CORPUS, DEFAULT_BENCHMARK_ENGINES);
const failed = runBenchmarkGate(reports, baselines, 2).filter((r) => !r.gate.passed);
assert.equal(
failed.length,
0,
`tokens-per-task regressed vs the committed baseline: ${JSON.stringify(failed)}` +
`if intentional, run: npm run check:compression-budget -- --update`
);
});
it("flags a regression when tokens-per-task rises beyond tolerance", async () => {
// ultra is stateless/deterministic. Build a baseline tighter than reality → current regresses.
const reports = await benchmarkEngines(BENCHMARK_CORPUS, ["ultra"]);
const tight: Record<string, BudgetBaseline> = {
ultra: {
tasks: Object.fromEntries(
Object.entries(tokensPerTask(reports.ultra)).map(([task, n]) => [
task,
Math.max(1, Math.floor(n / 2)),
])
),
},
};
const failed = runBenchmarkGate(reports, tight, 2).filter((r) => !r.gate.passed);
assert.ok(failed.length > 0, "a halved baseline must be flagged as a regression");
});
});

View File

@@ -0,0 +1,28 @@
import { describe, it } from "node:test";
import assert from "node:assert/strict";
import {
registerBuiltinCompressionEngines,
clearCompressionEngineRegistry,
getCompressionEngine,
} from "../../../open-sse/services/compression/index.ts";
// F5.3: registerBuiltinCompressionEngines() guards on a module-level `registered` latch.
// clearCompressionEngineRegistry() empties the engine map but does NOT reset that latch, so
// a subsequent registerBuiltinCompressionEngines() no-ops and leaves the registry empty —
// any getCompressionEngine() then returns null. This file runs in its own process so the
// latch starts false (no cross-file interference).
describe("builtin compression engine registration after clear", () => {
it("re-registers builtin engines after the registry is cleared", () => {
registerBuiltinCompressionEngines();
assert.ok(getCompressionEngine("rtk"), "builtins registered initially");
clearCompressionEngineRegistry();
assert.equal(getCompressionEngine("rtk"), null, "registry emptied by clear");
// The `registered` latch must not block this re-registration.
registerBuiltinCompressionEngines();
assert.ok(getCompressionEngine("rtk"), "builtins must repopulate after a clear");
assert.ok(getCompressionEngine("session-dedup"), "all builtins restored, not just one");
});
});

View File

@@ -0,0 +1,135 @@
import { describe, it } from "node:test";
import assert from "node:assert/strict";
import {
stepEventsToRunModel,
appendInFlightStep,
clearInFlightOnComplete,
} from "../../../src/app/(dashboard)/dashboard/compression/studio/compressionFlowModel.ts";
import { applyStackedCompression } from "../../../open-sse/services/compression/strategySelector.ts";
import { registerCompressionEngine } from "../../../open-sse/services/compression/index.ts";
import type { CompressionEngine } from "../../../open-sse/services/compression/engines/types.ts";
import type { CompressionStepPayload } from "../../../src/lib/events/types.ts";
function step(over: Partial<CompressionStepPayload>): CompressionStepPayload {
return {
requestId: "r1",
comboId: null,
mode: "stacked",
stepIndex: 0,
totalSteps: 2,
engine: "e",
state: "done",
originalTokens: 1000,
compressedTokens: 800,
savingsPercent: 20,
timestamp: 1,
...over,
};
}
describe("stepEventsToRunModel", () => {
it("builds a run model from accumulated step events (run-level totals span first→last)", () => {
const model = stepEventsToRunModel([
step({ engine: "a", stepIndex: 0, originalTokens: 1000, compressedTokens: 900, savingsPercent: 10, timestamp: 1 }),
step({ engine: "b", stepIndex: 1, originalTokens: 900, compressedTokens: 700, savingsPercent: 22, timestamp: 2 }),
]);
assert.equal(model.requestId, "r1");
assert.equal(model.mode, "stacked");
assert.equal(model.originalTokens, 1000); // first step's input
assert.equal(model.compressedTokens, 700); // last step's output
assert.equal(model.savingsPercent, 30); // (1000-700)/1000
assert.equal(model.steps.length, 2);
assert.equal(model.steps[1].engine, "b");
assert.equal(model.timestamp, 2);
});
});
describe("in-flight step reducer", () => {
it("appends steps for the same requestId and starts fresh on a new requestId", () => {
let s = appendInFlightStep(null, step({ requestId: "r1", engine: "a" }));
assert.equal(s.requestId, "r1");
assert.equal(s.steps.length, 1);
s = appendInFlightStep(s, step({ requestId: "r1", engine: "b" }));
assert.equal(s.steps.length, 2);
// A new requestId replaces the in-flight run (latest wins).
s = appendInFlightStep(s, step({ requestId: "r2", engine: "x" }));
assert.equal(s.requestId, "r2");
assert.equal(s.steps.length, 1);
});
it("clears the in-flight run only when the completing requestId matches", () => {
const s = appendInFlightStep(null, step({ requestId: "r1" }));
assert.equal(clearInFlightOnComplete(s, "other"), s);
assert.equal(clearInFlightOnComplete(s, "r1"), null);
});
});
// ── Integration: applyStackedCompression emits a step per engine ───────────────
function fakeEngine(id: string, compressed: boolean, orig: number, comp: number): CompressionEngine {
return {
id,
name: id,
description: "",
icon: "",
targets: ["messages"],
stackable: true,
stackPriority: 1,
metadata: {
id,
name: id,
description: "",
inputScope: "messages",
targetLatencyMs: 1,
supportsPreview: false,
stable: false,
},
apply(body) {
return {
body,
compressed,
stats: {
originalTokens: orig,
compressedTokens: comp,
savingsPercent: orig > 0 ? Math.round(((orig - comp) / orig) * 100) : 0,
techniquesUsed: [],
mode: "stacked",
timestamp: 0,
durationMs: 2,
},
};
},
compress(body) {
return this.apply(body);
},
getConfigSchema() {
return [];
},
validateConfig() {
return { valid: true, errors: [] };
},
};
}
describe("applyStackedCompression — onEngineStep emission", () => {
it("fires onEngineStep once per engine with index/total/state", () => {
registerCompressionEngine(fakeEngine("step-e1", true, 1000, 900));
registerCompressionEngine(fakeEngine("step-e2", false, 900, 900));
const captured: Array<{ stepIndex: number; totalSteps: number; engine: string; state: string }> = [];
applyStackedCompression(
{ messages: [{ role: "user", content: "hello" }] },
[{ engine: "step-e1" }, { engine: "step-e2" }],
{ onEngineStep: (s) => captured.push(s) }
);
assert.equal(captured.length, 2, "one step per engine");
assert.equal(captured[0].engine, "step-e1");
assert.equal(captured[0].stepIndex, 0);
assert.equal(captured[0].totalSteps, 2);
assert.equal(captured[0].state, "done");
assert.equal(captured[1].engine, "step-e2");
assert.equal(captured[1].stepIndex, 1);
assert.equal(captured[1].state, "skipped");
});
});

View File

@@ -0,0 +1,36 @@
import { describe, it } from "node:test";
import assert from "node:assert/strict";
import {
readMcpToolProfileFromEnv,
reduceToolManifest,
} from "../../../open-sse/mcp-server/toolCardinality.ts";
// F4.3 wiring: the MCP server now consults an opt-in tool profile (MCP_TOOL_DENY / MCP_TOOL_ALLOW)
// and disables denied tools so they are not announced to the model (token savings). Default (no
// env) is a no-op — every tool stays registered.
describe("MCP tool profile from env (cardinality opt-in)", () => {
it("returns null when no deny/allow env is set (no-op)", () => {
assert.equal(readMcpToolProfileFromEnv({}), null);
assert.equal(readMcpToolProfileFromEnv({ MCP_TOOL_DENY: "", MCP_TOOL_ALLOW: " " }), null);
});
it("parses MCP_TOOL_DENY / MCP_TOOL_ALLOW into a profile (trimmed, empties dropped)", () => {
const p = readMcpToolProfileFromEnv({ MCP_TOOL_DENY: "a, b ,c", MCP_TOOL_ALLOW: "x ," });
assert.deepEqual(p?.denyTools, ["a", "b", "c"]);
assert.deepEqual(p?.allowTools, ["x"]);
});
it("the deny gate drops a denied tool and keeps others (single-entry manifest decision)", () => {
const profile = readMcpToolProfileFromEnv({ MCP_TOOL_DENY: "noisy_tool" });
assert.ok(profile);
assert.equal(reduceToolManifest([{ name: "noisy_tool", scopes: [] }], profile).length, 0);
assert.equal(reduceToolManifest([{ name: "useful_tool", scopes: [] }], profile).length, 1);
});
it("allow-list mode keeps only the listed tools", () => {
const profile = readMcpToolProfileFromEnv({ MCP_TOOL_ALLOW: "keep_me" });
assert.ok(profile);
assert.equal(reduceToolManifest([{ name: "keep_me", scopes: [] }], profile).length, 1);
assert.equal(reduceToolManifest([{ name: "other", scopes: [] }], profile).length, 0);
});
});

View File

@@ -0,0 +1,66 @@
import { describe, it } from "node:test";
import assert from "node:assert/strict";
import { ensureEngineBreakdown } from "../../../open-sse/services/compression/engineBreakdown.ts";
import type { CompressionStats } from "../../../open-sse/services/compression/types.ts";
function stats(over: Partial<CompressionStats>): CompressionStats {
return {
originalTokens: 1000,
compressedTokens: 700,
savingsPercent: 30,
techniquesUsed: [],
mode: "rtk",
timestamp: 0,
...over,
};
}
// Single-engine compression modes (rtk/lite/standard/aggressive/ultra) produce stats with an
// empty engineBreakdown — only the stacked pipeline fills it. The dashboard studio then renders
// an empty Input→Output pipeline (no engine node, inert replay) for the most common case.
// ensureEngineBreakdown synthesizes a 1-entry breakdown from the overall stats so the studio
// always shows at least one real engine node.
describe("ensureEngineBreakdown", () => {
it("returns the existing breakdown unchanged when present (stacked)", () => {
const bd = [
{
engine: "rtk",
originalTokens: 1000,
compressedTokens: 700,
savingsPercent: 30,
techniquesUsed: ["a"],
},
];
assert.deepEqual(ensureEngineBreakdown(stats({ engineBreakdown: bd })), bd);
});
it("synthesizes a 1-entry breakdown for single-engine modes (empty/undefined breakdown)", () => {
const out = ensureEngineBreakdown(
stats({
mode: "lite",
engine: "lite",
originalTokens: 2000,
compressedTokens: 1500,
savingsPercent: 25,
techniquesUsed: ["lite-strip"],
rulesApplied: ["r1"],
durationMs: 3,
})
);
assert.equal(out.length, 1);
assert.equal(out[0].engine, "lite");
assert.equal(out[0].originalTokens, 2000);
assert.equal(out[0].compressedTokens, 1500);
assert.equal(out[0].savingsPercent, 25);
assert.deepEqual(out[0].techniquesUsed, ["lite-strip"]);
assert.deepEqual(out[0].rulesApplied, ["r1"]);
assert.equal(out[0].durationMs, 3);
});
it("falls back to mode for the engine label when stats.engine is absent", () => {
const out = ensureEngineBreakdown(stats({ mode: "standard", engineBreakdown: [] }));
assert.equal(out.length, 1);
assert.equal(out[0].engine, "standard");
assert.deepEqual(out[0].techniquesUsed, []);
});
});

View File

@@ -0,0 +1,119 @@
/**
* Registry `enabled` toggle — the stacked loop must honor setEngineEnabled.
*
* `enabled` was a flag the stacked pipeline never consulted: getCompressionEngine
* returned the engine regardless, so flipping it via setEngineEnabled had no effect
* (the toggle "lied"). Both the sync and async stacked loops now skip a step whose
* engine is disabled.
*/
import { describe, it, before, after, beforeEach } from "node:test";
import assert from "node:assert/strict";
import {
applyStackedCompression,
applyStackedCompressionAsync,
} from "../../../open-sse/services/compression/index.ts";
import {
registerCompressionEngine,
unregisterCompressionEngine,
setEngineEnabled,
} from "../../../open-sse/services/compression/engines/registry.ts";
import type {
CompressionEngine,
CompressionEngineTarget,
} from "../../../open-sse/services/compression/engines/types.ts";
import type {
CompressionPipelineStep,
CompressionResult,
} from "../../../open-sse/services/compression/types.ts";
const ENGINE_ID = "enabled-toggle-engine";
/** Engine that tags user content and reports a real gain when it runs. */
function makeTaggingEngine(id: string): CompressionEngine {
return {
id,
name: id,
description: id,
icon: "x",
targets: ["messages"] as CompressionEngineTarget[],
stackable: true,
stackPriority: 0,
metadata: {
id,
name: id,
description: id,
inputScope: "messages",
targetLatencyMs: 1,
supportsPreview: false,
stable: true,
},
compress: (body) => ({ body, compressed: false, stats: null }),
getConfigSchema: () => [],
validateConfig: () => ({ valid: true, errors: [] }),
apply: (body) => {
const messages = (body.messages as Array<{ role: string; content: string }>) ?? [];
const next = messages.map((m) =>
m.role === "user" ? { ...m, content: m.content + "|tagged" } : m
);
return {
body: { ...body, messages: next },
compressed: true,
stats: {
originalTokens: 100,
compressedTokens: 70,
savingsPercent: 30,
techniquesUsed: [id],
mode: "stacked",
timestamp: 0,
durationMs: 0.1,
},
};
},
};
}
function pipeline(...ids: string[]): CompressionPipelineStep[] {
return ids.map((engine) => ({ engine })) as unknown as CompressionPipelineStep[];
}
function userContent(result: CompressionResult): string {
const messages = result.body.messages as Array<{ role: string; content: string }>;
return messages.find((m) => m.role === "user")!.content;
}
function freshBody() {
return { messages: [{ role: "user", content: "hi" }] };
}
describe("registry enabled toggle — stacked loop honors setEngineEnabled", () => {
before(() => registerCompressionEngine(makeTaggingEngine(ENGINE_ID)));
beforeEach(() => setEngineEnabled(ENGINE_ID, true)); // default-on before each case
after(() => unregisterCompressionEngine(ENGINE_ID));
it("applies the engine while enabled (sync)", () => {
const result = applyStackedCompression(freshBody(), pipeline(ENGINE_ID));
assert.equal(result.compressed, true);
assert.equal(userContent(result), "hi|tagged");
});
it("skips the engine once disabled (sync)", () => {
setEngineEnabled(ENGINE_ID, false);
const result = applyStackedCompression(freshBody(), pipeline(ENGINE_ID));
assert.equal(result.compressed, false);
assert.equal(userContent(result), "hi"); // unchanged — step skipped
});
it("applies the engine while enabled (async)", async () => {
const result = await applyStackedCompressionAsync(freshBody(), pipeline(ENGINE_ID));
assert.equal(result.compressed, true);
assert.equal(userContent(result), "hi|tagged");
});
it("skips the engine once disabled (async)", async () => {
setEngineEnabled(ENGINE_ID, false);
const result = await applyStackedCompressionAsync(freshBody(), pipeline(ENGINE_ID));
assert.equal(result.compressed, false);
assert.equal(userContent(result), "hi");
});
});

View File

@@ -0,0 +1,221 @@
/**
* GCF (Graph Compact Format) vs legacy omni-tabular benchmark.
*
* Compares compression savings, round-trip correctness, and coverage on
* realistic payloads including cases the legacy encoder cannot handle.
*/
import { describe, it, before } from "node:test";
import assert from "node:assert/strict";
let encodeTabular: (arr: Record<string, unknown>[]) => string;
let decodeTabular: (text: string) => Record<string, unknown>[];
let encodeTabularBlockLegacy: (arr: Record<string, unknown>[]) => string;
let detectHomogeneous: (arr: unknown[]) => string[] | null;
let reconstructHeadroom: (body: Record<string, unknown>) => Record<string, unknown>;
before(async () => {
const tabMod = await import("../../../open-sse/services/compression/engines/headroom/tabular.ts");
encodeTabular = tabMod.encodeTabular;
decodeTabular = tabMod.decodeTabular;
encodeTabularBlockLegacy = tabMod.encodeTabularBlockLegacy;
const scMod =
await import("../../../open-sse/services/compression/engines/headroom/smartcrusher.ts");
detectHomogeneous = scMod.detectHomogeneous;
const idxMod = await import("../../../open-sse/services/compression/engines/headroom/index.ts");
reconstructHeadroom = idxMod.reconstructHeadroom;
});
// ─── test payloads ──────────────────────────────────────────────────────────
interface Payload {
name: string;
description: string;
data: Record<string, unknown>[];
legacyCanHandle: boolean;
}
function buildPayloads(): Payload[] {
return [
{
name: "homogeneous-simple",
description: "50 rows, 4 uniform columns (id, name, value, active)",
data: Array.from({ length: 50 }, (_, i) => ({
id: i + 1,
name: `item-${i + 1}`,
value: (i + 1) * 10,
active: i % 2 === 0,
})),
legacyCanHandle: true,
},
{
name: "homogeneous-wide",
description: "30 rows, 8 columns with varied types",
data: Array.from({ length: 30 }, (_, i) => ({
id: i,
firstName: `First-${i}`,
lastName: `Last-${i}`,
email: `user${i}@example.com`,
age: 20 + (i % 50),
salary: 50000 + i * 1000,
department: ["Engineering", "Sales", "Marketing", "Support"][i % 4],
active: i % 3 !== 0,
})),
legacyCanHandle: true,
},
{
name: "heterogeneous-keys",
description: "20 rows with different key sets (GCF handles, legacy skips)",
data: [
...Array.from({ length: 10 }, (_, i) => ({
id: i,
name: `user-${i}`,
role: "admin",
})),
...Array.from({ length: 10 }, (_, i) => ({
id: i + 10,
email: `u${i}@test.com`,
verified: true,
})),
],
legacyCanHandle: false,
},
{
name: "mixed-type-columns",
description: "25 rows with nullable and mixed-type columns",
data: Array.from({ length: 25 }, (_, i) => ({
id: i + 1,
score: i % 3 === 0 ? null : (i + 1) * 7,
label: i % 4 === 0 ? null : `label-${i}`,
value: i % 2 === 0 ? i * 10 : `str-${i}`,
})),
legacyCanHandle: false,
},
{
name: "nested-objects",
description: "20 rows with nested object values",
data: Array.from({ length: 20 }, (_, i) => ({
id: i,
user: {
name: `user-${i}`,
email: `user${i}@example.com`,
tier: i % 3 === 0 ? "premium" : "free",
},
amount: i * 100,
})),
// Legacy detects as homogeneous (same keys), but JSON-stringifies nested objects.
// GCF encodes nested objects natively with inline schemas for better compression.
legacyCanHandle: true,
},
{
name: "api-response-realistic",
description: "Realistic API response: 40 rows with mixed fields",
data: Array.from({ length: 40 }, (_, i) => ({
id: `req-${i.toString(16).padStart(4, "0")}`,
timestamp: `2024-01-${((i % 28) + 1).toString().padStart(2, "0")}T${(i % 24).toString().padStart(2, "0")}:00:00Z`,
method: ["GET", "POST", "PUT", "DELETE"][i % 4],
path: `/api/v1/resources/${i}`,
status: [200, 201, 400, 404, 500][i % 5],
latencyMs: 10 + Math.floor(i * 3.7),
userId: `user-${i % 15}`,
cached: i % 3 === 0,
})),
legacyCanHandle: true,
},
];
}
// ─── benchmark tests ────────────────────────────────────────────────────────
describe("GCF benchmark — compression savings", () => {
const payloads = buildPayloads();
for (const payload of payloads) {
it(`${payload.name}: GCF compresses with positive savings`, () => {
const jsonStr = JSON.stringify(payload.data);
const gcfEncoded = encodeTabular(payload.data);
const savings = ((jsonStr.length - gcfEncoded.length) / jsonStr.length) * 100;
assert.ok(
savings > 0,
`GCF should save space on ${payload.name} (got ${savings.toFixed(1)}%)`
);
});
}
for (const payload of payloads) {
it(`${payload.name}: GCF round-trips losslessly`, () => {
const gcfEncoded = encodeTabular(payload.data);
const decoded = decodeTabular(gcfEncoded);
assert.deepEqual(decoded, payload.data, `${payload.name} must round-trip without data loss`);
});
}
});
describe("GCF benchmark — coverage comparison with legacy", () => {
const payloads = buildPayloads();
it("legacy omni-tabular handles only homogeneous payloads", () => {
for (const payload of payloads) {
const isHomogeneous = detectHomogeneous(payload.data) !== null;
if (payload.legacyCanHandle) {
// Legacy CAN handle it (but may still use mixed types that corrupt round-trip)
// For truly homogeneous data, detectHomogeneous should return non-null
// (some payloads are "legacyCanHandle" in terms of key structure but have mixed types)
} else {
assert.equal(
isHomogeneous,
false,
`${payload.name}: legacy should NOT detect as homogeneous`
);
}
}
});
it("GCF handles ALL payloads (100% coverage)", () => {
for (const payload of payloads) {
const gcfEncoded = encodeTabular(payload.data);
assert.ok(gcfEncoded.includes("gcf-generic"), `${payload.name}: must produce GCF output`);
const decoded = decodeTabular(gcfEncoded);
assert.deepEqual(decoded, payload.data, `${payload.name}: GCF must round-trip`);
}
});
});
describe("GCF benchmark — savings table", () => {
it("prints a comparison table (informational)", () => {
const payloads = buildPayloads();
const rows: string[] = [];
rows.push("| Payload | JSON | GCF | Savings | Legacy | Legacy Savings | GCF Advantage |");
rows.push("|---------|------|-----|---------|--------|----------------|---------------|");
for (const payload of payloads) {
const jsonStr = JSON.stringify(payload.data);
const gcfEncoded = encodeTabular(payload.data);
const gcfSavings = ((jsonStr.length - gcfEncoded.length) / jsonStr.length) * 100;
let legacySize = "-";
let legacySavings = "-";
let advantage = "N/A (legacy can't encode)";
if (payload.legacyCanHandle && detectHomogeneous(payload.data)) {
const legacyBlock = `\`\`\`omni-tabular\n${encodeTabularBlockLegacy(payload.data)}\n\`\`\``;
legacySize = String(legacyBlock.length);
const ls = ((jsonStr.length - legacyBlock.length) / jsonStr.length) * 100;
legacySavings = ls.toFixed(1) + "%";
advantage = (gcfSavings - ls).toFixed(1) + "pp";
}
rows.push(
`| ${payload.name} | ${jsonStr.length} | ${gcfEncoded.length} | ${gcfSavings.toFixed(1)}% | ${legacySize} | ${legacySavings} | ${advantage} |`
);
}
// Print to stdout for visibility in test output
console.log("\n" + rows.join("\n") + "\n");
// Assert the table was built (not empty)
assert.ok(rows.length > 2, "benchmark table should have data rows");
});
});

View File

@@ -10,6 +10,8 @@ import {
checkTokensPerTaskGate,
replayTranscripts,
transcriptsToCorpus,
requestBodyToTranscript,
requestBodiesToTranscripts,
} from "../../../open-sse/services/compression/harness/index.ts";
const SAMPLE = "Call fetchUser() at https://api.example.com/v1 with MAX_RETRIES set to 3.0.0";
@@ -136,3 +138,45 @@ describe("compression harness — transcript replay (TV3)", () => {
assert.equal(report.meanRetention, 1);
});
});
describe("compression harness — transcript loader (TV3)", () => {
it("builds a transcript from a captured request body, flattening content blocks", () => {
const transcript = requestBodyToTranscript("req-1", {
model: "gpt-x",
messages: [
{ role: "system", content: "You are helpful." },
{
role: "user",
content: [
{ type: "text", text: "first block" },
{ type: "image_url", image_url: { url: "data:..." } },
{ type: "text", text: "second block" },
],
},
],
});
assert.equal(transcript.id, "req-1");
assert.equal(transcript.turns.length, 2);
assert.equal(transcript.turns[0].role, "system");
assert.equal(transcript.turns[0].content, "You are helpful.");
// multimodal content flattened to its text blocks (image dropped)
assert.equal(transcript.turns[1].content, "first block\nsecond block");
});
it("returns an empty transcript for a body without a messages array", () => {
assert.deepEqual(requestBodyToTranscript("empty", { foo: 1 }), { id: "empty", turns: [] });
assert.deepEqual(requestBodyToTranscript("nullish", null), { id: "nullish", turns: [] });
});
it("maps captured bodies into transcripts that feed the replay corpus", () => {
const transcripts = requestBodiesToTranscripts([
{ id: "a", body: { messages: [{ role: "user", content: "hi" }] } },
{ id: "b", body: { messages: [{ role: "user", content: " " }] } }, // empty turn → skipped
]);
assert.equal(transcripts.length, 2);
const corpus = transcriptsToCorpus(transcripts);
// transcript "a" contributes one case; "b" is all-blank so transcriptsToCorpus drops it
assert.equal(corpus.length, 1);
assert.equal(corpus[0].task, "a");
});
});

View File

@@ -88,10 +88,11 @@ describe("tabular encoder round-trip", () => {
assert.deepEqual(decoded, original);
});
it("encoded form contains an explicit [N rows] count marker", async () => {
it("encoded form contains an explicit [N] count marker with field declaration", async () => {
const original = makeRows(25);
const encoded = encodeTabular(original);
assert.match(encoded, /\[25 rows\]/);
// GCF uses [N]{fields} format (e.g. [25]{id,name,value,active})
assert.match(encoded, /\[25\]\{/);
});
});
@@ -144,7 +145,7 @@ describe("headroomEngine.apply — compression", () => {
);
});
it("compressed body contains the [N rows] count marker", async () => {
it("compressed body contains the [N] count marker with field declaration", async () => {
const n = 22;
const rows = makeRows(n);
const body = makeBody(rows);
@@ -153,7 +154,8 @@ describe("headroomEngine.apply — compression", () => {
assert.equal(result.compressed, true);
const bodyStr = JSON.stringify(result.body);
assert.match(bodyStr, /\[22 rows\]/, "compressed body must contain [N rows] marker");
// GCF uses [N]{fields} format
assert.match(bodyStr, /\[22\]\{/, "compressed body must contain [N]{fields} marker");
});
it("also compresses when the array is inside a ```json fence in message content", async () => {
@@ -175,16 +177,16 @@ describe("headroomEngine.apply — compression", () => {
// ─── 3. Conservative guards — nested/flat should NOT regress ─────────────────
describe("headroomEngine.apply — conservative guards (no regression)", () => {
it("does NOT compress a heterogeneous array (objects with different key sets)", async () => {
// Objects have different keys — not homogeneous
it("compresses a heterogeneous array (objects with different key sets) via GCF", async () => {
// GCF handles heterogeneous arrays natively: missing fields become ~ (absent)
const rows: Record<string, unknown>[] = [
...Array.from({ length: 10 }, (_, i) => ({ id: i, name: `n${i}` })),
...Array.from({ length: 10 }, (_, i) => ({ key: i, label: `l${i}`, extra: true })),
];
const body = makeBody(rows);
const result = headroomEngine.apply(body);
assert.equal(result.compressed, false, "heterogeneous array should NOT be compressed");
assert.deepEqual(result.body, body);
// GCF encodes heterogeneous arrays with union of all keys
assert.equal(result.compressed, true, "heterogeneous array should be compressed by GCF");
});
it("does NOT compress a tiny array below minRows (< default 8)", async () => {
@@ -305,3 +307,140 @@ describe("headroomEngine — losslessness on mixed-type columns (regression)", (
assert.deepEqual(restored, body, "mixed-type column must round-trip without data loss");
});
});
// ─── 6. GCF encoding: capabilities beyond legacy omni-tabular ──────────────
describe("GCF encoding — advanced capabilities", () => {
async function reconstruct(body: Record<string, unknown>) {
const mod = await import("../../../open-sse/services/compression/engines/headroom/index.ts");
return mod.reconstructHeadroom(body);
}
it("compresses heterogeneous arrays (different key sets) losslessly", async () => {
const rows: Record<string, unknown>[] = [
...Array.from({ length: 10 }, (_, i) => ({ id: i, name: `user-${i}` })),
...Array.from({ length: 10 }, (_, i) => ({
id: i + 10,
email: `u${i}@test.com`,
verified: true,
})),
];
const body = makeBody(rows);
const result = headroomEngine.apply(body);
assert.equal(result.compressed, true, "heterogeneous array should be compressed");
const restored = await reconstruct(result.body);
assert.deepEqual(restored, body, "heterogeneous array must round-trip losslessly");
});
it("compresses arrays with nested objects losslessly", async () => {
const rows = Array.from({ length: 15 }, (_, i) => ({
id: i,
name: `item-${i}`,
metadata: { category: `cat-${i % 3}`, priority: i % 5 },
}));
const body = makeBody(rows);
const result = headroomEngine.apply(body);
assert.equal(result.compressed, true, "nested objects should be compressed");
const restored = await reconstruct(result.body);
assert.deepEqual(restored, body, "nested objects must round-trip losslessly");
});
it("compresses arrays with nested arrays losslessly", async () => {
// Use enough rows with enough data to overcome GCF overhead on nested arrays
const rows = Array.from({ length: 30 }, (_, i) => ({
id: i,
name: `item-${i}-with-longer-name-for-savings`,
tags: ["alpha", "beta", `tag-${i}`],
scores: [i * 10, i * 20, i * 30],
}));
const body = makeBody(rows);
const result = headroomEngine.apply(body);
assert.equal(result.compressed, true, "nested arrays should be compressed");
const restored = await reconstruct(result.body);
assert.deepEqual(restored, body, "nested arrays must round-trip losslessly");
});
it("uses gcf-generic fence marker (not omni-tabular)", async () => {
const rows = makeRows(20);
const encoded = encodeTabular(rows);
assert.ok(encoded.includes("```gcf-generic"), "must use gcf-generic fence marker");
assert.ok(!encoded.includes("omni-tabular"), "must not use legacy omni-tabular marker");
});
it("still decodes legacy omni-tabular encoded content (backward compat)", async () => {
// Import legacy encoder
const mod = await import("../../../open-sse/services/compression/engines/headroom/tabular.ts");
const legacyEncode = mod.encodeTabularBlockLegacy;
const rows = makeRows(10);
const legacyBlock = `\`\`\`omni-tabular\n${legacyEncode(rows)}\n\`\`\``;
const decoded = decodeTabular(legacyBlock);
assert.deepEqual(decoded, rows, "legacy omni-tabular content must still decode correctly");
});
});
// ─── 7. GCF vs legacy benchmark comparison ─────────────────────────────────
describe("GCF vs legacy omni-tabular — compression comparison", () => {
it("GCF achieves comparable or better compression on homogeneous arrays", async () => {
const rows = makeRows(50);
const jsonStr = JSON.stringify(rows);
// Legacy omni-tabular
const mod = await import("../../../open-sse/services/compression/engines/headroom/tabular.ts");
const legacyBlock = `\`\`\`omni-tabular\n${mod.encodeTabularBlockLegacy(rows)}\n\`\`\``;
const legacySavings = ((jsonStr.length - legacyBlock.length) / jsonStr.length) * 100;
// GCF
const gcfEncoded = encodeTabular(rows);
const gcfSavings = ((jsonStr.length - gcfEncoded.length) / jsonStr.length) * 100;
// GCF should achieve at least as much savings as legacy on homogeneous data
assert.ok(
gcfSavings >= legacySavings * 0.8, // allow 20% tolerance
`GCF savings (${gcfSavings.toFixed(1)}%) should be within 80% of legacy (${legacySavings.toFixed(1)}%)`
);
});
it("GCF compresses cases that legacy omni-tabular skips entirely", async () => {
// Heterogeneous: legacy would skip, GCF handles it
const heteroRows: Record<string, unknown>[] = [
...Array.from({ length: 10 }, (_, i) => ({ id: i, name: `user-${i}`, role: "admin" })),
...Array.from({ length: 10 }, (_, i) => ({ id: i + 10, email: `u${i}@test.com` })),
];
const jsonStr = JSON.stringify(heteroRows);
// Legacy encoder would produce nothing useful for heterogeneous data
// (detectHomogeneous returns null)
const { detectHomogeneous } =
await import("../../../open-sse/services/compression/engines/headroom/smartcrusher.ts");
assert.equal(detectHomogeneous(heteroRows), null, "legacy should reject heterogeneous arrays");
// GCF compresses it
const gcfEncoded = encodeTabular(heteroRows);
const gcfSavings = ((jsonStr.length - gcfEncoded.length) / jsonStr.length) * 100;
assert.ok(
gcfSavings > 0,
`GCF should compress heterogeneous arrays (savings: ${gcfSavings.toFixed(1)}%)`
);
});
it("GCF compresses nested objects that legacy omni-tabular JSON-stringifies", async () => {
const nestedRows = Array.from({ length: 20 }, (_, i) => ({
id: i,
user: {
name: `user-${i}`,
email: `user${i}@example.com`,
tier: i % 3 === 0 ? "premium" : "free",
},
value: i * 100,
}));
const jsonStr = JSON.stringify(nestedRows);
const gcfEncoded = encodeTabular(nestedRows);
const gcfSavings = ((jsonStr.length - gcfEncoded.length) / jsonStr.length) * 100;
assert.ok(
gcfSavings >= 30,
`GCF should achieve >=30% savings on nested objects (got ${gcfSavings.toFixed(1)}%)`
);
});
});

View File

@@ -0,0 +1,110 @@
import { describe, it, beforeEach, afterEach, after } from "node:test";
import assert from "node:assert/strict";
import fs from "node:fs";
import os from "node:os";
import path from "node:path";
import { mcpAccessibilityConfigSchema } from "../../../src/shared/validation/compressionConfigSchemas.ts";
// mcpAccessibility tunes how the MCP server filters oversized tool outputs: server.ts reads the
// `compression/mcpAccessibility` DB key on every tool call (readMcpAccessibilityConfig). The
// #4206 numeric bounds existed but were unreachable in production — no write route, and the
// settings PUT schema (.strict()) rejected the key, so get/setMcpAccessibilityConfig had no
// callers. This proves the new schema + dedicated sub-route + DB round-trip make the config
// settable end to end, with clampMcpAccessibilityConfig owning the numeric floors.
const TEST_DATA_DIR = fs.mkdtempSync(path.join(os.tmpdir(), "omniroute-mcpaccess-"));
const ORIGINAL_DATA_DIR = process.env.DATA_DIR;
process.env.DATA_DIR = TEST_DATA_DIR;
const core = await import("../../../src/lib/db/core.ts");
const { getMcpAccessibilityConfig, setMcpAccessibilityConfig } =
await import("../../../src/lib/db/compression.ts");
const route = await import("../../../src/app/api/settings/compression/mcp-accessibility/route.ts");
function resetDir() {
core.resetDbInstance();
fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true });
fs.mkdirSync(TEST_DATA_DIR, { recursive: true });
}
describe("mcpAccessibility config reachability", () => {
beforeEach(resetDir);
afterEach(() => core.resetDbInstance());
after(() => {
core.resetDbInstance();
fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true });
if (ORIGINAL_DATA_DIR === undefined) delete process.env.DATA_DIR;
else process.env.DATA_DIR = ORIGINAL_DATA_DIR;
});
it("validates partial updates and rejects unknown / invalid fields", () => {
assert.equal(
mcpAccessibilityConfigSchema.safeParse({ enabled: false, maxTextChars: 8000 }).success,
true
);
// unknown key rejected (.strict)
assert.equal(mcpAccessibilityConfigSchema.safeParse({ bogus: 1 }).success, false);
// non-positive maxTextChars rejected at the schema boundary
assert.equal(mcpAccessibilityConfigSchema.safeParse({ maxTextChars: -5 }).success, false);
assert.equal(mcpAccessibilityConfigSchema.safeParse({ collapseThreshold: 0 }).success, false);
});
it("persists a partial update through set/getMcpAccessibilityConfig (clamp owns floors)", async () => {
await setMcpAccessibilityConfig({ maxTextChars: 8000, collapseThreshold: 12 });
let cfg = await getMcpAccessibilityConfig();
assert.equal(cfg.maxTextChars, 8000);
assert.equal(cfg.collapseThreshold, 12);
// below the engine floor (MCP_ACCESSIBILITY_MIN_MAX_TEXT_CHARS) → clamp reverts to the
// default, the documented "misconfiguration falls back to the default" behavior.
await setMcpAccessibilityConfig({ maxTextChars: 100 });
cfg = await getMcpAccessibilityConfig();
assert.equal(cfg.maxTextChars, 50000);
});
it("PUT + GET round-trip through the dedicated sub-route persists the config", async () => {
const putRes = await route.PUT(
new Request("http://localhost/api/settings/compression/mcp-accessibility", {
method: "PUT",
headers: { "content-type": "application/json" },
body: JSON.stringify({ maxTextChars: 12000, minLengthToProcess: 500 }),
// eslint-disable-next-line @typescript-eslint/no-explicit-any
}) as any
);
assert.equal(putRes.status, 200);
const putBody = await putRes.json();
assert.equal(putBody.maxTextChars, 12000);
assert.equal(putBody.minLengthToProcess, 500);
// Survives a fresh read from a new DB handle (not just the write-path return value).
core.resetDbInstance();
const getRes = await route.GET(
// eslint-disable-next-line @typescript-eslint/no-explicit-any
new Request("http://localhost/api/settings/compression/mcp-accessibility") as any
);
assert.equal(getRes.status, 200);
const getBody = await getRes.json();
assert.equal(getBody.maxTextChars, 12000);
assert.equal(getBody.minLengthToProcess, 500);
});
it("PUT merges over the current config (does not reset untouched fields)", async () => {
await setMcpAccessibilityConfig({ maxTextChars: 12000, collapseThreshold: 9 });
const putRes = await route.PUT(
new Request("http://localhost/api/settings/compression/mcp-accessibility", {
method: "PUT",
headers: { "content-type": "application/json" },
body: JSON.stringify({ enabled: false }),
// eslint-disable-next-line @typescript-eslint/no-explicit-any
}) as any
);
assert.equal(putRes.status, 200);
const body = await putRes.json();
assert.equal(body.enabled, false);
// untouched fields preserved (partial-merge-over-current, not over the defaults)
assert.equal(body.maxTextChars, 12000);
assert.equal(body.collapseThreshold, 9);
});
});

View File

@@ -0,0 +1,46 @@
import { test } from "node:test";
import assert from "node:assert/strict";
import { smartFilterText } from "../../../open-sse/services/compression/engines/mcpAccessibility/index.ts";
import { DEFAULT_MCP_ACCESSIBILITY_CONFIG } from "../../../open-sse/services/compression/engines/mcpAccessibility/constants.ts";
// F5.3: `headSize = config.maxTextChars - 300` goes negative when maxTextChars is below the
// 300-char tail reservation, and `out.slice(0, negative)` counts from the END — silently
// keeping a wrong (and oversized) fragment instead of the intended head. maxTextChars is
// only floored to > 0 on the write path, so a stored value in [1,300] reaches this code.
test("clamps head to >=0 when maxTextChars is below the tail reservation (≤300)", () => {
const config = {
...DEFAULT_MCP_ACCESSIBILITY_CONFIG,
maxTextChars: 50,
minLengthToProcess: 1,
};
const input = "A".repeat(500);
const out = smartFilterText(input, config);
// Bug: headSize = -250 → slice(0,-250) keeps the first 250 chars → output leaks a long
// run of 'A' and is far larger than maxTextChars. Fixed: headSize clamps to 0 → empty
// head → output is just the truncation notice (which contains no capital 'A').
assert.ok(!out.includes("A"), "head must be empty (clamped) — no leaked content from a negative slice");
assert.ok(out.includes("truncated"), "still emits the truncation notice");
});
test("reports omitted chars relative to the filtered text, not the raw input", () => {
// Noise lines get stripped before truncation, so `omitted` must be measured against the
// filtered text (`out`), not the longer raw `text`.
const noise = "- generic:\n".repeat(10); // stripped by NOISE_PATTERNS
const input = noise + "B".repeat(1000);
const config = {
...DEFAULT_MCP_ACCESSIBILITY_CONFIG,
maxTextChars: 400,
minLengthToProcess: 1,
};
const out = smartFilterText(input, config);
const match = out.match(/truncated (\d+) chars/);
assert.ok(match, "emits a truncation notice with an omitted count");
const omitted = Number(match[1]);
// Filtered text is ~1010 chars; head keeps 100 → omitted ~910. The raw input is 1110, so
// the buggy `text.length - head.length` would report ~1010 (> filtered length).
assert.ok(
omitted <= 1000,
`omitted must reflect the filtered text (<=1000), got ${omitted}`
);
});

View File

@@ -0,0 +1,48 @@
import { test } from "node:test";
import assert from "node:assert/strict";
import {
smartFilterText,
clampMcpAccessibilityConfig,
} from "../../../open-sse/services/compression/engines/mcpAccessibility/index.ts";
import { DEFAULT_MCP_ACCESSIBILITY_CONFIG } from "../../../open-sse/services/compression/engines/mcpAccessibility/constants.ts";
// smartFilterText reserves 300 chars for the truncation tail/notice, so any maxTextChars below
// that leaves headSize <= 0 and the whole tool result is replaced by the notice (total data
// loss). The DB normalizer floored maxTextChars only at > 0, and the production read path in
// server.ts bypassed bounding entirely. clampMcpAccessibilityConfig is the shared guard.
test("clamps maxTextChars below the tail reserve to the default", () => {
for (const bad of [1, 50, 300, 599]) {
assert.equal(
clampMcpAccessibilityConfig({ maxTextChars: bad }).maxTextChars,
DEFAULT_MCP_ACCESSIBILITY_CONFIG.maxTextChars,
`maxTextChars=${bad} must fall back to default`
);
}
});
test("keeps a sane maxTextChars (>= 600)", () => {
assert.equal(clampMcpAccessibilityConfig({ maxTextChars: 600 }).maxTextChars, 600);
assert.equal(clampMcpAccessibilityConfig({ maxTextChars: 1000 }).maxTextChars, 1000);
assert.equal(clampMcpAccessibilityConfig({ maxTextChars: 1234.9 }).maxTextChars, 1234);
});
test("bounds the other numeric fields and honors enabled", () => {
const c = clampMcpAccessibilityConfig({
collapseThreshold: -5,
minLengthToProcess: 0,
collapseKeepHead: -1,
enabled: false,
});
assert.equal(c.collapseThreshold, DEFAULT_MCP_ACCESSIBILITY_CONFIG.collapseThreshold);
assert.equal(c.minLengthToProcess, DEFAULT_MCP_ACCESSIBILITY_CONFIG.minLengthToProcess);
assert.equal(c.collapseKeepHead, DEFAULT_MCP_ACCESSIBILITY_CONFIG.collapseKeepHead);
assert.equal(c.enabled, false);
});
test("a clamped config never lets smartFilterText truncate the whole text away", () => {
// The previously-dangerous stored value: maxTextChars=50 → clamps to default, so a
// 1000-char tool result is NOT replaced wholesale by the truncation notice.
const cfg = clampMcpAccessibilityConfig({ maxTextChars: 50, minLengthToProcess: 1 });
const out = smartFilterText("A".repeat(1000), cfg);
assert.ok(out.includes("A".repeat(500)), "content preserved (not nuked by a tiny maxTextChars)");
});

View File

@@ -0,0 +1,57 @@
import { describe, it } from "node:test";
import assert from "node:assert/strict";
import { applyLineFilter } from "../../../open-sse/services/compression/engines/rtk/lineFilter.ts";
import type { RtkFilterDefinition } from "../../../open-sse/services/compression/engines/rtk/filterSchema.ts";
// A custom RTK filter can set `deduplicate: true` (rules.deduplicate in the filter JSON), and it
// was carried onto RtkFilterDefinition — but applyLineFilter never read it, so the flag did
// nothing. This wires it: when set, consecutive duplicate lines in the filter's output are
// collapsed (the same line-dedup the engine offers globally, now controllable per filter).
function filter(over: Partial<RtkFilterDefinition>): RtkFilterDefinition {
return {
id: "t",
name: "t",
description: "",
commandTypes: [],
commandPatterns: [],
matchPatterns: [],
category: "generic",
priority: 50,
stripPatterns: [],
keepPatterns: [],
priorityPatterns: [],
collapsePatterns: [],
stripAnsi: false,
replace: [],
matchOutput: [],
truncateLineAt: 0,
onEmpty: "",
filterStderr: false,
deduplicate: false,
maxLines: 0,
preserveHead: 20,
preserveTail: 20,
tests: [],
...over,
};
}
const TEXT = ["start", "dup", "dup", "dup", "dup", "end"].join("\n");
describe("applyLineFilter — per-filter deduplicate flag", () => {
it("collapses repeated lines and records the rule when deduplicate is set", () => {
const result = applyLineFilter(TEXT, filter({ deduplicate: true }));
assert.ok(result.appliedRules.includes("t:deduplicate"), "records the deduplicate rule");
const dupCount = result.text.split(/\r?\n/).filter((l) => l === "dup").length;
assert.ok(dupCount < 4, `the 4-line dup run must be collapsed (got ${dupCount} dup lines)`);
assert.ok(result.text.includes("start") && result.text.includes("end"), "keeps non-dup lines");
});
it("does NOT deduplicate when the flag is off (default)", () => {
const result = applyLineFilter(TEXT, filter({ deduplicate: false }));
assert.ok(!result.appliedRules.includes("t:deduplicate"));
const dupCount = result.text.split(/\r?\n/).filter((l) => l === "dup").length;
assert.equal(dupCount, 4, "the dup run must remain intact when deduplicate is off");
});
});

View File

@@ -0,0 +1,27 @@
import { describe, it, afterEach, mock } from "node:test";
import assert from "node:assert/strict";
import fs from "node:fs";
import { loadRtkFilters } from "../../../open-sse/services/compression/engines/rtk/filterLoader.ts";
// F5.3: collectFilterSources() enumerates the builtin filters dir with an unguarded
// fs.readdirSync. A read failure there (lost permission, TOCTOU between existsSync and
// readdirSync, NFS timeout, removed dir on a read-only container) must NOT propagate into
// the compression pipeline — compression is best-effort and may never fail the request.
describe("RTK filter loader resilience", () => {
afterEach(() => {
mock.restoreAll();
// Drop any cache poisoned during the mocked run.
loadRtkFilters({ refresh: true });
});
it("degrades gracefully (does not throw) when the builtin dir cannot be read", () => {
// The only readdirSync on the loadRtkFilters path is the builtin enumeration, so an
// unconditional throw exercises exactly that call site.
mock.method(fs, "readdirSync", () => {
throw Object.assign(new Error("EACCES (mock)"), { code: "EACCES" });
});
assert.doesNotThrow(() => loadRtkFilters({ refresh: true }));
});
});

View File

@@ -0,0 +1,54 @@
import { describe, it } from "node:test";
import assert from "node:assert/strict";
import {
validateRtkFilter,
isReDoSProne,
} from "../../../open-sse/services/compression/engines/rtk/filterSchema.ts";
// Custom RTK filters (DATA_DIR/rtk/filters.json) carry user-supplied regex strings that are
// compiled and run against untrusted tool output. A nested unbounded quantifier ((a+)+, (a*)*)
// can trigger catastrophic backtracking (ReDoS). validateRtkFilter must drop such patterns so
// they are never compiled. Dependency-free heuristic (safe-regex not installable here).
describe("RTK filter ReDoS guard", () => {
it("flags nested unbounded quantifiers and accepts safe patterns", () => {
assert.equal(isReDoSProne("(a+)+"), true);
assert.equal(isReDoSProne("(a*)*"), true);
assert.equal(isReDoSProne("([a-z]+)+"), true);
assert.equal(isReDoSProne("(a+|b)+"), true);
assert.equal(isReDoSProne("(?:\\d+)+"), true);
assert.equal(isReDoSProne("(ab)+"), false);
assert.equal(isReDoSProne("\\d{1,8}"), false);
assert.equal(isReDoSProne("error|fail|FAIL"), false);
assert.equal(isReDoSProne("^\\s*$"), false);
});
it("strips ReDoS-prone patterns from a canonical filter at validation", () => {
const def = validateRtkFilter({
id: "x",
label: "X",
category: "generic",
match: { commands: [], patterns: ["(a+)+", "ERROR\\b"], outputTypes: [] },
rules: { dropPatterns: ["(.*)*", "^\\s*$"] },
// preserve provided explicitly: a pack filter omitting it crashes validateRtkFilter
// (pre-existing: rtkFilterPreserveSchema.default({}) leaves errorPatterns undefined).
preserve: { errorPatterns: [], summaryPatterns: [] },
});
assert.deepEqual(def.matchPatterns, ["ERROR\\b"], "catastrophic matchPattern dropped");
assert.deepEqual(def.stripPatterns, ["^\\s*$"], "catastrophic dropPattern removed");
});
it("strips ReDoS-prone patterns from a legacy filter at validation", () => {
const def = validateRtkFilter({
id: "y",
name: "Y",
category: "generic",
commandTypes: ["shell"],
stripPatterns: ["([a-z]+)*", "keepme"],
});
assert.deepEqual(def.stripPatterns, ["keepme"], "catastrophic legacy stripPattern removed");
});
});

View File

@@ -0,0 +1,63 @@
import { describe, it, beforeEach, afterEach, after } from "node:test";
import assert from "node:assert/strict";
import fs from "node:fs";
import os from "node:os";
import path from "node:path";
import { rtkConfigSchema } from "../../../src/shared/validation/compressionConfigSchemas.ts";
import { DEFAULT_RTK_CONFIG } from "../../../open-sse/services/compression/types.ts";
// The RTK R5 grouping feature is read by the engine (config.enableGrouping / groupingThreshold)
// but was unreachable in production: the Zod schema (.strict()) rejected the two fields on write
// and normalizeRtkConfig dropped them on read. This proves both gates now let them through.
const TEST_DATA_DIR = fs.mkdtempSync(path.join(os.tmpdir(), "omniroute-rtk-grouping-"));
const ORIGINAL_DATA_DIR = process.env.DATA_DIR;
process.env.DATA_DIR = TEST_DATA_DIR;
const core = await import("../../../src/lib/db/core.ts");
const { getCompressionSettings, updateCompressionSettings } = await import(
"../../../src/lib/db/compression.ts"
);
describe("RTK grouping config persistence (R5)", () => {
beforeEach(() => {
core.resetDbInstance();
fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true });
fs.mkdirSync(TEST_DATA_DIR, { recursive: true });
});
afterEach(() => {
core.resetDbInstance();
});
after(() => {
core.resetDbInstance();
fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true });
if (ORIGINAL_DATA_DIR === undefined) delete process.env.DATA_DIR;
else process.env.DATA_DIR = ORIGINAL_DATA_DIR;
});
it("accepts enableGrouping / groupingThreshold on the write schema", () => {
assert.equal(
rtkConfigSchema.safeParse({ enableGrouping: true, groupingThreshold: 5 }).success,
true
);
// groupingThreshold below the minimum run length (2) is rejected.
assert.equal(rtkConfigSchema.safeParse({ groupingThreshold: 1 }).success, false);
});
it("preserves enableGrouping / groupingThreshold through a DB round-trip", async () => {
const settings = await updateCompressionSettings({
rtkConfig: { ...DEFAULT_RTK_CONFIG, enableGrouping: true, groupingThreshold: 7 },
});
assert.equal(settings.rtkConfig.enableGrouping, true);
assert.equal(settings.rtkConfig.groupingThreshold, 7);
// Survives a fresh read (not just the write-path return value).
core.resetDbInstance();
const reread = await getCompressionSettings();
assert.equal(reread.rtkConfig.enableGrouping, true);
assert.equal(reread.rtkConfig.groupingThreshold, 7);
});
});

View File

@@ -128,4 +128,40 @@ describe("RTK raw output retention", () => {
assert.ok(pointer);
assert.ok(readRtkRawOutput(pointer.id)?.includes("[REDACTED"));
});
it("never throws when the raw-output write fails (disk error → null pointer)", () => {
// Point DATA_DIR underneath a regular FILE so mkdirSync(recursive) throws ENOTDIR.
// maybePersistRtkRawOutput is best-effort capture: a write failure must degrade to a
// skipped capture (null), never propagate into the compression pipeline (F5.3).
const blocker = path.join(os.tmpdir(), `omniroute-rtk-blocked-${process.pid}-${Date.now()}`);
fs.writeFileSync(blocker, "x");
process.env.DATA_DIR = path.join(blocker, "nested");
let pointer: ReturnType<typeof maybePersistRtkRawOutput> | undefined;
assert.doesNotThrow(() => {
pointer = maybePersistRtkRawOutput("error: boom\n" + "noise\n".repeat(8), {
retention: "always",
});
});
assert.equal(pointer, null);
fs.rmSync(blocker, { force: true });
});
it("redacts Basic/Proxy auth headers and key fields the base patterns miss", () => {
const basic = redactRtkRawOutput("> Authorization: Basic dXNlcjpwYXNzd29yZA==");
assert.equal(basic.redacted, true);
assert.ok(!basic.text.includes("dXNlcjpwYXNzd29yZA=="), "Authorization: Basic base64 redacted");
const proxy = redactRtkRawOutput("Proxy-Authorization: Basic c2VjcmV0OnBhc3M=");
assert.equal(proxy.redacted, true);
assert.ok(!proxy.text.includes("c2VjcmV0OnBhc3M="), "Proxy-Authorization redacted");
const pkey = redactRtkRawOutput("private_key=abc123def456ghi");
assert.equal(pkey.redacted, true);
assert.ok(!pkey.text.includes("abc123def456ghi"), "private_key value redacted");
const cred = redactRtkRawOutput("credential: my-credential-value-x");
assert.equal(cred.redacted, true);
assert.ok(!cred.text.includes("my-credential-value-x"), "credential value redacted");
});
});

View File

@@ -0,0 +1,136 @@
import { describe, it, beforeEach, afterEach, after } from "node:test";
import assert from "node:assert/strict";
import fs from "node:fs";
import os from "node:os";
import path from "node:path";
import {
applyRtkCompression,
stripCode,
} from "../../../open-sse/services/compression/index.ts";
import { rtkConfigSchema } from "../../../src/shared/validation/compressionConfigSchemas.ts";
import { DEFAULT_RTK_CONFIG } from "../../../open-sse/services/compression/types.ts";
// codeStripper has always supported removeComments + preserveDocstrings, but the feature was
// unreachable: the RTK engine called stripCode with no options (so comments were never removed
// through the runtime), and preserveDocstrings was folded into opts yet never honored by
// stripJsTsComments. This proves the new RTK config fields wire it end to end and that
// preserveDocstrings now keeps JSDoc.
const TEST_DATA_DIR = fs.mkdtempSync(path.join(os.tmpdir(), "omniroute-rtk-strip-"));
const ORIGINAL_DATA_DIR = process.env.DATA_DIR;
process.env.DATA_DIR = TEST_DATA_DIR;
const core = await import("../../../src/lib/db/core.ts");
const { getCompressionSettings, updateCompressionSettings } = await import(
"../../../src/lib/db/compression.ts"
);
describe("RTK strip-code-comments — stripCode behavior", () => {
it("removes line/block comments but keeps JSDoc when preserveDocstrings is on", () => {
const code = [
"/** Adds two numbers. */",
"function add(a, b) {",
" // inline note",
" return a + b; /* trailing */",
"}",
].join("\n");
const out = stripCode(code, "typescript", {
removeComments: true,
preserveDocstrings: true,
removeEmptyLines: false,
collapseWhitespace: false,
});
assert.ok(out.text.includes("/** Adds two numbers. */"), "JSDoc preserved");
assert.ok(!out.text.includes("inline note"), "line comment removed");
assert.ok(!out.text.includes("trailing"), "trailing block comment removed");
});
it("removes JSDoc too when preserveDocstrings is off", () => {
const out = stripCode("/** doc */\nconst x = 1; // n", "typescript", {
removeComments: true,
preserveDocstrings: false,
removeEmptyLines: false,
collapseWhitespace: false,
});
assert.ok(!out.text.includes("doc"), "JSDoc removed when not preserving");
assert.ok(!out.text.includes("// n"), "line comment removed");
});
});
describe("RTK strip-code-comments — runtime reachability", () => {
it("strips fenced-block comments when applyToCodeBlocks + stripCodeComments are on", () => {
// RTK only processes tool/assistant messages (shouldCompressMessage); code-block stripping
// rides on applyToCodeBlocks for assistant content regardless of applyToAssistantMessages.
const body = {
messages: [
{
role: "assistant",
content: "```ts\n// secret note\nconst x = 1;\n/* block secret */\nconst y = 2;\n```",
},
],
};
const result = applyRtkCompression(body, {
config: {
...DEFAULT_RTK_CONFIG,
enabled: true,
applyToCodeBlocks: true,
stripCodeComments: true,
},
});
const serialized = JSON.stringify(result.body.messages);
assert.ok(!serialized.includes("secret note"), "line comment stripped via runtime");
assert.ok(!serialized.includes("block secret"), "block comment stripped via runtime");
assert.match(serialized, /const x = 1/);
assert.match(serialized, /const y = 2/);
});
it("leaves fenced-block comments intact when stripCodeComments is off (default)", () => {
const body = {
messages: [{ role: "assistant", content: "```ts\n// keep me\nconst x = 1;\n```" }],
};
const result = applyRtkCompression(body, {
config: { ...DEFAULT_RTK_CONFIG, enabled: true, applyToCodeBlocks: true },
});
assert.match(JSON.stringify(result.body.messages), /keep me/);
});
});
describe("RTK strip-code-comments — config persistence", () => {
beforeEach(() => {
core.resetDbInstance();
fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true });
fs.mkdirSync(TEST_DATA_DIR, { recursive: true });
});
afterEach(() => {
core.resetDbInstance();
});
after(() => {
core.resetDbInstance();
fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true });
if (ORIGINAL_DATA_DIR === undefined) delete process.env.DATA_DIR;
else process.env.DATA_DIR = ORIGINAL_DATA_DIR;
});
it("accepts stripCodeComments / preserveDocstrings on the write schema", () => {
assert.equal(
rtkConfigSchema.safeParse({ stripCodeComments: true, preserveDocstrings: false }).success,
true
);
});
it("preserves stripCodeComments / preserveDocstrings through a DB round-trip", async () => {
const settings = await updateCompressionSettings({
rtkConfig: { ...DEFAULT_RTK_CONFIG, stripCodeComments: true, preserveDocstrings: false },
});
assert.equal(settings.rtkConfig.stripCodeComments, true);
assert.equal(settings.rtkConfig.preserveDocstrings, false);
core.resetDbInstance();
const reread = await getCompressionSettings();
assert.equal(reread.rtkConfig.stripCodeComments, true);
assert.equal(reread.rtkConfig.preserveDocstrings, false);
});
});

View File

@@ -6,10 +6,7 @@
import { describe, it, before } from "node:test";
import assert from "node:assert/strict";
import {
sessionDedupEngine,
reconstructSessionDedup,
} from "../../../open-sse/services/compression/engines/session-dedup/index.ts";
import { sessionDedupEngine } from "../../../open-sse/services/compression/engines/session-dedup/index.ts";
import {
registerBuiltinCompressionEngines,
getCompressionEngine,
@@ -88,26 +85,6 @@ describe("session-dedup engine", () => {
assert.ok(result.stats!.compressedTokens < result.stats!.originalTokens);
});
it("round-trip: reconstructSessionDedup restores original body exactly", () => {
const body = makeBody([
{ role: "user", content: `Here is the code:\n${REPEATED_BLOCK}` },
{ role: "assistant", content: "I understand the code." },
{ role: "user", content: `Please review again:\n${REPEATED_BLOCK}` },
]);
const result = sessionDedupEngine.apply(body as Record<string, unknown>);
assert.equal(result.compressed, true);
const restored = reconstructSessionDedup(result.body);
// Deep-equal to original
assert.deepEqual(
restored.messages,
body.messages,
"reconstructed body must deep-equal original"
);
});
it("does NOT dedup small/unique blocks (no false positives)", () => {
const body = makeBody([
{ role: "user", content: "hi" },

View File

@@ -0,0 +1,103 @@
/**
* Ultra SLM tier — wiring the ultra mode's modelPath / slmFallbackToAggressive config
* to the real model path (the llmlingua engine).
*
* Until now ultra was a pure heuristic (pruneByScore) and modelPath /
* slmFallbackToAggressive were inert config. The async entry point now routes ultra
* through the llmlingua engine when modelPath is set, falling back per
* slmFallbackToAggressive when the model is unavailable / yields no gain.
*
* The llmlingua backend is injectable (setLlmlinguaBackend), so the tier is testable
* without the real ONNX model.
*/
import { describe, it, after, afterEach } from "node:test";
import assert from "node:assert/strict";
import { applyCompressionAsync } from "../../../open-sse/services/compression/index.ts";
import { setLlmlinguaBackend } from "../../../open-sse/services/compression/engines/llmlingua/index.ts";
import { DEFAULT_ULTRA_CONFIG } from "../../../open-sse/services/compression/types.ts";
// Comfortably above the llmlingua default 2000-token floor (estimate ≈ chars / 4).
const LARGE_PROSE = "The quick brown fox jumps over the lazy dog every morning. ".repeat(260);
function body() {
return { model: "gpt-4o", messages: [{ role: "user", content: LARGE_PROSE }] };
}
function ultraOpts(ultra: Record<string, unknown>) {
// Only config.ultra is read by the ultra SLM tier; the rest of CompressionConfig is unused here.
return { config: { ultra: { ...DEFAULT_ULTRA_CONFIG, ...ultra } } } as unknown as Parameters<
typeof applyCompressionAsync
>[2];
}
let backendCalls = 0;
function trackingCompressingBackend(text: string): Promise<string> {
backendCalls++;
return Promise.resolve(text.slice(0, Math.max(1, Math.floor(text.length / 3))));
}
function identityBackend(text: string): Promise<string> {
backendCalls++;
return Promise.resolve(text); // no gain → llmlingua reports compressed:false
}
function throwingBackend(_text: string): Promise<string> {
backendCalls++;
return Promise.reject(new Error("model unavailable"));
}
afterEach(() => {
backendCalls = 0;
});
after(() => setLlmlinguaBackend(null));
function techniques(stats: unknown): string[] {
return ((stats as { techniquesUsed?: string[] } | null)?.techniquesUsed ?? []) as string[];
}
describe("ultra SLM tier — modelPath routes through llmlingua", () => {
it("runs the SLM tier when modelPath is set and the model compresses", async () => {
setLlmlinguaBackend(trackingCompressingBackend);
const result = await applyCompressionAsync(
body(),
"ultra",
ultraOpts({ modelPath: "/models/fake.onnx", compressionRate: 0.5 })
);
assert.equal(backendCalls > 0, true, "backend was consulted");
assert.equal(result.compressed, true);
assert.equal((result.stats as { mode?: string } | null)?.mode, "ultra");
assert.ok(techniques(result.stats).includes("ultra-slm"), "tagged as the ultra SLM tier");
});
it("falls back to aggressive when the model yields no gain and slmFallbackToAggressive is on", async () => {
setLlmlinguaBackend(identityBackend);
const result = await applyCompressionAsync(
body(),
"ultra",
ultraOpts({ modelPath: "/models/fake.onnx", slmFallbackToAggressive: true })
);
assert.ok(techniques(result.stats).includes("aggressive"), "fell back to aggressive");
assert.ok(!techniques(result.stats).includes("ultra-slm"));
});
it("falls back to the heuristic when the model fails and slmFallbackToAggressive is off", async () => {
setLlmlinguaBackend(throwingBackend);
const result = await applyCompressionAsync(
body(),
"ultra",
ultraOpts({ modelPath: "/models/fake.onnx", slmFallbackToAggressive: false })
);
const techs = techniques(result.stats);
assert.equal((result.stats as { mode?: string } | null)?.mode, "ultra");
assert.ok(techs.includes("ultra"), "heuristic ultra ran");
assert.ok(!techs.includes("ultra-slm"), "not the SLM tier");
assert.ok(!techs.includes("aggressive"), "not the aggressive fallback");
});
it("uses the heuristic and never touches the model when modelPath is unset", async () => {
setLlmlinguaBackend(throwingBackend); // would blow up if (wrongly) consulted
const result = await applyCompressionAsync(body(), "ultra", ultraOpts({ modelPath: "" }));
assert.equal(backendCalls, 0, "model not consulted without modelPath");
assert.equal((result.stats as { mode?: string } | null)?.mode, "ultra");
assert.ok(!techniques(result.stats).includes("ultra-slm"));
});
});

View File

@@ -6,11 +6,7 @@ import {
STOPWORDS,
FORCE_PRESERVE_RE,
} from "../../../open-sse/services/compression/ultraHeuristic.ts";
import {
ultraCompress,
createSLMStub,
type SLMInterface,
} from "../../../open-sse/services/compression/ultra.ts";
import { ultraCompress } from "../../../open-sse/services/compression/ultra.ts";
import type { UltraConfig } from "../../../open-sse/services/compression/types.ts";
describe("scoreToken", () => {
@@ -255,35 +251,3 @@ describe("ultraCompress", () => {
assert.strictEqual(result.stats.savingsPercent, 0);
});
});
describe("createSLMStub", () => {
it("should return object with compress function", () => {
const stub = createSLMStub();
assert(stub);
assert(typeof stub.compress === "function");
});
it("stub.compress should return a string", async () => {
const stub = createSLMStub();
const result = await stub.compress("hello world", 0.5);
assert(typeof result === "string");
});
it("stub.compress result should be <= input length", async () => {
const stub = createSLMStub();
const input = "the quick brown fox jumps over the lazy dog";
const result = await stub.compress(input, 0.5);
assert(result.length <= input.length);
});
it("stub.compress on empty string should return empty", async () => {
const stub = createSLMStub();
const result = await stub.compress("", 0.5);
assert.strictEqual(result, "");
});
it("stub should have a name or identifier", () => {
const stub = createSLMStub();
assert(stub !== null && typeof stub === "object");
});
});

View File

@@ -43,12 +43,25 @@ function seedConnections(count = 8) {
}
}
async function waitForFile(filePath) {
for (let attempt = 0; attempt < 20; attempt++) {
if (fs.existsSync(filePath)) return;
// backupDbFile() kicks off db.backup() fire-and-forget — better-sqlite3 creates
// the destination file when the page copy STARTS, not when it finishes. Waiting
// on file existence alone races the copy: under load listDbBackups() can open a
// partially-written backup and read connectionCount as 0 (flake repro: under CPU
// contention the backup file existed but the seeded rows were not yet copied →
// connectionCount 0 ≠ 12). Wait for the real completion condition instead — the
// backup actually contains the seeded connections. The 30s ceiling only bounds
// the failure case; the green path returns as soon as the data lands (sub-second
// in practice — the wide ceiling absorbs heavy CI page-copy contention).
async function waitForBackupEntry(filename, expectedConnectionCount, timeoutMs = 30000) {
const startedAt = Date.now();
while (Date.now() - startedAt < timeoutMs) {
const entry = (await backupDb.listDbBackups()).find((backup) => backup.id === filename);
if (entry && entry.connectionCount === expectedConnectionCount) return entry;
await new Promise((resolve) => setTimeout(resolve, 50));
}
throw new Error(`Timed out waiting for file: ${filePath}`);
throw new Error(
`Timed out waiting for backup ${filename} to finish copying ${expectedConnectionCount} connections`
);
}
function makeDbBackupsJsonRequest(method: string, body: unknown): NextRequest {
@@ -75,13 +88,12 @@ test("backupDbFile creates manual backups and listDbBackups returns metadata", a
assert.ok(result);
const backupPath = path.join(core.DB_BACKUPS_DIR, result.filename);
await waitForFile(backupPath);
// Wait for the async backup to finish copying the 12 seeded connections, not
// merely for the destination file to appear (see waitForBackupEntry).
const entry = await waitForBackupEntry(result.filename, 12);
const backups = await backupDb.listDbBackups();
assert.equal(backups.length >= 1, true);
assert.equal(backups[0].reason, "manual");
assert.equal(backups[0].connectionCount, 12);
assert.equal(entry.reason, "manual");
assert.equal(entry.connectionCount, 12);
assert.equal(fs.existsSync(backupPath), true);
});

View File

@@ -0,0 +1,306 @@
import test from "node:test";
import assert from "node:assert/strict";
import fs from "node:fs";
// Static guards for the shared visual identity (Phase 1: graph-paper grid wallpaper).
// These lock in the cross-product design contract so an accidental edit can't silently
// remove the grid or re-introduce the opaque wrapper that hides it. See design.md.
const globalsCss = fs.readFileSync(new URL("../../src/app/globals.css", import.meta.url), "utf8");
const dashboardLayout = fs.readFileSync(
new URL("../../src/shared/components/layouts/DashboardLayout.tsx", import.meta.url),
"utf8"
);
test("globals.css defines the grid wallpaper tokens for both themes", () => {
// light (opacity tuned up from the site's 0.045 so the grid is visible on the
// dense dashboard — see the token comment in globals.css)
assert.match(globalsCss, /--grid-line:\s*rgba\(0,\s*0,\s*0,\s*0\.07\)/);
// dark
assert.match(globalsCss, /--grid-line:\s*rgba\(255,\s*255,\s*255,\s*0\.06\)/);
// size (shrunk ~30% from 46px for a tighter grid) + alternating-section overlay
assert.match(globalsCss, /--grid-size:\s*32px/);
assert.match(globalsCss, /--section-alt:\s*rgba\(0,\s*0,\s*0,\s*0\.022\)/);
assert.match(globalsCss, /--section-alt:\s*rgba\(255,\s*255,\s*255,\s*0\.018\)/);
});
test("globals.css renders the grid via a body::before fixed layer", () => {
// The pseudo-element must exist and be the grid renderer.
const before = globalsCss.slice(globalsCss.indexOf("body::before"));
assert.ok(before.length > 0, "body::before rule is present");
assert.match(before, /position:\s*fixed/);
assert.match(before, /z-index:\s*-1/);
assert.match(before, /pointer-events:\s*none/);
assert.match(before, /linear-gradient\(to right,\s*var\(--grid-line\) 1px, transparent 1px\)/);
assert.match(before, /linear-gradient\(to bottom,\s*var\(--grid-line\) 1px, transparent 1px\)/);
assert.match(before, /background-size:\s*var\(--grid-size\) var\(--grid-size\)/);
});
test("globals.css adds the shared identity tokens", () => {
assert.match(globalsCss, /--surface-2:\s*#f5f5fa/); // light
assert.match(globalsCss, /--surface-2:\s*#1c2230/); // dark
assert.match(globalsCss, /--radius:\s*14px/);
assert.match(
globalsCss,
/--grad-brand:\s*linear-gradient\(135deg,\s*var\(--color-primary\),\s*var\(--color-accent-light\)\)/
);
// exposed to Tailwind as bg-surface-2 for later phases
assert.match(globalsCss, /--color-surface-2:\s*var\(--surface-2\)/);
});
test("DashboardLayout wrapper stays transparent so the grid shows through", () => {
// Regression guard: the outer shell must NOT paint an opaque bg over the body grid.
assert.ok(
!dashboardLayout.includes("overflow-hidden bg-bg"),
"DashboardLayout outer wrapper must not use bg-bg (it would hide the grid wallpaper)"
);
assert.ok(
dashboardLayout.includes('className="flex h-dvh min-h-0 w-full overflow-hidden"'),
"DashboardLayout outer wrapper is present and transparent"
);
});
// ── Phase 2: primitives adopt the shared radius scale, brand gradient & border token ──
const read = (p: string) => fs.readFileSync(new URL(p, import.meta.url), "utf8");
test("globals.css exposes the semantic radius utilities", () => {
assert.match(globalsCss, /--radius-control:\s*9px/); // :root value
assert.match(globalsCss, /--radius-card:\s*var\(--radius\)/); // @theme → rounded-card (14px)
assert.match(globalsCss, /--radius-control:\s*var\(--radius-control\)/); // @theme → rounded-control
});
test("Button uses the brand gradient + accent variant + control radius", () => {
const button = read("../../src/shared/components/Button.tsx");
assert.match(button, /primary:\s*"bg-\[image:var\(--grad-brand\)\]/);
assert.match(button, /accent:\s*"bg-accent/);
assert.ok(
!button.includes("from-primary to-primary-hover"),
"the flat red→red gradient is replaced by --grad-brand"
);
assert.ok(button.includes("rounded-control"), "button sizes use the control radius");
});
test("Card / Modal / Input / Select adopt the radius scale and border token", () => {
const card = read("../../src/shared/components/Card.tsx");
const modal = read("../../src/shared/components/Modal.tsx");
const input = read("../../src/shared/components/Input.tsx");
const select = read("../../src/shared/components/Select.tsx");
assert.ok(card.includes("border border-border"), "card uses the --color-border token");
assert.ok(card.includes("rounded-card"), "card uses rounded-card (14px)");
assert.ok(!card.includes("border-black/5"), "the under-weight /5 border is gone");
assert.ok(modal.includes("rounded-card"), "modal uses rounded-card");
assert.ok(input.includes("rounded-control"), "input uses rounded-control (9px)");
assert.ok(select.includes("rounded-control"), "select uses rounded-control (9px)");
});
// ── Phase 3 (partial): status hex centralized + mono font token ──
test("status colors come from one canonical module", () => {
const mod = read("../../src/shared/constants/statusColors.ts");
assert.match(mod, /success:\s*"#22c55e"/);
assert.match(mod, /warning:\s*"#f59e0b"/);
assert.match(mod, /error:\s*"#ef4444"/);
const edges = read("../../src/shared/components/flow/edgeStyles.ts");
const badge = read("../../src/shared/components/TokenHealthBadge.tsx");
assert.ok(
edges.includes('from "@/shared/constants/statusColors"'),
"edgeStyles imports the module"
);
assert.ok(edges.includes("STATUS_HEX.success"), "edgeStyles uses STATUS_HEX, not a literal");
assert.ok(!edges.includes('"#22c55e"'), "edgeStyles no longer hardcodes the success hex");
assert.ok(badge.includes("STATUS_HEX.success"), "TokenHealthBadge uses STATUS_HEX");
assert.ok(!badge.includes('"#22c55e"'), "TokenHealthBadge no longer hardcodes the success hex");
});
test("globals.css defines a monospace token (site parity)", () => {
assert.match(globalsCss, /--font-mono:\s*ui-monospace/);
});
test("DataTable is theme-aware via --table-* tokens (dark = the exact old values)", () => {
// The dark token values must equal the rgba the component used to hardcode, so dark
// stays byte-identical while light gets fixed.
assert.match(globalsCss, /--table-header-bg:\s*rgba\(15,\s*15,\s*25,\s*0\.95\)/); // dark
assert.match(globalsCss, /--table-row-zebra:\s*rgba\(255,\s*255,\s*255,\s*0\.02\)/); // dark
assert.match(globalsCss, /--table-row-hover:\s*rgba\(255,\s*255,\s*255,\s*0\.04\)/); // dark
assert.match(globalsCss, /--table-cell-border:\s*rgba\(255,\s*255,\s*255,\s*0\.04\)/); // dark
assert.match(globalsCss, /--table-header-bg:\s*rgba\(249,\s*249,\s*251,\s*0\.95\)/); // light fix
const dt = read("../../src/shared/components/DataTable.tsx");
assert.ok(dt.includes("var(--table-header-bg)"), "header uses the token");
assert.ok(dt.includes("var(--table-row-zebra)"), "zebra uses the token");
assert.ok(dt.includes("var(--color-border)"), "header border uses the brand token");
assert.ok(
!/rgba\(|#[0-9a-fA-F]{3,6}/.test(dt),
"DataTable no longer hardcodes any color literal"
);
assert.ok(
!dt.includes("--text-secondary") && !dt.includes("--bg-table-header"),
"the dead var fallbacks are gone"
);
});
// ── Phase 4 (safe additives): cn() merge + Checkbox / Textarea primitives ──
test("cn() dedupes conflicting Tailwind classes via tailwind-merge", () => {
const cnSrc = read("../../src/shared/utils/cn.ts");
assert.match(cnSrc, /from "tailwind-merge"/);
assert.match(cnSrc, /from "clsx"/);
assert.match(cnSrc, /twMerge\(clsx\(/);
});
test("Checkbox + Textarea primitives exist and are exported", () => {
const barrel = read("../../src/shared/components/index.tsx");
assert.ok(barrel.includes('export { default as Checkbox } from "./Checkbox"'));
assert.ok(barrel.includes('export { default as Textarea } from "./Textarea"'));
const checkbox = read("../../src/shared/components/Checkbox.tsx");
const textarea = read("../../src/shared/components/Textarea.tsx");
assert.ok(
checkbox.includes("accent-[var(--color-accent)]"),
"checkbox uses the brand accent token"
);
assert.ok(textarea.includes("rounded-control"), "textarea uses the control radius");
});
// ── C6: form controls share one accent focus ring (separate from the red error state) ──
test("form controls focus on the accent ring, not the red primary", () => {
// The global :focus-visible ring already uses --color-accent. Align the form
// controls to it so keyboard focus is one consistent violet everywhere and the
// red focus ring no longer collides with the red error state.
assert.match(globalsCss, /--focus-ring:.*var\(--color-accent\)/);
for (const name of ["Input", "Select", "Textarea", "Toggle", "Checkbox"]) {
const src = read(`../../src/shared/components/${name}.tsx`);
assert.ok(/ring-accent\/30/.test(src), `${name} uses the accent focus ring`);
assert.ok(
!/(?:focus|focus-visible):ring-primary\/30/.test(src),
`${name} no longer uses the red primary focus ring`
);
// the red error ring stays intact where the control has an error state
if (src.includes("error")) {
assert.ok(src.includes("ring-red-500/20"), `${name} keeps the red error ring`);
}
}
});
// ── Phase 5: the grid reaches every standalone screen + the shell is fluid up to 4K ──
test("standalone full-screen pages stay transparent so the grid shows through", () => {
// Same contract as the DashboardLayout shell: a full-viewport wrapper must not paint
// an opaque bg-bg over the body::before grid. These are the auth / error / legal /
// status / onboarding screens that render outside the dashboard layout — the ones the
// first grid phase missed. (?![\w-]) keeps bg-bg-alt / bg-bg-main from matching.
const pages = [
"../../src/app/login/page.tsx",
"../../src/app/forgot-password/page.tsx",
"../../src/app/callback/page.tsx",
"../../src/app/maintenance/page.tsx",
"../../src/app/offline/page.tsx",
"../../src/app/status/page.tsx",
"../../src/app/terms/page.tsx",
"../../src/app/privacy/page.tsx",
"../../src/app/(dashboard)/dashboard/onboarding/page.tsx",
"../../src/shared/components/ErrorPageScaffold.tsx",
];
for (const p of pages) {
const src = read(p);
assert.ok(
!/min-h-screen[^"]*\bbg-bg(?![\w-])/.test(src) &&
!/\bbg-bg(?![\w-])[^"]*min-h-screen/.test(src),
`${p} must not paint bg-bg on a min-h-screen wrapper (it would hide the grid)`
);
}
});
test("DashboardLayout content shell is fluid up to ~4K before centering", () => {
// The inner content wrapper grows with the viewport up to a 4K cap (3840px) instead
// of the old max-w-7xl (1280px) that left wide side gutters on large monitors.
assert.ok(
dashboardLayout.includes("max-w-[3840px] mx-auto"),
"content wrapper caps at 3840px (4K) and centers only beyond that"
);
assert.ok(!dashboardLayout.includes("max-w-7xl"), "the old 1280px max-w-7xl cap is gone");
});
// ── Phase 6: data tables are opaque content surfaces so the grid never bleeds through ──
//
// The dashboard content area is intentionally transparent (the body::before grid shows
// through as a wallpaper). A data table whose nearest ancestor is NOT an opaque surface
// would let the grid bleed through its transparent even-rows / low-alpha zebra rows.
// Cards already carry bg-surface; these guards cover the shared table primitives and the
// tables that render *without* a Card. Tables verified to live inside a <Card>/Modal are
// intentionally left untouched (bg-surface there would be a redundant no-op).
test("DataTable primitive paints its own opaque surface", () => {
const dt = read("../../src/shared/components/DataTable.tsx");
assert.ok(
dt.includes("var(--color-surface)"),
"DataTable scroll container is opaque (its even rows are transparent by design)"
);
});
test("log table cards are opaque (no semi-transparent bg-black tint)", () => {
// bg-black/5|20 on a <Card> wins over the Card's own bg-surface via tailwind-merge,
// turning the big log tables ~95% transparent — the grid bled straight through them.
for (const p of [
"../../src/shared/components/ProxyLogger.tsx",
"../../src/shared/components/RequestLoggerV2.tsx",
]) {
const src = read(p);
assert.ok(
!src.includes("bg-black/5") && !src.includes("bg-black/20"),
`${p} must not tint the table Card with bg-black/5|20 (it drops the Card's opaque surface)`
);
assert.ok(src.includes("bg-surface"), `${p} table card uses the opaque bg-surface`);
}
});
test("card-less data tables wrap their table in an opaque surface", () => {
const expect = [
[
"../../src/app/(dashboard)/dashboard/batch/BatchListTab.tsx",
"rounded-xl border border-[var(--color-border)] bg-[var(--color-surface)]",
],
[
"../../src/app/(dashboard)/dashboard/batch/FilesListTab.tsx",
"rounded-xl border border-[var(--color-border)] bg-[var(--color-surface)]",
],
[
"../../src/app/(dashboard)/dashboard/cache/components/CacheEntriesTab.tsx",
"overflow-x-auto bg-surface",
],
[
"../../src/app/(dashboard)/dashboard/settings/components/proxy/FreePoolTab.tsx",
"rounded border border-border bg-surface",
],
[
"../../src/app/(dashboard)/dashboard/tools/agent-bridge/components/ModelMappingTable.tsx",
"overflow-hidden bg-surface",
],
[
"../../src/app/(dashboard)/dashboard/tools/traffic-inspector/components/shared/HeaderTable.tsx",
"bg-surface",
],
];
for (const [p, needle] of expect) {
const src = read(p);
assert.ok(
src.includes(needle),
`${p} must include "${needle}" so the table is opaque over the grid`
);
}
});
test("semi-transparent cache table boxes are now opaque", () => {
for (const p of [
"../../src/app/(dashboard)/dashboard/cache/components/ReasoningCacheTab.tsx",
"../../src/app/(dashboard)/dashboard/cache/page.tsx",
]) {
const src = read(p);
assert.ok(
!src.includes("bg-surface/35"),
`${p} table box no longer uses the ~35%-opaque bg-surface/35 (the grid bled through it)`
);
}
});

View File

@@ -0,0 +1,38 @@
import { describe, it } from "node:test";
import assert from "node:assert";
// 2026-06-17 free-tier refresh + 2026-06-18 live re-verification: providers whose free tier is
// confirmed gone have hasFree flipped to false so the dashboard / onboarding no longer advertises a
// free tier that does not exist. The budget catalog already dropped them. The 2026-06-18 batch
// (gitlawb, gitlawb-gmi, aimlapi, yi) was each re-verified against the official source before flipping
// (aimlapi docs: "The Free Tier is currently paused"; gitlawb GitHub issue #1345: MiMo revoked).
describe("2026 discontinued free tiers — providers.ts hasFree reconciliation", () => {
it("APIKEY_PROVIDERS dead tiers no longer advertise a free tier", async () => {
const { APIKEY_PROVIDERS } = await import("../../src/shared/constants/providers.ts");
for (const id of ["chutes", "kluster", "glhf", "phind", "gitlawb", "gitlawb-gmi", "aimlapi", "yi"]) {
const p = (APIKEY_PROVIDERS as Record<string, { hasFree?: boolean }>)[id];
assert.ok(p, `${id} should still exist in APIKEY_PROVIDERS (provider not removed, only its free flag)`);
assert.strictEqual(p.hasFree, false, `${id} should have hasFree:false (discontinued in 2026)`);
}
});
it("WEB_COOKIE_PROVIDERS phind (web/cookie path) no longer advertises a free tier", async () => {
const { WEB_COOKIE_PROVIDERS } = await import("../../src/shared/constants/providers.ts");
const p = (WEB_COOKIE_PROVIDERS as Record<string, { hasFree?: boolean }>)["phind"];
assert.ok(p, "phind should still exist in WEB_COOKIE_PROVIDERS");
assert.strictEqual(p.hasFree, false, "phind web/cookie should have hasFree:false (phind.com shut down 2026-01)");
});
it("intentionally-kept providers still advertise free (genuinely free / ToS-flagged, not flipped)", async () => {
const { NOAUTH_PROVIDERS, APIKEY_PROVIDERS } = await import("../../src/shared/constants/providers.ts");
// theoldllm is a keyless, no-signup web chat (genuinely free, just no catalogable API tier) — kept.
// iflytek/sparkdesk stay hasFree:true but carry a ToS-caution freeNote (Spark Lite is free, the ToS
// restricts proxy/relay use). gitlawb/gitlawb-gmi/aimlapi/yi were re-verified dead 2026-06-18 and are
// asserted false above — keeping them out of this list guards against a silent re-flip-to-true.
const noauth = NOAUTH_PROVIDERS as Record<string, { hasFree?: boolean }>;
const apikey = APIKEY_PROVIDERS as Record<string, { hasFree?: boolean; freeNote?: string }>;
assert.strictEqual(noauth["theoldllm"]?.hasFree, true, "theoldllm intentionally kept hasFree:true");
assert.strictEqual(apikey["iflytek"]?.hasFree, true, "iflytek kept free with ToS-caution note");
assert.match(apikey["iflytek"]?.freeNote ?? "", /caution/i, "iflytek freeNote should carry a caution");
});
});

View File

@@ -0,0 +1,76 @@
import test from "node:test";
import assert from "node:assert/strict";
import fs from "node:fs";
import os from "node:os";
import path from "node:path";
// Isolate the DB to a temp dir BEFORE importing any module that opens it.
const TEST_DATA_DIR = fs.mkdtempSync(path.join(os.tmpdir(), "omniroute-embed-telemetry-"));
process.env.DATA_DIR = TEST_DATA_DIR;
const core = await import("../../src/lib/db/core.ts");
const providersDb = await import("../../src/lib/db/providers.ts");
const { createEmbeddingResponse } = await import("../../src/lib/embeddings/service.ts");
const { OMNIROUTE_RESPONSE_HEADERS } = await import("../../src/shared/constants/headers.ts");
test.after(() => {
core.resetDbInstance();
fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true });
});
test("createEmbeddingResponse emits X-OmniRoute-* cost telemetry headers on success", async () => {
// Seed a credentialed apikey connection so getProviderCredentials resolves and
// the success path runs (no real upstream is hit — fetch is mocked below).
await providersDb.createProviderConnection({
provider: "mistral",
authType: "apikey",
name: "Test Mistral",
apiKey: "mistral-test-key",
});
const PROMPT_TOKENS = 7;
const originalFetch = globalThis.fetch;
globalThis.fetch = async () =>
new Response(
JSON.stringify({
data: [{ object: "embedding", embedding: [0.1, 0.2], index: 0 }],
usage: { prompt_tokens: PROMPT_TOKENS, total_tokens: PROMPT_TOKENS },
}),
{ status: 200, headers: { "content-type": "application/json" } }
);
try {
const res = await createEmbeddingResponse({
model: "mistral/mistral-embed",
input: "hello world",
});
assert.equal(res.status, 200, "embedding success path should return 200");
const cost = res.headers.get(OMNIROUTE_RESPONSE_HEADERS.responseCost);
assert.ok(cost, "X-OmniRoute-Response-Cost header must be present");
assert.match(
cost,
/^\d+\.\d{10}$/,
`X-OmniRoute-Response-Cost must be a 10-decimal cost string, got "${cost}"`
);
assert.equal(
res.headers.get(OMNIROUTE_RESPONSE_HEADERS.tokensIn),
String(PROMPT_TOKENS),
"X-OmniRoute-Tokens-In must equal the upstream prompt_tokens"
);
const version = res.headers.get(OMNIROUTE_RESPONSE_HEADERS.version);
assert.ok(
version && version.length > 0,
"X-OmniRoute-Version header must be present and non-empty"
);
// Sanity: the body is still the embeddings payload, unchanged.
const body = await res.json();
assert.deepEqual(body.usage, { prompt_tokens: PROMPT_TOKENS, total_tokens: PROMPT_TOKENS });
} finally {
globalThis.fetch = originalFetch;
}
});

View File

@@ -0,0 +1,141 @@
import { test } from "node:test";
import assert from "node:assert/strict";
import {
isFreeModel,
providerHasFreeModels,
selectModelsForImport,
sortModelsFreeFirst,
} from "@/shared/utils/freeModels";
import { FREE_MODEL_BUDGETS } from "@omniroute/open-sse/config/freeModelCatalog";
test("providerHasFreeModels: true for a provider in the free catalog", () => {
assert.equal(providerHasFreeModels("openrouter"), true);
});
test("providerHasFreeModels: false for an unknown provider", () => {
assert.equal(providerHasFreeModels("totally-not-a-real-provider-xyz"), false);
});
test("providerHasFreeModels: resolves a provider alias to its canonical id", () => {
// "ollamacloud" is the dashboard alias for the canonical id "ollama-cloud".
assert.equal(providerHasFreeModels("ollamacloud"), true);
});
test("isFreeModel: catalog membership works when called with the provider alias", () => {
// deepseek-v4-pro is a free ollama-cloud model; the list view calls with the alias.
assert.equal(isFreeModel("ollamacloud", { id: "deepseek-v4-pro" }), true);
});
test("isFreeModel: model id ending in :free is free", () => {
assert.equal(isFreeModel("openrouter", { id: "deepseek/deepseek-r1:free" }), true);
});
test("isFreeModel: zero prompt+completion price is free", () => {
assert.equal(
isFreeModel("openrouter", { id: "x/y", pricing: { prompt: "0", completion: "0" } }),
true
);
});
test("isFreeModel: a priced model is NOT free", () => {
assert.equal(
isFreeModel("openrouter", {
id: "openai/gpt-4o",
pricing: { prompt: "0.0000025", completion: "0.00001" },
}),
false
);
});
test("isFreeModel: a model with no pricing and no :free suffix is NOT free", () => {
assert.equal(isFreeModel("openrouter", { id: "some/paid-model" }), false);
});
test("isFreeModel: a model id listed in the free catalog for that provider is free", () => {
const sample = FREE_MODEL_BUDGETS[0];
assert.equal(isFreeModel(sample.provider, { id: sample.modelId }), true);
});
test("selectModelsForImport: passthrough when importFreeOnly is false", () => {
const models = [
{ id: "a:free" },
{ id: "b", pricing: { prompt: "0.01", completion: "0.02" } },
];
const result = selectModelsForImport("openrouter", models, false);
assert.equal(result.models.length, 2);
assert.equal(result.freeFilterEmpty, false);
});
test("selectModelsForImport: keeps only free models when importFreeOnly is true", () => {
const models = [
{ id: "free-one:free" },
{ id: "paid-one", pricing: { prompt: "0.01", completion: "0.02" } },
{ id: "free-two", pricing: { prompt: "0", completion: "0" } },
];
const result = selectModelsForImport("openrouter", models, true);
assert.deepEqual(
result.models.map((m) => m.id),
["free-one:free", "free-two"]
);
assert.equal(result.freeFilterEmpty, false);
});
test("selectModelsForImport: flags freeFilterEmpty when models exist but none are free", () => {
const models = [{ id: "paid", pricing: { prompt: "0.01", completion: "0.02" } }];
const result = selectModelsForImport("openrouter", models, true);
assert.equal(result.models.length, 0);
assert.equal(result.freeFilterEmpty, true);
});
test("selectModelsForImport: empty fetched list is not flagged as freeFilterEmpty", () => {
const result = selectModelsForImport("openrouter", [], true);
assert.equal(result.models.length, 0);
assert.equal(result.freeFilterEmpty, false);
});
test("sortModelsFreeFirst: free models come before paid ones", () => {
const items = [
{ id: "z-paid", isFree: false },
{ id: "a-free", isFree: true },
{ id: "m-paid", isFree: false },
{ id: "b-free", isFree: true },
];
const sorted = sortModelsFreeFirst(items, { isFree: (m) => m.isFree, key: (m) => m.id });
assert.deepEqual(
sorted.map((m) => m.id),
["a-free", "b-free", "m-paid", "z-paid"]
);
});
test("sortModelsFreeFirst: deterministic (alphabetical) within each group, regardless of input order", () => {
const a = sortModelsFreeFirst(
[
{ id: "c", isFree: true },
{ id: "a", isFree: true },
{ id: "b", isFree: true },
],
{ isFree: (m) => m.isFree, key: (m) => m.id }
);
// Re-sorting a shuffled copy yields the same order — stable across refetch/re-render.
const b = sortModelsFreeFirst(
[
{ id: "b", isFree: true },
{ id: "c", isFree: true },
{ id: "a", isFree: true },
],
{ isFree: (m) => m.isFree, key: (m) => m.id }
);
assert.deepEqual(a.map((m) => m.id), ["a", "b", "c"]);
assert.deepEqual(b.map((m) => m.id), ["a", "b", "c"]);
});
test("sortModelsFreeFirst: does not mutate the input array", () => {
const items = [
{ id: "z", isFree: false },
{ id: "a", isFree: true },
];
const before = items.map((m) => m.id);
sortModelsFreeFirst(items, { isFree: (m) => m.isFree, key: (m) => m.id });
assert.deepEqual(items.map((m) => m.id), before);
});

View File

@@ -0,0 +1,97 @@
import { test } from "node:test";
import assert from "node:assert/strict";
import { parseDuckDuckGoLite } from "../../open-sse/services/freeWebSearch.ts";
// Real DuckDuckGo lite shape (captured from lite.duckduckgo.com/lite/):
// double-quoted href BEFORE single-quoted class='result-link', direct URLs,
// <b> highlight tags inside titles/snippets, link[i] aligns with snippet[i].
const REAL_LITE_HTML = `
<table>
<tr>
<td valign="top">1.&nbsp;</td>
<td>
<a rel="nofollow" href="https://platform.claude.com/docs/en/api/overview" class='result-link'>API overview - <b>Claude</b> API Docs - Anthropic</a>
</td>
</tr>
<tr>
<td>&nbsp;&nbsp;&nbsp;</td>
<td class='result-snippet'><b>Claude</b> <b>API</b> Documentation. New to Claude?</td>
</tr>
<tr>
<td valign="top">2.&nbsp;</td>
<td>
<a rel="nofollow" href="https://www.anthropic.com/api" class='result-link'>Claude Platform | Claude - Anthropic</a>
</td>
</tr>
<tr>
<td>&nbsp;&nbsp;&nbsp;</td>
<td class='result-snippet'>Build with the most capable models.</td>
</tr>
</table>`;
test("parseDuckDuckGoLite extracts aligned title/url/snippet from real lite HTML", () => {
const results = parseDuckDuckGoLite(REAL_LITE_HTML);
assert.equal(results.length, 2);
assert.equal(results[0].url, "https://platform.claude.com/docs/en/api/overview");
assert.equal(results[0].title, "API overview - Claude API Docs - Anthropic");
assert.ok(results[0].snippet.includes("Claude API Documentation"));
assert.equal(results[1].url, "https://www.anthropic.com/api");
assert.equal(results[1].title, "Claude Platform | Claude - Anthropic");
assert.ok(results[1].snippet.includes("most capable models"));
});
test("parseDuckDuckGoLite strips <b> highlight tags and collapses whitespace", () => {
const results = parseDuckDuckGoLite(REAL_LITE_HTML);
assert.doesNotMatch(results[0].title, /<b>|<\/b>/);
assert.doesNotMatch(results[0].snippet, /<b>|<\/b>/);
});
test("parseDuckDuckGoLite decodes a uddg redirect href (defensive)", () => {
const html = `<a rel="nofollow" href="//duckduckgo.com/l/?uddg=https%3A%2F%2Fexample.com%2Fa%3Fb%3D1&rut=x" class='result-link'>Example</a>
<td class='result-snippet'>snippet</td>`;
const results = parseDuckDuckGoLite(html);
assert.equal(results[0].url, "https://example.com/a?b=1");
});
test("parseDuckDuckGoLite upgrades protocol-relative hrefs to https", () => {
const html = `<a href="//example.org/path" class='result-link'>Proto rel</a>
<td class='result-snippet'>s</td>`;
const results = parseDuckDuckGoLite(html);
assert.equal(results[0].url, "https://example.org/path");
});
test("parseDuckDuckGoLite returns [] when there are no result links", () => {
assert.deepEqual(parseDuckDuckGoLite("<html><body>no results</body></html>"), []);
assert.deepEqual(parseDuckDuckGoLite(""), []);
});
test("parseDuckDuckGoLite drops non-http(s) result URLs (javascript:/data:/file:)", () => {
const html = `<a href="javascript:alert(1)" class='result-link'>XSS</a>
<td class='result-snippet'>bad</td>
<a href="https://ok.example.com" class='result-link'>Safe</a>
<td class='result-snippet'>good</td>`;
const results = parseDuckDuckGoLite(html);
assert.equal(results.length, 1, "the javascript: link must be discarded");
assert.equal(results[0].url, "https://ok.example.com");
assert.doesNotMatch(JSON.stringify(results), /javascript:/);
});
test("parseDuckDuckGoLite is bounded on adversarial HTML (no catastrophic backtracking)", () => {
// Many unclosed result-link anchors + a huge filler tail must return promptly.
const pathological =
`<a href="https://x.com" class='result-link'>`.repeat(2000) + "x".repeat(2_000_000);
const start = Date.now();
const results = parseDuckDuckGoLite(pathological);
assert.ok(Date.now() - start < 1000, "must not hang on adversarial HTML");
assert.ok(Array.isArray(results));
});
test("parseDuckDuckGoLite tolerates a missing snippet (empty string, not crash)", () => {
const html = `<a href="https://x.com" class='result-link'>Only a link</a>`;
const results = parseDuckDuckGoLite(html);
assert.equal(results.length, 1);
assert.equal(results[0].snippet, "");
});

View File

@@ -0,0 +1,109 @@
/**
* Regression test for #4177 — Gemini mid-stream error silently swallowed.
*
* When the upstream Gemini SSE stream emits a JSON error object
* (e.g. `{"error":{"code":503,"message":"...","status":"UNAVAILABLE"}}`) instead of a
* `candidates` payload — typically after some partial reasoning content — the
* translator must surface it as `state.upstreamError` so the streaming pipeline can
* error the response out (and trigger combo fallback) rather than ending the stream
* with a default `finish_reason: "stop"` and a misleading HTTP 200.
*/
import test from "node:test";
import assert from "node:assert/strict";
const { geminiToOpenAIResponse } =
await import("../../open-sse/translator/response/gemini-to-openai.ts");
type StreamState = {
toolCalls: Map<string, unknown>;
messageId?: string;
model?: string;
upstreamError?: { status: number; type: string; code: string; message: string };
};
function createStreamingState(): StreamState {
return {
toolCalls: new Map(),
};
}
test("#4177 Gemini mid-stream 503 UNAVAILABLE is surfaced as upstreamError, not dropped", () => {
const state = createStreamingState();
const result = geminiToOpenAIResponse(
{
error: {
code: 503,
message:
"This model is currently experiencing high demand. Spikes in demand are usually temporary. Please try again later.",
status: "UNAVAILABLE",
},
},
state
);
// The error chunk produces no delta output...
assert.equal(result, null);
// ...but it MUST be recorded so stream.ts can error the stream out.
assert.ok(state.upstreamError, "expected state.upstreamError to be set for a 503 error chunk");
assert.equal(state.upstreamError.status, 503);
assert.equal(state.upstreamError.type, "server_error");
assert.equal(state.upstreamError.code, "UNAVAILABLE");
assert.match(state.upstreamError.message, /high demand/);
});
test("#4177 Gemini RESOURCE_EXHAUSTED maps to a 429 rate-limit upstreamError", () => {
const state = createStreamingState();
const result = geminiToOpenAIResponse(
{
error: {
code: 429,
message: "Resource has been exhausted (e.g. check quota).",
status: "RESOURCE_EXHAUSTED",
},
},
state
);
assert.equal(result, null);
assert.ok(state.upstreamError);
assert.equal(state.upstreamError.status, 429);
assert.equal(state.upstreamError.type, "rate_limit_error");
assert.equal(state.upstreamError.code, "RESOURCE_EXHAUSTED");
});
test("#4177 Gemini error wrapped in a `response` envelope (Antigravity/Cloud Code) is detected", () => {
const state = createStreamingState();
const result = geminiToOpenAIResponse(
{
response: {
error: { code: 503, message: "overloaded", status: "UNAVAILABLE" },
},
},
state
);
assert.equal(result, null);
assert.ok(state.upstreamError);
assert.equal(state.upstreamError.status, 503);
});
test("#4177 a valid candidate chunk does NOT set upstreamError (no false positive)", () => {
const state = createStreamingState();
const result = geminiToOpenAIResponse(
{
responseId: "resp-ok",
modelVersion: "gemini-2.5-flash",
candidates: [
{
content: { role: "model", parts: [{ text: "hello" }] },
index: 0,
},
],
usageMetadata: { promptTokenCount: 1, totalTokenCount: 2 },
},
state
);
assert.ok(result, "expected normal chunk to translate to OpenAI deltas");
assert.equal(state.upstreamError, undefined);
});

View File

@@ -10,7 +10,8 @@ describe("Gitlawb Opengateway providers", () => {
assert.strictEqual(provider.id, "gitlawb");
assert.strictEqual(provider.alias, "glb");
assert.ok(provider.name.includes("Gitlawb"));
assert.strictEqual(provider.hasFree, true);
// Free MiMo (xiaomi/mimo-v2.5) revoked 2026-05; Opengateway is now pay-as-you-go (re-verified 2026-06-18).
assert.strictEqual(provider.hasFree, false);
});
it("should have registry entry with correct baseUrl", async () => {
@@ -52,7 +53,8 @@ describe("Gitlawb Opengateway providers", () => {
assert.ok(provider, "gitlawb-gmi should exist in APIKEY_PROVIDERS");
assert.strictEqual(provider.id, "gitlawb-gmi");
assert.strictEqual(provider.alias, "glb-gmi");
assert.strictEqual(provider.hasFree, true);
// Free Nemotron promo ended 2026-06; GMI Cloud route is pay-as-you-go (re-verified 2026-06-18).
assert.strictEqual(provider.hasFree, false);
});
it("should have registry entry with gmi-cloud baseUrl", async () => {

View File

@@ -640,3 +640,44 @@ test("GlmExecutor Anthropic fallback keeps tool names unprefixed", async () => {
globalThis.fetch = originalFetch;
}
});
// Regression for #4255 — GLM-5.2+ thinking models share a single max_tokens
// budget for reasoning + response. When the client omits max_tokens, the
// executor must default to the model's full output capacity (131072) so deep
// reasoning isn't truncated by the generic GLM default (16_384). Scoped to
// GLM-5.2+ via transformForTransport — non-thinking GLM models are untouched.
test("GlmExecutor defaults GLM-5.2+ max_tokens to 131072 when the client omits it", () => {
const executor = new GlmExecutor("glm");
const body = { messages: [{ role: "user", content: "hi" }] };
const transformed = executor.transformForTransport("glm-5.2", body, false, {
apiKey: "glm-key",
}, "openai") as any;
assert.equal((body as any).max_tokens, undefined, "caller body must not be mutated");
assert.equal(transformed.max_tokens, 131072);
});
test("GlmExecutor preserves a client-supplied max_tokens for GLM-5.2+ (no override)", () => {
const executor = new GlmExecutor("glm");
const body = { messages: [{ role: "user", content: "hi" }], max_tokens: 4096 };
const transformed = executor.transformForTransport("glm-5.2", body, false, {
apiKey: "glm-key",
}, "openai") as any;
assert.equal(transformed.max_tokens, 4096);
});
test("GlmExecutor does NOT bump max_tokens for non-thinking GLM (glm-4.6)", () => {
const executor = new GlmExecutor("glm");
const body = { messages: [{ role: "user", content: "hi" }] };
const transformed = executor.transformForTransport("glm-4.6", body, false, {
apiKey: "glm-key",
}, "openai") as any;
// Stays at the generic GLM default (16_384) — never the 131072 thinking budget.
assert.notEqual(transformed.max_tokens, 131072);
assert.equal(transformed.max_tokens, 16_384);
});

View File

@@ -0,0 +1,99 @@
/**
* GPT-5 sampling guard — `stripGpt5SamplingWhenReasoning`.
*
* GPT-5 reasoning models reject non-default `temperature`/`top_p` with HTTP 400 when a
* reasoning effort is active, but GPT-5.1+ accept them again under `reasoning_effort:"none"`
* (the default). These tests pin the conditional strip on the `openai` Chat Completions
* surface: drop sampling only when reasoning is active, never for `none` / non-gpt-5 / other
* providers. Refs: litellm#27351, Azure Foundry reasoning matrix, openai-python#2072.
*/
import test from "node:test";
import assert from "node:assert/strict";
import { stripGpt5SamplingWhenReasoning } from "../../open-sse/services/gpt5SamplingGuard.ts";
test("strips temperature+top_p for openai gpt-5.x when reasoning_effort is active", () => {
const body = {
model: "gpt-5.4",
temperature: 0.7,
top_p: 0.9,
reasoning_effort: "high",
messages: [],
};
const result = stripGpt5SamplingWhenReasoning(body, "openai", "gpt-5.4");
assert.equal(result.temperature, undefined);
assert.equal(result.top_p, undefined);
assert.equal(result.reasoning_effort, "high"); // effort itself is untouched
});
test("keeps temperature when reasoning_effort=none (gpt-5.1+ non-reasoning mode)", () => {
const body = { model: "gpt-5.4", temperature: 0.7, reasoning_effort: "none", messages: [] };
const result = stripGpt5SamplingWhenReasoning(body, "openai", "gpt-5.4");
assert.equal(result.temperature, 0.7);
});
test("keeps sampling when there is no reasoning signal (default none for gpt-5.1+)", () => {
const body = { model: "gpt-5.5", temperature: 0.5, top_p: 0.8, messages: [] };
const result = stripGpt5SamplingWhenReasoning(body, "openai", "gpt-5.5");
assert.equal(result.temperature, 0.5);
assert.equal(result.top_p, 0.8);
});
test("nested reasoning.effort active also triggers the strip", () => {
const body = { model: "gpt-5.4", top_p: 0.8, reasoning: { effort: "medium" }, messages: [] };
const result = stripGpt5SamplingWhenReasoning(body, "openai", "gpt-5.4");
assert.equal(result.top_p, undefined);
});
test("model suffix -high triggers strip; -none keeps sampling", () => {
const high = stripGpt5SamplingWhenReasoning(
{ model: "gpt-5.4-high", temperature: 0.3 },
"openai",
"gpt-5.4-high"
);
assert.equal(high.temperature, undefined);
const none = stripGpt5SamplingWhenReasoning(
{ model: "gpt-5.4-none", temperature: 0.3 },
"openai",
"gpt-5.4-none"
);
assert.equal(none.temperature, 0.3);
});
test("non-openai provider is untouched (codex is guarded by the executor allowlist)", () => {
const body = { model: "gpt-5.4", temperature: 0.7, reasoning_effort: "high" };
const result = stripGpt5SamplingWhenReasoning(body, "codex", "gpt-5.4");
assert.equal(result.temperature, 0.7);
});
test("non-gpt-5 openai model is untouched (e.g. gpt-4o)", () => {
const body = { model: "gpt-4o", temperature: 0.7, reasoning_effort: "high" };
const result = stripGpt5SamplingWhenReasoning(body, "openai", "gpt-4o");
assert.equal(result.temperature, 0.7);
});
test("returns the same reference when no sampling params are present", () => {
const body = { model: "gpt-5.4", reasoning_effort: "high", messages: [] };
const result = stripGpt5SamplingWhenReasoning(body, "openai", "gpt-5.4");
assert.equal(result, body);
});
test("non-string model is a no-op", () => {
const body = { temperature: 0.7, reasoning_effort: "high" };
const result = stripGpt5SamplingWhenReasoning(body, "openai", null);
assert.equal(result.temperature, 0.7);
});
test("logs the stripped params when a logger is provided", () => {
const calls: Array<[string, string]> = [];
const log = { warn: (tag: string, message: string) => calls.push([tag, message]) };
stripGpt5SamplingWhenReasoning(
{ model: "gpt-5.4", temperature: 0.7, reasoning_effort: "high" },
"openai",
"gpt-5.4",
log
);
assert.equal(calls.length, 1);
assert.equal(calls[0][0], "PARAMS");
assert.match(calls[0][1], /temperature/);
});

View File

@@ -39,6 +39,10 @@ test("InterceptedRequestSchema — rejects invalid source enum", () => {
assert.ok(!InterceptedRequestSchema.safeParse({ ...validInterceptedRequest, source: "invalid-source" }).success);
});
test("InterceptedRequestSchema — accepts the tproxy source (decrypt capture mode)", () => {
assert.ok(InterceptedRequestSchema.safeParse({ ...validInterceptedRequest, source: "tproxy" }).success);
});
test("InterceptedRequestSchema — rejects negative requestSize", () => {
assert.ok(!InterceptedRequestSchema.safeParse({ ...validInterceptedRequest, requestSize: -1 }).success);
});

View File

@@ -0,0 +1,66 @@
import test from "node:test";
import assert from "node:assert/strict";
// Kimi K2.7 Code (released 2026-06-12) is Moonshot's coding-focused successor to
// K2.6: 1T MoE, 256K context, thinking-only (preserve_thinking forced), with a
// fixed sampling regime (temperature=1.0 / top_p=0.95). It must be advertised on
// both the OAuth coding endpoint (api.kimi.com/coding, Anthropic format — the
// path validated live on the test VPS) and the OpenAI endpoint
// (api.moonshot.ai/v1). Two ids: `kimi-k2.7-code` and `kimi-k2.7-code-highspeed`.
const { getRegistryEntry, getUnsupportedParams } = await import(
"../../open-sse/config/providerRegistry.ts"
);
const { getResolvedModelCapabilities, supportsReasoning } = await import(
"../../src/lib/modelCapabilities.ts"
);
const K27 = "kimi-k2.7-code";
const K27_HS = "kimi-k2.7-code-highspeed";
function modelIds(provider: string): string[] {
const entry = getRegistryEntry(provider);
assert.ok(entry, `${provider} registry entry must exist`);
return (entry.models ?? []).map((m) => m.id);
}
test("kimi-coding (OAuth) advertises kimi-k2.7-code + highspeed", () => {
const ids = modelIds("kimi-coding");
assert.ok(ids.includes(K27), "kimi-coding must list kimi-k2.7-code");
assert.ok(ids.includes(K27_HS), "kimi-coding must list kimi-k2.7-code-highspeed");
assert.ok(ids.includes("kimi-k2.6"), "existing kimi-k2.6 stays listed");
});
test("kimi-coding-apikey advertises kimi-k2.7-code (shares KIMI_CODING_SHARED)", () => {
const ids = modelIds("kimi-coding-apikey");
assert.ok(ids.includes(K27), "kimi-coding-apikey must list kimi-k2.7-code");
assert.ok(ids.includes(K27_HS), "kimi-coding-apikey must list kimi-k2.7-code-highspeed");
});
test("moonshot (OpenAI endpoint) advertises kimi-k2.7-code + highspeed", () => {
const ids = modelIds("moonshot");
assert.ok(ids.includes(K27), "moonshot must list kimi-k2.7-code");
assert.ok(ids.includes(K27_HS), "moonshot must list kimi-k2.7-code-highspeed");
assert.ok(ids.includes("kimi-k2.6"), "existing kimi-k2.6 stays listed");
});
test("kimi (OpenAI endpoint) advertises kimi-k2.7-code + highspeed", () => {
const ids = modelIds("kimi");
assert.ok(ids.includes(K27), "kimi must list kimi-k2.7-code");
assert.ok(ids.includes(K27_HS), "kimi must list kimi-k2.7-code-highspeed");
});
test("kimi-k2.7-code reports native 262144 context and is reasoning-capable", () => {
const caps = getResolvedModelCapabilities({ provider: "kimi-coding", model: K27 });
assert.equal(caps.contextWindow, 262144, "context window must be the native 256K (262144)");
// thinking-only model: the thinking budget pipeline must not strip its thinking
// config (applyThinkingBudget early-exits via supportsReasoning(model)).
assert.equal(supportsReasoning(K27), true, "kimi-k2.7-code must be reasoning-capable");
});
test("kimi-k2.7-code strips client temperature/top_p (fixed sampling upstream)", () => {
for (const provider of ["kimi-coding", "kimi-coding-apikey", "moonshot", "kimi"]) {
const unsupported = getUnsupportedParams(provider, K27);
assert.ok(unsupported.includes("temperature"), `${provider}: temperature must be stripped`);
assert.ok(unsupported.includes("top_p"), `${provider}: top_p must be stripped`);
}
});

View File

@@ -0,0 +1,101 @@
import { test } from "node:test";
import assert from "node:assert/strict";
import { redactSecrets, redactLogArgs } from "../../src/shared/utils/logRedaction.ts";
test("redactSecrets removes Authorization: Bearer tokens", () => {
const out = redactSecrets("upstream failed; Authorization: Bearer sk-abc123DEF456ghi789");
assert.match(out, /Authorization: Bearer \[REDACTED\]/);
assert.doesNotMatch(out, /sk-abc123/);
});
test("redactSecrets removes a bare bearer token", () => {
const out = redactSecrets("header bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.payload.sig");
assert.match(out, /Bearer \[REDACTED\]/i);
});
test("redactSecrets removes x-api-key values", () => {
const out = redactSecrets("sent x-api-key: 9f8e7d6c5b4a3210ffff");
assert.match(out, /x-api-key: \[REDACTED\]/i);
assert.doesNotMatch(out, /9f8e7d6c/);
});
test("redactSecrets removes a Telegram bot token in a URL", () => {
const out = redactSecrets("posting to https://api.telegram.org/bot123456789:AAExampleTokenValue_abcdEFGH/send");
assert.match(out, /api\.telegram\.org\/bot\[REDACTED\]/);
assert.doesNotMatch(out, /AAExampleTokenValue/);
});
test("redactSecrets removes sk- style API keys anywhere", () => {
const out = redactSecrets("key=sk-proj-ABCDEFGHIJ1234567890 done");
assert.match(out, /sk-\[REDACTED\]/);
assert.doesNotMatch(out, /ABCDEFGHIJ1234567890/);
});
test("redactSecrets returns clean strings unchanged (same reference)", () => {
const clean = "request completed in 42ms for model gpt-4o";
assert.equal(redactSecrets(clean), clean);
});
test("redactSecrets is bounded on adversarial input (no catastrophic backtracking)", () => {
const huge = "Authorization: Bearer " + "a".repeat(2_000_000);
const start = Date.now();
const out = redactSecrets(huge);
assert.ok(Date.now() - start < 1000, "must not hang");
assert.match(out, /\[REDACTED\]/);
});
test("redactLogArgs scrubs a string message argument", () => {
const [msg] = redactLogArgs(["call failed: Authorization: Bearer sk-secret1234567890abcd"]);
assert.doesNotMatch(String(msg), /sk-secret/);
assert.match(String(msg), /\[REDACTED\]/);
});
test("redactLogArgs scrubs nested object string values", () => {
const [obj] = redactLogArgs([
{ req: { headers: { authorization: "Bearer sk-deadbeefdeadbeef1234" } }, model: "gpt-4o" },
]) as [{ req: { headers: { authorization: string } }; model: string }];
assert.doesNotMatch(obj.req.headers.authorization, /sk-deadbeef/);
assert.match(obj.req.headers.authorization, /\[REDACTED\]/);
assert.equal(obj.model, "gpt-4o", "non-secret fields are preserved");
});
test("redactLogArgs scrubs an Error's message and stack when a secret is present", () => {
const err = new Error("connect failed with Authorization: Bearer sk-leakedKey1234567890");
const [scrubbed] = redactLogArgs([err]) as [Error];
assert.notEqual(scrubbed, err, "a secret-bearing error is replaced with a redacted clone");
assert.ok(scrubbed instanceof Error, "the redacted view is still a real Error");
assert.doesNotMatch(scrubbed.message, /sk-leakedKey/);
assert.match(scrubbed.message, /\[REDACTED\]/);
assert.doesNotMatch(String(scrubbed.stack), /sk-leakedKey/);
});
test("redactLogArgs leaves a clean Error untouched (preserves pino's serializer)", () => {
const err = new Error("plain timeout after 30s");
const [same] = redactLogArgs([err]);
assert.equal(same, err, "no secret → original Error instance is returned unchanged");
});
test("redactLogArgs returns the original object when nothing was redacted (no allocation)", () => {
const obj = { model: "gpt-4o", tokens: 42, nested: { a: "b" } };
const [same] = redactLogArgs([obj]);
assert.equal(same, obj, "clean object identity is preserved");
});
test("redactLogArgs survives circular references", () => {
const a: Record<string, unknown> = { name: "a" };
a.self = a;
assert.doesNotThrow(() => redactLogArgs([a]));
});
test("redactLogArgs is bounded on huge/deep objects", () => {
const deep: Record<string, unknown> = {};
let cur = deep;
for (let i = 0; i < 10_000; i++) {
cur.next = { token: "Bearer sk-xxxxxxxxxxxxxxxx" };
cur = cur.next as Record<string, unknown>;
}
const start = Date.now();
assert.doesNotThrow(() => redactLogArgs([deep]));
assert.ok(Date.now() - start < 1000, "must stay bounded on pathological structures");
});

View File

@@ -0,0 +1,47 @@
import { test } from "node:test";
import assert from "node:assert/strict";
import { mkdtempSync, readFileSync, existsSync } from "node:fs";
import { tmpdir } from "node:os";
import { join } from "node:path";
// Configure file logging BEFORE importing the logger (buildLogger runs at import time).
const dir = mkdtempSync(join(tmpdir(), "omniroute-logredact-"));
const logFile = join(dir, "app.log");
process.env.NODE_ENV = "production"; // JSON to file, no pino-pretty
process.env.APP_LOG_TO_FILE = "true";
process.env.APP_LOG_FILE_PATH = logFile;
process.env.APP_LOG_LEVEL = "debug";
const { createLogger } = await import("../../src/shared/utils/logger.ts");
/** Poll the (worker-thread-written) log file until the predicate holds or timeout. */
async function readLogWhen(
predicate: (contents: string) => boolean,
timeoutMs = 4000
): Promise<string> {
const start = Date.now();
while (Date.now() - start < timeoutMs) {
if (existsSync(logFile)) {
const contents = readFileSync(logFile, "utf8");
if (predicate(contents)) return contents;
}
await new Promise((r) => setTimeout(r, 50));
}
return existsSync(logFile) ? readFileSync(logFile, "utf8") : "";
}
test("logger redacts a Bearer secret in a free-form message and an error stack (end-to-end)", async () => {
const log = createLogger("redact-test");
log.info("upstream call Authorization: Bearer sk-superSecretKey1234567890done");
const err = new Error("boom while sending Authorization: Bearer sk-anotherSecretABCDEFGH12");
log.error({ err }, "request failed");
const contents = await readLogWhen(
(c) => c.includes("[REDACTED]") && !c.includes("sk-superSecretKey") && !c.includes("sk-anotherSecret")
);
assert.match(contents, /\[REDACTED\]/, "redaction marker must appear in the log output");
assert.doesNotMatch(contents, /sk-superSecretKey/, "message secret must be redacted");
assert.doesNotMatch(contents, /sk-anotherSecret/, "error-stack secret must be redacted");
});

View File

@@ -0,0 +1,242 @@
import test from "node:test";
import assert from "node:assert/strict";
import fs from "node:fs";
import os from "node:os";
import path from "node:path";
// Isolated DATA_DIR before any module that may open the SQLite singleton.
const TEST_DATA_DIR = fs.mkdtempSync(path.join(os.tmpdir(), "omniroute-media-cost-h-"));
process.env.DATA_DIR = TEST_DATA_DIR;
process.env.API_KEY_SECRET = process.env.API_KEY_SECRET || "media-cost-h-test-api-key-secret";
const core = await import("../../src/lib/db/core.ts");
const { OMNIROUTE_RESPONSE_HEADERS } = await import("../../src/shared/constants/headers.ts");
const { saveSyncedPricing } = await import("../../src/lib/pricingSync.ts");
const rerankHandler = await import("../../open-sse/handlers/rerank.ts");
const moderationHandler = await import("../../open-sse/handlers/moderations.ts");
const speechRoute = await import("../../src/app/api/v1/audio/speech/route.ts");
const transcriptionRoute = await import("../../src/app/api/v1/audio/transcriptions/route.ts");
const originalFetch = globalThis.fetch;
function restoreGlobals() {
globalThis.fetch = originalFetch;
}
test.afterEach(() => {
restoreGlobals();
});
test.after(() => {
restoreGlobals();
core.resetDbInstance();
fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true });
});
// Shared assertions: every successful media Response must carry the
// X-OmniRoute-* cost telemetry headers (parity with chat/embeddings).
// Cost may legitimately be 0 (free / unpriced modality) — formatOmniRouteCost
// still emits a fixed-10-decimal string ("0.0000000000"), so the format check
// holds regardless.
function assertCostTelemetryHeaders(response: Response) {
assert.equal(response.status, 200);
const cost = response.headers.get(OMNIROUTE_RESPONSE_HEADERS.responseCost);
assert.ok(cost, "response cost header must be present");
assert.match(
cost as string,
/^\d+\.\d{10}$/,
`cost header must be a fixed-10-decimal number, got: ${cost}`
);
const version = response.headers.get(OMNIROUTE_RESPONSE_HEADERS.version);
assert.ok(version && version.trim().length > 0, "version header must be non-empty");
const provider = response.headers.get(OMNIROUTE_RESPONSE_HEADERS.provider);
assert.ok(provider && provider.trim().length > 0, "provider header must be present");
}
test("rerank handler success Response carries cost telemetry headers", async () => {
globalThis.fetch = (async (url: unknown) => {
const stringUrl = String(url);
if (stringUrl === "https://api.cohere.com/v2/rerank") {
return new Response(
JSON.stringify({
id: "rerank-1",
results: [
{ index: 0, relevance_score: 0.9 },
{ index: 1, relevance_score: 0.1 },
],
meta: { api_version: { version: "2" }, billed_units: { search_units: 1 } },
}),
{ status: 200, headers: { "content-type": "application/json" } }
);
}
throw new Error(`Unexpected URL: ${stringUrl}`);
}) as typeof fetch;
const response = (await rerankHandler.handleRerank({
model: "cohere/rerank-v3.5",
query: "telemetry rerank",
documents: ["doc a", "doc b"],
credentials: { apiKey: "test-key" },
})) as Response;
assertCostTelemetryHeaders(response);
assert.equal(
response.headers.get(OMNIROUTE_RESPONSE_HEADERS.provider),
"cohere",
"provider header must reflect the resolved rerank provider"
);
const body = (await response.json()) as { results?: unknown[] };
assert.ok(
Array.isArray(body.results) && body.results.length === 2,
"should return rerank results"
);
});
test("rerank NVIDIA-format success Response reflects synthesized search unit in cost header", async () => {
// NVIDIA-format rerank: transformResponseFromProvider SYNTHESIZES
// meta.billed_units.search_units = 1 onto `result`, while the raw upstream
// `data` has NO `meta` at all. The handler must read search units from the
// transformed `result` (not the raw `data`), otherwise NVIDIA rerank is
// always priced at $0 even when pricing exists.
saveSyncedPricing({
nvidia: {
// calculateModalCost("rerank","nvidia","nvidia/nv-rerankqa-mistral-4b-v3")
// first looks up the scoped id, then retries with normalizeModelName
// (strips the "nvidia/" prefix) → this key resolves on the second try.
"nv-rerankqa-mistral-4b-v3": { input: 0, output: 0, search_unit_cost: 0.002 },
},
});
globalThis.fetch = (async (url: unknown) => {
const stringUrl = String(url);
if (stringUrl === "https://integrate.api.nvidia.com/v1/ranking") {
// NVIDIA shape — note: NO `meta` block at all.
return new Response(
JSON.stringify({
rankings: [
{ index: 0, logit: 0.9, text: "doc a" },
{ index: 1, logit: 0.4, text: "doc b" },
],
}),
{ status: 200, headers: { "content-type": "application/json" } }
);
}
throw new Error(`Unexpected URL: ${stringUrl}`);
}) as typeof fetch;
const response = (await rerankHandler.handleRerank({
model: "nvidia/nv-rerankqa-mistral-4b-v3",
query: "telemetry rerank nvidia",
documents: ["doc a", "doc b"],
credentials: { apiKey: "test-key" },
})) as Response;
assertCostTelemetryHeaders(response);
assert.equal(
response.headers.get(OMNIROUTE_RESPONSE_HEADERS.provider),
"nvidia",
"provider header must reflect the resolved rerank provider"
);
// 1 synthesized search unit × $0.002 = $0.002. With the OLD `data?.meta…`
// read this would be "0.0000000000" (raw NVIDIA data carries no meta).
assert.equal(
response.headers.get(OMNIROUTE_RESPONSE_HEADERS.responseCost),
"0.0020000000",
"NVIDIA rerank cost must reflect the synthesized 1 search unit read from result"
);
});
test("moderation handler success Response carries cost telemetry headers (cost 0)", async () => {
globalThis.fetch = (async (url: unknown) => {
const stringUrl = String(url);
if (stringUrl === "https://api.openai.com/v1/moderations") {
return new Response(
JSON.stringify({
id: "modr-1",
model: "omni-moderation-latest",
results: [{ flagged: false }],
}),
{ status: 200, headers: { "content-type": "application/json" } }
);
}
throw new Error(`Unexpected URL: ${stringUrl}`);
}) as typeof fetch;
const response = (await moderationHandler.handleModeration({
body: { model: "omni-moderation-latest", input: "telemetry moderation" },
credentials: { apiKey: "test-key" },
})) as Response;
assertCostTelemetryHeaders(response);
assert.equal(
response.headers.get(OMNIROUTE_RESPONSE_HEADERS.responseCost),
"0.0000000000",
"moderation is free → cost must be exactly 0"
);
});
test("v1 audio speech success Response carries cost telemetry headers", async () => {
globalThis.fetch = (async (url: unknown) => {
const stringUrl = String(url);
if (stringUrl === "http://localhost:8000/v1/audio/speech") {
return new Response(new Uint8Array([1, 2, 3, 4]), {
status: 200,
headers: { "content-type": "audio/mpeg" },
});
}
throw new Error(`Unexpected URL: ${stringUrl}`);
}) as typeof fetch;
const response = await speechRoute.POST(
new Request("http://localhost/api/v1/audio/speech", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({
model: "qwen/qwen3-tts",
input: "telemetry speech text",
}),
}),
{}
);
assertCostTelemetryHeaders(response);
assert.equal(
response.headers.get("Content-Type"),
"audio/mpeg",
"audio Content-Type must be preserved"
);
});
test("v1 audio transcription success Response carries cost telemetry headers (cost 0)", async () => {
globalThis.fetch = (async (url: unknown) => {
const stringUrl = String(url);
if (stringUrl === "http://localhost:8000/v1/audio/transcriptions") {
return new Response(JSON.stringify({ text: "transcribed telemetry" }), {
status: 200,
headers: { "content-type": "application/json" },
});
}
throw new Error(`Unexpected URL: ${stringUrl}`);
}) as typeof fetch;
const formData = new FormData();
formData.set("model", "qwen/qwen3-asr");
formData.set("file", new Blob([new Uint8Array([1, 2, 3])], { type: "audio/wav" }), "clip.wav");
const response = await transcriptionRoute.POST(
new Request("http://localhost/api/v1/audio/transcriptions", {
method: "POST",
body: formData,
})
);
assertCostTelemetryHeaders(response);
assert.equal(
response.headers.get(OMNIROUTE_RESPONSE_HEADERS.responseCost),
"0.0000000000",
"transcription duration unavailable → cost must be 0"
);
});

View File

@@ -0,0 +1,170 @@
import test from "node:test";
import assert from "node:assert/strict";
import fs from "node:fs";
import os from "node:os";
import path from "node:path";
// Isolated DATA_DIR before any module that may open the SQLite singleton.
const TEST_DATA_DIR = fs.mkdtempSync(path.join(os.tmpdir(), "omniroute-media-cost-"));
process.env.DATA_DIR = TEST_DATA_DIR;
process.env.API_KEY_SECRET = process.env.API_KEY_SECRET || "media-cost-test-api-key-secret";
const core = await import("../../src/lib/db/core.ts");
const { OMNIROUTE_RESPONSE_HEADERS } = await import("../../src/shared/constants/headers.ts");
const imageRoute = await import("../../src/app/api/v1/images/generations/route.ts");
const videoRoute = await import("../../src/app/api/v1/videos/generations/route.ts");
const musicRoute = await import("../../src/app/api/v1/music/generations/route.ts");
const originalFetch = globalThis.fetch;
const originalSetTimeout = globalThis.setTimeout;
// Skip the ComfyUI polling delays — invoke the callback synchronously.
function immediateTimeout(callback: (...a: unknown[]) => void, _ms?: number, ...args: unknown[]) {
if (typeof callback === "function") callback(...args);
return 0 as unknown as ReturnType<typeof setTimeout>;
}
function restoreGlobals() {
globalThis.fetch = originalFetch;
globalThis.setTimeout = originalSetTimeout;
}
test.afterEach(() => {
restoreGlobals();
});
test.after(() => {
restoreGlobals();
core.resetDbInstance();
fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true });
});
// Shared assertions: every successful media Response must carry the
// X-OmniRoute-* cost telemetry headers (parity with chat/embeddings).
function assertCostTelemetryHeaders(response: Response) {
assert.equal(response.status, 200);
const cost = response.headers.get(OMNIROUTE_RESPONSE_HEADERS.responseCost);
assert.ok(cost, "response cost header must be present");
assert.match(
cost as string,
/^\d+\.\d{10}$/,
`cost header must be a fixed-10-decimal number, got: ${cost}`
);
const version = response.headers.get(OMNIROUTE_RESPONSE_HEADERS.version);
assert.ok(version && version.trim().length > 0, "version header must be non-empty");
const provider = response.headers.get(OMNIROUTE_RESPONSE_HEADERS.provider);
assert.ok(provider && provider.trim().length > 0, "provider header must be present");
}
test("v1 images generation success Response carries cost telemetry headers", async () => {
globalThis.fetch = (async (url: unknown) => {
const stringUrl = String(url);
if (stringUrl === "http://localhost:7860/sdapi/v1/txt2img") {
return new Response(JSON.stringify({ images: ["YmFzZTY0LWltYWdl"] }), {
status: 200,
headers: { "content-type": "application/json" },
});
}
throw new Error(`Unexpected URL: ${stringUrl}`);
}) as typeof fetch;
const response = await imageRoute.POST(
new Request("http://localhost/api/v1/images/generations", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({
model: "sdwebui/stable-diffusion-v1-5",
prompt: "telemetry image",
}),
})
);
assertCostTelemetryHeaders(response);
const body = (await response.json()) as { data?: unknown[] };
assert.ok(Array.isArray(body.data) && body.data.length >= 1, "should return image data");
});
test("v1 videos generation success Response carries cost telemetry headers", async () => {
globalThis.setTimeout = immediateTimeout as typeof setTimeout;
globalThis.fetch = (async (url: unknown) => {
const stringUrl = String(url);
if (stringUrl === "http://localhost:8188/prompt") {
return new Response(JSON.stringify({ prompt_id: "video-cost-1" }), {
status: 200,
headers: { "content-type": "application/json" },
});
}
if (stringUrl === "http://localhost:8188/history/video-cost-1") {
return new Response(
JSON.stringify({
"video-cost-1": {
outputs: { 7: { gifs: [{ filename: "clip.webp", subfolder: "out", type: "output" }] } },
},
}),
{ status: 200, headers: { "content-type": "application/json" } }
);
}
if (stringUrl.includes("/view?")) {
return new Response(new Uint8Array([1, 2, 3, 4]), { status: 200 });
}
throw new Error(`Unexpected URL: ${stringUrl}`);
}) as typeof fetch;
const response = await videoRoute.POST(
new Request("http://localhost/api/v1/videos/generations", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({
model: "comfyui/animatediff",
prompt: "telemetry video",
duration: 6,
}),
})
);
assertCostTelemetryHeaders(response);
});
test("v1 music generation success Response carries cost telemetry headers", async () => {
globalThis.setTimeout = immediateTimeout as typeof setTimeout;
globalThis.fetch = (async (url: unknown) => {
const stringUrl = String(url);
if (stringUrl === "http://localhost:8188/prompt") {
return new Response(JSON.stringify({ prompt_id: "music-cost-1" }), {
status: 200,
headers: { "content-type": "application/json" },
});
}
if (stringUrl === "http://localhost:8188/history/music-cost-1") {
return new Response(
JSON.stringify({
"music-cost-1": {
outputs: { 7: { audio: [{ filename: "track.wav", subfolder: "out", type: "output" }] } },
},
}),
{ status: 200, headers: { "content-type": "application/json" } }
);
}
if (stringUrl.includes("/view?")) {
return new Response(new Uint8Array([5, 6, 7]), { status: 200 });
}
throw new Error(`Unexpected URL: ${stringUrl}`);
}) as typeof fetch;
const response = await musicRoute.POST(
new Request("http://localhost/api/v1/music/generations", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({
model: "comfyui/musicgen-medium",
prompt: "telemetry music",
duration: 18,
}),
})
);
assertCostTelemetryHeaders(response);
});

View File

@@ -0,0 +1,165 @@
/**
* tests/unit/memory-vectorstore-int8-quant.test.ts
*
* F4.4 / Q2 — opt-in sqlite-vec int8 storage quantization.
* - When MEMORY_VEC_QUANTIZATION=int8, ensureReady stores an ":int8"-suffixed
* signature and creates the vec table with an int8[N] column (vectors stored
* via vec_quantize_int8 'unit').
* - Recall: int8 nearest-neighbor matches the exact float32 nearest-neighbor on
* a deterministic fixture (top-1 identical, top-3 overlap >= 2/3).
* - Switching mode (none -> int8) is a signature change → resetForSignature
* recreates the table and marks all memories needs_reindex.
*/
import test from "node:test";
import assert from "node:assert/strict";
import fs from "node:fs";
import os from "node:os";
import path from "node:path";
const TEST_DATA_DIR = fs.mkdtempSync(path.join(os.tmpdir(), "omr-vecstore-int8-"));
process.env.DATA_DIR = TEST_DATA_DIR;
process.env.DISABLE_SQLITE_AUTO_BACKUP = "true";
const core = await import("../../src/lib/db/core.ts");
const vsModule = await import("../../src/lib/memory/vectorStore.ts");
const { getVectorStore, _resetVectorStoreSingleton } = vsModule;
import type { EmbeddingResolution } from "../../src/lib/memory/embedding/types.ts";
const DIM = 8;
function makeResolution(): EmbeddingResolution {
return {
source: "remote",
model: "test/dim8",
dimensions: DIM,
signature: `test:dim8:${DIM}`,
reason: "test",
};
}
function vec(values: number[]): Float32Array {
return new Float32Array(values);
}
// Deterministic, well-separated unit-ish fixture (8 dims, 6 memories).
const FIXTURE: Array<{ id: string; v: number[] }> = [
{ id: "m0", v: [1, 0, 0, 0, 0, 0, 0, 0] },
{ id: "m1", v: [0, 1, 0, 0, 0, 0, 0, 0] },
{ id: "m2", v: [0, 0, 1, 0, 0, 0, 0, 0] },
{ id: "m3", v: [0.6, 0.8, 0, 0, 0, 0, 0, 0] },
{ id: "m4", v: [0, 0, 0, 1, 0, 0, 0, 0] },
{ id: "m5", v: [0, 0, 0, 0, 0.7071, 0.7071, 0, 0] },
];
function l2(a: number[], b: number[]): number {
let s = 0;
for (let i = 0; i < a.length; i++) s += (a[i] - b[i]) ** 2;
return Math.sqrt(s);
}
function exactNearestIds(query: number[], k: number): string[] {
return [...FIXTURE]
.map((f) => ({ id: f.id, d: l2(f.v, query) }))
.sort((a, b) => a.d - b.d)
.slice(0, k)
.map((x) => x.id);
}
function cleanup() {
_resetVectorStoreSingleton();
core.resetDbInstance();
if (fs.existsSync(TEST_DATA_DIR)) fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true });
fs.mkdirSync(TEST_DATA_DIR, { recursive: true });
}
test.afterEach(() => {
delete process.env.MEMORY_VEC_QUANTIZATION;
cleanup();
});
test.after(() => {
core.resetDbInstance();
if (fs.existsSync(TEST_DATA_DIR)) fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true });
});
function getStoreOrSkip(t: { skip: (msg: string) => void }): ReturnType<typeof getVectorStore> {
_resetVectorStoreSingleton();
const store = getVectorStore();
if (store === null) {
t.skip("sqlite-vec not available in this environment — skipping");
return null;
}
return store;
}
function insertMemory(db: ReturnType<typeof core.getDbInstance>, id: string) {
db.prepare(
`INSERT INTO memories (id, api_key_id, type, key, content, created_at)
VALUES (?, 'key1', 'factual', ?, ?, datetime('now'))`,
).run(id, `key-${id}`, `content-${id}`);
}
async function seedFixture(store: NonNullable<ReturnType<typeof getVectorStore>>) {
const db = core.getDbInstance();
await store.ensureReady(makeResolution());
for (const f of FIXTURE) {
insertMemory(db, f.id);
await store.upsertVector(f.id, vec(f.v));
}
}
test("int8 mode: ensureReady stores an ':int8' signature", async (t) => {
process.env.MEMORY_VEC_QUANTIZATION = "int8";
const store = getStoreOrSkip(t);
if (!store) return;
await store.ensureReady(makeResolution());
const stats = await store.stats();
assert.ok(
stats.signature?.endsWith(":int8"),
`signature must carry the int8 marker, got ${stats.signature}`,
);
});
test("int8 recall: nearest-neighbor matches exact float32 NN on the fixture", async (t) => {
process.env.MEMORY_VEC_QUANTIZATION = "int8";
const store = getStoreOrSkip(t);
if (!store) return;
await seedFixture(store);
// Query close to m2 ([0,0,1,...]).
const query = [0.05, 0.05, 0.95, 0, 0, 0, 0, 0];
const hits = await store.searchVector(vec(query), 3);
assert.ok(hits.length >= 1, "int8 search must return results");
const exact = exactNearestIds(query, 3);
assert.equal(hits[0].memoryId, exact[0], `top-1 must match exact NN (${exact[0]})`);
const overlap = hits.slice(0, 3).filter((h) => exact.includes(h.memoryId)).length;
assert.ok(overlap >= 2, `top-3 overlap must be >= 2/3 (got ${overlap}; int8=${hits
.map((h) => h.memoryId)
.join(",")} exact=${exact.join(",")})`);
});
test("switching none → int8 is a signature change that triggers reindex", async (t) => {
const store = getStoreOrSkip(t);
if (!store) return;
// Start in float32 mode and seed.
await seedFixture(store);
const before = await store.stats();
assert.ok(!before.signature?.endsWith(":int8"), "baseline should be float32 (no int8 marker)");
// Flip to int8 and re-run ensureReady → recreate + mark all needs_reindex.
process.env.MEMORY_VEC_QUANTIZATION = "int8";
const res = await store.ensureReady(makeResolution());
assert.match(res.reason, /recreated/i, "ensureReady must recreate the table on mode switch");
const after = await store.stats();
assert.ok(after.signature?.endsWith(":int8"), "signature must now carry the int8 marker");
assert.equal(after.rowCount, 0, "table recreated empty (vectors await reindex)");
assert.ok(after.needsReindex >= FIXTURE.length, "all memories must be marked needs_reindex");
});

View File

@@ -0,0 +1,89 @@
/**
* Xiaomi MiMo thinking normalization — `normalizeMimoThinking`.
*
* MiMo controls reasoning ONLY via `thinking:{type:"enabled"|"disabled"}` and rejects
* extra/unknown request params with a strict "400 Param Incorrect". These tests pin the
* normalization that maps OmniRoute's internal reasoning signals onto MiMo's native shape:
* reduce any thinking object to `{type}`, and drop `reasoning_effort` / `reasoning`.
*/
import test from "node:test";
import assert from "node:assert/strict";
import { normalizeMimoThinking } from "../../open-sse/services/mimoThinking.ts";
test("thinking:{type:'disabled'} is preserved (lets a client turn thinking OFF)", () => {
const body = { model: "mimo-v2.5-pro", messages: [], thinking: { type: "disabled" } };
const result = normalizeMimoThinking(body);
assert.deepEqual(result.thinking, { type: "disabled" });
});
test("Claude-shaped thinking:{type:'enabled', budget_tokens} → {type:'enabled'} (extras stripped)", () => {
const body = {
model: "mimo-v2.5-pro",
messages: [],
thinking: { type: "enabled", budget_tokens: 2048, keep: null },
};
const result = normalizeMimoThinking(body);
// MiMo only accepts `type`; budget_tokens/keep would be rejected as extra params.
assert.deepEqual(result.thinking, { type: "enabled" });
});
test("thinking:{type:'adaptive'} collapses to MiMo's binary 'enabled'", () => {
const body = { model: "mimo-v2.5", messages: [], thinking: { type: "adaptive" } };
const result = normalizeMimoThinking(body);
assert.deepEqual(result.thinking, { type: "enabled" });
});
test("reasoning_effort is removed (MiMo does not understand it) and no thinking is synthesized", () => {
const body = { model: "mimo-v2-flash", messages: [], reasoning_effort: "high" };
const result = normalizeMimoThinking(body) as Record<string, unknown>;
assert.equal(result.reasoning_effort, undefined, "reasoning_effort must be dropped");
// Deliberately NOT synthesized — mimo-v2-omni is non-thinking; forcing it on could 400.
assert.equal(result.thinking, undefined, "no thinking object is invented from a bare effort hint");
});
test("nested `reasoning` object is removed", () => {
const body = { model: "mimo-v2.5", messages: [], reasoning: { effort: "high", summary: "auto" } };
const result = normalizeMimoThinking(body) as Record<string, unknown>;
assert.equal(result.reasoning, undefined, "reasoning must be dropped");
});
test("reasoning_effort alongside an explicit thinking:{type:'disabled'} → thinking wins, effort dropped", () => {
const body = {
model: "mimo-v2.5-pro",
messages: [],
reasoning_effort: "xhigh",
thinking: { type: "disabled", budget_tokens: 1000 },
};
const result = normalizeMimoThinking(body) as Record<string, unknown>;
assert.deepEqual(result.thinking, { type: "disabled" });
assert.equal(result.reasoning_effort, undefined);
});
test("body with neither thinking nor reasoning is returned UNTOUCHED (same reference)", () => {
const body = { model: "mimo-v2.5-pro", messages: [{ role: "user", content: "hi" }] };
const result = normalizeMimoThinking(body);
assert.equal(result, body, "no-op must not allocate a new object");
});
test("non-object body is returned unchanged", () => {
const body = null as unknown as Record<string, unknown>;
assert.equal(normalizeMimoThinking(body), body);
});
test("unrelated fields are preserved", () => {
const body = {
model: "mimo-v2.5-pro",
messages: [{ role: "user", content: "hi" }],
temperature: 0.7,
max_tokens: 1024,
thinking: { type: "enabled", budget_tokens: 4096 },
reasoning_effort: "high",
};
const result = normalizeMimoThinking(body) as Record<string, unknown>;
assert.equal(result.model, "mimo-v2.5-pro");
assert.equal(result.temperature, 0.7);
assert.equal(result.max_tokens, 1024);
assert.deepEqual(result.messages, [{ role: "user", content: "hi" }]);
assert.deepEqual(result.thinking, { type: "enabled" });
assert.equal(result.reasoning_effort, undefined);
});

View File

@@ -0,0 +1,93 @@
import test from "node:test";
import assert from "node:assert/strict";
// Regression guard: media providers surface in the dashboard via registry-derived
// serviceKinds.
//
// Root cause this fixes: `/dashboard/media-providers/[kind]` listed a provider only
// if it hand-declared `serviceKinds` in providers.ts. ~48 providers were wired into
// the audio/video/music/image/embedding registries (backend works) but declared no
// serviceKinds, so every media page was empty. The fix derives media membership from
// the registries (single source of truth) and unions it with declared serviceKinds.
//
// MiniMax was the flagged case: its international endpoint serves TTS/video/music, the
// China variant (minimax-cn) has no media registry entries.
const { getRegistryMediaKinds, resolveProviderServiceKinds, REGISTRY_MEDIA_KINDS } =
await import("../../open-sse/config/mediaServiceKinds.ts");
const { AI_PROVIDERS } = await import("../../src/shared/constants/providers.ts");
test("minimax (international) derives tts/video/music from the registries", () => {
const kinds = getRegistryMediaKinds("minimax").sort();
assert.deepEqual(kinds, ["music", "tts", "video"]);
});
test("minimax-cn derives no media kinds (China endpoint has no media registry entries)", () => {
assert.deepEqual(getRegistryMediaKinds("minimax-cn"), []);
});
test("representative media providers derive the expected kinds", () => {
// Each pair: provider id -> at least these kinds must be derived.
const cases: Record<string, string[]> = {
elevenlabs: ["tts"],
deepgram: ["stt", "tts"],
suno: ["music"],
udio: ["music"],
runwayml: ["video"],
openai: ["embedding", "image", "stt", "tts"],
cohere: ["embedding", "stt"],
};
for (const [id, expected] of Object.entries(cases)) {
const derived = getRegistryMediaKinds(id);
for (const kind of expected) {
assert.ok(derived.includes(kind as never), `${id} should derive ${kind}; got ${derived.join(",")}`);
}
}
});
test("resolveProviderServiceKinds unions declared kinds with derived media kinds", () => {
// A provider with a declared non-media kind keeps it AND gains derived media kinds.
const merged = resolveProviderServiceKinds("minimax", ["llm"]);
for (const expected of ["llm", "tts", "video", "music"]) {
assert.ok(merged.includes(expected), `expected ${expected} in ${merged.join(",")}`);
}
// De-dupes when declared overlaps derived.
const veo = resolveProviderServiceKinds("veoaifree-web", ["video"]);
assert.equal(veo.filter((k) => k === "video").length, 1);
});
test("media listing filter surfaces minimax where the old declared-only filter missed it", () => {
const cfg = AI_PROVIDERS as Record<string, { id: string; serviceKinds?: string[] }>;
// OLD behavior (the bug): filter by declared serviceKinds only.
const oldListFor = (kind: string) =>
Object.values(cfg)
.filter((p) => (p.serviceKinds ?? []).includes(kind))
.map((p) => p.id);
// NEW behavior (the fix): union declared with registry-derived kinds — mirrors page.tsx.
const newListFor = (kind: string) =>
Object.values(cfg)
.filter((p) => resolveProviderServiceKinds(p.id, p.serviceKinds).includes(kind))
.map((p) => p.id);
for (const kind of ["tts", "video", "music"]) {
assert.ok(!oldListFor(kind).includes("minimax"), `precondition (bug): old filter missed minimax under ${kind}`);
assert.ok(newListFor(kind).includes("minimax"), `fix: minimax now listed under ${kind}`);
assert.ok(!newListFor(kind).includes("minimax-cn"), `minimax-cn must not appear under ${kind}`);
}
// The fix is systemic, not minimax-only: many providers were invisible before.
assert.ok(oldListFor("tts").length < newListFor("tts").length, "fix surfaces additional tts providers");
});
test("derived kinds are always within the known media-kind set", () => {
for (const id of Object.keys(AI_PROVIDERS)) {
for (const kind of getRegistryMediaKinds(id)) {
assert.ok(
(REGISTRY_MEDIA_KINDS as readonly string[]).includes(kind),
`${id} derived unknown kind ${kind}`
);
}
}
});

View File

@@ -0,0 +1,32 @@
import { test } from "node:test";
import assert from "node:assert/strict";
import {
computeImageCost,
computeAudioCost,
computeRerankCost,
computeVideoCost,
calculateModalCost,
} from "../../src/lib/usage/costCalculator.ts";
test("computeImageCost: per-image flat × n", () => {
assert.equal(computeImageCost({ output_cost_per_image: 0.04 }, { n: 3 }), 0.12);
assert.equal(computeImageCost({}, { n: 3 }), 0);
assert.equal(computeImageCost({ output_cost_per_image: 0.04 }, { n: 0 }), 0);
});
test("computeAudioCost: per-second OR per-character, else 0", () => {
assert.equal(computeAudioCost({ input_cost_per_second: 0.0001 }, { seconds: 30 }), 0.003);
assert.equal(computeAudioCost({ input_cost_per_character: 0.000015 }, { characters: 1000 }), 0.015);
assert.equal(computeAudioCost({ input_cost_per_second: 0.0001 }, {}), 0);
});
test("computeRerankCost: per search unit", () => {
assert.equal(computeRerankCost({ search_unit_cost: 0.002 }, { searchUnits: 5 }), 0.01);
assert.equal(computeRerankCost({}, { searchUnits: 5 }), 0);
});
test("computeVideoCost: per video-second", () => {
assert.equal(computeVideoCost({ output_cost_per_video_per_second: 0.5 }, { seconds: 8 }), 4);
assert.equal(computeVideoCost({}, { seconds: 8 }), 0);
});
test("calculateModalCost returns 0 for unknown pricing (fail-open)", async () => {
const cost = await calculateModalCost("image", "no-such-provider", "no-such-model", { n: 2 });
assert.equal(cost, 0);
});

View File

@@ -0,0 +1,130 @@
/**
* Xiaomi MiMo vision capability — robust override against a wrong synced `attachment`.
*
* Per Xiaomi's official docs (mimo.mi.com .../multimodal-understanding/image-understanding)
* ONLY `mimo-v2.5` and `mimo-v2-omni` accept image input. The `*-pro` chat models
* (`mimo-v2.5-pro`, `mimo-v2-pro`) and `mimo-v2-flash` are TEXT-ONLY.
*
* models.dev mislabels `mimo-v2.5-pro` as attachment-capable (hermes-agent#18884),
* and `resolveVisionCapability` lets a synced `attachment:true` win first — which would
* route an image request to a blind model (the #4071 failure mode). A hard override
* keyed on the documented text-only ids must beat the synced verdict.
*
* The discriminator is `attachment`: a synced row sets `attachment` from the seeded
* value, while the override forces `supportsVision:false` regardless. So a row seeded
* with `attachment:true` whose `supportsVision` still resolves `false` proves the
* override — not the synced path — produced the verdict.
*/
import test from "node:test";
import assert from "node:assert/strict";
import fs from "node:fs";
import os from "node:os";
import path from "node:path";
const TEST_DATA_DIR = fs.mkdtempSync(path.join(os.tmpdir(), "omniroute-mimo-vision-"));
process.env.DATA_DIR = TEST_DATA_DIR;
const core = await import("../../src/lib/db/core.ts");
const modelsDevSync = await import("../../src/lib/modelsDevSync.ts");
const modelCapabilities = await import("../../src/lib/modelCapabilities.ts");
function buildCapability(overrides = {}) {
return {
tool_call: null,
reasoning: null,
attachment: null,
structured_output: null,
temperature: null,
modalities_input: "[]",
modalities_output: "[]",
knowledge_cutoff: null,
release_date: null,
last_updated: null,
status: null,
family: null,
open_weights: null,
limit_context: null,
limit_input: null,
limit_output: null,
interleaved_field: null,
...overrides,
};
}
function resetStorage() {
core.resetDbInstance();
fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true });
fs.mkdirSync(TEST_DATA_DIR, { recursive: true });
}
// Mirror the WRONG models.dev `xiaomi-mimo` keying: the text-only `*-pro` chat models
// carry attachment:true (the upstream mislabel), while the genuinely multimodal
// `mimo-v2.5` / `mimo-v2-omni` correctly carry attachment:true too.
function seedMimoCapabilities() {
modelsDevSync.saveModelsDevCapabilities({
"xiaomi-mimo": {
"mimo-v2.5-pro": buildCapability({
attachment: true, // upstream mislabel — must be overridden to text-only
modalities_input: JSON.stringify(["text", "image"]),
modalities_output: JSON.stringify(["text"]),
status: "stable",
}),
"mimo-v2-pro": buildCapability({
attachment: true, // upstream mislabel — must be overridden to text-only
modalities_input: JSON.stringify(["text", "image"]),
modalities_output: JSON.stringify(["text"]),
status: "stable",
}),
"mimo-v2.5": buildCapability({
attachment: true, // genuinely multimodal — must stay vision-capable
modalities_input: JSON.stringify(["text", "image", "audio", "video"]),
modalities_output: JSON.stringify(["text"]),
status: "stable",
}),
"mimo-v2-omni": buildCapability({
attachment: true, // genuinely multimodal — must stay vision-capable
modalities_input: JSON.stringify(["text", "image", "audio", "video"]),
modalities_output: JSON.stringify(["text"]),
status: "stable",
}),
},
});
}
test.beforeEach(() => {
resetStorage();
});
test.after(() => {
core.resetDbInstance();
fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true });
});
test("mimo-v2.5-pro stays text-only even when models.dev says attachment:true", () => {
seedMimoCapabilities();
const pro = modelCapabilities.getResolvedModelCapabilities("xiaomi-mimo/mimo-v2.5-pro");
// attachment is the seeded synced value, but the override forces vision false.
assert.equal(pro.attachment, true, "synced attachment row is present (proves override, not absence)");
assert.equal(pro.supportsVision, false, "text-only override must beat the wrong synced attachment");
});
test("mimo-v2-pro stays text-only even when models.dev says attachment:true", () => {
seedMimoCapabilities();
const pro = modelCapabilities.getResolvedModelCapabilities("xiaomi-mimo/mimo-v2-pro");
assert.equal(pro.supportsVision, false, "text-only override must beat the wrong synced attachment");
});
test("genuinely multimodal mimo models keep vision (override is precise, not broad)", () => {
seedMimoCapabilities();
const v25 = modelCapabilities.getResolvedModelCapabilities("xiaomi-mimo/mimo-v2.5");
const omni = modelCapabilities.getResolvedModelCapabilities("xiaomi-mimo/mimo-v2-omni");
assert.equal(v25.supportsVision, true, "mimo-v2.5 is multimodal — must NOT be caught by the override");
assert.equal(omni.supportsVision, true, "mimo-v2-omni is multimodal — must NOT be caught by the override");
});
test("the bare (unqualified) text-only id is also overridden", () => {
seedMimoCapabilities();
// No provider prefix — exercises the `^...$` branch of the override regex.
const bare = modelCapabilities.getResolvedModelCapabilities("mimo-v2.5-pro");
assert.equal(bare.supportsVision, false, "bare text-only id must also be overridden");
});

View File

@@ -0,0 +1,148 @@
/**
* #4073 — models.dev synced metadata must resolve for Mistral `-latest` aliases.
*
* Root cause (confirmed against the live models.dev API): models.dev catalogs
* Mistral Pixtral 12B under the SHORT id `pixtral-12b` (with `attachment: true`,
* `modalities.input: ["text","image"]`), while requests use the Mistral API
* alias `pixtral-12b-latest`. The synced lookup in `getSyncedCapabilityForResolved`
* tried the exact id, the raw id and the static-spec canonical id — all of which
* miss for `pixtral-12b-latest` — so vision fell through to the #4071 model-id
* heuristic and `attachment` stayed `null` (the symptom reported in #4073).
*
* The discriminator between "resolved via synced metadata" and "guessed via the
* #4071 heuristic" is `attachment`: the synced path sets `attachment` from
* `synced.attachment`; the heuristic only flips `supportsVision` and leaves
* `attachment` null. So these tests assert on `attachment` to prove the synced
* path — not the heuristic — produced the verdict.
*
* Other Mistral vision models already worked because models.dev keeps their
* `-latest` id verbatim (e.g. `pixtral-large-latest`, `mistral-medium-latest`);
* `pixtral-12b` is the one short-formed alias, hence the keying fix.
*/
import test from "node:test";
import assert from "node:assert/strict";
import fs from "node:fs";
import os from "node:os";
import path from "node:path";
const TEST_DATA_DIR = fs.mkdtempSync(path.join(os.tmpdir(), "omniroute-mistral-vision-"));
process.env.DATA_DIR = TEST_DATA_DIR;
const core = await import("../../src/lib/db/core.ts");
const modelsDevSync = await import("../../src/lib/modelsDevSync.ts");
const modelCapabilities = await import("../../src/lib/modelCapabilities.ts");
function buildCapability(overrides = {}) {
return {
tool_call: null,
reasoning: null,
attachment: null,
structured_output: null,
temperature: null,
modalities_input: "[]",
modalities_output: "[]",
knowledge_cutoff: null,
release_date: null,
last_updated: null,
status: null,
family: null,
open_weights: null,
limit_context: null,
limit_input: null,
limit_output: null,
interleaved_field: null,
...overrides,
};
}
function resetStorage() {
core.resetDbInstance();
fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true });
fs.mkdirSync(TEST_DATA_DIR, { recursive: true });
}
// Mirrors the real models.dev `mistral` provider keying observed on the live API:
// short-form `pixtral-12b` (vision), verbatim `pixtral-large-latest` (vision),
// short-form `ministral-8b` (text-only).
function seedMistralCapabilities() {
modelsDevSync.saveModelsDevCapabilities({
mistral: {
"pixtral-12b": buildCapability({
attachment: true,
modalities_input: JSON.stringify(["text", "image"]),
modalities_output: JSON.stringify(["text"]),
family: "pixtral",
status: "stable",
}),
"pixtral-large-latest": buildCapability({
attachment: true,
modalities_input: JSON.stringify(["text", "image"]),
modalities_output: JSON.stringify(["text"]),
family: "pixtral",
status: "stable",
}),
"ministral-8b": buildCapability({
attachment: false,
modalities_input: JSON.stringify(["text"]),
modalities_output: JSON.stringify(["text"]),
family: "ministral",
status: "stable",
}),
},
});
}
test.beforeEach(() => {
resetStorage();
});
test.after(() => {
core.resetDbInstance();
fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true });
});
test("#4073 mistral/pixtral-12b-latest resolves vision via the synced `-latest` alias (not the heuristic)", () => {
seedMistralCapabilities();
const latest = modelCapabilities.getResolvedModelCapabilities("mistral/pixtral-12b-latest");
// attachment === true can ONLY come from the synced row keyed `pixtral-12b`.
assert.equal(latest.attachment, true, "synced attachment must resolve via the stripped `-latest` alias");
assert.equal(latest.supportsVision, true);
});
test("#4073 exact-keyed `-latest` models still resolve directly (no regression)", () => {
seedMistralCapabilities();
// pixtral-large-latest is stored verbatim — the direct lookup must keep working.
const large = modelCapabilities.getResolvedModelCapabilities("mistral/pixtral-large-latest");
assert.equal(large.attachment, true);
assert.equal(large.supportsVision, true);
// And the bare short id resolves directly too.
const bare = modelCapabilities.getResolvedModelCapabilities("mistral/pixtral-12b");
assert.equal(bare.attachment, true);
assert.equal(bare.supportsVision, true);
});
test("#4073 the `-latest` strip carries the synced verdict for text-only models too", () => {
seedMistralCapabilities();
// ministral-8b is text-only; the heuristic does not recognise it, so the only
// way attachment is a concrete `false` (not null) is the synced row resolving
// through the stripped alias. This proves the strip returns the row's real
// verdict rather than fabricating a positive.
const ministral = modelCapabilities.getResolvedModelCapabilities("mistral/ministral-8b-latest");
assert.equal(ministral.attachment, false, "synced false must win, resolved via stripped alias");
assert.equal(ministral.supportsVision, false);
});
test("#4073 the `-latest` strip never fabricates a match for an unknown id", () => {
seedMistralCapabilities();
// No synced row for `unknown-text-model` (stripped) nor its `-latest` form, and
// the heuristic doesn't recognise it → attachment null, vision null. The strip
// must not invent a capability out of nothing.
const unknown = modelCapabilities.getResolvedModelCapabilities("mistral/unknown-text-model-latest");
assert.equal(unknown.attachment, null);
assert.equal(unknown.supportsVision, null);
});

View File

@@ -0,0 +1,128 @@
/**
* #4164 — the built-in `auto/*` combos must be advertised in `/v1/models`.
*
* OmniRoute ships a zero-setup `auto/*` catalog (auto/best-coding, auto/pro-
* reasoning, …) that the dashboard advertises and that resolve on demand via
* createBuiltinAutoCombo. But the `/v1/models` listing only emitted persisted DB
* combos + provider models, so clients that build their model picker from
* `/v1/models` (e.g. Hermes Agent) never saw any `auto/*` option.
*
* The catalog now emits every AUTO_TEMPLATE_VARIANTS id at the top of the list.
*/
import test from "node:test";
import assert from "node:assert/strict";
import fs from "node:fs";
import os from "node:os";
import path from "node:path";
const TEST_DATA_DIR = fs.mkdtempSync(path.join(os.tmpdir(), "omniroute-catalog-auto-"));
process.env.DATA_DIR = TEST_DATA_DIR;
process.env.API_KEY_SECRET = process.env.API_KEY_SECRET || "catalog-auto-test-secret";
const core = await import("../../src/lib/db/core.ts");
const v1ModelsCatalog = await import("../../src/app/api/v1/models/catalog.ts");
const builtinCatalog = await import("../../open-sse/services/autoCombo/builtinCatalog.ts");
function resetStorage() {
core.resetDbInstance();
fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true });
fs.mkdirSync(TEST_DATA_DIR, { recursive: true });
}
test.beforeEach(() => {
resetStorage();
});
test.after(() => {
core.resetDbInstance();
fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true });
});
test("#4164 /v1/models advertises every built-in auto/* combo", async () => {
const response = await v1ModelsCatalog.getUnifiedModelsResponse(
new Request("http://localhost/api/v1/models")
);
assert.equal(response.status, 200);
const body = (await response.json()) as { data: Array<{ id: string; owned_by?: string }> };
const ids = new Set(body.data.map((m) => m.id));
const expected = Object.keys(builtinCatalog.AUTO_TEMPLATE_VARIANTS);
assert.ok(expected.length > 0, "sanity: there are built-in auto/* variants");
for (const autoId of expected) {
assert.ok(ids.has(autoId), `expected /v1/models to advertise ${autoId}`);
}
// Spot-check a couple of well-known ones and their owner tag.
const bestCoding = body.data.find((m) => m.id === "auto/best-coding");
assert.ok(bestCoding, "auto/best-coding should be listed");
assert.equal(bestCoding?.owned_by, "combo");
});
test("#4164 auto/* combos appear at the top of the list", async () => {
const response = await v1ModelsCatalog.getUnifiedModelsResponse(
new Request("http://localhost/api/v1/models")
);
const body = (await response.json()) as { data: Array<{ id: string }> };
const expected = Object.keys(builtinCatalog.AUTO_TEMPLATE_VARIANTS);
// The first N entries (N = number of auto/* variants) should all be auto/*.
const head = body.data.slice(0, expected.length).map((m) => m.id);
for (const id of head) {
assert.match(id, /^auto\//, `top-of-list entry ${id} should be an auto/* combo`);
}
});
test("#4164 no duplicate auto/* ids even if a persisted combo shadows one", async () => {
// Defensive: even if a DB combo were named like an auto/* id, the listing must
// not emit the id twice.
const response = await v1ModelsCatalog.getUnifiedModelsResponse(
new Request("http://localhost/api/v1/models")
);
const body = (await response.json()) as { data: Array<{ id: string }> };
const autoIds = body.data.map((m) => m.id).filter((id) => id.startsWith("auto/"));
assert.equal(autoIds.length, new Set(autoIds).size, "auto/* ids must be unique");
});
test("#4189 every auto/* entry exposes token limits + baseline capabilities", async () => {
// #4164 emitted a bare auto/* entry (no token metadata). #4189 enriches each with
// the combo's advertised context/output limits + baseline capabilities so
// OpenAI-compatible clients that build their picker from /v1/models get a context
// window before the first request. Without the fix these fields are absent.
const response = await v1ModelsCatalog.getUnifiedModelsResponse(
new Request("http://localhost/api/v1/models")
);
assert.equal(response.status, 200);
const body = (await response.json()) as {
data: Array<{
id: string;
context_length?: number;
max_input_tokens?: number;
max_output_tokens?: number;
capabilities?: Record<string, boolean>;
}>;
};
const autoEntries = body.data.filter((m) => m.id.startsWith("auto/"));
assert.ok(autoEntries.length > 0, "sanity: at least one auto/* entry is listed");
for (const entry of autoEntries) {
assert.equal(
typeof entry.context_length,
"number",
`${entry.id} must expose a numeric context_length`
);
assert.ok((entry.context_length ?? 0) > 0, `${entry.id} context_length must be positive`);
assert.equal(typeof entry.max_input_tokens, "number", `${entry.id} must expose max_input_tokens`);
assert.equal(
typeof entry.max_output_tokens,
"number",
`${entry.id} must expose max_output_tokens`
);
assert.ok((entry.max_output_tokens ?? 0) > 0, `${entry.id} max_output_tokens must be positive`);
assert.ok(
entry.capabilities && typeof entry.capabilities === "object",
`${entry.id} must expose a capabilities map`
);
}
});

View File

@@ -1357,7 +1357,12 @@ test("v1 models catalog includes context_length for individual chat models", asy
new Request("http://localhost/api/v1/models")
);
const body = (await response.json()) as any;
const chatModels = body.data.filter((item) => !item.type || item.type === "chat");
// Individual chat models only — combos/routers (owned_by "combo", incl. the
// built-in auto/* entries from #4164) resolve dynamically and have no fixed
// context_length, so they are not "individual chat models" for this check.
const chatModels = body.data.filter(
(item) => (!item.type || item.type === "chat") && item.owned_by !== "combo"
);
assert.equal(response.status, 200);
assert.ok(chatModels.length > 0, "should have at least one chat model");

View File

@@ -0,0 +1,134 @@
import { test } from "node:test";
import assert from "node:assert/strict";
import {
NO_THINKING_PREFIX,
isNoThinkingAlias,
stripNoThinkingAlias,
toNoThinkingAlias,
shouldExposeNoThinkingAlias,
appendNoThinkingVariants,
applyNoThinkingAlias,
} from "../../open-sse/utils/noThinkingAlias.ts";
// ── prefix predicates ────────────────────────────────────────────────────────
test("NO_THINKING_PREFIX is the documented gateway prefix", () => {
assert.equal(NO_THINKING_PREFIX, "claude-3-omniroute-no-thinking/");
});
test("isNoThinkingAlias detects the prefix only", () => {
assert.equal(isNoThinkingAlias("claude-3-omniroute-no-thinking/anthropic/claude-opus-4-5"), true);
assert.equal(isNoThinkingAlias("anthropic/claude-opus-4-5"), false);
assert.equal(isNoThinkingAlias("claude-opus-4-5"), false);
// non-strings never match
assert.equal(isNoThinkingAlias(undefined as unknown as string), false);
assert.equal(isNoThinkingAlias(123 as unknown as string), false);
});
test("stripNoThinkingAlias unwraps the prefix and passes plain ids through", () => {
assert.equal(
stripNoThinkingAlias("claude-3-omniroute-no-thinking/anthropic/claude-opus-4-5"),
"anthropic/claude-opus-4-5"
);
assert.equal(stripNoThinkingAlias("claude-opus-4-5"), "claude-opus-4-5");
});
test("toNoThinkingAlias round-trips with stripNoThinkingAlias", () => {
const real = "anthropic/claude-sonnet-4-6";
const alias = toNoThinkingAlias(real);
assert.equal(alias, "claude-3-omniroute-no-thinking/anthropic/claude-sonnet-4-6");
assert.equal(isNoThinkingAlias(alias), true);
assert.equal(stripNoThinkingAlias(alias), real);
});
// ── request-side suppression ─────────────────────────────────────────────────
test("applyNoThinkingAlias rewrites the model and disables thinking (Claude format)", () => {
const body: Record<string, unknown> = {
model: "claude-3-omniroute-no-thinking/anthropic/claude-opus-4-5",
thinking: { type: "enabled", budget_tokens: 8000 },
reasoning_effort: "high",
messages: [],
};
const res = applyNoThinkingAlias(body, { claudeFormat: true });
assert.equal(res.applied, true);
assert.equal(res.realModel, "anthropic/claude-opus-4-5");
assert.equal(body.model, "anthropic/claude-opus-4-5");
assert.deepEqual(body.thinking, { type: "disabled" });
assert.ok(!("reasoning_effort" in body), "reasoning_effort must be stripped");
});
test("applyNoThinkingAlias strips reasoning fields without a thinking block (OpenAI format)", () => {
const body: Record<string, unknown> = {
model: "claude-3-omniroute-no-thinking/openai/gpt-5.4",
reasoning_effort: "high",
reasoning: { effort: "high" },
messages: [],
};
const res = applyNoThinkingAlias(body, { claudeFormat: false });
assert.equal(res.applied, true);
assert.equal(body.model, "openai/gpt-5.4");
assert.ok(!("thinking" in body), "no Claude thinking block on an OpenAI body");
assert.ok(!("reasoning_effort" in body), "reasoning_effort must be stripped");
assert.ok(!("reasoning" in body), "reasoning must be stripped");
});
test("applyNoThinkingAlias is a no-op for plain models", () => {
const body: Record<string, unknown> = { model: "anthropic/claude-opus-4-5", thinking: { type: "enabled" } };
const res = applyNoThinkingAlias(body, { claudeFormat: true });
assert.equal(res.applied, false);
assert.equal(body.model, "anthropic/claude-opus-4-5");
assert.deepEqual(body.thinking, { type: "enabled" }, "thinking is left untouched when not an alias");
});
test("applyNoThinkingAlias ignores a malformed prefix-only model", () => {
const body: Record<string, unknown> = { model: "claude-3-omniroute-no-thinking/" };
const res = applyNoThinkingAlias(body, { claudeFormat: true });
assert.equal(res.applied, false);
assert.equal(body.model, "claude-3-omniroute-no-thinking/", "left untouched when nothing follows the prefix");
});
// ── catalog gating ───────────────────────────────────────────────────────────
const entry = (id: string, owned_by = "anthropic") => ({ id, object: "model", owned_by });
test("shouldExposeNoThinkingAlias accepts a Claude reasoning model that honors disabled", () => {
assert.equal(shouldExposeNoThinkingAlias(entry("claude-opus-4-5")), true);
assert.equal(shouldExposeNoThinkingAlias(entry("anthropic/claude-sonnet-4-6")), true);
});
test("shouldExposeNoThinkingAlias rejects models where suppression is meaningless", () => {
// gpt-4o does not support thinking
assert.equal(shouldExposeNoThinkingAlias(entry("gpt-4o", "openai")), false);
// fable-5 rejects thinking.type:disabled — a no-thinking variant would be a lie
assert.equal(shouldExposeNoThinkingAlias(entry("claude-fable-5")), false);
// combos are virtual, never aliased
assert.equal(shouldExposeNoThinkingAlias(entry("my-combo", "combo")), false);
// never double-alias
assert.equal(
shouldExposeNoThinkingAlias(entry("claude-3-omniroute-no-thinking/anthropic/claude-opus-4-5")),
false
);
});
test("appendNoThinkingVariants adds one variant per eligible model and preserves the rest", () => {
const models = [
entry("claude-opus-4-5"),
entry("gpt-4o", "openai"),
entry("claude-fable-5"),
];
const out = appendNoThinkingVariants(models);
const ids = out.map((m) => m.id);
assert.ok(ids.includes("claude-3-omniroute-no-thinking/claude-opus-4-5"), "eligible model gets a variant");
assert.ok(!ids.includes("claude-3-omniroute-no-thinking/gpt-4o"), "non-thinking model has no variant");
assert.ok(!ids.includes("claude-3-omniroute-no-thinking/claude-fable-5"), "reject-disabled model has no variant");
assert.equal(out.length, models.length + 1, "exactly one variant appended");
// originals preserved up front
assert.deepEqual(out.slice(0, 3), models);
});
test("appendNoThinkingVariants returns the same array reference when nothing is eligible", () => {
const models = [entry("gpt-4o", "openai")];
assert.equal(appendNoThinkingVariants(models), models);
});

View File

@@ -2,11 +2,14 @@ import test from "node:test";
import assert from "node:assert/strict";
import {
attachOmniRouteMetaHeaders,
buildOmniRouteResponseMetaHeaders,
buildOmniRouteSseMetadataComment,
formatOmniRouteCost,
getOmniRouteTokenCounts,
} from "../../src/domain/omnirouteResponseMeta.ts";
import { APP_CONFIG } from "../../src/shared/constants/appConfig.ts";
import { OMNIROUTE_RESPONSE_HEADERS } from "../../src/shared/constants/headers.ts";
test("getOmniRouteTokenCounts normalizes common usage shapes", () => {
assert.deepEqual(
@@ -47,6 +50,57 @@ test("buildOmniRouteResponseMetaHeaders formats provider alias, tokens, latency,
assert.equal(headers["X-OmniRoute-Response-Cost"], "0.0012345679");
});
test("buildOmniRouteResponseMetaHeaders always emits X-OmniRoute-Version", () => {
const headers = buildOmniRouteResponseMetaHeaders({ provider: "openai", model: "gpt" });
assert.equal(headers[OMNIROUTE_RESPONSE_HEADERS.version], APP_CONFIG.version);
// Even with no provider/model at all, the version is still attached.
const bare = buildOmniRouteResponseMetaHeaders({});
assert.equal(bare[OMNIROUTE_RESPONSE_HEADERS.version], APP_CONFIG.version);
});
test("buildOmniRouteResponseMetaHeaders emits X-OmniRoute-Request-Id only when provided", () => {
const withId = buildOmniRouteResponseMetaHeaders({ model: "gpt", requestId: "req-123" });
assert.equal(withId[OMNIROUTE_RESPONSE_HEADERS.requestId], "req-123");
const noId = buildOmniRouteResponseMetaHeaders({ model: "gpt" });
assert.equal(noId[OMNIROUTE_RESPONSE_HEADERS.requestId], undefined);
const nullId = buildOmniRouteResponseMetaHeaders({ model: "gpt", requestId: null });
assert.equal(nullId[OMNIROUTE_RESPONSE_HEADERS.requestId], undefined);
const blankId = buildOmniRouteResponseMetaHeaders({ model: "gpt", requestId: " " });
assert.equal(blankId[OMNIROUTE_RESPONSE_HEADERS.requestId], undefined);
});
test("attachOmniRouteMetaHeaders mutates a Headers instance in place, preserving existing entries", () => {
const headers = new Headers({ "Content-Type": "application/json" });
attachOmniRouteMetaHeaders(headers, {
provider: "openai",
model: "gpt",
requestId: "req-abc",
});
assert.equal(headers.get("Content-Type"), "application/json");
assert.equal(headers.get(OMNIROUTE_RESPONSE_HEADERS.version), APP_CONFIG.version);
assert.equal(headers.get(OMNIROUTE_RESPONSE_HEADERS.requestId), "req-abc");
assert.equal(headers.get(OMNIROUTE_RESPONSE_HEADERS.model), "gpt");
});
test("attachOmniRouteMetaHeaders mutates a plain record in place, preserving existing entries", () => {
const headers: Record<string, string> = { "Content-Type": "application/json" };
attachOmniRouteMetaHeaders(headers, {
provider: "openai",
model: "gpt",
});
assert.equal(headers["Content-Type"], "application/json");
assert.equal(headers[OMNIROUTE_RESPONSE_HEADERS.version], APP_CONFIG.version);
assert.equal(headers[OMNIROUTE_RESPONSE_HEADERS.model], "gpt");
// No requestId provided → header omitted.
assert.equal(headers[OMNIROUTE_RESPONSE_HEADERS.requestId], undefined);
});
test("buildOmniRouteSseMetadataComment emits comment lines compatible with SSE", () => {
const comment = buildOmniRouteSseMetadataComment({
provider: "openai",

View File

@@ -0,0 +1,68 @@
/**
* Verbosity mapping across the OpenAI Chat <-> Responses request translators.
*
* Chat Completions carries GPT-5 verbosity as top-level `verbosity`; the Responses API
* nests it as `text.verbosity`. These tests pin both directions so the hint is not lost
* when a request crosses formats (e.g. a Chat client routed to a Responses backend).
*/
import test from "node:test";
import assert from "node:assert/strict";
import {
openaiToOpenAIResponsesRequest,
openaiResponsesToOpenAIRequest,
} from "../../open-sse/translator/request/openai-responses.ts";
function asRecord(value: unknown): Record<string, unknown> {
return value as Record<string, unknown>;
}
test("Chat -> Responses maps verbosity to text.verbosity", () => {
const out = asRecord(
openaiToOpenAIResponsesRequest(
"gpt-5.5",
{ model: "gpt-5.5", messages: [{ role: "user", content: "hi" }], verbosity: "low" },
true,
{}
)
);
assert.deepEqual(out.text, { verbosity: "low" });
assert.equal(out.verbosity, undefined);
});
test("Chat -> Responses ignores an invalid verbosity value", () => {
const out = asRecord(
openaiToOpenAIResponsesRequest(
"gpt-5.5",
{ model: "gpt-5.5", messages: [{ role: "user", content: "hi" }], verbosity: "loud" },
true,
{}
)
);
assert.equal(out.text, undefined);
});
test("Responses -> Chat maps text.verbosity to top-level verbosity and drops text", () => {
const out = asRecord(
openaiResponsesToOpenAIRequest(
"gpt-5.5",
{ model: "gpt-5.5", input: [{ role: "user", content: "hi" }], text: { verbosity: "high" } },
false,
{}
)
);
assert.equal(out.verbosity, "high");
assert.equal(out.text, undefined);
});
test("Responses -> Chat drops a stray non-verbosity text wrapper", () => {
const out = asRecord(
openaiResponsesToOpenAIRequest(
"gpt-5.5",
{ model: "gpt-5.5", input: [{ role: "user", content: "hi" }], text: { format: { type: "json" } } },
false,
{}
)
);
assert.equal(out.text, undefined);
assert.equal(out.verbosity, undefined);
});

View File

@@ -0,0 +1,32 @@
import test from "node:test";
import assert from "node:assert/strict";
import { readFileSync } from "node:fs";
import { fileURLToPath } from "node:url";
import yaml from "js-yaml";
// Regression guard: the OpenAI-compatible chat WebSocket endpoint (/api/v1/ws)
// must be documented in openapi.yaml so it shows up on the dashboard's
// "API Endpoints" page (which renders /api/openapi/spec, parsed from this file).
// The route (src/app/api/v1/ws/route.ts) shipped in v3.6.6 but was never listed
// in the spec, so it was invisible in the endpoints reference.
const ROOT = fileURLToPath(new URL("../../", import.meta.url));
const spec = yaml.load(readFileSync(ROOT + "docs/reference/openapi.yaml", "utf8")) as {
paths: Record<string, Record<string, { tags?: string[]; security?: unknown[]; responses?: Record<string, unknown> }>>;
};
test("openapi.yaml documents the /api/v1/ws chat WebSocket endpoint", () => {
const entry = spec.paths["/api/v1/ws"];
assert.ok(entry, "/api/v1/ws must be present in openapi.yaml paths");
assert.ok(entry.get, "/api/v1/ws must document the GET (handshake/upgrade) operation");
});
test("/api/v1/ws is tagged, authenticated and documents the WS upgrade responses", () => {
const op = spec.paths["/api/v1/ws"].get;
assert.ok((op.tags ?? []).length > 0, "should be tagged so it groups on the endpoints page");
assert.ok(Array.isArray(op.security) && op.security.length > 0, "should require auth (BearerAuth)");
const responses = op.responses ?? {};
for (const code of ["101", "426"]) {
assert.ok(code in responses, `should document the ${code} WebSocket response`);
}
});

View File

@@ -59,7 +59,10 @@ describe("transformToOmniRoute", () => {
assert.strictEqual(result["gemini-cli"]["gemini-2.5-flash"].input, 0.3);
});
test("skips non-chat models (embedding, image, audio)", () => {
test("ingests non-chat models (embedding token + image per-image)", () => {
// Phase 2 (cost-telemetry parity): non-chat modes are no longer skipped.
// Token-priced modes (embedding) are scaled to $/1M like chat; non-token
// modes (image) carry their per-image cost through verbatim as absolute USD.
const raw = {
"openai/text-embedding-3-small": {
input_cost_per_token: 0.00000002,
@@ -67,19 +70,43 @@ describe("transformToOmniRoute", () => {
litellm_provider: "openai",
mode: "embedding",
},
"openai/gpt-image-2": {
"openai/dall-e-3": {
input_cost_per_token: 0,
output_cost_per_token: 0,
litellm_provider: "openai",
mode: "image_generation",
output_cost_per_image: 0.04,
},
};
const result = transformToOmniRoute(raw);
const embedding = result.openai?.["text-embedding-3-small"];
assert.ok(embedding, "Should ingest token-priced embedding model");
assert.strictEqual(embedding.input, 0.02);
assert.strictEqual(embedding.mode, "embedding");
const image = result.openai?.["dall-e-3"];
assert.ok(image, "Should ingest image model with per-image cost");
assert.strictEqual(image.output_cost_per_image, 0.04);
assert.strictEqual(image.mode, "image_generation");
});
test("skips models with no token AND no non-token pricing", () => {
const raw = {
"openai/metadata-only": {
litellm_provider: "openai",
mode: "image_generation",
},
};
const result = transformToOmniRoute(raw);
// openai key should not exist since all models were filtered
const openaiModels = result.openai || {};
assert.strictEqual(Object.keys(openaiModels).length, 0, "Should skip non-chat models");
assert.strictEqual(
Object.keys(openaiModels).length,
0,
"Should skip models carrying no pricing of any kind"
);
});
test("includes cache pricing when available", () => {

View File

@@ -0,0 +1,54 @@
import { test } from "node:test";
import assert from "node:assert/strict";
import { transformToOmniRoute } from "../../src/lib/pricingSync.ts";
test("transformToOmniRoute ingests an image model's per-image cost", () => {
const out = transformToOmniRoute({
"dall-e-3": {
mode: "image_generation",
litellm_provider: "openai",
output_cost_per_image: 0.04,
},
});
assert.equal(out.openai?.["dall-e-3"]?.output_cost_per_image, 0.04);
});
test("transformToOmniRoute ingests an audio (per-second) model", () => {
const out = transformToOmniRoute({
"whisper-1": {
mode: "audio_transcription",
litellm_provider: "openai",
input_cost_per_second: 0.0001,
},
});
assert.equal(out.openai?.["whisper-1"]?.input_cost_per_second, 0.0001);
});
test("transformToOmniRoute still ingests chat token pricing (no regression)", () => {
const out = transformToOmniRoute({
"gpt-4o": {
mode: "chat",
litellm_provider: "openai",
input_cost_per_token: 0.0000025,
output_cost_per_token: 0.00001,
},
});
assert.equal(out.openai?.["gpt-4o"]?.input, 2.5);
assert.equal(out.openai?.["gpt-4o"]?.output, 10);
});
test("transformToOmniRoute maps newly-covered providers", () => {
const out = transformToOmniRoute({
"mistral-large": {
mode: "chat",
litellm_provider: "mistral",
input_cost_per_token: 0.000002,
output_cost_per_token: 0.000006,
},
"grok-2": {
mode: "chat",
litellm_provider: "xai",
input_cost_per_token: 0.000002,
output_cost_per_token: 0.00001,
},
});
assert.ok(out.mistral?.["mistral-large"]);
assert.ok(out.xai?.["grok-2"]);
});

Some files were not shown because too many files have changed in this diff Show More