Files
OmniRoute/tests/unit/agentrouter-models-discovery-7016.test.ts
Praveen K Palaniswamy 65e81158ab fix(ollama): route models by advertised capability (#11088)
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.
2026-08-23 11:45:01 -03:00

72 lines
3.3 KiB
TypeScript

import test from "node:test";
import assert from "node:assert/strict";
import { PROVIDER_MODELS_CONFIG } from "../../src/app/api/providers/[id]/models/discovery/providerModelsConfig.ts";
import { CLAUDE_CODE_COMPATIBLE_USER_AGENT } from "../../open-sse/services/claudeCodeCompatible.ts";
// Regression guard for #7016 — AgentRouter's "Import from /models" must hit the
// live /v1/models endpoint. Previously the provider had no PROVIDER_MODELS_CONFIG
// entry, so model discovery fell through to the local catalog and import reported
// "API unavailable — using local catalog". The live request must also carry the
// Claude Code wire image (the same one the chat path uses) or the gateway WAF
// rejects it; AgentRouter keeps its own x-api-key auth (#6056).
test("agentrouter has a live /v1/models discovery config", () => {
const cfg = PROVIDER_MODELS_CONFIG.agentrouter;
assert.ok(cfg, "expected an agentrouter entry in PROVIDER_MODELS_CONFIG");
assert.equal(cfg.method, "GET");
assert.equal(cfg.url, "https://agentrouter.org/v1/models");
assert.equal(typeof cfg.buildHeaders, "function");
assert.equal(typeof cfg.parseResponse, "function");
});
test("agentrouter discovery headers carry the Claude Code wire image + x-api-key", () => {
const cfg = PROVIDER_MODELS_CONFIG.agentrouter;
const headers = cfg.buildHeaders!("sk-agentrouter");
// CC wire-image markers (mirrors the chat path — see agentrouter-cc-wire-image.test.ts).
assert.equal(headers["User-Agent"], CLAUDE_CODE_COMPATIBLE_USER_AGENT);
assert.equal(headers["x-app"], "cli");
assert.equal(headers["anthropic-dangerous-direct-browser-access"], "true");
assert.ok(headers["anthropic-beta"], "expected the CC anthropic-beta header");
assert.ok(headers["X-Stainless-Package-Version"], "expected CC X-Stainless anchors");
// CRUX: AgentRouter keeps its OWN x-api-key auth (NOT the CC Bearer).
assert.equal(headers["x-api-key"], "sk-agentrouter");
assert.equal(headers["Authorization"], undefined);
});
test("agentrouter discovery parseResponse maps an OpenAI-style model list", () => {
const cfg = PROVIDER_MODELS_CONFIG.agentrouter;
const models = cfg.parseResponse!({
object: "list",
data: [
{ id: "claude-opus-4-8", object: "model", owned_by: "anthropic" },
{ id: "gpt-5.6-sol", object: "model", owned_by: "openai" },
],
});
assert.deepEqual(models, [
{ id: "claude-opus-4-8", object: "model", owned_by: "anthropic" },
{ id: "gpt-5.6-sol", object: "model", owned_by: "openai" },
]);
// Tolerant of the alternate `models` envelope shape too.
assert.deepEqual(cfg.parseResponse!({ models: [{ id: "claude-opus-5" }] }), [
{ id: "claude-opus-5" },
]);
});
test("agentrouter discovery headers leak no Authorization variant (case-insensitive)", () => {
const cfg = PROVIDER_MODELS_CONFIG.agentrouter;
const headers = cfg.buildHeaders!("sk-agentrouter");
const hasAuthVariant = Object.keys(headers).some((k) => k.toLowerCase() === "authorization");
assert.equal(hasAuthVariant, false, "no Authorization/authorization header must survive");
});
test("agentrouter parseResponse handles a bare array response (#7016)", () => {
const cfg = PROVIDER_MODELS_CONFIG.agentrouter;
assert.deepEqual(cfg.parseResponse!([{ id: "claude-sonnet-4-6" }]), [
{ id: "claude-sonnet-4-6" },
]);
});