import os import sys import re import json import logging import ast import operator as op from typing import List, Dict, Any, Optional from datetime import datetime, timedelta from smolagents import CodeAgent, DuckDuckGoSearchTool, InferenceClientModel, tool @tool def get_current_time() -> str: """Get the current date and time in a readable format.""" now = datetime.now() return now.strftime("%Y-%m-%d %H:%M:%S") @tool def calculate_basic_math(expression: str) -> str: """ Safely evaluate basic mathematical expressions using AST. Args: expression: A string containing a mathematical expression like "2+2" or "10*5" Returns: The result of the calculation as a string """ # Safe operations mapping SAFE_OPS = { ast.Add: op.add, ast.Sub: op.sub, ast.Mult: op.mul, ast.Div: op.truediv, ast.Pow: op.pow, ast.USub: op.neg } def _safe_eval(node): """Recursively evaluate AST nodes safely.""" if isinstance(node, ast.Num): # Numbers return node.n elif isinstance(node, ast.Constant): # Python 3.8+ constant nodes return node.value elif isinstance(node, ast.BinOp): # Binary operations return SAFE_OPS[type(node.op)](_safe_eval(node.left), _safe_eval(node.right)) elif isinstance(node, ast.UnaryOp): # Unary operations return SAFE_OPS[type(node.op)](_safe_eval(node.operand)) else: raise ValueError(f"Unsupported operation: {type(node)}") try: # Parse expression into AST and evaluate safely node = ast.parse(expression, mode='eval') result = _safe_eval(node.body) return f"Result: {result}" except Exception as e: return f"Error calculating '{expression}': {str(e)}" @tool def save_note(content: str, filename: Optional[str] = None) -> str: """ Save a note to a text file. Args: content: The content to save in the note filename: Optional filename. If not provided, uses timestamp Returns: Success message with filename """ try: if filename is None: timestamp = datetime.now().strftime("%Y%m%d_%H%M%S") filename = f"note_{timestamp}.txt" # Try to create notes directory, fall back to /tmp if permission denied try: os.makedirs("notes", exist_ok=True) notes_dir = "notes" except PermissionError: notes_dir = "/tmp/notes" os.makedirs(notes_dir, exist_ok=True) filepath = os.path.join(notes_dir, filename) with open(filepath, 'w', encoding='utf-8') as f: f.write(content) return f"✅ Note saved successfully to: {filepath}" except Exception as e: return f"❌ Error saving note: {str(e)}" @tool def list_saved_notes() -> str: """List all saved notes in the notes directory.""" try: # Check both possible notes directories all_files = [] for notes_dir in ["notes", "/tmp/notes"]: if os.path.exists(notes_dir): files = os.listdir(notes_dir) txt_files = [f for f in files if f.endswith('.txt')] all_files.extend([(f, notes_dir) for f in txt_files]) if not all_files: return "📂 No notes found. Save a note first!" file_list = "\n".join([f"- {file} ({location})" for file, location in sorted(all_files)]) return f"📂 Saved notes:\n{file_list}" except Exception as e: return f"❌ Error listing notes: {str(e)}"