Tool System Registration & JSON Parameter Self-Healing
🔌 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:
# 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 regexr',(\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 theWORKSPACE_DIRroot. - Hard Timeout Interrupt: When the agent calls the
terminaltool to run Shell scripts, the underlying layer enforces atimeoutthreshold. If the model launches blocking commands likeping google.comwithout a limit, the executor throwsTimeoutExpiredand forcibly kills the subprocess, freeing system resources.
🔗 Sub-topic Deep Dive Articles
For master-level understanding of the tool system and sanitization, explore these sub-pages:
- Tool Reflection Discovery & Signature Parameter Coercion (inspect.signature strong-type mapping)
- JSON Parameter Corruption Self-Healing & Surrogate Cleaning (regex self-healing JSON & unescaped interception)
- Tool Repeated-Call Circuit Breaker & Infinite Loop Intervention (tool_guardrails.py window interception)