From ea386015643ca47cb47fdfb41f1363ea2a525b04 Mon Sep 17 00:00:00 2001 From: TranslateMe Date: Thu, 8 Jan 2026 12:46:53 -0500 Subject: [PATCH] fix: Reset AbortController before starting generator to prevent infinite abort loop MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit When a generator exits with wasAborted=true, the AbortController remains in aborted state but generatorPromise is set to null. When a new observation arrives, ensureGeneratorRunning() sees generatorPromise=null and tries to start a new generator, but the new generator immediately sees signal.aborted=true and exits, causing an infinite "Generator aborted" loop. This fix resets the AbortController if it's already aborted before starting a new generator, allowing the session to recover from the stuck state. Bug reproduction: 1. Session receives observations 2. Something causes the generator to be aborted 3. generatorPromise = null, but abortController.signal.aborted = true 4. New observation arrives → starts generator → immediately aborted → loop Fix: Check if abortController.signal.aborted before starting generator, and create a new AbortController if needed. --- src/services/worker/http/routes/SessionRoutes.ts | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/src/services/worker/http/routes/SessionRoutes.ts b/src/services/worker/http/routes/SessionRoutes.ts index 3eb45396..396eb026 100644 --- a/src/services/worker/http/routes/SessionRoutes.ts +++ b/src/services/worker/http/routes/SessionRoutes.ts @@ -122,6 +122,16 @@ export class SessionRoutes extends BaseRouteHandler { ): void { if (!session) return; + // Reset AbortController if it was previously aborted + // This fixes the bug where a session gets stuck in an infinite "Generator aborted" loop + // after its AbortController was aborted (e.g., from a previous generator exit) + if (session.abortController.signal.aborted) { + logger.debug('SESSION', 'Resetting aborted AbortController before starting generator', { + sessionId: session.sessionDbId + }); + session.abortController = new AbortController(); + } + const agent = provider === 'openrouter' ? this.openRouterAgent : (provider === 'gemini' ? this.geminiAgent : this.sdkAgent); const agentName = provider === 'openrouter' ? 'OpenRouter' : (provider === 'gemini' ? 'Gemini' : 'Claude SDK');