Streaming
Client Transports
Consume Anvia streams from React and custom clients.
Use @anvia/react when a browser or React UI needs to consume streaming agent events.
The transport boundary is an async iterable:
type EventTransport<TRequest, TEvent> = {
send(request: TRequest, options?: TransportOptions): AsyncIterable<TEvent>;
};That lets UI state consume JSONL, SSE, WebSocket, local, or custom transports without changing the hook.
1. Fetch Events Directly
import { fetchEventStream } from "@anvia/react";
for await (const event of fetchEventStream<AgentStreamEvent>("/api/chat", {
method: "POST",
body: JSON.stringify({ message: "Hello", stream: true }),
headers: { "content-type": "application/json" },
})) {
if (event.type === "text_delta") {
renderDelta(event.delta);
}
}fetchEventStream(...) returns AsyncIterable<TEvent> and supports format: "jsonl" or format: "sse". If format is omitted, it infers SSE from content-type: text/event-stream and otherwise reads JSONL.
2. Create a Fetch Transport
import { createFetchTransport } from "@anvia/react";
const transport = createFetchTransport({
endpoint: "/api/chat",
format: "jsonl",
});
for await (const event of transport.send({ message: "Hello", stream: true })) {
console.log(event);
}The default transport uses POST, JSON request bodies, and JSONL response parsing.
3. Use Chat State in React
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>
);
}Passing endpoint is shorthand for a default JSONL fetch transport.
4. Pass a Custom Transport
const chat = useChat({
transport: {
async *send(request, options) {
yield* myWebSocketTransport(request, options);
},
},
});useChat(...) only consumes AsyncIterable events. It does not depend on fetch, JSONL, or SSE.
