From 2c8f4fcd5c78724206bfe03fe2e212cc63a29d54 Mon Sep 17 00:00:00 2001 From: "Gan, Jimmy" Date: Thu, 2 Apr 2026 10:22:15 +0800 Subject: [PATCH] fix: auto-assign tasks to PM agent when moved to in_progress, fix datetime serialization in WebSocket, add executor logging --- dashboard/backend/routers/opc_tasks.py | 11 ++++++++ dashboard/backend/routers/opc_ws.py | 28 +++++++++++++++++--- dashboard/backend/services/agent_executor.py | 8 ++++++ 3 files changed, 43 insertions(+), 4 deletions(-) diff --git a/dashboard/backend/routers/opc_tasks.py b/dashboard/backend/routers/opc_tasks.py index fa7f06b..2eba819 100644 --- a/dashboard/backend/routers/opc_tasks.py +++ b/dashboard/backend/routers/opc_tasks.py @@ -217,6 +217,17 @@ async def move_task( actor=user.username ) + # Auto-assign to default agent (PM) if not already assigned + if not current_task.get("assigned_to"): + updates["assigned_to"] = "pm" + updates["assigned_type"] = "agent" + # Create agent execution record + await opc_db.create_agent_execution( + task_id=task_id, + agent_id="pm", + actor=user.username + ) + if old_status == "in_progress" and move.status != "in_progress": await opc_db.stop_time_entry(task_id=task_id) diff --git a/dashboard/backend/routers/opc_ws.py b/dashboard/backend/routers/opc_ws.py index 3a03153..6f7afca 100644 --- a/dashboard/backend/routers/opc_ws.py +++ b/dashboard/backend/routers/opc_ws.py @@ -74,24 +74,44 @@ async def websocket_endpoint(websocket: WebSocket): async def broadcast_task_update(task_id: int, action: str, task_data: dict): """Broadcast task update to all connected clients""" + # Serialize datetime objects to ISO format + serialized_data = task_data.copy() + for key in ["created_at", "updated_at", "completed_at", "due_date"]: + if serialized_data.get(key): + serialized_data[key] = serialized_data[key].isoformat() if hasattr(serialized_data[key], 'isoformat') else serialized_data[key] + + timestamp = task_data.get("updated_at") + if timestamp and hasattr(timestamp, 'isoformat'): + timestamp = timestamp.isoformat() + message = { "type": "task_update", "task_id": task_id, "action": action, # created, updated, moved, deleted - "data": task_data, - "timestamp": task_data.get("updated_at") + "data": serialized_data, + "timestamp": timestamp } await manager.broadcast(message) async def broadcast_agent_execution(execution_id: int, status: str, execution_data: dict): """Broadcast agent execution update""" + # Serialize datetime objects to ISO format + serialized_data = execution_data.copy() + for key in ["started_at", "completed_at"]: + if serialized_data.get(key): + serialized_data[key] = serialized_data[key].isoformat() if hasattr(serialized_data[key], 'isoformat') else serialized_data[key] + + timestamp = execution_data.get("started_at") or execution_data.get("completed_at") + if timestamp and hasattr(timestamp, 'isoformat'): + timestamp = timestamp.isoformat() + message = { "type": "agent_execution", "execution_id": execution_id, "status": status, # pending, running, completed, failed, pending_approval - "data": execution_data, - "timestamp": execution_data.get("started_at") or execution_data.get("completed_at") + "data": serialized_data, + "timestamp": timestamp } await manager.broadcast(message) diff --git a/dashboard/backend/services/agent_executor.py b/dashboard/backend/services/agent_executor.py index b74b42a..bf860be 100644 --- a/dashboard/backend/services/agent_executor.py +++ b/dashboard/backend/services/agent_executor.py @@ -43,13 +43,18 @@ class AgentExecutor: async def start(self): """Start the executor service""" self.running = True + print("=== Agent Executor Loop Started ===") logger.info("Agent executor service started") while self.running: try: + print(f"[Executor] Checking for pending executions... (running={self.running})") await self._process_pending_executions() except Exception as e: + print(f"[Executor] Error in executor loop: {e}") logger.error(f"Error in executor loop: {e}") + import traceback + traceback.print_exc() await asyncio.sleep(5) # Check every 5 seconds @@ -61,11 +66,14 @@ class AgentExecutor: async def _process_pending_executions(self): """Process pending agent executions""" executions = await opc_db.get_agent_executions(status="pending", limit=10) + print(f"[Executor] Found {len(executions)} pending executions") for execution in executions: try: + print(f"[Executor] Processing execution {execution['id']} for agent {execution['agent_id']}") await self._execute_agent(execution) except Exception as e: + print(f"[Executor] Failed to execute agent {execution['agent_id']}: {e}") logger.error(f"Failed to execute agent {execution['agent_id']}: {e}") await self._mark_execution_failed(execution["id"], str(e))