Просмотр исходного кода

fix(foreground-fallback): don't clear retries on abort side effects

The session.status else branch cleared sessionRetries on ANY non-rate-limit
status, including abort events triggered by our own fallback. This reset
the counter to 0, so the next retry saw tried=0 and fired abort+fallback
again — creating an infinite loop until cancelled.

Retries now only clear on successful response (message.updated without
error) or session deletion.
Michael Henke 1 месяц назад
Родитель
Сommit
17ec559967

+ 15 - 3
src/hooks/foreground-fallback/index.test.ts

@@ -499,7 +499,11 @@ describe('ForegroundFallbackManager session.status', () => {
       type: 'session.status',
       properties: {
         sessionID: 'sess-retry2',
-        status: { type: 'retry', attempt: 1, message: 'rate limit, retrying...' },
+        status: {
+          type: 'retry',
+          attempt: 1,
+          message: 'rate limit, retrying...',
+        },
       },
     });
     expect(mocks.promptAsync).toHaveBeenCalledTimes(1);
@@ -509,14 +513,22 @@ describe('ForegroundFallbackManager session.status', () => {
       type: 'session.status',
       properties: {
         sessionID: 'sess-retry2',
-        status: { type: 'retry', attempt: 2, message: 'rate limit, retrying...' },
+        status: {
+          type: 'retry',
+          attempt: 2,
+          message: 'rate limit, retrying...',
+        },
       },
     });
     await mgr.handleEvent({
       type: 'session.status',
       properties: {
         sessionID: 'sess-retry2',
-        status: { type: 'retry', attempt: 3, message: 'rate limit, retrying...' },
+        status: {
+          type: 'retry',
+          attempt: 3,
+          message: 'rate limit, retrying...',
+        },
       },
     });
     expect(mocks.promptAsync).toHaveBeenCalledTimes(2);

+ 7 - 3
src/hooks/foreground-fallback/index.ts

@@ -229,10 +229,14 @@ export class ForegroundFallbackManager {
             await this.tryFallback(props.sessionID);
             this.sessionRetries.set(props.sessionID, 1);
           }
-        } else {
-          // Non-rate-limit status: clear retry count (recovery).
-          this.sessionRetries.delete(props.sessionID);
         }
+        // Note: do NOT clear sessionRetries here on non-rate-limit statuses.
+        // Abort events triggered by our own fallback carry non-rate-limit
+        // messages and would reset the counter, creating an infinite loop:
+        // abort → fallback → set retries to 1 → abort event clears retries
+        // → next retry sees tried=0 → abort+fallback again → repeat.
+        // Retries are only cleared on successful response (message.updated
+        // without error) or session deletion.
         break;
       }