# Quickstart

The AI components give your React app the screens of an AI assistant: a conversation that streams the agent's replies, a prompt composer with attachments and dictation, the agent's reasoning and tool calls, and a face for a voice agent. They ship with `stream-chat-react` in its `stream-chat-react/ai-components` entry point. The agent behind them runs on [Stream Agents](https://getstream.io/agents/docs/quickstart/?lang=javascript): you describe it once, with its instructions, knowledge, tools and voice, and your app talks to it with the `@stream-io/stream-agents` SDK.

This page shows what you can build, how the pieces fit together, and takes you from an empty project to a working assistant.

## What you can build

| You want to build                                                                               | Start with                                                                                                          |
| ----------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------- |
| An AI-first app, like ChatGPT or Claude: one user, one assistant, many conversations            | This page, then the [Personal assistant](https://getstream.io/chat/docs/sdk/react/ai-components/use-cases/personal-assistant/) use case |
| A support agent that answers from your help center, looks up orders and hands over to your team | The [Customer support agent](https://getstream.io/chat/docs/sdk/react/ai-components/use-cases/customer-support-agent/) use case         |
| A voice agent the user talks to, with a visual presence and a written transcript                | The [Voice agent](https://getstream.io/chat/docs/sdk/react/ai-components/use-cases/voice-agent/) use case                               |
| An agent that shows its work and asks before it acts                                            | [Reasoning and tool calls](https://getstream.io/chat/docs/sdk/react/ai-components/reasoning-and-tool-calls/)                            |
| An agent that runs tools in the browser, on the page the user has open                          | The [Personal assistant](https://getstream.io/chat/docs/sdk/react/ai-components/use-cases/personal-assistant/) use case                 |
| Replies that are UI, such as a trip plan with a map and a form                                  | [Generative UI](https://getstream.io/chat/docs/sdk/react/ai-components/generative-ui/)                                                  |
| AI replies in a chat you already built with `MessageList`                                       | [SDK integration](https://getstream.io/chat/docs/sdk/react/ai-components/sdk-integration/)                                              |

Voice runs through all of them. The composer has a microphone button that dictates into it, and the same agent can hold the conversation out loud: `VoiceSession` puts it on a call with the user, `VoiceGlow` or `VoiceWave` shows what it's doing, and `AIConversation` writes out what was said.

## How it fits together

Your app never talks to the model, and it doesn't run the agent. It opens a **session** with your agent and asks it things. The agent runs on Stream's router, which calls the model, runs the agent's tools and writes the conversation into a Stream Chat channel as it goes. The components show that channel:

```mermaid
sequenceDiagram
    participant App as React app
    participant Router as Stream Agents
    participant LLM as Model
    participant Chat as Stream Chat
    App->>Router: sessions.create() with @stream-io/stream-agents
    App->>Router: responses.create("How do I...?")
    Router->>LLM: The conversation so far
    LLM-->>Router: Reasoning, tool calls, tokens
    Router-->>Chat: The question, and the reply as it streams, with its steps
    Chat-->>App: The channel's messages
    Note over App: AIConversation shows them
```

- **`@stream-io/stream-agents`** signs the user in, opens sessions, asks, stops a reply, answers the questions of tools that ask first, and runs the tools your page gives the agent.
- **`stream-chat-react/ai-components`** shows it all: `AIConversation` and `AIMessageComposer`, the reasoning and tool calls of each reply, the UI the agent writes, and the voice visualizations.
- **Your agent** lives in a folder of plain files that you sync with the Stream CLI: its instructions, knowledge, skills, tools, connectors and models.

For voice, `VoiceSession` starts the agent on a call and joins it from the browser. The agent hears the user and answers out loud, and what is said is written into the session's channel.

## Before you start

- A Stream app, from the [Stream Dashboard](https://getstream.io/signup/?product=chat).
- The beta [Stream CLI](https://getstream.io/cli/docs/install/), which has the `getstream agents` commands.
- A React 18 or later app.

## Step 1: Create the agent

Install the beta CLI, pick your Stream app, and make an agent from the text template:

```sh
curl -fsSL https://getstream.io/cli/beta/install.sh | bash
getstream init                                     # pick or create a Stream app
getstream agents init my-agent --template text     # or --template voice
```

That creates `agents/my-agent/`, with the agent's settings in `agent.yaml`, its system prompt in `instructions.md`, and a guardrail in `guardrail.md`. The template's guardrail turns away anything that isn't about Acme Corp, its example company, so write what the agent is for in both files, then sync it to Stream and try it in the terminal:

```sh
getstream agents sync my-agent
getstream agents test my-agent
```

The [Stream Agents quickstart](https://getstream.io/agents/docs/quickstart/?lang=javascript) covers the agent's folder: knowledge, skills, tools, connectors and guardrails.

## Step 2: Install the SDKs

Add `@stream-io/stream-agents`, the client for your agent, and `stream-chat-react`, which has the views. `stream-chat` is the Stream Chat client that reads the conversation the agent writes:

```bash
npm install @stream-io/stream-agents stream-chat stream-chat-react
```

This page uses `stream-chat-react` v15, with `stream-chat` v10. The `stream-chat-react/ai-components` entry point needs no other package. Load its stylesheet next to the default SDK styles, once, where your app starts:

```tsx
import "stream-chat-react/dist/css/index.css";
import "stream-chat-react/dist/css/ai-components.css";
```

If your agent answers with [generative UI](https://getstream.io/chat/docs/sdk/react/ai-components/generative-ui/), also install the packages of the format it writes, A2UI or OpenUI, as that guide describes. The composer's microphone button dictates with the browser's Web Speech API, so it needs no package, and it renders nothing in browsers without it, such as Firefox.

Is your agent on a backend of your own? Skip `@stream-io/stream-agents`, and have your backend write the agent's replies into a Stream Chat channel, by hand or with the [Stream Chat AI SDK](https://getstream.io/chat/docs/sdk/react/ai-components/stream-chat-ai-sdk/) or the [Stream Chat LangChain SDK](https://getstream.io/chat/docs/sdk/react/ai-components/stream-chat-langchain-sdk/). [Conversation state](https://getstream.io/chat/docs/sdk/react/ai-components/conversation-state/) describes what it sends: the `ai_generated` and `generating` fields of a reply, and the AI indicator events that say what the agent is doing. The client keeps the latest of those on the channel, as one of the states `stream-chat` exports as `AIStates`:

- `AIStates.Thinking`, `AI_STATE_THINKING`: the model is working out an answer.
- `AIStates.ExternalSources`, `AI_STATE_EXTERNAL_SOURCES`: the model is checking external sources, such as with a tool call.
- `AIStates.Generating`, `AI_STATE_GENERATING`: the answer is being written into the message.
- `AIStates.Error`, `AI_STATE_ERROR`: the reply failed.
- `AIStates.Stop`, `AI_STATE_STOP`: the user asked to stop the reply.
- `AIStates.Idle`, `AI_STATE_IDLE`: nothing is happening.

The [`useAIState`](https://getstream.io/chat/docs/sdk/react/reference/hooks/ai-hooks/#useaistate) hook from `stream-chat-react` reads it.

## Step 3: Sign the user in

Create one `Client` for your app with your API key, and set the user once they sign in. The user's Stream token comes from your backend, which mints it with your API secret, as described in [authentication](https://getstream.io/docs/platform/authentication/). The client asks for it again when it expires:

```ts title="agent.ts"
import { Client } from "@stream-io/stream-agents";

export const api = new Client({ apiKey: "your_api_key" });

export async function signIn(user: { id: string; name: string }) {
  await api.setUser(user, () =>
    fetch("/api/stream-token").then((response) => response.text()),
  );
}
```

To try things out before you have a backend, mint a token for a test user with the CLI, `getstream token jane --ttl 2h`, and pass it as `api.setUser({ id: "jane" }, "...")`.

## Step 4: Connect a conversation to the agent

A session is one conversation with your agent, and its channel is where the agent writes it: the user's questions, each reply as it streams, and the reasoning and tool calls of each reply as the reply's attachments. Add a function to `agent.ts` that opens a session and its channel:

```ts title="agent.ts"
import type { Session } from "@stream-io/stream-agents";
// Lets session.chat() connect to Stream Chat. Import it once.
import "@stream-io/stream-agents/chat";
import type { Channel, StreamChat } from "stream-chat";

export type AgentChat = {
  session: Session;
  client: StreamChat;
  channel: Channel;
};

/** Opens a conversation with the agent, or the channel of one already open. */
export async function openConversation(session?: Session): Promise<AgentChat> {
  const opened = session ?? (await api.agent("my-agent").sessions.create());
  // Connects to Stream Chat as the user signIn() set.
  const { client, channel } = await opened.chat();
  const agentChannel = channel as Channel;
  await agentChannel.watch();
  return {
    session: opened,
    client: client as StreamChat,
    channel: agentChannel,
  };
}
```

The views show `AIMessage` values. `fromStreamMessage` turns each of the channel's messages into one: a reply is a message with `custom.ai_generated: true`, it's being written while `custom.generating` is `true`, and its steps are its `ai_reasoning` and `ai_tool_call` attachments. The channel's message paginator holds its messages oldest first, which is the order the conversation wants:

```ts title="useAgentMessages.ts"
import { useMemo } from "react";
import type { Channel, MessagePaginatorState } from "stream-chat";
import { useStateStore } from "stream-chat-react";
import { fromStreamMessage } from "stream-chat-react/ai-components";

const itemsSelector = (state: MessagePaginatorState) => ({
  items: state.items,
});

export function useAgentMessages(channel: Channel) {
  const { items } = useStateStore(
    channel.messagePaginator.state,
    itemsSelector,
  );
  return useMemo(
    () => (items ?? []).map((message) => fromStreamMessage(message)),
    [items],
  );
}
```

## Step 5: Show the conversation

Show the conversation with `AIConversation`, and the composer below it. The composer asks through the session, and the router writes the question into the channel itself. The `approver` answers the tools that ask before they run:

```tsx title="AgentConversation.tsx"
import { useMemo, useSyncExternalStore, type FormEvent } from "react";
import { Button, Chat } from "stream-chat-react";
import {
  AIClientIdentity,
  AIConversation,
  AIMessageComposer,
  type AIToolApprover,
} from "stream-chat-react/ai-components";

import type { AgentChat } from "./agent";
import { useAgentMessages } from "./useAgentMessages";

export const AgentConversation = ({ chat }: { chat: AgentChat }) => {
  const { session, client, channel } = chat;
  const messages = useAgentMessages(channel);
  // What the agent is doing: idle, listening, responding, working or ended.
  const { kind } = useSyncExternalStore(
    session.state.subscribe,
    session.state.get,
  );
  const isAnswering = kind === "responding" || kind === "working";

  const approver = useMemo<AIToolApprover>(
    () => ({
      userId: client.userId ?? "",
      clientId: AIClientIdentity.installId(),
      decide: async (call, allowed) => session.decide(call.id, { allowed }),
    }),
    [client, session],
  );

  const ask = (event: FormEvent<HTMLFormElement>) => {
    event.preventDefault();
    const text = String(new FormData(event.currentTarget).get("message") ?? "");
    if (!text.trim() || isAnswering) return;
    event.currentTarget.reset();
    void session.responses.create(text);
  };

  return (
    <Chat client={client}>
      {/* `str-chat` is the SDK's theme scope: its fonts, colors and spacing. */}
      <div
        className="str-chat"
        style={{
          display: "flex",
          flexDirection: "column",
          height: "100dvh",
          maxWidth: "48rem",
          marginInline: "auto",
        }}
      >
        <div style={{ flex: 1, minHeight: 0 }}>
          <AIConversation approver={approver} messages={messages} />
        </div>
        <div style={{ padding: "0 1rem 1rem" }}>
          <AIMessageComposer onSubmit={ask}>
            <AIMessageComposer.TextInput name="message" />
            {/* The composer stacks its children: put the buttons in a row. */}
            <div
              style={{
                display: "flex",
                gap: "0.25rem",
                justifyContent: "flex-end",
              }}
            >
              <AIMessageComposer.SpeechToTextButton />
              {isAnswering ? (
                <Button
                  appearance="outline"
                  onClick={() => session.interrupt()}
                  size="sm"
                  type="button"
                  variant="secondary"
                >
                  Stop
                </Button>
              ) : (
                <AIMessageComposer.SubmitButton />
              )}
            </div>
          </AIMessageComposer>
        </div>
      </div>
    </Chat>
  );
};
```

`AIConversation` scrolls inside itself, so give it a height, here as the growing child of a column. The composer's form grows to fill a flex container it's placed in, so it sits in a `div` of its own below the conversation, and it stacks what's inside it, so its buttons go in a row of their own. The column is at most `48rem` wide and centered, so lines stay short enough to read on a wide window.

The screen renders inside an element with the `str-chat` class, the SDK's theme scope. Inside it, the AI components and the SDK's `Button` take the SDK's fonts, colors and spacing. `Chat` provides the client and the translations but renders no element, so without one the page keeps the browser's default font. `Chat` gives the components the SDK's translations, as described in [Localization](#localization).

Sign the user in, then open a conversation, for example from a button:

```tsx title="App.tsx"
import { useState } from "react";
import { Button } from "stream-chat-react";

import { openConversation, signIn, type AgentChat } from "./agent";
import { AgentConversation } from "./AgentConversation";

export const App = () => {
  const [chat, setChat] = useState<AgentChat>();

  const start = async () => {
    await signIn({ id: "jane", name: "Jane" });
    setChat(await openConversation());
  };

  return chat ? (
    <AgentConversation chat={chat} />
  ) : (
    <div className="str-chat">
      <Button
        appearance="solid"
        onClick={() => void start()}
        size="md"
        type="button"
        variant="primary"
      >
        Ask the agent
      </Button>
    </div>
  );
};
```

Run the app and ask something. While the agent works on a reply that shows nothing yet, the conversation shows it thinking. Then the reply writes itself out, with Markdown, code and charts, and with the reasoning and tool calls that led to it. While it writes, the Stop button stops it, and under each finished reply the user can copy and share it.

The [Conversation view](https://getstream.io/chat/docs/sdk/react/ai-components/conversation-view/) guide covers what else the screen can show, such as the question while it's sent, older messages, and an empty state. The [Composer](https://getstream.io/chat/docs/sdk/react/ai-components/composer/) guide adds attachments and chat options.

## Step 6: Add voice

The composer already takes voice: its microphone button dictates into it.

To let the user talk to the agent instead, start a voice session. The agent joins a call right away, and the page joins it with the microphone on. `VoiceSession` lives in the `@stream-io/stream-agents/video` entry point, and the Video React SDK plays the agent's audio:

```bash
npm install @stream-io/video-react-sdk
```

Give the agent a face with `VoiceGlow`, which moves differently while the agent is connecting, listening, thinking and speaking:

```tsx title="AgentVoice.tsx"
import { VoiceSession } from "@stream-io/stream-agents/video";
import {
  ParticipantsAudio,
  StreamCall,
  StreamVideo,
  useCallStateHooks,
} from "@stream-io/video-react-sdk";
import { useEffect, useSyncExternalStore } from "react";
import { Button } from "stream-chat-react";
import { VoiceGlow } from "stream-chat-react/ai-components";

import { api } from "./agent";

/** Starts a session with voice on. Call it from a click. */
export const startVoice = () => VoiceSession.start(api.agent("my-agent"));

export const AgentVoice = ({ voice }: { voice: VoiceSession }) => {
  const { call, client, muted, status } = useSyncExternalStore(
    voice.subscribe,
    voice.get,
  );

  // Joins the call with the microphone on. Run twice, it joins once.
  useEffect(() => {
    voice.join().catch((error: unknown) => console.error(error));
  }, [voice]);

  return (
    <div className="str-chat">
      <VoiceGlow state={status} style={{ width: 240, height: 240 }} />
      {call && client && (
        <StreamVideo client={client}>
          <StreamCall call={call}>
            <AgentAudio />
          </StreamCall>
        </StreamVideo>
      )}
      <Button
        appearance="outline"
        onClick={() => void voice.setMuted(!muted)}
        size="md"
        type="button"
        variant="secondary"
      >
        {muted ? "Unmute" : "Mute"}
      </Button>
      {/* Leaves the call and ends the session startVoice() opened. */}
      <Button
        appearance="solid"
        onClick={() => void voice.leave()}
        size="md"
        type="button"
        variant="danger"
      >
        Hang up
      </Button>
    </div>
  );
};

/** Plays the agent. */
const AgentAudio = () => {
  const { useRemoteParticipants } = useCallStateHooks();
  return <ParticipantsAudio participants={useRemoteParticipants()} />;
};
```

Call `startVoice()` from a click: a browser asks for the microphone and plays audio only after one. `join()` rejects when joining fails, for example when the user denies the microphone.

What is said on the call is written into the session's channel, so `openConversation(voice.session)` and the views from step 5 show it as a transcript. The [Voice agent](https://getstream.io/chat/docs/sdk/react/ai-components/use-cases/voice-agent/) use case builds the whole screen: the agent's state, the visualizations, mute and hang up, and what was said written out as a conversation. An agent made with `--template voice` also lets you pick its speech-to-text and text-to-speech models, its voice and its greeting.

## Theming

The AI components follow the `stream-chat-react` theme. Inside `.str-chat` they pick up the SDK's light and dark theme tokens, and outside of it they fall back to built-in light colors.

To change them, set the `--str-chat__ai-*` CSS variables. The stylesheet never declares these variables itself, so your values win at any scope, including `:root`:

```css
:root {
  --str-chat__ai-accent: #7c3aed;
  --str-chat__ai-user-message-bg: #ede9fe;
  --str-chat__ai-syntax-keyword: #c084fc;
  --str-chat__ai-voice-color: #7c3aed;
}
```

| Variable                                                             | Styles                                                                           |
| -------------------------------------------------------------------- | -------------------------------------------------------------------------------- |
| `--str-chat__ai-text-primary`, `--str-chat__ai-text-secondary`       | Text                                                                             |
| `--str-chat__ai-accent`                                              | Accents, such as the icons of a reply's steps                                    |
| `--str-chat__ai-user-message-bg`, `--str-chat__ai-user-message-text` | The user's message bubbles                                                       |
| `--str-chat__ai-border`                                              | Borders, such as the composer's                                                  |
| `--str-chat__ai-syntax-*`                                            | Code highlighting                                                                |
| `--str-chat__ai-voice-color`, `--str-chat__ai-voice-backdrop`        | `VoiceGlow` and `VoiceWave`, and the surface they sit on, which picks their look |

The [AI components](https://getstream.io/chat/docs/sdk/react/reference/theming-variables/component-variables/#ai-components) section of the component variables reference lists more of them, with the SDK token each follows, and the stylesheet's [`_tokens.scss`](https://github.com/GetStream/stream-chat-react/blob/master/src/plugins/AIComponents/styling/_tokens.scss) has every one. Focus rings use the SDK's `--str-chat__border-utility-focused` token.

The rules use the `str-chat__ai-` class prefix (for example `str-chat__ai-message-composer__form` and `str-chat__ai-streaming-message`), so you can target them with your own CSS, in a [CSS layer](https://getstream.io/chat/docs/sdk/react/features/app-experience/theming/) like the rest of the SDK styles. The components draw `stream-chat-react` icons, which you replace through `WithComponents` like any other SDK icon.

### Localization

Every text the components show, such as the composer's "Ask a question..." placeholder or "Thought for 12s", goes through `Streami18n` like the rest of the SDK. Inside `Chat` (or a `TranslationProvider`) they follow the active language, and outside it they show their built-in English copy.

The keys are namespaced under `aiComponents.`. To change some of the English copy, pass `Chat` an instance whose `translationsForLanguage` lists the keys to change:

```tsx
import { Chat, Streami18n } from "stream-chat-react";

const streamI18n = new Streami18n({
  translationsForLanguage: {
    "aiComponents.messageComposer.textInput.placeholder":
      "Message the assistant",
  },
});

<Chat client={client} i18nInstance={streamI18n}>
  {/* the conversation and the composer */}
</Chat>;
```

Every other text stays as it is. English is the only bundled language, so register a dictionary with `registerTranslation()` to translate them, as described in the [Localization](https://getstream.io/chat/docs/sdk/react/features/app-experience/localization/) guide. The library's [README](https://github.com/GetStream/stream-chat-react/blob/master/src/plugins/AIComponents/README.md#7-internationalization) lists every key with its English copy.

## The components

Everything below is exported from `stream-chat-react/ai-components`.

| Component or hook                                                                                                                                                   | What it does                                                                                               | Guide                                                                                    |
| ------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------- |
| `AIConversation`                                                                                                                                                    | Lays out a conversation the way AI assistants do                                                           | [Conversation view](https://getstream.io/chat/docs/sdk/react/ai-components/conversation-view/)               |
| `AIUserMessage`, `AIAssistantMessage`, `AIReplyActions`, `AIMessageAttachment`                                                                                      | Show the user's messages and the agent's replies, their images and files, and the actions under each reply | [Conversation view](https://getstream.io/chat/docs/sdk/react/ai-components/conversation-view/)               |
| `AISuggestions`                                                                                                                                                     | Offers conversation starters                                                                               | [Conversation view](https://getstream.io/chat/docs/sdk/react/ai-components/conversation-view/)               |
| `fromStreamMessage`                                                                                                                                                 | Turns a Stream Chat message into the `AIMessage` the views show                                            | [Conversation state](https://getstream.io/chat/docs/sdk/react/ai-components/conversation-state/)             |
| `AIMessageComposer`, `ChatOptionsList`, `SelectedChatOptionChip`, `useText`, `useAttachments`, `useIsDisabled`, `useAIMessageComposerContext`                       | Takes what the user writes, with attachments, chat options and a model picker                              | [Composer](https://getstream.io/chat/docs/sdk/react/ai-components/composer/)                                 |
| `useSpeechToText`                                                                                                                                                   | Dictates with the browser's Web Speech API                                                                 | [Composer](https://getstream.io/chat/docs/sdk/react/ai-components/composer/)                                 |
| `StreamingMessage`, `AIMarkdown`                                                                                                                                    | Types out Markdown, code, tables and charts as they stream                                                 | [Streaming messages](https://getstream.io/chat/docs/sdk/react/ai-components/streaming-messages/)             |
| `AIStateIndicator`, `AITypingIndicator`                                                                                                                             | Shows what the agent is doing before its reply has text                                                    | [Streaming messages](https://getstream.io/chat/docs/sdk/react/ai-components/streaming-messages/)             |
| `AIMessageParts`, `AIMessagePart`, `AIReasoning`, `AIThinking`, `AIToolCall`                                                                                        | Shows a reply's reasoning and tool calls                                                                   | [Reasoning and tool calls](https://getstream.io/chat/docs/sdk/react/ai-components/reasoning-and-tool-calls/) |
| `AIToolApproval`, `AIToolApprovalCard`, `AIToolArguments`, `AIToolApproverProvider`, `useAIToolApprover`, `AIClientIdentity`                                        | Asks the user before a tool runs                                                                           | [Reasoning and tool calls](https://getstream.io/chat/docs/sdk/react/ai-components/reasoning-and-tool-calls/) |
| `AIToolAuthorization`, `AIToolAuthorizationCard`, `createPopupAuthorizer`, `completeConnectorSignIn`                                                                | Signs the user in to a connector a tool call waits for                                                     | [Reasoning and tool calls](https://getstream.io/chat/docs/sdk/react/ai-components/reasoning-and-tool-calls/) |
| `AIUIHost`, `AIUIView`, `defineAIUIComponent`, `AIUIComponentView`, `AIUIRuntimeView`, `AIUIEntrance`, `AIUIEntranceStage`, `useAIUIEntrance`, `useAIUIHostRefresh` | Shows UI the agent writes in place of a reply's text                                                       | [Generative UI](https://getstream.io/chat/docs/sdk/react/ai-components/generative-ui/)                       |
| `VoiceGlow`, `VoiceWave`, `useAudioLevel`                                                                                                                           | Shows what a voice agent is doing                                                                          | [Voice visualizations](https://getstream.io/chat/docs/sdk/react/ai-components/voice-visualizations/)         |
| `useHeardText`                                                                                                                                                      | Reveals a spoken reply at the pace the user hears it                                                       | [Voice agent](https://getstream.io/chat/docs/sdk/react/ai-components/use-cases/voice-agent/)                 |
| `--str-chat__ai-*` CSS variables                                                                                                                                    | Set the colors of all of them                                                                              | [Theming](#theming)                                                                      |

The main `stream-chat-react` entry point has AI support of its own, for chats built with `MessageList`: `StreamedMessageText`, an `AIStateIndicator` that follows the channel's AI state, and the `StopAIGenerationButton` the default composer shows, described in [SDK integration](https://getstream.io/chat/docs/sdk/react/ai-components/sdk-integration/). Its `useAIState` and `useMessageTextStreaming` hooks are in the [AI hooks](https://getstream.io/chat/docs/sdk/react/reference/hooks/ai-hooks/) reference, with `useSpeechToText` from this entry point.

## Migrating from `@stream-io/chat-react-ai`

The components used to ship as the standalone `@stream-io/chat-react-ai` package, which they replace. To move to `stream-chat-react/ai-components`:

1. **Dependencies.** Remove `@stream-io/chat-react-ai`, and upgrade `stream-chat-react` to v15. Remove `material-symbols` as well if you only installed it for these components: they render `stream-chat-react` icons now.
2. **Imports.** Replace the package name in imports, and the stylesheet path:

   | Before                                      | After                                          |
   | ------------------------------------------- | ---------------------------------------------- |
   | `@stream-io/chat-react-ai`                  | `stream-chat-react/ai-components`              |
   | `@stream-io/chat-react-ai/styles/index.css` | `stream-chat-react/dist/css/ai-components.css` |

3. **Class names and CSS variables.** The `aicr__` prefix became `str-chat__ai-`. `aicr__ai-message-composer…` becomes `str-chat__ai-message-composer…`, every other `aicr__…` class becomes `str-chat__ai-…`, and `--aicr__…` variables become `--str-chat__ai-…`. The [full mapping table](https://github.com/GetStream/stream-chat-react/blob/master/src/plugins/AIComponents/README.md#3-class-names-and-css-custom-properties) lists every renamed class and variable.
4. **`useMessageTextStreaming`.** The [hook](https://getstream.io/chat/docs/sdk/react/reference/hooks/ai-hooks/#usemessagetextstreaming) is no longer exported next to the AI components. Import it from `stream-chat-react` and rename its `letterIntervalMs` option to `streamingLetterIntervalMs`. The `StreamingMessage` props haven't changed.
5. **`SpeechToTextButton`.** It's only available as `AIMessageComposer.SpeechToTextButton`, and its `options` prop is now passed to the speech recognizer.

The component APIs are otherwise unchanged.

Coming from `stream-chat-react/ai-components` on v14? Its exports, props, class names and CSS variables are the same on v15. Only the translation keys changed, to the namespaced keys described in [Localization](#localization), so rename the ones you registered translations for.

## Next steps

- [Customer support agent](https://getstream.io/chat/docs/sdk/react/ai-components/use-cases/customer-support-agent/): answers from your help center, order lookups, a refund the user confirms, and a handover to your team.
- [Personal assistant](https://getstream.io/chat/docs/sdk/react/ai-components/use-cases/personal-assistant/): a list of conversations, tools that run in the browser, and a voice mode.
- [Voice agent](https://getstream.io/chat/docs/sdk/react/ai-components/use-cases/voice-agent/): a voice conversation with the agent as a glowing globe, and what was said written out.
- The AI cookbooks: an [AI chat widget](https://getstream.io/chat/docs/sdk/react/ui-cookbooks/ai/ai-chat-widget/), [streamed answers with a stop button](https://getstream.io/chat/docs/sdk/react/ui-cookbooks/ai/streamed-answers-with-stop-button/), and [voice agent visuals](https://getstream.io/chat/docs/sdk/react/ui-cookbooks/ai/voice-agent-visuals/).
- The [React assistant](https://github.com/GetStream/Vision-Agents/tree/accelerate/examples/voice_agents/react_assistant) sample, a complete app built on these components with a list of conversations, photos, voice mode, connector sign-ins and tools that run in the browser, and the ChatGPT-style app in the [`examples/ai-chatbot`](https://github.com/GetStream/stream-chat-react/tree/master/examples/ai-chatbot) folder of the `stream-chat-react` repository.
- [Stream Agents](https://getstream.io/agents/docs/quickstart/?lang=javascript): the agent itself, its tools, knowledge, connectors and phone numbers.

---

For the most recent version of this documentation, visit [https://getstream.io/chat/docs/sdk/react/ai-components/](https://getstream.io/chat/docs/sdk/react/ai-components/).