> ## Documentation Index
> Fetch the complete documentation index at: https://anvil.servicetitan.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Chat Layout - Web

> Compose messages, rich content, actions, and prompts into an agent conversation.

The chat layout organizes the content and controls inside an agent conversation. It does not define the surrounding application shell.

## Complete chat layout

ai-kit-patterns-chat-layout-complete-full-page

[StackBlitz demo](https://stackblitz.com/github/servicetitan/anvil2-docs-live-code/tree/main/examples/ai-kit-patterns-chat-layout-complete-full-page?file=src/App.tsx)

```tsx lines theme={null}
import { useState } from "react";
import {
  ActionLog,
  AgentMediaCard,
  AgentMessage,
  AgentThinking,
  ArtifactCard,
  CartoTheme,
  ChatLayout,
  PromptBar,
  SuggestionList,
  Text,
  UserMessage,
  type ActionLogStep,
  type MediaAttachment,
} from "@servicetitan/anvil2-ai-kit";
import * as cartoTokens from "@servicetitan/anvil2-ai-kit/tokens";
import "@servicetitan/anvil2-ai-kit/styles.css";

const { primitive } =
  cartoTokens as unknown as typeof import("@servicetitan/carto-tokens/vanilla-extract");

const media: MediaAttachment = {
  kind: "document",
  fileName: "Service agreement.pdf",
  fileTypeLabel: "PDF",
  href: "https://example.com/service-agreement.pdf",
};

const actionSteps: ActionLogStep[] = [
  {
    id: "agreement",
    title: "Reviewed the service agreement",
    status: "success",
  },
  {
    id: "schedule",
    title: "Prepared the arrival window update",
    status: "success",
  },
];

const timestamp = new Date(2026, 3, 1, 16, 40);

function App() {
  const [draft, setDraft] = useState("");

  return (
    <CartoTheme>
      <div
        style={{
          position: "fixed",
          inset: 0,
          display: "flex",
          alignItems: "center",
          justifyContent: "center",
          background: primitive.color.neutral["20"],
        }}
      >
        <div
          style={{
            width: 768,
            height: 1040,
            overflow: "hidden",
            background: primitive.color.neutral["0"],
            border: `1px solid ${primitive.color.neutral["80"]}`,
          }}
        >
          <ChatLayout
            conversation={
              <>
                <UserMessage
                  content="Update the arrival window and summarize the agreement."
                  timestamp={timestamp}
                />
                <AgentMessage
                  content={
                    <>
                      <ActionLog steps={actionSteps} defaultExpanded={false} />
                      <Text text="I found the agreement and prepared the requested update." />
                      <AgentMediaCard media={media} showPreview={false} />
                      <ArtifactCard
                        artifactType="document"
                        title="Service agreement summary"
                        description="Key terms and the proposed schedule update."
                        onPress={() => {}}
                      />
                    </>
                  }
                  copyText="I found the agreement and prepared the requested update."
                  timestamp={new Date(2026, 3, 1, 16, 40, 30)}
                  onLike={() => {}}
                  onDislike={() => {}}
                />
                <AgentThinking />
                <SuggestionList
                  suggestions={[
                    "Draft a customer update",
                    "Compare with the original",
                  ]}
                  onSelect={() => {}}
                />
              </>
            }
            prompt={
              <PromptBar
                value={draft}
                onChange={setDraft}
                onSend={() => setDraft("")}
                placeholder="Ask anything…"
              />
            }
          />
        </div>
      </div>
    </CartoTheme>
  );
}

export default App;
```

## User Message

ai-kit-patterns-chat-layout-user-content

[StackBlitz demo](https://stackblitz.com/github/servicetitan/anvil2-docs-live-code/tree/main/examples/ai-kit-patterns-chat-layout-user-content?file=src/App.tsx)

```tsx lines theme={null}
import {
  CartoTheme,
  SuggestionList,
  UserMediaMessage,
  UserMessage,
  type MediaAttachment,
} from "@servicetitan/anvil2-ai-kit";
import "@servicetitan/anvil2-ai-kit/styles.css";

const media: MediaAttachment = {
  kind: "document",
  fileName: "Service agreement.pdf",
  fileTypeLabel: "PDF",
  href: "https://example.com/service-agreement.pdf",
};

const timestamp = new Date(2026, 3, 1, 16, 40);

function App() {
  return (
    <CartoTheme>
      <div
        style={{
          display: "flex",
          flexDirection: "column",
          gap: 16,
          width: "48rem",
        }}
      >
        <UserMediaMessage
          media={media}
          timestamp={timestamp}
          revealToolbarOnHover
        />
        <UserMessage
          content="Summarize this agreement and flag anything unusual."
          timestamp={timestamp}
        />
        <SuggestionList
          suggestions={["Focus on payment terms", "Check renewal conditions"]}
          onSelect={() => {}}
        />
      </div>
    </CartoTheme>
  );
}

export default App;
```

### User Message

ai-kit-patterns-chat-layout-user-message

[StackBlitz demo](https://stackblitz.com/github/servicetitan/anvil2-docs-live-code/tree/main/examples/ai-kit-patterns-chat-layout-user-message?file=src/App.tsx)

```tsx lines theme={null}
import { CartoTheme, UserMessage } from "@servicetitan/anvil2-ai-kit";
import "@servicetitan/anvil2-ai-kit/styles.css";

function App() {
  return (
    <CartoTheme>
      <div style={{ width: "48rem" }}>
        <UserMessage
          content="Summarize this agreement and flag anything unusual."
          timestamp={new Date(2026, 3, 1, 16, 40)}
        />
      </div>
    </CartoTheme>
  );
}

export default App;
```

##### Multiple user messages

ai-kit-patterns-chat-layout-user-message-multiple

[StackBlitz demo](https://stackblitz.com/github/servicetitan/anvil2-docs-live-code/tree/main/examples/ai-kit-patterns-chat-layout-user-message-multiple?file=src/App.tsx)

```tsx lines theme={null}
import { CartoTheme, UserMessage } from "@servicetitan/anvil2-ai-kit";
import "@servicetitan/anvil2-ai-kit/styles.css";

function App() {
  return (
    <CartoTheme>
      <div
        style={{
          display: "flex",
          flexDirection: "column",
          gap: 16,
          width: "48rem",
        }}
      >
        <UserMessage
          content="Summarize this agreement."
          timestamp={new Date(2026, 3, 1, 16, 38)}
          revealToolbarOnHover
        />
        <UserMessage
          content="Focus on payment terms and renewal conditions."
          timestamp={new Date(2026, 3, 1, 16, 39)}
        />
      </div>
    </CartoTheme>
  );
}

export default App;
```

### User Media

ai-kit-patterns-chat-layout-user-media

[StackBlitz demo](https://stackblitz.com/github/servicetitan/anvil2-docs-live-code/tree/main/examples/ai-kit-patterns-chat-layout-user-media?file=src/App.tsx)

```tsx lines theme={null}
import {
  CartoTheme,
  UserMediaMessage,
  type MediaAttachment,
} from "@servicetitan/anvil2-ai-kit";
import "@servicetitan/anvil2-ai-kit/styles.css";

const media: MediaAttachment[] = [
  {
    kind: "document",
    fileName: "Service agreement.pdf",
    fileTypeLabel: "PDF",
    href: "https://example.com/service-agreement.pdf",
  },
  {
    kind: "image",
    fileName: "Site photo.jpg",
    fileTypeLabel: "Image",
    src: "data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='80' height='60'%3E%3Crect width='80' height='60' fill='%23dceeff'/%3E%3Cpath d='M8 48 28 26l14 14 10-10 20 18Z' fill='%2370b1ff'/%3E%3C/svg%3E",
    href: "https://example.com/site-photo.jpg",
  },
  {
    kind: "audio",
    fileName: "Customer call.mp3",
    fileTypeLabel: "Audio",
    src: "https://example.com/customer-call.mp3",
    href: "https://example.com/customer-call.mp3",
  },
  {
    kind: "video",
    fileName: "Walkthrough.mp4",
    fileTypeLabel: "Video",
    src: "https://example.com/walkthrough.mp4",
    href: "https://example.com/walkthrough.mp4",
  },
];

function App() {
  return (
    <CartoTheme>
      <div
        style={{
          display: "flex",
          flexDirection: "column",
          gap: 16,
          width: "48rem",
        }}
      >
        {media.map((attachment, index) => (
          <UserMediaMessage
            key={attachment.fileName}
            media={attachment}
            timestamp={new Date(2026, 3, 1, 16, 37 + index)}
            showPreview={false}
            revealToolbarOnHover={index < media.length - 1}
          />
        ))}
      </div>
    </CartoTheme>
  );
}

export default App;
```

### Suggestions

ai-kit-patterns-chat-layout-user-suggestions

[StackBlitz demo](https://stackblitz.com/github/servicetitan/anvil2-docs-live-code/tree/main/examples/ai-kit-patterns-chat-layout-user-suggestions?file=src/App.tsx)

```tsx lines theme={null}
import { CartoTheme, SuggestionList } from "@servicetitan/anvil2-ai-kit";
import "@servicetitan/anvil2-ai-kit/styles.css";

function App() {
  return (
    <CartoTheme>
      <div style={{ width: "48rem" }}>
        <SuggestionList
          suggestions={["Focus on payment terms", "Check renewal conditions"]}
          onSelect={() => {}}
        />
      </div>
    </CartoTheme>
  );
}

export default App;
```

### User Message Do's and Don'ts

| Guidance | Practice |
| - | - |
| Do | Maintain the layout order of User Message content. |
| Do | Maintain consistent spacing between elements around the User Message. |
| Do | On non-touch devices, reveal the toolbar on hover for messages before the latest message. |
| Don't | Change the User Message bubble color. |
| Don't | Change the User Message toolbar. |

## Agent Message

Agent message represents responses from the Agent. Unlike user messages, agent messages are fluid in their content and layout.

ai-kit-patterns-chat-layout-agent-content

[StackBlitz demo](https://stackblitz.com/github/servicetitan/anvil2-docs-live-code/tree/main/examples/ai-kit-patterns-chat-layout-agent-content?file=src/App.tsx)

```tsx lines theme={null}
import {
  ActionLog,
  AgentMediaCard,
  AgentMessage,
  AgentThinking,
  ArtifactCard,
  CartoTheme,
  GuidanceCard,
  Markdown,
  type ActionLogStep,
  type GuidanceChangeSection,
  type MediaAttachment,
} from "@servicetitan/anvil2-ai-kit";
import "@servicetitan/anvil2-ai-kit/styles.css";

const steps: ActionLogStep[] = [
  {
    id: "review",
    title: "Reviewed the service agreement",
    status: "success",
  },
];

const media: MediaAttachment = {
  kind: "document",
  fileName: "Service agreement.pdf",
  fileTypeLabel: "PDF",
  href: "https://example.com/service-agreement.pdf",
};

const changes: GuidanceChangeSection[] = [
  {
    type: "single",
    changes: [
      {
        id: "arrival-window",
        label: "Arrival window",
        from: "8–10 AM",
        to: "9–11 AM",
      },
    ],
  },
];

function App() {
  return (
    <CartoTheme>
      <div style={{ width: "48rem" }}>
        <AgentMessage
          content={
            <>
              <ActionLog steps={steps} defaultExpanded={false} />
              <Markdown source="I reviewed the agreement and prepared a **summary** with the requested update." />
              <AgentMediaCard media={media} showPreview={false} />
              <ArtifactCard
                artifactType="document"
                title="Service agreement summary"
                description="Key terms and the proposed schedule update."
                onPress={() => {}}
              />
              <GuidanceCard
                referenceLabel="Job #10428"
                changeSections={changes}
                onApply={() => {}}
                onEdit={() => {}}
                onDismiss={() => {}}
              />
            </>
          }
          copyText="I reviewed the agreement and prepared a summary."
          timestamp={new Date(2026, 3, 1, 16, 40)}
          onLike={() => {}}
          onDislike={() => {}}
        />
        <AgentThinking />
      </div>
    </CartoTheme>
  );
}

export default App;
```

### Markdown Text

ai-kit-patterns-chat-layout-agent-markdown

[StackBlitz demo](https://stackblitz.com/github/servicetitan/anvil2-docs-live-code/tree/main/examples/ai-kit-patterns-chat-layout-agent-markdown?file=src/App.tsx)

```tsx lines theme={null}
import { CartoTheme, Markdown } from "@servicetitan/anvil2-ai-kit";
import "@servicetitan/anvil2-ai-kit/styles.css";

function App() {
  return (
    <CartoTheme>
      <div style={{ width: "48rem" }}>
        <Markdown source="I reviewed the agreement and found **two items** that need attention." />
      </div>
    </CartoTheme>
  );
}

export default App;
```

##### Rich Markdown Agent Message

ai-kit-patterns-chat-layout-agent-markdown-rich

[StackBlitz demo](https://stackblitz.com/github/servicetitan/anvil2-docs-live-code/tree/main/examples/ai-kit-patterns-chat-layout-agent-markdown-rich?file=src/App.tsx)

```tsx lines theme={null}
import {
  AgentMessage,
  CartoTheme,
  Markdown,
} from "@servicetitan/anvil2-ai-kit";
import "@servicetitan/anvil2-ai-kit/styles.css";

const source = `### Agreement review

I reviewed the **service agreement** and found *two items* that need attention. The source is available in the [customer record](https://example.com/customer-record).

> The renewal window closes in 14 days.

#### Review checklist

- [x] Confirm payment terms
- [x] Compare the current arrival window
- [ ] Send the renewal notice

#### Risk summary

| Area | Status | Detail |
| --- | --- | --- |
| Payment | Clear | Net 30 terms |
| Renewal | Review | Notice required |
| Schedule | Updated | 9–11 AM |

1. Confirm the proposed schedule.
2. Notify the customer.
3. Archive the previous version.

The current setting is \`autoRenewal: true\`.

\`\`\`json
{
  "arrivalWindow": "9–11 AM",
  "noticeRequired": true
}
\`\`\`

~~No follow-up needed.~~ **Follow-up is required.**

Visit https://example.com/agreements for the full policy.

---`;

function App() {
  return (
    <CartoTheme>
      <div style={{ width: "48rem" }}>
        <AgentMessage
          content={<Markdown source={source} />}
          copyText={source}
          timestamp={new Date(2026, 3, 1, 16, 40)}
          onLike={() => {}}
          onDislike={() => {}}
        />
      </div>
    </CartoTheme>
  );
}

export default App;
```

Example of using many markdown types in one Agent Message. For illustrative purposes of features, this should not be considered a high quality agent message.

Agent messages are primarily built on top of markdown text. The majority of markdown features are supported. See the [Markdown component page](https://anvil.servicetitan.com/docs/components/markdown/design) for each feature in action.

### Action Log

ai-kit-patterns-chat-layout-agent-action-log

[StackBlitz demo](https://stackblitz.com/github/servicetitan/anvil2-docs-live-code/tree/main/examples/ai-kit-patterns-chat-layout-agent-action-log?file=src/App.tsx)

```tsx lines theme={null}
import {
  ActionLog,
  CartoTheme,
  type ActionLogStep,
} from "@servicetitan/anvil2-ai-kit";
import "@servicetitan/anvil2-ai-kit/styles.css";

const steps: ActionLogStep[] = [
  {
    id: "review",
    title: "Reviewed the service agreement",
    status: "success",
  },
  {
    id: "summary",
    title: "Prepared the summary",
    status: "success",
  },
];

function App() {
  return (
    <CartoTheme>
      <div style={{ width: "48rem" }}>
        <ActionLog steps={steps} defaultExpanded={false} />
      </div>
    </CartoTheme>
  );
}

export default App;
```

### Media Card

ai-kit-patterns-chat-layout-agent-media

[StackBlitz demo](https://stackblitz.com/github/servicetitan/anvil2-docs-live-code/tree/main/examples/ai-kit-patterns-chat-layout-agent-media?file=src/App.tsx)

```tsx lines theme={null}
import {
  AgentMediaCard,
  CartoTheme,
  type MediaAttachment,
} from "@servicetitan/anvil2-ai-kit";
import "@servicetitan/anvil2-ai-kit/styles.css";

const media: MediaAttachment = {
  kind: "document",
  fileName: "Service agreement.pdf",
  fileTypeLabel: "PDF",
  href: "https://example.com/service-agreement.pdf",
};

function App() {
  return (
    <CartoTheme>
      <div style={{ width: "48rem" }}>
        <AgentMediaCard media={media} showPreview={false} />
      </div>
    </CartoTheme>
  );
}

export default App;
```

Media cards represent an asset within the chat layout.

Differences between media representation between agent and user messages:

* Agent media cards can be ordered anywhere in the agent message. User message media is fixed to above the message content.
* Agent media cards stretch to the width of the agent message.

### Artifact Card

ai-kit-patterns-chat-layout-agent-artifact

[StackBlitz demo](https://stackblitz.com/github/servicetitan/anvil2-docs-live-code/tree/main/examples/ai-kit-patterns-chat-layout-agent-artifact?file=src/App.tsx)

```tsx lines theme={null}
import { ArtifactCard, CartoTheme } from "@servicetitan/anvil2-ai-kit";
import "@servicetitan/anvil2-ai-kit/styles.css";

function App() {
  return (
    <CartoTheme>
      <div style={{ width: "48rem" }}>
        <ArtifactCard
          artifactType="document"
          title="Service agreement summary"
          description="Key terms and the proposed schedule update."
          onPress={() => {}}
        />
      </div>
    </CartoTheme>
  );
}

export default App;
```

Artifact cards represent an asset within the chat layout. When selected, content should display in the [artifact panel](https://anvil.servicetitan.com/docs/patterns/agentic-experience-shell/web.md#panel).

### Guidance Card

ai-kit-patterns-chat-layout-agent-guidance

[StackBlitz demo](https://stackblitz.com/github/servicetitan/anvil2-docs-live-code/tree/main/examples/ai-kit-patterns-chat-layout-agent-guidance?file=src/App.tsx)

```tsx lines theme={null}
import {
  CartoTheme,
  GuidanceCard,
  type GuidanceChangeSection,
} from "@servicetitan/anvil2-ai-kit";
import "@servicetitan/anvil2-ai-kit/styles.css";

const changes: GuidanceChangeSection[] = [
  {
    type: "single",
    changes: [
      {
        id: "arrival-window",
        label: "Arrival window",
        from: "8–10 AM",
        to: "9–11 AM",
      },
    ],
  },
];

function App() {
  return (
    <CartoTheme>
      <div style={{ width: "48rem" }}>
        <GuidanceCard
          referenceLabel="Job #10428"
          changeSections={changes}
          onApply={() => {}}
          onEdit={() => {}}
          onDismiss={() => {}}
        />
      </div>
    </CartoTheme>
  );
}

export default App;
```

### Toolbar

ai-kit-patterns-chat-layout-agent-toolbar

[StackBlitz demo](https://stackblitz.com/github/servicetitan/anvil2-docs-live-code/tree/main/examples/ai-kit-patterns-chat-layout-agent-toolbar?file=src/App.tsx)

```tsx lines theme={null}
import { AgentMessage, CartoTheme } from "@servicetitan/anvil2-ai-kit";
import "@servicetitan/anvil2-ai-kit/styles.css";

function App() {
  return (
    <CartoTheme>
      <div style={{ width: "48rem" }}>
        <AgentMessage
          content="I reviewed the agreement and prepared the requested update."
          timestamp={new Date(2026, 3, 1, 16, 40)}
          onLike={() => {}}
          onDislike={() => {}}
        />
      </div>
    </CartoTheme>
  );
}

export default App;
```

### Agent Thinking

ai-kit-patterns-chat-layout-agent-thinking

[StackBlitz demo](https://stackblitz.com/github/servicetitan/anvil2-docs-live-code/tree/main/examples/ai-kit-patterns-chat-layout-agent-thinking?file=src/App.tsx)

```tsx lines theme={null}
import { AgentThinking, CartoTheme } from "@servicetitan/anvil2-ai-kit";
import "@servicetitan/anvil2-ai-kit/styles.css";

function App() {
  return (
    <CartoTheme>
      <div style={{ width: "48rem" }}>
        <AgentThinking label="Atlas is thinking…" />
      </div>
    </CartoTheme>
  );
}

export default App;
```

Agent Thinking represents the visual representation of where the agent is currently thinking. There is exactly one Agent Thinking in the chat layout.

#### Examples of Agent Thinking location in action

ai-kit-patterns-chat-layout-agent-thinking-after-user-message

[StackBlitz demo](https://stackblitz.com/github/servicetitan/anvil2-docs-live-code/tree/main/examples/ai-kit-patterns-chat-layout-agent-thinking-after-user-message?file=src/App.tsx)

```tsx lines theme={null}
import {
  AgentThinking,
  CartoTheme,
  UserMessage,
} from "@servicetitan/anvil2-ai-kit";
import "@servicetitan/anvil2-ai-kit/styles.css";

function App() {
  return (
    <CartoTheme>
      <div
        style={{
          display: "flex",
          flexDirection: "column",
          gap: 8,
          width: "48rem",
        }}
      >
        <UserMessage
          content="User message"
          timestamp={new Date(2026, 3, 1, 16, 40)}
        />
        <AgentThinking label="Atlas is thinking…" />
      </div>
    </CartoTheme>
  );
}

export default App;
```

Just after a user message, Agent Thinking acts as a loading state.

ai-kit-patterns-chat-layout-agent-thinking-streaming

[StackBlitz demo](https://stackblitz.com/github/servicetitan/anvil2-docs-live-code/tree/main/examples/ai-kit-patterns-chat-layout-agent-thinking-streaming?file=src/App.tsx)

```tsx lines theme={null}
import {
  AgentThinking,
  CartoTheme,
  Text,
  UserMessage,
} from "@servicetitan/anvil2-ai-kit";
import "@servicetitan/anvil2-ai-kit/styles.css";

function App() {
  return (
    <CartoTheme>
      <div
        style={{
          display: "flex",
          flexDirection: "column",
          gap: 8,
          width: "48rem",
        }}
      >
        <UserMessage
          content="User message"
          timestamp={new Date(2026, 3, 1, 16, 40)}
        />
        <Text text="This is text the agent is actively streaming in right now. Additional content can continue to appear while Atlas works." />
        <AgentThinking />
      </div>
    </CartoTheme>
  );
}

export default App;
```

As text streams in, Agent Thinking sits below the incoming text. Its label is typically omitted during streaming.

ai-kit-patterns-chat-layout-agent-thinking-finished-message

[StackBlitz demo](https://stackblitz.com/github/servicetitan/anvil2-docs-live-code/tree/main/examples/ai-kit-patterns-chat-layout-agent-thinking-finished-message?file=src/App.tsx)

```tsx lines theme={null}
import {
  AgentMessage,
  AgentThinking,
  Card,
  CartoTheme,
  Text,
  UserMessage,
} from "@servicetitan/anvil2-ai-kit";
import "@servicetitan/anvil2-ai-kit/styles.css";

const timestamp = new Date(2026, 3, 1, 16, 40);

function App() {
  return (
    <CartoTheme>
      <div
        style={{
          display: "flex",
          flexDirection: "column",
          gap: 8,
          width: "48rem",
        }}
      >
        <UserMessage content="User message" timestamp={timestamp} />
        <AgentMessage
          content={
            <>
              <Text text="This is text the agent has finished streaming." />
              <Card
                content={
                  <div
                    style={{
                      display: "flex",
                      justifyContent: "center",
                      padding: 32,
                    }}
                  >
                    <Text text="[Loaded Atlas content]" />
                  </div>
                }
              />
              <Text text="More text has finished streaming. Atlas is done." />
            </>
          }
          copyText="This is text the agent has finished streaming. More text has finished streaming. Atlas is done."
          timestamp={timestamp}
          onLike={() => {}}
          onDislike={() => {}}
        />
        <AgentThinking />
      </div>
    </CartoTheme>
  );
}

export default App;
```

After an agent message finishes, Agent Thinking sits below the toolbar.

### Agent Message Do's and Don'ts

* Do: Maintain a consistent location of the Agent Toolbar. Outside of Agent Thinking, this is always at the bottom of the agent message.
* Do: Show the Agent Toolbar only after the agent message is finished.
* Do: Use loading mechanisms when possible to indicate the agent is processing the message.
* Do: Arrange the layout of Agent Message content to produce a clear and readable message. Unlike user messages, agent messages are fluid in order for most parts of the message.
* Don't: Use multiple Agent Thinkings in the chat layout.

## Related Components

* [Prompt Bar](https://anvil.servicetitan.com/docs/components/prompt-bar/design) — Accepts free-form user input
* [User Message](https://anvil.servicetitan.com/docs/components/user-message/design) — Presents user-authored content
* Agent Message — Presents agent-authored content and feedback actions
* Media — Presents user- or agent-authored attachments
* [Artifact Card](https://anvil.servicetitan.com/docs/components/artifact-card/design) — Opens generated content
* [Suggestions](https://anvil.servicetitan.com/docs/components/suggestion/design) — Offers concise follow-up actions
* [Agent Prompt](https://anvil.servicetitan.com/docs/components/agent-prompt/design) — Requests a structured answer
* [Guidance Card](https://anvil.servicetitan.com/docs/components/guidance-card/design) — Presents proposed changes for review

## Related Patterns

* [Agentic Experience Shell](https://anvil.servicetitan.com/docs/patterns/agentic-experience-shell/web.md) — Composes the chat layout with supporting content


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.