fix: persist memories to disk immediately after memory_save#122
fix: persist memories to disk immediately after memory_save#122rohitg00 merged 2 commits intorohitg00:mainfrom
Conversation
Previously, kv.persist() was only called on SIGINT/SIGTERM. If the process was killed with SIGKILL, crashed, or the host terminated it forcefully (e.g. OpenCode session end), all saved memories were lost. Fix: call kv.persist() immediately after kv.set() in the memory_save handler so data is written to standalone.json on every save. Also export handleToolCall with an injectable kv parameter to allow unit testing, and add tests verifying that persist is called on save.
|
No actionable comments were generated in the recent review. 🎉 ℹ️ Recent review info⚙️ Run configurationConfiguration used: defaults Review profile: CHILL Plan: Pro Run ID: 📒 Files selected for processing (1)
🚧 Files skipped from review as they are similar to previous changes (1)
📝 WalkthroughWalkthrough
Changes
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~20 minutes Poem
🚥 Pre-merge checks | ✅ 2 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (2 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ 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.
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
src/mcp/standalone.ts (1)
34-47: 🛠️ Refactor suggestion | 🟠 MajorAlign
memory_savewith repository ID and timestamp rules.Use
generateId()(andfingerprintId()for content-addressable dedup) instead of manualDate.now()/Math.random()ID construction, and capture ISO time once for bothcreatedAt/updatedAt.As per coding guidelines:
src/**/*.ts: UsefingerprintId()for content-addressable deduplication andgenerateId()for unique IDs in TypeScript code; capture timestamps once withnew Date().toISOString()and reuse the value rather than calling multiple times.🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@src/mcp/standalone.ts` around lines 34 - 47, Replace the ad-hoc ID and timestamp logic in the memory save code (the block that creates id and sets the object in kvInstance.set) with the standard helpers: call generateId() to produce the unique memory ID and use fingerprintId(content) if you need content-addressable deduplication, and capture a single const isoNow = new Date().toISOString() to set both createdAt and updatedAt rather than calling Date.now()/Math.random() and multiple Date calls; update the object fields (id, createdAt, updatedAt) accordingly in the same kvInstance.set call.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Outside diff comments:
In `@src/mcp/standalone.ts`:
- Around line 34-47: Replace the ad-hoc ID and timestamp logic in the memory
save code (the block that creates id and sets the object in kvInstance.set) with
the standard helpers: call generateId() to produce the unique memory ID and use
fingerprintId(content) if you need content-addressable deduplication, and
capture a single const isoNow = new Date().toISOString() to set both createdAt
and updatedAt rather than calling Date.now()/Math.random() and multiple Date
calls; update the object fields (id, createdAt, updatedAt) accordingly in the
same kvInstance.set call.
ℹ️ Review info
⚙️ Run configuration
Configuration used: defaults
Review profile: CHILL
Plan: Pro
Run ID: 818ba2b7-6298-4137-9c93-67e6937c7fbf
📒 Files selected for processing (2)
src/mcp/standalone.tstest/mcp-standalone.test.ts
Replace ad-hoc ID/timestamp logic with project-standard helpers:
- generateId("mem") instead of manual Date.now()/Math.random() concatenation
- Single const isoNow = new Date().toISOString() shared by createdAt and updatedAt
fingerprintId is intentionally not used: memory_save always creates a new
unique entry (no dedup), so a content-addressable key would silently overwrite
duplicate content rather than append — matching existing project behaviour.
|
Thanks for this — SIGKILL data loss was a real hole and the injectable Nice touches worth calling out:
Landing as v0.8.4 in the next patch bump. |
Two community contributions on top of 0.8.3 land as a patch release so they reach users immediately and so `npx agentmemory-mcp` ships to the npm registry for the first time (closing out #120 on the live release). - #122 (Jason Landbridge): memory_save persists to disk immediately after every call, not just on SIGINT/SIGTERM, so memories survive SIGKILL from agent sessions ending forcefully - #121 (Jason Landbridge): OpenCode MCP config format corrected — opencode.json with mcp/type:local/command array instead of the wrong .opencode/config.json with mcpServers Version bumped across package.json, src/version.ts, types.ts, export-import supportedVersions, plugin.json, shim package.json and its dependency on the main package (~0.8.4). package-lock.json regenerated. 684 tests passing, clean build.
Thanks for the quick merge, and thank you for this awesome project! |
Problem
In
standalone.ts,kv.persist()(which writes the in-memory store to~/.agentmemory/standalone.json) was only called onSIGINT/SIGTERMsignal handlers:If the MCP server process is killed with
SIGKILL, crashes unexpectedly, or the host terminates it forcefully (e.g. when an AI coding agent session ends), all memories saved during that session are permanently lost becausestandalone.jsonis never written.Fix
Call
kv.persist()immediately afterkv.set()in thememory_savehandler, so data is written to disk on every save:Additional Changes
handleToolCallwith an injectablekvInstanceparameter (defaults to the module-levelkv) to enable unit testingtransport.jsandconfig.jsintest/mcp-standalone.test.tsto prevent side effects when importing the modulehandleToolCalldescribe block:memory_save persists to disk immediately after saving— verifieswriteFileSyncis calledmemory_save without persist path does not call writeFileSync— no unnecessary writes when no path configuredmemory_save throws when content is missing— validates error handlingmemory_recall returns matching memories— end-to-end recall testAll 625 existing tests continue to pass.
Summary by CodeRabbit
Bug Fixes
Tests