Passing your own context
Your tools need to know who is asking. Context is how that reaches them without going through the model.
Anything you like
A dataclass here, but it can be any object. The SDK never looks inside it.
@dataclass
class Customer:
name: str
plan: strA tool that asks for it
Add a first parameter typed as RunContextWrapper and the SDK passes it in. The model never sees this parameter, so it does not appear in the tool's schema.
@function_tool
def my_plan(context: RunContextWrapper[Customer]) -> str:
"""Return the plan the current customer is on."""
return f"{context.context.name} is on the {context.context.plan} plan."context.context reads awkwardly the first time. The outer object is the SDK's wrapper, which also carries the usage so far; the inner one is yours.
result = await Runner.run(agent, "which plan am I on?", context=Customer("Asha", "annual"))
print(result.final_output)The rule worth remembering
Context never reaches the model. It is your data, passed to your code. The model only learns about it if a tool returns some of it, which is exactly what happened here.
That makes it the right place for anything private: an account id, an internal customer record, a database handle, an API client. Nothing in there can leak into a prompt unless you put it there.
| What you want | Where it goes |
|---|---|
| Something the model must know to answer | the instructions, or the question |
| Something only your code needs | the context |
| Something private | the context, always |
- Add an
emailfield and return it from the tool. - Print
context.usageinside the tool. - Try reading the context from the instructions as well, as lesson 11 did.
You understood something today that you didn't yesterday.