Add selectable Redis Agent Memory backends#16
Conversation
a73ba82 to
e9b8ee7
Compare
Replace inline ruff/isort/pyink/mypy invocations with calls to make format-check, make lint, and make type-check. The test step keeps its --cov flags so coverage upload still works.
Add tests/integration/test_memory_backends_end_to_end.py covering: - RedisLongTermMemoryService.add_memory + search_memory round-trip against managed Redis Agent Memory and against the self-hosted Agent Memory Server. - RedisWorkingMemorySessionService append_event + get_session + delete_session round-trip against Redis Agent Memory. Tests skip when REDIS_AGENT_MEMORY_API_BASE_URL / REDIS_AGENT_MEMORY_API_KEY / REDIS_AGENT_MEMORY_STORE_ID or AGENT_MEMORY_SERVER_URL are not set, matching the existing pattern used by the search integration suite.
- pyproject.toml: 0.0.6 -> 0.0.7. - CHANGELOG.md: add [0.0.7] entry documenting the dual-backend memory work (services, tools, examples), the new memory extra shipping both clients, the docs/spec additions, the new live integration tests, and the CI Makefile refactor.
| REDIS_AGENT_MEMORY_URL = os.environ.get("REDIS_AGENT_MEMORY_API_BASE_URL") | ||
| REDIS_AGENT_MEMORY_API_KEY = os.environ.get("REDIS_AGENT_MEMORY_API_KEY") | ||
| REDIS_AGENT_MEMORY_STORE_ID = os.environ.get("REDIS_AGENT_MEMORY_STORE_ID") |
| return {"status": "error", "message": "memory_ids is required"} | ||
|
|
||
| try: |
| if self._config.backend == OPENSOURCE_AGENT_MEMORY_BACKEND: | ||
| response = await self._get_agent_memory_server_client().delete_long_term_memories( | ||
| memory_ids=memory_ids, | ||
| ) |
| memory_id = args.get("memory_id") | ||
| content = args.get("content") | ||
| topics = args.get("topics") | ||
| self._get_namespace(args.get("namespace")) | ||
| self._get_user_id(args.get("user_id")) | ||
| namespace = args.get("namespace") | ||
| user_id = args.get("user_id") | ||
|
|
| import logging | ||
| from typing import Any | ||
| import uuid | ||
|
|
Captures follow-up work for PR #16: - No example demonstrates redis-agent-memory backend under the adk web runner. travel_agent_memory_tools is the only adk web memory example and defaults to opensource-agent-memory. - All three memory examples default REDIS_MEMORY_BACKEND to opensource-agent-memory, contradicting the library default (redis-agent-memory) documented in docs/specs/redis-agent-memory-default.md. - simple_redis_memory and travel_agent_memory_hybrid cannot move to adk web because they register services through get_service_registry(), which only get_fast_api_app consults. Proposes adding a new examples/simple_managed_memory/ (memory tools only, managed backend default, no docker-compose) plus doc cleanups and a top-level examples/README.md matrix.
Restructure the memory example handover so the next person assesses both implementation coverage and example coverage from scratch: - Phase 1 reads the dispatch code in src/adk_redis/memory, src/adk_redis/sessions, and src/adk_redis/tools/memory, reads the installed redis-agent-memory SDK and the public Redis Agent Memory docs, then produces an ADK-surface-by-backend coverage table and a list of hard vs soft gaps. - Phase 2 audits examples against the phase 1 conclusions and proposes the concrete add/change/leave plan. Add a 'Capability differences from public docs' section pointing at the official Redis Agent Memory docs (preview product) and the ADK integration page, capturing concrete starting-point gaps to validate: - Auto-promotion exists on managed but the policy is opaque (no documented extraction strategy or debounce). - Auto-summarization, configurable extraction strategies, recency weights, and the MCP server endpoint are opensource-only. - Identifier naming differences (ownerId / storeId vs user_id / namespace) and how Session.state plus non-text event payloads behave on managed need verification. - The public ADK integration page does not yet describe the managed backend selector introduced by PR #16; flagged for coordination. Drop the prescriptive options-A-vs-B recommendation so the takeover person can decide based on the phase 1 findings.
| "events", | ||
| app_name, | ||
| user_id, | ||
| len(events), | ||
| ), |
| response = await self._get_agent_memory_server_client().delete_long_term_memories( | ||
| memory_ids=memory_ids, | ||
| ) |
| if not message: | ||
| return | ||
|
|
||
| await self._get_agent_memory_server_client().append_messages_to_working_memory( |
limjoobin
left a comment
There was a problem hiding this comment.
Looks good! Just some comments for clarity, but functionality-wise it looks clear that you're creating an abstraction layer for agent memory backends, to support the managed Redis Agent Memory and self-hosted AMS backends
| MemoryBackendName = Literal[ | ||
| "redis-agent-memory", | ||
| "opensource-agent-memory", | ||
| ] |
There was a problem hiding this comment.
Not particularly crucial, but is there a reason why we defined REDIS_AGENT_MEMORY_BACKEND and OPENSOURCE_AGENT_MEMORY_BACKEND, but still use the hardcoded values in the Literal?
Might be a good idea to use these defined values for DRY-ness.
| MemoryBackendName = Literal[ | |
| "redis-agent-memory", | |
| "opensource-agent-memory", | |
| ] | |
| MemoryBackendName = Literal[ | |
| REDIS_AGENT_MEMORY_BACKEND, | |
| OPENSOURCE_AGENT_MEMORY_BACKEND, | |
| ] |
| if memory.last_accessed | ||
| "id": read_field(memory, "id"), | ||
| "content": read_field(memory, "text"), | ||
| "topics": read_field(memory, "topics", []) or [], |
There was a problem hiding this comment.
actually i notice (across the repo) that or ... is always included when a default value is defined in read_field, but if it returns a default value, the or ... part seems to be redundant.
| def test_memory_tool_config_accepts_opensource_backend(): | ||
| """Memory tool config accepts the self-hosted backend value.""" | ||
| assert ( | ||
| MemoryToolConfig(backend="opensource-agent-memory").backend |
There was a problem hiding this comment.
Similar to before, it might be more DRY to use OPENSOURCE_AGENT_MEMORY_BACKEND from src/adk_redis/memory/_backends.py instead of hardcoding "opensource-agent-memory" for such instances when defining the backend
…ects - and : chars, and current IDs exceeded the limit. This fix handles the IDs, and return empty sessions before first event (when Redis has nothing yet), so the first message can flow and create the real session.
|
Sorry I made a typo - for commit 2de43e9, I meant to say that Redis Agent Memory doesn't accept underscore |
Summary
Adds selectable Redis Agent Memory backend support across all ADK memory
surfaces while preserving the self-hosted Agent Memory Server path.
All public services and tools now accept a
backendfield:backend="redis-agent-memory"(default): managed Redis Agent Memory viaredis-agent-memory>=0.0.4.backend="opensource-agent-memory": self-hosted Agent Memory Server viaagent-memory-client>=0.14.0.Public class names are unchanged:
RedisWorkingMemorySessionService,RedisLongTermMemoryService,MemoryToolConfig, and the six memory tools(
SearchMemoryTool,CreateMemoryTool,GetMemoryTool,UpdateMemoryTool,DeleteMemoryTool,MemoryPromptTool).Spec:
docs/specs/redis-agent-memory-default.md.What's in this PR
Code
src/adk_redis/memory/_backends.py:MemoryBackendNameliteral andbackend name constants.
src/adk_redis/memory/long_term_memory.py: dual-backend dispatch foradd_session_to_memory,add_events_to_memory,add_memory, andsearch_memory. Implements the newer ADK write hooks confirmed againstupstream
google/adk-pythonat commitae95a97, while stayingcompatible with installed ADK versions that don't call them yet.
src/adk_redis/sessions/working_memory.py: dual-backend dispatch forappend_event,get_session, andlist_sessions. Redis Agent Memorypath reconstructs ADK sessions from stored events; opensource path keeps
Working Memory APIs, summarization, and extraction strategy settings.
src/adk_redis/tools/memory/*.pyand_config.py: all six tools routeto the configured backend; adds
default_owner_idfor tools that runoutside an ADK user context.
Dependencies
pyproject.toml: thememoryextra now installs both clients(
agent-memory-client>=0.14.0,redis-agent-memory>=0.0.4).0.0.6to0.0.7.Docs
docs/specs/redis-agent-memory-default.md: design spec for the dualbackend, config surface, and test scope.
docs/specs/examples-memory-coverage-handover.md: handover for thefollow-up work needed on
examples/and on managed-backend capabilityparity. Frames it as a two-phase assessment (implementation coverage
first, example coverage second) and lists concrete capability gaps to
validate against the public Redis Agent Memory docs.
docs/concepts/memory.md,docs/concepts/sessions.md,docs/llms.txt: concept pages and llms index updated to reflect thebackend choice.
docs/user_guide/01_integration.md,docs/user_guide/how_to_guides/memory_service.md,docs/user_guide/how_to_guides/session_service.md,docs/user_guide/how_to_guides/memory_server_setup.md,docs/user_guide/how_to_guides/redis_setup.md: how-to guides updated.CHANGELOG.md: new[0.0.7]entry underAdded,Changed, andDocssections.Examples
examples/simple_redis_memory/,examples/travel_agent_memory_hybrid/,examples/travel_agent_memory_tools/: surface theREDIS_MEMORY_BACKENDenv var in
.env.example, README, and agent wiring so users can switchbackends without code changes. Defaults are currently
opensource-agent-memory; rebalancing against the library default(
redis-agent-memory) is captured in the handover doc.Tests
tests/memory/test_long_term_memory.py: backend dispatch, owner andnamespace filters, event-to-memory writes, explicit
add_memorypayloads, and config defaults for both backends.
tests/sessions/test_working_memory.py: session reconstruction,deterministic internal session IDs, and self-hosted backend parity.
tests/tools/test_memory_tools.py: create / search / update / deletepayloads for both backends.
tests/integration/test_memory_backends_end_to_end.py: new liveround-trip coverage for both backends. Skips when
REDIS_AGENT_MEMORY_API_BASE_URL/REDIS_AGENT_MEMORY_API_KEY/REDIS_AGENT_MEMORY_STORE_IDorAGENT_MEMORY_SERVER_URLare not set.CI
.github/workflows/ci.yml: lint, format-check, and type-check stepsnow invoke the corresponding Makefile targets so the Makefile is the
single source of truth for local and CI checks.
Status
origin/main. PR diff is scoped to the memorybackend work plus the handover doc.
make check: 112 passed, 10 skipped (integration suites skipcleanly without a configured backend) locally.
google/adk-python@ae95a97.Deferred to follow-up (see handover doc)
Captured in
docs/specs/examples-memory-coverage-handover.md:redis-agent-memorybackend underthe
adk webrunner. All three memory examples default toopensource-agent-memory, which is the opposite of the librarydefault.
self-hosted Agent Memory Server. Known starting gaps to validate:
configurable extraction strategy and debounce, working-memory
auto-summarization, recency-boost weights, the MCP server endpoint,
Session.stateround-tripping, and non-text event payload fidelity.redis.io/docs/.../integrate/google-adk/redis-agent-memory/does notyet describe the managed backend selector introduced here; flagged
for coordination with whoever owns that page.
examples/simple_redis_memory/.env.exampleis empty.simple_redis_memoryandtravel_agent_memory_hybridcan move off
get_fast_api_apptoadk web(currently blocked bythe ADK service-registry consumer being scoped to the FastAPI app
factory).
Remaining for this PR
memory integration tests run on every PR.
How to test locally