Files
OmniRoute/tests/unit/command-code-registry-vision.test.ts
Wahyu Hidayatulloh Pamungkas 3805494250 feat(vision-bridge): consolidate vision bridge fixes (catalog verdict, creds, cache key, CC vision) (#10859)
Validado no worktree combinado do lote: typecheck:core, lint, gates de qualidade (file-size rebaselineado com justificativa — crescimento legítimo em modelCapabilities.ts/commandCode.ts) e os 97+9 testes focados (vision-bridge, command-code vision, model-select-field-catalog-vision) todos verdes. Duas correções reais (#10808/#10809) bem documentadas. CI vermelho neste PR é o base-red já rastreado em #9985. Obrigado!
2026-08-21 02:13:07 -03:00

77 lines
3.5 KiB
TypeScript

/**
* Verify that command-code registry models with `supportsVision: true` resolve
* correctly via `getResolvedModelCapabilities`.
*
* Before the fix: the command-code registry had NO `supportsVision` flags.
* The guardrail used `getResolvedModelCapabilities` → `resolveVisionCapability`,
* which had no registry flag and no heuristic match, returning `null`/`false`.
* This caused the Vision Bridge to incorrectly reroute to opencode-zen (401).
*
* After the fix: the registry declares `supportsVision: true` for CC
* vision-capable models, so the guardrail sees native vision support and
* passes through unmodified — EXCEPT the text-only codex variant
* (`gpt-5.3-codex` via the Command Code gateway), which issue #10703 confirms
* cannot see images and was previously mis-flagged as vision in the registry.
* It follows the same `KNOWN_TEXT_ONLY_DESPITE_SYNC` hard-override path as
* `mimo-v2.5-pro`. `gpt-5.4-mini` is intentionally left as vision-capable —
* it's a real OpenAI multimodal model and the Command Code gateway forwards
* images correctly for it.
*/
import test from "node:test";
import assert from "node:assert/strict";
import { getResolvedModelCapabilities } from "../../src/lib/modelCapabilities.ts";
// ── Models that SHOULD have supportsVision: true ────────────────────────────
const CC_VISION: [string, string][] = [
["Claude Opus 4.7 (CC)", "command-code/claude-opus-4-7"],
["Claude Opus 4.6 (CC)", "command-code/claude-opus-4-6"],
["Claude Sonnet 4.6 (CC)", "command-code/claude-sonnet-4-6"],
["Claude Haiku 4.5 (CC)", "command-code/claude-haiku-4-5-20251001"],
["GPT-5.5 (CC)", "command-code/gpt-5.5"],
["GPT-5.4 (CC)", "command-code/gpt-5.4"],
["GPT-5.4 Mini (CC)", "command-code/gpt-5.4-mini"],
["Kimi K2.6 (CC)", "command-code/moonshotai/Kimi-K2.6"],
["Kimi K2.5 (CC)", "command-code/moonshotai/Kimi-K2.5"],
["Qwen 3.6 Plus (CC)", "command-code/Qwen/Qwen3.6-Plus"],
];
// ── Models that MUST NOT claim vision (text-only) ──────────────────────────
const CC_TEXT_ONLY: [string, string][] = [
["GPT-5.3 Codex (CC)", "command-code/gpt-5.3-codex"],
["DeepSeek V4 Pro (CC)", "command-code/deepseek/deepseek-v4-pro"],
["DeepSeek V4 Flash (CC)", "command-code/deepseek/deepseek-v4-flash"],
["GLM-5.1 (CC)", "command-code/zai-org/GLM-5.1"],
["GLM-5 (CC)", "command-code/zai-org/GLM-5"],
["MiniMax M2.7 (CC)", "command-code/MiniMaxAI/MiniMax-M2.7"],
["MiniMax M2.5 (CC)", "command-code/MiniMaxAI/MiniMax-M2.5"],
["Qwen 3.6 Max Preview (CC)", "command-code/Qwen/Qwen3.6-Max-Preview"],
];
for (const [name, modelId] of CC_VISION) {
test(`${name} resolves supportsVision: true`, () => {
const caps = getResolvedModelCapabilities(modelId);
assert.equal(caps.supportsVision, true, `${modelId} must have supportsVision: true`);
assert.equal(caps.provider, "command-code");
});
}
for (const [name, modelId] of CC_TEXT_ONLY) {
test(`${name} does not falsely claim vision`, () => {
const caps = getResolvedModelCapabilities(modelId);
assert.notEqual(
caps.supportsVision,
true,
`${modelId} is text-only — must not have supportsVision: true`
);
assert.equal(caps.provider, "command-code");
});
}
test("MiniMax M3 via command-code keeps existing vision capability (no regression)", () => {
const caps = getResolvedModelCapabilities("command-code/MiniMaxAI/MiniMax-M3");
assert.equal(caps.supportsVision, true);
});