Skip to content
This repository was archived by the owner on Jun 29, 2026. It is now read-only.

refactor(ai-chat): align chat ui with shadcn primitives#49

Merged
urjitc merged 14 commits into
mainfrom
refactor/ai-chat-shadcn-primitives
Jun 27, 2026
Merged

refactor(ai-chat): align chat ui with shadcn primitives#49
urjitc merged 14 commits into
mainfrom
refactor/ai-chat-shadcn-primitives

Conversation

@urjitc

@urjitc urjitc commented Jun 26, 2026

Copy link
Copy Markdown
Member

Summary

  • replace the old ai-elements chat surface with shadcn message, bubble, marker, attachment, and message-scroller primitives
  • move chat scrolling and row spacing onto the shadcn message-scroller composition, including anchored user turns and tighter scroll-fade utilities
  • simplify chat row rendering, pending/tool activity presentation, and prompt/composer wiring around the new primitives

Testing

  • pnpm check

View with Codesmith
Need help on this PR? Tag /codesmith with what you need. Autofix is enabled.


Summary by cubic

Refactored the chat to use shadcn primitives with an anchor-aware message-scroller and jump-to-latest, replacing the legacy surface and simplifying rows. Rebuilt messages, bubbles, markers, and attachments with previews and animated streaming via streamdown; model preference is now global across workspaces.

  • Refactors

    • Adopted @shadcn/react message-scroller (default scroll-to-last-anchor, peek, jump button) and removed @tanstack/react-virtual; added an overlayed empty state.
    • Rebuilt Message, Bubble, Marker, and Attachment primitives; added image previews, video thumbnails, and upload spinners; extracted attachment types/utilities; tweaked rails/layout and made the message toolbar appear on hover except for the latest assistant turn.
    • Introduced AiChatMessageResponse using streamdown for animated streaming and improved code blocks; imported streamdown CSS.
  • Bug Fixes

    • Fixed invalid Tailwind selectors in attachment/scroller; added shimmer and scroll‑fade utilities for better visibility.
    • Ensured safe external links (including protocol‑relative) and satisfied streamdown component typing.
    • Prevented duplicate optimistic user turns by matching both text and file URLs; adjusted video thumbnails to avoid preloading.

Written for commit 4971444. Summary will update on new commits.

Review in cubic

Summary by CodeRabbit

  • New Features
    • Refreshed chat visuals using new message bubbles, markers (live status), and updated attachment UI with dialog preview.
    • Reworked the chat feed to use smoother scrolling with a jump-to-latest button and improved empty/loading presentation.
    • Messages can now render optimistically while sending for faster-feeling chats.
  • Bug Fixes
    • Improved assistant pending/thinking and error states with clearer, live-updating UI.
    • Refined chat spacing and layout behavior for a more consistent experience.
    • Added reliable shimmer/logo effects with reduced-motion support in the UI styling.

@capy-ai

capy-ai Bot commented Jun 26, 2026

Copy link
Copy Markdown
Contributor

Capy auto-review is paused for this organization because the usage-cycle auto-review limit has been reached. Increase the limit or turn it off in billing settings to resume automatic reviews.

@coderabbitai

coderabbitai Bot commented Jun 26, 2026

Copy link
Copy Markdown

Review Change Stack

📝 Walkthrough

Walkthrough

The PR adds shared UI primitives and support styles, rewires AI chat attachments and prompt-input imports to workspace-local modules, replaces the virtualized chat list with a message-scroller flow, and updates assistant pending, tool activity, and optimistic message handling.

Changes

AI chat UI migration

