Can you check the April receipt?
Preview
Design guidance
Keep normalized messages and application state outside the Chat frame. The Vercel AI SDK or TanStack AI hook owns messages, transport, and run lifecycle; Ghost UI renders the normalized thread and binds only commands the active runtime supports. TanStack Start is a web application host. It is separate from the TanStack AI runtime used in the second SDK example.
Installation
Install the Chat parts and the adapters that match your runtime. The adapters are optional pure TypeScript utilities. They do not add an SDK runtime dependency to Ghost UI.
Install
Install
Install
Install
The local previews use both SDK hooks and small local transports that emit their native stream protocols. Install the SDK packages in your application when you copy these examples:
TanStack AI is already pinned in this repository. Applications that use the TanStack AI example need compatible @tanstack/ai, @tanstack/ai-client, and @tanstack/ai-react versions. The local TanStack connection uses the installed AG-UI event contract. The web preview is hosted by TanStack Start; that host does not provide or replace the AI runtime.
The adapters do not bundle a server, provider, API key, upload flow, or SDK runtime into Ghost UI. Composer file attachments need caller-owned conversion to the provider's media format. Upload files first when the provider needs a URL, then pass supported media parts to the SDK hook.
Basic usage
Use ChatContent for the caller-owned transcript. Add ChatHeader, ChatFooter, or ChatStatus only when that task needs them. Add a Composer in the footer when the conversation accepts input.
Structures
Examples
Human support chat
Keep the transcript and composer in one complete support task.
Assistant stream and stop
Grow a deterministic local answer and stop it while it is streaming without losing the transcript.
Read-only transcript
Show a completed transcript without a composer or dead input action.
Questionnaire handoff
Replace the composer with a real three-question handoff, then restore it after one acknowledged answer message.
Rich response
Compose one helpful answer with a citation, a useful file, and a caller-owned artifact.
Artifact custom data
Render named custom data through caller-owned Snippet and Tabs composition. This does not create an Artifact component.
SDK integration
Vercel and TanStack AI own messages, transport, streaming and cancellation. Ghost UI owns normalized rendering and draft interaction. These offline previews use the real hooks; replace the local transport with your API connection in an application. The shadcn AI SDK and TanStack helpers demonstrate the same boundary. Their current TanStack peer ranges do not match this repository, so these examples use native local transports.
Vercel AI SDK
The Vercel AI SDK hook owns messages, status, and the local streaming transport. This prepared follow-up uses the real useChat lifecycle and can be stopped while it streams.
Edit the earlier user message and resubmit through native sendMessage({ messageId, text }). Retry uses native targeted regeneration. The adapter exposes editing only when it has the current message snapshot. Attachments remain caller-converted.
For approval and clarification actions, bind the SDK command with the exact tool or request identity from the normalized part. bindApproval needs the provider approval ID. bindClarification needs the request ID and revision plus its tool name and tool-call ID. A fulfilled command does not resolve a request by itself; the application must acknowledge it in its message state.
TanStack AI
TanStack AI uses its own useChat hook and connection adapter. The same prepared weekly update streams through the TanStack connection and the hook's native stop command. Editing replaces the selected user message with the native setMessages prefix, then sends the replacement text. The current hook's reload retries only the latest assistant response; it does not expose arbitrary message retry.
Voice note
Record a short note, review playback, then send or remove it. Microphone access starts when you select Record. A denied permission keeps an error visible. Send adds one user message after acknowledgement; a failed send keeps the note ready for retry.
Voice note
Record a short note, review it, then send or remove it.
The caller owns recording and delivery. Copy the lifecycle helper with this example.
voice-session.ts
API reference
| Prop | Type | Default | Description |
|---|---|---|---|
label | string | "Chat" | Names the conversation region. |
inputPolicy | "allow" | "block" | "allow" | Provides caller context for whether a pending request blocks input. |
pendingInput | boolean | false | Marks an application-owned request as pending without interpreting composer text. |
inputMessage | string | "Answer the questions above to continue." | Context text exposed to composed input controls when the policy blocks input. |
| Prop | Type | Default | Description |
|---|---|---|---|
kind | "error" | "connection" | "info" | "info" | Names the caller-owned status kind. |
message | ReactNode | Provides the real error, connection, or informational status. | |
onRetry | () => void | Adds a caller-owned retry action when recovery is available. |
ChatMessage.actor remains the runtime role (user, assistant, or system). Optional author carries caller-mapped participant identity; optional delivery carries caller-supplied receipt state. ChatController.editAndResubmit({ messageId, text }) exists only when the adapter has the native edit operations and current message snapshot. TanStack AI retry targets only the latest assistant response; Vercel AI SDK also accepts a targeted message ID.
Chat is a named section. ChatContent is a flexible region that keeps focus with its caller-owned controls. ChatStatus uses a polite status announcement, or an alert for an error. The frame does not invent a live region for streaming tokens and does not move focus.