Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions libs/langchain_v1/langchain/agents/factory.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@
ModelRequest,
ModelResponse,
OmitFromSchema,
_BackendProtocol,
_InputAgentState,
_OutputAgentState,
)
Expand Down Expand Up @@ -520,6 +521,7 @@ def create_agent( # noqa: PLR0915
debug: bool = False,
name: str | None = None,
cache: BaseCache | None = None,
backend: _BackendProtocol | None = None,
) -> CompiledStateGraph[
AgentState[ResponseT], ContextT, _InputAgentState, _OutputAgentState[ResponseT]
]:
Expand Down Expand Up @@ -729,6 +731,7 @@ def _build_hook_runtime(runtime: Runtime[ContextT]) -> AgentRuntime[ContextT]:
runtime,
model_name=_agent_model_name,
tools=default_tools,
backend=backend,
)
)

Expand Down Expand Up @@ -1075,6 +1078,7 @@ def model_node(state: AgentState, runtime: Runtime[ContextT]) -> dict[str, Any]:
tools=default_tools,
tool_choice=None,
response_format=initial_response_format,
backend=backend,
)
)
request = ModelRequest.from_runtime(agent_runtime, messages=state["messages"], state=state)
Expand Down
22 changes: 22 additions & 0 deletions libs/langchain_v1/langchain/agents/middleware/types.py
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,23 @@
ResponseT = TypeVar("ResponseT")


class _BackendProtocol(Protocol):
"""Minimal backend protocol for agent storage operations.

Private to langchain — subpackages (e.g. deepagents) extend this with
additional methods and re-export it as their own ``BackendProtocol``.
"""

def read(self, path: str) -> str: ...
def write(self, path: str, content: str) -> Any: ...
def ls(self, path: str) -> Any: ...
def download_files(self, paths: list[str]) -> Any: ...
async def aread(self, path: str) -> str: ...
async def awrite(self, path: str, content: str) -> Any: ...
async def als(self, path: str) -> Any: ...
async def adownload_files(self, paths: list[str]) -> Any: ...


@dataclass(**_DC_KWARGS)
class AgentRuntime(Runtime[ContextT]):
"""Agent-scoped runtime injected into all middleware hook nodes.
Expand Down Expand Up @@ -100,6 +117,9 @@ class AgentRuntime(Runtime[ContextT]):
model_settings: dict[str, Any] = field(default_factory=dict)
"""Additional model-specific settings."""

backend: _BackendProtocol | None = field(default=None)
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 Backend cannot be overridden on ModelRequest

Adding AgentRuntime.backend makes backend part of the runtime state carried by model middleware, but ModelRequest.override() still only treats model/system_prompt/tool_choice/tools/response_format/model_settings as runtime fields. A middleware that tries to replace or clear the backend for a nested handler call via request.override(backend=...) will route backend to dataclasses.replace(self, ...) on ModelRequest, which raises TypeError: ModelRequest.__init__() got an unexpected keyword argument 'backend' at runtime. Include backend in the override typed dict and _runtime_fields (and optionally expose a backend property) so backend behaves like the other AgentRuntime fields.

(Refers to line 120)


Was this helpful? React with 👍 or 👎 to provide feedback.

"""Backend injected by the caller via ``create_agent(backend=...)``."""

@classmethod
def from_runtime(
cls,
Expand All @@ -113,6 +133,7 @@ def from_runtime(
tools: list[BaseTool | dict] | None = None,
response_format: ResponseFormat | None = None,
model_settings: dict[str, Any] | None = None,
backend: _BackendProtocol | None = None,
) -> AgentRuntime[ContextT]:
"""Construct an AgentRuntime from a base LangGraph Runtime."""
inherited = {f.name: getattr(runtime, f.name) for f in dc_fields(Runtime)}
Expand All @@ -126,6 +147,7 @@ def from_runtime(
tools=tools or [],
response_format=response_format,
model_settings=model_settings or {},
backend=backend,
)


Expand Down
Loading