import datetime import json import uuid from dataclasses import dataclass from pathlib import Path from typing import Dict, List import pytz from smolagents import tool @dataclass class Task: id: str = None completed: bool = False description: str = "" last_updated: str = "" def __post_init__(self): if self.id is None: self.id = str(uuid.uuid4()) def to_dict(self) -> Dict: return { "id": self.id, "completed": self.completed, "description": self.description, "last_updated": self.last_updated, } class TodoManager: def __init__(self, filepath: str = "todo.jsonl"): self.filepath = Path(filepath) if not self.filepath.exists(): self.filepath.write_text("") def _read_tasks(self) -> List[Task]: if not self.filepath.exists(): return [] try: with self.filepath.open("r", encoding="utf-8") as file: data = [json.loads(line) for line in file if line.strip()] return [ Task( description=item.get("description", item.get("task", "")), completed=item.get("completed", item.get("status") == "āœ…"), last_updated=item["last_updated"], id=item.get("id"), ) for item in data ] except json.JSONDecodeError: return [] def _save_tasks(self, tasks: List[Task]): with self.filepath.open("w") as file: for task in tasks: file.write(json.dumps(task.to_dict()) + "\n") @tool def get_current_time_in_timezone(timezone: str) -> str: """A tool that fetches the current local time in a specified timezone. Args: timezone: A string representing a valid timezone (e.g., 'America/New_York'). """ try: tz = pytz.timezone(timezone) local_time = datetime.datetime.now(tz).strftime("%Y-%m-%d %H:%M:%S") return f"The current local time in {timezone} is: {local_time}" except Exception as e: return f"Error fetching time for timezone '{timezone}': {str(e)}" @tool def get_todays_tasks() -> str: """List all tasks with their status and details. Args: None Returns: A formatted string containing all tasks with their status and IDs. """ manager = TodoManager("./todo.jsonl") tasks = manager._read_tasks() if not tasks: return "No tasks found" pending = [t for t in tasks if not t.completed] completed = [t for t in tasks if t.completed] # Uncomment this to show all tasks output = [f"šŸ“… Tasks Report for {datetime.date.today()}"] output.append("\nšŸ”“ Pending Tasks:") output.extend(f"[{t.id[:8]}] {t.description}" for t in pending) output.append("\nāœ… Completed Tasks:") # Show both pending and completed tasks output.extend(f"[{t.id[:8]}] {t.description}" for t in completed) output.append(f"\nTotal: {len(pending)} pending, {len(completed)} completed") return "\n".join(output) @tool def update_task_status(task_id: str) -> str: """Toggle a task's completion status between complete and pending. Args: task_id: First 8 characters of the task's UUID (e.g., '65118069' from '65118069-b2a4-4ea3-b8e9-d7921381cbfc'). You can find task IDs in square brackets when listing tasks. Returns: Success message with task details if found and updated. Error message if task not found or invalid input. Examples: > update_task_status('65118069') "āœ… Task [65118069] marked as complete: Repair my computer" > update_task_status('65118069') "āœ… Task [65118069] marked as pending: Repair my computer" """ # Validate task_id format if not task_id or not isinstance(task_id, str) or len(task_id) < 1: return "āŒ Please provide a valid task ID" try: manager = TodoManager("./todo.jsonl") tasks = manager._read_tasks() if not tasks: return "āŒ No tasks found in the todo list" # Find and update the task for task in tasks: if task.id.startswith(task_id): task.completed = not task.completed task.last_updated = datetime.date.today().strftime("%Y-%m-%d") manager._save_tasks(tasks) return f"āœ… Task [{task_id}] marked as {'complete' if task.completed else 'pending'}: {task.description}" return f"āŒ No task found with ID '{task_id}'" except (json.JSONDecodeError, IOError) as e: return f"āŒ Error accessing todo list: {str(e)}" except Exception as e: return f"āŒ Unexpected error: {str(e)}" @tool def add_task(description: str) -> str: """Add a new task to the todo list. Args: description: The text description of the task to add. Returns: A confirmation message indicating the task was added. """ manager = TodoManager("./todo.jsonl") tasks = manager._read_tasks() new_task = Task( description=description, completed=False, last_updated=datetime.date.today().strftime("%Y-%m-%d"), ) tasks.append(new_task) manager._save_tasks(tasks) return f"āœ… Added new task: {description}"