Skip to content

feat(web): insert path mentions for non-image file drops and pastes - #5543

Open
kristjaningi wants to merge 12 commits into
pingdotgg:mainfrom
kristjaningi:feat/composer-file-drop-path-mentions
Open

feat(web): insert path mentions for non-image file drops and pastes#5543
kristjaningi wants to merge 12 commits into
pingdotgg:mainfrom
kristjaningi:feat/composer-file-drop-path-mentions

Conversation

@kristjaningi

@kristjaningi kristjaningi commented Aug 6, 2026

Copy link
Copy Markdown

What

Dropping or pasting a non-image file into the composer currently fails with "Unsupported file type ... Please attach image files only." This PR turns those files into file mention chips instead, so the agent can read them where they already live:

  • Drop: non-image files (and folders) become mentions - workspace-relative when inside the repo, absolute otherwise. Images keep the exact existing attachment flow; mixed drops attach the images and mention the rest.
  • Paste: non-image clipboard files become mention chips at the cursor.
  • Desktop bridge: exposes webUtils.getPathForFile as an optional DesktopBridge method (Electron >= 32 removed File.path). Browser tabs have no OS path access; they keep the image-only flow with a clearer error.
  • Path mentions are only offered when the selected environment is the primary same-host backend; SSH/relay/remote/WSL environments have different filesystems and get the same image-only error.
  • Bonus: thread title seeds now render file links as their basename instead of raw [name](path) markup (also fixes titles for existing file-tree drag mentions).

Why this shape

Mentions are plain prompt text, so there are zero contract or server protocol changes. I'm aware of the orchestration V2 rework (#2829) that closed #4058 - this deliberately stays out of that layer entirely, and follows @juliusmarminge's suggestion there to just provide the path where the agent can find the file. Complementary to the attachment work in #3927.

Fixes #2126

Before Screenshots ⛔

image

After Screenshots ✅

CleanShot 2026-08-06 at 18 52 48@2x CleanShot 2026-08-06 at 18 53 46@2x CleanShot 2026-08-06 at 18 54 24@2x

Verification

  • New pure-logic tests for the drop partition, path relativization, and title basenames; typecheck clean across web, desktop, contracts, and shared.
  • Manually tested in the desktop app - screenshots and video coming shortly.

Note

Insert path mentions for non-image file drops and pastes in the chat composer

  • Dropping or pasting non-image files into the chat composer now inserts file-mention chips (workspace-relative when inside the project, absolute otherwise) instead of plain text; images continue to be attached as before.
  • Adds composerFileDrop.ts with platform-aware path resolution, file partitioning, and error composition utilities used by ChatComposer.
  • Exposes getPathForFile on window.desktopBridge via preload.ts so the renderer can resolve on-disk paths for dropped files.
  • Thread titles seeded from prompts containing file-mention links now use basenames via replaceComposerFileLinksWithBasenames instead of raw markdown.
  • Risk: unresolvable non-image file pastes are consumed (no plain-text fallback) and show a thread error instead.

Macroscope summarized 4683aee.


Note

Low Risk
Composer UX and prompt text only; no server protocol changes. Path gating limits wrong-filesystem mentions; extensive unit tests cover edge cases.

Overview
Non-image OS files dropped or pasted into the chat composer become file path mention chips (workspace-relative when inside the project, absolute otherwise) instead of failing as unsupported attachments. Images still use the existing attachment flow; mixed clipboard/drops attach images and mention the rest.

The desktop bridge adds optional getPathForFile via Electron webUtils so the renderer can resolve dropped file paths. Mentions are only offered for the primary same-host environment, with Windows vs POSIX path-style checks (e.g. WSL-only) so bad paths are not sent to the agent; browser/remote/SSH cases keep image-only behavior with clearer thread errors.

Lexical paste handling inserts mention chips for pasted non-image files; drop handling partitions files and appends serialized link text. Shared token/serialization logic now treats POSIX filenames with backslashes correctly. New thread titles seed from basenames via replaceComposerFileLinksWithBasenames instead of raw [name](path) markup. User docs add a composer page describing images, mentions, and limits.

Reviewed by Cursor Bugbot for commit 4683aee. Bugbot is set up for automated code reviews on this repo. Configure here.

Dropping or pasting a non-image file into the composer previously failed
with "Unsupported file type ... Please attach image files only." Referencing
a file by dragging it into the prompt is a standard workflow in comparable
tools, so non-image files now become file mention chips instead:

- Drop: non-image files are partitioned away from the image-attachment flow
  and inserted as mentions at the end of the prompt, workspace-relative when
  the file lives inside the repo, absolute otherwise. Directories (empty MIME
  type) work the same way. Mixed drops attach the images and mention the rest.
- Paste: the editor's paste command inserts mention chips at the cursor for
  non-image clipboard files, leaving images to the existing attachment path.
- Desktop bridge: expose webUtils.getPathForFile as an optional
  DesktopBridge.getPathForFile, since Electron >= 32 removed File.path and
  the renderer cannot learn a dropped file's location otherwise. Browser
  tabs have no OS path access and keep the previous behavior.
- Thread titles: seed titles now render file links as their basename instead
  of raw "[name](path)" markup. This also fixes titles for existing
  file-tree drag mentions.

No contract or server protocol changes: mentions are plain prompt text, so
remote environments and every provider handle them unchanged.
@coderabbitai

coderabbitai Bot commented Aug 6, 2026

Copy link
Copy Markdown

Important

Review skipped

Auto reviews are disabled on this repository. Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro Plus

Run ID: e8ddd24d-8b9b-4807-b4ad-241c8ce581a7

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

