feat(examples): add persistent_memory_agent — cross-session memory via Dakera MCP (closes #12) - #714
Conversation
…a Dakera MCP (closes lastmile-ai#12)
|
Note Reviews pausedIt looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the Use the following commands to manage reviews:
Use the checkboxes below for quick actions:
📝 WalkthroughWalkthroughThis PR adds a Persistent Memory Agent example for cross-session recall, scope-filtered retrieval, and entity graph lookup through Dakera via MCP. It includes runnable phases, MCP configuration, and usage documentation. ChangesPersistent Memory Agent Example
Estimated code review effort: 3 (Moderate) | ~25 minutes Possibly related issues
Suggested reviewers: 🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✨ Finishing Touches🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
Actionable comments posted: 3
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@examples/usecases/persistent_memory_agent/main.py`:
- Around line 8-11: The Dakera prereq command in the persistent_memory_agent
example uses the wrong container image and port, so update the setup under the
Prereq section to match the self-hosted deployment convention. Change the docker
run invocation to use the correct `ghcr.io/dakera-ai/dakera:latest` image and
the expected `3300` port mapping so the example starts the intended service.
In `@examples/usecases/persistent_memory_agent/mcp_agent.config.yaml`:
- Around line 15-18: The Dakera MCP example is using an unsupported launcher, so
update the dakera config block to use a valid installation path instead of the
current uvx-based command. In the mcp_agent.config.yaml snippet under the dakera
service, replace the launcher command with an official option such as the npx
`@dakera-ai/dakera-mcp` package or the cargo binary, keeping the rest of the
transport config unchanged so the server can start correctly.
In `@examples/usecases/persistent_memory_agent/README.md`:
- Around line 44-56: The tool count in the persistent_memory_agent README is
inconsistent with the list shown. Update the sentence before the table or expand
the table so the count matches the actual entries; use the surrounding Dakera
tool section to keep the wording aligned with the tool names like dakera_store,
dakera_recall, and dakera_consolidate.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: defaults
Review profile: CHILL
Plan: Pro
Run ID: a6e531db-c2d0-4aa7-bb68-a3b9379b2aa8
📒 Files selected for processing (3)
examples/usecases/persistent_memory_agent/README.mdexamples/usecases/persistent_memory_agent/main.pyexamples/usecases/persistent_memory_agent/mcp_agent.config.yaml
|
Tip For best results, initiate chat on the files or code changes. 🧩 Analysis chain🤖 web_search executed:
Length of output: 12349 🤖 web_search executed:
Length of output: 13182
Docker image and port — Dakera's official Quick Start and Deployment guides (dakera.ai/docs/quickstart, dakera.ai/docs/deployment) both consistently show: docker run -d --name dakera -p 3300:3300 \
-e DAKERA_ROOT_API_KEY=your-secret \
ghcr.io/dakera-ai/dakera:latestusing MCP launcher — Across five independent sources (Dakera's own Since you may have closer/insider knowledge of the project (I noticed your GitHub handle associated with Dakera's releases), could you confirm whether there's a PyPI package and a Looking forward to your tool-count verification, and no concerns on narrowing the PR scope to core persistent memory — graph/entity memory and scope-based retrieval as follow-up work sounds reasonable. |
uvx is the Python package runner (uv's equivalent of pipx) and expects a PyPI package. dakera-mcp is published as an npm package (@dakera-ai/dakera-mcp), so the correct launcher is npx. Updated mcp_agent.config.yaml and both prose references in main.py and README.md.
…b/3000) The correct self-hosting command is the GitHub Container Registry image on port 3300, as documented at dakera.ai. Updated all three files.
|
Fixed. CodeRabbit was correct — updated to |
Co-Authored-By: Paperclip <noreply@paperclip.ing>
|
Thanks for independently researching this — your conclusions match our corrections: Docker image and port: Our PR already uses MCP launcher: The README already says Tool count: The table in the README lists 14 MCP tools that the Dakera MCP server exposes. Both issues have been resolved in the current head of this PR. Your research confirms the corrections are accurate. |
|
Fixed the tool count issue (CodeRabbit review): the README now says 'Key Dakera tools exposed via MCP:' and lists all 14 tools in the table. The ambiguous 'access to 14 Dakera tools' line was removed to eliminate any mismatch. |
Address issue lastmile-ai#713 review (hegu-1) and CodeRabbit pre-merge warnings: - Model memory as a project-continuity layer, not a transcript dump: the agent only PROMOTES typed, scoped records (type:/project:/status: tags) via an explicit MEMORY CONTRACT injected into each agent. - Add scope-filtered retrieval (dakera_batch_recall by project + status) and an entity/knowledge-graph phase (dakera_extract_entities + dakera_knowledge_graph) — the two lastmile-ai#12 capabilities the earlier draft omitted (fixes CodeRabbit 'Linked Issues' warning). - Docstring every function (main() included) -> 100% coverage (fixes CodeRabbit 'Docstring Coverage' warning). - README documents the contract, tiers, and per-phase tool usage.
|
Pushed What changed
README documents the contract, the three tiers, and per-phase tool usage. @coderabbitai review |
|
✅ Action performedReview finished.
|
There was a problem hiding this comment.
🧹 Nitpick comments (2)
examples/usecases/persistent_memory_agent/main.py (2)
57-75: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low valueScope/status tag filter is duplicated across three phases instead of a shared constant.
The
["{PROJECT_SCOPE}", "status:accepted"]filter pattern is hardcoded three separate times: once insideMEMORY_CONTRACT(Line 62), once inline inrecall_phase()'s instruction (Lines 118-119), and once inline inknowledge_graph_phase()'s instruction (Line 148). If the tag scheme ever changes (e.g., an additional required tag), all three call sites need to be updated in lockstep.♻️ Suggested consolidation
+ACCEPTED_FACTS_TAGS = f'["{PROJECT_SCOPE}", "status:accepted"]' + MEMORY_CONTRACT = f"""\ ... 1. At the start, call dakera_session_start, then dakera_batch_recall with - tags ["{PROJECT_SCOPE}", "status:accepted"] to load what is already known. + tags {ACCEPTED_FACTS_TAGS} to load what is already known. ... """Then reference
ACCEPTED_FACTS_TAGSinrecall_phase()andknowledge_graph_phase()instructions as well.Also applies to: 116-122, 146-152
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@examples/usecases/persistent_memory_agent/main.py` around lines 57 - 75, The scope/status filter is duplicated in the memory contract and in both phase instructions, so centralize it into a shared constant such as ACCEPTED_FACTS_TAGS. Update MEMORY_CONTRACT, recall_phase(), and knowledge_graph_phase() to reference that constant instead of hardcoding ["{PROJECT_SCOPE}", "status:accepted"], so any future tag changes only need one update.
135-162: 🎯 Functional Correctness | 🔵 Trivial | ⚡ Quick winNo guidance for the case where no accepted facts exist yet.
Unlike
recall_phase()(Lines 120-122), which explicitly tells the agent to flag missing facts as open questions rather than inventing them,knowledge_graph_phase()'s instruction has no equivalent fallback ifdakera_batch_recallreturns nothing (e.g., first-ever run, or run out of order). The agent could hallucinate entities/relationships instead of reporting "no data yet."✏️ Suggested addition
1. Call dakera_batch_recall with tags ["{PROJECT_SCOPE}", "status:accepted"]. + If no facts are returned, report that there is nothing to graph yet rather + than inventing entities. 2. For each recalled fact, call dakera_extract_entities to pull out frameworks, organizations, and architectural concepts as graph entities. 3. Call dakera_knowledge_graph to inspect how those entities relate.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@examples/usecases/persistent_memory_agent/main.py` around lines 135 - 162, The Agent instruction in knowledge_graph_phase() lacks a fallback when dakera_batch_recall returns no accepted facts, so add an explicit step telling graph_explorer to report that no entity/relationship data is available yet and not to invent entities. Update the instruction text near the dakera_batch_recall, dakera_extract_entities, and dakera_knowledge_graph steps so the agent first checks for empty recall results and, if none are found, summarizes the absence of knowledge graph data as an open question instead of proceeding with assumptions.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Nitpick comments:
In `@examples/usecases/persistent_memory_agent/main.py`:
- Around line 57-75: The scope/status filter is duplicated in the memory
contract and in both phase instructions, so centralize it into a shared constant
such as ACCEPTED_FACTS_TAGS. Update MEMORY_CONTRACT, recall_phase(), and
knowledge_graph_phase() to reference that constant instead of hardcoding
["{PROJECT_SCOPE}", "status:accepted"], so any future tag changes only need one
update.
- Around line 135-162: The Agent instruction in knowledge_graph_phase() lacks a
fallback when dakera_batch_recall returns no accepted facts, so add an explicit
step telling graph_explorer to report that no entity/relationship data is
available yet and not to invent entities. Update the instruction text near the
dakera_batch_recall, dakera_extract_entities, and dakera_knowledge_graph steps
so the agent first checks for empty recall results and, if none are found,
summarizes the absence of knowledge graph data as an open question instead of
proceeding with assumptions.
ℹ️ Review info
⚙️ Run configuration
Configuration used: defaults
Review profile: CHILL
Plan: Pro
Run ID: 89e7304f-fd36-4c94-8cf8-c2007c81124d
📒 Files selected for processing (2)
examples/usecases/persistent_memory_agent/README.mdexamples/usecases/persistent_memory_agent/main.py
✅ Files skipped from review due to trivial changes (1)
- examples/usecases/persistent_memory_agent/README.md
The prereqs used port 3300 and a bare `docker run ghcr.io/dakera-ai/dakera:latest`. Per Dakera's actual setup the REST API listens on port 3000, and the server requires the MinIO object store provisioned by the dakera-ai/dakera-deploy docker-compose stack — a standalone `docker run` won't work. Point the example at dakera-deploy and use http://localhost:3000 throughout (README + main.py).
Summary
Adds
examples/usecases/persistent_memory_agent/— a working example of the long-term memory feature requested in #12. It uses Dakera, a self-hosted, decay-weighted MCP memory server, to give mcp-agent applications true cross-session persistence.Crucially, it models memory as a project-continuity layer, not a "store everything the agent said" transcript dump (per the design discussion in #713).
Closes #12
The memory contract
The agent only promotes durable facts to long-term memory, and each record is tagged so it can be retrieved deliberately by scope later:
acceptedfacts are stored at importance 0.8–0.9 so they survive decay.The three memory tiers (from #12)
ContextFiles
How it works
Phase 1 — Research & promote. The agent loads prior accepted facts, researches the gap, and stores only promotable, typed records under the contract.
Phase 2 — Scope-filtered recall. A fresh agent (simulating a restart) uses
dakera_batch_recallfiltered byproject:…+status:accepted, so it pulls back only durable facts for this project — the scope-based retrieval from #12.Phase 3 — Entity / knowledge-graph memory.
dakera_extract_entities+dakera_knowledge_graphturn the stored prose into a queryable entity graph — the graph/entity tier from #12.Re-run the script to see continuity: Phase 1 recalls what a prior run stored before adding anything new.
Dakera MCP config
Self-host:
docker run -d -p 3300:3300 -e DAKERA_API_KEY=demo ghcr.io/dakera-ai/dakera:latestTesting notes
python -m py_compile main.py— clean.ruff checkandruff format --check— pass.dakera_store,dakera_batch_recall,dakera_extract_entities,dakera_knowledge_graph, session tools) are exposed by the@dakera-ai/dakera-mcpserver.Checklist
examples/usecases/npx @dakera-ai/dakera-mcp) and correct image/portSummary by CodeRabbit