Layer / File(s) Summary
Shared primitives and assets
package.json, src/components/ui/{attachment.tsx,bubble.tsx,marker.tsx,message-scroller.tsx,message.tsx}, src/styles.css
New shared UI primitives are added, @shadcn/react is introduced, @tanstack/react-virtual is removed, and stylesheet assets for Streamdown, scroll fades, shimmer, and logo hover are added.
Attachment data and wiring
src/features/workspaces/components/ai-chat/ai-chat-attachments.ts, src/features/workspaces/components/ai-chat/AiChatAttachmentItem.tsx, src/features/workspaces/components/ai-chat/AiChatMessagePartView.tsx, src/features/workspaces/components/ai-chat/AiChatPrompt*.tsx, src/features/workspaces/components/ai-chat/ai-chat-prompt-input.tsx, src/features/workspaces/state/workspace-ai-composer-draft-store.ts
Attachment categories, labels, and sendable file parts are added, and the workspace chat attachment/prompt modules switch to the new attachment helpers and paths.
Optimistic message state
src/features/workspaces/components/ai-chat/useWorkspaceAiChat.ts
The hook appends an optimistic user message during submitted and streaming states and returns the visible message list.
Chat shell and loading layout
src/features/workspaces/components/ai-chat/ai-chat-layout.ts, src/features/workspaces/components/AiChatPanel.tsx, src/features/workspaces/components/ai-chat/AiChatThreadView.tsx, src/features/workspaces/components/ai-chat/AiChatTranscriptRail.tsx, src/features/workspaces/components/ai-chat/AiChatPanelToolbar.tsx
The panel, thread, rail, and loading layout move to the message-scroller shell, and the top-inset wrapper is removed.
Message list scroller
src/features/workspaces/components/ai-chat/AiChatMessageList.tsx
The message list switches from the virtualizer to message-scroller rendering with animated rows, new row keys, and updated empty and error states.
Message rows and streamed content
src/features/workspaces/components/ai-chat/AiChatMessageResponse.tsx, src/features/workspaces/components/ai-chat/AiChatMessagePartView.tsx, src/features/workspaces/components/ai-chat/AiChatMessageRow.tsx
Streamed markdown rendering and assistant/user row composition move to Bubble and MessageFooter-based layouts with latest-assistant action gating.
Pending and tool summaries
src/features/workspaces/components/ai-chat/AiChatAssistantPending.tsx, src/features/workspaces/components/ai-chat/AiChatToolActivityRow.tsx, src/features/workspaces/components/ai-chat/AiChatToolCard.tsx, src/features/workspaces/components/ai-chat/ai-chat-tool.tsx
Pending assistant text and tool activity summaries use Marker and Bubble primitives, and tool imports move to workspace-local modules.

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60 minutes

Possibly related PRs

Suggested labels

capy

Poem

I hopped through bubbles, bright and new,
Past shimmered text and markers too.
The scroller sang, the rows lined right,
A tiny chat went streaming light.
🐇

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title accurately summarizes the main refactor: aligning the AI chat UI with shadcn primitives.
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.
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
✨ 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 refactor/ai-chat-shadcn-primitives

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

Choose a reason for hiding this comment

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

Actionable comments posted: 5

🧹 Nitpick comments (1)
src/features/workspaces/components/ai-chat/AiChatAttachmentItem.tsx (1)

167-171: 🚀 Performance & Scalability | 🔵 Trivial | ⚡ Quick win

Avoid mounting live <video> elements in transcript attachments.

This stack removes list virtualization, so each historical video attachment now keeps a real media element mounted. That adds avoidable metadata fetch/decoder cost in long threads. Prefer a poster/icon thumbnail here, or at minimum disable preload and defer playback to the preview surface.

Possible low-impact mitigation
 			<AttachmentMedia>
-				<video className="size-full object-cover" muted src={data.url} />
+				<video
+					className="size-full object-cover"
+					muted
+					playsInline
+					preload="none"
+					src={data.url}
+				/>
 			</AttachmentMedia>
🤖 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 `@src/features/workspaces/components/ai-chat/AiChatAttachmentItem.tsx` around
lines 167 - 171, The video attachment render in AiChatAttachmentItem should not
mount a live <video> element inside the transcript list. Update the media branch
in the attachment rendering logic to use a static thumbnail/poster/icon for
historical items, or otherwise defer actual playback to the preview surface; if
a video element must remain, locate the data.type === "file" and
getMediaCategory(data) === "video" branch and disable eager loading/preload so
it does not fetch or decode until needed.
🤖 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.