Comment thread apps/web/src/components/chat/composerFileDrop.ts
Backslash is a valid filename character on POSIX, so normalizing it to "/"
turned a dropped /repo/a\b.txt into a mention for a/b.txt, a different or
nonexistent file. Separator normalization (and the case-insensitive
compare) now applies only when both sides are Windows paths.
Comment thread apps/web/src/components/chat/composerFileDrop.ts
Comment thread apps/web/src/components/chat/composerFileDrop.ts Outdated
Two workspaceRelativeDropPath fixes:

- A POSIX workspace root of "/" trimmed to an empty string and bailed, so
  files under a filesystem-root workspace were mentioned by absolute path.
  The empty-root guard now checks the original input, and the separator
  appended for the prefix check restores the trimmed root.
- The relative slice offset came from the lowercased comparable prefix,
  whose length can differ from the original for some Unicode (e.g. "İ"
  lowercases to two code points), truncating the result. Slice by the
  original root's length instead, and require the boundary character to be
  the separator so any residual misalignment falls back to the absolute
  path rather than a wrong relative one.
@kristjaningi
kristjaningi marked this pull request as ready for review August 6, 2026 19:07

@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: ded9627d13

ℹ️ 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".

Comment thread apps/web/src/components/chat/composerFileDrop.ts
Comment thread apps/web/src/components/composerInlineTokenPaste.ts Outdated
In desktop WSL-only mode the WSL server occupies the primary backend slot,
so the connection-target gate passed while webUtils.getPathForFile returned
Windows host paths the Linux-side agent cannot read. Dropped files were
mentioned as C:/... paths pointing nowhere.

The resolver now also compares the resolved path's style against the
selected environment's platform.os and treats mismatches as unresolvable,
surfacing the existing per-environment error instead. Mismatches are
rejected rather than translated because WSL mount roots are configurable
and a guessed /mnt/c/... path would silently point at a nonexistent file.
A paste can land while a chip is node-selected, so $getSelection() is not a
range selection and $insertPastedFileMentions bailed without inserting.
Nothing downstream recovers: the default paste cannot turn files into
mentions and the composer's paste handler prevents it while only reporting
unresolvable files, so resolvable files vanished with no chip and no error.
Fall back to a range selection at the end of the prompt instead of bailing.
@macroscopeapp

macroscopeapp Bot commented Aug 6, 2026

Copy link
Copy Markdown
Contributor

Approvability

Verdict: Needs human review

This PR adds a new feature (non-image file drop/paste to path mentions) with substantial new logic for cross-platform path resolution and desktop bridge integration. There is also an unresolved comment identifying a potential bug in error handling for mixed image/file drops.

You can customize Macroscope's approvability policy. Learn more.

@github-actions github-actions Bot added the vouch:unvouched PR author is not yet trusted in the VOUCHED list. label Aug 6, 2026
@github-actions github-actions Bot added the size:L 100-499 changed lines (additions + deletions). label Aug 8, 2026

@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: 00bf04e0c2

ℹ️ 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".

Comment thread apps/web/src/components/chat/composerFileDrop.ts Outdated
Comment thread apps/web/src/components/composerInlineTokenPaste.ts
kdcokenny added a commit to kdcokenny/t3code that referenced this pull request Aug 8, 2026
Ported from pingdotgg#5543.

Co-authored-by: Kristján Ingi <k.geirsson@gmail.com>

@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: dcf162b71b

ℹ️ 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".

Comment thread apps/web/src/components/chat/ChatComposer.tsx

@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: 61f56a001e

ℹ️ 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".

Comment thread apps/web/src/components/chat/composerFileDrop.ts
Comment thread apps/web/src/components/chat/ChatComposer.tsx
serializeComposerFileLink treated every backslash as a directory
separator, so a POSIX file named a\b.txt became a chip labeled b.txt.
Basename handling is now platform-aware, and token parsing still
accepts older Windows mentions that used a backslash as a separator.
addComposerImages clears the thread error on successful validation, so
writing the mention-unavailable message after it hid a real attachment
count error. Mixed drops now compose both messages in one write.
Non-image drops and pastes now insert path mentions on desktop, with
different fallbacks in the browser and on remote or WSL-only
environments. That is user-visible behavior and belongs in shipped docs.

@cursor cursor Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Cursor Bugbot has reviewed your changes using high effort and found 1 potential issue.

Fix All in Cursor

❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.

Reviewed by Cursor Bugbot for commit 4683aee. Configure here.

const addComposerImages = async (
files: File[],
options?: { fallbackThreadError?: string | null },
) => {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Mention error dropped on plan prompts

Medium Severity

Moving unresolved-file errors into addComposerImages via fallbackThreadError skips that path when plan questions are pending. The helper returns early after the image toast and never applies the fallback, and paste/drop only call setThreadError in the no-images branch, so a mixed image plus unresolved file no longer surfaces the mention error.

Additional Locations (2)
Fix in Cursor Fix in Web

Reviewed by Cursor Bugbot for commit 4683aee. Configure here.

@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: 4683aeefd0

ℹ️ 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".

Comment on lines +2332 to +2335
setThreadError(
threadId,
composeComposerFileDropThreadError(error, options?.fallbackThreadError ?? null),
);

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 mention errors after image compression fails

When a mixed paste/drop contains an unavailable non-image file—for example, in a browser or remote environment—and an image that passes initial validation but later fails compression, the mention error is combined only here; the later setThreadError(threadId, compressionError) overwrites it. The non-image file is therefore omitted without explanation, so retain or merge fallbackThreadError when reporting asynchronous compression failures as well.

AGENTS.md reference: AGENTS.md:L74-L74

Useful? React with 👍 / 👎.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

size:L 100-499 changed lines (additions + deletions). vouch:unvouched PR author is not yet trusted in the VOUCHED list.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Feature]: Any non-image file attachment support

1 participant