import test from "node:test"; import assert from "node:assert/strict"; // #4481 layer 2 — CCR-style `Router.webSearch`. When a request carries a NATIVE // web-search server tool (`web_search`, `web_search_preview`, or Anthropic's versioned // `web_search_20250305`) and an operator configured `webSearchRouteModel`, route the // whole request to that model instead of the default — so a provider that doesn't // implement the server tool (e.g. MiniMax) isn't asked to run a tool it 400s on. // Pure helpers, no DB. import { readFileSync } from "node:fs"; import { fileURLToPath } from "node:url"; import { dirname, join } from "node:path"; import { hasNativeWebSearchTool, resolveWebSearchRouteOverride, } from "../../open-sse/services/webSearchRouting.ts"; const REPO_ROOT = join(dirname(fileURLToPath(import.meta.url)), "..", ".."); // ── Wiring source-guard (RED on base: chat.ts doesn't call the router yet) ─ test("chat.ts wires the web-search router at the request entrypoint", () => { const chat = readFileSync(join(REPO_ROOT, "src/sse/handlers/chat.ts"), "utf8"); assert.match(chat, /from "@omniroute\/open-sse\/services\/webSearchRouting\.ts"/); assert.match(chat, /hasNativeWebSearchTool\(body\)/); assert.match(chat, /resolveWebSearchRouteOverride\(/); }); test("webSearchRouteModel is registered in the settings Zod schema", () => { const schema = readFileSync(join(REPO_ROOT, "src/shared/validation/settingsSchemas.ts"), "utf8"); assert.match(schema, /webSearchRouteModel:\s*z\.string\(\)/); }); test("the Routing settings tab exposes a webSearchRouteModel field", () => { const tab = readFileSync( join(REPO_ROOT, "src/app/(dashboard)/dashboard/settings/components/RoutingTab.tsx"), "utf8" ); assert.match(tab, /settings\.webSearchRouteModel/); assert.match(tab, /updateSetting\(\{ webSearchRouteModel:/); assert.match(tab, /webSearchRouteTitle/); }); test("en.json defines the web-search-routing UI strings", () => { const en = JSON.parse(readFileSync(join(REPO_ROOT, "src/i18n/messages/en.json"), "utf8")); const s = en.settings || {}; assert.equal(typeof s.webSearchRouteTitle, "string"); assert.equal(typeof s.webSearchRouteDesc, "string"); assert.equal(typeof s.webSearchRoutePlaceholder, "string"); }); // ── hasNativeWebSearchTool ─────────────────────────────────────────────── test("detects the plain and preview native web-search tool types", () => { assert.equal(hasNativeWebSearchTool({ tools: [{ type: "web_search" }] }), true); assert.equal(hasNativeWebSearchTool({ tools: [{ type: "web_search_preview" }] }), true); }); test("detects Anthropic's versioned web_search_20250305 (and future dated names)", () => { assert.equal( hasNativeWebSearchTool({ tools: [{ type: "web_search_20250305", name: "web_search" }] }), true ); assert.equal(hasNativeWebSearchTool({ tools: [{ type: "web_search_20251201" }] }), true); }); test("detects a native web-search tool anywhere in a mixed tools array", () => { assert.equal( hasNativeWebSearchTool({ tools: [{ type: "function", function: { name: "x" } }, { type: "web_search_20250305" }], }), true ); }); test("ignores a custom FUNCTION tool merely named web_search (has a function field)", () => { assert.equal( hasNativeWebSearchTool({ tools: [{ type: "function", function: { name: "web_search", parameters: {} } }], }), false ); // A bare web_search type WITH a function field is also not the native server tool. assert.equal( hasNativeWebSearchTool({ tools: [{ type: "web_search", function: { name: "x" } }] }), false ); }); test("returns false for no tools / non-web-search tools / malformed input", () => { assert.equal(hasNativeWebSearchTool({ tools: [] }), false); assert.equal(hasNativeWebSearchTool({ tools: [{ type: "code_interpreter" }] }), false); assert.equal(hasNativeWebSearchTool({}), false); assert.equal(hasNativeWebSearchTool({ tools: "nope" }), false); assert.equal(hasNativeWebSearchTool(null), false); assert.equal(hasNativeWebSearchTool(undefined), false); }); // ── resolveWebSearchRouteOverride ──────────────────────────────────────── const bodyWithSearch = { tools: [{ type: "web_search_20250305", name: "web_search" }] }; test("routes to the configured model when a native web-search tool is present", () => { const r = resolveWebSearchRouteOverride("minimax,MiniMax-M3", bodyWithSearch, { webSearchRouteModel: "openrouter,anthropic/claude-3.5-sonnet", }); assert.deepEqual(r, { wasRouted: true, model: "openrouter,anthropic/claude-3.5-sonnet" }); }); test("does NOT route when the request has no native web-search tool", () => { const r = resolveWebSearchRouteOverride("minimax,MiniMax-M3", { tools: [{ type: "function" }] }, { webSearchRouteModel: "openrouter,anthropic/claude-3.5-sonnet", }); assert.deepEqual(r, { wasRouted: false, model: "minimax,MiniMax-M3" }); }); test("does NOT route when no route model is configured (or it is blank)", () => { assert.deepEqual(resolveWebSearchRouteOverride("minimax,MiniMax-M3", bodyWithSearch, {}), { wasRouted: false, model: "minimax,MiniMax-M3", }); assert.deepEqual( resolveWebSearchRouteOverride("minimax,MiniMax-M3", bodyWithSearch, { webSearchRouteModel: " ", }), { wasRouted: false, model: "minimax,MiniMax-M3" } ); }); test("does NOT route (no-op) when the configured model equals the current model", () => { const r = resolveWebSearchRouteOverride("openrouter,claude", bodyWithSearch, { webSearchRouteModel: " openrouter,claude ", }); assert.deepEqual(r, { wasRouted: false, model: "openrouter,claude" }); }); test("trims the configured route model", () => { const r = resolveWebSearchRouteOverride("minimax,M3", bodyWithSearch, { webSearchRouteModel: " anthropic/claude-opus-4-8 ", }); assert.deepEqual(r, { wasRouted: true, model: "anthropic/claude-opus-4-8" }); }); test("ignores a non-string route config", () => { const r = resolveWebSearchRouteOverride("minimax,M3", bodyWithSearch, { webSearchRouteModel: 123 as unknown as string, }); assert.deepEqual(r, { wasRouted: false, model: "minimax,M3" }); });