Spaces:
Sleeping
Sleeping
File size: 4,966 Bytes
8bf4d58 | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 | """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
|