feat(desktop): chip a link pasted or typed into the composer - #72201
Merged
Conversation
The composer labeled a `@url:` chip with `refLabel`, which takes the last path segment — three PR links all read as their number. The transcript had its own better labeler that stopped at the hostname, so the same reference read differently before and after send. One `refChipLabel` now serves both: host without `www.`, path riding along for the chip's existing truncate to cut, and the full value on the chip's title so a cut-off link is still readable on hover.
`insertPlainTextAtCaret` dropped its text in verbatim, so a caller with directives in hand had no way to land them as chips. It becomes `insertComposerContentsAtCaret`, sharing the parse `renderComposerContents` already uses, and gains a sibling `replaceBeforeCaret` for swapping a just-typed token for a chip.
A pasted link went in as raw URL text, wrapping across the composer and staying inert. It now becomes the same `@url:` reference the "+ → Add URL" dialog inserts — parsed in place, so a link mid-sentence keeps its position and the punctuation that ended the sentence stays outside the chip. Typing one and pressing space commits it the same way. Both rich-editor surfaces get it: the composer and the message-edit box, whose paste went through `execCommand` and could not produce a chip at all.
OutThisLife
enabled auto-merge
July 26, 2026 20:28
Collaborator
Related: #54662 addressed native paste undo via execCommand. This PR needs manual DOM insertion to create URL chips and intentionally changes that undo behavior. The URL-chip capability is distinct, but maintainers should choose the desired editor contract. |
Contributor
૮ >ﻌ< ა ci reviewran on adfaa95 all good! |
randlee
pushed a commit
to randlee/hermes-agent
that referenced
this pull request
Aug 11, 2026
…rl-chips feat(desktop): chip a link pasted or typed into the composer
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.
A link pasted into the composer went in as raw URL text — wrapping across two or three lines, inert, and unrelated to the
@url:reference the "+ → Add URL" dialog produces for the exact same thing. Now both paths land the same chip.What changed
Paste.
handlePasteruns the clipboard text through a newlinkifyUrls()that rewrites barehttp(s)://…into@url:directives, then inserts through a chip-aware caret insert instead of the plain-text one. The rewrite is positional, so a link mid-paragraph stays where it was, the punctuation that ended the sentence stays outside the chip, a link already written as a directive is skipped, and an unbalanced)that closed a parenthetical is trimmed while…/wiki/Foo_(bar)keeps its own.Typing. A plain space finishing a typed link commits the same chip. It bails on a
textContent.includes('://')read before touching the caret range, so it costs one native string scan on every other space — the same guard shaperefreshTriggeruses.Both editors. The composer and the message-edit box. The latter's paste went through
document.execCommand('insertText', …), which cannot produce a chip at all, so it now uses the same insert the composer does. Consequence worth naming:execCommandfed the browser's native undo stack and a manual DOM insert doesn't, so Cmd+Z after a paste in the edit box now behaves the way it already did in the composer.The label
URL chips were unreadable. The composer labeled them with
refLabel, which takes the last path segment, so three PR links all read as their number. The transcript had a second labeler that stopped at the hostname, so the same reference read differently before and after send.One
refChipLabelnow serves both: host withoutwww., path riding along for the chip's existingtruncateatmax-w-56to cut, and the full value on the chip'stitleso a cut-off link stays readable on hover — which the transcript side already did.What this means for a sent message
@url:is a real context reference: the gateway fetches the page throughweb_extractwhen the turn runs. That is already what the Add URL dialog does, so a pasted link now behaves like a dialog-added one rather than like inert text. Backspace right after the chip removes it as one unit if that isn't wanted.Tests
url-refs.test.tscovers the rewrite (mid-sentence position, trailing punctuation, balanced parens, several links in one paste, already-a-directive, no scheme) and the typed-space commit including the modified-space no-op.rich-editor.test.tsgains coverage for directives landing as chips through the caret insert, and forreplaceBeforeCaretdeclining a caret with no room for the token. 323 tests pass acrosssrc/app/chat/composerandsrc/components/assistant-ui.Not yet looked at in a running app — the chip styling is the existing
DIRECTIVE_CHIP_CLASSthat@file:chips already use, so this only changes what fills it.