fix: OpenAI-compatible provider improvements (system messages, image support, stream interruption)#23501
fix: OpenAI-compatible provider improvements (system messages, image support, stream interruption)#23501jwcrystal wants to merge 3 commits intoanomalyco:devfrom
Conversation
…iders Custom OpenAI-compatible providers (Ollama, longent, etc.) were unable to process image attachments because capabilities.input.image defaulted to false. Now defaults to true for @ai-sdk/openai-compatible providers. Closes anomalyco#20802
- Add systemMessage capability schema ('single' | 'multiple')
- Add getSystemMessageMode helper with provider-aware defaults
- Anthropic keeps multiple system messages; all others merge into one
- Add reasoning_content support for DeepSeek/oMLX models
- Merge system messages in convert layer for OpenAI-compatible APIs
- Handle lone system message edge case (convert to user message)
Fixes 'Chat template error' for Qwen, Llama, Ollama, etc.
Closes anomalyco#5034
- Add SSE timeout, connection reset, abort, and stream truncation patterns to retryable() matching for automatic retry - Classify 'SSE read timed out' as APIError(isRetryable: true) - Emit error event in flush() when stream ends without finish_reason while output is still active, instead of silently accepting truncation Closes anomalyco#20466
|
The following comment was made by an LLM, it may be inaccurate: Based on my search, I found the following related PRs that are superseded by PR #23501:
These are not duplicates in the traditional sense—rather, PR #23501 is a combined fix that supersedes these three separate PRs, as explicitly stated in the PR description ("Supersedes: #16981, #21627, #21727"). This is the intended design where the current PR consolidates three related fixes into a single comprehensive change. |
|
Thanks for updating your PR! It now meets our contributing guidelines. 👍 |
310c9be to
18b7db5
Compare
Issue for this PR
Closes #20802
Closes #5034
Closes #20466
Supersedes #16981, #21627, #21727
Type of change
What does this PR do?
Three fixes for OpenAI-compatible providers (Ollama, local models, custom endpoints).
1. Image support for custom providers (closes #20802)
Custom OpenAI-compatible providers could not process image attachments.
capabilities.input.imagedefaulted tofalsefor providers without explicitmodalitiesdeclaration, sotransform.tsfiltered out image parts before they reached the existing conversion logic inconvert-to-openai-compatible-chat-messages.ts.Fix: one-line change — for
@ai-sdk/openai-compatibleproviders, defaultimagetotrueinstead offalse. The existing conversion logic already handles the rest.2. System message handling for non-Anthropic providers (closes #5034)
Local models (Qwen, Llama, Ollama, DeepSeek via oMLX) reject multiple system messages with "Chat template error: System message must be at the beginning". OpenCode sends multiple system messages (agent prompts, plugins) which breaks these providers.
Fix: added
systemMessagecapability ('single' | 'multiple') to the provider schema. Anthropic keeps multiple system messages (existing behavior). All other providers merge system messages into a single message joined by\n. Also addedreasoning_contentfield support alongside existingreasoning_textfor DeepSeek/oMLX reasoning output.3. Stream interruption handling (closes #20466)
OpenAI-compatible providers can interrupt SSE streams mid-response. Previously the truncated output was silently accepted as a complete response — no retry, no error.
Fix:
retry.ts: Added SSE timeout, connection reset, abort, and "stream ended unexpectedly" patterns toretryable()matchingmessage-v2.ts: ClassifiedSSE read timed outasAPIError(isRetryable: true)so retry mechanism picks it upopenai-compatible-chat-language-model.ts: Whenflush()is called without afinish_reasonwhile output is still active (text/reasoning/tool-call), emit an error event instead of silently accepting truncationHow did you verify your code works?
reasoning_contentis correctly parsed from DeepSeek/oMLX responsesdevbranch with typecheck passing (no new errors introduced)Screenshots / recordings
N/A — backend/provider fixes, no UI changes.
Checklist