Spaces:
Sleeping
Sleeping
| """MCP Tools for the AI Todo Chatbot agent. | |
| These tools provide task operations that the AI agent can call. | |
| Each tool enforces user isolation by requiring and validating user_id. | |
| """ | |
| from typing import Optional, Dict, Any | |
| from uuid import UUID | |
| from datetime import datetime | |
| from agents import function_tool | |
| from ..models.task import Task | |
| from ..database import get_db | |
| def add_task( | |
| user_id: str, | |
| title: str, | |
| description: Optional[str] = None | |
| ) -> Dict[str, Any]: | |
| """ | |
| Create a new task for the user. | |
| Args: | |
| user_id: The authenticated user's ID (UUID string) | |
| title: The title of the task (1-200 characters) | |
| description: Optional description of the task (max 1000 characters) | |
| Returns: | |
| Dictionary with task_id, title, and status | |
| """ | |
| try: | |
| user_uuid = UUID(user_id) | |
| with get_db() as db: | |
| task = Task( | |
| title=title[:200], | |
| description=description[:1000] if description else None, | |
| completed=False, | |
| user_id=user_uuid, | |
| created_at=datetime.utcnow(), | |
| updated_at=datetime.utcnow() | |
| ) | |
| db.add(task) | |
| db.commit() | |
| db.refresh(task) | |
| return { | |
| "task_id": task.id, | |
| "title": task.title, | |
| "status": "created", | |
| "message": f"Task '{title}' has been created." | |
| } | |
| except Exception as e: | |
| return { | |
| "status": "error", | |
| "message": f"Failed to create task: {str(e)}" | |
| } | |
| def list_tasks( | |
| user_id: str, | |
| status: Optional[str] = None | |
| ) -> Dict[str, Any]: | |
| """ | |
| List all tasks for the user. | |
| Args: | |
| user_id: The authenticated user's ID (UUID string) | |
| status: Optional filter - 'pending', 'completed', or None for all | |
| Returns: | |
| Dictionary with tasks array and summary | |
| """ | |
| try: | |
| user_uuid = UUID(user_id) | |
| with get_db() as db: | |
| query = db.query(Task).filter(Task.user_id == user_uuid) | |
| if status == "pending": | |
| query = query.filter(Task.completed == False) | |
| elif status == "completed": | |
| query = query.filter(Task.completed == True) | |
| tasks = query.order_by(Task.created_at.desc()).all() | |
| task_list = [ | |
| { | |
| "id": task.id, | |
| "title": task.title, | |
| "description": task.description, | |
| "completed": task.completed, | |
| "created_at": task.created_at.isoformat() if task.created_at else None | |
| } | |
| for task in tasks | |
| ] | |
| pending_count = sum(1 for t in tasks if not t.completed) | |
| completed_count = sum(1 for t in tasks if t.completed) | |
| return { | |
| "tasks": task_list, | |
| "total": len(tasks), | |
| "pending": pending_count, | |
| "completed": completed_count, | |
| "status": "success", | |
| "summary": f"You have {len(tasks)} task(s): {pending_count} pending, {completed_count} completed" | |
| } | |
| except Exception as e: | |
| return { | |
| "tasks": [], | |
| "status": "error", | |
| "message": f"Failed to list tasks: {str(e)}" | |
| } | |
| def complete_task( | |
| user_id: str, | |
| task_id: int | |
| ) -> Dict[str, Any]: | |
| """ | |
| Toggle the completion status of a task. | |
| Args: | |
| user_id: The authenticated user's ID (UUID string) | |
| task_id: The ID of the task to complete/uncomplete | |
| Returns: | |
| Dictionary with task_id, title, and new status | |
| """ | |
| try: | |
| user_uuid = UUID(user_id) | |
| with get_db() as db: | |
| task = ( | |
| db.query(Task) | |
| .filter(Task.id == task_id, Task.user_id == user_uuid) | |
| .first() | |
| ) | |
| if not task: | |
| return { | |
| "status": "error", | |
| "message": f"Task {task_id} not found. It may have been deleted or doesn't exist." | |
| } | |
| # Toggle completion status | |
| task.completed = not task.completed | |
| task.updated_at = datetime.utcnow() | |
| db.commit() | |
| db.refresh(task) | |
| new_status = "completed" if task.completed else "incomplete" | |
| return { | |
| "task_id": task.id, | |
| "title": task.title, | |
| "completed": task.completed, | |
| "status": new_status, | |
| "message": f"Task '{task.title}' marked as {new_status}." | |
| } | |
| except Exception as e: | |
| return { | |
| "status": "error", | |
| "message": f"Failed to update task: {str(e)}" | |
| } | |
| def update_task( | |
| user_id: str, | |
| task_id: int, | |
| title: Optional[str] = None, | |
| description: Optional[str] = None | |
| ) -> Dict[str, Any]: | |
| """ | |
| Update a task's title and/or description. | |
| Args: | |
| user_id: The authenticated user's ID (UUID string) | |
| task_id: The ID of the task to update | |
| title: New title for the task (optional) | |
| description: New description for the task (optional) | |
| Returns: | |
| Dictionary with task_id, updated fields, and status | |
| """ | |
| try: | |
| user_uuid = UUID(user_id) | |
| with get_db() as db: | |
| task = ( | |
| db.query(Task) | |
| .filter(Task.id == task_id, Task.user_id == user_uuid) | |
| .first() | |
| ) | |
| if not task: | |
| return { | |
| "status": "error", | |
| "message": f"Task {task_id} not found. It may have been deleted or doesn't exist." | |
| } | |
| updated_fields = [] | |
| if title is not None: | |
| task.title = title[:200] | |
| updated_fields.append("title") | |
| if description is not None: | |
| task.description = description[:1000] if description else None | |
| updated_fields.append("description") | |
| if not updated_fields: | |
| return { | |
| "status": "error", | |
| "message": "No fields provided to update." | |
| } | |
| task.updated_at = datetime.utcnow() | |
| db.commit() | |
| db.refresh(task) | |
| return { | |
| "task_id": task.id, | |
| "title": task.title, | |
| "description": task.description, | |
| "updated_fields": updated_fields, | |
| "status": "updated", | |
| "message": f"Task {task_id} has been updated." | |
| } | |
| except Exception as e: | |
| return { | |
| "status": "error", | |
| "message": f"Failed to update task: {str(e)}" | |
| } | |
| def delete_task( | |
| user_id: str, | |
| task_id: int | |
| ) -> Dict[str, Any]: | |
| """ | |
| Delete a task. | |
| Args: | |
| user_id: The authenticated user's ID (UUID string) | |
| task_id: The ID of the task to delete | |
| Returns: | |
| Dictionary with task_id, title, and status | |
| """ | |
| try: | |
| user_uuid = UUID(user_id) | |
| with get_db() as db: | |
| task = ( | |
| db.query(Task) | |
| .filter(Task.id == task_id, Task.user_id == user_uuid) | |
| .first() | |
| ) | |
| if not task: | |
| return { | |
| "status": "error", | |
| "message": f"Task {task_id} not found. It may have been deleted or doesn't exist." | |
| } | |
| task_title = task.title | |
| task_id_deleted = task.id | |
| db.delete(task) | |
| db.commit() | |
| return { | |
| "task_id": task_id_deleted, | |
| "title": task_title, | |
| "status": "deleted", | |
| "message": f"Task '{task_title}' has been deleted." | |
| } | |
| except Exception as e: | |
| return { | |
| "status": "error", | |
| "message": f"Failed to delete task: {str(e)}" | |
| } | |