import asyncio import json import time from tools import CalculatorArguments, ToolRegistry, ToolSpec def test_builtin_tool_definitions() -> None: registry = ToolRegistry() definitions = registry.definitions() assert [item["function"]["name"] for item in definitions] == [ # type: ignore[index] "get_current_time", "calculate", ] def test_calculator_and_time_tools() -> None: async def scenario() -> None: registry = ToolRegistry() calculation = await registry.execute( "calculate", '{"expression":"(2 + 3) * 4"}' ) current_time = await registry.execute( "get_current_time", '{"timezone":"Asia/Shanghai"}' ) assert calculation.is_error is False assert json.loads(calculation.content)["result"] == 20 assert current_time.is_error is False assert json.loads(current_time.content)["timezone"] == "Asia/Shanghai" asyncio.run(scenario()) def test_tool_argument_and_expression_errors_are_safe() -> None: async def scenario() -> None: registry = ToolRegistry() invalid_json = await registry.execute("calculate", "not-json") unknown = await registry.execute("missing", "{}") unsafe = await registry.execute( "calculate", '{"expression":"__import__(\\"os\\").system(\\"id\\")"}' ) invalid_timezone = await registry.execute( "get_current_time", '{"timezone":"Not/A_Real_Zone"}' ) assert invalid_json.is_error is True assert "invalid_arguments" in invalid_json.content assert unknown.is_error is True assert "unknown_tool" in unknown.content assert unsafe.is_error is True assert "execution_failed" in unsafe.content assert invalid_timezone.is_error is True assert "execution_failed" in invalid_timezone.content asyncio.run(scenario()) def test_tool_timeout_returns_error() -> None: def slow_handler(arguments): time.sleep(0.05) return {"result": 1} async def scenario() -> None: registry = ToolRegistry(timeout_seconds=0.01) registry._specs["calculate"] = ToolSpec( name="calculate", description="slow", arguments_model=CalculatorArguments, handler=slow_handler, ) result = await registry.execute("calculate", '{"expression":"1+1"}') assert result.is_error is True assert "timeout" in result.content asyncio.run(scenario())