# `cleveragents.tool` — Tool System The `tool` package provides the four-stage tool lifecycle (activate → validate → execute → deactivate), the tool registry, call router, container executor, and the tool-calling actor runtime. See [ADR-011](../adr/ADR-011-tool-system.md) and [ADR-037](../adr/ADR-037-tool-reachability-and-access-projection.md) for design rationale. --- ## Core Types ### `ToolSpec` ```python class ToolSpec(BaseModel): name: str description: str input_schema: dict[str, Any] # JSON Schema output_schema: dict[str, Any] | None = None read_only: bool = False checkpointable: bool = True source: str = "builtin" # "builtin" | "mcp" | "lsp" | "skill" ``` Declarative specification for a tool. Used for registration and schema validation. ### `ToolResult` ```python class ToolResult(BaseModel): success: bool output: Any error: ToolError | None = None trace: ToolExecutionTrace | None = None ``` ### `ToolError` ```python class ToolError(BaseModel): code: str message: str details: dict[str, Any] = {} ``` --- ## Registry ### `ToolRegistry` ```python from cleveragents.tool import ToolRegistry registry = ToolRegistry() registry.register(tool_spec, executor_fn) spec = registry.get("bash") ``` Central registry for all tools. Supports namespace-qualified names and source tagging (`builtin`, `mcp`, `lsp`, `skill`). --- ## Lifecycle ### `ToolRuntime` Manages the four-stage lifecycle for a single tool invocation: 1. **Activate** — acquire resources, check permissions, apply safety profile 2. **Validate** — JSON Schema validation of inputs 3. **Execute** — call the tool executor 4. **Deactivate** — release resources, record trace ### `ToolLifecycleCache` Per-plan cache of activated tool instances to avoid redundant activation overhead. ### `ToolDescriptor` Rich descriptor combining `ToolSpec` with runtime metadata (activation state, cost estimate, sandbox requirements). ### `ToolInstance` A single activated instance of a tool, bound to a specific plan and execution context. --- ## Lifecycle Errors | Exception | Description | |-----------|-------------| | `ToolActivationError` | Tool failed to activate | | `ToolDeactivationError` | Tool failed to deactivate cleanly | | `ToolNotActivatedError` | Tool called before activation | | `ToolExecutionError` | Tool execution failed | | `ToolRuntimeError` | Internal runtime error | | `ToolAccessDeniedError` | Permission check failed | | `ToolSafetyViolationError` | Safety profile violation | | `ToolSandboxRequiredError` | Tool requires sandbox but none available | | `ToolCheckpointRequiredError` | Checkpoint required before execution | | `ToolHumanApprovalRequiredError` | Human approval gate triggered | | `ToolCostLimitExceededError` | Budget limit exceeded | | `ToolRetryLimitExceededError` | Max retries exhausted | | `ToolCancelledError` | Tool cancelled via `CancellationToken` | --- ## Execution Context ### `ToolExecutionContext` ```python class ToolExecutionContext: plan_id: str session_id: str actor_name: str bound_resources: list[BoundResource] cancellation_token: CancellationToken read_only: bool ``` ### `CancellationToken` ```python token = CancellationToken() token.cancel() # signal cancellation token.is_cancelled # check state ``` ### `ToolExecutionTrace` Immutable record of a tool execution: inputs, outputs, duration, sandbox used, cost incurred. --- ## Router ### `ToolCallRouter` Translates between provider-specific tool call formats (OpenAI, Anthropic, Google) and the internal `ToolCallRequest` format. ```python from cleveragents.tool import ToolCallRouter, detect_provider_format router = ToolCallRouter(registry) format = detect_provider_format(raw_response) request = normalize_tool_call(raw_call, format) result = await router.route(request, context) ``` ### `ProviderFormat` Enum: `OPENAI`, `ANTHROPIC`, `GOOGLE`, `UNKNOWN`. ### Helper Functions | Function | Description | |----------|-------------| | `detect_provider_format(response)` | Detect provider from response shape | | `normalize_tool_call(call, fmt)` | Normalize to `ToolCallRequest` | | `normalize_tool_schema_for_provider(spec, fmt)` | Adapt schema for provider | | `generate_tool_call_id()` | Generate a unique call ID | | `classify_tool_error(exc)` | Map exception to `ToolCallErrorCategory` | --- ## Container Executor ### `ContainerToolExecutor` Executes tools inside an isolated container (Docker/Podman). ```python from cleveragents.tool import ContainerToolExecutor, ContainerConfig config = ContainerConfig(image="python:3.12-slim", timeout=30) executor = ContainerToolExecutor(config) result = await executor.execute("bash", {"command": "echo hello"}) ``` ### `ContainerConfig` | Field | Type | Description | |-------|------|-------------| | `image` | `str` | Container image | | `timeout` | `int` | Execution timeout in seconds | | `memory_limit` | `str \| None` | Memory limit (e.g. `"512m"`) | | `network` | `str` | Network mode (`"none"`, `"bridge"`) | --- ## Schema Validation ### `validate_tool_input(spec, inputs) → None` Validates `inputs` against `spec.input_schema`. Raises `ToolSchemaValidationError` on failure. ### `validate_tool_output(spec, output) → None` Validates tool output against `spec.output_schema` (if defined). --- ## Tool-Calling Actor Runtime ### `ToolCallingRuntime` Drives the LLM ↔ tool call loop for execution actors. ```python from cleveragents.tool import ToolCallingRuntime runtime = ToolCallingRuntime(llm_caller, tool_registry) result: ToolCallRunResult = await runtime.run(messages, context) ``` ### `LLMCaller` Protocol for calling an LLM. Implement this to plug in a custom provider. ### `MaxIterationsExceededError` Raised when the tool-call loop exceeds the configured maximum iterations. --- ## Path Mapper ### `PathMapper` Maps host paths to container/sandbox paths and back. Used by the sandbox and MCP adapter for path rewriting.