Skip to content
pandacoderz/ui

AI Chat

A complete chat surface that composes the nine core chat components, with a mock streaming transport you can swap for your API.

Ai Chat
Open preview

What’s inside

The block wires nine components into one screen:

  • Thread keeps the viewport pinned to new tokens.
  • Message renders user bubbles and assistant markdown with an action bar.
  • Reasoning shows thinking while it streams, then collapses.
  • Tool displays each tool call with status, input, and output.
  • Prompt Input with attach, model, send, and stop actions.
  • Suggestions on the empty state.
  • Model Selector in the header and inside the input.
  • Text Shimmer as the “Thinking…” placeholder.
  • Feedback Bar after the first completed reply.

Installation

npx shadcn@latest add https://ui.spencerwueste.com/r/ai-chat.json

The registry item pulls in every component it depends on.

Usage

import AIChat from "@/components/blocks/ai-chat/chat";

export default function Page() {
  return (
    <div className="h-dvh p-4">
      <AIChat />
    </div>
  );
}

Give the parent a bounded height. The block fills it and scrolls internally.

Going live

The demo uses mockTransport, an async generator that yields scripted events. To connect a real model, write a transport with the same shape:

import type { ChatTransport } from "@/components/blocks/ai-chat/types";

export const apiTransport: ChatTransport = async function* ({ messages, model, signal }) {
  const res = await fetch("/api/chat", {
    method: "POST",
    body: JSON.stringify({ messages, model }),
    signal,
  });
  const reader = res.body!.getReader();
  const decoder = new TextDecoder();
  while (true) {
    const { value, done } = await reader.read();
    if (done) break;
    for (const line of decoder.decode(value).split("\n").filter(Boolean)) {
      yield JSON.parse(line); // { type: "text-delta", text: "…" } etc.
    }
  }
  yield { type: "done" };
};

Then pass it in:

<AIChat transport={apiTransport} />

Event types

Event Payload Effect
reasoning-delta { text } Appends to the current reasoning part.
reasoning-done Marks reasoning complete (collapses the block).
tool-start { id, name, input? } Adds a running tool card.
tool-result { id, output } Completes the tool with output.
tool-error { id, errorText } Marks the tool as failed.
text-delta { text } Appends assistant text.
error { message } Ends the turn with an error message.
done Ends the turn.

API Reference

Prop Type Description
transport ChatTransport Event source. Defaults to mockTransport.
models ChatModel[] Options for the model selector.
defaultModel string Initially selected model id.
suggestions string[] Empty-state prompt chips.
title string Header title. Default “Assistant”.
className string Extra classes on the root.