Execution Loop
Agent Runner Startup
Section titled “Agent Runner Startup”flowchart LR
A[Coolify starts\nagent-runner] --> B[Load config\nfrom Backend API]
B --> C[Poll for active\nscheduled agents]
C --> D{Agents found?}
D -->|Yes| E[Register cron jobs\nfor each agent]
D -->|No| F[Wait 60s]
F --> C
E --> G[Begin cron\nlistening]
G --> H{Cron fires}
H --> I[Execute agent]
I --> H
Single Agent Execution
Section titled “Single Agent Execution”sequenceDiagram
participant CRON as Cron Job
participant AR as Agent Runner
participant BE as Backend :8080
participant AIS as AI Service :9300
participant DC as Discord
CRON->>AR: Agent 42 fires
AR->>BE: GET /api/v1/agents/42
BE-->>AR: {systemPrompt, toolsAllowed, alertCondition}
AR->>AR: Build execution context\n{startTime, agentId, workspaceId}
AR->>AIS: POST /api/v1/chat/sync\n{message: suggestedQuery,\n systemPrompt,\n toolsAllowed}
Note over AIS: AgentLoop runs\ntools called internally
AIS-->>AR: {response, toolsUsed, tokenUsage}
AR->>AR: Parse response\nExtract metrics
AR->>BE: POST /api/v1/agents/42/executions\n{status, duration, toolsUsed,\n aiResponse, alertTriggered}
alt Alert condition met
AR->>AR: Evaluate alertCondition\ne.g. error_rate > 5%
AR->>DC: POST webhook\n{embed with findings}
end
Execution Context Object
Section titled “Execution Context Object”interface AgentExecutionContext { agentId: number; workspaceId: string; startedAt: Date; systemPrompt: string; toolsAllowed: string[]; suggestedQuery: string; alertCondition?: { metric: string; // e.g. "error_count", "avg_latency" operator: 'gt' | 'lt' | 'eq'; threshold: number; }; alertChannel?: string; // Discord webhook URL}Execution Result Object
Section titled “Execution Result Object”interface AgentExecutionResult { agentId: number; workspaceId: string; startedAt: Date; finishedAt: Date; status: 'success' | 'failed' | 'timeout'; durationMs: number; toolsUsed: string[]; aiResponse: string; alertTriggered: boolean; alertValue?: number; errorMessage?: string;}Timeout Handling
Section titled “Timeout Handling”Agents have a 120-second timeout by default. If the AI Service doesn’t respond within that window:
AbortControllercancels the request- Execution is logged as
status: 'timeout' - Agent state transitions to
error - Discord notification sent: “Agent 42 timed out after 120s”
Retry Policy
Section titled “Retry Policy”| Failure Type | Retry? | Backoff |
|---|---|---|
| Network error | Yes | 3 retries, exponential |
| LLM error | Yes | 2 retries, 5s delay |
| Tool error | No (LLM decides) | — |
| Timeout | No | Log and move on |
Alert Evaluation
Section titled “Alert Evaluation”After each execution, the Agent Runner evaluates the alert condition against the AI response:
function evaluateAlert( condition: AlertCondition, aiResponse: string): { triggered: boolean; value?: number } { // Extract numeric value from AI response using regex // e.g. "error rate: 7.3%" → 7.3 const extracted = extractMetric(aiResponse, condition.metric);
if (extracted === null) return { triggered: false };
const triggered = condition.operator === 'gt' ? extracted > condition.threshold : condition.operator === 'lt' ? extracted < condition.threshold : extracted === condition.threshold;
return { triggered, value: extracted };}Discord Alert Format
Section titled “Discord Alert Format”When an alert triggers, the Agent Runner posts a Discord embed:
🚨 Agent Alert: Payment Error Monitor━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━Workspace: LogriteCondition: error_rate > 5%Detected: 7.3%
Agent Summary:"In the last hour, I found 47 payment timeouterrors (7.3% error rate). Most affected: Stripewebhook endpoint. Errors spiked at 14:23 UTC..."
[View Details] [Silence for 1h]Cron Registration
Section titled “Cron Registration”// Agent runner uses node-cron for schedule managementimport cron from 'node-cron';
function registerAgent(agent: AgentConfig): void { const task = cron.schedule(agent.schedule, async () => { const result = await executeAgent(agent); await storeResult(result); await evaluateAndAlert(result, agent); }, { timezone: 'UTC' });
activeTasks.set(agent.id, task);}Agent Re-polling
Section titled “Agent Re-polling”The Agent Runner re-polls the Backend every 60 seconds to pick up:
- Newly created agents
- Schedule changes
- Paused/deleted agents
setInterval(async () => { const current = await fetchActiveAgents(); reconcileCronJobs(current, activeTasks);}, 60_000);