opencode-puter-auth 1.0.38 → 1.0.41
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/README.md +194 -0
- package/dist/account-rotation.d.ts +243 -0
- package/dist/account-rotation.d.ts.map +1 -0
- package/dist/account-rotation.js +431 -0
- package/dist/account-rotation.js.map +1 -0
- package/dist/ai-provider/puter-chat-language-model.d.ts +19 -0
- package/dist/ai-provider/puter-chat-language-model.d.ts.map +1 -1
- package/dist/ai-provider/puter-chat-language-model.js +85 -8
- package/dist/ai-provider/puter-chat-language-model.js.map +1 -1
- package/dist/ai-provider/puter-chat-settings.d.ts +18 -0
- package/dist/ai-provider/puter-chat-settings.d.ts.map +1 -1
- package/dist/ai-provider/puter-provider.d.ts.map +1 -1
- package/dist/ai-provider/puter-provider.js +1 -0
- package/dist/ai-provider/puter-provider.js.map +1 -1
- package/dist/auth.d.ts +166 -18
- package/dist/auth.d.ts.map +1 -1
- package/dist/auth.js +167 -20
- package/dist/auth.js.map +1 -1
- package/dist/fallback.d.ts +200 -0
- package/dist/fallback.d.ts.map +1 -0
- package/dist/fallback.js +380 -0
- package/dist/fallback.js.map +1 -0
- package/dist/index.d.ts +6 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +6 -0
- package/dist/index.js.map +1 -1
- package/dist/types.d.ts +9 -0
- package/dist/types.d.ts.map +1 -1
- package/dist/types.js +8 -0
- package/dist/types.js.map +1 -1
- package/package.json +1 -1
|
@@ -0,0 +1,431 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Account Rotation Manager for opencode-puter-auth
|
|
3
|
+
*
|
|
4
|
+
* Provides automatic account rotation when rate limits are encountered.
|
|
5
|
+
* When an account returns a rate limit error (429/403), the manager:
|
|
6
|
+
* 1. Adds the account to a cooldown list
|
|
7
|
+
* 2. Switches to the next available account
|
|
8
|
+
* 3. Returns to the original account after cooldown expires
|
|
9
|
+
*
|
|
10
|
+
* This enables longer uninterrupted usage by cycling through multiple
|
|
11
|
+
* Puter accounts when individual accounts hit rate limits.
|
|
12
|
+
*
|
|
13
|
+
* @example
|
|
14
|
+
* ```ts
|
|
15
|
+
* const rotation = new AccountRotationManager(authManager, {
|
|
16
|
+
* cooldownMs: 300000, // 5 minutes
|
|
17
|
+
* enabled: true,
|
|
18
|
+
* });
|
|
19
|
+
*
|
|
20
|
+
* // Get the next available account (respecting cooldowns)
|
|
21
|
+
* const account = await rotation.getNextAvailableAccount();
|
|
22
|
+
*
|
|
23
|
+
* // Mark an account as rate-limited
|
|
24
|
+
* rotation.addToCooldown('mihai_chindris', 'Rate limit exceeded');
|
|
25
|
+
* ```
|
|
26
|
+
*/
|
|
27
|
+
/**
|
|
28
|
+
* Default cooldown duration for rate-limited accounts (5 minutes)
|
|
29
|
+
* Accounts typically need longer cooldown than models since Puter's
|
|
30
|
+
* account-level limits are stricter.
|
|
31
|
+
*/
|
|
32
|
+
export const DEFAULT_ACCOUNT_COOLDOWN_MS = 300000;
|
|
33
|
+
/**
|
|
34
|
+
* Error thrown when all accounts are on cooldown
|
|
35
|
+
*/
|
|
36
|
+
export class AllAccountsOnCooldownError extends Error {
|
|
37
|
+
accountStatuses;
|
|
38
|
+
nextAvailableIn;
|
|
39
|
+
constructor(statuses) {
|
|
40
|
+
const usernames = statuses.map(s => s.username).join(', ');
|
|
41
|
+
const nextAvailable = Math.min(...statuses.map(s => s.cooldownRemainingMs));
|
|
42
|
+
super(`All accounts on cooldown: ${usernames}. Next available in ${Math.round(nextAvailable / 1000)}s`);
|
|
43
|
+
this.name = 'AllAccountsOnCooldownError';
|
|
44
|
+
this.accountStatuses = statuses;
|
|
45
|
+
this.nextAvailableIn = nextAvailable;
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
/**
|
|
49
|
+
* Manages automatic account rotation when rate limits are encountered.
|
|
50
|
+
*
|
|
51
|
+
* Works with PuterAuthManager to cycle through multiple accounts,
|
|
52
|
+
* ensuring uninterrupted service even when individual accounts
|
|
53
|
+
* hit their rate limits.
|
|
54
|
+
*/
|
|
55
|
+
export class AccountRotationManager {
|
|
56
|
+
authManager;
|
|
57
|
+
cooldownMap = new Map();
|
|
58
|
+
usageStats = new Map();
|
|
59
|
+
cooldownMs;
|
|
60
|
+
enabled;
|
|
61
|
+
strategy;
|
|
62
|
+
currentIndex = 0;
|
|
63
|
+
logger;
|
|
64
|
+
/**
|
|
65
|
+
* Create a new AccountRotationManager
|
|
66
|
+
*
|
|
67
|
+
* @param authManager - The PuterAuthManager instance
|
|
68
|
+
* @param options - Configuration options
|
|
69
|
+
* @param logger - Optional logger for debugging
|
|
70
|
+
*/
|
|
71
|
+
constructor(authManager, options = {}, logger) {
|
|
72
|
+
this.authManager = authManager;
|
|
73
|
+
this.cooldownMs = options.cooldownMs ?? DEFAULT_ACCOUNT_COOLDOWN_MS;
|
|
74
|
+
this.enabled = options.enabled ?? true;
|
|
75
|
+
this.strategy = options.strategy ?? 'round-robin';
|
|
76
|
+
this.logger = logger;
|
|
77
|
+
}
|
|
78
|
+
/**
|
|
79
|
+
* Check if an account is currently on cooldown
|
|
80
|
+
*
|
|
81
|
+
* @param username - Account username to check
|
|
82
|
+
* @returns true if the account is on cooldown
|
|
83
|
+
*/
|
|
84
|
+
isAccountOnCooldown(username) {
|
|
85
|
+
const entry = this.cooldownMap.get(username);
|
|
86
|
+
if (!entry)
|
|
87
|
+
return false;
|
|
88
|
+
if (Date.now() >= entry.expiresAt) {
|
|
89
|
+
this.cooldownMap.delete(username);
|
|
90
|
+
return false;
|
|
91
|
+
}
|
|
92
|
+
return true;
|
|
93
|
+
}
|
|
94
|
+
/**
|
|
95
|
+
* Get remaining cooldown time for an account
|
|
96
|
+
*
|
|
97
|
+
* @param username - Account username to check
|
|
98
|
+
* @returns Remaining cooldown in ms, or 0 if not on cooldown
|
|
99
|
+
*/
|
|
100
|
+
getCooldownRemaining(username) {
|
|
101
|
+
const entry = this.cooldownMap.get(username);
|
|
102
|
+
if (!entry)
|
|
103
|
+
return 0;
|
|
104
|
+
const remaining = entry.expiresAt - Date.now();
|
|
105
|
+
if (remaining <= 0) {
|
|
106
|
+
this.cooldownMap.delete(username);
|
|
107
|
+
return 0;
|
|
108
|
+
}
|
|
109
|
+
return remaining;
|
|
110
|
+
}
|
|
111
|
+
/**
|
|
112
|
+
* Add an account to the cooldown list
|
|
113
|
+
*
|
|
114
|
+
* Each consecutive rate limit increases the cooldown duration
|
|
115
|
+
* exponentially (up to 4x base cooldown).
|
|
116
|
+
*
|
|
117
|
+
* @param username - Account username to add to cooldown
|
|
118
|
+
* @param reason - Reason for the cooldown
|
|
119
|
+
*/
|
|
120
|
+
addToCooldown(username, reason) {
|
|
121
|
+
const existing = this.cooldownMap.get(username);
|
|
122
|
+
const consecutiveRateLimits = (existing?.consecutiveRateLimits ?? 0) + 1;
|
|
123
|
+
// Exponential backoff: 1x, 2x, 3x, 4x (max)
|
|
124
|
+
const multiplier = Math.min(consecutiveRateLimits, 4);
|
|
125
|
+
const duration = this.cooldownMs * multiplier;
|
|
126
|
+
this.cooldownMap.set(username, {
|
|
127
|
+
expiresAt: Date.now() + duration,
|
|
128
|
+
reason,
|
|
129
|
+
consecutiveRateLimits,
|
|
130
|
+
});
|
|
131
|
+
// Update stats
|
|
132
|
+
const stats = this.usageStats.get(username) ?? { lastUsedAt: 0, rateLimitCount: 0 };
|
|
133
|
+
stats.rateLimitCount++;
|
|
134
|
+
this.usageStats.set(username, stats);
|
|
135
|
+
const durationSecs = Math.round(duration / 1000);
|
|
136
|
+
this.logger?.warn(`Account ${username} cooldown: ${durationSecs}s (${consecutiveRateLimits}x)`);
|
|
137
|
+
}
|
|
138
|
+
/**
|
|
139
|
+
* Remove an account from cooldown (e.g., after successful request)
|
|
140
|
+
*
|
|
141
|
+
* @param username - Account username to remove from cooldown
|
|
142
|
+
*/
|
|
143
|
+
removeFromCooldown(username) {
|
|
144
|
+
if (this.cooldownMap.has(username)) {
|
|
145
|
+
this.cooldownMap.delete(username);
|
|
146
|
+
this.logger?.debug(`Account ${username} removed from cooldown`);
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
/**
|
|
150
|
+
* Mark an account as recently used
|
|
151
|
+
*
|
|
152
|
+
* @param username - Account username that was used
|
|
153
|
+
*/
|
|
154
|
+
markAsUsed(username) {
|
|
155
|
+
const stats = this.usageStats.get(username) ?? { lastUsedAt: 0, rateLimitCount: 0 };
|
|
156
|
+
stats.lastUsedAt = Date.now();
|
|
157
|
+
this.usageStats.set(username, stats);
|
|
158
|
+
}
|
|
159
|
+
/**
|
|
160
|
+
* Get status of all accounts
|
|
161
|
+
*
|
|
162
|
+
* @returns Array of account statuses
|
|
163
|
+
*/
|
|
164
|
+
getAccountStatuses() {
|
|
165
|
+
const accounts = this.authManager.getAllAccounts();
|
|
166
|
+
return accounts.map(account => {
|
|
167
|
+
const cooldownRemaining = this.getCooldownRemaining(account.username);
|
|
168
|
+
const entry = this.cooldownMap.get(account.username);
|
|
169
|
+
const stats = this.usageStats.get(account.username);
|
|
170
|
+
return {
|
|
171
|
+
username: account.username,
|
|
172
|
+
isOnCooldown: cooldownRemaining > 0,
|
|
173
|
+
cooldownRemainingMs: cooldownRemaining,
|
|
174
|
+
cooldownReason: entry?.reason,
|
|
175
|
+
lastUsedAt: stats?.lastUsedAt ?? account.lastUsed,
|
|
176
|
+
rateLimitCount: stats?.rateLimitCount ?? 0,
|
|
177
|
+
};
|
|
178
|
+
});
|
|
179
|
+
}
|
|
180
|
+
/**
|
|
181
|
+
* Get list of available accounts (not on cooldown)
|
|
182
|
+
*
|
|
183
|
+
* @returns Array of available accounts
|
|
184
|
+
*/
|
|
185
|
+
getAvailableAccounts() {
|
|
186
|
+
return this.authManager.getAllAccounts().filter(account => !this.isAccountOnCooldown(account.username));
|
|
187
|
+
}
|
|
188
|
+
/**
|
|
189
|
+
* Get count of accounts currently on cooldown
|
|
190
|
+
*
|
|
191
|
+
* @returns Number of accounts on cooldown
|
|
192
|
+
*/
|
|
193
|
+
getAccountsOnCooldownCount() {
|
|
194
|
+
const accounts = this.authManager.getAllAccounts();
|
|
195
|
+
return accounts.filter(a => this.isAccountOnCooldown(a.username)).length;
|
|
196
|
+
}
|
|
197
|
+
/**
|
|
198
|
+
* Select the next account to use based on strategy
|
|
199
|
+
*
|
|
200
|
+
* @param availableAccounts - List of available accounts
|
|
201
|
+
* @returns The selected account
|
|
202
|
+
*/
|
|
203
|
+
selectNextAccount(availableAccounts) {
|
|
204
|
+
if (availableAccounts.length === 0) {
|
|
205
|
+
throw new Error('No available accounts');
|
|
206
|
+
}
|
|
207
|
+
if (availableAccounts.length === 1) {
|
|
208
|
+
return availableAccounts[0];
|
|
209
|
+
}
|
|
210
|
+
switch (this.strategy) {
|
|
211
|
+
case 'least-recently-used': {
|
|
212
|
+
// Find the account with the oldest lastUsedAt
|
|
213
|
+
let oldest = availableAccounts[0];
|
|
214
|
+
let oldestTime = this.usageStats.get(oldest.username)?.lastUsedAt ?? oldest.lastUsed ?? 0;
|
|
215
|
+
for (const account of availableAccounts) {
|
|
216
|
+
const lastUsed = this.usageStats.get(account.username)?.lastUsedAt ?? account.lastUsed ?? 0;
|
|
217
|
+
if (lastUsed < oldestTime) {
|
|
218
|
+
oldest = account;
|
|
219
|
+
oldestTime = lastUsed;
|
|
220
|
+
}
|
|
221
|
+
}
|
|
222
|
+
return oldest;
|
|
223
|
+
}
|
|
224
|
+
case 'round-robin':
|
|
225
|
+
default: {
|
|
226
|
+
// Cycle through accounts in order
|
|
227
|
+
const allAccounts = this.authManager.getAllAccounts();
|
|
228
|
+
// Find next available account starting from currentIndex
|
|
229
|
+
for (let i = 0; i < allAccounts.length; i++) {
|
|
230
|
+
const idx = (this.currentIndex + i) % allAccounts.length;
|
|
231
|
+
const account = allAccounts[idx];
|
|
232
|
+
if (availableAccounts.includes(account)) {
|
|
233
|
+
this.currentIndex = (idx + 1) % allAccounts.length;
|
|
234
|
+
return account;
|
|
235
|
+
}
|
|
236
|
+
}
|
|
237
|
+
// Fallback to first available
|
|
238
|
+
return availableAccounts[0];
|
|
239
|
+
}
|
|
240
|
+
}
|
|
241
|
+
}
|
|
242
|
+
/**
|
|
243
|
+
* Get the next available account, potentially rotating from current
|
|
244
|
+
*
|
|
245
|
+
* If the current account is on cooldown or has been rate-limited,
|
|
246
|
+
* switches to the next available account.
|
|
247
|
+
*
|
|
248
|
+
* @returns Rotation result with the selected account
|
|
249
|
+
* @throws AllAccountsOnCooldownError if all accounts are on cooldown
|
|
250
|
+
*/
|
|
251
|
+
async getNextAvailableAccount() {
|
|
252
|
+
const allAccounts = this.authManager.getAllAccounts();
|
|
253
|
+
const totalAccounts = allAccounts.length;
|
|
254
|
+
if (totalAccounts === 0) {
|
|
255
|
+
throw new Error('No accounts configured. Run `puter-auth login` to add an account.');
|
|
256
|
+
}
|
|
257
|
+
// If rotation is disabled, just return current account
|
|
258
|
+
if (!this.enabled) {
|
|
259
|
+
const current = this.authManager.getActiveAccount();
|
|
260
|
+
if (!current) {
|
|
261
|
+
throw new Error('No active account');
|
|
262
|
+
}
|
|
263
|
+
return {
|
|
264
|
+
account: current,
|
|
265
|
+
wasRotated: false,
|
|
266
|
+
accountsOnCooldown: this.getAccountsOnCooldownCount(),
|
|
267
|
+
totalAccounts,
|
|
268
|
+
};
|
|
269
|
+
}
|
|
270
|
+
const availableAccounts = this.getAvailableAccounts();
|
|
271
|
+
const accountsOnCooldown = totalAccounts - availableAccounts.length;
|
|
272
|
+
// If all accounts are on cooldown, throw error with details
|
|
273
|
+
if (availableAccounts.length === 0) {
|
|
274
|
+
const statuses = this.getAccountStatuses();
|
|
275
|
+
throw new AllAccountsOnCooldownError(statuses);
|
|
276
|
+
}
|
|
277
|
+
const currentAccount = this.authManager.getActiveAccount();
|
|
278
|
+
const currentUsername = currentAccount?.username;
|
|
279
|
+
// Check if current account is available
|
|
280
|
+
const currentIsAvailable = currentAccount &&
|
|
281
|
+
availableAccounts.some(a => a.username === currentAccount.username);
|
|
282
|
+
if (currentIsAvailable && accountsOnCooldown === 0) {
|
|
283
|
+
// Current account is fine and no rotation needed
|
|
284
|
+
return {
|
|
285
|
+
account: currentAccount,
|
|
286
|
+
wasRotated: false,
|
|
287
|
+
accountsOnCooldown: 0,
|
|
288
|
+
totalAccounts,
|
|
289
|
+
};
|
|
290
|
+
}
|
|
291
|
+
// Need to select a (potentially different) account
|
|
292
|
+
const selectedAccount = this.selectNextAccount(availableAccounts);
|
|
293
|
+
const wasRotated = selectedAccount.username !== currentUsername;
|
|
294
|
+
// If we selected a different account, switch to it
|
|
295
|
+
if (wasRotated) {
|
|
296
|
+
const targetIndex = allAccounts.findIndex(a => a.username === selectedAccount.username);
|
|
297
|
+
if (targetIndex >= 0) {
|
|
298
|
+
await this.authManager.switchAccount(targetIndex);
|
|
299
|
+
this.logger?.info(`Rotated to account: ${selectedAccount.username}`);
|
|
300
|
+
}
|
|
301
|
+
}
|
|
302
|
+
// Mark as used
|
|
303
|
+
this.markAsUsed(selectedAccount.username);
|
|
304
|
+
return {
|
|
305
|
+
account: selectedAccount,
|
|
306
|
+
wasRotated,
|
|
307
|
+
previousUsername: wasRotated ? currentUsername : undefined,
|
|
308
|
+
accountsOnCooldown,
|
|
309
|
+
totalAccounts,
|
|
310
|
+
};
|
|
311
|
+
}
|
|
312
|
+
/**
|
|
313
|
+
* Handle a rate limit error by adding current account to cooldown
|
|
314
|
+
* and returning the next available account
|
|
315
|
+
*
|
|
316
|
+
* @param error - The rate limit error
|
|
317
|
+
* @returns Next available account, or null if all on cooldown
|
|
318
|
+
*/
|
|
319
|
+
async handleRateLimitError(error) {
|
|
320
|
+
const currentAccount = this.authManager.getActiveAccount();
|
|
321
|
+
if (currentAccount) {
|
|
322
|
+
this.addToCooldown(currentAccount.username, error.message);
|
|
323
|
+
}
|
|
324
|
+
try {
|
|
325
|
+
return await this.getNextAvailableAccount();
|
|
326
|
+
}
|
|
327
|
+
catch (e) {
|
|
328
|
+
if (e instanceof AllAccountsOnCooldownError) {
|
|
329
|
+
return null;
|
|
330
|
+
}
|
|
331
|
+
throw e;
|
|
332
|
+
}
|
|
333
|
+
}
|
|
334
|
+
/**
|
|
335
|
+
* Clear all cooldowns (useful for testing or manual reset)
|
|
336
|
+
*/
|
|
337
|
+
clearCooldowns() {
|
|
338
|
+
this.cooldownMap.clear();
|
|
339
|
+
this.logger?.debug('All account cooldowns cleared');
|
|
340
|
+
}
|
|
341
|
+
/**
|
|
342
|
+
* Reset all statistics
|
|
343
|
+
*/
|
|
344
|
+
resetStats() {
|
|
345
|
+
this.usageStats.clear();
|
|
346
|
+
this.currentIndex = 0;
|
|
347
|
+
this.logger?.debug('Account rotation stats reset');
|
|
348
|
+
}
|
|
349
|
+
/**
|
|
350
|
+
* Update configuration
|
|
351
|
+
*/
|
|
352
|
+
configure(options) {
|
|
353
|
+
if (options.cooldownMs !== undefined) {
|
|
354
|
+
this.cooldownMs = options.cooldownMs;
|
|
355
|
+
}
|
|
356
|
+
if (options.enabled !== undefined) {
|
|
357
|
+
this.enabled = options.enabled;
|
|
358
|
+
}
|
|
359
|
+
if (options.strategy !== undefined) {
|
|
360
|
+
this.strategy = options.strategy;
|
|
361
|
+
}
|
|
362
|
+
}
|
|
363
|
+
/**
|
|
364
|
+
* Get current configuration
|
|
365
|
+
*/
|
|
366
|
+
getConfig() {
|
|
367
|
+
return {
|
|
368
|
+
cooldownMs: this.cooldownMs,
|
|
369
|
+
enabled: this.enabled,
|
|
370
|
+
strategy: this.strategy,
|
|
371
|
+
};
|
|
372
|
+
}
|
|
373
|
+
/**
|
|
374
|
+
* Check if rotation is needed (current account on cooldown)
|
|
375
|
+
*/
|
|
376
|
+
isRotationNeeded() {
|
|
377
|
+
if (!this.enabled)
|
|
378
|
+
return false;
|
|
379
|
+
const current = this.authManager.getActiveAccount();
|
|
380
|
+
if (!current)
|
|
381
|
+
return false;
|
|
382
|
+
return this.isAccountOnCooldown(current.username);
|
|
383
|
+
}
|
|
384
|
+
/**
|
|
385
|
+
* Get a summary of the rotation state
|
|
386
|
+
*/
|
|
387
|
+
getSummary() {
|
|
388
|
+
const allAccounts = this.authManager.getAllAccounts();
|
|
389
|
+
const available = this.getAvailableAccounts();
|
|
390
|
+
const current = this.authManager.getActiveAccount();
|
|
391
|
+
return {
|
|
392
|
+
enabled: this.enabled,
|
|
393
|
+
totalAccounts: allAccounts.length,
|
|
394
|
+
availableAccounts: available.length,
|
|
395
|
+
onCooldown: allAccounts.length - available.length,
|
|
396
|
+
currentAccount: current?.username ?? null,
|
|
397
|
+
strategy: this.strategy,
|
|
398
|
+
};
|
|
399
|
+
}
|
|
400
|
+
}
|
|
401
|
+
/**
|
|
402
|
+
* Global AccountRotationManager instance
|
|
403
|
+
*/
|
|
404
|
+
let globalAccountRotationManager = null;
|
|
405
|
+
/**
|
|
406
|
+
* Get the global AccountRotationManager instance
|
|
407
|
+
*
|
|
408
|
+
* @param authManager - The auth manager (required on first call)
|
|
409
|
+
* @param options - Configuration options
|
|
410
|
+
* @param logger - Optional logger
|
|
411
|
+
* @returns The global AccountRotationManager instance
|
|
412
|
+
*/
|
|
413
|
+
export function getGlobalAccountRotationManager(authManager, options, logger) {
|
|
414
|
+
if (!globalAccountRotationManager) {
|
|
415
|
+
if (!authManager) {
|
|
416
|
+
throw new Error('AuthManager required when creating AccountRotationManager');
|
|
417
|
+
}
|
|
418
|
+
globalAccountRotationManager = new AccountRotationManager(authManager, options, logger);
|
|
419
|
+
}
|
|
420
|
+
else if (options) {
|
|
421
|
+
globalAccountRotationManager.configure(options);
|
|
422
|
+
}
|
|
423
|
+
return globalAccountRotationManager;
|
|
424
|
+
}
|
|
425
|
+
/**
|
|
426
|
+
* Reset the global AccountRotationManager (useful for testing)
|
|
427
|
+
*/
|
|
428
|
+
export function resetGlobalAccountRotationManager() {
|
|
429
|
+
globalAccountRotationManager = null;
|
|
430
|
+
}
|
|
431
|
+
//# sourceMappingURL=account-rotation.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"account-rotation.js","sourceRoot":"","sources":["../src/account-rotation.ts"],"names":[],"mappings":"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"}
|
|
@@ -3,12 +3,19 @@
|
|
|
3
3
|
*
|
|
4
4
|
* Implements the AI SDK LanguageModelV3 interface using the official @heyputer/puter.js SDK.
|
|
5
5
|
* This enables Puter to work as a proper AI SDK provider in OpenCode.
|
|
6
|
+
*
|
|
7
|
+
* Features automatic model fallback when rate limits are encountered.
|
|
6
8
|
*/
|
|
7
9
|
import type { LanguageModelV3, LanguageModelV3CallOptions, LanguageModelV3GenerateResult, LanguageModelV3StreamResult } from '@ai-sdk/provider';
|
|
8
10
|
import type { PuterChatSettings, PuterChatConfig } from './puter-chat-settings.js';
|
|
9
11
|
/**
|
|
10
12
|
* Puter Chat Language Model implementing LanguageModelV3.
|
|
11
13
|
* Uses the official @heyputer/puter.js SDK for all API calls.
|
|
14
|
+
*
|
|
15
|
+
* Features automatic model fallback when rate limits are encountered:
|
|
16
|
+
* - Detects rate limit errors (429, 403)
|
|
17
|
+
* - Automatically switches to free OpenRouter models
|
|
18
|
+
* - Tracks model cooldowns to avoid repeated failures
|
|
12
19
|
*/
|
|
13
20
|
export declare class PuterChatLanguageModel implements LanguageModelV3 {
|
|
14
21
|
readonly specificationVersion: "v3";
|
|
@@ -17,6 +24,8 @@ export declare class PuterChatLanguageModel implements LanguageModelV3 {
|
|
|
17
24
|
private readonly settings;
|
|
18
25
|
private readonly config;
|
|
19
26
|
private puterInstance;
|
|
27
|
+
private readonly fallbackManager;
|
|
28
|
+
private readonly logger;
|
|
20
29
|
constructor(modelId: string, settings: PuterChatSettings, config: PuterChatConfig);
|
|
21
30
|
/**
|
|
22
31
|
* Initialize the Puter SDK with auth token.
|
|
@@ -37,6 +46,10 @@ export declare class PuterChatLanguageModel implements LanguageModelV3 {
|
|
|
37
46
|
private convertTools;
|
|
38
47
|
/**
|
|
39
48
|
* Build options for Puter SDK chat call.
|
|
49
|
+
*
|
|
50
|
+
* @param options - AI SDK call options
|
|
51
|
+
* @param streaming - Whether to enable streaming
|
|
52
|
+
* @param modelOverride - Optional model to use instead of this.modelId (for fallback)
|
|
40
53
|
*/
|
|
41
54
|
private buildSDKOptions;
|
|
42
55
|
/**
|
|
@@ -53,10 +66,16 @@ export declare class PuterChatLanguageModel implements LanguageModelV3 {
|
|
|
53
66
|
private extractTextContent;
|
|
54
67
|
/**
|
|
55
68
|
* Non-streaming generation using Puter SDK.
|
|
69
|
+
*
|
|
70
|
+
* Automatically falls back to alternative models when rate limits are hit,
|
|
71
|
+
* unless `disableFallback` is set in settings.
|
|
56
72
|
*/
|
|
57
73
|
doGenerate(options: LanguageModelV3CallOptions): Promise<LanguageModelV3GenerateResult>;
|
|
58
74
|
/**
|
|
59
75
|
* Streaming generation using Puter SDK.
|
|
76
|
+
*
|
|
77
|
+
* Automatically falls back to alternative models when rate limits are hit,
|
|
78
|
+
* unless `disableFallback` is set in settings.
|
|
60
79
|
*/
|
|
61
80
|
doStream(options: LanguageModelV3CallOptions): Promise<LanguageModelV3StreamResult>;
|
|
62
81
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"puter-chat-language-model.d.ts","sourceRoot":"","sources":["../../src/ai-provider/puter-chat-language-model.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"puter-chat-language-model.d.ts","sourceRoot":"","sources":["../../src/ai-provider/puter-chat-language-model.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,KAAK,EACV,eAAe,EACf,0BAA0B,EAC1B,6BAA6B,EAC7B,2BAA2B,EAW5B,MAAM,kBAAkB,CAAC;AAC1B,OAAO,KAAK,EAAE,iBAAiB,EAAE,eAAe,EAAE,MAAM,0BAA0B,CAAC;AAsGnF;;;;;;;;GAQG;AACH,qBAAa,sBAAuB,YAAW,eAAe;IAC5D,QAAQ,CAAC,oBAAoB,EAAG,IAAI,CAAU;IAC9C,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAC1B,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IAEzB,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAoB;IAC7C,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAkB;IACzC,OAAO,CAAC,aAAa,CAAyB;IAC9C,OAAO,CAAC,QAAQ,CAAC,eAAe,CAAkB;IAClD,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAS;gBAG9B,OAAO,EAAE,MAAM,EACf,QAAQ,EAAE,iBAAiB,EAC3B,MAAM,EAAE,eAAe;IAczB;;OAEG;YACW,YAAY;IA0B1B;;;OAGG;IACH,IAAI,aAAa,IAAI,MAAM,CAAC,MAAM,EAAE,MAAM,EAAE,CAAC,CAE5C;IAED;;OAEG;IACH,OAAO,CAAC,uBAAuB;IA4E/B;;OAEG;IACH,OAAO,CAAC,YAAY;IAapB;;;;;;OAMG;IACH,OAAO,CAAC,eAAe;IAqCvB;;OAEG;IACH,OAAO,CAAC,eAAe;IAgBvB;;OAEG;IACH,OAAO,CAAC,QAAQ;IAgBhB;;OAEG;IACH,OAAO,CAAC,kBAAkB;IAiB1B;;;;;OAKG;IACG,UAAU,CAAC,OAAO,EAAE,0BAA0B,GAAG,OAAO,CAAC,6BAA6B,CAAC;IA2F7F;;;;;OAKG;IACG,QAAQ,CAAC,OAAO,EAAE,0BAA0B,GAAG,OAAO,CAAC,2BAA2B,CAAC;CA2G1F"}
|
|
@@ -3,10 +3,19 @@
|
|
|
3
3
|
*
|
|
4
4
|
* Implements the AI SDK LanguageModelV3 interface using the official @heyputer/puter.js SDK.
|
|
5
5
|
* This enables Puter to work as a proper AI SDK provider in OpenCode.
|
|
6
|
+
*
|
|
7
|
+
* Features automatic model fallback when rate limits are encountered.
|
|
6
8
|
*/
|
|
9
|
+
import { getGlobalFallbackManager, } from '../fallback.js';
|
|
10
|
+
import { createLogger } from '../logger.js';
|
|
7
11
|
/**
|
|
8
12
|
* Puter Chat Language Model implementing LanguageModelV3.
|
|
9
13
|
* Uses the official @heyputer/puter.js SDK for all API calls.
|
|
14
|
+
*
|
|
15
|
+
* Features automatic model fallback when rate limits are encountered:
|
|
16
|
+
* - Detects rate limit errors (429, 403)
|
|
17
|
+
* - Automatically switches to free OpenRouter models
|
|
18
|
+
* - Tracks model cooldowns to avoid repeated failures
|
|
10
19
|
*/
|
|
11
20
|
export class PuterChatLanguageModel {
|
|
12
21
|
specificationVersion = 'v3';
|
|
@@ -15,11 +24,17 @@ export class PuterChatLanguageModel {
|
|
|
15
24
|
settings;
|
|
16
25
|
config;
|
|
17
26
|
puterInstance = null;
|
|
27
|
+
fallbackManager;
|
|
28
|
+
logger;
|
|
18
29
|
constructor(modelId, settings, config) {
|
|
19
30
|
this.modelId = modelId;
|
|
20
31
|
this.settings = settings;
|
|
21
32
|
this.config = config;
|
|
22
33
|
this.provider = config.provider;
|
|
34
|
+
// Initialize fallback manager with config options
|
|
35
|
+
this.fallbackManager = getGlobalFallbackManager(config.fallback);
|
|
36
|
+
// Create logger (uses console by default, can be configured)
|
|
37
|
+
this.logger = createLogger({ debug: false }); // Will be quiet unless debug enabled
|
|
23
38
|
}
|
|
24
39
|
/**
|
|
25
40
|
* Initialize the Puter SDK with auth token.
|
|
@@ -144,13 +159,17 @@ export class PuterChatLanguageModel {
|
|
|
144
159
|
}
|
|
145
160
|
/**
|
|
146
161
|
* Build options for Puter SDK chat call.
|
|
162
|
+
*
|
|
163
|
+
* @param options - AI SDK call options
|
|
164
|
+
* @param streaming - Whether to enable streaming
|
|
165
|
+
* @param modelOverride - Optional model to use instead of this.modelId (for fallback)
|
|
147
166
|
*/
|
|
148
|
-
buildSDKOptions(options, streaming) {
|
|
167
|
+
buildSDKOptions(options, streaming, modelOverride) {
|
|
149
168
|
// Filter to only function tools
|
|
150
169
|
const functionTools = options.tools?.filter((tool) => tool.type === 'function');
|
|
151
170
|
const tools = this.convertTools(functionTools);
|
|
152
171
|
const sdkOptions = {
|
|
153
|
-
model: this.modelId,
|
|
172
|
+
model: modelOverride ?? this.modelId,
|
|
154
173
|
stream: streaming,
|
|
155
174
|
};
|
|
156
175
|
// Only add optional params if they have values
|
|
@@ -232,13 +251,43 @@ export class PuterChatLanguageModel {
|
|
|
232
251
|
}
|
|
233
252
|
/**
|
|
234
253
|
* Non-streaming generation using Puter SDK.
|
|
254
|
+
*
|
|
255
|
+
* Automatically falls back to alternative models when rate limits are hit,
|
|
256
|
+
* unless `disableFallback` is set in settings.
|
|
235
257
|
*/
|
|
236
258
|
async doGenerate(options) {
|
|
237
259
|
const puter = await this.initPuterSDK();
|
|
238
260
|
const messages = this.convertPromptToMessages(options.prompt);
|
|
239
|
-
const sdkOptions = this.buildSDKOptions(options, false);
|
|
240
261
|
const warnings = [];
|
|
241
|
-
|
|
262
|
+
// Check if fallback is disabled for this request
|
|
263
|
+
const useFallback = !this.settings.disableFallback;
|
|
264
|
+
// Define the operation that will be executed (possibly with fallback)
|
|
265
|
+
const executeChat = async (model) => {
|
|
266
|
+
const sdkOptions = this.buildSDKOptions(options, false, model);
|
|
267
|
+
return await puter.ai.chat(messages, sdkOptions);
|
|
268
|
+
};
|
|
269
|
+
let response;
|
|
270
|
+
let actualModelUsed = this.modelId;
|
|
271
|
+
let wasFallback = false;
|
|
272
|
+
if (useFallback) {
|
|
273
|
+
// Execute with fallback support
|
|
274
|
+
const fallbackResult = await this.fallbackManager.executeWithFallback(this.modelId, executeChat, this.logger);
|
|
275
|
+
response = fallbackResult.result;
|
|
276
|
+
actualModelUsed = fallbackResult.usedModel;
|
|
277
|
+
wasFallback = fallbackResult.wasFallback;
|
|
278
|
+
if (wasFallback) {
|
|
279
|
+
// Add a warning that fallback was used
|
|
280
|
+
warnings.push({
|
|
281
|
+
type: 'other',
|
|
282
|
+
message: `Model ${this.modelId} rate limited, used fallback: ${actualModelUsed}`,
|
|
283
|
+
});
|
|
284
|
+
}
|
|
285
|
+
}
|
|
286
|
+
else {
|
|
287
|
+
// Execute without fallback
|
|
288
|
+
const sdkOptions = this.buildSDKOptions(options, false);
|
|
289
|
+
response = await puter.ai.chat(messages, sdkOptions);
|
|
290
|
+
}
|
|
242
291
|
const content = [];
|
|
243
292
|
// Extract text content (handles both string and array formats)
|
|
244
293
|
const textContent = this.extractTextContent(response.message?.content);
|
|
@@ -277,7 +326,7 @@ export class PuterChatLanguageModel {
|
|
|
277
326
|
finishReason: this.mapFinishReason(response.finish_reason),
|
|
278
327
|
usage: this.mapUsage(response.usage),
|
|
279
328
|
warnings,
|
|
280
|
-
request: { body: { messages,
|
|
329
|
+
request: { body: { messages, model: actualModelUsed } },
|
|
281
330
|
response: {
|
|
282
331
|
body: response,
|
|
283
332
|
},
|
|
@@ -285,14 +334,42 @@ export class PuterChatLanguageModel {
|
|
|
285
334
|
}
|
|
286
335
|
/**
|
|
287
336
|
* Streaming generation using Puter SDK.
|
|
337
|
+
*
|
|
338
|
+
* Automatically falls back to alternative models when rate limits are hit,
|
|
339
|
+
* unless `disableFallback` is set in settings.
|
|
288
340
|
*/
|
|
289
341
|
async doStream(options) {
|
|
290
342
|
const puter = await this.initPuterSDK();
|
|
291
343
|
const messages = this.convertPromptToMessages(options.prompt);
|
|
292
|
-
const sdkOptions = this.buildSDKOptions(options, true);
|
|
293
344
|
const warnings = [];
|
|
294
345
|
const generateId = this.config.generateId;
|
|
295
|
-
|
|
346
|
+
// Check if fallback is disabled for this request
|
|
347
|
+
const useFallback = !this.settings.disableFallback;
|
|
348
|
+
// Define the operation that initiates the stream
|
|
349
|
+
const initiateStream = async (model) => {
|
|
350
|
+
const sdkOptions = this.buildSDKOptions(options, true, model);
|
|
351
|
+
return await puter.ai.chat(messages, sdkOptions);
|
|
352
|
+
};
|
|
353
|
+
let streamResponse;
|
|
354
|
+
let actualModelUsed = this.modelId;
|
|
355
|
+
if (useFallback) {
|
|
356
|
+
// Execute stream initiation with fallback support
|
|
357
|
+
const fallbackResult = await this.fallbackManager.executeWithFallback(this.modelId, initiateStream, this.logger);
|
|
358
|
+
streamResponse = fallbackResult.result;
|
|
359
|
+
actualModelUsed = fallbackResult.usedModel;
|
|
360
|
+
if (fallbackResult.wasFallback) {
|
|
361
|
+
// Add a warning that fallback was used
|
|
362
|
+
warnings.push({
|
|
363
|
+
type: 'other',
|
|
364
|
+
message: `Model ${this.modelId} rate limited, used fallback: ${actualModelUsed}`,
|
|
365
|
+
});
|
|
366
|
+
}
|
|
367
|
+
}
|
|
368
|
+
else {
|
|
369
|
+
// Execute without fallback
|
|
370
|
+
const sdkOptions = this.buildSDKOptions(options, true);
|
|
371
|
+
streamResponse = await puter.ai.chat(messages, sdkOptions);
|
|
372
|
+
}
|
|
296
373
|
// Create a transform stream to convert Puter chunks to AI SDK format
|
|
297
374
|
const self = this;
|
|
298
375
|
let textId = null;
|
|
@@ -350,7 +427,7 @@ export class PuterChatLanguageModel {
|
|
|
350
427
|
});
|
|
351
428
|
return {
|
|
352
429
|
stream,
|
|
353
|
-
request: { body: { messages,
|
|
430
|
+
request: { body: { messages, model: actualModelUsed } },
|
|
354
431
|
};
|
|
355
432
|
}
|
|
356
433
|
}
|