@omnicross/subscriptions 0.1.3 → 0.1.4
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/LICENSE +21 -21
- package/NOTICE +45 -45
- package/README.md +15 -15
- package/dist/index.cjs +51 -39
- package/dist/index.js +15 -3
- package/package.json +59 -59
package/LICENSE
CHANGED
|
@@ -1,21 +1,21 @@
|
|
|
1
|
-
MIT License
|
|
2
|
-
|
|
3
|
-
Copyright (c) 2026 Sayo
|
|
4
|
-
|
|
5
|
-
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
-
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
-
in the Software without restriction, including without limitation the rights
|
|
8
|
-
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
-
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
-
furnished to do so, subject to the following conditions:
|
|
11
|
-
|
|
12
|
-
The above copyright notice and this permission notice shall be included in all
|
|
13
|
-
copies or substantial portions of the Software.
|
|
14
|
-
|
|
15
|
-
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
-
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
-
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
-
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
-
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
-
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
-
SOFTWARE.
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Sayo
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/NOTICE
CHANGED
|
@@ -1,45 +1,45 @@
|
|
|
1
|
-
@omnicross/subscriptions — THIRD-PARTY NOTICES
|
|
2
|
-
==============================================
|
|
3
|
-
|
|
4
|
-
This package contains the subscription-as-provider block (auth strategies,
|
|
5
|
-
account service, provider registry, dispatcher, OpenCodeGo routing). Some routing
|
|
6
|
-
shapes and configuration-data values were adapted,
|
|
7
|
-
clean-room, from the following third-party works. Those repositories are NOT
|
|
8
|
-
vendored into this tree; only original TypeScript that mirrors their routing
|
|
9
|
-
shape / config-data values lives here (see the in-code provenance comments).
|
|
10
|
-
|
|
11
|
-
--------------------------------------------------------------------------------
|
|
12
|
-
1. claude-relay-service (MIT License) — routing shape only
|
|
13
|
-
--------------------------------------------------------------------------------
|
|
14
|
-
|
|
15
|
-
The Codex (ChatGPT OAuth) upstream routing shape — the
|
|
16
|
-
`https://chatgpt.com/backend-api/codex/responses` endpoint dispatch in
|
|
17
|
-
`src/SubscriptionProviderRegistry.ts` — mirrors the route shape of
|
|
18
|
-
`claude-relay-service` (`src/routes/openaiRoutes.js`). Routing shape only; the
|
|
19
|
-
TypeScript is original, and the upstream repository is not vendored.
|
|
20
|
-
|
|
21
|
-
https://github.com/Wei-Shaw/claude-relay-service
|
|
22
|
-
Licensed under the MIT License.
|
|
23
|
-
|
|
24
|
-
--------------------------------------------------------------------------------
|
|
25
|
-
2. oc-go-cc (OpenCodeGo CC) — model-map + routing-shape / config-data
|
|
26
|
-
--------------------------------------------------------------------------------
|
|
27
|
-
|
|
28
|
-
The OpenCodeGo routing-shape, scenario router, model-map defaults, endpoint
|
|
29
|
-
shapes, and Anthropic-shape `x-api-key` fallback in
|
|
30
|
-
`src/opencodego/{defaults,endpoints,model-shape,ScenarioRouter}.ts` and
|
|
31
|
-
`src/auth/StaticBearerAuthStrategy.ts` are clean-room ports of the model-map and
|
|
32
|
-
routing shape from `oc-go-cc` (`internal/router/model_router.go`,
|
|
33
|
-
`internal/client/opencode.go`, `configs/config.example.json`). Configuration
|
|
34
|
-
data + routing shape only; the TypeScript is original, and the upstream
|
|
35
|
-
repository is not vendored.
|
|
36
|
-
|
|
37
|
-
--------------------------------------------------------------------------------
|
|
38
|
-
3. js-tiktoken (MIT License)
|
|
39
|
-
--------------------------------------------------------------------------------
|
|
40
|
-
|
|
41
|
-
`src/opencodego/token-count.ts` lazily imports `js-tiktoken` (cl100k_base
|
|
42
|
-
encoding) to estimate input-token counts for OpenCodeGo scenario routing.
|
|
43
|
-
|
|
44
|
-
https://github.com/dqbd/tiktoken
|
|
45
|
-
Licensed under the MIT License.
|
|
1
|
+
@omnicross/subscriptions — THIRD-PARTY NOTICES
|
|
2
|
+
==============================================
|
|
3
|
+
|
|
4
|
+
This package contains the subscription-as-provider block (auth strategies,
|
|
5
|
+
account service, provider registry, dispatcher, OpenCodeGo routing). Some routing
|
|
6
|
+
shapes and configuration-data values were adapted,
|
|
7
|
+
clean-room, from the following third-party works. Those repositories are NOT
|
|
8
|
+
vendored into this tree; only original TypeScript that mirrors their routing
|
|
9
|
+
shape / config-data values lives here (see the in-code provenance comments).
|
|
10
|
+
|
|
11
|
+
--------------------------------------------------------------------------------
|
|
12
|
+
1. claude-relay-service (MIT License) — routing shape only
|
|
13
|
+
--------------------------------------------------------------------------------
|
|
14
|
+
|
|
15
|
+
The Codex (ChatGPT OAuth) upstream routing shape — the
|
|
16
|
+
`https://chatgpt.com/backend-api/codex/responses` endpoint dispatch in
|
|
17
|
+
`src/SubscriptionProviderRegistry.ts` — mirrors the route shape of
|
|
18
|
+
`claude-relay-service` (`src/routes/openaiRoutes.js`). Routing shape only; the
|
|
19
|
+
TypeScript is original, and the upstream repository is not vendored.
|
|
20
|
+
|
|
21
|
+
https://github.com/Wei-Shaw/claude-relay-service
|
|
22
|
+
Licensed under the MIT License.
|
|
23
|
+
|
|
24
|
+
--------------------------------------------------------------------------------
|
|
25
|
+
2. oc-go-cc (OpenCodeGo CC) — model-map + routing-shape / config-data
|
|
26
|
+
--------------------------------------------------------------------------------
|
|
27
|
+
|
|
28
|
+
The OpenCodeGo routing-shape, scenario router, model-map defaults, endpoint
|
|
29
|
+
shapes, and Anthropic-shape `x-api-key` fallback in
|
|
30
|
+
`src/opencodego/{defaults,endpoints,model-shape,ScenarioRouter}.ts` and
|
|
31
|
+
`src/auth/StaticBearerAuthStrategy.ts` are clean-room ports of the model-map and
|
|
32
|
+
routing shape from `oc-go-cc` (`internal/router/model_router.go`,
|
|
33
|
+
`internal/client/opencode.go`, `configs/config.example.json`). Configuration
|
|
34
|
+
data + routing shape only; the TypeScript is original, and the upstream
|
|
35
|
+
repository is not vendored.
|
|
36
|
+
|
|
37
|
+
--------------------------------------------------------------------------------
|
|
38
|
+
3. js-tiktoken (MIT License)
|
|
39
|
+
--------------------------------------------------------------------------------
|
|
40
|
+
|
|
41
|
+
`src/opencodego/token-count.ts` lazily imports `js-tiktoken` (cl100k_base
|
|
42
|
+
encoding) to estimate input-token counts for OpenCodeGo scenario routing.
|
|
43
|
+
|
|
44
|
+
https://github.com/dqbd/tiktoken
|
|
45
|
+
Licensed under the MIT License.
|
package/README.md
CHANGED
|
@@ -1,15 +1,15 @@
|
|
|
1
|
-
# @omnicross/subscriptions
|
|
2
|
-
|
|
3
|
-
omnicross subscription-as-provider support — pass-through / OAuth-bearer / static-bearer auth strategies, the Claude / Codex / Gemini OAuth flows, and the OpenCodeGo scenario dispatcher + fallback chain.
|
|
4
|
-
|
|
5
|
-
Part of the [omnicross](https://github.com/Dumoedss/omnicross) monorepo — see the root README for the full overview.
|
|
6
|
-
|
|
7
|
-
```bash
|
|
8
|
-
npm install @omnicross/subscriptions
|
|
9
|
-
```
|
|
10
|
-
|
|
11
|
-
## License
|
|
12
|
-
|
|
13
|
-
[MIT](LICENSE)
|
|
14
|
-
|
|
15
|
-
This package adapts third-party work under its own license — see the `NOTICE` file.
|
|
1
|
+
# @omnicross/subscriptions
|
|
2
|
+
|
|
3
|
+
omnicross subscription-as-provider support — pass-through / OAuth-bearer / static-bearer auth strategies, the Claude / Codex / Gemini OAuth flows, and the OpenCodeGo scenario dispatcher + fallback chain.
|
|
4
|
+
|
|
5
|
+
Part of the [omnicross](https://github.com/Dumoedss/omnicross) monorepo — see the root README for the full overview.
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
npm install @omnicross/subscriptions
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
## License
|
|
12
|
+
|
|
13
|
+
[MIT](LICENSE)
|
|
14
|
+
|
|
15
|
+
This package adapts third-party work under its own license — see the `NOTICE` file.
|
package/dist/index.cjs
CHANGED
|
@@ -194,28 +194,40 @@ async function resolveSelectedToken(selector, tokens, providerId, sessionKey, ac
|
|
|
194
194
|
const gated = gateSchedulable(accounts, providerId, health, now, resolvedModel, supportedModelsById);
|
|
195
195
|
const poolGated = isPoolGated(accounts, health, resolvedModel);
|
|
196
196
|
const remapFor = (id) => remapReportForAccount(supportedModelsById.get(id), resolvedModel);
|
|
197
|
+
const preferredId = _optionalChain([ctx, 'optionalAccess', _5 => _5.preferredAccountId]);
|
|
198
|
+
if (preferredId) {
|
|
199
|
+
const preferred = gated.find((a) => a.id === preferredId);
|
|
200
|
+
if (preferred && preferred.schedulable !== false) {
|
|
201
|
+
const preferredToken = await tokens.getAccessTokenForAccount(providerId, preferredId);
|
|
202
|
+
if (preferredToken) {
|
|
203
|
+
maybeTouchLastUsed(selector, tokens, providerId, preferredId);
|
|
204
|
+
_optionalChain([report, 'optionalCall', _6 => _6(preferredId, preferredId === activeAccountId, remapFor(preferredId))]);
|
|
205
|
+
return preferredToken;
|
|
206
|
+
}
|
|
207
|
+
}
|
|
208
|
+
}
|
|
197
209
|
const targetId = pickByIdTarget(selector, gated, providerId, activeAccountId, sessionKey, now, poolGated);
|
|
198
210
|
if (targetId !== void 0) {
|
|
199
211
|
const byId = await tokens.getAccessTokenForAccount(providerId, targetId);
|
|
200
212
|
if (byId) {
|
|
201
213
|
maybeTouchLastUsed(selector, tokens, providerId, targetId);
|
|
202
|
-
_optionalChain([report, 'optionalCall',
|
|
214
|
+
_optionalChain([report, 'optionalCall', _7 => _7(targetId, false, remapFor(targetId))]);
|
|
203
215
|
return byId;
|
|
204
216
|
}
|
|
205
217
|
selector.evictAffinity(providerId, targetId);
|
|
206
|
-
_optionalChain([health, 'optionalAccess',
|
|
218
|
+
_optionalChain([health, 'optionalAccess', _8 => _8.recordUpstreamOutcome, 'call', _9 => _9(providerId, targetId, { status: 401, now })]);
|
|
207
219
|
const remaining = gated.filter((a) => a.id !== targetId);
|
|
208
220
|
const retryId = pickByIdTarget(selector, remaining, providerId, activeAccountId, sessionKey, now, poolGated);
|
|
209
221
|
if (retryId !== void 0) {
|
|
210
222
|
const retryToken = await tokens.getAccessTokenForAccount(providerId, retryId);
|
|
211
223
|
if (retryToken) {
|
|
212
224
|
maybeTouchLastUsed(selector, tokens, providerId, retryId);
|
|
213
|
-
_optionalChain([report, 'optionalCall',
|
|
225
|
+
_optionalChain([report, 'optionalCall', _10 => _10(retryId, false, remapFor(retryId))]);
|
|
214
226
|
return retryToken;
|
|
215
227
|
}
|
|
216
228
|
}
|
|
217
229
|
}
|
|
218
|
-
if (activeAccountId) _optionalChain([report, 'optionalCall',
|
|
230
|
+
if (activeAccountId) _optionalChain([report, 'optionalCall', _11 => _11(activeAccountId, true, remapFor(activeAccountId))]);
|
|
219
231
|
return activeGetter();
|
|
220
232
|
}
|
|
221
233
|
return activeGetter();
|
|
@@ -264,9 +276,9 @@ var OAuthBearerAuthStrategy = (_class2 = class {
|
|
|
264
276
|
this.selector,
|
|
265
277
|
this.tokens,
|
|
266
278
|
this.providerId,
|
|
267
|
-
_optionalChain([hints, 'optionalAccess',
|
|
279
|
+
_optionalChain([hints, 'optionalAccess', _12 => _12.sessionKey]),
|
|
268
280
|
() => this.resolveAccessToken(),
|
|
269
|
-
{ health: this.health, reportSelection: _optionalChain([hints, 'optionalAccess',
|
|
281
|
+
{ health: this.health, reportSelection: _optionalChain([hints, 'optionalAccess', _13 => _13.reportSelection]), resolvedModel: _optionalChain([hints, 'optionalAccess', _14 => _14.resolvedModel]), preferredAccountId: _optionalChain([hints, 'optionalAccess', _15 => _15.preferredAccountId]) }
|
|
270
282
|
);
|
|
271
283
|
if (!token) {
|
|
272
284
|
return;
|
|
@@ -288,7 +300,7 @@ var OAuthBearerAuthStrategy = (_class2 = class {
|
|
|
288
300
|
async describeStatus() {
|
|
289
301
|
const config = await this.tokens.getFullConfig();
|
|
290
302
|
const entry = this.providerId === "codex" ? config.codex : config.gemini;
|
|
291
|
-
if (!_optionalChain([entry, 'optionalAccess',
|
|
303
|
+
if (!_optionalChain([entry, 'optionalAccess', _16 => _16.accessToken])) {
|
|
292
304
|
return { providerId: this.providerId, ok: false, reason: "missing-credential" };
|
|
293
305
|
}
|
|
294
306
|
if (entry.status === "expired") {
|
|
@@ -305,7 +317,7 @@ var OAuthBearerAuthStrategy = (_class2 = class {
|
|
|
305
317
|
async resolveAccessToken() {
|
|
306
318
|
const config = await this.tokens.getFullConfig();
|
|
307
319
|
const entry = this.providerId === "codex" ? config.codex : config.gemini;
|
|
308
|
-
if (!_optionalChain([entry, 'optionalAccess',
|
|
320
|
+
if (!_optionalChain([entry, 'optionalAccess', _17 => _17.accessToken])) return null;
|
|
309
321
|
const expiresAtMs = entry.expiresAt ? new Date(entry.expiresAt).getTime() : 0;
|
|
310
322
|
const expiringSoon = expiresAtMs > 0 && Date.now() >= expiresAtMs - REFRESH_LEAD_MS;
|
|
311
323
|
if (expiringSoon && entry.refreshToken) {
|
|
@@ -315,7 +327,7 @@ var OAuthBearerAuthStrategy = (_class2 = class {
|
|
|
315
327
|
if (!refreshed) return null;
|
|
316
328
|
const fresh = await this.tokens.getFullConfig();
|
|
317
329
|
const freshEntry = this.providerId === "codex" ? fresh.codex : fresh.gemini;
|
|
318
|
-
return _nullishCoalesce(_optionalChain([freshEntry, 'optionalAccess',
|
|
330
|
+
return _nullishCoalesce(_optionalChain([freshEntry, 'optionalAccess', _18 => _18.accessToken]), () => ( null));
|
|
319
331
|
}
|
|
320
332
|
if (entry.status === "expired") return null;
|
|
321
333
|
return entry.accessToken;
|
|
@@ -341,9 +353,9 @@ var PassThroughAuthStrategy = (_class3 = class {
|
|
|
341
353
|
this.selector,
|
|
342
354
|
this.tokens,
|
|
343
355
|
"claude",
|
|
344
|
-
_optionalChain([hints, 'optionalAccess',
|
|
356
|
+
_optionalChain([hints, 'optionalAccess', _19 => _19.sessionKey]),
|
|
345
357
|
() => this.tokens.getValidClaudeAccessToken(),
|
|
346
|
-
{ health: this.health, reportSelection: _optionalChain([hints, 'optionalAccess',
|
|
358
|
+
{ health: this.health, reportSelection: _optionalChain([hints, 'optionalAccess', _20 => _20.reportSelection]), resolvedModel: _optionalChain([hints, 'optionalAccess', _21 => _21.resolvedModel]), preferredAccountId: _optionalChain([hints, 'optionalAccess', _22 => _22.preferredAccountId]) }
|
|
347
359
|
);
|
|
348
360
|
if (!token) return;
|
|
349
361
|
headers["Authorization"] = `Bearer ${token}`;
|
|
@@ -363,7 +375,7 @@ var PassThroughAuthStrategy = (_class3 = class {
|
|
|
363
375
|
async describeStatus() {
|
|
364
376
|
const config = await this.tokens.getFullConfig();
|
|
365
377
|
const claude = config.claude;
|
|
366
|
-
if (!_optionalChain([claude, 'optionalAccess',
|
|
378
|
+
if (!_optionalChain([claude, 'optionalAccess', _23 => _23.accessToken])) {
|
|
367
379
|
return { providerId: "claude", ok: false, reason: "missing-credential" };
|
|
368
380
|
}
|
|
369
381
|
if (claude.status === "expired") {
|
|
@@ -419,15 +431,15 @@ var StaticBearerAuthStrategy = (_class5 = class {
|
|
|
419
431
|
this.selector,
|
|
420
432
|
this.tokens,
|
|
421
433
|
"opencodego",
|
|
422
|
-
_optionalChain([hints, 'optionalAccess',
|
|
434
|
+
_optionalChain([hints, 'optionalAccess', _24 => _24.sessionKey]),
|
|
423
435
|
() => this.tokens.getValidOpenCodeGoApiKey(),
|
|
424
|
-
{ health: this.health, reportSelection: _optionalChain([hints, 'optionalAccess',
|
|
436
|
+
{ health: this.health, reportSelection: _optionalChain([hints, 'optionalAccess', _25 => _25.reportSelection]), resolvedModel: _optionalChain([hints, 'optionalAccess', _26 => _26.resolvedModel]), preferredAccountId: _optionalChain([hints, 'optionalAccess', _27 => _27.preferredAccountId]) }
|
|
425
437
|
);
|
|
426
438
|
if (!key) {
|
|
427
439
|
return;
|
|
428
440
|
}
|
|
429
441
|
headers["Authorization"] = `Bearer ${key}`;
|
|
430
|
-
if (_optionalChain([hints, 'optionalAccess',
|
|
442
|
+
if (_optionalChain([hints, 'optionalAccess', _28 => _28.upstreamUrl, 'optionalAccess', _29 => _29.includes, 'call', _30 => _30(ANTHROPIC_SHAPE_PATH)])) {
|
|
431
443
|
headers["x-api-key"] = key;
|
|
432
444
|
}
|
|
433
445
|
}
|
|
@@ -437,7 +449,7 @@ var StaticBearerAuthStrategy = (_class5 = class {
|
|
|
437
449
|
async describeStatus() {
|
|
438
450
|
const config = await this.tokens.getFullConfig();
|
|
439
451
|
const oc = config.opencodego;
|
|
440
|
-
if (!_optionalChain([oc, 'optionalAccess',
|
|
452
|
+
if (!_optionalChain([oc, 'optionalAccess', _31 => _31.apiKey])) {
|
|
441
453
|
return { providerId: "opencodego", ok: false, reason: "missing-credential" };
|
|
442
454
|
}
|
|
443
455
|
if (oc.status === "error") {
|
|
@@ -781,11 +793,11 @@ function resolveOpenCodeGoShape(entry) {
|
|
|
781
793
|
function resolveOpenCodeGoHalf(modelId, config) {
|
|
782
794
|
if (!config) return "go";
|
|
783
795
|
for (const entry of Object.values(_nullishCoalesce(config.modelMap, () => ( {})))) {
|
|
784
|
-
if (_optionalChain([entry, 'optionalAccess',
|
|
796
|
+
if (_optionalChain([entry, 'optionalAccess', _32 => _32.modelId]) === modelId) return _nullishCoalesce(entry.provider, () => ( "go"));
|
|
785
797
|
}
|
|
786
798
|
for (const list of Object.values(_nullishCoalesce(config.fallbacks, () => ( {})))) {
|
|
787
799
|
for (const entry of _nullishCoalesce(list, () => ( []))) {
|
|
788
|
-
if (_optionalChain([entry, 'optionalAccess',
|
|
800
|
+
if (_optionalChain([entry, 'optionalAccess', _33 => _33.modelId]) === modelId) return _nullishCoalesce(entry.provider, () => ( "go"));
|
|
789
801
|
}
|
|
790
802
|
}
|
|
791
803
|
return "go";
|
|
@@ -885,7 +897,7 @@ function hasBackgroundPattern(loweredSlices) {
|
|
|
885
897
|
return containsAny(loweredSlices, BACKGROUND_KEYWORDS);
|
|
886
898
|
}
|
|
887
899
|
function resolveOpenCodeGoScenario(summary, config) {
|
|
888
|
-
const longContextThreshold = _nullishCoalesce(_optionalChain([config, 'optionalAccess',
|
|
900
|
+
const longContextThreshold = _nullishCoalesce(_optionalChain([config, 'optionalAccess', _34 => _34.modelMap, 'optionalAccess', _35 => _35.long_context, 'optionalAccess', _36 => _36.contextThreshold]), () => ( DEFAULT_OPENCODEGO_LONG_CONTEXT_THRESHOLD));
|
|
889
901
|
if (summary.estimatedInputTokens >= longContextThreshold) {
|
|
890
902
|
return "long_context";
|
|
891
903
|
}
|
|
@@ -1015,7 +1027,7 @@ var SubscriptionProviderRegistry = (_class9 = class {
|
|
|
1015
1027
|
resolveUpstreamUrl: (model, config) => {
|
|
1016
1028
|
const oc = config;
|
|
1017
1029
|
const { half, shape } = resolveOpenCodeGoTarget(model, oc);
|
|
1018
|
-
const override = half === "zen" ? _optionalChain([oc, 'optionalAccess',
|
|
1030
|
+
const override = half === "zen" ? _optionalChain([oc, 'optionalAccess', _37 => _37.zenBaseUrl]) : _optionalChain([oc, 'optionalAccess', _38 => _38.baseUrl]);
|
|
1019
1031
|
return buildOpenCodeGoUrl(half, shape, override);
|
|
1020
1032
|
},
|
|
1021
1033
|
// zen seam (Decision 3): vary the provider transformer chain by resolved
|
|
@@ -1033,7 +1045,7 @@ var SubscriptionProviderRegistry = (_class9 = class {
|
|
|
1033
1045
|
modelTransformerNames: [],
|
|
1034
1046
|
modelMapper: (sdkModel, summary, config) => {
|
|
1035
1047
|
const scenario = resolveOpenCodeGoScenario(summary, config);
|
|
1036
|
-
const entry = _nullishCoalesce(_nullishCoalesce(_nullishCoalesce(_optionalChain([config, 'optionalAccess',
|
|
1048
|
+
const entry = _nullishCoalesce(_nullishCoalesce(_nullishCoalesce(_optionalChain([config, 'optionalAccess', _39 => _39.modelMap, 'optionalAccess', _40 => _40[scenario]]), () => ( _optionalChain([config, 'optionalAccess', _41 => _41.modelMap, 'optionalAccess', _42 => _42.default]))), () => ( DEFAULT_OPENCODEGO_MODEL_MAP[scenario])), () => ( DEFAULT_OPENCODEGO_MODEL_MAP.default));
|
|
1037
1049
|
if (!entry) {
|
|
1038
1050
|
return { resolvedModel: sdkModel, scenario };
|
|
1039
1051
|
}
|
|
@@ -1052,7 +1064,7 @@ var SubscriptionProviderRegistry = (_class9 = class {
|
|
|
1052
1064
|
// wedge permanently in half-open). When NO circuit is open this returns
|
|
1053
1065
|
// the same first non-attempted entry as the prior `!attempted` filter.
|
|
1054
1066
|
nextFallback: (scenario, attempted, config) => {
|
|
1055
|
-
const list = _nullishCoalesce(_nullishCoalesce(_optionalChain([config, 'optionalAccess',
|
|
1067
|
+
const list = _nullishCoalesce(_nullishCoalesce(_optionalChain([config, 'optionalAccess', _43 => _43.fallbacks, 'optionalAccess', _44 => _44[scenario]]), () => ( DEFAULT_OPENCODEGO_FALLBACKS[scenario])), () => ( []));
|
|
1056
1068
|
for (const entry of list) {
|
|
1057
1069
|
if (attempted.includes(entry.modelId)) continue;
|
|
1058
1070
|
if (this.breaker.allowRequest(entry.modelId)) return entry;
|
|
@@ -1153,7 +1165,7 @@ var SubscriptionDispatcher = class {
|
|
|
1153
1165
|
scenario = mapped.scenario;
|
|
1154
1166
|
req.anthropicBody.model = resolvedModel;
|
|
1155
1167
|
}
|
|
1156
|
-
const upstreamUrl = _optionalChain([this, 'access',
|
|
1168
|
+
const upstreamUrl = _optionalChain([this, 'access', _45 => _45.profile, 'access', _46 => _46.resolveUpstreamUrl, 'optionalCall', _47 => _47(resolvedModel, ocConfig)]);
|
|
1157
1169
|
if (!upstreamUrl) {
|
|
1158
1170
|
throw new Error(`[SubscriptionDispatcher] profile=${this.profile.providerId} missing resolveUpstreamUrl`);
|
|
1159
1171
|
}
|
|
@@ -1185,7 +1197,7 @@ var SubscriptionDispatcher = class {
|
|
|
1185
1197
|
);
|
|
1186
1198
|
try {
|
|
1187
1199
|
const upstream = await this.hooks.fetchWithRetry(upstreamUrl, headers, req.anthropicBody, currentModel);
|
|
1188
|
-
_optionalChain([this, 'access',
|
|
1200
|
+
_optionalChain([this, 'access', _48 => _48.profile, 'access', _49 => _49.recordModelOutcome, 'optionalCall', _50 => _50(currentModel, true)]);
|
|
1189
1201
|
this.markHealth(usedAccountId, 200);
|
|
1190
1202
|
await this.hooks.writeProxyResponse(req.res, upstream, req.isStream, req.reqId);
|
|
1191
1203
|
return;
|
|
@@ -1194,7 +1206,7 @@ var SubscriptionDispatcher = class {
|
|
|
1194
1206
|
if (handled.retryOnce) {
|
|
1195
1207
|
try {
|
|
1196
1208
|
const upstream = await this.hooks.fetchWithRetry(upstreamUrl, handled.headers, req.anthropicBody, currentModel);
|
|
1197
|
-
_optionalChain([this, 'access',
|
|
1209
|
+
_optionalChain([this, 'access', _51 => _51.profile, 'access', _52 => _52.recordModelOutcome, 'optionalCall', _53 => _53(currentModel, true)]);
|
|
1198
1210
|
this.markHealth(usedAccountId, 200);
|
|
1199
1211
|
await this.hooks.writeProxyResponse(req.res, upstream, req.isStream, req.reqId);
|
|
1200
1212
|
return;
|
|
@@ -1204,10 +1216,10 @@ var SubscriptionDispatcher = class {
|
|
|
1204
1216
|
}
|
|
1205
1217
|
}
|
|
1206
1218
|
if (caughtErrorBreakerOutcome(err) === "failure") {
|
|
1207
|
-
_optionalChain([this, 'access',
|
|
1219
|
+
_optionalChain([this, 'access', _54 => _54.profile, 'access', _55 => _55.recordModelOutcome, 'optionalCall', _56 => _56(currentModel, false)]);
|
|
1208
1220
|
}
|
|
1209
1221
|
this.markHealth(usedAccountId, errStatus(err), err);
|
|
1210
|
-
const next = _optionalChain([this, 'access',
|
|
1222
|
+
const next = _optionalChain([this, 'access', _57 => _57.profile, 'access', _58 => _58.nextFallback, 'optionalCall', _59 => _59(scenario, attempted, ocConfig)]);
|
|
1211
1223
|
if (!next || attempted.length >= MAX_FALLBACK_ATTEMPTS_LOCAL) {
|
|
1212
1224
|
throw err;
|
|
1213
1225
|
}
|
|
@@ -1221,7 +1233,7 @@ var SubscriptionDispatcher = class {
|
|
|
1221
1233
|
}
|
|
1222
1234
|
/** Standard subscription transformer chain — Codex/Gemini/OpenCodeGo OpenAI-shape. */
|
|
1223
1235
|
async dispatchTransformerChain(req, upstreamUrl, resolvedModel, scenario, ocConfig, sessionKey) {
|
|
1224
|
-
const providerNames = _nullishCoalesce(_optionalChain([this, 'access',
|
|
1236
|
+
const providerNames = _nullishCoalesce(_optionalChain([this, 'access', _60 => _60.profile, 'access', _61 => _61.resolveProviderTransformerNames, 'optionalCall', _62 => _62(resolvedModel, ocConfig)]), () => ( this.profile.providerTransformerNames));
|
|
1225
1237
|
const providerTransformers = this.resolveTransformers(providerNames);
|
|
1226
1238
|
const modelTransformers = this.resolveTransformers(this.profile.modelTransformerNames);
|
|
1227
1239
|
const transformerProvider = {
|
|
@@ -1262,7 +1274,7 @@ var SubscriptionDispatcher = class {
|
|
|
1262
1274
|
);
|
|
1263
1275
|
try {
|
|
1264
1276
|
const upstream = await this.hooks.fetchWithRetry(fetchUrl, headers, requestBody, currentModel);
|
|
1265
|
-
_optionalChain([this, 'access',
|
|
1277
|
+
_optionalChain([this, 'access', _63 => _63.profile, 'access', _64 => _64.recordModelOutcome, 'optionalCall', _65 => _65(currentModel, true)]);
|
|
1266
1278
|
this.markHealth(usedAccountId, 200);
|
|
1267
1279
|
const finalResponse = await this.hooks.executor.executeResponseChain(
|
|
1268
1280
|
requestBody,
|
|
@@ -1278,7 +1290,7 @@ var SubscriptionDispatcher = class {
|
|
|
1278
1290
|
if (handled.retryOnce) {
|
|
1279
1291
|
try {
|
|
1280
1292
|
const upstream = await this.hooks.fetchWithRetry(fetchUrl, handled.headers, requestBody, currentModel);
|
|
1281
|
-
_optionalChain([this, 'access',
|
|
1293
|
+
_optionalChain([this, 'access', _66 => _66.profile, 'access', _67 => _67.recordModelOutcome, 'optionalCall', _68 => _68(currentModel, true)]);
|
|
1282
1294
|
this.markHealth(usedAccountId, 200);
|
|
1283
1295
|
const finalResponse = await this.hooks.executor.executeResponseChain(
|
|
1284
1296
|
requestBody,
|
|
@@ -1295,10 +1307,10 @@ var SubscriptionDispatcher = class {
|
|
|
1295
1307
|
}
|
|
1296
1308
|
}
|
|
1297
1309
|
if (caughtErrorBreakerOutcome(err) === "failure") {
|
|
1298
|
-
_optionalChain([this, 'access',
|
|
1310
|
+
_optionalChain([this, 'access', _69 => _69.profile, 'access', _70 => _70.recordModelOutcome, 'optionalCall', _71 => _71(currentModel, false)]);
|
|
1299
1311
|
}
|
|
1300
1312
|
this.markHealth(usedAccountId, errStatus(err), err);
|
|
1301
|
-
const next = _optionalChain([this, 'access',
|
|
1313
|
+
const next = _optionalChain([this, 'access', _72 => _72.profile, 'access', _73 => _73.nextFallback, 'optionalCall', _74 => _74(scenario, attempted, ocConfig)]);
|
|
1302
1314
|
if (!next || attempted.length >= MAX_FALLBACK_ATTEMPTS_LOCAL) {
|
|
1303
1315
|
throw err;
|
|
1304
1316
|
}
|
|
@@ -1328,7 +1340,7 @@ var SubscriptionDispatcher = class {
|
|
|
1328
1340
|
return { firstModel: primaryModel, attempted: [] };
|
|
1329
1341
|
}
|
|
1330
1342
|
const skipped = [primaryModel];
|
|
1331
|
-
const firstAdmitting = _optionalChain([this, 'access',
|
|
1343
|
+
const firstAdmitting = _optionalChain([this, 'access', _75 => _75.profile, 'access', _76 => _76.nextFallback, 'optionalCall', _77 => _77(scenario, skipped, ocConfig)]);
|
|
1332
1344
|
if (firstAdmitting) {
|
|
1333
1345
|
console.warn(
|
|
1334
1346
|
`[AgentProxy:subscription] opencodego primary ${primaryModel} circuit open -> first admitting fallback ${firstAdmitting.modelId}`
|
|
@@ -1346,7 +1358,7 @@ var SubscriptionDispatcher = class {
|
|
|
1346
1358
|
* successfully (caller should retry once); otherwise re-throws.
|
|
1347
1359
|
*/
|
|
1348
1360
|
async maybeRetryAfterError(err, headers, req, resolvedModel, sessionKey) {
|
|
1349
|
-
const status = _nullishCoalesce(_optionalChain([err, 'optionalAccess',
|
|
1361
|
+
const status = _nullishCoalesce(_optionalChain([err, 'optionalAccess', _78 => _78.status]), () => ( 0));
|
|
1350
1362
|
if (status !== 401) {
|
|
1351
1363
|
return { retryOnce: false, headers };
|
|
1352
1364
|
}
|
|
@@ -1468,11 +1480,11 @@ var SubscriptionDispatcher = class {
|
|
|
1468
1480
|
};
|
|
1469
1481
|
var MAX_FALLBACK_ATTEMPTS_LOCAL = 3;
|
|
1470
1482
|
function errStatus(err) {
|
|
1471
|
-
const status = _optionalChain([err, 'optionalAccess',
|
|
1483
|
+
const status = _optionalChain([err, 'optionalAccess', _79 => _79.status]);
|
|
1472
1484
|
return typeof status === "number" ? status : null;
|
|
1473
1485
|
}
|
|
1474
1486
|
function errHeaders(err) {
|
|
1475
|
-
const h = _optionalChain([err, 'optionalAccess',
|
|
1487
|
+
const h = _optionalChain([err, 'optionalAccess', _80 => _80.headers]);
|
|
1476
1488
|
if (!h) return void 0;
|
|
1477
1489
|
if (typeof h.get === "function") return h;
|
|
1478
1490
|
if (typeof h === "object") return h;
|
|
@@ -1480,11 +1492,11 @@ function errHeaders(err) {
|
|
|
1480
1492
|
}
|
|
1481
1493
|
function errBodyText(err) {
|
|
1482
1494
|
const e = err;
|
|
1483
|
-
const raw = typeof _optionalChain([e, 'optionalAccess',
|
|
1484
|
-
return _optionalChain([raw, 'optionalAccess',
|
|
1495
|
+
const raw = typeof _optionalChain([e, 'optionalAccess', _81 => _81.bodyText]) === "string" ? e.bodyText : typeof _optionalChain([e, 'optionalAccess', _82 => _82.body]) === "string" ? e.body : void 0;
|
|
1496
|
+
return _optionalChain([raw, 'optionalAccess', _83 => _83.slice, 'call', _84 => _84(0, 2048)]);
|
|
1485
1497
|
}
|
|
1486
1498
|
function caughtErrorBreakerOutcome(err) {
|
|
1487
|
-
const status = _optionalChain([err, 'optionalAccess',
|
|
1499
|
+
const status = _optionalChain([err, 'optionalAccess', _85 => _85.status]);
|
|
1488
1500
|
if (typeof status !== "number") return "failure";
|
|
1489
1501
|
if (status === 0) return "neutral";
|
|
1490
1502
|
if (status >= 500 || status === 429) return "failure";
|
package/dist/index.js
CHANGED
|
@@ -194,6 +194,18 @@ async function resolveSelectedToken(selector, tokens, providerId, sessionKey, ac
|
|
|
194
194
|
const gated = gateSchedulable(accounts, providerId, health, now, resolvedModel, supportedModelsById);
|
|
195
195
|
const poolGated = isPoolGated(accounts, health, resolvedModel);
|
|
196
196
|
const remapFor = (id) => remapReportForAccount(supportedModelsById.get(id), resolvedModel);
|
|
197
|
+
const preferredId = ctx?.preferredAccountId;
|
|
198
|
+
if (preferredId) {
|
|
199
|
+
const preferred = gated.find((a) => a.id === preferredId);
|
|
200
|
+
if (preferred && preferred.schedulable !== false) {
|
|
201
|
+
const preferredToken = await tokens.getAccessTokenForAccount(providerId, preferredId);
|
|
202
|
+
if (preferredToken) {
|
|
203
|
+
maybeTouchLastUsed(selector, tokens, providerId, preferredId);
|
|
204
|
+
report?.(preferredId, preferredId === activeAccountId, remapFor(preferredId));
|
|
205
|
+
return preferredToken;
|
|
206
|
+
}
|
|
207
|
+
}
|
|
208
|
+
}
|
|
197
209
|
const targetId = pickByIdTarget(selector, gated, providerId, activeAccountId, sessionKey, now, poolGated);
|
|
198
210
|
if (targetId !== void 0) {
|
|
199
211
|
const byId = await tokens.getAccessTokenForAccount(providerId, targetId);
|
|
@@ -266,7 +278,7 @@ var OAuthBearerAuthStrategy = class {
|
|
|
266
278
|
this.providerId,
|
|
267
279
|
hints?.sessionKey,
|
|
268
280
|
() => this.resolveAccessToken(),
|
|
269
|
-
{ health: this.health, reportSelection: hints?.reportSelection, resolvedModel: hints?.resolvedModel }
|
|
281
|
+
{ health: this.health, reportSelection: hints?.reportSelection, resolvedModel: hints?.resolvedModel, preferredAccountId: hints?.preferredAccountId }
|
|
270
282
|
);
|
|
271
283
|
if (!token) {
|
|
272
284
|
return;
|
|
@@ -343,7 +355,7 @@ var PassThroughAuthStrategy = class {
|
|
|
343
355
|
"claude",
|
|
344
356
|
hints?.sessionKey,
|
|
345
357
|
() => this.tokens.getValidClaudeAccessToken(),
|
|
346
|
-
{ health: this.health, reportSelection: hints?.reportSelection, resolvedModel: hints?.resolvedModel }
|
|
358
|
+
{ health: this.health, reportSelection: hints?.reportSelection, resolvedModel: hints?.resolvedModel, preferredAccountId: hints?.preferredAccountId }
|
|
347
359
|
);
|
|
348
360
|
if (!token) return;
|
|
349
361
|
headers["Authorization"] = `Bearer ${token}`;
|
|
@@ -421,7 +433,7 @@ var StaticBearerAuthStrategy = class {
|
|
|
421
433
|
"opencodego",
|
|
422
434
|
hints?.sessionKey,
|
|
423
435
|
() => this.tokens.getValidOpenCodeGoApiKey(),
|
|
424
|
-
{ health: this.health, reportSelection: hints?.reportSelection, resolvedModel: hints?.resolvedModel }
|
|
436
|
+
{ health: this.health, reportSelection: hints?.reportSelection, resolvedModel: hints?.resolvedModel, preferredAccountId: hints?.preferredAccountId }
|
|
425
437
|
);
|
|
426
438
|
if (!key) {
|
|
427
439
|
return;
|
package/package.json
CHANGED
|
@@ -1,59 +1,59 @@
|
|
|
1
|
-
{
|
|
2
|
-
"name": "@omnicross/subscriptions",
|
|
3
|
-
"version": "0.1.
|
|
4
|
-
"description": "Omnicross subscription-as-provider auth strategies, OAuth flows, and the OpenCodeGo scenario dispatcher.",
|
|
5
|
-
"license": "MIT",
|
|
6
|
-
"author": "Sayo (https://github.com/Dumoedss)",
|
|
7
|
-
"homepage": "https://github.com/Dumoedss/omnicross#readme",
|
|
8
|
-
"keywords": [
|
|
9
|
-
"omnicross",
|
|
10
|
-
"llm",
|
|
11
|
-
"oauth",
|
|
12
|
-
"subscription",
|
|
13
|
-
"claude",
|
|
14
|
-
"codex",
|
|
15
|
-
"gemini"
|
|
16
|
-
],
|
|
17
|
-
"repository": {
|
|
18
|
-
"type": "git",
|
|
19
|
-
"url": "git+https://github.com/Dumoedss/omnicross.git",
|
|
20
|
-
"directory": "packages/subscriptions"
|
|
21
|
-
},
|
|
22
|
-
"publishConfig": {
|
|
23
|
-
"access": "public"
|
|
24
|
-
},
|
|
25
|
-
"engines": {
|
|
26
|
-
"node": ">=20"
|
|
27
|
-
},
|
|
28
|
-
"type": "module",
|
|
29
|
-
"main": "dist/index.cjs",
|
|
30
|
-
"module": "dist/index.js",
|
|
31
|
-
"types": "dist/index.d.ts",
|
|
32
|
-
"exports": {
|
|
33
|
-
".": {
|
|
34
|
-
"types": "./dist/index.d.ts",
|
|
35
|
-
"import": "./dist/index.js",
|
|
36
|
-
"require": "./dist/index.cjs"
|
|
37
|
-
},
|
|
38
|
-
"./*": {
|
|
39
|
-
"types": "./dist/*.d.ts",
|
|
40
|
-
"import": "./dist/*.js",
|
|
41
|
-
"require": "./dist/*.cjs"
|
|
42
|
-
}
|
|
43
|
-
},
|
|
44
|
-
"files": [
|
|
45
|
-
"dist",
|
|
46
|
-
"LICENSE",
|
|
47
|
-
"NOTICE",
|
|
48
|
-
"README.md"
|
|
49
|
-
],
|
|
50
|
-
"scripts": {
|
|
51
|
-
"build": "tsup",
|
|
52
|
-
"typecheck": "tsc -p tsconfig.typecheck.json --noEmit"
|
|
53
|
-
},
|
|
54
|
-
"dependencies": {
|
|
55
|
-
"@omnicross/contracts": "^0.1.0",
|
|
56
|
-
"@omnicross/core": "^0.1.0",
|
|
57
|
-
"js-tiktoken": "^1.0.21"
|
|
58
|
-
}
|
|
59
|
-
}
|
|
1
|
+
{
|
|
2
|
+
"name": "@omnicross/subscriptions",
|
|
3
|
+
"version": "0.1.4",
|
|
4
|
+
"description": "Omnicross subscription-as-provider auth strategies, OAuth flows, and the OpenCodeGo scenario dispatcher.",
|
|
5
|
+
"license": "MIT",
|
|
6
|
+
"author": "Sayo (https://github.com/Dumoedss)",
|
|
7
|
+
"homepage": "https://github.com/Dumoedss/omnicross#readme",
|
|
8
|
+
"keywords": [
|
|
9
|
+
"omnicross",
|
|
10
|
+
"llm",
|
|
11
|
+
"oauth",
|
|
12
|
+
"subscription",
|
|
13
|
+
"claude",
|
|
14
|
+
"codex",
|
|
15
|
+
"gemini"
|
|
16
|
+
],
|
|
17
|
+
"repository": {
|
|
18
|
+
"type": "git",
|
|
19
|
+
"url": "git+https://github.com/Dumoedss/omnicross.git",
|
|
20
|
+
"directory": "packages/subscriptions"
|
|
21
|
+
},
|
|
22
|
+
"publishConfig": {
|
|
23
|
+
"access": "public"
|
|
24
|
+
},
|
|
25
|
+
"engines": {
|
|
26
|
+
"node": ">=20"
|
|
27
|
+
},
|
|
28
|
+
"type": "module",
|
|
29
|
+
"main": "dist/index.cjs",
|
|
30
|
+
"module": "dist/index.js",
|
|
31
|
+
"types": "dist/index.d.ts",
|
|
32
|
+
"exports": {
|
|
33
|
+
".": {
|
|
34
|
+
"types": "./dist/index.d.ts",
|
|
35
|
+
"import": "./dist/index.js",
|
|
36
|
+
"require": "./dist/index.cjs"
|
|
37
|
+
},
|
|
38
|
+
"./*": {
|
|
39
|
+
"types": "./dist/*.d.ts",
|
|
40
|
+
"import": "./dist/*.js",
|
|
41
|
+
"require": "./dist/*.cjs"
|
|
42
|
+
}
|
|
43
|
+
},
|
|
44
|
+
"files": [
|
|
45
|
+
"dist",
|
|
46
|
+
"LICENSE",
|
|
47
|
+
"NOTICE",
|
|
48
|
+
"README.md"
|
|
49
|
+
],
|
|
50
|
+
"scripts": {
|
|
51
|
+
"build": "tsup",
|
|
52
|
+
"typecheck": "tsc -p tsconfig.typecheck.json --noEmit"
|
|
53
|
+
},
|
|
54
|
+
"dependencies": {
|
|
55
|
+
"@omnicross/contracts": "^0.1.0",
|
|
56
|
+
"@omnicross/core": "^0.1.0",
|
|
57
|
+
"js-tiktoken": "^1.0.21"
|
|
58
|
+
}
|
|
59
|
+
}
|