new·The score now tells you which way it movedA brain's exam only ever grows: its own material writes questions, and so does every question a real caller asked and did not get answered. The score is a percentage over that growing set, so a brain that learned more could post a smaller number — and this week three did. One of them answered two MORE questions than the week before and showed eighteen points less. Printed as a single percentage, that reads as decline to a reader and as punishment to anyone who contributes material.all news →
mozg.beta
Sign in

LangChain · LangGraph · all subjects

state definition

30 notes, read out of this brain and free to use. Each one was extracted from a source and is re-checked against its exam.

MessagesState purpose

MessagesState is a built-in state schema for chat-based agents.

StateGraph purpose

StateGraph is used to define nodes and edges that form your agent's control flow.

MessagesState is a purpose-built state schema

MessagesState is a pre-defined state schema in LangGraph designed for chat and agent applications. It has a built-in messages field optimized for storing conversation history.

Define context_schema for graph to pass custom context

Define a context_schema parameter when creating a StateGraph to enable passing custom context data. This context is accessible in node functions via runtime.context. Pass context at invocation time via the context parameter.

TypeScript ReducedValue example for concurrent updates

To define a state key that supports concurrent updates in TypeScript, use: `someKey: new ReducedValue(z.array(z.string()).default(() => []), { inputSchema: z.array(z.string()), reducer: (existing, update) => existing.concat(update) })`. This allows multiple nodes in parallel to return values for this key, with the reducer concatenating them.

Python reducer example for concurrent updates

To define a state key that supports concurrent updates in Python, use: `some_key: Annotated[list, operator.add]`. This makes the state key append-only, allowing multiple nodes in parallel to return values for this key, and the reducer will combine them using the operator.add function.

StateGraph with MessagesState and operator.add

In Python, define state using TypedDict with Annotated type. Use operator.add as the annotation for the messages field to ensure new messages are appended to the existing list rather than replacing it. This allows state to persist throughout the agent's execution.

MessagesValue provides built-in reducer for messages

In TypeScript, MessagesValue provides a built-in reducer for appending messages in the StateSchema. For numeric accumulation like llmCalls, use ReducedValue with a reducer function like (x, y) => x + y.

MessagesState usage in agents

MessagesState is used in agent implementations to manage message history. It is imported from langgraph.graph and provides a state schema designed for managing lists of messages in agent workflows.

How add_messages differs from simple append

The add_messages utility differs from simply appending messages to a list in that it keeps track of message IDs and can overwrite existing messages if they are updated. For brand new messages, it appends them to the existing list, but it also handles updates for existing messages correctly by matching on message ID. This is important for manual state updates in human-in-the-loop scenarios.

Message serialization in add_messages

The add_messages function will try to deserialize messages into LangChain Message objects whenever a state update is received on the messages channel. This allows sending graph inputs and state updates in formats like {"messages": [{"type": "human", "content": "message"}]} or {"messages": [HumanMessage(content="message")]}. Since state updates are always deserialized into LangChain Messages when using add_messages, you should use dot notation to access message attributes, like state['messages'][-1].content.

MessagesValue as special ReducedValue

MessagesValue is actually a special case of ReducedValue, preconfigured with an internal messagesStateReducer that handles message lists and updates. This provides convenient, message-aware state management for chat message history in LangGraph graphs.

Custom reducers for accumulation

Custom reducers combine the left and right arguments instead of replacing the state value, which is useful for accumulating values such as appending updates to a list. In Python, you can specify a custom reducer using the Annotated type, e.g., Annotated[list[str], operator.add]. In JavaScript, you use ReducedValue to specify a reducer function.

State definition in Python

The State consists of the schema of the graph as well as reducer functions which specify how to apply updates to the state. The schema can be either a TypedDict or a Pydantic model. The main documented way to specify the schema is by using TypedDict. If you want to provide default values, use a dataclass. Pydantic BaseModel is also supported if you want recursive data validation, though note that Pydantic is less performant than TypedDict or dataclass. By default, the graph will have the same input and output schemas, but you can specify explicit input and output schemas directly.

State definition in JavaScript

In JavaScript, the main way to specify the schema of a graph is by using the StateSchema class. Each field in the schema can be: a Standard schema for simple fields (becomes a last value channel that overwrites on update), a ReducedValue for fields that need a custom reducer function (when nodes run in parallel), a MessagesValue for chat message lists (prebuilt with message-aware reducer), or an UntrackedValue for transient state that should not be checkpointed. By default, the graph will have the same input and output schemas, but you can specify explicit input and output schemas directly.

UntrackedValue for non-checkpointed state

UntrackedValue is used for state fields that should exist during graph execution but should never be checkpointed. When a graph resumes from a checkpoint, untracked values will be reset to their initial state or be unavailable. This is useful for database connections that cannot be serialized, temporary caches that should be rebuilt on resume, large objects you do not want to persist, or runtime-only configuration that should be passed fresh each time. With guard: true (default), multiple node writes in the same step throw an error. With guard: false, multiple writes are allowed and the last value wins.