Inline comments:
In `@src/components/ui/attachment.tsx`:
- Around line 57-58: The image styling in the attachment component uses invalid
Tailwind selector syntax, so the direct image child does not receive the sizing
and object-fit utilities. Update the image variant in the attachment UI styles
to use the direct-child selector form `[&>img]` instead of `*:[img]`, keeping
the existing opacity and state-based classes intact so the `<img>` element is
targeted correctly.

In `@src/components/ui/message-scroller.tsx`:
- Around line 99-102: The MessageScroller button positioning uses a non-standard
utility that can break horizontal centering. Update the className in the
message-scroller component to use the stock Tailwind start-1/2 utility instead
of inset-s-1/2, keeping the existing translate and directional styles intact so
the control remains centered in both LTR and RTL layouts.

In `@src/features/workspaces/components/ai-chat/AiChatMessageList.tsx`:
- Around line 164-184: The animation hook reads previousRowsRef.current during
render inside useNewAiChatRowAnimationKeys, which is not compatible with React
Compiler memoization. Refactor this logic so the previous-row snapshot is stored
in render-tracked state or derived from committed state instead of a mutable ref
read during render, while keeping the animated key calculation based on
AiChatListRow, shouldAnimateAiChatRow, and the current rows list.

In `@src/features/workspaces/components/ai-chat/useWorkspaceAiChat.ts`:
- Around line 141-148: The acceptance check in hasAcceptedUserMessage is too
broad because it clears the optimistic row for any unseen user message, even if
it is unrelated. Update the logic in useWorkspaceAiChat so the optimistic send
is only cleared when the accepted message matches the optimistic message by
content and client token, in addition to being a new user message. Use the
existing optimisticUserMessage fields and the message.role/user-id comparison in
hasAcceptedUserMessage to locate the change.

In `@src/styles.css`:
- Around line 99-148: The new utility classes in styles.css are triggering
stylelint errors that should be auto-fixed. Update the scroll-fade utilities to
remove the extra empty lines before the flagged declarations, and normalize the
color keyword in the shimmer gradient from currentColor to the lowercase form
expected by value-keyword-case. Use the .scroll-fade-b, .scroll-fade-x, and
.shimmer rules as the targets for the cleanup.

---

Nitpick comments:
In `@src/features/workspaces/components/ai-chat/AiChatAttachmentItem.tsx`:
- Around line 167-171: The video attachment render in AiChatAttachmentItem
should not mount a live <video> element inside the transcript list. Update the
media branch in the attachment rendering logic to use a static
thumbnail/poster/icon for historical items, or otherwise defer actual playback
to the preview surface; if a video element must remain, locate the data.type ===
"file" and getMediaCategory(data) === "video" branch and disable eager
loading/preload so it does not fetch or decode until needed.
🪄 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: defaults

Review profile: CHILL

Plan: Pro

Run ID: 5205247d-fa99-43ab-ad83-5ccf6950c86e

📥 Commits

Reviewing files that changed from the base of the PR and between 5cf7d04 and a66214b.

⛔ Files ignored due to path filters (1)
  • pnpm-lock.yaml is excluded by !**/pnpm-lock.yaml
