<AIChatLog><AIChatMessage variant="user"><AIChatMessageAuthor aria-label="You said at 2:36pm" avatarName="Gibby Radki">You</AIChatMessageAuthor><AIChatMessageBody>What does the SMS delivery error code 30003 mean?</AIChatMessageBody></AIChatMessage><AIChatMessage variant="bot"><AIChatMessageAuthor aria-label="AI said">Good Bot</AIChatMessageAuthor><AIChatMessageBody>Here is what I found, error code 30003 means: The destination phone is unavailable or turned off, or it may be a landline or phone that doesn't support SMS.</AIChatMessageBody></AIChatMessage></AIChatLog>
An AI Chat Log is a way to display conversations between a user and AI. If you are looking for a chat between 2 or more humans, please refer to Chat Log.
The AI Chat Log package includes these main components:
- AIChatLog
- AIChatMessage
- AIChatMessageAuthor
- AIChatMessageBody
- AIChatMessageActionGroup
- AIChatMessageActionCard
- AIChatMessageLoading
To ensure the chat is accessible, only use the AI Chat components within an AIChatLog
component and use AIChatMessage
to wrap AIChatMessageBody
, AIChatMessageActionGroup
and components together.
The only other accessibility requirement is providing the AIChatMessageActionCard
a descriptive label via the aria-label
React prop.
The AIChatLog component has role="log"
which means that any new messages added to it are announced by assistive technology.
A message must include the author and body. Any message text from a user or a bot must be contained within the AIChatMessageBody
component. Due to lengthy AI responses, the chat layout is top-down.
const BasicMessage = () => {return (<AIChatLog><AIChatMessage variant="bot"><AIChatMessageAuthor aria-label="AI said">Good Bot</AIChatMessageAuthor><AIChatMessageBody>Here is what I found, error code 30003 means: The destination phone is unavailable or turned off, or it may be a landline or phone that doesn't support SMS.</AIChatMessageBody></AIChatMessage></AIChatLog>);};render(<BasicMessage />)
const BasicMessage = () => {return (<AIChatLog><AIChatMessage variant="user"><AIChatMessageAuthor aria-label="You said at 2:36pm" avatarName="Gibby Radki">You</AIChatMessageAuthor><AIChatMessageBody>I would like some information on twilio error codes for undelivered messages</AIChatMessageBody></AIChatMessage></AIChatLog>);};render(<BasicMessage />)
The AIChatMessageBody
component has two sizes, size="default"
and size="fullScreen"
. The fullScreen size is used where the ChatLog is displayed in the full width of the page where larger font size is needed.
<AIChatLog><AIChatMessage variant="user"><AIChatMessageAuthor aria-label="You said" avatarName="Gibby Radki">You</AIChatMessageAuthor><AIChatMessageBody size="default">I'm a message that should be displayed in compact elements</AIChatMessageBody></AIChatMessage><AIChatMessage variant="user"><AIChatMessageAuthor aria-label="You said" avatarName="Gibby Radki">You</AIChatMessageAuthor><AIChatMessageBody size="fullScreen">I'm a message that will be displayed in full screen width</AIChatMessageBody></AIChatMessage></AIChatLog>
Message actions can be used to provide quick responses or actions to the user.
AIChatMessageActionGroup
should be a child of AIChatMessage
so that the text and meta information are correctly grouped together for assistive technologies. AIChatMessageActionCard
also needs a readable aria-label
that summarizes what the meta information says.
Each item within AIChatMessageActionGroup
should be wrapped with AIChatMessageActionCard
. It is recommended to use reset button variants for content within AIChatMessageActionCard
.
Actions can still be added in AIChatMessageBody
which are returned from the AI response.
const MessageWithFeedback = () => {return (<AIChatLog><AIChatMessage variant="bot"><AIChatMessageAuthor aria-label="AI said">Good Bot</AIChatMessageAuthor><AIChatMessageBody>Here is what I found, error code 30003 means: The destination phone is unavailable or turned off, or it may be a landline or phone that doesn't support SMS.</AIChatMessageBody><AIChatMessageActionGroup><AIChatMessageActionCard aria-label="Feedback form">Is this helpful?<Button variant="reset" size="reset" aria-label="this is a helpful response"><ThumbsUpIcon decorative={false} title="like result" /></Button><Button variant="reset" size="reset"><ThumbsDownIcon decorative={false} title="dislike result" aria-label="this is not a helpful response" /></Button></AIChatMessageActionCard><AIChatMessageActionCard aria-label="Rewrite and copy buttons"><Button variant="reset" size="reset"><RefreshIcon decorative={true}/> Rewrite</Button><Button variant="reset" size="reset"><CopyIcon decorative={true}/> Copy</Button></AIChatMessageActionCard></AIChatMessageActionGroup></AIChatMessage></AIChatLog>);};render(<MessageWithFeedback />)
const MessageWithFeedback = () => {return (<AIChatLog><AIChatMessage variant="bot"><AIChatMessageAuthor aria-label="AI said">Good Bot</AIChatMessageAuthor><AIChatMessageBody><Paragraph>Below is a list of actions that can be taken with flex wrapping supported:</Paragraph><ButtonGroup><Button variant="secondary" size="rounded_small" onClick={() => {}} >View Logs</Button><Button variant="secondary" size="rounded_small" onClick={() => {}}>Run Diagnostics</Button><Button variant="secondary" size="rounded_small" onClick={() => {}}>Submit Bug Report</Button></ButtonGroup></AIChatMessageBody></AIChatMessage></AIChatLog>);};render(<MessageWithFeedback />)
Use the AIChatMessageLoading
component to indicate that the bot is typing or processing a response. During this time no user input should be accepted. No new messages should be added to a chat until the AI operation is finished processing.
The SkeletonLoader lengths vary on each render to give a more natural pending message body interaction.
const MessageWithLoading = () => {return (<AIChatLog><AIChatMessage variant="bot"><AIChatMessageAuthor aria-label="AI said">Good Bot</AIChatMessageAuthor><AIChatMessageBody><AIChatMessageLoading /></AIChatMessageBody></AIChatMessage></AIChatLog>);};render(<MessageWithLoading />)
const MessageWithLoadingAndStop = () => {return (<AIChatLog><AIChatMessage variant="bot"><AIChatMessageAuthor aria-label="AI said">Good Bot</AIChatMessageAuthor><AIChatMessageBody><AIChatMessageLoading onStopLoading={() => {}} /></AIChatMessageBody></AIChatMessage></AIChatLog>);};render(<MessageWithLoadingAndStop />)
The AIChatMessageBody
component has an optional animated
prop that can be used to apply a typewriter animation to the text. This should only be applied to the messages received from the AI.
It also accepts onAnimationStart
and onAnimationEnd
props to trigger actions when the animation starts and ends allowing additional logic such as scrolling to be implemented.
If you are using a Markdown parser to render the message body we recommend using markdown-to-jsx. It allows you to pass in Paste components to replace specific markdown elements. You can view our implementation for the Paste Assistant for an example. AIChatMessageBody implementation, Markdown options implementation
const exampleAIResponseText ="Twilio error codes are numeric codes returned by the Twilio API when an error occurs during a request, providing specific information about the problem encountered, such as invalid phone numbers, network issues, or authentication failures; they help developers identify and troubleshoot issues within their applications using Twilio services";const AnimatedBotScrollable = () => {const [isAnimating, setIsAnimating] = React.useState(false);const [userInterctedScroll, setUserInteractedScroll] = React.useState(false);const loggerRef = React.useRef(null);const scrollerRef = React.useRef(null);const { aiChats, push } = useAIChatLogger({variant: "bot",content: (<AIChatMessage variant="bot"><AIChatMessageAuthor aria-label="AI said">Good Bot</AIChatMessageAuthor><AIChatMessageBody>{exampleAIResponseText}</AIChatMessageBody></AIChatMessage>),});const scrollToChatEnd = () => {const scrollPosition = scrollerRef.current;const scrollHeight = loggerRef.current;scrollPosition?.scrollTo({ top: scrollHeight.scrollHeight, behavior: "smooth" });};const userScrolled = () => setUserInteractedScroll(true);const onAnimationEnd = () => {setIsAnimating(false);setUserInteractedScroll(false);};const onAnimationStart = () => {setUserInteractedScroll(false);setIsAnimating(true);};React.useEffect(() => {scrollerRef.current?.addEventListener("wheel", userScrolled);scrollerRef.current?.addEventListener("touchmove", userScrolled);const interval = setInterval(() => isAnimating && !userInterctedScroll && scrollToChatEnd(), 5);return () => {if (interval) clearInterval(interval);scrollerRef.current?.removeEventListener("wheel", userScrolled);scrollerRef.current?.removeEventListener("touchmove", userScrolled);};}, [isAnimating, userInterctedScroll, scrollerRef]);const pushLargeBotMessage = () => {push({variant: "bot",content: (<AIChatMessage variant="bot"><AIChatMessageAuthor aria-label="Bot said">Good Bot</AIChatMessageAuthor><AIChatMessageBody animated onAnimationEnd={onAnimationEnd} onAnimationStart={onAnimationStart}>{exampleAIResponseText}</AIChatMessageBody></AIChatMessage>),});};return (<Box><Box paddingX="space10" height="size20" overflowY="auto" ref={scrollerRef}><AIChatLogger ref={loggerRef} aiChats={aiChats} /></Box><Button variant="primary" onClick={pushLargeBotMessage}>Add animated bot message</Button></Box>);};render(<AnimatedBotScrollable />)
AIChatMessageAuthor
can be customized by passing an icon, image, or string to the avatarIcon
, avatarSrc
, or avatarName
props. Learn more about the API.
const AvatarExample = () => {return (<AIChatLog><AIChatMessage variant="user"><AIChatMessageAuthor avatarIcon={LogoTwilioIcon} aria-label="You said" avatarName="Gibby Radki">You</AIChatMessageAuthor></AIChatMessage><AIChatMessage variant="user"><AIChatMessageAuthor avatarSrc={Logo.src} aria-label="You said" avatarName="Gibby Radki">You</AIChatMessageAuthor></AIChatMessage></AIChatLog>);};render(<AvatarExample />)
This example combines all the separate features displayed previously into one example. It shows how all the features work together harmoniously through composition.
const AIChatLogExample = () => {return (<AIChatLog><AIChatMessage variant="user"><AIChatMessageAuthor aria-label="You said" avatarName="Gibby Radki">You</AIChatMessageAuthor><AIChatMessageBody>Hi, I'm getting errors codes when sending an SMS.</AIChatMessageBody></AIChatMessage><AIChatMessage variant="bot"><AIChatMessageAuthor aria-label="AI said">Good Bot</AIChatMessageAuthor><AIChatMessageBody><Paragraph>Error codes can be returned from various parts of the process. What error codes are you encountering?</Paragragh><ButtonGroup><Button variant="secondary" size="rounded_small" onClick={() => {}} >21608</Button><Button variant="secondary" size="rounded_small" onClick={() => {}}>30007</Button><Button variant="secondary" size="rounded_small" onClick={() => {}}>30009</Button></ButtonGroup></AIChatMessageBody></AIChatMessage><AIChatMessage variant="bot"><AIChatMessageAuthor aria-label="AI said">Good Bot</AIChatMessageAuthor><AIChatMessageBody>Error 21608 means you're trying to send a message from an unverified number. Is your number verified in your Twilio account?</AIChatMessageBody><AIChatMessageActionGroup><AIChatMessageActionCard aria-label="Feedback form">Is this helpful?<Button variant="reset" size="reset" aria-label="this is a helpful response"><ThumbsUpIcon decorative={false} title="like result" /></Button><Button variant="reset" size="reset"><ThumbsDownIcon decorative={false} title="dislike result" aria-label="this is not a helpful response"/></Button></AIChatMessageActionCard></AIChatMessageActionGroup></AIChatMessage><AIChatMessage variant="user"><AIChatMessageAuthor aria-label="You said" bot avatarName="Gibby Radki">You</AIChatMessageAuthor><AIChatMessageBody>No, how do I verify it?</AIChatMessageBody></AIChatMessage><AIChatMessage variant="bot"><AIChatMessageAuthor aria-label="AI said" bot>Good Bot</AIChatMessageAuthor><AIChatMessageBody><AIChatMessageLoading onStopLoading={() => {}} /></AIChatMessageBody></AIChatMessage></AIChatLog>);};render(<AIChatLogExample />)
The useAIChatLogger
hook provides a hook-based approach to managing AI chat state. It is best used with the <AIChatLogger />
component.
useAIChatLogger
returns 4 things:
- An array of
aiChats
. - A
push
method used to add a chat, optionally with a custom ID. - A
pop
method used to remove a chat, optionally via its ID. - A
clear
method used to remove all chats.
The <AIChatLogger />
component handles rendering the chats it is passed via props. It handles how chats enter and leave the UI.
const { aiChats } = useAIChatLogger();
return <AIChatLogger aiChats={aiChats} />;
You can push or pop a chat based on an action or event. In this example it's based on a button click:
const aiChatFactory = ([ message, variant, metaLabel, meta ]) => {const time = new Date(0).toLocaleString('en-US',{ hour: 'numeric', minute: 'numeric', timeZone: 'UTC', hour12: true })return {variant,content: (<AIChatMessage variant={variant}><AIChatMessageAuthor aria-label={metaLabel + time} avatarName={variant === 'bot' ? undefined : "Gibby Radki"}>{meta}</AIChatMessageAuthor><AIChatMessageBody>{message}</AIChatMessageBody></AIChatMessage>)}};const chatTemplates = [["Hello", "user", "You said at ", "You"],["Hi there", "bot", "AI said at ", "Good Bot"],["Greetings", "user", "You said at ", "You"],["Good to meet you", "bot", "AI said at ", "Good Bot"]];const AIChatLoggerExample = () => {const [templateIdx, setTemplateIdx] = React.useState(2);const { aiChats, push, pop, clear } = useAIChatLogger(aiChatFactory(chatTemplates[0]),aiChatFactory(chatTemplates[1]));const [loading, setLoading] = React.useState(false);const pushChat = () => {const template = chatTemplates[templateIdx];setTemplateIdx((idx) => ++idx % chatTemplates.length);const chat = aiChatFactory(template);if (template[1] === "bot") {const id = uid(chat.content);setLoading(true);push({id,variant: template[1],content: (<AIChatMessage variant="bot"><AIChatMessageAuthor aria-label="AI said">Good Bot</AIChatMessageAuthor><AIChatMessageBody><AIChatMessageLoading /></AIChatMessageBody></AIChatMessage>),});setTimeout(() => {pop(id);setLoading(false);push(chat);}, 1000);} else {push(chat);}}const popChat = () => {pop();setTemplateIdx((idx) => idx === 0 ? idx : --idx % chatTemplates.length);}return(<Stack orientation="vertical"><ButtonGroup><Button variant="primary" disabled={loading} onClick={pushChat}>Push Chat</Button><Button variant="primary" disabled={loading} onClick={popChat}>Pop Chat</Button><Button variant="primary" disabled={loading} onClick={clear}>Clear Chat</Button></ButtonGroup><AIChatLogger aiChats={aiChats} /></Stack>)}render(<AIChatLoggerExample />);
Keep any generated responses from the AI contained in the AIChatMessageBody
component. Each chat message should only have one AIChatMessageBody
component.
- Don’t accumulate error states in one screen, just display one error at a time, starting with the most critical one, until the user recovers.
- Check content guidelines for error states.
- Include another way for users to contact support if the error persists.
An error generating or regenerating a response
- Use a Callout to show an inline error.
- The Callout should replace the body message if no response was generated, or appear between the
AIChatMessageBody
and theAIChatMessageActionGroup
if the response is incomplete. - Include an in-chat action to recover (For example: regenerate or try again)
- Include a way for users to contact support if the error persists.
const MessageGenerationError = () => {return (<><AIChatLog><AIChatMessage variant="user"><AIChatMessageAuthor aria-label="You said at 2:36pm" avatarName="Gibby Ridki">You</AIChatMessageAuthor><AIChatMessageBody>Message filtered (30007)</AIChatMessageBody></AIChatMessage><AIChatMessage variant="bot"><AIChatMessageAuthor aria-label="AI said">Good Bot</AIChatMessageAuthor><AIChatMessageBody><Callout variant="error"><CalloutHeading as="h3">There was an error generating a response.</CalloutHeading><CalloutText>Please try again, if the error persists please <Anchor href="#">contact us</Anchor>.</CalloutText></Callout></AIChatMessageBody><AIChatMessageActionGroup><AIChatMessageActionCard aria-label="Feedback form"><Button variant="secondary_icon" aria-label="this is not a helpful response" size="reset"><RefreshIcon decorative title="dislike result" />Regenerate</Button></AIChatMessageActionCard></AIChatMessageActionGroup></AIChatMessage></AIChatLog><Box marginTop="space70"><ChatComposerContainer variant="contained"><ChatComposermaxHeight="size10"config={{namespace: "foo",onError: (error) => {throw error;},}}ariaLabel="Message"placeholder="Type here..."><ClearEditorPlugin /></ChatComposer><ChatComposerActionGroup><Button variant="secondary_icon" size="reset"><AttachIcon decorative={false} title="attach a file to your message" /></Button><Button variant="primary_icon" size="reset"><SendIcon decorative={false} title="Send" /></Button></ChatComposerActionGroup></ChatComposerContainer></Box></>);};render(<MessageGenerationError />)
An error when clicking on an Action that generates an AI response
- The Callout is placed under the response and action
- Include another way for users to contact support if the error persists.
const AIActionClickError = () => {return (<><AIChatLog><AIChatMessage variant="user"><AIChatMessageAuthor aria-label="You said at 2:36pm" avatarName="Gibby Ridki">You</AIChatMessageAuthor><AIChatMessageBody>Message filtered (30007)</AIChatMessageBody></AIChatMessage><AIChatMessage variant="bot"><AIChatMessageAuthor aria-label="AI said">Good Bot</AIChatMessageAuthor><AIChatMessageBody>We recommend reviewing our guidelines on filtering and scaling to better manage high volumes of messages.<Box paddingY="space50"><ButtonGroup><Button variant="secondary" size="rounded_small">30007</Button><Button variant="secondary" size="rounded_small">30007</Button><Button variant="secondary" size="rounded_small">30009</Button></ButtonGroup></Box><Callout variant="error"><CalloutHeading as="h3">The action couldn’t be completed.</CalloutHeading><CalloutText>Please try again, if the error persists please <Anchor href="#">contact us</Anchor>.</CalloutText></Callout></AIChatMessageBody></AIChatMessage></AIChatLog><Box marginTop="space70"><ChatComposerContainer variant="contained"><ChatComposermaxHeight="size10"config={{namespace: "foo",onError: (error) => {throw error;},}}ariaLabel="Message"placeholder="Type here..."><ClearEditorPlugin /></ChatComposer><ChatComposerActionGroup><Button variant="secondary_icon" size="reset"><AttachIcon decorative={false} title="attach a file to your message" /></Button><Button variant="primary_icon" size="reset"><SendIcon decorative={false} title="Send" /></Button></ChatComposerActionGroup></ChatComposerContainer></Box></>);};render(<AIActionClickError />)
An error when clicking actions on AI messages (clicking buttons, links)
- Use Help text error variant for actions not directly tied to generating a response or continuing the conversation, such as copying text or rating a response.
const ActionGroupError = () => {return (<><AIChatLog><AIChatMessage variant="user"><AIChatMessageAuthor aria-label="You said at 2:36pm" avatarName="Gibby Ridki">You</AIChatMessageAuthor><AIChatMessageBody>Message body text</AIChatMessageBody></AIChatMessage><AIChatMessage variant="bot"><AIChatMessageAuthor aria-label="AI said">Good Bot</AIChatMessageAuthor><AIChatMessageBody>Message body text<Box marginTop="space50"><SummaryDetail><SummaryDetailHeading><SummaryDetailToggleButton aria-label="BOOP" /><SummaryDetailHeadingContent><Text as="p" fontWeight="fontWeightBold">View data sources</Text></SummaryDetailHeadingContent></SummaryDetailHeading><SummaryDetailContent>Data Content</SummaryDetailContent></SummaryDetail></Box><AIChatMessageActionGroup><AIChatMessageActionCard aria-label="Feedback form">Is this helpful?<Button variant="reset" size="reset" aria-label="this is a helpful response"><ThumbsUpIcon decorative={false} title="like result" /></Button><Button variant="reset" size="reset" aria-label="this is not a helpful response"><ThumbsDownIcon decorative={false} title="dislike result" /></Button></AIChatMessageActionCard><AIChatMessageActionCard aria-label="Feedback form"><Button variant="secondary_icon" aria-label="this is not a helpful response" size="reset"><RefreshIcon decorative title="dislike result" />Regenerate</Button><Button variant="secondary_icon" aria-label="this is not a helpful response" size="reset"><CopyIcon decorative title="dislike result" />Copy</Button></AIChatMessageActionCard></AIChatMessageActionGroup><HelpText variant="error">The action couldn’t be completed. Please try again.</HelpText></AIChatMessageBody></AIChatMessage></AIChatLog><Box marginTop="space70"><ChatComposerContainer variant="contained"><ChatComposermaxHeight="size10"config={{namespace: "foo",onError: (error) => {throw error;},}}ariaLabel="Message"placeholder="Type here..."><ClearEditorPlugin /></ChatComposer><ChatComposerActionGroup><Button variant="secondary_icon" size="reset"><AttachIcon decorative={false} title="attach a file to your message" /></Button><Button variant="primary_icon" size="reset"><SendIcon decorative={false} title="Send" /></Button></ChatComposerActionGroup></ChatComposerContainer></Box></>);};render(<ActionGroupError />)
An error sending a message
- The error is placed in the Message Action Card
- Include an action to recover
const SendingMessageError = () => {return (<><AIChatLog><AIChatMessage variant="bot"><AIChatMessageAuthor aria-label="AI said">Good Bot</AIChatMessageAuthor><AIChatMessageBody>Messages from +1 234-292-2349 are failing due to the following top 3 errors which occurred in the past 7days:<Box paddingY="space50"><ButtonGroup><Button variant="secondary" size="rounded_small">30007</Button><Button variant="secondary" size="rounded_small">30034</Button><Button variant="secondary" size="rounded_small">30024</Button></ButtonGroup></Box><AIChatMessageActionGroup><AIChatMessageActionCard aria-label="Feedback form">Is this helpful?<Button variant="reset" size="reset" aria-label="this is a helpful response"><ThumbsUpIcon decorative={false} title="like result" /></Button><Button variant="reset" size="reset" aria-label="this is not a helpful response"><ThumbsDownIcon decorative={false} title="dislike result" /></Button></AIChatMessageActionCard></AIChatMessageActionGroup></AIChatMessageBody></AIChatMessage><AIChatMessage variant="user"><AIChatMessageAuthor aria-label="You said at 2:36pm" avatarName="Gibby Ridki">You</AIChatMessageAuthor><AIChatMessageBody>Message body text<AIChatMessageActionGroup><AIChatMessageActionCard aria-label="Feedback form"><HelpText marginTop="space0" variant="error">Message failed to send</HelpText><Button variant="secondary_icon" aria-label="this is not a helpful response" size="reset"><RepeatIcon decorative title="try again" />Try again</Button></AIChatMessageActionCard></AIChatMessageActionGroup></AIChatMessageBody></AIChatMessage></AIChatLog><Box marginTop="space70"><ChatComposerContainer variant="contained"><ChatComposermaxHeight="size10"config={{namespace: "foo",onError: (error) => {throw error;},}}ariaLabel="Message"placeholder="Type here..."><ClearEditorPlugin /></ChatComposer><ChatComposerActionGroup><Button variant="secondary_icon" size="reset"><AttachIcon decorative={false} title="attach a file to your message" /></Button><Button variant="primary_icon" size="reset"><SendIcon decorative={false} title="Send" /></Button></ChatComposerActionGroup></ChatComposerContainer></Box></>);};render(<SendingMessageError />)
Chat History Errors, Timeouts, Network errors...etc.
- An Alert will be placed above the Chat Composer
- The Alert will be dismissed once the user refreshes the page or when the error is resolved
const SystemError = () => {return (<><AIChatLog><AIChatMessage variant="user"><AIChatMessageAuthor aria-label="You said at 2:36pm" avatarName="Gibby Ridki">You</AIChatMessageAuthor><AIChatMessageBody>Message body text</AIChatMessageBody></AIChatMessage><AIChatMessage variant="bot"><AIChatMessageAuthor aria-label="AI said">Good Bot</AIChatMessageAuthor><AIChatMessageBody>Message body text<Box marginTop="space50"><SummaryDetail><SummaryDetailHeading><SummaryDetailToggleButton aria-label="BOOP" /><SummaryDetailHeadingContent><Text as="p" fontWeight="fontWeightBold">View data sources</Text></SummaryDetailHeadingContent></SummaryDetailHeading><SummaryDetailContent>Data Content</SummaryDetailContent></SummaryDetail></Box><AIChatMessageActionGroup><AIChatMessageActionCard aria-label="Feedback form">Is this helpful?<Button variant="reset" size="reset" aria-label="this is a helpful response"><ThumbsUpIcon decorative={false} title="like result" /></Button><Button variant="reset" size="reset" aria-label="this is not a helpful response"><ThumbsDownIcon decorative={false} title="dislike result" /></Button></AIChatMessageActionCard><AIChatMessageActionCard aria-label="Feedback form"><Button variant="secondary_icon" aria-label="this is not a helpful response" size="reset"><RefreshIcon decorative title="dislike result" />Regenerate</Button><Button variant="secondary_icon" aria-label="this is not a helpful response" size="reset"><CopyIcon decorative title="dislike result" />Copy</Button></AIChatMessageActionCard></AIChatMessageActionGroup></AIChatMessageBody></AIChatMessage></AIChatLog><Box marginTop="space70"><Alert variant="error"><div><strong>Something went wrong.</strong></div>If this issue persists please contact us through our help center.</Alert></Box><Box marginTop="space50"><ChatComposerContainer variant="contained"><ChatComposermaxHeight="size10"config={{namespace: "foo",onError: (error) => {throw error;},}}ariaLabel="Message"placeholder="Type here..."><ClearEditorPlugin /></ChatComposer><ChatComposerActionGroup><Button variant="secondary_icon" size="reset"><AttachIcon decorative={false} title="attach a file to your message" /></Button><Button variant="primary_icon" size="reset"><SendIcon decorative={false} title="Send" /></Button></ChatComposerActionGroup></ChatComposerContainer></Box></>);};render(<SystemError />)