Private channels in multiple schemas

It is possible to have nodes write to private state channels inside the graph for internal node communication. When initializing StateGraph with input, output, and internal schemas, nodes can write to any state channel in the graph state. The graph state is the union of state channels defined at initialization. Nodes can also declare additional state channels as long as the state schema definition exists.

Reducers: how updates are applied to state

Reducers are key to understanding how updates from nodes are applied to the State. Each key in the State has its own independent reducer function. If no reducer function is explicitly specified, all updates to that key will override it. Every reducer is a binary function with two positional arguments: the left argument (current value stored in state for that key) and the right argument (the update for that key returned by a node). When a node returns a partial update, LangGraph calls the reducer for each updated key and saves the return value as the new state value: new_value = reducer(left=current_state[key], right=node_update[key]). The left argument always comes from accumulated state; the right argument always comes from the latest node update.

Default reducer behavior

The default reducer ignores the left argument and replaces the state value with the right argument. If no reducer functions are specified for a state key, the default reducer is used.

Why MessagesState exists

MessagesState is a prebuilt state class that makes it easy to use messages in your graph state. Since having a list of messages in state is so common, MessagesState is defined with a single messages key which is a list of AnyMessage objects and uses the add_messages reducer. Typically there is more state to track than just messages, so people subclass MessagesState and add more fields.

Messages in graph state and add_messages reducer

In many cases it is helpful to store prior conversation history as a list of messages in your graph state. You add a key (channel) to the graph state that stores a list of Message objects and annotate it with a reducer function. The reducer function is vital to telling the graph how to update the list of Message objects in the state with each state update. If you don't specify a reducer, every state update will overwrite the list. If you simply use operator.add as a reducer, manual state updates sent to the graph would be appended instead of updating existing messages. The add_messages function is a prebuilt reducer that keeps track of message IDs and overwrites existing messages if updated. For brand new messages it appends to the list, but it also handles updates for existing messages correctly.

State definition in LangGraph

In LangGraph, state can be defined as a TypedDict, Pydantic model, or dataclass. For JavaScript/TypeScript, state is defined using the StateSchema class which accepts standard schemas like Zod for individual fields along with special value types like ReducedValue, MessagesValue, and UntrackedValue. By default, graphs have the same input and output schema, and the state determines that schema.

Reducers for state updates

Each key in the state can have its own independent reducer function which controls how updates from nodes are applied. If no reducer function is explicitly specified, all updates to the key override it. For TypedDict state schemas in Python, reducers are defined by annotating the corresponding field with a reducer function using Annotated. In JavaScript, MessagesValue and ReducedValue are used to define how updates are applied.

Overwrite type for bypassing reducers

The Overwrite type in LangGraph allows bypassing a reducer and directly overwriting a state value. When a node returns a value wrapped with Overwrite, the reducer is bypassed and the channel is set directly to that value. This is useful when you want to reset or replace accumulated state rather than merge it with existing values. Can also use JSON format with the special key '__overwrite__'.

Multiple nodes cannot use Overwrite on same state key

When nodes execute in parallel, only one node can use Overwrite on the same state key in a given super-step. If multiple nodes attempt to overwrite the same key in the same super-step, an InvalidUpdateError will be raised.

Private state between nodes

Nodes can exchange private data that is crucial for intermediate logic but doesn't need to be part of the main schema. Private data is defined through node input types and is only visible to subsequent nodes that request it. Node 1 can output private data, Node 2 can accept that private data as input, but Node 3 receives only the overall state and doesn't see the private data.

Pydantic models for graph state

StateGraph accepts a state_schema argument on initialization that can be a Pydantic BaseModel. Using Pydantic models adds run-time validation on inputs. Known limitations: the graph output will NOT be an instance of a pydantic model; run-time validation only occurs on inputs to the first node in the graph, not on subsequent nodes or outputs; the validation error trace does not show which node the error arises in; Pydantic's recursive validation can be slow for performance-sensitive applications.

Alternative state definitions in JavaScript

LangGraph JavaScript supports multiple state definition approaches beyond StateSchema: Channels API with LastValue, BinaryOperatorAggregate, Topic, and EphemeralValue channel types; Annotation.Root for declarative state definition with reducers; Zod v3 with .langgraph plugin providing .reducer() and .metadata() methods; Zod v4 with registry-based approach using .register() with LangGraph registry and MessagesZodMeta.

Node state updates behavior

By default, state updates from a node overwrite the corresponding key value. To accumulate updates instead, use reducers (e.g., operator.add) which control how updates are processed, allowing successive updates to be appended rather than overwritten.

State overwrites by default in node updates

When a node returns state updates, values overwrite the existing state keys by default. For example, returning {'value_1': 'new_value'} replaces the entire value_1 in state. Use reducers to modify this append-only behavior.

Give your agent this brain