Source code for atloop.orchestrator.executor.tool_executor

"""Tool executor for executing tool calls."""

import logging
from typing import Any, Dict, List

from atloop.orchestrator.coordinator import WorkflowCoordinator
from atloop.orchestrator.executor.result_adapter import ResultAdapter

logger = logging.getLogger(__name__)


[docs] class ToolExecutor: """Tool executor for executing tool calls."""
[docs] def __init__(self, coordinator: WorkflowCoordinator): """ Initialize tool executor. Args: coordinator: Workflow coordinator instance """ self.coordinator = coordinator logger.debug("[ToolExecutor] Initialized")
[docs] def execute_actions(self, actions: List[Dict[str, Any]]) -> List[Dict[str, Any]]: """ Execute a list of actions. Args: actions: List of action dictionaries Returns: List of tool execution results """ logger.debug(f"[ToolExecutor] Executing {len(actions)} actions") results = [] for i, action in enumerate(actions): logger.debug( f"[ToolExecutor] Executing action {i + 1}/{len(actions)}: {action.get('tool')}" ) try: result = self._execute_action(action) results.append(result) logger.debug( f"[ToolExecutor] Action {i + 1} completed: success={result.get('success', False)}" ) except Exception as e: logger.error(f"[ToolExecutor] Action {i + 1} failed: {e}") logger.debug( f"[ToolExecutor] Exception details: {type(e).__name__}: {e}", exc_info=True, ) results.append( ResultAdapter._from_error( action.get("tool", "unknown"), action.get("args", {}), str(e), ) ) logger.debug(f"[ToolExecutor] All actions executed: {len(results)} results") return results
def _execute_action(self, action: Dict[str, Any]) -> Dict[str, Any]: """ Execute a single action. ToolRegistry.execute() returns ToolResult in all code paths (success, unknown tool, or invalid args). ResultAdapter handles conversion to unified format, with defensive support for legacy/alternate implementations. Args: action: Action dictionary with 'tool' and 'args' keys Returns: Dict with keys: success, tool, args, result, ok, stdout, stderr, error, exit_code (format expected by ActPhase and MemorySummarizer) """ tool_name = action.get("tool") args = action.get("args", {}) logger.debug(f"[ToolExecutor] Executing tool: {tool_name} with args: {list(args.keys())}") # ToolRegistry.execute() returns ToolResult (ok, stdout, stderr, meta) result = self.coordinator.tool_runtime.registry.execute(tool_name, args) logger.debug(f"[ToolExecutor] Tool execution completed: {tool_name}") # Convert to unified format using ResultAdapter return ResultAdapter.to_action_result(tool_name, args, result)