Chapter 18

Tool Call Protocol and the 40+ Built-in Tool Ecosystem

Chapter 18: Tool Calling Protocol and the 40+ Built-in Tool Ecosystem

One of Hermes Agent's core competitive advantages is its out-of-the-box suite of 40+ built-in tools. These tools cover the full spectrum from web access and file operations to code execution and multimedia processing — the "hands and feet" through which an Agent perceives and changes the world. This chapter provides a comprehensive overview of the tool classification system, the JSON calling protocol, custom registration methods, and permission control mechanisms.


18.1 Tool Classification System

Hermes built-in tools are organized into six functional domains:

Hermes Tool Ecosystem
├── System Tools         — terminal, processes, environment variables
├── Network Tools        — search, HTTP, scraping
├── File Tools           — read/write, directories, compression
├── Code Tools           — execution, debugging, analysis
├── Multimedia Tools     — images, audio, video, PDF
└── Platform Tools       — Git, Docker, databases, APIs

Complete Tool Reference

System Tools (8)

Tool Name Description Typical Use Cases
terminal Execute shell commands Run scripts, install packages
process_manager Manage background processes Start/stop services
env_manager Read/write environment variables Configuration management
cron_scheduler Schedule periodic tasks Background automation
system_info Get system metrics CPU/memory/disk monitoring
clipboard Read/write clipboard Content passing between tools
notification Send system notifications Task completion alerts
sleep Wait for specified duration Polling interval control

Network Tools (9)

Tool Name Description Typical Use Cases
web_search Multi-engine web search Information retrieval
browser_navigate Browser navigation (Playwright) Dynamic page access
browser_click Click page elements Form filling, interactions
browser_screenshot Capture webpage screenshots Visual verification
http_request Send HTTP requests API calls
rss_reader Read RSS feeds News aggregation
html_extract Extract webpage content Data scraping
link_checker Check link availability Dead link detection
dns_lookup DNS resolution Network diagnostics

File Tools (7)

Tool Name Description Typical Use Cases
file_read Read file contents Code analysis, config reading
file_write Write to files Generate reports, save results
file_search Fuzzy file search Locate code files
directory_list List directory contents Project structure exploration
file_compress Compress/decompress files Packaging and distribution
file_diff Compare file differences Code review
file_watch Monitor file changes Hot-reload triggers

Code Tools (6)

Tool Name Description Typical Use Cases
code_execute Execute code snippets Python/JS sandbox execution
code_lint Static code analysis Style checking
code_format Format code black/prettier
code_test Run test suites pytest/jest
code_debug Debug code Breakpoint tracing
repl Interactive REPL session Experimental code testing

Multimedia Tools (6)

Tool Name Description Typical Use Cases
image_analyze Visual image analysis OCR, object recognition
image_generate Generate images DALL-E/Stable Diffusion
image_edit Edit images Crop, filters
audio_transcribe Speech-to-text (Whisper) Meeting transcription
pdf_extract Extract PDF content Document analysis
chart_generate Generate charts (Mermaid/matplotlib) Data visualization

Platform Tools (8)

Tool Name Description Typical Use Cases
git_operations Git version control Commits, branches, merges
docker_manage Docker container management Deploy, test environments
database_query Database queries (SQL/NoSQL) Data analysis
api_call Call external APIs Third-party service integration
email_send Send emails Automated notifications
calendar_manage Calendar management Meeting scheduling
spreadsheet Spreadsheet operations (Excel/CSV) Data processing
cloud_storage Cloud storage (S3/OSS) File upload/download

18.2 Tool Calling JSON Protocol

Hermes uses a strictly defined JSON protocol for tool calls, consisting of "call request" and "call response" objects.

18.2.1 Tool Call Request Format

{
  "tool_calls": [
    {
      "id": "call_abc123",
      "type": "function",
      "function": {
        "name": "web_search",
        "arguments": {
          "query": "Hermes Agent latest version features",
          "max_results": 10,
          "search_engine": "google",
          "date_range": "past_month",
          "safe_search": true
        }
      }
    }
  ]
}

