mirror of
https://github.com/diegosouzapw/OmniRoute.git
synced 2026-09-21 06:12:17 +03:00
Validado em lote numa worktree combinada com #12524, #12538, #12277 e #12367 sobre o tip de release/v3.8.51: os quatro boardaram sem conflito (áreas disjuntas — zai-web, nvidia, clova, cursor/devin/fable). typecheck:core limpo, check:provider-consistency OK (272 entradas REGISTRY, 355 providers canônicos), check:known-symbols OK, e 305/305 nos testes tocados pelos quatro PRs. Os IDs de modelo adicionados foram conferidos individualmente. Obrigado, @backryun.
79 lines
2.6 KiB
TypeScript
79 lines
2.6 KiB
TypeScript
/**
|
|
* Single source of truth for the model-id vision heuristic (#4072).
|
|
*
|
|
* Three code paths used to keep their own drifting lists, so the same model id
|
|
* could get up to three different vision verdicts:
|
|
* - `src/lib/modelCapabilities.ts` — last-resort fallback in `resolveVisionCapability` (#4071)
|
|
* - `src/app/api/v1/models/catalog.ts` — `/v1/models` listing capability
|
|
* - `open-sse/services/compression/lite.ts` — gate that decides whether lite
|
|
* compression strips images
|
|
*
|
|
* Concrete bugs that caused:
|
|
* - `lite.ts` was missing pixtral / llava / qwen-vl / glm-4v / kimi-vl /
|
|
* mistral-medium-3, so lite compression stripped images for those real vision
|
|
* models and blinded them (same class as #4071 / #4012).
|
|
* - `catalog.ts` was too broad: bare `gemma` (text) and bare `kimi` (e.g.
|
|
* `kimi-k2`, text) produced false-positive `vision: true` in `/v1/models`.
|
|
*
|
|
* Keep this list CONSERVATIVE: a false positive in routing or compression
|
|
* re-creates #4071 (an image routed to / kept for a model that cannot see it).
|
|
* The zero-touch path for newly released vision models is the models.dev sync
|
|
* (`modalities` / `attachment`), not this fallback — this list only needs the
|
|
* stable, well-known vision families.
|
|
*/
|
|
export const VISION_MODEL_ID_FRAGMENTS = [
|
|
"pixtral",
|
|
"llava",
|
|
"bakllava",
|
|
"qwen-vl",
|
|
"qwen2-vl",
|
|
"qwen2.5-vl",
|
|
"qwen3-vl",
|
|
"qvq",
|
|
"internvl",
|
|
"minicpm-v",
|
|
"moondream",
|
|
"mimo-vl",
|
|
"kimi-vl",
|
|
"glm-4v",
|
|
"glm-4.5v",
|
|
"glm-4.6v",
|
|
"glm-5.3-flash",
|
|
"gpt-4o",
|
|
"gpt-4.1",
|
|
"gpt-4-turbo",
|
|
"gpt-4-vision",
|
|
"gpt-5",
|
|
"gemini-1.5",
|
|
"gemini-2",
|
|
"gemini-3",
|
|
"gemini-exp",
|
|
"claude-3",
|
|
"claude-fable",
|
|
"claude-opus-4",
|
|
"claude-sonnet-4",
|
|
"claude-haiku-4",
|
|
"claude-fable",
|
|
"mistral-medium-3",
|
|
"minimax-m3",
|
|
"kimi-k2.",
|
|
// Naver CLOVA Studio: HCX-005 is the only v3 model with image input. Listed by
|
|
// exact id (not a family fragment) to stay conservative — live-verified on
|
|
// 2026-09-01 that it answers image prompts over both a public URL and a
|
|
// base64 data URI, while HCX-007 and HCX-DASH-002 reject images.
|
|
"hcx-005",
|
|
"-vision",
|
|
"multimodal",
|
|
] as const;
|
|
|
|
/**
|
|
* Whether a model id looks like a vision-capable model. Case-insensitive
|
|
* substring match against {@link VISION_MODEL_ID_FRAGMENTS}. Returns `false` for
|
|
* empty / nullish input.
|
|
*/
|
|
export function isVisionModelId(modelId: string | null | undefined): boolean {
|
|
if (!modelId) return false;
|
|
const normalized = String(modelId).toLowerCase();
|
|
return VISION_MODEL_ID_FRAGMENTS.some((fragment) => normalized.includes(fragment));
|
|
}
|