Unit 09.02: Shared state between agents
When two agents write to the same field, what happens is decided by the reducer - and the default reducer silently discards one of them.
Annotated fields accumulate; plain fields overwrite
A field annotated with operator.add merges updates. A plain field takes the last write. Both are correct behaviours for different fields, and the choice is the design decision.
The code runs two agents that both write notes and summary.
import operator
from typing import TypedDict, Annotated
from langgraph.graph import StateGraph, START, END
class State(TypedDict):
notes: Annotated[list, operator.add] # merged, not overwritten
summary: str # last write wins
def agent_a(state: State):
return {"notes": ["a: checked billing"], "summary": "from a"}
def agent_b(state: State):
return {"notes": ["b: checked logs"], "summary": "from b"}
g = StateGraph(State)
g.add_node("a", agent_a)
g.add_node("b", agent_b)
g.add_edge(START, "a")
g.add_edge("a", "b")
g.add_edge("b", END)
final = g.compile().invoke({"notes": [], "summary": ""})
print("notes :", final["notes"])
print("summary:", final["summary"])
# The reducer is the whole design decision. `notes` accumulates because it is
# annotated with `operator.add`; `summary` is overwritten because it is not.
# Two agents writing an unannotated field means one of them silently loses.
notes contains both agents' contributions. summary contains only the second agent's, because nothing told LangGraph to combine them - so the first agent's summary is gone, with no error and no warning.
That silence is the hazard. In a two-node test you notice; in a graph where the agents run under different conditions, the loss happens only on some paths, and it looks like an agent that sometimes fails to produce output.
The mistake this prevents
The mistake is discovering reducers only after a field goes missing. Decide per field, when designing the state, whether concurrent or repeated writes should accumulate or replace - and write the annotation then, not after an investigation.
Takeaway
Every shared field needs a deliberate reducer. Annotated fields accumulate, plain fields overwrite, and an overwritten field produces no error - only missing data.
