Skip to main content

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 four BaseMemoryService methods implemented: add_session_to_memory, add_events_to_memory, add_memory, search_memory. Plug it into Runner(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 — an after_model_callback that 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)

Source distribution for google-adk-memorysync 1.1.0
File Size Uploaded Provenance
google_adk_memorysync-1.1.0.tar.gz 18.9 kB Without provenance Details

Built distribution (wheel)

Table of built distributions (wheels) for google-adk-memorysync 1.1.0
File Interpreter ABI Platform
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.

Release history Release notifications | RSS feed

This release

1.1.0 This release

2 release files No provenance

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page