Repository navigation
fix: show provider error and recover session when image input is rejected - #1
Open
Shalin-Shah-2002 wants to merge 3 commits into
Open
Shalin-Shah-2002 wants to merge 3 commits into
Shalin-Shah-2002 wants to merge 3 commits into
Conversation
Provider error bodies over 500 characters were dropped from the error message entirely, leaving only "Provider request failed with HTTP 400". Extract the short reason from `error.message`, `error`, `message`, or `detail` so users can see why the provider rejected the request. Refs anomalyco#52042 Co-Authored-By: Claude Opus 5.5 <[email protected]> Claude-Session: https://claude.ai/code/session_018CFR7BogLxVEwTy74UxWUE
When a provider rejects a request because of an attachment (for example an image sent to a text-only custom model), V2 session history replayed the same attachment on every later turn, so the session could never recover. Replace attachments whose turn failed with an HTTP 4xx request error before producing any output with a short text note when replaying to the same model. Switching to a different model still sends them. Refs anomalyco#52042 Co-Authored-By: Claude Opus 5.5 <[email protected]> Claude-Session: https://claude.ai/code/session_018CFR7BogLxVEwTy74UxWUE
The V2 session runner sent every user attachment to the provider without checking the catalog model's input modalities, so declaring `modalities.input` for a custom model had no effect on V2 sessions. Return the catalog's declared input modalities alongside the resolved model and replace attachments the model does not support with the same "does not support <modality> input" note the V1 path uses. Models with unknown modalities keep sending attachments unchanged. Refs anomalyco#52042 Co-Authored-By: Claude Opus 5.5 <[email protected]> Claude-Session: https://claude.ai/code/session_018CFR7BogLxVEwTy74UxWUE
|
Hey! Your PR title Please update it to start with one of:
Where See CONTRIBUTING.md for details. |
|
Thanks for updating your PR! It now meets our contributing guidelines. 👍 |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Issue for this PR
Closes anomalyco#52042
Type of change
What does this PR do?
Sending an image to a text-only custom model broke the session in three ways. This fixes each one.
1. The real error was hidden (
packages/llm/src/route/executor.ts). The response body was only added to the error message when it was 500 characters or less. OpenAI-compatible providers usually return longer JSON, so users only sawProvider request failed with HTTP 400. Long bodies now get their reason fromerror.message,error,message, ordetail. The full redacted body is still kept onhttp.body.2. Declared modalities were ignored in V2 sessions (
session/runner/model.ts,llm.ts,to-llm-message.ts).modalities.inputalready reaches the catalog model, butSessionRunnerModel.resolvereturned an@opencode-ai/llmModelthat carries no capabilities, so the runner never checked them.resolvenow also returns the declaredinputlist. Unsupported attachments become the sameERROR: Cannot read "<file>" (this model does not support image input). Inform the user.note the V1 path uses. When the list is empty (unknown), attachments are sent as before. A text-only custom model can now set"modalities": { "input": ["text"] }and the image never reaches the provider.3. The rejected image was replayed forever (
session/runner/to-llm-message.ts). Every later turn, including drains after a restart, re-sent the image and failed again. When a user message's attachments are followed by an assistant turn that failed before any output with HTTP 400/413/415/422 on the same model, those attachments are replaced with a short note on replay. A different model still gets them, and 5xx or network errors never drop attachments. The check uses theHTTP <status>text fromRequestExecutorbecause stored assistant errors are only{ type: "unknown", message }. I can switch it to a structured error kind if preferred.Not covered: failed messages still aren't shown in the UI, which the issue also mentions.
How did you verify your code works?
packages/llm/test/executor.test.tsandpackages/core/test/session-runner-message.test.ts.packages/core/test/session-runner.test.ts: a model that declares onlytextgets a prompt with an image, and the provider request contains the note instead of the image.bun typecheckpasses inpackages/llmandpackages/core.bun testpasses inpackages/llm. Inpackages/core, 1106 of 1108 tests pass. The 2 failures are theutil.flock"unwritable lock roots" tests, which also fail ondevwhen run as root.Screenshots / recordings
N/A (not a UI change)
Checklist
🤖 Generated with Claude Code
https://claude.ai/code/session_018CFR7BogLxVEwTy74UxWUE