الأكاديمية ← دليل المطوّرتوثيق رسمي · إرشاد عربي

إضافات مزوّد الذاكرة

Memory Provider Plugins

متقدم8 دقائق قراءةالدرس 134 أسئلة✓ 2026-08-18
قبل أن تقرأ

ما هذه الصفحة، وماذا تحتوي.

المزوّد والنموذج: المزوّد هو الشركة التي تشغّل نموذج الذكاء الاصطناعي، والنموذج هو «العقل» الذي يفكّر لـHermes. Hermes نفسه لا يفكّر؛ هو ينظّم العمل ويستدعي النموذج. لذلك اختيار النموذج يحدّد جودة النتيجة وتكلفتها. ستستعمل هنا hermes memory setup وhermes plugins، والقراءة نحو 8 دقائق. انتبه: الأغلى ليس دائمًا الأفضل لمهمتك. جرّب مهمة واحدة على نموذجين وقارن، وضع سقفًا للإنفاق من البداية.

12أقسام
13أمثلة برمجية
4جداول
4أوامر
1,344كلمة من المصدر
الوصف الرسمي في سطر

How to build a memory provider plugin for Hermes Agent

ماذا ستستطيع بعدها

نتائج مأخوذة من هذه الصفحة، لا من قالب.

  • تعرف ما المزوّد والنموذج ولماذا قد تحتاجه.
  • تنفّذ hermes memory setup وhermes plugins وتفهم ما يحدث بعدها.
  • تقرأ الجدول وتأخذ منه السطر الذي يخصّك فقط.
  • تضبط HERMES_HOME في المكان الصحيح.
ما ستقابله من أسماء

كما تظهر تمامًا داخل Hermes.

الأوامر
  • hermes memory setup
  • hermes plugins
  • hermes my-provider config
  • hermes my-provider status
متغيرات البيئة
  • HERMES_HOME
  • SKILLS_DIR
خريطة الصفحة

انتقل مباشرة إلى ما تحتاجه.

  1. 01Installation Layouts
  2. 02The MemoryProvider ABC
  3. 03Required Methods
  4. 04Config Schema
  5. 05Save Config
  6. 06Plugin Entry Point
  7. 07plugin.yaml
  8. 08Threading Contract
  9. 09Profile Isolation
  10. 10Testing
  11. 11Adding CLI Commands
  12. 12Single Provider Rule
الصفحة الرسمية كاملة

بلا اختصار أو حذف.

النص أدناه منقول من المصدر الرسمي بالإنجليزية حتى تبقى الأوامر والأسماء دقيقة كما هي. قبل كل قسم شرح عربي يوضّح ما بداخله.

Memory provider plugins give Hermes Agent persistent, cross-session knowledge beyond the built-in MEMORY.md and USER.md. This guide covers how to build one.

Installation Layouts

خطوات عملية بالترتيب. نفّذ خطوة وتأكد أنها نجحت قبل الانتقال للتالية.

Hermes discovers memory providers from four sources, in this precedence order:

SourceLocationNotes
Bundledplugins/memory/<name>/Ships with Hermes. Closed to new providers — see CONTRIBUTING ↗.
User$HERMES_HOME/plugins/<name>/Dropped in by the user, per profile.
Project./.hermes/plugins/<name>/Opt-in via HERMES_ENABLE_PROJECT_PLUGINS=1.
Packagehermes_agent.memory_providers entry pointpip install, nothing to copy.

Earlier sources win on a name collision, so a directory dropped into a working tree can never shadow a shipped provider.

Discovery only enumerates — it never imports a provider. Nothing runs until memory.provider names it.

Directory Provider

A directory provider lives in plugins/memory/<name>/ when bundled with Hermes, in $HERMES_HOME/plugins/<name>/ when installed by a user, or in ./.hermes/plugins/<name>/ for a project-local one:

Text4 أسطر
plugins/memory/my-provider/
├── __init__.py      # MemoryProvider implementation + register() entry point
├── plugin.yaml      # Metadata (name, description, hooks)
└── README.md        # Setup instructions, config reference, tools

Packaged Provider

A pip-installed provider publishes an entry point in the hermes_agent.memory_providers group. The entry-point name is the provider name users select in memory.provider; its value points to the provider's register(ctx) function:

TOMLسطران
[project.entry-points."hermes_agent.memory_providers"]
my-provider = "my_provider:register"

Point the entry point at the package, or at a register(ctx) inside it, and keep your implementation, skills, and other resources in the normal Python package layout. No copy under $HERMES_HOME/plugins/ is required.

A package entry point gets everything a directory install does, including the two files Hermes reads from disk rather than importing — config_schema.py (the dashboard config panel) and cli.py (your hermes <provider> subcommands). Both are found next to your package's __init__.py, so point the entry point at a package rather than a single module if you ship either.

The MemoryProvider ABC

إعدادات تضبطها مرة وتنساها. غيّر واحدًا في كل مرة حتى تعرف أثر كل تغيير. تضبط HERMES_HOME خارج المحادثة، في بيئة التشغيل.

