Skip to content

feat(graph): auto-trigger mem::graph-extract on mem::remember#568

Open
efenex wants to merge 2 commits into
rohitg00:mainfrom
efenex:feat/v3-d-graph-extract-on-remember
Open

feat(graph): auto-trigger mem::graph-extract on mem::remember#568
efenex wants to merge 2 commits into
rohitg00:mainfrom
efenex:feat/v3-d-graph-extract-on-remember

Conversation

@efenex
Copy link
Copy Markdown
Contributor

@efenex efenex commented May 20, 2026

Summary

mem::remember (the explicit memory-save path used by memory_save MCP calls, plugin Stop hooks, JSONL imports, etc.) does NOT auto-trigger mem::graph-extract. Observations do auto-trigger extraction when GRAPH_EXTRACTION_ENABLED=true, but memories don't — so the knowledge graph grows from observation traffic only, leaving curated memories invisible to graph queries.

This wires the same auto-trigger pattern on the memory write path: after a successful mem::remember, fire mem::graph-extract against the newly-saved memory id when GRAPH_EXTRACTION_ENABLED=true. Best-effort; failure is logged-and-continued so a slow/down LLM provider can't block the save.

Impact

Closes the gap between observation-driven and memory-driven graph growth. After this:

  • mem::lineage (with includeGraph: true) sees the same node set whether a concept was extracted from observation traffic or written as a memory.
  • mem::smart-search graph-score component lights up for curated memories.
  • agentmemory graph-build (feat(graph): backfill graph from stored memories #538, if/when it lands) becomes a backfill tool for old data, not the only path for new data.

Related

Test plan

  • Existing tests pass (`npm test`)
  • `GRAPH_EXTRACTION_ENABLED=true mem::remember` produces graph nodes within the configured concurrency window
  • `GRAPH_EXTRACTION_ENABLED=false` (default) no-ops the trigger

🤖 Generated with Claude Code

Summary by CodeRabbit

Release Notes

  • New Features
    • Memory saving now supports optional knowledge-graph extraction. When enabled, saved memories asynchronously trigger graph extraction so save operations aren’t delayed. If the extraction trigger fails, a warning is logged but the original save still succeeds.

Review Change Stack

mem::remember persists a Memory record and indexes it into BM25 +
the vector store, but never fires the knowledge-graph extraction
pipeline. As a result, content saved via /agentmemory/remember —
including bulk imports like in-repo doc ingestion or post-hoc lesson
crystallization — doesn't populate KV.graphNodes/Edges. mem::reflect's
graph-clustering path then can't see this content and synthesizes
insights only from lessons + semantic facts + crystals + graph (which
itself is fed only by observation writes via triggers/events.ts).

Add a fire-and-forget triggerVoid for mem::graph-extract right after
the vector-index step, mirroring the observation pipeline's gate on
isGraphExtractionEnabled(). Reuses the existing memoryToObservation
helper (state/memory-utils.ts) so the wire format matches what
graph-extract already expects. Wrapped in try/catch so a failure
in the trigger setup never blocks the remember response.

No new env flags — gated on the existing GRAPH_EXTRACTION_ENABLED.
Operators who don't want auto-extraction from Memory writes simply
keep that flag off; observation-path extraction (which already
honors the same flag) is unaffected either way.

Companion to scripts/rebuild-graph.sh (commit 865c8d3), which
back-fills the graph for pre-V3-D content using a local LLM. With
both in place, ongoing remember POSTs auto-feed the graph and the
script is reserved for one-off bulk sweeps (or recovery after
large imports done with extraction disabled).
@vercel
Copy link
Copy Markdown

vercel Bot commented May 20, 2026

@efenex is attempting to deploy a commit to the rohitg00's projects Team on Vercel.

A member of the Team first needs to authorize it.

@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented May 20, 2026

📝 Walkthrough

Walkthrough

The mem::remember function gains conditional, fire-and-forget graph-extraction triggering. After saving and indexing a memory, if isGraphExtractionEnabled() returns true, the saved memory is converted to an observation and sent to mem::graph-extract asynchronously via sdk.triggerVoid. Trigger failures are caught, logged as warnings, and do not block the original response.

Changes

Graph Extraction Triggering

Layer / File(s) Summary
Conditional graph extraction triggering
src/functions/remember.ts
Import of isGraphExtractionEnabled from config enables gated asynchronous graph-extraction invocation after memory save. The trigger uses fire-and-forget semantics with non-blocking error logging.

Estimated code review effort

🎯 2 (Simple) | ⏱️ ~10 minutes

Possibly related PRs

  • rohitg00/agentmemory#215: Also wires conditional auto-invocation of mem::graph-extract gated by isGraphExtractionEnabled, but triggers at session end instead of after mem::remember.

Poem

🐰 A memory saved, now graphs shall grow,
Fire-and-forget, with gentle flow,
Config gates the extraction dance,
Errors caught but won't halt the advance! ✨

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly summarizes the main change: auto-triggering graph extraction on memory save when enabled. It accurately reflects the primary functionality addition in the changeset.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Warning

There were issues while running some tools. Please review the errors and either fix the tool's configuration or disable the tool if it's a critical failure.

🔧 ESLint

If the error stems from missing dependencies, add them to the package.json file. For unrecoverable errors (e.g., due to private dependencies), disable the tool in the CodeRabbit configuration.

ESLint skipped: no ESLint configuration detected in root package.json. To enable, add eslint to devDependencies.


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.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🧹 Nitpick comments (1)
src/functions/remember.ts (1)

123-133: ⚡ Quick win

Reduce the large WHAT-comment block.

Please trim this to a short intent note and rely on naming/function structure for behavior details.

As per coding guidelines, "Avoid code comments explaining WHAT — use clear naming instead".

🤖 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 `@src/functions/remember.ts` around lines 123 - 133, Replace the large
explanatory comment in src/functions/remember.ts with a concise intent note:
state that saved memories are enqueued for graph extraction (same behavior as
observation writes) when GRAPH_EXTRACTION_ENABLED is true and that extraction is
fire-and-forget to avoid blocking the remember response; keep references to the
existing helpers/paths (the observation event path event::session::compressed,
mem::reflect, graph-extract, and KV.graphNodes/Edges) only if needed for
clarity, and rely on function/variable names to convey the detailed behavior
instead of a long WHAT block.
🤖 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 `@src/functions/remember.ts`:
- Around line 135-144: The call to sdk.triggerVoid("mem::graph-extract", {
observations: [memoryToObservation(memory)] }) returns a Promise<void> so the
current try/catch around it won't catch async rejections; update the call in the
remember handler to either await the Promise (ensuring the enclosing function is
async) or append .catch(...) to the Promise and log via logger.warn including
memId: memory.id and the error message (err instanceof Error ? err.message :
String(err)) to mirror existing logging; ensure you reference sdk.triggerVoid,
memoryToObservation, and logger.warn when making the change.

---

Nitpick comments:
In `@src/functions/remember.ts`:
- Around line 123-133: Replace the large explanatory comment in
src/functions/remember.ts with a concise intent note: state that saved memories
are enqueued for graph extraction (same behavior as observation writes) when
GRAPH_EXTRACTION_ENABLED is true and that extraction is fire-and-forget to avoid
blocking the remember response; keep references to the existing helpers/paths
(the observation event path event::session::compressed, mem::reflect,
graph-extract, and KV.graphNodes/Edges) only if needed for clarity, and rely on
function/variable names to convey the detailed behavior instead of a long WHAT
block.
🪄 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: 928583d5-3cec-4f23-83e7-b2f7ae0aa802

📥 Commits

Reviewing files that changed from the base of the PR and between e371be9 and 545e97f.

📒 Files selected for processing (1)
  • src/functions/remember.ts

Comment thread src/functions/remember.ts
`sdk.triggerVoid()` returns `Promise<void>`, so the previous sync
try/catch only caught synchronous throws (argument validation, etc.).
Async rejections — provider timeout, engine queue full, downstream
extraction failure — escaped as unhandledRejection. CodeRabbit caught
this on rohitg00#568.

Keep the sync guard (defense in depth) and add a Promise.catch() so
either failure mode is logged-and-continued. Defensive type-narrow
the return value before attaching .catch in case a future iii-sdk
release changes triggerVoid's exact return shape.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick comments (1)
src/functions/remember.ts (1)

135-140: ⚡ Quick win

Remove the WHAT-style inline explanation block.

These lines restate control flow behavior; keep intent-focused comments only where naming cannot express why.

As per coding guidelines, "Avoid code comments explaining WHAT — use clear naming instead".

🤖 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 `@src/functions/remember.ts` around lines 135 - 140, Remove the WHAT-style
explanatory block comment that restates control flow (the multi-line comment
above the triggerVoid call) and replace it with an intent-focused one-liner (or
no comment) clarifying why we attach .catch() to the promise — e.g., "Ensure
fire-and-forget handles both sync throws and async rejections" — near the
triggerVoid invocation; update references around triggerVoid and the surrounding
try/catch so naming and the concise note communicate the why without restating
how the language works.
🤖 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 `@src/functions/remember.ts`:
- Around line 135-140: Remove the WHAT-style explanatory block comment that
restates control flow (the multi-line comment above the triggerVoid call) and
replace it with an intent-focused one-liner (or no comment) clarifying why we
attach .catch() to the promise — e.g., "Ensure fire-and-forget handles both sync
throws and async rejections" — near the triggerVoid invocation; update
references around triggerVoid and the surrounding try/catch so naming and the
concise note communicate the why without restating how the language works.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: ba3bf5d5-e18b-4827-87ec-9ed3e7d13a80

📥 Commits

Reviewing files that changed from the base of the PR and between 545e97f and e7489ed.

📒 Files selected for processing (1)
  • src/functions/remember.ts

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant