# How to add memory to a Google ADK agent that survives restarts (MemoryService, preload_memory, per-user recall)

*Disclosure: I'm Mohammed, founder of MemorySync. I drafted this with AI assistance and checked it against Google's ADK docs and MemorySync's ADK guide. Code status: on Oct 25, 2026 I installed google-adk 2.13.0 and google-adk-memorysync 1.1.0 (Python 3.13) and ran all imports and the agent, Runner, context tool, callbacks and tools construction shown. I then ran the whole flow locally with a stand-in model and MemorySync's HTTP responses mocked: one turn, `add_session_to_memory`, a second ingest of the same session, and a turn in a fresh Runner and session that used `preload_memory`. Later the same day I reran the flow against the live MemorySync API (no live Gemini call; stand-in model).*

In Google's Agent Development Kit (ADK), a **Session** holds the events and state of one conversation. The ADK docs call that short-term memory. Recalling things from *earlier* conversations is the job of a separate **MemoryService** ([ADK memory docs](https://adk.dev/sessions/memory/)). If your agent forgets a user every time you restart or open a new session, this is the layer to fix.

## What ADK gives you

`BaseMemoryService` has four operations:

- `add_session_to_memory(session)`: ingest a completed session.
- `add_events_to_memory(...)`: append a delta, such as the latest turn.
- `add_memory(...)`: add explicit `MemoryEntry` objects.
- `search_memory(...)`: query, usually through a tool.

The docs note that `add_events_to_memory` and `add_memory` are optional and not every service implements them. Python ADK ships three services:

| Service | Persistence (per ADK docs) |
|---|---|
| `InMemoryMemoryService` | None: data is lost on restart |
| `VertexAiMemoryBankService` | Yes, managed by Google's Agent Platform |
| `VertexAiRagMemoryService` | Yes, stored in Knowledge Engine |

Agents read memory through ADK's built-in tools. `load_memory` lets the model decide when to search, and `preload_memory` injects results before the turn.

So your options are: stay in-memory (fine for dev), adopt Vertex AI's services, or implement `BaseMemoryService` against another backend.

## Plugging in a third-party MemoryService

MemorySync publishes `google-adk-memorysync`, which implements all four `BaseMemoryService` methods ([guide](https://docs.memorysync.io/guides/google-adk?utm_source=hashnode&utm_medium=organic_page&utm_campaign=v5_oct25&utm_content=pseo_google-adk-memory-across-sessions)). It requires `google-adk` 2.0+ and Python 3.10+. Set `MEMORYSYNC_API_KEY` server-side.

```bash
pip install "google-adk>=2" google-adk-memorysync
```

### Step 1: Wire the service into the Runner

```python
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",   # any model your ADK setup supports
    instruction="You are a helpful assistant.",
    tools=[preload_memory],     # ADK's own tool, backed by the service
)

runner = Runner(
    agent=agent,
    app_name="support",
    session_service=InMemorySessionService(),
    memory_service=memory_service,
)
```

This construction ran on the box.

### Step 2: Ingest the session when a conversation ends

```python
session = await runner.session_service.get_session(
    app_name="support", user_id="customer-7", session_id="thread-42"
)
await memory_service.add_session_to_memory(session)
```

Per the guide, this sends the text messages the user wrote for fact extraction. Agent replies, partial streams and tool traffic are skipped. It raises on failure. Re-ingesting the same session doesn't extract anything twice, because each message carries a seed derived from its ADK event id. The next session for `customer-7`, in any process, has `preload_memory` inject what's known.

In my local run (stand-in model, mocked API), the ingest sent only the user's message, the second ingest sent the same event-id-based seed again, and the stored fact appeared in the model's input on a new session in a fresh Runner. In a later run against the live MemorySync API, ingesting the same session a second time returned `already_exists: true` and nothing was extracted twice, and a fresh Runner and session got the stored fact injected.

The ADK `user_id` is your isolation key. Use your real, stable user id. By default a user's memory follows them across ADK apps. Pass `MemorySyncMemoryService(scope_to_app=True)` to keep each `app_name` separate.

### Step 3 (alternative): Inject and capture every turn

If you don't want to manage the end-of-session ingest:

```python
from google_adk_memorysync import MemorySyncContextTool

agent = LlmAgent(
    name="assistant",
    model="gemini-2.5-flash",
    instruction="You are a helpful assistant.",
    tools=[MemorySyncContextTool()],   # recall before each turn + save the user's message
)
```

In a local run with a stand-in model and a mocked API, a stored fact reached the model's input and the user's message was the only thing written.

Use one capture path, not both. If you call `add_session_to_memory`, set `MemorySyncContextTool(persist=False)` and don't use the capture callback, so each message is sent once (the guide explains that the two paths use different seed schemes).

### Optional: memory tools for the model

`create_memorysync_tools(user_id="customer-7")` returns five tools: add, search, list, update and delete. On the box it returned 5 tools. Pass `read_only=True` for untrusted agents (that returned 2 on the box).

## Common questions

**Why does my ADK agent forget everything after a restart?** You're on `InMemoryMemoryService` (or no memory service at all). Its data lives in process memory, so ADK's docs say it is lost on restart.

**`load_memory` or `preload_memory`?** `load_memory` leaves recall to the model. `preload_memory` injects results before the turn. If recall must happen every turn, use injection.

**Is there a TypeScript version?** ADK has TypeScript, Go, Java and Kotlin SDKs. MemorySync's ADK package is Python only, and its docs point TypeScript users to its Vercel AI SDK or Mastra integrations.

**Can I use two memory services?** ADK's docs include an example of using two memory services. Check the "Can an agent have access to more than one memory service?" section.

See a fact survive a full page reload in the browser first: **[try MemorySync](https://memorysync.io/try?utm_source=hashnode&utm_medium=organic_page&utm_campaign=v5_oct25&utm_content=pseo_google-adk-memory-across-sessions)**. No signup is needed.

## Sources

- ADK docs, Memory: https://adk.dev/sessions/memory/
- MemorySync Google ADK guide: https://docs.memorysync.io/guides/google-adk
- google-adk-memorysync on PyPI: https://pypi.org/project/google-adk-memorysync/