18.2.2 Tool Call Response Format

{
  "tool_results": [
    {
      "tool_call_id": "call_abc123",
      "role": "tool",
      "name": "web_search",
      "content": {
        "status": "success",
        "results": [
          {
            "title": "Hermes 4: NousResearch's Latest Agent Model",
            "url": "https://nousresearch.com/hermes-4",
            "snippet": "Hermes 4 introduces improved function calling...",
            "score": 0.95
          }
        ],
        "total_results": 847000,
        "query_time_ms": 342
      }
    }
  ]
}

18.2.3 Complete Multi-Tool Call Sequence

// Step 1: Agent decision, initiating tool call
{
  "role": "assistant",
  "content": null,
  "tool_calls": [
    {
      "id": "call_001",
      "type": "function",
      "function": {
        "name": "web_search",
        "arguments": {
          "query": "Python asyncio best practices 2024",
          "max_results": 5
        }
      }
    }
  ]
}

// Step 2: Tool execution result returned
{
  "role": "tool",
  "tool_call_id": "call_001",
  "content": "Found 5 results: [...]"
}

// Step 3: Agent decides to call second tool based on results
{
  "role": "assistant",
  "content": null,
  "tool_calls": [
    {
      "id": "call_002",
      "type": "function",
      "function": {
        "name": "file_write",
        "arguments": {
          "path": "/output/asyncio_summary.md",
          "content": "# Python AsyncIO Best Practices\n\n..."
        }
      }
    }
  ]
}

// Step 4: Second tool result
{
  "role": "tool",
  "tool_call_id": "call_002",
  "content": "{\"success\": true, \"path\": \"/output/asyncio_summary.md\"}"
}

// Step 5: Agent final reply to user
{
  "role": "assistant",
  "content": "I've completed the research and saved the results to /output/asyncio_summary.md..."
}

18.2.4 Tool Schema Definition

Each tool's parameter structure follows JSON Schema Draft 7:

{
  "name": "http_request",
  "description": "Send an HTTP request and return the response content",
  "parameters": {
    "type": "object",
    "properties": {
      "url": {
        "type": "string",
        "description": "Target URL, must begin with http:// or https://",
        "format": "uri"
      },
      "method": {
        "type": "string",
        "enum": ["GET", "POST", "PUT", "DELETE", "PATCH", "HEAD"],
        "default": "GET"
      },
      "headers": {
        "type": "object",
        "additionalProperties": {"type": "string"}
      },
      "body": {
        "type": ["string", "object", "null"]
      },
      "timeout_seconds": {
        "type": "integer",
        "minimum": 1,
        "maximum": 300,
        "default": 30
      },
      "follow_redirects": {
        "type": "boolean",
        "default": true
      }
    },
    "required": ["url"]
  }
}

18.3 Custom Tool Registration

Beyond the 40+ built-in tools, Hermes supports three methods for registering custom tools.

Method 1: Python Decorator

The simplest approach, ideal for rapid prototyping:

from hermes.tools import tool, ToolResult

@tool(
    name="weather_query",
    description="Query current weather and forecast for a specified city",
    tags=["weather", "external-api"],
    timeout_seconds=15,
)
def get_weather(
    city: str,
    days: int = 3,
    unit: str = "celsius",
) -> ToolResult:
    import requests
    
    api_key = os.environ["WEATHER_API_KEY"]
    response = requests.get(
        "https://api.weatherapi.com/v1/forecast.json",
        params={"key": api_key, "q": city, "days": days},
        timeout=10,
    )
    
    data = response.json()
    return ToolResult(
        success=True,
        output={
            "city": data["location"]["name"],
            "current_temp": data["current"]["temp_c"],
            "condition": data["current"]["condition"]["text"],
            "forecast": [
                {
                    "date": day["date"],
                    "max": day["day"]["maxtemp_c"],
                    "min": day["day"]["mintemp_c"],
                }
                for day in data["forecast"]["forecastday"]
            ],
        }
    )

