Extensibility & Integrity

Tool System Registration & JSON Parameter Self-Healing

Comprehensive guide to tools/registry.py decorators, tool flow model & high-tolerance parameter parsing
Tool Execution and Parameter Sanitization
📊 Figure 3-1: Model Tool Call Dispatch & Damaged JSON Parameter Auto-Repair Flow

🔌 1. Unified Tool Discovery & Registration Mechanism

In Hermes, adding a custom tool for the LLM is extremely simple. The system implements a global registry manager in tools/registry.py, collecting parameters via decorator reflection:

💻 Hands-on: Writing a New Tool

Step 1, create a my_custom_tool.py script in the tools/ directory and attach the decorator following this template:

# tools/my_custom_tool.py
from tools.registry import registry

@registry.register(
    name="query_stock_price",
    description="Query the real-time stock price for a given ticker symbol.",
    schema={
        "type": "object",
        "properties": {
            "ticker": {"type": "string", "description": "The stock symbol, e.g. AAPL"},
            "limit": {"type": "integer", "description": "Max rows to return", "default": 10}
        },
        "required": ["ticker"]
    }
)
def query_stock_price(ticker: str, limit: int = 10) -> str:
    # Actual tool business logic
    return f"Real-time data for {ticker}: $185.20 (limited to {limit} records)"

Underlying Scan Mechanism: At startup, model_tools.py's discover_builtin_tools() uses Python's pkgutil.iter_modules() to traverse all .py files under the tools/ folder and execute importlib.import_module(). Since the decorator fires at module import time, the corresponding schema and function references are automatically poured into the global registry._tools hash table — no manual configuration required.

🛡️ 2. ToolExecutor Weak-Type Parameter Coercion & UML Topology

The LLM often outputs type-imprecise parameters (e.g., passing "100" as a string instead of integer 100). Passing these directly to strongly-typed Python business functions throws TypeError and breaks execution. Hermes embeds a ToolExecutor in agent/tool_executor.py, using Python's metaprogramming reflection to govern parameter types. The class structure design and input sanitization relationship is shown below:

Parameter Coercion and JSON Self-Healing UML
📊 Figure 3-2: ToolExecutor Reflection Coercion & JSON Self-Healing UML Static Structure
# ToolExecutor type self-healing logic
import inspect

def coerce_arguments(func, original_args: dict) -> dict:
    sig = inspect.signature(func)
    coerced = {}
    for param_name, param in sig.parameters.items():
        if param_name not in original_args:
            continue
        val = original_args[param_name]
        expected_type = param.annotation
        
        # 1. Boolean coercion
        if expected_type is bool and isinstance(val, str):
            coerced[param_name] = val.lower() in ("true", "1", "yes")
        # 2. Numeric coercion
        elif expected_type in (int, float) and isinstance(val, (str, float, int)):
            coerced[param_name] = expected_type(val)
        else:
            coerced[param_name] = val
    return coerced

Through this introspection coercion + ToolParameterCoercer mapping algorithm, tool execution robustness is drastically improved, shielding the agent from malformed model parameters.

🩹 3. Damaged JSON Regex Self-Healing & Unicode Cleaning

Under long contexts or high loads, LLM-generated JSON arguments are frequently damaged. Hermes integrates a high-performance self-healing algorithm in agent/message_sanitization.py:

⚙️ JSON Self-Healing Core: _repair_tool_call_arguments

If the LLM-generated JSON string is incomplete due to token truncation or network interruption (e.g., {"path": "/src", "recursive": true missing closing braces), regular json.loads() would crash. _repair_tool_call_arguments() uses heuristic algorithms to rescue:

  • Brace Completion: Detects unclosed {, [ via stack analysis and forcibly appends corresponding }, ] at the tail.
  • Trailing Comma Removal: Matches and removes extra commas like {"a": 1,} via regex r',(\s*[}\]])', ensuring strict JSON compliance.
  • Escape Self-Healing: For unescaped double quotes inside strings (e.g., "content": "He said "Hello" to me"), auto-scans and converts to \"Hello\".

🚫 Damaged Unicode Cleaning: _sanitize_surrogates

During streaming or irregular LLM tokenization, isolated UTF-16 surrogate characters (\ud800 to \udfff) may appear. Encoding these in Python triggers severe UnicodeEncodeError. This module filters invalid surrogate pairs through iterative cleaning, ensuring smooth database writes and log output:

# Clean invalid surrogate pair characters
def _sanitize_surrogates(text: str) -> str:
    # Forcibly replace orphaned Surrogate characters to prevent Python json encode crash
    return text.encode('utf-8', 'surrogateescape').decode('utf-8', 'ignore')

🚨 4. Tool Security Guardrails & Timeout Boundaries

In agent/tool_guardrails.py, Hermes enforces strict security lines to protect the host from model-induced OS damage:

  • Path Isolation: All file-modifying tools intercept .. upward traversal. All operations are restricted to the WORKSPACE_DIR root.
  • Hard Timeout Interrupt: When the agent calls the terminal tool to run Shell scripts, the underlying layer enforces a timeout threshold. If the model launches blocking commands like ping google.com without a limit, the executor throws TimeoutExpired and forcibly kills the subprocess, freeing system resources.