Files
kage-research/hermes-tool-guide.md
2026-04-09 00:39:52 +00:00

6.4 KiB

Hermes Tool Implementation Guide

Overview

This document explains how to create a Hermes tool that integrates with external services (like Pi agent).


What is a Hermes Tool?

A Hermes tool is a Python function that:

  1. Hermes calls when the agent decides to use it
  2. Receives parameters from the LLM
  3. Does work (calls external services, runs commands, etc.)
  4. Returns a string that Hermes shows to the agent

Tool Structure

Every Hermes tool needs:

def my_tool(param1: str, param2: Optional[int] = None) -> str:
    """
    Tool description that LLM sees.
    
    Args:
        param1: Description
        param2: Description
    
    Returns:
        What the tool returns
    """
    # Do work here
    return "result"

def check_my_tool_requirements() -> bool:
    """Check if tool can be used (e.g., external service available)."""
    return True

# Schema for LLM
MY_TOOL_SCHEMA = {
    "name": "my_tool",
    "description": "What the tool does",
    "parameters": {
        "type": "object",
        "properties": {
            "param1": {"type": "string", "description": "..."},
        },
        "required": ["param1"]
    }
}

# Register
registry.register(
    name="my_tool",
    toolset="my_toolset",  # Group in Hermes config
    schema=MY_TOOL_SCHEMA,
    handler=lambda args, **kw: my_tool(**args),
    check_fn=check_my_tool_requirements,
    emoji="📦",
)

Key Components

1. Function Handler

def my_tool(param1: str, ...) -> str:
    # Work
    return "result as string"

2. Requirements Check

def check_my_tool_requirements() -> bool:
    # Check external service, API key, etc.
    return True  # or False if not available

3. Schema (JSON)

MY_TOOL_SCHEMA = {
    "name": "tool_name",
    "description": "What it does (LLM reads this!)",
    "parameters": {
        "type": "object",
        "properties": {
            "param1": {"type": "string", "description": "..."},
        },
        "required": ["param1"]
    }
}

4. Registry

registry.register(
    name="tool_name",
    toolset="toolset_name",  # Enable in config
    schema=SCHEMA,
    handler=lambda args, **kw: my_tool(**args),
    check_fn=check_requirements,
    emoji="📦",
)

Example: Pi Agent Tool

See pi_agent_tool.py for a working example.

Flow

User: "Fix the bug in auth.py"
  ↓
Hermes Agent decides to use pi_agent tool
  ↓
Calls pi_agent_tool(message="Fix the bug...")
  ↓
Tool calls HTTP server (Level 4)
  ↓
HTTP server runs Pi agent
  ↓
Returns response to Hermes
  ↓
Hermes shows to user

How to Use

1. Start Pi Server (Level 4)

npx tsx level4.ts

2. Add Tool to Hermes

Option A: Copy to Hermes tools

cp pi_agent_tool.py ~/.hermes/hermes-agent/tools/

Option B: Add to Python path or custom tools directory

3. Enable in Hermes Config

# In config.yaml
toolset:
  - pi_agent

4. Use in Conversation

User: Can you fix the bug in auth.py?

Hermes: *uses pi_agent tool*

Tool result: Fixed the bug by changing line 42...

Tool Best Practices

1. Always Return a String

# Good
return "Result: found 5 files"

# Bad  
return {"result": "found 5"}  # JSON must be stringified

2. Handle Errors Gracefully

try:
    # Do work
    return result
except Exception as e:
    return f"Error: {str(e)}"

3. Add Requirements Check

def check_requirements() -> bool:
    # Check API keys, services, etc.
    return api_key is not None

4. Write Clear Descriptions

# Good - LLM knows when to use
"""
Analyze the codebase for security vulnerabilities.
Use after finding potential issues.
"""

# Bad - LLM confused
"""Do something"""

5. Keep Schema Simple

  • Only include needed parameters
  • Mark required parameters
  • Add descriptions for each parameter

Testing

1. Test the Function Directly

# In Python
result = pi_agent_tool(message="Say hello")
print(result)

2. Test with curl

curl -X POST http://localhost:3000/message \
  -d '{"message": "Hello"}'

3. Test with Hermes

  • Add to toolset
  • Ask Hermes to use the tool

Troubleshooting

Tool Not Found

  • Check tool is in ~/.hermes/hermes-agent/tools/
  • Check it's in the toolset config

Tool Not Available

  • Check check_*_requirements() returns True
  • Check external service is running

Tool Called but No Response

  • Check tool returns a string
  • Check for exceptions in handler

Integration Options: HTTP vs Direct Spawn

There are two ways to integrate Pi agent with Hermes:

Option 1: HTTP Server (Current Implementation)

Hermes → Python Tool → HTTP Request → Node/TS Server → Pi Agent
# In tool
import requests
response = requests.post("http://localhost:3000/message", json={"message": "..."})
return response.json()["response"]

Pros:

  • Easy to test/debug (curl, logs)
  • Stateful (agent stays alive between calls)
  • Reuses connections
  • Easier monitoring/rate-limiting

Cons:

  • More complex (two services)
  • HTTP overhead (~50ms per call)
  • Server must stay running

Option 2: Direct Spawn (Alternative)

Hermes → Python Tool → Spawn Process → Pi Wrapper
# In tool
import subprocess
process = subprocess.Popen(["npx", "tsx", "pi-wrapper.ts", message], 
                           stdout=subprocess.PIPE)
stdout, _ = process.communicate(timeout=300)
return stdout.decode()

Pros:

  • Simpler (one process per call)
  • No server to maintain
  • Matches Kugetsu's current pattern
  • Good for low traffic

Cons:

  • Slow startup (~100-500ms per call)
  • No state between calls
  • Harder to debug
  • Resource heavy under load

Comparison Table

Factor HTTP Server Direct Spawn
Latency ~50ms ~100-500ms
Memory Persistent (50-100MB) Per-call
State Yes No
Complexity Higher Lower
Debugging Network logs Process logs
Best For Production POC/Simple

Recommendation

  • High load / Production: HTTP Server
  • Low load / POC: Direct Spawn
  • Matches Kugetsu pattern: Direct Spawn

Files in This Project

File Description
pi_agent_tool.py Working Hermes tool (HTTP approach)
level4.ts HTTP server
hermes-tool-guide.md This document