From 63400211b829d725caa86c8b1fd6375f6ab8cf6b Mon Sep 17 00:00:00 2001 From: Lukas May Date: Wed, 4 Mar 2026 14:01:54 +0100 Subject: [PATCH] fix: Auto-complete tasks when agents finish successfully The orchestrator's agent:stopped listener only called scheduleDispatch(), never marking the agent's assigned task as completed. Tasks stayed in_progress forever after their agent finished. Now handleAgentStopped() calls dispatchManager.completeTask() before scheduling new dispatches, respecting requiresApproval and skipping manual (user_requested) stops. --- apps/server/execution/orchestrator.ts | 27 +++++++++++++++++++++++++-- 1 file changed, 25 insertions(+), 2 deletions(-) diff --git a/apps/server/execution/orchestrator.ts b/apps/server/execution/orchestrator.ts index a9238db..de62157 100644 --- a/apps/server/execution/orchestrator.ts +++ b/apps/server/execution/orchestrator.ts @@ -59,8 +59,12 @@ export class ExecutionOrchestrator { // Kick off dispatch when phases are queued (e.g. user clicks Execute) this.eventBus.on('phase:queued', () => this.scheduleDispatch()); - // Re-dispatch queued tasks when an agent finishes and frees a slot - this.eventBus.on('agent:stopped', () => this.scheduleDispatch()); + // Auto-complete task + re-dispatch when an agent finishes + this.eventBus.on('agent:stopped', (event) => { + this.handleAgentStopped(event).catch((err) => { + log.error({ err: err instanceof Error ? err.message : String(err) }, 'error handling agent:stopped'); + }); + }); log.info('execution orchestrator started'); } @@ -83,6 +87,25 @@ export class ExecutionOrchestrator { ); } + private async handleAgentStopped(event: AgentStoppedEvent): Promise { + const { taskId, reason, agentId } = event.payload; + + // Auto-complete task for successful agent completions, not manual stops + if (taskId && reason !== 'user_requested') { + try { + await this.dispatchManager.completeTask(taskId, agentId); + log.info({ taskId, agentId, reason }, 'task auto-completed on agent stop'); + } catch (err) { + log.warn( + { taskId, agentId, reason, err: err instanceof Error ? err.message : String(err) }, + 'failed to auto-complete task on agent stop', + ); + } + } + + this.scheduleDispatch(); + } + private async runDispatchCycle(): Promise { this.dispatchRunning = true; try {