Hermes-Agent is an agent harness for LLMs. ## Project Structure - `tools/` - Individual tool implementations (web, terminal, browser, vision, etc.) - `tools/__init__.py` - Exports all tools for importing - `model_tools.py` - Consolidates tool schemas and handlers for the agent - `toolsets.py` - Groups tools into logical toolsets (web, terminal, browser, etc.) - `toolset_distributions.py` - Probability-based tool selection for data generation - `run_agent.py` - Primary agent runner with AIAgent class - `batch_runner.py` - Parallel batch processing with checkpointing - `tests/` - Test scripts ## File Dependency Chain ``` tools/*.py → tools/__init__.py → model_tools.py → toolsets.py → toolset_distributions.py ↑ run_agent.py ──────────────────────────┘ batch_runner.py → run_agent.py + toolset_distributions.py ``` Always ensure consistency between tools, model_tools.py, and toolsets.py when changing any of them. ## Adding a New Tool Follow this strict order to maintain consistency: 1. Create `tools/your_tool.py` with: - Handler function (sync or async) returning a JSON string via `json.dumps()` - `check_*_requirements()` function to verify dependencies (e.g., API keys) - Schema definition following OpenAI function-calling format 2. Export in `tools/__init__.py`: - Import the handler and check function - Add to `__all__` list 3. Register in `model_tools.py`: - Create `get_*_tool_definitions()` function or add to existing - Add routing in `handle_function_call()` dispatcher - Update `get_all_tool_names()` with the tool name - Update `get_toolset_for_tool()` mapping - Update `get_available_toolsets()` and `check_toolset_requirements()` 4. Add to toolset in `toolsets.py`: - Add to existing toolset or create new one in TOOLSETS dict 5. Optionally add to `toolset_distributions.py` for batch processing ## Tool Implementation Pattern ```python # tools/example_tool.py import json import os def check_example_requirements() -> bool: """Check if required API keys/dependencies are available.""" return bool(os.getenv("EXAMPLE_API_KEY")) def example_tool(param: str, task_id: str = None) -> str: """Execute the tool and return JSON string result.""" try: result = {"success": True, "data": "..."} return json.dumps(result, ensure_ascii=False) except Exception as e: return json.dumps({"error": str(e)}, ensure_ascii=False) ``` All tool handlers MUST return a JSON string. Never return raw dicts. ## Stateful Tools Tools that maintain state (terminal, browser) require: - `task_id` parameter for session isolation between concurrent tasks - `cleanup_*()` function to release resources - Cleanup is called automatically in run_agent.py after conversation completes ## Environment Variables API keys are loaded from `.env` file in repo root: - `OPENROUTER_API_KEY` - Main LLM API access (primary provider) - `FIRECRAWL_API_KEY` - Web search/extract tools - `BROWSERBASE_API_KEY` / `BROWSERBASE_PROJECT_ID` - Browser automation - `FAL_KEY` - Image generation (FLUX model) - `NOUS_API_KEY` - Vision and Mixture-of-Agents tools ## Agent Loop (run_agent.py) The AIAgent class handles: - Processing enabled toolsets to provide to the model - Piping prompts to the agent - Looping LLM calls when tools are invoked, until natural language response - Returning the final response Uses OpenAI-compatible API (primarily OpenRouter) with the OpenAI Python SDK. ## Reasoning Model Support For models that support chain-of-thought reasoning: - Extract `reasoning_content` from API responses - Store in `assistant_msg["reasoning"]` for trajectory export - Pass back via `reasoning_content` field on subsequent turns ## Trajectory Format Conversations are saved in ShareGPT format for training: ```json {"from": "system", "value": "System prompt with ..."} {"from": "human", "value": "User message"} {"from": "gpt", "value": "reasoning\n{...}"} {"from": "tool", "value": "{...}"} {"from": "gpt", "value": "Final response"} ``` Tool calls use `` XML tags, responses use `` tags, reasoning uses `` tags. ## Batch Processing (batch_runner.py) For processing multiple prompts: - Parallel execution with multiprocessing - Content-based resume for fault tolerance (matches on prompt text, not indices) - Toolset distributions control probabilistic tool availability per prompt - Output: `data//trajectories.jsonl` (combined) + individual batch files ## Logging Trajectories restructure tools as a system prompt for storage in a format suitable for later training use.