ToolRuntime and runtime context: who is asking
Runtime context is per-run data, such as the user's id, that you pass to invoke with context=; tools read it through ToolRuntime, and the model never sees it unless a tool returns it.
Last updated: 29 Sep, 2026 · Deep Agents 0.7
The video lists runtime context as the second kind of context engineering, after the input context, and moves on; this lesson follows the docs. Input context is the same for every run. Runtime context changes per run: who is asking, their account, a database connection. It should not go in the prompt, both because it changes and because the model does not need to see it.
The context_schema syntax
@dataclass
class Traveller:
name: str
agent = create_deep_agent(model=model, tools=[...], context_schema=Traveller)
agent.invoke({"messages": [...]}, context=Traveller(name="asha"))A booking tool that knows who is asking
my_booking has no argument the model fills in. Its runtime parameter is filled by the agent, and runtime.context is the object passed to invoke. Save this as bookings.py:
from deepagents import create_deep_agent
from langchain.chat_models import init_chat_model
model = init_chat_model("groq:openai/gpt-oss-120b", temperature=0, max_retries=6)
from dataclasses import dataclass
from langchain.tools import ToolRuntime, tool
BOOKINGS = {"asha": "Seine Budget Inn, 3 nights from 12 December",
"ravi": "Hotel Lumiere, 2 nights from 3 January"}
@dataclass
class Traveller:
name: str
@tool
def my_booking(runtime: ToolRuntime[Traveller]) -> str:
"""Look up the hotel booking of the traveller who is asking."""
return BOOKINGS.get(runtime.context.name, "No booking found.")The agent
agent = create_deep_agent(
model=model,
tools=[my_booking],
context_schema=Traveller,
system_prompt="Answer in one sentence, using only what my_booking returns.",
)The same question from two travellers
for name in ["asha", "ravi"]:
result = agent.invoke({"messages": [{"role": "user", "content": "Which hotel did I book?"}]},
context=Traveller(name=name))
print(f"{name}: {result['messages'][-1].text}")asha: Seine Budget Inn. ravi: Hotel Lumiere.
What the two runs show
- The answers differ although the question and the agent are identical: only
contextchanged. - The model never chose the traveller.
my_bookinghas no argument for the model to fill in; the tool read the name from the runtime. - Nothing about Asha or Ravi was in the prompt, so one user cannot talk the model into reading another user's booking.
Runtime context vs state vs the prompt
| Runtime context | State (messages, files) | System prompt | |
|---|---|---|---|
| Changes per run | Yes | Grows during the run | No |
| Model sees it | Only through a tool | Yes, the messages | Yes |
| Typical content | User id, API clients, flags | Conversation, files, todos | Role and rules |
Runtime context also reaches subagents: a subagent gets the same context as the agent that called it.
Where runtime context fits
- Multi-user apps: the user's id picks their data, as here.
- Passing a database connection or API client to tools.
- Choosing a per-user store namespace for the backends from StoreBackend: files shared across threads.
ToolRuntime must be imported from langchain.tools and typed on the parameter. A plain runtime argument without the type becomes an argument the model is asked to fill in.Related
- Previous: Skills: SKILL.md loaded on demand
- Next: Subagents: delegating with the task tool
- Reference: Context engineering: runtime context
- Add a traveller
"meera"with no booking and run the question as her. - Add a
budget: intfield toTravellerand a tool that reports it. - Print the
my_bookingtool call'sargsto confirm the model sent none.
Little by little, you're building something great.