Skip to content

[feat] Mention drive files in the composer with @ - #6521

Open
ashrafchowdury wants to merge 5 commits into
release/v0.114.8from
feat/composer-file-mentions-6139
Open

[feat] Mention drive files in the composer with @#6521
ashrafchowdury wants to merge 5 commits into
release/v0.114.8from
feat/composer-file-mentions-6139

Conversation

@ashrafchowdury

Copy link
Copy Markdown
Contributor

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:

  • Recents and the drive root to start, grouped into SESSION and AGENT when both scopes are present.
  • Typing filters across the whole drive, with the matched part of the path highlighted.
  • Tab (or the row's chevron, for touch) enters a folder and clears the query so the new level lists rather than filters. Esc steps back one level per press, then closes.
  • Enter references the highlighted file, or the whole folder.
  • hey@agenta.ai mid-sentence never opens it, and with no matches Enter still 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:

Compare `audits/2026-08/slop-report.md` against `audits/2026-08/findings.json`

That has to be an inline-code node rather than three typed backtick characters. $convertToMarkdownString escapes 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. SlashCommandPlugin becomes CommandPalettePlugin plus a presentational PalettePanel, driven by a list of PaletteSpecs. A second independent plugin was not an option: both would claim Enter at COMMAND_PRIORITY_CRITICAL and race by mount order even while closed, keep divergent Escape latches, and clobber each other's aria-activedescendant on the one contenteditable root.

/ behaviour is unchanged. slashCommands.ts keeps every export as an alias layer over the new generic palette.ts, and its unit test passes unedited. That test is the regression contract.

The data lives in @agenta/chat. useFilePalette sits there because it needs @agenta/entities and @agenta/entity-ui, which @agenta/ui may not import. Every visual in the palette contract is a ReactNode, so the renderer stays drive-free while the hook supplies icons and the breadcrumb. Rows come from a pure filePaletteRows.ts over useLazyDriveTree, which already folds the agent mount under agent-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 useDeferredValue keeping typing off the scan.

Both surfaces, one prop. ChatComposer gains fileMentions, and the desktop dock and web/mobile's composer each pass it. It is off by default so the surfaces that run before a session exists (onboarding, the home task composer) are untouched. They have no drive and would open an always-empty menu.

@floating-ui/react moves from devDependencies to dependencies in @agenta/ui. It resolved by accident before, because mobile never mounted the plugin.

Tests

  • filePaletteInsert.render.test.tsx drives 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.ts covers 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.ts covers implied folders, the agent-files/ fold, runner-plumbing exclusions, ordering, the row cap, and subtree-scoped search.
  • slashCommands.test.ts passes with no edits.
  • Verified end to end against a real session in the running app: @ opens, search highlights, Tab drills two levels into the cloned repo, Esc walks back out, and the sent message renders the file chip.
  • Storybook: RichChatInput gains a FileMentions story 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. OnDemandFileRef resolves 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 separate chatFileRefs change.

What to QA

  • Open an agent session with files on the drive. Type @ in the composer. The palette lists recents and the root, grouped into SESSION and AGENT if both exist.
  • Keep typing part of a filename. Matches come from anywhere in the drive with the matched text highlighted.
  • Press Tab on a folder row. It enters the folder, the breadcrumb updates, and the query clears. Esc steps back one level, then closes.
  • Press Enter on a file and send. The message renders the filename as a file chip you can click.
  • Type hey@agenta.ai mid-sentence. The palette must not open.
  • Type @zzzz with no matches and press Enter. The message sends as written.
  • Same flow on /m, where the folder chevron is the tap target instead of Tab.
  • Regression: / still opens the command palette, filters, and drills into /model and /permissions exactly as before.

…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.
@vercel

vercel Bot commented Sep 4, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated
agenta-documentation Ready Ready Preview Sep 4, 2026 6:47am UTC

Request Review

@coderabbitai

coderabbitai Bot commented Sep 4, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

📝 Summary

Summary by CodeRabbit

  • New Features
    • Added file mentions using the @ trigger in supported chat composers.
    • Browse folders, search files, view recent files, and navigate results with keyboard controls.
    • Selected file paths are inserted into messages with appropriate formatting.
    • Added loading, empty-state, grouping, and accessibility improvements to composer palettes.
    • File mentions are available in regular chat and remain disabled during onboarding.
  • Style
    • Standardized Agent and Session origin labels with a quieter visual treatment.
  • Tests
    • Added coverage for file browsing, searching, navigation, insertion, and palette behavior.

Walkthrough

The composer now supports @ file mentions through a shared palette engine. Drive-backed rows provide browsing, search, recents, folder navigation, keyboard controls, inline-code insertion, and mobile and OSS surface wiring.

Changes

File Mention Palette

Layer / File(s) Summary
Shared palette contract and slash migration
web/packages/agenta-ui/src/RichChatInput/assets/*, web/packages/agenta-ui/src/RichChatInput/RichChatInput.tsx, web/packages/agenta-ui/src/RichChatInput/index.ts
Adds shared palette types and helpers. Reuses them for slash commands. RichChatInput now accepts combined slash and file palettes.
Unified palette interaction and rendering
web/packages/agenta-ui/src/RichChatInput/plugins/*, web/packages/agenta-ui/tests/unit/*
Adds CommandPalettePlugin and PalettePanel. The plugin handles trigger detection, filtering, selection, drill-in, keyboard input, positioning, and ARIA state. Tests cover run parsing and inline-code insertion.
Drive rows and file palette state
web/packages/agenta-chat/src/assets/*, web/packages/agenta-chat/src/hooks/*, web/packages/agenta-chat/src/components/ChatComposer.tsx, web/packages/agenta-chat/tests/unit/*, web/packages/agenta-entity-ui/src/drive/OriginTag.tsx
Adds capped browse, search, recent, and parent-path helpers. useFilePalette loads drive directories, builds sections, supports folder navigation, and supplies the @ palette. Tests cover row derivation.
Composer surfaces and supporting states
web/mobile/src/features/chat/Composer.tsx, web/oss/src/components/AgentChatSlice/components/AgentComposerDock.tsx, web/packages/agenta-shared/src/utils/shortcuts.ts, web/storybook/stories/domain/RichChatInput.stories.tsx
Enables file mentions on mobile and normal OSS chat surfaces. Registers mention shortcuts and adds live and static Storybook states.

Estimated code review effort: 4 (Complex) | ~45 minutes

Merge Risk: 🟡 Moderate · up to e6b4c

Folder navigation in the new @ file palette is currently broken because drilling into a folder closes the palette and returns it to root. This behavior and the outstanding formatting failure should be fixed before merge.

Sequence Diagram(s)

sequenceDiagram
  actor User
  participant ChatComposer
  participant useFilePalette
  participant DriveSessionProvider
  participant CommandPalettePlugin
  participant PalettePanel
  User->>ChatComposer: type @
  ChatComposer->>useFilePalette: activate file palette
  useFilePalette->>DriveSessionProvider: load directory entries
  DriveSessionProvider-->>useFilePalette: return drive listing
  useFilePalette->>CommandPalettePlugin: provide file sections
  CommandPalettePlugin->>PalettePanel: render filtered rows
  User->>PalettePanel: select file or folder
  PalettePanel->>CommandPalettePlugin: return selection
  CommandPalettePlugin->>ChatComposer: insert file reference
Loading
🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Linked Issues check ⚠️ Warning The PR satisfies the main #6139 requirements for file search, word-boundary activation, navigation, keyboard controls, file selection, and cross-surface enablement. It does not fully satisfy the requi… Update the file-reference rendering and resolution flow to support directory references and render selected folders as recognizable chips. Add coverage for folder selection and chip rendering before merging.
✅ Passed checks (4 passed)
Check name Status Explanation
Out of Scope Changes check ✅ Passed The changes are within scope for #6139. The generic palette refactor, shared palette UI, shortcut updates, dependency change, stories, tests, and OriginTag styling directly support the new file-mentio…
Docstring Coverage ✅ Passed Docstring coverage is 61.54% which is sufficient. The required threshold is 60.00%. Docstring coverage is scoped to functions touched by this diff. Analyzed 13 functions across 20 files.
Title check ✅ Passed The title clearly and concisely describes the main change: adding drive-file mentions to the composer with @.
Description check ✅ Passed The description is detailed and directly explains the @ file-mention feature, implementation, scope, tests, and known limitations.
Full details: Linked Issues check

Explanation

The PR satisfies the main #6139 requirements for file search, word-boundary activation, navigation, keyboard controls, file selection, and cross-surface enablement. It does not fully satisfy the requirement that selected folders render as recognizable file chips; the description confirms folder references remain plain inline code.

  • Fix all pre-merge checks with AI
✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feat/composer-file-mentions-6139

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.

@coderabbitai coderabbitai 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.

Actionable comments posted: 6

🧹 Nitpick comments (2)
web/packages/agenta-ui/src/RichChatInput/plugins/PalettePanel.tsx (1)

131-131: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Use Tailwind widths, not style; as per coding guidelines: “Avoid … inline style={{...}}.”

Source: Coding guidelines

web/packages/agenta-chat/src/assets/filePaletteRows.ts (1)

1-6: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Shorten 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

📥 Commits

Reviewing files that changed from the base of the PR and between ded2cc3 and 3fa5d9d.

⛔ Files ignored due to path filters (1)
  • web/pnpm-lock.yaml is excluded by !**/pnpm-lock.yaml
📒 Files selected for processing (22)
  • web/mobile/src/features/chat/Composer.tsx
  • web/oss/src/components/AgentChatSlice/components/AgentComposerDock.tsx
  • web/packages/agenta-chat/src/assets/filePaletteRows.ts
  • web/packages/agenta-chat/src/assets/index.ts
  • web/packages/agenta-chat/src/components/ChatComposer.tsx
  • web/packages/agenta-chat/src/hooks/index.ts
  • web/packages/agenta-chat/src/hooks/useFilePalette.tsx
  • web/packages/agenta-chat/tests/unit/filePaletteRows.test.ts
  • web/packages/agenta-entity-ui/src/drive/OriginTag.tsx
  • web/packages/agenta-shared/src/utils/shortcuts.ts
  • web/packages/agenta-ui/package.json
  • web/packages/agenta-ui/src/RichChatInput/RichChatInput.tsx
  • web/packages/agenta-ui/src/RichChatInput/assets/palette.ts
  • web/packages/agenta-ui/src/RichChatInput/assets/slashCommands.ts
  • web/packages/agenta-ui/src/RichChatInput/assets/slashPalette.tsx
  • web/packages/agenta-ui/src/RichChatInput/index.ts
  • web/packages/agenta-ui/src/RichChatInput/plugins/CommandPalettePlugin.tsx
  • web/packages/agenta-ui/src/RichChatInput/plugins/PalettePanel.tsx
  • web/packages/agenta-ui/src/RichChatInput/plugins/SlashCommandPlugin.tsx
  • web/packages/agenta-ui/tests/unit/filePaletteInsert.render.test.tsx
  • web/packages/agenta-ui/tests/unit/paletteRun.test.ts
  • web/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.

Comment thread web/packages/agenta-chat/src/assets/filePaletteRows.ts Outdated
Comment thread web/packages/agenta-chat/src/components/ChatComposer.tsx
Comment thread web/packages/agenta-chat/tests/unit/filePaletteRows.test.ts
Comment thread web/packages/agenta-ui/src/RichChatInput/plugins/PalettePanel.tsx
Comment thread web/packages/agenta-ui/src/RichChatInput/plugins/PalettePanel.tsx
@github-actions

github-actions Bot commented Sep 4, 2026

Copy link
Copy Markdown
Contributor

Railway Preview Environment

Preview URL https://gateway-pr-6521.up.railway.app/w
Project agenta-oss-clone-spike
Image tag pr-6521-f408023
Status Deployed
Railway logs Open logs
Workflow logs View workflow run
Updated at 2026-09-04T06:56:31.798Z

@ashrafchowdury
ashrafchowdury force-pushed the feat/composer-file-mentions-6139 branch from 3fa5d9d to f416f84 Compare September 4, 2026 06:32

@coderabbitai coderabbitai 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.

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

📥 Commits

Reviewing files that changed from the base of the PR and between 3fa5d9d and f416f84.

📒 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.

Comment thread web/packages/agenta-chat/tests/unit/filePaletteRows.test.ts
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.

@coderabbitai coderabbitai 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.

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 win

Keep the drill-in run active. replaceRun(active.trigger, "text") inserts @ , which closes the run and resets cwd; 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

📥 Commits

Reviewing files that changed from the base of the PR and between f416f84 and e6b4c2d.

📒 Files selected for processing (5)
  • web/packages/agenta-chat/src/assets/filePaletteRows.ts
  • web/packages/agenta-chat/src/hooks/useFilePalette.tsx
  • web/packages/agenta-chat/tests/unit/filePaletteRows.test.ts
  • web/packages/agenta-ui/src/RichChatInput/plugins/CommandPalettePlugin.tsx
  • web/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.

@ashrafchowdury
ashrafchowdury changed the base branch from main to release/v0.114.8 September 4, 2026 14:25
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.

(feat) Mention artifact files in the chat composer with @

1 participant