Skip to content

Commit f58f038

Browse files
lidge-junclaude
andcommitted
feat(types): tolerant no-vision model matching (Ollama ":size" tags)
Add modelInList(list, modelId): matches the full id OR the family before a ":size" tag, so a "gpt-oss" classification covers "gpt-oss:120b"/"gpt-oss:20b". Colon-less ids (grok-build-0.1) still match exactly. Used by the vision-sidecar gate and the web-search describeImages flag (both consume provider.noVisionModels). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
1 parent 1be0772 commit f58f038

3 files changed

Lines changed: 16 additions & 2 deletions

File tree

src/types.ts

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -120,6 +120,18 @@ export function namespacedToolName(namespace: string | undefined, name: string):
120120
return namespace ? `${namespace}__${name}` : name;
121121
}
122122

123+
/**
124+
* Whether `modelId` is in a per-provider classification list (e.g. `noVisionModels`). Matches the full
125+
* id, OR — for Ollama-style ids — the family before the ":size" tag, so a `gpt-oss` entry covers
126+
* `gpt-oss:120b`/`gpt-oss:20b`. Colon-less ids (e.g. `grok-build-0.1`) still match exactly only.
127+
*/
128+
export function modelInList(list: string[] | undefined, modelId: string): boolean {
129+
if (!list || list.length === 0) return false;
130+
if (list.includes(modelId)) return true;
131+
const colon = modelId.indexOf(":");
132+
return colon > 0 && list.includes(modelId.slice(0, colon));
133+
}
134+
123135
export interface OcxRequestOptions {
124136
maxOutputTokens?: number;
125137
temperature?: number;

src/vision/index.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import type { OcxConfig, OcxContentPart, OcxMessage, OcxParsedRequest, OcxProviderConfig, OcxTextContent } from "../types";
2+
import { modelInList } from "../types";
23
import { describeImage, type VisionSettings } from "./describe";
34

45
export { describeImage } from "./describe";
@@ -66,7 +67,7 @@ export function planVisionSidecar(
6667
parsed: OcxParsedRequest,
6768
incomingHeaders: Headers,
6869
): VisionPlan | undefined {
69-
if (!provider.noVisionModels?.includes(modelId)) return undefined;
70+
if (!modelInList(provider.noVisionModels, modelId)) return undefined;
7071
if (!messagesHaveImage(parsed)) return undefined;
7172
const cfg = config.visionSidecar ?? {};
7273
if (cfg.enabled === false) return undefined;

src/web-search/index.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import type { OcxConfig, OcxParsedRequest, OcxProviderConfig } from "../types";
2+
import { modelInList } from "../types";
23
import type { SidecarSettings } from "./executor";
34

45
export { runWithWebSearch } from "./loop";
@@ -54,7 +55,7 @@ export function planWebSearch(
5455
reasoning: cfg.reasoning ?? DEFAULT_SIDECAR_REASONING,
5556
timeoutMs: cfg.timeoutMs ?? DEFAULT_TIMEOUT_MS,
5657
// The routed model is text-only → have the search model verbalize image results.
57-
describeImages: !!provider.noVisionModels?.includes(modelId),
58+
describeImages: modelInList(provider.noVisionModels, modelId),
5859
},
5960
maxSearches: cfg.maxSearchesPerTurn ?? DEFAULT_MAX_SEARCHES,
6061
};

0 commit comments

Comments
 (0)