Skip to content

feat(fe): Chat with agent button#2794

Open
evanhutnik wants to merge 3 commits intomainfrom
evan/chat-with-ai
Open

feat(fe): Chat with agent button#2794
evanhutnik wants to merge 3 commits intomainfrom
evan/chat-with-ai

Conversation

@evanhutnik
Copy link
Copy Markdown
Contributor

Summary

Adds a Chat button to block TopBars that creates a new chat with the current entity pre-attached and opens it in a new split.

Available on:

  • Email threads — next to Task
  • PDF — left of Share (with divider)
  • Markdown / Tasks — left of Share (with divider)
  • Folders — left of Share (with divider)
  • Channels — left of the call button (with a small gap)

How it works

  • New shared module packages/app/component/ChatWithAgentButton.tsx exports ChatWithAgentButton, openChatWithAgent, ChatWithAgentIcon, and toChatChannelType.
  • openChatWithAgent(entity) builds the appropriate Attachment (email / document / project / channel), creates a chat via createChat(), seeds the attachment into the per-chat persisted state via the new storeChatStateImmediate helper in @core/component/AI/util/storage, and opens the chat in a new split.
  • When the chat block mounts, it loads the seeded attachment through its existing getChatInputStoredState(chatId) path — no changes needed in block-chat.
  • The visual button matches the Task button styling (bordered, hover transitions, animated star icon).

Notes

  • The channel adapter uses toChatChannelType to narrow @service-comms's ChannelType into @service-cognition's equivalent at the boundary, avoiding cross-service casts.
  • If buildAttachment cannot produce an attachment (e.g. unsupported document file type), openChatWithAgent shows a toast instead of silently no-oping.
  • The channel TopBar wraps the right-side content in a <Show> so no empty container renders when neither the chat button nor the call button is available.

@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented Apr 23, 2026

Warning

Rate limit exceeded

@evanhutnik has exceeded the limit for the number of commits that can be reviewed per hour. Please wait 20 minutes and 12 seconds before requesting another review.

Your organization is not enrolled in usage-based pricing. Contact your admin to enable usage-based pricing to continue reviews beyond the rate limit, or try again in 20 minutes and 12 seconds.

⌛ How to resolve this issue?

After the wait time has elapsed, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

We recommend that you space out your commits to avoid hitting the rate limit.

🚦 How do rate limits work?

CodeRabbit enforces hourly rate limits for each developer per organization.

Our paid plans have higher rate limits than the trial, open-source and free plans. In all cases, we re-allow further reviews after a brief timeout.

Please see our FAQ for further information.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro

Run ID: 84f752aa-da44-4312-b5dd-550e232dd00f

📥 Commits

Reviewing files that changed from the base of the PR and between 46c859e and fb382f2.

📒 Files selected for processing (2)
  • js/app/packages/app/component/ChatWithAgentButton.tsx
  • js/app/packages/block-channel/component/NewChannelBlockAdapter.tsx
📝 Walkthrough

Walkthrough

Introduces a ChatWithAgentButton component and supporting utilities to enable launching AI chats from email, document, project, and channel contexts. Adds openChatWithAgent function to construct attachments and create chats, ChatWithAgentEntity type for entity payloads, and toChatChannelType converter. Integrates the button across multiple block toolbars and adds storeChatStateImmediate for synchronous chat state persistence.

Changes

Cohort / File(s) Summary
Chat-with-Agent Core
js/app/packages/app/component/ChatWithAgentButton.tsx, js/app/packages/core/component/AI/util/storage.ts
New ChatWithAgentEntity type for email, document, project, and channel items; toChatChannelType() converter; openChatWithAgent() function constructing attachments and creating chats; ChatWithAgentButton component with hover animation; re-exported AnimatedStarIcon as ChatWithAgentIcon; new storeChatStateImmediate() for synchronous chat state persistence with timestamp.
Block Integration
js/app/packages/block-channel/component/NewChannelBlockAdapter.tsx, js/app/packages/block-email/component/TopBar.tsx, js/app/packages/block-md/component/TopBar.tsx, js/app/packages/block-pdf/component/TopBar.tsx, js/app/packages/block-project/component/TopBar.tsx
Conditional rendering of ChatWithAgentButton in header controls and toolbar tools with appropriate entity payloads; adjusted divider placement across toolbars; gated channel header right section on either chat-with-agent or calls availability.

