Files
cleveragents-core/robot/helper_actor_runtime.py
freemo 92c83ecc7e
CI / benchmark-publish (pull_request) Has been skipped
CI / lint (pull_request) Successful in 16s
CI / build (pull_request) Successful in 17s
CI / quality (pull_request) Successful in 19s
CI / typecheck (pull_request) Successful in 33s
CI / security (pull_request) Successful in 35s
CI / integration_tests (pull_request) Successful in 2m41s
CI / unit_tests (pull_request) Successful in 6m18s
CI / docker (pull_request) Successful in 1m2s
CI / benchmark-regression (pull_request) Successful in 15m41s
CI / coverage (pull_request) Failing after 20m52s
Fix: Fixed linting errors
2026-02-22 14:18:24 -05:00

214 lines
6.2 KiB
Python

"""Helper script for Robot Framework actor runtime smoke tests."""
from __future__ import annotations
import sys
from pathlib import Path
from typing import Any
# Ensure src is importable when run from workspace root
sys.path.insert(0, str(Path(__file__).resolve().parents[1] / "src"))
from cleveragents.tool.actor_context import ToolActorContext
from cleveragents.tool.actor_runtime import (
LLMResponse,
LLMToolCall,
ToolCallingRuntime,
)
from cleveragents.tool.registry import ToolRegistry
from cleveragents.tool.runner import ToolRunner
from cleveragents.tool.runtime import ToolSpec
def _echo(inputs: dict[str, Any]) -> dict[str, Any]:
return {"echoed": inputs}
def _fail(inputs: dict[str, Any]) -> dict[str, Any]:
raise RuntimeError("boom")
_captured: dict[str, Any] = {}
def _capture(inputs: dict[str, Any]) -> dict[str, Any]:
_captured.clear()
_captured.update(inputs)
return {"ok": True}
class SingleToolLLM:
"""Requests one tool call then returns."""
def __init__(self) -> None:
self._n = 0
def invoke(
self,
prompt: str,
tool_schemas: list[dict[str, Any]],
tool_results: list[dict[str, Any]] | None = None,
actor_config: dict[str, Any] | None = None,
) -> LLMResponse:
self._n += 1
if self._n == 1:
return LLMResponse(
tool_calls=[LLMToolCall(name="test/echo", arguments={"a": 1})]
)
return LLMResponse(content="done")
class AlwaysToolLLM:
"""Always requests tool calls."""
def invoke(
self,
prompt: str,
tool_schemas: list[dict[str, Any]],
tool_results: list[dict[str, Any]] | None = None,
actor_config: dict[str, Any] | None = None,
) -> LLMResponse:
return LLMResponse(
tool_calls=[LLMToolCall(name="test/echo", arguments={"x": 1})]
)
class FailToolLLM:
"""Requests failing tool then stops."""
def __init__(self) -> None:
self._n = 0
def invoke(
self,
prompt: str,
tool_schemas: list[dict[str, Any]],
tool_results: list[dict[str, Any]] | None = None,
actor_config: dict[str, Any] | None = None,
) -> LLMResponse:
self._n += 1
if self._n == 1:
return LLMResponse(tool_calls=[LLMToolCall(name="test/fail", arguments={})])
return LLMResponse(content="handled error")
class CaptureToolLLM:
"""Requests capturing tool then stops."""
def __init__(self) -> None:
self._n = 0
def invoke(
self,
prompt: str,
tool_schemas: list[dict[str, Any]],
tool_results: list[dict[str, Any]] | None = None,
actor_config: dict[str, Any] | None = None,
) -> LLMResponse:
self._n += 1
if self._n == 1:
return LLMResponse(
tool_calls=[LLMToolCall(name="test/capture", arguments={"d": 1})]
)
return LLMResponse(content="captured")
class ImmediateLLM:
"""Returns immediately without tool calls."""
def invoke(
self,
prompt: str,
tool_schemas: list[dict[str, Any]],
tool_results: list[dict[str, Any]] | None = None,
actor_config: dict[str, Any] | None = None,
) -> LLMResponse:
return LLMResponse(content="immediate")
def _make_registry_with_echo() -> ToolRegistry:
reg = ToolRegistry()
reg.register(ToolSpec(name="test/echo", description="Echo", handler=_echo))
return reg
def test_single_tool() -> None:
reg = _make_registry_with_echo()
runner = ToolRunner(reg)
rt = ToolCallingRuntime(registry=reg, runner=runner, llm_caller=SingleToolLLM())
result = rt.run_tool_loop(prompt="go")
assert result.content == "done"
assert len(result.tool_call_history) == 1
assert not result.terminated_by_limit
print("single-tool-ok")
def test_max_iterations() -> None:
reg = _make_registry_with_echo()
runner = ToolRunner(reg)
rt = ToolCallingRuntime(
registry=reg, runner=runner, llm_caller=AlwaysToolLLM(), max_iterations=3
)
result = rt.run_tool_loop(prompt="loop")
assert result.terminated_by_limit
assert result.iterations == 3
print("max-iterations-ok")
def test_error_handling() -> None:
reg = ToolRegistry()
reg.register(ToolSpec(name="test/fail", description="Fail", handler=_fail))
runner = ToolRunner(reg)
rt = ToolCallingRuntime(registry=reg, runner=runner, llm_caller=FailToolLLM())
result = rt.run_tool_loop(prompt="fail")
assert len(result.tool_call_history) == 1
assert not result.tool_call_history[0].success
assert result.tool_call_history[0].error is not None
print("error-handling-ok")
def test_context_props() -> None:
ctx = ToolActorContext(plan_id="p1", phase="execute", sandbox_root="/sb")
assert ctx.plan_id == "p1"
assert ctx.phase == "execute"
assert ctx.sandbox_root == "/sb"
assert len(ctx.tool_call_history) == 0
summary = ctx.as_summary()
assert summary["plan_id"] == "p1"
print("context-props-ok")
def test_sandbox_thread() -> None:
reg = ToolRegistry()
reg.register(ToolSpec(name="test/capture", description="Capture", handler=_capture))
runner = ToolRunner(reg)
ctx = ToolActorContext(plan_id="p2", phase="execute", sandbox_root="/sandbox/path")
rt = ToolCallingRuntime(registry=reg, runner=runner, llm_caller=CaptureToolLLM())
rt.run_tool_loop(prompt="capture", context=ctx)
assert _captured.get("sandbox_root") == "/sandbox/path"
print("sandbox-thread-ok")
def test_empty_registry() -> None:
reg = ToolRegistry()
runner = ToolRunner(reg)
rt = ToolCallingRuntime(registry=reg, runner=runner, llm_caller=ImmediateLLM())
result = rt.run_tool_loop(prompt="nothing")
assert result.content == "immediate"
assert len(result.tool_call_history) == 0
print("empty-registry-ok")
COMMANDS = {
"single_tool": test_single_tool,
"max_iterations": test_max_iterations,
"error_handling": test_error_handling,
"context_props": test_context_props,
"sandbox_thread": test_sandbox_thread,
"empty_registry": test_empty_registry,
}
if __name__ == "__main__":
cmd = sys.argv[1] if len(sys.argv) > 1 else "single_tool"
COMMANDS[cmd]()