mirror of
https://github.com/diegosouzapw/OmniRoute.git
synced 2026-09-14 02:42:24 +03:00
Landed with the design call resolved per the owner's pick — **option 1**: the synced store is now endpoint-agnostic (persistDiscoveredModels and managedModelImport no longer drop non-chat models at write time), and chat selectability moved to read time (auto-pool expansion in autoStrategy applies filterChatSelectableModels; the models-route projection already had its chatOnly filter). Your discovery test now passes end-to-end (3/3): /api/show capabilities persist per connection and image/embedding requests route through the advertising host. Reconciliation notes: conflicted areas merged onto the current tip (adobe discovery import, requestedModel preflight signature, resolvedProvider fast-path coexists with the synced-route override — explicit resolution wins); carried base-red drains (#10055 memoization, #11071 test variants) dropped as already-landed; the managed-model-import exclusion test was propagated to the new contract (image/video models persist; the read filter still hides them from chat pickers — pinned by a new assertion). Full battery: 205/206 focused (the one red is a confirmed periodic-timer timing flake on the loaded devbox — 20/20 isolated), autoCombo vitest 30/30, combo suites 46/46, gates + typecheck clean. Thank you @yourspraveen — the capability probe + routing design was right; it just needed the store contract opened up. Fixes #11087.
74 lines
2.3 KiB
TypeScript
74 lines
2.3 KiB
TypeScript
import test from "node:test";
|
|
import assert from "node:assert/strict";
|
|
import { mkdtempSync } from "node:fs";
|
|
import { tmpdir } from "node:os";
|
|
import { join } from "node:path";
|
|
|
|
process.env.DATA_DIR = mkdtempSync(join(tmpdir(), "omniroute-search-named-errors-"));
|
|
|
|
const { handleSearch } = await import("../../open-sse/handlers/search.ts");
|
|
const { formatSearchProviderFailure } = await import(
|
|
"../../open-sse/handlers/search/providerFailure.ts"
|
|
);
|
|
|
|
test("formatSearchProviderFailure names the provider and sanitized Node cause", () => {
|
|
const err = new TypeError("fetch failed");
|
|
(err as Error & { cause?: { code: string; address: string } }).cause = {
|
|
code: "ENETUNREACH",
|
|
address: "203.0.113.10",
|
|
};
|
|
|
|
const result = formatSearchProviderFailure("serper-search", err, false);
|
|
|
|
assert.equal(result.success, false);
|
|
assert.equal(result.status, 502);
|
|
assert.equal(
|
|
result.error,
|
|
"Search provider serper-search error: fetch failed (cause: ENETUNREACH)"
|
|
);
|
|
assert.equal(result.error.includes("203.0.113"), false);
|
|
});
|
|
|
|
test("formatSearchProviderFailure omits non-Node cause codes", () => {
|
|
const err = new TypeError("fetch failed");
|
|
(err as Error & { cause?: { code: string } }).cause = { code: "not-a-node-code" };
|
|
|
|
const result = formatSearchProviderFailure("brave-search", err, false);
|
|
|
|
assert.equal(result.status, 502);
|
|
assert.equal(result.error, "Search provider brave-search error: fetch failed");
|
|
});
|
|
|
|
test("handleSearch names the provider and sanitized cause on fetch failed 502", async () => {
|
|
const originalFetch = globalThis.fetch;
|
|
globalThis.fetch = async () => {
|
|
const err = new TypeError("fetch failed");
|
|
(err as Error & { cause?: { code: string; address: string } }).cause = {
|
|
code: "ENETUNREACH",
|
|
address: "203.0.113.10",
|
|
};
|
|
throw err;
|
|
};
|
|
|
|
try {
|
|
const result = await handleSearch({
|
|
query: "named provider 502",
|
|
provider: "serper-search",
|
|
maxResults: 5,
|
|
searchType: "web",
|
|
credentials: { apiKey: "test-key" },
|
|
log: null,
|
|
});
|
|
|
|
assert.equal(result.success, false);
|
|
assert.equal(result.status, 502);
|
|
assert.equal(
|
|
result.error,
|
|
"Search provider serper-search error: fetch failed (cause: ENETUNREACH)"
|
|
);
|
|
assert.equal(String(result.error).includes("203.0.113"), false);
|
|
} finally {
|
|
globalThis.fetch = originalFetch;
|
|
}
|
|
});
|