feat(console): #file mentions attach working-dir files to chat messages - #399
Conversation
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
skill-check — worker0 verified, 32 skipped (no docs/).
Four for four. Nicely done. |
|
Warning Review limit reached
Next review available in: 47 minutes Enable usage-based reviews in Billing to review now. Otherwise, wait until the next included review is available. How can I continue?After more reviews become available, a review can be triggered using the To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based reviews. How do review limits work?CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan review availability. For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, additional reviews become available more gradually as earlier reviews age out of the rolling window. Please refer docs for additional details. Review details⚙️ Run configurationConfiguration used: Organization UI Review profile: CHILL Plan: Pro Run ID: 📒 Files selected for processing (19)
📝 WalkthroughWalkthroughThis PR adds a ChangesFile Mention Feature
Estimated code review effort: 4 (Complex) | ~75 minutes Sequence Diagram(s)sequenceDiagram
participant User
participant ChatView
participant FileMentions as file-mentions.ts
participant Backend as backend.stream/real.ts
participant FileIndex as file-index.ts
User->>ChatView: types "`#file`(path)" and submits
ChatView->>FileMentions: parseFileMentions(text)
FileMentions-->>ChatView: mention paths
ChatView->>FileMentions: expandFileMentions(workingDir, paths)
FileMentions->>FileIndex: coder::read-file trigger
FileIndex-->>FileMentions: file contents / errors
FileMentions-->>ChatView: blocks, attachments, failures
ChatView->>ChatView: patch optimistic message attachments
ChatView->>Backend: stream(prompt, {attachedBlocks})
Backend->>Backend: build structured HarnessUserMessage
Backend-->>ChatView: stream events
sequenceDiagram
participant User
participant Editor as LexicalShell/Composer
participant Plugin as FileMentionsPlugin
participant FileIndex as file-index.ts
User->>Editor: types "#"
Editor->>Plugin: trigger typeahead
Plugin->>FileIndex: fetchFileIndex(workingDir)
FileIndex-->>Plugin: cached or fresh index
Plugin->>Plugin: fuzzyFilterFiles(index, query)
Plugin-->>Editor: render FlipMenu options
User->>Editor: selects option
Editor->>Editor: insert FileMentionNode pill
Possibly related PRs
Suggested reviewers: Poem
🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
✨ Finishing Touches🧪 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.
🧹 Nitpick comments (4)
console/web/src/lib/file-mentions.ts (1)
92-97: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick winDuplicated
TriggerFntype + default-trigger fallback across files.The
TriggerFntype and the "use provided trigger, else lazily fetchgetIiiClient()and call.trigger(...)" fallback pattern here (lines 92-97) is duplicated verbatim infile-index.ts(lines 33-36, 148-153). Since both live in the same feature layer, consider extracting a shared helper/module to avoid drift between the two copies.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@console/web/src/lib/file-mentions.ts` around lines 92 - 97, The default trigger fallback and TriggerFn typing are duplicated in file-mentions and file-index, so extract that shared logic into a common helper/module and reuse it from both locations. Move the “use provided trigger, otherwise lazily call getIiiClient() and client.trigger(...)” behavior into a single reusable function, then update fileMentions and fileIndex to reference that helper so the two copies cannot drift.console/web/src/lib/file-index.ts (1)
17-19: 🚀 Performance & Scalability | 🔵 Trivial | ⚡ Quick winNo cap on total flattened file count.
max_depthandper_folder_limitbound depth and per-directory fan-out, but there's no ceiling on the total number of files across the whole tree. A wide, shallow repo (many folders each near the 500-item limit) can still produce a very large flattened index that gets fuzzy-filtered on every keystroke in the typeahead. Consider adding a total-node cap (e.g., truncateflattenTree's output or stop the walk once a global budget is hit) as a defense-in-depth measure alongside the existing depth/per-folder bounds.Also applies to: 144-165
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@console/web/src/lib/file-index.ts` around lines 17 - 19, The file indexing flow in file-index.ts only limits depth and per-folder fan-out, but flattenTree can still accumulate an unbounded total number of entries for wide repos. Add a global maximum node/file budget in the flattening/walk logic so traversal stops or truncates once the cap is reached, and make sure the same limit is enforced wherever the flattened list is produced and cached. Use the existing TREE_MAX_DEPTH, TREE_PER_FOLDER_LIMIT, and flattenTree symbols to locate the traversal and apply the total-count guard alongside those bounds.console/web/src/components/chat/lexical/FileMentionNode.tsx (1)
195-251: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick winConsider extracting the shared selection/delete logic.
EditableFileMentionPill's selection tracking andCLICK_COMMAND/KEY_BACKSPACE_COMMAND/KEY_DELETE_COMMANDwiring duplicatesEditableFunctionMentionPillinFunctionMentionNode.tsxalmost verbatim. A shared hook (e.g.useMentionPillSelection(nodeKey)) would let future accessibility/selection fixes land once instead of twice.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@console/web/src/components/chat/lexical/FileMentionNode.tsx` around lines 195 - 251, `EditableFileMentionPill` duplicates the same selection and delete command wiring already used by `EditableFunctionMentionPill`, so extract the shared logic into a reusable hook such as `useMentionPillSelection(nodeKey)`. Move the `useLexicalNodeSelection`, `CLICK_COMMAND`, `KEY_BACKSPACE_COMMAND`, and `KEY_DELETE_COMMAND` handling into that shared hook, then have both mention pill components consume it while keeping their rendering code separate.console/web/src/components/chat/lexical/FileMentionTransformPlugin.tsx (1)
26-54: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick winExtract the shared match→splitText→replace logic.
The
start/endbranching andsplitTexthandling here is nearly identical toFunctionMentionTransformPlugin's transform. A small shared helper likereplaceMatchedTextWithNode(node, match, createNode)would remove this duplication across both transform plugins with minimal risk.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@console/web/src/components/chat/lexical/FileMentionTransformPlugin.tsx` around lines 26 - 54, The match→splitText→replace flow in FileMentionTransformPlugin is duplicated and should be shared with FunctionMentionTransformPlugin. Extract the common logic into a helper such as replaceMatchedTextWithNode that takes the TextNode, the regex match, and a node factory, then use it from the transform in FileMentionTransformPlugin to preserve the current behavior while removing the repeated start/end branching.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Nitpick comments:
In `@console/web/src/components/chat/lexical/FileMentionNode.tsx`:
- Around line 195-251: `EditableFileMentionPill` duplicates the same selection
and delete command wiring already used by `EditableFunctionMentionPill`, so
extract the shared logic into a reusable hook such as
`useMentionPillSelection(nodeKey)`. Move the `useLexicalNodeSelection`,
`CLICK_COMMAND`, `KEY_BACKSPACE_COMMAND`, and `KEY_DELETE_COMMAND` handling into
that shared hook, then have both mention pill components consume it while
keeping their rendering code separate.
In `@console/web/src/components/chat/lexical/FileMentionTransformPlugin.tsx`:
- Around line 26-54: The match→splitText→replace flow in
FileMentionTransformPlugin is duplicated and should be shared with
FunctionMentionTransformPlugin. Extract the common logic into a helper such as
replaceMatchedTextWithNode that takes the TextNode, the regex match, and a node
factory, then use it from the transform in FileMentionTransformPlugin to
preserve the current behavior while removing the repeated start/end branching.
In `@console/web/src/lib/file-index.ts`:
- Around line 17-19: The file indexing flow in file-index.ts only limits depth
and per-folder fan-out, but flattenTree can still accumulate an unbounded total
number of entries for wide repos. Add a global maximum node/file budget in the
flattening/walk logic so traversal stops or truncates once the cap is reached,
and make sure the same limit is enforced wherever the flattened list is produced
and cached. Use the existing TREE_MAX_DEPTH, TREE_PER_FOLDER_LIMIT, and
flattenTree symbols to locate the traversal and apply the total-count guard
alongside those bounds.
In `@console/web/src/lib/file-mentions.ts`:
- Around line 92-97: The default trigger fallback and TriggerFn typing are
duplicated in file-mentions and file-index, so extract that shared logic into a
common helper/module and reuse it from both locations. Move the “use provided
trigger, otherwise lazily call getIiiClient() and client.trigger(...)” behavior
into a single reusable function, then update fileMentions and fileIndex to
reference that helper so the two copies cannot drift.
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro
Run ID: fb1700d6-e1eb-41ab-aefb-ecd3ff18581f
📒 Files selected for processing (19)
console/web/src/components/chat/ChatView.tsxconsole/web/src/components/chat/Composer.tsxconsole/web/src/components/chat/LexicalShell.tsxconsole/web/src/components/chat/lexical/FileMentionNode.tsxconsole/web/src/components/chat/lexical/FileMentionTransformPlugin.tsxconsole/web/src/components/chat/lexical/FileMentionsPlugin.tsxconsole/web/src/components/chat/lexical/FlipMenu.tsxconsole/web/src/components/chat/lexical/MentionsPlugin.tsxconsole/web/src/components/chat/lexical/SlashCommandsPlugin.tsxconsole/web/src/lib/backend/harness-send.tsconsole/web/src/lib/backend/real.tsconsole/web/src/lib/backend/types.tsconsole/web/src/lib/file-index.test.tsconsole/web/src/lib/file-index.tsconsole/web/src/lib/file-mentions.test.tsconsole/web/src/lib/file-mentions.tsconsole/web/src/lib/markdown.tsxconsole/web/src/lib/sessions/entry-mapper.test.tsconsole/web/src/lib/sessions/entry-mapper.ts
- '#' typeahead in the composer lists files from the session working directory (coder::tree snapshot, fuzzy-filtered, TTL-cached) and inserts #file(<path>) pills; '@' function mentions are unchanged - on send, mentioned files are read in one coder::read-file batch scoped by fs_scope and attached as <attached-file> text blocks on a structured harness::send user message; plain sends keep string sugar - unreadable files (missing, binary, over budget) never block the send: they become error placeholder blocks plus a warning notice - transcript rendering collapses attachment blocks into size-labeled chips and renders mention tokens as pills, both live and on reload - extract the shared FlipMenu dropdown from the mentions and slash typeahead menus instead of copying it a third time
3711d2a to
752f2f1
Compare
Closes MOT-3860
Summary
Adds file mentions to the console chat composer: type
#, fuzzy-pick a file from the session working directory, and its content is attached to the message the model receives.#opens a files-only typeahead (boundedcoder::treesnapshot, fuzzy-filtered, 30s TTL cache) and inserts a#file(<path>)pill;@function mentions are unchanged.minLength: 1on the trigger keeps markdown headings (# foo) from opening the menu.coder::read-filebatch scoped byfs_scope: { root: workingDir }and attached as<attached-file …>text blocks on a structuredharness::senduser message. Plain sends keep the string-sugar wire form.FlipMenudropdown from the mentions/slash typeahead menus instead of copying it a third time.Zero harness/shell changes — client-side expansion over existing jail-validated functions; the transcript stores the content snapshot, so replays are deterministic and compaction-safe.
Test plan
tsc -b, vite build, and biome clean on all touched files#READMlists repo files (default excludes honored) → pill inserts → send firescoder::read-filethen structuredharness::send(verified in traces) → model reply summarizes the attached READMEREADME.md 11kbchip purely from the server transcript, no raw<attached-fileleakage@fnmenu,/compactinterception, and plain string-sugar sends unchanged;# headingopens no menuSummary by CodeRabbit
New Features
#file(...)mentions in chat to attach files from the current working directory.Bug Fixes