Google ADKgoogle-adk 2.8 · Python 3.10+
1
Curious builder0 XP earned · 300 to level 2
0 daysFinish a lesson to begin
Badge collection0 of 6 unlocked
28 small wins to finish your pathNext lesson

Three prefixes, three lifetimes

A key with no prefix belongs to this conversation. Three prefixes change that, and one of them is how an agent remembers you across conversations.

PrefixScopeLives as long as
noneThis sessionThe conversation
user:This user, every session in the appThe user, if the service persists
app:The whole app, every userThe application
temp:This one invocationThe current turn. Then it is gone

A tool that writes two of them

python
def remember(name: str, tool_context: ToolContext) -> dict:
    """Remember the customer's name for every future conversation."""
    tool_context.state["user:name"] = name
    tool_context.state["temp:working"] = "scratch"
    return {"status": "success"}

One key with the user prefix, one temporary. Everything else about the tool is the same as lesson 21.

python
agent = LlmAgent(
    name="support",
    model=PretendModel(replies=[call("remember", name="Asha"), say("Nice to meet you.")]),
    instruction="Be friendly.",
    tools=[remember],
)

runner = InMemoryRunner(agent=agent, app_name="demo")

Watching a prefix cross a session

Example
first = await runner.session_service.create_session(app_name="demo", user_id="u1")
message = types.Content(role="user", parts=[types.Part(text="I am Asha")])

async for _ in runner.run_async(user_id="u1", session_id=first.id, new_message=message):
    pass

done = await runner.session_service.get_session(
    app_name="demo", user_id="u1", session_id=first.id)
print("first session: ", dict(done.state))

The user key is there, and temp:working is not. Temporary means the current invocation only, and that one has finished.

Example
second = await runner.session_service.create_session(app_name="demo", user_id="u1")
print("second session:", dict(second.state))

other = await runner.session_service.create_session(app_name="demo", user_id="u2")
print("another user:  ", dict(other.state))

A brand new conversation for the same person already knows the name. A different person does not. That is the whole point of the prefix.

Where the persistence actually comes from

The prefixes describe scope. Whether anything survives a restart is a property of the session service. InMemorySessionService keeps user and app state across sessions, as you just saw, and loses everything when the process ends.

  • Learning and tests: in memory, which is what InMemoryRunner gives you.
  • A real deployment: a database session service, so a restart does not wipe conversations.
  • On Google Cloud: the managed service, which persists for you.
user: is a commitment
A user-scoped key is personal data with a longer life than the conversation. Decide deliberately what deserves the user: prefix, because it will still be there in a year.
Try it yourself
  • Change user:name to a plain key and watch the second session start empty.
  • Write to an app: key and read it from another user's session.

You understood something today that you didn't yesterday.