Getting started

Build a chatbot

Put a React chat UI on top of your chat endpoint.

Put a chat UI in front of your agent with the AI SDK useChat hook. Blazing Agents keeps the history, so the page only remembers the session ID.

Before you begin

Finish Connect Blazing Agents to your app. This page talks to that /api/chat endpoint, which works the same whether you wrote it in TypeScript or Python.

You need a React app served from the same origin as the endpoint, for example through your dev server's proxy. Install the chat hook:

npm install @blazingagents/sdk ai @ai-sdk/react

Add the chat component

BlazingAgentsChatTransport connects useChat to your endpoint. It sends only the newest message, picks up the new session ID from the first response, and sends that ID back on every later message.

Chat.tsx
import { useChat } from "@ai-sdk/react";
import { BlazingAgentsChatTransport } from "@blazingagents/sdk";
import { useState } from "react";

export function Chat({ token }: { token: string }) {
  const [input, setInput] = useState("");
  const [transport] = useState(
    () =>
      new BlazingAgentsChatTransport({
        api: "/api/chat",
        headers: { authorization: `Bearer ${token}` },
        sessionId: localStorage.getItem("chat-session") ?? undefined,
        onSessionId: (id) => localStorage.setItem("chat-session", id),
      }),
  );
  const { messages, sendMessage, status } = useChat({ transport });

  return (
    <main>
      {messages.map((message) => (
        <p key={message.id}>
          <strong>{message.role}:</strong>{" "}
          {message.parts.map((part) => (part.type === "text" ? part.text : ""))}
        </p>
      ))}
      <form
        onSubmit={(event) => {
          event.preventDefault();
          void sendMessage({ text: input });
          setInput("");
        }}
      >
        <input value={input} onChange={(event) => setInput(event.target.value)} />
        <button type="submit" disabled={status !== "ready"}>Send</button>
      </form>
    </main>
  );
}

Render <Chat token={...} /> with your user's sign-in token. With the demo endpoint from the previous page, that is the value of DEMO_USER_TOKEN. Send a message and the answer streams in. Reload the page and your next message continues the same conversation, because the session ID is in localStorage.

What to add next

The component above is the smallest chat that works. Add the pieces your product needs, by hand or by asking your coding agent.

  • Stop. Call stop() from useChat to cancel a turn. A cancelled turn adds nothing to the saved history. It cannot undo a tool call that already ran, and a resend can run that tool again.
  • Roll back failed turns. A turn that fails or is stopped is not saved by Blazing Agents, but useChat still shows it. Keep the messages from the last successful onFinish and restore them with setMessages() on error or stop. Leave the typed text in the input so the user can edit it and send again. Each send is a new attempt with a new message ID. There is no separate retry call.
  • Show errors. Render error from useChat and call clearError() before the next send.
  • Regenerate. Call regenerate() to replace the last saved answer. If it fails or is stopped, the old answer stays. Enable it only after a successful answer, because a prompt that failed was never saved.
  • New conversation. Remove chat-session from localStorage, create a new transport without a sessionId, and clear the messages. The next message starts a new session.
  • History after a reload. The component shows only the messages from the current page visit. Have your backend read earlier messages with client.sessions.messages() and pass them to useChat as messages. See reading the transcript.
  • Dropped connections. If the network drops after the agent finished, the answer may already be saved. Reload history before assuming it was lost.
  • Busy sessions. While a tool call in the session waits for approval, new messages return a session_busy error. Show it and let the user send again later. If two messages race in the same session, one of them fails rather than mixing the histories.
  • Images. Send them in the same message as extra file parts. See send an image.
  • Tool approvals. They arrive in the same stream when an agent needs a person to allow a tool call. Send the decision through your backend, not only with addToolApprovalResponse. See render the resumed answer.

Next

On this page