fix: complete OPC system implementation
Deploy Dashboard (Dev) / deploy-dev (push) Failing after 10m4s
Run Tests / Frontend Tests (push) Failing after 14m28s
Run Tests / Backend Tests (push) Failing after 14m50s
Run Tests / Test Summary (push) Has been cancelled

- Add database connection retry logic (3 attempts, 5s delay)
- Add missing database functions: get_task_by_id, get_agent_execution, approve_agent_execution, update_agent_config, update_execution_status
- Complete agent execution approval workflow
- Fix agent executor to handle approved executions
- Fix inefficient task queries (use direct ID lookup)
- Add error action handling in agent executor
- Improve LiteLLM error handling with specific exception types
- Reduce LiteLLM timeout from 60s to 30s
- Fix execution status update to only set started_at once
- Consolidate WebSocket datetime serialization with helper function
- Implement update agent endpoint
This commit is contained in:
Gan, Jimmy
2026-04-03 22:30:51 +08:00
parent a42e3d3050
commit 5da2ae01a0
5 changed files with 333 additions and 56 deletions
+55 -13
View File
@@ -65,13 +65,23 @@ 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")
# Process both pending and approved executions
pending_executions = await opc_db.get_agent_executions(status="pending", limit=10)
approved_executions = await opc_db.get_agent_executions(status="approved", limit=10)
executions = pending_executions + approved_executions
print(f"[Executor] Found {len(pending_executions)} pending and {len(approved_executions)} approved executions")
for execution in executions:
try:
print(f"[Executor] Processing execution {execution['id']} for agent {execution['agent_id']}")
await self._execute_agent(execution)
print(f"[Executor] Processing execution {execution['id']} for agent {execution['agent_id']} (status: {execution['status']})")
if execution['status'] == 'approved':
# Resume approved execution
await self._resume_approved_execution(execution)
else:
# Execute new pending execution
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}")
@@ -91,8 +101,7 @@ class AgentExecutor:
await self._update_execution_status(execution["id"], "running")
# Get task and context
tasks = await opc_db.get_tasks(limit=1000)
task = next((t for t in tasks if t["id"] == task_id), None)
task = await opc_db.get_task_by_id(task_id)
if not task:
raise ValueError(f"Task {task_id} not found")
@@ -118,6 +127,39 @@ class AgentExecutor:
# Send completion notification
await self._send_completion_notification(agent, task, result)
async def _resume_approved_execution(self, execution: Dict[str, Any]):
"""Resume an approved execution and execute its actions"""
agent_id = execution["agent_id"]
task_id = execution["task_id"]
# Get agent
agent = self.agents.get(agent_id)
if not agent:
raise ValueError(f"Agent {agent_id} not found")
# Get task
task = await opc_db.get_task_by_id(task_id)
if not task:
raise ValueError(f"Task {task_id} not found")
# Mark as running
await self._update_execution_status(execution["id"], "running")
# Get proposed actions from execution
result = execution.get("output_result", {})
actions = execution.get("actions_proposed", [])
logger.info(f"Resuming approved execution for agent {agent.name} on task {task['title']}")
# Execute approved actions
await self._execute_actions(task, actions)
# Mark as completed
await self._mark_execution_completed(execution["id"], result)
# Send completion notification
await self._send_completion_notification(agent, task, result)
async def _build_context(self, task: Dict[str, Any]) -> Dict[str, Any]:
"""Build context for agent execution"""
context = {
@@ -150,10 +192,16 @@ class AgentExecutor:
await self._action_send_notification(action)
elif action_type == "add_comment":
await self._action_add_comment(task, action)
elif action_type == "error":
# Handle error action - log and fail execution
error_msg = action.get("message", "Unknown error")
logger.error(f"Agent reported error: {error_msg}")
raise Exception(error_msg)
else:
logger.warning(f"Unknown action type: {action_type}")
except Exception as e:
logger.error(f"Failed to execute action {action_type}: {e}")
raise
async def _action_create_subtask(self, parent_task: Dict[str, Any], action: Dict[str, Any]):
"""Create a subtask"""
@@ -199,13 +247,7 @@ class AgentExecutor:
async def _update_execution_status(self, execution_id: int, status: str):
"""Update execution status"""
pool = await opc_db.get_pool()
async with pool.acquire() as conn:
await conn.execute("""
UPDATE agent_executions
SET status = $1, started_at = CURRENT_TIMESTAMP
WHERE id = $2
""", status, execution_id)
await opc_db.update_execution_status(execution_id, status)
async def _mark_execution_completed(self, execution_id: int, result: Dict[str, Any]):
"""Mark execution as completed"""