Skip to content

Streaming

Copy page

client.chat.stream() sends a message and delivers the response incrementally over Server-Sent Events. It is callback-driven and resolves with the final assembled ChatMessage.

const finalMessage = await client.chat.stream(thread.id, "Tell me a story", {
assistantName: "your-assistant-id", // required — the release's assistant/model id
onChunk: (text) => process.stdout.write(text),
onComplete: (message) => console.log("\n\ndone:", message.id),
onError: (error) => console.error(error),
});
stream(
chatId: string,
content: string,
options?: SendMessageOptions & StreamOptions,
): Promise<ChatMessage>

options accepts everything send() accepts (assistantName, attachments, metadata, replyTo, …) plus the streaming callbacks below.

CallbackFires when
onChunk(text)A content delta arrives. The simplest way to render tokens.
onComplete(message)The full message is assembled.
onError(error)The stream fails (a typed DivinciError).
onArenaVariant(variant)An arena variant arrives (arena mode).
onArenaComplete(variants)All arena variants have arrived.
onEvent(event)Low-level access to every event (see below).

For richer UIs (showing RAG sources, render-then-finalize, arena skeletons), use onEvent, which receives a discriminated union:

await client.chat.stream(thread.id, "What's covered under warranty?", {
assistantName: "your-assistant-id",
onEvent: (event) => {
switch (event.type) {
case "start":
beginBubble(event.messageId);
break;
case "chunk":
appendText(event.content);
break;
case "context":
renderSources(event.context); // RAG citations
break;
case "done":
finalize(event.message, event.usage);
break;
case "error":
showError(event.error);
break;
case "arena-variant":
renderVariant(event.variantIndex, event.variant);
break;
case "arena-complete":
enableVariantPicker(event.variants);
break;
}
},
});

Pass an AbortSignal to stop generation (e.g. a “Stop” button):

const controller = new AbortController();
const promise = client.chat.stream(thread.id, "Write a long essay", {
assistantName: "your-assistant-id",
onChunk: render,
signal: controller.signal,
});
stopButton.onclick = () => controller.abort();

Aborting rejects the promise; catch it and treat it as a user cancellation rather than an error.

function useStreamingSend(client: DivinciClient, threadId: string) {
const [text, setText] = useState("");
const controller = useRef<AbortController>();
const send = useCallback(async (prompt: string) => {
setText("");
controller.current = new AbortController();
await client.chat.stream(threadId, prompt, {
assistantName: "your-assistant-id",
onChunk: (delta) => setText((prev) => prev + delta),
signal: controller.current.signal,
});
}, [client, threadId]);
const stop = () => controller.current?.abort();
return { text, send, stop };
}