# `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.
