Repository navigation
Agent chat: rich copy out of the transcript, and rich paste into the composer - #36112
Conversation
…the composer Red on base: the composer pastes a Markdown list or Notes/web HTML list as flat lines or literal '- ' text, and there is no rich clipboard module. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Agent-Session: https://cmux.com/deeplink/agent?id=aid-d1d94e42440e6bac3569
…to the composer Leo, 2026-11-05: "we need to be doing this where you can copy and it's a rich copy of the transcript ... and we don't even render bullet points properly in our thing when we're pasting that stuff in." Copy on a message writes its Markdown (text/plain, as before) and the same message as HTML; Cmd-C on a selection inside one message writes clean HTML (no transcript classes or theme colors) with Markdown as its plain text. A composer paste whose HTML has lists, headings, quotes or tables, or whose text is Markdown with a list or fenced code, goes in as the blocks typing makes; everything else stays its plain lines (#23840), and Paste as Plain Text stays plain. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Agent-Session: https://cmux.com/deeplink/agent?id=aid-d1d94e42440e6bac3569
Bugbot needs on-demand usage enabledBugbot uses usage-based billing for this team and requires on-demand usage to be enabled. A team admin can enable on-demand usage in the Cursor dashboard. |
|
cmux status (one comment, edited in place; each line is updated by the job that owns it) Review App of this head (app.zip, kept 1 day)
Gallery before/after for
States
Pick other states with a Passes: CI passes on CI passes on Written by web and size checks: green Shipped in:
|
…, a pasted heading and code block Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Agent-Session: https://cmux.com/deeplink/agent?id=aid-d1d94e42440e6bac3569
Fleet run of composer-rich-paste.test.ts on 70323e4: the paste after Paste as Plain Text drew one bullet for two (WebKit), since the slice was open at its start and the first item joined the line before the caret. A pasted slice now opens only at a paragraph end. The round-trip test counted each item's own <p>; it now reads top-level paragraphs only. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Agent-Session: https://cmux.com/deeplink/agent?id=aid-d1d94e42440e6bac3569
…opy's Review (gpt-6-astra, BLOCK at 70323e4): a selection that starts and ends inside one typeset equation clones only glyphs, so selectionCopy took it and Cmd-C copied KaTeX glyphs instead of the TeX. It now leaves any range that touches an equation to mathCopy. selectionCopy.test.ts: red on the old code, green now. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Agent-Session: https://cmux.com/deeplink/agent?id=aid-d1d94e42440e6bac3569
|
Found 3 test failures on Blacksmith runners: Failures
|
|
Review (codex, router-review): SHIP at f1ff596 Reviewer: codex gpt-6-astra high, fast tier. Follow-ups: 2. They land as checklist items in this PR's one follow-up tracking issue in this repo ( SHIP at Visual verdict: no images; Leo tries the build
Follow-ups:
|
Web shards on f1ff596: Copy failed where the page has only clipboard.writeText (user-prompt-collapse, chat-icon-tooltips, sent-skill-dollars), because the rich copy tried the async write and the copy event and gave up. It now ends with copyTextResult's plain text. The math test's no-math selection is now the rich selection copy's (its text and clean HTML), not the page's own. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Agent-Session: https://cmux.com/deeplink/agent?id=aid-d1d94e42440e6bac3569
|
Review (codex gpt-6-astra high, router-review): BLOCK at 1e437fb BLOCK at 1e437fb Visual verdict: no images; Leo tries the build
Follow-ups:
|
…field and chips Review (gpt-6-astra, BLOCK at 1e437fb): the field kept a plain paste plain for 1 s while the composer's chip path (and the menu's paste through the host) allows 2 s, so a late Paste as Plain Text could still draw a list. Both now read pastedChips.ts PLAIN_PASTE_MS; composer-rich-paste waits 1.5 s before its plain paste. Also: an expanded card's Copy writes the rich copy too (review follow-up), and the selection copy installs per document, so a second DOM in one test process gets it. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Agent-Session: https://cmux.com/deeplink/agent?id=aid-d1d94e42440e6bac3569
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Agent-Session: https://cmux.com/deeplink/agent?id=aid-d1d94e42440e6bac3569
…age Markdown Review (gpt-6.1-sol, BLOCK at 0785306): a copied transcript message with a remote image and a list took the rich path, whose HTML conversion drops <img>, so the image's  never went in. A paste whose plain text carries image Markdown now takes the plain path, as before this PR. composer-rich-paste covers it. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Agent-Session: https://cmux.com/deeplink/agent?id=aid-d1d94e42440e6bac3569
…ion copy Review (gpt-6-astra, BLOCK at f952d19): - A paste whose HTML holds an <img> now takes the plain path and image intake too, not only one whose text has image Markdown; the rich path would drop the picture. - The selection copy unwrapped nothing and removed every <button>, so a visible link chip's words and an image that opens were lost. Buttons are now unwrapped (their icons still go) and images keep src and alt. selectionCopy.test.ts and composer-rich-paste.test.ts cover both. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Agent-Session: https://cmux.com/deeplink/agent?id=aid-d1d94e42440e6bac3569
|
Review (codex gpt-6-astra high, router-review): BLOCK at 23abcc7 BLOCK at 23abcc7 Visual verdict: no images; Leo tries the build
Follow-ups: none |
…targets Review (gpt-6-astra, BLOCK at 23abcc7): Copy's HTML wrote a reply's link target as written, so [x](javascript:...) became an executable href in the app it was pasted into. Copy and the selection copy now keep a link's target only for a web link (safeHref, as the transcript draws it) or a mail address, and a picture's only for a web image; anything else copies as its words. richClipboard.test.ts and selectionCopy.test.ts cover it. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Agent-Session: https://cmux.com/deeplink/agent?id=aid-d1d94e42440e6bac3569
|
Review (codex, router-review): SHIP at a5ff677 Reviewer: codex gpt-6-astra high, fast tier. Follow-ups: 1. They land as checklist items in this PR's one follow-up tracking issue in this repo ( SHIP at a5ff677 Visual verdict: no images; Leo tries the build
Follow-ups:
|
Webview replays at a5ff677 (read by claude-sr2-fleet-mesh-3): - pane-english flagged the clipboard HTML templates in richClipboard.ts; they carry l10n-allow (markup, not words a person reads). - composer-rich-paste's Copy round trip waited for a sent bubble, a step that is red on base in this harness (composer-line-breaks (a)); it now calls copyMarkdownResult, the writer MessageCopy and CardCopy use, from the page and pastes that back. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Agent-Session: https://cmux.com/deeplink/agent?id=aid-d1d94e42440e6bac3569
… root The pane's dev server is rooted at src/agent-session/acpmux, so /src/... did not resolve and the Copy round trip failed at its import. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Agent-Session: https://cmux.com/deeplink/agent?id=aid-d1d94e42440e6bac3569
|
Review (codex gpt-6-astra high, router-review): BLOCK at ada8050 BLOCK at ada8050 Visual verdict: Rich-paste formatting is consistent with Claude/ChatGPT. All 13 supplied before/after pairs are identical; no introduced visual defect found.
Follow-ups:
|
… selection keeps its list Review (gpt-6-astra, BLOCK at ada8050): plain code draws each line as an element inside <pre>, so the selection copy dropped indentation and line ends. Any selection touching a <pre> is now the page's own copy. Also (follow-up): a selection inside one list cloned bare <li>s and pasted back as paragraphs; it is now wrapped in its <ul>/<ol>, an ordered list from its first selected item's number. selectionCopy.test.ts covers both. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Agent-Session: https://cmux.com/deeplink/agent?id=aid-d1d94e42440e6bac3569
|
Review (codex gpt-6.1-sol xhigh, router-review): BLOCK at 0a37de1 BLOCK at 0a37de1 Visual verdict: rich bullets and code match the expected ChatGPT/Claude presentation. All 13 supplied before/after pairs are identical.
Follow-ups:
|
…st numbers right Review (gpt-6.1-sol, BLOCK at 0a37de1): - Copy's HTML now keeps a line break inside a paragraph as <br> (Marked breaks), so 'Intro\nnext line' stays two lines in other apps and when pasted back into the composer. - A selection inside one table is the page's own copy; the clone had bare cells and wrote 'alphabeta'. - The transcript's drawn list numbers and bullets (.cv-li__num, .cv-li__bullet) are dropped from the selection copy, so an ordered list copies as '4. four', not '4. 4.four'. richClipboard.test.ts and selectionCopy.test.ts cover all three, the list case on the transcript's real markup. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Agent-Session: https://cmux.com/deeplink/agent?id=aid-d1d94e42440e6bac3569
|
Review (codex, router-review): SHIP at 138bee4 Reviewer: codex gpt-6.1-sol xhigh, fast tier. Follow-ups: 1. They land as checklist items in this PR's one follow-up tracking issue in this repo ( SHIP at 138bee4 Visual verdict: no images; Leo tries the build
Follow-ups:
|
…opy-paste-markdown # Conflicts: # webviews/src/agent-session/acpmux/composer.gallery.ts
|
Review (codex, router-review): SHIP at 4cb7825 Reviewer: codex gpt-6-astra high, fast tier. Follow-ups: 1. They land as checklist items in this PR's one follow-up tracking issue in this repo ( SHIP at 4cb7825 Visual verdict: no images; Leo tries the build
Follow-ups:
|
![Fix with [code]smith](https://pr-comments-assets.blacksmith.sh/codesmith/fix-with-codesmith-light-3x.png)
Leo, 2026-11-05: "Okay, we need to be doing this where you can copy and it's a rich copy of the transcript, the agent chat stuff. Like it needs to be copying the formatting, because Claude does it, ChatGPT does it, we don't, and we don't even render bullet points properly in our thing when we're pasting that stuff in. So we need to just do that. Like, I mean, we have it when we manually type it, you know, with the space or whatever, but we need to be able to just have that on paste as well."
What changes
Rich copy out of the agent transcript
text/plain, as before, and adds the same message astext/html, the way Claude and ChatGPT copy. When you paste into Notes, Slack, Docs or Mail, the headings, bullets, numbered lists, bold, links, code blocks and tables come through (richClipboard.tscopyMarkdownResult, rendered withmarked, which the pane already uses). Raw HTML in a reply is copied as escaped text, not markup.text/plainis the selection as Markdown, so pasting into the composer or a terminal keeps the bullets (conversation/selectionCopy.ts). Some selections still use the page's default copy: one that contains math (mathCopy.ts handles it), one that contains highlighted code (its shadow root can't be cloned), and one that spans more than one message.The composer renders rich paste
-already makes: bullets, numbered lists, headings, code blocks, bold and links. Line breaks inside a paragraph stay line breaks, as they do in a plain paste. The text's own*and_stay literal characters.# comment(a lone heading or quote doesn't trigger Markdown), VS Code pastes, pastes into a code block, images and file names.onBeforeInput).Typing behavior is unchanged, and the plain-text copy is unchanged.
What the pasteboard gets (copy side)
When you click Copy on the bulleted reply from Leo's screenshots, the pasteboard gets two types:
text/plain(unchanged: the Markdown source)text/html(new; Notes, Slack, Docs and Mail paste this)A Cmd-C selection inside a reply gets the same kind of HTML, cloned from the reply with every class,
styleanddata-attribute removed, and buttons and icons dropped, with Markdown as itstext/plain(selectionCopy.test.ts).Gallery (composer paste)
The PR's gallery advisory run captures these
composer.gallery.tsstates in Linux Chromium, light and dark:paste-bulleted-reply-plain: before, and still the result of Paste as Plain Text. The reply goes in as literal-/**lines.paste-bulleted-reply: after. The same paste shows an intro line and three bullets, with bold and inline code.paste-heading-and-code: HTML with a heading, a list and a code block shows those blocks.Prior art
<br />): kept. Only a paste with Markdown blocks takes the new path, and its paragraphs keep their lines.ComposerBox.plainPaste, which now also tells the field.Changelog
Tests
bun test src/agent-session/acpmux/richClipboard.test.ts src/agent-session/acpmux/conversation/selectionCopy.test.ts: the Markdown→HTML conversion and back, Notes- and Docs-shaped HTML, escaping, the paste trigger rules, and selection-copy cleaning.webviews/test/composer-rich-paste.test.ts(Chromium and WebKit): a Markdown list pastes asul/olwith the intro's lines kept; Notes/web HTML pastes as a heading, a list and a code block; Cmd-Shift-V keeps- oneas text and the next paste is rich again; a# commentscript stays as lines; a message's Copy writes Markdown plus<ul>HTML, and pasting that back gives the list.webviews/test/composer-line-breaks.test.ts: still covers cmux NEXT composer: line breaks copy and paste as lines, never <br /> #23840's lines. Its clipboard mock gainedwrite, because Copy now writes both formats in one call.Observed / Not run
Observed:
138bee4a(run 41994387325): 25/25 browser tests (composer-rich-paste, pane-english, composer-line-breaks, composer-html-paste-edit) in Chromium and WebKit, 42/42 unit tests (richClipboard, selectionCopy, agent-pane-math, chat-icon-tooltips, card-corner-copy, user-prompt-collapse), lint 0 warnings, no type errors.0a37de19(gpt-6.1-sol): copy lost line breaks inside a paragraph, a selection inside a table copied bare cells, and an ordered-list selection copied the drawn numbers twice. Fixed in138bee4a, each covered inrichClipboard.test.ts/selectionCopy.test.ts.f7b86bc3(run 41966234063): 8/8 unit tests and 30/30 browser tests in Chromium and WebKit. That coverscomposer-rich-paste, pluscomposer-line-breaks(cmux NEXT composer: line breaks copy and paste as lines, never <br /> #23840),composer-html-paste-edit,composer-paste-endandgallery-composer-paste, all unchanged and passing. The fullbun run checkpassed: lint 0 warnings, no type errors.70323e4a) caught a real bug: in WebKit, a list pasted after text on the same line lost its first bullet, because that item was merged into the line. Fixed inf7b86bc3; the pasted slice now stays open only at an end that is a paragraph.70323e4a(gpt-6-astra): a selection entirely inside one equation was taken from mathCopy. Fixed inf1ff596b.selectionCopy.test.tsfails without the fix and passes with it.Not run: pasting into Notes or Slack in a DEV build. Gallery images come from this PR's advisory run.
🤖 Generated with Claude Code
Agent session: agent session