AnonaMemoryService in as your agent’s memory_service and it can recall
across sessions, deployments and restarts, scoped to the right user
automatically, because ADK hands you user_id on every call.
Setup
Nothing here is automatic
Both directions require you to wire something. This is how ADK’s memory services work in general, not a limitation of this adapter. Reading: two options, different cost. Attach the built-inload_memory
tool (above) and the model decides for itself when to call it, with zero calls
if it never asks. Attach preload_memory instead (from google.adk.tools import preload_memory) and it runs on its own, with no model decision
involved. But “automatic” here is more expensive than it sounds: it fires
before every model call, not once per turn. A single tool-calling turn
(the model calls one tool, then answers) measured 2 separate retrieve
calls, both for the identical query, because ADK re-runs it once per model
step, not once per turn. Unlike this SDK’s LangChain adapter, there is
no per-turn cache to collapse that back down. A three-tool-call turn costs
four retrieves for one logical question, all billed. Reach for
preload_memory only once that cost is a deliberate choice; load_memory
is the lower-cost default for most agents. You can also call
await tool_context.search_memory(query) directly from inside your own
tool or callback code if neither built-in shape fits.
Writing. A session is never saved to memory just because a run finished.
The supported hook is Context.add_session_to_memory(), reachable from any
callback that receives a context. after_agent_callback, as above, is the
natural place, since it fires once per runner.run_async() call, after any
internal tool-calling loop has finished. Skip this and Anona never receives
a single turn; the agent still runs, silently, with no memory. Note the
callback’s parameter must be named exactly callback_context, because ADK invokes
it as a keyword argument.
You can also call memory_service.add_session_to_memory(session) directly:
add_session_to_memory on the callback context is just a shortcut for that,
using the callback’s own session.
Calling this again on a session you’ve already saved, the normal shape of
a multi-turn conversation with one call per turn on the same session.id, is
safe: you don’t need to track what you’ve already sent yourself. In the
common case (each call sees the same, growing event history, true of the
after_agent_callback idiom above, and of a fresh
session_service.get_session(...) fetch) only what’s new goes out. If a call instead
receives a different, shorter view of the same session, for example a
trimmed fetch via GetSessionConfig(num_recent_events=N), this can’t
always tell which of those events it already saw, and resends the whole
view rather than guess and risk dropping something new. So: never a
silently lost turn; occasionally, in that specific case, a duplicate.
Per-user isolation, at no cost
ADK passesuser_id and app_name on every memory call, and this adapter
maps them onto Anona’s scope, asymmetrically between writing and reading:
app_name is written as agent_id but deliberately not forwarded on a
read. Anona consolidates raw memories into synthesized observations over
time, and an observation is tagged by user only, not by the agent that
happened to write the originating turns, so a two-key user_id +
agent_id search would never match a consolidated observation, only raw,
unconsolidated facts. Since app_name is the one scope key ADK supplies
automatically with no way to opt out, forwarding it on every read would have
silently hidden your agent’s best answers behind its rawest ones, for every
ADK user, all the time.
Isolation itself is unaffected: user_id (the key that actually keeps one
end user’s memories from another’s) is forwarded on every call, read and
write alike. One space serves every user of your app, and a memory written
under one user_id is only ever returned to that same user. You configure
nothing.
Failure behaviour
If Anona is unreachable,search_memory returns no memories and the agent
continues. Failures are logged, never raised.