Tools that see the session
A tool can read what the agent knows and change what happens next. One extra parameter does it, and the model never sees that parameter.
Asking for the context
from google.adk.tools import ToolContext
def remember_name(name: str, tool_context: ToolContext) -> dict:
"""Remember the customer's name for the rest of this conversation."""
tool_context.state["customer"] = name
return {"status": "success", "remembered": name}Add a parameter typed as ToolContext and ADK passes one in. It is found by the type annotation rather than the name, so you can call it whatever reads best.
agent = LlmAgent(
name="support",
model=PretendModel(replies=[call("remember_name", name="Asha"),
say("Nice to meet you, Asha.")]),
instruction="Be friendly.",
tools=[remember_name],
)Watching the change travel
runner = InMemoryRunner(agent=agent, app_name="demo")
session = await runner.session_service.create_session(app_name="demo", user_id="u1")
message = types.Content(role="user", parts=[types.Part(text="My name is Asha")])
async for event in runner.run_async(user_id="u1", session_id=session.id, new_message=message):
if event.actions and event.actions.state_delta:
print("state changed:", dict(event.actions.state_delta))The change arrived as part of an event before it was saved. Lesson 6 said actions was where side effects live, and this is the first one.
after = await runner.session_service.get_session(
app_name="demo", user_id="u1", session_id=session.id)
print("session state:", dict(after.state))And there it is on the session afterwards. The tool wrote it, the runner saved it, and the next turn of this conversation can read it.
What the context gives you
| On the context | What it is for |
|---|---|
state | The session scratchpad, readable and writable from inside a tool |
actions | Controls on what happens next, including handing over to another agent |
load_artifact, save_artifact | Files the agent produced or was given |
The model never sees this parameter. It is not in the declaration you printed in lesson 3, so it cannot be filled in by a model and cannot be influenced by anything the model says.
- Read
tool_context.statein a second tool and print what the first one left. - Rename the parameter to
ctxand check it still works.
Every expert started right here.