StateGraph and the Dice RollState schemas and reducers
No narration yet
Module 3, Lesson 125 min

State schemas and reducers

An agent loop (module 2) is one prebuilt shape. A StateGraph is you drawing your own shape: named nodes, edges between them, and a typed state object that flows through and accumulates.

Impulse's cold-mode heartbeat, sense then modulate then roll then route, is the system you love most. This module redraws it as an explicit StateGraph, parity-tested against src/strategy/dice.ts, rendered as a diagram, inspectable. It is the spine every later module upgrades.

State is a schema. You declare what the graph carries and how each field updates.

Declaring state with StateSchema
import {
  StateGraph, StateSchema, ReducedValue, MessagesValue,
  GraphNode, START, END, Command,
} from "@langchain/langgraph";
import * as z from "zod/v4";

const State = new StateSchema({
  messages: MessagesValue,
  retryCount: z.number().default(0),
  allSteps: new ReducedValue(
    z.array(z.string()).default(() => []),
    { inputSchema: z.string(), reducer: (cur, next) => [...cur, next] },
  ),
});

Reducers decide how a field merges when a node returns an update. A plain zod field is last-write-wins. MessagesValue appends messages. ReducedValue lets you define custom merge logic: in the example above, a node returns a single string and the reducer appends it to a running array. Reducers are why concurrent or streamed updates do not clobber each other.

Practice

Try it yourself

Recall

What a reducer is for

Two parts. The second one is where the concept earns its keep, so give a concrete case rather than a category.

What is a reducer for, and when would last-write-wins be the wrong merge strategy?

Quiz

StateSchema vs Annotation.Root

You open pod-factory's code and see Annotation.Root. What's the right read?