Spaces:
Paused
Paused
File size: 3,359 Bytes
0d3f7cc | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 | """Tool executor for agent actions."""
from __future__ import annotations
import logging
import time
from typing import Any
from hermes.core.exceptions import ToolError, ToolNotFoundError
from hermes.core.types import ToolCall, ToolResult
from hermes.tools.base.registry import tool_registry
logger = logging.getLogger(__name__)
class ToolExecutor:
"""Executes tool calls with error handling and retries."""
def __init__(self, allowed_tools: list[str] | None = None) -> None:
self.allowed_tools = allowed_tools
async def execute(self, tool_call: ToolCall) -> ToolResult:
"""Execute a tool call and return the result."""
start_time = time.monotonic()
try:
tool = tool_registry.get(tool_call.tool_name)
if tool is None:
raise ToolNotFoundError(tool_call.tool_name)
if self.allowed_tools and tool_call.tool_name not in self.allowed_tools:
raise ToolError(
f"Tool '{tool_call.tool_name}' not in allowed tools",
{"allowed": self.allowed_tools},
)
output = await tool.execute(**tool_call.arguments)
execution_time = (time.monotonic() - start_time) * 1000
from hermes.observability.metrics import metrics as m
m.record_tool_call(tool_call.tool_name, True, execution_time)
return ToolResult(
tool_call_id=tool_call.id,
tool_name=tool_call.tool_name,
success=True,
output=output,
execution_time_ms=execution_time,
)
except (ToolNotFoundError, ToolError) as e:
execution_time = (time.monotonic() - start_time) * 1000
logger.error(f"Tool error: {e}")
from hermes.observability.metrics import metrics as m
m.record_tool_call(tool_call.tool_name, False, execution_time)
return ToolResult(
tool_call_id=tool_call.id,
tool_name=tool_call.tool_name,
success=False,
error=str(e),
execution_time_ms=execution_time,
)
except TimeoutError:
execution_time = (time.monotonic() - start_time) * 1000
return ToolResult(
tool_call_id=tool_call.id,
tool_name=tool_call.tool_name,
success=False,
error=f"Tool '{tool_call.tool_name}' timed out",
execution_time_ms=execution_time,
)
except Exception as e:
execution_time = (time.monotonic() - start_time) * 1000
logger.exception(f"Unexpected error executing tool: {e}")
return ToolResult(
tool_call_id=tool_call.id,
tool_name=tool_call.tool_name,
success=False,
error=f"Unexpected error: {str(e)}",
execution_time_ms=execution_time,
)
async def execute_raw(self, tool_name: str, arguments: dict[str, Any]) -> ToolResult:
"""Execute a tool by name with arguments."""
tool_call = ToolCall(tool_name=tool_name, arguments=arguments)
return await self.execute(tool_call)
|