Jump to content

Connect Leeroopedia MCP: Equip your AI agents to search best practices, build plans, verify code, diagnose failures, and look up hyperparameter defaults.

Implementation:Langchain ai Langgraph AgentState Schema

From Leeroopedia
Attribute Value
API AgentState and AgentStateWithStructuredResponse TypedDicts
Workflow ReAct_Agent_Creation
Type Pattern Doc
Repository Langchain_ai_Langgraph
Source File libs/prebuilt/langgraph/prebuilt/chat_agent_executor.py
Source Lines L57-62 (AgentState), L88-91 (AgentStateWithStructuredResponse)

Overview

AgentState is a TypedDict that defines the default state schema for ReAct agents built with create_react_agent. It contains two fields: messages (an annotated sequence of messages with the add_messages reducer) and remaining_steps (a managed counter for recursion safety). AgentStateWithStructuredResponse extends AgentState with a structured_response field for agents that produce typed output.

Note: Both AgentState and AgentStateWithStructuredResponse are deprecated in favor of equivalents in the langchain.agents package. They remain functional for backward compatibility.

Description

AgentState

The AgentState TypedDict defines the minimal state required for a ReAct agent:

class AgentState(TypedDict):
    """The state of the agent."""
    messages: Annotated[Sequence[BaseMessage], add_messages]
    remaining_steps: NotRequired[RemainingSteps]
  • messages: The conversation history. The Annotated[..., add_messages] annotation attaches the add_messages reducer, which appends new messages to the existing list rather than replacing it. This is critical for the ReAct loop where each step adds new messages (AIMessage, ToolMessage) to the growing conversation.
  • remaining_steps: A NotRequired managed value of type RemainingSteps. This is automatically populated by the framework based on the recursion limit and steps taken. It is used by the agent's internal logic to detect when the step budget is nearly exhausted, allowing graceful termination instead of a GraphRecursionError.

AgentStateWithStructuredResponse

This extends AgentState with a field for structured output:

class AgentStateWithStructuredResponse(AgentState):
    """The state of the agent with a structured response."""
    structured_response: StructuredResponse  # dict | BaseModel

When create_react_agent is called with a response_format parameter, this schema is used as the default state. The structured_response field holds the output of the "generate_structured_response" node, which makes a separate LLM call after the agent loop to produce typed output matching the provided schema.

Default Schema Selection

Within create_react_agent, the state schema is selected as follows (lines 547-552):

if state_schema is None:
    state_schema = (
        AgentStateWithStructuredResponse
        if response_format is not None
        else AgentState
    )

If a custom state_schema is provided, it is validated to ensure it contains the required keys (messages, remaining_steps, and structured_response if applicable).

The add_messages Reducer

The add_messages reducer (from langgraph.graph.message) is central to agent state behavior. When a node returns {"messages": [new_msg]}, the reducer appends new_msg to the existing messages list in state. It also handles special cases:

  • RemoveMessage: Removes specific messages by ID from the list.
  • Message deduplication by ID when messages with matching IDs are provided.

This reducer pattern is what enables the "accumulating conversation history" behavior that the ReAct loop depends on.

Usage

# Default usage - AgentState is used automatically
from langgraph.prebuilt import create_react_agent

agent = create_react_agent("openai:gpt-4", tools=[my_tool])
# Uses AgentState internally

# With structured response - uses AgentStateWithStructuredResponse
from pydantic import BaseModel

class Result(BaseModel):
    answer: str

agent = create_react_agent(
    "openai:gpt-4",
    tools=[my_tool],
    response_format=Result,
)
# Uses AgentStateWithStructuredResponse internally

# Custom state schema
from typing import Annotated, Sequence
from typing_extensions import TypedDict, NotRequired
from langchain_core.messages import BaseMessage
from langgraph.graph.message import add_messages
from langgraph.managed import RemainingSteps

class CustomState(TypedDict):
    messages: Annotated[Sequence[BaseMessage], add_messages]
    remaining_steps: NotRequired[RemainingSteps]
    user_preferences: dict

agent = create_react_agent(
    "openai:gpt-4",
    tools=[my_tool],
    state_schema=CustomState,
)

Code Reference