Your plugin implements the MemoryProvider abstract base class from agent/memory_provider.py:

Python21 سطرًا
from agent.memory_provider import MemoryProvider

class MyMemoryProvider(MemoryProvider):
    @property
    def name(self) -> str:
        return "my-provider"

    def is_available(self) -> bool:
        """Check if this provider can activate. NO network calls."""
        return bool(os.environ.get("MY_API_KEY"))

    def initialize(self, session_id: str, **kwargs) -> None:
        """Called once at agent startup.

        kwargs always includes:
          hermes_home (str): Active HERMES_HOME path. Use for storage.
        """
        self._api_key = os.environ.get("MY_API_KEY", "")
        self._session_id = session_id

    # ... implement remaining methods

Required Methods

جدول مرجعي. لا تقرأه كله، ابحث عن السطر الذي يخصّك فقط.

Core Lifecycle

MethodWhen CalledMust Implement?
name (property)AlwaysYes
is_available()Agent init, before activationYes — no network calls
initialize(session_id, **kwargs)Agent startupYes
get_tool_schemas()After init, for tool injectionYes
handle_tool_call(tool_name, args, **kwargs)When agent uses your toolsYes (if you have tools)

Config

MethodPurposeMust Implement?
get_config_schema()Declare config fields for hermes memory setupYes
save_config(values, hermes_home)Write non-secret config to native locationYes (unless env-var-only)

Optional Hooks

MethodWhen CalledUse Case
system_prompt_block()System prompt assemblyStatic provider info
prefetch(query, *, session_id="")Before each API callReturn recalled context
queue_prefetch(query, *, session_id="")After each turnPre-warm for next turn
sync_turn(user, assistant, *, session_id="", messages=None)After each completed turnPersist conversation
on_session_end(messages)Conversation endsFinal extraction/flush
on_pre_compress(messages)Before context compressionSave insights before discard
on_memory_write(action, target, content)Built-in memory writesMirror to your backend
shutdown()Process exitClean up connections

Config Schema

أوامر تكتبها في الطرفية. افهم ما يفعله الأمر قبل نسخه. الأوامر هنا: hermes memory setup.

get_config_schema() returns a list of field descriptors used by hermes memory setup:

Python22 سطرًا
def get_config_schema(self):
    return [
        {
            "key": "api_key",
            "description": "My Provider API key",
            "secret": True,           # → written to .env
            "required": True,
            "env_var": "MY_API_KEY",   # explicit env var name
            "url": "https://my-provider.com/keys",  # where to get it
        },
        {
            "key": "region",
            "description": "Server region",
            "default": "us-east",
            "choices": ["us-east", "eu-west", "ap-south"],
        },
        {
            "key": "project",
            "description": "Project identifier",
            "default": "hermes",
        },
    ]

Fields with secret: True and env_var go to .env. Non-secret fields are passed to save_config().

Save Config

شرح للفكرة نفسها. اقرأه ببطء، فبقية الأقسام تبني عليه. تذكير: المزوّد هو الشركة التي تشغّل نموذج الذكاء الاصطناعي، والنموذج هو «العقل» الذي يفكّر لـHermes.

Python6 أسطر
def save_config(self, values: dict, hermes_home: str) -> None:
    """Write non-secret config to your native location."""
    import json
    from pathlib import Path
    config_path = Path(hermes_home) / "my-provider.json"
    config_path.write_text(json.dumps(values, indent=2))

For env-var-only providers, leave the default no-op.

Plugin Entry Point

إعدادات تضبطها مرة وتنساها. غيّر واحدًا في كل مرة حتى تعرف أثر كل تغيير. تضبط SKILLS_DIR خارج المحادثة، في بيئة التشغيل.

Python3 أسطر
def register(ctx) -> None:
    """Called by the memory plugin discovery system."""
    ctx.register_memory_provider(MyMemoryProvider())

A provider may also expose read-only skills from the same callback. Skills are qualified by the entry-point name and are loaded only when that memory provider is active:

Python11 سطرًا
from pathlib import Path

SKILLS_DIR = Path(__file__).parent / "skills"

def register(ctx) -> None:
    ctx.register_memory_provider(MyMemoryProvider())
    ctx.register_skill(
        "maintenance",
        SKILLS_DIR / "maintenance" / "SKILL.md",
        "Maintain the provider's memory store",
    )

With the my-provider entry point active, the skill is available as my-provider:maintenance through skill_view().

plugin.yaml

إعدادات تضبطها مرة وتنساها. غيّر واحدًا في كل مرة حتى تعرف أثر كل تغيير.

YAML5 أسطر
name: my-provider
version: 1.0.0
description: "Short description of what this provider does."
hooks:
  - on_session_end    # list hooks you implement

Threading Contract

شرح للفكرة نفسها. اقرأه ببطء، فبقية الأقسام تبني عليه.

