AgenticAI-RAG / src /tools /calculator.py
GreymanT's picture
Upload 80 files
8bf4d58 verified
"""Calculator tool for mathematical operations."""
import logging
import math
import operator
from typing import Any, Dict
import re
logger = logging.getLogger(__name__)
class Calculator:
"""Safe calculator for mathematical expressions."""
# Allowed operations
ALLOWED_OPERATORS = {
"+": operator.add,
"-": operator.sub,
"*": operator.mul,
"/": operator.truediv,
"//": operator.floordiv,
"%": operator.mod,
"**": operator.pow,
"^": operator.pow,
}
# Allowed functions
ALLOWED_FUNCTIONS = {
"abs": abs,
"round": round,
"min": min,
"max": max,
"sum": sum,
"sqrt": math.sqrt,
"sin": math.sin,
"cos": math.cos,
"tan": math.tan,
"log": math.log,
"log10": math.log10,
"exp": math.exp,
"pow": pow,
"ceil": math.ceil,
"floor": math.floor,
}
# Allowed constants
ALLOWED_CONSTANTS = {
"pi": math.pi,
"e": math.e,
"tau": math.tau,
}
def __init__(self):
"""Initialize calculator."""
pass
def calculate(self, expression: str) -> Dict[str, Any]:
"""
Safely evaluate a mathematical expression.
Args:
expression: Mathematical expression as string
Returns:
Dictionary with result or error
"""
try:
# Clean expression - ensure it's a string
if not isinstance(expression, str):
expression = str(expression)
expression = expression.strip()
# Replace constants
for const_name, const_value in self.ALLOWED_CONSTANTS.items():
expression = re.sub(
rf"\b{const_name}\b",
str(const_value),
expression,
flags=re.IGNORECASE,
)
# Replace function names
for func_name in self.ALLOWED_FUNCTIONS.keys():
expression = re.sub(
rf"\b{func_name}\b",
func_name,
expression,
flags=re.IGNORECASE,
)
# Replace ^ with ** for power
expression = expression.replace("^", "**")
# Build safe evaluation environment
safe_dict = {
"__builtins__": {},
**self.ALLOWED_FUNCTIONS,
**self.ALLOWED_CONSTANTS,
}
# Evaluate expression
result = eval(expression, safe_dict)
return {
"success": True,
"result": result,
"expression": expression,
}
except ZeroDivisionError:
return {
"success": False,
"error": "Division by zero",
"expression": expression,
}
except Exception as e:
logger.error(f"Error calculating expression '{expression}': {e}")
return {
"success": False,
"error": str(e),
"expression": expression,
}
def add(self, a: float, b: float) -> float:
"""Add two numbers."""
return a + b
def subtract(self, a: float, b: float) -> float:
"""Subtract b from a."""
return a - b
def multiply(self, a: float, b: float) -> float:
"""Multiply two numbers."""
return a * b
def divide(self, a: float, b: float) -> float:
"""Divide a by b."""
if b == 0:
raise ValueError("Division by zero")
return a / b
def power(self, base: float, exponent: float) -> float:
"""Raise base to the power of exponent."""
return base ** exponent
def sqrt(self, value: float) -> float:
"""Calculate square root."""
if value < 0:
raise ValueError("Cannot calculate square root of negative number")
return math.sqrt(value)
def get_tool_schema(self) -> Dict[str, Any]:
"""Get tool schema for agent integration."""
return {
"name": "calculator",
"description": "Perform mathematical calculations and evaluate expressions",
"parameters": {
"type": "object",
"properties": {
"expression": {
"type": "string",
"description": "Mathematical expression to evaluate (e.g., '2 + 2', 'sqrt(16)', 'pi * 2')",
},
},
"required": ["expression"],
},
}
# Global instance
_calculator: Calculator = None
def get_calculator() -> Calculator:
"""Get or create the global calculator instance."""
global _calculator
if _calculator is None:
_calculator = Calculator()
return _calculator