fix(provider): note file/dir @-mentions as text instead of failing the turn#58
Merged
Conversation
…e turn
The local Cursor SDK agent (the only backend the chat path uses) cannot
accept attachments in any form: `{url}` images throw "URL images are only
supported for cloud SDK agents", and inline `{data,mimeType}` base64 images
end the run with an empty `status:"error"` — surfacing to users as
"Cursor run ended with status error" on an `@image` or `@directory` mention.
Stop attaching file parts via SDKUserMessage.images. Route every non-text
file part (images, PDFs, directories, other media) through a text note so
the run always completes and the agent still learns a file was referenced.
Applies to both promptToCursorMessage and latestUserMessage (fresh + resumed
turns). Text/plain and directory mentions that opencode inlines upstream are
unaffected.
Add explicit unit tests for application/x-directory file parts (the case that regressed) in both promptToCursorMessage and latestUserMessage, and a test asserting the note falls back to the source file URL when a file part has no filename (exercises describeSource).
describeSource returned any non-data: string verbatim, so a raw base64 file part with no filename inlined the whole blob into the note text. Now only URL-shaped strings are used as names; everything else falls back to "file". file:// sources are emitted as filesystem paths (via fileURLToPath, href fallback on invalid URLs) since the local agent's workspace tools act on paths.
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.
Problem
Including a non-text
@-mention in an opencode prompt — an image, PDF, or directory — fails the whole turn with:Root cause
Non-text
@-mentions reach the provider as AI-SDKfileparts (data= afile://URL ordata:URI). The provider tried to forward them viaSDKUserMessage.images, but the Cursor local SDK agent — the only backend the chat path uses — rejects attachments in every form:{ url }images →ConfigurationError: URL images are only supported for cloud SDK agents{ data, mimeType }inline base64 images → run endsstatus:"error"with an empty result → the exact user-facing errorIsolated at the raw
@cursor/sdklevel and reproduced across the default model and a vision model (claude-sonnet-5) — text-only turns succeed, any attachment fails. (text/plainand directory mentions that opencode inlines upstream were never affected.)Fix
Stop attaching file parts. Route every non-text file part (images, PDFs, directories, other media) through a text note —
[attached file: <name> (<mime>) — not forwarded to Cursor]— in bothpromptToCursorMessageandlatestUserMessage(fresh + resumed pooled turns). The run always completes; the agent learns a file was referenced and can inspect it with its own workspace tools.Note: attachments still aren't seen natively (the local agent has no attachment/vision channel), but the turn no longer errors.
Verification
tsc --noEmitclean; build succeedsstatus=finished err=none:file://URL (object + string)file://URLfile://URL (object + string)All previously errored with
status="error".