📒 Files selected for processing (35)
  • package.json
  • src/components/ai-elements/attachments.tsx
  • src/components/ai-elements/conversation.tsx
  • src/components/ai-elements/message.tsx
  • src/components/ai-elements/shimmer.tsx
  • src/components/ui/attachment.tsx
  • src/components/ui/bubble.tsx
  • src/components/ui/marker.tsx
  • src/components/ui/message-scroller.tsx
  • src/components/ui/message.tsx
  • src/features/workspaces/components/AiChatPanel.tsx
  • src/features/workspaces/components/ai-chat/AiChatAssistantPending.tsx
  • src/features/workspaces/components/ai-chat/AiChatAttachmentDrop.tsx
  • src/features/workspaces/components/ai-chat/AiChatAttachmentItem.tsx
  • src/features/workspaces/components/ai-chat/AiChatMessageList.tsx
  • src/features/workspaces/components/ai-chat/AiChatMessagePartView.tsx
  • src/features/workspaces/components/ai-chat/AiChatMessageResponse.tsx
  • src/features/workspaces/components/ai-chat/AiChatMessageRow.tsx
  • src/features/workspaces/components/ai-chat/AiChatPanelToolbar.tsx
  • src/features/workspaces/components/ai-chat/AiChatPromptAttachments.tsx
  • src/features/workspaces/components/ai-chat/AiChatPromptContextBar.tsx
  • src/features/workspaces/components/ai-chat/AiChatPromptInput.tsx
  • src/features/workspaces/components/ai-chat/AiChatPromptSubmit.tsx
  • src/features/workspaces/components/ai-chat/AiChatThreadView.tsx
  • src/features/workspaces/components/ai-chat/AiChatToolActivityRow.tsx
  • src/features/workspaces/components/ai-chat/AiChatToolCard.tsx
  • src/features/workspaces/components/ai-chat/AiChatTranscriptRail.tsx
  • src/features/workspaces/components/ai-chat/ai-chat-attachments.ts
  • src/features/workspaces/components/ai-chat/ai-chat-code-block.tsx
  • src/features/workspaces/components/ai-chat/ai-chat-layout.ts
  • src/features/workspaces/components/ai-chat/ai-chat-prompt-input.tsx
  • src/features/workspaces/components/ai-chat/ai-chat-tool.tsx
  • src/features/workspaces/components/ai-chat/useWorkspaceAiChat.ts
  • src/features/workspaces/state/workspace-ai-composer-draft-store.ts
  • src/styles.css
💤 Files with no reviewable changes (4)
  • src/components/ai-elements/conversation.tsx
  • src/components/ai-elements/shimmer.tsx
  • src/components/ai-elements/message.tsx
  • src/components/ai-elements/attachments.tsx

Comment thread src/components/ui/attachment.tsx Outdated
Comment thread src/components/ui/message-scroller.tsx
Comment thread src/features/workspaces/components/ai-chat/AiChatMessageList.tsx Outdated
Comment thread src/features/workspaces/components/ai-chat/useWorkspaceAiChat.ts Outdated
Comment thread src/styles.css Outdated
…-scroller

Co-authored-by: Codesmith <codesmith-bot@users.noreply.github.com>

@cubic-dev-ai cubic-dev-ai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

5 issues found and verified against the latest diff

Prompt for AI agents (unresolved issues)

Check if these issues are valid — if so, understand the root cause of each and fix them. If appropriate, use sub-agents to investigate and fix each issue separately.


<file name="src/features/workspaces/components/ai-chat/AiChatMessageList.tsx">

<violation number="1" location="src/features/workspaces/components/ai-chat/AiChatMessageList.tsx:168">
P2: Reading `previousRowsRef.current` inside `useMemo` accesses a ref during render, which is incompatible with React Compiler memoization. The React Compiler cannot safely memoize code that reads ref values during render since the ref's `.current` value can change without triggering a re-render. Consider moving the previous-row snapshot into state (via `useState`) or computing animation keys from committed state in an effect.</violation>
</file>

<file name="src/features/workspaces/components/ai-chat/AiChatMessageResponse.tsx">

<violation number="1" location="src/features/workspaces/components/ai-chat/AiChatMessageResponse.tsx:14">
P1: Disables Streamdown link safety for chat markdown links. Assistant-generated links will open directly without the safety interstitial, increasing phishing/open-redirect risk.</violation>
</file>

<file name="src/features/workspaces/components/ai-chat/ai-chat-layout.ts">

<violation number="1" location="src/features/workspaces/components/ai-chat/ai-chat-layout.ts:6">
P3: Duplicate identical class-name constant. `aiChatLoadingScrollerContentClassName` has the same value as `aiChatMessageScrollerContentClassName`. If the layout intent is the same, use a single shared constant or alias to keep them in sync.</violation>
</file>

<file name="src/styles.css">

<violation number="1" location="src/styles.css:143">
P2: `.shimmer` gradient uses `currentColor` but class also sets `color: transparent` so `currentColor` resolves to `transparent` → shimmer is invisible. Either replace `currentColor` in the gradient with explicit colors (e.g., `var(--foreground)` / `color-mix(...)`) and keep `color: transparent` for the text-mask pattern, or remove `color: transparent` and rely on inherited `color` for `currentColor`.</violation>
</file>

Reply with feedback, questions, or to request a fix.

