AI & Agent Dev Bug Sandbox logo
AI & Agent Dev Bug Sandbox
Back to Radar

Create_agent Discards State_schema Subclass In Inferred Return Type

langchain.agents.create_agent's type annotations hardcode AgentState[ResponseT] for the state_schema parameter and return type, erasing the specific subclass passed by the user and causing type mismatch errors for downstream code.

mediumConfidence 95%LangchainAffected V1.2.15Affected V1.3.4

Origin Analysis

The StateT TypeVar bound to AgentState[Any] was introduced for the middleware parameter but was not wired to state_schema and the return type, leaving them fixed to AgentState[ResponseT]. This causes the generic parameter of CompiledStateGraph to lose the subclass information.
```python from typing import Annotated, NotRequired from langchain.agents import AgentState, create_agent from langchain_core.language_models.fake_chat_models import FakeListChatModel class MyState(AgentState): counter: NotRequired[int] graph = create_agent( model=FakeListChatModel(responses=["ok"]), tools=[], state_schema=MyState, ) reveal_type(graph) # Shows CompiledStateGraph[AgentState[Any], ...] instead of CompiledStateGraph[MyState, ...] ```

Fixing Code Block

--- a/libs/langchain_v1/langchain/agents/factory.py +++ b/libs/langchain_v1/langchain/agents/factory.py @@ -1,5 +1,6 @@ from typing import Any, Sequence from langchain_core.language_models.chat_models import BaseChatModel from langchain_core.messages import SystemMessage +from langchain.agents.middleware.types import StateT from langgraph.graph.state import CompiledStateGraph def create_agent( model: str | BaseChatModel, tools: Sequence[BaseTool | Callable[..., Any] | dict[str, Any]] | None = None, *, system_prompt: str | SystemMessage | None = None, middleware: Sequence[AgentMiddleware[StateT, ContextT]] = (), response_format: ResponseFormat[ResponseT] | type[ResponseT] | dict[str, Any] | None = None, - state_schema: type[AgentState[ResponseT]] | None = None, + state_schema: type[StateT] | None = None, context_schema: type[ContextT] | None = None, checkpointer: BaseCheckpointSaver | None = None, store: BaseStore | None = None, interrupt_before: list[str] | None = None, interrupt_after: list[str] | None = None, debug: bool = False, name: str | None = None, cache: BaseCache | None = None, verbose: bool | None = None, max_concurrency: int | None = None, recursion_limit: int | None = None, config: RunnableConfig | None = None, -) -> CompiledStateGraph[AgentState[ResponseT], ContextT, _InputAgentState, _OutputAgentState[ResponseT]]: +) -> CompiledStateGraph[StateT, ContextT, _InputAgentState, _OutputAgentState[ResponseT]]:
The fix imports the existing StateT TypeVar and uses it for the state_schema parameter and the return type. Because StateT is bound to AgentState[Any], it preserves backward compatibility while allowing subclasses to be inferred.

Edge Case Audit

This is a type-only change and does not affect runtime behavior. However, static type checkers may require users to update their type annotations if they previously relied on the erased type. Rollback is straightforward: revert the type annotations to the original AgentState[ResponseT] forms. No known concurrency or cross-platform issues.

Ecosystem Topology