Skip to content

feat(memory): graph-memory adapter + migration script (Phase D) - #5

Merged
PowerCreek merged 1 commit into
mainfrom
issue-54-memory-as-graph
May 22, 2026
Merged

feat(memory): graph-memory adapter + migration script (Phase D)#5
PowerCreek merged 1 commit into
mainfrom
issue-54-memory-as-graph

Conversation

@PowerCreek

Copy link
Copy Markdown

Hermes side of the two-repo Phase D graph-memory lift (devagentic#54). Last Lane C item — completes the lane.

Summary

Three pieces, mirroring C1's structure:

  1. agent/devagentic_memory.py — read-through adapter. When DEVAGENTIC_MEMORY_GRAPH=1, POSTs userFactQuery to a running devagentic and returns relevance-ranked facts. Returns [] on any failure (gate off, no user_id, network/parse error, no facts) so the caller's existing file-based memory fallback runs unchanged. Adapter never raises — every network path wrapped in try/except.
  2. scripts/migrate_memory_to_graph.py — one-way migration. Walks HERMES_HOME for MEMORY.md / USER.md / SOUL.md and POSTs each file as a kind:user-fact node via userFactCreate. --dry-run prints the plan without mutating; --tag attaches extra tags; --confidence tunes the default (0.9 for file-aged facts).
  3. tests/test_devagentic_memory.py — 15 pytest cases covering env gate, query happy / sad paths (empty query, no user_id, network failure, blank-body filtering), create_user_fact mutation shape, migration helpers (file iteration, empty/missing skip, today-tag format).

Companion devagentic PR: TechDevGroup/devagentic#144

User-id resolution

Mirrors the devagentic-local provider's contract (Phase G #50) and the skill adapter (Phase C #52):

  1. DEVAGENTIC_USER_ID env override.
  2. hermes_cli.profiles.get_active_profile_name().
  3. None → adapter returns empty.

Rollout

After both PRs land:

# 1. On dev, under the active hermes profile, migrate existing memory:
python scripts/migrate_memory_to_graph.py            # --dry-run first if cautious

# 2. Enable graph reads:
export DEVAGENTIC_MEMORY_GRAPH=1
hermes chat ...                                       # memory reads consult graph first

Acceptance (from devagentic#54)

  • Migration reads existing memory files, writes corresponding nodes (verified by test_iter_memory_files*; live-run pending operator dispatch).
  • Adapter consults devagentic when enabled; returns [] on any failure (verified by test_query_user_facts_off_returns_empty, test_query_user_facts_network_failure, etc.).
  • create_user_fact posts the right GraphQL mutation and returns the new fact id (verified by test_create_user_fact_posts_and_returns_id).
  • Empty / blank-body / no-user-id paths all return safely (4 dedicated tests).
  • CI green (pending CI run).

Design calls

  1. Adapter doesn't auto-rewrite existing memory call sites. Same call as C1: the adapter is purely additive. agent/memory_manager.py / tools/memory_tool.py aren't patched in this PR. Keeping the call-site swap behind a separate, focused PR isolates the network-introduced risk. Documented as deferred follow-up.
  2. File-level migration granularity (one fact per file). v0 keeps the supersede story simple (refining one file == one supersede). Paragraph / bullet granularity is documented as deferred — could split MEMORY.md by \n\n or by leading - bullets in a v1.
  3. Migration is append-only. Re-running creates fresh facts; older ones remain in the graph. To dedupe a re-migration, call userFactSupersede(old, new) manually for each pair (or wait for a --supersede-prior flag).
  4. Adapter never raises. Every network failure returns empty; callers keep their file fallback. Mirrors C1's skill adapter contract.

Deferred

  • Call-site swap in agent/memory_manager.py / tools/memory_tool.py — separate focused PR.
  • Paragraph- or bullet-level migration granularity.
  • --supersede-prior dedup flag on the migration script.
  • Honcho dialectic-user-model integration (issue notes it as a future).

Hermes side of the two-repo Phase D lift
(TechDevGroup/devagentic#54). agent/devagentic_memory.py is the
read-through adapter: when DEVAGENTIC_MEMORY_GRAPH=1, it POSTs
userFactQuery to a running devagentic and returns the
relevance-ranked facts; on any failure (gate off, network error,
parse error, no user_id) returns [] so the caller's existing
file-based memory fallback runs unchanged.

scripts/migrate_memory_to_graph.py is the one-way migration —
walks HERMES_HOME for MEMORY.md / USER.md / SOUL.md and POSTs
each file as a kind:user-fact node via userFactCreate. --dry-run
prints the plan; v0 granularity is one fact per file with
tags=[origin:<name>, migration:YYYY-MM-DD, ...].

Companion devagentic PR: TechDevGroup/devagentic#<TBD>

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@PowerCreek
PowerCreek merged commit c8d1c4e into main May 22, 2026
@PowerCreek
PowerCreek deleted the issue-54-memory-as-graph branch May 22, 2026 06:55
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