sync_turn() MUST be non-blocking. If your backend has latency (API calls, LLM processing), run the work in a daemon thread:

Python11 سطرًا
def sync_turn(self, user_content, assistant_content, *, session_id="", messages=None):
    def _sync():
        try:
            self._api.ingest(user_content, assistant_content, session_id=session_id, messages=messages)
        except Exception as e:
            logger.warning("Sync failed: %s", e)

    if self._sync_thread and self._sync_thread.is_alive():
        self._sync_thread.join(timeout=5.0)
    self._sync_thread = threading.Thread(target=_sync, daemon=True)
    self._sync_thread.start()

messages is optional OpenAI-style conversation context as of the completed turn. When present, it includes user/assistant messages, assistant tool calls, and tool result messages. Providers that do not need raw turn context can omit the messages parameter; Hermes will continue calling them with the legacy signature.

Cloud providers should document what parts of messages are sent off-device. Tool calls and tool results may contain file paths, command output, or other workspace data.

Profile Isolation

شرح للفكرة نفسها. اقرأه ببطء، فبقية الأقسام تبني عليه.

All storage paths must use the hermes_home kwarg from initialize(), not hardcoded ~/.hermes:

Python6 أسطر
# CORRECT — profile-scoped
from hermes_constants import get_hermes_home
data_dir = get_hermes_home() / "my-provider"

# WRONG — shared across all profiles
data_dir = Path("~/.hermes/my-provider").expanduser()

Testing

شرح للفكرة نفسها. اقرأه ببطء، فبقية الأقسام تبني عليه.

See tests/agent/test_memory_provider.py and adjacent memory tests (tests/agent/test_memory_session_switch.py, tests/agent/test_memory_user_id.py, tests/run_agent/test_memory_provider_init.py) for end-to-end patterns.

Python13 سطرًا
from agent.memory_manager import MemoryManager

mgr = MemoryManager()
mgr.add_provider(my_provider)
mgr.initialize_all(session_id="test-1", platform="cli")

# Test tool routing
result = mgr.handle_tool_call("my_tool", {"action": "add", "content": "test"})

# Test lifecycle
mgr.sync_all("user msg", "assistant msg")
mgr.on_session_end([])
mgr.shutdown_all()

Adding CLI Commands

أوامر تكتبها في الطرفية. افهم ما يفعله الأمر قبل نسخه. الأوامر هنا: hermes my-provider config، hermes my-provider status.

Memory provider plugins can register their own CLI subcommand tree (e.g. hermes my-provider status, hermes my-provider config). This uses a convention-based discovery system — no changes to core files needed.

How it works

  1. Add a cli.py file to your plugin directory
  2. Define a register_cli(subparser) function that builds the argparse tree
  3. The memory plugin system discovers it at startup via discover_plugin_cli_commands()
  4. Your commands appear under hermes <provider-name> <subcommand>

Active-provider gating: Your CLI commands only appear when your provider is the active memory.provider in config. If a user hasn't configured your provider, your commands won't show in hermes --help.

Example

Python21 سطرًا
# plugins/memory/my-provider/cli.py

def my_command(args):
    """Handler dispatched by argparse."""
    sub = getattr(args, "my_command", None)
    if sub == "status":
        print("Provider is active and connected.")
    elif sub == "config":
        print("Showing config...")
    else:
        print("Usage: hermes my-provider <status|config>")

def register_cli(subparser) -> None:
    """Build the hermes my-provider argparse tree.

    Called by discover_plugin_cli_commands() at argparse setup time.
    """
    subs = subparser.add_subparsers(dest="my_command")
    subs.add_parser("status", help="Show provider status")
    subs.add_parser("config", help="Show provider config")
    subparser.set_defaults(func=my_command)

Reference implementation

See plugins/memory/honcho/cli.py for a full example with 13 subcommands, cross-profile management (--target-profile), and config read/write.

Directory structure with CLI

Text5 أسطر
plugins/memory/my-provider/
├── __init__.py      # MemoryProvider implementation + register()
├── plugin.yaml      # Metadata
├── cli.py           # register_cli(subparser) — CLI commands
└── README.md        # Setup instructions

Single Provider Rule

شرح للفكرة نفسها. اقرأه ببطء، فبقية الأقسام تبني عليه.

Only one external memory provider can be active at a time. If a user tries to register a second, the MemoryManager rejects it with a warning. This prevents tool schema bloat and conflicting backends.

اختبار الفهم

4 أسئلة إجاباتها كلها في هذه الصفحة.

كل خيار اسم حقيقي من توثيق Hermes. حتى الخيارات الخاطئة حقيقية، لكنها من صفحات أخرى.

1. في جدول هذا الدرس، ما «Location» المقابل لـ«Project»؟
2. أي متغير بيئة من التالي يظهر فعليًا في هذا الدرس؟
3. أي عنوان من التالي لا يظهر في هذا الدرس؟
4. أي مفتاح إعداد يظهر في أمثلة هذا الدرس؟