# Tool Runtime The tool runtime provides the execution layer that sits on top of the domain `Tool` model. It is responsible for registering, discovering, activating, executing, and deactivating tools at runtime. ## Modules | Module | Purpose | |--------|---------| | `cleveragents.tool.runtime` | Data models: `ToolSpec`, `ToolResult`, `ToolError` | | `cleveragents.tool.registry` | In-memory `ToolRegistry` with thread-safe operations | | `cleveragents.tool.runner` | `ToolRunner` implementing the four-stage lifecycle | ## Tool Lifecycle Every tool execution follows a strict four-stage lifecycle: ``` discover -> activate -> execute -> deactivate ``` ### 1. Discover `ToolRunner.discover(registry?)` queries the registry for all available tools. An alternate registry may be passed for dynamic discovery. ### 2. Activate `ToolRunner.activate(tool_name)` validates that the tool exists and marks it as ready for execution. Raises `ToolError` with type `ActivationError` if the tool is not found. ### 3. Execute `ToolRunner.execute(tool_name, inputs)` runs the tool handler with the provided inputs. Key guarantees: - **JSON-serialisable IO**: Both inputs and outputs are validated to be JSON-serialisable. Non-serialisable data causes a `ToolResult` with `success=False`. - **Error normalisation**: Any exception raised by the handler is caught and returned as a `ToolResult(success=False, error=...)`. The caller never sees raw exceptions from tool handlers. - **Duration tracking**: Wall-clock execution time is recorded in `ToolResult.duration_ms`. ### 4. Deactivate `ToolRunner.deactivate(tool_name)` cleans up after execution. Returns `True` if the tool was active, `False` otherwise. ## Capability Flags `ToolSpec.capabilities` carries a `ToolCapability` instance (from the domain model) with the following flags: | Flag | Description | |------|-------------| | `read_only` | Tool only reads; never writes | | `writes` | Tool can write to resources | | `checkpointable` | Tool supports checkpoint/rollback | | `idempotent` | Safe to re-run without side effects | | `unsafe` | Requires extra safety checks | | `human_approval_required` | Needs explicit human approval | A `read_only` tool cannot have `writes=True` or `checkpointable=True`. ## Error Semantics ### ToolResult | Field | Type | Description | |-------|------|-------------| | `success` | `bool` | Whether execution succeeded | | `output` | `dict` | JSON-serialisable output payload | | `error` | `str \| None` | Error message on failure | | `duration_ms` | `float` | Execution wall-clock time (ms) | | `metadata` | `dict` | Arbitrary execution metadata | ### ToolError `ToolError` is an exception class for structured tool failures: | Attribute | Type | Description | |-----------|------|-------------| | `tool_name` | `str` | Namespaced tool name | | `error_type` | `str` | Category (e.g. `RegistrationError`) | | `details` | `str` | Human-readable explanation | ## Registry `ToolRegistry` is an in-memory, thread-safe registry: - **`register(spec)`** -- adds a tool; raises `ToolError` on name collision. - **`get(name)`** -- lookup by namespaced name; returns `None` if not found. - **`list_tools(namespace?, tool_type?)`** -- list with optional filters. - **`remove(name)`** -- unregister; returns `bool`. All mutating operations are protected by `threading.RLock`.