diff --git a/src/shared/constants/visionBridgeDefaults.ts b/src/shared/constants/visionBridgeDefaults.ts index 21050b0c6e..869e4dee8f 100644 --- a/src/shared/constants/visionBridgeDefaults.ts +++ b/src/shared/constants/visionBridgeDefaults.ts @@ -17,6 +17,11 @@ const FORCED_VISION_BRIDGE_MODELS = new Set([ "opencode-go/qwen3.5-plus", "opencode-zen/deepseek-v4-flash", "opencode-zen/deepseek-v4-pro", + // tokenrouter provider: upstream models overstate vision support. + // Force Vision Bridge so images are routed through the configured + // vision model instead of being passed through to text-only backends. + "tokenrouter/deepseek-v4-pro", + "tokenrouter/deepseek-v4-flash", ]); export function isVisionBridgeForcedModel(model: string | null | undefined): boolean { diff --git a/tests/unit/visionBridgeDefaults.test.ts b/tests/unit/visionBridgeDefaults.test.ts index 65042c8eb9..690da33c0d 100644 --- a/tests/unit/visionBridgeDefaults.test.ts +++ b/tests/unit/visionBridgeDefaults.test.ts @@ -39,6 +39,14 @@ test("isVisionBridgeForcedModel does not blanket-force GPT-family models", () => assert.strictEqual(isVisionBridgeForcedModel("openai/gpt-4o-mini"), false); }); +test("isVisionBridgeForcedModel forces tokenrouter deepseek models (text-only backend, #3946)", () => { + // These route through a Fireworks text-only backend that overstates vision + // support at the provider level, so they must be force-bridged or raw image + // data leaks to a backend that cannot process it. + assert.strictEqual(isVisionBridgeForcedModel("tokenrouter/deepseek-v4-pro"), true); + assert.strictEqual(isVisionBridgeForcedModel("tokenrouter/deepseek-v4-flash"), true); +}); + test("getVisionBridgeConfig returns defaults when no settings provided", () => { const config = getVisionBridgeConfig({});