From ef04de3e9851c1349e1a295eb3056557ab9e49e6 Mon Sep 17 00:00:00 2001 From: Teknium Date: Tue, 14 Apr 2026 21:03:34 -0700 Subject: [PATCH] docs: update tool-adding instructions for auto-discovery MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - AGENTS.md: 3 files → 2 files, remove _discover_tools() step - adding-tools.md: remove Step 3, note auto-discovery - architecture.md: update discovery description - tools-runtime.md: replace manual list with discover_builtin_tools() docs - hermes-agent skill: remove manual import step --- AGENTS.md | 8 ++-- .../hermes-agent/SKILL.md | 4 +- website/docs/developer-guide/adding-tools.md | 19 +++------- website/docs/developer-guide/architecture.md | 2 +- website/docs/developer-guide/tools-runtime.md | 38 ++++++------------- 5 files changed, 24 insertions(+), 47 deletions(-) diff --git a/AGENTS.md b/AGENTS.md index e4b998f5e..c5757cc52 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -13,7 +13,7 @@ source venv/bin/activate # ALWAYS activate before running Python ``` hermes-agent/ ├── run_agent.py # AIAgent class — core conversation loop -├── model_tools.py # Tool orchestration, _discover_tools(), handle_function_call() +├── model_tools.py # Tool orchestration, discover_builtin_tools(), handle_function_call() ├── toolsets.py # Toolset definitions, _HERMES_CORE_TOOLS list ├── cli.py # HermesCLI class — interactive CLI orchestrator ├── hermes_state.py # SessionDB — SQLite session store (FTS5 search) @@ -181,7 +181,7 @@ if canonical == "mycommand": ## Adding New Tools -Requires changes in **3 files**: +Requires changes in **2 files**: **1. Create `tools/your_tool.py`:** ```python @@ -204,9 +204,9 @@ registry.register( ) ``` -**2. Add import** in `model_tools.py` `_discover_tools()` list. +**2. Add to `toolsets.py`** — either `_HERMES_CORE_TOOLS` (all platforms) or a new toolset. -**3. Add to `toolsets.py`** — either `_HERMES_CORE_TOOLS` (all platforms) or a new toolset. +Auto-discovery: any `tools/*.py` file with a top-level `registry.register()` call is imported automatically — no manual import list to maintain. The registry handles schema collection, dispatch, availability checking, and error wrapping. All handlers MUST return a JSON string. diff --git a/skills/autonomous-ai-agents/hermes-agent/SKILL.md b/skills/autonomous-ai-agents/hermes-agent/SKILL.md index 9e0b412f5..77e1b1d18 100644 --- a/skills/autonomous-ai-agents/hermes-agent/SKILL.md +++ b/skills/autonomous-ai-agents/hermes-agent/SKILL.md @@ -650,9 +650,9 @@ registry.register( ) ``` -**2. Add import** in `model_tools.py` → `_discover_tools()` list. +**2. Add to `toolsets.py`** → `_HERMES_CORE_TOOLS` list. -**3. Add to `toolsets.py`** → `_HERMES_CORE_TOOLS` list. +Auto-discovery: any `tools/*.py` file with a top-level `registry.register()` call is imported automatically — no manual list needed. All handlers must return JSON strings. Use `get_hermes_home()` for paths, never hardcode `~/.hermes`. diff --git a/website/docs/developer-guide/adding-tools.md b/website/docs/developer-guide/adding-tools.md index 76f8477e3..497202bfc 100644 --- a/website/docs/developer-guide/adding-tools.md +++ b/website/docs/developer-guide/adding-tools.md @@ -14,11 +14,12 @@ Make it a **Tool** when it requires end-to-end integration with API keys, custom ## Overview -Adding a tool touches **3 files**: +Adding a tool touches **2 files**: 1. **`tools/your_tool.py`** — handler, schema, check function, `registry.register()` call 2. **`toolsets.py`** — add tool name to `_HERMES_CORE_TOOLS` (or a specific toolset) -3. **`model_tools.py`** — add `"tools.your_tool"` to the `_discover_tools()` list + +Any `tools/*.py` file with a top-level `registry.register()` call is auto-discovered at startup — no manual import list required. ## Step 1: Create the Tool File @@ -124,19 +125,9 @@ _HERMES_CORE_TOOLS = [ }, ``` -## Step 3: Add Discovery Import +## ~~Step 3: Add Discovery Import~~ (No longer needed) -In `model_tools.py`, add the module to the `_discover_tools()` list: - -```python -def _discover_tools(): - _modules = [ - ... - "tools.weather_tool", # <-- add here - ] -``` - -This import triggers the `registry.register()` call at the bottom of your tool file. +Tool modules with a top-level `registry.register()` call are auto-discovered by `discover_builtin_tools()` in `tools/registry.py`. No manual import list to maintain — just create your file in `tools/` and it's picked up at startup. ## Async Handlers diff --git a/website/docs/developer-guide/architecture.md b/website/docs/developer-guide/architecture.md index eec24815b..5b881c7e2 100644 --- a/website/docs/developer-guide/architecture.md +++ b/website/docs/developer-guide/architecture.md @@ -275,4 +275,4 @@ model_tools.py (imports tools/registry + triggers tool discovery) run_agent.py, cli.py, batch_runner.py, environments/ ``` -This chain means tool registration happens at import time, before any agent instance is created. Adding a new tool requires an import in `model_tools.py`'s `_discover_tools()` list. +This chain means tool registration happens at import time, before any agent instance is created. Any `tools/*.py` file with a top-level `registry.register()` call is auto-discovered — no manual import list needed. diff --git a/website/docs/developer-guide/tools-runtime.md b/website/docs/developer-guide/tools-runtime.md index 8e349a505..851ad6bc9 100644 --- a/website/docs/developer-guide/tools-runtime.md +++ b/website/docs/developer-guide/tools-runtime.md @@ -42,37 +42,23 @@ registry.register( Each call creates a `ToolEntry` stored in the singleton `ToolRegistry._tools` dict keyed by tool name. If a name collision occurs across toolsets, a warning is logged and the later registration wins. -### Discovery: `_discover_tools()` +### Discovery: `discover_builtin_tools()` -When `model_tools.py` is imported, it calls `_discover_tools()` which imports every tool module in order: +When `model_tools.py` is imported, it calls `discover_builtin_tools()` from `tools/registry.py`. This function scans every `tools/*.py` file using AST parsing to find modules that contain top-level `registry.register()` calls, then imports them: ```python -_modules = [ - "tools.web_tools", - "tools.terminal_tool", - "tools.file_tools", - "tools.vision_tools", - "tools.mixture_of_agents_tool", - "tools.image_generation_tool", - "tools.skills_tool", - "tools.skill_manager_tool", - "tools.browser_tool", - "tools.cronjob_tools", - "tools.rl_training_tool", - "tools.tts_tool", - "tools.todo_tool", - "tools.memory_tool", - "tools.session_search_tool", - "tools.clarify_tool", - "tools.code_execution_tool", - "tools.delegate_tool", - "tools.process_registry", - "tools.send_message_tool", - # "tools.honcho_tools", # Removed — Honcho is now a memory provider plugin - "tools.homeassistant_tool", -] +# tools/registry.py (simplified) +def discover_builtin_tools(tools_dir=None): + tools_path = Path(tools_dir) if tools_dir else Path(__file__).parent + for path in sorted(tools_path.glob("*.py")): + if path.name in {"__init__.py", "registry.py", "mcp_tool.py"}: + continue + if _module_registers_tools(path): # AST check for top-level registry.register() + importlib.import_module(f"tools.{path.stem}") ``` +This auto-discovery means new tool files are picked up automatically — no manual list to maintain. The AST check only matches top-level `registry.register()` calls (not calls inside functions), so helper modules in `tools/` are not imported. + Each import triggers the module's `registry.register()` calls. Errors in optional tools (e.g., missing `fal_client` for image generation) are caught and logged — they don't prevent other tools from loading. After core tool discovery, MCP tools and plugin tools are also discovered: