Agentic AI Atlasby a5c.ai
OverviewWikiGraphFor AgentsEdgesSearchWorkspace
/
GitHubDocsDiscord
iiRecord
Agentic AI Atlas · Memory Provider Plugins
page:docs-hermes-research-raw-memory-provider-plugina5c.ai
Search record views/
Record · tabs

Available views

II.Record viewspp. 1 - 1
overviewarticlejsongraph
II.
Page JSON

page:docs-hermes-research-raw-memory-provider-plugin

Structured · live

Memory Provider Plugins json

Inspect the normalized record payload exactly as the atlas UI reads it.

File · wiki/docs/hermes-research/raw/memory-provider-plugin.mdCluster · wiki
Record JSON
{
  "id": "page:docs-hermes-research-raw-memory-provider-plugin",
  "_kind": "Page",
  "_file": "wiki/docs/hermes-research/raw/memory-provider-plugin.md",
  "_cluster": "wiki",
  "attributes": {
    "nodeKind": "Page",
    "sourcePath": "docs/hermes-research/raw/memory-provider-plugin.md",
    "sourceKind": "repo-docs",
    "title": "Memory Provider Plugins",
    "displayName": "Memory Provider Plugins",
    "slug": "docs/hermes-research/raw/memory-provider-plugin",
    "articlePath": "wiki/docs/hermes-research/raw/memory-provider-plugin.md",
    "article": "\n# Memory Provider Plugins\n\n> Source: https://hermes-agent.nousresearch.com/docs/developer-guide/memory-provider-plugin\n\n## Overview\n\nMemory provider plugins extend Hermes Agent with persistent, cross-session knowledge capabilities beyond the built-in MEMORY.md and USER.md files. These are \"provider plugin\" types that follow a single-select, config-driven pattern managed via `hermes plugins`.\n\n## Directory Structure\n\nMemory providers reside in `plugins/memory/<name>/`:\n\n```\nplugins/memory/my-provider/\n  __init__.py      # MemoryProvider implementation + register() entry point\n  plugin.yaml      # Metadata (name, description, hooks)\n  cli.py           # Optional: register_cli(subparser) -- CLI commands\n  README.md        # Setup instructions, config reference, tools\n```\n\n## Core Implementation\n\n### The MemoryProvider ABC\n\nPlugins implement `MemoryProvider` from `agent/memory_provider.py`:\n\n```python\nfrom agent.memory_provider import MemoryProvider\n\nclass MyMemoryProvider(MemoryProvider):\n    @property\n    def name(self) -> str:\n        return \"my-provider\"\n\n    def is_available(self) -> bool:\n        \"\"\"Check if this provider can activate. NO network calls.\"\"\"\n        return bool(os.environ.get(\"MY_API_KEY\"))\n\n    def initialize(self, session_id: str, **kwargs) -> None:\n        \"\"\"Called once at agent startup.\n        kwargs always includes:\n          hermes_home (str): Active HERMES_HOME path. Use for storage.\n        \"\"\"\n        self._api_key = os.environ.get(\"MY_API_KEY\", \"\")\n        self._session_id = session_id\n```\n\n### Required Methods\n\n**Core Lifecycle:**\n\n| Method | When Called | Must Implement? |\n|--------|------------|-----------------|\n| `name` (property) | Always | **Yes** |\n| `is_available()` | Agent init, before activation | **Yes** -- no network calls |\n| `initialize(session_id, **kwargs)` | Agent startup | **Yes** |\n| `get_tool_schemas()` | After init, for tool injection | **Yes** |\n| `handle_tool_call(tool_name, args, **kwargs)` | When agent uses your tools | **Yes** (if you have tools) |\n\n**Config:**\n\n| Method | Purpose | Must Implement? |\n|--------|---------|-----------------|\n| `get_config_schema()` | Declare config fields for `hermes memory setup` | **Yes** |\n| `save_config(values, hermes_home)` | Write non-secret config to native location | **Yes** (unless env-var-only) |\n\n**Optional Hooks:**\n\n| Method | When Called | Use Case |\n|--------|------------|----------|\n| `system_prompt_block()` | System prompt assembly | Static provider info |\n| `prefetch(query, *, session_id=\"\")` | Before each API call | Return recalled context |\n| `queue_prefetch(query)` | After each turn | Pre-warm for next turn |\n| `sync_turn(user, assistant, *, session_id=\"\")` | After each completed turn | Persist conversation |\n| `on_session_end(messages)` | Conversation ends | Final extraction/flush |\n| `on_pre_compress(messages)` | Before context compression | Save insights before discard |\n| `on_memory_write(action, target, content)` | Built-in memory writes | Mirror to your backend |\n| `shutdown()` | Process exit | Clean up connections |\n\n## Configuration\n\n### Config Schema\n\nThe `get_config_schema()` method returns field descriptors for `hermes memory setup`:\n\n```python\ndef get_config_schema(self):\n    return [\n        {\n            \"key\": \"api_key\",\n            \"description\": \"My Provider API key\",\n            \"secret\": True,           # written to .env\n            \"required\": True,\n            \"env_var\": \"MY_API_KEY\",   # explicit env var name\n            \"url\": \"https://my-provider.com/keys\",  # where to get it\n        },\n        {\n            \"key\": \"region\",\n            \"description\": \"Server region\",\n            \"default\": \"us-east\",\n            \"choices\": [\"us-east\", \"eu-west\", \"ap-south\"],\n        },\n        {\n            \"key\": \"project\",\n            \"description\": \"Project identifier\",\n            \"default\": \"hermes\",\n        },\n    ]\n```\n\n**Best Practice:** Keep schemas minimal -- only prompt for essential settings (API keys, credentials). Document optional settings in config files referenced in README rather than adding to setup prompts.\n\n### Save Config\n\n```python\ndef save_config(self, values: dict, hermes_home: str) -> None:\n    \"\"\"Write non-secret config to your native location.\"\"\"\n    import json\n    from pathlib import Path\n    config_path = Path(hermes_home) / \"my-provider.json\"\n    config_path.write_text(json.dumps(values, indent=2))\n```\n\nFor environment-variable-only providers, leave the default no-op.\n\n## Plugin Registration\n\n### Entry Point\n\n```python\ndef register(ctx) -> None:\n    \"\"\"Called by the memory plugin discovery system.\"\"\"\n    ctx.register_memory_provider(MyMemoryProvider())\n```\n\n### plugin.yaml\n\n```yaml\nname: my-provider\nversion: 1.0.0\ndescription: \"Short description of what this provider does.\"\nhooks:\n  - on_session_end    # list hooks you implement\n```\n\n## Threading Contract\n\nThe `sync_turn()` method **must be non-blocking**. Run backend latency work in daemon threads:\n\n```python\ndef sync_turn(self, user_content, assistant_content, *, session_id=\"\", messages=None):\n    def _sync():\n        try:\n            self._api.ingest(user_content, assistant_content,\n                            session_id=session_id, messages=messages)\n        except Exception as e:\n            logger.warning(\"Sync failed: %s\", e)\n\n    if self._sync_thread and self._sync_thread.is_alive():\n        self._sync_thread.join(timeout=5.0)\n    self._sync_thread = threading.Thread(target=_sync, daemon=True)\n    self._sync_thread.start()\n```\n\nThe `messages` parameter includes OpenAI-style conversation context: user/assistant messages, tool calls, and results. Cloud providers must document which message parts transmit off-device.\n\n## Profile Isolation\n\nAll storage paths must use the `hermes_home` kwarg from `initialize()`:\n\n```python\n# CORRECT -- profile-scoped\nfrom hermes_constants import get_hermes_home\ndata_dir = get_hermes_home() / \"my-provider\"\n\n# WRONG -- shared across all profiles\ndata_dir = Path(\"~/.hermes/my-provider\").expanduser()\n```\n\n## Testing\n\n```python\nfrom agent.memory_manager import MemoryManager\n\nmgr = MemoryManager()\nmgr.add_provider(my_provider)\nmgr.initialize_all(session_id=\"test-1\", platform=\"cli\")\n\n# Test tool routing\nresult = mgr.handle_tool_call(\"my_tool\", {\"action\": \"add\", \"content\": \"test\"})\n\n# Test lifecycle\nmgr.sync_all(\"user msg\", \"assistant msg\")\nmgr.on_session_end([])\nmgr.shutdown_all()\n```\n\nReference test patterns: `tests/agent/test_memory_provider.py`, `tests/agent/test_memory_session_switch.py`, `tests/agent/test_memory_user_id.py`, `tests/run_agent/test_memory_provider_init.py`\n\n## CLI Commands\n\nMemory provider plugins can register custom CLI subcommands via convention-based discovery (no core file changes needed).\n\n### Implementation\n\n1. Add a `cli.py` file to the plugin directory\n2. Define a `register_cli(subparser)` function building the argparse tree\n3. The system discovers it at startup via `discover_plugin_cli_commands()`\n4. Commands appear under `hermes <provider-name> <subcommand>`\n\n**Active-provider gating:** CLI commands only appear when your provider is the active `memory.provider` in config.\n\n## Constraints\n\n**Single Provider Rule:** Only one external memory provider can be active at a time. Attempting to register a second triggers a MemoryManager warning, preventing tool schema bloat and backend conflicts.\n",
    "documents": []
  },
  "outgoingEdges": [],
  "incomingEdges": [
    {
      "from": "page:docs-hermes-research",
      "to": "page:docs-hermes-research-raw-memory-provider-plugin",
      "kind": "contains_page"
    }
  ]
}

Shortcuts

Back to overview
Open graph tab