Possibly related PRs

🚥 Pre-merge checks | ✅ 4
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The pull request title follows conventional commits format with 'feat' prefix and is 32 characters, well under the 72-character limit. It clearly summarizes the main change: adding a chat button feature.
Description check ✅ Passed The pull request description is comprehensive and directly related to the changeset, detailing the chat button feature across multiple block types, implementation approach, and integration considerations.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

Warning

Review ran into problems

🔥 Problems

Git: Failed to clone repository. Please run the @coderabbitai full review command to re-trigger a full review. If the issue persists, set path_filters to include or exclude specific files.


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 and usage tips.

@github-actions
Copy link
Copy Markdown

github-actions Bot commented Apr 23, 2026

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 4

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
js/app/packages/block-pdf/component/TopBar.tsx (1)

87-87: ⚠️ Potential issue | 🟠 Major

Stale fileType closure — chat will often fail to attach for PDFs.

fileType is read once at line 87 during the TopBar component's initial run. Solid components don't re-execute, so if blockMetadataSignal() hasn't populated yet (common on first render before metadata loads), fileType stays undefined for the lifetime of this toolbar instance. The Chat action/ChatWithAgentButton will then call openChatWithAgent with fileType: undefined, asFileType returns undefined, buildAttachment returns undefined, and the user sees the "Can't attach this item to a chat" toast even though the PDF is perfectly valid.

Read it reactively inside the closures instead.

🛠️ Proposed fix
-  const fileType = blockMetadataSignal()?.fileType;
+  const fileType = () => blockMetadataSignal()?.fileType;
@@
-      action: () =>
-        openChatWithAgent({
-          type: 'document',
-          id: documentId,
-          name: fileName(),
-          fileType,
-        }),
+      action: () =>
+        openChatWithAgent({
+          type: 'document',
+          id: documentId,
+          name: fileName(),
+          fileType: fileType(),
+        }),
       divideAbove: true,
       buttonComponent: () => (
         <ChatWithAgentButton
           entity={{
             type: 'document',
             id: documentId,
             name: fileName(),
-            fileType,
+            fileType: fileType(),
           }}
         />
       ),

Also check the fileType === 'docx' branch at line 192 — it has the same stale-closure problem for the "Download DOCX" menu item.

Also applies to: 232-253

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@js/app/packages/block-pdf/component/TopBar.tsx` at line 87, The TopBar
component currently captures fileType once into the const fileType =
blockMetadataSignal()?.fileType causing stale-closure bugs; update closures (the
Chat action/ChatWithAgentButton that calls openChatWithAgent,
asFileType/buildAttachment usage) to call blockMetadataSignal()?.fileType (or
read blockMetadataSignal() inside the handler) at invocation time instead of
using the top-level fileType variable so the latest metadata is used; also fix
the "Download DOCX" branch (the fileType === 'docx' conditional around the menu
item) and the other affected closures (around lines referenced for 232-253) to
evaluate fileType reactively inside their callbacks rather than relying on the
captured fileType constant.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@js/app/packages/app/component/ChatWithAgentButton.tsx`:
- Around line 98-116: The ChatWithAgentButton duplicates markup and spacing with
the inline Task button — extract a small reusable primitive (e.g.,
AnimatedToolbarButton) that encapsulates the wrapper div + button classes, hover
handling and animated icon props (use it to render AnimatedStarIcon and call
openChatWithAgent(entity)); remove the hardcoded ml-1 from ChatWithAgentButton's
outer wrapper so spacing is controlled by parent toolbars, and replace the Task
button and ChatWithAgentButton to use the new AnimatedToolbarButton to avoid
drift.
- Around line 80-96: openChatWithAgent currently returns silently when
createChat() fails or returns no chatId; surface a user-facing toast and log the
error for debugging. Update openChatWithAgent so that after calling createChat()
you check for ('error' in result) or a missing result.chatId and then call
toast.failure with a concise message like "Unable to create chat" (including
brief error info if present), and also console.warn or processLogger the
result/error; keep early return after logging/toast. References:
openChatWithAgent, createChat, buildAttachment, storeChatStateImmediate,
globalSplitManager.

