-
Notifications
You must be signed in to change notification settings - Fork 1.7k
feat: use conversation list smooth #2881
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
|
This pull request has been ignored for the connected project Preview Branches by Supabase. |
|
Warning Rate limit exceeded@Kitenite has exceeded the limit for the number of commits or files that can be reviewed per hour. Please wait 9 minutes and 30 seconds before requesting another review. ⌛ How to resolve this issue?After the wait time has elapsed, a review can be triggered using the 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. 📒 Files selected for processing (1)
Note Other AI code review bot(s) detectedCodeRabbit has detected other AI code review bot(s) in this pull request and will avoid duplicating their findings in the review comments. This may lead to a less comprehensive review. WalkthroughReplaces legacy chat scroll/renderer primitives with new ai-elements Conversation components, removes ChatMessageList/useAutoScroll/MarkdownRenderer, swaps MarkdownRenderer for Response, updates streaming render path, and adds a stick-to-bottom runtime dependency and new Conversation exports. Changes
Sequence Diagram(s)sequenceDiagram
autonumber
actor User
participant ChatTab as Chat Messages (component)
participant Conv as Conversation (StickToBottom)
participant Content as ConversationContent
participant Btn as ConversationScrollButton
User->>ChatTab: Open chat / send message
ChatTab->>Conv: Render Conversation (role="log")
Conv->>Content: Provide stick-to-bottom context
Content-->>ChatTab: Render base messages (Response)
ChatTab-->>Content: If isStreaming → render loading block
Note over Conv,Content: Context tracks isAtBottom and scrollToBottom
par User scrolls up
User->>Conv: Scroll
Conv-->>Btn: isAtBottom=false → show button
and New messages arrive
ChatTab->>Content: Append message(s)
alt isAtBottom
Conv->>Conv: Auto stick to bottom
else not at bottom
Conv-->>Btn: Keep button visible
end
end
User->>Btn: Click
Btn->>Conv: scrollToBottom()
Conv-->>Btn: isAtBottom=true (hide)
Estimated code review effort🎯 4 (Complex) | ⏱️ ~45 minutes Possibly related PRs
Poem
Pre-merge checks and finishing touches✅ Passed checks (3 passed)
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 |
|
|
||
| return ( | ||
| !isAtBottom && ( | ||
| <Button |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
For accessibility, consider adding an aria-label (e.g., 'Scroll to bottom') to the Button rendered by ConversationScrollButton.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 1
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
apps/web/client/src/app/project/[id]/_components/right-panel/chat-tab/chat-messages/user-message.tsx (1)
1-1: Must mark as client componentThis file uses React state/effects and browser APIs; add
'use client'per app-dir rules.+'use client';
🧹 Nitpick comments (5)
packages/ui/src/components/ai-elements/conversation.tsx (2)
12-20: Accessibility: provide label for the live regionAdd an accessible name to the log container to help screen readers identify the region.
export const Conversation = ({ className, ...props }: ConversationProps) => ( <StickToBottom className={cn('relative flex-1 overflow-y-auto', className)} initial="smooth" resize="smooth" - role="log" + role="log" + aria-label="Conversation" {...props} /> );
73-90: Icon-only button needs an accessible nameAdd
aria-label(and optionaltitle) so screen readers can announce the action.!isAtBottom && ( <Button className={cn( 'absolute bottom-4 left-[50%] translate-x-[-50%] rounded-full', className, )} onClick={handleScrollToBottom} + aria-label="Scroll to bottom" + title="Scroll to bottom" size="icon" type="button" variant="outline" {...props} > <ArrowDownIcon className="size-4" /> </Button> )apps/web/client/src/app/project/[id]/_components/right-panel/chat-tab/chat-messages/user-message.tsx (2)
83-90: Localize hardcoded toast copy
'Failed to resubmit message'is hardcoded. Inapps/web/client/src/app/**, usenext-intl.- toast.promise( - onEditMessage(message.id, getUserMessageContent(message), ChatType.EDIT), - { - error: 'Failed to resubmit message', - } - ) + const t = (await import('next-intl')).useTranslations(); + toast.promise( + onEditMessage(message.id, getUserMessageContent(message), ChatType.EDIT), + { error: t(transKeys.chat.retryError) } + );Confirm the actual translation key path (placeholder:
transKeys.chat.retryError) exists.
216-218: Avoid random keys in listsUsing
nanoid()in render causes unstable keys and remounts. Use a stable identifier fromcontextor a deterministic fallback.- {message.metadata?.context?.map((context) => ( - <SentContextPill key={nanoid()} context={context} /> - ))} + {message.metadata?.context?.map((context, i) => ( + <SentContextPill + key={context.id ?? `${context.type}:${context.value ?? i}`} + context={context} + /> + ))}apps/web/client/src/app/project/[id]/_components/right-panel/chat-tab/chat-messages/index.tsx (1)
74-75: Prefer stable key; drop indexIndexes in keys can cause subtle bugs on reordering.
message.idshould be sufficient.- return <div key={`message-${message.id}-${index}`} className="my-2">{messageNode}</div>; + return <div key={`message-${message.id}`} className="my-2">{messageNode}</div>;
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
⛔ Files ignored due to path filters (1)
bun.lockis excluded by!**/*.lock
📒 Files selected for processing (7)
apps/web/client/src/app/project/[id]/_components/right-panel/chat-tab/chat-messages/index.tsx(3 hunks)apps/web/client/src/app/project/[id]/_components/right-panel/chat-tab/chat-messages/user-message.tsx(1 hunks)packages/ui/package.json(1 hunks)packages/ui/src/components/ai-elements/conversation.tsx(1 hunks)packages/ui/src/components/ai-elements/index.tsx(1 hunks)packages/ui/src/components/chat/chat-message-list.tsx(0 hunks)packages/ui/src/components/chat/hooks/use-auto-scroll.tsx(0 hunks)
💤 Files with no reviewable changes (2)
- packages/ui/src/components/chat/chat-message-list.tsx
- packages/ui/src/components/chat/hooks/use-auto-scroll.tsx
🧰 Additional context used
📓 Path-based instructions (6)
**/*.{ts,tsx}
📄 CodeRabbit inference engine (AGENTS.md)
Do not use the any type unless necessary
Files:
packages/ui/src/components/ai-elements/index.tsxapps/web/client/src/app/project/[id]/_components/right-panel/chat-tab/chat-messages/user-message.tsxpackages/ui/src/components/ai-elements/conversation.tsxapps/web/client/src/app/project/[id]/_components/right-panel/chat-tab/chat-messages/index.tsx
{apps,packages}/**/*.{ts,tsx}
📄 CodeRabbit inference engine (CLAUDE.md)
Avoid using the any type unless absolutely necessary
Files:
packages/ui/src/components/ai-elements/index.tsxapps/web/client/src/app/project/[id]/_components/right-panel/chat-tab/chat-messages/user-message.tsxpackages/ui/src/components/ai-elements/conversation.tsxapps/web/client/src/app/project/[id]/_components/right-panel/chat-tab/chat-messages/index.tsx
apps/web/client/src/app/**/*.tsx
📄 CodeRabbit inference engine (AGENTS.md)
apps/web/client/src/app/**/*.tsx: Default to Server Components; add 'use client' when using events, state/effects, browser APIs, or client‑only libraries
Do not use process.env in client code; import env from @/env insteadAvoid hardcoded user-facing text; use next-intl messages/hooks
Files:
apps/web/client/src/app/project/[id]/_components/right-panel/chat-tab/chat-messages/user-message.tsxapps/web/client/src/app/project/[id]/_components/right-panel/chat-tab/chat-messages/index.tsx
apps/web/client/src/**/*.{ts,tsx}
📄 CodeRabbit inference engine (AGENTS.md)
apps/web/client/src/**/*.{ts,tsx}: Use path aliases @/* and ~/* for imports that map to apps/web/client/src/*
Avoid hardcoded user-facing text; use next-intl messages/hooks insteadUse path aliases @/* and ~/* for imports mapping to src/*
Files:
apps/web/client/src/app/project/[id]/_components/right-panel/chat-tab/chat-messages/user-message.tsxapps/web/client/src/app/project/[id]/_components/right-panel/chat-tab/chat-messages/index.tsx
apps/web/client/src/**/*.tsx
📄 CodeRabbit inference engine (AGENTS.md)
apps/web/client/src/**/*.tsx: Create MobX store instances with useState(() => new Store()) for stable references across renders
Keep the active MobX store in a useRef and perform async cleanup with setTimeout(() => storeRef.current?.clear(), 0) to avoid route-change races
Avoid useMemo for creating MobX store instances
Avoid putting the MobX store instance in effect dependency arrays if it causes loops; split concerns by domain
apps/web/client/src/**/*.tsx: Create MobX store instances with useState(() => new Store()) for stable identities across renders
Keep the active MobX store in a useRef and clean up asynchronously with setTimeout(() => storeRef.current?.clear(), 0)
Do not use useMemo to create MobX stores
Avoid placing MobX store instances in effect dependency arrays if it causes loops; split concerns instead
observer components must be client components; place a single client boundary at the feature entry; child observers need not repeat 'use client'
Files:
apps/web/client/src/app/project/[id]/_components/right-panel/chat-tab/chat-messages/user-message.tsxapps/web/client/src/app/project/[id]/_components/right-panel/chat-tab/chat-messages/index.tsx
apps/web/client/src/app/**/*.{ts,tsx}
📄 CodeRabbit inference engine (CLAUDE.md)
Default to Server Components; add 'use client' only when using events, state/effects, browser APIs, or client-only libs
Files:
apps/web/client/src/app/project/[id]/_components/right-panel/chat-tab/chat-messages/user-message.tsxapps/web/client/src/app/project/[id]/_components/right-panel/chat-tab/chat-messages/index.tsx
🧠 Learnings (2)
📚 Learning: 2025-09-16T19:22:52.461Z
Learnt from: CR
PR: onlook-dev/onlook#0
File: CLAUDE.md:0-0
Timestamp: 2025-09-16T19:22:52.461Z
Learning: Applies to apps/web/client/src/app/**/*.tsx : Avoid hardcoded user-facing text; use next-intl messages/hooks
Applied to files:
apps/web/client/src/app/project/[id]/_components/right-panel/chat-tab/chat-messages/user-message.tsx
📚 Learning: 2025-09-14T01:44:21.209Z
Learnt from: CR
PR: onlook-dev/onlook#0
File: AGENTS.md:0-0
Timestamp: 2025-09-14T01:44:21.209Z
Learning: Applies to apps/web/client/src/**/*.{ts,tsx} : Avoid hardcoded user-facing text; use next-intl messages/hooks instead
Applied to files:
apps/web/client/src/app/project/[id]/_components/right-panel/chat-tab/chat-messages/user-message.tsx
🧬 Code graph analysis (1)
apps/web/client/src/app/project/[id]/_components/right-panel/chat-tab/chat-messages/index.tsx (2)
packages/ui/src/components/ai-elements/conversation.tsx (3)
Conversation(12-20)ConversationContent(24-26)ConversationScrollButton(63-90)apps/web/client/src/app/project/[id]/_components/right-panel/chat-tab/chat-messages/error-message.tsx (1)
ErrorMessage(11-63)
🔇 Additional comments (4)
packages/ui/package.json (1)
116-116: LGTM: add runtime dependency for scroll behaviorPlacing
use-stick-to-bottomunderdependencies(not dev/peer) is correct since it’s used at runtime by exported UI components.packages/ui/src/components/ai-elements/index.tsx (1)
2-2: LGTM: re-export conversation primitivesPublicly exposing the conversation components is appropriate and aligns with usage downstream.
apps/web/client/src/app/project/[id]/_components/right-panel/chat-tab/chat-messages/index.tsx (2)
7-11: LGTM: move to Conversation primitivesImports reflect the new Conversation-based layout and are consistent with the UI package.
93-103: Render computed streaming messages (use messages, not baseMessages)Replace baseMessages with the computed messages array so the in‑progress assistant message replaces the "Thinking …" placeholder; localize the placeholder.
- <ConversationContent className="p-0 m-0"> - {baseMessages.map((message, index) => renderMessage(message, index))} + <ConversationContent className="p-0 m-0"> + {messages.map((message, index) => renderMessage(message, index))} {error && <ErrorMessage error={error} />} {isStreaming && <div className="flex w-full h-full flex-row items-center gap-2 px-4 my-2 text-small content-start text-foreground-secondary"> - <Icons.LoadingSpinner className="animate-spin" /> - <p>Thinking ...</p> + <Icons.LoadingSpinner className="animate-spin" /> + <p>{t(transKeys.editor.panels.edit.tabs.chat.thinking)}</p> </div>} </ConversationContent>Ensure transKeys.editor.panels.edit.tabs.chat.thinking exists; add it if missing.
| export type ConversationEmptyStateProps = ComponentProps<'div'> & { | ||
| title?: string; | ||
| description?: string; | ||
| icon?: React.ReactNode; | ||
| }; | ||
|
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fix TS: avoid React.ReactNode without importing React
React.ReactNode requires importing the React namespace. Prefer importing ReactNode type to avoid namespace usage.
Apply:
-import type { ComponentProps } from 'react';
+import type { ComponentProps, ReactNode } from 'react';
@@
export type ConversationEmptyStateProps = ComponentProps<'div'> & {
- title?: string;
- description?: string;
- icon?: React.ReactNode;
+ title?: string;
+ description?: string;
+ icon?: ReactNode;
};📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| export type ConversationEmptyStateProps = ComponentProps<'div'> & { | |
| title?: string; | |
| description?: string; | |
| icon?: React.ReactNode; | |
| }; | |
| import type { ComponentProps, ReactNode } from 'react'; | |
| export type ConversationEmptyStateProps = ComponentProps<'div'> & { | |
| title?: string; | |
| description?: string; | |
| icon?: ReactNode; | |
| }; |
🤖 Prompt for AI Agents
In packages/ui/src/components/ai-elements/conversation.tsx around lines 28 to
33, the prop type uses React.ReactNode which requires the React namespace;
change it to import the ReactNode type and use that instead. Update the file
imports to include `ReactNode` from 'react' (or add it to the existing import)
and replace `icon?: React.ReactNode;` with `icon?: ReactNode;` so the file no
longer relies on the React namespace.
| applied={applied} | ||
| isStream={isStream} | ||
| /> | ||
| <Response key={part.text}> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Replacing MarkdownRenderer with Response: ensure that any required markdown formatting is still handled. Also, using part.text as a key might lead to duplicates if texts repeat—consider a more unique identifier.
| <Response key={part.text}> | |
| <Response key={`${part.text}-${idx}`}> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 1
♻️ Duplicate comments (1)
apps/web/client/src/app/project/[id]/_components/right-panel/chat-tab/chat-messages/message-content/index.tsx (1)
24-26: Use stable, unique keys for streaming and duplicate texts
key={part.text}can collide for repeated texts and can cause remounts while streaming as the text changes. Prefer a stable composite key.- <Response key={part.text}> + <Response key={`${messageId}-text-${idx}`}> {part.text} </Response>
🧹 Nitpick comments (1)
apps/web/client/src/app/project/[id]/_components/right-panel/chat-tab/chat-messages/message-content/index.tsx (1)
43-49: Same key issue for ReasoningAvoid
key={part.text}here as well; use a stable composite key.- return ( - <Reasoning key={part.text} className={cn( + return ( + <Reasoning key={`${messageId}-reasoning-${idx}`} className={cn( "px-2 m-0 items-center gap-2 text-foreground-tertiary", isStream && isLastPart && "bg-gradient-to-l from-white/20 via-white/90 to-white/20 bg-[length:200%_100%] bg-clip-text text-transparent animate-shimmer filter drop-shadow-[0_0_10px_rgba(255,255,255,0.4)]" )} isStreaming={isStream}>
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (3)
apps/web/client/src/app/project/[id]/_components/right-panel/chat-tab/chat-messages/markdown-renderer.tsx(0 hunks)apps/web/client/src/app/project/[id]/_components/right-panel/chat-tab/chat-messages/message-content/index.tsx(2 hunks)packages/ui/src/globals.css(1 hunks)
💤 Files with no reviewable changes (1)
- apps/web/client/src/app/project/[id]/_components/right-panel/chat-tab/chat-messages/markdown-renderer.tsx
✅ Files skipped from review due to trivial changes (1)
- packages/ui/src/globals.css
🧰 Additional context used
📓 Path-based instructions (6)
apps/web/client/src/app/**/*.tsx
📄 CodeRabbit inference engine (AGENTS.md)
apps/web/client/src/app/**/*.tsx: Default to Server Components; add 'use client' when using events, state/effects, browser APIs, or client‑only libraries
Do not use process.env in client code; import env from @/env insteadAvoid hardcoded user-facing text; use next-intl messages/hooks
Files:
apps/web/client/src/app/project/[id]/_components/right-panel/chat-tab/chat-messages/message-content/index.tsx
apps/web/client/src/**/*.{ts,tsx}
📄 CodeRabbit inference engine (AGENTS.md)
apps/web/client/src/**/*.{ts,tsx}: Use path aliases @/* and ~/* for imports that map to apps/web/client/src/*
Avoid hardcoded user-facing text; use next-intl messages/hooks insteadUse path aliases @/* and ~/* for imports mapping to src/*
Files:
apps/web/client/src/app/project/[id]/_components/right-panel/chat-tab/chat-messages/message-content/index.tsx
apps/web/client/src/**/*.tsx
📄 CodeRabbit inference engine (AGENTS.md)
apps/web/client/src/**/*.tsx: Create MobX store instances with useState(() => new Store()) for stable references across renders
Keep the active MobX store in a useRef and perform async cleanup with setTimeout(() => storeRef.current?.clear(), 0) to avoid route-change races
Avoid useMemo for creating MobX store instances
Avoid putting the MobX store instance in effect dependency arrays if it causes loops; split concerns by domain
apps/web/client/src/**/*.tsx: Create MobX store instances with useState(() => new Store()) for stable identities across renders
Keep the active MobX store in a useRef and clean up asynchronously with setTimeout(() => storeRef.current?.clear(), 0)
Do not use useMemo to create MobX stores
Avoid placing MobX store instances in effect dependency arrays if it causes loops; split concerns instead
observer components must be client components; place a single client boundary at the feature entry; child observers need not repeat 'use client'
Files:
apps/web/client/src/app/project/[id]/_components/right-panel/chat-tab/chat-messages/message-content/index.tsx
**/*.{ts,tsx}
📄 CodeRabbit inference engine (AGENTS.md)
Do not use the any type unless necessary
Files:
apps/web/client/src/app/project/[id]/_components/right-panel/chat-tab/chat-messages/message-content/index.tsx
apps/web/client/src/app/**/*.{ts,tsx}
📄 CodeRabbit inference engine (CLAUDE.md)
Default to Server Components; add 'use client' only when using events, state/effects, browser APIs, or client-only libs
Files:
apps/web/client/src/app/project/[id]/_components/right-panel/chat-tab/chat-messages/message-content/index.tsx
{apps,packages}/**/*.{ts,tsx}
📄 CodeRabbit inference engine (CLAUDE.md)
Avoid using the any type unless absolutely necessary
Files:
apps/web/client/src/app/project/[id]/_components/right-panel/chat-tab/chat-messages/message-content/index.tsx
🧬 Code graph analysis (1)
apps/web/client/src/app/project/[id]/_components/right-panel/chat-tab/chat-messages/message-content/index.tsx (1)
packages/ui/src/components/ai-elements/response.tsx (1)
Response(9-17)
🔇 Additional comments (1)
apps/web/client/src/app/project/[id]/_components/right-panel/chat-tab/chat-messages/message-content/index.tsx (1)
2-2: Confirm 'use client' boundary for MobX + client-only ai-elementsapps/web/client/src/app/project/[id]/_components/right-panel/chat-tab/chat-messages/message-content/index.tsx uses mobx-react-lite's observer and @onlook/ui/ai-elements but contains no "use client" and no ancestor under apps/web/client/src/app/project includes "use client". Ensure this component is rendered under a client boundary — add "use client" at the feature entry (recommended) or convert this file to a client component; if it's unused, confirm and remove.
| <Response key={part.text}> | ||
| {part.text} | ||
| </Response> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🧩 Analysis chain
Verify Streamdown/Response sanitization (XSS guard)
Rendering user-supplied markdown/HTML must be sanitized. Please confirm Response/Streamdown escapes or sanitizes content.
🏁 Script executed:
#!/bin/bash
# Inspect UI package for unsafe HTML usage
rg -n 'dangerouslySetInnerHTML|sanitize|dompurify|xss' packages/ui -C2
rg -nP 'class\s+Streamdown|function\s+Streamdown' packages/ui -C3Length of output: 840
🏁 Script executed:
#!/bin/bash
set -euo pipefail
echo "---- showing target file ----"
sed -n '1,240p' apps/web/client/src/app/project/[id]/_components/right-panel/chat-tab/chat-messages/message-content/index.tsx || true
echo
echo "---- find Response component definitions/usages ----"
rg -n --hidden --glob '!node_modules' -S "(\bfunction\s+Response\b|\bconst\s+Response\b|\bexport\s+const\s+Response\b|\bexport\s+function\s+Response\b)" || true
rg -n --hidden --glob '!node_modules' -S "\b<Response\b" || true
echo
echo "---- find Streamdown definitions/usages ----"
rg -n --hidden --glob '!node_modules' -S "Streamdown" || true
echo
echo "---- find dangerouslySetInnerHTML across repo ----"
rg -n --hidden --glob '!node_modules' -S "dangerouslySetInnerHTML" || true
echo
echo "---- find common sanitizer libraries/usages ----"
rg -n --hidden --glob '!node_modules' -S "dompurify|DOMPurify|sanitize-html|sanitizeHtml|sanitize\\(|xss|isTrusted" || trueLength of output: 3184
🏁 Script executed:
#!/bin/bash
set -euo pipefail
echo "---- packages/ui src index (if exists) ----"
if [ -f packages/ui/src/index.ts ]; then
sed -n '1,240p' packages/ui/src/index.ts
else
echo "no packages/ui/src/index.ts"
fi
echo
echo "---- search for ai-elements export/import ----"
rg -n "@onlook/ui/ai-elements|\\bai-elements\\b" --hidden -S || true
echo
echo "---- search for Response component definitions/usages in packages/ui ----"
rg -n --hidden -S "(^export\\s+.*Response|\\bfunction\\s+Response\\b|\\bconst\\s+Response\\b|\\bclass\\s+Response\\b|<Response\\b)" packages/ui || true
echo
echo "---- search for Streamdown in repo ----"
rg -n --hidden -S "Streamdown" || true
echo
echo "---- search for dangerouslySetInnerHTML in repo ----"
rg -n --hidden -S "dangerouslySetInnerHTML" || true
echo
echo "---- search for DOMPurify or sanitize libs in repo ----"
rg -n --hidden -S "DOMPurify|dompurify|sanitize-html|sanitizeHtml|xss" || true
echo
echo "---- show any files that export from ai-elements in packages/ui ----"
rg -n --hidden -S "export .*from .*ai-elements" packages || trueLength of output: 3064
🏁 Script executed:
#!/bin/bash
set -euo pipefail
echo "---- cat response.tsx ----"
sed -n '1,320p' packages/ui/src/components/ai-elements/response.tsx || true
echo
echo "---- show surrounding ai-elements files ----"
ls -la packages/ui/src/components/ai-elements || true
echo
echo "---- search for Streamdown usage across repo ----"
rg -n --hidden -S "Streamdown" || true
echo
echo "---- search for any HTML rendering in response.tsx ----"
rg -n --hidden -n --context 3 "dangerouslySetInnerHTML|innerHTML|html" packages/ui/src/components/ai-elements/response.tsx || trueLength of output: 1434
Ensure HTML sanitization for Response/Streamdown output
Response is a thin wrapper over Streamdown and does not perform any escaping or sanitization itself—confirm that Streamdown is configured to strip or escape user-supplied HTML, or explicitly sanitize the rendered output (e.g. with DOMPurify) before passing it to Streamdown.
Description
Related Issues
Type of Change
Testing
Screenshots (if applicable)
Additional Notes
Important
Introduces a new conversation-style chat layout with sticky-to-bottom behavior and refactors message rendering to use unified components.
Conversation,ConversationContent,ConversationScrollButton, andConversationEmptyStatecomponents inconversation.tsxfor a new chat layout.use-stick-to-bottom.ChatMessageListwithConversationcomponents inindex.tsx.markdown-renderer.tsxanduse-auto-scroll.tsx.Responsecomponent inmessage-content/index.tsx.use-stick-to-bottomdependency inpackage.json.globals.cssto includestreamdownstyles.This description was created by
for 3e0e263. You can customize this summary. It will automatically update as commits are pushed.
Summary by CodeRabbit
New Features
Refactor
Chores