You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
fix: vision handling for OpenAI-compatible models (Gitlawb#1663)
* Fix vision handling for OpenAI-compatible models
Add route-aware vision capability checks for image reads so registered non-vision models get an actionable refusal before sending image content.
Classify provider-side image/text errors as canonical vision_not_supported responses, preserve image-only tool results for OpenAI-compatible shims, and strip rejected images from retry messages.
Add focused coverage for Xiaomi MiMo/OpenGateway route collisions, canonical errors, shim image handling, and the Read prompt.
* Address vision review findings
Move the Read tool vision gate before the UNC no-I/O early return so UNC image paths cannot bypass non-vision model checks.
Add direct FileReadTool.validateInput coverage for non-vision denials, provider override/env precedence, and UNC image paths.
Add the missing OPENAI_BASE_URL exclusion assertion for the Xiaomi MiMo canonical error path.
* Isolate vision gate tests from provider env
Clear OPENAI_BASE_URL and OPENAI_API_BASE before each FileReadTool vision-gate test so full-suite provider tests cannot leak route state into these cases.
* Fix vision gate test full-suite isolation
Import FileReadTool and prompt with a cache-busted module id so compact.test's process-global mock cannot replace validateInput during test:full.
Invoke validateInput directly instead of optional chaining, matching the review finding and making missing exports fail clearly.
* Lock vision prompt env mutations
Acquire the shared mutation lock before mutating OPENAI_BASE_URL and OPENAI_API_BASE in the FileReadTool vision prompt tests, and release it after restoring the environment.
// The command is `/model` in interactive sessions and `--model` in
46
+
// non-interactive (test/SDK) sessions — both forms are intentional.
47
+
expect(text).toMatch(/(\/model|--model)/)
48
+
expect(text).not.toContain('OPENAI_BASE_URL')
49
+
})
50
+
51
+
test('vision_not_supported from Xiaomi Mimo 400 "text is not set" uses the same canonical message (issue #1421)',()=>{
52
+
consterror=APIError.generate(
53
+
400,
54
+
undefined,
55
+
'OpenAI API error 400: {"error":{"code":"400","message":"Param Incorrect","param":"`text` is not set"}} [openai_category=vision_not_supported,host=api.xiaomimimo.com] Hint: The provider rejected an image-bearing request because it lacked a text part.',
Copy file name to clipboardExpand all lines: src/services/api/errors.ts
+27-1Lines changed: 27 additions & 1 deletion
Original file line number
Diff line number
Diff line change
@@ -99,8 +99,9 @@ function mapOpenAICompatibilityFailureToAssistantMessage(options: {
99
99
100
100
case'vision_not_supported':
101
101
returncreateAssistantAPIErrorMessage({
102
-
content: `The provider at ${options.host} returned 404 for a request containing images. The model (${options.model}) may not support image/vision inputs. Try removing images from your message, or ${switchCmd} to a vision-capable model.`,
@@ -344,6 +372,26 @@ export function classifyOpenAIHttpFailure(options: {
344
372
}
345
373
}
346
374
375
+
// Xiaomi Mimo and similar OpenAI-compatible providers reject image-bearing
376
+
// `role: "tool"` messages with a 400 carrying `text is not set` instead of
377
+
// a 404. Classify the same way as the 404 + hasImages branch so the user
378
+
// gets actionable guidance rather than the raw API error (issue #1421).
379
+
if(
380
+
options.status===400&&
381
+
options.hasImages&&
382
+
isMissingTextPartMessage(body)
383
+
){
384
+
return{
385
+
source: 'http',
386
+
category: 'vision_not_supported',
387
+
retryable: false,
388
+
status: options.status,
389
+
message: body,
390
+
requestUrl: options.url,
391
+
hint: 'The provider rejected a request containing an image (likely a tool result) because it did not include a text part. The model may not support image/vision inputs.',
0 commit comments