Skip to content

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

Open
anmolg1997 wants to merge 1 commit intogoogle:mainfrom
anmolg1997:feat/database-memory-service
Open

feat(memory): add DatabaseMemoryService with SQLAlchemy async backend#5339
anmolg1997 wants to merge 1 commit 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!

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

2 participants