176 lines
5.8 KiB
Python
176 lines
5.8 KiB
Python
"""Helper script for Robot Framework tool router smoke tests."""
|
|
|
|
from __future__ import annotations
|
|
|
|
import json
|
|
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.registry import ToolRegistry
|
|
from cleveragents.tool.router import (
|
|
NormalizedToolCallResult,
|
|
ProviderFormat,
|
|
StreamingToolUpdate,
|
|
ToolCallRouter,
|
|
classify_tool_error,
|
|
detect_provider_format,
|
|
generate_tool_call_id,
|
|
normalize_tool_call,
|
|
normalize_tool_schema_for_provider,
|
|
)
|
|
from cleveragents.tool.runner import ToolRunner
|
|
from cleveragents.tool.runtime import ToolSpec
|
|
|
|
|
|
def _echo(inputs: dict[str, Any]) -> dict[str, Any]:
|
|
return dict(inputs)
|
|
|
|
|
|
def _fail(inputs: dict[str, Any]) -> dict[str, Any]:
|
|
raise RuntimeError("boom")
|
|
|
|
|
|
def test_detect_openai() -> None:
|
|
fmt = detect_provider_format({"name": "x/y", "arguments": '{"a": 1}'})
|
|
assert fmt == ProviderFormat.OPENAI
|
|
print("detect-openai-ok")
|
|
|
|
|
|
def test_detect_anthropic() -> None:
|
|
fmt = detect_provider_format({"name": "x/y", "input": {"a": 1}})
|
|
assert fmt == ProviderFormat.ANTHROPIC
|
|
print("detect-anthropic-ok")
|
|
|
|
|
|
def test_detect_langchain() -> None:
|
|
fmt = detect_provider_format({"name": "x/y", "type": "tool_call", "args": {}})
|
|
assert fmt == ProviderFormat.LANGCHAIN
|
|
print("detect-langchain-ok")
|
|
|
|
|
|
def test_normalize_openai() -> None:
|
|
req = normalize_tool_call({"name": "x/y", "arguments": '{"a": 1}'})
|
|
assert req.tool_name == "x/y"
|
|
assert req.arguments["a"] == 1
|
|
assert req.provider_format == ProviderFormat.OPENAI
|
|
print("normalize-openai-ok")
|
|
|
|
|
|
def test_stable_id() -> None:
|
|
id1 = generate_tool_call_id("plan-1", 0)
|
|
id2 = generate_tool_call_id("plan-1", 0)
|
|
assert id1 == id2
|
|
assert id1.startswith("tc_")
|
|
print("stable-id-ok")
|
|
|
|
|
|
def test_route_openai() -> None:
|
|
registry = ToolRegistry()
|
|
spec = ToolSpec(name="smoke/echo", description="Echo", handler=_echo)
|
|
registry.register(spec)
|
|
runner = ToolRunner(registry)
|
|
router = ToolCallRouter(registry=registry, runner=runner, plan_id="plan-1")
|
|
result = router.route({"name": "smoke/echo", "arguments": '{"msg": "hi"}'})
|
|
assert result.result.success
|
|
assert result.provider_format == ProviderFormat.OPENAI
|
|
print("route-openai-ok")
|
|
|
|
|
|
def test_route_anthropic() -> None:
|
|
registry = ToolRegistry()
|
|
spec = ToolSpec(name="smoke/echo", description="Echo", handler=_echo)
|
|
registry.register(spec)
|
|
runner = ToolRunner(registry)
|
|
router = ToolCallRouter(registry=registry, runner=runner, plan_id="plan-2")
|
|
result = router.route({"name": "smoke/echo", "input": {"msg": "hi"}})
|
|
assert result.result.success
|
|
assert result.provider_format == ProviderFormat.ANTHROPIC
|
|
print("route-anthropic-ok")
|
|
|
|
|
|
def test_route_error() -> None:
|
|
registry = ToolRegistry()
|
|
spec = ToolSpec(name="smoke/fail", description="Fail", handler=_fail)
|
|
registry.register(spec)
|
|
runner = ToolRunner(registry)
|
|
router = ToolCallRouter(registry=registry, runner=runner, plan_id="plan-3")
|
|
result = router.route({"name": "smoke/fail", "arguments": "{}"})
|
|
assert not result.result.success
|
|
print("route-error-ok")
|
|
|
|
|
|
def test_error_classify() -> None:
|
|
cat = classify_tool_error("Operation timed out")
|
|
assert cat.value == "timeout"
|
|
cat2 = classify_tool_error("Permission denied")
|
|
assert cat2.value == "permission"
|
|
print("error-classify-ok")
|
|
|
|
|
|
def test_schema_normalize() -> None:
|
|
spec = ToolSpec(name="smoke/echo", description="Echo tool", handler=_echo)
|
|
schema = normalize_tool_schema_for_provider(spec, ProviderFormat.OPENAI)
|
|
assert "parameters" in schema
|
|
schema2 = normalize_tool_schema_for_provider(spec, ProviderFormat.ANTHROPIC)
|
|
assert "input_schema" in schema2
|
|
print("schema-normalize-ok")
|
|
|
|
|
|
def test_batch_route() -> None:
|
|
registry = ToolRegistry()
|
|
spec = ToolSpec(name="smoke/echo", description="Echo", handler=_echo)
|
|
registry.register(spec)
|
|
runner = ToolRunner(registry)
|
|
router = ToolCallRouter(registry=registry, runner=runner, plan_id="plan-batch")
|
|
payloads = [
|
|
{"name": "smoke/echo", "arguments": json.dumps({"i": i})} for i in range(3)
|
|
]
|
|
results = router.route_batch(payloads)
|
|
assert len(results) == 3
|
|
assert all(r.result.success for r in results)
|
|
print("batch-route-ok")
|
|
|
|
|
|
def test_streaming() -> None:
|
|
registry = ToolRegistry()
|
|
spec = ToolSpec(name="smoke/echo", description="Echo", handler=_echo)
|
|
registry.register(spec)
|
|
runner = ToolRunner(registry)
|
|
router = ToolCallRouter(registry=registry, runner=runner, plan_id="plan-stream")
|
|
items = list(
|
|
router.route_streaming({"name": "smoke/echo", "arguments": '{"msg": "s"}'})
|
|
)
|
|
updates = [i for i in items if isinstance(i, StreamingToolUpdate)]
|
|
results = [i for i in items if isinstance(i, NormalizedToolCallResult)]
|
|
assert len(updates) >= 2
|
|
assert len(results) == 1
|
|
assert results[0].result.success
|
|
print("streaming-ok")
|
|
|
|
|
|
if __name__ == "__main__":
|
|
cmd = sys.argv[1] if len(sys.argv) > 1 else "detect_openai"
|
|
commands = {
|
|
"detect_openai": test_detect_openai,
|
|
"detect_anthropic": test_detect_anthropic,
|
|
"detect_langchain": test_detect_langchain,
|
|
"normalize_openai": test_normalize_openai,
|
|
"stable_id": test_stable_id,
|
|
"route_openai": test_route_openai,
|
|
"route_anthropic": test_route_anthropic,
|
|
"route_error": test_route_error,
|
|
"error_classify": test_error_classify,
|
|
"schema_normalize": test_schema_normalize,
|
|
"batch_route": test_batch_route,
|
|
"streaming": test_streaming,
|
|
}
|
|
handler = commands.get(cmd)
|
|
if handler is None:
|
|
print(f"Unknown command: {cmd}", file=sys.stderr)
|
|
sys.exit(1)
|
|
handler()
|