@anvia/react
React hooks and client transports for Anvia chat applications.
@anvia/react provides useChat, transport abstractions, and stream parsers for building chat UIs that connect to an Anvia server endpoint.
Install
pnpm add @anvia/reactPeer dependency: react >= 18.
Quick Start
import { useChat } from "@anvia/react";
export function Chat() {
const chat = useChat({ endpoint: "/api/chat" });
return (
<form
onSubmit={(event) => {
event.preventDefault();
void chat.send();
}}
>
<div>{chat.text}</div>
<input
value={chat.input}
onChange={(event) => chat.setInput(event.target.value)}
/>
<button disabled={chat.status === "streaming"}>Send</button>
</form>
);
}This connects to a server route that returns a JSONL or SSE event stream (see @anvia/server).
Configuration
useChat accepts these options:
| Option | Type | Default | Purpose |
|---|---|---|---|
endpoint | string | URL | -- | URL for the default fetch transport |
transport | EventTransport | -- | Custom transport (overrides endpoint) |
format | "jsonl" | "sse" | "jsonl" | Stream format for the default transport |
initialMessages | ChatMessage[] | [] | Pre-populated message history |
createRequest | function | -- | Custom request builder |
eventToDelta | function | -- | Extract text delta from an event |
eventToFinal | function | -- | Extract final text from an event |
onEvent | function | -- | Callback for each streamed event |
onError | function | -- | Error callback |
useChat Return Value
type UseChatResult<TEvent, TMessage> = {
messages: TMessage[]; // conversation history
events: TEvent[]; // raw streamed events
input: string; // current input value
setInput(input: string): void;
send(input?: string): Promise<void>;
stop(): void; // abort the current stream
reset(messages?: TMessage[]): void;
status: "idle" | "streaming" | "error";
error: unknown;
text: string; // accumulated assistant text
};Transports
The transport layer is the boundary between your UI and the network. The default fetch transport works for most cases.
import { createFetchTransport, createChatTransport } from "@anvia/react";
// Generic fetch transport
const transport = createFetchTransport({
endpoint: "/api/chat",
format: "jsonl",
});
// Chat-specific transport (POST JSON by default)
const transport = createChatTransport({
endpoint: "/api/chat",
format: "sse",
});Pass a custom transport to useChat when you need WebSocket, local, or other non-HTTP transports.
Stream Parsers
Use these directly when you need raw stream access without useChat:
import { readJsonlStream, readSseStream, fetchEventStream } from "@anvia/react";
// Parse a ReadableStream as JSONL
for await (const event of readJsonlStream(stream)) {
console.log(event);
}
// Fetch and parse a stream in one call
for await (const event of fetchEventStream("/api/chat", {
method: "POST",
body: JSON.stringify({ message: "Hello" }),
format: "jsonl",
})) {
console.log(event);
}EventTransport Interface
All transports implement this interface:
type EventTransport<TRequest, TEvent> = {
send(request: TRequest, options?: TransportOptions): AsyncIterable<TEvent>;
};This makes useChat transport-agnostic: swap JSONL for SSE, HTTP for WebSocket, or a mock for testing without changing the hook.
Server Pairing
Pair @anvia/react with @anvia/server on the backend:
// Server (Next.js, Hono, Express, etc.)
import { createEventStream } from "@anvia/server";
return createEventStream(agent.prompt(message).stream(), {
format: "jsonl",
});// Client
const chat = useChat({ endpoint: "/api/chat", format: "jsonl" });Related
- Client Transports for transport concepts
- Readable Streams for stream internals
- React Reference for full API types
@anvia/serverfor the server-side counterpart
