Files

196 lines
6.1 KiB
Python

"""ASV benchmarks for ToolCallRouter operations.
Measures the performance of:
- Provider format detection
- Payload normalization
- Stable ID generation
- Tool call routing (OpenAI, Anthropic, LangChain)
- Batch routing
- Schema normalization
- Error classification
"""
from __future__ import annotations
import json
import sys
from pathlib import Path
from typing import Any
try:
from cleveragents.tool.registry import ToolRegistry
from cleveragents.tool.router import (
ProviderFormat,
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
except ModuleNotFoundError:
sys.path.insert(0, str(Path(__file__).resolve().parents[1] / "src"))
from cleveragents.tool.registry import ToolRegistry
from cleveragents.tool.router import (
ProviderFormat,
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)
class FormatDetectionSuite:
"""Benchmark provider format detection."""
def setup(self) -> None:
"""Prepare payloads."""
self.openai_payload = {"name": "bench/echo", "arguments": '{"a": 1}'}
self.anthropic_payload = {"name": "bench/echo", "input": {"a": 1}}
self.langchain_payload = {
"name": "bench/echo",
"type": "tool_call",
"args": {"a": 1},
}
def time_detect_openai(self) -> None:
"""Benchmark OpenAI format detection."""
detect_provider_format(self.openai_payload)
def time_detect_anthropic(self) -> None:
"""Benchmark Anthropic format detection."""
detect_provider_format(self.anthropic_payload)
def time_detect_langchain(self) -> None:
"""Benchmark LangChain format detection."""
detect_provider_format(self.langchain_payload)
class NormalizationSuite:
"""Benchmark payload normalization."""
def setup(self) -> None:
"""Prepare payloads."""
self.openai_payload = {"name": "bench/echo", "arguments": '{"a": 1}'}
self.anthropic_payload = {"name": "bench/echo", "input": {"a": 1}}
def time_normalize_openai(self) -> None:
"""Benchmark OpenAI payload normalization."""
normalize_tool_call(self.openai_payload)
def time_normalize_anthropic(self) -> None:
"""Benchmark Anthropic payload normalization."""
normalize_tool_call(self.anthropic_payload)
class IDGenerationSuite:
"""Benchmark stable ID generation."""
def time_generate_id(self) -> None:
"""Benchmark single ID generation."""
generate_tool_call_id("plan-bench", 42)
def time_generate_100_ids(self) -> None:
"""Benchmark generating 100 IDs."""
for i in range(100):
generate_tool_call_id("plan-bench", i)
class RoutingSuite:
"""Benchmark tool call routing."""
def setup(self) -> None:
"""Prepare registry and router."""
self.registry = ToolRegistry()
spec = ToolSpec(
name="bench/echo",
description="Benchmark echo tool",
handler=_echo,
)
self.registry.register(spec)
self.runner = ToolRunner(self.registry)
self.router = ToolCallRouter(
registry=self.registry,
runner=self.runner,
plan_id="plan-bench",
)
self.openai_payload = {
"name": "bench/echo",
"arguments": '{"msg": "hello"}',
}
self.anthropic_payload = {
"name": "bench/echo",
"input": {"msg": "hello"},
}
self.langchain_payload = {
"name": "bench/echo",
"type": "tool_call",
"args": {"msg": "hello"},
}
def time_route_openai(self) -> None:
"""Benchmark routing an OpenAI tool call."""
self.router.route(self.openai_payload)
def time_route_anthropic(self) -> None:
"""Benchmark routing an Anthropic tool call."""
self.router.route(self.anthropic_payload)
def time_route_langchain(self) -> None:
"""Benchmark routing a LangChain tool call."""
self.router.route(self.langchain_payload)
def time_route_batch_10(self) -> None:
"""Benchmark routing a batch of 10 tool calls."""
payloads = [
{"name": "bench/echo", "arguments": json.dumps({"i": i})} for i in range(10)
]
self.router.route_batch(payloads)
class SchemaSuite:
"""Benchmark schema normalization."""
def setup(self) -> None:
"""Prepare tool spec."""
self.spec = ToolSpec(
name="bench/echo",
description="Benchmark echo tool",
handler=_echo,
input_schema={"type": "object", "properties": {"a": {"type": "integer"}}},
)
def time_normalize_openai_schema(self) -> None:
"""Benchmark schema normalization for OpenAI."""
normalize_tool_schema_for_provider(self.spec, ProviderFormat.OPENAI)
def time_normalize_anthropic_schema(self) -> None:
"""Benchmark schema normalization for Anthropic."""
normalize_tool_schema_for_provider(self.spec, ProviderFormat.ANTHROPIC)
class ErrorClassificationSuite:
"""Benchmark error classification."""
def time_classify_timeout(self) -> None:
"""Benchmark classifying timeout error."""
classify_tool_error("Operation timed out after 30s")
def time_classify_permission(self) -> None:
"""Benchmark classifying permission error."""
classify_tool_error("Permission denied: cannot write")
def time_classify_generic(self) -> None:
"""Benchmark classifying generic error."""
classify_tool_error("Something unexpected happened")