fix(sdk): export DeepAgentState (#3653)

Follow-up to the `state_schema` parameter added in `create_deep_agent`.
Exposes `DeepAgentState` as a public import so callers can subclass it
for custom schemas, and adds missing test coverage to verify that a
custom schema is actually threaded through declarative subagent
compilation and that the `SubAgentMiddleware` constructor annotations
are runtime-resolvable.
This commit is contained in:
Mason Daugherty
2026-05-28 17:44:45 -04:00
committed by GitHub
parent 550a8abf3c
commit 14a904757c
4 changed files with 46 additions and 4 deletions
+1 -2
View File
@@ -4,10 +4,9 @@
## [0.6.6](https://github.com/langchain-ai/deepagents/compare/deepagents==0.6.5...deepagents==0.6.6) (2026-05-28)
### Features
* **sdk:** allow passing `state_schema` in `create_deep_agent` ([#3642](https://github.com/langchain-ai/deepagents/issues/3642)) ([37839bd](https://github.com/langchain-ai/deepagents/commit/37839bd7d67fba8c11ff0ccaaa8ac92b39609450))
* Allow passing `state_schema` in `create_deep_agent` ([#3642](https://github.com/langchain-ai/deepagents/issues/3642)) ([37839bd](https://github.com/langchain-ai/deepagents/commit/37839bd7d67fba8c11ff0ccaaa8ac92b39609450))
## [0.6.5](https://github.com/langchain-ai/deepagents/compare/deepagents==0.6.4...deepagents==0.6.5) (2026-05-28)
+2 -1
View File
@@ -6,7 +6,7 @@ from deepagents._subagent_transformer import (
SubagentTransformer,
)
from deepagents._version import __version__
from deepagents.graph import create_deep_agent
from deepagents.graph import DeepAgentState, create_deep_agent
from deepagents.middleware.async_subagents import AsyncSubAgent, AsyncSubAgentMiddleware
from deepagents.middleware.filesystem import FilesystemMiddleware, FilesystemPermission
from deepagents.middleware.memory import MemoryMiddleware
@@ -28,6 +28,7 @@ __all__ = [
"AsyncSubAgentMiddleware",
"AsyncSubagentRunStream",
"CompiledSubAgent",
"DeepAgentState",
"FilesystemMiddleware",
"FilesystemPermission",
"GeneralPurposeSubagentProfile",
@@ -1,5 +1,7 @@
"""Unit tests for SubAgentMiddleware initialization and configuration."""
from typing import get_type_hints
import pytest
from langchain.agents import create_agent
from langchain_core.messages import AIMessage
@@ -45,6 +47,12 @@ class TestSubagentMiddlewareInit:
assert len(middleware.tools) == 1
assert middleware.tools[0].name == "task"
def test_public_init_type_hints_are_runtime_resolvable(self) -> None:
"""Public constructor annotations should support runtime introspection."""
hints = get_type_hints(SubAgentMiddleware.__init__)
assert "state_schema" in hints
def test_subagent_middleware_with_custom_subagent(self) -> None:
"""Test SubAgentMiddleware initialization with a custom subagent."""
middleware = SubAgentMiddleware(
+35 -1
View File
@@ -16,6 +16,7 @@ from langchain_core.tools import BaseTool, StructuredTool
from deepagents._api.deprecation import LangChainDeprecationWarning
from deepagents._tools import _apply_tool_description_overrides, _tool_name
from deepagents._version import __version__
from deepagents.backends import StateBackend
from deepagents.graph import (
_REQUIRED_MIDDLEWARE_CLASSES,
_REQUIRED_MIDDLEWARE_NAMES,
@@ -700,7 +701,16 @@ class TestExtraMiddlewareWiring:
class TestStateSchema:
"""End-to-end tests for the `state_schema` parameter on `create_deep_agent`."""
"""Tests for the `state_schema` parameter on `create_deep_agent`.
Covers wiring (the schema reaches `create_agent` and `SubAgentMiddleware`) and
that a custom schema is applied when declarative subagents compile, so the
custom field is exposed as a channel on the subagent graph.
The round-trip of a custom field through a compiled agent is not retested here:
it is `create_agent`'s contract, covered upstream in langchain's
`test_state_schema.py`. These tests only assert deepagents' own wiring.
"""
def test_default_state_schema_uses_deep_agent_state(self) -> None:
fake_model = GenericFakeChatModel(messages=iter([AIMessage(content="ok")]))
@@ -752,6 +762,30 @@ class TestStateSchema:
sub_mw = next(m for m in mw_stack if isinstance(m, SubAgentMiddleware))
assert sub_mw._state_schema is MyState
def test_declarative_subagent_compiles_with_custom_state_schema(self) -> None:
"""A declarative subagent's compiled runnable exposes the custom field as a channel."""
class MyState(DeepAgentState):
page_url: str
middleware = SubAgentMiddleware(
backend=StateBackend(),
subagents=[
{
"name": "researcher",
"description": "Research agent",
"system_prompt": "You are a researcher.",
"model": GenericFakeChatModel(messages=iter([AIMessage(content="ok")])),
"tools": [],
}
],
state_schema=MyState,
)
runnable = middleware._get_subagents()[0]["runnable"]
properties = runnable.get_input_jsonschema()["properties"]
assert "page_url" in properties
class _OtherStubMW(AgentMiddleware[Any, Any, Any]):
"""Second stub class so exclusion tests can assert coexistence with `_StubMW`."""