feat(integrations): add hermes-agent-memory native provider for OB1#280
feat(integrations): add hermes-agent-memory native provider for OB1#280MicScalise wants to merge 4 commits into
Conversation
Native Hermes Agent MemoryProvider that connects Hermes runtimes to the OB1 v1 Agent Memory contract — same backend the OpenClaw plugin talks to, so OpenClaw and Hermes agents share one governed memory. - Auto-recall before each turn (prefetch + queue_prefetch with 90s cache) - Auto-writeback after each turn (sync_turn → outputs[]) - Synchronous structured-finding writeback at session end - Background writeback + summary string at compression time - 7 explicit tools: recall, writeback, search, report_usage, list_review_queue, review_memory, get_recall_trace - x-brain-key auth (matches OB1 v1, not Bearer) - Per-turn model+provider attribution with config.yaml fallback - Subagent/cron/flush guard prevents corrupting parent task_id 75 pytest tests, network-mocked, run offline in <1s. Verified live end-to-end against a self-hosted Supabase + agent-memory-api Edge Function deployment. Companion to integrations/openclaw-agent-memory/ — same governance, different runtime.
|
Hey @MicScalise — welcome to Open Brain Source! 👋 Thanks for submitting your first PR. The automated review will run shortly and check things like metadata, folder structure, and README completeness. If anything needs fixing, the review comment will tell you exactly what. Once the automated checks pass, a human admin will review for quality and clarity. Expect a response within a few days. If you have questions, check out CONTRIBUTING.md or open an issue. |
…unconfirmed=true
Two Edge Function defaults make naive recall return zero rows even when
match_thoughts finds the embedding correctly:
1. Writeback stores memories with visibility="personal" (the column
default in agent_memories), but scopeMatches() at /recall drops
personal-visibility memories unless scope.visibility="personal" is
passed by the recall.
2. Writes default to provenance.requires_review=true (governance), which
gives the row review_status="pending"; scope.include_unconfirmed=false
filters all pending memories out, including the agent's own writes
from earlier turns.
The combination meant every Hermes auto-recall returned empty even when
the relevant prior turn was clearly in OB1 — the agent never saw its
own previous memories.
Fix: pass scope.visibility="personal" in all recall paths (prefetch,
do_recall, ob1_recall tool) and default include_unconfirmed_recall=True
in the provider config so pending memories are visible to their author.
Pending memories are still ranked lower than confirmed ones via the
Edge Function's scoreMemory(), so this preserves governance signal.
Verified live: a Hermes turn querying "What did we decide about the
Qwen3.6-27B coder model?" now recalls 8 prior memories (was 0 before
the fix) and synthesizes them correctly.
Mirrors the OpenClaw plugin's workspaceMode option (PR NateBJones-Projects#283 Phase 9) so both runtimes have symmetric multi-tenant memory semantics. Config (in $HERMES_HOME/ob1.json or via env vars): workspace_mode: "shared" | "per-agent" (default: "shared") workspace_prefix: "<optional-prefix>" (per-agent mode only) workspace_id: "<fallback>" (used in shared mode + as fallback in per-agent mode) Env: OPENBRAIN_WORKSPACE_MODE, OPENBRAIN_WORKSPACE_PREFIX In "per-agent" mode workspace_id = workspace_prefix + agent_identity, so each Hermes agent identity gets its own isolated OB1 workspace. Empty or "default" agent identities fall back to the configured workspace so the plugin never sends an empty workspace_id. Implementation: * _resolve_workspace_id() — pure helper applying the mode rules, matching the OpenClaw plugin's resolveAgentWorkspaceId() logic so cross-runtime behavior is identical. * initialize() reads agent_identity BEFORE resolving workspace_id so per-agent mode can use it. * _load_ob1_config() handles new env vars + validates workspace_mode to one of the allowed values (defaults invalid values to "shared"). Tests: 6 new TestResolveWorkspaceId cases covering all four resolution paths (shared-fallback, per-agent-with-identity, prefix application, default-identity fallback, empty-identity fallback, unknown-mode-as-shared). Total suite: 81 tests passing. Backwards compatible. workspace_mode defaults to "shared" so existing deployments behave exactly as before.
|
Thanks for the contribution. This is a substantial, well-organized integration — a Hermes Because it sits in the Agent Memory direction, a few things for the maintainer rather than a code fix. It ties to the same direction question as the OpenClaw cluster (#278 / #281 / #283 / #309) — whatever governance model OB1 settles on there should apply consistently here. Worth checking whether Recommend maintainer review, alongside the OpenClaw cluster direction decision. — Alan (community reviewer; non-binding) |
…onfirmed default) Two changes per @alan's community review on PR NateBJones-Projects#280: 1. Remove subfolder LICENSE (MIT) so this dir inherits the repo's FSL-1.1-MIT. The MIT-in-FSL nested-license situation was a real compatibility issue; following the same convention as integrations/openclaw-agent-memory/ which inherits root LICENSE.md. 2. Change include_unconfirmed_recall config fallback from False to True (line 159 of plugin/__init__.py) so it matches the DEFAULTS dict at line 96 and the design intent documented in phase-8 lessons learned. Recall returned 0 with False — pending memories (which is the default for governed writes per require_review_by_default=True) were filtered out before reaching the caller. Edge Function's scoreMemory still ranks pending memories lower so they don't dominate; they just appear. Same governance direction as PR NateBJones-Projects#283 (OpenClaw companion). Whatever the maintainer settles on for the OpenClaw cluster (NateBJones-Projects#278/281/283/309) applies consistently here; current change aligns Hermes-OB1 with the resolved defaults documented in the Hermes-OB1 phase-8 final report. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
|
Thanks Alan — all three points addressed. New commit 1. LICENSE compatibility (FSL-1.1-MIT) 2.
Flipped line 159 fallback to 3. Governance direction across the cluster |
|
Thanks for the quick turnaround — all three points look addressed. Removing the nested LICENSE is the right call; inheriting the repo root and matching the I haven't re-read the — Alan |
|
Thanks Alan — appreciate the second look. Happy to rebase or adjust if anything shifts when the cluster direction lands. |
Summary
Adds
integrations/hermes-agent-memory/— a native Hermes AgentMemoryProviderthat connects Hermes runtimes to the OB1 v1 Agent Memory contract. Same backend as the OpenClaw plugin, so OpenClaw agents and Hermes agents share one governed memory.This is a companion to
integrations/openclaw-agent-memory/— same governance, different runtime.What it does
prefetch(), with background warm-up viaqueue_prefetch()(90s TTL cache)sync_turn()— payload structured as OB1outputs[]on_session_end()— heuristic mapping intodecisions / lessons / constraints / next_steps / unresolved_questions / failureson_pre_compress()— extracts findings before compression discards messagesob1_recall,ob1_writeback,ob1_search,ob1_report_usage,ob1_list_review_queue,ob1_review_memory,ob1_get_recall_traceAuthorization: Bearer)on_turn_startkwargs, falls back to~/.hermes/config.yaml(realyaml.safe_load, not line-scanning)task_idWhy this exists
OpenClaw and Hermes are sibling agent runtimes. Without a Hermes-native provider, Hermes agents can't participate in the same governed memory the OpenClaw plugin uses — defeating the cross-runtime "shared brain" promise. This plugin closes that gap with no extra infrastructure (talks to the same
agent-memory-apiEdge Function).Tests
75 pytest tests, network-mocked at
urllib.request.urlopen, run offline in <1 second:```bash
cd integrations/hermes-agent-memory/plugin
pytest tests/
===== 75 passed in 0.44s =====
```
Coverage: pure helpers, OB1 v1 schema shape on the wire (recall + writeback + report_usage), client error handling, lifecycle (active/inactive transitions, subagent guard, save_config sanitization), prefetch + queue_prefetch caching (cold/warm/stale/burst-dedup/shutdown), sync_turn (skip-trivial, skip-short, ob1-context stripping), session-end finding extraction, pre-compress, and all seven tool handlers.
Verified live
End-to-end against a self-hosted Supabase +
agent-memory-apiEdge Function deployment. Real Hermes turns auto-recall, auto-write back with correctruntime_name=hermes,model=anthropic/claude-opus-4.6,provider=anthropic, andtask_idlinkage. Agent self-organizes around thesystem_prompt_blockand callsob1_writebackexplicitly for decision/lesson categorization.Test plan
See `integrations/hermes-agent-memory/README.md` for the full setup walkthrough and `CHANGELOG.md` for v0.1.0 release notes.
Related
Filed alongside #279 (NBJ OpenClaw plugin missing memory-host hooks). This PR's Hermes provider is unrelated to that issue — it's a parallel native implementation for the Hermes runtime side.