Method 2: YAML Configuration File

Suited for DevOps pipelines — no code changes required:

# tools/custom_tools.yaml
tools:
  - name: jira_create_ticket
    description: "Create a ticket in Jira"
    type: http_wrapper
    endpoint: "https://your-org.atlassian.net/rest/api/3/issue"
    method: POST
    auth:
      type: basic
      username_env: JIRA_USER
      password_env: JIRA_API_TOKEN
    parameters:
      - name: summary
        type: string
        required: true
      - name: priority
        type: string
        enum: [Highest, High, Medium, Low, Lowest]
        default: Medium
      - name: project_key
        type: string
        required: true
    tags: [jira, project-management]
    timeout_seconds: 30
hermes tool register --config ./tools/custom_tools.yaml

Method 3: Inheriting BaseTool

For complex tools requiring full lifecycle control:

from hermes.tools import BaseTool, ToolResult, ToolContext

class DatabaseQueryTool(BaseTool):
    name = "database_query_advanced"
    description = "Execute SQL or NoSQL queries against PostgreSQL/MySQL/MongoDB"
    
    async def setup(self):
        self.connection_pool = {}
    
    async def run(self, params: dict, context: ToolContext) -> ToolResult:
        dialect = params.get("dialect", "postgresql")
        conn = await self._get_connection(params["connection_string"], dialect)
        
        try:
            result = await self._execute_query(conn, params["query"], dialect)
            return ToolResult(
                success=True,
                output={
                    "rows": result.rows,
                    "row_count": len(result.rows),
                    "columns": result.columns,
                    "query_time_ms": result.execution_time_ms,
                }
            )
        except Exception as e:
            return ToolResult(success=False, error=str(e))
    
    async def teardown(self):
        for conn in self.connection_pool.values():
            await conn.close()

18.4 Tool Permission Control

Hermes implements a fine-grained tool permission system to prevent unauthorized operations.

Permission Hierarchy

Global Permissions
    └── Session Permissions
            └── Tool Permissions
                    └── Parameter-level Restrictions

Permission Configuration

# hermes_permissions.yaml
profiles:
  readonly_research:
    allow:
      - network:search
      - network:fetch
      - file:read
    deny:
      - file:write
      - file:delete
      - terminal:execute
  
  full_developer:
    allow: ["*"]
    deny:
      - env:write
    restrictions:
      file:write:
        allowed_paths: [/workspace/**, /tmp/**]
        denied_paths: [/workspace/.env, /workspace/secrets/**]
      terminal:execute:
        denied_commands: ["rm -rf /", ":(){ :|:& };:"]
  
  production_deploy:
    allow: [git:read, docker:run, network:fetch]
    deny: [terminal:execute, file:delete]
    approval_required: [docker:run, database:write]

Runtime Permission Check

class PermissionChecker:
    def check(self, tool_name: str, params: dict, context: AgentContext) -> PermissionResult:
        required = self._get_tool_permissions(tool_name)
        
        for perm in required:
            if perm in context.permission_profile.denied:
                return PermissionResult(
                    allowed=False,
                    reason=f"Permission {perm} is denied in the current profile"
                )
        
        if tool_name == "file_write":
            path = params.get("path", "")
            if not self._is_path_allowed(path, context):
                return PermissionResult(
                    allowed=False,
                    reason=f"Path {path} is outside the allowed write scope"
                )
        
        return PermissionResult(allowed=True)

18.5 Summary

This chapter provided a comprehensive overview of the Hermes Agent tool ecosystem:

Review Questions

  1. When an Agent invokes multiple tools simultaneously (parallel tool calling), how do you ensure the result ordering correctly maps back to each tool_call_id?

  2. The file_write tool uses glob pattern matching for path restrictions. If a user requests writing to /workspace/../etc/passwd, how is the path traversal attack defended against?

  3. Custom YAML-configured tools can be hot-loaded without restarting Hermes. During a hot-reload, how are in-flight tool calls protected from interruption?

Rate this chapter
4.7  / 5  (17 ratings)

💬 Comments