import asyncio
from opper_agents import Agent, tool, hook
from pydantic import BaseModel, Field
# Define tools
@tool
def add(a: float, b: float) -> float:
"""Add two numbers together."""
return a + b
@tool
def subtract(a: float, b: float) -> float:
"""Subtract b from a."""
return a - b
@tool
def multiply(a: float, b: float) -> float:
"""Multiply two numbers together."""
return a * b
@tool
def divide(a: float, b: float) -> float:
"""Divide a by b."""
if b == 0:
raise ValueError("Cannot divide by zero")
return a / b
@tool
def power(base: float, exponent: float) -> float:
"""Raise base to the power of exponent."""
return base ** exponent
@tool
def sqrt(n: float) -> float:
"""Calculate the square root of a number."""
if n < 0:
raise ValueError("Cannot calculate square root of negative number")
return n ** 0.5
# Define output schema for structured results
class MathResult(BaseModel):
answer: float = Field(description="The final numerical answer")
explanation: str = Field(description="Step-by-step explanation of the solution")
operations_used: list[str] = Field(description="List of operations performed")
# Track tool usage with hooks
@hook("tool_call")
async def log_tool(context, agent, tool, parameters, **kwargs):
print(f" → {tool.name}({parameters})")
@hook("tool_result")
async def log_result(context, agent, tool, result, **kwargs):
print(f" = {result.result}")
# Create the agent
agent = Agent(
name="MathAgent",
description="Solves mathematical problems step by step",
instructions="""You are a precise math assistant. When solving problems:
1. Break down complex calculations into simple steps
2. Use the appropriate tool for each operation
3. Show your work clearly in the explanation
4. Always verify your answer makes sense""",
tools=[add, subtract, multiply, divide, power, sqrt],
output_schema=MathResult,
hooks=[log_tool, log_result],
verbose=False
)
async def main():
problems = [
"What is 15 + 27?",
"Calculate (5 + 3) * 4",
"What is the square root of 144, then add 5?",
"If I have $100 and spend 35%, how much do I have left?",
]
for problem in problems:
print(f"\n{'='*50}")
print(f"Problem: {problem}")
print("-" * 50)
result = await agent.process(problem)
print(f"\nAnswer: {result.answer}")
print(f"Explanation: {result.explanation}")
print(f"Operations: {', '.join(result.operations_used)}")
if __name__ == "__main__":
asyncio.run(main())