Your server speaks AG-UI. TanStack useChat still misses finishReason, the model id, or leftover usage. Put those extras in metadata.tanstack on the event. Spec fields stay at the top.
Copy this RUN_FINISHED event first:
{
"type": "RUN_FINISHED",
"threadId": "thread-1",
"runId": "run-1",
"usage": [
{
"inputTokens": 12,
"outputTokens": 34,
"totalTokens": 46
}
],
"metadata": {
"tanstack": {
"finishReason": "stop",
"model": "gpt-5.5"
}
}
}The client copies metadata.tanstack onto the chunk. After chunk.type === "RUN_FINISHED", read chunk.metadata?.tanstack?.finishReason. In-process usage is TanStack TokenUsage (promptTokens). The wire uses the spec array (inputTokens).
Send these on every successful run:
| Field | Where | Why the client needs it |
|---|---|---|
| type, threadId, runId | Spec top level | Frame the run. Missing ids break resume and correlation. |
| usage[] | Spec top level on RUN_FINISHED / RUN_ERROR | Token counts. Use inputTokens, outputTokens, totalTokens. |
| finishReason | metadata.tanstack on RUN_FINISHED | After a tool result, the client continues only when this is not "stop". |
| model | metadata.tanstack | SSE [DONE] fallback and generation reconstruct. |
finishReason is one of "stop", "length", "content_filter", "tool_calls", or null.
If you omit finishReason after a tool result, the client treats it as not "stop" and can send another turn.
import { useChat, fetchServerSentEvents } from "@tanstack/ai-react";
const { messages } = useChat({
connection: fetchServerSentEvents("/api/chat"),
onChunk: (chunk) => {
if (chunk.type === "RUN_FINISHED") {
console.log(chunk.usage);
console.log(chunk.metadata?.tanstack?.finishReason);
console.log(chunk.metadata?.tanstack?.model);
}
},
});Do not import a helper. Check chunk.type, then read chunk.metadata?.tanstack.
AG-UI RUN_ERROR has message and optional code at the top. Put correlation ids in metadata.tanstack:
{
"type": "RUN_ERROR",
"message": "Provider timeout",
"code": "TIMEOUT",
"metadata": {
"tanstack": {
"threadId": "thread-1",
"runId": "run-1",
"model": "gpt-5.5"
}
}
}Add these when you use the matching feature:
A TanStack chat() server already writes this bag. Use this page when you emit AG-UI events yourself.
See Streaming for the event table, and AG-UI Client Compliance for the request body.