# Tool Execution The core package provides a unified tool execution engine that runs actions, agents, workflows, and commands through a common `FeatureExecutor` interface. All feature types are treated as tools with a consistent execution contract. ## Execution Functions ### `executeAction(name, payload, options)` Executes an action by name, resolving it from the SQLite database and dispatching to the appropriate handler based on file extension: ```typescript import { executeAction } from "@agent-smith/core"; // Execute a YAML action (shell command) const result = await executeAction("read", ["./file.txt"], {}); // Execute with options const result2 = await executeAction("process", ["data.json"], { debug: true }); ``` The function: 1. Looks up the action by name using `getFeatureSpec()` 2. Dispatches based on extension: - **`.js`**: Dynamically imports the module and calls the exported `action` function via `createJsAction()` - **`.yml`**: Reads the YAML spec, extracts the `cmd` and `args`, and executes via `execute()` (child process spawn) - **`.py`**: Executes the script via `runPyScript()` using the `python-shell` package ### `executeWorkflow(name, args, options)` Executes a workflow as a sequence of steps. Each step can be an `agent`, `action`, `adaptater`, or `cmd`: ```typescript import { executeWorkflow } from "@agent-smith/core"; const result = await executeWorkflow("data-pipeline", ["input.csv"], { verbose: true, debug: false }); ``` The workflow engine: 1. Loads the workflow definition via `readWorkflow()` 2. Iterates through each step sequentially 3. Passes context between steps — the result of each step becomes input for the next 4. Accumulates results in a `taskRes` object that flows through the pipeline **Context passing pattern:** - First step receives raw command arguments (`cmdArgs`) - Subsequent steps receive the accumulated `taskRes` from previous steps - String/array results are stored as `taskRes.args` - Object results are spread into `taskRes` - The final step's result is returned ### `executeAgent(name, args, options)` Executes an agent by resolving its prompt and delegating to `useAgentExecutor()`: ```typescript import { executeAgent } from "@agent-smith/core"; import type { InferenceResult } from "@agent-smith/types"; const result: InferenceResult = await executeAgent("writer", ["AI trends"], { model: "llama3", temperature: 0.7 }); ``` ### `useAgentExecutor(name, payload, options)` Creates an agent execution context with MCP server initialization, backend resolution, and inference parameter application: ```typescript import { useAgentExecutor } from "@agent-smith/core"; const executor = await useAgentExecutor("researcher", { prompt: "Analyze the data" }, {}); const result = await executor.execute(); // Returns: InferenceResult ``` The executor function: 1. Reads the agent spec and resolves MCP servers 2. Determines the backend (options > agent settings > agent spec > default) 3. Creates an `Agent` instance from `@agent-smith/agent` 4. Applies agent-specific inference parameters (model, temperature, etc.) 5. Starts MCP servers and extracts their tools into the agent's tool list 6. Compiles grammar if `tsGrammar` is provided 7. Runs the agent with streaming enabled 8. Handles error cases (502, 404, 400, fetch failures, abort) ## Multi-Language Tool Support ### JavaScript ESM Actions JavaScript actions are dynamically imported using `pathToFileURL()` and Vite's dynamic import: ```typescript // actions/transform.js export async function action(args, options) { const [input] = args; return input.toUpperCase(); } ``` The `createJsAction()` wrapper catches errors and re-throws them with context: ```typescript import { createJsAction } from "@agent-smith/core/actions/read"; ``` ### Python Actions Python actions use the `python-shell` package. The script receives arguments as CLI parameters: ```typescript // Core dispatches to runPyScript() const result = await executeAction("analyze", ["data.csv"], {}); ``` The `runPyScript()` function: 1. Creates a `PythonShell` instance with the script path and arguments 2. Collects stdout messages into an array 3. Returns `{ data: string[], error?: Error }` ### YAML/Shell Actions YAML actions define a command and optional arguments in the YAML spec: ```yaml tool: name: grep description: Search for patterns arguments: pattern: description: Search pattern (string) args: ["grep", "-r"] ``` The `systemAction()` function extracts the command, appends runtime arguments, and executes via `spawn()`: ```typescript const result = await executeAction("grep", ["error"], {}); // Executes: grep -r error ``` ## Workflow Step Types | Type | Resolution | Execution | |------|-----------|-----------| | `agent` | `executeAgent()` | Runs LLM inference with tool calling | | `action` | `executeAction()` | Runs JS/Python/shell action | | `adaptater` | `executeAdaptater()` | Runs JS data adapter | | `cmd` | Dynamic import of `runCmd` | Runs Commander.js command | ## Error Handling Tool execution follows consistent error patterns: - **Feature not found**: Throws `Error(\`${type} ${name} not found at ${path}\`)` - **Action execution errors**: Wrapped with context: `executing js action:${e}. Args: ${JSON.stringify(args)}` - **Python errors**: Thrown as `Error(\`python error: ${error}\`)` - **Workflow step errors**: Wrapped with step number: `workflow task ${i + 1}: ${e}` - **Agent inference errors**: Handled for specific HTTP codes (502, 404, 400) and abort conditions ```typescript try { await executeAction("nonexistent", [], {}); } catch (e) { console.error(e.message); // "Action nonexistent not found at undefined" } ``` ## Tool Spec Extraction The `extractToolDoc()` function extracts tool specifications from feature files: ```typescript import { extractToolDoc } from "@agent-smith/core"; const { found, toolDoc } = extractToolDoc("read", "yml", "/path/to/actions"); // toolDoc: JSON string of the ToolSpec ``` For agents, `extractAgentToolDocAndVariables()` extracts both the tool spec and variable definitions: ```typescript import { extractAgentToolDocAndVariables } from "@agent-smith/core"; const { toolDoc, variables, type, category } = extractAgentToolDocAndVariables( "writer", "yml", "/path/to/agents" ); // variables: { required: string[], optional: string[] } ``` Next: MCP Client