Skip to content

feat(memory): add DatabaseMemoryService with SQLAlchemy async backend#5339

Open
anmolg1997 wants to merge 3 commits intogoogle:mainfrom
anmolg1997:feat/database-memory-service
Open

feat(memory): add DatabaseMemoryService with SQLAlchemy async backend#5339
anmolg1997 wants to merge 3 commits intogoogle:mainfrom
anmolg1997:feat/database-memory-service

Conversation

@anmolg1997
Copy link
Copy Markdown
Contributor

Summary

Adds DatabaseMemoryService, a durable, SQL-backed memory service that works with any SQLAlchemy-compatible async database (SQLite via aiosqlite, PostgreSQL via asyncpg, MySQL/MariaDB, etc.).

  • Fills the gap between the volatile InMemoryMemoryService and the cloud-only Firestore/Vertex AI options — gives self-hosted deployments a persistent memory backend with zero cloud dependencies
  • Mirrors the keyword-extraction approach of FirestoreMemoryService and reuses the SQLAlchemy patterns from DatabaseSessionService
  • Implements add_session_to_memory, add_events_to_memory (delta ingestion), and search_memory
  • Includes lazy table creation with double-checked locking, async context manager support, and proper rollback-on-exception handling

Motivation

Currently, developers not using Vertex AI or Google Cloud Firestore have no persistent memory option — InMemoryMemoryService is explicitly volatile and loses all data on restart. This is a frequently requested feature:

Design Decisions

Decision Rationale
Placed in google.adk.memory (not integrations/) Follows DatabaseSessionService placement in sessions/, and uses no external cloud SDK
Reuses DynamicJSON from sessions.schemas.shared Consistent JSON/JSONB handling across SQLAlchemy services
Separate _memory_schemas.py for ORM models Mirrors the sessions/schemas/ pattern, keeps concerns separated
Keyword search (not semantic/vector) Matches FirestoreMemoryService approach — semantic search can be added via a future SearchBackend abstraction
Lazy __getattr__ import in __init__.py Matches DatabaseSessionService pattern — avoids hard SQLAlchemy dependency for users who don't need it

Changes

File Description
src/google/adk/memory/database_memory_service.py New — DatabaseMemoryService implementation
src/google/adk/memory/_memory_schemas.py New — SQLAlchemy ORM model (StorageMemoryEntry)
src/google/adk/memory/__init__.py Updated — lazy export of DatabaseMemoryService
tests/unittests/memory/test_database_memory_service.py New — 19 tests covering CRUD, search, scoping, dedup, persistence

Usage

from google.adk.memory import DatabaseMemoryService

# SQLite (zero-config)
memory = DatabaseMemoryService("sqlite+aiosqlite:///memory.db")

# PostgreSQL
memory = DatabaseMemoryService("postgresql+asyncpg://user:pass@host/db")

async with memory:
    await memory.add_session_to_memory(session)
    result = await memory.search_memory(
        app_name="my_app", user_id="u1", query="agent tool usage"
    )

Test plan

  • 19 unit tests passing (pytest tests/unittests/memory/test_database_memory_service.py)
  • All 59 existing memory tests still pass (pytest tests/unittests/memory/)
  • Code formatted with isort + pyink per CONTRIBUTING.md
  • Tested with in-memory SQLite and file-based SQLite
  • Context manager lifecycle (__aenter__/__aexit__) verified

Adds a durable, SQL-backed memory service that works with any
SQLAlchemy-compatible async database (SQLite, PostgreSQL, MySQL/MariaDB).

This fills the gap between the volatile InMemoryMemoryService and
the cloud-only Firestore/Vertex AI options, giving self-hosted
deployments a persistent memory backend with zero cloud dependencies.

The implementation mirrors the keyword-extraction approach used by
FirestoreMemoryService and reuses the existing SQLAlchemy patterns
established by DatabaseSessionService.

Closes google#2524
Closes google#2976
@adk-bot
Copy link
Copy Markdown
Collaborator

adk-bot commented Apr 15, 2026

Response from ADK Triaging Agent

Hello @anmolg1997, thank you for creating this PR!

Could you please provide logs or a screenshot of the passed pytest results?

This information will help reviewers to review your PR more efficiently. Thanks!

