---
title: "Chat"
description: "Build a chat where replies mix text and generated UI - with your own state, with the AI SDK's useChat, or with @gistui/chat's store and layouts."
---

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

# Chat

In a chat, a reply is usually some text **and** a UI. Use the inline prompt: the model then writes chat text and puts the program in `gistui` code fences.

```ts
const system = prompt({ mode: "inline" }).text;
```

There are three ways to build the client, from most to least control.

## 1. Your own chat state

`splitReply` separates a reply into text parts and UI parts. `replyProgram` joins all the fences of one reply into one program.

```tsx
import { replyProgram, splitReply } from "@gistui/chat";

const parts = splitReply(text, { streaming }); // [{ kind: "text", text }, { kind: "ui", source, open }]
const program = replyProgram(parts);

// Render the text parts as chat text, then the UI once:
<GistUI library={ui} source={program} streaming={streaming} onAction={handle} />;
```

Other code blocks (`ts`, `json`) stay chat text.

## 2. The AI SDK's `useChat`

The same two functions work on the text of a `useChat` message. The full example is in [Vercel AI SDK](/docs/models/vercel-ai-sdk/#a-chat-with-usechat).

## 3. `@gistui/chat`

A headless store with model adapters and thread storage, plus React layouts.

```sh
npm i @gistui/chat @gistui/react @gistui/styles
yarn add @gistui/chat @gistui/react @gistui/styles
pnpm add @gistui/chat @gistui/react @gistui/styles
bun add @gistui/chat @gistui/react @gistui/styles
```

```tsx
import { aiSdk, createChat, localThread } from "@gistui/chat";
import { Chat } from "@gistui/chat/react";
import "@gistui/chat/chat.css";
import "@gistui/styles/styles.css";
import { ui } from "@gistui/react/ui";

const store = createChat({
  adapter: aiSdk({ url: "/api/chat" }),
  storage: localThread("support"),
});

<Chat store={store} library={ui} layout="sidebar" title="Assistant" suggestions={["Show last month's sales"]} />;
```

### Adapters

| Adapter | Talks to |
|---|---|
| `aiSdk({ url })` | A Vercel AI SDK route returning `toUIMessageStreamResponse()` |
| `openai({ model, url? })` | OpenAI Chat Completions and every compatible API |
| `anthropic({ model, url? })` | Anthropic Messages |
| `agui({ url })` | An AG-UI agent endpoint |
| `textStream({ url })` | Any endpoint that streams plain text |

Call models from your server. `apiKey` on an adapter sends the key from the browser, where every visitor can read it: it is for local prototypes only.

### The store

`createChat({ adapter, system?, initialMessages?, storage?, onError? })` returns a store with `send(text)`, `regenerate()`, `stop()`, `clear()` and a subscribable snapshot of the messages. It has no framework dependency, so it works under Vue, Svelte or Solid with your own markup.

### Layouts

`<Chat layout>` is `"full"` (a page), `"sidebar"` or `"tray"` (a bottom sheet). It takes the same `tools`, `mutations`, `onToolCall`, `theme`, `color`, `tokens`, `darkTokens` and `lockUntil` as `<GistUI>`.

## What the chat package handles for you

- **UI actions become messages.** A button's label or a form's summary goes back as the next message with `origin: "ui"`. The thread labels it "Sent from the UI", and the model receives it wrapped, so text chosen by a generated program is never mistaken for typed text. Send one yourself with `store.send(text, { origin: "ui" })`.
- **Only the latest answer refreshes.** Earlier answers still load and respond, but their timed queries are paused.
- **History is clean.** `requestHistory(messages)` is what the model receives: failed, empty and still-streaming replies are left out.
- **Threads persist.** The thread is saved after each sent message, about once a second while a reply streams, and at the end. A saved error keeps its HTTP status but not the provider's text.

## Editing an earlier UI

To let the model change a UI it already showed instead of writing it again, see [Edits and multi-turn](/docs/language/edits/).

Source: https://gistui.com/docs/guides/chat/index.mdx
