myrmidon / python /src /server /services /projects /tasks /update_logic.py
tek Atrust
chore(deploy): build monolithic server for Hugging Face
d5ef46f
Raw
History Blame Contribute Delete
5.4 kB
"""
Update Logic Submodule for Task Service
"""
from datetime import datetime
from typing import Any
from src.server.config.logfire_config import get_logger
from src.server.services.shared_constants import AI_AGENT_ROLES
from src.server.utils.sse_manager import sse_manager
logger = get_logger(__name__)
async def update_task_logic(
task_service_instance, task_id: str, update_fields: dict[str, Any]
) -> tuple[bool, dict[str, Any]]:
"""
Update task with specified fields.
"""
try:
# Get current task state to check for status change
success, result = await task_service_instance.get_task(task_id)
if not success:
return False, result
current_task = result["task"]
# Build update data
update_data = {"updated_at": datetime.now().isoformat()}
# Validate and add fields
if "title" in update_fields:
update_data["title"] = update_fields["title"]
if "description" in update_fields:
update_data["description"] = update_fields["description"]
if "status" in update_fields:
new_status = update_fields["status"]
is_valid, error_msg = task_service_instance.validate_status(new_status)
if not is_valid:
return False, {"error": error_msg}
update_data["status"] = new_status
# If task is being marked as 'done', set completed_at timestamp
if new_status == "done" and current_task.get("status") != "done":
update_data["completed_at"] = datetime.now().isoformat()
# If task is being moved from 'done' to another status, clear completed_at
elif new_status != "done" and current_task.get("status") == "done":
update_data["completed_at"] = None # type: ignore
if "assignee" in update_fields:
is_valid, error_msg = task_service_instance.validate_assignee(update_fields["assignee"])
if not is_valid:
return False, {"error": error_msg}
update_data["assignee"] = update_fields["assignee"]
if "assignee_id" in update_fields:
update_data["assignee_id"] = update_fields["assignee_id"]
if "collaborator_agent_ids" in update_fields:
update_data["collaborator_agent_ids"] = update_fields["collaborator_agent_ids"]
if "task_order" in update_fields:
update_data["task_order"] = update_fields["task_order"]
if "feature" in update_fields:
update_data["feature"] = update_fields["feature"]
if "attachments" in update_fields:
update_data["attachments"] = update_fields["attachments"]
if "due_date" in update_fields:
# Ensure datetime is serialized to string for Supabase
due_val = update_fields["due_date"]
if hasattr(due_val, "isoformat"):
update_data["due_date"] = due_val.isoformat()
else:
update_data["due_date"] = due_val
if "priority" in update_fields:
update_data["priority"] = update_fields["priority"]
if "is_recurring" in update_fields:
update_data["is_recurring"] = update_fields["is_recurring"]
if "crawler_target_id" in update_fields:
update_data["crawler_target_id"] = update_fields["crawler_target_id"]
if "schedule_config" in update_fields:
update_data["schedule_config"] = update_fields["schedule_config"]
if "completed_at" in update_fields:
comp_val = update_fields["completed_at"]
if hasattr(comp_val, "isoformat"):
update_data["completed_at"] = comp_val.isoformat()
else:
update_data["completed_at"] = comp_val
# Update task
def _update_query():
return (
task_service_instance.supabase_client.table("archon_tasks")
.update(update_data)
.eq("id", task_id)
.execute()
)
success_update, update_result = task_service_instance.execute_query(
query_func=_update_query, error_context=f"Task with ID {task_id} not found"
)
if success_update:
task = update_result["data"][0]
# If the assignee was updated to an AI agent, notify the MCP
if "assignee" in update_fields:
new_assignee = update_fields["assignee"]
agent_id = None
for name, aid in AI_AGENT_ROLES.items():
if new_assignee and (name.startswith(new_assignee) or new_assignee in name):
agent_id = aid
break
if agent_id:
task_service_instance._notify_ai_agent_of_assignment(
task_id=task_id, agent_id=agent_id
)
# Phase 5.1.0: Broadcast update via SSE
await sse_manager.broadcast(
"task_updated", {"task_id": task_id, "status": task.get("status"), "task": task}
)
return True, {"task": task, "message": "Task updated successfully"}
return False, update_result
except Exception as e:
logger.error(f"Error updating task: {e}")
return False, {"error": f"Error updating task: {str(e)}"}