Re-trigger cubic

Comment thread src/features/workspaces/components/ai-chat/AiChatMessageResponse.tsx Outdated
Comment thread src/styles.css
Comment thread src/features/workspaces/components/ai-chat/AiChatMessageList.tsx Outdated
Comment thread src/features/workspaces/components/ai-chat/useWorkspaceAiChat.ts Outdated
Comment thread src/features/workspaces/components/ai-chat/ai-chat-layout.ts Outdated
@greptile-apps

greptile-apps Bot commented Jun 26, 2026

Copy link
Copy Markdown

Greptile Summary

This PR replaces the legacy ai-elements chat surface with shadcn-aligned primitives (bubble, marker, message, message-scroller, attachment) and swaps @tanstack/react-virtual for the @shadcn/react MessageScroller with anchor-aware auto-scroll. It also introduces streamdown for animated streaming markdown, extracts attachment types into ai-chat-attachments.ts, and promotes the AI model preference from per-workspace session state to a single global store entry.

  • Scroller & rows: MessageScrollerProvider with defaultScrollPosition="last-anchor" replaces the virtual list; user messages are marked as scroll anchors, and the tailPending indicator is co-located within the last message's MessageScrollerItem rather than carrying a separate positional key — eliminating the animation-restart issue flagged in the previous review.
  • Streamdown integration: AiChatMessageResponse wires isAnimating={isStreaming} and uses streamdown's default link-safety settings (previous enabled: false override has been removed).
  • Global model preference: aiChatModelId lifted out of WorkspaceUiSession into top-level WorkspaceUiState; storage key bumped to v5 to avoid schema collision with the old per-workspace field.

Confidence Score: 5/5

Safe to merge — the refactor is well-scoped and all issues raised in previous reviews have been addressed.

The scroll-anchor logic correctly ties pending indicators to the last user-turn item, the streamdown link-safety override was removed, the duplicate layout constant was consolidated, and the global model store migration is handled cleanly with a version bump. No incorrect data flow, broken state, or missing guards were found across the changed files.

No files require special attention.

Important Files Changed

Filename Overview
src/features/workspaces/components/ai-chat/AiChatMessageList.tsx Replaced @tanstack/react-virtual with @shadcn/react message-scroller primitives; scroll-anchor logic (user messages only) and empty-state overlay are correct; tailPending is now co-located with the last message row rather than a separate key, removing the animation-restart issue.
src/features/workspaces/components/ai-chat/AiChatMessageRow.tsx Rebuilt around Bubble/BubbleContent and new Message/MessageContent/MessageFooter primitives; toolbar hover-visibility via group-hover/message is wired correctly through the Message component's group/message class.
src/features/workspaces/components/ai-chat/AiChatMessageResponse.tsx New component wrapping streamdown for animated streaming markdown; link safety is at streamdown defaults (no explicit disable); animation is correctly gated on isStreaming.
src/features/workspaces/state/workspace-ui-store.ts aiChatModelId lifted from per-workspace session to top-level store state; storage key bumped to v5 to avoid schema collision; partialize correctly serializes the new field.
src/components/ui/message-scroller.tsx Thin wrapper around @shadcn/react message-scroller primitives; scroll-fade and data-autoscrolling:scrollbar-none utilities are applied correctly; jump-to-latest button animation handled via data-active attributes.
src/components/ui/attachment.tsx New attachment primitive built with CVA variants for size/orientation; AttachmentTrigger uses useRender from @base-ui for the overlay button pattern; scroll-fade-x on AttachmentGroup is provided by the local styles.css fallback.
src/features/workspaces/components/ai-chat/ai-chat-attachments.ts Extracted attachment types and utilities from ai-elements; toSendableFileParts correctly filters by status=ready and strips internal id/status fields before sending to the AI SDK.
src/styles.css Added scroll-fade/scroll-fade-x/shimmer utilities as local fallbacks for shadcn utilities not yet in the installed package; shimmer animation is covered by Tailwind's prefers-reduced-motion preflight; streamdown CSS and @source directives added.
src/features/workspaces/components/ai-chat/AiChatAttachmentItem.tsx Rebuilt with new attachment primitives; image preview dialog and remove action are correct; video is intentionally thumbnail-only (40px tile, no controls, as noted in the comment).
src/features/workspaces/components/ai-chat/ai-chat-prompt-input.tsx Moved from ai-elements to feature directory; PromptInput form handling, attachment context, and textarea Enter-key submission logic unchanged from prior implementation.
src/components/ui/bubble.tsx New bubble primitive with ghost/secondary/destructive/tinted/outline variants; BubbleContent uses useRender for polymorphic rendering; oklch colour-mixing for tinted variant is well-scoped.
src/features/workspaces/model/workspace-ui.ts aiChatModelId removed from WorkspaceUiSession; setAiChatModelSession helper removed since model is now global; isSameWorkspaceUiSession updated to match.

