Revert "fix(config): externalize ws for copilot-m365-web executor (#6098, closes #6062)"

This reverts commit e61b75f007.
This commit is contained in:
Diego Rodrigues de Sa e Souza
2026-07-03 16:40:11 -03:00
parent e61b75f007
commit 604afeacf4
510 changed files with 6988 additions and 31652 deletions

View File

@@ -1,279 +0,0 @@
/**
* Integration tests for /api/cli-tools/codewhale-settings
*
* CodeWhale (https://github.com/Hmbown/CodeWhale) is the actively-maintained
* successor to DeepSeek TUI (same author, renamed project). This route mirrors
* deepseek-tui-settings/route.ts but writes/reads a dual config path:
* - primary: ~/.codewhale/config.toml
* - legacy: ~/.deepseek/config.toml (kept in sync when it already exists,
* so users upgrading their CLI binary keep working)
*/
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-codewhale-settings-"));
process.env.DATA_DIR = TEST_DATA_DIR;
process.env.API_KEY_SECRET = "test-api-key-secret-codewhale";
process.env.JWT_SECRET = "test-jwt-secret-codewhale";
const core = await import("../../src/lib/db/core.ts");
const localDb = await import("../../src/lib/localDb.ts");
const { GET, POST, DELETE } = await import("../../src/app/api/cli-tools/codewhale-settings/route.ts");
async function resetStorage() {
delete process.env.INITIAL_PASSWORD;
core.resetDbInstance();
fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true });
fs.mkdirSync(TEST_DATA_DIR, { recursive: true });
}
async function enableAuth() {
process.env.INITIAL_PASSWORD = "test-bootstrap";
await localDb.updateSettings({ requireLogin: true, password: "" });
}
test.beforeEach(async () => {
await resetStorage();
});
// ── Test 1: GET without auth → 401 ──────────────────────────────────────────
test("codewhale-settings GET: returns 401 when auth required and no token", async () => {
await enableAuth();
const res = await GET(new Request("http://localhost/api/cli-tools/codewhale-settings"));
assert.equal(res.status, 401, `Expected 401, got ${res.status}`);
});
// ── Test 2: GET without auth requirement → 200 ───────────────────────────────
test("codewhale-settings GET: returns 200 when auth not required", async () => {
const res = await GET(new Request("http://localhost/api/cli-tools/codewhale-settings"));
assert.equal(res.status, 200, `Expected 200, got ${res.status}`);
const body = await res.json();
assert.ok(
"installed" in body || "config" in body,
"Response should contain installed or config field"
);
});
// ── Test 3: POST with invalid body → 400 ─────────────────────────────────────
test("codewhale-settings POST: 400 when baseUrl is missing", async () => {
const res = await POST(
new Request("http://localhost/api/cli-tools/codewhale-settings", {
method: "POST",
headers: { "content-type": "application/json" },
body: JSON.stringify({ apiKey: "sk-test", model: "deepseek-v4-pro" }),
})
);
assert.equal(res.status, 400, `Expected 400, got ${res.status}`);
const body = await res.json();
assert.ok(body.error !== undefined);
});
test("codewhale-settings POST: 400 when model is missing", async () => {
const res = await POST(
new Request("http://localhost/api/cli-tools/codewhale-settings", {
method: "POST",
headers: { "content-type": "application/json" },
body: JSON.stringify({ baseUrl: "http://localhost:20128", apiKey: "sk-test" }),
})
);
assert.equal(res.status, 400, `Expected 400, got ${res.status}`);
});
// ── Test 4: POST with valid body → writes PRIMARY config.toml only (no legacy dir) ──
test("codewhale-settings POST: writes primary ~/.codewhale/config.toml for a fresh install", async () => {
const tmpHome = fs.mkdtempSync(path.join(os.tmpdir(), "codewhale-home-"));
const origHome = process.env.HOME;
process.env.HOME = tmpHome;
try {
const res = await POST(
new Request("http://localhost/api/cli-tools/codewhale-settings", {
method: "POST",
headers: { "content-type": "application/json" },
body: JSON.stringify({
baseUrl: "http://localhost:20128",
apiKey: "sk-test-codewhale-key",
model: "deepseek-v4-pro",
}),
})
);
assert.ok([200, 403, 500].includes(res.status), `Unexpected status ${res.status}`);
if (res.status === 200) {
const body = await res.json();
assert.equal(body.success, true);
const primaryPath = path.join(tmpHome, ".codewhale", "config.toml");
assert.ok(fs.existsSync(primaryPath), "Primary ~/.codewhale/config.toml must be written");
const content = fs.readFileSync(primaryPath, "utf-8");
assert.ok(content.includes("managed by OmniRoute"), "Config should have OmniRoute marker");
assert.ok(content.includes("http://localhost:20128"), "Config should contain base URL");
assert.ok(content.includes("[openai]"), "Config should have [openai] section");
// No legacy ~/.deepseek dir existed before the write — must NOT be created.
const legacyPath = path.join(tmpHome, ".deepseek", "config.toml");
assert.ok(
!fs.existsSync(legacyPath),
"Legacy ~/.deepseek/config.toml must not be created for a fresh install"
);
}
} finally {
process.env.HOME = origHome;
fs.rmSync(tmpHome, { recursive: true, force: true });
}
});
// ── Test 5: POST keeps an EXISTING legacy ~/.deepseek config in sync ────────
test("codewhale-settings POST: syncs an existing legacy ~/.deepseek/config.toml", async () => {
const tmpHome = fs.mkdtempSync(path.join(os.tmpdir(), "codewhale-home-legacy-"));
const origHome = process.env.HOME;
process.env.HOME = tmpHome;
try {
// Simulate an existing DeepSeek TUI install (pre-CodeWhale upgrade).
const legacyDir = path.join(tmpHome, ".deepseek");
fs.mkdirSync(legacyDir, { recursive: true });
fs.writeFileSync(path.join(legacyDir, "config.toml"), 'provider = "deepseek"\n');
const res = await POST(
new Request("http://localhost/api/cli-tools/codewhale-settings", {
method: "POST",
headers: { "content-type": "application/json" },
body: JSON.stringify({
baseUrl: "http://localhost:20128",
apiKey: "sk-test-codewhale-key",
model: "deepseek-v4-flash",
}),
})
);
assert.ok([200, 403, 500].includes(res.status), `Unexpected status ${res.status}`);
if (res.status === 200) {
const primaryPath = path.join(tmpHome, ".codewhale", "config.toml");
const legacyPath = path.join(tmpHome, ".deepseek", "config.toml");
assert.ok(fs.existsSync(primaryPath), "Primary config must be written");
assert.ok(fs.existsSync(legacyPath), "Legacy config must still exist");
const primaryContent = fs.readFileSync(primaryPath, "utf-8");
const legacyContent = fs.readFileSync(legacyPath, "utf-8");
assert.ok(primaryContent.includes("http://localhost:20128"));
assert.ok(
legacyContent.includes("http://localhost:20128"),
"Legacy config must be kept in sync with the new base URL"
);
assert.equal(primaryContent, legacyContent, "Primary and legacy configs should match");
}
} finally {
process.env.HOME = origHome;
fs.rmSync(tmpHome, { recursive: true, force: true });
}
});
// ── Test 6: GET reads from legacy path when only legacy config exists ───────
test("codewhale-settings GET: falls back to legacy ~/.deepseek/config.toml when primary is absent", async () => {
const tmpHome = fs.mkdtempSync(path.join(os.tmpdir(), "codewhale-home-getlegacy-"));
const origHome = process.env.HOME;
process.env.HOME = tmpHome;
try {
const legacyDir = path.join(tmpHome, ".deepseek");
fs.mkdirSync(legacyDir, { recursive: true });
fs.writeFileSync(
path.join(legacyDir, "config.toml"),
'# managed by OmniRoute (plan 14)\n[openai]\nbase_url = "http://localhost:20128"\n'
);
const res = await GET(new Request("http://localhost/api/cli-tools/codewhale-settings"));
assert.equal(res.status, 200);
const body = await res.json();
if (body.config) {
assert.ok(body.config.includes("managed by OmniRoute"));
assert.equal(body.hasOmniRoute, true);
}
} finally {
process.env.HOME = origHome;
fs.rmSync(tmpHome, { recursive: true, force: true });
}
});
// ── Test 7: DELETE → removes both primary and legacy config files ───────────
test("codewhale-settings DELETE: removes primary and legacy config files", async () => {
const tmpHome = fs.mkdtempSync(path.join(os.tmpdir(), "codewhale-home-del-"));
const origHome = process.env.HOME;
process.env.HOME = tmpHome;
try {
const primaryDir = path.join(tmpHome, ".codewhale");
const legacyDir = path.join(tmpHome, ".deepseek");
fs.mkdirSync(primaryDir, { recursive: true });
fs.mkdirSync(legacyDir, { recursive: true });
fs.writeFileSync(
path.join(primaryDir, "config.toml"),
'# managed by OmniRoute (plan 14)\n[openai]\nbase_url = "http://localhost:20128"\n'
);
fs.writeFileSync(
path.join(legacyDir, "config.toml"),
'# managed by OmniRoute (plan 14)\n[openai]\nbase_url = "http://localhost:20128"\n'
);
const res = await DELETE(
new Request("http://localhost/api/cli-tools/codewhale-settings", { method: "DELETE" })
);
assert.ok([200, 403, 500].includes(res.status), `Expected 200/403/500, got ${res.status}`);
if (res.status === 200) {
const body = await res.json();
assert.equal(body.success, true);
assert.ok(!fs.existsSync(path.join(primaryDir, "config.toml")), "Primary config removed");
assert.ok(!fs.existsSync(path.join(legacyDir, "config.toml")), "Legacy config removed");
}
} finally {
process.env.HOME = origHome;
fs.rmSync(tmpHome, { recursive: true, force: true });
}
});
// ── Test 8: Error sanitization (Hard Rule #12) ───────────────────────────────
test("codewhale-settings: error responses do not leak stack traces", async () => {
const badReq = new Request("http://localhost/api/cli-tools/codewhale-settings", {
method: "POST",
headers: { "content-type": "application/json" },
body: "{ bad json }",
});
const res = await POST(badReq);
const bodyStr = JSON.stringify(await res.json());
assert.ok(
!bodyStr.match(/\s+at\s+\/[^\s]/),
"Error response must not contain absolute-path stack traces"
);
});
// ── Test 9: Hard Rule #13 (no exec/spawn) ────────────────────────────────────
test("codewhale-settings route.ts: does not call exec() or spawn() directly", () => {
const routePath = path.resolve(
import.meta.dirname,
"../../src/app/api/cli-tools/codewhale-settings/route.ts"
);
const content = fs.readFileSync(routePath, "utf-8");
assert.ok(!content.match(/\bexec\s*\(/), "Handler must not use exec()");
assert.ok(!content.match(/\bspawn\s*\(/), "Handler must not use spawn()");
});
test.after(async () => {
await resetStorage();
fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true });
delete process.env.DATA_DIR;
delete process.env.API_KEY_SECRET;
delete process.env.JWT_SECRET;
});

View File

@@ -13,10 +13,8 @@
* Prerequisites when running for real:
* - npm is in PATH
* - Network access to registry.npmjs.org
* - Ports 20130 (9router), 8317 (cliproxy), and 8080 (bifrost) are available
* - Ports 20130 (9router) and 8317 (cliproxy) are available
* - DATA_DIR is writable
* - Bifrost lazily downloads its Go binary from downloads.getmaxim.ai on first
* start, so the bifrost block additionally needs network access to that host.
*/
import { describe, it } from "node:test";
@@ -247,86 +245,6 @@ describe("cliproxy — full lifecycle (opt-in, RUN_SERVICES_INT=1)", () => {
});
});
// ---------------------------------------------------------------------------
// bifrost lifecycle
// ---------------------------------------------------------------------------
describe("bifrost — full lifecycle (opt-in, RUN_SERVICES_INT=1)", () => {
it("STEP 1: install bifrost (latest)", async (t) => {
if (maybeSkip(t)) return;
const { status, body } = await apiPost("/api/services/bifrost/install", {
version: "latest",
});
assert.ok(
status === 200,
`Expected 200 from install, got ${status}: ${JSON.stringify(body).slice(0, 300)}`
);
const b = body as Record<string, unknown>;
assert.ok(b.ok === true, "install response must have ok:true");
assert.ok(
typeof b.installedVersion === "string",
"install response must have installedVersion"
);
assert.ok(typeof b.durationMs === "number", "install response must have durationMs");
});
it("STEP 2: verify status is stopped after install", async (t) => {
if (maybeSkip(t)) return;
const { status, body } = await apiGet("/api/services/bifrost/status");
assert.equal(status, 200);
const b = body as Record<string, unknown>;
assert.equal(b.state, "stopped", `Expected stopped state after install, got: ${b.state}`);
assert.ok(
typeof b.installedVersion === "string",
"installedVersion should be set after install"
);
});
it("STEP 3: start bifrost", async (t) => {
if (maybeSkip(t)) return;
const { status, body } = await apiPost("/api/services/bifrost/start");
assert.ok(
status === 200,
`Expected 200 from start, got ${status}: ${JSON.stringify(body).slice(0, 300)}`
);
const b = body as Record<string, unknown>;
assert.ok(
["starting", "running"].includes(b.state as string),
`Expected starting or running, got: ${b.state}`
);
});
it("STEP 4: wait for bifrost to become healthy (≤60s — Go binary download on first start)", async (t) => {
if (maybeSkip(t)) return;
// First start lazily downloads the Go binary, so allow a longer window than
// the 9router/cliproxy blocks (30s). Confirms open question §2b/§6 (Windows +
// headless boot) against a real download.
const finalStatus = await waitForState("/api/services/bifrost/status", "running", 60_000);
const b = finalStatus as Record<string, unknown>;
assert.equal(b.state, "running");
assert.equal(b.health, "healthy");
assert.ok(typeof b.pid === "number", "pid must be a number when running");
assert.equal(b.port, 8080, "bifrost must report its default port 8080");
});
it("STEP 5: stop bifrost", async (t) => {
if (maybeSkip(t)) return;
const { status, body } = await apiPost("/api/services/bifrost/stop");
assert.equal(status, 200);
const b = body as Record<string, unknown>;
assert.ok(
["stopping", "stopped"].includes(b.state as string),
`Expected stopping or stopped, got: ${b.state}`
);
});
it("STEP 6: status returns stopped after stop", async (t) => {
if (maybeSkip(t)) return;
const final = await waitForState("/api/services/bifrost/status", "stopped", 15_000);
assert.equal((final as Record<string, unknown>).state, "stopped");
});
});
// ---------------------------------------------------------------------------
// Security smoke (requires running server)
// ---------------------------------------------------------------------------

View File

@@ -52,18 +52,6 @@ describe("isLocalOnlyPath — /api/services/* and /dashboard/providers/services/
assert.equal(isLocalOnlyPath("/api/services/cliproxy/status"), true);
});
it("returns true for /api/services/bifrost/start", () => {
assert.equal(isLocalOnlyPath("/api/services/bifrost/start"), true);
});
it("returns true for /api/services/bifrost/install", () => {
assert.equal(isLocalOnlyPath("/api/services/bifrost/install"), true);
});
it("returns true for /api/services/bifrost/status", () => {
assert.equal(isLocalOnlyPath("/api/services/bifrost/status"), true);
});
it("returns true for /api/services/ (root prefix)", () => {
assert.equal(isLocalOnlyPath("/api/services/"), true);
});
@@ -122,10 +110,6 @@ describe("isLocalOnlyBypassableByManageScope — /api/services/* is NOT bypassab
it("returns false for /api/services/cliproxy/install", () => {
assert.equal(isLocalOnlyBypassableByManageScope("/api/services/cliproxy/install"), false);
});
it("returns false for /api/services/bifrost/install (spawn-capable)", () => {
assert.equal(isLocalOnlyBypassableByManageScope("/api/services/bifrost/install"), false);
});
});
// ---------------------------------------------------------------------------

View File

@@ -33,10 +33,10 @@
"Content-Type": "application/json",
"User-Agent": "claude-cli/2.1.195 (external, cli)",
"X-App": "cli",
"X-Stainless-Arch": "<ARCH>",
"X-Stainless-Arch": "x64",
"X-Stainless-Helper-Method": "stream",
"X-Stainless-Lang": "js",
"X-Stainless-Os": "<OS>",
"X-Stainless-Os": "Linux",
"X-Stainless-Package-Version": "0.94.0",
"X-Stainless-Retry-Count": "0",
"X-Stainless-Runtime": "node",
@@ -51,10 +51,10 @@
"Content-Type": "application/json",
"User-Agent": "claude-cli/2.1.195 (external, cli)",
"X-App": "cli",
"X-Stainless-Arch": "<ARCH>",
"X-Stainless-Arch": "x64",
"X-Stainless-Helper-Method": "stream",
"X-Stainless-Lang": "js",
"X-Stainless-Os": "<OS>",
"X-Stainless-Os": "Linux",
"X-Stainless-Package-Version": "0.94.0",
"X-Stainless-Retry-Count": "0",
"X-Stainless-Runtime": "node",
@@ -70,10 +70,10 @@
"Content-Type": "application/json",
"User-Agent": "claude-cli/2.1.195 (external, cli)",
"X-App": "cli",
"X-Stainless-Arch": "<ARCH>",
"X-Stainless-Arch": "x64",
"X-Stainless-Helper-Method": "stream",
"X-Stainless-Lang": "js",
"X-Stainless-Os": "<OS>",
"X-Stainless-Os": "Linux",
"X-Stainless-Package-Version": "0.94.0",
"X-Stainless-Retry-Count": "0",
"X-Stainless-Runtime": "node",
@@ -94,18 +94,18 @@
"Accept": "text/event-stream",
"Authorization": "Bearer <TOK>",
"Content-Type": "application/json",
"User-Agent": "Antigravity/4.2.0 (<PLATFORM>) Chrome/142.0.7444.175 Electron/39.2.3"
"User-Agent": "Antigravity/4.2.0 (X11; Linux x86_64) Chrome/142.0.7444.175 Electron/39.2.3"
},
"nonStream": {
"Authorization": "Bearer <TOK>",
"Content-Type": "application/json",
"User-Agent": "Antigravity/4.2.0 (<PLATFORM>) Chrome/142.0.7444.175 Electron/39.2.3"
"User-Agent": "Antigravity/4.2.0 (X11; Linux x86_64) Chrome/142.0.7444.175 Electron/39.2.3"
},
"oauth": {
"Accept": "text/event-stream",
"Authorization": "Bearer <TOK>",
"Content-Type": "application/json",
"User-Agent": "Antigravity/4.2.0 (<PLATFORM>) Chrome/142.0.7444.175 Electron/39.2.3"
"User-Agent": "Antigravity/4.2.0 (X11; Linux x86_64) Chrome/142.0.7444.175 Electron/39.2.3"
}
},
"url": {
@@ -241,18 +241,18 @@
"Accept": "text/event-stream",
"Authorization": "Bearer <TOK>",
"Content-Type": "application/json",
"User-Agent": "Antigravity/4.2.0 (<PLATFORM>) Chrome/142.0.7444.175 Electron/39.2.3"
"User-Agent": "Antigravity/4.2.0 (X11; Linux x86_64) Chrome/142.0.7444.175 Electron/39.2.3"
},
"nonStream": {
"Authorization": "Bearer <TOK>",
"Content-Type": "application/json",
"User-Agent": "Antigravity/4.2.0 (<PLATFORM>) Chrome/142.0.7444.175 Electron/39.2.3"
"User-Agent": "Antigravity/4.2.0 (X11; Linux x86_64) Chrome/142.0.7444.175 Electron/39.2.3"
},
"oauth": {
"Accept": "text/event-stream",
"Authorization": "Bearer <TOK>",
"Content-Type": "application/json",
"User-Agent": "Antigravity/4.2.0 (<PLATFORM>) Chrome/142.0.7444.175 Electron/39.2.3"
"User-Agent": "Antigravity/4.2.0 (X11; Linux x86_64) Chrome/142.0.7444.175 Electron/39.2.3"
}
},
"url": {
@@ -289,52 +289,6 @@
"stream": "https://api.airforce/v1/chat/completions"
}
},
"auggie": {
"format": "openai",
"headers": {
"apiKey": {
"Accept": "text/event-stream",
"Authorization": "Bearer <TOK>",
"Content-Type": "application/json"
},
"nonStream": {
"Authorization": "Bearer <TOK>",
"Content-Type": "application/json"
},
"oauth": {
"Accept": "text/event-stream",
"Authorization": "Bearer <TOK>",
"Content-Type": "application/json"
}
},
"url": {
"nonStream": "auggie://cli/stdio",
"stream": "auggie://cli/stdio"
}
},
"bai": {
"format": "openai",
"headers": {
"apiKey": {
"Accept": "text/event-stream",
"Authorization": "Bearer <TOK>",
"Content-Type": "application/json"
},
"nonStream": {
"Authorization": "Bearer <TOK>",
"Content-Type": "application/json"
},
"oauth": {
"Accept": "text/event-stream",
"Authorization": "Bearer <TOK>",
"Content-Type": "application/json"
}
},
"url": {
"nonStream": "https://api.b.ai/v1/chat/completions",
"stream": "https://api.b.ai/v1/chat/completions"
}
},
"baichuan": {
"format": "openai",
"headers": {
@@ -611,29 +565,6 @@
"stream": "https://api.cerebras.ai/v1/chat/completions"
}
},
"charm-hyper": {
"format": "openai",
"headers": {
"apiKey": {
"Accept": "text/event-stream",
"Authorization": "Bearer <TOK>",
"Content-Type": "application/json"
},
"nonStream": {
"Authorization": "Bearer <TOK>",
"Content-Type": "application/json"
},
"oauth": {
"Accept": "text/event-stream",
"Authorization": "Bearer <TOK>",
"Content-Type": "application/json"
}
},
"url": {
"nonStream": "https://hyper.charm.land/v1/chat/completions",
"stream": "https://hyper.charm.land/v1/chat/completions"
}
},
"chatgpt-web": {
"format": "openai",
"headers": {
@@ -714,10 +645,10 @@
"Content-Type": "application/json",
"User-Agent": "claude-cli/2.1.195 (external, cli)",
"X-App": "cli",
"X-Stainless-Arch": "<ARCH>",
"X-Stainless-Arch": "x64",
"X-Stainless-Helper-Method": "stream",
"X-Stainless-Lang": "js",
"X-Stainless-Os": "<OS>",
"X-Stainless-Os": "Linux",
"X-Stainless-Package-Version": "0.94.0",
"X-Stainless-Retry-Count": "0",
"X-Stainless-Runtime": "node",
@@ -732,10 +663,10 @@
"Content-Type": "application/json",
"User-Agent": "claude-cli/2.1.195 (external, cli)",
"X-App": "cli",
"X-Stainless-Arch": "<ARCH>",
"X-Stainless-Arch": "x64",
"X-Stainless-Helper-Method": "stream",
"X-Stainless-Lang": "js",
"X-Stainless-Os": "<OS>",
"X-Stainless-Os": "Linux",
"X-Stainless-Package-Version": "0.94.0",
"X-Stainless-Retry-Count": "0",
"X-Stainless-Runtime": "node",
@@ -751,10 +682,10 @@
"Content-Type": "application/json",
"User-Agent": "claude-cli/2.1.195 (external, cli)",
"X-App": "cli",
"X-Stainless-Arch": "<ARCH>",
"X-Stainless-Arch": "x64",
"X-Stainless-Helper-Method": "stream",
"X-Stainless-Lang": "js",
"X-Stainless-Os": "<OS>",
"X-Stainless-Os": "Linux",
"X-Stainless-Package-Version": "0.94.0",
"X-Stainless-Retry-Count": "0",
"X-Stainless-Runtime": "node",
@@ -841,35 +772,6 @@
"stream": "https://api.cline.bot/api/v1/chat/completions"
}
},
"clinepass": {
"format": "openai",
"headers": {
"apiKey": {
"Accept": "text/event-stream",
"Authorization": "Bearer <TOK>",
"Content-Type": "application/json",
"HTTP-Referer": "https://cline.bot",
"X-Title": "Cline"
},
"nonStream": {
"Authorization": "Bearer <TOK>",
"Content-Type": "application/json",
"HTTP-Referer": "https://cline.bot",
"X-Title": "Cline"
},
"oauth": {
"Accept": "text/event-stream",
"Authorization": "Bearer <TOK>",
"Content-Type": "application/json",
"HTTP-Referer": "https://cline.bot",
"X-Title": "Cline"
}
},
"url": {
"nonStream": "https://api.cline.bot/api/v1/chat/completions",
"stream": "https://api.cline.bot/api/v1/chat/completions"
}
},
"cloudflare-ai": {
"format": "openai",
"headers": {
@@ -965,7 +867,7 @@
"Authorization": "Bearer <TOK>",
"Content-Type": "application/json",
"Openai-Beta": "responses=experimental",
"User-Agent": "codex-cli/0.142.0 (<OS>; <ARCH>)",
"User-Agent": "codex-cli/0.142.0 (Windows 10.0.26200; x64)",
"Version": "0.142.0",
"X-Codex-Beta-Features": "responses_websockets"
},
@@ -973,7 +875,7 @@
"Authorization": "Bearer <TOK>",
"Content-Type": "application/json",
"Openai-Beta": "responses=experimental",
"User-Agent": "codex-cli/0.142.0 (<OS>; <ARCH>)",
"User-Agent": "codex-cli/0.142.0 (Windows 10.0.26200; x64)",
"Version": "0.142.0",
"X-Codex-Beta-Features": "responses_websockets"
},
@@ -982,7 +884,7 @@
"Authorization": "Bearer <TOK>",
"Content-Type": "application/json",
"Openai-Beta": "responses=experimental",
"User-Agent": "codex-cli/0.142.0 (<OS>; <ARCH>)",
"User-Agent": "codex-cli/0.142.0 (Windows 10.0.26200; x64)",
"Version": "0.142.0",
"X-Codex-Beta-Features": "responses_websockets"
}
@@ -1754,14 +1656,14 @@
"Authorization": "Bearer <TOK>",
"Content-Type": "application/json",
"HTTP-Referer": "https://github.com/Gitlawb/openclaude",
"User-Agent": "OpenClaude/1.0 (<OS>; <ARCH>)",
"User-Agent": "OpenClaude/1.0 (linux; x86_64)",
"X-Title": "OpenClaude CLI"
},
"nonStream": {
"Authorization": "Bearer <TOK>",
"Content-Type": "application/json",
"HTTP-Referer": "https://github.com/Gitlawb/openclaude",
"User-Agent": "OpenClaude/1.0 (<OS>; <ARCH>)",
"User-Agent": "OpenClaude/1.0 (linux; x86_64)",
"X-Title": "OpenClaude CLI"
},
"oauth": {
@@ -1769,7 +1671,7 @@
"Authorization": "Bearer <TOK>",
"Content-Type": "application/json",
"HTTP-Referer": "https://github.com/Gitlawb/openclaude",
"User-Agent": "OpenClaude/1.0 (<OS>; <ARCH>)",
"User-Agent": "OpenClaude/1.0 (linux; x86_64)",
"X-Title": "OpenClaude CLI"
}
},
@@ -1786,14 +1688,14 @@
"Authorization": "Bearer <TOK>",
"Content-Type": "application/json",
"HTTP-Referer": "https://github.com/Gitlawb/openclaude",
"User-Agent": "OpenClaude/1.0 (<OS>; <ARCH>)",
"User-Agent": "OpenClaude/1.0 (linux; x86_64)",
"X-Title": "OpenClaude CLI"
},
"nonStream": {
"Authorization": "Bearer <TOK>",
"Content-Type": "application/json",
"HTTP-Referer": "https://github.com/Gitlawb/openclaude",
"User-Agent": "OpenClaude/1.0 (<OS>; <ARCH>)",
"User-Agent": "OpenClaude/1.0 (linux; x86_64)",
"X-Title": "OpenClaude CLI"
},
"oauth": {
@@ -1801,7 +1703,7 @@
"Authorization": "Bearer <TOK>",
"Content-Type": "application/json",
"HTTP-Referer": "https://github.com/Gitlawb/openclaude",
"User-Agent": "OpenClaude/1.0 (<OS>; <ARCH>)",
"User-Agent": "OpenClaude/1.0 (linux; x86_64)",
"X-Title": "OpenClaude CLI"
}
},
@@ -2755,29 +2657,6 @@
"stream": "https://api.modal.ai/v1/chat/completions"
}
},
"modelscope": {
"format": "openai",
"headers": {
"apiKey": {
"Accept": "text/event-stream",
"Authorization": "Bearer <TOK>",
"Content-Type": "application/json"
},
"nonStream": {
"Authorization": "Bearer <TOK>",
"Content-Type": "application/json"
},
"oauth": {
"Accept": "text/event-stream",
"Authorization": "Bearer <TOK>",
"Content-Type": "application/json"
}
},
"url": {
"nonStream": "https://api-inference.modelscope.cn/v1/chat/completions",
"stream": "https://api-inference.modelscope.cn/v1/chat/completions"
}
},
"monsterapi": {
"format": "openai",
"headers": {
@@ -3008,29 +2887,6 @@
"stream": "https://inference.api.nscale.com/v1/chat/completions"
}
},
"nube": {
"format": "openai",
"headers": {
"apiKey": {
"Accept": "text/event-stream",
"Authorization": "Bearer <TOK>",
"Content-Type": "application/json"
},
"nonStream": {
"Authorization": "Bearer <TOK>",
"Content-Type": "application/json"
},
"oauth": {
"Accept": "text/event-stream",
"Authorization": "Bearer <TOK>",
"Content-Type": "application/json"
}
},
"url": {
"nonStream": "https://ai.nube.sh/api/v1/chat/completions",
"stream": "https://ai.nube.sh/api/v1/chat/completions"
}
},
"nvidia": {
"format": "openai",
"headers": {
@@ -3457,29 +3313,6 @@
"stream": "https://qianfan.baidubce.com/v2/chat/completions"
}
},
"qiniu": {
"format": "openai",
"headers": {
"apiKey": {
"Accept": "text/event-stream",
"Authorization": "Bearer <TOK>",
"Content-Type": "application/json"
},
"nonStream": {
"Authorization": "Bearer <TOK>",
"Content-Type": "application/json"
},
"oauth": {
"Accept": "text/event-stream",
"Authorization": "Bearer <TOK>",
"Content-Type": "application/json"
}
},
"url": {
"nonStream": "https://api.qnaigc.com/v1/chat/completions",
"stream": "https://api.qnaigc.com/v1/chat/completions"
}
},
"qoder": {
"format": "openai",
"headers": {
@@ -3516,13 +3349,13 @@
"Connection": "keep-alive",
"Content-Type": "application/json",
"Sec-Fetch-Mode": "cors",
"User-Agent": "QwenCode/0.19.3 (<OS>; <ARCH>)",
"User-Agent": "QwenCode/0.19.3 (linux; x64)",
"X-Dashscope-AuthType": "qwen-oauth",
"X-Dashscope-CacheControl": "enable",
"X-Dashscope-UserAgent": "QwenCode/0.19.3 (<OS>; <ARCH>)",
"X-Stainless-Arch": "<ARCH>",
"X-Dashscope-UserAgent": "QwenCode/0.19.3 (linux; x64)",
"X-Stainless-Arch": "x64",
"X-Stainless-Lang": "js",
"X-Stainless-Os": "<OS>",
"X-Stainless-Os": "Linux",
"X-Stainless-Package-Version": "5.11.0",
"X-Stainless-Retry-Count": "1",
"X-Stainless-Runtime": "node",
@@ -3534,13 +3367,13 @@
"Connection": "keep-alive",
"Content-Type": "application/json",
"Sec-Fetch-Mode": "cors",
"User-Agent": "QwenCode/0.19.3 (<OS>; <ARCH>)",
"User-Agent": "QwenCode/0.19.3 (linux; x64)",
"X-Dashscope-AuthType": "qwen-oauth",
"X-Dashscope-CacheControl": "enable",
"X-Dashscope-UserAgent": "QwenCode/0.19.3 (<OS>; <ARCH>)",
"X-Stainless-Arch": "<ARCH>",
"X-Dashscope-UserAgent": "QwenCode/0.19.3 (linux; x64)",
"X-Stainless-Arch": "x64",
"X-Stainless-Lang": "js",
"X-Stainless-Os": "<OS>",
"X-Stainless-Os": "Linux",
"X-Stainless-Package-Version": "5.11.0",
"X-Stainless-Retry-Count": "1",
"X-Stainless-Runtime": "node",
@@ -3553,13 +3386,13 @@
"Connection": "keep-alive",
"Content-Type": "application/json",
"Sec-Fetch-Mode": "cors",
"User-Agent": "QwenCode/0.19.3 (<OS>; <ARCH>)",
"User-Agent": "QwenCode/0.19.3 (linux; x64)",
"X-Dashscope-AuthType": "qwen-oauth",
"X-Dashscope-CacheControl": "enable",
"X-Dashscope-UserAgent": "QwenCode/0.19.3 (<OS>; <ARCH>)",
"X-Stainless-Arch": "<ARCH>",
"X-Dashscope-UserAgent": "QwenCode/0.19.3 (linux; x64)",
"X-Stainless-Arch": "x64",
"X-Stainless-Lang": "js",
"X-Stainless-Os": "<OS>",
"X-Stainless-Os": "Linux",
"X-Stainless-Package-Version": "5.11.0",
"X-Stainless-Retry-Count": "1",
"X-Stainless-Runtime": "node",
@@ -3778,29 +3611,6 @@
"stream": "https://api.stepfun.com/v1/chat/completions"
}
},
"sumopod": {
"format": "openai",
"headers": {
"apiKey": {
"Accept": "text/event-stream",
"Authorization": "Bearer <TOK>",
"Content-Type": "application/json"
},
"nonStream": {
"Authorization": "Bearer <TOK>",
"Content-Type": "application/json"
},
"oauth": {
"Accept": "text/event-stream",
"Authorization": "Bearer <TOK>",
"Content-Type": "application/json"
}
},
"url": {
"nonStream": "https://ai.sumopod.com/v1/chat/completions",
"stream": "https://ai.sumopod.com/v1/chat/completions"
}
},
"suno": {
"format": "openai",
"headers": {
@@ -4287,29 +4097,6 @@
"stream": "https://server.self-serve.windsurf.com"
}
},
"x5lab": {
"format": "openai",
"headers": {
"apiKey": {
"Accept": "text/event-stream",
"Authorization": "Bearer <TOK>",
"Content-Type": "application/json"
},
"nonStream": {
"Authorization": "Bearer <TOK>",
"Content-Type": "application/json"
},
"oauth": {
"Accept": "text/event-stream",
"Authorization": "Bearer <TOK>",
"Content-Type": "application/json"
}
},
"url": {
"nonStream": "https://api.x5lab.dev/v1/chat/completions",
"stream": "https://api.x5lab.dev/v1/chat/completions"
}
},
"xai": {
"format": "openai",
"headers": {

View File

@@ -1,32 +0,0 @@
import test from "node:test";
import assert from "node:assert/strict";
const { parseRetryFromErrorText } = await import("../../open-sse/services/accountFallback.ts");
test("parseRetryFromErrorText reads nested ISO retryAfter from a 429 JSON body", () => {
const futureIso = new Date(Date.now() + 120_000).toISOString();
const waitMs = parseRetryFromErrorText(JSON.stringify({ error: { retryAfter: futureIso } }));
assert.ok(waitMs !== null, "expected a parsed wait time, got null");
assert.ok(Math.abs((waitMs as number) - 120_000) <= 2_000, `expected ~120000ms, got ${waitMs}`);
});
test("parseRetryFromErrorText reads top-level retryAfter when nested field is absent", () => {
const futureIso = new Date(Date.now() + 60_000).toISOString();
const waitMs = parseRetryFromErrorText(JSON.stringify({ retryAfter: futureIso }));
assert.ok(waitMs !== null, "expected a parsed wait time, got null");
assert.ok(Math.abs((waitMs as number) - 60_000) <= 2_000, `expected ~60000ms, got ${waitMs}`);
});
test("parseRetryFromErrorText reads millisecond retry hints from 429 JSON bodies", () => {
assert.equal(parseRetryFromErrorText(JSON.stringify({ retry_after_ms: 45_000 })), 45_000);
assert.equal(
parseRetryFromErrorText(JSON.stringify({ error: { retry_after_ms: 12_000 } })),
12_000
);
assert.equal(parseRetryFromErrorText(JSON.stringify({ retryAfterMs: 8_000 })), 8_000);
});
test("parseRetryFromErrorText ignores past ISO retryAfter values in JSON bodies", () => {
const pastIso = new Date(Date.now() - 60_000).toISOString();
assert.equal(parseRetryFromErrorText(JSON.stringify({ error: { retryAfter: pastIso } })), null);
});

View File

@@ -1,44 +0,0 @@
import { describe, it } from "node:test";
import assert from "node:assert";
import { readFileSync } from "node:fs";
const modalPath =
"src/app/(dashboard)/dashboard/providers/[id]/components/modals/EditConnectionModal.tsx";
const source = readFileSync(modalPath, "utf8");
describe("agy Project ID UI support", () => {
it("declares a single Antigravity-family provider gate", () => {
assert.ok(
source.includes(
'const isAntigravityFamily = provider === "antigravity" || provider === "agy";'
),
"isAntigravityFamily must include antigravity and agy without a separate Google Project ID gate"
);
});
it("does not keep the old supportsGoogleProjectId alias", () => {
assert.equal(source.includes("supportsGoogleProjectId"), false);
});
it("uses antigravityProjectIdLabel for Antigravity-family providers", () => {
assert.ok(
source.includes('label={t("antigravityProjectIdLabel")}'),
"projectId label must use Antigravity-family copy"
);
});
it("uses isAntigravityFamily for antigravityClientProfile UI", () => {
assert.ok(
source.includes("{isAntigravityFamily && (\n <div") &&
source.includes('label={t("antigravityClientProfileLabel")}'),
"client profile Select must render for isAntigravityFamily"
);
});
it("uses isAntigravityFamily for client profile save", () => {
assert.ok(
source.includes("if (isAntigravityFamily) {"),
"client profile save must use isAntigravityFamily"
);
});
});

View File

@@ -1,71 +0,0 @@
/**
* Regression for #5899 (PR #5920): the OpenAI-compatible models-discovery URL
* builder must strip a trailing `/v1` UNCONDITIONALLY before appending
* `/v1/models`. A gateway baseUrl like ".../v1/chat/completions" was reduced to
* ".../v1" (the old `else if` skipped the /v1 strip once `/chat/completions`
* matched) and then produced ".../v1/v1/models" — a 308 redirect that blocked
* model discovery. The fix converts the `/v1` strip to an independent `if`
* (guarding against a literal "scheme://v1" authority) in BOTH the general
* discovery path and the `provider === "openai"` custom-base-URL path.
*/
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-5899-"));
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 modelsRoute = await import("../../src/app/api/providers/[id]/models/route.ts");
test.after(() => {
core.resetDbInstance();
fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true });
});
test("#5899 openai gateway baseUrl ending in /v1/chat/completions never probes /v1/v1/models", async () => {
const connection = await providersDb.createProviderConnection({
provider: "openai",
authType: "apikey",
name: "airforce-gateway",
apiKey: "sk-airforce",
providerSpecificData: { baseUrl: "https://api.airforce/v1/chat/completions" },
});
const requestedUrls: string[] = [];
const originalFetch = globalThis.fetch;
globalThis.fetch = async (url) => {
const u = String(url);
requestedUrls.push(u);
// The correctly-stripped candidate must be the one that serves models.
if (u === "https://api.airforce/v1/models") {
return Response.json({ object: "list", data: [{ id: "gpt-4o" }, { id: "gpt-5" }] });
}
// The double-prefixed URL upstream answered with a 308 redirect (#5899).
if (u === "https://api.airforce/v1/v1/models") {
return new Response(null, { status: 308, headers: { location: u } });
}
return new Response("not found", { status: 404 });
};
try {
await modelsRoute.GET(
new Request(`http://localhost/api/providers/${connection.id}/models?refresh=true`),
{ params: { id: connection.id } }
);
} finally {
globalThis.fetch = originalFetch;
}
assert.ok(
requestedUrls.includes("https://api.airforce/v1/models"),
`expected a request to the correctly-stripped /v1/models URL; got: ${JSON.stringify(requestedUrls)}`
);
assert.ok(
!requestedUrls.includes("https://api.airforce/v1/v1/models"),
`must never probe the double-prefixed /v1/v1/models URL; got: ${JSON.stringify(requestedUrls)}`
);
});

View File

@@ -1,48 +0,0 @@
import { test } from "node:test";
import assert from "node:assert/strict";
import { readFileSync } from "node:fs";
import { fileURLToPath } from "node:url";
import { dirname, join } from "node:path";
// Split-guard for the antigravity executor SSE-collect extraction.
// The pure SSE-payload -> collected-stream parser lives in antigravity/sseCollect.ts
// (no host state, no fetch/auth). Host imports the helpers it uses and re-exports
// processAntigravitySSEPayload for external importers (tests).
const HERE = dirname(fileURLToPath(import.meta.url));
const EXE = join(HERE, "../../open-sse/executors");
const HOST = join(EXE, "antigravity.ts");
const LEAF = join(EXE, "antigravity/sseCollect.ts");
test("leaf hosts the SSE-collect helpers and does not import the host", () => {
const src = readFileSync(LEAF, "utf8");
for (const sym of [
"processAntigravitySSEPayload",
"processAntigravitySSEText",
"flushAntigravitySSEText",
"stripZeroWidth",
]) {
assert.match(src, new RegExp(`export (function|type) ${sym}\\b`));
}
assert.doesNotMatch(src, /from "\.\.\/antigravity\.ts"/);
});
test("host re-exports processAntigravitySSEPayload", () => {
const host = readFileSync(HOST, "utf8");
assert.match(
host,
/export \{ processAntigravitySSEPayload \} from "\.\/antigravity\/sseCollect\.ts"/
);
assert.match(host, /from "\.\/antigravity\/sseCollect\.ts"/);
});
test("SSE-collect helpers are callable and tolerate empty/garbage input", async () => {
const { processAntigravitySSEPayload, stripZeroWidth } =
await import("../../open-sse/executors/antigravity/sseCollect.ts");
assert.equal(typeof processAntigravitySSEPayload, "function");
// stripZeroWidth removes zero-width markers from strings, passes through non-strings.
assert.equal(stripZeroWidth("ab"), "ab");
assert.deepEqual(stripZeroWidth(42), 42);
// A malformed payload must not throw (defensive parse).
const collected = { textContent: "" };
assert.doesNotThrow(() => processAntigravitySSEPayload("not-json", collected));
});

View File

@@ -1,127 +0,0 @@
/**
* Regression test for #6026.
*
* Antigravity IDE (via AgentBridge/MITM → `/v1/antigravity` → translator) can ship a
* truncated history whose FIRST turn is a tool result (`functionResponse`) with no
* preceding tool call. When that survives the antigravity→openai→claude chain, Anthropic
* (Vertex `claude-opus-4.6`) rejects it with HTTP 400:
*
* messages.0.content.1: unexpected tool_use_id found in tool_result blocks:
* toolu_vrtx_...: Each tool_result block must have a corresponding tool_use block in
* the previous message.
*
* The fix strips orphan tool_results at the antigravity message-assembly point
* (`antigravityToOpenAIRequest`) by reusing `fixToolPairs`, so the orphan never reaches
* the upstream Claude request.
*
* PURE-FUNCTION ONLY — this test imports the translator + sanitizer functions directly.
* It must NEVER start the MITM proxy, bind :443/:80, touch /etc/hosts, or install a CA.
*/
import test from "node:test";
import assert from "node:assert/strict";
const { antigravityToOpenAIRequest } = await import(
"../../open-sse/translator/request/antigravity-to-openai.ts"
);
const { fixToolPairs } = await import("../../open-sse/services/contextManager.ts");
test("#6026: antigravityToOpenAIRequest strips an orphan functionResponse (no preceding functionCall)", () => {
const result = antigravityToOpenAIRequest(
"ag/claude-opus-4-6",
{
request: {
contents: [
{
// First (and only) turn is a tool result with NO preceding tool call.
role: "user",
parts: [
{
functionResponse: {
id: "toolu_vrtx_test",
name: "read_file",
response: { result: { ok: true } },
},
},
],
},
],
},
},
false
);
// The orphan tool message must be gone — otherwise the openai→claude step would emit an
// orphan tool_result block and Anthropic would 400.
const orphan = result.messages.find(
(m: Record<string, unknown>) => m.role === "tool" && m.tool_call_id === "toolu_vrtx_test"
);
assert.equal(orphan, undefined, "orphan tool_result message must be stripped");
assert.equal(
result.messages.some((m: Record<string, unknown>) => m.role === "tool"),
false,
"no orphan tool messages should remain"
);
});
test("#6026: well-formed functionCall/functionResponse pair is preserved (no regression)", () => {
const result = antigravityToOpenAIRequest(
"ag/claude-opus-4-6",
{
request: {
contents: [
{
role: "model",
parts: [{ functionCall: { id: "toolu_vrtx_ok", name: "read_file", args: {} } }],
},
{
role: "user",
parts: [
{
functionResponse: {
id: "toolu_vrtx_ok",
name: "read_file",
response: { result: { ok: true } },
},
},
],
},
],
},
},
false
);
const assistant = result.messages.find(
(m: Record<string, unknown>) => m.role === "assistant"
);
const tool = result.messages.find((m: Record<string, unknown>) => m.role === "tool");
assert.ok(assistant, "assistant tool_call message must survive");
assert.ok(tool, "matched tool_result message must survive");
assert.equal((tool as Record<string, unknown>).tool_call_id, "toolu_vrtx_ok");
});
test("#6026: fixToolPairs removes the exact Anthropic-shape orphan tool_result block", () => {
// Mirrors the reporter's failing body: messages[0] is a user message whose content array
// holds a tool_result block with no matching tool_use anywhere in the request.
const messages: Record<string, unknown>[] = [
{
role: "user",
content: [
{ type: "text", text: "continue" },
{ type: "tool_result", tool_use_id: "toolu_vrtx_test", content: "stale" },
],
},
];
const fixed = fixToolPairs(messages);
const stillHasOrphan = fixed.some(
(m) =>
m.role === "user" &&
Array.isArray(m.content) &&
(m.content as Record<string, unknown>[]).some(
(b) => b.type === "tool_result" && b.tool_use_id === "toolu_vrtx_test"
)
);
assert.equal(stillHasOrphan, false, "orphan tool_result block must be stripped");
});

View File

@@ -27,12 +27,7 @@ test("chat handler maps API key provider quota bypass scope to auth bypass optio
});
test("auto combo disables hard provider quota cutoffs when relay requests bypass", () => {
// The auto-strategy bypass logic was extracted verbatim from combo.ts into the
// resolveAutoStrategy leaf (Block J Task 2); the source scan follows the code.
const source = fs.readFileSync(
path.join(repoRoot, "open-sse/services/combo/resolveAutoStrategy.ts"),
"utf8"
);
const source = fs.readFileSync(path.join(repoRoot, "open-sse/services/combo.ts"), "utf8");
assert.match(source, /relayOptions\?\.bypassProviderQuotaPolicy === true/);
assert.match(source, /quotaPreflight:[\s\S]*enabled: false/);

View File

@@ -19,7 +19,6 @@ process.env.OMNIROUTE_DISABLE_REDIS_AUTH_CACHE = "1";
const ORIGINAL_JWT_SECRET = process.env.JWT_SECRET;
const ORIGINAL_INITIAL_PASSWORD = process.env.INITIAL_PASSWORD;
const ORIGINAL_CORS_ALLOW_ALL = process.env.CORS_ALLOW_ALL;
const core = await import("../../../src/lib/db/core.ts");
const settingsDb = await import("../../../src/lib/db/settings.ts");
@@ -40,8 +39,6 @@ test.after(() => {
else process.env.JWT_SECRET = ORIGINAL_JWT_SECRET;
if (ORIGINAL_INITIAL_PASSWORD === undefined) delete process.env.INITIAL_PASSWORD;
else process.env.INITIAL_PASSWORD = ORIGINAL_INITIAL_PASSWORD;
if (ORIGINAL_CORS_ALLOW_ALL === undefined) delete process.env.CORS_ALLOW_ALL;
else process.env.CORS_ALLOW_ALL = ORIGINAL_CORS_ALLOW_ALL;
});
// ─── AC-1 — shape ─────────────────────────────────────────────────────────
@@ -156,44 +153,6 @@ test("AC-2: bypassPrefixes additions land in the inventory", async () => {
assert.deepEqual(body.bypassPrefixes, ["/api/mcp/", "/api/mcp/v2/"]);
});
// ─── #5602 — CORS status surfaced for the dashboard wildcard warning ──────
test("#5602: cors.allowAll is false by default (no CORS_ALLOW_ALL)", async () => {
process.env.JWT_SECRET = "test-jwt-secret-authz-inventory";
process.env.INITIAL_PASSWORD = "initial-pass-cors-a";
delete process.env.CORS_ALLOW_ALL;
await settingsDb.updateSettings({ requireLogin: true });
const response = await inventoryRoute.GET(
await makeManagementSessionRequest("http://localhost/api/settings/authz-inventory", {
method: "GET",
})
);
assert.equal(response.status, 200);
const body = (await response.json()) as {
cors: { allowAll: boolean; allowedOrigins: string[] };
};
assert.ok(body.cors, "response should carry a cors envelope");
assert.equal(body.cors.allowAll, false);
assert.deepEqual(body.cors.allowedOrigins, []);
});
test("#5602: cors.allowAll reflects CORS_ALLOW_ALL=true", async () => {
process.env.JWT_SECRET = "test-jwt-secret-authz-inventory";
process.env.INITIAL_PASSWORD = "initial-pass-cors-b";
process.env.CORS_ALLOW_ALL = "true";
await settingsDb.updateSettings({ requireLogin: true });
const response = await inventoryRoute.GET(
await makeManagementSessionRequest("http://localhost/api/settings/authz-inventory", {
method: "GET",
})
);
assert.equal(response.status, 200);
const body = (await response.json()) as { cors: { allowAll: boolean } };
assert.equal(body.cors.allowAll, true);
});
// ─── AC-12 — anonymous request rejected (no inventory leak) ───────────────
test("AC-12: anonymous request (no cookie, no Bearer) → 401", async () => {

View File

@@ -1,155 +0,0 @@
import { describe, test, before, after } from "node:test";
import assert from "node:assert/strict";
import { mkdtempSync, rmSync } from "node:fs";
import { tmpdir } from "node:os";
import { join } from "node:path";
// Isolated DB + auth disabled so requireManagementAuth passes (no key configured).
let tmpDataDir: string;
let core: typeof import("@/lib/db/core");
let db: typeof import("@/lib/db/discoveryResults");
let resultsRoute: typeof import("@/app/api/discovery/results/route");
let resultByIdRoute: typeof import("@/app/api/discovery/results/[id]/route");
let scanRoute: typeof import("@/app/api/discovery/scan/route");
let verifyRoute: typeof import("@/app/api/discovery/verify/[id]/route");
function req(method: string, url: string, body?: unknown): Request {
return new Request(`http://localhost${url}`, {
method,
headers: { "content-type": "application/json" },
body: body === undefined ? undefined : JSON.stringify(body),
});
}
before(async () => {
tmpDataDir = mkdtempSync(join(tmpdir(), "omniroute-discovery-routes-"));
process.env.DATA_DIR = tmpDataDir;
delete process.env.REQUIRE_API_KEY;
process.env.OMNIROUTE_DISABLE_AUTH = "1";
core = await import("@/lib/db/core");
core.resetDbInstance();
core.getDbInstance();
db = await import("@/lib/db/discoveryResults");
resultsRoute = await import("@/app/api/discovery/results/route");
resultByIdRoute = await import("@/app/api/discovery/results/[id]/route");
scanRoute = await import("@/app/api/discovery/scan/route");
verifyRoute = await import("@/app/api/discovery/verify/[id]/route");
});
after(() => {
core.resetDbInstance();
if (tmpDataDir) rmSync(tmpDataDir, { recursive: true, force: true });
});
describe("discovery API routes", () => {
test("GET /results lists persisted findings (and filters by providerId)", async () => {
db.upsertDiscoveryResult({
providerId: "acme",
method: "free_tier",
authType: "none",
feasibility: 3,
riskLevel: "none",
status: "pending",
});
const res = await resultsRoute.GET(req("GET", "/api/discovery/results?providerId=acme"));
assert.equal(res.status, 200);
const body = await res.json();
assert.ok(Array.isArray(body.results));
assert.ok(body.results.some((r: { providerId: string }) => r.providerId === "acme"));
});
test("GET /results/:id returns the row, 404 when missing, 400 on bad id", async () => {
const created = db.upsertDiscoveryResult({
providerId: "beta",
method: "trial",
authType: "api_key",
feasibility: 2,
riskLevel: "low",
status: "pending",
});
const ok = await resultByIdRoute.GET(req("GET", `/api/discovery/results/${created.id}`), {
params: Promise.resolve({ id: String(created.id) }),
});
assert.equal(ok.status, 200);
const missing = await resultByIdRoute.GET(req("GET", "/api/discovery/results/999999"), {
params: Promise.resolve({ id: "999999" }),
});
assert.equal(missing.status, 404);
const bad = await resultByIdRoute.GET(req("GET", "/api/discovery/results/abc"), {
params: Promise.resolve({ id: "abc" }),
});
assert.equal(bad.status, 400);
});
test("POST /scan persists findings; rejects an empty providerId with 400", async () => {
const res = await scanRoute.POST(req("POST", "/api/discovery/scan", { providerId: "gamma" }));
assert.equal(res.status, 200);
const body = await res.json();
assert.ok(Array.isArray(body.results) && body.results.length > 0);
assert.ok(body.results[0].id > 0);
// the persisted row is now queryable
assert.ok(db.getDiscoveryResults("gamma").length > 0);
const invalid = await scanRoute.POST(req("POST", "/api/discovery/scan", { providerId: "" }));
assert.equal(invalid.status, 400);
const malformed = new Request("http://localhost/api/discovery/scan", {
method: "POST",
headers: { "content-type": "application/json" },
body: "{not json",
});
const malformedRes = await scanRoute.POST(malformed);
assert.equal(malformedRes.status, 400);
});
test("POST /verify/:id marks verified, 404 when missing", async () => {
const created = db.upsertDiscoveryResult({
providerId: "delta",
method: "public_api",
authType: "api_key",
feasibility: 5,
riskLevel: "none",
status: "pending",
});
const res = await verifyRoute.POST(req("POST", `/api/discovery/verify/${created.id}`), {
params: Promise.resolve({ id: String(created.id) }),
});
assert.equal(res.status, 200);
const body = await res.json();
assert.equal(body.result.status, "verified");
const missing = await verifyRoute.POST(req("POST", "/api/discovery/verify/999999"), {
params: Promise.resolve({ id: "999999" }),
});
assert.equal(missing.status, 404);
});
test("DELETE /results/:id removes the row, 404 on second delete", async () => {
const created = db.upsertDiscoveryResult({
providerId: "epsilon",
method: "free_tier",
authType: "none",
feasibility: 1,
riskLevel: "none",
status: "pending",
});
const first = await resultByIdRoute.DELETE(req("DELETE", `/api/discovery/results/${created.id}`), {
params: Promise.resolve({ id: String(created.id) }),
});
assert.equal(first.status, 200);
const second = await resultByIdRoute.DELETE(req("DELETE", `/api/discovery/results/${created.id}`), {
params: Promise.resolve({ id: String(created.id) }),
});
assert.equal(second.status, 404);
});
test("error responses do not leak stack traces", async () => {
const missing = await resultByIdRoute.GET(req("GET", "/api/discovery/results/424242"), {
params: Promise.resolve({ id: "424242" }),
});
const body = await missing.json();
assert.ok(!String(body.error?.message ?? "").includes("at /"));
});
});

View File

@@ -1,30 +0,0 @@
import assert from "node:assert/strict";
import test from "node:test";
import {
GET,
OPTIONS,
} from "../../../../src/app/api/v1/provider-plugin-manifest/route.ts";
test("provider plugin manifest route returns JSON-safe manifest", async () => {
const response = await GET();
const body = await response.json();
assert.equal(response.status, 200);
assert.equal(response.headers.get("Content-Type"), "application/json");
assert.equal(body.schemaVersion, 1);
assert.equal(body.generatedFrom, "open-sse/config/providers");
assert.ok(body.providers.length > 100);
assert.ok(body.providers.some((provider: { id: string }) => provider.id === "openai"));
const serialized = JSON.stringify(body);
assert.equal(serialized.includes("clientSecret"), false);
});
test("provider plugin manifest route handles CORS preflight", async () => {
const response = await OPTIONS();
assert.equal(response.status, 200);
assert.equal(response.headers.get("Access-Control-Allow-Methods"), "GET, OPTIONS");
assert.equal(response.headers.get("Access-Control-Allow-Headers"), "*");
});

View File

@@ -5,7 +5,6 @@ import {
getRoutingFallbackHeader,
resolveRelayRoutingBackend,
shouldTryBifrost,
shouldTryBifrostForRequest,
} from "../../../../src/app/api/v1/relay/chat/completions/routingBackend.ts";
test("relay routing backend defaults to TypeScript without bifrost", () => {
@@ -99,56 +98,3 @@ test("relay routing backend keeps strict bifrost failures out of auto fallback a
assert.equal(getRoutingFallbackHeader("bifrost", config), undefined);
assert.equal(resolveRelayRoutingBackend({ OMNIROUTE_RELAY_BACKEND: "bifrost" }), "bifrost");
});
test("relay routing backend auto mode tries bifrost for manifest-eligible providers", () => {
const config = getBifrostRoutingConfig({
BIFROST_BASE_URL: "http://127.0.0.1:8080",
});
assert.deepEqual(
shouldTryBifrostForRequest("auto", config, { model: "openai/gpt-4.1" }, () => ({
eligible: true,
reasons: [],
})),
{ tryBifrost: true }
);
});
test("relay routing backend auto mode skips bifrost for manifest-ineligible providers", () => {
const config = getBifrostRoutingConfig({
BIFROST_BASE_URL: "http://127.0.0.1:8080",
});
assert.deepEqual(
shouldTryBifrostForRequest("auto", config, { model: "cw/claude-sonnet-4.6" }, () => ({
eligible: false,
reasons: ["custom executor: claude-web"],
})),
{ tryBifrost: false, fallbackReason: "bifrost-ineligible" }
);
});
test("relay routing backend auto mode keeps unknown providers on TS fallback", () => {
const config = getBifrostRoutingConfig({
BIFROST_BASE_URL: "http://127.0.0.1:8080",
});
assert.deepEqual(
shouldTryBifrostForRequest("auto", config, { model: "unknown/model" }, () => null),
{ tryBifrost: false, fallbackReason: "bifrost-provider-unknown" }
);
});
test("relay routing backend strict bifrost bypasses manifest eligibility", () => {
const config = getBifrostRoutingConfig({
BIFROST_BASE_URL: "http://127.0.0.1:8080",
});
assert.deepEqual(
shouldTryBifrostForRequest("bifrost", config, { model: "cw/claude-sonnet-4.6" }, () => ({
eligible: false,
reasons: ["custom executor: claude-web"],
})),
{ tryBifrost: true }
);
});

View File

@@ -1,91 +0,0 @@
import { describe, test } from "node:test";
import assert from "node:assert/strict";
import { z } from "zod";
import { validatedJsonBody } from "@/shared/validation/helpers";
function makeRequest(body: string, contentType = "application/json"): Request {
return new Request("http://localhost/test", {
method: "POST",
headers: { "content-type": contentType },
body,
});
}
describe("validatedJsonBody", () => {
const schema = z.object({
name: z.string().min(1),
count: z.number().int().nonnegative(),
});
test("returns the parsed and validated data on success", async () => {
const result = await validatedJsonBody(makeRequest('{"name":"hello","count":3}'), schema);
assert.equal(result.success, true);
if (result.success) {
assert.deepEqual(result.data, { name: "hello", count: 3 });
}
});
test("returns a 400 with structured details when the body fails Zod validation", async () => {
const result = await validatedJsonBody(makeRequest('{"name":"","count":-1}'), schema);
assert.equal(result.success, false);
if (!result.success) {
assert.equal(result.response.status, 400);
const body = await result.response.json();
assert.equal(body.error.message, "Invalid request");
assert.ok(Array.isArray(body.error.details));
const fields = body.error.details.map((d: { field: string }) => d.field);
assert.ok(fields.includes("name"));
assert.ok(fields.includes("count"));
}
});
test("returns a 400 with a body-parse failure for malformed JSON", async () => {
const result = await validatedJsonBody(makeRequest("not json at all"), schema);
assert.equal(result.success, false);
if (!result.success) {
assert.equal(result.response.status, 400);
const body = await result.response.json();
assert.deepEqual(body, {
error: {
message: "Invalid request",
details: [{ field: "body", message: "Invalid JSON body" }],
},
});
}
});
test("returns a 400 for an empty body", async () => {
const result = await validatedJsonBody(makeRequest(""), schema);
assert.equal(result.success, false);
if (!result.success) {
assert.equal(result.response.status, 400);
}
});
test("returns a 400 when required fields are missing entirely", async () => {
const result = await validatedJsonBody(makeRequest("{}"), schema);
assert.equal(result.success, false);
if (!result.success) {
assert.equal(result.response.status, 400);
const body = await result.response.json();
const fields = body.error.details.map((d: { field: string }) => d.field);
assert.ok(fields.includes("name"));
assert.ok(fields.includes("count"));
}
});
test("preserves the same envelope shape between parse and validate failure", async () => {
const parseFailure = await validatedJsonBody(makeRequest("nope"), schema);
const validateFailure = await validatedJsonBody(makeRequest("{}"), schema);
assert.equal(parseFailure.success, false);
assert.equal(validateFailure.success, false);
if (!parseFailure.success && !validateFailure.success) {
const parseBody = await parseFailure.response.json();
const validateBody = await validateFailure.response.json();
assert.equal(typeof parseBody.error.message, "string");
assert.equal(typeof validateBody.error.message, "string");
assert.ok(Array.isArray(parseBody.error.details));
assert.ok(Array.isArray(validateBody.error.details));
}
});
});

View File

@@ -1,199 +0,0 @@
import test from "node:test";
import assert from "node:assert/strict";
const { handleAudioTranslation } = await import("../../open-sse/handlers/audioTranslation.ts");
function buildFile(contents, name, type) {
return new File([Buffer.from(contents)], name, { type });
}
test("handleAudioTranslation requires model", async () => {
const formData = new FormData();
formData.append("file", buildFile("abc", "audio.wav", "audio/wav"));
const response = await handleAudioTranslation({ formData, credentials: { apiKey: "x" } });
const payload = (await response.json()) as any;
assert.equal(response.status, 400);
assert.equal(payload.error.message, "model is required");
});
test("handleAudioTranslation requires a file upload", async () => {
const formData = new FormData();
formData.append("model", "openai/whisper-1");
const response = await handleAudioTranslation({ formData, credentials: { apiKey: "x" } });
const payload = (await response.json()) as any;
assert.equal(response.status, 400);
assert.equal(payload.error.message, "file is required");
});
test("handleAudioTranslation requires credentials for authenticated providers", async () => {
const formData = new FormData();
formData.append("model", "openai/whisper-1");
formData.append("file", buildFile("abc", "clip.wav", "audio/wav"));
const response = await handleAudioTranslation({ formData, credentials: null });
const payload = (await response.json()) as any;
assert.equal(response.status, 401);
assert.equal(payload.error.message, "No credentials for translation provider: openai");
});
test("handleAudioTranslation rejects unsupported providers", async () => {
const formData = new FormData();
formData.append("model", "unknown/provider");
formData.append("file", buildFile("abc", "clip.wav", "audio/wav"));
const response = await handleAudioTranslation({
formData,
credentials: { apiKey: "x" },
});
const payload = (await response.json()) as any;
assert.equal(response.status, 400);
assert.match(payload.error.message, /No translation provider found for model "unknown\/provider"/);
});
test("handleAudioTranslation dispatches OpenAI-compatible multipart requests and returns { text }", async () => {
const originalFetch = globalThis.fetch;
let captured;
globalThis.fetch = async (url, options = {}) => {
captured = {
url: String(url),
headers: options.headers,
body: options.body,
};
return new Response(JSON.stringify({ text: "hello world" }), {
status: 200,
headers: { "content-type": "application/json" },
});
};
try {
const formData = new FormData();
formData.append("model", "openai/whisper-1");
formData.append("file", buildFile("abc", "clip.webm", "audio/webm"));
formData.append("prompt", "greeting");
formData.append("response_format", "json");
formData.append("temperature", "0.2");
// Translation always outputs English — a caller-supplied `language` must
// NOT be forwarded upstream (differs from /v1/audio/transcriptions).
formData.append("language", "pt");
const response = await handleAudioTranslation({
formData,
credentials: { apiKey: "openai-key" },
});
assert.equal(response.status, 200);
assert.equal(captured.url, "https://api.openai.com/v1/audio/translations");
assert.equal(captured.headers.Authorization, "Bearer openai-key");
assert.match(captured.headers["Content-Type"], /^multipart\/form-data; boundary=/);
const bodyText = new TextDecoder().decode(captured.body);
assert.ok(bodyText.includes('name="model"'));
assert.ok(bodyText.includes("whisper-1"));
assert.ok(bodyText.includes('name="prompt"'));
assert.ok(bodyText.includes("greeting"));
assert.ok(bodyText.includes('name="response_format"'));
assert.ok(bodyText.includes('name="temperature"'));
assert.ok(bodyText.includes("0.2"));
assert.ok(bodyText.includes('name="file"'));
assert.ok(bodyText.includes('filename="clip.webm"'));
assert.ok(!bodyText.includes('name="language"'));
assert.deepEqual(await response.json(), { text: "hello world" });
} finally {
globalThis.fetch = originalFetch;
}
});
test("handleAudioTranslation dispatches Groq-compatible multipart requests", async () => {
const originalFetch = globalThis.fetch;
let captured;
globalThis.fetch = async (url, options = {}) => {
captured = { url: String(url), headers: options.headers };
return new Response(JSON.stringify({ text: "bonjour" }), {
status: 200,
headers: { "content-type": "application/json" },
});
};
try {
const formData = new FormData();
formData.append("model", "groq/whisper-large-v3");
formData.append("file", buildFile("abc", "clip.wav", "audio/wav"));
const response = await handleAudioTranslation({
formData,
credentials: { apiKey: "groq-key" },
});
assert.equal(response.status, 200);
assert.equal(captured.url, "https://api.groq.com/openai/v1/audio/translations");
assert.equal(captured.headers.Authorization, "Bearer groq-key");
assert.deepEqual(await response.json(), { text: "bonjour" });
} finally {
globalThis.fetch = originalFetch;
}
});
test("handleAudioTranslation surfaces parsed upstream errors without leaking internals", async () => {
const originalFetch = globalThis.fetch;
globalThis.fetch = async () =>
new Response(JSON.stringify({ error: { message: "too many requests" } }), {
status: 429,
headers: { "content-type": "application/json" },
});
try {
const formData = new FormData();
formData.append("model", "openai/whisper-1");
formData.append("file", buildFile("abc", "clip.wav", "audio/wav"));
const response = await handleAudioTranslation({
formData,
credentials: { apiKey: "openai-key" },
});
const payload = (await response.json()) as any;
assert.equal(response.status, 429);
assert.equal(payload.error.message, "too many requests");
assert.ok(!payload.error.message.includes("at /"));
} finally {
globalThis.fetch = originalFetch;
}
});
test("handleAudioTranslation sanitizes stack-trace-shaped messages on fetch failure", async () => {
const originalFetch = globalThis.fetch;
globalThis.fetch = async () => {
throw new Error("Fetch failed at /home/user/project/src/secure.ts:10:5");
};
try {
const formData = new FormData();
formData.append("model", "openai/whisper-1");
formData.append("file", buildFile("abc", "clip.wav", "audio/wav"));
const response = await handleAudioTranslation({
formData,
credentials: { apiKey: "openai-key" },
});
const payload = (await response.json()) as any;
assert.equal(response.status, 500);
// Rule: error responses must never leak absolute source paths / stack traces.
assert.ok(!payload.error.message.includes("at /"));
assert.ok(!payload.error.message.includes("secure.ts"));
} finally {
globalThis.fetch = originalFetch;
}
});

View File

@@ -1,380 +0,0 @@
/**
* AuggieExecutor unit tests.
*
* Rather than mocking node:child_process (fragile under ESM without
* --experimental-vm-modules — see tests/unit/dns-config-generic.test.ts for the
* same tradeoff), these tests point `AUGGIE_BIN` at small real, disposable shell
* scripts that stand in for the `auggie` CLI. No live `auggie` binary is required
* or touched — CI never needs the real Augment CLI installed.
*/
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 { AuggieExecutor, buildAuggiePrompt, resolveAuggieBin, resolveAuggieModel } = await import(
"@omniroute/open-sse/executors/auggie"
);
const TMP_DIR = fs.mkdtempSync(path.join(os.tmpdir(), "omniroute-auggie-test-"));
/** Write an executable shell script and return its absolute path. */
function writeFakeBin(name: string, script: string): string {
const p = path.join(TMP_DIR, name);
fs.writeFileSync(p, `#!/bin/sh\n${script}\n`, { mode: 0o755 });
return p;
}
async function readSseEvents(response: Response): Promise<Record<string, unknown>[]> {
const text = await response.text();
const events: Record<string, unknown>[] = [];
for (const line of text.split("\n")) {
if (!line.startsWith("data: ")) continue;
const payload = line.slice("data: ".length).trim();
if (payload === "[DONE]") continue;
events.push(JSON.parse(payload));
}
return events;
}
test.after(() => {
fs.rmSync(TMP_DIR, { recursive: true, force: true });
});
// ─── buildAuggiePrompt ────────────────────────────────────────────────────
test("buildAuggiePrompt flattens system/user/assistant turns with role tags", () => {
const prompt = buildAuggiePrompt([
{ role: "system", content: "Be terse." },
{ role: "user", content: "hi" },
{ role: "assistant", content: "hello" },
{ role: "user", content: "how are you?" },
]);
assert.equal(
prompt,
"[System]\nBe terse.\n\n[User]\nhi\n\n[Assistant]\nhello\n\n[User]\nhow are you?"
);
});
test("buildAuggiePrompt flattens array-shaped content blocks and skips empty turns", () => {
const prompt = buildAuggiePrompt([
{ role: "user", content: [{ type: "text", text: "part1 " }, { type: "text", text: "part2" }] },
{ role: "user", content: "" },
{ role: "user", content: [] },
]);
assert.equal(prompt, "[User]\npart1 part2");
});
test("buildAuggiePrompt returns a placeholder for an empty conversation", () => {
assert.equal(buildAuggiePrompt([]), "(empty)");
});
// ─── resolveAuggieBin ─────────────────────────────────────────────────────
test("resolveAuggieBin honors AUGGIE_BIN env override", () => {
const prev = process.env.AUGGIE_BIN;
try {
process.env.AUGGIE_BIN = "/custom/path/to/auggie";
assert.equal(resolveAuggieBin(), "/custom/path/to/auggie");
} finally {
if (prev === undefined) delete process.env.AUGGIE_BIN;
else process.env.AUGGIE_BIN = prev;
}
});
// ─── execute(): ENOENT → CLI not found ─────────────────────────────────────
test("execute() surfaces a sanitized 'CLI not found' error on ENOENT (streaming)", async () => {
const prevBin = process.env.AUGGIE_BIN;
process.env.AUGGIE_BIN = path.join(TMP_DIR, "does-not-exist-binary");
try {
const executor = new AuggieExecutor();
const { response } = await executor.execute({
model: "claude-sonnet-4.6",
body: { messages: [{ role: "user", content: "hi" }] },
stream: true,
credentials: {} as never,
});
assert.equal(response.headers.get("Content-Type"), "text/event-stream");
const events = await readSseEvents(response);
const errorEvent = events.find((e) => (e as any).error);
assert.ok(errorEvent, "expected an error SSE event");
const message = String((errorEvent as any).error.message);
// The configured bin path is intentionally included (actionable for the
// operator) — sanitizeErrorMessage only strips stack-trace-shaped source
// paths (`*.ts`/`*.js` + line:col), not arbitrary CLI binary paths.
assert.match(message, /Auggie CLI not found/);
assert.equal(message.includes("\n"), false, "message must not contain a stack trace");
} finally {
if (prevBin === undefined) delete process.env.AUGGIE_BIN;
else process.env.AUGGIE_BIN = prevBin;
}
});
test("execute() surfaces a sanitized 'CLI not found' error on ENOENT (non-streaming)", async () => {
const prevBin = process.env.AUGGIE_BIN;
process.env.AUGGIE_BIN = path.join(TMP_DIR, "does-not-exist-binary-2");
try {
const executor = new AuggieExecutor();
const { response } = await executor.execute({
model: "claude-sonnet-4.6",
body: { messages: [{ role: "user", content: "hi" }] },
stream: false,
credentials: {} as never,
});
assert.equal(response.headers.get("Content-Type"), "application/json");
assert.equal(response.status, 502);
const body = await response.json();
assert.match(String(body.error.message), /Auggie CLI not found/);
} finally {
if (prevBin === undefined) delete process.env.AUGGIE_BIN;
else process.env.AUGGIE_BIN = prevBin;
}
});
// ─── execute(): non-zero exit → sanitized error ────────────────────────────
test("execute() surfaces a sanitized error when the CLI exits non-zero (streaming)", async () => {
const bin = writeFakeBin("fake-auggie-fail.sh", 'echo "boom at /home/attacker/secret.ts:42" 1>&2\nexit 3');
const prevBin = process.env.AUGGIE_BIN;
process.env.AUGGIE_BIN = bin;
try {
const executor = new AuggieExecutor();
const { response } = await executor.execute({
model: "claude-sonnet-4.6",
body: { messages: [{ role: "user", content: "hi" }] },
stream: true,
credentials: {} as never,
});
const events = await readSseEvents(response);
const errorEvent = events.find((e) => (e as any).error);
assert.ok(errorEvent, "expected an error SSE event");
const message = String((errorEvent as any).error.message);
assert.match(message, /exited with code 3/);
assert.equal(message.includes("/home/attacker/secret.ts"), false, "path must be sanitized");
} finally {
if (prevBin === undefined) delete process.env.AUGGIE_BIN;
else process.env.AUGGIE_BIN = prevBin;
}
});
test("execute() surfaces a sanitized error when the CLI exits non-zero (non-streaming)", async () => {
const bin = writeFakeBin("fake-auggie-fail2.sh", "exit 1");
const prevBin = process.env.AUGGIE_BIN;
process.env.AUGGIE_BIN = bin;
try {
const executor = new AuggieExecutor();
const { response } = await executor.execute({
model: "claude-sonnet-4.6",
body: { messages: [{ role: "user", content: "hi" }] },
stream: false,
credentials: {} as never,
});
assert.equal(response.status, 502);
const body = await response.json();
assert.match(String(body.error.message), /exited with code 1/);
} finally {
if (prevBin === undefined) delete process.env.AUGGIE_BIN;
else process.env.AUGGIE_BIN = prevBin;
}
});
// ─── execute(): stream vs non-stream shape ─────────────────────────────────
test("execute() with stream=true returns SSE deltas + [DONE]", async () => {
const bin = writeFakeBin("fake-auggie-echo.sh", 'printf "hello world"');
const prevBin = process.env.AUGGIE_BIN;
process.env.AUGGIE_BIN = bin;
try {
const executor = new AuggieExecutor();
const { response } = await executor.execute({
model: "claude-sonnet-4.6",
body: { messages: [{ role: "user", content: "say hi" }] },
stream: true,
credentials: {} as never,
});
assert.equal(response.headers.get("Content-Type"), "text/event-stream");
const events = await readSseEvents(response);
// First chunk announces the assistant role.
assert.equal((events[0] as any).choices[0].delta.role, "assistant");
// Content is streamed as delta chunks that concatenate to the full text.
const contentDeltas = events
.map((e) => (e as any).choices?.[0]?.delta?.content)
.filter((c) => typeof c === "string");
assert.equal(contentDeltas.join(""), "hello world");
// Final chunk signals completion.
const last = events[events.length - 1] as any;
assert.equal(last.choices[0].finish_reason, "stop");
} finally {
if (prevBin === undefined) delete process.env.AUGGIE_BIN;
else process.env.AUGGIE_BIN = prevBin;
}
});
test("execute() with stream=false returns a single chat.completion JSON body", async () => {
const bin = writeFakeBin("fake-auggie-echo2.sh", 'printf "hello world"');
const prevBin = process.env.AUGGIE_BIN;
process.env.AUGGIE_BIN = bin;
try {
const executor = new AuggieExecutor();
const { response } = await executor.execute({
model: "claude-sonnet-4.6",
body: { messages: [{ role: "user", content: "say hi" }] },
stream: false,
credentials: {} as never,
});
assert.equal(response.headers.get("Content-Type"), "application/json");
assert.equal(response.status, 200);
const body = await response.json();
assert.equal(body.object, "chat.completion");
assert.equal(body.choices[0].message.role, "assistant");
assert.equal(body.choices[0].message.content, "hello world");
assert.equal(body.choices[0].finish_reason, "stop");
assert.ok(body.usage);
} finally {
if (prevBin === undefined) delete process.env.AUGGIE_BIN;
else process.env.AUGGIE_BIN = prevBin;
}
});
// ─── resolveAuggieModel ─────────────────────────────────────────────────────
test("resolveAuggieModel defaults to a real allowlisted model when unset", () => {
const result = resolveAuggieModel(undefined);
assert.equal(result.ok, true);
if (result.ok) assert.equal(typeof result.model, "string");
});
test("resolveAuggieModel accepts a known registry model id verbatim", () => {
const result = resolveAuggieModel("claude-haiku-4.5");
assert.deepEqual(result, { ok: true, model: "claude-haiku-4.5" });
});
// ─── execute(): model allowlist (argument-injection defense) ──────────────
test("execute() rejects a model not in the registry allowlist and never spawns", async () => {
const marker = path.join(TMP_DIR, "spawned-unknown-model.marker");
const bin = writeFakeBin("fake-auggie-unknown.sh", `touch "${marker}"\nprintf "hi"`);
const prevBin = process.env.AUGGIE_BIN;
process.env.AUGGIE_BIN = bin;
try {
const executor = new AuggieExecutor();
const { response } = await executor.execute({
model: "totally-not-a-real-model",
body: { messages: [{ role: "user", content: "hi" }] },
stream: false,
credentials: {} as never,
});
assert.equal(response.status, 400);
const body = await response.json();
assert.match(String(body.error.message), /Unknown Auggie model/);
assert.equal(fs.existsSync(marker), false, "subprocess must never be spawned");
} finally {
if (prevBin === undefined) delete process.env.AUGGIE_BIN;
else process.env.AUGGIE_BIN = prevBin;
}
});
test("execute() rejects a model starting with '-' (flag smuggling) and never spawns (streaming)", async () => {
const marker = path.join(TMP_DIR, "spawned-flag-smuggle.marker");
const bin = writeFakeBin("fake-auggie-flag.sh", `touch "${marker}"\nprintf "hi"`);
const prevBin = process.env.AUGGIE_BIN;
process.env.AUGGIE_BIN = bin;
try {
const executor = new AuggieExecutor();
const { response } = await executor.execute({
model: "-rf",
body: { messages: [{ role: "user", content: "hi" }] },
stream: true,
credentials: {} as never,
});
assert.equal(response.headers.get("Content-Type"), "text/event-stream");
const events = await readSseEvents(response);
const errorEvent = events.find((e) => (e as any).error);
assert.ok(errorEvent, "expected an error SSE event");
assert.match(String((errorEvent as any).error.message), /must not start with "-"/);
assert.equal(fs.existsSync(marker), false, "subprocess must never be spawned");
} finally {
if (prevBin === undefined) delete process.env.AUGGIE_BIN;
else process.env.AUGGIE_BIN = prevBin;
}
});
test("execute() spawns with a valid allowlisted model, no shell, and a '--' argv separator", async () => {
const argvFile = path.join(TMP_DIR, "captured-argv.txt");
const bin = writeFakeBin(
"fake-auggie-argv.sh",
`for a in "$@"; do printf '%s\\n' "$a" >> "${argvFile}"; done\nprintf "ok"`
);
const prevBin = process.env.AUGGIE_BIN;
process.env.AUGGIE_BIN = bin;
try {
const executor = new AuggieExecutor();
const { response } = await executor.execute({
model: "claude-opus-4.6",
body: { messages: [{ role: "user", content: "hi" }] },
stream: false,
credentials: {} as never,
});
assert.equal(response.status, 200);
const body = await response.json();
assert.equal(body.choices[0].message.content, "ok");
const argv = fs.readFileSync(argvFile, "utf8").trim().split("\n");
assert.deepEqual(argv, ["--print", "--quiet", "--model", "claude-opus-4.6", "--"]);
} finally {
if (prevBin === undefined) delete process.env.AUGGIE_BIN;
else process.env.AUGGIE_BIN = prevBin;
fs.rmSync(argvFile, { force: true });
}
});
// ─── execute(): abort kills the subprocess promptly ────────────────────────
test("execute() aborts a long-running CLI process instead of hanging (streaming)", async () => {
// Sleeps far longer than the test timeout unless killed on abort.
const bin = writeFakeBin("fake-auggie-sleep.sh", "sleep 30");
const prevBin = process.env.AUGGIE_BIN;
process.env.AUGGIE_BIN = bin;
try {
const executor = new AuggieExecutor();
const controller = new AbortController();
const { response } = await executor.execute({
model: "claude-sonnet-4.6",
body: { messages: [{ role: "user", content: "hi" }] },
stream: true,
credentials: {} as never,
signal: controller.signal,
});
// Give the child process a beat to spawn, then abort.
await new Promise((resolve) => setTimeout(resolve, 100));
controller.abort();
// Reading the stream must resolve promptly (i.e. the stream closes) rather
// than hanging for the full 30s sleep.
const start = Date.now();
await response.text();
const elapsed = Date.now() - start;
assert.ok(elapsed < 5000, `expected abort to close the stream quickly, took ${elapsed}ms`);
} finally {
if (prevBin === undefined) delete process.env.AUGGIE_BIN;
else process.env.AUGGIE_BIN = prevBin;
}
});
// ─── refreshCredentials() is a no-op ────────────────────────────────────────
test("refreshCredentials() is a no-op (auggie has no OmniRoute-managed credentials)", async () => {
const executor = new AuggieExecutor();
const result = await executor.refreshCredentials({} as never);
assert.equal(result, null);
});
test("buildUrl/buildHeaders/transformRequest match the CLI-passthrough shape", () => {
const executor = new AuggieExecutor();
assert.equal(executor.buildUrl(), "auggie://cli/stdio");
assert.deepEqual(executor.buildHeaders(), {});
assert.equal(executor.transformRequest(), null);
});

View File

@@ -1,27 +0,0 @@
import { describe, test } from "node:test";
import assert from "node:assert/strict";
import {
isLocalOnlyPath,
isLocalOnlyBypassableByManageScope,
} from "@/server/authz/routeGuard";
// Security guard: the discovery surface must be strict-loopback only. If someone
// removes "/api/discovery/" from LOCAL_ONLY_API_PREFIXES, or adds it to the
// manage-scope bypass list, these assertions fail — the scan route makes
// outbound probes (SSRF-adjacent) and must never be tunnel-reachable.
describe("discovery routes are strict local-only", () => {
for (const path of [
"/api/discovery/results",
"/api/discovery/results/42",
"/api/discovery/scan",
"/api/discovery/verify/42",
]) {
test(`isLocalOnlyPath("${path}") === true`, () => {
assert.equal(isLocalOnlyPath(path), true);
});
test(`"${path}" is NOT bypassable by manage-scope (strict loopback)`, () => {
assert.equal(isLocalOnlyBypassableByManageScope(path), false);
});
}
});

View File

@@ -138,50 +138,6 @@ test("runAuthzPipeline redirects unauthenticated /home/* nested paths to login (
assert.equal(response.headers.get("x-omniroute-route-class"), "MANAGEMENT");
});
// PR #1810 (upstream 9router): reverse-proxy subpath deployment via
// OMNIROUTE_BASE_PATH. Next.js strips the basePath from nextUrl.pathname
// before route classification, so the redirect targets must re-add it via
// request.nextUrl.basePath to stay inside the deployed subpath.
test("runAuthzPipeline prefixes the root-to-dashboard redirect with basePath when set", async () => {
await forceAuthRequired();
const req = new NextRequest("http://localhost/omniroute/", {
nextConfig: { basePath: "/omniroute" },
});
const response = await pipeline.runAuthzPipeline(req, { enforce: true });
assert.equal(response.status, 307);
assert.equal(response.headers.get("location"), "http://localhost/omniroute/dashboard");
});
test("runAuthzPipeline prefixes the dashboard login redirect with basePath when set", async () => {
await forceAuthRequired();
const req = new NextRequest("http://localhost/omniroute/dashboard", {
nextConfig: { basePath: "/omniroute" },
});
const response = await pipeline.runAuthzPipeline(req, { enforce: true });
assert.equal(response.status, 307);
assert.equal(response.headers.get("location"), "http://localhost/omniroute/login");
assert.equal(response.headers.get("x-omniroute-route-class"), "MANAGEMENT");
});
test("runAuthzPipeline leaves redirect targets unprefixed when basePath is empty", async () => {
await forceAuthRequired();
const req = new NextRequest("http://localhost/dashboard", {
nextConfig: { basePath: "" },
});
const response = await pipeline.runAuthzPipeline(req, { enforce: true });
assert.equal(response.status, 307);
assert.equal(response.headers.get("location"), "http://localhost/login");
});
test("runAuthzPipeline allows onboarding when login is required but no password exists", async () => {
delete process.env.INITIAL_PASSWORD;
await settingsDb.updateSettings({

View File

@@ -189,25 +189,6 @@ test("isLocalOnlyBypassableByManageScope: /api/services/* is NOT bypassable (spa
assert.equal(isLocalOnlyBypassableByManageScope("/api/services/"), false);
});
// Hard Rule #17 — Mux (coder/mux) embedded service (spawns child processes via
// runNpm install + node server spawn): every /api/services/mux/* route MUST be
// classified local-only, same as every other embedded service under this prefix.
test("isLocalOnlyPath: /api/services/mux/* is local-only (Hard Rule #17)", () => {
assert.equal(isLocalOnlyPath("/api/services/mux/install"), true);
assert.equal(isLocalOnlyPath("/api/services/mux/start"), true);
assert.equal(isLocalOnlyPath("/api/services/mux/stop"), true);
assert.equal(isLocalOnlyPath("/api/services/mux/restart"), true);
assert.equal(isLocalOnlyPath("/api/services/mux/update"), true);
assert.equal(isLocalOnlyPath("/api/services/mux/status"), true);
assert.equal(isLocalOnlyPath("/api/services/mux/auto-start"), true);
assert.equal(isLocalOnlyPath("/api/services/mux/logs"), true);
});
test("isLocalOnlyBypassableByManageScope: /api/services/mux/* is NOT bypassable (spawn-capable)", () => {
assert.equal(isLocalOnlyBypassableByManageScope("/api/services/mux/start"), false);
assert.equal(isLocalOnlyBypassableByManageScope("/api/services/mux/install"), false);
});
test("management policy rejects /api/services/ from non-localhost (status 403)", async () => {
const ctx = makeCtx("/api/services/9router/start", { host: "evil.tunnel.io" });
const outcome = await managementPolicy.evaluate(ctx);

View File

@@ -1,159 +0,0 @@
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 { APIKEY_PROVIDERS } = await import("../../src/shared/constants/providers.ts");
const { PROVIDER_ENDPOINTS } = await import("../../src/shared/constants/config.ts");
const { REGISTRY: providerRegistry } = await import("../../open-sse/config/providerRegistry.ts");
const { isValidModel } = await import("../../src/shared/constants/models.ts");
const BAI_CHAT_URL = "https://api.b.ai/v1/chat/completions";
const BAI_MODELS_URL = "https://api.b.ai/v1/models";
test("b.ai is registered as an API-key provider", () => {
const entry = APIKEY_PROVIDERS.bai;
assert.ok(entry, "APIKEY_PROVIDERS.bai must be defined");
assert.equal(entry.id, "bai");
assert.equal(entry.alias, "bai");
assert.equal(entry.name, "b.ai");
assert.equal(entry.website, "https://b.ai");
assert.equal(entry.passthroughModels, true);
});
test("b.ai is distinct from the existing thebai (TheB.AI) provider", () => {
const bai = APIKEY_PROVIDERS.bai;
const thebai = APIKEY_PROVIDERS.thebai;
assert.ok(bai, "APIKEY_PROVIDERS.bai must be defined");
assert.ok(thebai, "APIKEY_PROVIDERS.thebai must be defined");
assert.notEqual(bai.id, thebai.id);
assert.notEqual(bai.website, thebai.website);
assert.equal(bai.website, "https://b.ai");
assert.equal(thebai.website, "https://theb.ai");
});
test("b.ai exposes the OpenAI-compatible chat completions endpoint", () => {
assert.equal(PROVIDER_ENDPOINTS.bai, BAI_CHAT_URL);
});
test("b.ai registry entry uses OpenAI format with bearer API-key auth", () => {
const entry = providerRegistry.bai;
assert.ok(entry, "providerRegistry.bai must be defined");
assert.equal(entry.id, "bai");
assert.equal(entry.alias, "bai");
assert.equal(entry.format, "openai");
assert.equal(entry.executor, "default");
assert.equal(entry.authType, "apikey");
assert.equal(entry.authHeader, "bearer");
assert.equal(entry.baseUrl, BAI_CHAT_URL);
assert.equal(entry.modelsUrl, BAI_MODELS_URL);
assert.equal(entry.passthroughModels, true);
});
test("b.ai ships no static model seed — relies fully on passthrough + live catalog", () => {
const models = providerRegistry.bai.models;
assert.deepEqual(models, []);
});
test("b.ai accepts any model id via passthrough models (GPT/Claude/Gemini/Kimi/GLM behind one key)", () => {
assert.equal(isValidModel("bai", "gpt-5.2"), true);
assert.equal(isValidModel("bai", "claude-opus-4-5"), true);
assert.equal(isValidModel("bai", "gemini-3-pro"), true);
assert.equal(isValidModel("bai", "kimi-k2.5"), true);
});
const TEST_DATA_DIR = fs.mkdtempSync(path.join(os.tmpdir(), "omniroute-bai-"));
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 modelsRoute = await import("../../src/app/api/providers/[id]/models/route.ts");
async function resetStorage() {
core.resetDbInstance();
fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true });
fs.mkdirSync(TEST_DATA_DIR, { recursive: true });
}
test.after(() => {
core.resetDbInstance();
fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true });
});
interface ModelsBody {
provider: string;
connectionId: string;
models: Array<{ id: string }>;
source?: string;
}
test("b.ai import fetches the live /v1/models catalog", async () => {
await resetStorage();
const connection = await providersDb.createProviderConnection({
provider: "bai",
authType: "apikey",
name: "bai-live",
apiKey: "bai-key",
});
let fetched = false;
const originalFetch = globalThis.fetch;
globalThis.fetch = async (url) => {
if (String(url) === BAI_MODELS_URL) {
fetched = true;
return Response.json({
object: "list",
data: [{ id: "gpt-5.2" }, { id: "claude-opus-4-5" }, { id: "kimi-k2.5" }],
});
}
return new Response("not found", { status: 404 });
};
try {
const response = await modelsRoute.GET(
new Request(`http://localhost/api/providers/${connection.id}/models?refresh=true`),
{ params: { id: connection.id } }
);
assert.equal(response.status, 200);
const body = (await response.json()) as ModelsBody;
assert.equal(body.provider, "bai");
assert.equal(body.source, "api", "should serve the live upstream catalog");
assert.ok(fetched, `should have probed ${BAI_MODELS_URL}`);
const ids = body.models.map((model) => model.id);
assert.ok(ids.includes("gpt-5.2"), `live catalog model missing: ${ids.join(",")}`);
assert.ok(ids.includes("kimi-k2.5"), `live catalog model missing: ${ids.join(",")}`);
} finally {
globalThis.fetch = originalFetch;
}
});
test("b.ai import falls back to an empty local catalog when live fetch fails", async () => {
await resetStorage();
const connection = await providersDb.createProviderConnection({
provider: "bai",
authType: "apikey",
name: "bai-fallback",
apiKey: "bai-key-2",
});
const originalFetch = globalThis.fetch;
globalThis.fetch = async () => new Response("bad gateway", { status: 502 });
try {
const response = await modelsRoute.GET(
new Request(`http://localhost/api/providers/${connection.id}/models?refresh=true`),
{ params: { id: connection.id } }
);
assert.equal(response.status, 200);
const body = (await response.json()) as ModelsBody;
assert.equal(body.provider, "bai");
assert.equal(body.source, "local_catalog", "import must not break when upstream is down");
assert.deepEqual(
body.models.map((model) => model.id),
[]
);
} finally {
globalThis.fetch = originalFetch;
}
});

View File

@@ -1,55 +0,0 @@
import { test } from "node:test";
import assert from "node:assert/strict";
import { readFileSync } from "node:fs";
import { fileURLToPath } from "node:url";
import { dirname, join } from "node:path";
// Split-guard for the base executor header-helper extraction.
// The pure upstream-header helpers live in base/headers.ts (no host state, no fetch).
// base.ts re-exports all 6 so the ~18 executors + tests that import them from "./base.ts"
// keep resolving unchanged.
const HERE = dirname(fileURLToPath(import.meta.url));
const EXE = join(HERE, "../../open-sse/executors");
const HOST = join(EXE, "base.ts");
const LEAF = join(EXE, "base/headers.ts");
test("leaf hosts the header helpers and does not import the host", () => {
const src = readFileSync(LEAF, "utf8");
for (const sym of [
"mergeUpstreamExtraHeaders",
"setUserAgentHeader",
"isOpenAICompatibleEndpoint",
"stripStainlessHeadersForOpenAICompat",
]) {
assert.match(src, new RegExp(`export function ${sym}\\b`));
}
assert.doesNotMatch(src, /from "\.\.\/base\.ts"/);
});
test("host re-exports all 6 header helpers for external importers", () => {
const host = readFileSync(HOST, "utf8");
for (const sym of [
"mergeUpstreamExtraHeaders",
"getCustomUserAgent",
"setUserAgentHeader",
"applyConfiguredUserAgent",
"isOpenAICompatibleEndpoint",
"stripStainlessHeadersForOpenAICompat",
]) {
assert.match(host, new RegExp(`\\b${sym}\\b`));
}
assert.match(host, /from "\.\/base\/headers\.ts"/);
});
test("header helpers behave via base.ts (the public import path)", async () => {
const mod = await import("../../open-sse/executors/base.ts");
assert.equal(mod.isOpenAICompatibleEndpoint("openai-compatible-x", "https://x/y"), true);
const headers: Record<string, string> = { "x-stainless-lang": "js", "User-Agent": "openai-node" };
const stripped = mod.stripStainlessHeadersForOpenAICompat(
headers,
"openai-compatible-x",
"https://x/v1/chat/completions"
);
assert.ok(stripped.includes("x-stainless-lang"));
assert.equal(headers["x-stainless-lang"], undefined);
});

View File

@@ -1,34 +0,0 @@
import { test } from "node:test";
import assert from "node:assert/strict";
import { readFileSync } from "node:fs";
import { fileURLToPath } from "node:url";
import { dirname, join } from "node:path";
// Split-guard for the base executor reasoning-effort extraction.
// The provider-aware reasoning_effort sanitation lives in base/reasoningEffort.ts
// (deps are config/services only — no host import, no cycle). base.ts re-exports it
// so external importers (mimoThinking + tests) keep the "./base.ts" path.
const HERE = dirname(fileURLToPath(import.meta.url));
const EXE = join(HERE, "../../open-sse/executors");
test("leaf hosts sanitizeReasoningEffortForProvider and does not import the host", () => {
const src = readFileSync(join(EXE, "base/reasoningEffort.ts"), "utf8");
assert.match(src, /export function sanitizeReasoningEffortForProvider\b/);
assert.doesNotMatch(src, /from "\.\.\/base\.ts"/);
});
test("base.ts re-exports it for external importers", () => {
const host = readFileSync(join(EXE, "base.ts"), "utf8");
assert.match(
host,
/export \{[^}]*sanitizeReasoningEffortForProvider[^}]*\} from "\.\/base\/reasoningEffort\.ts"/s
);
});
test("both import paths resolve to the same function", async () => {
const viaHost = (await import("../../open-sse/executors/base.ts"))
.sanitizeReasoningEffortForProvider;
const viaLeaf = (await import("../../open-sse/executors/base/reasoningEffort.ts"))
.sanitizeReasoningEffortForProvider;
assert.equal(viaHost, viaLeaf);
});

View File

@@ -11,7 +11,6 @@ import {
requiresWebSessionCredential,
getWebSessionCredentialRequirement,
hasUsableWebSessionCredential,
resolveWebSessionImportApiKey,
} from "../../src/shared/providers/webSessionCredentials.ts";
describe("bulkWebSessionImportSchema", () => {
@@ -150,63 +149,24 @@ describe("web-session credential helpers", () => {
}),
true
);
assert.equal(hasUsableWebSessionCredential("chatgpt-web", { cookie: "" }), false);
assert.equal(hasUsableWebSessionCredential("chatgpt-web", {}), false);
assert.equal(
hasUsableWebSessionCredential("chatgpt-web", { cookie: "" }),
false
);
assert.equal(
hasUsableWebSessionCredential("chatgpt-web", {}),
false
);
});
it("hasUsableWebSessionCredential validates token data correctly", () => {
assert.equal(hasUsableWebSessionCredential("deepseek-web", { token: "my-token" }), true);
assert.equal(hasUsableWebSessionCredential("deepseek-web", { token: " " }), false);
});
});
describe("resolveWebSessionImportApiKey (token-kind imports must populate apiKey)", () => {
// Regression: the bulk web-session import stored token-kind credentials
// (deepseek-web, copilot-web, t3-chat-web, …) only in providerSpecificData and
// left apiKey null. Both the connection validator (validateDeepSeekWebProvider)
// and the executor (extractUserToken → credentials.apiKey) read the token from
// apiKey, so imported token-kind connections were never recognized. Token-kind
// must resolve the credential into apiKey; cookie-kind keeps apiKey null (those
// executors read providerSpecificData.cookie).
it("returns the credential for a token-kind provider (deepseek-web)", () => {
const req = getWebSessionCredentialRequirement("deepseek-web");
assert.equal(
resolveWebSessionImportApiKey(req, "j9CVFGvd8Y/deadbeeftoken"),
"j9CVFGvd8Y/deadbeeftoken"
hasUsableWebSessionCredential("deepseek-web", { token: "my-token" }),
true
);
});
it("preserves a JSON-wrapped userToken verbatim (extractUserToken unwraps it later)", () => {
const req = getWebSessionCredentialRequirement("deepseek-web");
const blob = '{"value":"abc123","__version":"0"}';
assert.equal(resolveWebSessionImportApiKey(req, blob), blob);
});
it("returns null for cookie-kind providers (they read providerSpecificData.cookie)", () => {
assert.equal(
resolveWebSessionImportApiKey(
getWebSessionCredentialRequirement("claude-web"),
"sessionKey=abc"
),
null
hasUsableWebSessionCredential("deepseek-web", { token: " " }),
false
);
assert.equal(
resolveWebSessionImportApiKey(
getWebSessionCredentialRequirement("chatgpt-web"),
"__Secure-next-auth.session-token=abc"
),
null
);
});
it("returns null for a whitespace-only or missing credential", () => {
const req = getWebSessionCredentialRequirement("deepseek-web");
assert.equal(resolveWebSessionImportApiKey(req, " "), null);
assert.equal(resolveWebSessionImportApiKey(null, "anything"), null);
});
it("trims surrounding whitespace from the stored token", () => {
const req = getWebSessionCredentialRequirement("copilot-web");
assert.equal(resolveWebSessionImportApiKey(req, " tok-123 "), "tok-123");
});
});

View File

@@ -66,29 +66,6 @@ test("Fable 5 catalog exposes claude-fable-5 in cc and kiro providers with match
assert.ok(kiroPricing["claude-fable-5"], "kiro pricing must include claude-fable-5");
});
test("Sonnet 5 catalog exposes claude-sonnet-5 across cc/kiro/anthropic/blackbox with Sonnet-tier pricing", () => {
// Sonnet 5 must be wired everywhere the last flagship (Fable 5) was — but as a
// Sonnet-tier model: $3/$15 pricing (NOT the Opus/Fable $15/$75), 1M ctx / 128K out.
for (const providerId of ["cc", "kiro", "anthropic", "blackbox"]) {
const ids = new Set(getModelsByProviderId(providerId).map((m) => m.id));
assert.ok(ids.has("claude-sonnet-5"), `${providerId} must expose claude-sonnet-5`);
}
const kiroSonnet5 = getModelsByProviderId("kiro").find((m) => m.id === "claude-sonnet-5");
assert.equal(kiroSonnet5?.contextLength, 1000000);
assert.equal(kiroSonnet5?.maxOutputTokens, 128000);
const ccPricing = (DEFAULT_PRICING as Record<string, Record<string, unknown>>).cc;
assert.ok(ccPricing["claude-sonnet-5"], "cc pricing must include claude-sonnet-5");
const kiroPricing = (DEFAULT_PRICING as Record<string, Record<string, unknown>>).kiro;
const kiroSonnet5Price = kiroPricing["claude-sonnet-5"] as { input: number; output: number };
assert.ok(kiroSonnet5Price, "kiro pricing must include claude-sonnet-5");
// Sonnet-tier, not Opus-tier — guards against copying Fable 5's $15/$75.
assert.equal(kiroSonnet5Price.input, 3.0);
assert.equal(kiroSonnet5Price.output, 15.0);
});
test("Kiro catalog exposes Claude Opus 4.8 alongside 4.7 with matching pricing", () => {
const models = getModelsByProviderId("kiro");
const ids = new Set(models.map((model) => model.id));

View File

@@ -452,7 +452,7 @@ test("DefaultExecutor uses CC-compatible path and headers", () => {
assert.equal(headers.Authorization, "Bearer sk-test");
assert.equal(headers["x-api-key"], undefined);
assert.equal(headers["X-Claude-Code-Session-Id"], "session-3");
assert.equal(headers.Accept, "text/event-stream");
assert.equal(headers.Accept, "application/json");
});
test("validateProviderApiKey uses CC skeleton request after /models fallback", async () => {
@@ -493,7 +493,7 @@ test("validateProviderApiKey uses CC skeleton request after /models fallback", a
assert.equal(calls[1].body.stream, true);
assert.equal(calls[1].headers.Authorization, "Bearer sk-test");
assert.equal(calls[1].headers["x-api-key"], undefined);
assert.equal(calls[1].headers.Accept, "text/event-stream");
assert.equal(calls[1].headers.Accept, "application/json");
});
test("handleChatCore forces SSE upstream for CC compatible providers while returning JSON to non-stream clients", async () => {
@@ -571,7 +571,7 @@ test("handleChatCore forces SSE upstream for CC compatible providers while retur
assert.equal(result.success, true);
assert.equal(calls.length, 1);
assert.equal(calls[0].headers.Accept, "text/event-stream");
assert.equal(calls[0].headers.Accept, "application/json");
assert.equal(calls[0].body.stream, true);
assert.equal(calls[0].body.stream_options, undefined);
assert.equal(JSON.stringify(calls[0].body).includes('"cache_control"'), false);

View File

@@ -1,33 +0,0 @@
import test from "node:test";
import assert from "node:assert/strict";
const { APIKEY_PROVIDERS } = await import("../../src/shared/constants/providers.ts");
const { REGISTRY: providerRegistry } = await import("../../open-sse/config/providerRegistry.ts");
const CHARM_HYPER_CHAT_URL = "https://hyper.charm.land/v1/chat/completions";
const CHARM_HYPER_MODELS_URL = "https://hyper.charm.land/v1/models";
test("Charm Hyper is registered as a free API-key provider", () => {
const entry = APIKEY_PROVIDERS["charm-hyper"];
assert.ok(entry, "APIKEY_PROVIDERS['charm-hyper'] must be defined");
assert.equal(entry.id, "charm-hyper");
assert.equal(entry.alias, "charm-hyper");
assert.equal(entry.name, "Charm Hyper");
assert.equal(entry.website, "https://hyper.charm.land");
assert.equal(entry.hasFree, true);
assert.equal(entry.passthroughModels, true);
});
test("Charm Hyper registry entry uses OpenAI format with bearer API-key auth", () => {
const entry = providerRegistry["charm-hyper"];
assert.ok(entry, "providerRegistry['charm-hyper'] must be defined");
assert.equal(entry.id, "charm-hyper");
assert.equal(entry.alias, "charm-hyper");
assert.equal(entry.format, "openai");
assert.equal(entry.executor, "default");
assert.equal(entry.authType, "apikey");
assert.equal(entry.authHeader, "bearer");
assert.equal(entry.baseUrl, CHARM_HYPER_CHAT_URL);
assert.equal(entry.modelsUrl, CHARM_HYPER_MODELS_URL);
assert.equal(entry.passthroughModels, true);
});

View File

@@ -499,9 +499,7 @@ test("chatCore keeps Responses-native Codex payloads in native passthrough mode"
assert.equal(result.success, true);
assert.match(call.url, /\/responses$/);
assert.deepEqual(call.body.input, [
{ type: "message", role: "user", content: [{ type: "input_text", text: "ship it" }] },
]);
assert.deepEqual(call.body.input, [{ type: "message", role: "user", content: [{ type: "input_text", text: "ship it" }] }]);
assert.equal(call.body.instructions, "custom system prompt");
assert.equal(call.body.store, false);
assert.deepEqual(call.body.metadata, { source: "codex-client" });
@@ -673,8 +671,9 @@ test("chatCore builds Claude Code-compatible upstream requests for CC providers"
});
assert.equal(result.success, true);
assert.equal(call.headers.Accept ?? call.headers.accept, "text/event-stream");
assert.deepEqual([call.body.stream, call.body.context_management], [true, undefined]);
assert.equal(call.headers.Accept ?? call.headers.accept, "application/json");
assert.equal(call.body.stream, true);
assert.equal(call.body.context_management, undefined);
assert.equal(call.body.system.length, 1);
assert.match(call.body.system[0].text, /Claude Agent SDK/);
assert.equal(typeof call.body.metadata.user_id, "string");

View File

@@ -1,35 +0,0 @@
import { test } from "node:test";
import assert from "node:assert/strict";
import { readFileSync } from "node:fs";
import { fileURLToPath } from "node:url";
import { dirname, join } from "node:path";
// Split-guard for the chatgpt-web model-mapping extraction.
// The static model maps + pure thinking-effort resolvers live in the pure leaf
// chatgpt-web/models.ts (no module state). Host imports the two it uses back.
const HERE = dirname(fileURLToPath(import.meta.url));
const EXE = join(HERE, "../../open-sse/executors");
const HOST = join(EXE, "chatgpt-web.ts");
const LEAF = join(EXE, "chatgpt-web/models.ts");
test("leaf hosts the model maps + resolvers and does not import the host", () => {
const src = readFileSync(LEAF, "utf8");
for (const sym of ["MODEL_MAP", "resolveChatGptModel", "resolveThinkingEffort"]) {
assert.match(src, new RegExp(`export (const|function) ${sym}\\b`));
}
assert.doesNotMatch(src, /from "\.\.\/chatgpt-web\.ts"/);
});
test("host imports the resolvers back from the leaf", () => {
const host = readFileSync(HOST, "utf8");
assert.match(host, /from "\.\/chatgpt-web\/models\.ts"/);
});
test("resolveChatGptModel maps a dot-form model id to a chatgpt slug", async () => {
const { resolveChatGptModel, MODEL_MAP } =
await import("../../open-sse/executors/chatgpt-web/models.ts");
const firstKey = Object.keys(MODEL_MAP)[0];
const resolved = resolveChatGptModel(firstKey);
assert.equal(typeof resolved.slug, "string");
assert.ok(resolved.slug.length > 0);
});

View File

@@ -1,55 +0,0 @@
import test from "node:test";
import assert from "node:assert/strict";
import { execFileSync } from "node:child_process";
import path from "node:path";
import { fileURLToPath } from "node:url";
const mod = await import("../../scripts/check/check-pr-evidence.mjs");
const { evaluatePrBody } = mod;
const SCRIPT = path.resolve(
path.dirname(fileURLToPath(import.meta.url)),
"../../scripts/check/check-pr-evidence.mjs"
);
function run(body) {
try {
const out = execFileSync("node", [SCRIPT], {
encoding: "utf8",
env: { ...process.env, PR_BODY: body },
});
return { code: 0, out };
} catch (err) {
return { code: err.status ?? 1, out: `${err.stdout || ""}${err.stderr || ""}` };
}
}
test("evaluatePrBody: no outcome claim → pass (no evidence required)", () => {
const r = evaluatePrBody("Adds a helper module.");
assert.equal(r.result, "pass");
assert.match(r.reason, /no evidence required/i);
});
test("evaluatePrBody: outcome claim + evidence block → pass", () => {
const r = evaluatePrBody("Tests pass.\n\n## Evidence\n```\ntests 20 / pass 20 / fail 0\n```");
assert.equal(r.result, "pass");
});
test("evaluatePrBody: outcome claim without evidence → fail", () => {
const r = evaluatePrBody("All 20 tests pass and 0 errors.");
assert.equal(r.result, "fail");
});
test("the FAIL report explains that editing the body does not re-run the gate (push instead)", () => {
const { code, out } = run("All 20 tests pass and 0 errors."); // claim, no evidence
assert.equal(code, 1, "gate fails on a claim with no evidence");
assert.match(out, /Result: FAIL/);
assert.match(out, /does NOT re-run this gate/);
assert.match(out, /push a commit/i);
});
test("the hint does NOT appear when the gate passes", () => {
const { code, out } = run("Tests pass.\n\n## Evidence\n```\ntests 20 / pass 20 / fail 0\n```");
assert.equal(code, 0);
assert.match(out, /Result: PASS/);
assert.doesNotMatch(out, /does NOT re-run this gate/);
});

View File

@@ -1,178 +0,0 @@
/**
* TDD test for the Claude Code auto-mode classifier compat mode (opt-in, default off).
*
* Claude Code's `--permission-mode auto` sends an internal `/v1/messages` security-classifier
* request and requires the response to START with the literal token `<block>no</block>` (ALLOW)
* or `<block>yes</block>` (BLOCK) — anything else is unparseable and Claude Code fails closed
* with "Auto mode could not evaluate this action and is blocking it for safety".
*
* When a combo/fallback route sends the classifier call to a cheap model that returns 200 with
* empty content, the well-formed-but-empty Claude message OmniRoute produces still fails that
* parser. With `claudeClassifierCompat` set to "auto" (or "always"), handleChatCore detects the
* classifier request and short-circuits with a synthetic ALLOW response — WITHOUT ever calling
* the upstream provider. Default is "off": nothing changes unless an operator explicitly opts in.
*/
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-claude-classifier-compat-"));
process.env.DATA_DIR = TEST_DATA_DIR;
const core = await import("../../src/lib/db/core.ts");
const { updateSettings } = await import("../../src/lib/db/settings.ts");
const { handleChatCore } = await import("../../open-sse/handlers/chatCore.ts");
const { shouldDefaultAllowClassifier, buildDefaultAllowClaudeMessage } = await import(
"../../open-sse/handlers/chatCore/claudeClassifierCompat.ts"
);
const { FORMATS } = await import("../../open-sse/translator/formats.ts");
const originalFetch = globalThis.fetch;
function noopLog() {
return { debug() {}, info() {}, warn() {}, error() {} };
}
// Shape of the classifier request Claude Code's `--permission-mode auto` sends internally:
// a Claude Messages request carrying the security-monitor system prompt AND `</block>` as a
// stop sequence — the two independent signals the compat detector relies on.
const CLASSIFIER_BODY = {
model: "claude-3-5-haiku-20241022",
stream: false,
system: [
{
type: "text",
text: "You are a security monitor for autonomous AI coding agents. Evaluate the following action and respond with <block>yes</block> or <block>no</block>.",
},
],
stop_sequences: ["</block>"],
messages: [
{
role: "user",
content: [{ type: "text", text: "<transcript>WebFetch https://example.com</transcript>" }],
},
],
max_tokens: 8,
};
test.after(() => {
globalThis.fetch = originalFetch;
core.resetDbInstance();
fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true });
});
// ─── Settings default is opt-in (off) ────────────────────────────────────────
// Runs FIRST, before any updateSettings() write, so it reads the pristine DB.
// (DATA_DIR freezes at the first DB open, so a later "fresh dir" swap would still
// read this same DB — hence assert the default up front.)
test("settings default: claudeClassifierCompat is 'off' (opt-in)", async () => {
const { getSettings } = await import("../../src/lib/db/settings.ts");
const settings = await getSettings();
assert.equal(settings.claudeClassifierCompat, "off", "claudeClassifierCompat defaults to off");
});
// ─── Pure detector: shouldDefaultAllowClassifier ─────────────────────────────
test("detector: off never short-circuits (pass-through preserved by default)", () => {
assert.equal(shouldDefaultAllowClassifier(FORMATS.CLAUDE, CLASSIFIER_BODY, "off"), false);
assert.equal(shouldDefaultAllowClassifier(FORMATS.CLAUDE, CLASSIFIER_BODY, undefined), false);
});
test("detector: auto fires on the security-monitor system-prompt marker", () => {
const body = {
system: [{ type: "text", text: "You are a security monitor for autonomous AI coding agents." }],
stop_sequences: [],
};
assert.equal(shouldDefaultAllowClassifier(FORMATS.CLAUDE, body, "auto"), true);
});
test("detector: auto fires on the </block> stop_sequence token", () => {
const body = { system: [{ type: "text", text: "unrelated" }], stop_sequences: ["</block>"] };
assert.equal(shouldDefaultAllowClassifier(FORMATS.CLAUDE, body, "auto"), true);
});
test("detector: auto does NOT fire on a regular Claude request (no marker, no </block>)", () => {
const body = {
system: [{ type: "text", text: "You are a helpful coding assistant." }],
stop_sequences: [],
messages: [{ role: "user", content: "hello" }],
};
assert.equal(shouldDefaultAllowClassifier(FORMATS.CLAUDE, body, "auto"), false);
});
test("detector: never fires for non-Claude source formats even in always mode", () => {
assert.equal(shouldDefaultAllowClassifier(FORMATS.OPENAI, CLASSIFIER_BODY, "always"), false);
});
test("detector: always fires for every Claude-format request", () => {
const plain = { system: [{ type: "text", text: "hi" }], stop_sequences: [] };
assert.equal(shouldDefaultAllowClassifier(FORMATS.CLAUDE, plain, "always"), true);
});
// ─── Pure builder: buildDefaultAllowClaudeMessage ────────────────────────────
test("builder: synthetic message text STARTS WITH <block>no</block>", async () => {
const built = buildDefaultAllowClaudeMessage("claude-3-5-haiku-20241022");
assert.equal(built.success, true);
const payload = (await built.response.json()) as {
type: string;
role: string;
stop_reason: string;
content: Array<{ type: string; text?: string }>;
};
assert.equal(payload.type, "message");
assert.equal(payload.role, "assistant");
assert.equal(payload.stop_reason, "end_turn");
const text = payload.content.find((b) => b.type === "text")?.text ?? "";
assert.ok(
text.startsWith("<block>no</block>"),
`expected synthetic text to start with <block>no</block>, got: ${text}`
);
assert.ok(!text.includes("<block>yes"), "must not signal BLOCK");
});
// ─── Handler-level: end-to-end short-circuit through handleChatCore ──────────
test("handler: claudeClassifierCompat=auto short-circuits WITHOUT calling upstream, text starts with <block>no</block>", async () => {
await updateSettings({ claudeClassifierCompat: "auto" });
let fetchCalls = 0;
globalThis.fetch = (async () => {
fetchCalls++;
throw new Error("upstream fetch should NOT be called when the classifier short-circuits");
}) as typeof fetch;
try {
const result = await handleChatCore({
body: structuredClone(CLASSIFIER_BODY),
modelInfo: { provider: "openai", model: "gpt-4o-mini", extendedContext: false },
credentials: { apiKey: "sk-test", providerSpecificData: {} },
log: noopLog(),
clientRawRequest: {
endpoint: "/v1/messages",
body: structuredClone(CLASSIFIER_BODY),
headers: new Headers({ accept: "application/json" }),
},
userAgent: "unit-test",
});
assert.equal(fetchCalls, 0, "upstream fetch must NOT be called");
assert.equal(result.success, true, "handleChatCore must report success");
const payload = (await (result as { response: Response }).response.json()) as {
type: string;
content: Array<{ type: string; text?: string }>;
};
assert.equal(payload.type, "message");
const text = payload.content.find((b) => b.type === "text")?.text ?? "";
assert.ok(
text.startsWith("<block>no</block>"),
`expected classifier response to start with <block>no</block>, got: ${text}`
);
} finally {
globalThis.fetch = originalFetch;
}
});

View File

@@ -47,7 +47,7 @@ test("buildClaudeCodeCompatibleHeaders emits bearer auth headers and session id"
const streamHeaders = buildClaudeCodeCompatibleHeaders("sk-demo", true, "session-123");
const jsonHeaders = buildClaudeCodeCompatibleHeaders("sk-demo", false);
assert.equal(streamHeaders.Accept, "text/event-stream");
assert.equal(streamHeaders.Accept, "application/json");
assert.equal(streamHeaders.Authorization, "Bearer sk-demo");
assert.equal(streamHeaders["x-api-key"], undefined);
assert.equal(streamHeaders["X-Claude-Code-Session-Id"], "session-123");

View File

@@ -1,38 +0,0 @@
import { test } from "node:test";
import assert from "node:assert/strict";
import { readFileSync } from "node:fs";
import { fileURLToPath } from "node:url";
import { dirname, join } from "node:path";
// Split-guard for the claude-web executor payload extraction.
// The pure payload types + transforms + default tools/style live in the leaf
// claude-web/payload.ts (no host state, no fetch/auth). Host imports back the
// symbols it uses (ClaudeWebRequestPayload, transformToClaude, transformFromClaude).
const HERE = dirname(fileURLToPath(import.meta.url));
const EXE = join(HERE, "../../open-sse/executors");
const HOST = join(EXE, "claude-web.ts");
const LEAF = join(EXE, "claude-web/payload.ts");
test("leaf hosts the payload builders/transforms and does not import the host", () => {
const src = readFileSync(LEAF, "utf8");
for (const sym of ["transformToClaude", "transformFromClaude", "getDefaultTools"]) {
assert.match(src, new RegExp(`export function ${sym}\\b`));
}
assert.match(src, /export interface ClaudeWebRequestPayload\b/);
assert.doesNotMatch(src, /from "\.\.\/claude-web\.ts"/);
});
test("host imports the transforms back from the leaf", () => {
const host = readFileSync(HOST, "utf8");
assert.match(host, /from "\.\/claude-web\/payload\.ts"/);
});
test("transformToClaude builds a Claude-web payload with model + tools", async () => {
const { transformToClaude } = await import("../../open-sse/executors/claude-web/payload.ts");
const payload = transformToClaude(
{ messages: [{ role: "user", content: "hi" }] },
"claude-sonnet-4-6"
);
assert.equal(typeof payload, "object");
assert.ok(Array.isArray(payload.tools));
});

View File

@@ -44,7 +44,6 @@ const NOT_ACP_SPAWNABLE_IDS = [
"roo",
"jcode",
"deepseek-tui",
"codewhale",
"smelt",
"pi",
"hermes-agent",

View File

@@ -30,7 +30,7 @@ test(`CLI_TOOLS has exactly ${EXPECTED_AGENT_COUNT} agent entries`, () => {
);
});
test("CLI_TOOLS total code entries (including none) equals 24 (20 visible + 4 none)", () => {
test("CLI_TOOLS total code entries (including none) equals 22 (18 visible + 4 none)", () => {
// code-none entries: antigravity, kiro, cursor (app), hermes (simple guide)
const codeNone = codeAll.filter((t) => t.baseUrlSupport === "none");
assert.equal(
@@ -38,11 +38,11 @@ test("CLI_TOOLS total code entries (including none) equals 24 (20 visible + 4 no
4,
`Expected 4 code entries with baseUrlSupport='none', got ${codeNone.length}: ${codeNone.map((t) => t.id).join(", ")}`
);
assert.equal(codeAll.length, 24, `Expected 24 total code entries, got ${codeAll.length}`);
assert.equal(codeAll.length, 22, `Expected 22 total code entries, got ${codeAll.length}`);
});
test("CLI_TOOLS total (code + agent) = 30", () => {
assert.equal(all.length, 30, `Expected 30 total entries, got ${all.length}`);
test("CLI_TOOLS total (code + agent) = 28", () => {
assert.equal(all.length, 28, `Expected 28 total entries, got ${all.length}`);
});
test("All code-none entries have configType mitm OR are legacy excluded entries", () => {
@@ -66,7 +66,7 @@ test("All agent entries have baseUrlSupport 'full' or 'partial' (no agent is 'no
}
});
test("The 20 visible code entries match D15 list exactly (+ crush + codewhale)", () => {
test("The 18 visible code entries match D15 list exactly", () => {
const d15List = new Set([
"claude",
"codex",
@@ -79,7 +79,6 @@ test("The 20 visible code entries match D15 list exactly (+ crush + codewhale)",
"forge",
"jcode",
"deepseek-tui",
"codewhale",
"opencode",
"droid",
"copilot",
@@ -87,7 +86,6 @@ test("The 20 visible code entries match D15 list exactly (+ crush + codewhale)",
"smelt",
"pi",
"custom",
"crush",
]);
const visibleIds = new Set(codeVisible.map((t) => t.id));
for (const id of d15List) {

View File

@@ -40,27 +40,12 @@ function readConfig() {
return JSON.parse(fs.readFileSync(path.join(CONFIG_DIR, "opencode.json"), "utf8"));
}
// #5959-class deflake: the command under test prints CLI progress with multi-byte
// glyphs (printInfo/printSuccess "✔"/printError "✖" via console.log). Under the
// node:test runner those stdout writes interleave with the child's V8-serialized
// report frames and can corrupt the stream ("Unable to deserialize cloned data
// due to invalid or unsupported version"). No test here asserts on stdout, so
// silence the stdout-writing console methods for the duration of this file
// (same pattern as tests/unit/cli/setup-claude.test.ts, #6019/#6021).
const _console = { log: console.log, info: console.info, warn: console.warn };
describe("omniroute setup opencode", () => {
before(() => {
console.log = () => {};
console.info = () => {};
console.warn = () => {};
makeFakePluginDist();
});
after(() => {
console.log = _console.log;
console.info = _console.info;
console.warn = _console.warn;
try {
fs.rmSync(FIXTURE_ROOT, { recursive: true, force: true });
} catch {
@@ -87,11 +72,7 @@ describe("omniroute setup opencode", () => {
const [modulePath, options] = cfg.plugin[0];
assert.equal(modulePath, "./plugins/omniroute/dist/index.js");
assert.equal(options.providerId, "omniroute");
assert.equal(
options.baseURL,
"http://10.0.0.5:20128",
"--base-url flag must reach the registered entry"
);
assert.equal(options.baseURL, "http://10.0.0.5:20128", "--base-url flag must reach the registered entry");
});
it("is idempotent: re-running updates the entry in place instead of duplicating it", async () => {
@@ -104,15 +85,10 @@ describe("omniroute setup opencode", () => {
const cfg = readConfig();
const omniEntries = cfg.plugin.filter(
(p: unknown) =>
Array.isArray(p) && (p[1] as { providerId?: string })?.providerId === "omniroute"
(p: unknown) => Array.isArray(p) && (p[1] as { providerId?: string })?.providerId === "omniroute"
);
assert.equal(omniEntries.length, 1, "re-run must not duplicate the entry");
assert.equal(
omniEntries[0][1].baseURL,
"http://10.0.0.9:20128",
"re-run updates baseURL in place"
);
assert.equal(omniEntries[0][1].baseURL, "http://10.0.0.9:20128", "re-run updates baseURL in place");
});
it("removes the legacy opencode-omniroute-auth entry (#3711) and preserves unrelated plugins", async () => {

View File

@@ -1,233 +0,0 @@
/**
* Unit tests for the "Crush" CLI tool dashboard entry (ported from upstream
* decolua/9router#1233). Mirrors the assertions used for the "pi" tool in
* tests/unit/cli-tools-schema.test.ts, plus a GET/POST/DELETE round-trip for
* /api/cli-tools/crush-settings modeled on tests/integration/cli-settings-pi.test.ts.
*/
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";
// ── Catalog shape ────────────────────────────────────────────────────────────
test("CLI_TOOLS contains a 'crush' entry modeled on 'pi'", async () => {
const { CLI_TOOLS } = await import("../../src/shared/constants/cliTools.ts");
const crush = CLI_TOOLS["crush"];
assert.ok(crush, "crush entry must exist in CLI_TOOLS");
assert.equal(crush.id, "crush");
assert.equal(crush.name, "Crush");
assert.equal(crush.configType, "custom");
assert.equal(crush.category, "code");
assert.equal(crush.acpSpawnable, false);
assert.equal(crush.baseUrlSupport, "full");
assert.equal(crush.defaultCommand, "crush");
assert.equal(typeof crush.description, "string");
assert.ok(crush.description.length > 0);
assert.equal(typeof crush.docsUrl, "string");
assert.ok(crush.docsUrl.length > 0);
});
test("getCliTool('crush') resolves the catalog entry", async () => {
const { getCliTool } = await import("../../src/shared/constants/cliTools.ts");
const crush = getCliTool("crush");
assert.ok(crush);
assert.equal(crush.id, "crush");
});
// ── Runtime config path reconciliation with setup-crush.mjs ─────────────────
test("getCliConfigPaths('crush') resolves to ~/.config/crush/crush.json (matches setup-crush.mjs default)", async () => {
const { getCliConfigPaths } = await import("../../src/shared/services/cliRuntime.ts");
const paths = getCliConfigPaths("crush");
assert.ok(paths);
assert.ok(
paths.config?.endsWith(path.join(".config", "crush", "crush.json")),
`Expected config path to end with .config/crush/crush.json, got: ${paths.config}`
);
});
// ── /api/cli-tools/crush-settings round-trip ─────────────────────────────────
const TEST_DATA_DIR = fs.mkdtempSync(path.join(os.tmpdir(), "omniroute-crush-settings-"));
process.env.DATA_DIR = TEST_DATA_DIR;
process.env.API_KEY_SECRET = "test-api-key-secret-crush";
process.env.JWT_SECRET = "test-jwt-secret-crush";
const core = await import("../../src/lib/db/core.ts");
const localDb = await import("../../src/lib/localDb.ts");
const { GET, POST, DELETE } = await import("../../src/app/api/cli-tools/crush-settings/route.ts");
async function resetStorage() {
delete process.env.INITIAL_PASSWORD;
core.resetDbInstance();
fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true });
fs.mkdirSync(TEST_DATA_DIR, { recursive: true });
}
async function enableAuth() {
process.env.INITIAL_PASSWORD = "test-bootstrap";
await localDb.updateSettings({ requireLogin: true, password: "" });
}
test.beforeEach(async () => {
await resetStorage();
});
test("crush-settings GET: returns 401 when auth required and no token", async () => {
await enableAuth();
const res = await GET(new Request("http://localhost/api/cli-tools/crush-settings"));
assert.equal(res.status, 401, `Expected 401, got ${res.status}`);
});
test("crush-settings GET: returns 200 when auth not required", async () => {
const res = await GET(new Request("http://localhost/api/cli-tools/crush-settings"));
assert.equal(res.status, 200, `Expected 200, got ${res.status}`);
const body = await res.json();
assert.ok(
"installed" in body || "config" in body,
"Response should contain installed or config field"
);
});
test("crush-settings POST: 400 when baseUrl is missing", async () => {
const res = await POST(
new Request("http://localhost/api/cli-tools/crush-settings", {
method: "POST",
headers: { "content-type": "application/json" },
body: JSON.stringify({ apiKey: "sk-test", model: "openai/gpt-5" }),
})
);
assert.equal(res.status, 400, `Expected 400, got ${res.status}`);
const body = await res.json();
assert.ok(body.error !== undefined);
});
test("crush-settings POST: 400 when model is missing", async () => {
const res = await POST(
new Request("http://localhost/api/cli-tools/crush-settings", {
method: "POST",
headers: { "content-type": "application/json" },
body: JSON.stringify({ baseUrl: "http://localhost:20128", apiKey: "sk-test" }),
})
);
assert.equal(res.status, 400, `Expected 400, got ${res.status}`);
});
test("crush-settings POST: writes crush.json with an openai-compat providers.omniroute block", async () => {
const tmpHome = fs.mkdtempSync(path.join(os.tmpdir(), "crush-home-"));
const origHome = process.env.HOME;
process.env.HOME = tmpHome;
try {
const res = await POST(
new Request("http://localhost/api/cli-tools/crush-settings", {
method: "POST",
headers: { "content-type": "application/json" },
body: JSON.stringify({
baseUrl: "http://localhost:20128",
apiKey: "sk-test-crush-key",
model: "openai/gpt-5.4-mini",
}),
})
);
assert.ok([200, 403, 500].includes(res.status), `Unexpected status ${res.status}`);
if (res.status === 200) {
const body = await res.json();
assert.equal(body.success, true);
const configPath = path.join(tmpHome, ".config", "crush", "crush.json");
if (fs.existsSync(configPath)) {
const written = JSON.parse(fs.readFileSync(configPath, "utf-8"));
const provider = written.providers?.omniroute;
assert.ok(provider, "providers.omniroute must be written");
assert.equal(provider.type, "openai-compat");
assert.ok(provider.base_url.includes("localhost:20128"));
assert.ok(provider.base_url.endsWith("/v1"));
assert.ok(Array.isArray(provider.models) && provider.models.length === 1);
assert.equal(provider.models[0].id, "openai/gpt-5.4-mini");
}
}
} finally {
process.env.HOME = origHome;
fs.rmSync(tmpHome, { recursive: true, force: true });
}
});
test("crush-settings DELETE: removes only the omniroute provider entry", async () => {
const tmpHome = fs.mkdtempSync(path.join(os.tmpdir(), "crush-home-del-"));
const origHome = process.env.HOME;
process.env.HOME = tmpHome;
try {
const crushDir = path.join(tmpHome, ".config", "crush");
fs.mkdirSync(crushDir, { recursive: true });
fs.writeFileSync(
path.join(crushDir, "crush.json"),
JSON.stringify({
providers: {
omniroute: {
type: "openai-compat",
base_url: "http://localhost:20128/v1",
api_key: "sk-test",
models: [
{ id: "openai/gpt-5", name: "OmniRoute: openai/gpt-5", context_window: 128000 },
],
},
other: { type: "openai-compat", base_url: "http://example.com/v1" },
},
})
);
const res = await DELETE(
new Request("http://localhost/api/cli-tools/crush-settings", { method: "DELETE" })
);
assert.ok([200, 403, 500].includes(res.status), `Expected 200/403/500, got ${res.status}`);
if (res.status === 200) {
const body = await res.json();
assert.equal(body.success, true);
const configPath = path.join(crushDir, "crush.json");
if (fs.existsSync(configPath)) {
const written = JSON.parse(fs.readFileSync(configPath, "utf-8"));
assert.equal(written.providers?.omniroute, undefined);
assert.ok(written.providers?.other, "Unrelated providers must be preserved");
}
}
} finally {
process.env.HOME = origHome;
fs.rmSync(tmpHome, { recursive: true, force: true });
}
});
test("crush-settings: error responses do not leak stack traces", async () => {
const badReq = new Request("http://localhost/api/cli-tools/crush-settings", {
method: "POST",
headers: { "content-type": "application/json" },
body: "{ bad json }",
});
const res = await POST(badReq);
const bodyStr = JSON.stringify(await res.json());
assert.ok(
!bodyStr.match(/\s+at\s+\/[^\s]/),
"Error response must not contain absolute-path stack traces"
);
});
test("crush-settings route.ts: does not call exec() or spawn() directly", () => {
const routePath = path.resolve(
import.meta.dirname,
"../../src/app/api/cli-tools/crush-settings/route.ts"
);
const content = fs.readFileSync(routePath, "utf-8");
assert.ok(!content.match(/\bexec\s*\(/), "Handler must not use exec()");
assert.ok(!content.match(/\bspawn\s*\(/), "Handler must not use spawn()");
});
test.after(async () => {
await resetStorage();
fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true });
delete process.env.DATA_DIR;
delete process.env.API_KEY_SECRET;
delete process.env.JWT_SECRET;
});

View File

@@ -1,14 +1,11 @@
import test from "node:test";
import assert from "node:assert/strict";
test("CLI_TOOLS registry contains all expected tools (plan 14 — 30 total + crush + codewhale)", async () => {
test("CLI_TOOLS registry contains all expected tools (plan 14 — 28 total)", async () => {
const { CLI_TOOLS } = await import("../../src/shared/constants/cliTools.ts");
// windsurf and amp removed per plan 14 D17 (MITM backlog plan 11)
// New entries added: roo, jcode, deepseek-tui, smelt, pi, aider, forge,
// cursor-cli, goose, interpreter, warp, agent-deck (+ hermes-agent already existed)
// crush added — ported from upstream decolua/9router#1233
// codewhale added 2026-07-02 as a dual entry alongside deepseek-tui
// (CodeWhale is the actively-maintained successor to DeepSeek TUI).
const expected = [
"claude",
"codex",
@@ -32,14 +29,12 @@ test("CLI_TOOLS registry contains all expected tools (plan 14 — 30 total + cru
"roo",
"jcode",
"deepseek-tui",
"codewhale",
"smelt",
"pi",
"goose",
"interpreter",
"warp",
"agent-deck",
"crush",
];
for (const id of expected) {
assert.ok(id in CLI_TOOLS, `Missing tool: ${id}`);

View File

@@ -1,4 +1,4 @@
import { test, before, after } from "node:test";
import { test } from "node:test";
import assert from "node:assert/strict";
import fs from "node:fs/promises";
import os from "node:os";
@@ -10,27 +10,6 @@ import {
import { buildClaudeEnv, resolveLaunchTarget } from "../../../bin/cli/commands/launch.mjs";
import { categoriseModel } from "../../../bin/cli/commands/setup-codex.mjs";
// #5959 — deflake: `node --test` runs each file in a child process that streams
// its report back to the parent as V8-serialized frames on fd 1 (stdout). The CLI
// helpers under test (`syncClaudeProfilesFromModels`) print progress via
// `console.log`, and that stdout output interleaves with the serialized frames,
// corrupting the stream — the parent then throws
// "Unable to deserialize cloned data due to invalid or unsupported version" at
// file teardown ~50% of runs (all subtests pass; only the file errors). No test
// here asserts on stdout, so silence the stdout-writing console methods for the
// duration of this file. Restored in `after` for good hygiene.
const _console = { log: console.log, info: console.info, warn: console.warn };
before(() => {
console.log = () => {};
console.info = () => {};
console.warn = () => {};
});
after(() => {
console.log = _console.log;
console.info = _console.info;
console.warn = _console.warn;
});
// ── setup-claude profile generation ──────────────────────────────────────────
test("buildProfileSettings pins the model + base URL + gateway discovery", () => {
@@ -89,30 +68,19 @@ test("syncClaudeProfilesFromModels writes directory-per-profile settings + threa
}
});
test("syncClaudeProfilesFromModels dry-run writes nothing and reports via the injected log (#5959)", async () => {
test("syncClaudeProfilesFromModels dry-run writes nothing", async () => {
const claudeHome = await fs.mkdtemp(path.join(os.tmpdir(), "omniroute-claude-dry-"));
// The collector keeps the dry-run's multi-byte "──" heading OFF this child
// process's stdout: under the node:test runner that write corrupts the V8
// serialization stream ~50% of runs (#5959, "Unable to deserialize cloned
// data due to invalid or unsupported version").
const lines: string[] = [];
try {
const result = await syncClaudeProfilesFromModels([{ id: "glm/glm-5.2" }], {
claudeHome,
baseUrl: "http://vps:20128",
dryRun: true,
log: (line: string) => lines.push(line),
});
assert.equal(result.written, 1);
// Dry-run reports the would-be file + its content through the log sink…
assert.equal(lines.length, 2);
const settingsPath = path.join(claudeHome, "profiles", "glm52", "settings.json");
assert.ok(lines[0].includes(settingsPath));
const printed = JSON.parse(lines[1]);
assert.equal(printed.model, "glm/glm-5.2");
assert.equal(printed.env.ANTHROPIC_BASE_URL, "http://vps:20128");
// …and writes nothing to disk.
await assert.rejects(fs.stat(settingsPath), /ENOENT/);
await assert.rejects(
fs.stat(path.join(claudeHome, "profiles", "glm52", "settings.json")),
/ENOENT/
);
} finally {
await fs.rm(claudeHome, { recursive: true, force: true });
}

View File

@@ -1,174 +0,0 @@
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";
// DefaultExecutor transitively touches the DB layer (provider/key rotation
// lookups) at import/call time. Point DATA_DIR at an isolated temp dir
// BEFORE importing it so these tests never read/write the operator's real
// ~/.omniroute database (see CLAUDE.md "Database Handles in Tests").
const TEST_DATA_DIR = fs.mkdtempSync(path.join(os.tmpdir(), "omniroute-client-identity-"));
process.env.DATA_DIR = TEST_DATA_DIR;
const {
CLIENT_IDENTITY_PROFILES,
CLIENT_IDENTITY_PROFILE_OPTIONS,
getClientIdentityProfileHeaders,
isClientIdentityProfileId,
} = await import("../../src/shared/constants/clientIdentityProfiles.ts");
const { isForbiddenCustomHeaderName } = await import("../../src/shared/constants/upstreamHeaders.ts");
const { DefaultExecutor } = await import("../../open-sse/executors/default.ts");
const core = await import("../../src/lib/db/core.ts");
test.after(async () => {
core.resetDbInstance();
fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true });
});
test("getClientIdentityProfileHeaders: default profile adds no headers", () => {
assert.deepEqual(getClientIdentityProfileHeaders("default"), {});
assert.deepEqual(getClientIdentityProfileHeaders(undefined), {});
assert.deepEqual(getClientIdentityProfileHeaders(null), {});
});
test("getClientIdentityProfileHeaders: unknown profile id falls back to no headers", () => {
assert.deepEqual(getClientIdentityProfileHeaders("not-a-real-profile"), {});
});
test("getClientIdentityProfileHeaders: known CLI profiles expose their preset headers", () => {
const claudeCli = getClientIdentityProfileHeaders("claude-cli");
assert.equal(claudeCli["User-Agent"], "claude-cli/2.1.195 (external, cli)");
assert.equal(claudeCli["X-App"], "cli");
const codexCli = getClientIdentityProfileHeaders("codex-cli");
assert.equal(codexCli["User-Agent"], "codex_cli_rs/0.136.0");
assert.equal(codexCli.originator, "codex_cli_rs");
const geminiCli = getClientIdentityProfileHeaders("gemini-cli");
assert.equal(geminiCli["User-Agent"], "GeminiCLI/0.1.0 (linux; x64)");
});
test("getClientIdentityProfileHeaders: returns a fresh mutable copy (catalog stays frozen)", () => {
const headers = getClientIdentityProfileHeaders("claude-cli");
headers["User-Agent"] = "tampered";
assert.equal(
CLIENT_IDENTITY_PROFILES["claude-cli"].headers["User-Agent"],
"claude-cli/2.1.195 (external, cli)"
);
});
test("isClientIdentityProfileId / CLIENT_IDENTITY_PROFILE_OPTIONS stay in sync with the catalog", () => {
for (const id of Object.keys(CLIENT_IDENTITY_PROFILES)) {
assert.equal(isClientIdentityProfileId(id), true);
}
assert.equal(isClientIdentityProfileId("bogus"), false);
const optionValues = CLIENT_IDENTITY_PROFILE_OPTIONS.map((o) => o.value);
assert.deepEqual(optionValues, Object.keys(CLIENT_IDENTITY_PROFILES));
assert.equal(CLIENT_IDENTITY_PROFILE_OPTIONS[0].value, "default");
});
test("a selected profile's headers land in providerSpecificData.customHeaders", () => {
// This is exactly what the compatible-provider modal does when an operator
// picks a profile from the <Select>: merge the preset onto the existing
// customHeaders record before persisting the node/connection.
const profileHeaders = getClientIdentityProfileHeaders("codex-cli");
const providerSpecificData = {
baseUrl: "https://proxy.example.com/v1",
customHeaders: { ...profileHeaders, "X-Operator-Set": "keep-me" },
};
assert.equal(providerSpecificData.customHeaders["User-Agent"], "codex_cli_rs/0.136.0");
assert.equal(providerSpecificData.customHeaders.originator, "codex_cli_rs");
assert.equal(providerSpecificData.customHeaders["X-Operator-Set"], "keep-me");
});
test("profile headers merged into customHeaders survive applyCustomHeaders sanitization via DefaultExecutor", () => {
const executor = new DefaultExecutor("openai-compatible-test");
const profileHeaders = getClientIdentityProfileHeaders("claude-cli");
const headers = executor.buildHeaders(
{
apiKey: "test-key",
providerSpecificData: {
baseUrl: "https://proxy.example.com/v1",
customHeaders: profileHeaders,
},
},
true
) as Record<string, string>;
assert.equal(headers["User-Agent"], "claude-cli/2.1.195 (external, cli)");
assert.equal(headers["X-App"], "cli");
assert.equal(headers["Authorization"], "Bearer test-key");
});
test("a malicious profile-shaped header set has its auth/cookie entries dropped by applyCustomHeaders", () => {
const executor = new DefaultExecutor("openai-compatible-test");
// Simulate a compromised/hand-crafted profile that tries to smuggle in
// credential-owning header names alongside a legitimate identity header.
// isForbiddenCustomHeaderName is the single source of truth used by both
// the Zod schema and the executor, so assert against it directly too.
const maliciousProfileHeaders: Record<string, string> = {
"User-Agent": "totally-legit-cli/1.0",
Authorization: "Bearer stolen-token",
"x-api-key": "stolen-key",
cookie: "session=stolen",
};
assert.equal(isForbiddenCustomHeaderName("Authorization"), true);
assert.equal(isForbiddenCustomHeaderName("x-api-key"), true);
assert.equal(isForbiddenCustomHeaderName("cookie"), true);
const headers = executor.buildHeaders(
{
apiKey: "real-key",
providerSpecificData: {
baseUrl: "https://proxy.example.com/v1",
customHeaders: maliciousProfileHeaders,
},
},
true
) as Record<string, string>;
assert.equal(headers["User-Agent"], "totally-legit-cli/1.0");
assert.equal(headers["Authorization"], "Bearer real-key");
assert.notEqual(headers["Authorization"], "Bearer stolen-token");
assert.equal(headers["x-api-key"], undefined);
assert.equal(headers["cookie"], undefined);
});
test("DefaultExecutor.execute sends the selected profile's headers for a compatible-node connection", async () => {
const executor = new DefaultExecutor("openai-compatible-test");
const originalFetch = globalThis.fetch;
let capturedHeaders: Record<string, string> = {};
globalThis.fetch = async (_url: string | URL | Request, init: RequestInit = {}) => {
capturedHeaders = (init.headers as Record<string, string>) || {};
return new Response(JSON.stringify({ ok: true }), {
status: 200,
headers: { "Content-Type": "application/json" },
});
};
try {
await executor.execute({
model: "gpt-4.1",
body: { messages: [{ role: "user", content: "hi" }] },
stream: false,
credentials: {
apiKey: "real-key",
providerSpecificData: {
baseUrl: "https://test.proxy.com/v1",
customHeaders: getClientIdentityProfileHeaders("gemini-cli"),
},
},
});
assert.equal(capturedHeaders["User-Agent"], "GeminiCLI/0.1.0 (linux; x64)");
assert.equal(capturedHeaders["Authorization"], "Bearer real-key");
} finally {
globalThis.fetch = originalFetch;
}
});

View File

@@ -1,27 +0,0 @@
import test from "node:test";
import assert from "node:assert/strict";
const { unwrapClineNonStreamingEnvelope } = await import(
"../../open-sse/handlers/chatCore/clineResponseEnvelope.ts"
);
test("unwrapClineNonStreamingEnvelope extracts Cline wrapped chat completions", () => {
const wrapped = {
success: true,
data: {
id: "chatcmpl_cline",
model: "cline/model",
choices: [{ index: 0, message: { role: "assistant", content: "ok" } }],
usage: { prompt_tokens: 3, completion_tokens: 2, total_tokens: 5 },
},
};
assert.deepEqual(unwrapClineNonStreamingEnvelope("cline", wrapped), wrapped.data);
});
test("unwrapClineNonStreamingEnvelope keeps non-Cline and malformed envelopes untouched", () => {
const wrapped = { success: true, data: { message: "missing choices" } };
assert.equal(unwrapClineNonStreamingEnvelope("openai", wrapped), wrapped);
assert.equal(unwrapClineNonStreamingEnvelope("cline", wrapped), wrapped);
});

View File

@@ -1,117 +0,0 @@
import test from "node:test";
import assert from "node:assert/strict";
const { APIKEY_PROVIDERS } = await import("../../src/shared/constants/providers.ts");
const { REGISTRY: providerRegistry } = await import("../../open-sse/config/providerRegistry.ts");
const { unwrapClinepassEnvelope } = await import("../../open-sse/utils/clinepassEnvelope.ts");
const { filterClinepassModels } = await import("../../open-sse/services/clinepassModels.ts");
const { parseUpstreamError, buildErrorBody } = await import("../../open-sse/utils/error.ts");
// ── Provider metadata (Zod-validated APIKEY catalog) ─────────────────────────
test("ClinePass is registered as an API-key provider with the canonical identity", () => {
const cp = APIKEY_PROVIDERS.clinepass;
assert.ok(cp, "APIKEY_PROVIDERS.clinepass must be defined");
assert.equal(cp.id, "clinepass");
assert.equal(cp.alias, "clinepass");
assert.equal(cp.name, "ClinePass");
assert.equal(cp.website, "https://cline.bot");
assert.equal(
(cp as { notice?: { apiKeyUrl?: string } }).notice?.apiKeyUrl,
"https://app.cline.bot/settings/api-keys"
);
});
test("ClinePass registry entry uses OpenAI format with bearer apikey auth + Cline headers", () => {
const entry = providerRegistry.clinepass;
assert.ok(entry, "providerRegistry.clinepass must be defined");
assert.equal(entry.id, "clinepass");
assert.equal(entry.format, "openai");
assert.equal(entry.executor, "default");
assert.equal(entry.authType, "apikey");
assert.equal(entry.authHeader, "bearer");
assert.equal(entry.baseUrl, "https://api.cline.bot/api/v1/chat/completions");
assert.equal(entry.extraHeaders?.["HTTP-Referer"], "https://cline.bot");
assert.equal(entry.extraHeaders?.["X-Title"], "Cline");
});
test("ClinePass models are cline-pass/* and deepseek entries flag reasoning", () => {
const models = providerRegistry.clinepass.models;
const ids = models.map((m: { id: string }) => m.id);
assert.ok(ids.length >= 8, "expect a non-trivial seed list");
assert.equal(new Set(ids).size, ids.length, "model ids must be unique");
for (const id of ids) {
assert.ok(id.startsWith("cline-pass/"), `${id} must be in the cline-pass/ namespace`);
}
const deepseek = models.filter((m: { id: string }) => m.id.includes("deepseek"));
assert.ok(deepseek.length >= 2, "expect the two DeepSeek V4 entries");
for (const m of deepseek) {
assert.equal((m as { supportsReasoning?: boolean }).supportsReasoning, true);
}
});
// ── Envelope unwrap ──────────────────────────────────────────────────────────
test("unwrapClinepassEnvelope: success unwraps to data", () => {
const inner = { id: "chatcmpl-1", choices: [] };
const { body, error } = unwrapClinepassEnvelope({ success: true, data: inner }, "clinepass");
assert.equal(error, null);
assert.deepEqual(body, inner);
});
test("unwrapClinepassEnvelope: {success:false} yields an error", () => {
const { body, error } = unwrapClinepassEnvelope(
{ success: false, error: "empty response content", statusCode: 502 },
"clinepass"
);
assert.equal(body, null);
assert.ok(error);
assert.equal(error?.message, "empty response content");
assert.equal(error?.status, 502);
});
test("unwrapClinepassEnvelope: nested error.message extracted", () => {
const { error } = unwrapClinepassEnvelope(
{ success: false, error: { message: "quota exceeded" } },
"clinepass"
);
assert.equal(error?.message, "quota exceeded");
});
test("unwrapClinepassEnvelope: non-clinepass provider passes through untouched", () => {
const payload = { success: false, error: "boom" };
const { body, error } = unwrapClinepassEnvelope(payload, "openai");
assert.equal(error, null);
assert.deepEqual(body, payload);
});
test("unwrapClinepassEnvelope: non-object / array / no-success passthrough", () => {
assert.deepEqual(unwrapClinepassEnvelope("plain", "clinepass"), { body: "plain", error: null });
assert.deepEqual(unwrapClinepassEnvelope([1, 2], "clinepass"), { body: [1, 2], error: null });
const bare = { id: "x" };
assert.deepEqual(unwrapClinepassEnvelope(bare, "clinepass"), { body: bare, error: null });
});
// ── Model filter ─────────────────────────────────────────────────────────────
test("filterClinepassModels keeps only cline-pass/* ids", () => {
const out = filterClinepassModels([
{ id: "cline-pass/glm-5.2", name: "GLM" },
{ id: "openai/gpt-5.5" },
{ id: "cline-pass/deepseek-v4-pro" },
{ notId: true },
]);
assert.deepEqual(out, [
{ id: "cline-pass/glm-5.2", name: "GLM" },
{ id: "cline-pass/deepseek-v4-pro", name: "cline-pass/deepseek-v4-pro" },
]);
assert.deepEqual(filterClinepassModels("not-array"), []);
});
// ── Error sanitization (Rule #12 — no stack leak) ────────────────────────────
test("parseUpstreamError unwraps clinepass envelope error without leaking a stack", async () => {
const upstream = new Response(
JSON.stringify({ success: false, error: "upstream at /srv/x.js:1:1 failed" }),
{ status: 502, headers: { "content-type": "application/json" } }
);
const parsed = await parseUpstreamError(upstream, "clinepass");
const body = buildErrorBody(502, parsed.message) as { error: { message: string } };
assert.ok(!body.error.message.includes("at /"), "sanitized error must not include a stack frame");
});

View File

@@ -1,77 +0,0 @@
import test from "node:test";
import assert from "node:assert/strict";
import { DefaultExecutor } from "../../open-sse/executors/default.ts";
// DefaultExecutor.ensureThinkingBudget — clinepass-gated max_tokens floor for
// reasoning models (prevents empty content when the budget is undersized).
test("bumps undersized max_tokens to 4096 for a clinepass reasoning model", () => {
const executor = new DefaultExecutor("clinepass");
const body = {
model: "cline-pass/deepseek-v4-pro",
reasoning_effort: "high",
max_tokens: 512,
} as Record<string, unknown>;
executor.ensureThinkingBudget(body, "cline-pass/deepseek-v4-pro");
assert.equal(body.max_tokens, 4096);
});
test("sets max_tokens floor when absent for a reasoning model", () => {
const executor = new DefaultExecutor("clinepass");
const body = {
model: "cline-pass/deepseek-v4-flash",
reasoning_effort: "medium",
} as Record<string, unknown>;
executor.ensureThinkingBudget(body, "cline-pass/deepseek-v4-flash");
assert.equal(body.max_tokens, 4096);
});
test("leaves an already-sufficient budget untouched", () => {
const executor = new DefaultExecutor("clinepass");
const body = {
model: "cline-pass/deepseek-v4-pro",
reasoning_effort: "high",
max_tokens: 8000,
} as Record<string, unknown>;
executor.ensureThinkingBudget(body, "cline-pass/deepseek-v4-pro");
assert.equal(body.max_tokens, 8000);
});
test("no-op when reasoning is disabled", () => {
const executor = new DefaultExecutor("clinepass");
const body = {
model: "cline-pass/deepseek-v4-pro",
max_tokens: 100,
} as Record<string, unknown>;
executor.ensureThinkingBudget(body, "cline-pass/deepseek-v4-pro");
assert.equal(body.max_tokens, 100);
});
test("no-op for a non-reasoning clinepass model", () => {
const executor = new DefaultExecutor("clinepass");
const body = {
model: "cline-pass/glm-5.2",
reasoning_effort: "high",
max_tokens: 100,
} as Record<string, unknown>;
executor.ensureThinkingBudget(body, "cline-pass/glm-5.2");
assert.equal(body.max_tokens, 100);
});
test("no-op for a non-clinepass provider (gate)", () => {
const executor = new DefaultExecutor("openrouter");
const body = {
model: "cline-pass/deepseek-v4-pro",
reasoning_effort: "high",
max_tokens: 100,
} as Record<string, unknown>;
executor.ensureThinkingBudget(body, "cline-pass/deepseek-v4-pro");
assert.equal(body.max_tokens, 100);
});

View File

@@ -1,200 +0,0 @@
/**
* Regression test for Codex "banked reset credits" (issue #5199).
*
* DISPLAY ONLY: OmniRoute already calls the ChatGPT backend
* `/backend-api/wham/usage` endpoint for quota tracking. Some eligibility-gated
* accounts additionally expose `rate_limit_reset_credits.available_count` (a
* count of extra rate-limit resets banked on the account) and, optionally,
* `rate_limit_reached_type` (which window is currently blocking). This test
* verifies:
* 1. The field is parsed and surfaced additively when present, across both
* independent parsers that read this payload (codexUsageQuotas.ts used by
* the dashboard usage fetcher, and codexQuotaFetcher.ts used by the
* preflight/monitor fetcher).
* 2. Existing quota parsing is completely unaffected when the field is
* absent (fail-open — no throw, no regression to session/weekly/etc).
*
* Redemption of banked reset credits is an unofficial, mutating upstream
* endpoint and is explicitly OUT OF SCOPE — this only reads and surfaces data
* already present in the existing usage-fetch response.
*/
import test from "node:test";
import assert from "node:assert/strict";
import { buildCodexUsageQuotas } from "../../open-sse/services/codexUsageQuotas.ts";
import { getCodexUsage } from "../../open-sse/services/usage/codex.ts";
import {
fetchCodexQuota,
invalidateCodexQuotaCache,
registerCodexConnection,
unregisterCodexConnection,
} from "../../open-sse/services/codexQuotaFetcher.ts";
const originalFetch = globalThis.fetch;
test.afterEach(() => {
globalThis.fetch = originalFetch;
});
// ─── codexUsageQuotas.ts (dashboard usage-fetch path) ──────────────────────
test("buildCodexUsageQuotas surfaces bankedResetCredits when present", () => {
const { quotas, bankedResetCredits, rateLimitReachedType } = buildCodexUsageQuotas({
rate_limit: {
primary_window: { used_percent: 10 },
secondary_window: { used_percent: 20 },
},
rate_limit_reset_credits: { available_count: 3 },
rate_limit_reached_type: { type: "secondary_window" },
});
assert.equal(bankedResetCredits, 3);
assert.equal(rateLimitReachedType, "secondary_window");
// Existing quotas remain intact.
assert.equal(quotas.session?.used, 10);
assert.equal(quotas.weekly?.used, 20);
});
test("buildCodexUsageQuotas tolerates camelCase field shape", () => {
const { bankedResetCredits, rateLimitReachedType } = buildCodexUsageQuotas({
rateLimit: { primaryWindow: { usedPercent: 5 } },
rateLimitResetCredits: { availableCount: 7 },
rateLimitReachedType: "primary_window",
});
assert.equal(bankedResetCredits, 7);
assert.equal(rateLimitReachedType, "primary_window");
});
test("buildCodexUsageQuotas leaves bankedResetCredits undefined when absent (fail-open)", () => {
const result = buildCodexUsageQuotas({
rate_limit: {
primary_window: { used_percent: 10 },
secondary_window: { used_percent: 20 },
},
});
assert.equal(result.bankedResetCredits, undefined);
assert.equal(result.rateLimitReachedType, undefined);
// Existing quota parsing is unaffected — no throw, no missing windows.
assert.equal(result.quotas.session?.used, 10);
assert.equal(result.quotas.weekly?.used, 20);
});
test("buildCodexUsageQuotas never throws on a garbage rate_limit_reset_credits shape", () => {
assert.doesNotThrow(() => {
const result = buildCodexUsageQuotas({
rate_limit: { primary_window: { used_percent: 1 } },
rate_limit_reset_credits: "not-an-object",
rate_limit_reached_type: 12345,
});
assert.equal(result.bankedResetCredits, undefined);
assert.equal(result.rateLimitReachedType, undefined);
});
});
// ─── usage/codex.ts (getCodexUsage — full dashboard fetch) ─────────────────
test("getCodexUsage threads bankedResetCredits through additively", async () => {
globalThis.fetch = async () =>
new Response(
JSON.stringify({
plan_type: "plus",
rate_limit: {
primary_window: { used_percent: 15 },
secondary_window: { used_percent: 25 },
},
rate_limit_reset_credits: { available_count: 2 },
}),
{ status: 200, headers: { "content-type": "application/json" } }
);
const usage = await getCodexUsage("token", { workspaceId: "ws-1" });
assert.equal((usage as any).plan, "plus");
assert.equal((usage as any).bankedResetCredits, 2);
assert.equal((usage as any).quotas.session.used, 15);
assert.equal((usage as any).quotas.weekly.used, 25);
});
test("getCodexUsage omits bankedResetCredits and stays intact when absent", async () => {
globalThis.fetch = async () =>
new Response(
JSON.stringify({
plan_type: "plus",
rate_limit: {
primary_window: { used_percent: 15 },
secondary_window: { used_percent: 25 },
},
}),
{ status: 200, headers: { "content-type": "application/json" } }
);
const usage = await getCodexUsage("token", { workspaceId: "ws-1" });
assert.equal("bankedResetCredits" in (usage as any), false);
assert.equal((usage as any).quotas.session.used, 15);
assert.equal((usage as any).quotas.weekly.used, 25);
});
// ─── codexQuotaFetcher.ts (preflight/monitor path) ─────────────────────────
test("fetchCodexQuota surfaces bankedResetCredits from the dual-window parser", async () => {
const connectionId = `codex-banked-${Date.now()}`;
globalThis.fetch = async () =>
new Response(
JSON.stringify({
rate_limit: {
primary_window: { used_percent: 70, reset_after_seconds: 45 },
secondary_window: { used_percent: 20, reset_after_seconds: 300 },
},
rate_limit_reset_credits: { available_count: 4 },
rate_limit_reached_type: { type: "primary_window" },
}),
{ status: 200, headers: { "content-type": "application/json" } }
);
const quota = await fetchCodexQuota(connectionId, {
accessToken: "token",
providerSpecificData: { workspaceId: "ws" },
});
assert.ok(quota);
assert.equal(quota?.bankedResetCredits, 4);
assert.equal(quota?.rateLimitReachedType, "primary_window");
// Existing dual-window parsing stays intact.
assert.equal(quota?.window5h.percentUsed, 0.7);
assert.equal(quota?.window7d.percentUsed, 0.2);
invalidateCodexQuotaCache(connectionId);
unregisterCodexConnection(connectionId);
});
test("fetchCodexQuota omits bankedResetCredits when the payload does not have it (fail-open)", async () => {
const connectionId = `codex-nobanked-${Date.now()}`;
registerCodexConnection(connectionId, { accessToken: "token" });
globalThis.fetch = async () =>
new Response(
JSON.stringify({
rate_limit: {
primary_window: { used_percent: 30 },
secondary_window: { used_percent: 10 },
},
}),
{ status: 200, headers: { "content-type": "application/json" } }
);
const quota = await fetchCodexQuota(connectionId);
assert.ok(quota);
assert.equal(quota?.bankedResetCredits, undefined);
assert.equal(quota?.rateLimitReachedType, undefined);
assert.equal(quota?.window5h.percentUsed, 0.3);
assert.equal(quota?.window7d.percentUsed, 0.1);
invalidateCodexQuotaCache(connectionId);
unregisterCodexConnection(connectionId);
});

View File

@@ -1,36 +0,0 @@
import { test } from "node:test";
import assert from "node:assert/strict";
import { readFileSync } from "node:fs";
import { fileURLToPath } from "node:url";
import { dirname, join } from "node:path";
// Split-guard for the codex executor quota extraction.
// The pure quota-snapshot parsing + reset/cooldown scheduling lives in codex/quota.ts.
// Host re-exports the 4 public symbols (chatCore/codexQuota.ts + tests import them).
const HERE = dirname(fileURLToPath(import.meta.url));
const EXE = join(HERE, "../../open-sse/executors");
const HOST = join(EXE, "codex.ts");
const LEAF = join(EXE, "codex/quota.ts");
test("leaf hosts the quota helpers and does not import the host", () => {
const src = readFileSync(LEAF, "utf8");
for (const sym of [
"parseCodexQuotaHeaders",
"getCodexResetTime",
"getCodexDualWindowCooldownMs",
"CodexQuotaSnapshot",
]) {
assert.match(src, new RegExp(`export (function|interface) ${sym}\\b`));
}
assert.doesNotMatch(src, /from "\.\.\/codex\.ts"/);
});
test("host re-exports the quota symbols for external importers", () => {
const host = readFileSync(HOST, "utf8");
assert.match(host, /from "\.\/codex\/quota\.ts"/);
});
test("parseCodexQuotaHeaders returns null without quota headers", async () => {
const { parseCodexQuotaHeaders } = await import("../../open-sse/executors/codex/quota.ts");
assert.equal(parseCodexQuotaHeaders({}), null);
});

View File

@@ -1,143 +0,0 @@
// Route-wiring tests for /api/oauth/codex/import-token (#1290).
//
// Imports a Codex connection from a bare ChatGPT access token — no refresh
// token required. Auth is disabled via settings (requireLogin:false) so we
// reach the schema/decode logic rather than a 401. DB handles are released
// in test.after (CLAUDE.md learning: unreleased SQLite handles hang node:test).
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-codex-import-token-"));
process.env.DATA_DIR = TEST_DATA_DIR;
const core = await import("../../src/lib/db/core.ts");
const settingsDb = await import("../../src/lib/db/settings.ts");
const providersDb = await import("../../src/lib/db/providers.ts");
const route = await import("../../src/app/api/oauth/codex/import-token/route.ts");
function b64url(obj: unknown): string {
return Buffer.from(JSON.stringify(obj))
.toString("base64")
.replace(/=+$/, "")
.replace(/\+/g, "-")
.replace(/\//g, "_");
}
function makeJwt(payload: Record<string, unknown>): string {
const header = b64url({ alg: "RS256", typ: "JWT" });
const body = b64url(payload);
return `${header}.${body}.signature`;
}
test.before(async () => {
await settingsDb.updateSettings({ requireLogin: false });
});
test.after(async () => {
core.resetDbInstance();
fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true });
});
async function postImportToken(body: unknown) {
const request = new Request("http://localhost:20128/api/oauth/codex/import-token", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify(body),
});
const response = await route.POST(request);
return { status: response.status, body: await response.json() };
}
test("import-token: decodes email + workspace claims from the access token and creates a connection", async () => {
const accessToken = makeJwt({
email: "bare-token@example.com",
"https://api.openai.com/auth": {
chatgpt_account_id: "acct-bare",
chatgpt_plan_type: "plus",
},
});
const { status, body } = await postImportToken({ accessToken });
assert.equal(status, 200);
assert.equal(body.success, true);
assert.equal(body.connection.provider, "codex");
assert.equal(body.connection.email, "bare-token@example.com");
const rows = await providersDb.getProviderConnections({ provider: "codex" });
const created = rows.find((r) => r.id === body.connection.id);
assert.equal(created?.authType, "access_token");
assert.equal(created?.accessToken, accessToken);
assert.ok(!created?.refreshToken, "no refresh token should be persisted");
assert.deepEqual(created?.providerSpecificData, {
chatgptAccountId: "acct-bare",
chatgptPlanType: "plus",
});
});
test("import-token: falls back to the explicit `name` when the JWT carries no email", async () => {
const accessToken = makeJwt({
"https://api.openai.com/auth": { chatgpt_account_id: "acct-noemail" },
});
const { status, body } = await postImportToken({ accessToken, name: "My Bare Token" });
assert.equal(status, 200);
assert.equal(body.connection.name, "My Bare Token");
});
test("import-token: missing accessToken fails schema validation with 400", async () => {
const { status, body } = await postImportToken({});
assert.equal(status, 400);
assert.ok(typeof body.error.message === "string" && body.error.message.length > 0);
});
test("import-token: empty-string accessToken fails schema validation with 400", async () => {
const { status } = await postImportToken({ accessToken: " " });
assert.equal(status, 400);
});
test("import-token: undecodable token with no name and no claims is rejected with 400", async () => {
const { status, body } = await postImportToken({ accessToken: "not-a-jwt" });
assert.equal(status, 400);
assert.match(body.error.message, /decode|account info/i);
});
test("import-token: undecodable token IS accepted when an explicit name is supplied", async () => {
const { status, body } = await postImportToken({
accessToken: "not-a-jwt-but-thats-ok",
name: "Manually Labeled",
});
assert.equal(status, 200);
assert.equal(body.connection.name, "Manually Labeled");
});
test("import-token: malformed JSON body is rejected with 400", async () => {
const request = new Request("http://localhost:20128/api/oauth/codex/import-token", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: "{not json",
});
const response = await route.POST(request);
assert.equal(response.status, 400);
});
test("import-token: repeated imports for the same email never dedup (each is a new connection)", async () => {
const tokenA = makeJwt({ email: "repeat@example.com" });
const tokenB = makeJwt({ email: "repeat@example.com" });
const first = await postImportToken({ accessToken: tokenA });
const second = await postImportToken({ accessToken: tokenB });
assert.equal(first.status, 200);
assert.equal(second.status, 200);
assert.notEqual(first.body.connection.id, second.body.connection.id);
});
test("import-token: error responses never leak a stack trace", async () => {
const { body } = await postImportToken({});
assert.ok(!JSON.stringify(body).includes("at /"), "must not leak a stack trace");
assert.ok(!JSON.stringify(body).includes(".ts:"), "must not leak a source location");
});

View File

@@ -1,181 +0,0 @@
// #5903: Codex session affinity must win over a per-request reset-aware
// re-scoring. The reset-aware combo strategy (open-sse/services/combo/quotaStrategies.ts)
// recomputes its "winner" connection on every request and hands it to
// getProviderCredentials as forcedConnectionId (src/sse/handlers/chat.ts).
// Before the fix, forcedConnectionId narrowed the connection pool BEFORE
// session affinity was consulted, so a fresh quota-scoring winner silently
// evicted the existing pin (deleteSessionAccountAffinity) on every request —
// breaking "same session -> reuse pinned account".
//
// This test drives auth.getProviderCredentials directly (the same call shape
// chat.ts uses: sessionKey + forcedConnectionId together) to reproduce the
// bug without needing the full combo/quota-scoring machinery.
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-codex-affinity-5903-"));
process.env.DATA_DIR = TEST_DATA_DIR;
process.env.API_KEY_SECRET = process.env.API_KEY_SECRET || "codex-affinity-5903-test-secret";
const core = await import("../../src/lib/db/core.ts");
const providersDb = await import("../../src/lib/db/providers.ts");
const settingsDb = await import("../../src/lib/db/settings.ts");
const apiKeysDb = await import("../../src/lib/db/apiKeys.ts");
const affinityDb = await import("../../src/lib/db/sessionAccountAffinity.ts");
const auth = await import("../../src/sse/services/auth.ts");
async function resetStorage() {
core.resetDbInstance();
apiKeysDb.resetApiKeyState();
fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true });
fs.mkdirSync(TEST_DATA_DIR, { recursive: true });
}
async function seedConnection(provider: string, overrides: any = {}) {
return providersDb.createProviderConnection({
provider,
authType: overrides.authType || "oauth",
name: overrides.name || `${provider}-${Math.random().toString(16).slice(2, 8)}`,
accessToken: overrides.accessToken || `at-${Math.random().toString(16).slice(2, 10)}`,
refreshToken: overrides.refreshToken,
isActive: overrides.isActive ?? true,
testStatus: overrides.testStatus || "active",
priority: overrides.priority,
providerSpecificData: overrides.providerSpecificData || {},
});
}
test.beforeEach(async () => {
await resetStorage();
});
test.after(async () => {
core.resetDbInstance();
apiKeysDb.resetApiKeyState();
fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true });
});
test("codex session affinity wins over a per-request reset-aware forcedConnectionId (#5903)", async () => {
await settingsDb.updateSettings({
fallbackStrategy: "reset-aware",
codexSessionAffinityTtlMs: 60_000,
});
const connectionA = await seedConnection("codex", { name: "codex-reset-aware-a" });
const connectionB = await seedConnection("codex", { name: "codex-reset-aware-b" });
// Request 1: reset-aware quota scoring picks A as the winner for session S.
const request1 = await auth.getProviderCredentials("codex", null, null, "gpt-5.5", {
sessionKey: "session-S",
forcedConnectionId: connectionA.id,
});
assert.equal(request1?.connectionId, connectionA.id, "request 1 should pin to the scored winner A");
assert.equal(
affinityDb.getSessionAccountAffinity("session-S", "codex", 60_000)?.connectionId,
connectionA.id,
"affinity row must be created for session-S pointing at A"
);
// Request 2: quota state shifted and reset-aware now scores B higher for
// the SAME session. Without the fix, forcedConnectionId=B narrows the pool
// to just B before affinity is checked, evicting the A pin and re-pinning
// to B. With the fix, the existing active pin (A) must win.
const request2 = await auth.getProviderCredentials("codex", null, null, "gpt-5.5", {
sessionKey: "session-S",
forcedConnectionId: connectionB.id,
});
assert.equal(
request2?.connectionId,
connectionA.id,
"request 2 must still use the pinned connection A, not the freshly re-scored B"
);
assert.equal(
affinityDb.getSessionAccountAffinity("session-S", "codex", 60_000)?.connectionId,
connectionA.id,
"affinity row for session-S must remain pinned to A after re-scoring"
);
// A brand-new session (S2) has no existing pin, so the freshly re-scored
// winner (B) must be honored and a NEW pin created for S2.
const request3 = await auth.getProviderCredentials("codex", null, null, "gpt-5.5", {
sessionKey: "session-S2",
forcedConnectionId: connectionB.id,
});
assert.equal(request3?.connectionId, connectionB.id, "a new session must honor the fresh re-scored pick");
assert.equal(
affinityDb.getSessionAccountAffinity("session-S2", "codex", 60_000)?.connectionId,
connectionB.id,
"a new affinity row for session-S2 must be created pointing at B"
);
// Session S must remain unaffected by S2's independent pin.
assert.equal(
affinityDb.getSessionAccountAffinity("session-S", "codex", 60_000)?.connectionId,
connectionA.id,
"session-S pin must stay isolated from session-S2"
);
});
test("reset-aware forcedConnectionId is honored when the pinned connection becomes ineligible (#5903)", async () => {
await settingsDb.updateSettings({
fallbackStrategy: "reset-aware",
codexSessionAffinityTtlMs: 60_000,
});
const connectionA = await seedConnection("codex", { name: "codex-reset-aware-ineligible-a" });
const connectionB = await seedConnection("codex", { name: "codex-reset-aware-ineligible-b" });
const request1 = await auth.getProviderCredentials("codex", null, null, "gpt-5.5", {
sessionKey: "session-failover",
forcedConnectionId: connectionA.id,
});
assert.equal(request1?.connectionId, connectionA.id);
// A becomes rate-limited (e.g. 429 handled by markAccountUnavailable in
// production). Reset-aware re-scores and now forces B. The pin (A) is no
// longer eligible, so the freshly forced B must be used instead of
// failing the whole request.
await providersDb.updateProviderConnection(connectionA.id, {
rateLimitedUntil: new Date(Date.now() + 60_000).toISOString(),
});
const request2 = await auth.getProviderCredentials("codex", null, null, "gpt-5.5", {
sessionKey: "session-failover",
forcedConnectionId: connectionB.id,
});
assert.equal(
request2?.connectionId,
connectionB.id,
"an ineligible pin must fall through to the freshly forced connection"
);
});
test("no session affinity configured: reset-aware forcedConnectionId applies exactly as before (#5903)", async () => {
await settingsDb.updateSettings({
fallbackStrategy: "reset-aware",
codexSessionAffinityTtlMs: 0,
});
const connectionA = await seedConnection("codex", { name: "codex-no-affinity-a" });
const connectionB = await seedConnection("codex", { name: "codex-no-affinity-b" });
const request1 = await auth.getProviderCredentials("codex", null, null, "gpt-5.5", {
sessionKey: "session-no-ttl",
forcedConnectionId: connectionA.id,
});
assert.equal(request1?.connectionId, connectionA.id);
const request2 = await auth.getProviderCredentials("codex", null, null, "gpt-5.5", {
sessionKey: "session-no-ttl",
forcedConnectionId: connectionB.id,
});
assert.equal(
request2?.connectionId,
connectionB.id,
"with affinity disabled (ttl=0) each request must honor the fresh forcedConnectionId"
);
});

View File

@@ -1,29 +0,0 @@
import { test } from "node:test";
import assert from "node:assert/strict";
import { readFileSync } from "node:fs";
import { fileURLToPath } from "node:url";
import { dirname, join } from "node:path";
// Split-guard for the codex executor tool-normalization extraction.
// The hosted-tool passthrough + free-plan gating live in codex/tools.ts (self-contained,
// console.debug only). codex.ts re-exports them so external importers keep the path.
const HERE = dirname(fileURLToPath(import.meta.url));
const EXE = join(HERE, "../../open-sse/executors");
test("leaf hosts the tool normalizers and does not import the host", () => {
const src = readFileSync(join(EXE, "codex/tools.ts"), "utf8");
assert.match(src, /export function normalizeCodexTools\b/);
assert.match(src, /export function isCodexFreePlan\b/);
assert.doesNotMatch(src, /from "\.\.\/codex\.ts"/);
});
test("codex.ts re-exports them for external importers", () => {
const host = readFileSync(join(EXE, "codex.ts"), "utf8");
assert.match(host, /export \{[^}]*normalizeCodexTools[^}]*\} from "\.\/codex\/tools\.ts"/s);
});
test("both import paths resolve to the same function", async () => {
const viaHost = (await import("../../open-sse/executors/codex.ts")).normalizeCodexTools;
const viaLeaf = (await import("../../open-sse/executors/codex/tools.ts")).normalizeCodexTools;
assert.equal(viaHost, viaLeaf);
});

View File

@@ -37,19 +37,10 @@ test("invalid verbosity is dropped and text removed", () => {
assert.equal(body.verbosity, undefined);
});
test("no verbosity + Responses text.format is preserved", () => {
const format = { type: "json_schema", name: "schema", schema: { type: "object" } };
const body: Record<string, unknown> = { text: { format }, input: [] };
test("no verbosity + stray non-verbosity text → text removed (status quo)", () => {
const body: Record<string, unknown> = { text: { format: { type: "json" } }, input: [] };
normalizeCodexVerbosity(body);
assert.deepEqual(body.text, { format });
});
test("verbosity is merged with existing Responses text.format", () => {
const format = { type: "json_schema", name: "schema", schema: { type: "object" } };
const body: Record<string, unknown> = { verbosity: "low", text: { format }, input: [] };
normalizeCodexVerbosity(body);
assert.deepEqual(body.text, { format, verbosity: "low" });
assert.equal(body.verbosity, undefined);
assert.equal(body.text, undefined);
});
test("verbosity is normalized case-insensitively", () => {

View File

@@ -1,72 +0,0 @@
import { test, after } from "node:test";
import assert from "node:assert/strict";
import { applyStrategyOrdering } from "@omniroute/open-sse/services/combo/applyStrategyOrdering.ts";
import { resetDbInstance } from "@/lib/db/core.ts";
// Split guard for Block J Task 3: the non-`auto` strategy-ordering chain
// (lkgp / strict-random / random / fill-first / p2c / ... / quota-share) was
// extracted verbatim into applyStrategyOrdering. These tests pin the exits that
// need no DB/deck state (random / fill-first / unknown); the DB-backed branches
// (lkgp, reset-*, quota-share) are covered end-to-end by the 47 consumer tests
// (router-strategies / combo-strategy-fallbacks / rr-session-stickiness).
after(() => {
// some branches (lkgp/quota-share) may touch the DB singleton; release handles.
resetDbInstance();
});
const noopLog = { info() {}, warn() {}, error() {}, debug() {} } as never;
const target = (provider: string, modelStr: string): never =>
({
kind: "model",
stepId: "s1",
executionKey: `${provider}>${modelStr}`,
modelStr,
provider,
providerId: null,
connectionId: null,
weight: 1,
label: null,
}) as never;
const deps = () =>
({
combo: { id: "c1", name: "c1", config: {} },
config: {},
body: { messages: [] },
log: noopLog,
apiKeyAllowedConnections: null,
}) as never;
const keys = (arr: Array<{ executionKey: string }>) => arr.map((t) => t.executionKey).sort();
test("exports applyStrategyOrdering", () => {
assert.equal(typeof applyStrategyOrdering, "function");
});
test("unknown strategy -> input order unchanged (same reference contents)", async () => {
const input = [target("openai", "gpt-4o"), target("anthropic", "claude-3")];
const out = await applyStrategyOrdering("no-such-strategy", input, deps());
assert.deepEqual(
out.map((t: { executionKey: string }) => t.executionKey),
["openai>gpt-4o", "anthropic>claude-3"]
);
});
test("fill-first -> preserves priority order", async () => {
const input = [target("a", "m1"), target("b", "m2"), target("c", "m3")];
const out = await applyStrategyOrdering("fill-first", input, deps());
assert.deepEqual(
out.map((t: { executionKey: string }) => t.executionKey),
["a>m1", "b>m2", "c>m3"]
);
});
test("random -> same multiset of targets (a permutation)", async () => {
const input = [target("a", "m1"), target("b", "m2"), target("c", "m3")];
const out = await applyStrategyOrdering("random", input, deps());
assert.equal(out.length, 3);
assert.deepEqual(keys(out), keys(input));
});

View File

@@ -1,79 +0,0 @@
import { test } from "node:test";
import assert from "node:assert/strict";
import { parseAutoConfig } from "@omniroute/open-sse/services/combo/autoConfig.ts";
import { DEFAULT_WEIGHTS } from "@omniroute/open-sse/services/autoCombo/scoring.ts";
// Split guard for Block J Task 2: parseAutoConfig was extracted verbatim from
// handleComboChat's inline auto-strategy config block. These assertions pin the
// pure derivation so the extraction stays behavior-identical.
const target = (provider: string, modelStr: string) =>
({ provider, modelStr, executionKey: `${provider}>${modelStr}` }) as never;
test("defaults: rules strategy, provider-derived pool, default weights", () => {
const cfg = parseAutoConfig({ name: "c", config: {} } as never, [
target("openai", "gpt-4o"),
target("anthropic", "claude-3"),
target("openai", "gpt-4o-mini"),
]);
assert.equal(cfg.routingStrategy, "rules");
assert.deepEqual(cfg.candidatePool, ["openai", "anthropic"]);
assert.equal(cfg.weights, DEFAULT_WEIGHTS);
assert.equal(cfg.explorationRate, 0.05);
assert.equal(cfg.budgetCap, undefined);
assert.equal(cfg.modePack, undefined);
});
test("routerStrategy takes precedence over routingStrategy/strategyName", () => {
const cfg = parseAutoConfig(
{
name: "c",
autoConfig: {
routerStrategy: "lkgp",
routingStrategy: "cost",
strategyName: "p2c",
},
} as never,
[]
);
assert.equal(cfg.routingStrategy, "lkgp");
});
test("explicit candidatePool, weights, exploration and budget are honored", () => {
const customWeights = { latency: 1 } as never;
const cfg = parseAutoConfig(
{
name: "c",
autoConfig: {
candidatePool: ["glm", "openai"],
weights: customWeights,
explorationRate: 0.3,
budgetCap: 5,
modePack: "coding",
},
} as never,
[target("ignored", "x")]
);
assert.deepEqual(cfg.candidatePool, ["glm", "openai"]);
assert.equal(cfg.weights, customWeights);
assert.equal(cfg.explorationRate, 0.3);
assert.equal(cfg.budgetCap, 5);
assert.equal(cfg.modePack, "coding");
});
test("config.auto is preferred over top-level config", () => {
const cfg = parseAutoConfig(
{ name: "c", config: { auto: { routerStrategy: "cost" }, routerStrategy: "rules" } } as never,
[]
);
assert.equal(cfg.routingStrategy, "cost");
});
test("non-finite explorationRate falls back to 0.05", () => {
const cfg = parseAutoConfig(
{ name: "c", autoConfig: { explorationRate: "not-a-number" } } as never,
[]
);
assert.equal(cfg.explorationRate, 0.05);
});

View File

@@ -1,183 +0,0 @@
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";
/**
* #5923 (Finding #4) — the quota-exhaustion preflight cutoff only ran for
* strategy === "auto" (buildAutoCandidates / routableCandidates in combo.ts).
* Priority/weighted/etc. strategies funneled through the shared executeTarget
* per-target loop, which only checked the provider circuit breaker + model
* lockout — never a per-(provider, connection) quota-exhaustion cutoff. A 0%-
* remaining connection stayed eligible as the lead leg until it reactively
* 429'd.
*
* Regression guard: with the quota-exhaustion opt-in enabled
* (`resilienceSettings.quotaPreflight.enabled = true`), a "priority" combo
* whose first-listed connection is at 0% remaining must skip straight to the
* sibling connection of the SAME provider — never dispatching to the
* exhausted connection. This must stay strictly per-connection: it must NOT
* touch the provider circuit breaker (both connections belong to the same
* provider, and the healthy one must remain fully eligible).
*/
const TEST_DATA_DIR = fs.mkdtempSync(
path.join(os.tmpdir(), "omniroute-quota-cutoff-priority-5923-")
);
process.env.DATA_DIR = TEST_DATA_DIR;
const dbCore = await import("../../src/lib/db/core.ts");
const { handleComboChat } = await import("../../open-sse/services/combo.ts");
const { registerQuotaFetcher } = await import("../../open-sse/services/quotaPreflight.ts");
const { getCircuitBreaker } = await import("../../src/shared/utils/circuitBreaker.ts");
test.after(() => {
dbCore.resetDbInstance();
fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true });
});
function makeLog() {
return {
info() {},
warn() {},
debug() {},
error() {},
};
}
function okResponse(model: string) {
return Response.json({ choices: [{ message: { role: "assistant", content: model } }] });
}
const PROVIDER = "openai";
const EXHAUSTED_CONNECTION_ID = "conn-exhausted-5923";
const HEALTHY_CONNECTION_ID = "conn-healthy-5923";
test("#5923 priority combo skips a 0%-remaining lead connection but keeps the sibling connection eligible", async () => {
registerQuotaFetcher(PROVIDER, async (connectionId: string) => {
if (connectionId === EXHAUSTED_CONNECTION_ID) {
return { used: 100, total: 100, percentUsed: 1 };
}
return { used: 5, total: 100, percentUsed: 0.05 };
});
const combo = {
name: `priority-quota-cutoff-5923-${Date.now()}`,
strategy: "priority",
models: [
{
kind: "model",
provider: PROVIDER,
providerId: PROVIDER,
model: "gpt-4o-mini",
connectionId: EXHAUSTED_CONNECTION_ID,
id: "step-a",
},
{
kind: "model",
provider: PROVIDER,
providerId: PROVIDER,
model: "gpt-4o-mini",
connectionId: HEALTHY_CONNECTION_ID,
id: "step-b",
},
],
};
const calls: Array<string | null> = [];
const response = await handleComboChat({
body: { model: combo.name, messages: [{ role: "user", content: "hi" }] },
combo,
allCombos: [combo],
isModelAvailable: undefined,
relayOptions: undefined,
signal: undefined,
settings: {
resilienceSettings: {
quotaPreflight: {
enabled: true,
defaultThresholdPercent: 2,
warnThresholdPercent: 20,
},
},
},
log: makeLog(),
handleSingleModel: async (
_body: unknown,
modelStr: string,
target?: { connectionId?: string | null }
) => {
calls.push(target?.connectionId ?? null);
return okResponse(modelStr);
},
} as Parameters<typeof handleComboChat>[0]);
assert.equal(response.status, 200);
assert.ok(calls.length > 0, "expected at least one dispatched target");
assert.equal(
calls[0],
HEALTHY_CONNECTION_ID,
"the 0%-remaining lead connection must be skipped; the sibling connection must be dispatched instead"
);
assert.ok(
!calls.includes(EXHAUSTED_CONNECTION_ID),
"the exhausted connection must never be dispatched to"
);
// Strictly per-connection — the provider circuit breaker must stay CLOSED.
// Only one connection was skipped; the provider itself never failed.
assert.equal(
getCircuitBreaker(PROVIDER).getStatus().state,
"CLOSED",
"quota-exhaustion cutoff must never trip the whole-provider circuit breaker"
);
});
test("#5923 priority combo does NOT skip a 0%-remaining connection when the cutoff setting is disabled (default)", async () => {
const provider = "openai";
const exhaustedConnectionId = "conn-exhausted-disabled-5923";
registerQuotaFetcher(provider, async () => ({ used: 100, total: 100, percentUsed: 1 }));
const combo = {
name: `priority-quota-cutoff-disabled-5923-${Date.now()}`,
strategy: "priority",
models: [
{
kind: "model",
provider,
providerId: provider,
model: "gpt-4o-mini",
connectionId: exhaustedConnectionId,
id: "step-a",
},
],
};
const calls: Array<string | null> = [];
const response = await handleComboChat({
body: { model: combo.name, messages: [{ role: "user", content: "hi" }] },
combo,
allCombos: [combo],
isModelAvailable: undefined,
relayOptions: undefined,
signal: undefined,
// No resilienceSettings override → quotaPreflight.enabled defaults to false (opt-in).
settings: {},
log: makeLog(),
handleSingleModel: async (
_body: unknown,
modelStr: string,
target?: { connectionId?: string | null }
) => {
calls.push(target?.connectionId ?? null);
return okResponse(modelStr);
},
} as Parameters<typeof handleComboChat>[0]);
assert.equal(response.status, 200);
assert.deepEqual(
calls,
[exhaustedConnectionId],
"with the cutoff setting OFF (default), the exhausted connection must still be dispatched to (unchanged auto-off behavior)"
);
});

View File

@@ -1,88 +0,0 @@
import { test, after } from "node:test";
import assert from "node:assert/strict";
import { resolveAutoStrategyOrder } from "@omniroute/open-sse/services/combo/resolveAutoStrategy.ts";
import { resetDbInstance } from "@/lib/db/core.ts";
// resolveAutoStrategyOrder loads the LKGP via the DB singleton (dynamic import);
// release the handle so the node:test runner does not hang on teardown (learning #3).
after(() => {
resetDbInstance();
});
// Split guard for Block J Task 2 (coupled slice): the `if (strategy === "auto")`
// branch of handleComboChat was extracted verbatim into resolveAutoStrategyOrder,
// with `buildAutoCandidates` injected (it lives in combo.ts, so a direct import
// would cycle). These tests pin the DI contract and the two control-flow exits
// that the host now forwards: an early 429 Response, and the default-ordering
// pass-through. The routable-selection path is covered end-to-end by the 60
// consumer tests (router-strategies / auto-combo-engine / combo-strategy-fallbacks).
const noopLog = {
info() {},
warn() {},
error() {},
debug() {},
} as never;
const target = (provider: string, modelStr: string): never =>
({
kind: "model",
stepId: "s1",
executionKey: `${provider}>${modelStr}`,
modelStr,
provider,
providerId: null,
connectionId: null,
weight: 1,
label: null,
}) as never;
const baseDeps = (buildAutoCandidates: never) =>
({
orderedTargets: [target("openai", "gpt-4o"), target("anthropic", "claude-3")],
body: { messages: [{ role: "user", content: "hi" }] },
combo: { id: "c1", name: "autoc", config: {} },
settings: null,
config: {},
relayOptions: null,
resilienceSettings: { quotaPreflight: { enabled: false } },
log: noopLog,
buildAutoCandidates,
}) as never;
test("exports resolveAutoStrategyOrder", () => {
assert.equal(typeof resolveAutoStrategyOrder, "function");
});
test("no candidates -> keeps default ordering, no explicit router", async () => {
const build = (async () => []) as never;
const result = await resolveAutoStrategyOrder(baseDeps(build));
assert.ok(!("earlyResponse" in result));
if ("orderedTargets" in result) {
assert.equal(result.autoUsedExplicitRouter, false);
// default ordering preserved (both original targets survive)
assert.equal(result.orderedTargets.length, 2);
assert.equal(result.orderedTargets[0].provider, "openai");
}
});
test("all candidates quota-cutoff-blocked -> early 429 Response", async () => {
const build = (async () => [
{
kind: "model",
stepId: "s1",
executionKey: "openai>gpt-4o",
modelStr: "gpt-4o",
provider: "openai",
model: "gpt-4o",
quotaCutoffBlocked: true,
},
]) as never;
const result = await resolveAutoStrategyOrder(baseDeps(build));
assert.ok("earlyResponse" in result);
if ("earlyResponse" in result) {
assert.ok(result.earlyResponse instanceof Response);
assert.equal(result.earlyResponse.status, 429);
}
});

View File

@@ -14,22 +14,16 @@ import path from "node:path";
import { fileURLToPath } from "node:url";
const __dirname = path.dirname(fileURLToPath(import.meta.url));
// The LKGP fallback (and every non-auto strategy ordering) was extracted verbatim
// from combo.ts into the applyStrategyOrdering leaf (Block J Task 3); the guard
// scans follow the code to the leaf that now owns the `target.modelStr` usages.
const STRATEGY_SRC = path.resolve(
__dirname,
"../../open-sse/services/combo/applyStrategyOrdering.ts"
);
const COMBO_SRC = path.resolve(__dirname, "../../open-sse/services/combo.ts");
const TEST_ROUTE_SRC = path.resolve(__dirname, "../../src/app/api/combos/test/route.ts");
test("#2359 LKGP findIndex guards modelStr against non-string", () => {
const src = fs.readFileSync(STRATEGY_SRC, "utf8");
test("#2359 combo.ts LKGP findIndex guards modelStr against non-string", () => {
const src = fs.readFileSync(COMBO_SRC, "utf8");
// The findIndex on orderedTargets must check `typeof target.modelStr === "string"`
// before calling .startsWith. Anchor on the LKGP fallback branch.
assert.ok(
/typeof target\.modelStr === "string"[\s\S]{0,80}target\.modelStr\.startsWith/.test(src),
"LKGP fallback must type-check target.modelStr before calling .startsWith"
"LKGP fallback in combo.ts must type-check target.modelStr before calling .startsWith"
);
});
@@ -47,8 +41,8 @@ test("#2359 combo test route falls back instead of throwing on missing modelStr"
);
});
test("#2359 strategy ordering has no remaining unguarded target.modelStr.<method> usages", () => {
const src = fs.readFileSync(STRATEGY_SRC, "utf8");
test("#2359 combo.ts has no remaining unguarded target.modelStr.<method> usages", () => {
const src = fs.readFileSync(COMBO_SRC, "utf8");
// Strip the line that contains the guard so the regex below only catches
// direct, unguarded method calls.
const stripped = src.replace(/typeof target\.modelStr === "string"[^\n]*\n[^\n]*/g, "");

View File

@@ -1,78 +0,0 @@
import { test } from "node:test";
import assert from "node:assert/strict";
import { buildTargetTimeoutRunner } from "../../open-sse/services/combo/targetTimeoutRunner.ts";
const noopLog = { warn() {}, info() {}, error() {}, debug() {} } as any;
test("timeout<=0: passthrough direto (sem timer)", async () => {
let called = false;
const runner = buildTargetTimeoutRunner({
handleSingleModel: async () => {
called = true;
return new Response("ok");
},
comboTargetTimeoutMs: 0,
log: noopLog,
});
const res = await runner({}, "m");
assert.equal(called, true);
assert.equal(await res.text(), "ok");
});
test("timeout<=0: erro do upstream vira errorResponse 502", async () => {
const runner = buildTargetTimeoutRunner({
handleSingleModel: async () => {
throw new Error("boom");
},
comboTargetTimeoutMs: 0,
log: noopLog,
});
const res = await runner({}, "m");
assert.equal(res.status, 502);
});
test("excede o limite: aborta e retorna 524 timed out", async () => {
const runner = buildTargetTimeoutRunner({
handleSingleModel: (_b, _m, target) =>
new Promise<Response>((resolve) => {
// resolve só se abortado (simula um upstream que respeita o signal)
const sig = (target as any)?.modelAbortSignal as AbortSignal | undefined;
sig?.addEventListener("abort", () => resolve(new Response(null, { status: 599 })));
}),
comboTargetTimeoutMs: 20,
log: noopLog,
});
const res = await runner({}, "slow-model");
assert.equal(res.status, 524);
const body = await res.json();
assert.match(JSON.stringify(body), /timed out/i);
});
test("sucesso rápido vence a corrida do timeout", async () => {
const runner = buildTargetTimeoutRunner({
handleSingleModel: async () => new Response("fast", { status: 200 }),
comboTargetTimeoutMs: 1000,
log: noopLog,
});
const res = await runner({}, "m");
assert.equal(res.status, 200);
assert.equal(await res.text(), "fast");
});
test("hedge do parent já abortado propaga o abort ao filho", async () => {
const parent = new AbortController();
parent.abort(new Error("hedge-cancelled"));
let sawAbort = false;
const runner = buildTargetTimeoutRunner({
handleSingleModel: (_b, _m, target) =>
new Promise<Response>((resolve) => {
const sig = (target as any)?.modelAbortSignal as AbortSignal | undefined;
if (sig?.aborted) sawAbort = true;
resolve(new Response("ok"));
}),
comboTargetTimeoutMs: 1000,
log: noopLog,
});
await runner({}, "m", { modelAbortSignal: parent.signal } as any);
assert.equal(sawAbort, true);
});

View File

@@ -166,200 +166,3 @@ test("a 200/benign status with no exhaustion mutates nothing and returns false",
0
);
});
test("does NOT mark provider exhausted for per-model-quota providers (different model)", () => {
const s = sets();
const exhausted = applyComboTargetExhaustion(target({ provider: "gemini" }), {
...baseOpts,
result: { status: 429 },
fallbackResult: { reason: "quota_exhausted" },
errorText: "quota exceeded for model gpt-4",
sets: s,
});
assert.equal(exhausted, false);
assert.equal(s.exhaustedProviders.has("gemini"), false);
assert.ok(s.transientRateLimitedProviders.has("gemini"));
});
test("does NOT mark provider exhausted for empty provider strings", () => {
const s = sets();
const exhausted = applyComboTargetExhaustion(target({ provider: "" }), {
...baseOpts,
result: { status: 503 },
fallbackResult: { error: { code: "quota_exhausted" } },
errorText: "quota exhausted",
allAccountsRateLimited: true,
sets: s,
});
assert.equal(exhausted, false);
});
test("does NOT mark transientRateLimited on 429 when isTokenLimitBreach is true", () => {
const s = sets();
const exhausted = applyComboTargetExhaustion(target(), {
...baseOpts,
result: { status: 429 },
fallbackResult: {},
errorText: "Token limit exceeded",
isTokenLimitBreach: true,
sets: s,
});
assert.equal(exhausted, false);
assert.equal(s.transientRateLimitedProviders.has("test-dedup-provider"), false);
assert.equal(s.exhaustedProviders.has("test-dedup-provider"), false);
});
test("does NOT mark anything for circuit-open (X-OmniRoute-Provider-Breaker header)", () => {
const s = sets();
const exhausted = applyComboTargetExhaustion(target(), {
...baseOpts,
result: { status: 503, headers: new Map([["x-omniroute-provider-breaker", "open"]]) },
fallbackResult: {},
errorText: "",
sets: s,
});
assert.equal(exhausted, false);
assert.equal(s.exhaustedProviders.has("test-dedup-provider"), false);
assert.equal(s.exhaustedConnections.has("test-dedup-provider:conn-1"), false);
assert.equal(s.transientRateLimitedProviders.has("test-dedup-provider"), false);
});
test("does NOT mark exhaustion for non-connection-level status codes (400)", () => {
const s = sets();
const exhausted = applyComboTargetExhaustion(target(), {
...baseOpts,
result: { status: 400 },
fallbackResult: {},
errorText: "Bad Request",
sets: s,
});
assert.equal(exhausted, false);
assert.equal(s.exhaustedConnections.size, 0);
assert.equal(s.exhaustedProviders.size, 0);
assert.equal(s.transientRateLimitedProviders.size, 0);
});
test("does NOT mark connection exhausted for per-model-quota provider on 500 (gemini model-level error)", () => {
const s = sets();
const exhausted = applyComboTargetExhaustion(
target({ provider: "gemini", connectionId: "gemini-conn-1" }),
{
...baseOpts,
result: { status: 500 },
fallbackResult: {},
errorText: "Internal error encountered.",
rawModel: "gemma-4-31b-it",
sets: s,
}
);
assert.equal(exhausted, false);
assert.equal(s.exhaustedProviders.has("gemini"), false);
assert.equal(s.exhaustedConnections.has("gemini:gemini-conn-1"), false);
assert.equal(s.transientRateLimitedProviders.has("gemini"), false);
});
// Sanitized Gemini 500 response — model-level "Internal error encountered" should NOT exhaust
// the connection, allowing sibling models on the same provider to be tried.
test("gemini 500 INTERNAL (sanitized real response) does NOT exhaust connection — sibling retry", () => {
const s = sets();
const exhausted = applyComboTargetExhaustion(
target({ provider: "gemini", connectionId: "gemini-key-abc" }),
{
...baseOpts,
result: { status: 500 },
fallbackResult: {},
errorText: "Internal error encountered.",
rawModel: "gemma-4-31b-it",
structuredError: { code: 500, status: "INTERNAL", message: "Internal error encountered." },
sets: s,
}
);
assert.equal(exhausted, false, "providerExhausted must be false");
assert.equal(s.exhaustedProviders.has("gemini"), false, "must not exhaust provider");
assert.equal(
s.exhaustedConnections.has("gemini:gemini-key-abc"),
false,
"must not exhaust connection — sibling model may succeed"
);
assert.equal(s.transientRateLimitedProviders.has("gemini"), false);
});
// Non-500 connection-level errors MUST exhaust the connection even for per-model-quota providers.
// A 503 (Service Unavailable) means the upstream is down — retrying sibling models wastes calls.
test("gemini 503 DOES exhaust connection (upstream down, not model-level)", () => {
const s = sets();
const exhausted = applyComboTargetExhaustion(
target({ provider: "gemini", connectionId: "gemini-key-abc" }),
{
...baseOpts,
result: { status: 503 },
fallbackResult: {},
errorText: "The service is currently unavailable.",
rawModel: "gemma-4-31b-it",
sets: s,
}
);
assert.equal(exhausted, false, "providerExhausted is false (not quota)");
assert.equal(
s.exhaustedConnections.has("gemini:gemini-key-abc"),
true,
"503 must exhaust connection — upstream is down"
);
assert.equal(s.exhaustedProviders.size, 0);
});
test("gemini 502 DOES exhaust connection (bad gateway)", () => {
const s = sets();
const exhausted = applyComboTargetExhaustion(
target({ provider: "gemini", connectionId: "gemini-key-abc" }),
{
...baseOpts,
result: { status: 502 },
fallbackResult: {},
errorText: "Bad Gateway",
rawModel: "gemma-4-31b-it",
sets: s,
}
);
assert.equal(exhausted, false);
assert.equal(s.exhaustedConnections.has("gemini:gemini-key-abc"), true);
});
test("gemini 504 DOES exhaust connection (gateway timeout)", () => {
const s = sets();
applyComboTargetExhaustion(target({ provider: "gemini", connectionId: "gemini-key-abc" }), {
...baseOpts,
result: { status: 504 },
fallbackResult: {},
errorText: "Gateway Timeout",
rawModel: "gemini-2.0-flash",
sets: s,
});
assert.equal(s.exhaustedConnections.has("gemini:gemini-key-abc"), true);
});
test("gemini 408 DOES exhaust connection (request timeout)", () => {
const s = sets();
applyComboTargetExhaustion(target({ provider: "gemini", connectionId: "gemini-key-abc" }), {
...baseOpts,
result: { status: 408 },
fallbackResult: {},
errorText: "Request Timeout",
rawModel: "gemini-2.0-flash",
sets: s,
});
assert.equal(s.exhaustedConnections.has("gemini:gemini-key-abc"), true);
});
test("gemini 524 DOES exhaust connection (cloudflare timeout)", () => {
const s = sets();
applyComboTargetExhaustion(target({ provider: "gemini", connectionId: "gemini-key-abc" }), {
...baseOpts,
result: { status: 524 },
fallbackResult: {},
errorText: "A Timeout Occurred",
rawModel: "gemini-2.0-flash",
sets: s,
});
assert.equal(s.exhaustedConnections.has("gemini:gemini-key-abc"), true);
});

View File

@@ -3,7 +3,6 @@ import assert from "node:assert/strict";
import { NextResponse } from "next/server";
import {
applyCorsHeaders,
getCorsStatus,
resolveAllowedOrigin,
setRuntimeAllowedOrigins,
STATIC_CORS_HEADERS,
@@ -189,48 +188,6 @@ describe("cors/origins.applyCorsHeaders", () => {
});
});
describe("cors/origins.getCorsStatus", () => {
let envSnap: Record<string, string | undefined>;
beforeEach(() => {
envSnap = snapshotEnv();
for (const key of ENV_KEYS) delete process.env[key];
setRuntimeAllowedOrigins("");
});
afterEach(() => {
restoreEnv(envSnap);
setRuntimeAllowedOrigins("");
});
it("default (no env, no runtime) → allowAll false, empty origins", () => {
assert.deepEqual(getCorsStatus(), { allowAll: false, allowedOrigins: [] });
});
it("CORS_ALLOW_ALL=true → allowAll true", () => {
process.env.CORS_ALLOW_ALL = "true";
assert.equal(getCorsStatus().allowAll, true);
});
it("legacy CORS_ORIGIN=* → allowAll true", () => {
process.env.CORS_ORIGIN = "*";
assert.equal(getCorsStatus().allowAll, true);
});
it("merges env + runtime allowlists, normalized, sorted, deduped", () => {
process.env.CORS_ALLOWED_ORIGINS = "https://Env.Example.com/, https://shared.example.com";
setRuntimeAllowedOrigins("https://runtime.example.com, https://shared.example.com/");
assert.deepEqual(getCorsStatus(), {
allowAll: false,
allowedOrigins: [
"https://env.example.com",
"https://runtime.example.com",
"https://shared.example.com",
],
});
});
});
describe("cors/origins.STATIC_CORS_HEADERS", () => {
it("never contains Access-Control-Allow-Origin", () => {
assert.equal(

View File

@@ -1,49 +0,0 @@
import { test } from "node:test";
import assert from "node:assert/strict";
import { readFileSync } from "node:fs";
import { fileURLToPath } from "node:url";
import { dirname, join } from "node:path";
// Split-guard for the cursor executor pure-helper extraction.
// Two pure leaves: cursor/prompt.ts (isRecordLike + toolChoiceDirectiveLine +
// buildCursorOutputConstraints) and cursor/composer.ts (composer thinking decoding).
// The host re-exports the 3 composer helpers for external importers (tests).
const HERE = dirname(fileURLToPath(import.meta.url));
const EXE = join(HERE, "../../open-sse/executors");
const HOST = join(EXE, "cursor.ts");
const PROMPT = join(EXE, "cursor/prompt.ts");
const COMPOSER = join(EXE, "cursor/composer.ts");
test("leaves are pure and do not import the host", () => {
const prompt = readFileSync(PROMPT, "utf8");
const composer = readFileSync(COMPOSER, "utf8");
assert.match(prompt, /export function toolChoiceDirectiveLine\b/);
assert.match(prompt, /export function buildCursorOutputConstraints\b/);
assert.match(composer, /export function isComposerModel\b/);
assert.doesNotMatch(prompt, /from "\.\.\/cursor\.ts"/);
assert.doesNotMatch(composer, /from "\.\.\/cursor\.ts"/);
});
test("host re-exports the composer helpers", () => {
const host = readFileSync(HOST, "utf8");
assert.match(host, /from "\.\/cursor\/composer\.ts"/);
assert.match(host, /from "\.\/cursor\/prompt\.ts"/);
});
test("composer thinking decoding behaves via the leaf", async () => {
const { visibleComposerContentFromThinking, composerReasoningRemainder, isComposerModel } =
await import("../../open-sse/executors/cursor/composer.ts");
assert.equal(isComposerModel("composer-1"), true);
assert.equal(isComposerModel("gpt-4"), false);
assert.equal(visibleComposerContentFromThinking("hidden</think>visible"), "visible");
assert.equal(composerReasoningRemainder("hidden</think>visible"), "hidden");
});
test("prompt constraint builder behaves via the leaf", async () => {
const { toolChoiceDirectiveLine, buildCursorOutputConstraints } =
await import("../../open-sse/executors/cursor/prompt.ts");
assert.match(toolChoiceDirectiveLine("required"), /MUST call at least one/);
assert.equal(toolChoiceDirectiveLine("auto"), "");
assert.match(buildCursorOutputConstraints({ max_tokens: 100 }), /100 output tokens/);
assert.equal(buildCursorOutputConstraints({}), "");
});

View File

@@ -1,17 +0,0 @@
/**
* MuxServiceTab unit test — verifies module shape only (no DOM renderer wired
* into the node:test runner for this suite; mirrors CliproxyServiceTab.tsx's
* module-shape test).
*/
import { describe, it } from "node:test";
import assert from "node:assert/strict";
describe("MuxServiceTab — module shape", () => {
it("exports MuxServiceTab function", async () => {
const mod = await import(
"../../../../../src/app/(dashboard)/dashboard/providers/services/tabs/MuxServiceTab.tsx"
);
assert.equal(typeof mod.MuxServiceTab, "function");
});
});

View File

@@ -1,119 +0,0 @@
// #1290 — bare-access-token Codex import. createProviderConnection must
// never dedup authType "access_token" rows (each import is intentionally a
// new connection — a raw access token has no stable long-lived identity to
// safely match against), and must derive a connection name from email when
// no explicit name is supplied, mirroring the existing "oauth" behavior.
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-access-token-1290-"));
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");
async function resetStorage() {
core.resetDbInstance();
for (let attempt = 0; attempt < 10; attempt++) {
try {
if (fs.existsSync(TEST_DATA_DIR)) {
fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true });
}
break;
} catch (error: unknown) {
const code = (error as { code?: string } | null)?.code;
if ((code === "EBUSY" || code === "EPERM") && attempt < 9) {
await new Promise((resolve) => setTimeout(resolve, 50 * (attempt + 1)));
} else {
throw error;
}
}
}
fs.mkdirSync(TEST_DATA_DIR, { recursive: true });
}
test.beforeEach(async () => {
await resetStorage();
});
test.after(async () => {
core.resetDbInstance();
fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true });
});
test("createProviderConnection: authType access_token never dedups — same email creates a new row each time", async () => {
const first = await providersDb.createProviderConnection({
provider: "codex",
authType: "access_token",
accessToken: "eyJfirst.token.sig",
email: "user@example.com",
testStatus: "active",
});
const second = await providersDb.createProviderConnection({
provider: "codex",
authType: "access_token",
accessToken: "eyJsecond.token.sig",
email: "user@example.com",
testStatus: "active",
});
assert.notEqual(first.id, second.id);
const rows = await providersDb.getProviderConnections({ provider: "codex" });
assert.equal(rows.length, 2);
assert.deepEqual(
rows.map((r) => r.accessToken).sort(),
["eyJfirst.token.sig", "eyJsecond.token.sig"].sort()
);
});
test("createProviderConnection: authType access_token falls back to email for the connection name", async () => {
const conn = await providersDb.createProviderConnection({
provider: "codex",
authType: "access_token",
accessToken: "eyJtoken.sig",
email: "labeled@example.com",
});
assert.equal(conn.name, "labeled@example.com");
});
test("createProviderConnection: authType access_token prefers an explicit name over email", async () => {
const conn = await providersDb.createProviderConnection({
provider: "codex",
authType: "access_token",
accessToken: "eyJtoken.sig",
email: "labeled@example.com",
name: "My Bare Token",
});
assert.equal(conn.name, "My Bare Token");
});
test("createProviderConnection: authType access_token does not collide with an existing oauth row for the same email", async () => {
const oauthConn = await providersDb.createProviderConnection({
provider: "codex",
authType: "oauth",
accessToken: "oauth-access",
refreshToken: "oauth-refresh",
email: "shared@example.com",
});
const tokenConn = await providersDb.createProviderConnection({
provider: "codex",
authType: "access_token",
accessToken: "eyJbare.token.sig",
email: "shared@example.com",
});
assert.notEqual(oauthConn.id, tokenConn.id);
// The oauth row must be untouched (not silently overwritten by the
// access_token import).
const refreshed = await providersDb.getProviderConnections({ provider: "codex" });
const oauthRow = refreshed.find((r) => r.id === oauthConn.id);
assert.equal(oauthRow?.authType, "oauth");
assert.equal(oauthRow?.refreshToken, "oauth-refresh");
});

View File

@@ -1,143 +0,0 @@
import { describe, test, before, after } from "node:test";
import assert from "node:assert/strict";
import { mkdtempSync, rmSync } from "node:fs";
import { tmpdir } from "node:os";
import { join } from "node:path";
// Isolate the DB into a throwaway DATA_DIR so migrations run against a fresh file.
let tmpDataDir: string;
let mod: typeof import("@/lib/db/discoveryResults");
let core: typeof import("@/lib/db/core");
before(async () => {
tmpDataDir = mkdtempSync(join(tmpdir(), "omniroute-discovery-"));
process.env.DATA_DIR = tmpDataDir;
core = await import("@/lib/db/core");
core.resetDbInstance();
// Touch the instance so migrations (incl. 074_discovery_results) apply.
core.getDbInstance();
mod = await import("@/lib/db/discoveryResults");
});
after(() => {
core.resetDbInstance();
if (tmpDataDir) rmSync(tmpDataDir, { recursive: true, force: true });
});
describe("discoveryResults DB module", () => {
test("upsert inserts a new row and returns it with an id", () => {
const row = mod.upsertDiscoveryResult({
providerId: "acme",
method: "free_tier",
authType: "none",
feasibility: 4,
riskLevel: "low",
status: "pending",
models: ["acme-large", "acme-small"],
endpoint: "https://acme.example/api",
});
assert.ok(typeof row.id === "number" && row.id > 0);
assert.equal(row.providerId, "acme");
assert.deepEqual(row.models, ["acme-large", "acme-small"]);
assert.equal(row.status, "pending");
});
test("upsert on the same (provider, method, endpoint) updates instead of duplicating", () => {
const first = mod.upsertDiscoveryResult({
providerId: "beta",
method: "web_cookie",
authType: "cookie",
feasibility: 3,
riskLevel: "medium",
status: "pending",
endpoint: "https://beta.example/chat",
});
const second = mod.upsertDiscoveryResult({
providerId: "beta",
method: "web_cookie",
authType: "cookie",
feasibility: 5,
riskLevel: "medium",
status: "testing",
endpoint: "https://beta.example/chat",
});
assert.equal(second.id, first.id);
assert.equal(second.feasibility, 5);
assert.equal(second.status, "testing");
const all = mod.getDiscoveryResults("beta");
assert.equal(all.length, 1);
});
test("getDiscoveryResults filters by providerId and returns all when omitted", () => {
const beta = mod.getDiscoveryResults("beta");
assert.ok(beta.every((r) => r.providerId === "beta"));
const all = mod.getDiscoveryResults();
assert.ok(all.length >= 2);
});
test("getDiscoveryResultById returns the row or null", () => {
const created = mod.upsertDiscoveryResult({
providerId: "gamma",
method: "trial",
authType: "api_key",
feasibility: 2,
riskLevel: "low",
status: "pending",
});
const found = mod.getDiscoveryResultById(created.id!);
assert.equal(found?.providerId, "gamma");
assert.equal(mod.getDiscoveryResultById(999999), null);
});
test("markVerified sets status=verified and stamps verified_at", () => {
const created = mod.upsertDiscoveryResult({
providerId: "delta",
method: "public_api",
authType: "api_key",
feasibility: 5,
riskLevel: "none",
status: "pending",
});
const updated = mod.markVerified(created.id!);
assert.equal(updated?.status, "verified");
assert.ok(updated?.verifiedAt);
});
test("markVerified on a missing id returns null", () => {
assert.equal(mod.markVerified(999999), null);
});
test("deleteDiscoveryResult removes the row and returns true, false if absent", () => {
const created = mod.upsertDiscoveryResult({
providerId: "epsilon",
method: "free_tier",
authType: "none",
feasibility: 1,
riskLevel: "none",
status: "pending",
});
assert.equal(mod.deleteDiscoveryResult(created.id!), true);
assert.equal(mod.getDiscoveryResultById(created.id!), null);
assert.equal(mod.deleteDiscoveryResult(created.id!), false);
});
});
describe("discovery service reporter delegation", () => {
test("persistDiscoveryResult writes through and getDiscoveryResults reads it back", async () => {
const svc = await import("@/lib/discovery/index");
const saved = svc.persistDiscoveryResult({
providerId: "zeta",
method: "public_api",
authType: "api_key",
feasibility: 5,
riskLevel: "none",
status: "verified",
models: ["zeta-1"],
});
assert.ok(saved.id! > 0);
const read = svc.getDiscoveryResults("zeta");
assert.equal(read.length, 1);
assert.equal(read[0].providerId, "zeta");
assert.deepEqual(read[0].models, ["zeta-1"]);
});
});

View File

@@ -1,135 +0,0 @@
import { describe, it, afterEach } from "node:test";
import assert from "node:assert/strict";
import {
DeepSeekWebWithAutoRefreshExecutor,
} from "../../open-sse/executors/deepseek-web-with-auto-refresh.ts";
import { DeepSeekWebExecutor } from "../../open-sse/executors/deepseek-web.ts";
// Regression: the base DeepSeekWebExecutor.execute() never throws — it converts
// upstream auth failures (401/403) into a returned error Response. The auto-refresh
// subclass used to trigger refresh+retry only from its catch block (thrown errors),
// so the retry path was dead code: a stale access token surfaced a 401 to the client
// on every refresh boundary instead of self-healing. See executor-deepseek-web-auto-refresh.
const baseProto = DeepSeekWebExecutor.prototype;
const originalExecute = baseProto.execute;
function makeInput(overrides: Record<string, unknown> = {}) {
return {
model: "deepseek-web",
body: { messages: [{ role: "user", content: "hi" }] },
stream: false,
credentials: { apiKey: "user-token-abc" },
signal: null,
log: null,
...overrides,
} as any;
}
afterEach(() => {
baseProto.execute = originalExecute;
});
describe("DeepSeekWebWithAutoRefreshExecutor — 401 Response retry (regression)", () => {
it("refreshes and retries when the base returns a 401 error Response", async () => {
const executor = new DeepSeekWebWithAutoRefreshExecutor({ autoRefresh: false });
let baseCalls = 0;
baseProto.execute = async function () {
baseCalls++;
if (baseCalls === 1) {
return {
response: new Response(
JSON.stringify({ error: { message: "DeepSeek token expired" } }),
{ status: 401, headers: { "Content-Type": "application/json" } }
),
url: "https://chat.deepseek.com/api/v0/chat/completion",
headers: {},
transformedBody: {},
};
}
return {
response: new Response(
JSON.stringify({ choices: [{ message: { role: "assistant", content: "ok" } }] }),
{ status: 200, headers: { "Content-Type": "application/json" } }
),
url: "https://chat.deepseek.com/api/v0/chat/completion",
headers: {},
transformedBody: {},
};
};
let refreshCalls = 0;
(executor as any).doRefreshSession = async () => {
refreshCalls++;
};
const result = await executor.execute(makeInput());
assert.equal(refreshCalls, 1, "auto-refresh should fire exactly once on a 401 Response");
assert.equal(baseCalls, 2, "base execute should run twice (initial 401 → refreshed retry)");
assert.equal(result.response.status, 200, "the retried request's success should reach the client");
});
it("does not refresh/retry on a successful 200 Response", async () => {
const executor = new DeepSeekWebWithAutoRefreshExecutor({ autoRefresh: false });
let baseCalls = 0;
baseProto.execute = async function () {
baseCalls++;
return {
response: new Response(JSON.stringify({ choices: [] }), {
status: 200,
headers: { "Content-Type": "application/json" },
}),
url: "https://chat.deepseek.com/api/v0/chat/completion",
headers: {},
transformedBody: {},
};
};
let refreshCalls = 0;
(executor as any).doRefreshSession = async () => {
refreshCalls++;
};
const result = await executor.execute(makeInput());
assert.equal(baseCalls, 1, "base execute should run once on success");
assert.equal(refreshCalls, 0, "no refresh on a 200 Response");
assert.equal(result.response.status, 200);
});
it("stops retrying (no loop) when refresh cannot recover a dead userToken", async () => {
const executor = new DeepSeekWebWithAutoRefreshExecutor({ autoRefresh: false });
let baseCalls = 0;
baseProto.execute = async function () {
baseCalls++;
return {
response: new Response(JSON.stringify({ error: { message: "expired" } }), {
status: 401,
headers: { "Content-Type": "application/json" },
}),
url: "https://chat.deepseek.com/api/v0/chat/completion",
headers: {},
transformedBody: {},
};
};
let refreshCalls = 0;
(executor as any).doRefreshSession = async () => {
refreshCalls++;
throw new Error("Token expired — get a new userToken from DeepSeek localStorage");
};
const result = await executor.execute(makeInput());
// Refresh is attempted once; when it throws (dead userToken), we surface the
// original 401 instead of looping forever.
assert.equal(refreshCalls, 1, "refresh attempted once");
assert.equal(baseCalls, 1, "no retry when refresh itself fails");
assert.equal(result.response.status, 401, "original auth failure surfaces to the client");
});
});

View File

@@ -1,34 +0,0 @@
import { test } from "node:test";
import assert from "node:assert/strict";
import { readFileSync } from "node:fs";
import { fileURLToPath } from "node:url";
import { dirname, join } from "node:path";
// Split-guard for the deepseek-web executor stream-format extraction.
// The pure content/citation formatters live in deepseek-web/stream-format.ts
// (module-private; host imports them into transformSSE/collectSSEContent).
const HERE = dirname(fileURLToPath(import.meta.url));
const EXE = join(HERE, "../../open-sse/executors");
const HOST = join(EXE, "deepseek-web.ts");
const LEAF = join(EXE, "deepseek-web/stream-format.ts");
test("leaf hosts the formatters and does not import the host", () => {
const src = readFileSync(LEAF, "utf8");
for (const sym of ["formatStreamContent", "appendSearchCitations", "isThinkingModel"]) {
assert.match(src, new RegExp(`export function ${sym}\\b`));
}
assert.doesNotMatch(src, /from "\.\.\/deepseek-web\.ts"/);
});
test("host imports the formatters back from the leaf", () => {
const host = readFileSync(HOST, "utf8");
assert.match(host, /from "\.\/deepseek-web\/stream-format\.ts"/);
});
test("formatStreamContent + model classifiers behave", async () => {
const { isThinkingModel, isSearchModel, formatStreamContent } =
await import("../../open-sse/executors/deepseek-web/stream-format.ts");
assert.equal(typeof isThinkingModel("deepseek-reasoner"), "boolean");
assert.equal(typeof isSearchModel("deepseek-search"), "boolean");
assert.equal(typeof formatStreamContent("hi", "deepseek-chat"), "string");
});

View File

@@ -311,19 +311,8 @@ test("execute: sends PoW response header", async () => {
"Has Bearer token"
);
assert.ok(compCall.headers["X-Ds-Pow-Response"], "Has PoW header");
// Header set matches the current chat.deepseek.com web client (v2.0.0):
// legacy X-App-Version dropped, X-Client-Bundle-Id added, version bumped.
assert.ok(
!("X-App-Version" in compCall.headers),
"Legacy X-App-Version must not be sent (removed in web client 2.0.0)"
);
assert.equal(
compCall.headers["X-Client-Bundle-Id"],
"com.deepseek.chat",
"Sends X-Client-Bundle-Id"
);
assert.equal(compCall.headers["X-Client-Version"], "2.0.0", "Sends current X-Client-Version");
assert.equal(compCall.headers["X-Client-Platform"], "web", "Has X-Client-Platform");
assert.ok(compCall.headers["X-App-Version"], "Has X-App-Version");
assert.ok(compCall.headers["X-Client-Platform"] === "web", "Has X-Client-Platform");
} finally {
mock.restore();
}

View File

@@ -1,36 +0,0 @@
import { test } from "node:test";
import assert from "node:assert/strict";
import { readFileSync } from "node:fs";
import { fileURLToPath } from "node:url";
import { dirname, join } from "node:path";
// Split-guard for the default executor URL-normalizer extraction.
// The pure per-provider chat-URL normalizers live in default/urlNormalizers.ts
// (string transforms only). Host imports them back into buildUrl/transformRequest.
const HERE = dirname(fileURLToPath(import.meta.url));
const EXE = join(HERE, "../../open-sse/executors");
const HOST = join(EXE, "default.ts");
const LEAF = join(EXE, "default/urlNormalizers.ts");
test("leaf hosts the normalizers and does not import the host", () => {
const src = readFileSync(LEAF, "utf8");
for (const sym of [
"normalizeOpenAIChatUrl",
"normalizeSapChatUrl",
"getOpenRouterConnectionPreset",
]) {
assert.match(src, new RegExp(`export function ${sym}\\b`));
}
assert.doesNotMatch(src, /from "\.\.\/default\.ts"/);
});
test("host imports the normalizers back from the leaf", () => {
const host = readFileSync(HOST, "utf8");
assert.match(host, /from "\.\/default\/urlNormalizers\.ts"/);
});
test("normalizeOpenAIChatUrl appends chat/completions for a bare base URL", async () => {
const { normalizeOpenAIChatUrl } =
await import("../../open-sse/executors/default/urlNormalizers.ts");
assert.match(normalizeOpenAIChatUrl("https://api.example.com"), /\/v1\/chat\/completions$/);
});

View File

@@ -1,195 +0,0 @@
import test from "node:test";
import assert from "node:assert/strict";
const {
trackDevice,
getDeviceCount,
getDeviceDetails,
getAllDeviceCounts,
expireDevices,
extractIpFromHeaders,
maskIp,
clearDeviceTracker,
} = await import("../../open-sse/services/deviceTracker.ts");
test.beforeEach(() => {
delete process.env.DEVICE_TRACKER_TTL_MS;
delete process.env.DEVICE_TRACKER_MAX_DEVICES_PER_KEY;
delete process.env.DEVICE_TRACKER_MAX_TOTAL_DEVICES;
clearDeviceTracker();
});
// ─── Fingerprint dedup ──────────────────────────────────────────────────────
test("trackDevice: same IP + UA for a key counts as one device", async () => {
await trackDevice("key-1", "203.0.113.5", "Mozilla/5.0 test-agent");
await trackDevice("key-1", "203.0.113.5", "Mozilla/5.0 test-agent");
await trackDevice("key-1", "203.0.113.5", "Mozilla/5.0 test-agent");
assert.equal(getDeviceCount("key-1"), 1);
});
test("trackDevice: different User-Agent for same key/IP counts as a new device", async () => {
await trackDevice("key-1", "203.0.113.5", "curl/8.0");
await trackDevice("key-1", "203.0.113.5", "python-requests/2.31");
assert.equal(getDeviceCount("key-1"), 2);
});
test("trackDevice: different IP for same key/UA counts as a new device", async () => {
await trackDevice("key-1", "203.0.113.5", "curl/8.0");
await trackDevice("key-1", "198.51.100.9", "curl/8.0");
assert.equal(getDeviceCount("key-1"), 2);
});
test("trackDevice: repeated tracking refreshes lastSeen instead of duplicating", async () => {
await trackDevice("key-1", "203.0.113.5", "curl/8.0");
const [before] = getDeviceDetails("key-1");
await new Promise((resolve) => setTimeout(resolve, 5));
await trackDevice("key-1", "203.0.113.5", "curl/8.0");
const [after] = getDeviceDetails("key-1");
assert.equal(getDeviceCount("key-1"), 1);
assert.ok(after.lastSeen >= before.lastSeen);
});
test("trackDevice: no-ops and returns null when apiKeyId is missing", async () => {
const fingerprint = await trackDevice(null, "203.0.113.5", "curl/8.0");
assert.equal(fingerprint, null);
assert.equal(getDeviceCount(null), 0);
});
// ─── Per-key isolation ──────────────────────────────────────────────────────
test("trackDevice: devices are scoped per API key, not global", async () => {
await trackDevice("key-1", "203.0.113.5", "curl/8.0");
await trackDevice("key-2", "203.0.113.5", "curl/8.0"); // same fingerprint, different key
assert.equal(getDeviceCount("key-1"), 1);
assert.equal(getDeviceCount("key-2"), 1);
const allCounts = getAllDeviceCounts();
assert.equal(allCounts["key-1"], 1);
assert.equal(allCounts["key-2"], 1);
});
// ─── TTL expiry ─────────────────────────────────────────────────────────────
test("expireDevices: evicts devices whose lastSeen exceeds the TTL window", async () => {
process.env.DEVICE_TRACKER_TTL_MS = "1000";
clearDeviceTracker();
await trackDevice("key-1", "203.0.113.5", "curl/8.0");
assert.equal(getDeviceCount("key-1"), 1);
const farFuture = Date.now() + 5000;
const expiredCount = expireDevices(farFuture);
assert.equal(expiredCount, 1);
assert.equal(getDeviceCount("key-1"), 0);
});
test("expireDevices: keeps devices seen within the TTL window", async () => {
process.env.DEVICE_TRACKER_TTL_MS = "60000";
clearDeviceTracker();
await trackDevice("key-1", "203.0.113.5", "curl/8.0");
const soon = Date.now() + 1000;
const expiredCount = expireDevices(soon);
assert.equal(expiredCount, 0);
assert.equal(getDeviceCount("key-1"), 1);
});
// ─── Eviction under caps ────────────────────────────────────────────────────
test("trackDevice: enforces maxDevicesPerApiKey by evicting the oldest device", async () => {
process.env.DEVICE_TRACKER_MAX_DEVICES_PER_KEY = "2";
clearDeviceTracker();
await trackDevice("key-1", "203.0.113.1", "ua-1");
await new Promise((resolve) => setTimeout(resolve, 2));
await trackDevice("key-1", "203.0.113.2", "ua-2");
await new Promise((resolve) => setTimeout(resolve, 2));
// Third distinct device should evict the oldest (203.0.113.1 / ua-1).
await trackDevice("key-1", "203.0.113.3", "ua-3");
assert.equal(getDeviceCount("key-1"), 2);
const uaSet = new Set(getDeviceDetails("key-1").map((d) => d.userAgent));
assert.ok(!uaSet.has("ua-1"), "oldest device should have been evicted");
assert.ok(uaSet.has("ua-2"));
assert.ok(uaSet.has("ua-3"));
});
test("trackDevice: enforces maxTotalDevices globally across all keys", async () => {
process.env.DEVICE_TRACKER_MAX_TOTAL_DEVICES = "2";
clearDeviceTracker();
await trackDevice("key-1", "203.0.113.1", "ua-1");
await new Promise((resolve) => setTimeout(resolve, 2));
await trackDevice("key-2", "203.0.113.2", "ua-2");
await new Promise((resolve) => setTimeout(resolve, 2));
await trackDevice("key-3", "203.0.113.3", "ua-3");
const total = Object.values(getAllDeviceCounts()).reduce((a, b) => a + b, 0);
assert.equal(total, 2);
// key-1's device was the oldest globally and should be gone.
assert.equal(getDeviceCount("key-1"), 0);
});
// ─── IP masking ─────────────────────────────────────────────────────────────
test("maskIp: masks the last two octets of an IPv4 address", () => {
assert.equal(maskIp("203.0.113.42"), "203.0.x.x");
});
test("maskIp: masks an IPv6 address down to its first three groups", () => {
assert.equal(maskIp("2001:db8:85a3:0:0:8a2e:370:7334"), "2001:db8:85a3:...");
});
test("maskIp: returns 'unknown' for missing/unknown input", () => {
assert.equal(maskIp(null), "unknown");
assert.equal(maskIp(undefined), "unknown");
assert.equal(maskIp("unknown"), "unknown");
});
test("trackDevice: never stores the raw IP — only the masked form", async () => {
await trackDevice("key-1", "203.0.113.42", "curl/8.0");
const [detail] = getDeviceDetails("key-1");
assert.equal(detail.ip, "203.0.x.x");
assert.notEqual(detail.ip, "203.0.113.42");
});
test("getDeviceDetails: truncates the fingerprint instead of exposing the full SHA-256 hash", async () => {
await trackDevice("key-1", "203.0.113.42", "curl/8.0");
const [detail] = getDeviceDetails("key-1");
assert.equal(detail.fingerprint.length, 12);
});
// ─── IP extraction from headers ─────────────────────────────────────────────
test("extractIpFromHeaders: prefers cf-connecting-ip over x-forwarded-for", () => {
const ip = extractIpFromHeaders({
"cf-connecting-ip": "203.0.113.5",
"x-forwarded-for": "198.51.100.9, 10.0.0.1",
});
assert.equal(ip, "203.0.113.5");
});
test("extractIpFromHeaders: falls back to the first hop of x-forwarded-for", () => {
const ip = extractIpFromHeaders({ "x-forwarded-for": "198.51.100.9, 10.0.0.1" });
assert.equal(ip, "198.51.100.9");
});
test("extractIpFromHeaders: works with a real Headers instance", () => {
const headers = new Headers({ "x-real-ip": "192.0.2.7" });
assert.equal(extractIpFromHeaders(headers), "192.0.2.7");
});
test("extractIpFromHeaders: returns 'unknown' when no IP header is present", () => {
assert.equal(extractIpFromHeaders({}), "unknown");
assert.equal(extractIpFromHeaders(null), "unknown");
});

View File

@@ -1,35 +0,0 @@
import { test } from "node:test";
import assert from "node:assert/strict";
import { readFileSync } from "node:fs";
import { fileURLToPath } from "node:url";
import { dirname, join } from "node:path";
// Split-guard for the duckduckgo-web challenge-solver extraction.
// The anti-abuse challenge solver + FE signals live in duckduckgo-web/challenge.ts
// (pure of module state; the vm sandbox + 5s timeout are preserved). Host imports back.
const HERE = dirname(fileURLToPath(import.meta.url));
const EXE = join(HERE, "../../open-sse/executors");
const HOST = join(EXE, "duckduckgo-web.ts");
const LEAF = join(EXE, "duckduckgo-web/challenge.ts");
test("leaf hosts the solver and does not import the host", () => {
const src = readFileSync(LEAF, "utf8");
assert.match(src, /export async function solveDuckDuckGoChallenge\b/);
assert.match(src, /export function makeDuckDuckGoFeSignals\b/);
assert.doesNotMatch(src, /from "\.\.\/duckduckgo-web\.ts"/);
// The vm sandbox timeout must survive the move (security invariant).
assert.match(src, /timeout/);
});
test("host imports the solver back from the leaf", () => {
const host = readFileSync(HOST, "utf8");
assert.match(host, /from "\.\/duckduckgo-web\/challenge\.ts"/);
});
test("makeDuckDuckGoFeSignals returns a base64 string", async () => {
const { makeDuckDuckGoFeSignals } =
await import("../../open-sse/executors/duckduckgo-web/challenge.ts");
const out = makeDuckDuckGoFeSignals();
assert.equal(typeof out, "string");
assert.ok(out.length > 0);
});

View File

@@ -1,110 +0,0 @@
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";
import http from "node:http";
// 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-proxy-"));
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 settingsDb = await import("../../src/lib/db/settings.ts");
const { createEmbeddingResponse } = await import("../../src/lib/embeddings/service.ts");
const { resolveProxyForRequest } = await import("../../open-sse/utils/proxyFetch.ts");
test.after(() => {
core.resetDbInstance();
fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true });
});
async function withHttpServer(handler: http.RequestListener, fn: (baseUrl: string) => Promise<void>) {
const server = http.createServer(handler);
await new Promise<void>((resolve, reject) => {
server.once("error", reject);
server.listen(0, "127.0.0.1", () => resolve());
});
const address = server.address();
assert.ok(address && typeof address === "object");
try {
await fn(`http://127.0.0.1:${(address as { port: number }).port}`);
} finally {
await new Promise<void>((resolve, reject) => {
server.close((err) => (err ? reject(err) : resolve()));
});
}
}
test("embeddings forward the connection-level (key) pinned proxy to the upstream fetch", async () => {
// T14 Proxy Fast-Fail performs a real TCP reachability check before running
// the request inside the proxy context, so the "proxy" must be a real,
// reachable local listener (its actual response body is irrelevant here —
// the assertion is about which proxy context the upstream fetch observes).
await withHttpServer(
(_req, res) => {
res.writeHead(200);
res.end("ok");
},
async (proxyBaseUrl) => {
const proxyUrl = new URL(proxyBaseUrl);
const connection = await providersDb.createProviderConnection({
provider: "mistral",
authType: "apikey",
name: "Test Mistral Proxy",
apiKey: "mistral-test-key",
});
// Pin a proxy at the connection ("key") level — the most specific level,
// exactly like a user would configure per-connection in the dashboard.
await settingsDb.setProxyForLevel("key", (connection as any).id, {
type: "http",
host: proxyUrl.hostname,
port: Number(proxyUrl.port),
});
let capturedProxySource: string | null = null;
let capturedProxyUrl: string | null = null;
const originalFetch = globalThis.fetch;
globalThis.fetch = async (input: RequestInfo | URL) => {
const targetUrl = typeof input === "string" ? input : (input as URL).toString();
const resolved = resolveProxyForRequest(targetUrl);
capturedProxySource = resolved.source;
capturedProxyUrl = resolved.proxyUrl;
return new Response(
JSON.stringify({
data: [{ object: "embedding", embedding: [0.1, 0.2], index: 0 }],
usage: { prompt_tokens: 3, total_tokens: 3 },
}),
{ 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 request should succeed");
} finally {
globalThis.fetch = originalFetch;
}
// The upstream fetch must have run inside the AsyncLocalStorage proxy
// context carrying the connection's pinned proxy — not "direct" (no
// context) and not the env-var proxy fallback.
assert.equal(
capturedProxySource,
"context",
`expected the embeddings upstream fetch to run inside a proxy context, got source="${capturedProxySource}"`
);
assert.ok(
capturedProxyUrl && capturedProxyUrl.includes(`${proxyUrl.hostname}:${proxyUrl.port}`),
`expected the connection's pinned proxy to be forwarded, got "${capturedProxyUrl}"`
);
}
);
});

View File

@@ -80,10 +80,6 @@ test("resolveEndpointCategory: maps /v1/moderations to 'moderations'", () => {
assert.equal(resolveEndpointCategory("/v1/moderations"), "moderations");
});
test("resolveEndpointCategory: maps /v1/ocr to 'ocr'", () => {
assert.equal(resolveEndpointCategory("/v1/ocr"), "ocr");
});
test("resolveEndpointCategory: maps /v1/batches to 'batches'", () => {
assert.equal(resolveEndpointCategory("/v1/batches"), "batches");
});

View File

@@ -587,7 +587,7 @@ test("DefaultExecutor.buildHeaders rotates extra API keys and builds Claude Code
assert.equal(ccHeaders["x-api-key"], undefined);
assert.equal(ccHeaders["anthropic-version"], CLAUDE_CODE_COMPATIBLE_ANTHROPIC_VERSION);
assert.equal(ccHeaders["X-Claude-Code-Session-Id"], "session-1");
assert.equal(ccHeaders.Accept, "text/event-stream");
assert.equal(ccHeaders.Accept, "application/json");
assert.equal(ccJsonHeaders.Accept, "application/json");
});

View File

@@ -1,151 +0,0 @@
import test from "node:test";
import assert from "node:assert/strict";
const { firecrawlFetch } = await import("../../open-sse/executors/firecrawl-fetch.ts");
// ── #2253 (decolua/9router): self-hosted Firecrawl support ────────────────────
// FIRECRAWL_BASE_URL lets operators point the executor at a self-hosted instance.
// The API key stays required for the default cloud endpoint, but becomes optional
// once a custom base URL is configured (self-hosted instances usually run with no
// auth in front of them).
function withEnv(vars: Record<string, string | undefined>, fn: () => Promise<void>) {
const original: Record<string, string | undefined> = {};
for (const key of Object.keys(vars)) {
original[key] = process.env[key];
}
for (const [key, value] of Object.entries(vars)) {
if (value === undefined) delete process.env[key];
else process.env[key] = value;
}
return fn().finally(() => {
for (const [key, value] of Object.entries(original)) {
if (value === undefined) delete process.env[key];
else process.env[key] = value;
}
});
}
test("firecrawlFetch routes to FIRECRAWL_BASE_URL when set", async () => {
await withEnv({ FIRECRAWL_BASE_URL: "http://127.0.0.1:3002" }, async () => {
const originalFetch = globalThis.fetch;
let capturedUrl = "";
globalThis.fetch = async (url) => {
capturedUrl = String(url);
return new Response(JSON.stringify({ data: { markdown: "# Self-hosted" } }), {
status: 200,
headers: { "content-type": "application/json" },
});
};
try {
const result = await firecrawlFetch({
url: "https://example.com",
format: "markdown",
depth: 0,
includeMetadata: false,
credentials: { apiKey: "any-key" },
});
assert.equal(result.success, true);
assert.equal(capturedUrl, "http://127.0.0.1:3002/v1/scrape");
} finally {
globalThis.fetch = originalFetch;
}
});
});
test("firecrawlFetch allows missing apiKey when FIRECRAWL_BASE_URL is custom", async () => {
await withEnv({ FIRECRAWL_BASE_URL: "http://127.0.0.1:3002" }, async () => {
const originalFetch = globalThis.fetch;
let capturedHeaders: Record<string, string> = {};
globalThis.fetch = async (_url, init = {}) => {
capturedHeaders = (init as RequestInit).headers as Record<string, string>;
return new Response(JSON.stringify({ data: { markdown: "# Self-hosted" } }), {
status: 200,
headers: { "content-type": "application/json" },
});
};
try {
const result = await firecrawlFetch({
url: "https://example.com",
format: "markdown",
depth: 0,
includeMetadata: false,
credentials: {},
});
assert.equal(result.success, true, "custom base URL must not require an API key");
assert.equal(
capturedHeaders["Authorization"],
undefined,
"no Authorization header should be sent without an apiKey"
);
} finally {
globalThis.fetch = originalFetch;
}
});
});
test("firecrawlFetch still requires apiKey against the default cloud base URL", async () => {
await withEnv({ FIRECRAWL_BASE_URL: undefined }, async () => {
const result = await firecrawlFetch({
url: "https://example.com",
format: "markdown",
depth: 0,
includeMetadata: false,
credentials: {},
});
assert.equal(result.success, false);
assert.equal(result.status, 401);
assert.ok(!result.error?.includes("at /"), "error must not contain stack trace");
});
});
test("firecrawlFetch honors FIRECRAWL_TIMEOUT_MS override", async () => {
await withEnv(
{ FIRECRAWL_BASE_URL: "http://127.0.0.1:3002", FIRECRAWL_TIMEOUT_MS: "5" },
async () => {
const originalFetch = globalThis.fetch;
globalThis.fetch = async (_url, init = {}) => {
const signal = (init as RequestInit).signal;
return new Promise((resolve, reject) => {
const timer = setTimeout(
() =>
resolve(
new Response(JSON.stringify({ data: { markdown: "late" } }), {
status: 200,
headers: { "content-type": "application/json" },
})
),
50
);
signal?.addEventListener("abort", () => {
clearTimeout(timer);
reject(new DOMException("Aborted", "AbortError"));
});
});
};
try {
const result = await firecrawlFetch({
url: "https://example.com",
format: "markdown",
depth: 0,
includeMetadata: false,
credentials: {},
});
assert.equal(result.success, false);
assert.equal(result.status, 504);
} finally {
globalThis.fetch = originalFetch;
}
}
);
});

View File

@@ -19,7 +19,7 @@ describe("KimiWebExecutor", () => {
it("execute returns a 400 error when no JWT is provided", async () => {
const executor = new mod.KimiWebExecutor();
const result = await executor.execute({
model: "k2d6",
model: "kimi-default",
body: { messages: [{ role: "user", content: "hi" }] },
stream: false,
credentials: { apiKey: "" },
@@ -43,7 +43,7 @@ describe("KimiWebExecutor", () => {
});
}) as typeof fetch;
await executor.execute({
model: "k2d6",
model: "kimi-default",
body: { messages: [{ role: "user", content: "hi" }] },
stream: false,
credentials: { apiKey: "kimi-auth=fake.jwt.token" },
@@ -57,28 +57,6 @@ describe("KimiWebExecutor", () => {
});
});
describe("resolveModelConfig", () => {
const { resolveModelConfig } = mod;
it("maps k2d6-thinking to the K2D5 scenario with thinking enabled", () => {
const cfg = resolveModelConfig("k2d6-thinking");
assert.equal(cfg.scenario, "SCENARIO_K2D5");
assert.equal(cfg.thinking, true);
});
it("maps k2d6 (Instant) to the K2D5 scenario without thinking", () => {
const cfg = resolveModelConfig("k2d6");
assert.equal(cfg.scenario, "SCENARIO_K2D5");
assert.equal(cfg.thinking, false);
});
it("falls back to K2D5 + no thinking for an unknown model id", () => {
const cfg = resolveModelConfig("k2d6-agent");
assert.equal(cfg.scenario, "SCENARIO_K2D5");
assert.equal(cfg.thinking, false);
});
});
describe("extractKimiJwt", () => {
const { extractKimiJwt } = mod;

View File

@@ -1,94 +0,0 @@
import test from "node:test";
import assert from "node:assert/strict";
import { XaiExecutor } from "../../open-sse/executors/xai.ts";
import { getExecutor, hasSpecializedExecutor } from "../../open-sse/executors/index.ts";
import { xaiProvider } from "../../open-sse/config/providers/registry/xai/index.ts";
// Real xai catalog ids (open-sse/config/providers/registry/xai/index.ts):
// grok-4.3 — plain, reasoning-capable
// grok-build-0.1 — build/tool model, no reasoning mode
// grok-4.20-multi-agent-0309 — neutral (not in either allow/deny list)
// grok-4.20-0309-reasoning — already encodes reasoning in the id
// grok-4.20-0309-non-reasoning — already encodes non-reasoning in the id
const credentials = { apiKey: "test-key" };
test("XaiExecutor is registered under the 'xai' key and set as the registry executor", () => {
assert.equal(hasSpecializedExecutor("xai"), true);
assert.ok(getExecutor("xai") instanceof XaiExecutor);
assert.equal(xaiProvider.executor, "xai");
});
test("strips a -{level} suffix from an allow-listed model and sets reasoning_effort", () => {
const executor = new XaiExecutor();
for (const level of ["low", "medium", "high", "xhigh"] as const) {
const body = { model: `grok-4.3-${level}`, messages: [] };
const out = executor.transformRequest(`grok-4.3-${level}`, body, false, credentials) as Record<
string,
unknown
>;
assert.equal(out.model, "grok-4.3", `level=${level} should strip suffix from model id`);
assert.equal(out.reasoning_effort, level, `level=${level} should set reasoning_effort`);
}
});
test("suffix parsing also applies to the explicit -reasoning variant without double-mutating it", () => {
const executor = new XaiExecutor();
const body = { model: "grok-4.20-0309-reasoning-high", messages: [] };
const out = executor.transformRequest(
"grok-4.20-0309-reasoning-high",
body,
false,
credentials
) as Record<string, unknown>;
assert.equal(out.model, "grok-4.20-0309-reasoning");
assert.equal(out.reasoning_effort, "high");
});
test("strips reasoning_effort for a deny-listed model (grok-build-0.1)", () => {
const executor = new XaiExecutor();
const body = { model: "grok-build-0.1", reasoning_effort: "high", messages: [] };
const out = executor.transformRequest("grok-build-0.1", body, false, credentials) as Record<
string,
unknown
>;
assert.equal(out.model, "grok-build-0.1");
assert.equal(out.reasoning_effort, undefined);
});
test("strips reasoning_effort for the explicit -non-reasoning variant (already encodes reasoning state)", () => {
const executor = new XaiExecutor();
const body = {
model: "grok-4.20-0309-non-reasoning",
reasoning_effort: "high",
messages: [],
};
const out = executor.transformRequest(
"grok-4.20-0309-non-reasoning",
body,
false,
credentials
) as Record<string, unknown>;
assert.equal(out.model, "grok-4.20-0309-non-reasoning");
assert.equal(out.reasoning_effort, undefined);
});
test("leaves a plain, unlisted model id and body unchanged (no suffix, not allow/deny listed)", () => {
const executor = new XaiExecutor();
const body = { model: "grok-4.20-multi-agent-0309", messages: [{ role: "user", content: "hi" }] };
const out = executor.transformRequest(
"grok-4.20-multi-agent-0309",
body,
false,
credentials
) as Record<string, unknown>;
assert.equal(out.model, "grok-4.20-multi-agent-0309");
assert.equal(out.reasoning_effort, undefined);
assert.deepEqual(out.messages, body.messages);
});

View File

@@ -29,14 +29,13 @@ test.after(() => {
// ── Registry ─────────────────────────────────────────────────────────────────
test("getAllProviders returns exactly 4 providers", () => {
test("getAllProviders returns exactly 3 providers", () => {
const providers = getAllProviders();
assert.equal(providers.length, 4);
assert.equal(providers.length, 3);
const ids = providers.map((p) => p.id);
assert.ok(ids.includes("1proxy"));
assert.ok(ids.includes("proxifly"));
assert.ok(ids.includes("iplocate"));
assert.ok(ids.includes("webshare"));
});
test("getProvider returns the correct provider by id", () => {

View File

@@ -1,46 +0,0 @@
import { test } from "node:test";
import assert from "node:assert/strict";
import { parseSSELine, stripAnsiCodes } from "../../open-sse/utils/streamHelpers.ts";
test("parseSSELine resolves an ANSI/VT100-prefixed data: frame (gemini-cli redraw)", () => {
// gemini-cli prefixes SSE frames with cursor-redraw escapes (\x1b[2K clears the
// line, \x1b[1A moves the cursor up). 0x1b is not whitespace, so before the fix
// trimStart().startsWith("data:") failed and the frame was silently dropped (#2273).
const line = `\x1b[2K\x1b[1Adata: ${JSON.stringify({
choices: [{ delta: { content: "hi" } }],
})}`;
const r = parseSSELine(line);
assert.ok(r, "expected a parsed payload, got null (frame was dropped)");
assert.equal(r?.choices?.[0]?.delta?.content, "hi");
});
test("parseSSELine returns null for a pure-ANSI line (nothing after stripping)", () => {
assert.equal(parseSSELine("\x1b[2K\x1b[1A"), null);
});
test("stripAnsiCodes strips CSI/SGR/OSC/C0 but preserves \\t \\n \\r", () => {
// CSI cursor moves + SGR color codes
assert.equal(stripAnsiCodes("\x1b[2K\x1b[1Ahello"), "hello");
assert.equal(stripAnsiCodes("\x1b[31mred\x1b[0m"), "red");
// OSC sequence terminated by BEL (\x07)
assert.equal(stripAnsiCodes("\x1b]0;title\x07text"), "text");
// OSC sequence terminated by ST (\x1b\\)
assert.equal(stripAnsiCodes("\x1b]8;;https://x\x1b\\link"), "link");
// stray C0 control byte
assert.equal(stripAnsiCodes("a\x00b"), "ab");
// whitespace preserved
assert.equal(stripAnsiCodes("a\tb\nc\rd"), "a\tb\nc\rd");
});
test("stripAnsiCodes passes null/undefined through unchanged", () => {
assert.equal(stripAnsiCodes(null), null);
assert.equal(stripAnsiCodes(undefined), undefined);
});
test("stripAnsiCodes runs in linear time on adversarial input (ReDoS guard)", () => {
const hostile = "\x1b[" + "0;".repeat(50000) + "m";
const start = Date.now();
stripAnsiCodes(hostile);
assert.ok(Date.now() - start < 1000, "stripAnsiCodes should not backtrack catastrophically");
});

View File

@@ -1,41 +0,0 @@
/**
* #2309 — antigravity/gemini returned [400] "Invalid JSON payload received.
* Unknown name \"multipleOf\" at 'request.tools[0].function_declarations[...]"
*
* Root cause: `multipleOf` (a JSON Schema numeric constraint) was NOT listed in
* `GEMINI_UNSUPPORTED_SCHEMA_KEYS`, so `cleanJSONSchemaForAntigravity` left it in
* the function-declaration parameters. The Gemini/antigravity upstream (OpenAPI
* 3.0 schema subset) rejects `multipleOf` with a hard 400.
*
* Fix: add `multipleOf` to the unsupported-keys set so it is stripped at every
* level (top-level property, nested object, and inside array `items`). Sibling
* numeric constraints `minimum`/`maximum` ARE accepted by Gemini and must stay.
*/
import test from "node:test";
import assert from "node:assert/strict";
import {
cleanJSONSchemaForAntigravity,
GEMINI_UNSUPPORTED_SCHEMA_KEYS,
} from "../../open-sse/translator/helpers/geminiHelper.ts";
test("#2309 multipleOf is stripped at all levels for antigravity/gemini schemas", () => {
const schema = {
type: "object",
properties: {
count: { type: "integer", multipleOf: 2, minimum: 0 },
ratio: { type: "number", multipleOf: 0.5 },
tags: { type: "array", items: { type: "number", multipleOf: 10 } },
},
};
const cleaned = JSON.stringify(cleanJSONSchemaForAntigravity(schema));
assert.ok(!cleaned.includes("multipleOf"), "multipleOf must be removed");
// Gemini DOES support minimum/maximum — those must survive.
assert.ok(cleaned.includes("minimum"), "minimum must be preserved");
});
test("#2309 multipleOf is in GEMINI_UNSUPPORTED_SCHEMA_KEYS", () => {
assert.ok(GEMINI_UNSUPPORTED_SCHEMA_KEYS.has("multipleOf"));
});

View File

@@ -1,110 +0,0 @@
import test from "node:test";
import assert from "node:assert/strict";
const mod = await import("../../scripts/release/gen-contributors.mjs");
const {
extractVersionSection,
parseContributors,
renderContributors,
injectContributors,
NOISE_HANDLES,
} = mod;
const FIXTURE = `# Changelog
## [Unreleased]
---
## [3.9.0] — 2026-08-01
### ✨ New Features
- **feat(a):** thing one. ([#100](https://github.com/x/y/pull/100) — thanks @alice)
- **feat(b):** uses \`@toon-format/toon\` and \`@dnd-kit\`. ([#101](https://github.com/x/y/pull/101) — thanks @bob)
### 🔧 Bug Fixes
- **fix(c):** direct commit fix. (thanks @carol)
- **fix(d):** extracted. Extracted from [#102](https://github.com/x/y/pull/102) by [@dave](https://github.com/dave).
### 📝 Maintenance
- **refactor(rollup):** god-file split ([#200](https://github.com/x/y/pull/200), [#201](https://github.com/x/y/pull/201) — thanks @erin); editorconfig ([#202](https://github.com/x/y/pull/202) — thanks @frank). — thanks @diegosouzapw
---
## [3.8.99] — 2026-07-31
### 🔧 Bug Fixes
- **fix(z):** other version, must not leak. ([#999](https://github.com/x/y/pull/999) — thanks @zoe)
---
`;
test("extractVersionSection returns only the target version body (not the next section)", () => {
const sec = extractVersionSection(FIXTURE, "3.9.0");
assert.ok(sec.includes("thing one"), "includes 3.9.0 content");
assert.ok(!sec.includes("must not leak"), "excludes 3.8.99 content");
assert.ok(!sec.includes("#999"), "does not bleed into next version");
});
test("parseContributors credits per parenthetical group, not a flat scan", () => {
const agg = parseContributors(extractVersionSection(FIXTURE, "3.9.0"));
// rollup: erin gets 200+201, frank gets 202 — NOT both getting all three
assert.deepEqual(
[...agg.get("erin")].sort((a, b) => a - b),
[200, 201]
);
assert.deepEqual([...agg.get("frank")], [202]);
// simple bullets
assert.deepEqual([...agg.get("alice")], [100]);
// direct-commit credit with no PR ref
assert.ok(agg.has("carol") && agg.get("carol").size === 0);
// "Extracted from #N by @X"
assert.deepEqual([...agg.get("dave")], [102]);
});
test("noise handles and the maintainer are excluded from the contributor map", () => {
const agg = parseContributors(extractVersionSection(FIXTURE, "3.9.0"));
assert.ok(!agg.has("toon-format"), "package scope is not a contributor");
assert.ok(!agg.has("dnd-kit"), "package scope is not a contributor");
assert.ok(!agg.has("diegosouzapw"), "maintainer is rendered separately, not in the map");
assert.ok(NOISE_HANDLES.has("toon-format"));
});
test("renderContributors emits an alphabetical table with maintainer last", () => {
const agg = parseContributors(extractVersionSection(FIXTURE, "3.9.0"));
const table = renderContributors("3.9.0", agg);
assert.ok(table.startsWith("### 🙌 Contributors"));
const rows = table.split("\n").filter((l) => l.startsWith("| [@"));
const handles = rows.map((r) => r.match(/@([A-Za-z0-9_-]+)/)[1]);
assert.equal(handles[handles.length - 1], "diegosouzapw", "maintainer is last");
const external = handles.slice(0, -1);
assert.deepEqual(
external,
[...external].sort((a, b) => a.localeCompare(b)),
"external sorted"
);
assert.ok(table.includes("| [@carol](https://github.com/carol) | direct commit / report |"));
});
test("injectContributors inserts before the closing --- and is idempotent", () => {
const once = injectContributors(
FIXTURE,
"3.9.0",
renderContributors("3.9.0", parseContributors(extractVersionSection(FIXTURE, "3.9.0")))
);
assert.ok(once.includes("### 🙌 Contributors"), "section injected");
// 3.8.99 untouched
assert.ok(once.includes("must not leak"));
// idempotent: injecting again does not duplicate
const twice = injectContributors(
once,
"3.9.0",
renderContributors("3.9.0", parseContributors(extractVersionSection(once, "3.9.0")))
);
const count = (twice.match(/### 🙌 Contributors/g) || []).length;
assert.equal(count, 1, "no duplicate Contributors section on re-run");
});

View File

@@ -1,145 +0,0 @@
import test from "node:test";
import assert from "node:assert/strict";
import { GitlabExecutor } from "../../open-sse/executors/gitlab.ts";
function jsonResponse(body: unknown, status = 200) {
return new Response(JSON.stringify(body), {
status,
headers: { "Content-Type": "application/json" },
});
}
const WEATHER_TOOL = {
type: "function",
function: {
name: "get_weather",
description: "Get the current weather for a city",
parameters: {
type: "object",
properties: { city: { type: "string" } },
required: ["city"],
},
},
};
test("GitlabExecutor emulates OpenAI tool_calls when body.tools is present (#6051)", async () => {
const executor = new GitlabExecutor();
const originalFetch = globalThis.fetch;
const calls: Array<{ url: string; body: Record<string, unknown> }> = [];
// Upstream (GitLab code_suggestions) replies with the tool invocation as raw
// text, exactly how a web/completion model would when handed the tool contract.
globalThis.fetch = async (url, init = {}) => {
calls.push({ url: String(url), body: JSON.parse(String(init.body || "{}")) });
return jsonResponse({
model: { name: "code-gecko" },
choices: [
{
text: 'Sure, let me check.\n<tool>{"name": "get_weather", "arguments": {"city": "Paris"}}</tool>',
},
],
});
};
try {
const result = await executor.execute({
model: "gitlab-duo-code-suggestions",
body: {
messages: [{ role: "user", content: "What's the weather in Paris?" }],
tools: [WEATHER_TOOL],
tool_choice: "auto",
},
stream: false,
credentials: { apiKey: "glpat-test" },
signal: AbortSignal.timeout(10_000),
log: null,
} as any);
// The serialized tool contract must reach the GitLab prompt.
assert.equal(calls.length, 1);
assert.match(
String((calls[0].body.current_file as any)?.content_above_cursor ?? ""),
/get_weather/,
"tool contract must be serialized into the GitLab prompt"
);
const body = (await result.response.json()) as any;
const choice = body.choices[0];
assert.equal(choice.finish_reason, "tool_calls");
assert.ok(Array.isArray(choice.message.tool_calls), "tool_calls array must be present");
assert.equal(choice.message.tool_calls.length, 1);
assert.equal(choice.message.tool_calls[0].type, "function");
assert.equal(choice.message.tool_calls[0].function.name, "get_weather");
assert.deepEqual(JSON.parse(choice.message.tool_calls[0].function.arguments), {
city: "Paris",
});
assert.equal(choice.message.content, null);
} finally {
globalThis.fetch = originalFetch;
}
});
test("GitlabExecutor streams a tool_calls chunk when tools are present (#6051)", async () => {
const executor = new GitlabExecutor();
const originalFetch = globalThis.fetch;
globalThis.fetch = async () =>
jsonResponse({
model: { name: "code-gecko" },
choices: [{ text: '<tool>{"name": "get_weather", "arguments": {"city": "Paris"}}</tool>' }],
});
try {
const result = await executor.execute({
model: "gitlab-duo-code-suggestions",
body: {
messages: [{ role: "user", content: "weather in Paris?" }],
tools: [WEATHER_TOOL],
},
stream: true,
credentials: { apiKey: "glpat-test" },
signal: AbortSignal.timeout(10_000),
log: null,
} as any);
assert.equal(result.response.headers.get("Content-Type"), "text/event-stream");
const text = await result.response.text();
assert.match(text, /"tool_calls"/, "SSE stream must carry a tool_calls delta");
assert.match(text, /get_weather/);
assert.match(text, /"finish_reason":"tool_calls"/);
assert.match(text, /data: \[DONE\]/);
} finally {
globalThis.fetch = originalFetch;
}
});
test("GitlabExecutor keeps plain-text finish_reason:stop for non-tool requests (#6051)", async () => {
const executor = new GitlabExecutor();
const originalFetch = globalThis.fetch;
globalThis.fetch = async () =>
jsonResponse({
model: { name: "code-gecko" },
choices: [{ text: "def hello():\n return 'world'" }],
});
try {
const result = await executor.execute({
model: "gitlab-duo-code-suggestions",
body: { messages: [{ role: "user", content: "Write a hello world function" }] },
stream: false,
credentials: { apiKey: "glpat-test" },
signal: AbortSignal.timeout(10_000),
log: null,
} as any);
const body = (await result.response.json()) as any;
const choice = body.choices[0];
assert.equal(choice.finish_reason, "stop");
assert.equal(choice.message.tool_calls, undefined);
assert.match(choice.message.content, /hello/);
} finally {
globalThis.fetch = originalFetch;
}
});

View File

@@ -1,52 +0,0 @@
import test from "node:test";
import assert from "node:assert/strict";
import { getModelInfoCore } from "../../open-sse/services/model.ts";
// Bug #5852: resolveModelByProviderInference() in open-sse/services/model.ts had an
// unconditional `/^gpt-/i` heuristic that fired for ANY model id starting with
// "gpt-", hijacking open-weight models cataloged under other providers (e.g.
// "gpt-oss-120b", served by fireworks/cerebras/scaleway/byteplus) into
// provider "openai", which does not carry them — producing a 404 with no
// fallback for bare (non-combo) requests.
//
// Fix: the fallback must only apply when there are ZERO known catalog
// candidates for the model id (providers.length === 0).
const KNOWN_GPT_OSS_120B_PROVIDERS = new Set(["fireworks", "cerebras", "scaleway", "byteplus"]);
test("gpt-oss-120b resolves into its cataloged open-weight providers, not openai (#5852)", async () => {
const info = await getModelInfoCore("gpt-oss-120b", null);
assert.notEqual(
info.provider,
"openai",
"gpt-oss-120b must not be hijacked into the openai-family fallback"
);
// Multiple providers catalog this open-weight model id, so the resolver correctly
// reports it as ambiguous (asking the caller to disambiguate with a provider/model
// prefix) instead of silently defaulting to openai (which doesn't carry it → 404).
assert.equal(info.errorType, "ambiguous_model");
assert.ok(Array.isArray(info.candidateProviders) && info.candidateProviders.length > 0);
assert.ok(
info.candidateProviders.some((p: string) => KNOWN_GPT_OSS_120B_PROVIDERS.has(p)),
`expected at least one candidate from ${[...KNOWN_GPT_OSS_120B_PROVIDERS].join(
", "
)}, got ${JSON.stringify(info.candidateProviders)}`
);
assert.ok(
!info.candidateProviders.includes("openai"),
"openai must not be listed as a candidate for gpt-oss-120b"
);
});
test("regression guard: a genuinely-uncataloged openai-family id still falls back to openai (#5852)", async () => {
const info = await getModelInfoCore("gpt-5.9-imaginary-unreleased", null);
assert.equal(
info.provider,
"openai",
"uncataloged gpt-* ids with zero known candidates must still fall back to openai"
);
});

View File

@@ -1,36 +0,0 @@
import { test } from "node:test";
import assert from "node:assert/strict";
import { readFileSync } from "node:fs";
import { fileURLToPath } from "node:url";
import { dirname, join } from "node:path";
// Split-guard for the grok-web executor extraction.
// Pure clusters live in 4 leaves: types.ts (stream types), tool-bridge.ts (OpenAI<->Grok
// tool translation), native-tools.ts (native-tool selection + mapping), text-cleanup.ts
// (markup cleanup). All are module-private (no host re-export). No leaf imports the host.
const HERE = dirname(fileURLToPath(import.meta.url));
const DIR = join(HERE, "../../open-sse/executors/grok-web");
const HOST = join(HERE, "../../open-sse/executors/grok-web.ts");
test("leaves are acyclic: none imports the host, layered types<-tool-bridge<-native-tools", () => {
for (const f of ["types", "tool-bridge", "native-tools", "text-cleanup"]) {
const src = readFileSync(join(DIR, `${f}.ts`), "utf8");
assert.doesNotMatch(src, /from "\.\.\/grok-web\.ts"/, `${f} must not import the host`);
}
assert.doesNotMatch(readFileSync(join(DIR, "types.ts"), "utf8"), /^import /m);
assert.match(readFileSync(join(DIR, "native-tools.ts"), "utf8"), /from "\.\/tool-bridge\.ts"/);
});
test("host imports the tool-bridge + native-tools + text-cleanup helpers", () => {
const host = readFileSync(HOST, "utf8");
assert.match(host, /from "\.\/grok-web\/tool-bridge\.ts"/);
assert.match(host, /from "\.\/grok-web\/native-tools\.ts"/);
assert.match(host, /from "\.\/grok-web\/text-cleanup\.ts"/);
});
test("text-cleanup strips Grok markup", async () => {
const { cleanGrokContentText } =
await import("../../open-sse/executors/grok-web/text-cleanup.ts");
assert.equal(typeof cleanGrokContentText, "function");
assert.equal(typeof cleanGrokContentText("plain text"), "string");
});

View File

@@ -1,103 +0,0 @@
import test from "node:test";
import assert from "node:assert/strict";
import {
resolveHfPipelineTag,
sortHfSuggestedModels,
type HfModelSummary,
} from "../../open-sse/services/hfModelSuggestions.ts";
test("resolveHfPipelineTag: maps the 'image' kind to HF's text-to-image pipeline_tag", () => {
assert.equal(resolveHfPipelineTag("image"), "text-to-image");
});
test("resolveHfPipelineTag: returns null for an unmapped kind", () => {
assert.equal(resolveHfPipelineTag("video"), null);
assert.equal(resolveHfPipelineTag("does-not-exist"), null);
});
test("sortHfSuggestedModels: sorts descending by downloads (default)", () => {
const models: HfModelSummary[] = [
{ id: "a/low", downloads: 10, likes: 500 },
{ id: "b/high", downloads: 1000, likes: 1 },
{ id: "c/mid", downloads: 100, likes: 50 },
];
const result = sortHfSuggestedModels(models);
assert.deepEqual(
result.map((m) => m.id),
["b/high", "c/mid", "a/low"]
);
});
test("sortHfSuggestedModels: sorts descending by likes when requested", () => {
const models: HfModelSummary[] = [
{ id: "a/low", downloads: 10, likes: 500 },
{ id: "b/high", downloads: 1000, likes: 1 },
{ id: "c/mid", downloads: 100, likes: 50 },
];
const result = sortHfSuggestedModels(models, "likes");
assert.deepEqual(
result.map((m) => m.id),
["a/low", "c/mid", "b/high"]
);
});
test("sortHfSuggestedModels: caps results at the requested limit", () => {
const models: HfModelSummary[] = Array.from({ length: 30 }, (_, i) => ({
id: `model/${i}`,
downloads: i,
}));
const result = sortHfSuggestedModels(models, "downloads", 5);
assert.equal(result.length, 5);
// Highest downloads (29..25) come first
assert.deepEqual(
result.map((m) => m.id),
["model/29", "model/28", "model/27", "model/26", "model/25"]
);
});
test("sortHfSuggestedModels: drops entries without a usable string id", () => {
const models = [
{ id: "", downloads: 999 },
{ id: " ", downloads: 998 },
{ downloads: 997 },
{ id: "valid/model", downloads: 1 },
] as HfModelSummary[];
const result = sortHfSuggestedModels(models);
assert.deepEqual(
result.map((m) => m.id),
["valid/model"]
);
});
test("sortHfSuggestedModels: treats missing/non-numeric metric values as 0 (no throw)", () => {
const models = [
{ id: "a/no-metric" },
{ id: "b/has-metric", downloads: 5 },
{ id: "c/nan-metric", downloads: Number.NaN },
] as HfModelSummary[];
const result = sortHfSuggestedModels(models, "downloads");
assert.deepEqual(
result.map((m) => m.id),
["b/has-metric", "a/no-metric", "c/nan-metric"]
);
});
test("sortHfSuggestedModels: handles an empty input array", () => {
assert.deepEqual(sortHfSuggestedModels([]), []);
});
test("sortHfSuggestedModels: falls back to a default limit for an invalid limit value", () => {
const models: HfModelSummary[] = Array.from({ length: 25 }, (_, i) => ({
id: `model/${i}`,
downloads: i,
}));
const result = sortHfSuggestedModels(models, "downloads", 0);
assert.equal(result.length, 20);
});

View File

@@ -1,32 +0,0 @@
import { test } from "node:test";
import assert from "node:assert/strict";
import { readFileSync } from "node:fs";
import { fileURLToPath } from "node:url";
import { dirname, join } from "node:path";
// Split-guard for the huggingchat executor JSONL-stream extraction.
// The pure JSONL->OpenAI-SSE translation lives in huggingchat/jsonlStream.ts
// (consumes a passed-in ReadableStream; no host state/fetch/auth). Host imports it back.
const HERE = dirname(fileURLToPath(import.meta.url));
const EXE = join(HERE, "../../open-sse/executors");
const HOST = join(EXE, "huggingchat.ts");
const LEAF = join(EXE, "huggingchat/jsonlStream.ts");
test("leaf hosts the jsonl translators and does not import the host", () => {
const src = readFileSync(LEAF, "utf8");
assert.match(src, /export async function\* streamJsonlToOpenAi\b/);
assert.match(src, /export async function readJsonlResponse\b/);
assert.match(src, /export function (sseChunk|parseJsonlLine)\b/);
assert.doesNotMatch(src, /from "\.\.\/huggingchat\.ts"/);
});
test("host imports the jsonl translators back from the leaf", () => {
const host = readFileSync(HOST, "utf8");
assert.match(host, /from "\.\/huggingchat\/jsonlStream\.ts"/);
});
test("parseJsonlLine parses a jsonl data line", async () => {
const { parseJsonlLine } = await import("../../open-sse/executors/huggingchat/jsonlStream.ts");
assert.equal(typeof parseJsonlLine, "function");
assert.doesNotThrow(() => parseJsonlLine("not json"));
});

View File

@@ -1,43 +0,0 @@
import { describe, it } from "node:test";
import assert from "node:assert/strict";
import { detectBrowserLocale } from "../../src/i18n/detectBrowserLocale";
const SUPPORTED_LOCALES = ["en", "pt-BR", "es", "zh-TW", "fr", "de"] as const;
describe("detectBrowserLocale", () => {
it("returns the exact match when a browser language equals a supported locale", () => {
assert.equal(detectBrowserLocale(["pt-BR"], SUPPORTED_LOCALES), "pt-BR");
});
it("folds zh-HK to zh-TW when zh-TW is supported", () => {
assert.equal(detectBrowserLocale(["zh-HK"], SUPPORTED_LOCALES), "zh-TW");
});
it("folds zh-MO to zh-TW when zh-TW is supported", () => {
assert.equal(detectBrowserLocale(["zh-MO"], SUPPORTED_LOCALES), "zh-TW");
});
it("falls back to a language-prefix match when no exact match exists", () => {
assert.equal(detectBrowserLocale(["en-US"], SUPPORTED_LOCALES), "en");
});
it("returns null when nothing matches", () => {
assert.equal(detectBrowserLocale(["ja-JP"], SUPPORTED_LOCALES), null);
});
it("returns null for an empty languages list", () => {
assert.equal(detectBrowserLocale([], SUPPORTED_LOCALES), null);
});
it("returns null for an empty locales list", () => {
assert.equal(detectBrowserLocale(["en-US"], []), null);
});
it("tries each browser language in order until one matches", () => {
assert.equal(detectBrowserLocale(["ja-JP", "fr-CA"], SUPPORTED_LOCALES), "fr");
});
it("is case-insensitive", () => {
assert.equal(detectBrowserLocale(["PT-br"], SUPPORTED_LOCALES), "pt-BR");
});
});

View File

@@ -3,10 +3,7 @@ import assert from "node:assert/strict";
import { kiroProvider } from "../../open-sse/config/providers/registry/kiro/index.ts";
const { getNextFamilyFallback } = await import("../../open-sse/services/modelFamilyFallback.ts");
// Regression for the port of decolua/9router#2267 ("claude-sonnet-5 is not supported"),
// upstream PR diegosouzapw/OmniRoute#5796.
// Regression for the port of decolua/9router#2267 ("claude-sonnet-5 is not supported").
//
// The Kiro provider's OAuth model catalog lives in `registry/kiro/index.ts` `models[]`.
// That list is both the model selector's source and the fallback for the live
@@ -31,12 +28,3 @@ test("kiro claude-sonnet-5 declares the 1M-context / 128K-output capability", ()
assert.equal(sonnet5.contextLength, 1000000);
assert.equal(sonnet5.maxOutputTokens, 128000);
});
test("claude-sonnet-5 degrades to the Sonnet family, not Opus", () => {
// Sonnet 5 is Sonnet-tier: its first fallback must be a cheaper Sonnet, never an Opus.
const next = getNextFamilyFallback("kiro/claude-sonnet-5", new Set(["kiro/claude-sonnet-5"]));
assert.ok(
next && /claude-sonnet-4/.test(next),
`expected claude-sonnet-5 to fall back within the Sonnet family, got: ${next}`
);
});

View File

@@ -1,35 +0,0 @@
import { test } from "node:test";
import assert from "node:assert/strict";
import { readFileSync } from "node:fs";
import { fileURLToPath } from "node:url";
import { dirname, join } from "node:path";
// Split-guard for the kiro executor EventStream framing extraction.
// The pure AWS EventStream binary framing (ByteQueue, CRC32, parseEventFrame) lives in
// kiro/eventstream.ts (self-contained, no host imports). Host imports back what it uses.
const HERE = dirname(fileURLToPath(import.meta.url));
const EXE = join(HERE, "../../open-sse/executors");
const HOST = join(EXE, "kiro.ts");
const LEAF = join(EXE, "kiro/eventstream.ts");
test("leaf hosts the framing primitives and does not import the host", () => {
const src = readFileSync(LEAF, "utf8");
assert.match(src, /export class ByteQueue\b/);
assert.match(src, /export function crc32\b/);
assert.match(src, /export function parseEventFrame\b/);
assert.doesNotMatch(src, /from "\.\.\/kiro\.ts"/);
});
test("host imports the framing primitives back from the leaf", () => {
const host = readFileSync(HOST, "utf8");
assert.match(host, /from "\.\/kiro\/eventstream\.ts"/);
});
test("crc32 is deterministic and ByteQueue buffers bytes", async () => {
const { crc32, ByteQueue } = await import("../../open-sse/executors/kiro/eventstream.ts");
const a = crc32(new Uint8Array([1, 2, 3]));
const b = crc32(new Uint8Array([1, 2, 3]));
assert.equal(a, b);
const q = new ByteQueue();
assert.equal(typeof q, "object");
});

View File

@@ -1,35 +0,0 @@
/**
* #2306 — When Claude Code routes through the Kiro/CodeWhisperer backend, the
* `system` message was normalized to `role: user` WITHOUT any wrapper, so the
* full system prompt (env info, tool defs, memory instructions, etc.) appeared
* as raw user text — indistinguishable from real user input, polluting context.
*
* Fix: wrap system-origin content in `<system-reminder>...</system-reminder>`
* before it is merged into the Kiro user message. Real user turns stay raw.
*/
import test from "node:test";
import assert from "node:assert/strict";
import { buildKiroPayload } from "../../open-sse/translator/request/openai-to-kiro.ts";
test("#2306 system prompt is wrapped in <system-reminder> for Kiro, not raw user text", () => {
const body = {
messages: [
{ role: "system", content: "You are Claude Code. ENV: cwd=/tmp. Secret: do not reveal." },
{ role: "user", content: "hello there" },
],
};
const payload = JSON.stringify(buildKiroPayload("claude-sonnet-4-5", body, false, {}));
assert.ok(payload.includes("<system-reminder>"), "system content must be wrapped");
assert.ok(payload.includes("You are Claude Code"), "system text must still be present");
// The real user turn must NOT be wrapped.
assert.ok(payload.includes("hello there"), "user text preserved");
});
test("#2306 a plain user-only request is never wrapped in <system-reminder>", () => {
const body = { messages: [{ role: "user", content: "just a normal question" }] };
const payload = JSON.stringify(buildKiroPayload("claude-sonnet-4-5", body, false, {}));
assert.ok(!payload.includes("<system-reminder>"), "no system → no wrapper");
});

View File

@@ -1,63 +0,0 @@
import test from "node:test";
import assert from "node:assert/strict";
const mod = await import("../../scripts/release/list-uncovered-commits.mjs");
const { refsOf, typeOf, computeUncovered, changelogRefWindow } = mod;
test("refsOf extracts every #N from a subject", () => {
assert.deepEqual(refsOf("fix(x): thing (#5842) (#5901)"), [5842, 5901]);
assert.deepEqual(refsOf("chore: no refs here"), []);
});
test("typeOf reads the conventional-commit type", () => {
assert.equal(typeOf("feat(api): x"), "feat");
assert.equal(typeOf("fix: y"), "fix");
assert.equal(typeOf("refactor(db)!: z"), "refactor");
assert.equal(typeOf("Merge branch main"), "other");
});
test("computeUncovered: a commit is covered iff ANY of its refs is in the changelog window", () => {
const commits = [
{ hash: "a1", subject: "fix(x): covered by issue ref (#100)" }, // issue 100 in changelog
{ hash: "b2", subject: "feat(y): uncovered feature (#200)" }, // 200 not in changelog
{ hash: "c3", subject: "refactor(z): internal (#300)" }, // rollup type, uncovered
{ hash: "d4", subject: "chore: no ref at all" }, // no ref → uncovered, rollup
];
const refs = new Set([100]); // only #100 is documented
const { covered, uncovered } = computeUncovered(commits, refs);
assert.equal(covered, 1);
assert.equal(uncovered.length, 3);
const byHash = Object.fromEntries(uncovered.map((c) => [c.hash, c]));
assert.equal(byHash.b2.rollup, false, "feat is user-facing, not a rollup candidate");
assert.equal(byHash.c3.rollup, true, "refactor is a rollup candidate");
assert.equal(byHash.d4.rollup, true, "chore is a rollup candidate");
});
test("changelogRefWindow scans [Unreleased] + the version section but not older versions", () => {
const cl = `# Changelog
## [Unreleased]
- **fix:** something ([#10](u))
---
## [3.9.0] — x
### 🔧 Bug Fixes
- **fix(a):** landed ([#20](u))
---
## [3.8.99] — y
- **fix(old):** must not count ([#999](u))
---
`;
const refs = changelogRefWindow(cl, "3.9.0");
assert.ok(refs.has(10), "picks up [Unreleased] refs");
assert.ok(refs.has(20), "picks up the target version refs");
assert.ok(!refs.has(999), "does NOT bleed into the previous version");
});

View File

@@ -347,76 +347,3 @@ test("handleMcpStreamableHTTP keeps 400 for a missing session id (non-initialize
// only the *present-but-unknown* case changed to 404. This must NOT regress.
assert.equal(res.status, 400);
});
test("handleMcpStreamableHTTP auto-recovers when stale session id is sent with initialize", async () => {
mod.shutdownMcpHttp();
const initReq = new Request("http://localhost/api/mcp/stream", {
method: "POST",
headers: {
"Content-Type": "application/json",
Accept: "application/json, text/event-stream",
},
body: JSON.stringify({
jsonrpc: "2.0",
method: "initialize",
id: 1,
params: {
protocolVersion: "2025-03-26",
capabilities: {},
clientInfo: { name: "test-client", version: "1.0.0" },
},
}),
});
const firstRes = await mod.handleMcpStreamableHTTP(initReq);
const staleSessionId = firstRes.headers.get("mcp-session-id");
if (!staleSessionId) {
mod.shutdownMcpHttp();
return;
}
mod.shutdownMcpHttp();
assert.equal(mod.isMcpHttpActive(), false);
const reinitReq = new Request("http://localhost/api/mcp/stream", {
method: "POST",
headers: {
"Content-Type": "application/json",
Accept: "application/json, text/event-stream",
"mcp-session-id": staleSessionId,
},
body: JSON.stringify({
jsonrpc: "2.0",
method: "initialize",
id: 2,
params: {
protocolVersion: "2025-03-26",
capabilities: {},
clientInfo: { name: "test-client", version: "1.0.0" },
},
}),
});
const recoveryRes = await mod.handleMcpStreamableHTTP(reinitReq);
assert.notEqual(
recoveryRes.status,
404,
"Stale session + initialize must NOT return 404 — server should auto-recover"
);
assert.ok(
recoveryRes.status >= 200 && recoveryRes.status < 300,
`Expected 2xx response on auto-recovery, got ${recoveryRes.status}`
);
const newSessionId = recoveryRes.headers.get("mcp-session-id");
assert.ok(newSessionId, "Server must issue a new mcp-session-id on auto-recovery");
assert.equal(
mod.isMcpHttpActive(),
true,
"Server must have an active session after auto-recovery"
);
mod.shutdownMcpHttp();
});

View File

@@ -81,19 +81,6 @@ test("media listing filter surfaces minimax where the old declared-only filter m
assert.ok(oldListFor("tts").length < newListFor("tts").length, "fix surfaces additional tts providers");
});
test("ocr is a registry-backed media kind and mistral derives it", () => {
assert.ok(
(REGISTRY_MEDIA_KINDS as readonly string[]).includes("ocr"),
"REGISTRY_MEDIA_KINDS should include ocr once the OCR registry is wired"
);
assert.ok(
getRegistryMediaKinds("mistral").includes("ocr" as never),
"mistral should derive the ocr media kind from OCR_PROVIDERS"
);
const merged = resolveProviderServiceKinds("mistral", ["llm"]);
assert.ok(merged.includes("ocr"), `expected ocr in ${merged.join(",")}`);
});
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)) {

View File

@@ -1,65 +0,0 @@
import test from "node:test";
import assert from "node:assert/strict";
import { modelscopeProvider } from "../../open-sse/config/providers/registry/modelscope/index.ts";
import { REGISTRY } from "../../open-sse/config/providerRegistry.ts";
import { APIKEY_PROVIDERS } from "../../src/shared/constants/providers/apikey/index.ts";
import { AI_PROVIDERS, getProviderById } from "../../src/shared/constants/providers.ts";
// Upstream 9router PR #1764 (@tn5052) ports ModelScope (Alibaba 魔搭) as an OpenAI-compatible
// BYOK free-tier provider. The upstream PR hardcoded `https://api-inference.modelscope.ai/...`
// (`.ai` TLD) — ModelScope's own docs confirm the real production domain is
// `api-inference.modelscope.cn` (`.cn` TLD). This suite locks in the verified domain and
// guards against a regression back to the unverified `.ai` domain.
test("providers-shape: modelscope is registered in APIKEY_PROVIDERS metadata", () => {
assert.ok("modelscope" in APIKEY_PROVIDERS, "modelscope missing from APIKEY_PROVIDERS");
const meta = (APIKEY_PROVIDERS as Record<string, Record<string, unknown>>).modelscope;
assert.equal(meta.id, "modelscope");
assert.equal(meta.alias, "ms");
assert.equal(meta.name, "ModelScope");
assert.equal(meta.website, "https://modelscope.cn");
assert.equal(meta.hasFree, true);
});
test("providers-shape: modelscope is a canonical AI_PROVIDERS entry resolvable by id", () => {
assert.ok("modelscope" in AI_PROVIDERS, "modelscope missing from AI_PROVIDERS");
const provider = getProviderById("modelscope");
assert.ok(provider, "getProviderById('modelscope') returned nothing");
assert.equal(provider?.id, "modelscope");
});
test("registry resolution: modelscope resolves in the provider REGISTRY as OpenAI-compatible", () => {
assert.ok("modelscope" in REGISTRY, "modelscope missing from REGISTRY");
const entry = REGISTRY.modelscope;
assert.equal(entry.format, "openai");
assert.equal(entry.executor, "default");
assert.equal(entry.authType, "apikey");
assert.equal(entry.authHeader, "bearer");
assert.equal(entry, modelscopeProvider);
});
test("registry resolution: modelscope uses passthrough models with an empty static seed list", () => {
assert.equal(modelscopeProvider.passthroughModels, true);
assert.deepEqual(modelscopeProvider.models, []);
assert.equal(
modelscopeProvider.modelsUrl,
"https://api-inference.modelscope.cn/v1/models",
"modelsUrl must point at the verified .cn domain"
);
});
test("baseUrl guard: modelscope targets the verified api-inference.modelscope.cn domain (not .ai)", () => {
assert.equal(
modelscopeProvider.baseUrl,
"https://api-inference.modelscope.cn/v1/chat/completions"
);
assert.ok(
modelscopeProvider.baseUrl.includes("api-inference.modelscope.cn"),
`baseUrl must use the verified .cn domain, got: ${modelscopeProvider.baseUrl}`
);
assert.ok(
!modelscopeProvider.baseUrl.includes("modelscope.ai"),
"baseUrl must not regress to the upstream PR's unverified .ai domain"
);
});

View File

@@ -2,9 +2,6 @@ import test from "node:test";
import assert from "node:assert/strict";
const { handleModeration } = await import("../../open-sse/handlers/moderations.ts");
const { MODERATION_PROVIDERS, getModerationProvider, parseModerationModel } = await import(
"../../open-sse/config/moderationRegistry.ts"
);
const originalFetch = globalThis.fetch;
@@ -12,42 +9,6 @@ test.afterEach(() => {
globalThis.fetch = originalFetch;
});
test("MODERATION_PROVIDERS registers mistral with the Mistral moderations base URL", () => {
const provider = getModerationProvider("mistral");
assert.ok(provider);
assert.equal(provider.baseUrl, "https://api.mistral.ai/v1/moderations");
assert.ok(provider.models.some((m: { id: string }) => m.id === "mistral-moderation-latest"));
assert.ok(MODERATION_PROVIDERS.mistral);
});
test("parseModerationModel routes mistral moderation models to the mistral provider", () => {
assert.deepEqual(parseModerationModel("mistral/mistral-moderation-latest"), {
provider: "mistral",
model: "mistral-moderation-latest",
});
assert.deepEqual(parseModerationModel("mistral-moderation-latest"), {
provider: "mistral",
model: "mistral-moderation-latest",
});
});
test("handleModeration proxies mistral moderation requests to the mistral endpoint", async () => {
let captured: any;
globalThis.fetch = async (url: any, options: any = {}) => {
captured = { url: String(url), headers: options.headers };
return Response.json({ id: "modr-mistral", results: [{ flagged: false }] });
};
const response = await handleModeration({
body: { model: "mistral/mistral-moderation-latest", input: "check this" },
credentials: { apiKey: "sk-mistral" },
});
assert.equal(captured.url, "https://api.mistral.ai/v1/moderations");
assert.equal(captured.headers.Authorization, "Bearer sk-mistral");
assert.equal(response.status, 200);
});
test("handleModeration requires input", async () => {
const response = await handleModeration({
body: { model: "openai/omni-moderation-latest" },

View File

@@ -1,33 +0,0 @@
import { test } from "node:test";
import assert from "node:assert/strict";
import { readFileSync } from "node:fs";
import { fileURLToPath } from "node:url";
import { dirname, join } from "node:path";
// Split-guard for the muse-spark-web Meta AI response-parser extraction.
// The pure SSE/JSON parsing + content/reasoning/error extraction lives in
// muse-spark-web/response-parser.ts (no host state/fetch/auth). Host imports it back.
const HERE = dirname(fileURLToPath(import.meta.url));
const EXE = join(HERE, "../../open-sse/executors");
const HOST = join(EXE, "muse-spark-web.ts");
const LEAF = join(EXE, "muse-spark-web/response-parser.ts");
test("leaf hosts the parser and does not import the host", () => {
const src = readFileSync(LEAF, "utf8");
for (const sym of ["parseMetaAiResponseText", "parseMetaSseFrames", "isRecord"]) {
assert.match(src, new RegExp(`export function ${sym}\\b`));
}
assert.doesNotMatch(src, /from "\.\.\/muse-spark-web\.ts"/);
});
test("host imports the parser back from the leaf", () => {
const host = readFileSync(HOST, "utf8");
assert.match(host, /from "\.\/muse-spark-web\/response-parser\.ts"/);
});
test("parseMetaAiResponseText tolerates empty input", async () => {
const { parseMetaAiResponseText } =
await import("../../open-sse/executors/muse-spark-web/response-parser.ts");
const out = parseMetaAiResponseText("", false);
assert.equal(typeof out, "object");
});

View File

@@ -37,15 +37,6 @@ test("next config exposes standalone build settings and canonical rewrites", asy
"fumadocs-ui",
"fumadocs-core",
]);
// #6062: `ws` and its native masking helpers must stay external so the
// copilot-m365-web executor keeps a working WebSocket masking path at runtime
// (bundling ws breaks `bufferutil` → `TypeError: b.mask is not a function`).
for (const pkg of ["ws", "bufferutil", "utf-8-validate"]) {
assert.ok(
nextConfig.serverExternalPackages.includes(pkg),
`expected serverExternalPackages to externalize "${pkg}" (#6062)`
);
}
assert.equal(headers[0].source, "/:path*");
assert.match(securityHeaders["Content-Security-Policy"], /default-src 'self'/);
assert.match(securityHeaders["Content-Security-Policy"], /frame-ancestors 'none'/);

View File

@@ -1,35 +0,0 @@
import test from "node:test";
import assert from "node:assert/strict";
const { APIKEY_PROVIDERS } = await import("../../src/shared/constants/providers.ts");
const { REGISTRY: providerRegistry } = await import("../../open-sse/config/providerRegistry.ts");
test("Nube.sh is registered as an API-key provider with the canonical identity", () => {
const nube = APIKEY_PROVIDERS.nube;
assert.ok(nube, "APIKEY_PROVIDERS.nube must be defined");
assert.equal(nube.id, "nube");
assert.equal(nube.alias, "nube");
assert.equal(nube.name, "Nube.sh");
assert.equal(nube.website, "https://nube.sh");
assert.equal(typeof nube.textIcon, "string");
});
test("Nube.sh registry entry uses OpenAI format with bearer apikey auth", () => {
const entry = providerRegistry.nube;
assert.ok(entry, "providerRegistry.nube must be defined");
assert.equal(entry.id, "nube");
assert.equal(entry.format, "openai");
assert.equal(entry.executor, "default");
assert.equal(entry.authType, "apikey");
assert.equal(entry.authHeader, "bearer");
assert.equal(entry.baseUrl, "https://ai.nube.sh/api/v1/chat/completions");
});
test("Nube.sh ships no fabricated model IDs and relies on passthrough enumeration", () => {
const entry = providerRegistry.nube;
// The live catalog is only reachable with a valid key (401 unauthenticated), so we do
// NOT hardcode unverifiable model IDs — models pass through and are enumerated live.
assert.equal(entry.passthroughModels, true);
assert.deepEqual(entry.models, []);
assert.equal(entry.modelsUrl, "https://ai.nube.sh/api/v1/models");
});

View File

@@ -1,314 +0,0 @@
import test from "node:test";
import assert from "node:assert/strict";
// Ported from upstream 9router#1195: NVIDIA NIM image generation (FLUX models).
// NVIDIA already exists as a CHAT provider (integrate.api.nvidia.com,
// OpenAI-compatible) — image generation is a distinct host (ai.api.nvidia.com)
// with a native NIM body shape, so it gets its own `nvidia-nim` format/handler
// (handleNvidiaNimImageGeneration) rather than reusing the OpenAI image path.
import { handleImageGeneration } from "../../open-sse/handlers/imageGeneration.ts";
import { getImageProvider } from "../../open-sse/config/imageRegistry.ts";
import {
buildNvidiaNimRequestBody,
normalizeNvidiaNimImages,
} from "../../open-sse/handlers/imageGeneration/providers/nvidiaNim.ts";
test("nvidia is registered as an nvidia-nim image provider with the 4 FLUX models", () => {
const cfg = getImageProvider("nvidia");
assert.ok(cfg, "expected an IMAGE_PROVIDERS entry for nvidia");
assert.equal(cfg.format, "nvidia-nim");
assert.equal(cfg.baseUrl, "https://ai.api.nvidia.com/v1/genai");
assert.equal(cfg.authType, "apikey");
assert.equal(cfg.authHeader, "bearer");
const ids = cfg.models.map((m) => m.id);
assert.deepEqual(ids, [
"black-forest-labs/flux.1-dev",
"black-forest-labs/flux.1-schnell",
"black-forest-labs/flux.1-kontext-dev",
"black-forest-labs/flux.2-klein-4b",
]);
});
test("handleImageGeneration(nvidia/flux.1-schnell): URL construction + minimal body shaping", async () => {
const originalFetch = globalThis.fetch;
let capturedUrl;
let capturedOptions;
globalThis.fetch = async (url, options) => {
capturedUrl = String(url);
capturedOptions = options;
return new Response(
JSON.stringify({ artifacts: [{ base64: "base64nvidia", finishReason: "SUCCESS" }] }),
{ status: 200, headers: { "content-type": "application/json" } }
);
};
try {
const result = await handleImageGeneration({
body: {
model: "nvidia/black-forest-labs/flux.1-schnell",
prompt: "A neon city",
width: 1344,
height: 1024,
seed: 7,
steps: 4,
},
credentials: { apiKey: "nv-token" },
log: null,
});
assert.equal(result.success, true);
assert.equal(capturedUrl, "https://ai.api.nvidia.com/v1/genai/black-forest-labs/flux.1-schnell");
assert.equal(capturedOptions.method, "POST");
assert.equal(capturedOptions.headers.Authorization, "Bearer nv-token");
assert.equal(capturedOptions.headers.Accept, "application/json");
const requestBody = JSON.parse(capturedOptions.body);
assert.deepEqual(requestBody, {
prompt: "A neon city",
width: 1344,
height: 1024,
seed: 7,
steps: 4,
});
assert.equal(result.data.data[0].b64_json, "base64nvidia");
assert.equal(result.data.data[0].finish_reason, "SUCCESS");
} finally {
globalThis.fetch = originalFetch;
}
});
test("handleImageGeneration(nvidia/flux.2-klein-4b): sends edit input image as an array", async () => {
const originalFetch = globalThis.fetch;
globalThis.fetch = async () =>
new Response(JSON.stringify({ artifacts: [{ base64: "base64nvidiaedit" }] }), {
status: 200,
headers: { "content-type": "application/json" },
});
try {
const result = await handleImageGeneration({
body: {
model: "nvidia/black-forest-labs/flux.2-klein-4b",
prompt: "Make the frog wear tiny glasses",
image: "data:image/png;example_id,0",
width: 1024,
height: 1024,
seed: 0,
steps: 4,
},
credentials: { apiKey: "nv-token" },
log: null,
});
assert.equal(result.success, true);
assert.equal(result.data.data[0].b64_json, "base64nvidiaedit");
} finally {
globalThis.fetch = originalFetch;
}
});
test("buildNvidiaNimRequestBody(flux.2-klein-4b): image sent as an array, width/height passthrough", () => {
const req = buildNvidiaNimRequestBody("black-forest-labs/flux.2-klein-4b", {
prompt: "Make the frog wear tiny glasses",
image: "data:image/png;example_id,0",
width: 1024,
height: 1024,
seed: 0,
steps: 4,
});
assert.deepEqual(req, {
prompt: "Make the frog wear tiny glasses",
width: 1024,
height: 1024,
image: ["data:image/png;example_id,0"],
seed: 0,
steps: 4,
});
});
test("buildNvidiaNimRequestBody(flux.1-dev): omits input image in base mode", () => {
const req = buildNvidiaNimRequestBody("black-forest-labs/flux.1-dev", {
prompt: "A simple coffee shop interior",
mode: "base",
image: "data:image/png;example_id,0",
cfg_scale: 1.1,
width: 768,
height: 1344,
seed: 0,
steps: 50,
});
assert.deepEqual(req, {
prompt: "A simple coffee shop interior",
mode: "base",
width: 768,
height: 1344,
cfg_scale: 1.1,
seed: 0,
steps: 50,
});
});
test("buildNvidiaNimRequestBody(flux.1-dev): drops out-of-range dimensions and non-positive cfg_scale", () => {
const req = buildNvidiaNimRequestBody("black-forest-labs/flux.1-dev", {
prompt: "A simple coffee shop interior",
mode: "base",
image: "data:image/png;example_id,0",
cfg_scale: 0,
width: 1792, // out of the 768-1344 range
height: 1024,
seed: 0,
steps: 50,
});
assert.deepEqual(req, {
prompt: "A simple coffee shop interior",
mode: "base",
seed: 0,
steps: 50,
});
assert.ok(!("width" in req) && !("height" in req) && !("cfg_scale" in req));
});
test("buildNvidiaNimRequestBody(flux.1-dev): sends control image as a string for non-base modes", () => {
const req = buildNvidiaNimRequestBody("black-forest-labs/flux.1-dev", {
prompt: "A simple coffee shop interior",
mode: "depth",
image: "data:image/png;example_id,0",
cfg_scale: 3.5,
width: 1024,
height: 1024,
seed: 0,
steps: 50,
});
assert.deepEqual(req, {
prompt: "A simple coffee shop interior",
width: 1024,
height: 1024,
mode: "depth",
image: "data:image/png;example_id,0",
cfg_scale: 3.5,
seed: 0,
steps: 50,
});
});
test("buildNvidiaNimRequestBody(flux.1-kontext-dev): uses aspect_ratio instead of width/height", () => {
const req = buildNvidiaNimRequestBody("black-forest-labs/flux.1-kontext-dev", {
prompt: "Now the mouse is holding pizza instead",
image: "data:image/png;example_id,0",
aspect_ratio: "match_input_image",
width: 1024,
height: 1024,
steps: 30,
cfg_scale: 3.5,
seed: 0,
});
assert.deepEqual(req, {
prompt: "Now the mouse is holding pizza instead",
image: "data:image/png;example_id,0",
aspect_ratio: "match_input_image",
cfg_scale: 3.5,
seed: 0,
steps: 30,
});
});
test("handleImageGeneration(nvidia/flux.1-kontext-dev): requires an input image, does not fetch", async () => {
const originalFetch = globalThis.fetch;
let fetchCalled = false;
globalThis.fetch = async () => {
fetchCalled = true;
throw new Error("fetch should not be called without an input image");
};
try {
const result = await handleImageGeneration({
body: {
model: "nvidia/black-forest-labs/flux.1-kontext-dev",
prompt: "Now the mouse is holding pizza instead",
},
credentials: { apiKey: "nv-token" },
log: null,
});
assert.equal(result.success, false);
assert.equal(result.status, 400);
assert.match(result.error, /requires an input image/i);
assert.equal(fetchCalled, false);
} finally {
globalThis.fetch = originalFetch;
}
});
test("normalizeNvidiaNimImages: accepts artifacts[], images[], data[], and single-value shapes", () => {
assert.deepEqual(normalizeNvidiaNimImages({ artifacts: [{ base64: "a1" }] }).data, [
{ b64_json: "a1" },
]);
assert.deepEqual(normalizeNvidiaNimImages({ images: ["b1", "b2"] }).data, [
{ b64_json: "b1" },
{ b64_json: "b2" },
]);
assert.deepEqual(normalizeNvidiaNimImages({ data: [{ b64_json: "c1" }] }).data, [
{ b64_json: "c1" },
]);
assert.deepEqual(normalizeNvidiaNimImages({ image: "d1" }).data, [{ b64_json: "d1" }]);
assert.deepEqual(normalizeNvidiaNimImages({ result: { image: "e1" } }).data, [
{ b64_json: "e1" },
]);
// Already-OpenAI-shaped responses pass through untouched.
const passthrough = { created: 123, data: [{ b64_json: "f1" }] };
assert.deepEqual(normalizeNvidiaNimImages(passthrough), passthrough);
// Unrecognized shape -> empty data, never throws.
assert.deepEqual(normalizeNvidiaNimImages({ nonsense: true }).data, []);
});
test("handleImageGeneration(nvidia): upstream error body never leaks a stack trace", async () => {
const originalFetch = globalThis.fetch;
globalThis.fetch = async () => {
throw new Error(`boom at /home/user/secret/path/imageGeneration.ts:123:45`);
};
try {
const result = await handleImageGeneration({
body: {
model: "nvidia/black-forest-labs/flux.1-schnell",
prompt: "test",
},
credentials: { apiKey: "nv-token" },
log: null,
});
assert.equal(result.success, false);
assert.equal(result.status, 502);
assert.ok(!result.error.includes("/home/"), "error must not leak an absolute path/stack");
assert.ok(!result.error.includes(":123:45"), "error must not leak a stack trace location");
} finally {
globalThis.fetch = originalFetch;
}
});
test("handleImageGeneration(nvidia): upstream non-2xx response is surfaced with its status", async () => {
const originalFetch = globalThis.fetch;
globalThis.fetch = async () =>
new Response("rate limited", { status: 429, headers: { "content-type": "text/plain" } });
try {
const result = await handleImageGeneration({
body: {
model: "nvidia/black-forest-labs/flux.1-schnell",
prompt: "test",
},
credentials: { apiKey: "nv-token" },
log: null,
});
assert.equal(result.success, false);
assert.equal(result.status, 429);
} finally {
globalThis.fetch = originalFetch;
}
});

View File

@@ -1,188 +0,0 @@
import test from "node:test";
import assert from "node:assert/strict";
const { POST, OPTIONS } = await import("../../src/app/api/v1/ocr/route.ts");
const { handleOcr } = await import("../../open-sse/handlers/ocr.ts");
const { OCR_PROVIDERS, getOcrProvider, parseOcrModel, getAllOcrModels } =
await import("../../open-sse/config/ocrRegistry.ts");
const { v1OcrSchema } = await import("../../src/shared/validation/schemas/apiV1.ts");
const originalFetch = globalThis.fetch;
test.afterEach(() => {
globalThis.fetch = originalFetch;
});
function ocrRequest(body: string) {
return new Request("http://localhost/v1/ocr", {
method: "POST",
headers: { "Content-Type": "application/json" },
body,
});
}
// ── Registry ───────────────────────────────────────────────────────────────
test("OCR_PROVIDERS registers mistral with the Mistral OCR base URL", () => {
assert.equal(OCR_PROVIDERS.mistral.baseUrl, "https://api.mistral.ai/v1/ocr");
const provider = getOcrProvider("mistral");
assert.ok(provider);
assert.equal(provider.authHeader, "bearer");
assert.ok(provider.models.some((m: { id: string }) => m.id === "mistral-ocr-latest"));
});
test("parseOcrModel routes bare and prefixed mistral models to the mistral provider", () => {
assert.deepEqual(parseOcrModel("mistral-ocr-latest"), {
provider: "mistral",
model: "mistral-ocr-latest",
});
assert.deepEqual(parseOcrModel("mistral/mistral-ocr-latest"), {
provider: "mistral",
model: "mistral-ocr-latest",
});
// Unknown model → no provider resolved
assert.deepEqual(parseOcrModel("mystery-model"), {
provider: null,
model: "mystery-model",
});
});
test("getAllOcrModels exposes the mistral OCR model with a provider prefix", () => {
const models = getAllOcrModels();
assert.ok(models.some((m: { id: string }) => m.id === "mistral/mistral-ocr-latest"));
});
// ── Schema (Zod, Rule #7) ────────────────────────────────────────────────────
test("v1OcrSchema rejects a body without a document", () => {
const result = v1OcrSchema.safeParse({ model: "mistral-ocr-latest" });
assert.equal(result.success, false);
});
test("v1OcrSchema accepts a document_url document object", () => {
const result = v1OcrSchema.safeParse({
model: "mistral-ocr-latest",
document: { type: "document_url", document_url: "https://example.com/a.pdf" },
});
assert.equal(result.success, true);
});
test("v1OcrSchema accepts an image_url document object", () => {
const result = v1OcrSchema.safeParse({
document: { type: "image_url", image_url: "https://example.com/a.png" },
});
assert.equal(result.success, true);
});
// ── Route (public /v1/ocr entry point) ───────────────────────────────────────
test("POST /v1/ocr returns 400 for invalid JSON without leaking a stack trace", async () => {
const response = await POST(ocrRequest("not json at all"));
const body = (await response.json()) as any;
assert.equal(response.status, 400);
assert.equal(body.error.message, "Invalid JSON body");
// Rule #12 — error responses must never leak stack traces.
assert.ok(!body.error.message.includes("at /"));
});
test("OPTIONS /v1/ocr answers the CORS preflight", async () => {
const response = await OPTIONS();
assert.equal(response.status, 200);
assert.match(response.headers.get("access-control-allow-methods") || "", /OPTIONS/);
});
// ── Handler ──────────────────────────────────────────────────────────────────
test("handleOcr requires a document", async () => {
const response = await handleOcr({
body: { model: "mistral-ocr-latest" },
credentials: { apiKey: "sk-test" },
});
const payload = (await response.json()) as any;
assert.equal(response.status, 400);
assert.equal(payload.error.message, "document is required");
});
test("handleOcr rejects unknown OCR models", async () => {
const response = await handleOcr({
body: { model: "mystery/ocr", document: { document_url: "x" } },
credentials: { apiKey: "sk-test" },
});
const payload = (await response.json()) as any;
assert.equal(response.status, 400);
assert.match(payload.error.message, /No OCR provider found/);
});
test("handleOcr requires credentials for the resolved provider", async () => {
const response = await handleOcr({
body: { document: { document_url: "x" } },
credentials: null,
});
const payload = (await response.json()) as any;
assert.equal(response.status, 401);
assert.equal(payload.error.message, "No credentials for OCR provider: mistral");
});
test("handleOcr proxies a successful request to the mistral OCR endpoint", async () => {
let captured: any;
globalThis.fetch = async (url: any, options: any = {}) => {
captured = {
url: String(url),
headers: options.headers,
body: JSON.parse(String(options.body || "{}")),
};
return Response.json({ pages: [{ index: 0, markdown: "hello" }] });
};
const response = await handleOcr({
body: { document: { type: "document_url", document_url: "https://example.com/a.pdf" } },
credentials: { apiKey: "sk-mistral" },
});
assert.equal(captured.url, "https://api.mistral.ai/v1/ocr");
assert.equal(captured.headers.Authorization, "Bearer sk-mistral");
// model defaults to mistral-ocr-latest and the document is forwarded upstream.
assert.equal(captured.body.model, "mistral-ocr-latest");
assert.deepEqual(captured.body.document, {
type: "document_url",
document_url: "https://example.com/a.pdf",
});
assert.equal(response.status, 200);
assert.deepEqual(await response.json(), { pages: [{ index: 0, markdown: "hello" }] });
});
test("handleOcr passes upstream error payloads through with the upstream status", async () => {
globalThis.fetch = async () =>
new Response('{"error":"bad request"}', {
status: 422,
headers: { "content-type": "application/json" },
});
const response = await handleOcr({
body: { model: "mistral/mistral-ocr-latest", document: { document_url: "x" } },
credentials: { apiKey: "sk-test" },
});
assert.equal(response.status, 422);
assert.equal(await response.text(), '{"error":"bad request"}');
});
test("handleOcr returns a sanitized 500 when the upstream request throws", async () => {
globalThis.fetch = async () => {
throw new Error("socket closed");
};
const response = await handleOcr({
body: { model: "mistral-ocr-latest", document: { document_url: "x" } },
credentials: { apiKey: "sk-test" },
});
const payload = (await response.json()) as any;
assert.equal(response.status, 500);
assert.match(payload.error.message, /OCR request failed: socket closed/);
assert.ok(!payload.error.message.includes("at /"));
});

View File

@@ -1,56 +0,0 @@
import { test } from "node:test";
import assert from "node:assert/strict";
import { readFileSync } from "node:fs";
import { fileURLToPath } from "node:url";
import { dirname, join } from "node:path";
// Split-guard for the openai-responses request-translator extraction.
// Pure shared primitives live in `openai-responses/helpers.ts`; the chat->Responses
// direction (`openaiToOpenAIResponsesRequest`) lives in `openai-responses/toResponses.ts`.
// The host keeps `openaiResponsesToOpenAIRequest` + both register() calls and re-exports
// the moved function so external importers (tests) keep working unchanged.
const HERE = dirname(fileURLToPath(import.meta.url));
const REQ = join(HERE, "../../open-sse/translator/request");
const HOST = join(REQ, "openai-responses.ts");
const HELPERS = join(REQ, "openai-responses/helpers.ts");
const TO_RESPONSES = join(REQ, "openai-responses/toResponses.ts");
test("helpers leaf is pure (no host import) and exports the shared primitives", () => {
const src = readFileSync(HELPERS, "utf8");
assert.doesNotMatch(src, /from "\.\.\/openai-responses\.ts"/);
for (const sym of ["toRecord", "toString", "clampCallId", "normalizeVerbosity"]) {
assert.match(src, new RegExp(`export (function|const) ${sym}\\b`));
}
});
test("toResponses leaf hosts the chat->Responses direction and imports helpers, not the host", () => {
const src = readFileSync(TO_RESPONSES, "utf8");
assert.match(src, /export function openaiToOpenAIResponsesRequest\(/);
assert.match(src, /from "\.\/helpers\.ts"/);
assert.doesNotMatch(src, /from "\.\.\/openai-responses\.ts"/);
});
test("host re-exports the moved function and keeps both register() directions", () => {
const src = readFileSync(HOST, "utf8");
assert.match(
src,
/export \{ openaiToOpenAIResponsesRequest \} from "\.\/openai-responses\/toResponses\.ts"/
);
assert.match(src, /export function openaiResponsesToOpenAIRequest\(/);
assert.match(src, /register\(FORMATS\.OPENAI_RESPONSES, FORMATS\.OPENAI,/);
assert.match(src, /register\(FORMATS\.OPENAI, FORMATS\.OPENAI_RESPONSES,/);
});
test("both directions are callable via the host module", async () => {
const mod = await import("../../open-sse/translator/request/openai-responses.ts");
assert.equal(typeof mod.openaiResponsesToOpenAIRequest, "function");
assert.equal(typeof mod.openaiToOpenAIResponsesRequest, "function");
// chat->Responses basic shape: wraps into { input: [...], stream: true }.
const out = mod.openaiToOpenAIResponsesRequest(
"gpt-4",
{ messages: [{ role: "user", content: "hi" }] },
true,
null
) as Record<string, unknown>;
assert.ok(Array.isArray(out.input));
});

View File

@@ -1,37 +1,14 @@
/**
* TDD regression for #5312 (FIX D / RC-D) and #5945.
* TDD regression for #5312 (FIX D / RC-D): openai-to-claude reconstructed a Claude
* `thinking` block from signature-less `reasoning_content` and stamped it with the
* fabricated DEFAULT_THINKING_CLAUDE_SIGNATURE. Anthropic validates signatures and
* rejects the fake one with 400 "Invalid signature in thinking block" — and
* claudeHelper's latest-assistant guard preserves the block verbatim, so the fake
* signature leaks upstream.
*
* #5312 (FIX D / RC-D): openai-to-claude reconstructed a Claude `thinking` block from
* signature-less `reasoning_content` and stamped it with the fabricated
* DEFAULT_THINKING_CLAUDE_SIGNATURE. Anthropic validates signatures and rejects the
* fake one with 400 "Invalid signature in thinking block" — and claudeHelper's
* latest-assistant guard preserves the block verbatim, so the fake signature leaks
* upstream.
*
* Fix (#5312): when a precursor thinking block IS required by Anthropic's schema
* (assistant turn has tool_use AND the outbound request has extended thinking
* enabled), emit a signature-less `redacted_thinking` placeholder (matching what
* prepareClaudeRequest produces downstream) instead of a fabricated-signature
* `thinking` block. A REAL part.signature must always be preserved verbatim — never
* overwritten with the default.
*
* #5945 (over-correction of #5312): the original #5312 fix injected the
* redacted_thinking placeholder UNCONDITIONALLY whenever ANY assistant history
* message carried non-empty `reasoning_content` — regardless of whether the current
* outbound request has thinking enabled, and regardless of whether that assistant
* turn even contains a `tool_use` block (the only case Anthropic's schema actually
* requires a preceding thinking/redacted_thinking block). This fabricated a content
* block the client never sent; reported by dev-cj: Claude Sonnet 5 via the "Pi"
* harness detected the extra block and refused the turn as prompt injection.
*
* Fix (#5945): gate the injection on BOTH (a) the assistant turn containing a
* tool_use block and (b) the outbound request having extended thinking enabled.
* Otherwise `reasoning_content` is dropped silently — it carries no useful signal
* for a plain-text replay turn, and the client never asked for it to appear.
*
* These two fixes are not in tension: #5312 legitimately fixed a real Anthropic 400
* for the case the redacted_thinking block IS required; #5945 narrows the trigger to
* exactly that case instead of firing for every reasoning_content-bearing message.
* Fix: emit a signature-less `redacted_thinking` placeholder (matching what
* prepareClaudeRequest produces downstream). A REAL part.signature must always be
* preserved verbatim — never overwritten with the default.
*/
import test from "node:test";
import assert from "node:assert/strict";
@@ -43,7 +20,7 @@ const { DEFAULT_THINKING_CLAUDE_SIGNATURE } = await import(
"../../open-sse/config/defaultThinkingSignature.ts"
);
test("#5945: reasoning_content on a plain-text assistant turn (no tool_use, thinking not requested) yields NO redacted_thinking/thinking block", () => {
test("#5312 RC-D: signature-less reasoning_content yields no fabricated-signature thinking block", () => {
const result = openaiToClaudeRequest(
"claude-opus-4-8",
{
@@ -51,7 +28,6 @@ test("#5945: reasoning_content on a plain-text assistant turn (no tool_use, thin
{ role: "user", content: "hello" },
{ role: "assistant", reasoning_content: "thinking about it", content: "hi there" },
],
// no body.thinking / body.reasoning_effort — thinking is NOT enabled for this request.
},
false
);
@@ -59,101 +35,24 @@ test("#5945: reasoning_content on a plain-text assistant turn (no tool_use, thin
const assistant = result.messages.find((m) => m.role === "assistant");
assert.ok(assistant, "expected assistant message");
// No fabricated block at all — reasoning_content must be dropped silently, exactly
// like OPENAI_INCOMPATIBLE_ECHO_FIELDS drops other echo-only fields.
assert.equal(
assistant.content.find((b) => b && (b.type === "thinking" || b.type === "redacted_thinking")),
undefined,
"must NOT fabricate a thinking/redacted_thinking block the client never sent"
);
assert.deepEqual(
assistant.content.map((b) => b.type),
["text"],
"assistant content should contain only the real text block"
);
});
test("#5945: reasoning_content + tool_use, but thinking NOT enabled on the outbound request, yields NO injection", () => {
const result = openaiToClaudeRequest(
"claude-opus-4-8",
{
messages: [
{ role: "user", content: "hello" },
{
role: "assistant",
reasoning_content: "thinking about it",
tool_calls: [
{
id: "call_1",
type: "function",
function: { name: "get_weather", arguments: "{}" },
},
],
},
],
// no body.thinking / body.reasoning_effort — thinking is NOT enabled.
},
false
);
const assistant = result.messages.find((m) => m.role === "assistant");
assert.ok(assistant, "expected assistant message");
assert.equal(
assistant.content.find((b) => b && (b.type === "thinking" || b.type === "redacted_thinking")),
undefined,
"must NOT inject a precursor thinking block when the request itself has thinking disabled"
);
assert.ok(
assistant.content.some((b) => b.type === "tool_use"),
"tool_use block must still be present"
);
});
test("#5312: reasoning_content + tool_use + thinking ENABLED still gets a signature-less redacted_thinking precursor (the legitimate #5312 400-fix case)", () => {
const result = openaiToClaudeRequest(
"claude-opus-4-8",
{
thinking: { type: "enabled", budget_tokens: 4096 },
messages: [
{ role: "user", content: "hello" },
{
role: "assistant",
reasoning_content: "thinking about it",
tool_calls: [
{
id: "call_1",
type: "function",
function: { name: "get_weather", arguments: "{}" },
},
],
},
],
},
false
);
const assistant = result.messages.find((m) => m.role === "assistant");
assert.ok(assistant, "expected assistant message");
// No block may carry the fabricated default signature on a `thinking`-typed block.
// No block may carry the fabricated default signature.
const fake = assistant.content.find(
(b) => b && b.type === "thinking" && b.signature === DEFAULT_THINKING_CLAUDE_SIGNATURE
(b) => b && b.signature === DEFAULT_THINKING_CLAUDE_SIGNATURE
);
assert.equal(fake, undefined, "must NOT emit a `thinking` block with the fabricated signature");
assert.equal(fake, undefined, "must NOT emit a thinking block with the fabricated signature");
// It becomes a redacted_thinking placeholder (Anthropic accepts without sig check),
// and it must precede the tool_use block.
assert.equal(assistant.content[0].type, "redacted_thinking", "must be the precursor block");
assert.equal(assistant.content[0].data, DEFAULT_THINKING_CLAUDE_SIGNATURE);
// No `thinking`-typed block at all from signature-less reasoning_content.
assert.equal(
assistant.content[0].signature,
assistant.content.find((b) => b && b.type === "thinking"),
undefined,
"redacted_thinking must not carry a signature"
);
assert.ok(
assistant.content.some((b) => b.type === "tool_use"),
"tool_use block must still be present"
"signature-less reasoning_content must not produce a `thinking` block"
);
// It becomes a redacted_thinking placeholder (Anthropic accepts without sig check).
const redacted = assistant.content.find((b) => b && b.type === "redacted_thinking");
assert.ok(redacted, "expected a redacted_thinking placeholder");
assert.equal(redacted.data, DEFAULT_THINKING_CLAUDE_SIGNATURE);
assert.equal(redacted.signature, undefined, "redacted_thinking must not carry a signature");
});
test("#5312 RC-D: a REAL thinking signature is preserved verbatim", () => {

View File

@@ -1,38 +0,0 @@
import { test } from "node:test";
import assert from "node:assert/strict";
import { readFileSync } from "node:fs";
import { fileURLToPath } from "node:url";
import { dirname, join } from "node:path";
// Split-guard for the openai-to-claude thinking-budget extraction.
// `fitThinkingToMaxTokens` (+ its private helpers safeCapMaxOutputTokens / MIN_*)
// live in the pure leaf `openai-to-claude/thinkingBudget.ts`; the host re-exports
// the public symbol so external importers (tests) keep working unchanged.
const HERE = dirname(fileURLToPath(import.meta.url));
const REQ = join(HERE, "../../open-sse/translator/request");
const HOST = join(REQ, "openai-to-claude.ts");
const LEAF = join(REQ, "openai-to-claude/thinkingBudget.ts");
test("leaf hosts fitThinkingToMaxTokens and does not import the host", () => {
const leaf = readFileSync(LEAF, "utf8");
assert.match(leaf, /export function fitThinkingToMaxTokens\(/);
assert.match(leaf, /function safeCapMaxOutputTokens\(/);
assert.doesNotMatch(leaf, /from "\.\.\/openai-to-claude\.ts"/);
});
test("host re-exports fitThinkingToMaxTokens from the leaf", () => {
const host = readFileSync(HOST, "utf8");
assert.match(
host,
/export \{ fitThinkingToMaxTokens \} from "\.\/openai-to-claude\/thinkingBudget\.ts"/
);
});
test("re-exported fitThinkingToMaxTokens is callable via the host module and behaves", async () => {
const mod = await import("../../open-sse/translator/request/openai-to-claude.ts");
assert.equal(typeof mod.fitThinkingToMaxTokens, "function");
// No budgeted thinking → max_tokens floored to >= 1, thinking passed through.
const out = mod.fitThinkingToMaxTokens("gpt-4o-mini", 0, undefined);
assert.equal(out.thinking, undefined);
assert.ok(out.maxTokens >= 1);
});

View File

@@ -1,44 +0,0 @@
import { test } from "node:test";
import assert from "node:assert/strict";
import { readFileSync } from "node:fs";
import { fileURLToPath } from "node:url";
import { dirname, join } from "node:path";
// Split-guard for the openai-to-kiro message-helper extraction.
// The pure tool/message helpers (parseToolInput / normalizeKiroToolSchema /
// serializeToolResultContent) live in the leaf `openai-to-kiro/messageHelpers.ts`;
// the host imports them back for convertMessages. They were module-private, so the
// public export set is unchanged (no re-export needed).
const HERE = dirname(fileURLToPath(import.meta.url));
const REQ = join(HERE, "../../open-sse/translator/request");
const HOST = join(REQ, "openai-to-kiro.ts");
const LEAF = join(REQ, "openai-to-kiro/messageHelpers.ts");
test("leaf hosts the pure helpers and does not import the host", () => {
const src = readFileSync(LEAF, "utf8");
for (const sym of ["parseToolInput", "normalizeKiroToolSchema", "serializeToolResultContent"]) {
assert.match(src, new RegExp(`export function ${sym}\\b`));
}
assert.doesNotMatch(src, /from "\.\.\/openai-to-kiro\.ts"/);
});
test("host imports the helpers back from the leaf", () => {
const src = readFileSync(HOST, "utf8");
assert.match(src, /from "\.\/openai-to-kiro\/messageHelpers\.ts"/);
// buildKiroPayload stays exported on the host module.
assert.match(src, /export function buildKiroPayload\(/);
});
test("normalizeKiroToolSchema strips empty required arrays and additionalProperties", async () => {
const { normalizeKiroToolSchema } =
await import("../../open-sse/translator/request/openai-to-kiro/messageHelpers.ts");
const out = normalizeKiroToolSchema({
type: "object",
required: [],
additionalProperties: false,
properties: { a: { type: "string" } },
});
assert.equal("required" in out, false);
assert.equal("additionalProperties" in out, false);
assert.deepEqual(out.properties, { a: { type: "string" } });
});

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