Files
metabuilder/workflow/executor/python/tool_runner.py
johndoe6345789 3d6ae4cbf7 feat: Add complete Python workflow executor from AutoMetabuilder
Add full Python workflow execution engine with:

Core Executor:
- engine.py: WorkflowEngine for running n8n configs
- n8n_executor.py: N8N-style workflow execution with connections
- node_executor.py: Individual node execution with plugin dispatch
- loop_executor.py: Loop node execution with iteration control
- execution_order.py: Topological sort for node ordering

Schema & Validation:
- n8n_schema.py: N8N workflow schema types and validation
- n8n_converter.py: Legacy to n8n schema conversion

Plugin System:
- plugin_loader.py: Dynamic plugin loading
- plugin_registry.py: Plugin discovery and registration
- plugin_map.json: 116 plugin type mappings

Runtime & Context:
- runtime.py: Workflow runtime container
- input_resolver.py: Binding and coercion resolution
- value_helpers.py: Value normalization helpers
- workflow_context_builder.py: Runtime context assembly
- workflow_config_loader.py: Configuration loading
- workflow_engine_builder.py: Engine assembly with dependencies

Utilities:
- tool_calls_handler.py: LLM tool call handling
- tool_runner.py: Tool execution with logging
- notification_helpers.py: Slack/Discord notifications
- workflow_adapter.py: N8N format handling
- workflow_graph.py: Node/edge graph for visualization

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-21 16:42:30 +00:00

30 lines
1.0 KiB
Python

"""Run tools with logging and filtering."""
class ToolRunner:
"""Run tool callables with shared logging."""
def __init__(self, tool_map: dict, msgs: dict, logger):
self.tool_map = tool_map
self.msgs = msgs
self.logger = logger
def call(self, tool_name: str, **kwargs):
"""Call a named tool with filtered kwargs."""
tool = self.tool_map.get(tool_name)
if not tool:
msg = self.msgs.get(
"error_tool_not_found",
"Tool {name} not found or unavailable."
).format(name=tool_name)
self.logger.error(msg)
return msg
filtered_kwargs = {k: v for k, v in kwargs.items() if v is not None}
try:
result = tool(**filtered_kwargs)
return result if result is not None else "Success"
except Exception as error: # pylint: disable=broad-exception-caught
error_msg = f"Error executing {tool_name}: {error}"
self.logger.error(error_msg)
return error_msg