mirror of
https://github.com/langchain-ai/deepagents.git
synced 2026-07-22 17:55:31 -04:00
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:
@@ -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)
|
||||
|
||||
|
||||
@@ -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(
|
||||
|
||||
@@ -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`."""
|
||||
|
||||
Reference in New Issue
Block a user