Browse Source

Merge pull request #484 from zackslash/fix/insufficient-balance-detection

Alvin 2 months ago
parent
commit
8ccda032b6

+ 30 - 0
src/hooks/foreground-fallback/index.test.ts

@@ -85,6 +85,10 @@ describe('isRateLimitError', () => {
     expect(isRateLimitError({ message: 'overloaded_error' })).toBe(true);
   });
 
+  test('returns true for "Insufficient balance."', () => {
+    expect(isRateLimitError({ message: 'Insufficient balance.' })).toBe(true);
+  });
+
   test('returns false for non-rate-limit error', () => {
     expect(isRateLimitError({ message: 'invalid API key' })).toBe(false);
   });
@@ -326,6 +330,32 @@ describe('ForegroundFallbackManager session.status', () => {
     expect(mocks.promptAsync).toHaveBeenCalledTimes(1);
   });
 
+  test('triggers fallback on retry status with insufficient balance message', async () => {
+    const { client, mocks } = createMockClient();
+    const mgr = new ForegroundFallbackManager(client, makeChains(), true);
+
+    await mgr.handleEvent({
+      type: 'message.updated',
+      properties: {
+        info: {
+          sessionID: 'sess-5',
+          providerID: 'anthropic',
+          modelID: 'claude-opus-4-5',
+        },
+      },
+    });
+
+    await mgr.handleEvent({
+      type: 'session.status',
+      properties: {
+        sessionID: 'sess-5',
+        status: { type: 'retry', message: 'Insufficient balance.' },
+      },
+    });
+
+    expect(mocks.promptAsync).toHaveBeenCalledTimes(1);
+  });
+
   test('ignores session.status with non-rate-limit retry message', async () => {
     const { client, mocks } = createMockClient();
     const mgr = new ForegroundFallbackManager(client, makeChains(), true);

+ 2 - 1
src/hooks/foreground-fallback/index.ts

@@ -35,7 +35,7 @@ const RATE_LIMIT_PATTERNS = [
   /usage limit/i,
   /overloaded/i,
   /resource.?exhausted/i,
-  /insufficient.?quota/i,
+  /insufficient.?(quota|balance)/i,
   /high concurrency/i,
   /reduce concurrency/i,
 ];
@@ -168,6 +168,7 @@ export class ForegroundFallbackManager {
           msg.includes('quota exceeded') ||
           msg.includes('exceededbudget') ||
           msg.includes('over budget') ||
+          msg.includes('insufficient') ||
           msg.includes('high concurrency') ||
           msg.includes('reduce concurrency')
         ) {