|
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] |
|
|
|
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:") |
|
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" |
|
""" |
|
|
|
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" |
|
|
|
|
|
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}" |
|
|