diff --git a/.changeset/pretty-melons-punch.md b/.changeset/pretty-melons-punch.md
index 3b8d854eb0..fe79eb8599 100644
--- a/.changeset/pretty-melons-punch.md
+++ b/.changeset/pretty-melons-punch.md
@@ -3,4 +3,4 @@
"@twilio-paste/core": patch
---
-[Button] Add border radius 20 to size="reset" buttons which can be overridden by passing a border radius token to variant="reset" and size="reset" buttons
\ No newline at end of file
+[Button] Add border radius 20 to size="reset" buttons which can be overridden by passing a border radius token to variant="reset" and size="reset" buttons
diff --git a/cypress/integration/sitemap-vrt/constants.ts b/cypress/integration/sitemap-vrt/constants.ts
index 49e88dd27e..c7367f49f6 100644
--- a/cypress/integration/sitemap-vrt/constants.ts
+++ b/cypress/integration/sitemap-vrt/constants.ts
@@ -24,6 +24,9 @@ export const SITEMAP = [
"/components/account-switcher/",
"/components/account-switcher/api",
"/components/account-switcher/changelog",
+ "/components/ai-chat-log/",
+ "/components/ai-chat-log/api",
+ "/components/ai-chat-log/changelog",
"/components/aspect-ratio/",
"/components/aspect-ratio/api",
"/components/aspect-ratio/changelog",
diff --git a/packages/paste-core/components/ai-chat-log/CHANGELOG.md b/packages/paste-core/components/ai-chat-log/CHANGELOG.md
new file mode 100644
index 0000000000..e69de29bb2
diff --git a/packages/paste-website/src/component-examples/AIChatLogExamples.ts b/packages/paste-website/src/component-examples/AIChatLogExamples.ts
new file mode 100644
index 0000000000..4a86abaea5
--- /dev/null
+++ b/packages/paste-website/src/component-examples/AIChatLogExamples.ts
@@ -0,0 +1,302 @@
+export const basicBotMessage = `
+const BasicMessage = () => {
+ return (
+
+
+ Good Bot
+
+ 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.
+
+
+
+ );
+};
+
+render(
+
+)`.trim();
+export const basicHumanMessage = `
+const BasicMessage = () => {
+ return (
+
+
+ Gibby Radki
+
+ I would like some information on twilio error codes for undelivered messages
+
+
+
+ );
+};
+
+render(
+
+)`.trim();
+export const botWithFeedback = `
+const MessageWithFeedback = () => {
+ return (
+
+
+ Good Bot
+
+ 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.
+
+
+
+ Is this helpful?
+
+
+
+
+
+
+
+
+
+
+ );
+};
+
+render(
+
+)`.trim();
+export const botWithBodyActions = `
+const MessageWithFeedback = () => {
+ return (
+
+
+ Good Bot
+
+ Below is a list of actions that can be taken with flex wrapping supported:
+
+
+
+
+
+
+
+
+
+
+
+ );
+};
+
+render(
+
+)`.trim();
+export const botWithLoadingStopButton = `
+const MessageWithLoadingAndStop = () => {
+ return (
+
+
+
+ Good Bot
+
+
+ {}} />
+
+
+
+ );
+};
+
+render(
+
+)`.trim();
+export const botWithLoading = `
+const MessageWithLoading = () => {
+ return (
+
+
+
+ Good Bot
+
+
+
+
+
+
+ );
+};
+
+render(
+
+)`.trim();
+export const kitchenSink = `
+const AIChatLogExample = () => {
+ return (
+
+
+ Gibby Radki
+
+ Hi, I'm getting errors codes when sending an SMS.
+
+
+
+ Good Bot
+
+ Error codes can be returned from various parts of the process. What error codes are you encountering?
+
+
+
+
+
+
+
+
+ Good Bot
+
+ Error 21608 means you're trying to send a message from an unverified number. Is your number verified in your Twilio account?
+
+
+
+ Is this helpful?
+
+
+
+
+
+
+
+ Gibby Radki
+
+
+ No, how do I verify it?
+
+
+
+
+ Good Bot
+
+
+ {}} />
+
+
+
+ );
+};
+
+render(
+
+)`.trim();
+export const aiChatLoggerExample = `
+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: (
+
+ {meta}
+
+ {message}
+
+
+ )
+ }
+};
+
+const chatTemplates = [
+ ["Hello", "user", "You said at ", "Gibby Radki"],
+ ["Hi there", "bot", "AI said at ", "Good Bot"],
+ ["Greetings", "user", "You said at ", "Gibby Radki"],
+ ["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: (
+
+ Good Bot
+
+
+
+
+ ),
+ });
+ setTimeout(() => {
+ pop(id);
+ setLoading(false);
+ push(chat);
+ }, 1000);
+ } else {
+ push(chat);
+ }
+ }
+
+ const popChat = () => {
+ pop();
+ setTemplateIdx((idx) => idx === 0 ? idx : --idx % chatTemplates.length);
+ }
+
+ return(
+
+
+
+
+
+
+
+
+ )
+}
+
+render();
+`.trim();
diff --git a/packages/paste-website/src/pages/components/ai-chat-log/api.mdx b/packages/paste-website/src/pages/components/ai-chat-log/api.mdx
new file mode 100644
index 0000000000..06d8a5efe2
--- /dev/null
+++ b/packages/paste-website/src/pages/components/ai-chat-log/api.mdx
@@ -0,0 +1,100 @@
+export const meta = {
+ title: "AI Chat Log - API",
+ package: "@twilio-paste/ai-chat-log",
+ description:
+ "An AI Chat Log is a collection of Chat components for displaying conversations between a human and an AI bot",
+ slug: "/components/ai-chat-log/api",
+};
+
+import Changelog from "@twilio-paste/ai-chat-log/CHANGELOG.md"; // I don't know why this is needed but if you remove it the page fails to render
+import packageJson from "@twilio-paste/ai-chat-log/package.json";
+
+import { SidebarCategoryRoutes } from "../../../constants";
+import ComponentPageLayout from "../../../layouts/ComponentPageLayout";
+import { getFeature, getNavigationData, getComponentApi } from "../../../utils/api";
+
+export default ComponentPageLayout;
+
+export const getStaticProps = async () => {
+ const navigationData = await getNavigationData();
+ const feature = await getFeature("AI Chat Log");
+ const { componentApi, componentApiTocData } = getComponentApi("@twilio-paste/ai-chat-log");
+ return {
+ props: {
+ data: {
+ ...packageJson,
+ ...feature,
+ },
+ componentApi,
+ mdxHeadings: [...mdxHeadings, ...componentApiTocData],
+ navigationData,
+ pageHeaderData: {
+ categoryRoute: SidebarCategoryRoutes.COMPONENTS,
+ githubUrl: "https://github.com/twilio-labs/paste/tree/main/packages/paste-core/components/ai-chat-log",
+ storybookUrl: "/?path=/story/components-chatlog--example-chat-log",
+ },
+ },
+ };
+};
+
+## Installation
+
+```bash
+yarn add @twilio-paste/ai-chat-log - or - yarn add @twilio-paste/core
+```
+
+## Usage
+
+```jsx
+import {
+ AIChatLog,
+ AIChatMessage,
+ AIChatMessageAuthor,
+ AIChatMessageBody,
+ AIChatMessageFeedback,
+ AIChatMessageLoading,
+ AIChatMessageMeta,
+} from "@twilio-paste/core/ai-chat-log";
+
+export const Basic = () => {
+ return (
+
+
+ Gibby Radki
+
+ Hi, I'm getting errors codes when sending an SMS.
+
+
+
+ Good Bot
+
+ Error codes can be returned from various parts of the process. What error codes are you encountering?
+
+
+
+ Is this helpful?
+
+
+
+
+
+
+
+
+
+
+ );
+};
+```
+
+## Props
+
+
diff --git a/packages/paste-website/src/pages/components/ai-chat-log/changelog.mdx b/packages/paste-website/src/pages/components/ai-chat-log/changelog.mdx
new file mode 100644
index 0000000000..b78049f582
--- /dev/null
+++ b/packages/paste-website/src/pages/components/ai-chat-log/changelog.mdx
@@ -0,0 +1,38 @@
+export const meta = {
+ title: "AI Chat Log - Components",
+ package: "@twilio-paste/ai-chat-log",
+ description:
+ "An AI Chat Log is a collection of Chat components for displaying conversations between a human and an AI bot.",
+ slug: "/components/ai-chat-log/changelog",
+};
+
+import Changelog from "@twilio-paste/ai-chat-log/CHANGELOG.md";
+import packageJson from "@twilio-paste/ai-chat-log/package.json";
+
+import { SidebarCategoryRoutes } from "../../../constants";
+import ComponentPageLayout from "../../../layouts/ComponentPageLayout";
+import { getFeature, getNavigationData } from "../../../utils/api";
+
+export default ComponentPageLayout;
+
+export const getStaticProps = async () => {
+ const navigationData = await getNavigationData();
+ const feature = await getFeature("AI Chat Log");
+ return {
+ props: {
+ data: {
+ ...packageJson,
+ ...feature,
+ },
+ navigationData,
+ mdxHeadings,
+ pageHeaderData: {
+ categoryRoute: SidebarCategoryRoutes.COMPONENTS,
+ githubUrl: "https://github.com/twilio-labs/paste/tree/main/packages/paste-core/components/ai-chat-log",
+ storybookUrl: "/?path=/story/components-chatlog--example-chat-log",
+ },
+ },
+ };
+};
+
+
diff --git a/packages/paste-website/src/pages/components/ai-chat-log/index.mdx b/packages/paste-website/src/pages/components/ai-chat-log/index.mdx
new file mode 100644
index 0000000000..0e4a120740
--- /dev/null
+++ b/packages/paste-website/src/pages/components/ai-chat-log/index.mdx
@@ -0,0 +1,340 @@
+export const meta = {
+ title: "AI Chat Log - Components",
+ package: "@twilio-paste/ai-chat-log",
+ description:
+ "An AI Chat Log is a collection of AI Chat components for displaying conversations between a human and an AI bot.",
+ slug: "/components/ai-chat-log/",
+};
+
+import { uid } from "@twilio-paste/uid-library";
+import { HelpText } from "@twilio-paste/help-text";
+import { Button } from "@twilio-paste/button";
+import { ButtonGroup } from "@twilio-paste/button-group";
+import { Stack } from "@twilio-paste/stack";
+import {
+ AIChatLog,
+ AIChatMessage,
+ AIChatMessageAuthor,
+ AIChatMessageBody,
+ AIChatMessageLoading,
+ AIChatLogger,
+ useAIChatLogger,
+ AIChatMessageActionCard,
+ AIChatMessageActionGroup,
+} from "@twilio-paste/core/ai-chat-log";
+import { ThumbsUpIcon } from "@twilio-paste/icons/esm/ThumbsUpIcon";
+import { ThumbsDownIcon } from "@twilio-paste/icons/esm/ThumbsDownIcon";
+import { RefreshIcon } from "@twilio-paste/icons/esm/RefreshIcon";
+import { CopyIcon } from "@twilio-paste/icons/esm/CopyIcon";
+
+import Changelog from "@twilio-paste/ai-chat-log/CHANGELOG.md";
+
+import { SidebarCategoryRoutes } from "../../../constants";
+
+import {
+ basicBotMessage,
+ basicHumanMessage,
+ botWithFeedback,
+ botWithLoadingStopButton,
+ botWithLoading,
+ kitchenSink,
+ aiChatLoggerExample,
+ botWithBodyActions,
+} from "../../../component-examples/AIChatLogExamples";
+import packageJson from "@twilio-paste/ai-chat-log/package.json";
+import ComponentPageLayout from "../../../layouts/ComponentPageLayout";
+import { getFeature, getNavigationData } from "../../../utils/api";
+
+export default ComponentPageLayout;
+
+export const getStaticProps = async () => {
+ const navigationData = await getNavigationData();
+ const feature = await getFeature("AI Chat Log");
+ return {
+ props: {
+ data: {
+ ...packageJson,
+ ...feature,
+ },
+ navigationData,
+ mdxHeadings,
+ pageHeaderData: {
+ categoryRoute: SidebarCategoryRoutes.COMPONENTS,
+ githubUrl: "https://github.com/twilio-labs/paste/tree/main/packages/paste-core/components/ai-chat-log",
+ storybookUrl: "/?path=/story/components-chatlog--example-chat-log",
+ },
+ },
+ };
+};
+
+
+ {`
+
+ Gibby Radki
+
+ What does the SMS delivery error code 30003 mean?
+
+
+
+ Good Bot
+
+ 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.
+
+
+`}
+
+
+## Guidelines
+
+### About AI Chat Log
+
+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 [ChatLog](/components/chat-log).
+
+The AI Chat Log package includes these main components:
+
+- AIChatLog
+- AIChatMessage
+- AIChatMessageAuthor
+- AIChatMessageBody
+- AIChatMessageActionGroup
+- AIChatMessageActionCard
+- AIChatMessageLoading
+
+### Accessibility
+
+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.
+
+## Examples
+
+### Basic Message
+
+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 now top-down.
+
+#### Bot
+
+
+ {basicBotMessage}
+
+
+#### User
+
+
+ {basicHumanMessage}
+
+
+### Message Body Sizes
+
+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.
+
+
+ {`
+
+ Gibby Radki
+
+ I'm a message that should be displayed in compact elements
+
+
+
+ Gibby Radki
+
+ I'm a message that will be displayed in full screen width
+
+
+`}
+
+
+### Message with Actions
+
+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.
+
+#### Feedback in AIChatMessageActionCard
+
+
+ {botWithFeedback}
+
+
+#### Buttons in AIChatMessageBody from AI Response
+
+
+ {botWithBodyActions}
+
+
+### Loading States
+
+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.
+
+#### Loading
+
+
+ {botWithLoading}
+
+
+#### Loading with Stop Button
+
+
+ {botWithLoadingStopButton}
+
+
+### Example AI Chat Log
+
+This example combines all the separate features displayed previously into one example. It shows how all the features work together harmoniously through composition.
+
+
+ {kitchenSink}
+
+
+### useAIChatLogger hook
+
+The `useAIChatLogger` hook provides a hook-based approach to managing AI chat state. It is best used with the `` 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.
+
+##### AIChatLogger component
+
+The `` component handles rendering the chats it is passed via props. It handles how chats enter and leave the UI.
+
+```
+const { aiChats } = useAIChatLogger();
+return ;
+```
+
+##### Adding and removing a chat
+
+You can push or pop a chat based on an action or event. In this example it's based on a button click:
+
+
+ {aiChatLoggerExample}
+
+
+## Composition Notes
+
+Keep any generated responses from the AI contained in the `AIChatMessageBody` component. Each chat message shouls only have one `AIChatMessageBody` component.
diff --git a/packages/paste-website/src/pages/components/chat-log/index.mdx b/packages/paste-website/src/pages/components/chat-log/index.mdx
index 6638f26bcb..d7f6729504 100644
--- a/packages/paste-website/src/pages/components/chat-log/index.mdx
+++ b/packages/paste-website/src/pages/components/chat-log/index.mdx
@@ -100,7 +100,7 @@ export const getStaticProps = async () => {
### About Chat Log
-A Chat Log is a way to display conversations between people and can include complex content like attachments. The chat can be between two or more people.
+A Chat Log is a way to display conversations between people and can include complex content like attachments. The chat can be between two or more people. If you are looking for a chat between a human and an AI please refer to [AIChatLog](/components/ai-chat-log).
The Chat Log package includes these main components:
@@ -292,7 +292,7 @@ This example combines all the separate features displayed previously into one ex
The `useChatLogger` hook provides a hook based approach to managing chat state. It is best used with the `` component.
-`useChatLogger` returns 3 things:
+`useChatLogger` returns 4 things:
- An array of `chats`.
- A `push` method used to add a chat, optionally with a custom ID