|
2 | 2 |
|
3 | 3 | import { type ComponentProps } from 'react'; |
4 | 4 | import { type AgentState, type ReceivedMessage } from '@livekit/components-react'; |
| 5 | +import { Streamdown } from 'streamdown'; |
| 6 | +import { Bubble, BubbleContent } from '@/components/ui/bubble'; |
| 7 | +import { Message, MessageContent } from '@/components/ui/message'; |
5 | 8 | import { |
6 | | - Conversation, |
7 | | - ConversationContent, |
8 | | - ConversationScrollButton, |
9 | | -} from '@/components/ai-elements/conversation'; |
10 | | -import { Message, MessageContent, MessageResponse } from '@/components/ai-elements/message'; |
| 9 | + MessageScroller, |
| 10 | + MessageScrollerButton, |
| 11 | + MessageScrollerContent, |
| 12 | + MessageScrollerItem, |
| 13 | + MessageScrollerProvider, |
| 14 | + MessageScrollerViewport, |
| 15 | +} from '@/components/ui/message-scroller'; |
11 | 16 | import { AgentChatIndicator } from '@/components/agents-ui/agent-chat-indicator'; |
12 | 17 | import { AnimatePresence } from 'motion/react'; |
13 | 18 |
|
@@ -52,28 +57,38 @@ export function AgentChatTranscript({ |
52 | 57 | ...props |
53 | 58 | }: AgentChatTranscriptProps) { |
54 | 59 | return ( |
55 | | - <Conversation className={className} {...props}> |
56 | | - <ConversationContent> |
57 | | - {messages.map((receivedMessage) => { |
58 | | - const { id, timestamp, from, message } = receivedMessage; |
59 | | - const time = new Date(timestamp); |
60 | | - const messageOrigin = from?.isLocal ? 'user' : 'assistant'; |
61 | | - const locale = typeof navigator !== 'undefined' ? navigator.language : 'en-US'; |
62 | | - const title = time.toLocaleTimeString(locale, { timeStyle: 'full' }); |
| 60 | + <MessageScrollerProvider autoScroll defaultScrollPosition="last-anchor"> |
| 61 | + <MessageScroller className={className} {...props}> |
| 62 | + <MessageScrollerViewport> |
| 63 | + <MessageScrollerContent aria-busy={agentState === 'thinking'}> |
| 64 | + {messages.map((receivedMessage) => { |
| 65 | + const { id, timestamp, from, message } = receivedMessage; |
| 66 | + const time = new Date(timestamp); |
| 67 | + const isUser = from?.isLocal; |
| 68 | + const locale = typeof navigator !== 'undefined' ? navigator.language : 'en-US'; |
| 69 | + const title = time.toLocaleTimeString(locale, { timeStyle: 'full' }); |
63 | 70 |
|
64 | | - return ( |
65 | | - <Message key={id} title={title} from={messageOrigin}> |
66 | | - <MessageContent> |
67 | | - <MessageResponse>{message}</MessageResponse> |
68 | | - </MessageContent> |
69 | | - </Message> |
70 | | - ); |
71 | | - })} |
72 | | - <AnimatePresence> |
73 | | - {agentState === 'thinking' && <AgentChatIndicator size="sm" />} |
74 | | - </AnimatePresence> |
75 | | - </ConversationContent> |
76 | | - <ConversationScrollButton /> |
77 | | - </Conversation> |
| 71 | + return ( |
| 72 | + <MessageScrollerItem key={id} messageId={id} scrollAnchor={isUser}> |
| 73 | + <Message align={isUser ? 'end' : 'start'} title={title}> |
| 74 | + <MessageContent> |
| 75 | + <Bubble align={isUser ? 'end' : 'start'} variant={isUser ? 'secondary' : 'ghost'}> |
| 76 | + <BubbleContent> |
| 77 | + <Streamdown>{message}</Streamdown> |
| 78 | + </BubbleContent> |
| 79 | + </Bubble> |
| 80 | + </MessageContent> |
| 81 | + </Message> |
| 82 | + </MessageScrollerItem> |
| 83 | + ); |
| 84 | + })} |
| 85 | + <AnimatePresence> |
| 86 | + {agentState === 'thinking' && <AgentChatIndicator size="sm" />} |
| 87 | + </AnimatePresence> |
| 88 | + </MessageScrollerContent> |
| 89 | + </MessageScrollerViewport> |
| 90 | + <MessageScrollerButton /> |
| 91 | + </MessageScroller> |
| 92 | + </MessageScrollerProvider> |
78 | 93 | ); |
79 | 94 | } |
0 commit comments