feat(agents): AgentRuntime fields + _build_runtime hook for middleware#37879
feat(agents): AgentRuntime fields + _build_runtime hook for middleware#37879Sydney Runkle (sydney-runkle) wants to merge 10 commits into
Conversation
…dleware enrichment AgentRuntime gains model_name and tools fields populated by create_agent at wire time. A private _build_runtime hook on AgentMiddleware lets subpackages (e.g. deepagents) return an enriched runtime subclass from their middleware without exposing those fields in LangChain. All four middleware hook nodes (before_agent, before_model, after_model, after_agent) now receive AgentRuntime instead of the bare LangGraph Runtime; existing Runtime annotations remain valid via Liskov substitution.
…odelRequest.from_runtime
| model: BaseChatModel | None = field(default=None) | ||
| """Resolved model instance, if not a dynamic callable.""" | ||
|
|
||
| system_prompt: str | None = field(default=None) | ||
| """System prompt for the agent.""" |
There was a problem hiding this comment.
🟡 Hook runtimes leave new fields empty
The new AgentRuntime fields are only populated when model_node builds a ModelRequest; the hook-node wrappers still call AgentRuntime.from_runtime(..., model_name=..., tools=...) without passing model, system_prompt, tool_choice, or response_format. As a result, a before_model/after_model middleware that uses the newly documented runtime.model or runtime.system_prompt receives None even for an agent created with a concrete model and system prompt (I verified this with a before_model(self, state, runtime) hook). Please pass the same agent fields through the hook wrappers before exposing them on AgentRuntime, or avoid advertising them there.
(Refers to lines 86-90)
Was this helpful? React with 👍 or 👎 to provide feedback.
…ardcoding inherited fields
…ent, slim ModelRequest - _build_runtime calls now chain across all middlewares before dispatch instead of being called per-middleware independently - create_agent accepts backend= (object|None); passed to AgentRuntime - AgentRuntime gains backend: object|None field + from_runtime param - ModelRequest drops duplicated fields; model/system_prompt/tools/etc are now properties that delegate to runtime, eliminating redundancy - _wrap_hook/_wrap_async_hook no longer take a mw argument
| messages: list[AnyMessage] | ||
| state: AgentState | ||
| runtime: Runtime[ContextT] # type: ignore[valid-type] | ||
| model_settings: dict[str, Any] = field(default_factory=dict) | ||
| runtime: AgentRuntime[ContextT] # type: ignore[valid-type] |
There was a problem hiding this comment.
🟠 ModelRequest constructor now rejects existing calls
Removing these dataclass fields from ModelRequest.__init__ breaks existing code that constructs a request directly with the documented invocation fields. This is not just theoretical: the current test suite still has many call sites such as ModelRequest(model=..., system_prompt=..., tools=..., response_format=...), and at this HEAD that raises TypeError: ModelRequest.__init__() got an unexpected keyword argument 'model'. Since ModelRequest is exported from the middleware package and used by middleware tests/users, please preserve the old constructor shape (for example with a custom __init__ that builds an AgentRuntime) while still delegating properties to the runtime internally.
(Refers to lines 167-169)
Was this helpful? React with 👍 or 👎 to provide feedback.
backend belongs only on deepagents.AgentRuntime, injected exclusively via BackendMiddleware._build_runtime — not on the langchain layer
| tools=default_tools, | ||
| tool_choice=None, | ||
| response_format=initial_response_format, | ||
| backend=backend, |
There was a problem hiding this comment.
🟠 Async agents crash on backend reference
The backend parameter was removed from create_agent and AgentRuntime.from_runtime, but the async model node still passes backend=backend. Any agent.ainvoke() now fails before the model runs with NameError: name 'backend' is not defined (I verified this with a minimal create_agent(...).ainvoke(...)). Please remove this argument here as well, matching the sync path above.
(Refers to line 1134)
Was this helpful? React with 👍 or 👎 to provide feedback.
Adds
AgentRuntimeand a_build_runtimehook so subpackages can enrich the runtime without touching langchain internals.ModelRequestshared fields (model,tools,system_prompt, etc.) are now properties delegating toruntime, eliminating duplication.Non-breaking: existing
runtime: Runtimeannotations acceptAgentRuntimevia Liskov substitution.