Repository navigation
feat(provider): forward image attachments to Cursor SDK - #133
Conversation
| const image = extractFromPart(part); | ||
| if (image) found.push(image); | ||
| } | ||
| if (found.length > 0) { |
There was a problem hiding this comment.
Thanks mate, one small gap here: when the latest message has no image, this keeps looking back and picks up an image from an earlier message. That means a text-only turn can send an old image again. It should stop at the latest message and send no image when that message has none. The test for a text-only message should check this too.
There was a problem hiding this comment.
Thanks for the review — good catch, and you were right.
The old loop scanned backwards and skipped user messages without images, so a text-only turn could resurrect an image from an earlier turn. Fixed as you described:
extractImagesFromMessagesnow resolves only the last user message and stops there. If that message has no usable images (or itscontentis not an array) it returnsundefined, so no image is sent — it never looks past the latest message.- One implementation note: instead of
Array.prototype.findLastI used a reverse loop thatbreaks at the last user message, because the project targetslib: ES2022(findLastis ES2023 → TS2550). - Tests: the previous case
does not pick images from a user message that has none if an earlier one doesasserted exactly the old behaviour, so I inverted it toreturns undefined when the last user message has no images even if an earlier one does. The "last user message carries an image" case is still covered and still passes. - Also rebased onto current
main(the branch had conflicts with the OpenCode 2.0 work — resolved by keeping both theparamsandimagesfields) and added the two new test files totest:ci:unitso they actually run in CI.
CI: unit + integration both green. Thanks again!
7ef5ee0 to
f2925ab
Compare
|
Thanks mate for the resubmission. I verified the wiring against the installed SDK, I'll land one small fix on main: the dedupe key compares Cheers RAMA |
What
Forwards image attachments from the incoming OpenAI-style request to Cursor's SDK, so images attached in opencode reach the model instead of being silently dropped.
Why
Today the plugin collapses every request into a text-only prompt string. Image content parts (
{ type: "image_url", image_url: { url: "data:..." } }) are discarded — even though the Cursor SDK natively supports them:(
SDKUserMessage.images?: SDKImage[], see@cursor/sdkoptions.d.ts)How
extractImagesFromMessages(messages)(src/proxy/image-extract.ts):data:URLs →{ data, mimeType }; other URLs →{ url }; malformed data URLs are skipped (never forwarded as bare URLs); duplicates removedsdk-child.sendRequest(..., images)→ NDJSON (field written only when non-empty) → runnerscripts/sdk-runner.mjs: new purebuildUserMessage(prompt, images)returns{ text, images }when images exist, the plain string otherwise (byte-identical behavior without images)cursor-agentbackend ignores the field (verified: its runner destructures only known keys)Requirement for end-to-end use (not changed in this patch)
For opencode to actually send attachments, the model entry must declare support, e.g.:
The plugin's model sync does not add these flags today — documented as a follow-up (kept out of this diff on purpose).
Tests
buildUserMessagestring-vs-objectNotes
attachment/modalitieson synced model entries + docs note.Re-submission note
This is a re-submission: the previous PR (#131) was closed pending local verification on real hardware. GitHub refuses to reopen it (
state cannot be changed — the branch was force-pushed or recreated), so a new PR is opened from the same branch. Branch content is unchanged (1 commit ahead ofmain, 0 behind). Now verified locally before submitting.