Stream modes: values, updates, messages, custom
Autonomy is invisible today: Impulse rolls a dice and you find out from a log later. This module streams a graph run node-by-node into a browser panel, the same SSE pattern cockpit already uses. You will watch a dice roll happen live from your phone.
Streaming turns one blocking call into a sequence of events. Instead of await graph.invoke(…) returning once at the end, graph.stream(…) yields chunks as the graph runs.
for await (const chunk of await graph.stream(inputs, { streamMode: "updates" })) {
// chunk is the state delta from the node that just ran
}Stream modes decide what each chunk contains: values is the full state after each step; updates is only the delta each node returned (best for “which node just ran and what did it write”); messages is LLM tokens as they generate, for typewriter output; custom is arbitrary events you emit yourself from inside a node.
for await (const [mode, chunk] of await graph.stream(inputs, {
streamMode: ["updates", "custom"],
})) {
if (mode === "custom") renderDiceEvent(chunk);
else lightUpNode(chunk);
}Pass an array to combine modes; chunks then arrive as [mode, chunk] tuples so you can tell them apart.
Try it yourself
values vs updates for lighting up nodes
You want to light up the node that just ran in a live panel. Which stream mode do you want?
Show answer
Correct answer: C — updates, because it's only the delta the node just returned, so you see exactly what it wrote
updates gives you just the delta from the node that ran -- exactly what you need to know "this node ran, here's what it wrote" without having to diff two full-state snapshots yourself.