forked from HAL9000/cleveragents-core
125 lines
4.1 KiB
Markdown
125 lines
4.1 KiB
Markdown
# Actor Runtime — Tool-Calling Loop
|
|
|
|
The **ToolCallingRuntime** provides the execution loop for tool-calling
|
|
actors. It maps `ToolRegistry` specs to LLM-provider tool schemas,
|
|
sends prompts to the LLM, routes tool call requests through
|
|
`ToolCallRouter` / `ToolRunner`, and feeds results back to the LLM
|
|
until a final response is produced or the iteration limit is reached.
|
|
|
|
## Architecture
|
|
|
|
```
|
|
ToolCallingRuntime
|
|
|-- ToolRegistry (tool spec source)
|
|
|-- ToolRunner (4-stage tool execution)
|
|
|-- ToolCallRouter (optional; provider format translation)
|
|
|-- LLMCaller (LLM invocation protocol)
|
|
+-- ToolActorContext (sandbox, resources, history)
|
|
```
|
|
|
|
## Loop Semantics
|
|
|
|
```
|
|
1. Convert ToolRegistry specs -> provider tool schemas
|
|
2. Send prompt + tool schemas to LLM via LLMCaller
|
|
3. If LLM returns tool calls:
|
|
a. Route each call through ToolCallRouter -> ToolRunner
|
|
b. Capture metadata (tool name, inputs, outputs, duration, success)
|
|
c. Thread sandbox root + resource bindings into tool inputs
|
|
d. Feed tool results back to LLM
|
|
e. Increment iteration counter; go to step 2
|
|
4. If LLM responds without tool calls:
|
|
a. Return final response with complete tool call history
|
|
5. If max_iterations reached:
|
|
a. Return partial result with terminated_by_limit=True
|
|
```
|
|
|
|
## Safety: Max Iterations
|
|
|
|
The `max_iterations` parameter (default **25**) prevents infinite loops
|
|
when the LLM continuously requests tool calls without producing a final
|
|
answer. When the limit is reached the runtime returns a
|
|
`ToolCallRunResult` with `terminated_by_limit=True` and whatever content
|
|
has been accumulated so far.
|
|
|
|
## Error Semantics
|
|
|
|
| Error | Condition | Behavior |
|
|
|---|---|---|
|
|
| `ValueError` | Empty prompt | Raised immediately |
|
|
| `TypeError` | Invalid registry/runner type | Raised at construction |
|
|
| `ValueError` | `max_iterations < 1` | Raised at construction |
|
|
| Tool not found | LLM calls a tool not in registry | `ToolCallRecord` with `success=False` |
|
|
| Tool execution error | Handler raises | `ToolCallRecord` with `success=False`, `error` set |
|
|
| Max iterations | Loop count exceeds limit | Returns `terminated_by_limit=True` |
|
|
|
|
## Tool Call Metadata
|
|
|
|
Every tool call is recorded as a `ToolCallRecord` containing:
|
|
|
|
| Field | Type | Description |
|
|
|---|---|---|
|
|
| `tool_name` | `str` | Name of the tool invoked |
|
|
| `inputs` | `dict` | Arguments sent to the tool |
|
|
| `output` | `dict` | Output returned by the tool |
|
|
| `duration_ms` | `float` | Execution time in milliseconds |
|
|
| `success` | `bool` | Whether the call succeeded |
|
|
| `error` | `str | None` | Error message if failed |
|
|
| `iteration` | `int` | Loop iteration when the call was made |
|
|
|
|
## Sandbox Threading
|
|
|
|
When a `ToolActorContext` is provided with a `sandbox_root` and/or
|
|
`resource_bindings`, these values are threaded into tool inputs as
|
|
default keys (`sandbox_root`, `resource_bindings`) so that tools
|
|
receive the execution environment context automatically.
|
|
|
|
## ToolActorContext
|
|
|
|
The `ToolActorContext` carries:
|
|
|
|
- **plan_id** — unique plan identifier
|
|
- **phase** — current plan phase (e.g. `execute`, `strategize`)
|
|
- **sandbox_root** — filesystem path to the sandbox directory
|
|
- **automation_profile** — governing automation profile name
|
|
- **resource_bindings** — slot-to-resource mappings from the plan
|
|
- **project_resources** — additional project resource metadata
|
|
- **tool_call_history** — running list of `ToolCallRecord` entries
|
|
|
|
## Usage Example
|
|
|
|
```python
|
|
from cleveragents.tool import (
|
|
ToolCallingRuntime,
|
|
ToolRegistry,
|
|
ToolRunner,
|
|
ToolActorContext,
|
|
)
|
|
|
|
registry = ToolRegistry()
|
|
runner = ToolRunner(registry)
|
|
# register tools...
|
|
|
|
runtime = ToolCallingRuntime(
|
|
registry=registry,
|
|
runner=runner,
|
|
llm_caller=my_llm_caller,
|
|
max_iterations=10,
|
|
)
|
|
|
|
context = ToolActorContext(
|
|
plan_id="plan-123",
|
|
phase="execute",
|
|
sandbox_root="/tmp/sandbox",
|
|
)
|
|
|
|
result = runtime.run_tool_loop(
|
|
prompt="Implement the feature described in the plan.",
|
|
context=context,
|
|
)
|
|
|
|
print(result.content)
|
|
print(f"Tool calls: {len(result.tool_call_history)}")
|
|
print(f"Iterations: {result.iterations}")
|
|
```
|