@azumag/opencode-rate-limit-fallback 1.39.0 → 1.40.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -19,6 +19,7 @@ export declare class FallbackHandler {
19
19
  private retryState;
20
20
  private fallbackInProgress;
21
21
  private fallbackMessages;
22
+ private sessionLock;
22
23
  private metricsManager;
23
24
  private subagentTracker;
24
25
  private retryManager;
@@ -19,6 +19,7 @@ export class FallbackHandler {
19
19
  retryState;
20
20
  fallbackInProgress;
21
21
  fallbackMessages;
22
+ sessionLock;
22
23
  // Metrics manager reference
23
24
  metricsManager;
24
25
  // Subagent tracker reference
@@ -46,6 +47,7 @@ export class FallbackHandler {
46
47
  this.retryState = new Map();
47
48
  this.fallbackInProgress = new Map();
48
49
  this.fallbackMessages = new Map();
50
+ this.sessionLock = new Set();
49
51
  // Initialize retry manager
50
52
  this.retryManager = new RetryManager(config.retryPolicy || {}, logger);
51
53
  }
@@ -147,10 +149,16 @@ export class FallbackHandler {
147
149
  * Handle the rate limit fallback process
148
150
  */
149
151
  async handleRateLimitFallback(sessionID, currentProviderID, currentModelID) {
152
+ // Resolve target session before acquiring lock
153
+ const rootSessionID = this.subagentTracker.getRootSession(sessionID);
154
+ const targetSessionID = rootSessionID || sessionID;
155
+ // Session-level lock: prevent concurrent fallback processing
156
+ if (this.sessionLock.has(targetSessionID)) {
157
+ this.logger.debug(`Fallback already in progress for session ${targetSessionID}, skipping`);
158
+ return;
159
+ }
160
+ this.sessionLock.add(targetSessionID);
150
161
  try {
151
- // Get root session and hierarchy using subagent tracker
152
- const rootSessionID = this.subagentTracker.getRootSession(sessionID);
153
- const targetSessionID = rootSessionID || sessionID;
154
162
  const hierarchy = this.subagentTracker.getHierarchy(sessionID);
155
163
  // If no model info provided, try to get from tracked session model
156
164
  if (!currentProviderID || !currentModelID) {
@@ -309,10 +317,11 @@ export class FallbackHandler {
309
317
  name: errorName,
310
318
  });
311
319
  // Record retry failure on error
312
- const rootSessionID = this.subagentTracker.getRootSession(sessionID);
313
- const targetSessionID = rootSessionID || sessionID;
314
320
  this.retryManager.recordFailure(targetSessionID);
315
321
  }
322
+ finally {
323
+ this.sessionLock.delete(targetSessionID);
324
+ }
316
325
  }
317
326
  /**
318
327
  * Handle message updated events for metrics recording
@@ -419,6 +428,7 @@ export class FallbackHandler {
419
428
  this.retryState.clear();
420
429
  this.fallbackInProgress.clear();
421
430
  this.fallbackMessages.clear();
431
+ this.sessionLock.clear();
422
432
  this.retryManager.destroy();
423
433
  // Destroy circuit breaker
424
434
  if (this.circuitBreaker) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@azumag/opencode-rate-limit-fallback",
3
- "version": "1.39.0",
3
+ "version": "1.40.0",
4
4
  "description": "OpenCode plugin that automatically switches to fallback models when rate limited",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",