Skip to content

ACP input: @ git file mentions and clipboard image paste - #61

Merged
samwdp merged 1 commit into
masterfrom
cursor/acp-input-mentions-images-948e
Aug 18, 2026
Merged

ACP input: @ git file mentions and clipboard image paste#61
samwdp merged 1 commit into
masterfrom
cursor/acp-input-mentions-images-948e

Conversation

@samwdp

@samwdp samwdp commented Aug 18, 2026

Copy link
Copy Markdown
Owner

Summary

Extends the ACP prompt input with two context attachments, composed into real ACP ContentBlocks on submit (not just extra text in the message).

1. @ git file picker

Typing @ in the ACP input opens a picker of git files (git ls-files --cached --others --exclude-standard), matching the workspace file picker. Return replaces the @query token with @relative/path.

On submit, each @path mention becomes:

  • ContentBlock::ResourceLink with a file:// URI (ACP baseline; every agent must support this)
  • ContentBlock::Image when the mentioned file is itself an image, with base64 data + MIME type + file URI (same as Zed when attaching an image file)

Emails like user@host.com do not trigger the picker; @ must start a token.

2. Clipboard image paste

Ctrl+Shift+V in the ACP input prefers image clipboard data over text, following Zed / ACP:

  1. Read image MIME payloads via SDL3 (image/png, image/jpeg, image/webp, …)
  2. Fall back to text/uri-list / a copied image file path (file-manager copy)
  3. Sniff magic bytes for MIME, keep original bytes, base64-encode for ACP
  4. Insert ![name](acp-image:N) in the input and store the payload on the buffer

On submit that token becomes:

{ "type": "image", "mimeType": "image/png", "data": "<base64>", "uri": "volt://agent/pasted-image?name=Image" }

This matches the ACP image content block and Zed’s pasted-image mention (uri + base64 + MIME), so vision-capable agents receive the pixels in-context rather than a path string.

Raw clipboard screenshots are labeled Image; copies of named files keep the filename.

Test plan

  • cargo test -p editor-sdl --lib for the new unit/integration tests:
    • @ opens the git file picker and Return inserts @src/main.rs
    • pasted PNG becomes ![Image](acp-image:1) plus stored base64
    • prompt composition splits text / ResourceLink / Image blocks
    • existing slash-command picker tests still pass
Open in Web Open in Cursor 

Typing @ in the ACP input opens a git file picker; Return inserts an
@path mention that is sent as an ACP ResourceLink (or Image block for
image files). Ctrl+Shift+V pastes clipboard images as Image content
blocks with base64 payload and MIME type, matching Zed/ACP prompt
context.

Co-authored-by: samwdp <samwdp@gmail.com>
@cursor

cursor Bot commented Aug 18, 2026

Copy link
Copy Markdown

Cursor Agent can help with this pull request. Just @cursor in comments and I'll start working on changes in this branch.
Learn more about Cursor Agents

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: d9c8d9c71a

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

.map_err(|_| "acp manager lock was poisoned".to_owned())?;
manager.session_for_buffer(buffer_id)
};
let workspace_root = active_workspace_root(runtime)?.or_else(|| git_root(runtime).ok());

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Resolve mentions against the same root used by the picker

When a workspace is a subdirectory of a Git repository, the picker lists --full-name paths relative to the repository root, but submission prefers the workspace root here. For example, selecting pkg/src/lib.rs from a workspace rooted at /repo/pkg produces a link to /repo/pkg/pkg/src/lib.rs, so every selected mention can reference the wrong or nonexistent file. Preserve and use the picker’s Git root, or use the same root-selection order in both paths.

Useful? React with 👍 / 👎.

Comment on lines +1205 to +1206
let replacement = format!("@{relative_path} ");
input.replace_char_range(mention.at_char, mention.end_char, &replacement);

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Encode file mentions containing whitespace

When the selected Git filename contains a space, this inserts an unquoted token such as @docs/user guide.md . The mention parser stops at the first whitespace, so submission creates a resource link for only docs/user and leaves guide.md as ordinary text. Use an escaping or structured representation that preserves the complete picker path.

Useful? React with 👍 / 👎.

Comment on lines +24645 to +24650
fn paste_into_active_input_buffer(runtime: &mut EditorRuntime) -> Result<bool, String> {
match read_system_clipboard_paste() {
ClipboardPaste::Empty => Ok(false),
ClipboardPaste::Text(text) => paste_text_into_active_input_buffer(runtime, &text),
ClipboardPaste::Image(image) => paste_image_into_active_input_buffer(runtime, image),
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Preserve text paste fallback outside ACP inputs

When a non-ACP input is active and the clipboard advertises image data alongside text, or its text is an existing image path, read_system_clipboard_paste returns Image and this branch delegates to an ACP-only handler that returns false. The shortcut is still consumed, so browser and other prompt inputs no longer paste the text they accepted before this change. Only prefer images for ACP buffers, or fall back to the clipboard text when image insertion is unsupported.

Useful? React with 👍 / 👎.

Comment on lines +184 to +189
let mime_type = match mime_type {
Some(mime) => mime,
None => {
image::load_from_memory(&bytes).ok()?;
"image/png".to_owned()
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Convert decoded images before labeling them as PNG

When loading a TIFF file through an @ mention, MIME sniffing returns nothing but image::load_from_memory succeeds, after which the original TIFF bytes are retained while being labeled image/png. The resulting ACP image block therefore contains data that does not match its MIME type and clients decoding it as PNG will reject it. Either infer the actual format or re-encode the decoded image to PNG before returning this MIME type.

Useful? React with 👍 / 👎.

@samwdp
samwdp merged commit 4cbbcc5 into master Aug 18, 2026
6 checks passed
@samwdp
samwdp deleted the cursor/acp-input-mentions-images-948e branch August 18, 2026 06:21
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants