feat: add Hermes Agent memory-provider integration#329
Conversation
Ship a Hermes Agent memory-provider plugin at `integrations/hermes/` and an `everos integrations install/uninstall hermes` installer that symlinks the bundle into `~/.hermes/plugins/everos/`. Hermes discovers user-installed plugins and loads them via the MemoryProvider subclass-fallback path, so no `hermes-agent` PR is required. The plugin is an HTTP client to the EverOS v1 API: - sync_turn -> POST /memory/add (two mixed-role MessageItems, ms timestamps) - on_session_end -> POST /memory/flush - prefetch -> POST /memory/search (two-phase, 1.5s hot-path wait) - on_memory_write -> mirror target="user" only - tools: everos_search / everos_list / everos_add / everos_flush - circuit breaker (5 transient failures -> 120s cooldown) OSS setup writes `~/.everos/everos.toml` ([llm]/[embedding]/[rerank]) and seeds `ome.toml` for the agent track when enabled. The bundle lives outside `src/everos/`, so it is unconstrained by the DDD/import-linter contracts and uses stdlib logging (it runs in the Hermes process). 136 hermetic tests cover the client, config, setup, formatting, provider lifecycle + tools + circuit breaker, the Hermes-side CLI, and the installer. Verified end-to-end with real models (LLM + embedding via OpenRouter): extraction writes episode markdown and search recalls the atomic fact.
How this integrates with Hermes Agent as a long-term memory provider
1. Discovery & loadingThe bundle at When Hermes starts, its plugin loader scans 2. The write path (every turn → durable memory)After each completed Hermes turn,
The markdown is the source of truth — plain, human-readable, durable. SQLite (state) and LanceDB (vectors + BM25) are derived indexes rebuilt from it. So memory survives across Hermes restarts, machine moves (copy the 3. The recall path (every turn → relevant context injected)Before each turn,
So when you ask "what output format do I prefer?", the agent sees the stored episode — "hermes-test instructed that they prefer tabular output for data presentations." — before it answers. 4. What makes it "long-term"
5. Explicit tools (agent-driven recall/write)Beyond passive prefetch, the agent gets four tools:
6. Mirroring built-in memory
7. ResilienceA circuit breaker trips after 5 consecutive transient failures (server down, LLM/embedding 503) and pauses calls for 120s — so a down EverOS server never crashes Hermes or stalls the conversation; it just degrades to built-in memory until the server recovers. Two deployment modes
In short: Hermes keeps talking to its agent as usual; every turn is quietly written to durable, searchable, self-consolidating markdown memory on the EverOS side, and the relevant bits are injected back before each answer. |
Add a dedicated docs page (docs/hermes-integration.md) covering install, modes, config, the write/recall lifecycle, agent tools, the Hermes-side CLI, resilience, and troubleshooting. Link it from the docs index (Tutorials) and document the new `everos integrations` subcommand (install/uninstall) in cli.md.
Summary
Adds a Hermes Agent memory-provider integration so Hermes can use an EverOS server as its cross-session memory backend. Ships entirely from the EverOS repo — no
hermes-agentPR required.MemoryProviderplugin bundle atintegrations/hermes/(HTTP client to the EverOS v1 API).everos integrations install/uninstall hermesTyper sub-group that symlinks the bundle into~/.hermes/plugins/everos/. Hermes discovers user-installed plugins and loads them via theMemoryProvidersubclass-fallback path.sync_turn→/memory/add(two mixed-roleMessageItems, ms timestamps),on_session_end→/memory/flush,prefetch→/memory/search(two-phase, 1.5s hot-path wait),on_memory_write→mirrortarget="user"only.everos_search,everos_list,everos_add,everos_flush.~/.everos/everos.toml([llm]/[embedding]/[rerank]) and seedsome.tomlfor the agent track when enabled.The bundle lives outside
src/everos/, so it is unconstrained by the DDD/import-linter contracts and uses stdliblogging(it runs in the Hermes process, not EverOS's).Area
Verification
End-to-end against the real Hermes Agent v0.18.0 binary + a real EverOS server (LLM
deepseek/deepseek-v4-flash+ embeddingqwen/qwen3-embedding-8bvia OpenRouter), in an isolated HERMES_HOME/EVEROS_ROOT:hermes memory status→everos (local) ← active,available ✓(plugin discovered + loaded via subclass-fallback).hermes everos status→ health reachable, correct config/scope.POST /memory/add(the adapter's exactsync_turnpayload) →accumulated.POST /memory/flush→extracted(LLM ran) → episode markdown written: "hermes-test instructed that they prefer tabular output for data presentations."POST /memory/search+hermes everos search→ both return the episode + atomic fact (recall works).~/.hermesand~/.everosuntouched.Full LLM extraction+recall requires an accessible LLM model + embedding endpoint in
~/.everos/everos.toml; the adapter's HTTP contract is also covered by 136 hermetic tests with fakes.Checklist
main.integrations/hermes/README.md).envfiles, dependency folders, or generated output.Notes for Reviewers
src/everos/(repo-rootintegrations/hermes/) so it stays out of theeverosimport graph and the DDD/import-linter contracts. It uses stdliblogging, not EverOS structlog, because it runs in the Hermes process.make check-datetime/check-cjkare scoped tosrc/+testsand do not flag the bundle.register(ctx)); confirmed athermes-agent/plugins/memory/__init__.py:_load_provider_from_dir.^[a-zA-Z0-9_.@+-]+$matches the server-sidePathSafeIdinsrc/everos/entrypoints/api/routes/memorize.py(thedocs/api.md§ScopeId list omits@/+; the server is ground truth). Documented in_constants.py.EVEROS_HERMES_PLUGIN_SOURCEenv →--sourceflag → repo-root walk-up fromeveros.__file__(covers editable/dev installs). PyPI-wheel-only consumers pass--source(vendoring into the wheel is a documented future enhancement).By submitting this pull request, I agree that my contribution is licensed under the Apache License 2.0.