Implement the four-stage tool lifecycle (discover/activate/execute/deactivate) with capability enforcement, per-plan activation caching, JSON Schema validation, execution tracing, and cancellation propagation. New modules: - tool/context.py: ToolExecutionContext, BoundResource, Change, CancellationToken - tool/lifecycle.py: ToolRuntime, ToolInstance protocol, ToolLifecycleCache - tool/schema_validator.py: JSON Schema input/output validation Tests: 57 Behave scenarios, 6 Robot smoke tests, 5 ASV benchmarks Coverage: context 100%, schema_validator 100%, lifecycle 94%, overall 97%
3.5 KiB
Tool Lifecycle Runtime
The tool lifecycle runtime orchestrates the four-stage lifecycle
(discover/activate/execute/deactivate) for all tool sources
(MCP, Agent Skills, built-ins, custom, wrapped).
Architecture
ToolRuntime
├── ToolLifecycleCache (per-plan activation reuse)
├── ToolInstance (Protocol) (concrete tool implementations)
├── ToolExecutionContext (plan metadata + resources + cancellation)
└── schema_validator (JSON Schema input/output validation)
Four-Stage Lifecycle
1. Discover
Returns lightweight ToolDescriptor metadata without activating the tool.
Used during registration and tool enumeration.
2. Activate
Prepares the tool for execution within a plan context. Called at most once per plan via the lifecycle cache. May start external processes (MCP), load instructions (Agent Skills), or no-op (built-ins).
3. Execute
Runs the tool with validated parameters. The runtime:
- Checks cancellation
- Auto-activates if not yet activated for the plan
- Enforces capability flags (read-only, checkpoint requirements)
- Validates inputs against JSON Schema
- Executes the tool with tracing
- Validates outputs against JSON Schema
- Records changes into the execution context
4. Deactivate
Cleans up after all executions. Called once per plan on completion, failure, or cancellation. Must be idempotent and must not raise.
Capability Enforcement
| Constraint | Condition | Error |
|---|---|---|
| Read-only plan | Tool has writes=True |
ToolAccessDeniedError |
| Checkpoint required | Tool has checkpointable=False |
ToolCheckpointRequiredError |
Per-Plan Activation Cache
The ToolLifecycleCache ensures:
- Each tool is activated at most once per plan
deactivate()is guaranteed for every activated tool when the plan ends- Thread-safe via
RLockfor concurrent plan execution
Cancellation
The CancellationToken propagates cancellation from the plan lifecycle:
- Set via
cancel()whenagents plan cancelis invoked - Tools check
ctx.cancellation_token.is_cancelledfor long-running ops ctx.cancellation_token.check()raisesToolCancelledErrorimmediately
JSON Schema Validation
Uses JSON Schema draft 2020-12 via jsonschema.Draft202012Validator:
input_schema: validated before execution; failures return error resultoutput_schema: validated after execution; failures logged as warning
Execution Tracing
Every execution produces a ToolExecutionTrace with:
started_at/ended_at(ISO-8601)duration_msresult_size_bytessuccess/error
Error Hierarchy
ToolRuntimeError
├── ToolAccessDeniedError
├── ToolCheckpointRequiredError
├── ToolNotActivatedError
├── ToolActivationError
├── ToolExecutionError
└── ToolDeactivationError
ToolCancelledError (standalone, not ToolRuntimeError)
ToolSchemaValidationError (standalone)
Key Files
| File | Purpose |
|---|---|
src/cleveragents/tool/__init__.py |
Package exports |
src/cleveragents/tool/context.py |
ToolExecutionContext, BoundResource, Change, CancellationToken, ToolExecutionTrace |
src/cleveragents/tool/lifecycle.py |
ToolRuntime, ToolInstance, ToolLifecycleCache, ToolDescriptor, ToolResult |
src/cleveragents/tool/schema_validator.py |
JSON Schema validation for inputs/outputs |
src/cleveragents/domain/models/core/tool.py |
Tool, Validation, ToolCapability domain models |