google-adk-memorysync
Long-term memory for Google ADK (Agent Development Kit), backed by MemorySync — a real BaseMemoryService whose ingestion methods actually store your sessions, powering ADK's native load_memory / preload_memory tools with durable, cross-session, cross-app memory.
MemorySyncMemoryService— all fourBaseMemoryServicemethods implemented:add_session_to_memory,add_events_to_memory,add_memory,search_memory. Plug it intoRunner(memory_service=...)and ADK's own memory tools just work.MemorySyncContextTool— guaranteed memory injection before every turn plus automatic capture of the user's messages, no memory-tool calls left to model discretion.create_memory_callbacks— anafter_model_callbackthat captures the user's message once the model has answered it.- Five agent tools — add, search, list, update, delete; they never raise.
- Async helpers —
get_memory_context,search_memories,save_turn.
What the user says is sent to fact extraction: MemorySync stores the durable facts a message contains (filler such as "ok" or "thanks" yields none), not the message itself. Assistant replies are not stored as memories, so no surface sends them.
pip install google-adk-memorysync google-adk
Set MEMORYSYNC_API_KEY in the environment (create a key at app.memorysync.io), or pass api_key explicitly. Python 3.10+, google-adk 2.x.
The memory service
from google.adk.agents import LlmAgent
from google.adk.runners import Runner
from google.adk.sessions import InMemorySessionService
from google.adk.tools import preload_memory
from google_adk_memorysync import MemorySyncMemoryService
memory_service = MemorySyncMemoryService() # reads MEMORYSYNC_API_KEY
agent = LlmAgent(
name="assistant",
model="gemini-2.5-flash",
instruction="You are a helpful assistant.",
tools=[preload_memory], # ADK's native tool — our service powers it
)
runner = Runner(
agent=agent,
app_name="support",
session_service=InMemorySessionService(),
memory_service=memory_service,
)
# ... after a conversation, ingest the session:
session = await runner.session_service.get_session(
app_name="support", user_id="customer-7", session_id=session_id
)
await memory_service.add_session_to_memory(session)
The next run — any session, any process, any deploy — preload_memory injects what MemorySync knows about the user before the model call.
Ingestion is real. add_session_to_memory sends every completed text message the user wrote to fact extraction (the agent's replies, streaming partial chunks, tool traffic and authorless events are skipped) and raises on failure — a memory service that silently drops sessions is data loss behind a green pipeline. Re-ingesting the same session is recognised server-side and extracts nothing twice: every message carries an idempotency seed derived from its ADK event id, plus the event's timestamp.
Incremental ingestion. add_events_to_memory(app_name=..., user_id=..., events=[...]) sends the user's messages as they happen and converges with a later whole-session add_session_to_memory — same seeds on both paths, each message extracted exactly once.
Search never raises. search_memory returns proper MemoryEntry objects (content, author when the memory's metadata names one, timestamp, custom_metadata.memory_id) so ADK's preload_memory formatter renders them natively; failures degrade to an empty response through on_error.
Scoping. By default the same user's memory follows them across ADK apps (that's the point of a memory service); pass scope_to_app=True to silo each app_name.
Guaranteed context injection
ADK's load_memory leaves recall to model discretion and preload_memory only injects — nothing captures what the user says as it happens. The context tool does both:
from google_adk_memorysync import MemorySyncContextTool
agent = LlmAgent(
name="assistant",
model="gemini-2.5-flash",
instruction="You are a helpful assistant.",
tools=[MemorySyncContextTool()], # inject memory + send user turns
)
Before every turn it recalls relevant memories for tool_context.user_id and appends them to the request instructions — once per invocation, even when a multi-tool turn makes several model calls. After injection it sends the user's message to fact extraction (persist=False for read-only). Outages degrade to a memoryless turn through on_error, never a crashed one.
To remember a message only once the model has answered it, capture with the callback instead and keep the tool for recall:
from google_adk_memorysync import MemorySyncContextTool, create_memory_callbacks
agent = LlmAgent(
name="assistant",
model="gemini-2.5-flash",
instruction="You are a helpful assistant.",
tools=[MemorySyncContextTool(persist=False)], # recall only
**create_memory_callbacks(), # after_model_callback sends the user's message
)
The callback sends the invocation's user message (callback_context.user_content) after the model's first complete text response — once per invocation; streaming chunks, failed model calls and function-call-only steps send nothing. The model's reply is not sent.
Retries are recognised server-side and extract nothing twice: the context tool, the callback and save_turn derive the same content seed for a message in a session (so the tool and the callback together still extract it once, and the second send is not counted), and the memory service keys each message on its ADK event id. The two seed schemes are separate — when you also call add_session_to_memory for a session, turn per-turn capture off (persist=False, no callback) so each message is sent once.
Agent tools
from google_adk_memorysync import create_memorysync_tools
agent = LlmAgent(
name="assistant",
model="gemini-2.5-flash",
instruction="Use the memory tools to remember durable facts.",
tools=create_memorysync_tools(user_id="customer-7"),
)
# Untrusted agents: search + list only.
create_memorysync_tools(user_id="customer-7", read_only=True)
add_memory, search_memory, list_memories, update_memory, delete_memory — the same five operations, same response strings as the MemorySync LangChain, AI SDK, CrewAI, Mastra, OpenAI Agents and LlamaIndex tool sets. Plain async callables that ADK auto-wraps as FunctionTools; failures return short readable strings, never exceptions.
Helpers
from google_adk_memorysync import get_memory_context, save_turn, search_memories
context = await get_memory_context("what should I cook?", user_id="customer-7")
hits = await search_memories("dietary preferences", user_id="customer-7")
await save_turn(user_id="customer-7", user="I'm vegetarian", assistant="Noted!")
save_turn sends the user message to fact extraction; assistant is accepted so an exchange can be passed as-is, but it is not sent — assistant replies are not stored as memories. It raises on failure — an explicit persist call is owed the truth.
Version support
| Package | Requires | Runtime |
|---|---|---|
google-adk-memorysync 1.1.0 |
google-adk >=2,<3 |
Python 3.10+ |
CI drives a REAL ADK Runner — native preload_memory end to end, repeated-ingestion convergence, partial-event filtering, per-invocation injection dedup — against the latest google-adk 2.x release on every push.
Documentation
Metadata
Release files for google-adk-memorysync 1.1.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | Provenance | |
|---|---|---|---|---|
| google_adk_memorysync-1.1.0.tar.gz | 18.9 kB | Without provenance | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| google_adk_memorysync-1.1.0-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 45.0 kB
Release files / google_adk_memorysync-1.1.0.tar.gz
| Download URL | google_adk_memorysync-1.1.0.tar.gz |
|---|---|
| Size | 18.9 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
d34e9cf111747d6ec5ca845e81025ab63a7bc116e0f0d741962b3e5010a2e26d
|
|
BLAKE2b-256 checksum How to use checksums |
0e7566e8f1c64eb3d89127f5cc4b73ff26aaba8bf53b9492f2b7b2ec69c25c4f
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/7.0.0 CPython/3.11.5
|
Release files / google_adk_memorysync-1.1.0-py3-none-any.whl
| Download URL | google_adk_memorysync-1.1.0-py3-none-any.whl |
|---|---|
| Size | 26.1 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
bfae927cbf49ece9507870f9f5b9e7d11e229d44ea62d1a74d72a9c7c5c8c65c
|
|
BLAKE2b-256 checksum How to use checksums |
f20e11100de4ad35baa705b39be7349e8d5f5222d41e0c6cad8038886ab50ca8
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/7.0.0 CPython/3.11.5
|
Security for google-adk-memorysync 1.1.0
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
No provenance found
None of the files in this release were uploaded with provenance metadata.
A note on package security
PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.
To learn more about protecting yourself from malicious actors, visit our package security documentation.