mirror of
https://github.com/MBombeck/HealthLog.git
synced 2026-11-11 22:02:16 +00:00
The Anthropic vision check listed the Claude 3 and 4 families by prefix, so a key pinned to claude-sonnet-5, claude-opus-5 or a Fable model was told the provider cannot read images, and lab and document OCR refused the upload even though the model handles image and PDF blocks. Replace the per-release prefix list with a rule: any claude-<tier>-<major> slug from the 4 family upward, plus every claude-fable-* model, counts as vision-capable. Claude 3 handling is unchanged. The Settings preset list gains claude-sonnet-5 and claude-opus-5 alongside the existing entries.
142 lines
5.5 KiB
TypeScript
142 lines
5.5 KiB
TypeScript
import { describe, it, expect } from "vitest";
|
|
|
|
import {
|
|
supportsVisionForConfig,
|
|
supportsPdfForProvider,
|
|
} from "../vision-capability";
|
|
|
|
describe("supportsVisionForConfig", () => {
|
|
it("accepts the Claude 3 / 3.5 / 3.7 / 4 families for anthropic", () => {
|
|
for (const model of [
|
|
"claude-3-opus-20240229",
|
|
"claude-3-sonnet-20240229",
|
|
"claude-3-haiku-20240307",
|
|
"claude-3-5-sonnet-latest",
|
|
"claude-3-7-sonnet",
|
|
"claude-sonnet-4-6",
|
|
"claude-opus-4-1",
|
|
"claude-haiku-4",
|
|
]) {
|
|
expect(supportsVisionForConfig("anthropic", model)).toBe(true);
|
|
}
|
|
});
|
|
|
|
it("accepts current Claude 5-generation and Fable pins for anthropic", () => {
|
|
for (const model of [
|
|
"claude-sonnet-5",
|
|
"claude-opus-5",
|
|
"claude-haiku-4-5",
|
|
"claude-fable-5",
|
|
"claude-fable-5-1",
|
|
"claude-opus-4-8",
|
|
]) {
|
|
expect(supportsVisionForConfig("anthropic", model)).toBe(true);
|
|
}
|
|
});
|
|
|
|
it("rejects legacy / text-only anthropic models", () => {
|
|
expect(supportsVisionForConfig("anthropic", "claude-2.1")).toBe(false);
|
|
expect(supportsVisionForConfig("anthropic", "claude-instant-1")).toBe(
|
|
false,
|
|
);
|
|
expect(supportsVisionForConfig("anthropic", null)).toBe(false);
|
|
});
|
|
|
|
it("accepts gpt-4o/4.1/turbo/o-series for openai + admin variants", () => {
|
|
for (const providerType of [
|
|
"openai",
|
|
"admin-openai",
|
|
"admin-key",
|
|
] as const) {
|
|
expect(supportsVisionForConfig(providerType, "gpt-4o")).toBe(true);
|
|
expect(supportsVisionForConfig(providerType, "gpt-4o-mini")).toBe(true);
|
|
expect(supportsVisionForConfig(providerType, "gpt-5.6-terra")).toBe(true);
|
|
expect(supportsVisionForConfig(providerType, "gpt-4.1")).toBe(true);
|
|
expect(supportsVisionForConfig(providerType, "gpt-4-turbo")).toBe(true);
|
|
// Full o-series reasoning models read images.
|
|
expect(supportsVisionForConfig(providerType, "o1")).toBe(true);
|
|
expect(supportsVisionForConfig(providerType, "o3")).toBe(true);
|
|
expect(supportsVisionForConfig(providerType, "o4")).toBe(true);
|
|
}
|
|
});
|
|
|
|
it("rejects non-vision openai models", () => {
|
|
expect(supportsVisionForConfig("openai", "gpt-3.5-turbo")).toBe(false);
|
|
expect(supportsVisionForConfig("openai", "gpt-4")).toBe(false);
|
|
expect(supportsVisionForConfig("openai", null)).toBe(false);
|
|
});
|
|
|
|
it("rejects text-only o-series variants (-mini / -preview) for openai", () => {
|
|
// o1-mini / o1-preview / o3-mini accept the `o*` prefix but have no image
|
|
// input — claiming vision here 400s the user at the image block.
|
|
for (const providerType of [
|
|
"openai",
|
|
"admin-openai",
|
|
"admin-key",
|
|
] as const) {
|
|
expect(supportsVisionForConfig(providerType, "o1-mini")).toBe(false);
|
|
expect(supportsVisionForConfig(providerType, "o1-preview")).toBe(false);
|
|
expect(supportsVisionForConfig(providerType, "o3-mini")).toBe(false);
|
|
}
|
|
});
|
|
|
|
it("trusts local (operator opted in) regardless of model string", () => {
|
|
expect(supportsVisionForConfig("local", "llava")).toBe(true);
|
|
expect(supportsVisionForConfig("local", null)).toBe(true);
|
|
});
|
|
|
|
it("reports vision for codex on multimodal slugs, including -codex", () => {
|
|
for (const model of [
|
|
"gpt-5.5",
|
|
"gpt-5.4",
|
|
"gpt-5.4-mini",
|
|
"gpt-4o",
|
|
"gpt-4.1",
|
|
"o1",
|
|
// The GPT-5.x `-codex` specialists are vision-capable: the wire reads
|
|
// an `input_image` block on these slugs (docs/codex-protocol-spec.md +
|
|
// OpenAI's current model lineup). The old "-codex is text-only"
|
|
// exclusion was stale.
|
|
"gpt-5-codex",
|
|
"gpt-5.3-codex",
|
|
"gpt-5.1-codex-mini",
|
|
]) {
|
|
expect(supportsVisionForConfig("codex", model)).toBe(true);
|
|
}
|
|
// Non-multimodal / unknown slugs and a missing slug → false.
|
|
expect(supportsVisionForConfig("codex", "gpt-4")).toBe(false);
|
|
expect(supportsVisionForConfig("codex", "gpt-3.5-turbo")).toBe(false);
|
|
expect(supportsVisionForConfig("codex", null)).toBe(false);
|
|
// Text-only o-series variants are excluded for codex too.
|
|
expect(supportsVisionForConfig("codex", "o1-mini")).toBe(false);
|
|
expect(supportsVisionForConfig("codex", "o3-mini")).toBe(false);
|
|
expect(supportsVisionForConfig("codex", "o1-preview")).toBe(false);
|
|
// Full o-series stays vision-capable.
|
|
expect(supportsVisionForConfig("codex", "o3")).toBe(true);
|
|
});
|
|
|
|
it("mirrors codex vision capability for the shared central codex (admin-codex)", () => {
|
|
// The operator-shared central Codex runs the same wire on the same resolved
|
|
// slug, so its vision gate is identical to `codex`.
|
|
expect(supportsVisionForConfig("admin-codex", "gpt-5.5")).toBe(true);
|
|
expect(supportsVisionForConfig("admin-codex", "gpt-5.3-codex")).toBe(true);
|
|
expect(supportsVisionForConfig("admin-codex", "gpt-4")).toBe(false);
|
|
expect(supportsVisionForConfig("admin-codex", "o3-mini")).toBe(false);
|
|
expect(supportsVisionForConfig("admin-codex", null)).toBe(false);
|
|
});
|
|
|
|
it("never reports vision for none", () => {
|
|
expect(supportsVisionForConfig("none", "gpt-4o")).toBe(false);
|
|
});
|
|
});
|
|
|
|
describe("supportsPdfForProvider", () => {
|
|
it("only anthropic supports native PDF", () => {
|
|
expect(supportsPdfForProvider("anthropic")).toBe(true);
|
|
expect(supportsPdfForProvider("openai")).toBe(false);
|
|
expect(supportsPdfForProvider("admin-openai")).toBe(false);
|
|
expect(supportsPdfForProvider("local")).toBe(false);
|
|
expect(supportsPdfForProvider("codex")).toBe(false);
|
|
});
|
|
});
|