@adk-bot adk-bot added the services [Component] This issue is related to runtime services, e.g. sessions, memory, artifacts, etc label Apr 15, 2026
@anmolg1997
Copy link
Copy Markdown
Contributor Author

Hi @adk-bot — thanks for the prompt! Here are the full pytest results:

New tests (19/19 passing):

tests/unittests/memory/test_database_memory_service.py::test_extract_keywords PASSED
tests/unittests/memory/test_database_memory_service.py::test_add_session_to_memory PASSED
tests/unittests/memory/test_database_memory_service.py::test_add_session_with_no_events PASSED
tests/unittests/memory/test_database_memory_service.py::test_add_session_to_memory_filters_no_content_events PASSED
tests/unittests/memory/test_database_memory_service.py::test_add_session_to_memory_skips_stop_words_only PASSED
tests/unittests/memory/test_database_memory_service.py::test_search_memory_empty_query PASSED
tests/unittests/memory/test_database_memory_service.py::test_search_memory_only_stop_words PASSED
tests/unittests/memory/test_database_memory_service.py::test_search_memory_simple_match PASSED
tests/unittests/memory/test_database_memory_service.py::test_search_memory_case_insensitive PASSED
tests/unittests/memory/test_database_memory_service.py::test_search_memory_multiple_matches PASSED
tests/unittests/memory/test_database_memory_service.py::test_search_memory_no_match PASSED
tests/unittests/memory/test_database_memory_service.py::test_search_memory_scoped_by_user PASSED
tests/unittests/memory/test_database_memory_service.py::test_search_memory_deduplication PASSED
tests/unittests/memory/test_database_memory_service.py::test_add_events_to_memory PASSED
tests/unittests/memory/test_database_memory_service.py::test_add_events_to_memory_without_session_id PASSED
tests/unittests/memory/test_database_memory_service.py::test_add_events_to_memory_skips_empty PASSED
tests/unittests/memory/test_database_memory_service.py::test_context_manager PASSED
tests/unittests/memory/test_database_memory_service.py::test_file_based_sqlite PASSED
tests/unittests/memory/test_database_memory_service.py::test_invalid_db_url PASSED
======================== 19 passed in 1.16s ========================

Full memory test suite (59/59 passing — no regressions):

tests/unittests/memory/test_database_memory_service.py - 19 passed
tests/unittests/memory/test_in_memory_memory_service.py - 11 passed
tests/unittests/memory/test_vertex_ai_memory_bank_service.py - 29 passed
======================= 59 passed in 16.37s ========================

All CI checks (CLA, header-check, agent-triage) are also passing.

@anmolg1997
Copy link
Copy Markdown
Contributor Author

Hi @wuliang229 — thank you for approving #5338! Would you be able to take a look at this one as well when you get a chance? It adds a SQL-backed DatabaseMemoryService (mirrors the existing DatabaseSessionService patterns) with 19 unit tests, all passing. Appreciate it!

@rohityan rohityan self-assigned this Apr 16, 2026
rohityan and others added 2 commits April 16, 2026 14:07
Addresses the mypy-new-error gate failures on Python 3.10/3.13:

- memory/__init__.py: add `-> Any` return annotation to the lazy
  `__getattr__(name)` so it satisfies `no-untyped-def`. Matches the
  convention used by `tools/__init__.py` and `skills/__init__.py`.
- memory/_memory_schemas.py: silence SQLAlchemy's `DeclarativeBase`
  type-stub `Any` base-class warning (same pattern as other places
  where SQLAlchemy is used; pre-existing analogous errors in
  sessions/schemas/{v0,v1}.py are grandfathered on main).
- memory/database_memory_service.py: annotate `__aexit__` parameters
  so mypy no longer flags `no-untyped-def`.

Verified locally:
  * `mypy .` reports zero errors in the three new files
    (the mypy-diff gate compares against main; all remaining errors
    under `src/google/adk/memory/` are pre-existing on main).
  * All 19 DatabaseMemoryService unit tests still pass.
  * pyink --check and isort --check-only are clean.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

services [Component] This issue is related to runtime services, e.g. sessions, memory, artifacts, etc

Projects

None yet

Development

Successfully merging this pull request may close these issues.

SQLite-based memory service implementation Add support for additional Memory Bank services: DatabaseMemoryService/RedisMemoryService

3 participants