fix: complete OPC system implementation
- 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:
@@ -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"""
|
||||
|
||||
Reference in New Issue
Block a user