google / google/adk-python

feat(memory): SQL-backed DatabaseMemoryService with scratchpad for durable agent memory

Open
#4,735 1 comment 0 reactions 2 assignees Claimed by @DeanChensj View on GitHub
needs review services
Dominant language
Python
Stars
21.5k
Forks
4k
Avg merge
1d 14h
Merged PRs (30d)
37

Description

## Summary

The ADK currently ships only `InMemoryMemoryService` (volatile, keyword-only, test-only) and cloud-specific Vertex AI services. There is no durable, self-hosted memory option for production deployments that do not use Vertex AI.

## Problem

Developers running ADK agents on-premise or against non-Google cloud providers have no way to persist agent memory across process restarts without writing their own implementation from scratch.

## Proposed Solution

Add `DatabaseMemoryService` — a `BaseMemoryService` implementation backed by any SQLAlchemy-supported async database (SQLite, PostgreSQL, MySQL, MariaDB, Spanner via the existing SQLAlchemy adapter).

### Core features

- **Durable memory** — events and direct `MemoryEntry` writes are stored in a SQL table (`adk_memory_entries`) that survives process restarts
- **Idempotent session ingest** — `add_session_to_memory` is safe to call multiple times (DELETE + re-INSERT)
- **Delta ingest** — `add_events_to_memory` skips already-stored `event_id`s
- **Pluggable search** — `MemorySearchBackend` ABC allows swapping in FTS or vector-embedding backends; ships with `KeywordSearchBackend` (LIKE/ILIKE, AND-first → OR-fallback)
- **Scratchpad** — a KV store (`adk_scratchpad_kv`) and append-only log (`adk_scratchpad_log`) for intermediate working memory during task execution, exposed as four `BaseTool` subclasses agents can call directly

### Zero-config for SQLite

```python
from google.adk.memory import DatabaseMemoryService

svc = DatabaseMemoryService("sqlite+aiosqlite:///:memory:") # tests / local dev
svc = DatabaseMemoryService("postgresql+asyncpg://user:pass@host/db") # production
```

### New public API surface

| Symbol | Module |
|--------|--------|
| `DatabaseMemoryService` | `google.adk.memory` |
| `MemorySearchBackend` | `google.adk.memory` |
| `KeywordSearchBackend` | `google.adk.memory` |
| `scratchpad_get_tool` | `google.adk.tools.scratchpad_tool` |
| `scratchpad_set_tool` | `google.adk.tools.scratchpad_tool` |
| `scratchpad_append_log_tool` | `google.adk.tools.scratchpad_tool` |
| `scratchpad_get_log_tool` | `google.adk.tools.scratchpad_tool` |

## Test coverage

38 unit tests using `sqlite+aiosqlite:///:memory:` (no external DB required):
- All `BaseMemoryService` methods
- Scratchpad KV and log operations
- All 4 tool happy-paths and wrong-service error paths
- Multi-user isolation and session scoping

## Files changed

```
src/google/adk/memory/schemas/__init__.py (new)
src/google/adk/memory/schemas/memory_schema.py (new)
src/google/adk/memory/memory_search_backend.py (new)
src/google/adk/memory/database_memory_service.py (new)
src/google/adk/tools/scratchpad_tool.py (new)
src/google/adk/memory/__init__.py (modified — adds exports)
tests/unittests/memory/test_database_memory_service.py (new)
```

## Related

Complements the existing `DatabaseSessionService` which follows the same SQLAlchemy async pattern.

Contributor guide

Open the contributing guide

Assessment

This issue has not been assessed yet.

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.