e9c96c3d0c
CI / build (push) Successful in 17s
CI / lint (push) Failing after 19s
CI / helm (push) Successful in 34s
CI / security (push) Failing after 42s
CI / quality (push) Has been cancelled
CI / unit_tests (push) Has been cancelled
CI / e2e_tests (push) Has been cancelled
CI / integration_tests (push) Has been cancelled
CI / typecheck (push) Has been cancelled
CI / benchmark-publish (push) Has been cancelled
CI / coverage (push) Has been cancelled
CI / benchmark-regression (push) Has been cancelled
CI / docker (push) Has been cancelled
CI / status-check (push) Has been cancelled
Add docs/api/ with per-module API documentation for core, a2a, actor, skills, tool, mcp, resource, and config packages. Add docs/architecture.md with a developer-oriented system overview including component map, layer diagram, plan lifecycle, and key design decisions. Update mkdocs.yml nav to expose both new sections. ISSUES CLOSED: #N/A
245 lines
5.9 KiB
Markdown
245 lines
5.9 KiB
Markdown
# `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.
|