Reviews (2): Last reviewed commit: "chore(gitignore): ignore local reference..." | Re-trigger Greptile

Comment thread src/features/workspaces/components/ai-chat/AiChatMessageResponse.tsx Outdated
Comment thread src/features/workspaces/components/ai-chat/ai-chat-layout.ts Outdated
Comment thread src/features/workspaces/components/ai-chat/AiChatAttachmentItem.tsx
…elint violations

Co-authored-by: Codesmith <codesmith-bot@users.noreply.github.com>

@cubic-dev-ai cubic-dev-ai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

1 issue found across 2 files (changes from recent commits).

Prompt for AI agents (unresolved issues)

Check if these issues are valid — if so, understand the root cause of each and fix them. If appropriate, use sub-agents to investigate and fix each issue separately.


<file name="src/features/workspaces/components/ai-chat/AiChatMessageList.tsx">

<violation number="1" location="src/features/workspaces/components/ai-chat/AiChatMessageList.tsx:168">
P2: Reading `previousRowsRef.current` inside `useMemo` accesses a ref during render, which is incompatible with React Compiler memoization. The React Compiler cannot safely memoize code that reads ref values during render since the ref's `.current` value can change without triggering a re-render. Consider moving the previous-row snapshot into state (via `useState`) or computing animation keys from committed state in an effect.</violation>
</file>

Tip: Review your code locally with the cubic CLI to iterate faster.

Re-trigger cubic

Comment thread src/features/workspaces/components/ai-chat/useWorkspaceAiChat.ts Outdated
urjitc and others added 3 commits June 26, 2026 21:06
…ut constant, and video preload

Co-authored-by: Codesmith <codesmith-bot@users.noreply.github.com>
Co-authored-by: Codesmith <codesmith-bot@users.noreply.github.com>
Co-authored-by: Codesmith <codesmith-bot@users.noreply.github.com>

@cubic-dev-ai cubic-dev-ai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

2 issues found across 6 files (changes from recent commits).

Prompt for AI agents (unresolved issues)

Check if these issues are valid — if so, understand the root cause of each and fix them. If appropriate, use sub-agents to investigate and fix each issue separately.


<file name="src/features/workspaces/components/ai-chat/AiChatMessageList.tsx">

<violation number="1" location="src/features/workspaces/components/ai-chat/AiChatMessageList.tsx:168">
P2: Reading `previousRowsRef.current` inside `useMemo` accesses a ref during render, which is incompatible with React Compiler memoization. The React Compiler cannot safely memoize code that reads ref values during render since the ref's `.current` value can change without triggering a re-render. Consider moving the previous-row snapshot into state (via `useState`) or computing animation keys from committed state in an effect.</violation>
</file>

Tip: Review your code locally with the cubic CLI to iterate faster.

Re-trigger cubic

Comment thread src/features/workspaces/components/ai-chat/AiChatAttachmentItem.tsx Outdated
Comment thread src/features/workspaces/components/ai-chat/AiChatMessageResponse.tsx Outdated
urjitc and others added 4 commits June 26, 2026 21:16
Co-authored-by: Codesmith <codesmith-bot@users.noreply.github.com>
…l-relative links

Co-authored-by: Codesmith <codesmith-bot@users.noreply.github.com>
…wn Components type

Co-authored-by: Codesmith <codesmith-bot@users.noreply.github.com>
…er limit

