Tahasaif3's picture
'code'
e103642
"""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
@function_tool
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)}"
}
@function_tool
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)}"
}
@function_tool
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)}"
}
@function_tool
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)}"
}
@function_tool
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)}"
}