Source Location

File libs/prebuilt/langgraph/prebuilt/chat_agent_executor.py
AgentState Lines 57-62
AgentStateWithStructuredResponse Lines 88-91
StructuredResponse type BaseModel
Schema selection logic Lines 538-552

Signature

class AgentState(TypedDict):
    """The state of the agent."""
    messages: Annotated[Sequence[BaseMessage], add_messages]
    remaining_steps: NotRequired[RemainingSteps]
class AgentStateWithStructuredResponse(AgentState):
    """The state of the agent with a structured response."""
    structured_response: StructuredResponse

Import

from langgraph.prebuilt.chat_agent_executor import AgentState
from langgraph.prebuilt.chat_agent_executor import AgentStateWithStructuredResponse

I/O Contract

AgentState Fields

Field Type Required Reducer Description
messages Annotated[Sequence[BaseMessage], add_messages] Yes add_messages Conversation history. New messages are appended by the reducer. Contains HumanMessage, AIMessage, ToolMessage, and SystemMessage objects.
remaining_steps RemainingSteps No (NotRequired) Managed Steps remaining before recursion limit. Managed by the framework; typically not set by users.

AgentStateWithStructuredResponse Additional Fields

Field Type Required Reducer Description
structured_response BaseModel) Yes Default (replace) Typed output produced by the "generate_structured_response" node. Schema determined by the response_format parameter.

Input Format

When invoking an agent, the input should match the state schema:

# Minimal input
{"messages": [("user", "Hello")]}

# With HumanMessage
{"messages": [HumanMessage(content="Hello")]}

# With custom state fields
{"messages": [("user", "Hello")], "user_preferences": {"language": "en"}}

Output Format

# Standard output (AgentState)
{
    "messages": [
        HumanMessage(content="Hello"),
        AIMessage(content="Hi there! How can I help?"),
    ],
    "remaining_steps": 23,
}

# With structured response (AgentStateWithStructuredResponse)
{
    "messages": [...],
    "remaining_steps": 21,
    "structured_response": Result(answer="42"),
}

Usage Examples

Accessing State in Tools via InjectedState

from typing import Annotated
from langchain_core.tools import tool
from langgraph.prebuilt import InjectedState, create_react_agent

@tool
def message_count(state: Annotated[dict, InjectedState]) -> str:
    """Report the number of messages in the conversation."""
    return f"There are {len(state['messages'])} messages"

agent = create_react_agent("openai:gpt-4", tools=[message_count])
result = agent.invoke({"messages": [("user", "How many messages are there?")]})

Custom State with Structured Response

from typing import Annotated, Sequence
from typing_extensions import TypedDict, NotRequired
from langchain_core.messages import BaseMessage
from langgraph.graph.message import add_messages
from langgraph.managed import RemainingSteps
from pydantic import BaseModel

class AnalysisResult(BaseModel):
    sentiment: str
    key_topics: list[str]

class AnalysisState(TypedDict):
    messages: Annotated[Sequence[BaseMessage], add_messages]
    remaining_steps: NotRequired[RemainingSteps]
    structured_response: dict  # Required for response_format
    document_text: str         # Custom field for analysis context

agent = create_react_agent(
    "openai:gpt-4",
    tools=[my_analysis_tool],
    state_schema=AnalysisState,
    response_format=AnalysisResult,
)

result = agent.invoke({
    "messages": [("user", "Analyze this document")],
    "document_text": "The document content...",
})
print(result["structured_response"])
# AnalysisResult(sentiment="positive", key_topics=["AI", "agents"])

Remaining Steps Safety Check

# The remaining_steps field is managed automatically.
# When steps are nearly exhausted, the agent returns gracefully:
agent = create_react_agent(
    "openai:gpt-4",
    tools=[complex_tool],
)

result = agent.invoke(
    {"messages": [("user", "Do complex analysis")]},
    config={"recursion_limit": 5},  # Low limit for demonstration
)
# If the agent needs more steps than allowed, the last message will be:
# AIMessage(content="Sorry, need more steps to process this request.")

Related Pages

Page Connections

Double-click a node to navigate. Hold to expand connections.
Principle
Implementation
Heuristic
Environment