First_agent_template / todo_agents.py
mertcobanov's picture
Add todo management tools and refactor app configuration
80b16e1
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}"