Files
OmniRoute/tests/unit/vision-models-cc-fragments.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

83 lines
2.6 KiB
TypeScript

/**
* Verify that the new VISION_MODEL_ID_FRAGMENTS additions correctly identify
* Command Code vision-capable models via the last-resort heuristic.
*
* Before the fix: `gpt-5`, `kimi-k2.`, and `claude-fable` were absent from
* VISION_MODEL_ID_FRAGMENTS. Without registry `supportsVision` flags either,
* the last-resort heuristic returned `false` for these models, causing the
* Vision Bridge guardrail to reroute image-bearing requests away from
* command-code's own vision-capable upstream to opencode-zen — which then
* failed with 401 "Missing API key."
*/
import { describe, it } from "node:test";
import assert from "node:assert/strict";
import { isVisionModelId } from "../../src/shared/constants/visionModels.ts";
// ── New fragments — MUST now be recognized as vision ────────────────────────
const NEWLY_VISION = [
// gpt-5 fragment covers all GPT-5.x variants
"gpt-5.5",
"gpt-5.4",
"gpt-5.3-codex",
"gpt-5.4-mini",
"gpt-5.6",
"gpt-5.6-luna",
// kimi-k2. fragment (with dot) — covers K2.5/K2.6/K2.7 but NOT bare "kimi-k2"
"moonshotai/Kimi-K2.6",
"kimi-k2.5",
"kimi-k2.7-code",
"moonshotai/Kimi-K2.7-Code",
// claude-fable fragment
"claude-fable-5",
];
// ── Models that must remain non-vision ──────────────────────────────────────
const STILL_NOT_VISION = [
"kimi-k2", // bare kimi-k2 is text-only — must NOT match "kimi-k2."
"deepseek/deepseek-v4-pro",
"deepseek/deepseek-v4-flash",
"zai-org/GLM-5.1",
"zai-org/GLM-5",
"MiniMaxAI/MiniMax-M2.7",
"MiniMaxAI/MiniMax-M2.5",
"mimo-v2.5-pro",
"mimo-v2-pro",
"gemma-2-9b",
"ministral-14b-latest",
];
describe("VISION_MODEL_ID_FRAGMENTS — Command Code coverage", () => {
for (const id of NEWLY_VISION) {
it(`recognizes ${id} as vision via new fragments`, () => {
assert.equal(isVisionModelId(id), true, `${id} must be recognized as vision-capable`);
});
}
for (const id of STILL_NOT_VISION) {
it(`keeps ${id} as non-vision (no false positive)`, () => {
assert.equal(isVisionModelId(id), false, `${id} must remain non-vision`);
});
}
it("existing fragments remain functional (no regression)", () => {
const existing = [
"minimax-m3",
"MiniMaxAI/MiniMax-M3",
"gpt-4o",
"claude-opus-4-7",
"claude-sonnet-4-6",
"claude-haiku-4-5-20251001",
"gemini-3-pro",
"qwen3-vl-plus",
"pixtral-12b",
"mistral-medium-3",
];
for (const id of existing) {
assert.equal(isVisionModelId(id), true, `${id} must stay vision`);
}
});
});