From 91ce7dc4c0f091023f9c43d4074f1b7aa38bc8fa Mon Sep 17 00:00:00 2001 From: Lukas May Date: Thu, 5 Mar 2026 10:10:40 +0100 Subject: [PATCH] fix: Prevent commit-retry infinite loop by preserving retry count across cleanup commitRetryCount was being deleted in cleanupAgentState(), which runs before tryAutoCleanup() checks the count. This reset the counter to 0 on every cycle, making MAX_COMMIT_RETRIES=1 dead code. Agents would retry commits forever. Move commitRetryCount cleanup to stop()/delete() only, letting tryAutoCleanup() manage it during the retry lifecycle. --- apps/server/agent/manager.ts | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/apps/server/agent/manager.ts b/apps/server/agent/manager.ts index 6ca303f..6c62c0d 100644 --- a/apps/server/agent/manager.ts +++ b/apps/server/agent/manager.ts @@ -107,13 +107,14 @@ export class MultiProviderAgentManager implements AgentManager { /** * Centralized cleanup of all in-memory state for an agent. - * Cancels polling timer, removes from activeAgents and commitRetryCount. + * Cancels polling timer, removes from activeAgents. + * NOTE: Does NOT clear commitRetryCount — that's managed by tryAutoCleanup() + * and explicitly by stop()/delete() to avoid resetting retries mid-cycle. */ private cleanupAgentState(agentId: string): void { const active = this.activeAgents.get(agentId); if (active?.cancelPoll) active.cancelPoll(); this.activeAgents.delete(agentId); - this.commitRetryCount.delete(agentId); } /** @@ -635,6 +636,7 @@ export class MultiProviderAgentManager implements AgentManager { await active.tailer.stop(); } this.cleanupAgentState(agentId); + this.commitRetryCount.delete(agentId); // Sync credentials before marking stopped await this.syncCredentialsPostCompletion(agentId); @@ -811,6 +813,7 @@ export class MultiProviderAgentManager implements AgentManager { await active.tailer.stop(); } this.cleanupAgentState(agentId); + this.commitRetryCount.delete(agentId); // 2. Best-effort cleanup try { await this.cleanupManager.removeAgentWorktrees(agent.name, agent.initiativeId); }