[feat] Mention drive files in the composer with @ - #6521
Conversation
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
📝 SummarySummary by CodeRabbit
WalkthroughThe composer gains an ChangesFile mention palette
Estimated code review effort: 4 (Complex) | ~60 minutes Merge Risk: 🟡 Moderate · up to This change adds drive-file mentions to the composer, but folder selection can close the active mention flow instead of navigating into the chosen folder. That breaks a core file-discovery path and should be corrected before merge. Sequence Diagram(s)sequenceDiagram
participant User
participant ChatComposer
participant useFilePalette
participant CommandPalettePlugin
participant PalettePanel
User->>ChatComposer: type @ and query
ChatComposer->>useFilePalette: update file palette state
useFilePalette->>CommandPalettePlugin: provide palette sections
CommandPalettePlugin->>PalettePanel: render filtered rows
User->>PalettePanel: select file or folder
PalettePanel->>CommandPalettePlugin: return selection or drill-in
CommandPalettePlugin->>ChatComposer: insert drive reference
🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
Full details: Linked Issues checkExplanation The PR implements most of issue Resolution Enable fileMentions for every required ChatComposer surface, including desktop and other applicable surfaces. Update chatFileRefs or the reference-resolution path so selected folders resolve and render as recognizable chips. Add tests for both surface coverage and folder references before merging.
✨ Finishing Touches📝 Generate docstrings
🧪 Generate unit tests (beta)
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. Comment |
There was a problem hiding this comment.
Actionable comments posted: 6
🧹 Nitpick comments (2)
web/packages/agenta-ui/src/RichChatInput/plugins/PalettePanel.tsx (1)
131-131: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick winUse Tailwind widths, not
style; as per coding guidelines: “Avoid … inlinestyle={{...}}.”Source: Coding guidelines
web/packages/agenta-chat/src/assets/filePaletteRows.ts (1)
1-6: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick winShorten new code comments.
web/packages/agenta-chat/src/assets/filePaletteRows.ts#L1-L6: Reduce this block to one short line.web/packages/agenta-chat/src/assets/filePaletteRows.ts#L43-L46: Reduce this block to one short line.web/packages/agenta-chat/src/assets/filePaletteRows.ts#L73-L76: Reduce this block to one short line.web/storybook/stories/domain/RichChatInput.stories.tsx#L401-L401: Reduce this comment to one short line.web/storybook/stories/domain/RichChatInput.stories.tsx#L477-L477: Reduce this comment to one short line.
As per coding guidelines: “Hard rule. At most ONE short line per comment.”Source: Coding guidelines
ℹ️ Review info
⚙️ Run configuration
Configuration used: Repository YAML (base), Organization UI (inherited)
Review profile: CHILL
Plan: Team
Run ID: 71825f08-d469-460e-b09a-8e97fdb11660
⛔ Files ignored due to path filters (1)
web/pnpm-lock.yamlis excluded by!**/pnpm-lock.yaml
📒 Files selected for processing (22)
web/mobile/src/features/chat/Composer.tsxweb/oss/src/components/AgentChatSlice/components/AgentComposerDock.tsxweb/packages/agenta-chat/src/assets/filePaletteRows.tsweb/packages/agenta-chat/src/assets/index.tsweb/packages/agenta-chat/src/components/ChatComposer.tsxweb/packages/agenta-chat/src/hooks/index.tsweb/packages/agenta-chat/src/hooks/useFilePalette.tsxweb/packages/agenta-chat/tests/unit/filePaletteRows.test.tsweb/packages/agenta-entity-ui/src/drive/OriginTag.tsxweb/packages/agenta-shared/src/utils/shortcuts.tsweb/packages/agenta-ui/package.jsonweb/packages/agenta-ui/src/RichChatInput/RichChatInput.tsxweb/packages/agenta-ui/src/RichChatInput/assets/palette.tsweb/packages/agenta-ui/src/RichChatInput/assets/slashCommands.tsweb/packages/agenta-ui/src/RichChatInput/assets/slashPalette.tsxweb/packages/agenta-ui/src/RichChatInput/index.tsweb/packages/agenta-ui/src/RichChatInput/plugins/CommandPalettePlugin.tsxweb/packages/agenta-ui/src/RichChatInput/plugins/PalettePanel.tsxweb/packages/agenta-ui/src/RichChatInput/plugins/SlashCommandPlugin.tsxweb/packages/agenta-ui/tests/unit/filePaletteInsert.render.test.tsxweb/packages/agenta-ui/tests/unit/paletteRun.test.tsweb/storybook/stories/domain/RichChatInput.stories.tsx
💤 Files with no reviewable changes (1)
- web/packages/agenta-ui/src/RichChatInput/plugins/SlashCommandPlugin.tsx
Included review availability: Your plan provides up to 8 included reviews per hour; 3 remain after this review.
Railway Preview Environment
|
3fa5d9d to
f416f84
Compare
There was a problem hiding this comment.
Actionable comments posted: 1
ℹ️ Review info
⚙️ Run configuration
Configuration used: Repository YAML (base), Organization UI (inherited)
Review profile: CHILL
Plan: Team
Run ID: 9aee6bf2-0de4-4b8e-a1d9-79fb8ba9f497
📒 Files selected for processing (1)
web/packages/agenta-chat/tests/unit/filePaletteRows.test.ts
Included review availability: Your plan provides up to 8 included reviews per hour; 2 remain after this review.
316448c to
e6b4c2d
Compare
There was a problem hiding this comment.
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
web/packages/agenta-ui/src/RichChatInput/plugins/CommandPalettePlugin.tsx (1)
259-259: 🎯 Functional Correctness | 🟠 Major | ⚡ Quick winKeep the drill-in run active.
replaceRun(active.trigger, "text")inserts@, which closes the run and resetscwd; allow this rewrite to skip the separator.
ℹ️ Review info
⚙️ Run configuration
Configuration used: Repository YAML (base), Organization UI (inherited)
Review profile: CHILL
Plan: Team
Run ID: 00178951-9fe2-452e-8af9-bf2c8c28da86
📒 Files selected for processing (5)
web/packages/agenta-chat/src/assets/filePaletteRows.tsweb/packages/agenta-chat/src/hooks/useFilePalette.tsxweb/packages/agenta-chat/tests/unit/filePaletteRows.test.tsweb/packages/agenta-ui/src/RichChatInput/plugins/CommandPalettePlugin.tsxweb/packages/agenta-ui/src/RichChatInput/plugins/PalettePanel.tsx
Included review availability: Your plan provides up to 8 included reviews per hour; 1 remains after this review.
…te plugin The `@` file menu needs the same Lexical mechanics the `/` menu already has. A second plugin would claim Enter at CRITICAL alongside the first and race by mount order even while closed, keep a divergent dismissal latch, and clobber the same aria-activedescendant on the one contenteditable root. So the plugin now takes N palette specs and owns the keyboard once. The `/` palette's behaviour is unchanged: slashCommands.ts keeps every export and its unit test passes unedited. Also moves @floating-ui/react to dependencies, since mobile is about to take a runtime path through it.
Typing `@` opens the same palette `/` opens, listing the session drive: recents and the root to start, type to search the whole drive, Tab into a folder, Enter to reference a file or a folder. The reference goes in as an inline-code drive path, which is what the sent message already renders as a file chip. Inline code rather than typed backticks because $convertToMarkdownString escapes a backtick in unformatted text — a plain-text path would ship escaped and never resolve. The palette is built in @agenta/chat over the drive's existing lazy listing and search, so both the desktop dock and the mobile composer get it from the one ChatComposer prop. The surfaces that run before a session exists (onboarding, the home task composer) stay off: they have no drive to reference.
The insert has to write an inline-code node: $convertToMarkdownString escapes a backtick typed as ordinary text, so a path written as plain characters would leave the composer escaped and never resolve to a file chip. The render test asserts the serialized message, and that the caret lands outside the span. The story covers the states a reviewer cannot reach by clicking a mock drive — search with the match highlighted, a folder still listing, and no matches.
…column Four things the palette got wrong against the real drive: - Every row carried a Session or Agent pill, so the scope was repeated on each line. Two group headings say it once, and a level that is all one scope needs neither. - The Agent tag was tinted, which read as a status beside the neutral Session one when the two are just halves of the same distinction. Both are quiet now, everywhere the tag appears. - The breadcrumb header drew a house icon of its own on top of the one DriveBreadcrumb already opens with. - A folder row's meta sat 6px left of a file row's: the drill-in button kept its UA padding. The footer hints wrapped to a second line on a deep path too.
- The palette was on by default. `fileMentions` is optional, so a composer that omitted it reached the hook as undefined and picked up its `enabled = true` default, opening the menu on surfaces that have no drive to reference. - `recentRows(recents, 0)` returned every row: the cap was checked after the push, and `=== limit` never tripped from above. - An insert put a space after itself even when the run already had one, so a mention placed mid-sentence left two. - A right-click selected the row under the cursor. - The folder's drill-in target only answered `mousedown`, so keyboard activation did nothing. The action moves to `click`, which both raise. - The shimmer row's width came from an inline style rather than a utility class.
e6b4c2d to
2b6e866
Compare
|
Note GitHub couldn't provide a complete incremental comparison for this pull request, so CodeRabbit is performing a full review instead. This review may take a little longer. |
There was a problem hiding this comment.
Actionable comments posted: 1
ℹ️ Review info
⚙️ Run configuration
Configuration used: Repository YAML (base), Organization UI (inherited)
Review profile: CHILL
Plan: Team
Run ID: 2be0bac9-3b31-48bc-9009-7c6a94679d09
⛔ Files ignored due to path filters (1)
web/pnpm-lock.yamlis excluded by!**/pnpm-lock.yaml
📒 Files selected for processing (21)
web/mobile/src/features/chat/Composer.tsxweb/packages/agenta-chat/src/assets/filePaletteRows.tsweb/packages/agenta-chat/src/assets/index.tsweb/packages/agenta-chat/src/components/ChatComposer.tsxweb/packages/agenta-chat/src/hooks/index.tsweb/packages/agenta-chat/src/hooks/useFilePalette.tsxweb/packages/agenta-chat/tests/unit/filePaletteRows.test.tsweb/packages/agenta-entity-ui/src/drive/OriginTag.tsxweb/packages/agenta-shared/src/utils/shortcuts.tsweb/packages/agenta-ui/package.jsonweb/packages/agenta-ui/src/RichChatInput/RichChatInput.tsxweb/packages/agenta-ui/src/RichChatInput/assets/palette.tsweb/packages/agenta-ui/src/RichChatInput/assets/slashCommands.tsweb/packages/agenta-ui/src/RichChatInput/assets/slashPalette.tsxweb/packages/agenta-ui/src/RichChatInput/index.tsweb/packages/agenta-ui/src/RichChatInput/plugins/CommandPalettePlugin.tsxweb/packages/agenta-ui/src/RichChatInput/plugins/PalettePanel.tsxweb/packages/agenta-ui/src/RichChatInput/plugins/SlashCommandPlugin.tsxweb/packages/agenta-ui/tests/unit/filePaletteInsert.render.test.tsxweb/packages/agenta-ui/tests/unit/paletteRun.test.tsweb/storybook/stories/domain/RichChatInput.stories.tsx
💤 Files with no reviewable changes (1)
- web/packages/agenta-ui/src/RichChatInput/plugins/SlashCommandPlugin.tsx
🚧 Files skipped from review as they are similar to previous changes (19)
- web/packages/agenta-ui/tests/unit/filePaletteInsert.render.test.tsx
- web/packages/agenta-chat/tests/unit/filePaletteRows.test.ts
- web/packages/agenta-ui/src/RichChatInput/assets/slashPalette.tsx
- web/mobile/src/features/chat/Composer.tsx
- web/packages/agenta-entity-ui/src/drive/OriginTag.tsx
- web/packages/agenta-ui/tests/unit/paletteRun.test.ts
- web/packages/agenta-shared/src/utils/shortcuts.ts
- web/packages/agenta-ui/src/RichChatInput/index.ts
- web/packages/agenta-ui/src/RichChatInput/plugins/PalettePanel.tsx
- web/packages/agenta-ui/src/RichChatInput/RichChatInput.tsx
- web/packages/agenta-ui/src/RichChatInput/assets/slashCommands.ts
- web/packages/agenta-chat/src/assets/filePaletteRows.ts
- web/storybook/stories/domain/RichChatInput.stories.tsx
- web/packages/agenta-chat/src/assets/index.ts
- web/packages/agenta-chat/src/components/ChatComposer.tsx
- web/packages/agenta-ui/src/RichChatInput/plugins/CommandPalettePlugin.tsx
- web/packages/agenta-chat/src/hooks/useFilePalette.tsx
- web/packages/agenta-chat/src/hooks/index.ts
- web/packages/agenta-ui/package.json
Included review availability: Your plan provides up to 8 included reviews per hour; 7 remain after this review.
| /** | ||
| * Palette types + run matching for the chat composer's trigger menus. | ||
| * | ||
| * ONE plugin drives every palette (`/` commands, `@` file mentions): two would race for Enter at | ||
| * CRITICAL by mount order, keep divergent dismissal latches, and clobber each other's | ||
| * `aria-activedescendant` on the single contenteditable root. | ||
| * | ||
| * Kept out of the plugin file so a host can import the types without pulling Lexical in. | ||
| */ |
There was a problem hiding this comment.
📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick win
Use one-line source comments. These JSDoc blocks violate the rule. As per coding guidelines: “At most ONE short line per comment.”
Also applies to: 12-16, 19-23, 78-81, 102-109, 120-124, 135-138, 152-155
Source: Coding guidelines
Closes #6139
Context
When an agent writes a file, there is no quick way to point at it in the next message. You either describe the path in prose and hope the agent resolves the right file, or re-upload a copy through the paperclip, even though the session drive already holds the artifact.
The
/palette already solves the same problem for commands. This gives@the equivalent for files.What this adds
Typing
@at a word boundary opens the same palette/opens, listing the session drive:SESSIONandAGENTwhen both scopes are present.Tab(or the row's chevron, for touch) enters a folder and clears the query so the new level lists rather than filters.Escsteps back one level per press, then closes.Enterreferences the highlighted file, or the whole folder.hey@agenta.aimid-sentence never opens it, and with no matchesEnterstill sends the message as written.The mention goes in as an inline-code drive path, which is exactly what a sent message already renders as a file chip through
chatFileRefs:That has to be an inline-code node rather than three typed backtick characters.
$convertToMarkdownStringescapes a backtick in unformatted text (MarkdownExport.exportTextFormat), so a path written as plain characters would ship as\`a/b.md\`and never resolve.Changes
One plugin, N palettes.
SlashCommandPluginbecomesCommandPalettePluginplus a presentationalPalettePanel, driven by a list ofPaletteSpecs. A second independent plugin was not an option: both would claim Enter atCOMMAND_PRIORITY_CRITICALand race by mount order even while closed, keep divergent Escape latches, and clobber each other'saria-activedescendanton the one contenteditable root./behaviour is unchanged.slashCommands.tskeeps every export as an alias layer over the new genericpalette.ts, and its unit test passes unedited. That test is the regression contract.The data lives in
@agenta/chat.useFilePalettesits there because it needs@agenta/entitiesand@agenta/entity-ui, which@agenta/uimay not import. Every visual in the palette contract is aReactNode, so the renderer stays drive-free while the hook supplies icons and the breadcrumb. Rows come from a purefilePaletteRows.tsoveruseLazyDriveTree, which already folds the agent mount underagent-files/and already swaps to the whole-tree fetch while searching.No backend change. Search reuses the client-side path the Files drawer already pays for, held back 180ms and capped at 30 rows, with
useDeferredValuekeeping typing off the scan.Mobile only, behind one prop.
ChatComposergainsfileMentions, andweb/mobile's composer passes it. Nothing underweb/ossorweb/eechanges, so the desktop composer is untouched. The prop is off by default, which also keeps the surfaces that run before a session exists (onboarding, the home task composer) clear. They have no drive and would open an always-empty menu.The palette itself lives in the shared packages, so turning it on for desktop later is one prop on the dock.
@floating-ui/reactmoves fromdevDependenciestodependenciesin@agenta/ui. It resolved by accident before, because mobile never mounted the plugin.Tests
filePaletteInsert.render.test.tsxdrives the palette and asserts the serialized message is`a/b.md`, unescaped, with the caret left outside the code span so the next word stays plain text. This pins the escaping behaviour above.paletteRun.test.tscovers the@pattern: a path stays one run (@docs/gui), an email mid-sentence does not open it, and the dismissal latch discriminates by palette.filePaletteRows.test.tscovers implied folders, theagent-files/fold, runner-plumbing exclusions, ordering, the row cap, and subtree-scoped search.slashCommands.test.tspasses with no edits.@opens, search highlights,Tabdrills two levels into the cloned repo,Escwalks back out, and the sent message renders the file chip.RichChatInputgains aFileMentionsstory with a live palette plus the states you cannot click to (search, folder loading, empty).Known gap: a folder reference does not become a chip in the sent message.
OnDemandFileRefresolves by reading the path, which 404s on a directory, so it stays plain inline code. Correct and readable, but making it chip-able is a separatechatFileRefschange.What to QA
All checks are on
/m. The desktop composer should be unchanged.@in the composer. The palette lists recents and the root, grouped intoSESSIONandAGENTif both exist.Tabon a folder row. It enters the folder, the breadcrumb updates, and the query clears.Escsteps back one level, then closes.Enteron a file and send. The message renders the filename as a file chip you can click.hey@agenta.aimid-sentence. The palette must not open.@zzzzwith no matches and pressEnter. The message sends as written.Tabkey./still opens the command palette, filters, and drills into/modeland/permissionsexactly as before. Check it on desktop as well as/m, since both now run through the rewritten plugin.