/** * Engine selection, and the promise that an unsupported recency window is * refused rather than dropped. */ import assert from "node:assert/strict"; import { test } from "node:test"; import { ENGINE_ENV_VAR, DEFAULT_ENGINE, resolveEngine } from "../src/engine-target.ts"; import { enginesSupportingRecency, parseEngineId } from "../src/engines.ts"; import { selectEngine } from "../src/search.ts"; const ok = (r: ReturnType) => { assert.equal(r.kind, "ok"); if (r.kind !== "ok") throw new Error("unreachable"); return r; }; test("nothing configured means the built-in default", () => { const r = ok(resolveEngine(null, {}, null)); assert.equal(r.id, DEFAULT_ENGINE); assert.equal(r.source, "default"); }); test("precedence is parameter, then env, then stored", () => { assert.equal(ok(resolveEngine(null, {}, "bing")).id, "bing"); assert.equal(ok(resolveEngine(null, { [ENGINE_ENV_VAR]: "brave" }, "bing")).id, "brave"); // The parameter beating the env var is the deliberate difference from the CDP // target: it is what lets the agent fall back when an engine is blocked. const r = ok(resolveEngine("duckduckgo", { [ENGINE_ENV_VAR]: "brave" }, "bing")); assert.equal(r.id, "duckduckgo"); assert.equal(r.source, "parameter"); }); test("aliases resolve, including the short ones a human would type", () => { for (const [raw, expected] of [ ["ddg", "duckduckgo"], ["duck", "duckduckgo"], ["DuckDuckGo", "duckduckgo"], [" bing ", "bing"], ["g", "google"], ["BRAVE", "brave"], ] as const) { assert.equal(parseEngineId(raw), expected, raw); } }); test("an unknown name is reported, never quietly skipped for the next source", () => { // A typo in the env var must not silently search Google instead. const r = resolveEngine(null, { [ENGINE_ENV_VAR]: "gooogle" }, "bing"); assert.equal(r.kind, "invalid"); if (r.kind !== "invalid") throw new Error("unreachable"); assert.equal(r.source, "env"); assert.equal(r.raw, "gooogle"); }); test("blank values fall through rather than counting as a choice", () => { assert.equal(ok(resolveEngine(" ", { [ENGINE_ENV_VAR]: " " }, "bing")).id, "bing"); }); test("an unsupported recency window is refused, and names engines that support it", async () => { // Bing has no year window and Brave has no time filter; both must say so // rather than returning unfiltered results that look filtered. for (const engine of ["bing", "brave"] as const) { const error = await selectEngine({ query: "q", numResults: 5, recency: "year", engine }).then( () => null, (e: Error) => e, ); assert.ok(error, `${engine} should have refused`); assert.equal(error.name, "RecencyUnsupportedError", engine); for (const alt of enginesSupportingRecency("year")) assert.match(error.message, new RegExp(alt), engine); } }); test("windows an engine does support are accepted", async () => { for (const [engine, recency] of [ ["google", "year"], ["duckduckgo", "year"], ["bing", "month"], ] as const) { const chosen = await selectEngine({ query: "q", numResults: 5, recency, engine }); assert.equal(chosen.engine.id, engine); } }); test("brave with no recency is fine — the refusal is about the window, not the engine", async () => { const chosen = await selectEngine({ query: "q", numResults: 5, engine: "brave" }); assert.equal(chosen.engine.id, "brave"); });