From 8366e259baecbafbf88dd59f224cf448163790a8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A8=8B=E5=BA=8F=E5=91=98=E9=98=BF=E6=B1=9F=28Relakkes?= =?UTF-8?q?=29?= Date: Sun, 31 May 2026 23:30:25 +0800 Subject: [PATCH] fix: recover OpenAI text-only image rejections OpenAI-compatible chat proxies serialize user images as image_url parts. Text-only upstreams such as DeepSeek-compatible endpoints can reject that schema before the model can respond, so classify the schema rejection as the existing unsupported-image condition and let the media recovery path strip the offending image on later turns. Constraint: OpenAI-compatible providers vary in whether content parts accept image_url; text-only endpoints can fail during request deserialization. Rejected: Strip images before every OpenAI-compatible request | would break vision-capable OpenAI-compatible models and silently remove user input. Confidence: high Scope-risk: narrow Directive: Do not broaden this to strip OpenAI image parts preflight unless provider/model vision capability is explicitly modeled. Tested: bun test src/services/api/errors.test.ts Tested: bun test tests/mediaRecoveryAndEstimation.test.ts Tested: bun test src/server/__tests__/proxy-transform.test.ts Tested: bun run check:server Not-tested: Live DeepSeek proxy request with real image credentials. --- src/services/api/errors.test.ts | 5 +++++ src/services/api/errors.ts | 3 +++ 2 files changed, 8 insertions(+) diff --git a/src/services/api/errors.test.ts b/src/services/api/errors.test.ts index 9c8c9e3f..92508240 100644 --- a/src/services/api/errors.test.ts +++ b/src/services/api/errors.test.ts @@ -17,6 +17,11 @@ describe('image unsupported API errors', () => { 'unsupported modality: image input is not available', ), ).toBe(true) + expect( + isUnsupportedImageInputErrorMessage( + 'Failed to deserialize the JSON body into the target type: messages[1]: unknown variant `image_url`, expected `text` at line 1 column 394097', + ), + ).toBe(true) expect(isUnsupportedImageInputErrorMessage('image exceeds maximum')).toBe(false) }) diff --git a/src/services/api/errors.ts b/src/services/api/errors.ts index c5df6dd1..a77459c6 100644 --- a/src/services/api/errors.ts +++ b/src/services/api/errors.ts @@ -430,6 +430,9 @@ export function extractUnknownErrorFormat(value: unknown): string | undefined { export function isUnsupportedImageInputErrorMessage(message: string): boolean { const raw = message.toLowerCase() if (!raw.includes('image')) return false + if (raw.includes('image_url') && raw.includes('expected') && raw.includes('text')) { + return true + } return ( raw.includes('not support') || raw.includes('not supported') ||