Conversation
ba083f7 to
5f20c49
Compare
5f20c49 to
35975da
Compare
35975da to
504ddc0
Compare
| facts = self._query_memory_facts(assertion_name, _DEFAULT_MEMORY_CONTEXT_GRAPH) | ||
| except Exception as e: | ||
| logger.debug(f"[dkg] Recall from assertion failed: {e}") | ||
| if facts: |
There was a problem hiding this comment.
🔴 Bug: This early return makes the legacy fallback stop working as soon as agent-context has any note. For upgraded profiles that already have provider memory in a custom context_graph, the first new default write will hide all older notes even though this PR documents that they should remain visible. Merge/dedupe the legacy facts with the new agent-context facts (or migrate them) instead of returning here, and add a regression test for the mixed-data case.
| score = _keyword_overlap(text, keywords) | ||
| layer = _memory_search_layer(cg, view) | ||
| source = "sessions" if cg == "agent-context" else "memory" | ||
| source = "sessions" if cg == _DEFAULT_MEMORY_CONTEXT_GRAPH else "memory" |
There was a problem hiding this comment.
🟡 Issue: agent-context hits are all tagged as source: "sessions", but dkg_memory also stores durable provider notes in agent-context via urn:hermes:content. That makes the new provenance fields inaccurate and prevents callers from distinguishing simple memory notes from chat-session recall. Derive source from the predicate/assertion type here so Hermes memory entries still report memory.
504ddc0 to
a5c18cb
Compare
| const sentinelOpen = | ||
| /<recalled-memory\b(?=[^>]*\bdata-source\s*=\s*(?:"dkg-auto-recall"|'dkg-auto-recall'))[^>]*>/i; | ||
| return text.replace( | ||
| new RegExp(sentinelOpen.source + /[\s\S]*?<\/recalled-memory>/.source, 'gi'), |
There was a problem hiding this comment.
🔴 Bug: This only removes well-formed recalled-memory pairs. If the model output is truncated after the sentinel open tag, the recalled snippets survive persistence and get re-indexed on later turns, which is exactly the contamination this change is trying to prevent. Strip sentinelOpen...$ as well here (and keep the Python helper aligned).
| target = args.get("target", "memory") | ||
| content = args.get("content", "") | ||
| old_text = args.get("old_text", "") | ||
| context_graph_id = _first_text(args, "context_graph_id") or _DEFAULT_MEMORY_CONTEXT_GRAPH |
There was a problem hiding this comment.
🔴 Bug: context_graph_id now controls where dkg_memory writes, but a malformed non-string value falls through _first_text(...) and silently writes to agent-context. That turns a bad tool call into a data-routing bug. Validate context_graph_id when the key is present and return tool_error on non-string input, like the other DKG handlers do.
| facts = self._query_memory_facts(assertion_name, _DEFAULT_MEMORY_CONTEXT_GRAPH) | ||
| except Exception as e: | ||
| logger.debug(f"[dkg] Recall from assertion failed: {e}") | ||
| if facts: |
There was a problem hiding this comment.
🔴 Bug: Returning here means legacy notes disappear as soon as agent-context contains even one new fact. Upgraded profiles with historical memory in a custom context_graph will lose all of that older context after the first unscoped write. Either merge legacy + default facts during recall or migrate the legacy assertion forward instead of treating it as an all-or-nothing fallback.
a5c18cb to
af1aeca
Compare
| target = args.get("target", "memory") | ||
| content = args.get("content", "") | ||
| old_text = args.get("old_text", "") | ||
| context_graph_id = _first_text(args, "context_graph_id") or _DEFAULT_MEMORY_CONTEXT_GRAPH |
There was a problem hiding this comment.
🔴 Bug: context_graph_id is read through _first_text, so any non-string value is silently treated as "missing" and the write falls back to agent-context. A malformed tool call like { "context_graph_id": ["project-cg"] } would store the note in personal memory with no error. Please validate that overrides are non-empty strings before defaulting, and apply the same guard in memory_search, which uses the same parsing pattern.
|
|
||
| return self._cache.get("memory", []) + self._cache.get("user", []) | ||
| legacy_context_graph = self._legacy_memory_context_graph() | ||
| if legacy_context_graph: |
There was a problem hiding this comment.
🔴 Bug: this legacy read now runs unconditionally for every non-default self._context_graph, but the docs and surrounding comments describe it as a fallback only when agent-context is empty. As written, any future dkg_memory(..., context_graph_id=self._context_graph) note will be merged back into _recall_facts() and leak into the default provider memory prompt. Gate the legacy query behind an empty-default-memory check (or a one-time migration flag) instead of always merging it.
af1aeca to
e515e53
Compare
Source issue
Closes #385
Summary
main(200d987b) after additional PRs merged, preserving main's newer Hermes setup parity,dkg_share, context-graph privacy, and build behavior.prefetch()assertion-only recall with the same six-layer DKG fan-out helper used bymemory_search.dkg_memory.context_graph_idsupport while keeping unscoped simple memory writes defaulted toagent-context/memory.OpenClaw parity notes
agent-contextWM/SWM/VM.context_graph_id/target_context_graph; staticcontext_graphconfig does not count as current selection.agent-context-wm,agent-context-swm,agent-context-vm,project-wm,project-swm,project-vm.Files changed
packages/adapter-hermes/hermes-plugin/__init__.pypackages/adapter-hermes/test/hermes-adapter.test.tspackages/cli/src/daemon/routes/hermes.tspackages/cli/test/daemon-hermes.test.tspackages/adapter-hermes/README.mddocs/setup/SETUP_HERMES.mdpackages/cli/skills/dkg-node/SKILL.mdBehavioral details
memory_searchfor query planning, fan-out, ranking, dedupe, and provenance.agent-contextrecall always runs across WM/SWM/VM. A selected project graph is included only when supplied throughcontext_graph_id/target_context_graphon the call.<recalled-memory data-source="dkg-auto-recall">with escaped snippet text and untrusted-context framing.dkg_memory.context_graph_idstores scoped notes under separate cache buckets and queues writes with the target graph id. Unscoped writes continue to targetagent-context/memory.context_graphare read as a legacy fallback when the newagent-contextassertion is empty or unavailable.memory_searchno longer filters out short literals with a hardSTRLEN >= 20cutoff.Test evidence
Latest rebase sanity, after updating onto
mainat200d987b:python -m py_compile packages/adapter-hermes/hermes-plugin/__init__.py packages/adapter-hermes/hermes-plugin/client.pypassed.git diff --check upstream/main...HEADpassed.pnpm --filter @origintrail-official/dkg-adapter-hermes test -- hermes-adapter.test.tspassed: 86 tests.pnpm --filter @origintrail-official/dkg-core buildpassed; this refreshed workspace exports after pulling main.pnpm --filter @origintrail-official/dkg buildpassed.pnpm --filter @origintrail-official/dkg test -- test/daemon-hermes.test.ts --reporter=verbosepassed: 66 tests. The command still prints the known post-run Windows message,The system cannot find the path specified., after exiting successfully.Earlier parity/review-round evidence retained from the prior rebase:
pnpm --filter @origintrail-official/dkg-adapter-openclaw test -- before-prompt-build-hook.test.ts memory-integration.test.ts memory-search-tool.test.ts ChatTurnWriter.test.ts ChatTurnWriter.sanitize.test.ts plugin.test.ts dkg-client.test.tspassed: 7 files, 451 tests.pnpm --filter @origintrail-official/dkg-agent... buildpassed.pnpm --filter @origintrail-official/dkg-epcis buildpassed.Manual verification status
Security / persistence notes
sync_turn()persistence./api/hermes-channel/persist-turnalso strips adapter-generated recalled-memory blocks before chat storage, transition recording, and extraction import.data-sourceattributes, and malformed unmatched openings so recalled context does not boomerang or cause data loss.dkg_memory.context_graph_idavoids cache and queue bleed between default personal memory and project notes.dkg_memorywrites still useagent-contextunlesscontext_graph_idis explicit.Known risks or follow-ups