Mini-Agent / tests /test_tool_schema.py
AbdulElahGwaith's picture
Upload folder using huggingface_hub
dc893fb verified
"""Test cases for Tool schema methods."""
from typing import Any
import pytest
from mini_agent.tools.base import Tool, ToolResult
class MockWeatherTool(Tool):
"""Mock weather tool for testing."""
@property
def name(self) -> str:
return "get_weather"
@property
def description(self) -> str:
return "Get weather information"
@property
def parameters(self) -> dict[str, Any]:
return {
"type": "object",
"properties": {
"location": {
"type": "string",
"description": "Location name",
},
},
"required": ["location"],
}
async def execute(self, **kwargs) -> ToolResult:
return ToolResult(success=True, content="Weather data")
class MockCalculatorTool(Tool):
"""Mock calculator tool for testing."""
@property
def name(self) -> str:
return "calculator"
@property
def description(self) -> str:
return "Perform calculations"
@property
def parameters(self) -> dict[str, Any]:
return {
"type": "object",
"properties": {
"expression": {
"type": "string",
"description": "Math expression",
},
},
"required": ["expression"],
}
async def execute(self, **kwargs) -> ToolResult:
return ToolResult(success=True, content="42")
class MockSearchTool(Tool):
"""Mock search tool with complex schema."""
@property
def name(self) -> str:
return "search_database"
@property
def description(self) -> str:
return "Search the database"
@property
def parameters(self) -> dict[str, Any]:
return {
"type": "object",
"properties": {
"query": {
"type": "string",
"description": "Search query",
},
"filters": {
"type": "object",
"properties": {
"category": {"type": "string"},
"min_price": {"type": "number"},
"max_price": {"type": "number"},
},
},
"limit": {
"type": "integer",
"minimum": 1,
"maximum": 100,
"default": 10,
},
},
"required": ["query"],
}
async def execute(self, **kwargs) -> ToolResult:
return ToolResult(success=True, content="Search results")
class MockEnumTool(Tool):
"""Mock tool with enum parameter."""
@property
def name(self) -> str:
return "set_status"
@property
def description(self) -> str:
return "Set status"
@property
def parameters(self) -> dict[str, Any]:
return {
"type": "object",
"properties": {
"status": {
"type": "string",
"enum": ["active", "inactive", "pending"],
"description": "Status value",
}
},
"required": ["status"],
}
async def execute(self, **kwargs) -> ToolResult:
return ToolResult(success=True, content="Status set")
def test_tool_to_schema():
"""Test Tool.to_schema() method."""
tool = MockWeatherTool()
schema = tool.to_schema()
assert isinstance(schema, dict)
assert schema["name"] == "get_weather"
assert schema["description"] == "Get weather information"
assert "input_schema" in schema
assert schema["input_schema"]["type"] == "object"
assert "location" in schema["input_schema"]["properties"]
assert schema["input_schema"]["required"] == ["location"]
def test_tool_to_openai_schema():
"""Test Tool.to_openai_schema() method."""
tool = MockWeatherTool()
schema = tool.to_openai_schema()
assert isinstance(schema, dict)
assert schema["type"] == "function"
assert "function" in schema
assert schema["function"]["name"] == "get_weather"
assert schema["function"]["description"] == "Get weather information"
assert "parameters" in schema["function"]
assert schema["function"]["parameters"]["type"] == "object"
assert "location" in schema["function"]["parameters"]["properties"]
def test_tool_schema_complex():
"""Test tool with complex input schema."""
tool = MockSearchTool()
schema = tool.to_schema()
assert schema["name"] == "search_database"
assert "query" in schema["input_schema"]["properties"]
assert "filters" in schema["input_schema"]["properties"]
assert "limit" in schema["input_schema"]["properties"]
assert schema["input_schema"]["required"] == ["query"]
def test_tool_openai_schema_complex():
"""Test OpenAI schema conversion for complex tool."""
tool = MockSearchTool()
schema = tool.to_openai_schema()
assert schema["type"] == "function"
params = schema["function"]["parameters"]
assert "query" in params["properties"]
assert "filters" in params["properties"]
assert "limit" in params["properties"]
assert params["required"] == ["query"]
def test_multiple_tools():
"""Test creating multiple tool instances."""
tool1 = MockWeatherTool()
tool2 = MockCalculatorTool()
tools = [tool1, tool2]
assert len(tools) == 2
assert tools[0].name == "get_weather"
assert tools[1].name == "calculator"
# Convert all to Anthropic schemas
anthropic_schemas = [t.to_schema() for t in tools]
assert len(anthropic_schemas) == 2
assert all(isinstance(s, dict) for s in anthropic_schemas)
assert all("name" in s and "description" in s and "input_schema" in s for s in anthropic_schemas)
# Convert all to OpenAI schemas
openai_schemas = [t.to_openai_schema() for t in tools]
assert len(openai_schemas) == 2
assert all(isinstance(s, dict) for s in openai_schemas)
assert all(s["type"] == "function" for s in openai_schemas)
def test_tool_with_enum():
"""Test tool with enum parameter."""
tool = MockEnumTool()
schema = tool.to_schema()
status_prop = schema["input_schema"]["properties"]["status"]
assert "enum" in status_prop
assert status_prop["enum"] == ["active", "inactive", "pending"]
# Test OpenAI schema too
openai_schema = tool.to_openai_schema()
status_prop_openai = openai_schema["function"]["parameters"]["properties"]["status"]
assert "enum" in status_prop_openai
assert status_prop_openai["enum"] == ["active", "inactive", "pending"]
def test_tool_schema_consistency():
"""Test that both schema methods produce consistent data."""
tool = MockCalculatorTool()
anthropic_schema = tool.to_schema()
openai_schema = tool.to_openai_schema()
# Names should match
assert anthropic_schema["name"] == openai_schema["function"]["name"]
# Descriptions should match
assert anthropic_schema["description"] == openai_schema["function"]["description"]
# Parameters should match (just different nesting)
assert anthropic_schema["input_schema"] == openai_schema["function"]["parameters"]
@pytest.mark.asyncio
async def test_tool_execute():
"""Test that tools can be executed."""
tool = MockWeatherTool()
result = await tool.execute(location="Tokyo")
assert isinstance(result, ToolResult)
assert result.success is True
assert result.content == "Weather data"
if __name__ == "__main__":
pytest.main([__file__, "-v"])