ToolRuntime: Choosing State, Store, and Context
ToolRuntime bundles state, store, context, and streaming into a single typed parameter for tools. This article is about when to use it, which data goes where, and what breaks in production when you choose wrong.
Quick Reference
- →from langchain.tools import ToolRuntime # or from langgraph.prebuilt import ToolRuntime
- →ToolRuntime(Generic[ContextT, StateT]) — two type params; StateT defaults to dict
- →runtime.context: immutable per-invocation config (user_id, tenant, flags)
- →runtime.state: mutable current-run graph state | runtime.store: cross-session persistence
- →runtime.stream_writer: emit custom events | runtime.tool_call_id: correlate invocations
- →InjectedState / InjectedStore / InjectedConfig are NOT deprecated — use them for single-field access
- →Always include messages=[ToolMessage(...)] in Command(update={...}) — omitting it stalls the graph
Should You Use ToolRuntime?
ToolRuntime consolidates state, store, context, config, and streaming into a single typed parameter. It does NOT replace InjectedState, InjectedStore, or InjectedConfig — those patterns still work and are sometimes simpler. ToolRuntime is a convenience consolidation. Use it when a tool needs two or more runtime services simultaneously; use individual annotations when a tool only needs one.
A LangChain contributor confirmed (forum thread, 2025): these are complementary patterns. ToolRuntime is the preferred consolidation when a tool needs multiple runtime services, but the individual annotations remain valid and are sometimes clearer for single-field access.
| Situation | Use | Why |
|---|---|---|
| Tool needs state only | Annotated[dict, InjectedState] | One annotation, no generic needed, intent is clear |
| Tool needs store only | Annotated[BaseStore, InjectedStore] | Same — simpler than ToolRuntime for a single service |
| Tool needs state + store + context | ToolRuntime[MyContext, MyState] | One parameter instead of three separate annotations |
| Tool needs streaming only | get_stream_writer() from langgraph.config | No ToolRuntime overhead for a single utility |
| Building with create_agent() | ToolRuntime | create_agent wires context_schema injection; ToolRuntime is the natural fit |
| Gradual migration | Mix both | Migrate tool-by-tool; both patterns work in the same ToolNode |