In `@js/app/packages/block-channel/component/NewChannelBlockAdapter.tsx`:
- Around line 109-129: The code calls toChatChannelType(channelType()) twice and
has a spacing conflict with ChatWithAgentButton's hardcoded ml-1; fix by
creating a single memo/accessor (e.g., const chatType =
toChatChannelType(channelType());) and use chatType() in the outer Show guard
and the inner Show/render body and pass chatType() into ChatWithAgentButton's
entity.channelType, and remove the redundant render-prop invocation; also remove
the hardcoded ml-1 on ChatWithAgentButton's outer div so spacing is governed by
the parent gap-1.5 (references: toChatChannelType, channelType,
ChatWithAgentButton, ChannelCallButton, ENABLE_CALLS).

In `@js/app/packages/block-email/component/TopBar.tsx`:
- Around line 187-204: The three related pieces—action, buttonComponent, and
condition—can diverge because action re-checks emailCtx.thread()?.db_id
independently; update action to assume condition was met and use the same
guarded value (thread id) or early-return consistently with condition, e.g.,
retrieve const threadId = emailCtx.thread()?.db_id once and if absent return,
then call openChatWithAgent({ type: 'email', id: threadId, name: props.title });
ensure this same guard pattern is mirrored in buttonComponent (which already
returns null when id is missing) so action, buttonComponent, and condition
remain consistent; reference: action, buttonComponent, condition,
emailCtx.thread()?.db_id, openChatWithAgent, ChatWithAgentButton, props.title.

---

Outside diff comments:
In `@js/app/packages/block-pdf/component/TopBar.tsx`:
- Line 87: The TopBar component currently captures fileType once into the const
fileType = blockMetadataSignal()?.fileType causing stale-closure bugs; update
closures (the Chat action/ChatWithAgentButton that calls openChatWithAgent,
asFileType/buildAttachment usage) to call blockMetadataSignal()?.fileType (or
read blockMetadataSignal() inside the handler) at invocation time instead of
using the top-level fileType variable so the latest metadata is used; also fix
the "Download DOCX" branch (the fileType === 'docx' conditional around the menu
item) and the other affected closures (around lines referenced for 232-253) to
evaluate fileType reactively inside their callbacks rather than relying on the
captured fileType constant.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro

Run ID: 2c533add-5a9b-44b3-be1d-96d3b98fb940

📥 Commits

Reviewing files that changed from the base of the PR and between c8eb4e3 and 46c859e.

⛔ Files ignored due to path filters (1)
  • js/bun.lock is excluded by !**/*.lock, !**/bun.lock
📒 Files selected for processing (7)
  • js/app/packages/app/component/ChatWithAgentButton.tsx
  • js/app/packages/block-channel/component/NewChannelBlockAdapter.tsx
  • js/app/packages/block-email/component/TopBar.tsx
  • js/app/packages/block-md/component/TopBar.tsx
  • js/app/packages/block-pdf/component/TopBar.tsx
  • js/app/packages/block-project/component/TopBar.tsx
  • js/app/packages/core/component/AI/util/storage.ts

Comment thread js/app/packages/app/component/ChatWithAgentButton.tsx
Comment thread js/app/packages/app/component/ChatWithAgentButton.tsx
Comment thread js/app/packages/block-channel/component/NewChannelBlockAdapter.tsx Outdated
Comment thread js/app/packages/block-email/component/TopBar.tsx
evanhutnik and others added 2 commits April 23, 2026 12:31
- toast + warn when createChat() fails in openChatWithAgent
- hoist toChatChannelType into a single accessor in NewTop

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant