@omnicross/subscriptions 0.1.5 → 0.1.7
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/NOTICE +4 -33
- package/dist/{chunk-TPW5Q25Y.cjs → chunk-PWV5NBO5.cjs} +47 -16
- package/dist/{chunk-IXGHVMZB.js → chunk-UETFQ5LB.js} +47 -16
- package/dist/index.cjs +323 -154
- package/dist/index.d.cts +12 -12
- package/dist/index.d.ts +12 -12
- package/dist/index.js +278 -109
- package/dist/oauth.cjs +2 -2
- package/dist/oauth.d.cts +1 -5
- package/dist/oauth.d.ts +1 -5
- package/dist/oauth.js +1 -1
- package/package.json +1 -1
package/dist/index.cjs
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
|
|
4
4
|
|
|
5
|
-
var
|
|
5
|
+
var _chunkPWV5NBO5cjs = require('./chunk-PWV5NBO5.cjs');
|
|
6
6
|
|
|
7
7
|
// src/scheduler/SubscriptionAccountSelector.ts
|
|
8
8
|
var SESSION_AFFINITY_TTL_MS = 36e5;
|
|
@@ -108,6 +108,15 @@ var SubscriptionAccountSelector = (_class = class {constructor() { _class.protot
|
|
|
108
108
|
// src/SubscriptionAccountService.ts
|
|
109
109
|
var _SubscriptionAccountHealth = require('@omnicross/core/pipeline/SubscriptionAccountHealth');
|
|
110
110
|
|
|
111
|
+
// src/scheduler/accountSelection.ts
|
|
112
|
+
|
|
113
|
+
|
|
114
|
+
|
|
115
|
+
var _AccountAllowanceScheduling = require('@omnicross/core/pipeline/AccountAllowanceScheduling');
|
|
116
|
+
|
|
117
|
+
|
|
118
|
+
var _BoundAccountSelectionError = require('@omnicross/core/pipeline/BoundAccountSelectionError');
|
|
119
|
+
|
|
111
120
|
// src/scheduler/accountModelMap.ts
|
|
112
121
|
function canonicalModelId(value) {
|
|
113
122
|
const idx = value.indexOf(",");
|
|
@@ -154,19 +163,104 @@ function gateSchedulable(accounts, providerId, health, now, resolvedModel, suppo
|
|
|
154
163
|
return accounts.map((a) => {
|
|
155
164
|
const healthOk = health ? health.isSchedulable(providerId, a.id, now) : true;
|
|
156
165
|
const modelOk = resolvedModel ? accountSupportsModel(supportedModelsById.get(a.id), resolvedModel) : true;
|
|
157
|
-
return { ...a, schedulable: healthOk && modelOk };
|
|
166
|
+
return { ...a, schedulable: a.schedulable !== false && healthOk && modelOk };
|
|
158
167
|
});
|
|
159
168
|
}
|
|
160
169
|
function isPoolGated(accounts, health, resolvedModel) {
|
|
161
170
|
return (health !== void 0 || resolvedModel !== void 0) && accounts.length >= 2;
|
|
162
171
|
}
|
|
172
|
+
function hasUsableToken(token) {
|
|
173
|
+
return typeof token === "string" && token.trim() !== "";
|
|
174
|
+
}
|
|
175
|
+
async function resolveStrictPreferredToken(selector, tokens, providerId, preferredId, activeGetter, ctx) {
|
|
176
|
+
let config;
|
|
177
|
+
try {
|
|
178
|
+
config = await tokens.getFullConfig();
|
|
179
|
+
} catch (e2) {
|
|
180
|
+
throw new (0, _BoundAccountSelectionError.BoundAccountSelectionError)(providerId, "unavailable");
|
|
181
|
+
}
|
|
182
|
+
let accounts;
|
|
183
|
+
let activeAccountId;
|
|
184
|
+
let supportedModelsById;
|
|
185
|
+
try {
|
|
186
|
+
({ accounts, activeAccountId, supportedModelsById } = readSchedulableAccounts(config, providerId));
|
|
187
|
+
} catch (e3) {
|
|
188
|
+
throw new (0, _BoundAccountSelectionError.BoundAccountSelectionError)(providerId, "unavailable");
|
|
189
|
+
}
|
|
190
|
+
const preferred = accounts.find((account) => account.id === preferredId);
|
|
191
|
+
if (!preferred) {
|
|
192
|
+
throw new (0, _BoundAccountSelectionError.BoundAccountSelectionError)(providerId, "not-found");
|
|
193
|
+
}
|
|
194
|
+
if (preferred.schedulable === false) {
|
|
195
|
+
throw new (0, _BoundAccountSelectionError.BoundAccountSelectionError)(providerId, "disabled");
|
|
196
|
+
}
|
|
197
|
+
if (ctx.health && !ctx.health.isSchedulable(providerId, preferredId, ctx.now)) {
|
|
198
|
+
throw new (0, _BoundAccountSelectionError.BoundAccountSelectionError)(providerId, "unhealthy");
|
|
199
|
+
}
|
|
200
|
+
if (ctx.resolvedModel && !accountSupportsModel(supportedModelsById.get(preferredId), ctx.resolvedModel)) {
|
|
201
|
+
throw new (0, _BoundAccountSelectionError.BoundAccountSelectionError)(providerId, "model-incompatible");
|
|
202
|
+
}
|
|
203
|
+
const allowance = _AccountAllowanceScheduling.getSharedAccountAllowanceScheduling.call(void 0, ).evaluate(
|
|
204
|
+
providerId,
|
|
205
|
+
preferredId,
|
|
206
|
+
_nullishCoalesce(preferred.priority, () => ( DEFAULT_ACCOUNT_PRIORITY)),
|
|
207
|
+
ctx.now
|
|
208
|
+
);
|
|
209
|
+
if (allowance.action === "pause") {
|
|
210
|
+
throw new (0, _BoundAccountSelectionError.BoundAccountSelectionError)(providerId, "allowance-paused", allowance.resumeAt);
|
|
211
|
+
}
|
|
212
|
+
let token = null;
|
|
213
|
+
try {
|
|
214
|
+
token = tokens.getAccessTokenForAccount ? await tokens.getAccessTokenForAccount(providerId, preferredId) : preferredId === activeAccountId ? await activeGetter() : null;
|
|
215
|
+
} catch (e4) {
|
|
216
|
+
throw new (0, _BoundAccountSelectionError.BoundAccountSelectionError)(providerId, "unavailable");
|
|
217
|
+
}
|
|
218
|
+
if (!hasUsableToken(token)) {
|
|
219
|
+
throw new (0, _BoundAccountSelectionError.BoundAccountSelectionError)(providerId, "empty-token");
|
|
220
|
+
}
|
|
221
|
+
const remapped = remapReportForAccount(supportedModelsById.get(preferredId), ctx.resolvedModel);
|
|
222
|
+
if (selector) maybeTouchLastUsed(selector, tokens, providerId, preferredId);
|
|
223
|
+
_optionalChain([ctx, 'access', _ => _.reportSelection, 'optionalCall', _2 => _2(preferredId, preferredId === activeAccountId, remapped)]);
|
|
224
|
+
return token;
|
|
225
|
+
}
|
|
226
|
+
function gateByAllowance(accounts, providerId, now) {
|
|
227
|
+
const scheduling = _AccountAllowanceScheduling.getSharedAccountAllowanceScheduling.call(void 0, );
|
|
228
|
+
const evaluatedAt = _nullishCoalesce(now, () => ( Date.now()));
|
|
229
|
+
const eligibleBeforePolicy = accounts.filter((account) => account.schedulable !== false);
|
|
230
|
+
if (eligibleBeforePolicy.length === 0) return accounts;
|
|
231
|
+
const decisions = /* @__PURE__ */ new Map();
|
|
232
|
+
const gated = accounts.map((account) => {
|
|
233
|
+
if (account.schedulable === false) return account;
|
|
234
|
+
const decision = scheduling.evaluate(
|
|
235
|
+
providerId,
|
|
236
|
+
account.id,
|
|
237
|
+
_nullishCoalesce(account.priority, () => ( DEFAULT_ACCOUNT_PRIORITY)),
|
|
238
|
+
evaluatedAt
|
|
239
|
+
);
|
|
240
|
+
decisions.set(account.id, decision);
|
|
241
|
+
return {
|
|
242
|
+
...account,
|
|
243
|
+
priority: decision.effectivePriority,
|
|
244
|
+
schedulable: decision.schedulable
|
|
245
|
+
};
|
|
246
|
+
});
|
|
247
|
+
if (gated.some((account) => account.schedulable !== false)) return gated;
|
|
248
|
+
const paused = eligibleBeforePolicy.map((account) => decisions.get(account.id)).filter((decision) => _optionalChain([decision, 'optionalAccess', _3 => _3.action]) === "pause");
|
|
249
|
+
if (paused.length !== eligibleBeforePolicy.length) return gated;
|
|
250
|
+
const resumeAt = paused.map((decision) => _optionalChain([decision, 'optionalAccess', _4 => _4.resumeAt])).filter((value) => !!value).sort()[0];
|
|
251
|
+
throw new (0, _AccountAllowanceScheduling.AccountAllowanceExhaustedError)(providerId, resumeAt);
|
|
252
|
+
}
|
|
163
253
|
function readSchedulableAccounts(config, providerId) {
|
|
164
254
|
const raw = _nullishCoalesce(config[ACCOUNTS_KEY[providerId]], () => ( []));
|
|
165
255
|
const accounts = raw.map((a) => ({
|
|
166
256
|
id: a.id,
|
|
257
|
+
group: typeof a.group === "string" && a.group.trim() !== "" ? a.group.trim() : providerId,
|
|
167
258
|
priority: a.priority,
|
|
168
259
|
lastUsedAt: a.lastUsedAt,
|
|
169
|
-
createdAt: a.createdAt
|
|
260
|
+
createdAt: a.createdAt,
|
|
261
|
+
// Persisted opt-out is absolute, including a one-account pool. Legacy rows
|
|
262
|
+
// omit the field and therefore remain enabled.
|
|
263
|
+
schedulable: a.enabled !== false
|
|
170
264
|
}));
|
|
171
265
|
const supportedModelsById = new Map(
|
|
172
266
|
raw.map((a) => [a.id, a.supportedModels])
|
|
@@ -184,24 +278,64 @@ function pickByIdTarget(selector, gated, providerId, activeAccountId, sessionKey
|
|
|
184
278
|
return void 0;
|
|
185
279
|
}
|
|
186
280
|
async function resolveSelectedToken(selector, tokens, providerId, sessionKey, activeGetter, ctx) {
|
|
187
|
-
const health = _optionalChain([ctx, 'optionalAccess',
|
|
188
|
-
const report = _optionalChain([ctx, 'optionalAccess',
|
|
189
|
-
const now = _optionalChain([ctx, 'optionalAccess',
|
|
190
|
-
const resolvedModel = _optionalChain([ctx, 'optionalAccess',
|
|
281
|
+
const health = _optionalChain([ctx, 'optionalAccess', _5 => _5.health]);
|
|
282
|
+
const report = _optionalChain([ctx, 'optionalAccess', _6 => _6.reportSelection]);
|
|
283
|
+
const now = _optionalChain([ctx, 'optionalAccess', _7 => _7.now]);
|
|
284
|
+
const resolvedModel = _optionalChain([ctx, 'optionalAccess', _8 => _8.resolvedModel]);
|
|
285
|
+
const preferredId = typeof _optionalChain([ctx, 'optionalAccess', _9 => _9.preferredAccountId]) === "string" && ctx.preferredAccountId.trim() !== "" ? ctx.preferredAccountId.trim() : void 0;
|
|
286
|
+
const preferredGroup = typeof _optionalChain([ctx, 'optionalAccess', _10 => _10.preferredAccountGroup]) === "string" && ctx.preferredAccountGroup.trim() !== "" ? ctx.preferredAccountGroup.trim() : void 0;
|
|
287
|
+
if (preferredId && ctx && ctx.boundAccountFallbackPolicy !== "pool") {
|
|
288
|
+
return resolveStrictPreferredToken(selector, tokens, providerId, preferredId, activeGetter, ctx);
|
|
289
|
+
}
|
|
191
290
|
if (selector && tokens.getAccessTokenForAccount) {
|
|
192
291
|
const config = await tokens.getFullConfig();
|
|
193
292
|
const { accounts, activeAccountId, supportedModelsById } = readSchedulableAccounts(config, providerId);
|
|
194
|
-
const
|
|
195
|
-
|
|
293
|
+
const groupAccounts = preferredGroup ? accounts.filter((account) => account.group === preferredGroup) : accounts;
|
|
294
|
+
if (preferredGroup && groupAccounts.length === 0 && _optionalChain([ctx, 'optionalAccess', _11 => _11.boundAccountFallbackPolicy]) !== "pool") {
|
|
295
|
+
throw new (0, _BoundAccountSelectionError.BoundAccountSelectionError)(providerId, "not-found");
|
|
296
|
+
}
|
|
297
|
+
let candidates = groupAccounts.length > 0 ? groupAccounts : accounts;
|
|
298
|
+
let healthAndModelGated = gateSchedulable(
|
|
299
|
+
candidates,
|
|
300
|
+
providerId,
|
|
301
|
+
health,
|
|
302
|
+
now,
|
|
303
|
+
resolvedModel,
|
|
304
|
+
supportedModelsById
|
|
305
|
+
);
|
|
306
|
+
let gated = gateByAllowance(healthAndModelGated, providerId, now);
|
|
307
|
+
let groupHasUsableCredential = gated.some((account) => account.schedulable !== false);
|
|
308
|
+
if (groupHasUsableCredential && preferredGroup && _optionalChain([ctx, 'optionalAccess', _12 => _12.boundAccountFallbackPolicy]) === "pool" && candidates !== accounts) {
|
|
309
|
+
groupHasUsableCredential = false;
|
|
310
|
+
for (const account of gated) {
|
|
311
|
+
if (account.schedulable === false) continue;
|
|
312
|
+
if (await tokens.getAccessTokenForAccount(providerId, account.id)) {
|
|
313
|
+
groupHasUsableCredential = true;
|
|
314
|
+
break;
|
|
315
|
+
}
|
|
316
|
+
}
|
|
317
|
+
}
|
|
318
|
+
if (preferredGroup && _optionalChain([ctx, 'optionalAccess', _13 => _13.boundAccountFallbackPolicy]) === "pool" && candidates !== accounts && !groupHasUsableCredential) {
|
|
319
|
+
candidates = accounts;
|
|
320
|
+
healthAndModelGated = gateSchedulable(
|
|
321
|
+
candidates,
|
|
322
|
+
providerId,
|
|
323
|
+
health,
|
|
324
|
+
now,
|
|
325
|
+
resolvedModel,
|
|
326
|
+
supportedModelsById
|
|
327
|
+
);
|
|
328
|
+
gated = gateByAllowance(healthAndModelGated, providerId, now);
|
|
329
|
+
}
|
|
330
|
+
const poolGated = isPoolGated(candidates, health, resolvedModel) || candidates.some((account) => account.schedulable === false) || preferredGroup !== void 0;
|
|
196
331
|
const remapFor = (id) => remapReportForAccount(supportedModelsById.get(id), resolvedModel);
|
|
197
|
-
const preferredId = _optionalChain([ctx, 'optionalAccess', _5 => _5.preferredAccountId]);
|
|
198
332
|
if (preferredId) {
|
|
199
333
|
const preferred = gated.find((a) => a.id === preferredId);
|
|
200
334
|
if (preferred && preferred.schedulable !== false) {
|
|
201
335
|
const preferredToken = await tokens.getAccessTokenForAccount(providerId, preferredId);
|
|
202
336
|
if (preferredToken) {
|
|
203
337
|
maybeTouchLastUsed(selector, tokens, providerId, preferredId);
|
|
204
|
-
_optionalChain([report, 'optionalCall',
|
|
338
|
+
_optionalChain([report, 'optionalCall', _14 => _14(preferredId, preferredId === activeAccountId, remapFor(preferredId))]);
|
|
205
339
|
return preferredToken;
|
|
206
340
|
}
|
|
207
341
|
}
|
|
@@ -211,23 +345,44 @@ async function resolveSelectedToken(selector, tokens, providerId, sessionKey, ac
|
|
|
211
345
|
const byId = await tokens.getAccessTokenForAccount(providerId, targetId);
|
|
212
346
|
if (byId) {
|
|
213
347
|
maybeTouchLastUsed(selector, tokens, providerId, targetId);
|
|
214
|
-
_optionalChain([report, 'optionalCall',
|
|
348
|
+
_optionalChain([report, 'optionalCall', _15 => _15(targetId, false, remapFor(targetId))]);
|
|
215
349
|
return byId;
|
|
216
350
|
}
|
|
217
351
|
selector.evictAffinity(providerId, targetId);
|
|
218
|
-
_optionalChain([health, 'optionalAccess',
|
|
352
|
+
_optionalChain([health, 'optionalAccess', _16 => _16.recordUpstreamOutcome, 'call', _17 => _17(providerId, targetId, { status: 401, now })]);
|
|
219
353
|
const remaining = gated.filter((a) => a.id !== targetId);
|
|
220
354
|
const retryId = pickByIdTarget(selector, remaining, providerId, activeAccountId, sessionKey, now, poolGated);
|
|
221
355
|
if (retryId !== void 0) {
|
|
222
356
|
const retryToken = await tokens.getAccessTokenForAccount(providerId, retryId);
|
|
223
357
|
if (retryToken) {
|
|
224
358
|
maybeTouchLastUsed(selector, tokens, providerId, retryId);
|
|
225
|
-
_optionalChain([report, 'optionalCall',
|
|
359
|
+
_optionalChain([report, 'optionalCall', _18 => _18(retryId, false, remapFor(retryId))]);
|
|
226
360
|
return retryToken;
|
|
227
361
|
}
|
|
228
362
|
}
|
|
229
363
|
}
|
|
230
|
-
if (activeAccountId)
|
|
364
|
+
if (activeAccountId) {
|
|
365
|
+
if (preferredGroup && _optionalChain([ctx, 'optionalAccess', _19 => _19.boundAccountFallbackPolicy]) !== "pool" && !candidates.some((account) => account.id === activeAccountId)) {
|
|
366
|
+
throw new (0, _BoundAccountSelectionError.BoundAccountSelectionError)(providerId, "unavailable");
|
|
367
|
+
}
|
|
368
|
+
const persistedActive = accounts.find((account) => account.id === activeAccountId);
|
|
369
|
+
if (_optionalChain([persistedActive, 'optionalAccess', _20 => _20.schedulable]) === false) return null;
|
|
370
|
+
const activeAllowance = _AccountAllowanceScheduling.getSharedAccountAllowanceScheduling.call(void 0, ).evaluate(
|
|
371
|
+
providerId,
|
|
372
|
+
activeAccountId,
|
|
373
|
+
_nullishCoalesce(_optionalChain([persistedActive, 'optionalAccess', _21 => _21.priority]), () => ( DEFAULT_ACCOUNT_PRIORITY)),
|
|
374
|
+
now
|
|
375
|
+
);
|
|
376
|
+
if (activeAllowance.action === "pause") {
|
|
377
|
+
throw new (0, _AccountAllowanceScheduling.AccountAllowanceExhaustedError)(providerId, activeAllowance.resumeAt);
|
|
378
|
+
}
|
|
379
|
+
const token = await activeGetter();
|
|
380
|
+
if (hasUsableToken(token)) {
|
|
381
|
+
maybeTouchLastUsed(selector, tokens, providerId, activeAccountId);
|
|
382
|
+
_optionalChain([report, 'optionalCall', _22 => _22(activeAccountId, true, remapFor(activeAccountId))]);
|
|
383
|
+
}
|
|
384
|
+
return token;
|
|
385
|
+
}
|
|
231
386
|
return activeGetter();
|
|
232
387
|
}
|
|
233
388
|
return activeGetter();
|
|
@@ -276,9 +431,16 @@ var OAuthBearerAuthStrategy = (_class2 = class {
|
|
|
276
431
|
this.selector,
|
|
277
432
|
this.tokens,
|
|
278
433
|
this.providerId,
|
|
279
|
-
_optionalChain([hints, 'optionalAccess',
|
|
434
|
+
_optionalChain([hints, 'optionalAccess', _23 => _23.sessionKey]),
|
|
280
435
|
() => this.resolveAccessToken(),
|
|
281
|
-
{
|
|
436
|
+
{
|
|
437
|
+
health: this.health,
|
|
438
|
+
reportSelection: _optionalChain([hints, 'optionalAccess', _24 => _24.reportSelection]),
|
|
439
|
+
resolvedModel: _optionalChain([hints, 'optionalAccess', _25 => _25.resolvedModel]),
|
|
440
|
+
preferredAccountId: _optionalChain([hints, 'optionalAccess', _26 => _26.preferredAccountId]),
|
|
441
|
+
preferredAccountGroup: _optionalChain([hints, 'optionalAccess', _27 => _27.preferredAccountGroup]),
|
|
442
|
+
boundAccountFallbackPolicy: _optionalChain([hints, 'optionalAccess', _28 => _28.boundAccountFallbackPolicy])
|
|
443
|
+
}
|
|
282
444
|
);
|
|
283
445
|
if (!token) {
|
|
284
446
|
return;
|
|
@@ -300,7 +462,7 @@ var OAuthBearerAuthStrategy = (_class2 = class {
|
|
|
300
462
|
async describeStatus() {
|
|
301
463
|
const config = await this.tokens.getFullConfig();
|
|
302
464
|
const entry = this.providerId === "codex" ? config.codex : config.gemini;
|
|
303
|
-
if (!_optionalChain([entry, 'optionalAccess',
|
|
465
|
+
if (!_optionalChain([entry, 'optionalAccess', _29 => _29.accessToken])) {
|
|
304
466
|
return { providerId: this.providerId, ok: false, reason: "missing-credential" };
|
|
305
467
|
}
|
|
306
468
|
if (entry.status === "expired") {
|
|
@@ -317,7 +479,7 @@ var OAuthBearerAuthStrategy = (_class2 = class {
|
|
|
317
479
|
async resolveAccessToken() {
|
|
318
480
|
const config = await this.tokens.getFullConfig();
|
|
319
481
|
const entry = this.providerId === "codex" ? config.codex : config.gemini;
|
|
320
|
-
if (!_optionalChain([entry, 'optionalAccess',
|
|
482
|
+
if (!_optionalChain([entry, 'optionalAccess', _30 => _30.accessToken])) return null;
|
|
321
483
|
const expiresAtMs = entry.expiresAt ? new Date(entry.expiresAt).getTime() : 0;
|
|
322
484
|
const expiringSoon = expiresAtMs > 0 && Date.now() >= expiresAtMs - REFRESH_LEAD_MS;
|
|
323
485
|
if (expiringSoon && entry.refreshToken) {
|
|
@@ -327,7 +489,7 @@ var OAuthBearerAuthStrategy = (_class2 = class {
|
|
|
327
489
|
if (!refreshed) return null;
|
|
328
490
|
const fresh = await this.tokens.getFullConfig();
|
|
329
491
|
const freshEntry = this.providerId === "codex" ? fresh.codex : fresh.gemini;
|
|
330
|
-
return _nullishCoalesce(_optionalChain([freshEntry, 'optionalAccess',
|
|
492
|
+
return _nullishCoalesce(_optionalChain([freshEntry, 'optionalAccess', _31 => _31.accessToken]), () => ( null));
|
|
331
493
|
}
|
|
332
494
|
if (entry.status === "expired") return null;
|
|
333
495
|
return entry.accessToken;
|
|
@@ -353,9 +515,16 @@ var PassThroughAuthStrategy = (_class3 = class {
|
|
|
353
515
|
this.selector,
|
|
354
516
|
this.tokens,
|
|
355
517
|
"claude",
|
|
356
|
-
_optionalChain([hints, 'optionalAccess',
|
|
518
|
+
_optionalChain([hints, 'optionalAccess', _32 => _32.sessionKey]),
|
|
357
519
|
() => this.tokens.getValidClaudeAccessToken(),
|
|
358
|
-
{
|
|
520
|
+
{
|
|
521
|
+
health: this.health,
|
|
522
|
+
reportSelection: _optionalChain([hints, 'optionalAccess', _33 => _33.reportSelection]),
|
|
523
|
+
resolvedModel: _optionalChain([hints, 'optionalAccess', _34 => _34.resolvedModel]),
|
|
524
|
+
preferredAccountId: _optionalChain([hints, 'optionalAccess', _35 => _35.preferredAccountId]),
|
|
525
|
+
preferredAccountGroup: _optionalChain([hints, 'optionalAccess', _36 => _36.preferredAccountGroup]),
|
|
526
|
+
boundAccountFallbackPolicy: _optionalChain([hints, 'optionalAccess', _37 => _37.boundAccountFallbackPolicy])
|
|
527
|
+
}
|
|
359
528
|
);
|
|
360
529
|
if (!token) return;
|
|
361
530
|
headers["Authorization"] = `Bearer ${token}`;
|
|
@@ -375,7 +544,7 @@ var PassThroughAuthStrategy = (_class3 = class {
|
|
|
375
544
|
async describeStatus() {
|
|
376
545
|
const config = await this.tokens.getFullConfig();
|
|
377
546
|
const claude = config.claude;
|
|
378
|
-
if (!_optionalChain([claude, 'optionalAccess',
|
|
547
|
+
if (!_optionalChain([claude, 'optionalAccess', _38 => _38.accessToken])) {
|
|
379
548
|
return { providerId: "claude", ok: false, reason: "missing-credential" };
|
|
380
549
|
}
|
|
381
550
|
if (claude.status === "expired") {
|
|
@@ -431,15 +600,22 @@ var StaticBearerAuthStrategy = (_class5 = class {
|
|
|
431
600
|
this.selector,
|
|
432
601
|
this.tokens,
|
|
433
602
|
"opencodego",
|
|
434
|
-
_optionalChain([hints, 'optionalAccess',
|
|
603
|
+
_optionalChain([hints, 'optionalAccess', _39 => _39.sessionKey]),
|
|
435
604
|
() => this.tokens.getValidOpenCodeGoApiKey(),
|
|
436
|
-
{
|
|
605
|
+
{
|
|
606
|
+
health: this.health,
|
|
607
|
+
reportSelection: _optionalChain([hints, 'optionalAccess', _40 => _40.reportSelection]),
|
|
608
|
+
resolvedModel: _optionalChain([hints, 'optionalAccess', _41 => _41.resolvedModel]),
|
|
609
|
+
preferredAccountId: _optionalChain([hints, 'optionalAccess', _42 => _42.preferredAccountId]),
|
|
610
|
+
preferredAccountGroup: _optionalChain([hints, 'optionalAccess', _43 => _43.preferredAccountGroup]),
|
|
611
|
+
boundAccountFallbackPolicy: _optionalChain([hints, 'optionalAccess', _44 => _44.boundAccountFallbackPolicy])
|
|
612
|
+
}
|
|
437
613
|
);
|
|
438
614
|
if (!key) {
|
|
439
615
|
return;
|
|
440
616
|
}
|
|
441
617
|
headers["Authorization"] = `Bearer ${key}`;
|
|
442
|
-
if (_optionalChain([hints, 'optionalAccess',
|
|
618
|
+
if (_optionalChain([hints, 'optionalAccess', _45 => _45.upstreamUrl, 'optionalAccess', _46 => _46.includes, 'call', _47 => _47(ANTHROPIC_SHAPE_PATH)])) {
|
|
443
619
|
headers["x-api-key"] = key;
|
|
444
620
|
}
|
|
445
621
|
}
|
|
@@ -449,7 +625,7 @@ var StaticBearerAuthStrategy = (_class5 = class {
|
|
|
449
625
|
async describeStatus() {
|
|
450
626
|
const config = await this.tokens.getFullConfig();
|
|
451
627
|
const oc = config.opencodego;
|
|
452
|
-
if (!_optionalChain([oc, 'optionalAccess',
|
|
628
|
+
if (!_optionalChain([oc, 'optionalAccess', _48 => _48.apiKey])) {
|
|
453
629
|
return { providerId: "opencodego", ok: false, reason: "missing-credential" };
|
|
454
630
|
}
|
|
455
631
|
if (oc.status === "error") {
|
|
@@ -523,31 +699,29 @@ var _GeminiCodeAssistTransformer = require('@omnicross/core/transformer/transfor
|
|
|
523
699
|
|
|
524
700
|
// src/opencodego/CircuitBreaker.ts
|
|
525
701
|
var CircuitBreaker = (_class7 = class {
|
|
526
|
-
__init12() {this.
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
/** `now()` at the last recorded failure — drives the open→half-open elapsed check. */
|
|
534
|
-
__init16() {this.lastFailureTime = 0}
|
|
702
|
+
__init12() {this.snapshot = {
|
|
703
|
+
mode: "closed",
|
|
704
|
+
consecutiveFailures: 0,
|
|
705
|
+
openedAt: 0,
|
|
706
|
+
probeAdmissions: 0,
|
|
707
|
+
probeSuccesses: 0
|
|
708
|
+
}}
|
|
535
709
|
|
|
536
710
|
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
|
|
542
|
-
|
|
711
|
+
constructor(opts = {}) {;_class7.prototype.__init12.call(this);
|
|
712
|
+
this.limits = {
|
|
713
|
+
threshold: _nullishCoalesce(opts.threshold, () => ( 3)),
|
|
714
|
+
openMs: _nullishCoalesce(opts.openMs, () => ( 3e4)),
|
|
715
|
+
halfOpenMaxCalls: _nullishCoalesce(opts.halfOpenMaxCalls, () => ( 3))
|
|
716
|
+
};
|
|
543
717
|
this.now = _nullishCoalesce(opts.now, () => ( Date.now));
|
|
544
718
|
}
|
|
545
719
|
/** Current state (diagnostics / tests). */
|
|
546
720
|
getState() {
|
|
547
|
-
return this.
|
|
721
|
+
return this.snapshot.mode;
|
|
548
722
|
}
|
|
549
723
|
/**
|
|
550
|
-
* Admission gate
|
|
724
|
+
* Admission gate. Returns whether a
|
|
551
725
|
* request to this model is allowed RIGHT NOW. Side-effecting BY DESIGN:
|
|
552
726
|
* - `closed` → always admit.
|
|
553
727
|
* - `open` → if `now() - lastFailureTime > openMs`, FLIP to `half-open`,
|
|
@@ -558,74 +732,91 @@ var CircuitBreaker = (_class7 = class {
|
|
|
558
732
|
* recorded outcome resolves the state).
|
|
559
733
|
*/
|
|
560
734
|
allowRequest() {
|
|
561
|
-
|
|
562
|
-
|
|
563
|
-
|
|
564
|
-
|
|
565
|
-
|
|
566
|
-
|
|
567
|
-
|
|
568
|
-
|
|
569
|
-
|
|
570
|
-
|
|
571
|
-
|
|
572
|
-
case "half-open":
|
|
573
|
-
if (this.halfOpenCalls < this.halfOpenMaxCalls) {
|
|
574
|
-
this.halfOpenCalls += 1;
|
|
575
|
-
return true;
|
|
576
|
-
}
|
|
577
|
-
return false;
|
|
578
|
-
default:
|
|
579
|
-
return true;
|
|
735
|
+
if (this.snapshot.mode === "closed") return true;
|
|
736
|
+
if (this.snapshot.mode === "open") {
|
|
737
|
+
const elapsed = this.now() - this.snapshot.openedAt;
|
|
738
|
+
if (elapsed <= this.limits.openMs) return false;
|
|
739
|
+
this.snapshot = {
|
|
740
|
+
...this.snapshot,
|
|
741
|
+
mode: "half-open",
|
|
742
|
+
probeAdmissions: 1,
|
|
743
|
+
probeSuccesses: 0
|
|
744
|
+
};
|
|
745
|
+
return true;
|
|
580
746
|
}
|
|
747
|
+
if (this.snapshot.probeAdmissions >= this.limits.halfOpenMaxCalls) return false;
|
|
748
|
+
this.snapshot = {
|
|
749
|
+
...this.snapshot,
|
|
750
|
+
probeAdmissions: this.snapshot.probeAdmissions + 1
|
|
751
|
+
};
|
|
752
|
+
return true;
|
|
581
753
|
}
|
|
582
754
|
/**
|
|
583
|
-
* Record a successful attempt
|
|
755
|
+
* Record a successful attempt.
|
|
584
756
|
* - `half-open` → increment `successCount`; at `halfOpenMaxCalls` successes,
|
|
585
757
|
* CLOSE the circuit and reset all counters.
|
|
586
758
|
* - `closed` → reset the consecutive `failureCount` (a single good call
|
|
587
759
|
* clears the streak).
|
|
588
760
|
*/
|
|
589
761
|
recordSuccess() {
|
|
590
|
-
if (this.
|
|
591
|
-
|
|
592
|
-
if (this.
|
|
593
|
-
this.
|
|
594
|
-
this.failureCount = 0;
|
|
595
|
-
this.successCount = 0;
|
|
596
|
-
this.halfOpenCalls = 0;
|
|
762
|
+
if (this.snapshot.mode === "open") return;
|
|
763
|
+
if (this.snapshot.mode === "closed") {
|
|
764
|
+
if (this.snapshot.consecutiveFailures !== 0) {
|
|
765
|
+
this.snapshot = { ...this.snapshot, consecutiveFailures: 0 };
|
|
597
766
|
}
|
|
598
767
|
return;
|
|
599
768
|
}
|
|
600
|
-
this.
|
|
769
|
+
const probeSuccesses = this.snapshot.probeSuccesses + 1;
|
|
770
|
+
if (probeSuccesses >= this.limits.halfOpenMaxCalls) {
|
|
771
|
+
this.snapshot = {
|
|
772
|
+
mode: "closed",
|
|
773
|
+
consecutiveFailures: 0,
|
|
774
|
+
openedAt: 0,
|
|
775
|
+
probeAdmissions: 0,
|
|
776
|
+
probeSuccesses: 0
|
|
777
|
+
};
|
|
778
|
+
return;
|
|
779
|
+
}
|
|
780
|
+
this.snapshot = { ...this.snapshot, probeSuccesses };
|
|
601
781
|
}
|
|
602
782
|
/**
|
|
603
|
-
* Record a failed attempt
|
|
783
|
+
* Record a failed attempt.
|
|
604
784
|
* - `half-open` → immediately RE-OPEN (one probe failure is enough); stamp
|
|
605
785
|
* `lastFailureTime`, reset `successCount`.
|
|
606
786
|
* - `closed` → increment the consecutive `failureCount`; at `threshold`,
|
|
607
787
|
* OPEN the circuit. Always stamp `lastFailureTime`.
|
|
608
788
|
*/
|
|
609
789
|
recordFailure() {
|
|
610
|
-
|
|
611
|
-
if (this.
|
|
612
|
-
this.
|
|
613
|
-
|
|
614
|
-
|
|
790
|
+
const openedAt = this.now();
|
|
791
|
+
if (this.snapshot.mode === "half-open") {
|
|
792
|
+
this.snapshot = {
|
|
793
|
+
...this.snapshot,
|
|
794
|
+
mode: "open",
|
|
795
|
+
openedAt,
|
|
796
|
+
probeAdmissions: 0,
|
|
797
|
+
probeSuccesses: 0
|
|
798
|
+
};
|
|
615
799
|
return;
|
|
616
800
|
}
|
|
617
|
-
this.
|
|
618
|
-
|
|
619
|
-
this.
|
|
801
|
+
const consecutiveFailures = this.snapshot.consecutiveFailures + 1;
|
|
802
|
+
this.snapshot = {
|
|
803
|
+
...this.snapshot,
|
|
804
|
+
consecutiveFailures,
|
|
805
|
+
openedAt,
|
|
806
|
+
mode: consecutiveFailures >= this.limits.threshold ? "open" : this.snapshot.mode
|
|
807
|
+
};
|
|
808
|
+
if (this.snapshot.mode === "open") {
|
|
809
|
+
this.snapshot.probeAdmissions = 0;
|
|
810
|
+
this.snapshot.probeSuccesses = 0;
|
|
620
811
|
}
|
|
621
812
|
}
|
|
622
813
|
}, _class7);
|
|
623
814
|
var CircuitBreakerRegistry = (_class8 = class {
|
|
624
|
-
constructor(options = {}) {;_class8.prototype.
|
|
815
|
+
constructor(options = {}) {;_class8.prototype.__init13.call(this);
|
|
625
816
|
this.options = options;
|
|
626
817
|
}
|
|
627
818
|
|
|
628
|
-
|
|
819
|
+
__init13() {this.breakers = /* @__PURE__ */ new Map()}
|
|
629
820
|
/** Get (or lazily create) the breaker for a model id. */
|
|
630
821
|
get(modelId) {
|
|
631
822
|
let breaker = this.breakers.get(modelId);
|
|
@@ -665,8 +856,7 @@ var DEFAULT_OPENCODEGO_MODEL_MAP = {
|
|
|
665
856
|
modelId: "glm-5"
|
|
666
857
|
},
|
|
667
858
|
complex: {
|
|
668
|
-
//
|
|
669
|
-
// drifted to `mimo-v2-pro` (audit D4).
|
|
859
|
+
// Complex tasks use the higher-capability GLM variant by default.
|
|
670
860
|
modelId: "glm-5.1"
|
|
671
861
|
},
|
|
672
862
|
fast: {
|
|
@@ -793,11 +983,11 @@ function resolveOpenCodeGoShape(entry) {
|
|
|
793
983
|
function resolveOpenCodeGoHalf(modelId, config) {
|
|
794
984
|
if (!config) return "go";
|
|
795
985
|
for (const entry of Object.values(_nullishCoalesce(config.modelMap, () => ( {})))) {
|
|
796
|
-
if (_optionalChain([entry, 'optionalAccess',
|
|
986
|
+
if (_optionalChain([entry, 'optionalAccess', _49 => _49.modelId]) === modelId) return _nullishCoalesce(entry.provider, () => ( "go"));
|
|
797
987
|
}
|
|
798
988
|
for (const list of Object.values(_nullishCoalesce(config.fallbacks, () => ( {})))) {
|
|
799
989
|
for (const entry of _nullishCoalesce(list, () => ( []))) {
|
|
800
|
-
if (_optionalChain([entry, 'optionalAccess',
|
|
990
|
+
if (_optionalChain([entry, 'optionalAccess', _50 => _50.modelId]) === modelId) return _nullishCoalesce(entry.provider, () => ( "go"));
|
|
801
991
|
}
|
|
802
992
|
}
|
|
803
993
|
return "go";
|
|
@@ -805,67 +995,44 @@ function resolveOpenCodeGoHalf(modelId, config) {
|
|
|
805
995
|
|
|
806
996
|
// src/opencodego/ScenarioRouter.ts
|
|
807
997
|
var COMPLEX_KEYWORDS = [
|
|
808
|
-
// Architectural
|
|
809
|
-
"architect",
|
|
810
998
|
"architecture",
|
|
811
999
|
"refactor",
|
|
812
1000
|
"redesign",
|
|
813
|
-
"complex",
|
|
814
|
-
"difficult",
|
|
815
|
-
"challenging",
|
|
816
1001
|
"optimize",
|
|
817
1002
|
"performance",
|
|
818
|
-
"efficiency",
|
|
819
|
-
"design pattern",
|
|
820
|
-
"best practice",
|
|
821
|
-
// Tool-related keywords indicate complex operations
|
|
822
|
-
"execute",
|
|
823
|
-
"run command",
|
|
824
|
-
"bash",
|
|
825
|
-
"shell",
|
|
826
1003
|
"implement",
|
|
827
1004
|
"build",
|
|
828
|
-
"create",
|
|
829
|
-
"add feature",
|
|
830
|
-
"write to",
|
|
831
1005
|
"edit file",
|
|
832
|
-
"
|
|
1006
|
+
"debug",
|
|
1007
|
+
"migrate",
|
|
1008
|
+
"benchmark"
|
|
833
1009
|
];
|
|
834
1010
|
var THINKING_KEYWORDS = [
|
|
835
1011
|
"think",
|
|
836
|
-
"thinking",
|
|
837
1012
|
"plan",
|
|
838
1013
|
"reason",
|
|
839
|
-
"reasoning",
|
|
840
1014
|
"analyze",
|
|
841
|
-
"
|
|
842
|
-
"
|
|
1015
|
+
"step by step",
|
|
1016
|
+
"evaluate",
|
|
1017
|
+
"compare tradeoffs"
|
|
843
1018
|
];
|
|
844
1019
|
var ANT_THINKING_MARKER = "antThinking";
|
|
845
1020
|
var TOOL_BLOCKERS = [
|
|
846
1021
|
"tool",
|
|
847
1022
|
"function",
|
|
848
|
-
"
|
|
849
|
-
"run command",
|
|
1023
|
+
"command",
|
|
850
1024
|
"write",
|
|
851
1025
|
"edit",
|
|
852
|
-
"create",
|
|
853
1026
|
"delete",
|
|
854
|
-
"remove",
|
|
855
1027
|
"implement",
|
|
856
1028
|
"build",
|
|
857
|
-
"add",
|
|
858
1029
|
"modify"
|
|
859
1030
|
];
|
|
860
1031
|
var BACKGROUND_KEYWORDS = [
|
|
861
1032
|
"list directory",
|
|
862
|
-
"ls -",
|
|
863
|
-
"dir",
|
|
864
1033
|
"show file",
|
|
865
|
-
"
|
|
866
|
-
"cat file",
|
|
1034
|
+
"read file",
|
|
867
1035
|
"what is",
|
|
868
|
-
"what's",
|
|
869
1036
|
"tell me about",
|
|
870
1037
|
"check status",
|
|
871
1038
|
"show status"
|
|
@@ -897,7 +1064,7 @@ function hasBackgroundPattern(loweredSlices) {
|
|
|
897
1064
|
return containsAny(loweredSlices, BACKGROUND_KEYWORDS);
|
|
898
1065
|
}
|
|
899
1066
|
function resolveOpenCodeGoScenario(summary, config) {
|
|
900
|
-
const longContextThreshold = _nullishCoalesce(_optionalChain([config, 'optionalAccess',
|
|
1067
|
+
const longContextThreshold = _nullishCoalesce(_optionalChain([config, 'optionalAccess', _51 => _51.modelMap, 'optionalAccess', _52 => _52.long_context, 'optionalAccess', _53 => _53.contextThreshold]), () => ( DEFAULT_OPENCODEGO_LONG_CONTEXT_THRESHOLD));
|
|
901
1068
|
if (summary.estimatedInputTokens >= longContextThreshold) {
|
|
902
1069
|
return "long_context";
|
|
903
1070
|
}
|
|
@@ -921,7 +1088,7 @@ function opencodegoTransformerNamesForShape(shape) {
|
|
|
921
1088
|
return ["gemini"];
|
|
922
1089
|
case "chat":
|
|
923
1090
|
default:
|
|
924
|
-
return ["
|
|
1091
|
+
return ["openai"];
|
|
925
1092
|
}
|
|
926
1093
|
}
|
|
927
1094
|
function resolveOpenCodeGoTarget(modelId, config) {
|
|
@@ -930,7 +1097,7 @@ function resolveOpenCodeGoTarget(modelId, config) {
|
|
|
930
1097
|
return { half, shape };
|
|
931
1098
|
}
|
|
932
1099
|
var SubscriptionProviderRegistry = (_class9 = class {
|
|
933
|
-
constructor(accounts, tokens) {;_class9.prototype.
|
|
1100
|
+
constructor(accounts, tokens) {;_class9.prototype.__init14.call(this);
|
|
934
1101
|
this.accounts = accounts;
|
|
935
1102
|
this.tokens = tokens;
|
|
936
1103
|
const claude = this.accounts.getStrategy("claude");
|
|
@@ -976,7 +1143,7 @@ var SubscriptionProviderRegistry = (_class9 = class {
|
|
|
976
1143
|
authStrategy: codex,
|
|
977
1144
|
mode: "transformer",
|
|
978
1145
|
// ChatGPT internal endpoint — accepts the OpenAI Responses API
|
|
979
|
-
// format
|
|
1146
|
+
// format and uses the Codex OAuth access token below.
|
|
980
1147
|
// The Codex OAuth access token grants access here; the public
|
|
981
1148
|
// `api.openai.com/v1/responses` endpoint would reject the same token.
|
|
982
1149
|
resolveUpstreamUrl: () => "https://chatgpt.com/backend-api/codex/responses",
|
|
@@ -1022,16 +1189,16 @@ var SubscriptionProviderRegistry = (_class9 = class {
|
|
|
1022
1189
|
// `ocConfig`; the core `/v1/messages` plan builder passes the opaque
|
|
1023
1190
|
// `route.subscriptionConfig`). With NO zen config every resolved model
|
|
1024
1191
|
// is go-half → byte-identical to the prior resolver.
|
|
1025
|
-
// `// UNVERIFIED (no live zen key)`: the
|
|
1026
|
-
//
|
|
1192
|
+
// `// UNVERIFIED (no live zen key)`: the ZEN endpoint hosts and paths
|
|
1193
|
+
// are covered by in-process tests only.
|
|
1027
1194
|
resolveUpstreamUrl: (model, config) => {
|
|
1028
1195
|
const oc = config;
|
|
1029
1196
|
const { half, shape } = resolveOpenCodeGoTarget(model, oc);
|
|
1030
|
-
const override = half === "zen" ? _optionalChain([oc, 'optionalAccess',
|
|
1197
|
+
const override = half === "zen" ? _optionalChain([oc, 'optionalAccess', _54 => _54.zenBaseUrl]) : _optionalChain([oc, 'optionalAccess', _55 => _55.baseUrl]);
|
|
1031
1198
|
return buildOpenCodeGoUrl(half, shape, override);
|
|
1032
1199
|
},
|
|
1033
1200
|
// zen seam (Decision 3): vary the provider transformer chain by resolved
|
|
1034
|
-
// shape (anthropic⇒[] verbatim, chat⇒
|
|
1201
|
+
// shape (anthropic⇒[] verbatim, chat⇒openai, responses⇒openai-response,
|
|
1035
1202
|
// gemini⇒gemini). OPTIONAL on the profile type — only opencodego sets it;
|
|
1036
1203
|
// claude/codex/gemini omit it and fall back to `providerTransformerNames`,
|
|
1037
1204
|
// keeping their routing byte-identical. The static `providerTransformerNames`
|
|
@@ -1041,11 +1208,11 @@ var SubscriptionProviderRegistry = (_class9 = class {
|
|
|
1041
1208
|
const { shape } = resolveOpenCodeGoTarget(model, config);
|
|
1042
1209
|
return opencodegoTransformerNamesForShape(shape);
|
|
1043
1210
|
},
|
|
1044
|
-
providerTransformerNames: ["
|
|
1211
|
+
providerTransformerNames: ["openai"],
|
|
1045
1212
|
modelTransformerNames: [],
|
|
1046
1213
|
modelMapper: (sdkModel, summary, config) => {
|
|
1047
1214
|
const scenario = resolveOpenCodeGoScenario(summary, config);
|
|
1048
|
-
const entry = _nullishCoalesce(_nullishCoalesce(_nullishCoalesce(_optionalChain([config, 'optionalAccess',
|
|
1215
|
+
const entry = _nullishCoalesce(_nullishCoalesce(_nullishCoalesce(_optionalChain([config, 'optionalAccess', _56 => _56.modelMap, 'optionalAccess', _57 => _57[scenario]]), () => ( _optionalChain([config, 'optionalAccess', _58 => _58.modelMap, 'optionalAccess', _59 => _59.default]))), () => ( DEFAULT_OPENCODEGO_MODEL_MAP[scenario])), () => ( DEFAULT_OPENCODEGO_MODEL_MAP.default));
|
|
1049
1216
|
if (!entry) {
|
|
1050
1217
|
return { resolvedModel: sdkModel, scenario };
|
|
1051
1218
|
}
|
|
@@ -1055,16 +1222,15 @@ var SubscriptionProviderRegistry = (_class9 = class {
|
|
|
1055
1222
|
// circuit is open. `breaker.allowRequest(modelId)` is the admission
|
|
1056
1223
|
// gate — calling it has the side effect of flipping an `open` model to
|
|
1057
1224
|
// `half-open` once its 30s window elapses AND counting a half-open admit
|
|
1058
|
-
// slot. It MUST therefore be consulted
|
|
1059
|
-
// on the candidate about to be attempted
|
|
1060
|
-
// (`fallback.go` calls `AllowRequest` once, on the model it returns).
|
|
1225
|
+
// slot. It MUST therefore be consulted exactly once per returned model,
|
|
1226
|
+
// on the candidate about to be attempted.
|
|
1061
1227
|
// An early-returning scan (NOT `Array.filter`, which would `allowRequest`
|
|
1062
1228
|
// every candidate and burn the admit slots of half-open models AFTER the
|
|
1063
1229
|
// chosen one — those are never attempted, never recorded, so they would
|
|
1064
1230
|
// wedge permanently in half-open). When NO circuit is open this returns
|
|
1065
1231
|
// the same first non-attempted entry as the prior `!attempted` filter.
|
|
1066
1232
|
nextFallback: (scenario, attempted, config) => {
|
|
1067
|
-
const list = _nullishCoalesce(_nullishCoalesce(_optionalChain([config, 'optionalAccess',
|
|
1233
|
+
const list = _nullishCoalesce(_nullishCoalesce(_optionalChain([config, 'optionalAccess', _60 => _60.fallbacks, 'optionalAccess', _61 => _61[scenario]]), () => ( DEFAULT_OPENCODEGO_FALLBACKS[scenario])), () => ( []));
|
|
1068
1234
|
for (const entry of list) {
|
|
1069
1235
|
if (attempted.includes(entry.modelId)) continue;
|
|
1070
1236
|
if (this.breaker.allowRequest(entry.modelId)) return entry;
|
|
@@ -1091,11 +1257,11 @@ var SubscriptionProviderRegistry = (_class9 = class {
|
|
|
1091
1257
|
* process singleton, built here and captured by the opencodego profile's
|
|
1092
1258
|
* `nextFallback` (consult) + `recordModelOutcome` (record) closures. Because
|
|
1093
1259
|
* the `SubscriptionProviderRegistry` is itself a process singleton (via
|
|
1094
|
-
* `setSubscriptionProviderRegistry`), breaker state persists across requests
|
|
1095
|
-
*
|
|
1096
|
-
*
|
|
1260
|
+
* `setSubscriptionProviderRegistry`), breaker state persists across requests.
|
|
1261
|
+
* Constructed with the production thresholds (3 / 30s / 3) and the default
|
|
1262
|
+
* `Date.now` clock.
|
|
1097
1263
|
*/
|
|
1098
|
-
|
|
1264
|
+
__init14() {this.breaker = new CircuitBreakerRegistry()}
|
|
1099
1265
|
/** Returns the dispatch profile for a known subscription provider, or
|
|
1100
1266
|
* `null` for unknown ids (callers must treat null as "fall back to the
|
|
1101
1267
|
* legacy LLM provider DB lookup"). */
|
|
@@ -1121,6 +1287,8 @@ function getSubscriptionProviderRegistry() {
|
|
|
1121
1287
|
}
|
|
1122
1288
|
|
|
1123
1289
|
// src/SubscriptionDispatcher.ts
|
|
1290
|
+
|
|
1291
|
+
|
|
1124
1292
|
var _geminicodeassistresolver = require('@omnicross/core/ports/gemini-code-assist-resolver');
|
|
1125
1293
|
|
|
1126
1294
|
|
|
@@ -1165,7 +1333,7 @@ var SubscriptionDispatcher = class {
|
|
|
1165
1333
|
scenario = mapped.scenario;
|
|
1166
1334
|
req.anthropicBody.model = resolvedModel;
|
|
1167
1335
|
}
|
|
1168
|
-
const upstreamUrl = _optionalChain([this, 'access',
|
|
1336
|
+
const upstreamUrl = _optionalChain([this, 'access', _62 => _62.profile, 'access', _63 => _63.resolveUpstreamUrl, 'optionalCall', _64 => _64(resolvedModel, ocConfig)]);
|
|
1169
1337
|
if (!upstreamUrl) {
|
|
1170
1338
|
throw new Error(`[SubscriptionDispatcher] profile=${this.profile.providerId} missing resolveUpstreamUrl`);
|
|
1171
1339
|
}
|
|
@@ -1197,7 +1365,7 @@ var SubscriptionDispatcher = class {
|
|
|
1197
1365
|
);
|
|
1198
1366
|
try {
|
|
1199
1367
|
const upstream = await this.hooks.fetchWithRetry(upstreamUrl, headers, req.anthropicBody, currentModel);
|
|
1200
|
-
_optionalChain([this, 'access',
|
|
1368
|
+
_optionalChain([this, 'access', _65 => _65.profile, 'access', _66 => _66.recordModelOutcome, 'optionalCall', _67 => _67(currentModel, true)]);
|
|
1201
1369
|
this.markHealth(usedAccountId, 200);
|
|
1202
1370
|
await this.hooks.writeProxyResponse(req.res, upstream, req.isStream, req.reqId);
|
|
1203
1371
|
return;
|
|
@@ -1206,7 +1374,7 @@ var SubscriptionDispatcher = class {
|
|
|
1206
1374
|
if (handled.retryOnce) {
|
|
1207
1375
|
try {
|
|
1208
1376
|
const upstream = await this.hooks.fetchWithRetry(upstreamUrl, handled.headers, req.anthropicBody, currentModel);
|
|
1209
|
-
_optionalChain([this, 'access',
|
|
1377
|
+
_optionalChain([this, 'access', _68 => _68.profile, 'access', _69 => _69.recordModelOutcome, 'optionalCall', _70 => _70(currentModel, true)]);
|
|
1210
1378
|
this.markHealth(usedAccountId, 200);
|
|
1211
1379
|
await this.hooks.writeProxyResponse(req.res, upstream, req.isStream, req.reqId);
|
|
1212
1380
|
return;
|
|
@@ -1216,10 +1384,10 @@ var SubscriptionDispatcher = class {
|
|
|
1216
1384
|
}
|
|
1217
1385
|
}
|
|
1218
1386
|
if (caughtErrorBreakerOutcome(err) === "failure") {
|
|
1219
|
-
_optionalChain([this, 'access',
|
|
1387
|
+
_optionalChain([this, 'access', _71 => _71.profile, 'access', _72 => _72.recordModelOutcome, 'optionalCall', _73 => _73(currentModel, false)]);
|
|
1220
1388
|
}
|
|
1221
1389
|
this.markHealth(usedAccountId, errStatus(err), err);
|
|
1222
|
-
const next = _optionalChain([this, 'access',
|
|
1390
|
+
const next = _optionalChain([this, 'access', _74 => _74.profile, 'access', _75 => _75.nextFallback, 'optionalCall', _76 => _76(scenario, attempted, ocConfig)]);
|
|
1223
1391
|
if (!next || attempted.length >= MAX_FALLBACK_ATTEMPTS_LOCAL) {
|
|
1224
1392
|
throw err;
|
|
1225
1393
|
}
|
|
@@ -1233,7 +1401,7 @@ var SubscriptionDispatcher = class {
|
|
|
1233
1401
|
}
|
|
1234
1402
|
/** Standard subscription transformer chain — Codex/Gemini/OpenCodeGo OpenAI-shape. */
|
|
1235
1403
|
async dispatchTransformerChain(req, upstreamUrl, resolvedModel, scenario, ocConfig, sessionKey) {
|
|
1236
|
-
const providerNames = _nullishCoalesce(_optionalChain([this, 'access',
|
|
1404
|
+
const providerNames = _nullishCoalesce(_optionalChain([this, 'access', _77 => _77.profile, 'access', _78 => _78.resolveProviderTransformerNames, 'optionalCall', _79 => _79(resolvedModel, ocConfig)]), () => ( this.profile.providerTransformerNames));
|
|
1237
1405
|
const providerTransformers = this.resolveTransformers(providerNames);
|
|
1238
1406
|
const modelTransformers = this.resolveTransformers(this.profile.modelTransformerNames);
|
|
1239
1407
|
const transformerProvider = {
|
|
@@ -1274,7 +1442,7 @@ var SubscriptionDispatcher = class {
|
|
|
1274
1442
|
);
|
|
1275
1443
|
try {
|
|
1276
1444
|
const upstream = await this.hooks.fetchWithRetry(fetchUrl, headers, requestBody, currentModel);
|
|
1277
|
-
_optionalChain([this, 'access',
|
|
1445
|
+
_optionalChain([this, 'access', _80 => _80.profile, 'access', _81 => _81.recordModelOutcome, 'optionalCall', _82 => _82(currentModel, true)]);
|
|
1278
1446
|
this.markHealth(usedAccountId, 200);
|
|
1279
1447
|
const finalResponse = await this.hooks.executor.executeResponseChain(
|
|
1280
1448
|
requestBody,
|
|
@@ -1290,7 +1458,7 @@ var SubscriptionDispatcher = class {
|
|
|
1290
1458
|
if (handled.retryOnce) {
|
|
1291
1459
|
try {
|
|
1292
1460
|
const upstream = await this.hooks.fetchWithRetry(fetchUrl, handled.headers, requestBody, currentModel);
|
|
1293
|
-
_optionalChain([this, 'access',
|
|
1461
|
+
_optionalChain([this, 'access', _83 => _83.profile, 'access', _84 => _84.recordModelOutcome, 'optionalCall', _85 => _85(currentModel, true)]);
|
|
1294
1462
|
this.markHealth(usedAccountId, 200);
|
|
1295
1463
|
const finalResponse = await this.hooks.executor.executeResponseChain(
|
|
1296
1464
|
requestBody,
|
|
@@ -1307,10 +1475,10 @@ var SubscriptionDispatcher = class {
|
|
|
1307
1475
|
}
|
|
1308
1476
|
}
|
|
1309
1477
|
if (caughtErrorBreakerOutcome(err) === "failure") {
|
|
1310
|
-
_optionalChain([this, 'access',
|
|
1478
|
+
_optionalChain([this, 'access', _86 => _86.profile, 'access', _87 => _87.recordModelOutcome, 'optionalCall', _88 => _88(currentModel, false)]);
|
|
1311
1479
|
}
|
|
1312
1480
|
this.markHealth(usedAccountId, errStatus(err), err);
|
|
1313
|
-
const next = _optionalChain([this, 'access',
|
|
1481
|
+
const next = _optionalChain([this, 'access', _89 => _89.profile, 'access', _90 => _90.nextFallback, 'optionalCall', _91 => _91(scenario, attempted, ocConfig)]);
|
|
1314
1482
|
if (!next || attempted.length >= MAX_FALLBACK_ATTEMPTS_LOCAL) {
|
|
1315
1483
|
throw err;
|
|
1316
1484
|
}
|
|
@@ -1340,7 +1508,7 @@ var SubscriptionDispatcher = class {
|
|
|
1340
1508
|
return { firstModel: primaryModel, attempted: [] };
|
|
1341
1509
|
}
|
|
1342
1510
|
const skipped = [primaryModel];
|
|
1343
|
-
const firstAdmitting = _optionalChain([this, 'access',
|
|
1511
|
+
const firstAdmitting = _optionalChain([this, 'access', _92 => _92.profile, 'access', _93 => _93.nextFallback, 'optionalCall', _94 => _94(scenario, skipped, ocConfig)]);
|
|
1344
1512
|
if (firstAdmitting) {
|
|
1345
1513
|
console.warn(
|
|
1346
1514
|
`[AgentProxy:subscription] opencodego primary ${primaryModel} circuit open -> first admitting fallback ${firstAdmitting.modelId}`
|
|
@@ -1358,7 +1526,7 @@ var SubscriptionDispatcher = class {
|
|
|
1358
1526
|
* successfully (caller should retry once); otherwise re-throws.
|
|
1359
1527
|
*/
|
|
1360
1528
|
async maybeRetryAfterError(err, headers, req, resolvedModel, sessionKey) {
|
|
1361
|
-
const status = _nullishCoalesce(_optionalChain([err, 'optionalAccess',
|
|
1529
|
+
const status = _nullishCoalesce(_optionalChain([err, 'optionalAccess', _95 => _95.status]), () => ( 0));
|
|
1362
1530
|
if (status !== 401) {
|
|
1363
1531
|
return { retryOnce: false, headers };
|
|
1364
1532
|
}
|
|
@@ -1378,6 +1546,7 @@ var SubscriptionDispatcher = class {
|
|
|
1378
1546
|
try {
|
|
1379
1547
|
await this.profile.authStrategy.applyHeaders(headers, hints);
|
|
1380
1548
|
} catch (err) {
|
|
1549
|
+
if (_AccountAllowanceScheduling.isAccountAllowanceExhaustedError.call(void 0, err) || _BoundAccountSelectionError.isBoundAccountSelectionError.call(void 0, err)) throw err;
|
|
1381
1550
|
console.warn("[AgentProxy:subscription] authStrategy.applyHeaders threw:", _serializeError.serializeError.call(void 0, err));
|
|
1382
1551
|
}
|
|
1383
1552
|
}
|
|
@@ -1480,11 +1649,11 @@ var SubscriptionDispatcher = class {
|
|
|
1480
1649
|
};
|
|
1481
1650
|
var MAX_FALLBACK_ATTEMPTS_LOCAL = 3;
|
|
1482
1651
|
function errStatus(err) {
|
|
1483
|
-
const status = _optionalChain([err, 'optionalAccess',
|
|
1652
|
+
const status = _optionalChain([err, 'optionalAccess', _96 => _96.status]);
|
|
1484
1653
|
return typeof status === "number" ? status : null;
|
|
1485
1654
|
}
|
|
1486
1655
|
function errHeaders(err) {
|
|
1487
|
-
const h = _optionalChain([err, 'optionalAccess',
|
|
1656
|
+
const h = _optionalChain([err, 'optionalAccess', _97 => _97.headers]);
|
|
1488
1657
|
if (!h) return void 0;
|
|
1489
1658
|
if (typeof h.get === "function") return h;
|
|
1490
1659
|
if (typeof h === "object") return h;
|
|
@@ -1492,11 +1661,11 @@ function errHeaders(err) {
|
|
|
1492
1661
|
}
|
|
1493
1662
|
function errBodyText(err) {
|
|
1494
1663
|
const e = err;
|
|
1495
|
-
const raw = typeof _optionalChain([e, 'optionalAccess',
|
|
1496
|
-
return _optionalChain([raw, 'optionalAccess',
|
|
1664
|
+
const raw = typeof _optionalChain([e, 'optionalAccess', _98 => _98.bodyText]) === "string" ? e.bodyText : typeof _optionalChain([e, 'optionalAccess', _99 => _99.body]) === "string" ? e.body : void 0;
|
|
1665
|
+
return _optionalChain([raw, 'optionalAccess', _100 => _100.slice, 'call', _101 => _101(0, 2048)]);
|
|
1497
1666
|
}
|
|
1498
1667
|
function caughtErrorBreakerOutcome(err) {
|
|
1499
|
-
const status = _optionalChain([err, 'optionalAccess',
|
|
1668
|
+
const status = _optionalChain([err, 'optionalAccess', _102 => _102.status]);
|
|
1500
1669
|
if (typeof status !== "number") return "failure";
|
|
1501
1670
|
if (status === 0) return "neutral";
|
|
1502
1671
|
if (status >= 500 || status === 429) return "failure";
|
|
@@ -1534,4 +1703,4 @@ function stripAuthHeaders(headers) {
|
|
|
1534
1703
|
|
|
1535
1704
|
|
|
1536
1705
|
|
|
1537
|
-
exports.DEFAULT_ACCOUNT_PRIORITY = DEFAULT_ACCOUNT_PRIORITY; exports.LAST_USED_PERSIST_THROTTLE_MS = LAST_USED_PERSIST_THROTTLE_MS; exports.SESSION_AFFINITY_TTL_MS = SESSION_AFFINITY_TTL_MS; exports.SubscriptionAccountSelector = SubscriptionAccountSelector; exports.SubscriptionAccountService = SubscriptionAccountService; exports.SubscriptionDispatcher = SubscriptionDispatcher; exports.SubscriptionProviderRegistry = SubscriptionProviderRegistry; exports.claudeOAuth =
|
|
1706
|
+
exports.DEFAULT_ACCOUNT_PRIORITY = DEFAULT_ACCOUNT_PRIORITY; exports.LAST_USED_PERSIST_THROTTLE_MS = LAST_USED_PERSIST_THROTTLE_MS; exports.SESSION_AFFINITY_TTL_MS = SESSION_AFFINITY_TTL_MS; exports.SubscriptionAccountSelector = SubscriptionAccountSelector; exports.SubscriptionAccountService = SubscriptionAccountService; exports.SubscriptionDispatcher = SubscriptionDispatcher; exports.SubscriptionProviderRegistry = SubscriptionProviderRegistry; exports.claudeOAuth = _chunkPWV5NBO5cjs.claude_exports; exports.codexOAuth = _chunkPWV5NBO5cjs.codex_exports; exports.geminiOAuth = _chunkPWV5NBO5cjs.gemini_exports; exports.getSubscriptionAccountService = getSubscriptionAccountService; exports.getSubscriptionProviderRegistry = getSubscriptionProviderRegistry; exports.setSubscriptionAccountService = setSubscriptionAccountService; exports.setSubscriptionProviderRegistry = setSubscriptionProviderRegistry;
|