Co-authored-by: Codesmith <codesmith-bot@users.noreply.github.com>

@cubic-dev-ai cubic-dev-ai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

1 issue found across 5 files (changes from recent commits).

Prompt for AI agents (unresolved issues)

Check if these issues are valid — if so, understand the root cause of each and fix them. If appropriate, use sub-agents to investigate and fix each issue separately.


<file name="src/features/workspaces/components/ai-chat/AiChatAttachmentItem.tsx">

<violation number="1" location="src/features/workspaces/components/ai-chat/AiChatAttachmentItem.tsx:171">
P2: Removing `preload="metadata"` from thumbnail-only video attachments may regress thumbnail reliability and increase unnecessary network usage.</violation>
</file>

Tip: Review your code locally with the cubic CLI to iterate faster.

Re-trigger cubic

return (
<AttachmentMedia>
{/* Thumbnail-only tile — controls omitted intentionally (40 px square). */}
<video className="size-full object-cover" muted src={data.url} />

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2: Removing preload="metadata" from thumbnail-only video attachments may regress thumbnail reliability and increase unnecessary network usage.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At src/features/workspaces/components/ai-chat/AiChatAttachmentItem.tsx, line 171:

<comment>Removing `preload="metadata"` from thumbnail-only video attachments may regress thumbnail reliability and increase unnecessary network usage.</comment>

<file context>
@@ -179,13 +167,8 @@ function AiChatAttachmentMedia({ data }: { data: AttachmentData }) {
-					src={data.url}
-				/>
+				{/* Thumbnail-only tile — controls omitted intentionally (40 px square). */}
+				<video className="size-full object-cover" muted src={data.url} />
 			</AttachmentMedia>
 		);
</file context>
Suggested change
<video className="size-full object-cover" muted src={data.url} />
<video className="size-full object-cover" muted preload="metadata" src={data.url} />

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.

The video element matches the original PR commit, which had no preload attribute. A prior review comment (3484167588) correctly identified that preload="metadata" only hints at loading metadata (duration/dimensions) and does not guarantee first-frame rendering — browsers on iOS Safari and other constrained environments may show a blank tile instead. The current state is the right tradeoff.

@urjitc

urjitc commented Jun 26, 2026

Copy link
Copy Markdown
Member Author

@greptile-apps please review again. Updated branch with b388927: simplified the shadcn scroller row model, removed the app-level optimistic user message layer, removed positional assistant row keys and animation-wrapper bookkeeping, restored Streamdown default link safety, and kept the focused Tailwind/scroller/style fixes.

@cubic-dev-ai cubic-dev-ai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

1 issue found across 11 files (changes from recent commits).

Prompt for AI agents (unresolved issues)

Check if these issues are valid — if so, understand the root cause of each and fix them. If appropriate, use sub-agents to investigate and fix each issue separately.


<file name="src/features/workspaces/state/workspace-ui-store.ts">

<violation number="1" location="src/features/workspaces/state/workspace-ui-store.ts:225">
P1: Persisted store version changed without migration path, discarding previously saved workspace UI sessions on upgrade</violation>
</file>

Tip: Review your code locally with the cubic CLI to iterate faster.

Re-trigger cubic

}),
{
name: "thinkex.workspace-ui.v4",
name: "thinkex.workspace-ui.v5",

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P1: Persisted store version changed without migration path, discarding previously saved workspace UI sessions on upgrade

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At src/features/workspaces/state/workspace-ui-store.ts, line 225:

<comment>Persisted store version changed without migration path, discarding previously saved workspace UI sessions on upgrade</comment>

<file context>
@@ -218,9 +222,10 @@ export const useWorkspaceUiStore = create<WorkspaceUiState>()(
 			}),
 			{
-				name: "thinkex.workspace-ui.v4",
+				name: "thinkex.workspace-ui.v5",
 				skipHydration: true,
 				partialize: (state) => ({
</file context>

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.

The store name is still thinkex.workspace-ui.v4 in both the original PR commit and the current HEAD — no version bump occurred in this PR. The comment is based on a diff that does not exist in the actual code.

@urjitc
urjitc merged commit 6b1c8b8 into main Jun 27, 2026
5 checks passed
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant