@azumag/opencode-rate-limit-fallback 1.0.21 → 1.1.2
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.
- package/dist/index.d.ts +1 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +322 -305
- package/dist/index.js.map +1 -0
- package/package.json +20 -19
package/dist/index.d.ts
CHANGED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,qBAAqB,CAAC;AA6NlD,eAAO,MAAM,iBAAiB,EAAE,MA4c/B,CAAC;AAEF,eAAe,iBAAiB,CAAC"}
|
package/dist/index.js
CHANGED
|
@@ -1,12 +1,51 @@
|
|
|
1
|
-
import { existsSync, readFileSync
|
|
2
|
-
import { join
|
|
3
|
-
//
|
|
4
|
-
|
|
1
|
+
import { existsSync, readFileSync } from "fs";
|
|
2
|
+
import { join } from "path";
|
|
3
|
+
// Event type guards
|
|
4
|
+
function isSessionErrorEvent(event) {
|
|
5
|
+
return event.type === "session.error" &&
|
|
6
|
+
typeof event.properties === "object" &&
|
|
7
|
+
event.properties !== null &&
|
|
8
|
+
"sessionID" in event.properties &&
|
|
9
|
+
"error" in event.properties;
|
|
10
|
+
}
|
|
11
|
+
function isMessageUpdatedEvent(event) {
|
|
12
|
+
return event.type === "message.updated" &&
|
|
13
|
+
typeof event.properties === "object" &&
|
|
14
|
+
event.properties !== null &&
|
|
15
|
+
"info" in event.properties;
|
|
16
|
+
}
|
|
17
|
+
function isSessionStatusEvent(event) {
|
|
18
|
+
return event.type === "session.status" &&
|
|
19
|
+
typeof event.properties === "object" &&
|
|
20
|
+
event.properties !== null;
|
|
21
|
+
}
|
|
22
|
+
// Subagent event type guards
|
|
23
|
+
function isSubagentSessionCreatedEvent(event) {
|
|
24
|
+
return event.type === "subagent.session.created" &&
|
|
25
|
+
typeof event.properties === "object" &&
|
|
26
|
+
event.properties !== null &&
|
|
27
|
+
"sessionID" in event.properties &&
|
|
28
|
+
"parentSessionID" in event.properties;
|
|
29
|
+
}
|
|
5
30
|
const DEFAULT_FALLBACK_MODELS = [
|
|
6
31
|
{ providerID: "anthropic", modelID: "claude-sonnet-4-20250514" },
|
|
7
32
|
{ providerID: "google", modelID: "gemini-2.5-pro" },
|
|
8
33
|
{ providerID: "google", modelID: "gemini-2.5-flash" },
|
|
9
34
|
];
|
|
35
|
+
const VALID_FALLBACK_MODES = ["cycle", "stop", "retry-last"];
|
|
36
|
+
const RATE_LIMIT_INDICATORS = [
|
|
37
|
+
"rate limit",
|
|
38
|
+
"rate_limit",
|
|
39
|
+
"ratelimit",
|
|
40
|
+
"too many requests",
|
|
41
|
+
"quota exceeded",
|
|
42
|
+
"resource exhausted",
|
|
43
|
+
"usage limit",
|
|
44
|
+
"high concurrency usage of this api",
|
|
45
|
+
"high concurrency",
|
|
46
|
+
"reduce concurrency",
|
|
47
|
+
"429",
|
|
48
|
+
];
|
|
10
49
|
const DEFAULT_CONFIG = {
|
|
11
50
|
fallbackModels: DEFAULT_FALLBACK_MODELS,
|
|
12
51
|
cooldownMs: 60 * 1000,
|
|
@@ -27,16 +66,17 @@ function loadConfig(directory) {
|
|
|
27
66
|
const content = readFileSync(configPath, "utf-8");
|
|
28
67
|
const userConfig = JSON.parse(content);
|
|
29
68
|
const mode = userConfig.fallbackMode;
|
|
30
|
-
const validModes = ["cycle", "stop", "retry-last"];
|
|
31
69
|
return {
|
|
32
70
|
...DEFAULT_CONFIG,
|
|
33
71
|
...userConfig,
|
|
34
72
|
fallbackModels: userConfig.fallbackModels || DEFAULT_CONFIG.fallbackModels,
|
|
35
|
-
fallbackMode:
|
|
73
|
+
fallbackMode: VALID_FALLBACK_MODES.includes(mode) ? mode : DEFAULT_CONFIG.fallbackMode,
|
|
36
74
|
};
|
|
37
75
|
}
|
|
38
76
|
catch (error) {
|
|
39
|
-
|
|
77
|
+
if (process.env.NODE_ENV === "development") {
|
|
78
|
+
console.warn(`Failed to load config from ${configPath}:`, error);
|
|
79
|
+
}
|
|
40
80
|
}
|
|
41
81
|
}
|
|
42
82
|
}
|
|
@@ -46,126 +86,119 @@ function getModelKey(providerID, modelID) {
|
|
|
46
86
|
return `${providerID}/${modelID}`;
|
|
47
87
|
}
|
|
48
88
|
function isRateLimitError(error) {
|
|
49
|
-
if (!error)
|
|
89
|
+
if (!error || typeof error !== "object")
|
|
50
90
|
return false;
|
|
51
|
-
|
|
91
|
+
// More type-safe error object structure
|
|
92
|
+
const err = error;
|
|
93
|
+
// Check for 429 status code in APIError
|
|
94
|
+
if (err.name === "APIError" && err.data?.statusCode === 429) {
|
|
52
95
|
return true;
|
|
53
96
|
}
|
|
54
|
-
|
|
55
|
-
const
|
|
56
|
-
const
|
|
57
|
-
const
|
|
58
|
-
|
|
59
|
-
"rate_limit",
|
|
60
|
-
"ratelimit",
|
|
61
|
-
"too many requests",
|
|
62
|
-
"quota exceeded",
|
|
63
|
-
"resource exhausted",
|
|
64
|
-
"usage limit",
|
|
65
|
-
"high concurrency usage of this api",
|
|
66
|
-
"high concurrency",
|
|
67
|
-
"reduce concurrency",
|
|
68
|
-
"429",
|
|
69
|
-
];
|
|
70
|
-
return rateLimitIndicators.some((indicator) => responseBody.includes(indicator) ||
|
|
97
|
+
// Type-safe access to error fields
|
|
98
|
+
const responseBody = String(err.data?.responseBody || "").toLowerCase();
|
|
99
|
+
const message = String(err.data?.message || err.message || "").toLowerCase();
|
|
100
|
+
const errorName = String(err.name || "").toLowerCase();
|
|
101
|
+
return RATE_LIMIT_INDICATORS.some((indicator) => responseBody.includes(indicator) ||
|
|
71
102
|
message.includes(indicator) ||
|
|
72
103
|
errorName.includes(indicator));
|
|
73
104
|
}
|
|
105
|
+
// Constants for deduplication and state management
|
|
106
|
+
const DEDUP_WINDOW_MS = 5000;
|
|
107
|
+
const STATE_TIMEOUT_MS = 30000;
|
|
108
|
+
const CLEANUP_INTERVAL_MS = 300000; // 5 minutes
|
|
109
|
+
const SESSION_ENTRY_TTL_MS = 3600000; // 1 hour
|
|
110
|
+
// Track cleanup intervals globally to prevent TypeScript warnings
|
|
111
|
+
const activeCleanupIntervals = [];
|
|
74
112
|
export const RateLimitFallback = async ({ client, directory }) => {
|
|
75
113
|
const config = loadConfig(directory);
|
|
76
|
-
const logFilePath = join(process.env.HOME || "", ".opencode", "rate-limit-fallback-debug.log");
|
|
77
|
-
// Ensure log directory exists
|
|
78
|
-
try {
|
|
79
|
-
mkdirSync(dirname(logFilePath), { recursive: true });
|
|
80
|
-
}
|
|
81
|
-
catch { }
|
|
82
|
-
// Write to file for debugging
|
|
83
|
-
const logToFile = (message) => {
|
|
84
|
-
try {
|
|
85
|
-
appendFileSync(logFilePath, `[${new Date().toISOString()}] ${message}\n`);
|
|
86
|
-
}
|
|
87
|
-
catch { }
|
|
88
|
-
};
|
|
89
|
-
logToFile(`Plugin loaded, config: ${JSON.stringify(config)}`);
|
|
90
|
-
console.log("[rate-limit-fallback] Plugin loaded, config:", config);
|
|
91
|
-
// Use client.app.log for better logging in both run and TUI modes
|
|
92
|
-
try {
|
|
93
|
-
await client.app.log({
|
|
94
|
-
body: {
|
|
95
|
-
service: "rate-limit-fallback",
|
|
96
|
-
level: "info",
|
|
97
|
-
message: `Plugin loaded, config: ${JSON.stringify(config)}`,
|
|
98
|
-
},
|
|
99
|
-
});
|
|
100
|
-
}
|
|
101
|
-
catch (e) {
|
|
102
|
-
logToFile(`client.app.log failed: ${e}`);
|
|
103
|
-
console.log("[rate-limit-fallback] Plugin loaded, config:", config);
|
|
104
|
-
}
|
|
105
114
|
if (!config.enabled) {
|
|
106
|
-
logToFile("Plugin disabled, returning empty object");
|
|
107
|
-
try {
|
|
108
|
-
await client.app.log({
|
|
109
|
-
body: {
|
|
110
|
-
service: "rate-limit-fallback",
|
|
111
|
-
level: "info",
|
|
112
|
-
message: "Plugin disabled, returning empty object",
|
|
113
|
-
},
|
|
114
|
-
});
|
|
115
|
-
}
|
|
116
|
-
catch {
|
|
117
|
-
console.log("[rate-limit-fallback] Plugin disabled, returning empty object");
|
|
118
|
-
}
|
|
119
115
|
return {};
|
|
120
116
|
}
|
|
121
117
|
const rateLimitedModels = new Map();
|
|
122
118
|
const retryState = new Map();
|
|
123
119
|
const currentSessionModel = new Map();
|
|
124
120
|
const fallbackInProgress = new Map(); // sessionID -> timestamp
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
121
|
+
// Subagent session tracking
|
|
122
|
+
const sessionHierarchies = new Map(); // rootSessionID -> SessionHierarchy
|
|
123
|
+
const sessionToRootMap = new Map(); // sessionID -> rootSessionID
|
|
124
|
+
const maxSubagentDepth = config.maxSubagentDepth ?? 10;
|
|
125
|
+
// Helper functions for session hierarchy management
|
|
126
|
+
function getOrCreateHierarchy(rootSessionID) {
|
|
127
|
+
let hierarchy = sessionHierarchies.get(rootSessionID);
|
|
128
|
+
if (!hierarchy) {
|
|
129
|
+
hierarchy = {
|
|
130
|
+
rootSessionID,
|
|
131
|
+
subagents: new Map(),
|
|
132
|
+
sharedFallbackState: "none",
|
|
133
|
+
sharedConfig: config,
|
|
134
|
+
createdAt: Date.now(),
|
|
135
|
+
lastActivity: Date.now(),
|
|
137
136
|
};
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
service: "rate-limit-fallback",
|
|
141
|
-
level: variantMap[variant],
|
|
142
|
-
message,
|
|
143
|
-
},
|
|
144
|
-
});
|
|
137
|
+
sessionHierarchies.set(rootSessionID, hierarchy);
|
|
138
|
+
sessionToRootMap.set(rootSessionID, rootSessionID);
|
|
145
139
|
}
|
|
140
|
+
return hierarchy;
|
|
146
141
|
}
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
message: `${title}: ${message}`,
|
|
165
|
-
},
|
|
166
|
-
});
|
|
142
|
+
function registerSubagent(sessionID, parentSessionID) {
|
|
143
|
+
// Validate parent session exists
|
|
144
|
+
// Parent session must either be registered in sessionToRootMap or be a new root session
|
|
145
|
+
const parentRootSessionID = sessionToRootMap.get(parentSessionID);
|
|
146
|
+
// Determine root session - if parent doesn't exist, treat it as a new root
|
|
147
|
+
const rootSessionID = parentRootSessionID || parentSessionID;
|
|
148
|
+
// If parent is not a subagent but we're treating it as a root, create a hierarchy for it
|
|
149
|
+
// This allows sessions to become roots when their first subagent is registered
|
|
150
|
+
const hierarchy = getOrCreateHierarchy(rootSessionID);
|
|
151
|
+
const parentSubagent = hierarchy.subagents.get(parentSessionID);
|
|
152
|
+
const depth = parentSubagent ? parentSubagent.depth + 1 : 1;
|
|
153
|
+
// Enforce max depth
|
|
154
|
+
if (depth > maxSubagentDepth) {
|
|
155
|
+
if (process.env.NODE_ENV === "development") {
|
|
156
|
+
console.warn(`Subagent depth ${depth} exceeds max ${maxSubagentDepth}`);
|
|
157
|
+
}
|
|
158
|
+
return false;
|
|
167
159
|
}
|
|
160
|
+
const subagent = {
|
|
161
|
+
sessionID,
|
|
162
|
+
parentSessionID,
|
|
163
|
+
depth,
|
|
164
|
+
fallbackState: "none",
|
|
165
|
+
createdAt: Date.now(),
|
|
166
|
+
lastActivity: Date.now(),
|
|
167
|
+
};
|
|
168
|
+
hierarchy.subagents.set(sessionID, subagent);
|
|
169
|
+
sessionToRootMap.set(sessionID, rootSessionID);
|
|
170
|
+
hierarchy.lastActivity = Date.now();
|
|
171
|
+
return true;
|
|
172
|
+
}
|
|
173
|
+
function getRootSession(sessionID) {
|
|
174
|
+
return sessionToRootMap.get(sessionID) || null;
|
|
168
175
|
}
|
|
176
|
+
function getHierarchy(sessionID) {
|
|
177
|
+
const rootSessionID = getRootSession(sessionID);
|
|
178
|
+
return rootSessionID ? sessionHierarchies.get(rootSessionID) || null : null;
|
|
179
|
+
}
|
|
180
|
+
// Cleanup stale session model entries (every 5 minutes)
|
|
181
|
+
const cleanupInterval = setInterval(() => {
|
|
182
|
+
const now = Date.now();
|
|
183
|
+
for (const [sessionID, entry] of currentSessionModel.entries()) {
|
|
184
|
+
// Remove entries older than 1 hour
|
|
185
|
+
if (now - entry.lastUpdated > SESSION_ENTRY_TTL_MS) {
|
|
186
|
+
currentSessionModel.delete(sessionID);
|
|
187
|
+
}
|
|
188
|
+
}
|
|
189
|
+
// Clean up stale session hierarchies
|
|
190
|
+
for (const [rootSessionID, hierarchy] of sessionHierarchies.entries()) {
|
|
191
|
+
if (now - hierarchy.lastActivity > SESSION_ENTRY_TTL_MS) {
|
|
192
|
+
// Clean up all subagents in this hierarchy
|
|
193
|
+
for (const subagentID of hierarchy.subagents.keys()) {
|
|
194
|
+
sessionToRootMap.delete(subagentID);
|
|
195
|
+
}
|
|
196
|
+
sessionHierarchies.delete(rootSessionID);
|
|
197
|
+
sessionToRootMap.delete(rootSessionID);
|
|
198
|
+
}
|
|
199
|
+
}
|
|
200
|
+
}, CLEANUP_INTERVAL_MS);
|
|
201
|
+
activeCleanupIntervals.push(cleanupInterval);
|
|
169
202
|
function isModelRateLimited(providerID, modelID) {
|
|
170
203
|
const key = getModelKey(providerID, modelID);
|
|
171
204
|
const limitedAt = rateLimitedModels.get(key);
|
|
@@ -183,29 +216,17 @@ export const RateLimitFallback = async ({ client, directory }) => {
|
|
|
183
216
|
}
|
|
184
217
|
function findNextAvailableModel(currentProviderID, currentModelID, attemptedModels) {
|
|
185
218
|
const currentKey = getModelKey(currentProviderID, currentModelID);
|
|
186
|
-
|
|
187
|
-
// If current model is not in the fallback list,
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
for (let i = 0; i < config.fallbackModels.length; i++) {
|
|
191
|
-
const model = config.fallbackModels[i];
|
|
192
|
-
const key = getModelKey(model.providerID, model.modelID);
|
|
193
|
-
if (!attemptedModels.has(key) && !isModelRateLimited(model.providerID, model.modelID)) {
|
|
194
|
-
return model;
|
|
195
|
-
}
|
|
196
|
-
}
|
|
197
|
-
return null;
|
|
198
|
-
}
|
|
199
|
-
// Search for the next model after current position
|
|
200
|
-
for (let i = startIndex + 1; i < config.fallbackModels.length; i++) {
|
|
219
|
+
const startIndex = config.fallbackModels.findIndex(m => getModelKey(m.providerID, m.modelID) === currentKey);
|
|
220
|
+
// If current model is not in the fallback list (startIndex is -1), start from 0
|
|
221
|
+
const searchStartIndex = Math.max(0, startIndex);
|
|
222
|
+
for (let i = searchStartIndex + 1; i < config.fallbackModels.length; i++) {
|
|
201
223
|
const model = config.fallbackModels[i];
|
|
202
224
|
const key = getModelKey(model.providerID, model.modelID);
|
|
203
225
|
if (!attemptedModels.has(key) && !isModelRateLimited(model.providerID, model.modelID)) {
|
|
204
226
|
return model;
|
|
205
227
|
}
|
|
206
228
|
}
|
|
207
|
-
|
|
208
|
-
for (let i = 0; i <= startIndex && i < config.fallbackModels.length; i++) {
|
|
229
|
+
for (let i = 0; i <= searchStartIndex && i < config.fallbackModels.length; i++) {
|
|
209
230
|
const model = config.fallbackModels[i];
|
|
210
231
|
const key = getModelKey(model.providerID, model.modelID);
|
|
211
232
|
if (!attemptedModels.has(key) && !isModelRateLimited(model.providerID, model.modelID)) {
|
|
@@ -214,38 +235,80 @@ export const RateLimitFallback = async ({ client, directory }) => {
|
|
|
214
235
|
}
|
|
215
236
|
return null;
|
|
216
237
|
}
|
|
217
|
-
async function handleRateLimitFallback(sessionID, currentProviderID, currentModelID
|
|
238
|
+
async function handleRateLimitFallback(sessionID, currentProviderID, currentModelID) {
|
|
239
|
+
// Determine the target session ID for fallback processing
|
|
240
|
+
// For subagent sessions, trigger fallback at the root level (parent-centered approach)
|
|
241
|
+
let targetSessionID = sessionID;
|
|
218
242
|
try {
|
|
219
|
-
//
|
|
220
|
-
const
|
|
221
|
-
|
|
222
|
-
|
|
243
|
+
// Check if this is a subagent session
|
|
244
|
+
const hierarchy = getHierarchy(sessionID);
|
|
245
|
+
const rootSessionID = getRootSession(sessionID);
|
|
246
|
+
if (rootSessionID && hierarchy) {
|
|
247
|
+
targetSessionID = rootSessionID;
|
|
248
|
+
// If already processing fallback for this hierarchy, skip
|
|
249
|
+
const lastFallback = fallbackInProgress.get(targetSessionID);
|
|
250
|
+
if (lastFallback && Date.now() - lastFallback < DEDUP_WINDOW_MS) {
|
|
251
|
+
return;
|
|
252
|
+
}
|
|
253
|
+
fallbackInProgress.set(targetSessionID, Date.now());
|
|
254
|
+
// Update the shared fallback state
|
|
255
|
+
hierarchy.sharedFallbackState = "in_progress";
|
|
256
|
+
hierarchy.lastActivity = Date.now();
|
|
257
|
+
// Update the subagent's state
|
|
258
|
+
const subagent = hierarchy.subagents.get(sessionID);
|
|
259
|
+
if (subagent) {
|
|
260
|
+
subagent.fallbackState = "in_progress";
|
|
261
|
+
subagent.lastActivity = Date.now();
|
|
262
|
+
}
|
|
263
|
+
}
|
|
264
|
+
else {
|
|
265
|
+
// Prevent duplicate fallback processing within DEDUP_WINDOW_MS for non-subagent sessions
|
|
266
|
+
const lastFallback = fallbackInProgress.get(targetSessionID);
|
|
267
|
+
if (lastFallback && Date.now() - lastFallback < DEDUP_WINDOW_MS) {
|
|
268
|
+
return;
|
|
269
|
+
}
|
|
270
|
+
fallbackInProgress.set(targetSessionID, Date.now());
|
|
223
271
|
}
|
|
224
|
-
fallbackInProgress.set(sessionID, Date.now());
|
|
225
272
|
// If no model info provided, try to get from tracked session model
|
|
226
273
|
if (!currentProviderID || !currentModelID) {
|
|
227
|
-
const tracked = currentSessionModel.get(
|
|
274
|
+
const tracked = currentSessionModel.get(targetSessionID);
|
|
228
275
|
if (tracked) {
|
|
229
276
|
currentProviderID = tracked.providerID;
|
|
230
277
|
currentModelID = tracked.modelID;
|
|
231
278
|
}
|
|
232
279
|
}
|
|
233
|
-
//
|
|
234
|
-
|
|
280
|
+
// Abort current session with error handling
|
|
281
|
+
try {
|
|
282
|
+
await client.session.abort({ path: { id: targetSessionID } });
|
|
283
|
+
}
|
|
284
|
+
catch (abortError) {
|
|
285
|
+
// Log abort error but continue with fallback
|
|
286
|
+
if (process.env.NODE_ENV === "development") {
|
|
287
|
+
console.warn("Failed to abort session:", abortError);
|
|
288
|
+
}
|
|
289
|
+
}
|
|
290
|
+
await client.tui.showToast({
|
|
291
|
+
body: {
|
|
292
|
+
title: "Rate Limit Detected",
|
|
293
|
+
message: `Switching from ${currentModelID || 'current model'}...`,
|
|
294
|
+
variant: "warning",
|
|
295
|
+
duration: 3000,
|
|
296
|
+
},
|
|
297
|
+
});
|
|
298
|
+
const messagesResult = await client.session.messages({ path: { id: targetSessionID } });
|
|
235
299
|
if (!messagesResult.data) {
|
|
236
|
-
fallbackInProgress.delete(
|
|
300
|
+
fallbackInProgress.delete(targetSessionID);
|
|
237
301
|
return;
|
|
238
302
|
}
|
|
239
303
|
const messages = messagesResult.data;
|
|
240
304
|
const lastUserMessage = [...messages].reverse().find(m => m.info.role === "user");
|
|
241
305
|
if (!lastUserMessage) {
|
|
242
|
-
fallbackInProgress.delete(
|
|
306
|
+
fallbackInProgress.delete(targetSessionID);
|
|
243
307
|
return;
|
|
244
308
|
}
|
|
245
|
-
toast("Rate Limit Detected", `Switching from ${currentModelID || 'current model'}...`, "warning").catch(() => { });
|
|
246
309
|
const stateKey = `${sessionID}:${lastUserMessage.info.id}`;
|
|
247
310
|
let state = retryState.get(stateKey);
|
|
248
|
-
if (!state || Date.now() - state.lastAttemptTime >
|
|
311
|
+
if (!state || Date.now() - state.lastAttemptTime > STATE_TIMEOUT_MS) {
|
|
249
312
|
state = { attemptedModels: new Set(), lastAttemptTime: Date.now() };
|
|
250
313
|
retryState.set(stateKey, state);
|
|
251
314
|
}
|
|
@@ -272,7 +335,14 @@ export const RateLimitFallback = async ({ client, directory }) => {
|
|
|
272
335
|
if (!isLastModelCurrent && !isModelRateLimited(lastModel.providerID, lastModel.modelID)) {
|
|
273
336
|
// Use the last model for one more try
|
|
274
337
|
nextModel = lastModel;
|
|
275
|
-
|
|
338
|
+
await client.tui.showToast({
|
|
339
|
+
body: {
|
|
340
|
+
title: "Last Resort",
|
|
341
|
+
message: `Trying ${lastModel.modelID} one more time...`,
|
|
342
|
+
variant: "warning",
|
|
343
|
+
duration: 3000,
|
|
344
|
+
},
|
|
345
|
+
});
|
|
276
346
|
}
|
|
277
347
|
else {
|
|
278
348
|
// Last model also failed, reset for next prompt
|
|
@@ -287,218 +357,165 @@ export const RateLimitFallback = async ({ client, directory }) => {
|
|
|
287
357
|
// "stop" mode: nextModel remains null, will show error below
|
|
288
358
|
}
|
|
289
359
|
if (!nextModel) {
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
360
|
+
await client.tui.showToast({
|
|
361
|
+
body: {
|
|
362
|
+
title: "No Fallback Available",
|
|
363
|
+
message: config.fallbackMode === "stop"
|
|
364
|
+
? "All fallback models exhausted"
|
|
365
|
+
: "All models are rate limited",
|
|
366
|
+
variant: "error",
|
|
367
|
+
duration: 5000,
|
|
368
|
+
},
|
|
369
|
+
});
|
|
293
370
|
retryState.delete(stateKey);
|
|
294
|
-
fallbackInProgress.delete(
|
|
371
|
+
fallbackInProgress.delete(targetSessionID);
|
|
295
372
|
return;
|
|
296
373
|
}
|
|
297
374
|
state.attemptedModels.add(getModelKey(nextModel.providerID, nextModel.modelID));
|
|
298
375
|
state.lastAttemptTime = Date.now();
|
|
299
376
|
const parts = lastUserMessage.parts
|
|
300
|
-
.filter((p) =>
|
|
377
|
+
.filter((p) => {
|
|
378
|
+
const part = p;
|
|
379
|
+
return part.type === "text" || part.type === "file";
|
|
380
|
+
})
|
|
301
381
|
.map((p) => {
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
382
|
+
const part = p;
|
|
383
|
+
if (part.type === "text")
|
|
384
|
+
return { type: "text", text: String(part.text) };
|
|
385
|
+
if (part.type === "file")
|
|
386
|
+
return { type: "file", path: String(part.path), mediaType: String(part.mediaType) };
|
|
306
387
|
return null;
|
|
307
388
|
})
|
|
308
|
-
.filter(
|
|
389
|
+
.filter((p) => p !== null);
|
|
309
390
|
if (parts.length === 0) {
|
|
310
|
-
fallbackInProgress.delete(
|
|
391
|
+
fallbackInProgress.delete(targetSessionID);
|
|
311
392
|
return;
|
|
312
393
|
}
|
|
394
|
+
await client.tui.showToast({
|
|
395
|
+
body: {
|
|
396
|
+
title: "Retrying",
|
|
397
|
+
message: `Using ${nextModel.providerID}/${nextModel.modelID}`,
|
|
398
|
+
variant: "info",
|
|
399
|
+
duration: 3000,
|
|
400
|
+
},
|
|
401
|
+
});
|
|
313
402
|
// Track the new model for this session
|
|
314
|
-
currentSessionModel.set(
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
};
|
|
319
|
-
//
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
catch (abortErr) {
|
|
333
|
-
logToFile(`abort failed (${Date.now() - t0}ms): ${abortErr}`);
|
|
403
|
+
currentSessionModel.set(targetSessionID, {
|
|
404
|
+
providerID: nextModel.providerID,
|
|
405
|
+
modelID: nextModel.modelID,
|
|
406
|
+
lastUpdated: Date.now(),
|
|
407
|
+
});
|
|
408
|
+
// If this is a root session with subagents, propagate the model to all subagents
|
|
409
|
+
if (hierarchy && hierarchy.rootSessionID === targetSessionID) {
|
|
410
|
+
hierarchy.sharedFallbackState = "completed";
|
|
411
|
+
hierarchy.lastActivity = Date.now();
|
|
412
|
+
// Update model tracking for all subagents
|
|
413
|
+
for (const [subagentID, subagent] of hierarchy.subagents.entries()) {
|
|
414
|
+
currentSessionModel.set(subagentID, {
|
|
415
|
+
providerID: nextModel.providerID,
|
|
416
|
+
modelID: nextModel.modelID,
|
|
417
|
+
lastUpdated: Date.now(),
|
|
418
|
+
});
|
|
419
|
+
subagent.fallbackState = "completed";
|
|
420
|
+
subagent.lastActivity = Date.now();
|
|
334
421
|
}
|
|
335
422
|
}
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
423
|
+
// Convert internal MessagePart to SDK-compatible format
|
|
424
|
+
const sdkParts = parts.map((part) => {
|
|
425
|
+
if (part.type === "text") {
|
|
426
|
+
return { type: "text", text: part.text };
|
|
427
|
+
}
|
|
428
|
+
// For file parts, we need to match the FilePartInput format
|
|
429
|
+
// Using path as url since we're dealing with local files
|
|
430
|
+
return {
|
|
431
|
+
type: "file",
|
|
432
|
+
url: part.path,
|
|
433
|
+
mime: part.mediaType || "application/octet-stream",
|
|
434
|
+
};
|
|
435
|
+
});
|
|
436
|
+
await client.session.prompt({
|
|
437
|
+
path: { id: targetSessionID },
|
|
438
|
+
body: {
|
|
439
|
+
parts: sdkParts,
|
|
440
|
+
model: { providerID: nextModel.providerID, modelID: nextModel.modelID },
|
|
441
|
+
},
|
|
442
|
+
});
|
|
443
|
+
await client.tui.showToast({
|
|
444
|
+
body: {
|
|
445
|
+
title: "Fallback Successful",
|
|
446
|
+
message: `Now using ${nextModel.modelID}`,
|
|
447
|
+
variant: "success",
|
|
448
|
+
duration: 3000,
|
|
449
|
+
},
|
|
340
450
|
});
|
|
341
|
-
logToFile(`promptAsync completed for session ${sessionID} (${Date.now() - t1}ms, total ${Date.now() - t0}ms) with model ${nextModel.providerID}/${nextModel.modelID}`);
|
|
342
|
-
// Toast is best-effort notification. The toast() function (line ~185) has
|
|
343
|
-
// built-in fallback: showToast failure → app.log. After promptAsync the
|
|
344
|
-
// server may already be disposing, so both showToast and app.log could fail.
|
|
345
|
-
// The outer .catch() ensures even total toast() failure never blocks or throws.
|
|
346
|
-
toast("Fallback Active", `Now using ${nextModel.modelID}`, "success").catch(() => { });
|
|
347
451
|
retryState.delete(stateKey);
|
|
348
|
-
//
|
|
349
|
-
|
|
452
|
+
// Explicitly clean up fallbackInProgress after cooldown period
|
|
453
|
+
// This prevents memory leaks while maintaining the deduplication window
|
|
454
|
+
setTimeout(() => {
|
|
455
|
+
fallbackInProgress.delete(targetSessionID);
|
|
456
|
+
}, DEDUP_WINDOW_MS);
|
|
350
457
|
}
|
|
351
458
|
catch (err) {
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
459
|
+
fallbackInProgress.delete(targetSessionID);
|
|
460
|
+
if (process.env.NODE_ENV === "development") {
|
|
461
|
+
console.error("Fallback failed:", err);
|
|
462
|
+
}
|
|
355
463
|
}
|
|
356
464
|
}
|
|
357
465
|
return {
|
|
358
466
|
event: async ({ event }) => {
|
|
359
|
-
|
|
360
|
-
logToFile(`Event received: ${event.type}`);
|
|
361
|
-
try {
|
|
362
|
-
await client.app.log({
|
|
363
|
-
body: {
|
|
364
|
-
service: "rate-limit-fallback",
|
|
365
|
-
level: "debug",
|
|
366
|
-
message: `Event received: ${event.type}`,
|
|
367
|
-
},
|
|
368
|
-
});
|
|
369
|
-
}
|
|
370
|
-
catch (e) {
|
|
371
|
-
logToFile(`client.app.log failed for event: ${e}`);
|
|
372
|
-
console.log("[rate-limit-fallback] Event received:", event.type);
|
|
373
|
-
}
|
|
374
|
-
if (event.type === "session.error") {
|
|
467
|
+
if (isSessionErrorEvent(event)) {
|
|
375
468
|
const { sessionID, error } = event.properties;
|
|
376
|
-
logToFile(`session.error: sessionID=${sessionID}, error=${JSON.stringify(error)}`);
|
|
377
|
-
try {
|
|
378
|
-
await client.app.log({
|
|
379
|
-
body: {
|
|
380
|
-
service: "rate-limit-fallback",
|
|
381
|
-
level: "debug",
|
|
382
|
-
message: `session.error: sessionID=${sessionID}, error=${JSON.stringify(error)}`,
|
|
383
|
-
},
|
|
384
|
-
});
|
|
385
|
-
}
|
|
386
|
-
catch {
|
|
387
|
-
console.log("[rate-limit-fallback] session.error:", sessionID, error);
|
|
388
|
-
}
|
|
389
469
|
if (sessionID && error && isRateLimitError(error)) {
|
|
390
|
-
|
|
391
|
-
try {
|
|
392
|
-
await client.app.log({
|
|
393
|
-
body: {
|
|
394
|
-
service: "rate-limit-fallback",
|
|
395
|
-
level: "info",
|
|
396
|
-
message: "Rate limit error detected, attempting fallback",
|
|
397
|
-
},
|
|
398
|
-
});
|
|
399
|
-
}
|
|
400
|
-
catch {
|
|
401
|
-
console.log("[rate-limit-fallback] Rate limit error detected, attempting fallback");
|
|
402
|
-
}
|
|
403
|
-
await handleRateLimitFallback(sessionID, "", "", true); // skipAbort = true (already in error state)
|
|
470
|
+
await handleRateLimitFallback(sessionID, "", "");
|
|
404
471
|
}
|
|
405
472
|
}
|
|
406
|
-
if (event
|
|
407
|
-
const info = event.properties
|
|
408
|
-
logToFile(`message.updated: ${JSON.stringify(info)}`);
|
|
409
|
-
try {
|
|
410
|
-
await client.app.log({
|
|
411
|
-
body: {
|
|
412
|
-
service: "rate-limit-fallback",
|
|
413
|
-
level: "debug",
|
|
414
|
-
message: `message.updated: ${JSON.stringify(info)}`,
|
|
415
|
-
},
|
|
416
|
-
});
|
|
417
|
-
}
|
|
418
|
-
catch {
|
|
419
|
-
console.log("[rate-limit-fallback] message.updated:", info);
|
|
420
|
-
}
|
|
421
|
-
// Track assistant message model info for later use in fallback
|
|
422
|
-
if (info?.role === "assistant" && info?.sessionID && info?.providerID && info?.modelID) {
|
|
423
|
-
currentSessionModel.set(info.sessionID, {
|
|
424
|
-
providerID: info.providerID,
|
|
425
|
-
modelID: info.modelID,
|
|
426
|
-
});
|
|
427
|
-
}
|
|
473
|
+
if (isMessageUpdatedEvent(event)) {
|
|
474
|
+
const info = event.properties.info;
|
|
428
475
|
if (info?.error && isRateLimitError(info.error)) {
|
|
429
|
-
|
|
430
|
-
try {
|
|
431
|
-
await client.app.log({
|
|
432
|
-
body: {
|
|
433
|
-
service: "rate-limit-fallback",
|
|
434
|
-
level: "info",
|
|
435
|
-
message: "Rate limit error in message, attempting fallback",
|
|
436
|
-
},
|
|
437
|
-
});
|
|
438
|
-
}
|
|
439
|
-
catch {
|
|
440
|
-
console.log("[rate-limit-fallback] Rate limit error in message, attempting fallback");
|
|
441
|
-
}
|
|
442
|
-
await handleRateLimitFallback(info.sessionID, info.providerID || "", info.modelID || "", true); // skipAbort = true (already in error state)
|
|
476
|
+
await handleRateLimitFallback(info.sessionID, info.providerID || "", info.modelID || "");
|
|
443
477
|
}
|
|
444
478
|
}
|
|
445
|
-
if (event
|
|
479
|
+
if (isSessionStatusEvent(event)) {
|
|
446
480
|
const props = event.properties;
|
|
447
481
|
const status = props?.status;
|
|
448
|
-
logToFile(`session.status: ${JSON.stringify(status)}`);
|
|
449
|
-
try {
|
|
450
|
-
await client.app.log({
|
|
451
|
-
body: {
|
|
452
|
-
service: "rate-limit-fallback",
|
|
453
|
-
level: "debug",
|
|
454
|
-
message: `session.status: ${JSON.stringify(status)}`,
|
|
455
|
-
},
|
|
456
|
-
});
|
|
457
|
-
}
|
|
458
|
-
catch {
|
|
459
|
-
console.log("[rate-limit-fallback] session.status:", status);
|
|
460
|
-
}
|
|
461
|
-
// Note: interrupted status is handled by the fallback sequence (abort → promptAsync).
|
|
462
|
-
// We don't need to handle it separately here as it would cause duplicate prompt sends.
|
|
463
482
|
if (status?.type === "retry" && status?.message) {
|
|
464
483
|
const message = status.message.toLowerCase();
|
|
465
484
|
const isRateLimitRetry = message.includes("usage limit") ||
|
|
466
485
|
message.includes("rate limit") ||
|
|
467
486
|
message.includes("high concurrency") ||
|
|
468
487
|
message.includes("reduce concurrency");
|
|
469
|
-
logToFile(`Is rate limit retry: ${isRateLimitRetry}, message: ${message}`);
|
|
470
|
-
try {
|
|
471
|
-
await client.app.log({
|
|
472
|
-
body: {
|
|
473
|
-
service: "rate-limit-fallback",
|
|
474
|
-
level: "debug",
|
|
475
|
-
message: `Is rate limit retry: ${isRateLimitRetry}, message: ${message}`,
|
|
476
|
-
},
|
|
477
|
-
});
|
|
478
|
-
}
|
|
479
|
-
catch {
|
|
480
|
-
console.log("[rate-limit-fallback] Is rate limit retry:", isRateLimitRetry, "message:", message);
|
|
481
|
-
}
|
|
482
488
|
if (isRateLimitRetry) {
|
|
483
489
|
// Try fallback on any attempt, handleRateLimitFallback will manage state
|
|
484
|
-
logToFile("Attempting fallback for rate limit retry");
|
|
485
|
-
try {
|
|
486
|
-
await client.app.log({
|
|
487
|
-
body: {
|
|
488
|
-
service: "rate-limit-fallback",
|
|
489
|
-
level: "info",
|
|
490
|
-
message: "Attempting fallback for rate limit retry",
|
|
491
|
-
},
|
|
492
|
-
});
|
|
493
|
-
}
|
|
494
|
-
catch {
|
|
495
|
-
console.log("[rate-limit-fallback] Attempting fallback for rate limit retry");
|
|
496
|
-
}
|
|
497
490
|
await handleRateLimitFallback(props.sessionID, "", "");
|
|
498
491
|
}
|
|
499
492
|
}
|
|
500
493
|
}
|
|
494
|
+
// Handle subagent session creation events
|
|
495
|
+
// Note: Using type assertion for subagent events since they may not be in the official Event union yet
|
|
496
|
+
const rawEvent = event;
|
|
497
|
+
if (isSubagentSessionCreatedEvent(rawEvent)) {
|
|
498
|
+
const { sessionID, parentSessionID } = rawEvent.properties;
|
|
499
|
+
if (config.enableSubagentFallback !== false) {
|
|
500
|
+
registerSubagent(sessionID, parentSessionID);
|
|
501
|
+
if (process.env.NODE_ENV === "development") {
|
|
502
|
+
console.log(`Registered subagent ${sessionID} under parent ${parentSessionID}`);
|
|
503
|
+
}
|
|
504
|
+
}
|
|
505
|
+
}
|
|
506
|
+
},
|
|
507
|
+
// Cleanup function to prevent memory leaks
|
|
508
|
+
cleanup: () => {
|
|
509
|
+
clearInterval(cleanupInterval);
|
|
510
|
+
const index = activeCleanupIntervals.indexOf(cleanupInterval);
|
|
511
|
+
if (index > -1) {
|
|
512
|
+
activeCleanupIntervals.splice(index, 1);
|
|
513
|
+
}
|
|
514
|
+
// Clean up all session hierarchies
|
|
515
|
+
sessionHierarchies.clear();
|
|
516
|
+
sessionToRootMap.clear();
|
|
501
517
|
},
|
|
502
518
|
};
|
|
503
519
|
};
|
|
504
520
|
export default RateLimitFallback;
|
|
521
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../index.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,14 +1,10 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@azumag/opencode-rate-limit-fallback",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.1.2",
|
|
4
4
|
"description": "OpenCode plugin that automatically switches to fallback models when rate limited",
|
|
5
|
+
"main": "dist/index.js",
|
|
6
|
+
"types": "dist/index.d.ts",
|
|
5
7
|
"type": "module",
|
|
6
|
-
"main": "./dist/index.js",
|
|
7
|
-
"scripts": {
|
|
8
|
-
"build": "tsc",
|
|
9
|
-
"test": "vitest",
|
|
10
|
-
"prepublishOnly": "npm run build"
|
|
11
|
-
},
|
|
12
8
|
"keywords": [
|
|
13
9
|
"opencode",
|
|
14
10
|
"plugin",
|
|
@@ -26,22 +22,27 @@
|
|
|
26
22
|
"url": "https://github.com/azumag/opencode-rate-limit-fallback/issues"
|
|
27
23
|
},
|
|
28
24
|
"homepage": "https://github.com/azumag/opencode-rate-limit-fallback#readme",
|
|
25
|
+
"scripts": {
|
|
26
|
+
"build": "tsc",
|
|
27
|
+
"typecheck": "tsc --noEmit",
|
|
28
|
+
"clean": "rm -rf dist",
|
|
29
|
+
"prepublishOnly": "npm run clean && npm run build",
|
|
30
|
+
"test": "vitest run",
|
|
31
|
+
"test:watch": "vitest",
|
|
32
|
+
"test:coverage": "vitest run --coverage"
|
|
33
|
+
},
|
|
29
34
|
"files": [
|
|
30
|
-
"dist"
|
|
35
|
+
"dist",
|
|
36
|
+
"README.md",
|
|
37
|
+
"LICENSE"
|
|
31
38
|
],
|
|
32
|
-
"
|
|
33
|
-
"
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
39
|
+
"devDependencies": {
|
|
40
|
+
"@types/node": "^25.2.2",
|
|
41
|
+
"@vitest/coverage-v8": "^4.0.18",
|
|
42
|
+
"typescript": "^5.3.0",
|
|
43
|
+
"vitest": "^4.0.18"
|
|
37
44
|
},
|
|
38
45
|
"dependencies": {
|
|
39
46
|
"@opencode-ai/plugin": "latest"
|
|
40
|
-
},
|
|
41
|
-
"devDependencies": {
|
|
42
|
-
"@tsconfig/node22": "^22.0.5",
|
|
43
|
-
"@types/node": "^25.2.2",
|
|
44
|
-
"typescript": "^5.9.3",
|
|
45
|
-
"vitest": "^3.2.4"
|
|
46
47
|
}
|
|
47
48
|
}
|