@omnicross/core 0.1.2 → 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 +57 -57
- package/README.md +15 -15
- package/dist/auth/GeminiCodeAssistProjectResolver.cjs +6 -1
- package/dist/auth/GeminiCodeAssistProjectResolver.js +6 -1
- package/dist/chunk-3QFXFCHG.js +33 -0
- package/dist/chunk-4IH4EL7M.cjs +9 -0
- package/dist/chunk-4YINUUKQ.cjs +33 -0
- package/dist/chunk-5ENKBSWO.js +311 -0
- package/dist/chunk-6RPZADX3.cjs +92 -0
- package/dist/chunk-7Y47UCF2.js +142 -0
- package/dist/chunk-AEOZIDEB.cjs +32 -0
- package/dist/chunk-APYG5QD7.cjs +50 -0
- package/dist/{chunk-MNYKI4CI.js → chunk-BPKCU575.js} +29 -0
- package/dist/{chunk-SN3YWBX7.cjs → chunk-DKPXN34V.cjs} +2108 -538
- package/dist/{chunk-4NBS6KPV.cjs → chunk-DQ5VAYZ6.cjs} +7 -8
- package/dist/chunk-E3UCVHLP.cjs +142 -0
- package/dist/chunk-FCR77GYM.cjs +33 -0
- package/dist/{chunk-74TMJA7Z.js → chunk-HRRYG2AX.js} +8 -4
- package/dist/chunk-HUZZZ3JL.js +32 -0
- package/dist/{chunk-KUU2RNG6.cjs → chunk-HYN75H6G.cjs} +3 -0
- package/dist/{chunk-QOCNX236.js → chunk-IAXWICZU.js} +24 -1
- package/dist/{chunk-JO5NLTLY.js → chunk-IK3KE3AU.js} +3 -0
- package/dist/{chunk-V5KPWNYX.cjs → chunk-JMJBSACD.cjs} +3 -3
- package/dist/chunk-K5NM7VAH.js +33 -0
- package/dist/{chunk-N3V2J5ZO.cjs → chunk-KFI44N2R.cjs} +8 -4
- package/dist/chunk-L74VDN4A.cjs +32 -0
- package/dist/chunk-OCEUVQHW.cjs +112 -0
- package/dist/chunk-OE6TDIWW.js +22 -0
- package/dist/chunk-OZFM4X3S.js +18 -0
- package/dist/{chunk-LKZJEL6E.cjs → chunk-Q27JY5RG.cjs} +6 -4
- package/dist/{chunk-SPVWWUHX.cjs → chunk-QWBWGODS.cjs} +24 -1
- package/dist/{chunk-2FEVTJWG.js → chunk-QYTT6GE3.js} +1929 -359
- package/dist/{chunk-UYPEN5XE.cjs → chunk-RGTR7CIO.cjs} +6 -6
- package/dist/chunk-RPII3E6Z.cjs +145 -0
- package/dist/{chunk-XBSYYZIY.cjs → chunk-SNYBEXLB.cjs} +31 -2
- package/dist/{chunk-2DCNB7DF.cjs → chunk-SU2GCLAC.cjs} +30 -10
- package/dist/{chunk-5HTVET6E.js → chunk-TIER4SUC.js} +24 -4
- package/dist/chunk-TKJMZBAH.js +32 -0
- package/dist/{chunk-ZSVQT3PW.js → chunk-UBWEBKRC.js} +5 -6
- package/dist/chunk-UHGVBFU3.js +385 -0
- package/dist/chunk-UIBD2YY5.cjs +22 -0
- package/dist/chunk-UNEFIWXI.cjs +32 -0
- package/dist/chunk-VACWOIRE.cjs +385 -0
- package/dist/{chunk-O466Y272.js → chunk-VPBAUQ2M.js} +7 -7
- package/dist/chunk-VQY5W4YW.cjs +311 -0
- package/dist/chunk-WLYIIEAF.js +50 -0
- package/dist/chunk-WNY4WMRF.js +32 -0
- package/dist/chunk-XEKD23J5.js +9 -0
- package/dist/chunk-XK5CIRMQ.js +112 -0
- package/dist/chunk-XSVNC2UD.cjs +18 -0
- package/dist/chunk-XTEI64OU.js +145 -0
- package/dist/chunk-XX6NQJMA.js +92 -0
- package/dist/{chunk-745DV5FL.js → chunk-Y7FO65VT.js} +3 -3
- package/dist/{chunk-PXUJF5HS.js → chunk-ZY6KU6P3.js} +4 -2
- package/dist/completion/CompletionService.cjs +30 -17
- package/dist/completion/CompletionService.js +29 -16
- package/dist/completion/NativeSearchInjector.cjs +3 -3
- package/dist/completion/NativeSearchInjector.js +2 -2
- package/dist/completion/openrouter-headers.cjs +3 -6
- package/dist/completion/openrouter-headers.d.cts +9 -12
- package/dist/completion/openrouter-headers.d.ts +9 -12
- package/dist/completion/openrouter-headers.js +2 -5
- package/dist/completion/openrouter-models.cjs +4 -3
- package/dist/completion/openrouter-models.js +2 -1
- package/dist/completion.cjs +30 -17
- package/dist/completion.js +29 -16
- package/dist/index.cjs +151 -20
- package/dist/index.d.cts +44 -10
- package/dist/index.d.ts +44 -10
- package/dist/index.js +160 -29
- package/dist/keyPolicy-Cp0FntZl.d.cts +90 -0
- package/dist/keyPolicy-Cp0FntZl.d.ts +90 -0
- package/dist/outbound-api/auditCapture.cjs +9 -0
- package/dist/outbound-api/auditCapture.d.cts +52 -0
- package/dist/outbound-api/auditCapture.d.ts +52 -0
- package/dist/outbound-api/auditCapture.js +9 -0
- package/dist/outbound-api/auditRedact.cjs +8 -0
- package/dist/outbound-api/auditRedact.d.cts +30 -0
- package/dist/outbound-api/auditRedact.d.ts +30 -0
- package/dist/outbound-api/auditRedact.js +8 -0
- package/dist/outbound-api/billingCapture.cjs +8 -0
- package/dist/outbound-api/billingCapture.d.cts +61 -0
- package/dist/outbound-api/billingCapture.d.ts +61 -0
- package/dist/outbound-api/billingCapture.js +8 -0
- package/dist/outbound-api/quotaWarn.cjs +12 -0
- package/dist/outbound-api/quotaWarn.d.cts +43 -0
- package/dist/outbound-api/quotaWarn.d.ts +43 -0
- package/dist/outbound-api/quotaWarn.js +12 -0
- package/dist/outbound-api/routeResolver.cjs +5 -2
- package/dist/outbound-api/routeResolver.d.cts +9 -2
- package/dist/outbound-api/routeResolver.d.ts +9 -2
- package/dist/outbound-api/routeResolver.js +4 -1
- package/dist/outbound-api/types.cjs +6 -1
- package/dist/outbound-api/types.d.cts +12 -144
- package/dist/outbound-api/types.d.ts +12 -144
- package/dist/outbound-api/types.js +6 -0
- package/dist/outbound-api.cjs +144 -17
- package/dist/outbound-api.d.cts +655 -25
- package/dist/outbound-api.d.ts +655 -25
- package/dist/outbound-api.js +148 -21
- package/dist/pipeline/AuthSource.d.cts +29 -1
- package/dist/pipeline/AuthSource.d.ts +29 -1
- package/dist/pipeline/LlmConfigProviderAuth.cjs +3 -3
- package/dist/pipeline/LlmConfigProviderAuth.js +2 -2
- package/dist/pipeline/SubscriptionAccountHealth.cjs +22 -0
- package/dist/pipeline/SubscriptionAccountHealth.d.cts +235 -0
- package/dist/pipeline/SubscriptionAccountHealth.d.ts +235 -0
- package/dist/pipeline/SubscriptionAccountHealth.js +22 -0
- package/dist/pipeline/SubscriptionAuthSource.cjs +2 -2
- package/dist/pipeline/SubscriptionAuthSource.d.cts +3 -2
- package/dist/pipeline/SubscriptionAuthSource.d.ts +3 -2
- package/dist/pipeline/SubscriptionAuthSource.js +1 -1
- package/dist/pipeline/SubscriptionAuthStrategy.d.cts +30 -1
- package/dist/pipeline/SubscriptionAuthStrategy.d.ts +30 -1
- package/dist/pipeline/auditSink.cjs +14 -0
- package/dist/pipeline/auditSink.d.cts +48 -0
- package/dist/pipeline/auditSink.d.ts +48 -0
- package/dist/pipeline/auditSink.js +14 -0
- package/dist/pipeline/auditUsageStash.cjs +10 -0
- package/dist/pipeline/auditUsageStash.d.cts +37 -0
- package/dist/pipeline/auditUsageStash.d.ts +37 -0
- package/dist/pipeline/auditUsageStash.js +10 -0
- package/dist/pipeline/billingEmit.cjs +14 -0
- package/dist/pipeline/billingEmit.d.cts +49 -0
- package/dist/pipeline/billingEmit.d.ts +49 -0
- package/dist/pipeline/billingEmit.js +14 -0
- package/dist/pipeline/executeProviderCall.cjs +2 -2
- package/dist/pipeline/executeProviderCall.js +1 -1
- package/dist/pipeline/upstreamFetch.cjs +14 -0
- package/dist/pipeline/upstreamFetch.d.cts +83 -0
- package/dist/pipeline/upstreamFetch.d.ts +83 -0
- package/dist/pipeline/upstreamFetch.js +14 -0
- package/dist/pipeline/webhookEmit.cjs +10 -0
- package/dist/pipeline/webhookEmit.d.cts +36 -0
- package/dist/pipeline/webhookEmit.d.ts +36 -0
- package/dist/pipeline/webhookEmit.js +10 -0
- package/dist/ports/usage-event-store.d.cts +26 -1
- package/dist/ports/usage-event-store.d.ts +26 -1
- package/dist/ports.d.cts +8 -1
- package/dist/ports.d.ts +8 -1
- package/dist/provider-proxy/ProviderProxy.cjs +30 -17
- package/dist/provider-proxy/ProviderProxy.js +29 -16
- package/dist/provider-proxy/identity/SubscriptionIdentityStore.cjs +15 -0
- package/dist/provider-proxy/identity/SubscriptionIdentityStore.d.cts +121 -0
- package/dist/provider-proxy/identity/SubscriptionIdentityStore.d.ts +121 -0
- package/dist/provider-proxy/identity/SubscriptionIdentityStore.js +15 -0
- package/dist/provider-proxy/identity/fingerprintHeaders.cjs +20 -0
- package/dist/provider-proxy/identity/fingerprintHeaders.d.cts +89 -0
- package/dist/provider-proxy/identity/fingerprintHeaders.d.ts +89 -0
- package/dist/provider-proxy/identity/fingerprintHeaders.js +20 -0
- package/dist/provider-proxy/ingress/providerProxyShared.cjs +30 -17
- package/dist/provider-proxy/ingress/providerProxyShared.d.cts +11 -2
- package/dist/provider-proxy/ingress/providerProxyShared.d.ts +11 -2
- package/dist/provider-proxy/ingress/providerProxyShared.js +29 -16
- package/dist/provider-proxy/matchText.cjs +4 -2
- package/dist/provider-proxy/matchText.d.cts +14 -1
- package/dist/provider-proxy/matchText.d.ts +14 -1
- package/dist/provider-proxy/matchText.js +3 -1
- package/dist/provider-proxy/types.d.cts +30 -0
- package/dist/provider-proxy/types.d.ts +30 -0
- package/dist/provider-proxy.cjs +30 -17
- package/dist/provider-proxy.js +29 -16
- package/dist/{routeResolver-HE-ZO0fO.d.ts → routeResolver-C4T7yClx.d.ts} +36 -10
- package/dist/{routeResolver-BrbK6ja9.d.cts → routeResolver-CB3tvJKy.d.cts} +36 -10
- package/dist/transformer/transformers/OpenAIResponseTransformer.cjs +2 -2
- package/dist/transformer/transformers/OpenAIResponseTransformer.js +1 -1
- package/dist/transformer/transformers.cjs +7 -7
- package/dist/transformer/transformers.js +8 -8
- package/dist/transformer.cjs +9 -9
- package/dist/transformer.js +8 -8
- package/dist/types-B8Arpxn0.d.cts +754 -0
- package/dist/types-lgPYQuZS.d.ts +754 -0
- package/dist/usage/usage-recorder.cjs +3 -2
- package/dist/usage/usage-recorder.d.cts +19 -1
- package/dist/usage/usage-recorder.d.ts +19 -1
- package/dist/usage/usage-recorder.js +2 -1
- package/dist/usage.cjs +3 -2
- package/dist/usage.js +2 -1
- package/package.json +64 -62
- package/dist/chunk-3MEACFK3.js +0 -193
- package/dist/chunk-6VIXXLMX.cjs +0 -14
- package/dist/chunk-E3WHL7CO.js +0 -14
- package/dist/chunk-G2FUJNA2.cjs +0 -193
|
@@ -1,9 +1,15 @@
|
|
|
1
|
-
"use strict";Object.defineProperty(exports, "__esModule", {value: true}); function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } function _nullishCoalesce(lhs, rhsFn) { if (lhs != null) { return lhs; } else { return rhsFn(); } } function _optionalChain(ops) { let lastAccessLHS = undefined; let value = ops[0]; let i = 1; while (i < ops.length) { const op = ops[i]; const fn = ops[i + 1]; i += 2; if ((op === 'optionalAccess' || op === 'optionalCall') && value == null) { return undefined; } if (op === 'access' || op === 'optionalAccess') { lastAccessLHS = value; value = fn(value); } else if (op === 'call' || op === 'optionalCall') { value = fn((...args) => value.call(lastAccessLHS, ...args)); lastAccessLHS = undefined; } } return value; } var _class; var _class2; var _class3; var _class4; var _class5;
|
|
1
|
+
"use strict";Object.defineProperty(exports, "__esModule", {value: true}); function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } function _nullishCoalesce(lhs, rhsFn) { if (lhs != null) { return lhs; } else { return rhsFn(); } } function _optionalChain(ops) { let lastAccessLHS = undefined; let value = ops[0]; let i = 1; while (i < ops.length) { const op = ops[i]; const fn = ops[i + 1]; i += 2; if ((op === 'optionalAccess' || op === 'optionalCall') && value == null) { return undefined; } if (op === 'access' || op === 'optionalAccess') { lastAccessLHS = value; value = fn(value); } else if (op === 'call' || op === 'optionalCall') { value = fn((...args) => value.call(lastAccessLHS, ...args)); lastAccessLHS = undefined; } } return value; } var _class; var _class2; var _class3; var _class4; var _class5; var _class6; var _class7; var _class8; var _class9; var _class10; var _class11; var _class12; var _class13;
|
|
2
2
|
|
|
3
|
-
var
|
|
3
|
+
var _chunkHQP3K7PUcjs = require('./chunk-HQP3K7PU.cjs');
|
|
4
4
|
|
|
5
5
|
|
|
6
|
-
var
|
|
6
|
+
var _chunk4VAVYUZScjs = require('./chunk-4VAVYUZS.cjs');
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
var _chunk7YN22L2Hcjs = require('./chunk-7YN22L2H.cjs');
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
var _chunkSU2GCLACcjs = require('./chunk-SU2GCLAC.cjs');
|
|
7
13
|
|
|
8
14
|
|
|
9
15
|
var _chunk46ZIFWYGcjs = require('./chunk-46ZIFWYG.cjs');
|
|
@@ -12,23 +18,28 @@ var _chunk46ZIFWYGcjs = require('./chunk-46ZIFWYG.cjs');
|
|
|
12
18
|
var _chunkGBHYAGX3cjs = require('./chunk-GBHYAGX3.cjs');
|
|
13
19
|
|
|
14
20
|
|
|
15
|
-
var
|
|
21
|
+
var _chunkRPII3E6Zcjs = require('./chunk-RPII3E6Z.cjs');
|
|
16
22
|
|
|
17
23
|
|
|
18
|
-
var _chunk2DCNB7DFcjs = require('./chunk-2DCNB7DF.cjs');
|
|
19
24
|
|
|
25
|
+
var _chunk6RPZADX3cjs = require('./chunk-6RPZADX3.cjs');
|
|
20
26
|
|
|
21
|
-
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
var _chunkQWBWGODScjs = require('./chunk-QWBWGODS.cjs');
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
var _chunkUIBD2YY5cjs = require('./chunk-UIBD2YY5.cjs');
|
|
22
33
|
|
|
23
34
|
|
|
24
35
|
var _chunkR3HK6R4Bcjs = require('./chunk-R3HK6R4B.cjs');
|
|
25
36
|
|
|
26
37
|
|
|
27
|
-
var
|
|
38
|
+
var _chunkHYN75H6Gcjs = require('./chunk-HYN75H6G.cjs');
|
|
28
39
|
|
|
29
40
|
|
|
30
41
|
|
|
31
|
-
var
|
|
42
|
+
var _chunkQ27JY5RGcjs = require('./chunk-Q27JY5RG.cjs');
|
|
32
43
|
|
|
33
44
|
|
|
34
45
|
var _chunkQXD4MV2Xcjs = require('./chunk-QXD4MV2X.cjs');
|
|
@@ -37,33 +48,57 @@ var _chunkQXD4MV2Xcjs = require('./chunk-QXD4MV2X.cjs');
|
|
|
37
48
|
var _chunkNYUNU75Acjs = require('./chunk-NYUNU75A.cjs');
|
|
38
49
|
|
|
39
50
|
|
|
40
|
-
|
|
51
|
+
|
|
52
|
+
var _chunkVQY5W4YWcjs = require('./chunk-VQY5W4YW.cjs');
|
|
53
|
+
|
|
54
|
+
|
|
55
|
+
var _chunkKFI44N2Rcjs = require('./chunk-KFI44N2R.cjs');
|
|
41
56
|
|
|
42
57
|
|
|
43
58
|
var _chunkSVNDB62Dcjs = require('./chunk-SVNDB62D.cjs');
|
|
44
59
|
|
|
45
60
|
|
|
61
|
+
var _chunkAPYG5QD7cjs = require('./chunk-APYG5QD7.cjs');
|
|
62
|
+
|
|
63
|
+
|
|
64
|
+
|
|
65
|
+
var _chunk4YINUUKQcjs = require('./chunk-4YINUUKQ.cjs');
|
|
66
|
+
|
|
67
|
+
|
|
68
|
+
|
|
69
|
+
|
|
70
|
+
|
|
71
|
+
|
|
72
|
+
|
|
73
|
+
|
|
74
|
+
|
|
75
|
+
var _chunkVACWOIREcjs = require('./chunk-VACWOIRE.cjs');
|
|
76
|
+
|
|
77
|
+
|
|
46
78
|
|
|
47
79
|
|
|
48
80
|
var _chunkA2YMUCBTcjs = require('./chunk-A2YMUCBT.cjs');
|
|
49
81
|
|
|
50
82
|
|
|
51
|
-
var
|
|
83
|
+
var _chunkE3UCVHLPcjs = require('./chunk-E3UCVHLP.cjs');
|
|
52
84
|
|
|
53
85
|
|
|
54
86
|
|
|
55
87
|
var _chunkSUEGJ75Dcjs = require('./chunk-SUEGJ75D.cjs');
|
|
56
88
|
|
|
57
89
|
|
|
58
|
-
var
|
|
59
|
-
|
|
90
|
+
var _chunkOCEUVQHWcjs = require('./chunk-OCEUVQHW.cjs');
|
|
60
91
|
|
|
61
92
|
|
|
62
|
-
var
|
|
93
|
+
var _chunkJMJBSACDcjs = require('./chunk-JMJBSACD.cjs');
|
|
63
94
|
|
|
64
95
|
|
|
65
96
|
var _chunkGMMT7RVNcjs = require('./chunk-GMMT7RVN.cjs');
|
|
66
97
|
|
|
98
|
+
|
|
99
|
+
|
|
100
|
+
var _chunkUNEFIWXIcjs = require('./chunk-UNEFIWXI.cjs');
|
|
101
|
+
|
|
67
102
|
// src/completion/StreamEventBuffer.ts
|
|
68
103
|
var TERMINAL_TYPES = /* @__PURE__ */ new Set(["done", "error", "abort"]);
|
|
69
104
|
var QUEUE_CAP = 200;
|
|
@@ -325,7 +360,7 @@ function convertMessageToGemini(msg) {
|
|
|
325
360
|
|
|
326
361
|
// src/completion/openrouter-utils.ts
|
|
327
362
|
function getOpenRouterProviderConfig(provider, modelId) {
|
|
328
|
-
if (!
|
|
363
|
+
if (!_chunkUNEFIWXIcjs.isOpenRouterProvider.call(void 0, provider)) {
|
|
329
364
|
return void 0;
|
|
330
365
|
}
|
|
331
366
|
const modelConfig = _optionalChain([provider, 'access', _ => _.modelConfigs, 'optionalAccess', _2 => _2.find, 'call', _3 => _3((m) => m.id === modelId)]);
|
|
@@ -462,10 +497,11 @@ function recordAnthropicNonStreamUsage(recorder, bodyText, attribution) {
|
|
|
462
497
|
sessionId: attribution.sessionId,
|
|
463
498
|
providerId: attribution.providerId,
|
|
464
499
|
model: attribution.model,
|
|
465
|
-
apiKeyId:
|
|
500
|
+
apiKeyId: attribution.apiKeyId,
|
|
466
501
|
engineOrigin: "codex-ingress",
|
|
467
502
|
usage: tapped,
|
|
468
|
-
rawUsage: parsed.usage
|
|
503
|
+
rawUsage: parsed.usage,
|
|
504
|
+
auditResponse: attribution.auditResponse
|
|
469
505
|
});
|
|
470
506
|
} catch (e4) {
|
|
471
507
|
}
|
|
@@ -481,7 +517,7 @@ function getSharedExecutor() {
|
|
|
481
517
|
}
|
|
482
518
|
var sharedResponses = null;
|
|
483
519
|
function getResponsesEndpointTransformer() {
|
|
484
|
-
if (!sharedResponses) sharedResponses = new (0,
|
|
520
|
+
if (!sharedResponses) sharedResponses = new (0, _chunkSU2GCLACcjs.OpenAIResponseTransformer)();
|
|
485
521
|
return sharedResponses;
|
|
486
522
|
}
|
|
487
523
|
var sharedAnthropic = null;
|
|
@@ -502,7 +538,84 @@ function readBody(req) {
|
|
|
502
538
|
req.on("error", reject);
|
|
503
539
|
});
|
|
504
540
|
}
|
|
505
|
-
|
|
541
|
+
function rewriteJsonModel(bodyText, rewriteModel) {
|
|
542
|
+
try {
|
|
543
|
+
const obj = JSON.parse(bodyText);
|
|
544
|
+
if (!obj || typeof obj !== "object") return bodyText;
|
|
545
|
+
let changed = false;
|
|
546
|
+
if (typeof obj.model === "string") {
|
|
547
|
+
obj.model = rewriteModel;
|
|
548
|
+
changed = true;
|
|
549
|
+
}
|
|
550
|
+
const nested = obj.response;
|
|
551
|
+
if (nested && typeof nested === "object" && typeof nested.model === "string") {
|
|
552
|
+
nested.model = rewriteModel;
|
|
553
|
+
changed = true;
|
|
554
|
+
}
|
|
555
|
+
return changed ? JSON.stringify(obj) : bodyText;
|
|
556
|
+
} catch (e5) {
|
|
557
|
+
return bodyText;
|
|
558
|
+
}
|
|
559
|
+
}
|
|
560
|
+
function rewriteSseLine(line, rewriteModel) {
|
|
561
|
+
if (!line.startsWith("data:") || !line.includes('"model"')) return line;
|
|
562
|
+
const nl = /\r?\n$/.exec(line);
|
|
563
|
+
const newline = nl ? nl[0] : "";
|
|
564
|
+
const withoutNl = newline ? line.slice(0, line.length - newline.length) : line;
|
|
565
|
+
const afterData = withoutNl.slice("data:".length);
|
|
566
|
+
const leadingSpace = afterData.startsWith(" ") ? " " : "";
|
|
567
|
+
const payload = afterData.slice(leadingSpace.length);
|
|
568
|
+
if (payload === "" || payload === "[DONE]") return line;
|
|
569
|
+
try {
|
|
570
|
+
const obj = JSON.parse(payload);
|
|
571
|
+
if (!obj || typeof obj !== "object") return line;
|
|
572
|
+
const type = typeof obj.type === "string" ? obj.type : "";
|
|
573
|
+
let changed = false;
|
|
574
|
+
if (type === "message_start") {
|
|
575
|
+
const message = obj.message;
|
|
576
|
+
if (message && typeof message === "object" && typeof message.model === "string") {
|
|
577
|
+
message.model = rewriteModel;
|
|
578
|
+
changed = true;
|
|
579
|
+
}
|
|
580
|
+
} else if (type === "response.created" || type === "response.in_progress" || type === "response.completed" || type === "response.failed" || type === "response.incomplete") {
|
|
581
|
+
const response = obj.response;
|
|
582
|
+
if (response && typeof response === "object" && typeof response.model === "string") {
|
|
583
|
+
response.model = rewriteModel;
|
|
584
|
+
changed = true;
|
|
585
|
+
}
|
|
586
|
+
}
|
|
587
|
+
if (!changed) return line;
|
|
588
|
+
return `data:${leadingSpace}${JSON.stringify(obj)}${newline}`;
|
|
589
|
+
} catch (e6) {
|
|
590
|
+
return line;
|
|
591
|
+
}
|
|
592
|
+
}
|
|
593
|
+
async function relayStreamWithModelRewrite(res, body, rewriteModel) {
|
|
594
|
+
const reader = body.getReader();
|
|
595
|
+
const decoder = new TextDecoder();
|
|
596
|
+
let buffer = "";
|
|
597
|
+
try {
|
|
598
|
+
for (; ; ) {
|
|
599
|
+
const { done, value } = await reader.read();
|
|
600
|
+
if (done) break;
|
|
601
|
+
buffer += decoder.decode(value, { stream: true });
|
|
602
|
+
let out = "";
|
|
603
|
+
let nlIndex;
|
|
604
|
+
while ((nlIndex = buffer.indexOf("\n")) !== -1) {
|
|
605
|
+
const linePart = buffer.slice(0, nlIndex + 1);
|
|
606
|
+
buffer = buffer.slice(nlIndex + 1);
|
|
607
|
+
out += rewriteSseLine(linePart, rewriteModel);
|
|
608
|
+
}
|
|
609
|
+
if (out) res.write(out);
|
|
610
|
+
}
|
|
611
|
+
const tail = buffer + decoder.decode();
|
|
612
|
+
if (tail) res.write(rewriteSseLine(tail, rewriteModel));
|
|
613
|
+
} finally {
|
|
614
|
+
reader.releaseLock();
|
|
615
|
+
res.end();
|
|
616
|
+
}
|
|
617
|
+
}
|
|
618
|
+
async function relayResponse(res, providerResponse, isStream, rewriteModel) {
|
|
506
619
|
const contentType = _nullishCoalesce(providerResponse.headers.get("Content-Type"), () => ( ""));
|
|
507
620
|
const status = providerResponse.status && providerResponse.status >= 100 ? providerResponse.status : 200;
|
|
508
621
|
if (isStream || contentType.includes("text/event-stream")) {
|
|
@@ -515,6 +628,10 @@ async function relayResponse(res, providerResponse, isStream) {
|
|
|
515
628
|
res.end();
|
|
516
629
|
return null;
|
|
517
630
|
}
|
|
631
|
+
if (rewriteModel) {
|
|
632
|
+
await relayStreamWithModelRewrite(res, providerResponse.body, rewriteModel);
|
|
633
|
+
return null;
|
|
634
|
+
}
|
|
518
635
|
const reader = providerResponse.body.getReader();
|
|
519
636
|
try {
|
|
520
637
|
for (; ; ) {
|
|
@@ -529,8 +646,9 @@ async function relayResponse(res, providerResponse, isStream) {
|
|
|
529
646
|
return null;
|
|
530
647
|
}
|
|
531
648
|
const bodyText = await providerResponse.text();
|
|
649
|
+
const clientText = rewriteModel ? rewriteJsonModel(bodyText, rewriteModel) : bodyText;
|
|
532
650
|
res.writeHead(status, { "Content-Type": contentType.includes("json") ? contentType : "application/json" });
|
|
533
|
-
res.end(
|
|
651
|
+
res.end(clientText);
|
|
534
652
|
return bodyText;
|
|
535
653
|
}
|
|
536
654
|
function writeError(res, status, message) {
|
|
@@ -568,17 +686,18 @@ async function buildSubscriptionPlan(res, route, deps, anthropicBody, routeModel
|
|
|
568
686
|
resolvedModel = mapped.resolvedModel;
|
|
569
687
|
scenario = mapped.scenario;
|
|
570
688
|
}
|
|
571
|
-
const
|
|
689
|
+
const sessionKey = _chunkQWBWGODScjs.deriveSubscriptionSessionKey.call(void 0, anthropicBody);
|
|
690
|
+
const plan = buildSubscriptionIterationPlan(profile, route, deps, resolvedModel, isStream, scenario, sessionKey);
|
|
572
691
|
if (!plan) {
|
|
573
692
|
writeError(res, 502, "Subscription profile is missing resolveUpstreamUrl");
|
|
574
693
|
return null;
|
|
575
694
|
}
|
|
576
695
|
return plan;
|
|
577
696
|
}
|
|
578
|
-
function buildSubscriptionIterationPlan(profile, route, deps, resolvedModel, isStream, scenario) {
|
|
697
|
+
function buildSubscriptionIterationPlan(profile, route, deps, resolvedModel, isStream, scenario, sessionKey) {
|
|
579
698
|
const upstreamUrl = _optionalChain([profile, 'access', _8 => _8.resolveUpstreamUrl, 'optionalCall', _9 => _9(resolvedModel, route.subscriptionConfig)]);
|
|
580
699
|
if (!upstreamUrl) return null;
|
|
581
|
-
const auth = _nullishCoalesce(route.auth, () => ( new (0,
|
|
700
|
+
const auth = _nullishCoalesce(route.auth, () => ( new (0, _chunkKFI44N2Rcjs.SubscriptionAuthSource)(profile)));
|
|
582
701
|
const sameFormat = profile.mode === "pass-through" || upstreamUrl.endsWith("/v1/messages");
|
|
583
702
|
const overrideNames = _optionalChain([profile, 'access', _10 => _10.resolveProviderTransformerNames, 'optionalCall', _11 => _11(
|
|
584
703
|
resolvedModel,
|
|
@@ -598,6 +717,7 @@ function buildSubscriptionIterationPlan(profile, route, deps, resolvedModel, isS
|
|
|
598
717
|
};
|
|
599
718
|
return {
|
|
600
719
|
auth,
|
|
720
|
+
preferredAccountId: route.preferredAccountId,
|
|
601
721
|
chain,
|
|
602
722
|
transformerProvider,
|
|
603
723
|
resolvedModel,
|
|
@@ -622,7 +742,8 @@ function buildSubscriptionIterationPlan(profile, route, deps, resolvedModel, isS
|
|
|
622
742
|
upstreamUrl,
|
|
623
743
|
sameFormat,
|
|
624
744
|
isSubscription: true,
|
|
625
|
-
scenario
|
|
745
|
+
scenario,
|
|
746
|
+
sessionKey
|
|
626
747
|
};
|
|
627
748
|
}
|
|
628
749
|
function usesResponsesChain(names) {
|
|
@@ -641,7 +762,7 @@ function buildSubscriptionRequestSummary(anthropicBody) {
|
|
|
641
762
|
estimatedInputTokens: Math.ceil(totalChars / 4),
|
|
642
763
|
// Single source of truth (shared with the dispatcher builder) so both
|
|
643
764
|
// ingress paths yield identical `matchText` for the same body.
|
|
644
|
-
matchText:
|
|
765
|
+
matchText: _chunkQWBWGODScjs.collectMatchText.call(void 0, anthropicBody)
|
|
645
766
|
};
|
|
646
767
|
}
|
|
647
768
|
function collectText(value) {
|
|
@@ -657,14 +778,27 @@ function collectText(value) {
|
|
|
657
778
|
}
|
|
658
779
|
return 0;
|
|
659
780
|
}
|
|
660
|
-
|
|
781
|
+
function proxyProviderId(plan) {
|
|
782
|
+
return plan.isSubscription ? plan.transformerProvider.name : "byo";
|
|
783
|
+
}
|
|
784
|
+
async function runPipeline(anthropicBody, plan, reportSelection) {
|
|
661
785
|
const executor = getSharedExecutor();
|
|
662
786
|
const endpointTransformer = getAnthropicEndpointTransformer();
|
|
663
787
|
const { auth, chain, transformerProvider, resolvedModel, isStream, resolveUrl, upstreamUrl } = plan;
|
|
788
|
+
let proxyAccountId;
|
|
664
789
|
const authHeaders = {};
|
|
665
|
-
await auth.applyHeaders(authHeaders, {
|
|
790
|
+
await auth.applyHeaders(authHeaders, {
|
|
791
|
+
upstreamUrl,
|
|
792
|
+
model: resolvedModel,
|
|
793
|
+
sessionKey: plan.sessionKey,
|
|
794
|
+
preferredAccountId: plan.preferredAccountId,
|
|
795
|
+
reportSelection: (accountId, isActive) => {
|
|
796
|
+
proxyAccountId = accountId;
|
|
797
|
+
_optionalChain([reportSelection, 'optionalCall', _12 => _12(accountId, isActive)]);
|
|
798
|
+
}
|
|
799
|
+
});
|
|
666
800
|
let rawStatus = null;
|
|
667
|
-
const { response } = await
|
|
801
|
+
const { response } = await _chunkHYN75H6Gcjs.executeProviderCall.call(void 0, {
|
|
668
802
|
executor,
|
|
669
803
|
request: anthropicBody,
|
|
670
804
|
provider: transformerProvider,
|
|
@@ -682,7 +816,11 @@ async function runPipeline(anthropicBody, plan) {
|
|
|
682
816
|
},
|
|
683
817
|
fetchFn: (url, headers, body) => {
|
|
684
818
|
console.info(`[ProviderProxy:anthropic] -> ${url} model=${resolvedModel} stream=${isStream}`);
|
|
685
|
-
return
|
|
819
|
+
return _chunkOCEUVQHWcjs.fetchUpstream.call(void 0,
|
|
820
|
+
url,
|
|
821
|
+
{ method: "POST", headers, body: JSON.stringify(body) },
|
|
822
|
+
{ providerId: proxyProviderId(plan), accountId: proxyAccountId }
|
|
823
|
+
).then((r) => {
|
|
686
824
|
rawStatus = r.status;
|
|
687
825
|
return r;
|
|
688
826
|
});
|
|
@@ -691,29 +829,96 @@ async function runPipeline(anthropicBody, plan) {
|
|
|
691
829
|
});
|
|
692
830
|
return { response, rawStatus };
|
|
693
831
|
}
|
|
694
|
-
async function runSubscriptionSameFormatFetch(rawBody, plan) {
|
|
832
|
+
async function runSubscriptionSameFormatFetch(rawBody, plan, reportSelection, options = {}) {
|
|
833
|
+
let proxyAccountId;
|
|
834
|
+
let remappedModel;
|
|
695
835
|
const headers = { "content-type": "application/json" };
|
|
696
836
|
await plan.auth.applyHeaders(headers, {
|
|
697
837
|
upstreamUrl: plan.upstreamUrl,
|
|
698
|
-
model: plan.resolvedModel
|
|
838
|
+
model: plan.resolvedModel,
|
|
839
|
+
sessionKey: plan.sessionKey,
|
|
840
|
+
preferredAccountId: plan.preferredAccountId,
|
|
841
|
+
reportSelection: (accountId, isActive, remapped) => {
|
|
842
|
+
proxyAccountId = accountId;
|
|
843
|
+
remappedModel = remapped;
|
|
844
|
+
_optionalChain([reportSelection, 'optionalCall', _13 => _13(accountId, isActive, remapped)]);
|
|
845
|
+
}
|
|
699
846
|
});
|
|
847
|
+
if (plan.isSubscription && plan.transformerProvider.name === "claude") {
|
|
848
|
+
_chunk6RPZADX3cjs.applyFingerprint.call(void 0,
|
|
849
|
+
_chunkRPII3E6Zcjs.getSharedIdentityStore.call(void 0, ),
|
|
850
|
+
headers,
|
|
851
|
+
plan.transformerProvider.name,
|
|
852
|
+
proxyAccountId,
|
|
853
|
+
options.callerIdentity
|
|
854
|
+
);
|
|
855
|
+
}
|
|
856
|
+
const applyRemap = remappedModel !== void 0 && outboundRemapApplies(plan);
|
|
857
|
+
const outboundBody = applyRemap ? rewriteBodyModel(rawBody, remappedModel) : rawBody;
|
|
858
|
+
const outboundModel = applyRemap ? remappedModel : plan.resolvedModel;
|
|
700
859
|
console.info(
|
|
701
|
-
`[ProviderProxy:anthropic] (subscription same-format) -> ${plan.upstreamUrl} model=${
|
|
860
|
+
`[ProviderProxy:anthropic] (subscription same-format) -> ${plan.upstreamUrl} model=${outboundModel} stream=${plan.isStream}`
|
|
861
|
+
);
|
|
862
|
+
const response = await _chunkOCEUVQHWcjs.fetchUpstream.call(void 0,
|
|
863
|
+
plan.upstreamUrl,
|
|
864
|
+
{ method: "POST", headers, body: outboundBody },
|
|
865
|
+
{ providerId: proxyProviderId(plan), accountId: proxyAccountId }
|
|
702
866
|
);
|
|
703
|
-
const response = await fetch(plan.upstreamUrl, { method: "POST", headers, body: rawBody });
|
|
704
867
|
return { response, rawStatus: response.status };
|
|
705
868
|
}
|
|
706
|
-
|
|
707
|
-
|
|
869
|
+
function outboundRemapApplies(plan) {
|
|
870
|
+
return plan.isSubscription && plan.transformerProvider.name === "claude";
|
|
871
|
+
}
|
|
872
|
+
function rewriteBodyModel(rawBody, model) {
|
|
873
|
+
try {
|
|
874
|
+
const parsed = JSON.parse(rawBody);
|
|
875
|
+
if (!parsed || typeof parsed !== "object" || Array.isArray(parsed)) return rawBody;
|
|
876
|
+
parsed.model = model;
|
|
877
|
+
return JSON.stringify(parsed);
|
|
878
|
+
} catch (e7) {
|
|
879
|
+
return rawBody;
|
|
880
|
+
}
|
|
881
|
+
}
|
|
882
|
+
async function runSubscriptionAttemptWith401Retry(anthropicBody, relayBody, plan, options = {}) {
|
|
883
|
+
let selectedAccountId;
|
|
884
|
+
const reportSelection = (accountId) => {
|
|
885
|
+
selectedAccountId = accountId;
|
|
886
|
+
};
|
|
887
|
+
const runOnce = () => plan.sameFormat ? runSubscriptionSameFormatFetch(relayBody, plan, reportSelection, options) : runPipeline(anthropicBody, plan, reportSelection);
|
|
708
888
|
const first = await runOnce();
|
|
709
|
-
|
|
710
|
-
|
|
711
|
-
|
|
712
|
-
|
|
713
|
-
|
|
889
|
+
let result = first;
|
|
890
|
+
if (first.rawStatus === 401) {
|
|
891
|
+
const refreshed = await _optionalChain([plan, 'access', _14 => _14.auth, 'access', _15 => _15.onUnauthorized, 'optionalCall', _16 => _16(plan.sessionKey)]);
|
|
892
|
+
if (refreshed) {
|
|
893
|
+
console.info("[ProviderProxy:anthropic] 401 \u2192 token refreshed; retrying once");
|
|
894
|
+
result = await runOnce();
|
|
895
|
+
} else {
|
|
896
|
+
console.warn("[ProviderProxy:anthropic] 401 not recoverable (onUnauthorized returned false)");
|
|
897
|
+
}
|
|
714
898
|
}
|
|
715
|
-
|
|
716
|
-
return
|
|
899
|
+
await markSubscriptionHealth(plan, selectedAccountId, result);
|
|
900
|
+
return result;
|
|
901
|
+
}
|
|
902
|
+
async function readBoundedBody(response, max = 2048) {
|
|
903
|
+
try {
|
|
904
|
+
const text = await response.clone().text();
|
|
905
|
+
return text.slice(0, max);
|
|
906
|
+
} catch (e8) {
|
|
907
|
+
return void 0;
|
|
908
|
+
}
|
|
909
|
+
}
|
|
910
|
+
async function markSubscriptionHealth(plan, selectedAccountId, result) {
|
|
911
|
+
if (!plan.isSubscription || selectedAccountId === void 0) return;
|
|
912
|
+
const providerId = plan.transformerProvider.name;
|
|
913
|
+
const status = result.rawStatus;
|
|
914
|
+
const { resetHeaderSeconds, retryAfterSeconds } = _chunkVQY5W4YWcjs.resolveResetSeconds.call(void 0, providerId, result.response.headers);
|
|
915
|
+
const bodyText = status === 403 ? await readBoundedBody(result.response) : void 0;
|
|
916
|
+
_chunkVQY5W4YWcjs.getSharedAccountHealth.call(void 0, ).recordUpstreamOutcome(providerId, selectedAccountId, {
|
|
917
|
+
status,
|
|
918
|
+
resetHeaderSeconds,
|
|
919
|
+
retryAfterSeconds,
|
|
920
|
+
bodyText
|
|
921
|
+
});
|
|
717
922
|
}
|
|
718
923
|
function isFallbackEligibleStatus(rawStatus) {
|
|
719
924
|
return rawStatus === null || rawStatus >= 500 || rawStatus === 429;
|
|
@@ -726,11 +931,11 @@ function breakerOutcome(rawStatus) {
|
|
|
726
931
|
function recordBreakerOutcome(profile, modelId, rawStatus) {
|
|
727
932
|
const outcome = breakerOutcome(rawStatus);
|
|
728
933
|
if (outcome === "neutral") return;
|
|
729
|
-
_optionalChain([profile, 'optionalAccess',
|
|
934
|
+
_optionalChain([profile, 'optionalAccess', _17 => _17.recordModelOutcome, 'optionalCall', _18 => _18(modelId, outcome === "success")]);
|
|
730
935
|
}
|
|
731
|
-
async function runSubscriptionAttemptOutcome(anthropicBody, relayBody, plan) {
|
|
936
|
+
async function runSubscriptionAttemptOutcome(anthropicBody, relayBody, plan, options = {}) {
|
|
732
937
|
try {
|
|
733
|
-
return { kind: "result", result: await runSubscriptionAttemptWith401Retry(anthropicBody, relayBody, plan) };
|
|
938
|
+
return { kind: "result", result: await runSubscriptionAttemptWith401Retry(anthropicBody, relayBody, plan, options) };
|
|
734
939
|
} catch (error) {
|
|
735
940
|
return { kind: "thrown", error };
|
|
736
941
|
}
|
|
@@ -742,11 +947,11 @@ function settleOutcome(outcome) {
|
|
|
742
947
|
if (outcome.kind === "thrown") throw outcome.error;
|
|
743
948
|
return outcome.result;
|
|
744
949
|
}
|
|
745
|
-
async function runPipelineWithSubscriptionRetry(anthropicBody, rawBody, initialPlan, route, deps) {
|
|
950
|
+
async function runPipelineWithSubscriptionRetry(anthropicBody, rawBody, initialPlan, route, deps, options = {}) {
|
|
746
951
|
const profile = route.subscriptionProfile;
|
|
747
952
|
const scenario = initialPlan.scenario;
|
|
748
|
-
if (!_optionalChain([profile, 'optionalAccess',
|
|
749
|
-
const loneOutcome = await runSubscriptionAttemptOutcome(anthropicBody, rawBody, initialPlan);
|
|
953
|
+
if (!_optionalChain([profile, 'optionalAccess', _19 => _19.nextFallback]) || scenario === void 0) {
|
|
954
|
+
const loneOutcome = await runSubscriptionAttemptOutcome(anthropicBody, rawBody, initialPlan, options);
|
|
750
955
|
recordBreakerOutcome(profile, initialPlan.resolvedModel, outcomeStatus(loneOutcome));
|
|
751
956
|
return settleOutcome(loneOutcome);
|
|
752
957
|
}
|
|
@@ -757,7 +962,7 @@ async function runPipelineWithSubscriptionRetry(anthropicBody, rawBody, initialP
|
|
|
757
962
|
if (profile.allowModel && !profile.allowModel(initialPlan.resolvedModel)) {
|
|
758
963
|
attempted.push(initialPlan.resolvedModel);
|
|
759
964
|
const firstAdmitting = profile.nextFallback(scenario, attempted, route.subscriptionConfig);
|
|
760
|
-
const gatedPlan = firstAdmitting ? buildSubscriptionIterationPlan(profile, route, deps, firstAdmitting.modelId, initialPlan.isStream, scenario) : null;
|
|
965
|
+
const gatedPlan = firstAdmitting ? buildSubscriptionIterationPlan(profile, route, deps, firstAdmitting.modelId, initialPlan.isStream, scenario, initialPlan.sessionKey) : null;
|
|
761
966
|
if (firstAdmitting && gatedPlan) {
|
|
762
967
|
console.warn(
|
|
763
968
|
`[ProviderProxy:anthropic] subscription primary ${initialPlan.resolvedModel} circuit open -> first admitting fallback ${firstAdmitting.modelId}`
|
|
@@ -772,7 +977,7 @@ async function runPipelineWithSubscriptionRetry(anthropicBody, rawBody, initialP
|
|
|
772
977
|
);
|
|
773
978
|
}
|
|
774
979
|
}
|
|
775
|
-
let outcome = await runSubscriptionAttemptOutcome(firstBodyObj, firstRelayBody, plan);
|
|
980
|
+
let outcome = await runSubscriptionAttemptOutcome(firstBodyObj, firstRelayBody, plan, options);
|
|
776
981
|
recordBreakerOutcome(profile, plan.resolvedModel, outcomeStatus(outcome));
|
|
777
982
|
if (!attempted.includes(plan.resolvedModel)) attempted.push(plan.resolvedModel);
|
|
778
983
|
while (attempted.length < MAX_FALLBACK_ATTEMPTS) {
|
|
@@ -785,7 +990,8 @@ async function runPipelineWithSubscriptionRetry(anthropicBody, rawBody, initialP
|
|
|
785
990
|
deps,
|
|
786
991
|
next.modelId,
|
|
787
992
|
plan.isStream,
|
|
788
|
-
scenario
|
|
993
|
+
scenario,
|
|
994
|
+
initialPlan.sessionKey
|
|
789
995
|
);
|
|
790
996
|
if (!nextPlan) return settleOutcome(outcome);
|
|
791
997
|
const sinceLabel = outcome.kind === "thrown" ? "thrown error" : `status ${String(outcome.result.rawStatus)}`;
|
|
@@ -796,7 +1002,7 @@ async function runPipelineWithSubscriptionRetry(anthropicBody, rawBody, initialP
|
|
|
796
1002
|
const fallbackRelayBody = nextPlan.sameFormat ? JSON.stringify(fallbackBodyObj) : rawBody;
|
|
797
1003
|
plan = nextPlan;
|
|
798
1004
|
attempted.push(next.modelId);
|
|
799
|
-
outcome = await runSubscriptionAttemptOutcome(fallbackBodyObj, fallbackRelayBody, plan);
|
|
1005
|
+
outcome = await runSubscriptionAttemptOutcome(fallbackBodyObj, fallbackRelayBody, plan, options);
|
|
800
1006
|
recordBreakerOutcome(profile, plan.resolvedModel, outcomeStatus(outcome));
|
|
801
1007
|
}
|
|
802
1008
|
return settleOutcome(outcome);
|
|
@@ -808,7 +1014,7 @@ async function handleAnthropicMessagesByo(res, rawBody, route, deps, options = {
|
|
|
808
1014
|
let anthropicBody;
|
|
809
1015
|
try {
|
|
810
1016
|
anthropicBody = JSON.parse(rawBody);
|
|
811
|
-
} catch (
|
|
1017
|
+
} catch (e9) {
|
|
812
1018
|
writeError(res, 400, "Invalid JSON in request body");
|
|
813
1019
|
return;
|
|
814
1020
|
}
|
|
@@ -819,13 +1025,16 @@ async function handleAnthropicMessagesByo(res, rawBody, route, deps, options = {
|
|
|
819
1025
|
const plan = route.authMode === "subscription" ? await buildSubscriptionPlan(res, route, deps, anthropicBody, resolvedModel, isStream) : await buildByoPlan(res, route, deps, resolvedModel, isStream);
|
|
820
1026
|
if (!plan) return;
|
|
821
1027
|
anthropicBody.model = plan.resolvedModel;
|
|
822
|
-
const providerResponse = route.authMode === "subscription" ? await runPipelineWithSubscriptionRetry(anthropicBody, rawBody, plan, route, deps) : await runPipelineWithPoolReporting(anthropicBody, rawBody, plan, options);
|
|
823
|
-
const bodyText = await relayResponse(res, providerResponse.response, isStream);
|
|
1028
|
+
const providerResponse = route.authMode === "subscription" ? await runPipelineWithSubscriptionRetry(anthropicBody, rawBody, plan, route, deps, options) : await runPipelineWithPoolReporting(anthropicBody, rawBody, plan, options);
|
|
1029
|
+
const bodyText = await relayResponse(res, providerResponse.response, isStream, route.requestedModel);
|
|
824
1030
|
if (bodyText && deps.usageRecorder) {
|
|
825
1031
|
recordAnthropicNonStreamUsage(deps.usageRecorder, bodyText, {
|
|
826
1032
|
sessionId: route.sessionId,
|
|
827
1033
|
providerId: _nullishCoalesce(route.providerId, () => ( "anthropic")),
|
|
828
|
-
model: plan.resolvedModel
|
|
1034
|
+
model: plan.resolvedModel,
|
|
1035
|
+
apiKeyId: _nullishCoalesce(route.apiKeyId, () => ( null)),
|
|
1036
|
+
// request-audit-log: correlate this request's tokens/cost to its audit record.
|
|
1037
|
+
auditResponse: res
|
|
829
1038
|
});
|
|
830
1039
|
}
|
|
831
1040
|
} catch (err) {
|
|
@@ -850,7 +1059,7 @@ async function buildByoPlan(res, route, deps, resolvedModel, isStream) {
|
|
|
850
1059
|
writeError(res, 502, "API key not configured");
|
|
851
1060
|
return null;
|
|
852
1061
|
}
|
|
853
|
-
const auth = _nullishCoalesce(route.auth, () => ( new (0,
|
|
1062
|
+
const auth = _nullishCoalesce(route.auth, () => ( new (0, _chunkQ27JY5RGcjs.LlmConfigProviderAuth)({
|
|
854
1063
|
provider,
|
|
855
1064
|
apiKey,
|
|
856
1065
|
apiKeyPool: _nullishCoalesce(deps.apiKeyPool, () => ( null)),
|
|
@@ -878,17 +1087,17 @@ async function buildByoPlan(res, route, deps, resolvedModel, isStream) {
|
|
|
878
1087
|
isSubscription: false,
|
|
879
1088
|
provider,
|
|
880
1089
|
apiKey,
|
|
881
|
-
extendedContextEnabled: _nullishCoalesce(_optionalChain([route, 'access',
|
|
1090
|
+
extendedContextEnabled: _nullishCoalesce(_optionalChain([route, 'access', _20 => _20.anthropicSdkHints, 'optionalAccess', _21 => _21.extendedContext, 'optionalAccess', _22 => _22.enabled]), () => ( false))
|
|
882
1091
|
};
|
|
883
1092
|
}
|
|
884
|
-
async function runSameFormatFetch(
|
|
1093
|
+
async function runSameFormatFetch(bodyToSend, plan, options, keyOverride) {
|
|
885
1094
|
const { provider, apiKey, resolvedModel, isStream, extendedContextEnabled } = plan;
|
|
886
1095
|
if (!provider) {
|
|
887
1096
|
throw new Error("[ProviderProxy:anthropic] same-format BYO path requires a provider row");
|
|
888
1097
|
}
|
|
889
1098
|
const effectiveKey = _nullishCoalesce(_nullishCoalesce(keyOverride, () => ( apiKey)), () => ( ""));
|
|
890
|
-
const headers =
|
|
891
|
-
const callerBeta = _optionalChain([options, 'access',
|
|
1099
|
+
const headers = _chunkQ27JY5RGcjs.getProviderHeaders.call(void 0, provider, effectiveKey);
|
|
1100
|
+
const callerBeta = _optionalChain([options, 'access', _23 => _23.callerAnthropicBeta, 'optionalAccess', _24 => _24.trim, 'call', _25 => _25()]);
|
|
892
1101
|
if (callerBeta) {
|
|
893
1102
|
const existing = _nullishCoalesce(headers["anthropic-beta"], () => ( headers["Anthropic-Beta"]));
|
|
894
1103
|
const parts = new Set(
|
|
@@ -902,14 +1111,29 @@ async function runSameFormatFetch(rawBody, plan, options, keyOverride) {
|
|
|
902
1111
|
_chunkGBHYAGX3cjs.injectExtendedContextBeta.call(void 0, headers, resolvedModel, _nullishCoalesce(extendedContextEnabled, () => ( false)));
|
|
903
1112
|
const url = _chunkA2YMUCBTcjs.buildProviderApiUrl.call(void 0, provider, { model: resolvedModel, stream: isStream });
|
|
904
1113
|
console.info(`[ProviderProxy:anthropic] (same-format) -> ${url} model=${resolvedModel} stream=${isStream}`);
|
|
905
|
-
const response = await
|
|
1114
|
+
const response = await _chunkOCEUVQHWcjs.fetchUpstream.call(void 0,
|
|
1115
|
+
url,
|
|
1116
|
+
{ method: "POST", headers, body: bodyToSend },
|
|
1117
|
+
{ providerId: "byo" }
|
|
1118
|
+
);
|
|
906
1119
|
return { response, rawStatus: response.status };
|
|
907
1120
|
}
|
|
1121
|
+
function resolveSameFormatBody(anthropicBody, rawBody, plan) {
|
|
1122
|
+
let originalModel;
|
|
1123
|
+
try {
|
|
1124
|
+
const m = JSON.parse(rawBody).model;
|
|
1125
|
+
originalModel = typeof m === "string" ? m : void 0;
|
|
1126
|
+
} catch (e10) {
|
|
1127
|
+
originalModel = void 0;
|
|
1128
|
+
}
|
|
1129
|
+
return plan.resolvedModel !== originalModel ? JSON.stringify(anthropicBody) : rawBody;
|
|
1130
|
+
}
|
|
908
1131
|
async function runPipelineWithPoolReporting(anthropicBody, rawBody, plan, options) {
|
|
909
|
-
const
|
|
1132
|
+
const sameFormatBody = plan.sameFormat ? resolveSameFormatBody(anthropicBody, rawBody, plan) : rawBody;
|
|
1133
|
+
const runOnce = (keyOverride) => plan.sameFormat ? runSameFormatFetch(sameFormatBody, plan, options, keyOverride) : runPipeline(anthropicBody, plan);
|
|
910
1134
|
const first = await runOnce();
|
|
911
|
-
const outcome = await _optionalChain([plan, 'access',
|
|
912
|
-
if (_optionalChain([outcome, 'optionalAccess',
|
|
1135
|
+
const outcome = await _optionalChain([plan, 'access', _26 => _26.auth, 'access', _27 => _27.onResult, 'optionalCall', _28 => _28(first.rawStatus)]);
|
|
1136
|
+
if (_optionalChain([outcome, 'optionalAccess', _29 => _29.rebound])) {
|
|
913
1137
|
console.info(
|
|
914
1138
|
"[ProviderProxy:anthropic] pool re-bound key after status",
|
|
915
1139
|
first.rawStatus,
|
|
@@ -930,7 +1154,8 @@ async function handleAnthropicMessagesRequest(req, res, route, deps) {
|
|
|
930
1154
|
const rawBody = await readBody(req);
|
|
931
1155
|
const callerBetaRaw = req.headers["anthropic-beta"];
|
|
932
1156
|
const callerAnthropicBeta = Array.isArray(callerBetaRaw) ? callerBetaRaw.join(",") : callerBetaRaw;
|
|
933
|
-
|
|
1157
|
+
const callerIdentity = _chunk6RPZADX3cjs.captureCallerIdentity.call(void 0, _chunkRPII3E6Zcjs.getSharedIdentityStore.call(void 0, ), req.headers);
|
|
1158
|
+
await handleAnthropicMessagesByo(res, rawBody, route, deps, { callerAnthropicBeta, callerIdentity });
|
|
934
1159
|
return;
|
|
935
1160
|
}
|
|
936
1161
|
const hints = route.anthropicSdkHints;
|
|
@@ -992,12 +1217,13 @@ function recordGeminiNonStreamUsage(recorder, bodyText, attribution) {
|
|
|
992
1217
|
sessionId: attribution.sessionId,
|
|
993
1218
|
providerId: attribution.providerId,
|
|
994
1219
|
model: attribution.model,
|
|
995
|
-
apiKeyId:
|
|
1220
|
+
apiKeyId: attribution.apiKeyId,
|
|
1221
|
+
auditResponse: attribution.auditResponse,
|
|
996
1222
|
engineOrigin: "codex-ingress",
|
|
997
1223
|
usage: tapped,
|
|
998
1224
|
rawUsage: parsed.usageMetadata
|
|
999
1225
|
});
|
|
1000
|
-
} catch (
|
|
1226
|
+
} catch (e11) {
|
|
1001
1227
|
}
|
|
1002
1228
|
}
|
|
1003
1229
|
|
|
@@ -1006,14 +1232,14 @@ var GENERATE_CONTENT_ACTION = ":generateContent";
|
|
|
1006
1232
|
var STREAM_GENERATE_CONTENT_ACTION = ":streamGenerateContent";
|
|
1007
1233
|
function isGeminiGenerateContentRequest(method, url) {
|
|
1008
1234
|
if (method !== "POST" || !url) return false;
|
|
1009
|
-
const path = _nullishCoalesce(_optionalChain([url, 'access',
|
|
1235
|
+
const path = _nullishCoalesce(_optionalChain([url, 'access', _30 => _30.split, 'call', _31 => _31("?"), 'access', _32 => _32[0], 'optionalAccess', _33 => _33.replace, 'call', _34 => _34(/\/+$/, "")]), () => ( ""));
|
|
1010
1236
|
const lastSegment = _nullishCoalesce(path.split("/").pop(), () => ( ""));
|
|
1011
1237
|
return lastSegment.includes(STREAM_GENERATE_CONTENT_ACTION) || lastSegment.includes(GENERATE_CONTENT_ACTION);
|
|
1012
1238
|
}
|
|
1013
1239
|
function isGeminiStreamRequest(url) {
|
|
1014
1240
|
if (!url) return false;
|
|
1015
1241
|
const [path, query = ""] = url.split("?");
|
|
1016
|
-
const lastSegment = _nullishCoalesce((_nullishCoalesce(_optionalChain([path, 'optionalAccess',
|
|
1242
|
+
const lastSegment = _nullishCoalesce((_nullishCoalesce(_optionalChain([path, 'optionalAccess', _35 => _35.replace, 'call', _36 => _36(/\/+$/, "")]), () => ( ""))).split("/").pop(), () => ( ""));
|
|
1017
1243
|
if (lastSegment.includes(STREAM_GENERATE_CONTENT_ACTION)) return true;
|
|
1018
1244
|
return /(^|&)alt=sse(&|$)/.test(query);
|
|
1019
1245
|
}
|
|
@@ -1021,7 +1247,7 @@ async function handleGeminiGenerateContentRequest(res, rawBody, url, route, deps
|
|
|
1021
1247
|
let geminiBody;
|
|
1022
1248
|
try {
|
|
1023
1249
|
geminiBody = JSON.parse(rawBody);
|
|
1024
|
-
} catch (
|
|
1250
|
+
} catch (e12) {
|
|
1025
1251
|
writeError(res, 400, "Invalid JSON in request body");
|
|
1026
1252
|
return;
|
|
1027
1253
|
}
|
|
@@ -1042,7 +1268,10 @@ async function handleGeminiGenerateContentRequest(res, rawBody, url, route, deps
|
|
|
1042
1268
|
recordGeminiNonStreamUsage(deps.usageRecorder, bodyText, {
|
|
1043
1269
|
sessionId: route.sessionId,
|
|
1044
1270
|
providerId: _nullishCoalesce(route.providerId, () => ( "gemini")),
|
|
1045
|
-
model: resolvedModel
|
|
1271
|
+
model: resolvedModel,
|
|
1272
|
+
apiKeyId: _nullishCoalesce(route.apiKeyId, () => ( null)),
|
|
1273
|
+
// request-audit-log: correlate this request's tokens/cost to its audit record.
|
|
1274
|
+
auditResponse: res
|
|
1046
1275
|
});
|
|
1047
1276
|
}
|
|
1048
1277
|
} catch (err) {
|
|
@@ -1067,7 +1296,7 @@ async function buildByoPlan2(res, route, deps, resolvedModel, isStream) {
|
|
|
1067
1296
|
writeError(res, 502, "API key not configured");
|
|
1068
1297
|
return null;
|
|
1069
1298
|
}
|
|
1070
|
-
const auth = _nullishCoalesce(route.auth, () => ( new (0,
|
|
1299
|
+
const auth = _nullishCoalesce(route.auth, () => ( new (0, _chunkQ27JY5RGcjs.LlmConfigProviderAuth)({
|
|
1071
1300
|
provider,
|
|
1072
1301
|
apiKey,
|
|
1073
1302
|
apiKeyPool: _nullishCoalesce(deps.apiKeyPool, () => ( null)),
|
|
@@ -1099,7 +1328,7 @@ async function runPipeline2(geminiBody, plan) {
|
|
|
1099
1328
|
const authHeaders = {};
|
|
1100
1329
|
await auth.applyHeaders(authHeaders, { upstreamUrl, model: resolvedModel });
|
|
1101
1330
|
let rawStatus = null;
|
|
1102
|
-
const { response } = await
|
|
1331
|
+
const { response } = await _chunkHYN75H6Gcjs.executeProviderCall.call(void 0, {
|
|
1103
1332
|
executor,
|
|
1104
1333
|
request: geminiBody,
|
|
1105
1334
|
provider: transformerProvider,
|
|
@@ -1117,7 +1346,11 @@ async function runPipeline2(geminiBody, plan) {
|
|
|
1117
1346
|
},
|
|
1118
1347
|
fetchFn: (url, headers, body) => {
|
|
1119
1348
|
console.log(`[ProviderProxy:gemini] -> ${url} model=${resolvedModel} stream=${isStream}`);
|
|
1120
|
-
return
|
|
1349
|
+
return _chunkOCEUVQHWcjs.fetchUpstream.call(void 0,
|
|
1350
|
+
url,
|
|
1351
|
+
{ method: "POST", headers, body: JSON.stringify(body) },
|
|
1352
|
+
{ providerId: "byo" }
|
|
1353
|
+
).then((r) => {
|
|
1121
1354
|
rawStatus = r.status;
|
|
1122
1355
|
return r;
|
|
1123
1356
|
});
|
|
@@ -1128,8 +1361,8 @@ async function runPipeline2(geminiBody, plan) {
|
|
|
1128
1361
|
}
|
|
1129
1362
|
async function runPipelineWithPoolReporting2(geminiBody, plan) {
|
|
1130
1363
|
const first = await runPipeline2(geminiBody, plan);
|
|
1131
|
-
const outcome = await _optionalChain([plan, 'access',
|
|
1132
|
-
if (_optionalChain([outcome, 'optionalAccess',
|
|
1364
|
+
const outcome = await _optionalChain([plan, 'access', _37 => _37.auth, 'access', _38 => _38.onResult, 'optionalCall', _39 => _39(first.rawStatus)]);
|
|
1365
|
+
if (_optionalChain([outcome, 'optionalAccess', _40 => _40.rebound])) {
|
|
1133
1366
|
console.log(
|
|
1134
1367
|
"[ProviderProxy:gemini] pool re-bound key after status",
|
|
1135
1368
|
first.rawStatus,
|
|
@@ -1169,46 +1402,48 @@ function recordChatCompletionsNonStreamUsage(recorder, bodyText, attribution) {
|
|
|
1169
1402
|
sessionId: attribution.sessionId,
|
|
1170
1403
|
providerId: attribution.providerId,
|
|
1171
1404
|
model: attribution.model,
|
|
1172
|
-
apiKeyId:
|
|
1405
|
+
apiKeyId: attribution.apiKeyId,
|
|
1406
|
+
auditResponse: attribution.auditResponse,
|
|
1173
1407
|
engineOrigin: "codex-ingress",
|
|
1174
1408
|
usage: tapped,
|
|
1175
1409
|
rawUsage: parsed.usage
|
|
1176
1410
|
});
|
|
1177
|
-
} catch (
|
|
1411
|
+
} catch (e13) {
|
|
1178
1412
|
}
|
|
1179
1413
|
}
|
|
1180
1414
|
|
|
1181
1415
|
// src/provider-proxy/ingress/openaiChatIngress.ts
|
|
1182
1416
|
function isOpenAIChatRequest(method, url) {
|
|
1183
1417
|
if (method !== "POST" || !url) return false;
|
|
1184
|
-
const path = _nullishCoalesce(_optionalChain([url, 'access',
|
|
1418
|
+
const path = _nullishCoalesce(_optionalChain([url, 'access', _41 => _41.split, 'call', _42 => _42("?"), 'access', _43 => _43[0], 'optionalAccess', _44 => _44.replace, 'call', _45 => _45(/\/+$/, "")]), () => ( ""));
|
|
1185
1419
|
return path.endsWith("/chat/completions");
|
|
1186
1420
|
}
|
|
1421
|
+
var CHAT_BRIDGE_SUBSCRIPTION_PROVIDERS = /* @__PURE__ */ new Set(["claude"]);
|
|
1422
|
+
var IDENTITY_ENDPOINT_TRANSFORMER = { name: "identity-openai-chat" };
|
|
1187
1423
|
async function handleOpenAIChatRequest(res, rawBody, route, deps) {
|
|
1188
1424
|
let chatBody;
|
|
1189
1425
|
try {
|
|
1190
1426
|
chatBody = JSON.parse(rawBody);
|
|
1191
|
-
} catch (
|
|
1427
|
+
} catch (e14) {
|
|
1192
1428
|
writeError(res, 400, "Invalid JSON in request body");
|
|
1193
1429
|
return;
|
|
1194
1430
|
}
|
|
1195
|
-
if (route.authMode === "subscription") {
|
|
1196
|
-
writeError(res, 502, "OpenAI Chat Completions ingress does not support subscription auth");
|
|
1197
|
-
return;
|
|
1198
|
-
}
|
|
1199
1431
|
const isStream = chatBody.stream === true;
|
|
1200
1432
|
const resolvedModel = route.model;
|
|
1201
1433
|
chatBody.model = resolvedModel;
|
|
1202
1434
|
try {
|
|
1203
|
-
const plan = await buildByoPlan3(res, route, deps, resolvedModel, isStream);
|
|
1435
|
+
const plan = route.authMode === "subscription" ? await buildSubscriptionPlan2(res, route, deps, resolvedModel, isStream) : await buildByoPlan3(res, route, deps, resolvedModel, isStream);
|
|
1204
1436
|
if (!plan) return;
|
|
1205
|
-
const providerResponse = await runPipelineWithPoolReporting3(chatBody, plan);
|
|
1437
|
+
const providerResponse = plan.isSubscription ? await runPipelineWithSubscriptionRetry2(chatBody, plan) : await runPipelineWithPoolReporting3(chatBody, plan);
|
|
1206
1438
|
const bodyText = await relayResponse(res, providerResponse.response, isStream);
|
|
1207
1439
|
if (bodyText && deps.usageRecorder) {
|
|
1208
1440
|
recordChatCompletionsNonStreamUsage(deps.usageRecorder, bodyText, {
|
|
1209
1441
|
sessionId: route.sessionId,
|
|
1210
1442
|
providerId: _nullishCoalesce(route.providerId, () => ( "openai")),
|
|
1211
|
-
model: resolvedModel
|
|
1443
|
+
model: resolvedModel,
|
|
1444
|
+
apiKeyId: _nullishCoalesce(route.apiKeyId, () => ( null)),
|
|
1445
|
+
// request-audit-log: correlate this request's tokens/cost to its audit record.
|
|
1446
|
+
auditResponse: res
|
|
1212
1447
|
});
|
|
1213
1448
|
}
|
|
1214
1449
|
} catch (err) {
|
|
@@ -1233,7 +1468,7 @@ async function buildByoPlan3(res, route, deps, resolvedModel, isStream) {
|
|
|
1233
1468
|
writeError(res, 502, "API key not configured");
|
|
1234
1469
|
return null;
|
|
1235
1470
|
}
|
|
1236
|
-
const auth = _nullishCoalesce(route.auth, () => ( new (0,
|
|
1471
|
+
const auth = _nullishCoalesce(route.auth, () => ( new (0, _chunkQ27JY5RGcjs.LlmConfigProviderAuth)({
|
|
1237
1472
|
provider,
|
|
1238
1473
|
apiKey,
|
|
1239
1474
|
apiKeyPool: _nullishCoalesce(deps.apiKeyPool, () => ( null)),
|
|
@@ -1255,16 +1490,69 @@ async function buildByoPlan3(res, route, deps, resolvedModel, isStream) {
|
|
|
1255
1490
|
resolvedModel,
|
|
1256
1491
|
isStream,
|
|
1257
1492
|
resolveUrl: (config) => config.url instanceof URL ? config.url.toString() : byoUrl,
|
|
1258
|
-
upstreamUrl: byoUrl
|
|
1493
|
+
upstreamUrl: byoUrl,
|
|
1494
|
+
proxyProviderId: "byo",
|
|
1495
|
+
isSubscription: false
|
|
1496
|
+
};
|
|
1497
|
+
}
|
|
1498
|
+
async function buildSubscriptionPlan2(res, route, deps, resolvedModel, isStream) {
|
|
1499
|
+
const profile = route.subscriptionProfile;
|
|
1500
|
+
if (!profile) {
|
|
1501
|
+
writeError(res, 502, "Subscription mode requires a subscription profile");
|
|
1502
|
+
return null;
|
|
1503
|
+
}
|
|
1504
|
+
const providerId = profile.authStrategy.providerId;
|
|
1505
|
+
if (!CHAT_BRIDGE_SUBSCRIPTION_PROVIDERS.has(providerId)) {
|
|
1506
|
+
writeError(
|
|
1507
|
+
res,
|
|
1508
|
+
501,
|
|
1509
|
+
`the OpenAI-chat\u2192subscription bridge currently supports claude only; subscription provider '${providerId}' is not implemented on this endpoint yet (use the /v1/responses endpoint, a Claude subscription, or a BYO provider)`
|
|
1510
|
+
);
|
|
1511
|
+
return null;
|
|
1512
|
+
}
|
|
1513
|
+
const upstreamUrl = _optionalChain([profile, 'access', _46 => _46.resolveUpstreamUrl, 'optionalCall', _47 => _47(resolvedModel)]);
|
|
1514
|
+
if (!upstreamUrl) {
|
|
1515
|
+
writeError(res, 502, "Subscription profile is missing resolveUpstreamUrl");
|
|
1516
|
+
return null;
|
|
1517
|
+
}
|
|
1518
|
+
const auth = _nullishCoalesce(route.auth, () => ( new (0, _chunkKFI44N2Rcjs.SubscriptionAuthSource)(profile)));
|
|
1519
|
+
const chain = _chunkNYUNU75Acjs.resolveSubscriptionChain.call(void 0,
|
|
1520
|
+
profile,
|
|
1521
|
+
deps.llmConfig.getTransformerService(),
|
|
1522
|
+
IDENTITY_ENDPOINT_TRANSFORMER
|
|
1523
|
+
);
|
|
1524
|
+
const transformerProvider = {
|
|
1525
|
+
name: providerId,
|
|
1526
|
+
baseUrl: upstreamUrl,
|
|
1527
|
+
apiKey: "",
|
|
1528
|
+
models: [resolvedModel]
|
|
1529
|
+
};
|
|
1530
|
+
return {
|
|
1531
|
+
auth,
|
|
1532
|
+
chain,
|
|
1533
|
+
transformerProvider,
|
|
1534
|
+
resolvedModel,
|
|
1535
|
+
isStream,
|
|
1536
|
+
resolveUrl: (config) => config.url instanceof URL ? config.url.toString() : typeof config.url === "string" ? config.url : upstreamUrl,
|
|
1537
|
+
upstreamUrl,
|
|
1538
|
+
proxyProviderId: providerId,
|
|
1539
|
+
isSubscription: true
|
|
1259
1540
|
};
|
|
1260
1541
|
}
|
|
1261
1542
|
async function runPipeline3(chatBody, plan) {
|
|
1262
1543
|
const executor = getSharedExecutor();
|
|
1263
1544
|
const { auth, chain, transformerProvider, resolvedModel, isStream, resolveUrl, upstreamUrl } = plan;
|
|
1545
|
+
let proxyAccountId;
|
|
1264
1546
|
const authHeaders = {};
|
|
1265
|
-
await auth.applyHeaders(authHeaders, {
|
|
1547
|
+
await auth.applyHeaders(authHeaders, {
|
|
1548
|
+
upstreamUrl,
|
|
1549
|
+
model: resolvedModel,
|
|
1550
|
+
reportSelection: (accountId) => {
|
|
1551
|
+
proxyAccountId = accountId;
|
|
1552
|
+
}
|
|
1553
|
+
});
|
|
1266
1554
|
let rawStatus = null;
|
|
1267
|
-
const { response } = await
|
|
1555
|
+
const { response } = await _chunkHYN75H6Gcjs.executeProviderCall.call(void 0, {
|
|
1268
1556
|
executor,
|
|
1269
1557
|
request: chatBody,
|
|
1270
1558
|
provider: transformerProvider,
|
|
@@ -1281,7 +1569,11 @@ async function runPipeline3(chatBody, plan) {
|
|
|
1281
1569
|
},
|
|
1282
1570
|
fetchFn: (url, headers, body) => {
|
|
1283
1571
|
console.log(`[ProviderProxy:chat] -> ${url} model=${resolvedModel} stream=${isStream}`);
|
|
1284
|
-
return
|
|
1572
|
+
return _chunkOCEUVQHWcjs.fetchUpstream.call(void 0,
|
|
1573
|
+
url,
|
|
1574
|
+
{ method: "POST", headers, body: JSON.stringify(body) },
|
|
1575
|
+
{ providerId: plan.proxyProviderId, accountId: proxyAccountId }
|
|
1576
|
+
).then((r) => {
|
|
1285
1577
|
rawStatus = r.status;
|
|
1286
1578
|
return r;
|
|
1287
1579
|
});
|
|
@@ -1292,8 +1584,8 @@ async function runPipeline3(chatBody, plan) {
|
|
|
1292
1584
|
}
|
|
1293
1585
|
async function runPipelineWithPoolReporting3(chatBody, plan) {
|
|
1294
1586
|
const first = await runPipeline3(chatBody, plan);
|
|
1295
|
-
const outcome = await _optionalChain([plan, 'access',
|
|
1296
|
-
if (_optionalChain([outcome, 'optionalAccess',
|
|
1587
|
+
const outcome = await _optionalChain([plan, 'access', _48 => _48.auth, 'access', _49 => _49.onResult, 'optionalCall', _50 => _50(first.rawStatus)]);
|
|
1588
|
+
if (_optionalChain([outcome, 'optionalAccess', _51 => _51.rebound])) {
|
|
1297
1589
|
console.log(
|
|
1298
1590
|
"[ProviderProxy:chat] pool re-bound key after status",
|
|
1299
1591
|
first.rawStatus,
|
|
@@ -1303,6 +1595,17 @@ async function runPipelineWithPoolReporting3(chatBody, plan) {
|
|
|
1303
1595
|
}
|
|
1304
1596
|
return first;
|
|
1305
1597
|
}
|
|
1598
|
+
async function runPipelineWithSubscriptionRetry2(chatBody, plan) {
|
|
1599
|
+
const first = await runPipeline3(chatBody, plan);
|
|
1600
|
+
if (first.rawStatus !== 401) return first;
|
|
1601
|
+
const refreshed = await _optionalChain([plan, 'access', _52 => _52.auth, 'access', _53 => _53.onUnauthorized, 'optionalCall', _54 => _54()]);
|
|
1602
|
+
if (!refreshed) {
|
|
1603
|
+
console.warn("[ProviderProxy:chat] 401 not recoverable (onUnauthorized returned false)");
|
|
1604
|
+
return first;
|
|
1605
|
+
}
|
|
1606
|
+
console.log("[ProviderProxy:chat] 401 \u2192 token refreshed; retrying once");
|
|
1607
|
+
return runPipeline3(chatBody, plan);
|
|
1608
|
+
}
|
|
1306
1609
|
|
|
1307
1610
|
// src/provider-proxy/usage/recordResponsesUsage.ts
|
|
1308
1611
|
function readResponsesUsage(usage) {
|
|
@@ -1333,26 +1636,27 @@ function recordResponsesNonStreamUsage(recorder, bodyText, attribution) {
|
|
|
1333
1636
|
sessionId: attribution.sessionId,
|
|
1334
1637
|
providerId: attribution.providerId,
|
|
1335
1638
|
model: attribution.model,
|
|
1336
|
-
apiKeyId:
|
|
1639
|
+
apiKeyId: attribution.apiKeyId,
|
|
1640
|
+
auditResponse: attribution.auditResponse,
|
|
1337
1641
|
engineOrigin: "codex-ingress",
|
|
1338
1642
|
usage: tapped,
|
|
1339
1643
|
rawUsage: parsed.usage
|
|
1340
1644
|
});
|
|
1341
|
-
} catch (
|
|
1645
|
+
} catch (e15) {
|
|
1342
1646
|
}
|
|
1343
1647
|
}
|
|
1344
1648
|
|
|
1345
1649
|
// src/provider-proxy/ingress/openaiResponsesIngress.ts
|
|
1346
1650
|
function isOpenAIResponsesRequest(method, url) {
|
|
1347
1651
|
if (method !== "POST" || !url) return false;
|
|
1348
|
-
const path = _nullishCoalesce(_optionalChain([url, 'access',
|
|
1652
|
+
const path = _nullishCoalesce(_optionalChain([url, 'access', _55 => _55.split, 'call', _56 => _56("?"), 'access', _57 => _57[0], 'optionalAccess', _58 => _58.replace, 'call', _59 => _59(/\/+$/, "")]), () => ( ""));
|
|
1349
1653
|
return path.endsWith("/responses");
|
|
1350
1654
|
}
|
|
1351
1655
|
async function handleOpenAIResponsesRequest(res, rawBody, route, deps) {
|
|
1352
1656
|
let responsesBody;
|
|
1353
1657
|
try {
|
|
1354
1658
|
responsesBody = JSON.parse(rawBody);
|
|
1355
|
-
} catch (
|
|
1659
|
+
} catch (e16) {
|
|
1356
1660
|
writeError(res, 400, "Invalid JSON in request body");
|
|
1357
1661
|
return;
|
|
1358
1662
|
}
|
|
@@ -1360,15 +1664,18 @@ async function handleOpenAIResponsesRequest(res, rawBody, route, deps) {
|
|
|
1360
1664
|
const resolvedModel = route.model;
|
|
1361
1665
|
responsesBody.model = resolvedModel;
|
|
1362
1666
|
try {
|
|
1363
|
-
const plan = route.authMode === "subscription" ? await
|
|
1667
|
+
const plan = route.authMode === "subscription" ? await buildSubscriptionPlan3(res, route, deps, resolvedModel, isStream) : await buildByoPlan4(res, route, deps, resolvedModel, isStream);
|
|
1364
1668
|
if (!plan) return;
|
|
1365
|
-
const providerResponse = route.authMode === "subscription" ? await
|
|
1366
|
-
const bodyText = await relayResponse(res, providerResponse.response, isStream);
|
|
1669
|
+
const providerResponse = route.authMode === "subscription" ? await runPipelineWithSubscriptionRetry3(responsesBody, plan) : await runPipelineWithPoolReporting4(responsesBody, plan);
|
|
1670
|
+
const bodyText = await relayResponse(res, providerResponse.response, isStream, route.requestedModel);
|
|
1367
1671
|
if (bodyText && deps.usageRecorder) {
|
|
1368
1672
|
recordResponsesNonStreamUsage(deps.usageRecorder, bodyText, {
|
|
1369
1673
|
sessionId: route.sessionId,
|
|
1370
1674
|
providerId: _nullishCoalesce(route.providerId, () => ( "codex")),
|
|
1371
|
-
model: resolvedModel
|
|
1675
|
+
model: resolvedModel,
|
|
1676
|
+
apiKeyId: _nullishCoalesce(route.apiKeyId, () => ( null)),
|
|
1677
|
+
// request-audit-log: correlate this request's tokens/cost to its audit record.
|
|
1678
|
+
auditResponse: res
|
|
1372
1679
|
});
|
|
1373
1680
|
}
|
|
1374
1681
|
} catch (err) {
|
|
@@ -1393,7 +1700,7 @@ async function buildByoPlan4(res, route, deps, resolvedModel, isStream) {
|
|
|
1393
1700
|
writeError(res, 502, "API key not configured");
|
|
1394
1701
|
return null;
|
|
1395
1702
|
}
|
|
1396
|
-
const auth = _nullishCoalesce(route.auth, () => ( new (0,
|
|
1703
|
+
const auth = _nullishCoalesce(route.auth, () => ( new (0, _chunkQ27JY5RGcjs.LlmConfigProviderAuth)({
|
|
1397
1704
|
provider,
|
|
1398
1705
|
apiKey,
|
|
1399
1706
|
apiKeyPool: _nullishCoalesce(deps.apiKeyPool, () => ( null)),
|
|
@@ -1415,21 +1722,22 @@ async function buildByoPlan4(res, route, deps, resolvedModel, isStream) {
|
|
|
1415
1722
|
resolvedModel,
|
|
1416
1723
|
isStream,
|
|
1417
1724
|
resolveUrl: (config) => config.url instanceof URL ? config.url.toString() : byoUrl,
|
|
1418
|
-
upstreamUrl: byoUrl
|
|
1725
|
+
upstreamUrl: byoUrl,
|
|
1726
|
+
proxyProviderId: "byo"
|
|
1419
1727
|
};
|
|
1420
1728
|
}
|
|
1421
|
-
async function
|
|
1729
|
+
async function buildSubscriptionPlan3(res, route, deps, resolvedModel, isStream) {
|
|
1422
1730
|
const profile = route.subscriptionProfile;
|
|
1423
1731
|
if (!profile) {
|
|
1424
1732
|
writeError(res, 502, "Subscription mode requires a codex subscription profile");
|
|
1425
1733
|
return null;
|
|
1426
1734
|
}
|
|
1427
|
-
const upstreamUrl = _optionalChain([profile, 'access',
|
|
1735
|
+
const upstreamUrl = _optionalChain([profile, 'access', _60 => _60.resolveUpstreamUrl, 'optionalCall', _61 => _61(resolvedModel)]);
|
|
1428
1736
|
if (!upstreamUrl) {
|
|
1429
1737
|
writeError(res, 502, "Subscription profile is missing resolveUpstreamUrl");
|
|
1430
1738
|
return null;
|
|
1431
1739
|
}
|
|
1432
|
-
const auth = _nullishCoalesce(route.auth, () => ( new (0,
|
|
1740
|
+
const auth = _nullishCoalesce(route.auth, () => ( new (0, _chunkKFI44N2Rcjs.SubscriptionAuthSource)(profile)));
|
|
1433
1741
|
const chain = _chunkNYUNU75Acjs.resolveSubscriptionChain.call(void 0,
|
|
1434
1742
|
profile,
|
|
1435
1743
|
deps.llmConfig.getTransformerService(),
|
|
@@ -1451,6 +1759,7 @@ async function buildSubscriptionPlan2(res, route, deps, resolvedModel, isStream)
|
|
|
1451
1759
|
}
|
|
1452
1760
|
return {
|
|
1453
1761
|
auth,
|
|
1762
|
+
preferredAccountId: route.preferredAccountId,
|
|
1454
1763
|
chain,
|
|
1455
1764
|
transformerProvider,
|
|
1456
1765
|
resolvedModel,
|
|
@@ -1459,7 +1768,8 @@ async function buildSubscriptionPlan2(res, route, deps, resolvedModel, isStream)
|
|
|
1459
1768
|
// stream vs non-stream colon-method URL in `config.url`); fall back to the
|
|
1460
1769
|
// profile's `resolveUpstreamUrl` for non-Code-Assist subscriptions.
|
|
1461
1770
|
resolveUrl: (config) => config.url instanceof URL ? config.url.toString() : typeof config.url === "string" ? config.url : upstreamUrl,
|
|
1462
|
-
upstreamUrl
|
|
1771
|
+
upstreamUrl,
|
|
1772
|
+
proxyProviderId: profile.authStrategy.providerId
|
|
1463
1773
|
};
|
|
1464
1774
|
}
|
|
1465
1775
|
async function resolveGeminiCodeAssistProject(profile) {
|
|
@@ -1476,10 +1786,18 @@ async function runPipeline4(responsesBody, plan) {
|
|
|
1476
1786
|
const executor = getSharedExecutor();
|
|
1477
1787
|
const endpointTransformer = getResponsesEndpointTransformer();
|
|
1478
1788
|
const { auth, chain, transformerProvider, resolvedModel, isStream, resolveUrl, upstreamUrl } = plan;
|
|
1789
|
+
let proxyAccountId;
|
|
1479
1790
|
const authHeaders = {};
|
|
1480
|
-
await auth.applyHeaders(authHeaders, {
|
|
1791
|
+
await auth.applyHeaders(authHeaders, {
|
|
1792
|
+
upstreamUrl,
|
|
1793
|
+
model: resolvedModel,
|
|
1794
|
+
preferredAccountId: plan.preferredAccountId,
|
|
1795
|
+
reportSelection: (accountId) => {
|
|
1796
|
+
proxyAccountId = accountId;
|
|
1797
|
+
}
|
|
1798
|
+
});
|
|
1481
1799
|
let rawStatus = null;
|
|
1482
|
-
const { response } = await
|
|
1800
|
+
const { response } = await _chunkHYN75H6Gcjs.executeProviderCall.call(void 0, {
|
|
1483
1801
|
executor,
|
|
1484
1802
|
request: responsesBody,
|
|
1485
1803
|
provider: transformerProvider,
|
|
@@ -1497,7 +1815,11 @@ async function runPipeline4(responsesBody, plan) {
|
|
|
1497
1815
|
},
|
|
1498
1816
|
fetchFn: (url, headers, body) => {
|
|
1499
1817
|
console.log(`[ProviderProxy:responses] -> ${url} model=${resolvedModel} stream=${isStream}`);
|
|
1500
|
-
return
|
|
1818
|
+
return _chunkOCEUVQHWcjs.fetchUpstream.call(void 0,
|
|
1819
|
+
url,
|
|
1820
|
+
{ method: "POST", headers, body: JSON.stringify(body) },
|
|
1821
|
+
{ providerId: plan.proxyProviderId, accountId: proxyAccountId }
|
|
1822
|
+
).then((r) => {
|
|
1501
1823
|
rawStatus = r.status;
|
|
1502
1824
|
return r;
|
|
1503
1825
|
});
|
|
@@ -1508,8 +1830,8 @@ async function runPipeline4(responsesBody, plan) {
|
|
|
1508
1830
|
}
|
|
1509
1831
|
async function runPipelineWithPoolReporting4(responsesBody, plan) {
|
|
1510
1832
|
const first = await runPipeline4(responsesBody, plan);
|
|
1511
|
-
const outcome = await _optionalChain([plan, 'access',
|
|
1512
|
-
if (_optionalChain([outcome, 'optionalAccess',
|
|
1833
|
+
const outcome = await _optionalChain([plan, 'access', _62 => _62.auth, 'access', _63 => _63.onResult, 'optionalCall', _64 => _64(first.rawStatus)]);
|
|
1834
|
+
if (_optionalChain([outcome, 'optionalAccess', _65 => _65.rebound])) {
|
|
1513
1835
|
console.log(
|
|
1514
1836
|
"[ProviderProxy:responses] pool re-bound key after status",
|
|
1515
1837
|
first.rawStatus,
|
|
@@ -1519,10 +1841,10 @@ async function runPipelineWithPoolReporting4(responsesBody, plan) {
|
|
|
1519
1841
|
}
|
|
1520
1842
|
return first;
|
|
1521
1843
|
}
|
|
1522
|
-
async function
|
|
1844
|
+
async function runPipelineWithSubscriptionRetry3(responsesBody, plan) {
|
|
1523
1845
|
const first = await runPipeline4(responsesBody, plan);
|
|
1524
1846
|
if (first.rawStatus !== 401) return first;
|
|
1525
|
-
const refreshed = await _optionalChain([plan, 'access',
|
|
1847
|
+
const refreshed = await _optionalChain([plan, 'access', _66 => _66.auth, 'access', _67 => _67.onUnauthorized, 'optionalCall', _68 => _68()]);
|
|
1526
1848
|
if (!refreshed) {
|
|
1527
1849
|
console.warn("[ProviderProxy:responses] 401 not recoverable (onUnauthorized returned false)");
|
|
1528
1850
|
return first;
|
|
@@ -1544,7 +1866,7 @@ function resolveRouteToken(req) {
|
|
|
1544
1866
|
if (fromAuth) return fromAuth;
|
|
1545
1867
|
const googKey = req.headers["x-goog-api-key"];
|
|
1546
1868
|
const value = Array.isArray(googKey) ? googKey[0] : googKey;
|
|
1547
|
-
return _optionalChain([value, 'optionalAccess',
|
|
1869
|
+
return _optionalChain([value, 'optionalAccess', _69 => _69.trim, 'call', _70 => _70()]) || void 0;
|
|
1548
1870
|
}
|
|
1549
1871
|
async function routeRequest(req, res, routes, deps) {
|
|
1550
1872
|
const token = resolveRouteToken(req);
|
|
@@ -1696,12 +2018,439 @@ function __resetProviderProxyForTests() {
|
|
|
1696
2018
|
// src/outbound-api/OutboundApiServer.ts
|
|
1697
2019
|
|
|
1698
2020
|
var _os = require('os');
|
|
2021
|
+
var _healthloggingtypes = require('@omnicross/contracts/health-logging-types');
|
|
2022
|
+
|
|
2023
|
+
// src/outbound-api/keyedMutex.ts
|
|
2024
|
+
var KeyedMutex = (_class3 = class {constructor() { _class3.prototype.__init4.call(this); }
|
|
2025
|
+
/** key → the tail of the pending-op chain (resolves when the last op frees). */
|
|
2026
|
+
__init4() {this.tails = /* @__PURE__ */ new Map()}
|
|
2027
|
+
/**
|
|
2028
|
+
* Run `fn` exclusively for `key`: it starts only after every previously
|
|
2029
|
+
* enqueued op for the SAME key has settled, and the next waiter starts only
|
|
2030
|
+
* after `fn` settles. Returns `fn`'s result (or rejection). Never lets one op's
|
|
2031
|
+
* failure wedge the queue (waiters proceed regardless).
|
|
2032
|
+
*/
|
|
2033
|
+
async runExclusive(key, fn) {
|
|
2034
|
+
const prev = _nullishCoalesce(this.tails.get(key), () => ( Promise.resolve()));
|
|
2035
|
+
let release2;
|
|
2036
|
+
const gate = new Promise((resolve) => {
|
|
2037
|
+
release2 = resolve;
|
|
2038
|
+
});
|
|
2039
|
+
const chain = prev.then(() => gate);
|
|
2040
|
+
this.tails.set(key, chain);
|
|
2041
|
+
await prev.catch(() => void 0);
|
|
2042
|
+
try {
|
|
2043
|
+
return await fn();
|
|
2044
|
+
} finally {
|
|
2045
|
+
release2();
|
|
2046
|
+
if (this.tails.get(key) === chain) this.tails.delete(key);
|
|
2047
|
+
}
|
|
2048
|
+
}
|
|
2049
|
+
}, _class3);
|
|
1699
2050
|
|
|
1700
2051
|
// src/outbound-api/outboundApiRouter.ts
|
|
1701
2052
|
var _stream = require('stream');
|
|
1702
2053
|
|
|
2054
|
+
// src/outbound-api/apiServerConfig.ts
|
|
2055
|
+
var _audittypes = require('@omnicross/contracts/audit-types');
|
|
2056
|
+
var _billingtypes = require('@omnicross/contracts/billing-types');
|
|
2057
|
+
|
|
2058
|
+
|
|
2059
|
+
|
|
2060
|
+
var _webhooktypes = require('@omnicross/contracts/webhook-types');
|
|
2061
|
+
var OUTBOUND_API_SERVER_CONFIG_KEY = "outboundApiServer.config";
|
|
2062
|
+
var DEFAULT_USER_MESSAGE_QUEUE = {
|
|
2063
|
+
enabled: false,
|
|
2064
|
+
delayMs: 200,
|
|
2065
|
+
waitTimeoutMs: 6e4
|
|
2066
|
+
};
|
|
2067
|
+
var DEFAULT_CONCURRENCY_QUEUE = {
|
|
2068
|
+
maxQueueSizeFactor: 2,
|
|
2069
|
+
minQueueSize: 4,
|
|
2070
|
+
waitTimeoutMs: 6e4
|
|
2071
|
+
};
|
|
2072
|
+
var DEFAULT_ACCOUNT_HEALTH = {
|
|
2073
|
+
overloadCooldownEnabled: true,
|
|
2074
|
+
overloadCooldownMs: 10 * 6e4
|
|
2075
|
+
};
|
|
2076
|
+
function normalizeAccountHealth(raw) {
|
|
2077
|
+
const ah = _optionalChain([raw, 'optionalAccess', _71 => _71.accountHealth]);
|
|
2078
|
+
return {
|
|
2079
|
+
overloadCooldownEnabled: _optionalChain([ah, 'optionalAccess', _72 => _72.overloadCooldownEnabled]) !== false,
|
|
2080
|
+
overloadCooldownMs: clampNumber(
|
|
2081
|
+
_optionalChain([ah, 'optionalAccess', _73 => _73.overloadCooldownMs]),
|
|
2082
|
+
6e4,
|
|
2083
|
+
36e5,
|
|
2084
|
+
DEFAULT_ACCOUNT_HEALTH.overloadCooldownMs
|
|
2085
|
+
)
|
|
2086
|
+
};
|
|
2087
|
+
}
|
|
2088
|
+
var DEFAULT_ACCOUNT_PROBE = {
|
|
2089
|
+
enabled: false,
|
|
2090
|
+
intervalMs: 15 * 6e4,
|
|
2091
|
+
onlyMultiAccount: true,
|
|
2092
|
+
timeoutMs: 5e3,
|
|
2093
|
+
historySize: 10,
|
|
2094
|
+
staggerMs: 500
|
|
2095
|
+
};
|
|
2096
|
+
function normalizeAccountProbe(raw) {
|
|
2097
|
+
const ap = _optionalChain([raw, 'optionalAccess', _74 => _74.accountProbe]);
|
|
2098
|
+
return {
|
|
2099
|
+
enabled: _optionalChain([ap, 'optionalAccess', _75 => _75.enabled]) === true,
|
|
2100
|
+
intervalMs: clampNumber(_optionalChain([ap, 'optionalAccess', _76 => _76.intervalMs]), 6e4, 864e5, DEFAULT_ACCOUNT_PROBE.intervalMs),
|
|
2101
|
+
onlyMultiAccount: _optionalChain([ap, 'optionalAccess', _77 => _77.onlyMultiAccount]) !== false,
|
|
2102
|
+
timeoutMs: clampNumber(_optionalChain([ap, 'optionalAccess', _78 => _78.timeoutMs]), 1e3, 6e4, DEFAULT_ACCOUNT_PROBE.timeoutMs),
|
|
2103
|
+
historySize: Math.trunc(
|
|
2104
|
+
clampNumber(_optionalChain([ap, 'optionalAccess', _79 => _79.historySize]), 1, 200, DEFAULT_ACCOUNT_PROBE.historySize)
|
|
2105
|
+
),
|
|
2106
|
+
staggerMs: clampNumber(_optionalChain([ap, 'optionalAccess', _80 => _80.staggerMs]), 0, 6e4, DEFAULT_ACCOUNT_PROBE.staggerMs)
|
|
2107
|
+
};
|
|
2108
|
+
}
|
|
2109
|
+
function normalizeAudit(raw) {
|
|
2110
|
+
const a = _optionalChain([raw, 'optionalAccess', _81 => _81.audit]);
|
|
2111
|
+
return {
|
|
2112
|
+
enabled: _optionalChain([a, 'optionalAccess', _82 => _82.enabled]) === true,
|
|
2113
|
+
captureBodies: _optionalChain([a, 'optionalAccess', _83 => _83.captureBodies]) === true,
|
|
2114
|
+
maxBodyBytes: Math.trunc(
|
|
2115
|
+
clampNumber(_optionalChain([a, 'optionalAccess', _84 => _84.maxBodyBytes]), 256, 1048576, _audittypes.DEFAULT_AUDIT_CONFIG.maxBodyBytes)
|
|
2116
|
+
),
|
|
2117
|
+
retentionDays: Math.trunc(
|
|
2118
|
+
clampNumber(_optionalChain([a, 'optionalAccess', _85 => _85.retentionDays]), 1, 365, _audittypes.DEFAULT_AUDIT_CONFIG.retentionDays)
|
|
2119
|
+
),
|
|
2120
|
+
trustForwardedFor: _optionalChain([a, 'optionalAccess', _86 => _86.trustForwardedFor]) === true
|
|
2121
|
+
};
|
|
2122
|
+
}
|
|
2123
|
+
function normalizeBilling(raw) {
|
|
2124
|
+
const b = _optionalChain([raw, 'optionalAccess', _87 => _87.billing]);
|
|
2125
|
+
const config = {
|
|
2126
|
+
enabled: _optionalChain([b, 'optionalAccess', _88 => _88.enabled]) === true,
|
|
2127
|
+
maxRetryAgeMs: Math.trunc(
|
|
2128
|
+
clampNumber(_optionalChain([b, 'optionalAccess', _89 => _89.maxRetryAgeMs]), 6e4, 2592e6, _billingtypes.DEFAULT_BILLING_CONFIG.maxRetryAgeMs)
|
|
2129
|
+
)
|
|
2130
|
+
};
|
|
2131
|
+
if (typeof _optionalChain([b, 'optionalAccess', _90 => _90.endpoint]) === "string" && b.endpoint.trim()) config.endpoint = b.endpoint.trim();
|
|
2132
|
+
if (typeof _optionalChain([b, 'optionalAccess', _91 => _91.secret]) === "string" && b.secret.length > 0) config.secret = b.secret;
|
|
2133
|
+
return config;
|
|
2134
|
+
}
|
|
2135
|
+
var DEFAULT_FINGERPRINT = { enabled: false };
|
|
2136
|
+
function normalizeFingerprint(raw) {
|
|
2137
|
+
const f = _optionalChain([raw, 'optionalAccess', _92 => _92.fingerprint]);
|
|
2138
|
+
const out = { enabled: _optionalChain([f, 'optionalAccess', _93 => _93.enabled]) === true };
|
|
2139
|
+
if (typeof _optionalChain([f, 'optionalAccess', _94 => _94.ua]) === "string" && f.ua.trim().length > 0) out.ua = f.ua.trim();
|
|
2140
|
+
return out;
|
|
2141
|
+
}
|
|
2142
|
+
function normalizeVoucher(raw) {
|
|
2143
|
+
return { enabled: _optionalChain([raw, 'optionalAccess', _95 => _95.voucher, 'optionalAccess', _96 => _96.enabled]) === true };
|
|
2144
|
+
}
|
|
2145
|
+
var PROXY_TYPES = ["http", "https", "socks5"];
|
|
2146
|
+
function normalizeProxyConfig(raw) {
|
|
2147
|
+
if (!raw || typeof raw !== "object") return void 0;
|
|
2148
|
+
const r = raw;
|
|
2149
|
+
if (typeof r["url"] === "string" && r["url"].trim().length > 0) {
|
|
2150
|
+
return { url: r["url"].trim() };
|
|
2151
|
+
}
|
|
2152
|
+
const type = r["type"];
|
|
2153
|
+
const host = r["host"];
|
|
2154
|
+
const port = r["port"];
|
|
2155
|
+
if (typeof type === "string" && PROXY_TYPES.includes(type) && typeof host === "string" && host.trim().length > 0 && typeof port === "number" && Number.isFinite(port) && port >= 1 && port <= 65535) {
|
|
2156
|
+
const out = {
|
|
2157
|
+
type,
|
|
2158
|
+
host: host.trim(),
|
|
2159
|
+
port: Math.trunc(port)
|
|
2160
|
+
};
|
|
2161
|
+
if (typeof r["username"] === "string" && r["username"].length > 0) out.username = r["username"];
|
|
2162
|
+
if (typeof r["password"] === "string" && r["password"].length > 0) out.password = r["password"];
|
|
2163
|
+
return out;
|
|
2164
|
+
}
|
|
2165
|
+
return void 0;
|
|
2166
|
+
}
|
|
2167
|
+
function normalizeProxySegment(raw) {
|
|
2168
|
+
if (!raw || typeof raw !== "object") return void 0;
|
|
2169
|
+
const r = raw;
|
|
2170
|
+
const out = {};
|
|
2171
|
+
const global = normalizeProxyConfig(r["global"]);
|
|
2172
|
+
if (global) out.global = global;
|
|
2173
|
+
if (r["byProvider"] && typeof r["byProvider"] === "object") {
|
|
2174
|
+
const byProvider = {};
|
|
2175
|
+
for (const [key, value] of Object.entries(r["byProvider"])) {
|
|
2176
|
+
if (!key.trim()) continue;
|
|
2177
|
+
const cfg = normalizeProxyConfig(value);
|
|
2178
|
+
if (cfg) byProvider[key] = cfg;
|
|
2179
|
+
}
|
|
2180
|
+
if (Object.keys(byProvider).length > 0) out.byProvider = byProvider;
|
|
2181
|
+
}
|
|
2182
|
+
return out.global || out.byProvider ? out : void 0;
|
|
2183
|
+
}
|
|
2184
|
+
function normalizeWebhookDestination(raw) {
|
|
2185
|
+
if (!raw || typeof raw !== "object") return void 0;
|
|
2186
|
+
const r = raw;
|
|
2187
|
+
const id = typeof r["id"] === "string" ? r["id"].trim() : "";
|
|
2188
|
+
const url = typeof r["url"] === "string" ? r["url"].trim() : "";
|
|
2189
|
+
const type = r["type"];
|
|
2190
|
+
if (!id || !url || typeof type !== "string" || !_webhooktypes.WEBHOOK_DESTINATION_TYPES.includes(type)) {
|
|
2191
|
+
return void 0;
|
|
2192
|
+
}
|
|
2193
|
+
const out = {
|
|
2194
|
+
id,
|
|
2195
|
+
type,
|
|
2196
|
+
url,
|
|
2197
|
+
enabled: r["enabled"] !== false
|
|
2198
|
+
};
|
|
2199
|
+
if (typeof r["secret"] === "string" && r["secret"].length > 0) out.secret = r["secret"];
|
|
2200
|
+
if (Array.isArray(r["events"])) {
|
|
2201
|
+
const events = r["events"].filter(
|
|
2202
|
+
(e) => typeof e === "string" && _webhooktypes.WEBHOOK_EVENT_KINDS.includes(e)
|
|
2203
|
+
);
|
|
2204
|
+
if (events.length > 0) out.events = events;
|
|
2205
|
+
}
|
|
2206
|
+
return out;
|
|
2207
|
+
}
|
|
2208
|
+
function normalizeWebhookSegment(raw) {
|
|
2209
|
+
if (!raw || typeof raw !== "object") return void 0;
|
|
2210
|
+
const r = raw;
|
|
2211
|
+
const destinations = [];
|
|
2212
|
+
if (Array.isArray(r["destinations"])) {
|
|
2213
|
+
for (const entry of r["destinations"]) {
|
|
2214
|
+
const d = normalizeWebhookDestination(entry);
|
|
2215
|
+
if (d) destinations.push(d);
|
|
2216
|
+
}
|
|
2217
|
+
}
|
|
2218
|
+
const enabled = r["enabled"] === true;
|
|
2219
|
+
if (!enabled && destinations.length === 0) return void 0;
|
|
2220
|
+
return { enabled, destinations };
|
|
2221
|
+
}
|
|
2222
|
+
function clampNumber(value, min, max, fallback) {
|
|
2223
|
+
const n = typeof value === "number" && Number.isFinite(value) ? value : fallback;
|
|
2224
|
+
return Math.min(max, Math.max(min, n));
|
|
2225
|
+
}
|
|
2226
|
+
function normalizeQueueSegments(raw) {
|
|
2227
|
+
const umq = _optionalChain([raw, 'optionalAccess', _97 => _97.userMessageQueue]);
|
|
2228
|
+
const cq = _optionalChain([raw, 'optionalAccess', _98 => _98.concurrencyQueue]);
|
|
2229
|
+
return {
|
|
2230
|
+
userMessageQueue: {
|
|
2231
|
+
enabled: _optionalChain([umq, 'optionalAccess', _99 => _99.enabled]) === true,
|
|
2232
|
+
delayMs: clampNumber(_optionalChain([umq, 'optionalAccess', _100 => _100.delayMs]), 0, 1e4, DEFAULT_USER_MESSAGE_QUEUE.delayMs),
|
|
2233
|
+
waitTimeoutMs: clampNumber(
|
|
2234
|
+
_optionalChain([umq, 'optionalAccess', _101 => _101.waitTimeoutMs]),
|
|
2235
|
+
1e3,
|
|
2236
|
+
3e5,
|
|
2237
|
+
DEFAULT_USER_MESSAGE_QUEUE.waitTimeoutMs
|
|
2238
|
+
)
|
|
2239
|
+
},
|
|
2240
|
+
concurrencyQueue: {
|
|
2241
|
+
maxQueueSizeFactor: clampNumber(
|
|
2242
|
+
_optionalChain([cq, 'optionalAccess', _102 => _102.maxQueueSizeFactor]),
|
|
2243
|
+
1,
|
|
2244
|
+
10,
|
|
2245
|
+
DEFAULT_CONCURRENCY_QUEUE.maxQueueSizeFactor
|
|
2246
|
+
),
|
|
2247
|
+
minQueueSize: clampNumber(_optionalChain([cq, 'optionalAccess', _103 => _103.minQueueSize]), 1, 100, DEFAULT_CONCURRENCY_QUEUE.minQueueSize),
|
|
2248
|
+
waitTimeoutMs: clampNumber(
|
|
2249
|
+
_optionalChain([cq, 'optionalAccess', _104 => _104.waitTimeoutMs]),
|
|
2250
|
+
1e3,
|
|
2251
|
+
3e5,
|
|
2252
|
+
DEFAULT_CONCURRENCY_QUEUE.waitTimeoutMs
|
|
2253
|
+
)
|
|
2254
|
+
}
|
|
2255
|
+
};
|
|
2256
|
+
}
|
|
2257
|
+
var ALL_ENDPOINTS = ["chat", "responses", "messages", "gemini"];
|
|
2258
|
+
function blankModelMap(endpoint) {
|
|
2259
|
+
const modelMap = {};
|
|
2260
|
+
for (const kind of _chunkVACWOIREcjs.modelKindsForEndpoint.call(void 0, endpoint)) modelMap[kind] = "";
|
|
2261
|
+
return modelMap;
|
|
2262
|
+
}
|
|
2263
|
+
function defaultEndpointConfig(endpoint) {
|
|
2264
|
+
if (_chunkVACWOIREcjs.isKindMappedEndpoint.call(void 0, endpoint)) {
|
|
2265
|
+
return { endpoint, modelMap: blankModelMap(endpoint), useSubscription: false };
|
|
2266
|
+
}
|
|
2267
|
+
if (endpoint === "chat") {
|
|
2268
|
+
return { endpoint, models: [], useSubscription: false };
|
|
2269
|
+
}
|
|
2270
|
+
return {
|
|
2271
|
+
endpoint,
|
|
2272
|
+
defaultModel: "",
|
|
2273
|
+
backgroundModel: "",
|
|
2274
|
+
useSubscription: false
|
|
2275
|
+
};
|
|
2276
|
+
}
|
|
2277
|
+
function normalizePrefixTargets(raw) {
|
|
2278
|
+
if (!raw || typeof raw !== "object") return void 0;
|
|
2279
|
+
const r = raw;
|
|
2280
|
+
const out = {};
|
|
2281
|
+
for (const key of ["claude", "gpt", "gemini"]) {
|
|
2282
|
+
const v = r[key];
|
|
2283
|
+
if (typeof v === "string" && v.trim() !== "") out[key] = v.trim();
|
|
2284
|
+
}
|
|
2285
|
+
return out.claude || out.gpt || out.gemini ? out : void 0;
|
|
2286
|
+
}
|
|
2287
|
+
function normalizeEndpointConfig(e) {
|
|
2288
|
+
const endpoint = e.endpoint;
|
|
2289
|
+
const useSubscription = e.useSubscription === true;
|
|
2290
|
+
const boundAccountId = typeof e.boundAccountId === "string" && e.boundAccountId.trim() !== "" ? e.boundAccountId : void 0;
|
|
2291
|
+
const boundKeyId = typeof e.boundKeyId === "string" && e.boundKeyId.trim() !== "" ? e.boundKeyId : void 0;
|
|
2292
|
+
let config;
|
|
2293
|
+
if (_chunkVACWOIREcjs.isKindMappedEndpoint.call(void 0, endpoint)) {
|
|
2294
|
+
const rawMap = e.modelMap && typeof e.modelMap === "object" ? e.modelMap : {};
|
|
2295
|
+
const modelMap = {};
|
|
2296
|
+
for (const kind of _chunkVACWOIREcjs.modelKindsForEndpoint.call(void 0, endpoint)) {
|
|
2297
|
+
const v = rawMap[kind];
|
|
2298
|
+
modelMap[kind] = typeof v === "string" ? v : "";
|
|
2299
|
+
}
|
|
2300
|
+
config = { endpoint, modelMap, useSubscription };
|
|
2301
|
+
} else if (endpoint === "chat") {
|
|
2302
|
+
const models = Array.isArray(e.models) ? e.models.filter((m) => typeof m === "string" && m.trim() !== "") : [];
|
|
2303
|
+
config = { endpoint, models, useSubscription };
|
|
2304
|
+
if (e.dispatchMode === "prefix") {
|
|
2305
|
+
config.dispatchMode = "prefix";
|
|
2306
|
+
const targets = normalizePrefixTargets(e.prefixTargets);
|
|
2307
|
+
if (targets) config.prefixTargets = targets;
|
|
2308
|
+
}
|
|
2309
|
+
} else {
|
|
2310
|
+
config = {
|
|
2311
|
+
endpoint,
|
|
2312
|
+
defaultModel: typeof e.defaultModel === "string" ? e.defaultModel : "",
|
|
2313
|
+
backgroundModel: typeof e.backgroundModel === "string" ? e.backgroundModel : "",
|
|
2314
|
+
useSubscription
|
|
2315
|
+
};
|
|
2316
|
+
if (Array.isArray(e.backgroundModelIds)) {
|
|
2317
|
+
config.backgroundModelIds = e.backgroundModelIds;
|
|
2318
|
+
}
|
|
2319
|
+
}
|
|
2320
|
+
if (boundAccountId) config.boundAccountId = boundAccountId;
|
|
2321
|
+
if (boundKeyId) config.boundKeyId = boundKeyId;
|
|
2322
|
+
return config;
|
|
2323
|
+
}
|
|
2324
|
+
function defaultServerConfig() {
|
|
2325
|
+
const queues = normalizeQueueSegments(void 0);
|
|
2326
|
+
return {
|
|
2327
|
+
enabled: false,
|
|
2328
|
+
networkBinding: false,
|
|
2329
|
+
endpoints: ALL_ENDPOINTS.map(defaultEndpointConfig),
|
|
2330
|
+
port: DEFAULT_OUTBOUND_PORT,
|
|
2331
|
+
userMessageQueue: queues.userMessageQueue,
|
|
2332
|
+
concurrencyQueue: queues.concurrencyQueue,
|
|
2333
|
+
accountHealth: normalizeAccountHealth(void 0),
|
|
2334
|
+
accountProbe: normalizeAccountProbe(void 0),
|
|
2335
|
+
audit: normalizeAudit(void 0),
|
|
2336
|
+
billing: normalizeBilling(void 0),
|
|
2337
|
+
fingerprint: normalizeFingerprint(void 0),
|
|
2338
|
+
voucher: normalizeVoucher(void 0)
|
|
2339
|
+
};
|
|
2340
|
+
}
|
|
2341
|
+
function normalizeServerConfig(raw) {
|
|
2342
|
+
const base = defaultServerConfig();
|
|
2343
|
+
if (!raw) return base;
|
|
2344
|
+
const byEndpoint = /* @__PURE__ */ new Map();
|
|
2345
|
+
for (const e of _nullishCoalesce(raw.endpoints, () => ( []))) {
|
|
2346
|
+
if (e && ALL_ENDPOINTS.includes(e.endpoint)) {
|
|
2347
|
+
byEndpoint.set(e.endpoint, normalizeEndpointConfig(e));
|
|
2348
|
+
}
|
|
2349
|
+
}
|
|
2350
|
+
const queues = normalizeQueueSegments(raw);
|
|
2351
|
+
const config = {
|
|
2352
|
+
enabled: raw.enabled === true,
|
|
2353
|
+
networkBinding: raw.networkBinding === true,
|
|
2354
|
+
endpoints: ALL_ENDPOINTS.map(
|
|
2355
|
+
(ep) => _nullishCoalesce(byEndpoint.get(ep), () => ( defaultEndpointConfig(ep)))
|
|
2356
|
+
),
|
|
2357
|
+
port: _nullishCoalesce(raw.port, () => ( base.port)),
|
|
2358
|
+
userMessageQueue: queues.userMessageQueue,
|
|
2359
|
+
concurrencyQueue: queues.concurrencyQueue,
|
|
2360
|
+
accountHealth: normalizeAccountHealth(raw),
|
|
2361
|
+
accountProbe: normalizeAccountProbe(raw),
|
|
2362
|
+
audit: normalizeAudit(raw),
|
|
2363
|
+
billing: normalizeBilling(raw),
|
|
2364
|
+
fingerprint: normalizeFingerprint(raw),
|
|
2365
|
+
voucher: normalizeVoucher(raw)
|
|
2366
|
+
};
|
|
2367
|
+
const proxy = normalizeProxySegment(raw.proxy);
|
|
2368
|
+
if (proxy) config.proxy = proxy;
|
|
2369
|
+
const webhook = normalizeWebhookSegment(raw.webhook);
|
|
2370
|
+
if (webhook) config.webhook = webhook;
|
|
2371
|
+
return config;
|
|
2372
|
+
}
|
|
2373
|
+
async function loadServerConfig(store) {
|
|
2374
|
+
const raw = await store.get(
|
|
2375
|
+
OUTBOUND_API_SERVER_CONFIG_KEY
|
|
2376
|
+
);
|
|
2377
|
+
return normalizeServerConfig(raw);
|
|
2378
|
+
}
|
|
2379
|
+
async function saveServerConfig(store, config) {
|
|
2380
|
+
await store.set(OUTBOUND_API_SERVER_CONFIG_KEY, config);
|
|
2381
|
+
}
|
|
2382
|
+
function mergeServerConfig(current, patch) {
|
|
2383
|
+
return normalizeServerConfig({
|
|
2384
|
+
enabled: _nullishCoalesce(patch.enabled, () => ( current.enabled)),
|
|
2385
|
+
networkBinding: _nullishCoalesce(patch.networkBinding, () => ( current.networkBinding)),
|
|
2386
|
+
endpoints: _nullishCoalesce(patch.endpoints, () => ( current.endpoints)),
|
|
2387
|
+
port: _nullishCoalesce(patch.port, () => ( current.port)),
|
|
2388
|
+
userMessageQueue: _nullishCoalesce(patch.userMessageQueue, () => ( current.userMessageQueue)),
|
|
2389
|
+
concurrencyQueue: _nullishCoalesce(patch.concurrencyQueue, () => ( current.concurrencyQueue)),
|
|
2390
|
+
accountHealth: _nullishCoalesce(patch.accountHealth, () => ( current.accountHealth)),
|
|
2391
|
+
accountProbe: _nullishCoalesce(patch.accountProbe, () => ( current.accountProbe)),
|
|
2392
|
+
audit: _nullishCoalesce(patch.audit, () => ( current.audit)),
|
|
2393
|
+
billing: _nullishCoalesce(patch.billing, () => ( current.billing)),
|
|
2394
|
+
// Proxy is layer-replaced (not deep-merged): a PUT carrying `proxy` swaps the
|
|
2395
|
+
// whole segment; omitting it keeps the current one. `undefined` on both ⇒ absent.
|
|
2396
|
+
proxy: _nullishCoalesce(patch.proxy, () => ( current.proxy)),
|
|
2397
|
+
// Webhook is layer-replaced too (a PUT carrying `webhook` swaps the whole
|
|
2398
|
+
// segment; omitting it keeps the current one). `undefined` on both ⇒ absent.
|
|
2399
|
+
webhook: _nullishCoalesce(patch.webhook, () => ( current.webhook)),
|
|
2400
|
+
// Fingerprint is always-filled (normalizeFingerprint synthesizes a default);
|
|
2401
|
+
// a PUT carrying it replaces the segment, else the current one is kept.
|
|
2402
|
+
fingerprint: _nullishCoalesce(patch.fingerprint, () => ( current.fingerprint)),
|
|
2403
|
+
// Voucher is always-filled (normalizeVoucher synthesizes a default); a PUT
|
|
2404
|
+
// carrying it replaces the segment, else the current one is kept.
|
|
2405
|
+
voucher: _nullishCoalesce(patch.voucher, () => ( current.voucher))
|
|
2406
|
+
});
|
|
2407
|
+
}
|
|
2408
|
+
|
|
1703
2409
|
// src/outbound-api/outboundApiKeyAuth.ts
|
|
1704
2410
|
|
|
2411
|
+
|
|
2412
|
+
// src/outbound-api/keyPolicy.ts
|
|
2413
|
+
var DAY_MS = 864e5;
|
|
2414
|
+
function computeKeyExpiry(row, now) {
|
|
2415
|
+
const mode = _nullishCoalesce(row.activationMode, () => ( "fixed"));
|
|
2416
|
+
if (mode === "activation") {
|
|
2417
|
+
if (row.activatedAt == null) return { expired: false, needsActivation: true };
|
|
2418
|
+
if (row.activationDays == null) return { expired: false };
|
|
2419
|
+
const effectiveExpiresAt = row.activatedAt + row.activationDays * DAY_MS;
|
|
2420
|
+
return { expired: now >= effectiveExpiresAt, effectiveExpiresAt };
|
|
2421
|
+
}
|
|
2422
|
+
if (row.expiresAt == null) return { expired: false };
|
|
2423
|
+
return { expired: now >= row.expiresAt, effectiveExpiresAt: row.expiresAt };
|
|
2424
|
+
}
|
|
2425
|
+
function checkKeyQuota(limits, spend) {
|
|
2426
|
+
if (!limits) return { allowed: true };
|
|
2427
|
+
if (limits.dailyUsd != null && spend.dailyUsd >= limits.dailyUsd) {
|
|
2428
|
+
return { allowed: false, scope: "daily", limitUsd: limits.dailyUsd, spentUsd: spend.dailyUsd };
|
|
2429
|
+
}
|
|
2430
|
+
if (limits.weeklyUsd != null && spend.weeklyUsd >= limits.weeklyUsd) {
|
|
2431
|
+
return { allowed: false, scope: "weekly", limitUsd: limits.weeklyUsd, spentUsd: spend.weeklyUsd };
|
|
2432
|
+
}
|
|
2433
|
+
if (limits.totalUsd != null && spend.totalUsd >= limits.totalUsd) {
|
|
2434
|
+
return { allowed: false, scope: "total", limitUsd: limits.totalUsd, spentUsd: spend.totalUsd };
|
|
2435
|
+
}
|
|
2436
|
+
return { allowed: true };
|
|
2437
|
+
}
|
|
2438
|
+
function canonicalModelId(value) {
|
|
2439
|
+
const idx = value.indexOf(",");
|
|
2440
|
+
const bare = idx >= 0 ? value.slice(idx + 1) : value;
|
|
2441
|
+
return bare.trim().toLowerCase();
|
|
2442
|
+
}
|
|
2443
|
+
function checkModelAllowed(restriction, resolvedModelId) {
|
|
2444
|
+
if (!restriction) return { allowed: true };
|
|
2445
|
+
const target = canonicalModelId(resolvedModelId);
|
|
2446
|
+
const listed = restriction.models.some((m) => canonicalModelId(m) === target);
|
|
2447
|
+
if (restriction.mode === "allowlist") {
|
|
2448
|
+
return listed ? { allowed: true } : { allowed: false, model: resolvedModelId };
|
|
2449
|
+
}
|
|
2450
|
+
return listed ? { allowed: false, model: resolvedModelId } : { allowed: true };
|
|
2451
|
+
}
|
|
2452
|
+
|
|
2453
|
+
// src/outbound-api/outboundApiKeyAuth.ts
|
|
1705
2454
|
var SECRET_BYTES = 32;
|
|
1706
2455
|
var PREFIX_LEN = 14;
|
|
1707
2456
|
var KEY_PREFIX = "sk-omnicross-";
|
|
@@ -1749,143 +2498,706 @@ async function createNamedKey(db, name) {
|
|
|
1749
2498
|
plaintextOnce: secret
|
|
1750
2499
|
};
|
|
1751
2500
|
}
|
|
1752
|
-
|
|
1753
|
-
|
|
2501
|
+
function extractCostLimits(row) {
|
|
2502
|
+
const limits = {};
|
|
2503
|
+
if (row.dailyCostLimitUsd != null) limits.dailyUsd = row.dailyCostLimitUsd;
|
|
2504
|
+
if (row.totalCostLimitUsd != null) limits.totalUsd = row.totalCostLimitUsd;
|
|
2505
|
+
if (row.weeklyCostLimitUsd != null) limits.weeklyUsd = row.weeklyCostLimitUsd;
|
|
2506
|
+
return limits.dailyUsd != null || limits.totalUsd != null || limits.weeklyUsd != null ? limits : void 0;
|
|
2507
|
+
}
|
|
2508
|
+
function extractRateLimit(row) {
|
|
2509
|
+
if (row.rateLimitMaxRequests == null && row.rateLimitWindowMs == null) return void 0;
|
|
2510
|
+
const override = {};
|
|
2511
|
+
if (row.rateLimitMaxRequests != null) override.maxRequests = row.rateLimitMaxRequests;
|
|
2512
|
+
if (row.rateLimitWindowMs != null) override.windowMs = row.rateLimitWindowMs;
|
|
2513
|
+
return override;
|
|
2514
|
+
}
|
|
2515
|
+
function extractModelRestriction(row) {
|
|
2516
|
+
if (row.enableModelRestriction !== true) return void 0;
|
|
2517
|
+
return {
|
|
2518
|
+
mode: _nullishCoalesce(row.restrictionMode, () => ( "blacklist")),
|
|
2519
|
+
models: _nullishCoalesce(row.restrictedModels, () => ( []))
|
|
2520
|
+
};
|
|
2521
|
+
}
|
|
2522
|
+
function toVerifiedKey(row) {
|
|
2523
|
+
const key = { id: row.id };
|
|
2524
|
+
if (row.maxConcurrency !== void 0 && row.maxConcurrency !== null) {
|
|
2525
|
+
key.maxConcurrency = row.maxConcurrency;
|
|
2526
|
+
}
|
|
2527
|
+
const costLimits = extractCostLimits(row);
|
|
2528
|
+
if (costLimits) key.costLimits = costLimits;
|
|
2529
|
+
const rateLimit = extractRateLimit(row);
|
|
2530
|
+
if (rateLimit) key.rateLimit = rateLimit;
|
|
2531
|
+
const modelRestriction = extractModelRestriction(row);
|
|
2532
|
+
if (modelRestriction) key.modelRestriction = modelRestriction;
|
|
2533
|
+
return key;
|
|
2534
|
+
}
|
|
2535
|
+
async function verifyKey(db, presentedKey, now = Date.now()) {
|
|
2536
|
+
if (!presentedKey) return { status: "invalid" };
|
|
1754
2537
|
const trimmed = presentedKey.trim();
|
|
1755
|
-
if (!trimmed) return
|
|
2538
|
+
if (!trimmed) return { status: "invalid" };
|
|
1756
2539
|
const row = await db.outboundApiKeysGetByHash(hashKey(trimmed));
|
|
1757
|
-
if (!row) return
|
|
1758
|
-
if (!row.enabled || row.revokedAt !== null) return
|
|
2540
|
+
if (!row) return { status: "invalid" };
|
|
2541
|
+
if (!row.enabled || row.revokedAt !== null) return { status: "invalid" };
|
|
2542
|
+
const expiry = computeKeyExpiry(row, now);
|
|
2543
|
+
if (expiry.expired) return { status: "expired" };
|
|
1759
2544
|
void db.outboundApiKeysTouchLastUsed(row.id).catch(() => {
|
|
1760
2545
|
});
|
|
1761
|
-
|
|
1762
|
-
|
|
1763
|
-
|
|
1764
|
-
// src/outbound-api/roleDetection.ts
|
|
1765
|
-
var _canonicalmodels = require('@omnicross/contracts/canonical-models');
|
|
1766
|
-
var BACKGROUND_TIER_TOKENS = /* @__PURE__ */ new Set([
|
|
1767
|
-
"haiku",
|
|
1768
|
-
"mini",
|
|
1769
|
-
"flash",
|
|
1770
|
-
"small",
|
|
1771
|
-
"lite",
|
|
1772
|
-
"nano",
|
|
1773
|
-
"8b"
|
|
1774
|
-
]);
|
|
1775
|
-
function modelTokens(normalizedId) {
|
|
1776
|
-
return normalizedId.split(/[-._:/\s]+/).filter(Boolean);
|
|
1777
|
-
}
|
|
1778
|
-
function isBackgroundTierModel(rawModelId) {
|
|
1779
|
-
if (!rawModelId) return false;
|
|
1780
|
-
const tokens = modelTokens(_canonicalmodels.normalizeModelId.call(void 0, rawModelId));
|
|
1781
|
-
return tokens.some((tok) => BACKGROUND_TIER_TOKENS.has(tok));
|
|
1782
|
-
}
|
|
1783
|
-
function extractRequestedModel(ingressFormat, body) {
|
|
1784
|
-
const model = body["model"];
|
|
1785
|
-
return typeof model === "string" && model ? model : void 0;
|
|
1786
|
-
}
|
|
1787
|
-
function anthropicHasVision(body) {
|
|
1788
|
-
const messages = body["messages"];
|
|
1789
|
-
if (!Array.isArray(messages)) return false;
|
|
1790
|
-
for (const msg of messages) {
|
|
1791
|
-
const content = _optionalChain([msg, 'optionalAccess', _64 => _64.content]);
|
|
1792
|
-
if (!Array.isArray(content)) continue;
|
|
1793
|
-
for (const part of content) {
|
|
1794
|
-
if (_optionalChain([part, 'optionalAccess', _65 => _65.type]) === "image") return true;
|
|
1795
|
-
}
|
|
2546
|
+
if (expiry.needsActivation) {
|
|
2547
|
+
void db.outboundApiKeysMarkActivated(row.id, now).catch(() => {
|
|
2548
|
+
});
|
|
1796
2549
|
}
|
|
1797
|
-
return
|
|
2550
|
+
return { status: "ok", key: toVerifiedKey(row) };
|
|
2551
|
+
}
|
|
2552
|
+
async function verifyPresentedKey(db, presentedKey) {
|
|
2553
|
+
const result = await verifyKey(db, presentedKey);
|
|
2554
|
+
return result.status === "ok" ? result.key : null;
|
|
1798
2555
|
}
|
|
1799
|
-
|
|
1800
|
-
|
|
1801
|
-
|
|
1802
|
-
|
|
1803
|
-
|
|
1804
|
-
|
|
1805
|
-
|
|
1806
|
-
|
|
2556
|
+
|
|
2557
|
+
// src/outbound-api/outboundConcurrencyGate.ts
|
|
2558
|
+
var ConcurrencyQueueFullError = (_class4 = class extends Error {
|
|
2559
|
+
constructor(apiKeyId, maxQueueSize) {
|
|
2560
|
+
super(`concurrency queue full (max ${maxQueueSize}) for key '${apiKeyId}'`);_class4.prototype.__init5.call(this);;
|
|
2561
|
+
this.apiKeyId = apiKeyId;
|
|
2562
|
+
this.maxQueueSize = maxQueueSize;
|
|
2563
|
+
this.name = "ConcurrencyQueueFullError";
|
|
2564
|
+
}
|
|
2565
|
+
|
|
2566
|
+
|
|
2567
|
+
__init5() {this.code = "concurrency_queue_full"}
|
|
2568
|
+
}, _class4);
|
|
2569
|
+
var ConcurrencyWaitTimeoutError = (_class5 = class extends Error {
|
|
2570
|
+
constructor(apiKeyId, waitTimeoutMs) {
|
|
2571
|
+
super(`concurrency wait timed out after ${waitTimeoutMs}ms for key '${apiKeyId}'`);_class5.prototype.__init6.call(this);;
|
|
2572
|
+
this.apiKeyId = apiKeyId;
|
|
2573
|
+
this.waitTimeoutMs = waitTimeoutMs;
|
|
2574
|
+
this.name = "ConcurrencyWaitTimeoutError";
|
|
2575
|
+
}
|
|
2576
|
+
|
|
2577
|
+
|
|
2578
|
+
__init6() {this.code = "concurrency_wait_timeout"}
|
|
2579
|
+
}, _class5);
|
|
2580
|
+
var ConcurrencyWaitCancelledError = (_class6 = class extends Error {
|
|
2581
|
+
constructor(apiKeyId) {
|
|
2582
|
+
super(`concurrency wait cancelled for key '${apiKeyId}'`);_class6.prototype.__init7.call(this);;
|
|
2583
|
+
this.apiKeyId = apiKeyId;
|
|
2584
|
+
this.name = "ConcurrencyWaitCancelledError";
|
|
2585
|
+
}
|
|
2586
|
+
|
|
2587
|
+
__init7() {this.code = "concurrency_wait_cancelled"}
|
|
2588
|
+
}, _class6);
|
|
2589
|
+
function isConcurrencyRejection(err) {
|
|
2590
|
+
return err instanceof ConcurrencyQueueFullError || err instanceof ConcurrencyWaitTimeoutError || err instanceof ConcurrencyWaitCancelledError;
|
|
2591
|
+
}
|
|
2592
|
+
var OutboundConcurrencyGate = (_class7 = class {constructor() { _class7.prototype.__init8.call(this); }
|
|
2593
|
+
__init8() {this.states = /* @__PURE__ */ new Map()}
|
|
2594
|
+
ensure(apiKeyId) {
|
|
2595
|
+
let state = this.states.get(apiKeyId);
|
|
2596
|
+
if (!state) {
|
|
2597
|
+
state = { active: 0, waiters: [] };
|
|
2598
|
+
this.states.set(apiKeyId, state);
|
|
1807
2599
|
}
|
|
2600
|
+
return state;
|
|
1808
2601
|
}
|
|
1809
|
-
|
|
1810
|
-
|
|
1811
|
-
|
|
1812
|
-
|
|
1813
|
-
|
|
1814
|
-
|
|
1815
|
-
|
|
1816
|
-
|
|
1817
|
-
|
|
1818
|
-
|
|
2602
|
+
/** Delete a key's state once it is fully idle (no active, no waiters). */
|
|
2603
|
+
gc(apiKeyId) {
|
|
2604
|
+
const state = this.states.get(apiKeyId);
|
|
2605
|
+
if (state && state.active === 0 && state.waiters.length === 0) {
|
|
2606
|
+
this.states.delete(apiKeyId);
|
|
2607
|
+
}
|
|
2608
|
+
}
|
|
2609
|
+
/**
|
|
2610
|
+
* Acquire a concurrency slot for `apiKeyId` under `limit`. Grants immediately
|
|
2611
|
+
* when `active < limit`; else enqueues FIFO while under the per-key queue cap;
|
|
2612
|
+
* else rejects queue-full. `limit <= 0` = unlimited (always granted).
|
|
2613
|
+
*/
|
|
2614
|
+
acquire(apiKeyId, limit, options) {
|
|
2615
|
+
const state = this.ensure(apiKeyId);
|
|
2616
|
+
const cap = limit > 0 ? limit : Infinity;
|
|
2617
|
+
if (state.active < cap) {
|
|
2618
|
+
state.active += 1;
|
|
2619
|
+
const slot = this.makeSlot(apiKeyId);
|
|
2620
|
+
return { granted: Promise.resolve(slot), cancel: slot.cancel };
|
|
2621
|
+
}
|
|
2622
|
+
const maxQueueSize = Math.max(
|
|
2623
|
+
Number.isFinite(cap) ? cap * options.maxQueueSizeFactor : Infinity,
|
|
2624
|
+
options.minQueueSize
|
|
2625
|
+
);
|
|
2626
|
+
if (state.waiters.length >= maxQueueSize) {
|
|
2627
|
+
const err = new ConcurrencyQueueFullError(apiKeyId, maxQueueSize);
|
|
2628
|
+
return { granted: Promise.reject(err), cancel: () => {
|
|
2629
|
+
} };
|
|
2630
|
+
}
|
|
2631
|
+
let settled = false;
|
|
2632
|
+
let granted = false;
|
|
2633
|
+
let resolveGrant;
|
|
2634
|
+
let rejectGrant;
|
|
2635
|
+
const grantedPromise = new Promise((resolve, reject) => {
|
|
2636
|
+
resolveGrant = resolve;
|
|
2637
|
+
rejectGrant = reject;
|
|
2638
|
+
});
|
|
2639
|
+
const waiter = {
|
|
2640
|
+
cap,
|
|
2641
|
+
settled: false,
|
|
2642
|
+
timeoutHandle: null,
|
|
2643
|
+
grant: () => {
|
|
2644
|
+
if (settled) return;
|
|
2645
|
+
settled = true;
|
|
2646
|
+
granted = true;
|
|
2647
|
+
waiter.settled = true;
|
|
2648
|
+
if (waiter.timeoutHandle) clearTimeout(waiter.timeoutHandle);
|
|
2649
|
+
state.active += 1;
|
|
2650
|
+
resolveGrant(this.makeSlot(apiKeyId));
|
|
2651
|
+
},
|
|
2652
|
+
fail: (err) => {
|
|
2653
|
+
if (settled) return;
|
|
2654
|
+
settled = true;
|
|
2655
|
+
waiter.settled = true;
|
|
2656
|
+
if (waiter.timeoutHandle) clearTimeout(waiter.timeoutHandle);
|
|
2657
|
+
const idx = state.waiters.indexOf(waiter);
|
|
2658
|
+
if (idx >= 0) state.waiters.splice(idx, 1);
|
|
2659
|
+
rejectGrant(err);
|
|
2660
|
+
this.gc(apiKeyId);
|
|
1819
2661
|
}
|
|
2662
|
+
};
|
|
2663
|
+
waiter.timeoutHandle = setTimeout(() => {
|
|
2664
|
+
waiter.fail(new ConcurrencyWaitTimeoutError(apiKeyId, options.waitTimeoutMs));
|
|
2665
|
+
}, options.waitTimeoutMs);
|
|
2666
|
+
state.waiters.push(waiter);
|
|
2667
|
+
const cancel = () => {
|
|
2668
|
+
if (settled || granted) return;
|
|
2669
|
+
waiter.fail(new ConcurrencyWaitCancelledError(apiKeyId));
|
|
2670
|
+
};
|
|
2671
|
+
return { granted: grantedPromise, cancel };
|
|
2672
|
+
}
|
|
2673
|
+
/** Build an idempotent granted slot (`release` decrements; `cancel` is a no-op). */
|
|
2674
|
+
makeSlot(apiKeyId) {
|
|
2675
|
+
let released = false;
|
|
2676
|
+
const release2 = () => {
|
|
2677
|
+
if (released) return;
|
|
2678
|
+
released = true;
|
|
2679
|
+
const state = this.states.get(apiKeyId);
|
|
2680
|
+
if (!state) return;
|
|
2681
|
+
state.active = Math.max(0, state.active - 1);
|
|
2682
|
+
this.dispatchNext(apiKeyId);
|
|
2683
|
+
this.gc(apiKeyId);
|
|
2684
|
+
};
|
|
2685
|
+
return { release: release2, cancel: () => {
|
|
2686
|
+
} };
|
|
2687
|
+
}
|
|
2688
|
+
/** After a release freed a slot, grant the FIFO head if it fits under its cap. */
|
|
2689
|
+
dispatchNext(apiKeyId) {
|
|
2690
|
+
const state = this.states.get(apiKeyId);
|
|
2691
|
+
if (!state || state.waiters.length === 0) return;
|
|
2692
|
+
const head = state.waiters[0];
|
|
2693
|
+
if (state.active < head.cap) {
|
|
2694
|
+
state.waiters.shift();
|
|
2695
|
+
head.grant();
|
|
1820
2696
|
}
|
|
1821
|
-
|
|
2697
|
+
}
|
|
2698
|
+
/** Snapshot for observability — only keys with active slots or waiters. */
|
|
2699
|
+
getStatus() {
|
|
2700
|
+
const out = [];
|
|
2701
|
+
for (const [apiKeyId, state] of this.states) {
|
|
2702
|
+
if (state.active > 0 || state.waiters.length > 0) {
|
|
2703
|
+
out.push({ apiKeyId, active: state.active, waiting: state.waiters.length });
|
|
2704
|
+
}
|
|
2705
|
+
}
|
|
2706
|
+
return out;
|
|
2707
|
+
}
|
|
2708
|
+
/** Drop all state + pending timers (tests / teardown). */
|
|
2709
|
+
reset() {
|
|
2710
|
+
for (const state of this.states.values()) {
|
|
2711
|
+
for (const w of state.waiters) {
|
|
2712
|
+
if (w.timeoutHandle) clearTimeout(w.timeoutHandle);
|
|
2713
|
+
}
|
|
2714
|
+
}
|
|
2715
|
+
this.states.clear();
|
|
2716
|
+
}
|
|
2717
|
+
}, _class7);
|
|
2718
|
+
|
|
2719
|
+
// src/outbound-api/outboundRateLimiter.ts
|
|
2720
|
+
var DEFAULT_WINDOW_MS = 6e4;
|
|
2721
|
+
var DEFAULT_MAX_REQUESTS = 60;
|
|
2722
|
+
var OutboundRateLimiter = (_class8 = class {
|
|
2723
|
+
|
|
2724
|
+
|
|
2725
|
+
/** apiKeyId → ascending request timestamps within the current window. */
|
|
2726
|
+
__init9() {this.hits = /* @__PURE__ */ new Map()}
|
|
2727
|
+
constructor(options = {}) {;_class8.prototype.__init9.call(this);
|
|
2728
|
+
this.windowMs = _nullishCoalesce(options.windowMs, () => ( DEFAULT_WINDOW_MS));
|
|
2729
|
+
this.maxRequests = _nullishCoalesce(options.maxRequests, () => ( DEFAULT_MAX_REQUESTS));
|
|
2730
|
+
}
|
|
2731
|
+
/**
|
|
2732
|
+
* Record a request for `apiKeyId` and decide whether it is allowed. Prunes
|
|
2733
|
+
* timestamps older than the window first; when allowed, the request's
|
|
2734
|
+
* timestamp is appended.
|
|
2735
|
+
*
|
|
2736
|
+
* `override` (outbound-key-policy) supplies a PER-KEY window/max for this
|
|
2737
|
+
* bucket, superseding the instance defaults for THAT key. Absent ⇒ the
|
|
2738
|
+
* instance default 60/60s (byte-identical to before this change). An effective
|
|
2739
|
+
* `maxRequests` of `0` means UNLIMITED — the request is allowed and NOT
|
|
2740
|
+
* recorded (no bucket growth).
|
|
2741
|
+
*/
|
|
2742
|
+
check(apiKeyId, now = Date.now(), override) {
|
|
2743
|
+
const maxRequests = _nullishCoalesce(_optionalChain([override, 'optionalAccess', _105 => _105.maxRequests]), () => ( this.maxRequests));
|
|
2744
|
+
const windowMs = _nullishCoalesce(_optionalChain([override, 'optionalAccess', _106 => _106.windowMs]), () => ( this.windowMs));
|
|
2745
|
+
if (maxRequests === 0) return { allowed: true, retryAfterSeconds: 0 };
|
|
2746
|
+
const cutoff = now - windowMs;
|
|
2747
|
+
const timestamps = (_nullishCoalesce(this.hits.get(apiKeyId), () => ( []))).filter((ts) => ts > cutoff);
|
|
2748
|
+
if (timestamps.length >= maxRequests) {
|
|
2749
|
+
if (timestamps.length === 0) {
|
|
2750
|
+
this.hits.delete(apiKeyId);
|
|
2751
|
+
return { allowed: false, retryAfterSeconds: Math.max(1, Math.ceil(windowMs / 1e3)) };
|
|
2752
|
+
}
|
|
2753
|
+
const oldest = timestamps[0];
|
|
2754
|
+
const retryAfterMs = Math.max(0, oldest + windowMs - now);
|
|
2755
|
+
this.hits.set(apiKeyId, timestamps);
|
|
2756
|
+
return {
|
|
2757
|
+
allowed: false,
|
|
2758
|
+
retryAfterSeconds: Math.max(1, Math.ceil(retryAfterMs / 1e3))
|
|
2759
|
+
};
|
|
2760
|
+
}
|
|
2761
|
+
timestamps.push(now);
|
|
2762
|
+
this.hits.set(apiKeyId, timestamps);
|
|
2763
|
+
return { allowed: true, retryAfterSeconds: 0 };
|
|
2764
|
+
}
|
|
2765
|
+
/** Drop all recorded state (tests / teardown). */
|
|
2766
|
+
reset() {
|
|
2767
|
+
this.hits.clear();
|
|
2768
|
+
}
|
|
2769
|
+
}, _class8);
|
|
2770
|
+
|
|
2771
|
+
// src/outbound-api/userMessageDetection.ts
|
|
2772
|
+
function asArray(v) {
|
|
2773
|
+
return Array.isArray(v) ? v : [];
|
|
2774
|
+
}
|
|
2775
|
+
function asObject(v) {
|
|
2776
|
+
return v !== null && typeof v === "object" && !Array.isArray(v) ? v : null;
|
|
2777
|
+
}
|
|
2778
|
+
function last(arr) {
|
|
2779
|
+
return arr.length > 0 ? arr[arr.length - 1] : void 0;
|
|
2780
|
+
}
|
|
2781
|
+
function isUserMessageAnthropic(body) {
|
|
2782
|
+
const messages = asArray(body["messages"]);
|
|
2783
|
+
const lastMsg = asObject(last(messages));
|
|
2784
|
+
if (!lastMsg || lastMsg["role"] !== "user") return false;
|
|
2785
|
+
const content = lastMsg["content"];
|
|
2786
|
+
if (typeof content === "string") return true;
|
|
2787
|
+
if (Array.isArray(content)) {
|
|
2788
|
+
const hasToolResult = content.some(
|
|
2789
|
+
(block) => _optionalChain([asObject, 'call', _107 => _107(block), 'optionalAccess', _108 => _108["type"]]) === "tool_result"
|
|
2790
|
+
);
|
|
2791
|
+
return !hasToolResult;
|
|
1822
2792
|
}
|
|
1823
2793
|
return false;
|
|
1824
2794
|
}
|
|
1825
|
-
function
|
|
1826
|
-
const
|
|
1827
|
-
if (
|
|
1828
|
-
|
|
1829
|
-
const
|
|
1830
|
-
if (!
|
|
1831
|
-
|
|
1832
|
-
|
|
1833
|
-
if (_optionalChain([p, 'optionalAccess', _72 => _72.inline_data]) || _optionalChain([p, 'optionalAccess', _73 => _73.inlineData]) || _optionalChain([p, 'optionalAccess', _74 => _74.file_data]) || _optionalChain([p, 'optionalAccess', _75 => _75.fileData])) return true;
|
|
1834
|
-
}
|
|
2795
|
+
function isUserMessageResponses(body) {
|
|
2796
|
+
const input = body["input"];
|
|
2797
|
+
if (typeof input === "string") return input.length > 0;
|
|
2798
|
+
if (Array.isArray(input)) {
|
|
2799
|
+
const lastItem = asObject(last(input));
|
|
2800
|
+
if (!lastItem) return false;
|
|
2801
|
+
if (lastItem["type"] === "function_call_output") return false;
|
|
2802
|
+
return lastItem["role"] === "user";
|
|
1835
2803
|
}
|
|
1836
2804
|
return false;
|
|
1837
2805
|
}
|
|
1838
|
-
function
|
|
1839
|
-
|
|
1840
|
-
|
|
1841
|
-
|
|
1842
|
-
|
|
1843
|
-
|
|
1844
|
-
|
|
1845
|
-
|
|
1846
|
-
|
|
1847
|
-
|
|
2806
|
+
function isUserMessageChat(body) {
|
|
2807
|
+
const messages = asArray(body["messages"]);
|
|
2808
|
+
const lastMsg = asObject(last(messages));
|
|
2809
|
+
if (!lastMsg) return false;
|
|
2810
|
+
return lastMsg["role"] === "user";
|
|
2811
|
+
}
|
|
2812
|
+
function isUserMessageGemini(body) {
|
|
2813
|
+
const contents = asArray(body["contents"]);
|
|
2814
|
+
const lastContent = asObject(last(contents));
|
|
2815
|
+
if (!lastContent || lastContent["role"] !== "user") return false;
|
|
2816
|
+
const parts = asArray(lastContent["parts"]);
|
|
2817
|
+
const hasFunctionResponse = parts.some(
|
|
2818
|
+
(part) => _optionalChain([asObject, 'call', _109 => _109(part), 'optionalAccess', _110 => _110["functionResponse"]]) !== void 0
|
|
2819
|
+
);
|
|
2820
|
+
return !hasFunctionResponse;
|
|
2821
|
+
}
|
|
2822
|
+
function isUserMessageRequest(endpoint, parsedBody) {
|
|
2823
|
+
const body = asObject(parsedBody);
|
|
2824
|
+
if (!body) return false;
|
|
2825
|
+
switch (endpoint) {
|
|
2826
|
+
case "messages":
|
|
2827
|
+
return isUserMessageAnthropic(body);
|
|
2828
|
+
case "responses":
|
|
2829
|
+
return isUserMessageResponses(body);
|
|
2830
|
+
case "chat":
|
|
2831
|
+
return isUserMessageChat(body);
|
|
2832
|
+
case "gemini":
|
|
2833
|
+
return isUserMessageGemini(body);
|
|
1848
2834
|
default:
|
|
1849
2835
|
return false;
|
|
1850
2836
|
}
|
|
1851
|
-
}
|
|
1852
|
-
|
|
1853
|
-
|
|
1854
|
-
|
|
1855
|
-
|
|
1856
|
-
|
|
1857
|
-
|
|
1858
|
-
|
|
1859
|
-
|
|
1860
|
-
|
|
1861
|
-
|
|
1862
|
-
|
|
1863
|
-
|
|
1864
|
-
|
|
1865
|
-
|
|
1866
|
-
|
|
2837
|
+
}
|
|
2838
|
+
|
|
2839
|
+
// src/outbound-api/userMessageSerialQueue.ts
|
|
2840
|
+
var SerialQueueTimeoutError = (_class9 = class extends Error {
|
|
2841
|
+
constructor(providerId, waitTimeoutMs) {
|
|
2842
|
+
super(`user-message serial queue wait timed out after ${waitTimeoutMs}ms for '${providerId}'`);_class9.prototype.__init10.call(this);;
|
|
2843
|
+
this.providerId = providerId;
|
|
2844
|
+
this.waitTimeoutMs = waitTimeoutMs;
|
|
2845
|
+
this.name = "SerialQueueTimeoutError";
|
|
2846
|
+
}
|
|
2847
|
+
|
|
2848
|
+
|
|
2849
|
+
__init10() {this.code = "serial_queue_timeout"}
|
|
2850
|
+
}, _class9);
|
|
2851
|
+
function isSerialQueueTimeout(err) {
|
|
2852
|
+
return err instanceof SerialQueueTimeoutError;
|
|
2853
|
+
}
|
|
2854
|
+
var UserMessageSerialQueue = (_class10 = class {constructor() { _class10.prototype.__init11.call(this); }
|
|
2855
|
+
__init11() {this.states = /* @__PURE__ */ new Map()}
|
|
2856
|
+
ensure(providerId) {
|
|
2857
|
+
let state = this.states.get(providerId);
|
|
2858
|
+
if (!state) {
|
|
2859
|
+
state = { holding: false, lastReleaseTs: null, waiters: [], dispatchHandle: null };
|
|
2860
|
+
this.states.set(providerId, state);
|
|
2861
|
+
}
|
|
2862
|
+
return state;
|
|
2863
|
+
}
|
|
2864
|
+
/**
|
|
2865
|
+
* Acquire the serial slot for `providerId`. Resolves immediately when the slot
|
|
2866
|
+
* is free, no one is queued, and the `delayMs` gap since the last release has
|
|
2867
|
+
* elapsed; otherwise enqueues FIFO and resolves in order (or rejects with a
|
|
2868
|
+
* {@link SerialQueueTimeoutError} after `waitTimeoutMs`).
|
|
2869
|
+
*/
|
|
2870
|
+
acquire(providerId, options) {
|
|
2871
|
+
const { waitTimeoutMs, delayMs } = options;
|
|
2872
|
+
const now = _nullishCoalesce(options.now, () => ( Date.now()));
|
|
2873
|
+
const state = this.ensure(providerId);
|
|
2874
|
+
const spacingElapsed = state.lastReleaseTs === null || now - state.lastReleaseTs >= delayMs;
|
|
2875
|
+
if (!state.holding && state.waiters.length === 0 && spacingElapsed) {
|
|
2876
|
+
state.holding = true;
|
|
2877
|
+
return Promise.resolve(this.makeSlot(providerId));
|
|
2878
|
+
}
|
|
2879
|
+
return new Promise((resolve, reject) => {
|
|
2880
|
+
const waiter = {
|
|
2881
|
+
delayMs,
|
|
2882
|
+
resolve,
|
|
2883
|
+
reject,
|
|
2884
|
+
timeoutHandle: null,
|
|
2885
|
+
done: false
|
|
2886
|
+
};
|
|
2887
|
+
waiter.timeoutHandle = setTimeout(() => {
|
|
2888
|
+
if (waiter.done) return;
|
|
2889
|
+
waiter.done = true;
|
|
2890
|
+
const idx = state.waiters.indexOf(waiter);
|
|
2891
|
+
if (idx >= 0) state.waiters.splice(idx, 1);
|
|
2892
|
+
reject(new SerialQueueTimeoutError(providerId, waitTimeoutMs));
|
|
2893
|
+
}, waitTimeoutMs);
|
|
2894
|
+
state.waiters.push(waiter);
|
|
2895
|
+
this.maybeDispatch(providerId);
|
|
2896
|
+
});
|
|
2897
|
+
}
|
|
2898
|
+
/** Build an idempotent release for a granted slot. */
|
|
2899
|
+
makeSlot(providerId) {
|
|
2900
|
+
let released = false;
|
|
2901
|
+
return {
|
|
2902
|
+
release: () => {
|
|
2903
|
+
if (released) return;
|
|
2904
|
+
released = true;
|
|
2905
|
+
const state = this.states.get(providerId);
|
|
2906
|
+
if (!state) return;
|
|
2907
|
+
state.holding = false;
|
|
2908
|
+
state.lastReleaseTs = Date.now();
|
|
2909
|
+
this.maybeDispatch(providerId);
|
|
2910
|
+
}
|
|
2911
|
+
};
|
|
2912
|
+
}
|
|
2913
|
+
/**
|
|
2914
|
+
* Grant the head waiter when the slot is free and the head's `delayMs` gap has
|
|
2915
|
+
* elapsed; otherwise schedule a dispatch for the residual gap. No-op while the
|
|
2916
|
+
* slot is held (release re-invokes this) or the queue is empty.
|
|
2917
|
+
*/
|
|
2918
|
+
maybeDispatch(providerId) {
|
|
2919
|
+
const state = this.states.get(providerId);
|
|
2920
|
+
if (!state || state.holding || state.waiters.length === 0) return;
|
|
2921
|
+
const head = state.waiters[0];
|
|
2922
|
+
const now = Date.now();
|
|
2923
|
+
const elapsed = state.lastReleaseTs === null ? Infinity : now - state.lastReleaseTs;
|
|
2924
|
+
const residual = Math.max(0, head.delayMs - elapsed);
|
|
2925
|
+
if (residual <= 0) {
|
|
2926
|
+
this.grantHead(providerId);
|
|
2927
|
+
return;
|
|
2928
|
+
}
|
|
2929
|
+
if (state.dispatchHandle !== null) return;
|
|
2930
|
+
state.dispatchHandle = setTimeout(() => {
|
|
2931
|
+
state.dispatchHandle = null;
|
|
2932
|
+
this.grantHead(providerId);
|
|
2933
|
+
}, residual);
|
|
2934
|
+
}
|
|
2935
|
+
/** Hand the slot to the FIFO head (if free and someone is waiting). */
|
|
2936
|
+
grantHead(providerId) {
|
|
2937
|
+
const state = this.states.get(providerId);
|
|
2938
|
+
if (!state || state.holding || state.waiters.length === 0) return;
|
|
2939
|
+
if (state.dispatchHandle !== null) {
|
|
2940
|
+
clearTimeout(state.dispatchHandle);
|
|
2941
|
+
state.dispatchHandle = null;
|
|
2942
|
+
}
|
|
2943
|
+
const head = state.waiters.shift();
|
|
2944
|
+
if (!head) return;
|
|
2945
|
+
if (head.timeoutHandle) clearTimeout(head.timeoutHandle);
|
|
2946
|
+
head.done = true;
|
|
2947
|
+
state.holding = true;
|
|
2948
|
+
head.resolve(this.makeSlot(providerId));
|
|
2949
|
+
}
|
|
2950
|
+
/** Snapshot for observability — only keys holding a slot or with waiters. */
|
|
2951
|
+
getStatus() {
|
|
2952
|
+
const out = [];
|
|
2953
|
+
for (const [providerId, state] of this.states) {
|
|
2954
|
+
if (state.holding || state.waiters.length > 0) {
|
|
2955
|
+
out.push({ providerId, holding: state.holding, waiting: state.waiters.length });
|
|
2956
|
+
}
|
|
2957
|
+
}
|
|
2958
|
+
return out;
|
|
2959
|
+
}
|
|
2960
|
+
/** Drop all state + pending timers (tests / teardown). */
|
|
2961
|
+
reset() {
|
|
2962
|
+
for (const state of this.states.values()) {
|
|
2963
|
+
if (state.dispatchHandle) clearTimeout(state.dispatchHandle);
|
|
2964
|
+
for (const w of state.waiters) {
|
|
2965
|
+
if (w.timeoutHandle) clearTimeout(w.timeoutHandle);
|
|
2966
|
+
}
|
|
2967
|
+
}
|
|
2968
|
+
this.states.clear();
|
|
2969
|
+
}
|
|
2970
|
+
}, _class10);
|
|
2971
|
+
|
|
2972
|
+
// src/outbound-api/voucher.ts
|
|
2973
|
+
|
|
2974
|
+
var CODE_ENTROPY_CHARS = 32;
|
|
2975
|
+
var CODE_PREFIX = "CC_";
|
|
2976
|
+
var DISPLAY_PREFIX_LEN = 8;
|
|
2977
|
+
var DAY_MS2 = 864e5;
|
|
2978
|
+
function generateVoucherCode() {
|
|
2979
|
+
return CODE_PREFIX + randomBase62(CODE_ENTROPY_CHARS);
|
|
2980
|
+
}
|
|
2981
|
+
function hashVoucherCode(code) {
|
|
2982
|
+
return _crypto.createHash.call(void 0, "sha256").update(code, "utf8").digest("hex");
|
|
2983
|
+
}
|
|
2984
|
+
function voucherCodePrefix(code) {
|
|
2985
|
+
return code.slice(0, DISPLAY_PREFIX_LEN);
|
|
2986
|
+
}
|
|
2987
|
+
function newVoucherId() {
|
|
2988
|
+
return `vch_${Date.now()}_${randomBase62(8)}`;
|
|
2989
|
+
}
|
|
2990
|
+
function computeVoucherGrant(voucher, currentKey, now) {
|
|
2991
|
+
if (voucher.type === "credit") {
|
|
2992
|
+
const current = _nullishCoalesce(_optionalChain([currentKey, 'optionalAccess', _111 => _111.totalCostLimitUsd]), () => ( 0));
|
|
2993
|
+
let granted2 = current + (_nullishCoalesce(voucher.creditUsd, () => ( 0)));
|
|
2994
|
+
if (voucher.maxTotalCostLimitUsd != null) {
|
|
2995
|
+
granted2 = Math.min(granted2, voucher.maxTotalCostLimitUsd);
|
|
2996
|
+
}
|
|
2997
|
+
return { totalCostLimitUsd: granted2 };
|
|
2998
|
+
}
|
|
2999
|
+
const currentExpiry = _nullishCoalesce(_optionalChain([currentKey, 'optionalAccess', _112 => _112.expiresAt]), () => ( now));
|
|
3000
|
+
let granted = currentExpiry + (_nullishCoalesce(voucher.renewalDays, () => ( 0))) * DAY_MS2;
|
|
3001
|
+
if (voucher.maxExpiryDays != null) {
|
|
3002
|
+
granted = Math.min(granted, now + voucher.maxExpiryDays * DAY_MS2);
|
|
3003
|
+
}
|
|
3004
|
+
return { expiresAt: granted };
|
|
3005
|
+
}
|
|
3006
|
+
function toVoucherInfo(v) {
|
|
3007
|
+
const info = {
|
|
3008
|
+
id: v.id,
|
|
3009
|
+
codePrefix: v.codePrefix,
|
|
3010
|
+
type: v.type,
|
|
3011
|
+
status: v.status,
|
|
3012
|
+
createdAt: v.createdAt
|
|
3013
|
+
};
|
|
3014
|
+
if (v.creditUsd != null) info.creditUsd = v.creditUsd;
|
|
3015
|
+
if (v.renewalDays != null) info.renewalDays = v.renewalDays;
|
|
3016
|
+
if (v.maxTotalCostLimitUsd != null) info.maxTotalCostLimitUsd = v.maxTotalCostLimitUsd;
|
|
3017
|
+
if (v.maxExpiryDays != null) info.maxExpiryDays = v.maxExpiryDays;
|
|
3018
|
+
if (v.redeemedAt != null) info.redeemedAt = v.redeemedAt;
|
|
3019
|
+
if (v.redeemedByKeyId != null) info.redeemedByKeyId = v.redeemedByKeyId;
|
|
3020
|
+
if (v.grantApplied != null) info.grantApplied = v.grantApplied;
|
|
3021
|
+
if (v.grantedTotalCostLimitUsd != null) info.grantedTotalCostLimitUsd = v.grantedTotalCostLimitUsd;
|
|
3022
|
+
if (v.grantedExpiresAt != null) info.grantedExpiresAt = v.grantedExpiresAt;
|
|
3023
|
+
if (v.revokedAt != null) info.revokedAt = v.revokedAt;
|
|
3024
|
+
return info;
|
|
3025
|
+
}
|
|
3026
|
+
|
|
3027
|
+
// src/outbound-api/voucherRedeem.ts
|
|
3028
|
+
function isRedeemRequest(method, url) {
|
|
3029
|
+
if (method !== "POST" || !url) return false;
|
|
3030
|
+
const path = _nullishCoalesce(_optionalChain([url, 'access', _113 => _113.split, 'call', _114 => _114("?"), 'access', _115 => _115[0], 'optionalAccess', _116 => _116.replace, 'call', _117 => _117(/\/+$/, "")]), () => ( ""));
|
|
3031
|
+
return path.endsWith("/redeem");
|
|
3032
|
+
}
|
|
3033
|
+
function writeErr(res, status, message, headers = {}) {
|
|
3034
|
+
if (res.headersSent) return;
|
|
3035
|
+
res.writeHead(status, { "Content-Type": "application/json", ...headers });
|
|
3036
|
+
res.end(JSON.stringify({ error: { type: "voucher_error", message } }));
|
|
3037
|
+
}
|
|
3038
|
+
function writeResult(res, result) {
|
|
3039
|
+
if (res.headersSent) return;
|
|
3040
|
+
res.writeHead(200, { "Content-Type": "application/json" });
|
|
3041
|
+
res.end(JSON.stringify({ ok: true, ...result }));
|
|
3042
|
+
}
|
|
3043
|
+
function readBody2(req) {
|
|
3044
|
+
return new Promise((resolve, reject) => {
|
|
3045
|
+
const chunks = [];
|
|
3046
|
+
req.on("data", (c) => chunks.push(c));
|
|
3047
|
+
req.on("end", () => resolve(Buffer.concat(chunks).toString("utf8")));
|
|
3048
|
+
req.on("error", reject);
|
|
3049
|
+
});
|
|
3050
|
+
}
|
|
3051
|
+
function grantToResult(type, granted) {
|
|
3052
|
+
const result = { type };
|
|
3053
|
+
if (granted.totalCostLimitUsd != null) result.totalCostLimitUsd = granted.totalCostLimitUsd;
|
|
3054
|
+
if (granted.expiresAt != null) result.expiresAt = granted.expiresAt;
|
|
3055
|
+
return result;
|
|
3056
|
+
}
|
|
3057
|
+
function currentResult(type, keyRow) {
|
|
3058
|
+
const result = { type };
|
|
3059
|
+
if (type === "credit") {
|
|
3060
|
+
if (_optionalChain([keyRow, 'optionalAccess', _118 => _118.totalCostLimitUsd]) != null) result.totalCostLimitUsd = keyRow.totalCostLimitUsd;
|
|
3061
|
+
} else if (_optionalChain([keyRow, 'optionalAccess', _119 => _119.expiresAt]) != null) {
|
|
3062
|
+
result.expiresAt = keyRow.expiresAt;
|
|
3063
|
+
}
|
|
3064
|
+
return result;
|
|
3065
|
+
}
|
|
3066
|
+
function recordedAbsolute(v) {
|
|
3067
|
+
const granted = {};
|
|
3068
|
+
if (v.grantedTotalCostLimitUsd != null) granted.totalCostLimitUsd = v.grantedTotalCostLimitUsd;
|
|
3069
|
+
if (v.grantedExpiresAt != null) granted.expiresAt = v.grantedExpiresAt;
|
|
3070
|
+
return granted;
|
|
3071
|
+
}
|
|
3072
|
+
function policyFrom(granted) {
|
|
3073
|
+
const policy = {};
|
|
3074
|
+
if (granted.totalCostLimitUsd != null) policy.totalCostLimitUsd = granted.totalCostLimitUsd;
|
|
3075
|
+
if (granted.expiresAt != null) policy.expiresAt = granted.expiresAt;
|
|
3076
|
+
return policy;
|
|
3077
|
+
}
|
|
3078
|
+
var NOT_REDEEMABLE = "Invalid or non-redeemable code";
|
|
3079
|
+
var fallbackMutex = null;
|
|
3080
|
+
function getFallbackMutex() {
|
|
3081
|
+
fallbackMutex ??= new KeyedMutex();
|
|
3082
|
+
return fallbackMutex;
|
|
3083
|
+
}
|
|
3084
|
+
async function handleVoucherRedeem(req, res, deps, voucherEnabled, redeemLimiter, verifiedKeyId, presentedKey, now, redeemMutex) {
|
|
3085
|
+
if (!voucherEnabled || !deps.voucherDb) {
|
|
3086
|
+
writeErr(res, 403, "Voucher redemption is not enabled");
|
|
3087
|
+
return;
|
|
3088
|
+
}
|
|
3089
|
+
const voucherDb = deps.voucherDb;
|
|
3090
|
+
const rl = redeemLimiter.check(verifiedKeyId, now);
|
|
3091
|
+
if (!rl.allowed) {
|
|
3092
|
+
writeErr(res, 429, "Too many redeem attempts", { "Retry-After": String(rl.retryAfterSeconds) });
|
|
3093
|
+
return;
|
|
3094
|
+
}
|
|
3095
|
+
const raw = await readBody2(req);
|
|
3096
|
+
let code;
|
|
3097
|
+
try {
|
|
3098
|
+
code = raw ? JSON.parse(raw)["code"] : void 0;
|
|
3099
|
+
} catch (e17) {
|
|
3100
|
+
writeErr(res, 400, "Invalid JSON in request body");
|
|
3101
|
+
return;
|
|
1867
3102
|
}
|
|
1868
|
-
|
|
1869
|
-
|
|
1870
|
-
|
|
1871
|
-
switch (endpoint) {
|
|
1872
|
-
case "chat":
|
|
1873
|
-
return "openai-chat";
|
|
1874
|
-
case "responses":
|
|
1875
|
-
return "openai-responses";
|
|
1876
|
-
case "messages":
|
|
1877
|
-
return "anthropic-messages";
|
|
1878
|
-
case "gemini":
|
|
1879
|
-
return "gemini-generatecontent";
|
|
3103
|
+
if (typeof code !== "string" || !code.trim()) {
|
|
3104
|
+
writeErr(res, 400, "Missing redemption code");
|
|
3105
|
+
return;
|
|
1880
3106
|
}
|
|
3107
|
+
const codeHash = hashVoucherCode(code.trim());
|
|
3108
|
+
const keyHash = hashKey(presentedKey.trim());
|
|
3109
|
+
const applyFirstPass = async (voucher, absolute) => {
|
|
3110
|
+
const ok = await deps.db.outboundApiKeysSetPolicy(verifiedKeyId, policyFrom(absolute));
|
|
3111
|
+
if (!ok) {
|
|
3112
|
+
await voucherDb.voucherRevertRedeem(voucher.id, verifiedKeyId);
|
|
3113
|
+
return { ok: false, status: 409, message: "Could not apply the grant \u2014 please retry" };
|
|
3114
|
+
}
|
|
3115
|
+
await voucherDb.voucherMarkGrantApplied(voucher.id);
|
|
3116
|
+
return { ok: true, result: grantToResult(voucher.type, absolute) };
|
|
3117
|
+
};
|
|
3118
|
+
const reconcileOne = async (voucher) => {
|
|
3119
|
+
const ok = await deps.db.outboundApiKeysSetPolicy(verifiedKeyId, policyFrom(recordedAbsolute(voucher)));
|
|
3120
|
+
if (ok) await voucherDb.voucherMarkGrantApplied(voucher.id);
|
|
3121
|
+
};
|
|
3122
|
+
const reconcileStranded = async () => {
|
|
3123
|
+
const all = await voucherDb.voucherList();
|
|
3124
|
+
const stranded = all.filter((v) => v.status === "redeemed" && v.grantApplied !== true && v.redeemedByKeyId === verifiedKeyId).sort((a, b) => (_nullishCoalesce(a.redeemedAt, () => ( 0))) - (_nullishCoalesce(b.redeemedAt, () => ( 0))));
|
|
3125
|
+
for (const v of stranded) await reconcileOne(v);
|
|
3126
|
+
};
|
|
3127
|
+
const runCritical = async () => {
|
|
3128
|
+
await reconcileStranded();
|
|
3129
|
+
const voucher = await voucherDb.voucherGetByHash(codeHash);
|
|
3130
|
+
if (!voucher || voucher.status === "revoked") {
|
|
3131
|
+
return { ok: false, status: 400, message: NOT_REDEEMABLE };
|
|
3132
|
+
}
|
|
3133
|
+
if (voucher.status === "redeemed") {
|
|
3134
|
+
if (voucher.redeemedByKeyId !== verifiedKeyId) {
|
|
3135
|
+
return { ok: false, status: 400, message: NOT_REDEEMABLE };
|
|
3136
|
+
}
|
|
3137
|
+
if (voucher.grantApplied === true) {
|
|
3138
|
+
const keyRow2 = await deps.db.outboundApiKeysGetByHash(keyHash);
|
|
3139
|
+
return { ok: true, result: currentResult(voucher.type, keyRow2) };
|
|
3140
|
+
}
|
|
3141
|
+
return await applyFirstPass(voucher, recordedAbsolute(voucher));
|
|
3142
|
+
}
|
|
3143
|
+
const keyRow = await deps.db.outboundApiKeysGetByHash(keyHash);
|
|
3144
|
+
const absolute = computeVoucherGrant(voucher, keyRow, now);
|
|
3145
|
+
const won = await voucherDb.voucherRedeemCas(voucher.id, verifiedKeyId, absolute, now);
|
|
3146
|
+
if (!won) {
|
|
3147
|
+
const after = await voucherDb.voucherGetByHash(codeHash);
|
|
3148
|
+
if (_optionalChain([after, 'optionalAccess', _120 => _120.status]) === "redeemed" && after.redeemedByKeyId === verifiedKeyId) {
|
|
3149
|
+
return after.grantApplied === true ? { ok: true, result: currentResult(after.type, await deps.db.outboundApiKeysGetByHash(keyHash)) } : await applyFirstPass(after, recordedAbsolute(after));
|
|
3150
|
+
}
|
|
3151
|
+
return { ok: false, status: 409, message: "Code was already redeemed" };
|
|
3152
|
+
}
|
|
3153
|
+
return await applyFirstPass(voucher, absolute);
|
|
3154
|
+
};
|
|
3155
|
+
const mutex = _nullishCoalesce(redeemMutex, () => ( getFallbackMutex()));
|
|
3156
|
+
const outcome = await mutex.runExclusive(verifiedKeyId, runCritical);
|
|
3157
|
+
if (outcome.ok) writeResult(res, outcome.result);
|
|
3158
|
+
else writeErr(res, outcome.status, outcome.message);
|
|
1881
3159
|
}
|
|
1882
3160
|
|
|
1883
3161
|
// src/outbound-api/outboundApiRouter.ts
|
|
3162
|
+
var fallbackRedeemLimiter = null;
|
|
3163
|
+
function getFallbackRedeemLimiter() {
|
|
3164
|
+
fallbackRedeemLimiter ??= new OutboundRateLimiter({ maxRequests: 10, windowMs: 6e4 });
|
|
3165
|
+
return fallbackRedeemLimiter;
|
|
3166
|
+
}
|
|
1884
3167
|
function writeJsonError(res, status, message, headers = {}) {
|
|
1885
3168
|
if (res.headersSent) return;
|
|
1886
3169
|
res.writeHead(status, { "Content-Type": "application/json", ...headers });
|
|
1887
3170
|
res.end(JSON.stringify({ error: { type: "outbound_api_error", message } }));
|
|
1888
3171
|
}
|
|
3172
|
+
function writeCostLimitError(res, scope, limitUsd, spentUsd) {
|
|
3173
|
+
if (res.headersSent) return;
|
|
3174
|
+
res.writeHead(402, { "Content-Type": "application/json" });
|
|
3175
|
+
res.end(
|
|
3176
|
+
JSON.stringify({
|
|
3177
|
+
error: {
|
|
3178
|
+
type: "outbound_api_error",
|
|
3179
|
+
message: `Cost limit reached for this key (${scope}): $${spentUsd.toFixed(4)} of $${limitUsd.toFixed(4)}`
|
|
3180
|
+
},
|
|
3181
|
+
scope,
|
|
3182
|
+
limitUsd,
|
|
3183
|
+
spentUsd
|
|
3184
|
+
})
|
|
3185
|
+
);
|
|
3186
|
+
}
|
|
3187
|
+
function writeModelNotAllowedError(res, model, mode) {
|
|
3188
|
+
if (res.headersSent) return;
|
|
3189
|
+
res.writeHead(403, { "Content-Type": "application/json" });
|
|
3190
|
+
res.end(
|
|
3191
|
+
JSON.stringify({
|
|
3192
|
+
error: {
|
|
3193
|
+
type: "outbound_api_error",
|
|
3194
|
+
message: `Model '${model}' is not permitted for this key (${mode})`
|
|
3195
|
+
},
|
|
3196
|
+
model,
|
|
3197
|
+
mode
|
|
3198
|
+
})
|
|
3199
|
+
);
|
|
3200
|
+
}
|
|
1889
3201
|
function extractPresentedKey(req) {
|
|
1890
3202
|
const auth = req.headers["authorization"];
|
|
1891
3203
|
if (typeof auth === "string" && auth.trim()) {
|
|
@@ -1894,14 +3206,14 @@ function extractPresentedKey(req) {
|
|
|
1894
3206
|
}
|
|
1895
3207
|
const xApiKey = req.headers["x-api-key"];
|
|
1896
3208
|
const xApi = Array.isArray(xApiKey) ? xApiKey[0] : xApiKey;
|
|
1897
|
-
if (_optionalChain([xApi, 'optionalAccess',
|
|
3209
|
+
if (_optionalChain([xApi, 'optionalAccess', _121 => _121.trim, 'call', _122 => _122()])) return xApi.trim();
|
|
1898
3210
|
const goog = req.headers["x-goog-api-key"];
|
|
1899
3211
|
const g = Array.isArray(goog) ? goog[0] : goog;
|
|
1900
|
-
return _optionalChain([g, 'optionalAccess',
|
|
3212
|
+
return _optionalChain([g, 'optionalAccess', _123 => _123.trim, 'call', _124 => _124()]) || void 0;
|
|
1901
3213
|
}
|
|
1902
3214
|
function selectEndpoint(method, url) {
|
|
1903
3215
|
if (method !== "POST" || !url) return null;
|
|
1904
|
-
const path = _nullishCoalesce(_optionalChain([url, 'access',
|
|
3216
|
+
const path = _nullishCoalesce(_optionalChain([url, 'access', _125 => _125.split, 'call', _126 => _126("?"), 'access', _127 => _127[0], 'optionalAccess', _128 => _128.replace, 'call', _129 => _129(/\/+$/, "")]), () => ( ""));
|
|
1905
3217
|
if (path.endsWith("/chat/completions")) return "chat";
|
|
1906
3218
|
if (path.endsWith("/responses")) return "responses";
|
|
1907
3219
|
if (path.includes("/v1/messages")) return "messages";
|
|
@@ -1917,7 +3229,18 @@ function extractGeminiModelFromUrl(url) {
|
|
|
1917
3229
|
const m = /\/models\/([^/:]+):(?:stream)?[gG]enerateContent$/.exec(path.replace(/\/+$/, ""));
|
|
1918
3230
|
return m ? decodeURIComponent(m[1]) : void 0;
|
|
1919
3231
|
}
|
|
1920
|
-
function
|
|
3232
|
+
function isModelsListRequest(url) {
|
|
3233
|
+
if (!url) return false;
|
|
3234
|
+
const path = _nullishCoalesce(_optionalChain([url, 'access', _130 => _130.split, 'call', _131 => _131("?"), 'access', _132 => _132[0], 'optionalAccess', _133 => _133.replace, 'call', _134 => _134(/\/+$/, "")]), () => ( ""));
|
|
3235
|
+
return path.endsWith("/models");
|
|
3236
|
+
}
|
|
3237
|
+
function writeChatModelsList(res, config) {
|
|
3238
|
+
const chat = config.endpoints.find((e) => e.endpoint === "chat");
|
|
3239
|
+
const data = (_nullishCoalesce(_optionalChain([chat, 'optionalAccess', _135 => _135.models]), () => ( []))).map((ref) => _chunkVACWOIREcjs.parseModelRef.call(void 0, ref)).filter((p) => p !== null).map((p) => ({ id: p.modelId, object: "model", owned_by: "omnicross" }));
|
|
3240
|
+
res.writeHead(200, { "Content-Type": "application/json" });
|
|
3241
|
+
res.end(JSON.stringify({ object: "list", data }));
|
|
3242
|
+
}
|
|
3243
|
+
function readBody3(req) {
|
|
1921
3244
|
return new Promise((resolve, reject) => {
|
|
1922
3245
|
const chunks = [];
|
|
1923
3246
|
req.on("data", (chunk) => chunks.push(chunk));
|
|
@@ -1930,20 +3253,48 @@ function shimAuthHeader(req, routeToken) {
|
|
|
1930
3253
|
delete req.headers["x-goog-api-key"];
|
|
1931
3254
|
delete req.headers["x-api-key"];
|
|
1932
3255
|
}
|
|
1933
|
-
async function handleOutboundRequest(req, res, deps, config, rateLimiter) {
|
|
3256
|
+
async function handleOutboundRequest(req, res, deps, config, rateLimiter, serialQueue, concurrencyGate, redeemLimiter, redeemMutex) {
|
|
3257
|
+
const now = Date.now();
|
|
3258
|
+
const audit = _chunkE3UCVHLPcjs.beginAuditCapture.call(void 0, req, res, now);
|
|
3259
|
+
const billing = _chunkAPYG5QD7cjs.beginBillingCapture.call(void 0, req, res, now);
|
|
1934
3260
|
const presented = extractPresentedKey(req);
|
|
1935
|
-
const
|
|
1936
|
-
if (
|
|
1937
|
-
writeJsonError(
|
|
3261
|
+
const verification = await verifyKey(deps.db, presented, now);
|
|
3262
|
+
if (verification.status !== "ok") {
|
|
3263
|
+
writeJsonError(
|
|
3264
|
+
res,
|
|
3265
|
+
401,
|
|
3266
|
+
verification.status === "expired" ? "API key has expired" : "Invalid or missing API key"
|
|
3267
|
+
);
|
|
3268
|
+
return;
|
|
3269
|
+
}
|
|
3270
|
+
const verified = verification.key;
|
|
3271
|
+
if (audit) audit.keyId = verified.id;
|
|
3272
|
+
if (billing) billing.keyId = verified.id;
|
|
3273
|
+
if (isRedeemRequest(req.method, req.url)) {
|
|
3274
|
+
await handleVoucherRedeem(
|
|
3275
|
+
req,
|
|
3276
|
+
res,
|
|
3277
|
+
deps,
|
|
3278
|
+
_optionalChain([config, 'access', _136 => _136.voucher, 'optionalAccess', _137 => _137.enabled]) === true,
|
|
3279
|
+
_nullishCoalesce(redeemLimiter, () => ( getFallbackRedeemLimiter())),
|
|
3280
|
+
verified.id,
|
|
3281
|
+
_nullishCoalesce(presented, () => ( "")),
|
|
3282
|
+
now,
|
|
3283
|
+
redeemMutex
|
|
3284
|
+
);
|
|
1938
3285
|
return;
|
|
1939
3286
|
}
|
|
1940
|
-
const decision = rateLimiter.check(verified.id);
|
|
3287
|
+
const decision = rateLimiter.check(verified.id, now, verified.rateLimit);
|
|
1941
3288
|
if (!decision.allowed) {
|
|
1942
3289
|
writeJsonError(res, 429, "Rate limit exceeded", {
|
|
1943
3290
|
"Retry-After": String(decision.retryAfterSeconds)
|
|
1944
3291
|
});
|
|
1945
3292
|
return;
|
|
1946
3293
|
}
|
|
3294
|
+
if (req.method === "GET" && isModelsListRequest(req.url)) {
|
|
3295
|
+
writeChatModelsList(res, config);
|
|
3296
|
+
return;
|
|
3297
|
+
}
|
|
1947
3298
|
const endpoint = selectEndpoint(req.method, req.url);
|
|
1948
3299
|
if (!endpoint) {
|
|
1949
3300
|
writeJsonError(res, 404, `Unsupported: ${req.method} ${req.url}`);
|
|
@@ -1954,53 +3305,165 @@ async function handleOutboundRequest(req, res, deps, config, rateLimiter) {
|
|
|
1954
3305
|
writeJsonError(res, 503, `endpoint '${endpoint}' is not configured`);
|
|
1955
3306
|
return;
|
|
1956
3307
|
}
|
|
1957
|
-
|
|
1958
|
-
|
|
1959
|
-
|
|
1960
|
-
|
|
1961
|
-
|
|
1962
|
-
|
|
1963
|
-
|
|
1964
|
-
|
|
1965
|
-
|
|
1966
|
-
|
|
1967
|
-
|
|
1968
|
-
|
|
3308
|
+
if (verified.costLimits && deps.keySpendTracker) {
|
|
3309
|
+
const spend = await deps.keySpendTracker.getSpend(verified.id, now);
|
|
3310
|
+
const quota = checkKeyQuota(verified.costLimits, spend);
|
|
3311
|
+
if (!quota.allowed) {
|
|
3312
|
+
_chunkUIBD2YY5cjs.emitWebhookEvent.call(void 0, {
|
|
3313
|
+
kind: "key.quotaExceeded",
|
|
3314
|
+
at: now,
|
|
3315
|
+
keyId: verified.id,
|
|
3316
|
+
scope: quota.scope,
|
|
3317
|
+
limitUsd: quota.limitUsd,
|
|
3318
|
+
spentUsd: quota.spentUsd
|
|
3319
|
+
});
|
|
3320
|
+
writeCostLimitError(res, quota.scope, quota.limitUsd, quota.spentUsd);
|
|
3321
|
+
return;
|
|
3322
|
+
}
|
|
3323
|
+
for (const warn of _chunk4YINUUKQcjs.computeQuotaWarnings.call(void 0, verified.costLimits, spend)) {
|
|
3324
|
+
if (_chunk4YINUUKQcjs.markQuotaWarnedOnce.call(void 0, verified.id, warn.scope, warn.windowStart)) {
|
|
3325
|
+
_chunkUIBD2YY5cjs.emitWebhookEvent.call(void 0, {
|
|
3326
|
+
kind: "key.quotaWarning",
|
|
3327
|
+
at: now,
|
|
3328
|
+
keyId: verified.id,
|
|
3329
|
+
scope: warn.scope,
|
|
3330
|
+
limitUsd: warn.limitUsd,
|
|
3331
|
+
spentUsd: warn.spentUsd
|
|
3332
|
+
});
|
|
3333
|
+
}
|
|
3334
|
+
}
|
|
1969
3335
|
}
|
|
1970
|
-
const
|
|
1971
|
-
|
|
1972
|
-
|
|
1973
|
-
|
|
1974
|
-
|
|
1975
|
-
|
|
1976
|
-
|
|
1977
|
-
|
|
1978
|
-
|
|
1979
|
-
|
|
1980
|
-
|
|
1981
|
-
|
|
1982
|
-
|
|
1983
|
-
|
|
1984
|
-
|
|
1985
|
-
|
|
1986
|
-
|
|
1987
|
-
|
|
1988
|
-
|
|
1989
|
-
|
|
1990
|
-
|
|
3336
|
+
const concurrencyLimit = verified.maxConcurrency;
|
|
3337
|
+
let releaseConcurrency = null;
|
|
3338
|
+
if (typeof concurrencyLimit === "number" && concurrencyLimit > 0) {
|
|
3339
|
+
const cq = _nullishCoalesce(config.concurrencyQueue, () => ( DEFAULT_CONCURRENCY_QUEUE));
|
|
3340
|
+
const acquisition = concurrencyGate.acquire(verified.id, concurrencyLimit, {
|
|
3341
|
+
maxQueueSizeFactor: cq.maxQueueSizeFactor,
|
|
3342
|
+
minQueueSize: cq.minQueueSize,
|
|
3343
|
+
waitTimeoutMs: cq.waitTimeoutMs
|
|
3344
|
+
});
|
|
3345
|
+
const cancelOnClose = () => acquisition.cancel();
|
|
3346
|
+
res.once("close", cancelOnClose);
|
|
3347
|
+
let slot;
|
|
3348
|
+
try {
|
|
3349
|
+
slot = await acquisition.granted;
|
|
3350
|
+
} catch (err) {
|
|
3351
|
+
res.removeListener("close", cancelOnClose);
|
|
3352
|
+
if (isConcurrencyRejection(err)) {
|
|
3353
|
+
writeJsonError(res, 429, "Concurrency limit exceeded", { "Retry-After": "5" });
|
|
3354
|
+
return;
|
|
3355
|
+
}
|
|
3356
|
+
throw err;
|
|
3357
|
+
}
|
|
3358
|
+
res.removeListener("close", cancelOnClose);
|
|
3359
|
+
const release2 = () => slot.release();
|
|
3360
|
+
releaseConcurrency = release2;
|
|
3361
|
+
res.once("close", release2);
|
|
1991
3362
|
}
|
|
1992
|
-
const routeMap = deps.providerProxy.getRouteMap();
|
|
1993
|
-
const token = routeMap.addRoute(resolved.route);
|
|
1994
3363
|
try {
|
|
1995
|
-
|
|
1996
|
-
const
|
|
1997
|
-
|
|
1998
|
-
|
|
1999
|
-
|
|
2000
|
-
|
|
2001
|
-
|
|
3364
|
+
const ingressFormat = _chunkVACWOIREcjs.endpointToIngressFormat.call(void 0, endpoint);
|
|
3365
|
+
const rawBody = await readBody3(req);
|
|
3366
|
+
let parsedBody = {};
|
|
3367
|
+
try {
|
|
3368
|
+
parsedBody = rawBody ? JSON.parse(rawBody) : {};
|
|
3369
|
+
} catch (e18) {
|
|
3370
|
+
writeJsonError(res, 400, "Invalid JSON in request body");
|
|
3371
|
+
return;
|
|
3372
|
+
}
|
|
3373
|
+
if (audit) audit.setRequestBody(rawBody);
|
|
3374
|
+
if (endpoint === "gemini" && typeof parsedBody["model"] !== "string") {
|
|
3375
|
+
const urlModel = extractGeminiModelFromUrl(req.url);
|
|
3376
|
+
if (urlModel) parsedBody["model"] = urlModel;
|
|
3377
|
+
}
|
|
3378
|
+
const sessionId = deps.proxyDeps.apiKeyPool ? `outbound:${verified.id}` : null;
|
|
3379
|
+
const resolved = _chunkVACWOIREcjs.isKindMappedEndpoint.call(void 0, endpoint) || endpoint === "chat" ? await _chunkVACWOIREcjs.resolveRoute.call(void 0, {
|
|
3380
|
+
config: endpointConfig,
|
|
3381
|
+
ingressFormat,
|
|
3382
|
+
llmConfig: deps.llmConfig,
|
|
3383
|
+
sessionId,
|
|
3384
|
+
// Capture the ORIGINAL requested id BEFORE any downstream swap; for
|
|
3385
|
+
// kind-mapped endpoints it selects the kind AND is stamped onto
|
|
3386
|
+
// `route.requestedModel`; for chat it is matched against the list.
|
|
3387
|
+
requestedModel: _chunkVACWOIREcjs.extractRequestedModel.call(void 0, ingressFormat, parsedBody),
|
|
3388
|
+
// Attribution: stamp the verified named-key id onto the route.
|
|
3389
|
+
apiKeyId: verified.id
|
|
3390
|
+
}) : await _chunkVACWOIREcjs.resolveRoute.call(void 0, {
|
|
3391
|
+
config: endpointConfig,
|
|
3392
|
+
role: _chunkVACWOIREcjs.detectRequestRole.call(void 0, ingressFormat, parsedBody, {
|
|
3393
|
+
backgroundModelIds: endpointConfig.backgroundModelIds
|
|
3394
|
+
}),
|
|
3395
|
+
ingressFormat,
|
|
3396
|
+
llmConfig: deps.llmConfig,
|
|
3397
|
+
sessionId,
|
|
3398
|
+
// Attribution: stamp the verified named-key id onto the route.
|
|
3399
|
+
apiKeyId: verified.id
|
|
3400
|
+
});
|
|
3401
|
+
if (!resolved.ok) {
|
|
3402
|
+
writeJsonError(res, resolved.error.status, resolved.error.message);
|
|
3403
|
+
return;
|
|
3404
|
+
}
|
|
3405
|
+
if (audit) {
|
|
3406
|
+
audit.model = resolved.route.model;
|
|
3407
|
+
audit.provider = resolved.route.providerId;
|
|
3408
|
+
}
|
|
3409
|
+
if (billing) {
|
|
3410
|
+
billing.model = resolved.route.model;
|
|
3411
|
+
billing.provider = resolved.route.providerId;
|
|
3412
|
+
billing.authMode = resolved.route.authMode;
|
|
3413
|
+
}
|
|
3414
|
+
if (verified.modelRestriction) {
|
|
3415
|
+
const modelDecision = checkModelAllowed(verified.modelRestriction, resolved.route.model);
|
|
3416
|
+
if (!modelDecision.allowed) {
|
|
3417
|
+
writeModelNotAllowedError(res, modelDecision.model, verified.modelRestriction.mode);
|
|
3418
|
+
return;
|
|
3419
|
+
}
|
|
3420
|
+
}
|
|
3421
|
+
let releaseSerial = null;
|
|
3422
|
+
const providerKey = resolved.route.providerId;
|
|
3423
|
+
if (_optionalChain([config, 'access', _138 => _138.userMessageQueue, 'optionalAccess', _139 => _139.enabled]) && providerKey && isUserMessageRequest(endpoint, parsedBody)) {
|
|
3424
|
+
const umq = config.userMessageQueue;
|
|
3425
|
+
try {
|
|
3426
|
+
const serialSlot = await serialQueue.acquire(providerKey, {
|
|
3427
|
+
waitTimeoutMs: umq.waitTimeoutMs,
|
|
3428
|
+
delayMs: umq.delayMs
|
|
3429
|
+
});
|
|
3430
|
+
releaseSerial = () => serialSlot.release();
|
|
3431
|
+
} catch (err) {
|
|
3432
|
+
if (isSerialQueueTimeout(err)) {
|
|
3433
|
+
writeJsonError(res, 503, "User-message serial queue wait timed out");
|
|
3434
|
+
return;
|
|
3435
|
+
}
|
|
3436
|
+
throw err;
|
|
3437
|
+
}
|
|
3438
|
+
}
|
|
3439
|
+
if (releaseSerial) {
|
|
3440
|
+
const original = res.writeHead.bind(res);
|
|
3441
|
+
const releaseOnce = releaseSerial;
|
|
3442
|
+
res.writeHead = ((...args) => {
|
|
3443
|
+
res.writeHead = original;
|
|
3444
|
+
releaseOnce();
|
|
3445
|
+
return original(...args);
|
|
3446
|
+
});
|
|
3447
|
+
}
|
|
3448
|
+
const routeMap = deps.providerProxy.getRouteMap();
|
|
3449
|
+
const token = routeMap.addRoute(resolved.route);
|
|
3450
|
+
try {
|
|
3451
|
+
shimAuthHeader(req, token);
|
|
3452
|
+
const replay = makeReplayRequest(req, rawBody);
|
|
3453
|
+
await routeRequest(replay, res, routeMap, deps.proxyDeps);
|
|
3454
|
+
} catch (err) {
|
|
3455
|
+
const message = _chunkSVNDB62Dcjs.serializeError.call(void 0, err);
|
|
3456
|
+
if (deps.logger) deps.logger.error("[OutboundApi] dispatch error:", message);
|
|
3457
|
+
else console.error("[OutboundApi] dispatch error:", message);
|
|
3458
|
+
_chunkUIBD2YY5cjs.emitWebhookEvent.call(void 0, { kind: "server.error", at: Date.now(), message });
|
|
3459
|
+
if (audit) audit.error = message;
|
|
3460
|
+
writeJsonError(res, 502, message);
|
|
3461
|
+
} finally {
|
|
3462
|
+
routeMap.removeRoute(token);
|
|
3463
|
+
if (releaseSerial) releaseSerial();
|
|
3464
|
+
}
|
|
2002
3465
|
} finally {
|
|
2003
|
-
|
|
3466
|
+
if (releaseConcurrency) releaseConcurrency();
|
|
2004
3467
|
}
|
|
2005
3468
|
}
|
|
2006
3469
|
function makeReplayRequest(req, rawBody) {
|
|
@@ -2014,65 +3477,50 @@ function makeReplayRequest(req, rawBody) {
|
|
|
2014
3477
|
return readable;
|
|
2015
3478
|
}
|
|
2016
3479
|
|
|
2017
|
-
// src/outbound-api/outboundRateLimiter.ts
|
|
2018
|
-
var DEFAULT_WINDOW_MS = 6e4;
|
|
2019
|
-
var DEFAULT_MAX_REQUESTS = 60;
|
|
2020
|
-
var OutboundRateLimiter = (_class3 = class {
|
|
2021
|
-
|
|
2022
|
-
|
|
2023
|
-
/** apiKeyId → ascending request timestamps within the current window. */
|
|
2024
|
-
__init4() {this.hits = /* @__PURE__ */ new Map()}
|
|
2025
|
-
constructor(options = {}) {;_class3.prototype.__init4.call(this);
|
|
2026
|
-
this.windowMs = _nullishCoalesce(options.windowMs, () => ( DEFAULT_WINDOW_MS));
|
|
2027
|
-
this.maxRequests = _nullishCoalesce(options.maxRequests, () => ( DEFAULT_MAX_REQUESTS));
|
|
2028
|
-
}
|
|
2029
|
-
/**
|
|
2030
|
-
* Record a request for `apiKeyId` and decide whether it is allowed. Prunes
|
|
2031
|
-
* timestamps older than the window first; when allowed, the request's
|
|
2032
|
-
* timestamp is appended.
|
|
2033
|
-
*/
|
|
2034
|
-
check(apiKeyId, now = Date.now()) {
|
|
2035
|
-
const cutoff = now - this.windowMs;
|
|
2036
|
-
const timestamps = (_nullishCoalesce(this.hits.get(apiKeyId), () => ( []))).filter((ts) => ts > cutoff);
|
|
2037
|
-
if (timestamps.length >= this.maxRequests) {
|
|
2038
|
-
if (timestamps.length === 0) {
|
|
2039
|
-
this.hits.delete(apiKeyId);
|
|
2040
|
-
return { allowed: false, retryAfterSeconds: Math.max(1, Math.ceil(this.windowMs / 1e3)) };
|
|
2041
|
-
}
|
|
2042
|
-
const oldest = timestamps[0];
|
|
2043
|
-
const retryAfterMs = Math.max(0, oldest + this.windowMs - now);
|
|
2044
|
-
this.hits.set(apiKeyId, timestamps);
|
|
2045
|
-
return {
|
|
2046
|
-
allowed: false,
|
|
2047
|
-
retryAfterSeconds: Math.max(1, Math.ceil(retryAfterMs / 1e3))
|
|
2048
|
-
};
|
|
2049
|
-
}
|
|
2050
|
-
timestamps.push(now);
|
|
2051
|
-
this.hits.set(apiKeyId, timestamps);
|
|
2052
|
-
return { allowed: true, retryAfterSeconds: 0 };
|
|
2053
|
-
}
|
|
2054
|
-
/** Drop all recorded state (tests / teardown). */
|
|
2055
|
-
reset() {
|
|
2056
|
-
this.hits.clear();
|
|
2057
|
-
}
|
|
2058
|
-
}, _class3);
|
|
2059
|
-
|
|
2060
3480
|
// src/outbound-api/OutboundApiServer.ts
|
|
2061
3481
|
var DEFAULT_OUTBOUND_PORT = 8765;
|
|
2062
3482
|
var LOOPBACK_ADDR = "127.0.0.1";
|
|
2063
3483
|
var LAN_ADDR = "0.0.0.0";
|
|
2064
|
-
var
|
|
2065
|
-
|
|
3484
|
+
var OutboundApiConfigError = class extends Error {
|
|
3485
|
+
|
|
3486
|
+
constructor(missing) {
|
|
3487
|
+
super(
|
|
3488
|
+
"Outbound API server cannot start: incomplete model-kind configuration \u2014 " + missing.map((m) => `${m.endpoint} missing [${m.missingKinds.join(", ")}]`).join("; ")
|
|
3489
|
+
);
|
|
3490
|
+
this.name = "OutboundApiConfigError";
|
|
3491
|
+
this.missing = missing;
|
|
3492
|
+
}
|
|
3493
|
+
};
|
|
3494
|
+
var OutboundApiServer = (_class11 = class {
|
|
3495
|
+
constructor(deps, onPortChange) {;_class11.prototype.__init12.call(this);_class11.prototype.__init13.call(this);_class11.prototype.__init14.call(this);_class11.prototype.__init15.call(this);_class11.prototype.__init16.call(this);_class11.prototype.__init17.call(this);_class11.prototype.__init18.call(this);_class11.prototype.__init19.call(this);_class11.prototype.__init20.call(this);
|
|
2066
3496
|
this.deps = deps;
|
|
2067
3497
|
this.onPortChange = onPortChange;
|
|
2068
3498
|
}
|
|
2069
3499
|
|
|
2070
3500
|
|
|
2071
|
-
|
|
2072
|
-
|
|
2073
|
-
|
|
2074
|
-
|
|
2075
|
-
|
|
3501
|
+
__init12() {this.server = null}
|
|
3502
|
+
__init13() {this.boundPort = 0}
|
|
3503
|
+
__init14() {this.boundAddr = LOOPBACK_ADDR}
|
|
3504
|
+
__init15() {this.endpoints = []}
|
|
3505
|
+
|
|
3506
|
+
|
|
3507
|
+
|
|
3508
|
+
__init16() {this.rateLimiter = new OutboundRateLimiter()}
|
|
3509
|
+
/**
|
|
3510
|
+
* Redeem-attempt limiter (voucher-redemption #9, design D6) — a SEPARATE bucket
|
|
3511
|
+
* from the traffic `rateLimiter`, keyed by the authenticating key id, so
|
|
3512
|
+
* brute-forcing `CC_` codes is throttled (a handful/min) without touching the
|
|
3513
|
+
* per-key request rate. Conservative fixed defaults (10 / 60s).
|
|
3514
|
+
*/
|
|
3515
|
+
__init17() {this.redeemLimiter = new OutboundRateLimiter({ maxRequests: 10, windowMs: 6e4 })}
|
|
3516
|
+
/**
|
|
3517
|
+
* Per-key redeem mutex (voucher-redemption #9, MJ1 fix). One instance for the
|
|
3518
|
+
* server's lifetime so concurrent redeem REQUESTS for the same key serialize
|
|
3519
|
+
* (relative grant increments accumulate instead of clobbering a snapshot).
|
|
3520
|
+
*/
|
|
3521
|
+
__init18() {this.redeemMutex = new KeyedMutex()}
|
|
3522
|
+
__init19() {this.serialQueue = new UserMessageSerialQueue()}
|
|
3523
|
+
__init20() {this.concurrencyGate = new OutboundConcurrencyGate()}
|
|
2076
3524
|
/**
|
|
2077
3525
|
* Apply a config. Restarts the listener ONLY when the bind address or port
|
|
2078
3526
|
* changes (or when toggling enabled); per-endpoint routing config is updated
|
|
@@ -2080,12 +3528,25 @@ var OutboundApiServer = (_class4 = class {
|
|
|
2080
3528
|
*/
|
|
2081
3529
|
async applyConfig(input) {
|
|
2082
3530
|
this.endpoints = input.endpoints;
|
|
3531
|
+
this.userMessageQueue = input.userMessageQueue;
|
|
3532
|
+
this.concurrencyQueue = input.concurrencyQueue;
|
|
3533
|
+
this.voucherConfig = input.voucher;
|
|
2083
3534
|
const wantAddr = input.networkBinding ? LAN_ADDR : LOOPBACK_ADDR;
|
|
2084
3535
|
const wantPort = _nullishCoalesce(input.port, () => ( DEFAULT_OUTBOUND_PORT));
|
|
2085
3536
|
if (!input.enabled) {
|
|
2086
3537
|
await this.stop();
|
|
2087
3538
|
return;
|
|
2088
3539
|
}
|
|
3540
|
+
const missing = _chunkVACWOIREcjs.validateServerModelConfig.call(void 0, {
|
|
3541
|
+
enabled: true,
|
|
3542
|
+
networkBinding: input.networkBinding,
|
|
3543
|
+
endpoints: input.endpoints,
|
|
3544
|
+
port: input.port
|
|
3545
|
+
});
|
|
3546
|
+
if (missing.length > 0) {
|
|
3547
|
+
await this.stop();
|
|
3548
|
+
throw new OutboundApiConfigError(missing);
|
|
3549
|
+
}
|
|
2089
3550
|
const running = this.server !== null;
|
|
2090
3551
|
const bindChanged = running && (this.boundAddr !== wantAddr || this.boundPort !== wantPort);
|
|
2091
3552
|
if (running && !bindChanged) {
|
|
@@ -2100,8 +3561,8 @@ var OutboundApiServer = (_class4 = class {
|
|
|
2100
3561
|
const actualPort = await this.listen(bindAddr, port);
|
|
2101
3562
|
this.boundAddr = bindAddr;
|
|
2102
3563
|
this.boundPort = actualPort;
|
|
2103
|
-
if (actualPort !== port) _optionalChain([this, 'access',
|
|
2104
|
-
|
|
3564
|
+
if (actualPort !== port) _optionalChain([this, 'access', _140 => _140.onPortChange, 'optionalCall', _141 => _141(actualPort)]);
|
|
3565
|
+
this.logInfo(`[OutboundApiServer] Listening on ${bindAddr}:${actualPort}`);
|
|
2105
3566
|
return actualPort;
|
|
2106
3567
|
}
|
|
2107
3568
|
/** Bind once; on EADDRINUSE retry with an ephemeral port (port 0). */
|
|
@@ -2123,7 +3584,7 @@ var OutboundApiServer = (_class4 = class {
|
|
|
2123
3584
|
const addr = server.address();
|
|
2124
3585
|
if (addr && typeof addr === "object") {
|
|
2125
3586
|
server.removeListener("error", onError);
|
|
2126
|
-
server.on("error", (e) =>
|
|
3587
|
+
server.on("error", (e) => this.logError("[OutboundApiServer] server error", _chunkSVNDB62Dcjs.serializeError.call(void 0, e)));
|
|
2127
3588
|
this.server = server;
|
|
2128
3589
|
resolve(addr.port);
|
|
2129
3590
|
} else {
|
|
@@ -2134,21 +3595,58 @@ var OutboundApiServer = (_class4 = class {
|
|
|
2134
3595
|
}
|
|
2135
3596
|
/** Per-request handler. Auth is enforced on EVERY request (incl. loopback). */
|
|
2136
3597
|
onRequest(req, res) {
|
|
3598
|
+
if (this.deps.healthReportProvider && this.tryServeHealth(req, res)) return;
|
|
2137
3599
|
handleOutboundRequest(
|
|
2138
3600
|
req,
|
|
2139
3601
|
res,
|
|
2140
3602
|
this.deps,
|
|
2141
|
-
{
|
|
2142
|
-
|
|
3603
|
+
{
|
|
3604
|
+
endpoints: this.endpoints,
|
|
3605
|
+
userMessageQueue: this.userMessageQueue,
|
|
3606
|
+
concurrencyQueue: this.concurrencyQueue,
|
|
3607
|
+
voucher: this.voucherConfig
|
|
3608
|
+
},
|
|
3609
|
+
this.rateLimiter,
|
|
3610
|
+
this.serialQueue,
|
|
3611
|
+
this.concurrencyGate,
|
|
3612
|
+
this.redeemLimiter,
|
|
3613
|
+
this.redeemMutex
|
|
2143
3614
|
).catch((err) => {
|
|
2144
3615
|
const message = _chunkSVNDB62Dcjs.serializeError.call(void 0, err);
|
|
2145
|
-
|
|
3616
|
+
this.logError("[OutboundApiServer] unhandled error:", message);
|
|
2146
3617
|
if (!res.headersSent) {
|
|
2147
3618
|
res.writeHead(500, { "Content-Type": "application/json" });
|
|
2148
3619
|
res.end(JSON.stringify({ error: { type: "outbound_api_error", message } }));
|
|
2149
3620
|
}
|
|
2150
3621
|
});
|
|
2151
3622
|
}
|
|
3623
|
+
/**
|
|
3624
|
+
* Serve `GET|HEAD /health` (+ `/healthz`) from the injected provider, returning
|
|
3625
|
+
* true when it handled the request. 200 when `ok`, else 503; secret-free body.
|
|
3626
|
+
*/
|
|
3627
|
+
tryServeHealth(req, res) {
|
|
3628
|
+
const provider = this.deps.healthReportProvider;
|
|
3629
|
+
if (!provider) return false;
|
|
3630
|
+
if (req.method !== "GET" && req.method !== "HEAD") return false;
|
|
3631
|
+
const path = _optionalChain([(_nullishCoalesce(req.url, () => ( "/"))), 'access', _142 => _142.split, 'call', _143 => _143("?"), 'access', _144 => _144[0], 'optionalAccess', _145 => _145.replace, 'call', _146 => _146(/\/+$/, "")]) || "/";
|
|
3632
|
+
if (path !== "/health" && path !== "/healthz") return false;
|
|
3633
|
+
const report = provider();
|
|
3634
|
+
res.writeHead(_healthloggingtypes.healthHttpStatus.call(void 0, report.status), { "Content-Type": "application/json" });
|
|
3635
|
+
res.end(req.method === "HEAD" ? void 0 : JSON.stringify(report));
|
|
3636
|
+
return true;
|
|
3637
|
+
}
|
|
3638
|
+
/** Route an info lifecycle line through the injected logger, else `console.log`
|
|
3639
|
+
* (byte-identical legacy fallback when no logger is wired). */
|
|
3640
|
+
logInfo(message) {
|
|
3641
|
+
if (this.deps.logger) this.deps.logger.info(message);
|
|
3642
|
+
else console.log(message);
|
|
3643
|
+
}
|
|
3644
|
+
/** Route an error lifecycle line through the injected logger, else `console.error`. */
|
|
3645
|
+
logError(message, detail) {
|
|
3646
|
+
if (this.deps.logger) this.deps.logger.error(message, detail);
|
|
3647
|
+
else if (detail === void 0) console.error(message);
|
|
3648
|
+
else console.error(message, detail);
|
|
3649
|
+
}
|
|
2152
3650
|
/** Stop the listener and release the port. */
|
|
2153
3651
|
async stop() {
|
|
2154
3652
|
const server = this.server;
|
|
@@ -2157,7 +3655,7 @@ var OutboundApiServer = (_class4 = class {
|
|
|
2157
3655
|
this.boundPort = 0;
|
|
2158
3656
|
return new Promise((resolve) => {
|
|
2159
3657
|
server.close(() => {
|
|
2160
|
-
|
|
3658
|
+
this.logInfo("[OutboundApiServer] Stopped");
|
|
2161
3659
|
resolve();
|
|
2162
3660
|
});
|
|
2163
3661
|
});
|
|
@@ -2189,7 +3687,18 @@ var OutboundApiServer = (_class4 = class {
|
|
|
2189
3687
|
lanFormats: lanBase ? formatUrls(lanBase) : null
|
|
2190
3688
|
};
|
|
2191
3689
|
}
|
|
2192
|
-
|
|
3690
|
+
/**
|
|
3691
|
+
* Live queue-occupancy snapshot (only active entries). This getter's name +
|
|
3692
|
+
* shape are FROZEN — `omnicross-uqc-daemon` spreads it into its `/status`
|
|
3693
|
+
* response; the existing {@link getStatus} shape is deliberately NOT changed.
|
|
3694
|
+
*/
|
|
3695
|
+
getQueueStatus() {
|
|
3696
|
+
return {
|
|
3697
|
+
serial: this.serialQueue.getStatus(),
|
|
3698
|
+
concurrency: this.concurrencyGate.getStatus()
|
|
3699
|
+
};
|
|
3700
|
+
}
|
|
3701
|
+
}, _class11);
|
|
2193
3702
|
function formatUrls(base) {
|
|
2194
3703
|
return {
|
|
2195
3704
|
chat: `${base}/v1/chat/completions`,
|
|
@@ -2209,66 +3718,88 @@ function firstLanIPv4() {
|
|
|
2209
3718
|
return null;
|
|
2210
3719
|
}
|
|
2211
3720
|
|
|
2212
|
-
// src/outbound-api/
|
|
2213
|
-
|
|
2214
|
-
|
|
2215
|
-
|
|
2216
|
-
return {
|
|
2217
|
-
endpoint,
|
|
2218
|
-
defaultModel: "",
|
|
2219
|
-
backgroundModel: "",
|
|
2220
|
-
useSubscription: false
|
|
2221
|
-
};
|
|
3721
|
+
// src/outbound-api/keySpendTracker.ts
|
|
3722
|
+
function startOfLocalDay(ts) {
|
|
3723
|
+
const d = new Date(ts);
|
|
3724
|
+
return new Date(d.getFullYear(), d.getMonth(), d.getDate()).getTime();
|
|
2222
3725
|
}
|
|
2223
|
-
function
|
|
2224
|
-
|
|
2225
|
-
|
|
2226
|
-
|
|
2227
|
-
|
|
2228
|
-
port: DEFAULT_OUTBOUND_PORT
|
|
2229
|
-
};
|
|
3726
|
+
function startOfLocalWeek(ts) {
|
|
3727
|
+
const d = new Date(ts);
|
|
3728
|
+
const day = new Date(d.getFullYear(), d.getMonth(), d.getDate());
|
|
3729
|
+
day.setDate(day.getDate() - day.getDay());
|
|
3730
|
+
return day.getTime();
|
|
2230
3731
|
}
|
|
2231
|
-
|
|
2232
|
-
|
|
2233
|
-
|
|
2234
|
-
|
|
2235
|
-
|
|
2236
|
-
|
|
2237
|
-
|
|
2238
|
-
|
|
2239
|
-
|
|
2240
|
-
|
|
2241
|
-
|
|
2242
|
-
|
|
2243
|
-
|
|
2244
|
-
|
|
3732
|
+
var KeySpendTracker = (_class12 = class {
|
|
3733
|
+
constructor(seeder) {;_class12.prototype.__init21.call(this);
|
|
3734
|
+
this.seeder = seeder;
|
|
3735
|
+
}
|
|
3736
|
+
|
|
3737
|
+
/** apiKeyId → live accumulated spend (seeded lazily). */
|
|
3738
|
+
__init21() {this.spend = /* @__PURE__ */ new Map()}
|
|
3739
|
+
/**
|
|
3740
|
+
* Read the key's accumulated spend, seeding from the durable store on a cache
|
|
3741
|
+
* miss and rolling the daily/weekly windows on a hit.
|
|
3742
|
+
*/
|
|
3743
|
+
async getSpend(apiKeyId, now) {
|
|
3744
|
+
const existing = this.spend.get(apiKeyId);
|
|
3745
|
+
if (existing) {
|
|
3746
|
+
rollWindows(existing, now);
|
|
3747
|
+
return existing;
|
|
2245
3748
|
}
|
|
3749
|
+
const seeded = await this.seed(apiKeyId, now);
|
|
3750
|
+
const existingAfterSeed = this.spend.get(apiKeyId);
|
|
3751
|
+
if (existingAfterSeed) {
|
|
3752
|
+
rollWindows(existingAfterSeed, now);
|
|
3753
|
+
return existingAfterSeed;
|
|
3754
|
+
}
|
|
3755
|
+
this.spend.set(apiKeyId, seeded);
|
|
3756
|
+
return seeded;
|
|
3757
|
+
}
|
|
3758
|
+
/**
|
|
3759
|
+
* Increment the aggregate for one recorded request. No-op when the key has not
|
|
3760
|
+
* been seeded yet — a later `getSpend` will lazy-seed from the durable store,
|
|
3761
|
+
* which already includes this record, so it is neither lost nor double-counted.
|
|
3762
|
+
*/
|
|
3763
|
+
add(apiKeyId, costUsd, now) {
|
|
3764
|
+
const s = this.spend.get(apiKeyId);
|
|
3765
|
+
if (!s) return;
|
|
3766
|
+
rollWindows(s, now);
|
|
3767
|
+
s.dailyUsd += costUsd;
|
|
3768
|
+
s.weeklyUsd += costUsd;
|
|
3769
|
+
s.totalUsd += costUsd;
|
|
3770
|
+
}
|
|
3771
|
+
/** Drop all cached spend (tests / teardown). */
|
|
3772
|
+
reset() {
|
|
3773
|
+
this.spend.clear();
|
|
3774
|
+
}
|
|
3775
|
+
/**
|
|
3776
|
+
* Derive a fresh spend snapshot for `apiKeyId` from the durable store in a
|
|
3777
|
+
* SINGLE scan (all three windows at once). `endTs` is EXCLUSIVE, so `now + 1`
|
|
3778
|
+
* includes a record stamped at exactly `now`.
|
|
3779
|
+
*/
|
|
3780
|
+
async seed(apiKeyId, now) {
|
|
3781
|
+
const dailyWindowStart = startOfLocalDay(now);
|
|
3782
|
+
const weeklyWindowStart = startOfLocalWeek(now);
|
|
3783
|
+
const { totalUsd, dailyUsd, weeklyUsd } = await this.seeder.getSpendByKey({
|
|
3784
|
+
apiKeyId,
|
|
3785
|
+
dayStartTs: dailyWindowStart,
|
|
3786
|
+
weekStartTs: weeklyWindowStart,
|
|
3787
|
+
endTs: now + 1
|
|
3788
|
+
});
|
|
3789
|
+
return { dailyUsd, dailyWindowStart, weeklyUsd, weeklyWindowStart, totalUsd };
|
|
3790
|
+
}
|
|
3791
|
+
}, _class12);
|
|
3792
|
+
function rollWindows(s, now) {
|
|
3793
|
+
const day = startOfLocalDay(now);
|
|
3794
|
+
if (s.dailyWindowStart !== day) {
|
|
3795
|
+
s.dailyUsd = 0;
|
|
3796
|
+
s.dailyWindowStart = day;
|
|
3797
|
+
}
|
|
3798
|
+
const week = startOfLocalWeek(now);
|
|
3799
|
+
if (s.weeklyWindowStart !== week) {
|
|
3800
|
+
s.weeklyUsd = 0;
|
|
3801
|
+
s.weeklyWindowStart = week;
|
|
2246
3802
|
}
|
|
2247
|
-
return {
|
|
2248
|
-
enabled: raw.enabled === true,
|
|
2249
|
-
networkBinding: raw.networkBinding === true,
|
|
2250
|
-
endpoints: ALL_ENDPOINTS.map(
|
|
2251
|
-
(ep) => _nullishCoalesce(byEndpoint.get(ep), () => ( defaultEndpointConfig(ep)))
|
|
2252
|
-
),
|
|
2253
|
-
port: _nullishCoalesce(raw.port, () => ( base.port))
|
|
2254
|
-
};
|
|
2255
|
-
}
|
|
2256
|
-
async function loadServerConfig(store) {
|
|
2257
|
-
const raw = await store.get(
|
|
2258
|
-
OUTBOUND_API_SERVER_CONFIG_KEY
|
|
2259
|
-
);
|
|
2260
|
-
return normalizeServerConfig(raw);
|
|
2261
|
-
}
|
|
2262
|
-
async function saveServerConfig(store, config) {
|
|
2263
|
-
await store.set(OUTBOUND_API_SERVER_CONFIG_KEY, config);
|
|
2264
|
-
}
|
|
2265
|
-
function mergeServerConfig(current, patch) {
|
|
2266
|
-
return normalizeServerConfig({
|
|
2267
|
-
enabled: _nullishCoalesce(patch.enabled, () => ( current.enabled)),
|
|
2268
|
-
networkBinding: _nullishCoalesce(patch.networkBinding, () => ( current.networkBinding)),
|
|
2269
|
-
endpoints: _nullishCoalesce(patch.endpoints, () => ( current.endpoints)),
|
|
2270
|
-
port: _nullishCoalesce(patch.port, () => ( current.port))
|
|
2271
|
-
});
|
|
2272
3803
|
}
|
|
2273
3804
|
|
|
2274
3805
|
// src/outbound-api/index.ts
|
|
@@ -2304,7 +3835,7 @@ async function callOpenAICompletion(provider, apiKey, options, logger) {
|
|
|
2304
3835
|
}
|
|
2305
3836
|
}
|
|
2306
3837
|
const apiUrl = _chunkA2YMUCBTcjs.buildProviderApiUrl.call(void 0, provider, { model: options.model, stream: false });
|
|
2307
|
-
const headers =
|
|
3838
|
+
const headers = _chunkQ27JY5RGcjs.getProviderHeaders.call(void 0, provider, apiKey);
|
|
2308
3839
|
logger.info("Calling OpenAI completion API", { url: apiUrl, model: options.model });
|
|
2309
3840
|
const response = await fetch(apiUrl, {
|
|
2310
3841
|
method: "POST",
|
|
@@ -2350,7 +3881,7 @@ async function callAnthropicCompletion(provider, apiKey, options, logger) {
|
|
|
2350
3881
|
stream: false
|
|
2351
3882
|
};
|
|
2352
3883
|
const apiUrl2 = _chunkA2YMUCBTcjs.buildProviderApiUrl.call(void 0, provider, { model: options.model, stream: false });
|
|
2353
|
-
const headers2 =
|
|
3884
|
+
const headers2 = _chunkQ27JY5RGcjs.getProviderHeaders.call(void 0, provider, apiKey);
|
|
2354
3885
|
logger.info("Calling Anthropic completion API with images", { url: apiUrl2, model: options.model });
|
|
2355
3886
|
const response2 = await fetch(apiUrl2, {
|
|
2356
3887
|
method: "POST",
|
|
@@ -2372,7 +3903,7 @@ async function callAnthropicCompletion(provider, apiKey, options, logger) {
|
|
|
2372
3903
|
message: {
|
|
2373
3904
|
id: `assistant-${Date.now()}`,
|
|
2374
3905
|
role: "assistant",
|
|
2375
|
-
content: _optionalChain([choice2, 'access',
|
|
3906
|
+
content: _optionalChain([choice2, 'access', _147 => _147.message, 'optionalAccess', _148 => _148.content]) || "",
|
|
2376
3907
|
timestamp: Date.now()
|
|
2377
3908
|
},
|
|
2378
3909
|
usage: openaiResponse2.usage ? {
|
|
@@ -2398,7 +3929,7 @@ async function callAnthropicCompletion(provider, apiKey, options, logger) {
|
|
|
2398
3929
|
};
|
|
2399
3930
|
const anthropicRequest = _chunkSUEGJ75Dcjs.convertOpenAIToAnthropic.call(void 0, openaiRequest, config);
|
|
2400
3931
|
const apiUrl = _chunkA2YMUCBTcjs.buildProviderApiUrl.call(void 0, provider, { model: options.model, stream: false });
|
|
2401
|
-
const headers =
|
|
3932
|
+
const headers = _chunkQ27JY5RGcjs.getProviderHeaders.call(void 0, provider, apiKey);
|
|
2402
3933
|
logger.info("Calling Anthropic completion API", { url: apiUrl, model: options.model });
|
|
2403
3934
|
const response = await fetch(apiUrl, {
|
|
2404
3935
|
method: "POST",
|
|
@@ -2452,7 +3983,7 @@ async function callGeminiCompletion(provider, apiKey, options, logger) {
|
|
|
2452
3983
|
request.systemInstruction = systemInstruction;
|
|
2453
3984
|
}
|
|
2454
3985
|
const apiUrl = _chunkA2YMUCBTcjs.buildProviderApiUrl.call(void 0, provider, { model: options.model, stream: false });
|
|
2455
|
-
const headers =
|
|
3986
|
+
const headers = _chunkQ27JY5RGcjs.getProviderHeaders.call(void 0, provider, apiKey);
|
|
2456
3987
|
logger.info("Calling Gemini completion API", { url: apiUrl, model: options.model });
|
|
2457
3988
|
const response = await fetch(apiUrl, {
|
|
2458
3989
|
method: "POST",
|
|
@@ -2477,7 +4008,7 @@ async function callGeminiCompletion(provider, apiKey, options, logger) {
|
|
|
2477
4008
|
const candidate = candidates[0];
|
|
2478
4009
|
const content = candidate.content;
|
|
2479
4010
|
let textContent = "";
|
|
2480
|
-
if (_optionalChain([content, 'optionalAccess',
|
|
4011
|
+
if (_optionalChain([content, 'optionalAccess', _149 => _149.parts])) {
|
|
2481
4012
|
for (const part of content.parts) {
|
|
2482
4013
|
if (part.text) {
|
|
2483
4014
|
textContent += part.text;
|
|
@@ -2523,7 +4054,7 @@ async function callOpenAIResponseCompletion(provider, apiKey, options, logger) {
|
|
|
2523
4054
|
}
|
|
2524
4055
|
}
|
|
2525
4056
|
const apiUrl = _chunkA2YMUCBTcjs.buildProviderApiUrl.call(void 0, provider, { model: options.model, stream: false });
|
|
2526
|
-
const headers =
|
|
4057
|
+
const headers = _chunkQ27JY5RGcjs.getProviderHeaders.call(void 0, provider, apiKey);
|
|
2527
4058
|
logger.info("Calling OpenAI Response API", { url: apiUrl, model: options.model });
|
|
2528
4059
|
const response = await fetch(apiUrl, {
|
|
2529
4060
|
method: "POST",
|
|
@@ -2589,9 +4120,9 @@ async function streamOpenAICompletion(provider, apiKey, options, messageId, call
|
|
|
2589
4120
|
}
|
|
2590
4121
|
}
|
|
2591
4122
|
const apiUrl = _chunkA2YMUCBTcjs.buildProviderApiUrl.call(void 0, provider, { model: options.model, stream: true });
|
|
2592
|
-
const headers =
|
|
4123
|
+
const headers = _chunkQ27JY5RGcjs.getProviderHeaders.call(void 0, provider, apiKey);
|
|
2593
4124
|
if (options.nativeSearchAugmentation) {
|
|
2594
|
-
|
|
4125
|
+
_chunkJMJBSACDcjs.applyAugmentation.call(void 0, request, options.nativeSearchAugmentation);
|
|
2595
4126
|
}
|
|
2596
4127
|
logger.info("Streaming OpenAI completion request", {
|
|
2597
4128
|
url: apiUrl,
|
|
@@ -2610,7 +4141,7 @@ async function streamOpenAICompletion(provider, apiKey, options, messageId, call
|
|
|
2610
4141
|
});
|
|
2611
4142
|
if (!response.ok) {
|
|
2612
4143
|
const errorText = await response.text();
|
|
2613
|
-
_optionalChain([callbacks, 'access',
|
|
4144
|
+
_optionalChain([callbacks, 'access', _150 => _150.onError, 'optionalCall', _151 => _151(`API error (${response.status}): ${errorText}`)]);
|
|
2614
4145
|
return;
|
|
2615
4146
|
}
|
|
2616
4147
|
const result = await _chunkHQP3K7PUcjs.streamSSEResponse.call(void 0, response, "openai", {
|
|
@@ -2620,7 +4151,7 @@ async function streamOpenAICompletion(provider, apiKey, options, messageId, call
|
|
|
2620
4151
|
onVideo: callbacks.onVideo,
|
|
2621
4152
|
onError: callbacks.onError
|
|
2622
4153
|
});
|
|
2623
|
-
_optionalChain([callbacks, 'access',
|
|
4154
|
+
_optionalChain([callbacks, 'access', _152 => _152.onDone, 'optionalCall', _153 => _153(
|
|
2624
4155
|
{
|
|
2625
4156
|
id: messageId,
|
|
2626
4157
|
role: "assistant",
|
|
@@ -2685,14 +4216,14 @@ async function streamAnthropicCompletion(provider, apiKey, options, messageId, c
|
|
|
2685
4216
|
}
|
|
2686
4217
|
}
|
|
2687
4218
|
const apiUrl = _chunkA2YMUCBTcjs.buildProviderApiUrl.call(void 0, provider, { model: options.model, stream: true });
|
|
2688
|
-
const headers =
|
|
4219
|
+
const headers = _chunkQ27JY5RGcjs.getProviderHeaders.call(void 0, provider, apiKey);
|
|
2689
4220
|
if (options.nativeSearchAugmentation) {
|
|
2690
|
-
|
|
4221
|
+
_chunkJMJBSACDcjs.applyAugmentation.call(void 0, anthropicRequest, options.nativeSearchAugmentation);
|
|
2691
4222
|
}
|
|
2692
4223
|
logger.info("Streaming Anthropic completion request", {
|
|
2693
4224
|
url: apiUrl,
|
|
2694
4225
|
model: anthropicRequest.model,
|
|
2695
|
-
messagesCount: _optionalChain([anthropicRequest, 'access',
|
|
4226
|
+
messagesCount: _optionalChain([anthropicRequest, 'access', _154 => _154.messages, 'optionalAccess', _155 => _155.length]),
|
|
2696
4227
|
max_tokens: anthropicRequest.max_tokens,
|
|
2697
4228
|
temperature: anthropicRequest.temperature,
|
|
2698
4229
|
stream: anthropicRequest.stream,
|
|
@@ -2709,7 +4240,7 @@ async function streamAnthropicCompletion(provider, apiKey, options, messageId, c
|
|
|
2709
4240
|
if (!response.ok) {
|
|
2710
4241
|
const errorText = await response.text();
|
|
2711
4242
|
logger.error("Anthropic API error", void 0, { status: response.status, errorText });
|
|
2712
|
-
_optionalChain([callbacks, 'access',
|
|
4243
|
+
_optionalChain([callbacks, 'access', _156 => _156.onError, 'optionalCall', _157 => _157(`API error (${response.status}): ${errorText}`)]);
|
|
2713
4244
|
return;
|
|
2714
4245
|
}
|
|
2715
4246
|
const result = await _chunkHQP3K7PUcjs.streamSSEResponse.call(void 0, response, "anthropic", {
|
|
@@ -2720,10 +4251,10 @@ async function streamAnthropicCompletion(provider, apiKey, options, messageId, c
|
|
|
2720
4251
|
});
|
|
2721
4252
|
logger.info("Anthropic stream complete", {
|
|
2722
4253
|
contentLength: result.content.length,
|
|
2723
|
-
reasoningLength: _optionalChain([result, 'access',
|
|
4254
|
+
reasoningLength: _optionalChain([result, 'access', _158 => _158.reasoning, 'optionalAccess', _159 => _159.length]) || 0,
|
|
2724
4255
|
blocksCount: result.blocks.length
|
|
2725
4256
|
});
|
|
2726
|
-
_optionalChain([callbacks, 'access',
|
|
4257
|
+
_optionalChain([callbacks, 'access', _160 => _160.onDone, 'optionalCall', _161 => _161(
|
|
2727
4258
|
{
|
|
2728
4259
|
id: messageId,
|
|
2729
4260
|
role: "assistant",
|
|
@@ -2757,9 +4288,9 @@ async function streamGeminiCompletion(provider, apiKey, options, messageId, call
|
|
|
2757
4288
|
request.systemInstruction = systemInstruction;
|
|
2758
4289
|
}
|
|
2759
4290
|
const apiUrl = _chunkA2YMUCBTcjs.buildProviderApiUrl.call(void 0, provider, { model: options.model, stream: true });
|
|
2760
|
-
const headers =
|
|
4291
|
+
const headers = _chunkQ27JY5RGcjs.getProviderHeaders.call(void 0, provider, apiKey);
|
|
2761
4292
|
if (options.nativeSearchAugmentation) {
|
|
2762
|
-
|
|
4293
|
+
_chunkJMJBSACDcjs.applyAugmentation.call(void 0, request, options.nativeSearchAugmentation);
|
|
2763
4294
|
}
|
|
2764
4295
|
logger.info("Streaming Gemini completion request", {
|
|
2765
4296
|
url: apiUrl,
|
|
@@ -2779,7 +4310,7 @@ async function streamGeminiCompletion(provider, apiKey, options, messageId, call
|
|
|
2779
4310
|
if (!response.ok) {
|
|
2780
4311
|
const errorText = await response.text();
|
|
2781
4312
|
logger.error("Gemini API error", void 0, { status: response.status, errorText });
|
|
2782
|
-
_optionalChain([callbacks, 'access',
|
|
4313
|
+
_optionalChain([callbacks, 'access', _162 => _162.onError, 'optionalCall', _163 => _163(`API error (${response.status}): ${errorText}`)]);
|
|
2783
4314
|
return;
|
|
2784
4315
|
}
|
|
2785
4316
|
const result = await _chunkHQP3K7PUcjs.streamSSEResponse.call(void 0, response, "gemini", {
|
|
@@ -2788,7 +4319,7 @@ async function streamGeminiCompletion(provider, apiKey, options, messageId, call
|
|
|
2788
4319
|
onError: callbacks.onError
|
|
2789
4320
|
});
|
|
2790
4321
|
logger.info("Gemini stream complete", { contentLength: result.content.length });
|
|
2791
|
-
_optionalChain([callbacks, 'access',
|
|
4322
|
+
_optionalChain([callbacks, 'access', _164 => _164.onDone, 'optionalCall', _165 => _165(
|
|
2792
4323
|
{
|
|
2793
4324
|
id: messageId,
|
|
2794
4325
|
role: "assistant",
|
|
@@ -2823,7 +4354,7 @@ async function streamOpenAIResponseCompletion(provider, apiKey, options, message
|
|
|
2823
4354
|
}
|
|
2824
4355
|
}
|
|
2825
4356
|
const apiUrl = _chunkA2YMUCBTcjs.buildProviderApiUrl.call(void 0, provider, { model: options.model, stream: true });
|
|
2826
|
-
const headers =
|
|
4357
|
+
const headers = _chunkQ27JY5RGcjs.getProviderHeaders.call(void 0, provider, apiKey);
|
|
2827
4358
|
logger.info("Streaming OpenAI Response API request", {
|
|
2828
4359
|
url: apiUrl,
|
|
2829
4360
|
providerId: options.providerId,
|
|
@@ -2840,7 +4371,7 @@ async function streamOpenAIResponseCompletion(provider, apiKey, options, message
|
|
|
2840
4371
|
});
|
|
2841
4372
|
if (!response.ok) {
|
|
2842
4373
|
const errorText = await response.text();
|
|
2843
|
-
_optionalChain([callbacks, 'access',
|
|
4374
|
+
_optionalChain([callbacks, 'access', _166 => _166.onError, 'optionalCall', _167 => _167(`API error (${response.status}): ${errorText}`)]);
|
|
2844
4375
|
return;
|
|
2845
4376
|
}
|
|
2846
4377
|
const result = await _chunkHQP3K7PUcjs.streamSSEResponse.call(void 0, response, "openai-response", {
|
|
@@ -2849,7 +4380,7 @@ async function streamOpenAIResponseCompletion(provider, apiKey, options, message
|
|
|
2849
4380
|
onError: callbacks.onError
|
|
2850
4381
|
});
|
|
2851
4382
|
logger.info("OpenAI Response API stream complete", { contentLength: result.content.length });
|
|
2852
|
-
_optionalChain([callbacks, 'access',
|
|
4383
|
+
_optionalChain([callbacks, 'access', _168 => _168.onDone, 'optionalCall', _169 => _169(
|
|
2853
4384
|
{
|
|
2854
4385
|
id: messageId,
|
|
2855
4386
|
role: "assistant",
|
|
@@ -2877,7 +4408,7 @@ async function resolveEffectiveMaxTokens(llmConfig, getProvider, logger, provide
|
|
|
2877
4408
|
}
|
|
2878
4409
|
try {
|
|
2879
4410
|
const globalParams = await llmConfig.getGlobalModelParameters();
|
|
2880
|
-
if (_optionalChain([globalParams, 'optionalAccess',
|
|
4411
|
+
if (_optionalChain([globalParams, 'optionalAccess', _170 => _170.maxTokens, 'optionalAccess', _171 => _171.enabled]) && globalParams.maxTokens.value > 0) {
|
|
2881
4412
|
logger.debug("Using global maxTokens", { maxTokens: globalParams.maxTokens.value });
|
|
2882
4413
|
return globalParams.maxTokens.value;
|
|
2883
4414
|
}
|
|
@@ -2887,8 +4418,8 @@ async function resolveEffectiveMaxTokens(llmConfig, getProvider, logger, provide
|
|
|
2887
4418
|
const MAX_TOKENS_CAP = 131072;
|
|
2888
4419
|
const provider = await getProvider(providerId);
|
|
2889
4420
|
if (provider) {
|
|
2890
|
-
const modelConfig = _optionalChain([provider, 'access',
|
|
2891
|
-
if (_optionalChain([modelConfig, 'optionalAccess',
|
|
4421
|
+
const modelConfig = _optionalChain([provider, 'access', _172 => _172.modelConfigs, 'optionalAccess', _173 => _173.find, 'call', _174 => _174((m) => m.id === modelId)]);
|
|
4422
|
+
if (_optionalChain([modelConfig, 'optionalAccess', _175 => _175.maxTokens]) && modelConfig.maxTokens > 0) {
|
|
2892
4423
|
const cappedMaxTokens = Math.min(modelConfig.maxTokens, MAX_TOKENS_CAP);
|
|
2893
4424
|
logger.debug("Using model config maxTokens", {
|
|
2894
4425
|
maxTokens: modelConfig.maxTokens,
|
|
@@ -2898,8 +4429,8 @@ async function resolveEffectiveMaxTokens(llmConfig, getProvider, logger, provide
|
|
|
2898
4429
|
}
|
|
2899
4430
|
if (provider.modelGroups) {
|
|
2900
4431
|
for (const group of provider.modelGroups) {
|
|
2901
|
-
const model = _optionalChain([group, 'access',
|
|
2902
|
-
if (_optionalChain([model, 'optionalAccess',
|
|
4432
|
+
const model = _optionalChain([group, 'access', _176 => _176.models, 'optionalAccess', _177 => _177.find, 'call', _178 => _178((m) => m.id === modelId)]);
|
|
4433
|
+
if (_optionalChain([model, 'optionalAccess', _179 => _179.maxTokens]) && model.maxTokens > 0) {
|
|
2903
4434
|
const cappedMaxTokens = Math.min(model.maxTokens, MAX_TOKENS_CAP);
|
|
2904
4435
|
logger.debug("Using modelGroup model maxTokens", {
|
|
2905
4436
|
maxTokens: model.maxTokens,
|
|
@@ -2944,7 +4475,7 @@ async function resolveThinkingBudget(getProvider, logger, providerId, modelId, m
|
|
|
2944
4475
|
}
|
|
2945
4476
|
const thinkingBudget = _thinkingconfig.calculateThinkingBudget.call(void 0, modelId, thinkLevel, maxTokens);
|
|
2946
4477
|
const provider = await getProvider(providerId);
|
|
2947
|
-
const providerName = _optionalChain([provider, 'optionalAccess',
|
|
4478
|
+
const providerName = _optionalChain([provider, 'optionalAccess', _180 => _180.name, 'optionalAccess', _181 => _181.toLowerCase, 'call', _182 => _182()]) || "";
|
|
2948
4479
|
const apiFormat = provider ? _chunkA2YMUCBTcjs.resolveApiFormat.call(void 0, provider) : "openai";
|
|
2949
4480
|
if (apiFormat === "anthropic" || providerName === "anthropic" || providerName.includes("claude")) {
|
|
2950
4481
|
const thinkingConfig = _thinkingconfig.buildAnthropicThinking.call(void 0, modelId, thinkLevel, maxTokens);
|
|
@@ -2981,7 +4512,7 @@ function logToolFormat(tools, logger) {
|
|
|
2981
4512
|
tools: openaiTools.map((t) => t.function.name),
|
|
2982
4513
|
firstTool: {
|
|
2983
4514
|
name: firstTool.function.name,
|
|
2984
|
-
description: _optionalChain([firstTool, 'access',
|
|
4515
|
+
description: _optionalChain([firstTool, 'access', _183 => _183.function, 'access', _184 => _184.description, 'optionalAccess', _185 => _185.slice, 'call', _186 => _186(0, 100)]),
|
|
2985
4516
|
parameters: firstTool.function.parameters
|
|
2986
4517
|
}
|
|
2987
4518
|
});
|
|
@@ -2992,7 +4523,7 @@ function logToolFormat(tools, logger) {
|
|
|
2992
4523
|
tools: anthropicTools.map((t) => t.name),
|
|
2993
4524
|
firstTool: {
|
|
2994
4525
|
name: firstTool.name,
|
|
2995
|
-
description: _optionalChain([firstTool, 'access',
|
|
4526
|
+
description: _optionalChain([firstTool, 'access', _187 => _187.description, 'optionalAccess', _188 => _188.slice, 'call', _189 => _189(0, 100)]),
|
|
2996
4527
|
input_schema: firstTool.input_schema
|
|
2997
4528
|
}
|
|
2998
4529
|
});
|
|
@@ -3003,9 +4534,9 @@ function logToolFormat(tools, logger) {
|
|
|
3003
4534
|
count: allDeclarations.length,
|
|
3004
4535
|
tools: allDeclarations.map((t) => t.name),
|
|
3005
4536
|
firstTool: {
|
|
3006
|
-
name: _optionalChain([allDeclarations, 'access',
|
|
3007
|
-
description: _optionalChain([allDeclarations, 'access',
|
|
3008
|
-
parameters: _optionalChain([allDeclarations, 'access',
|
|
4537
|
+
name: _optionalChain([allDeclarations, 'access', _190 => _190[0], 'optionalAccess', _191 => _191.name]),
|
|
4538
|
+
description: _optionalChain([allDeclarations, 'access', _192 => _192[0], 'optionalAccess', _193 => _193.description, 'optionalAccess', _194 => _194.slice, 'call', _195 => _195(0, 100)]),
|
|
4539
|
+
parameters: _optionalChain([allDeclarations, 'access', _196 => _196[0], 'optionalAccess', _197 => _197.parameters])
|
|
3009
4540
|
}
|
|
3010
4541
|
});
|
|
3011
4542
|
}
|
|
@@ -3064,7 +4595,7 @@ function buildToolRequest(apiFormat, conversationMessages, actualModel, options,
|
|
|
3064
4595
|
function extractDeltaContent(rawJson, apiFormat) {
|
|
3065
4596
|
const json = rawJson;
|
|
3066
4597
|
if (apiFormat === "google") {
|
|
3067
|
-
const parts = _optionalChain([json, 'access',
|
|
4598
|
+
const parts = _optionalChain([json, 'access', _198 => _198.candidates, 'optionalAccess', _199 => _199[0], 'optionalAccess', _200 => _200.content, 'optionalAccess', _201 => _201.parts]) || [];
|
|
3068
4599
|
let text = "";
|
|
3069
4600
|
for (const part of parts) {
|
|
3070
4601
|
if (part.thought === true) continue;
|
|
@@ -3072,15 +4603,15 @@ function extractDeltaContent(rawJson, apiFormat) {
|
|
|
3072
4603
|
}
|
|
3073
4604
|
return text;
|
|
3074
4605
|
} else if (apiFormat === "anthropic") {
|
|
3075
|
-
return _optionalChain([json, 'access',
|
|
4606
|
+
return _optionalChain([json, 'access', _202 => _202.delta, 'optionalAccess', _203 => _203.text]) || "";
|
|
3076
4607
|
} else {
|
|
3077
|
-
return _optionalChain([json, 'access',
|
|
4608
|
+
return _optionalChain([json, 'access', _204 => _204.choices, 'optionalAccess', _205 => _205[0], 'optionalAccess', _206 => _206.delta, 'optionalAccess', _207 => _207.content]) || "";
|
|
3078
4609
|
}
|
|
3079
4610
|
}
|
|
3080
4611
|
function extractDeltaReasoning(rawJson, apiFormat) {
|
|
3081
4612
|
const json = rawJson;
|
|
3082
4613
|
if (apiFormat === "google") {
|
|
3083
|
-
const parts = _optionalChain([json, 'access',
|
|
4614
|
+
const parts = _optionalChain([json, 'access', _208 => _208.candidates, 'optionalAccess', _209 => _209[0], 'optionalAccess', _210 => _210.content, 'optionalAccess', _211 => _211.parts]) || [];
|
|
3084
4615
|
let reasoning = "";
|
|
3085
4616
|
for (const part of parts) {
|
|
3086
4617
|
if (part.thought === true && part.text) reasoning += part.text;
|
|
@@ -3089,14 +4620,14 @@ function extractDeltaReasoning(rawJson, apiFormat) {
|
|
|
3089
4620
|
} else if (apiFormat === "anthropic") {
|
|
3090
4621
|
return "";
|
|
3091
4622
|
} else {
|
|
3092
|
-
const delta = _optionalChain([json, 'access',
|
|
3093
|
-
return (_optionalChain([delta, 'optionalAccess',
|
|
4623
|
+
const delta = _optionalChain([json, 'access', _212 => _212.choices, 'optionalAccess', _213 => _213[0], 'optionalAccess', _214 => _214.delta]);
|
|
4624
|
+
return (_optionalChain([delta, 'optionalAccess', _215 => _215.thinking, 'optionalAccess', _216 => _216.content]) || "") + (_optionalChain([delta, 'optionalAccess', _217 => _217.reasoning_content]) || "");
|
|
3094
4625
|
}
|
|
3095
4626
|
}
|
|
3096
4627
|
function extractToolCalls(rawJson, apiFormat, toolCalls, callbacks, logger, pendingOpenAIToolCalls) {
|
|
3097
4628
|
const json = rawJson;
|
|
3098
4629
|
if (apiFormat === "google") {
|
|
3099
|
-
const parts = _optionalChain([json, 'access',
|
|
4630
|
+
const parts = _optionalChain([json, 'access', _218 => _218.candidates, 'optionalAccess', _219 => _219[0], 'optionalAccess', _220 => _220.content, 'optionalAccess', _221 => _221.parts]) || [];
|
|
3100
4631
|
for (const part of parts) {
|
|
3101
4632
|
if (part.functionCall) {
|
|
3102
4633
|
logger.info("Function call detected", { functionCall: part.functionCall });
|
|
@@ -3106,13 +4637,13 @@ function extractToolCalls(rawJson, apiFormat, toolCalls, callbacks, logger, pend
|
|
|
3106
4637
|
args: part.functionCall.args || {}
|
|
3107
4638
|
};
|
|
3108
4639
|
toolCalls.push(toolCall);
|
|
3109
|
-
_optionalChain([callbacks, 'access',
|
|
4640
|
+
_optionalChain([callbacks, 'access', _222 => _222.onToolCall, 'optionalCall', _223 => _223(toolCall)]);
|
|
3110
4641
|
logger.info("Tool called", { toolName: toolCall.name });
|
|
3111
4642
|
}
|
|
3112
4643
|
}
|
|
3113
4644
|
} else if (apiFormat !== "anthropic") {
|
|
3114
|
-
const delta = _optionalChain([json, 'access',
|
|
3115
|
-
if (_optionalChain([delta, 'optionalAccess',
|
|
4645
|
+
const delta = _optionalChain([json, 'access', _224 => _224.choices, 'optionalAccess', _225 => _225[0], 'optionalAccess', _226 => _226.delta]);
|
|
4646
|
+
if (_optionalChain([delta, 'optionalAccess', _227 => _227.tool_calls]) && pendingOpenAIToolCalls) {
|
|
3116
4647
|
for (const tc of delta.tool_calls) {
|
|
3117
4648
|
const index = _nullishCoalesce(tc.index, () => ( 0));
|
|
3118
4649
|
let pending = pendingOpenAIToolCalls.get(index);
|
|
@@ -3121,8 +4652,8 @@ function extractToolCalls(rawJson, apiFormat, toolCalls, callbacks, logger, pend
|
|
|
3121
4652
|
pendingOpenAIToolCalls.set(index, pending);
|
|
3122
4653
|
}
|
|
3123
4654
|
if (tc.id) pending.id = tc.id;
|
|
3124
|
-
if (_optionalChain([tc, 'access',
|
|
3125
|
-
if (_optionalChain([tc, 'access',
|
|
4655
|
+
if (_optionalChain([tc, 'access', _228 => _228.function, 'optionalAccess', _229 => _229.name])) pending.name += tc.function.name;
|
|
4656
|
+
if (_optionalChain([tc, 'access', _230 => _230.function, 'optionalAccess', _231 => _231.arguments])) pending.arguments += tc.function.arguments;
|
|
3126
4657
|
}
|
|
3127
4658
|
}
|
|
3128
4659
|
}
|
|
@@ -3137,7 +4668,7 @@ function finalizeOpenAIToolCalls(pendingOpenAIToolCalls, toolCalls, callbacks, l
|
|
|
3137
4668
|
args: JSON.parse(pending.arguments || "{}")
|
|
3138
4669
|
};
|
|
3139
4670
|
toolCalls.push(toolCall);
|
|
3140
|
-
_optionalChain([callbacks, 'access',
|
|
4671
|
+
_optionalChain([callbacks, 'access', _232 => _232.onToolCall, 'optionalCall', _233 => _233(toolCall)]);
|
|
3141
4672
|
logger.info("Tool called (OpenAI)", { toolName: toolCall.name, args: toolCall.args });
|
|
3142
4673
|
} catch (e) {
|
|
3143
4674
|
logger.error("Failed to parse OpenAI tool call arguments", e instanceof Error ? e : void 0, {
|
|
@@ -3151,38 +4682,38 @@ function finalizeOpenAIToolCalls(pendingOpenAIToolCalls, toolCalls, callbacks, l
|
|
|
3151
4682
|
function parseStreamChunk(rawJson, apiFormat, callbacks, logger) {
|
|
3152
4683
|
const json = rawJson;
|
|
3153
4684
|
if (apiFormat === "google") {
|
|
3154
|
-
const candidate = _optionalChain([json, 'access',
|
|
4685
|
+
const candidate = _optionalChain([json, 'access', _234 => _234.candidates, 'optionalAccess', _235 => _235[0]]);
|
|
3155
4686
|
if (!candidate) {
|
|
3156
4687
|
logger.warn("No candidate found in Gemini response");
|
|
3157
4688
|
return;
|
|
3158
4689
|
}
|
|
3159
|
-
const parts = _optionalChain([candidate, 'access',
|
|
4690
|
+
const parts = _optionalChain([candidate, 'access', _236 => _236.content, 'optionalAccess', _237 => _237.parts]) || [];
|
|
3160
4691
|
for (const part of parts) {
|
|
3161
4692
|
if (part.thought === true && part.text) {
|
|
3162
|
-
_optionalChain([callbacks, 'access',
|
|
4693
|
+
_optionalChain([callbacks, 'access', _238 => _238.onReasoning, 'optionalCall', _239 => _239(part.text)]);
|
|
3163
4694
|
continue;
|
|
3164
4695
|
} else if (part.thoughtSignature && !part.thought) {
|
|
3165
4696
|
logger.debug("Gemini returned thoughtSignature without thought content");
|
|
3166
4697
|
}
|
|
3167
4698
|
if (part.text) {
|
|
3168
|
-
_optionalChain([callbacks, 'access',
|
|
4699
|
+
_optionalChain([callbacks, 'access', _240 => _240.onDelta, 'optionalCall', _241 => _241(part.text)]);
|
|
3169
4700
|
}
|
|
3170
4701
|
}
|
|
3171
4702
|
} else if (apiFormat === "anthropic") {
|
|
3172
4703
|
const delta = json.delta;
|
|
3173
|
-
if (_optionalChain([delta, 'optionalAccess',
|
|
3174
|
-
_optionalChain([callbacks, 'access',
|
|
4704
|
+
if (_optionalChain([delta, 'optionalAccess', _242 => _242.text])) {
|
|
4705
|
+
_optionalChain([callbacks, 'access', _243 => _243.onDelta, 'optionalCall', _244 => _244(delta.text)]);
|
|
3175
4706
|
}
|
|
3176
4707
|
} else {
|
|
3177
|
-
const delta = _optionalChain([json, 'access',
|
|
3178
|
-
if (_optionalChain([delta, 'optionalAccess',
|
|
3179
|
-
_optionalChain([callbacks, 'access',
|
|
4708
|
+
const delta = _optionalChain([json, 'access', _245 => _245.choices, 'optionalAccess', _246 => _246[0], 'optionalAccess', _247 => _247.delta]);
|
|
4709
|
+
if (_optionalChain([delta, 'optionalAccess', _248 => _248.content])) {
|
|
4710
|
+
_optionalChain([callbacks, 'access', _249 => _249.onDelta, 'optionalCall', _250 => _250(delta.content)]);
|
|
3180
4711
|
}
|
|
3181
|
-
if (_optionalChain([delta, 'optionalAccess',
|
|
3182
|
-
_optionalChain([callbacks, 'access',
|
|
4712
|
+
if (_optionalChain([delta, 'optionalAccess', _251 => _251.thinking, 'optionalAccess', _252 => _252.content])) {
|
|
4713
|
+
_optionalChain([callbacks, 'access', _253 => _253.onReasoning, 'optionalCall', _254 => _254(delta.thinking.content)]);
|
|
3183
4714
|
}
|
|
3184
|
-
if (_optionalChain([delta, 'optionalAccess',
|
|
3185
|
-
_optionalChain([callbacks, 'access',
|
|
4715
|
+
if (_optionalChain([delta, 'optionalAccess', _255 => _255.reasoning_content])) {
|
|
4716
|
+
_optionalChain([callbacks, 'access', _256 => _256.onReasoning, 'optionalCall', _257 => _257(delta.reasoning_content)]);
|
|
3186
4717
|
}
|
|
3187
4718
|
}
|
|
3188
4719
|
}
|
|
@@ -3195,7 +4726,7 @@ function buildIterationBlocks(iteration, content, reasoning, blocks, callbacks)
|
|
|
3195
4726
|
content: reasoning
|
|
3196
4727
|
};
|
|
3197
4728
|
blocks.push(thinkingBlock);
|
|
3198
|
-
_optionalChain([callbacks, 'access',
|
|
4729
|
+
_optionalChain([callbacks, 'access', _258 => _258.onBlock, 'optionalCall', _259 => _259(thinkingBlock)]);
|
|
3199
4730
|
}
|
|
3200
4731
|
if (content && content.trim()) {
|
|
3201
4732
|
const textBlock = {
|
|
@@ -3204,7 +4735,7 @@ function buildIterationBlocks(iteration, content, reasoning, blocks, callbacks)
|
|
|
3204
4735
|
content
|
|
3205
4736
|
};
|
|
3206
4737
|
blocks.push(textBlock);
|
|
3207
|
-
_optionalChain([callbacks, 'access',
|
|
4738
|
+
_optionalChain([callbacks, 'access', _260 => _260.onBlock, 'optionalCall', _261 => _261(textBlock)]);
|
|
3208
4739
|
}
|
|
3209
4740
|
}
|
|
3210
4741
|
async function executeToolCalls(toolCalls, mcpTools, mcpService, blocks, callbacks, logger, builtinExecutor) {
|
|
@@ -3219,7 +4750,7 @@ async function executeToolCalls(toolCalls, mcpTools, mcpService, blocks, callbac
|
|
|
3219
4750
|
status: "running"
|
|
3220
4751
|
};
|
|
3221
4752
|
blocks.push(toolUseBlock);
|
|
3222
|
-
_optionalChain([callbacks, 'access',
|
|
4753
|
+
_optionalChain([callbacks, 'access', _262 => _262.onBlock, 'optionalCall', _263 => _263(toolUseBlock)]);
|
|
3223
4754
|
try {
|
|
3224
4755
|
logger.info("Executing tool", { toolName: toolCall.name });
|
|
3225
4756
|
const mcpTool = mcpTools.find((t) => t.id === toolCall.name);
|
|
@@ -3242,8 +4773,8 @@ async function executeToolCalls(toolCalls, mcpTools, mcpService, blocks, callbac
|
|
|
3242
4773
|
result = { isError: true, content: [{ type: "text", text: "MCP service not available" }] };
|
|
3243
4774
|
}
|
|
3244
4775
|
logger.info("Tool result received", { result });
|
|
3245
|
-
_optionalChain([callbacks, 'access',
|
|
3246
|
-
const resultText = _optionalChain([result, 'access',
|
|
4776
|
+
_optionalChain([callbacks, 'access', _264 => _264.onToolResult, 'optionalCall', _265 => _265(toolCall.id, result)]);
|
|
4777
|
+
const resultText = _optionalChain([result, 'access', _266 => _266.content, 'optionalAccess', _267 => _267[0], 'optionalAccess', _268 => _268.text]) || JSON.stringify(result);
|
|
3247
4778
|
const toolResultBlock = {
|
|
3248
4779
|
id: `${toolCall.id}_result`,
|
|
3249
4780
|
type: "tool_result",
|
|
@@ -3253,11 +4784,11 @@ async function executeToolCalls(toolCalls, mcpTools, mcpService, blocks, callbac
|
|
|
3253
4784
|
isError: result.isError
|
|
3254
4785
|
};
|
|
3255
4786
|
blocks.push(toolResultBlock);
|
|
3256
|
-
_optionalChain([callbacks, 'access',
|
|
4787
|
+
_optionalChain([callbacks, 'access', _269 => _269.onBlock, 'optionalCall', _270 => _270(toolResultBlock)]);
|
|
3257
4788
|
const toolUseBlockRef = blocks.find((b) => b.id === `${toolCall.id}_use`);
|
|
3258
4789
|
if (toolUseBlockRef && toolUseBlockRef.type === "tool_use") {
|
|
3259
4790
|
toolUseBlockRef.status = result.isError ? "error" : "completed";
|
|
3260
|
-
_optionalChain([callbacks, 'access',
|
|
4791
|
+
_optionalChain([callbacks, 'access', _271 => _271.onBlock, 'optionalCall', _272 => _272({ ...toolUseBlockRef })]);
|
|
3261
4792
|
}
|
|
3262
4793
|
toolResults.push({ toolCall, result });
|
|
3263
4794
|
} catch (error) {
|
|
@@ -3267,7 +4798,7 @@ async function executeToolCalls(toolCalls, mcpTools, mcpService, blocks, callbac
|
|
|
3267
4798
|
isError: true,
|
|
3268
4799
|
content: [{ type: "text", text: `Error: ${errorMessage}` }]
|
|
3269
4800
|
};
|
|
3270
|
-
_optionalChain([callbacks, 'access',
|
|
4801
|
+
_optionalChain([callbacks, 'access', _273 => _273.onToolResult, 'optionalCall', _274 => _274(toolCall.id, errorResult)]);
|
|
3271
4802
|
const errorToolResultBlock = {
|
|
3272
4803
|
id: `${toolCall.id}_result`,
|
|
3273
4804
|
type: "tool_result",
|
|
@@ -3277,11 +4808,11 @@ async function executeToolCalls(toolCalls, mcpTools, mcpService, blocks, callbac
|
|
|
3277
4808
|
isError: true
|
|
3278
4809
|
};
|
|
3279
4810
|
blocks.push(errorToolResultBlock);
|
|
3280
|
-
_optionalChain([callbacks, 'access',
|
|
4811
|
+
_optionalChain([callbacks, 'access', _275 => _275.onBlock, 'optionalCall', _276 => _276(errorToolResultBlock)]);
|
|
3281
4812
|
const errorToolUseBlockRef = blocks.find((b) => b.id === `${toolCall.id}_use`);
|
|
3282
4813
|
if (errorToolUseBlockRef && errorToolUseBlockRef.type === "tool_use") {
|
|
3283
4814
|
errorToolUseBlockRef.status = "error";
|
|
3284
|
-
_optionalChain([callbacks, 'access',
|
|
4815
|
+
_optionalChain([callbacks, 'access', _277 => _277.onBlock, 'optionalCall', _278 => _278({ ...errorToolUseBlockRef })]);
|
|
3285
4816
|
}
|
|
3286
4817
|
toolResults.push({ toolCall, result: errorResult });
|
|
3287
4818
|
}
|
|
@@ -3291,7 +4822,7 @@ async function executeToolCalls(toolCalls, mcpTools, mcpService, blocks, callbac
|
|
|
3291
4822
|
function mapToolArguments(args, mcpTool, logger) {
|
|
3292
4823
|
const mappedArgs = { ...args };
|
|
3293
4824
|
const toolSchema = mcpTool.inputSchema;
|
|
3294
|
-
if (_optionalChain([toolSchema, 'optionalAccess',
|
|
4825
|
+
if (_optionalChain([toolSchema, 'optionalAccess', _279 => _279.properties])) {
|
|
3295
4826
|
const expectedParams = Object.keys(toolSchema.properties);
|
|
3296
4827
|
const paramMappings = {
|
|
3297
4828
|
"search_query": ["query", "q", "searchQuery", "search"],
|
|
@@ -3325,25 +4856,25 @@ async function streamWithTools(options, callbacks, mcpService, llmConfig, getPro
|
|
|
3325
4856
|
options.providerId,
|
|
3326
4857
|
options.model
|
|
3327
4858
|
);
|
|
3328
|
-
const actualProviderId = _optionalChain([routedInfo, 'optionalAccess',
|
|
3329
|
-
const actualModel = _optionalChain([routedInfo, 'optionalAccess',
|
|
4859
|
+
const actualProviderId = _optionalChain([routedInfo, 'optionalAccess', _280 => _280.actualProviderId]) || options.providerId;
|
|
4860
|
+
const actualModel = _optionalChain([routedInfo, 'optionalAccess', _281 => _281.actualModelId]) || options.model;
|
|
3330
4861
|
const provider = await getProvider(actualProviderId);
|
|
3331
4862
|
if (!provider) {
|
|
3332
|
-
_optionalChain([callbacks, 'access',
|
|
4863
|
+
_optionalChain([callbacks, 'access', _282 => _282.onError, 'optionalCall', _283 => _283(`Provider not found: ${actualProviderId}`)]);
|
|
3333
4864
|
return;
|
|
3334
4865
|
}
|
|
3335
4866
|
if (!provider.enabled) {
|
|
3336
|
-
_optionalChain([callbacks, 'access',
|
|
4867
|
+
_optionalChain([callbacks, 'access', _284 => _284.onError, 'optionalCall', _285 => _285(`Provider is disabled: ${provider.name}`)]);
|
|
3337
4868
|
return;
|
|
3338
4869
|
}
|
|
3339
4870
|
const { apiKey: effectiveKey } = _chunkA2YMUCBTcjs.resolveProviderEndpoint.call(void 0, provider);
|
|
3340
4871
|
const apiKey = resolveApiKey2(effectiveKey);
|
|
3341
4872
|
if (!apiKey) {
|
|
3342
|
-
_optionalChain([callbacks, 'access',
|
|
4873
|
+
_optionalChain([callbacks, 'access', _286 => _286.onError, 'optionalCall', _287 => _287("API key not configured")]);
|
|
3343
4874
|
return;
|
|
3344
4875
|
}
|
|
3345
4876
|
const messageId = `msg_${Date.now()}_${Math.random().toString(36).slice(2)}`;
|
|
3346
|
-
_optionalChain([callbacks, 'access',
|
|
4877
|
+
_optionalChain([callbacks, 'access', _288 => _288.onStart, 'optionalCall', _289 => _289(messageId)]);
|
|
3347
4878
|
const globalParams = await llmConfig.getGlobalModelParameters();
|
|
3348
4879
|
const MAX_ITERATIONS = _nullishCoalesce(globalParams.toolMaxTurns, () => ( 100));
|
|
3349
4880
|
let iteration = 0;
|
|
@@ -3375,9 +4906,9 @@ async function streamWithTools(options, callbacks, mcpService, llmConfig, getPro
|
|
|
3375
4906
|
provider
|
|
3376
4907
|
);
|
|
3377
4908
|
if (options.nativeSearchAugmentation) {
|
|
3378
|
-
|
|
4909
|
+
_chunkJMJBSACDcjs.applyAugmentation.call(void 0, requestBody, options.nativeSearchAugmentation);
|
|
3379
4910
|
}
|
|
3380
|
-
const headers =
|
|
4911
|
+
const headers = _chunkQ27JY5RGcjs.getProviderHeaders.call(void 0, provider, apiKey);
|
|
3381
4912
|
logger.info("Sending tool call request", {
|
|
3382
4913
|
url,
|
|
3383
4914
|
headers,
|
|
@@ -3390,12 +4921,12 @@ async function streamWithTools(options, callbacks, mcpService, llmConfig, getPro
|
|
|
3390
4921
|
});
|
|
3391
4922
|
if (!response.ok) {
|
|
3392
4923
|
const errorText = await response.text();
|
|
3393
|
-
_optionalChain([callbacks, 'access',
|
|
4924
|
+
_optionalChain([callbacks, 'access', _290 => _290.onError, 'optionalCall', _291 => _291(`API error (${response.status}): ${errorText}`)]);
|
|
3394
4925
|
return;
|
|
3395
4926
|
}
|
|
3396
|
-
const reader = _optionalChain([response, 'access',
|
|
4927
|
+
const reader = _optionalChain([response, 'access', _292 => _292.body, 'optionalAccess', _293 => _293.getReader, 'call', _294 => _294()]);
|
|
3397
4928
|
if (!reader) {
|
|
3398
|
-
_optionalChain([callbacks, 'access',
|
|
4929
|
+
_optionalChain([callbacks, 'access', _295 => _295.onError, 'optionalCall', _296 => _296("No response body")]);
|
|
3399
4930
|
return;
|
|
3400
4931
|
}
|
|
3401
4932
|
const decoder = new TextDecoder();
|
|
@@ -3428,7 +4959,7 @@ async function streamWithTools(options, callbacks, mcpService, llmConfig, getPro
|
|
|
3428
4959
|
logger.debug("Parsed JSON", { json });
|
|
3429
4960
|
if (json.error) {
|
|
3430
4961
|
logger.error("API Error", void 0, { error: json.error });
|
|
3431
|
-
_optionalChain([callbacks, 'access',
|
|
4962
|
+
_optionalChain([callbacks, 'access', _297 => _297.onError, 'optionalCall', _298 => _298(`API Error: ${json.error.message || JSON.stringify(json.error)}`)]);
|
|
3432
4963
|
return;
|
|
3433
4964
|
}
|
|
3434
4965
|
parseStreamChunk(json, apiFormat, callbacks, logger);
|
|
@@ -3461,7 +4992,7 @@ async function streamWithTools(options, callbacks, mcpService, llmConfig, getPro
|
|
|
3461
4992
|
toolCallsLength: toolCalls.length,
|
|
3462
4993
|
executableToolCallsLength: executableToolCalls.length,
|
|
3463
4994
|
hasMcpTools: !!options.mcpTools,
|
|
3464
|
-
mcpToolsLength: _optionalChain([options, 'access',
|
|
4995
|
+
mcpToolsLength: _optionalChain([options, 'access', _299 => _299.mcpTools, 'optionalAccess', _300 => _300.length]),
|
|
3465
4996
|
hasMcpService: !!mcpService
|
|
3466
4997
|
});
|
|
3467
4998
|
if (executableToolCalls.length > 0 && options.mcpTools && (mcpService || builtinExecutor)) {
|
|
@@ -3482,7 +5013,7 @@ async function streamWithTools(options, callbacks, mcpService, llmConfig, getPro
|
|
|
3482
5013
|
builtinExecutor
|
|
3483
5014
|
);
|
|
3484
5015
|
const toolResultsText = toolResults.map(({ toolCall, result }) => {
|
|
3485
|
-
const resultText = typeof result === "string" ? result : _optionalChain([result, 'access',
|
|
5016
|
+
const resultText = typeof result === "string" ? result : _optionalChain([result, 'access', _301 => _301.content, 'optionalAccess', _302 => _302[0], 'optionalAccess', _303 => _303.text]) || JSON.stringify(result);
|
|
3486
5017
|
return `Tool ${toolCall.name} result:
|
|
3487
5018
|
${resultText}`;
|
|
3488
5019
|
}).join("\n\n");
|
|
@@ -3500,12 +5031,12 @@ ${resultText}`;
|
|
|
3500
5031
|
}
|
|
3501
5032
|
} catch (streamError) {
|
|
3502
5033
|
logger.error("Stream processing error", streamError instanceof Error ? streamError : void 0);
|
|
3503
|
-
_optionalChain([callbacks, 'access',
|
|
5034
|
+
_optionalChain([callbacks, 'access', _304 => _304.onError, 'optionalCall', _305 => _305(`Stream error: ${streamError instanceof Error ? streamError.message : "Unknown error"}`)]);
|
|
3504
5035
|
return;
|
|
3505
5036
|
}
|
|
3506
5037
|
}
|
|
3507
5038
|
logger.info("Sending final callback", { blocksCount: blocks.length });
|
|
3508
|
-
_optionalChain([callbacks, 'access',
|
|
5039
|
+
_optionalChain([callbacks, 'access', _306 => _306.onDone, 'optionalCall', _307 => _307({
|
|
3509
5040
|
id: messageId,
|
|
3510
5041
|
role: "assistant",
|
|
3511
5042
|
content: finalContent,
|
|
@@ -3516,7 +5047,7 @@ ${resultText}`;
|
|
|
3516
5047
|
} catch (error) {
|
|
3517
5048
|
logger.error("Error in streamWithTools", error instanceof Error ? error : void 0);
|
|
3518
5049
|
const message = error instanceof Error ? error.message : "Unknown error";
|
|
3519
|
-
_optionalChain([callbacks, 'access',
|
|
5050
|
+
_optionalChain([callbacks, 'access', _308 => _308.onError, 'optionalCall', _309 => _309(message)]);
|
|
3520
5051
|
}
|
|
3521
5052
|
}
|
|
3522
5053
|
|
|
@@ -3555,8 +5086,8 @@ async function completeWithTransformers(options, llmConfig, getProvider, resolve
|
|
|
3555
5086
|
options.providerId,
|
|
3556
5087
|
options.model
|
|
3557
5088
|
);
|
|
3558
|
-
const actualProviderId = _optionalChain([routedInfo, 'optionalAccess',
|
|
3559
|
-
const actualModel = _optionalChain([routedInfo, 'optionalAccess',
|
|
5089
|
+
const actualProviderId = _optionalChain([routedInfo, 'optionalAccess', _310 => _310.actualProviderId]) || options.providerId;
|
|
5090
|
+
const actualModel = _optionalChain([routedInfo, 'optionalAccess', _311 => _311.actualModelId]) || options.model;
|
|
3560
5091
|
const provider = await getProvider(actualProviderId);
|
|
3561
5092
|
if (!provider) {
|
|
3562
5093
|
return { success: false, error: `Provider not found: ${actualProviderId}` };
|
|
@@ -3594,7 +5125,7 @@ async function completeWithTransformers(options, llmConfig, getProvider, resolve
|
|
|
3594
5125
|
models: provider.models || []
|
|
3595
5126
|
};
|
|
3596
5127
|
const executor = getSharedExecutor2();
|
|
3597
|
-
const { response } = await
|
|
5128
|
+
const { response } = await _chunkHYN75H6Gcjs.executeProviderCall.call(void 0, {
|
|
3598
5129
|
executor,
|
|
3599
5130
|
request: unifiedRequest,
|
|
3600
5131
|
provider: transformerProvider,
|
|
@@ -3603,9 +5134,9 @@ async function completeWithTransformers(options, llmConfig, getProvider, resolve
|
|
|
3603
5134
|
extendedContext: options.useExtendedContext ? { enabled: true, model: actualModel } : void 0,
|
|
3604
5135
|
resolveUrl: (config) => config.url instanceof URL ? config.url.toString() : _chunkA2YMUCBTcjs.buildProviderApiUrl.call(void 0, provider, { model: actualModel, stream: false }),
|
|
3605
5136
|
buildHeaders: (config) => ({
|
|
3606
|
-
...
|
|
5137
|
+
..._chunkQ27JY5RGcjs.getProviderHeaders.call(void 0, provider, apiKey),
|
|
3607
5138
|
...config.headers,
|
|
3608
|
-
...
|
|
5139
|
+
..._chunkUNEFIWXIcjs.isOpenRouterProvider.call(void 0, provider) ? _chunkUNEFIWXIcjs.OPENROUTER_APP_HEADERS : {}
|
|
3609
5140
|
}),
|
|
3610
5141
|
// Add OpenRouter provider routing config if applicable
|
|
3611
5142
|
prepareBody: (requestBody) => addOpenRouterProviderToRequest(
|
|
@@ -3637,18 +5168,18 @@ async function completeWithTransformers(options, llmConfig, getProvider, resolve
|
|
|
3637
5168
|
{ endpointTransformer: void 0 }
|
|
3638
5169
|
);
|
|
3639
5170
|
const data = await transformedResponse.json();
|
|
3640
|
-
const choice = _optionalChain([data, 'access',
|
|
5171
|
+
const choice = _optionalChain([data, 'access', _312 => _312.choices, 'optionalAccess', _313 => _313[0]]);
|
|
3641
5172
|
if (!choice) {
|
|
3642
5173
|
return { success: false, error: "No choices in response" };
|
|
3643
5174
|
}
|
|
3644
|
-
const rawToolCalls = _optionalChain([choice, 'access',
|
|
3645
|
-
const toolCalls = _optionalChain([rawToolCalls, 'optionalAccess',
|
|
5175
|
+
const rawToolCalls = _optionalChain([choice, 'access', _314 => _314.message, 'optionalAccess', _315 => _315.tool_calls]);
|
|
5176
|
+
const toolCalls = _optionalChain([rawToolCalls, 'optionalAccess', _316 => _316.map, 'call', _317 => _317((tc) => ({
|
|
3646
5177
|
id: tc.id,
|
|
3647
5178
|
name: tc.function.name,
|
|
3648
5179
|
args: typeof tc.function.arguments === "string" ? JSON.parse(tc.function.arguments) : tc.function.arguments
|
|
3649
5180
|
}))]);
|
|
3650
5181
|
const tapped = readUsageFromOpenAIResponse(data.usage);
|
|
3651
|
-
if (_optionalChain([recording, 'optionalAccess',
|
|
5182
|
+
if (_optionalChain([recording, 'optionalAccess', _318 => _318.recorder]) && tapped) {
|
|
3652
5183
|
recording.recorder.record({
|
|
3653
5184
|
messageId: _nullishCoalesce(options.messageId, () => ( null)),
|
|
3654
5185
|
parentMessageId: _nullishCoalesce(options.parentMessageId, () => ( null)),
|
|
@@ -3666,9 +5197,9 @@ async function completeWithTransformers(options, llmConfig, getProvider, resolve
|
|
|
3666
5197
|
message: {
|
|
3667
5198
|
id: `msg_${Date.now()}`,
|
|
3668
5199
|
role: "assistant",
|
|
3669
|
-
content: _optionalChain([choice, 'access',
|
|
5200
|
+
content: _optionalChain([choice, 'access', _319 => _319.message, 'optionalAccess', _320 => _320.content]) || "",
|
|
3670
5201
|
timestamp: Date.now(),
|
|
3671
|
-
thinking: data.reasoning_content || _optionalChain([choice, 'access',
|
|
5202
|
+
thinking: data.reasoning_content || _optionalChain([choice, 'access', _321 => _321.message, 'optionalAccess', _322 => _322.thinking, 'optionalAccess', _323 => _323.content]) ? { content: data.reasoning_content || _optionalChain([choice, 'access', _324 => _324.message, 'optionalAccess', _325 => _325.thinking, 'optionalAccess', _326 => _326.content]) || "", signature: _optionalChain([choice, 'access', _327 => _327.message, 'optionalAccess', _328 => _328.thinking, 'optionalAccess', _329 => _329.signature]) } : void 0,
|
|
3672
5203
|
toolCalls
|
|
3673
5204
|
},
|
|
3674
5205
|
usage: data.usage ? {
|
|
@@ -3689,21 +5220,21 @@ async function completeStreamWithTransformers(options, callbacks, llmConfig, get
|
|
|
3689
5220
|
options.providerId,
|
|
3690
5221
|
options.model
|
|
3691
5222
|
);
|
|
3692
|
-
const actualProviderId = _optionalChain([routedInfo, 'optionalAccess',
|
|
3693
|
-
const actualModel = _optionalChain([routedInfo, 'optionalAccess',
|
|
5223
|
+
const actualProviderId = _optionalChain([routedInfo, 'optionalAccess', _330 => _330.actualProviderId]) || options.providerId;
|
|
5224
|
+
const actualModel = _optionalChain([routedInfo, 'optionalAccess', _331 => _331.actualModelId]) || options.model;
|
|
3694
5225
|
const provider = await getProvider(actualProviderId);
|
|
3695
5226
|
if (!provider) {
|
|
3696
|
-
_optionalChain([callbacks, 'access',
|
|
5227
|
+
_optionalChain([callbacks, 'access', _332 => _332.onError, 'optionalCall', _333 => _333(`Provider not found: ${actualProviderId}`)]);
|
|
3697
5228
|
return;
|
|
3698
5229
|
}
|
|
3699
5230
|
if (!provider.enabled) {
|
|
3700
|
-
_optionalChain([callbacks, 'access',
|
|
5231
|
+
_optionalChain([callbacks, 'access', _334 => _334.onError, 'optionalCall', _335 => _335(`Provider is disabled: ${provider.name}`)]);
|
|
3701
5232
|
return;
|
|
3702
5233
|
}
|
|
3703
5234
|
const { apiKey: effectiveKey } = _chunkA2YMUCBTcjs.resolveProviderEndpoint.call(void 0, provider);
|
|
3704
5235
|
const apiKey = resolveApiKey2(effectiveKey);
|
|
3705
5236
|
if (!apiKey) {
|
|
3706
|
-
_optionalChain([callbacks, 'access',
|
|
5237
|
+
_optionalChain([callbacks, 'access', _336 => _336.onError, 'optionalCall', _337 => _337("API key not configured")]);
|
|
3707
5238
|
return;
|
|
3708
5239
|
}
|
|
3709
5240
|
const { chain, hasTransformers } = await resolveChainWithMain(
|
|
@@ -3715,7 +5246,7 @@ async function completeStreamWithTransformers(options, callbacks, llmConfig, get
|
|
|
3715
5246
|
return completeStreamFallback(options, callbacks);
|
|
3716
5247
|
}
|
|
3717
5248
|
const messageId = `msg_${Date.now()}`;
|
|
3718
|
-
_optionalChain([callbacks, 'access',
|
|
5249
|
+
_optionalChain([callbacks, 'access', _338 => _338.onStart, 'optionalCall', _339 => _339(messageId)]);
|
|
3719
5250
|
const unifiedRequest = {
|
|
3720
5251
|
model: actualModel,
|
|
3721
5252
|
messages: options.messages.map((m) => ({
|
|
@@ -3733,7 +5264,7 @@ async function completeStreamWithTransformers(options, callbacks, llmConfig, get
|
|
|
3733
5264
|
models: provider.models || []
|
|
3734
5265
|
};
|
|
3735
5266
|
const executor = getSharedExecutor2();
|
|
3736
|
-
const { response } = await
|
|
5267
|
+
const { response } = await _chunkHYN75H6Gcjs.executeProviderCall.call(void 0, {
|
|
3737
5268
|
executor,
|
|
3738
5269
|
request: unifiedRequest,
|
|
3739
5270
|
provider: transformerProvider,
|
|
@@ -3742,9 +5273,9 @@ async function completeStreamWithTransformers(options, callbacks, llmConfig, get
|
|
|
3742
5273
|
extendedContext: options.useExtendedContext ? { enabled: true, model: actualModel } : void 0,
|
|
3743
5274
|
resolveUrl: (config) => config.url instanceof URL ? config.url.toString() : _chunkA2YMUCBTcjs.buildProviderApiUrl.call(void 0, provider, { model: actualModel, stream: true }),
|
|
3744
5275
|
buildHeaders: (config) => ({
|
|
3745
|
-
...
|
|
5276
|
+
..._chunkQ27JY5RGcjs.getProviderHeaders.call(void 0, provider, apiKey),
|
|
3746
5277
|
...config.headers,
|
|
3747
|
-
...
|
|
5278
|
+
..._chunkUNEFIWXIcjs.isOpenRouterProvider.call(void 0, provider) ? _chunkUNEFIWXIcjs.OPENROUTER_APP_HEADERS : {}
|
|
3748
5279
|
}),
|
|
3749
5280
|
// Add OpenRouter provider routing config if applicable
|
|
3750
5281
|
prepareBody: (requestBody) => addOpenRouterProviderToRequest(
|
|
@@ -3763,7 +5294,7 @@ async function completeStreamWithTransformers(options, callbacks, llmConfig, get
|
|
|
3763
5294
|
});
|
|
3764
5295
|
if (!response.ok) {
|
|
3765
5296
|
const errorText = await response.text();
|
|
3766
|
-
_optionalChain([callbacks, 'access',
|
|
5297
|
+
_optionalChain([callbacks, 'access', _340 => _340.onError, 'optionalCall', _341 => _341(`API error (${response.status}): ${errorText}`)]);
|
|
3767
5298
|
return;
|
|
3768
5299
|
}
|
|
3769
5300
|
const transformedResponse = await executor.executeResponseChain(
|
|
@@ -3773,9 +5304,9 @@ async function completeStreamWithTransformers(options, callbacks, llmConfig, get
|
|
|
3773
5304
|
chain,
|
|
3774
5305
|
{ endpointTransformer: void 0 }
|
|
3775
5306
|
);
|
|
3776
|
-
const reader = _optionalChain([transformedResponse, 'access',
|
|
5307
|
+
const reader = _optionalChain([transformedResponse, 'access', _342 => _342.body, 'optionalAccess', _343 => _343.getReader, 'call', _344 => _344()]);
|
|
3777
5308
|
if (!reader) {
|
|
3778
|
-
_optionalChain([callbacks, 'access',
|
|
5309
|
+
_optionalChain([callbacks, 'access', _345 => _345.onError, 'optionalCall', _346 => _346("No response body")]);
|
|
3779
5310
|
return;
|
|
3780
5311
|
}
|
|
3781
5312
|
const decoder = new TextDecoder();
|
|
@@ -3793,22 +5324,22 @@ async function completeStreamWithTransformers(options, callbacks, llmConfig, get
|
|
|
3793
5324
|
if (data === "[DONE]") continue;
|
|
3794
5325
|
try {
|
|
3795
5326
|
const json = JSON.parse(data);
|
|
3796
|
-
const delta = _optionalChain([json, 'access',
|
|
3797
|
-
if (_optionalChain([delta, 'optionalAccess',
|
|
5327
|
+
const delta = _optionalChain([json, 'access', _347 => _347.choices, 'optionalAccess', _348 => _348[0], 'optionalAccess', _349 => _349.delta]);
|
|
5328
|
+
if (_optionalChain([delta, 'optionalAccess', _350 => _350.content])) {
|
|
3798
5329
|
content += delta.content;
|
|
3799
|
-
_optionalChain([callbacks, 'access',
|
|
5330
|
+
_optionalChain([callbacks, 'access', _351 => _351.onDelta, 'optionalCall', _352 => _352(delta.content)]);
|
|
3800
5331
|
}
|
|
3801
|
-
if (_optionalChain([delta, 'optionalAccess',
|
|
5332
|
+
if (_optionalChain([delta, 'optionalAccess', _353 => _353.thinking, 'optionalAccess', _354 => _354.content])) {
|
|
3802
5333
|
reasoning += delta.thinking.content;
|
|
3803
|
-
_optionalChain([callbacks, 'access',
|
|
5334
|
+
_optionalChain([callbacks, 'access', _355 => _355.onReasoning, 'optionalCall', _356 => _356(delta.thinking.content)]);
|
|
3804
5335
|
}
|
|
3805
|
-
if (_optionalChain([delta, 'optionalAccess',
|
|
5336
|
+
if (_optionalChain([delta, 'optionalAccess', _357 => _357.reasoning_content])) {
|
|
3806
5337
|
reasoning += delta.reasoning_content;
|
|
3807
|
-
_optionalChain([callbacks, 'access',
|
|
5338
|
+
_optionalChain([callbacks, 'access', _358 => _358.onReasoning, 'optionalCall', _359 => _359(delta.reasoning_content)]);
|
|
3808
5339
|
}
|
|
3809
5340
|
if (json.usage) {
|
|
3810
5341
|
const tapped = readUsageFromOpenAIResponse(json.usage);
|
|
3811
|
-
if (_optionalChain([recording, 'optionalAccess',
|
|
5342
|
+
if (_optionalChain([recording, 'optionalAccess', _360 => _360.recorder]) && tapped) {
|
|
3812
5343
|
recording.recorder.record({
|
|
3813
5344
|
messageId: _nullishCoalesce(options.messageId, () => ( null)),
|
|
3814
5345
|
parentMessageId: _nullishCoalesce(options.parentMessageId, () => ( null)),
|
|
@@ -3821,7 +5352,7 @@ async function completeStreamWithTransformers(options, callbacks, llmConfig, get
|
|
|
3821
5352
|
rawUsage: json.usage
|
|
3822
5353
|
});
|
|
3823
5354
|
}
|
|
3824
|
-
_optionalChain([callbacks, 'access',
|
|
5355
|
+
_optionalChain([callbacks, 'access', _361 => _361.onDone, 'optionalCall', _362 => _362(
|
|
3825
5356
|
{
|
|
3826
5357
|
id: messageId,
|
|
3827
5358
|
role: "assistant",
|
|
@@ -3842,7 +5373,7 @@ async function completeStreamWithTransformers(options, callbacks, llmConfig, get
|
|
|
3842
5373
|
}
|
|
3843
5374
|
}
|
|
3844
5375
|
}
|
|
3845
|
-
_optionalChain([callbacks, 'access',
|
|
5376
|
+
_optionalChain([callbacks, 'access', _363 => _363.onDone, 'optionalCall', _364 => _364({
|
|
3846
5377
|
id: messageId,
|
|
3847
5378
|
role: "assistant",
|
|
3848
5379
|
content,
|
|
@@ -3854,13 +5385,13 @@ async function completeStreamWithTransformers(options, callbacks, llmConfig, get
|
|
|
3854
5385
|
}
|
|
3855
5386
|
} catch (error) {
|
|
3856
5387
|
const message = error instanceof Error ? error.message : "Unknown error";
|
|
3857
|
-
_optionalChain([callbacks, 'access',
|
|
5388
|
+
_optionalChain([callbacks, 'access', _365 => _365.onError, 'optionalCall', _366 => _366(message)]);
|
|
3858
5389
|
}
|
|
3859
5390
|
}
|
|
3860
5391
|
|
|
3861
5392
|
// src/completion/CompletionService.ts
|
|
3862
|
-
var CompletionService = (
|
|
3863
|
-
constructor(paths, llmConfig, logger) {;
|
|
5393
|
+
var CompletionService = (_class13 = class {
|
|
5394
|
+
constructor(paths, llmConfig, logger) {;_class13.prototype.__init22.call(this);_class13.prototype.__init23.call(this);_class13.prototype.__init24.call(this);_class13.prototype.__init25.call(this);
|
|
3864
5395
|
this.paths = paths;
|
|
3865
5396
|
this.llmConfig = llmConfig;
|
|
3866
5397
|
this.logger = logger;
|
|
@@ -3868,10 +5399,10 @@ var CompletionService = (_class5 = class {
|
|
|
3868
5399
|
|
|
3869
5400
|
|
|
3870
5401
|
|
|
3871
|
-
|
|
3872
|
-
|
|
3873
|
-
|
|
3874
|
-
|
|
5402
|
+
__init22() {this.apiKeyPool = null}
|
|
5403
|
+
__init23() {this.usageRecorder = null}
|
|
5404
|
+
__init24() {this.usageEventSink = null}
|
|
5405
|
+
__init25() {this.visionFallbackProvider = null}
|
|
3875
5406
|
/**
|
|
3876
5407
|
* Set the API key pool service for multi-key load balancing.
|
|
3877
5408
|
* When set, keys are resolved via the pool instead of directly from the provider.
|
|
@@ -3921,8 +5452,8 @@ var CompletionService = (_class5 = class {
|
|
|
3921
5452
|
options.providerId,
|
|
3922
5453
|
options.model
|
|
3923
5454
|
);
|
|
3924
|
-
const actualProviderId = _optionalChain([routedInfo, 'optionalAccess',
|
|
3925
|
-
const actualModel = _optionalChain([routedInfo, 'optionalAccess',
|
|
5455
|
+
const actualProviderId = _optionalChain([routedInfo, 'optionalAccess', _367 => _367.actualProviderId]) || options.providerId;
|
|
5456
|
+
const actualModel = _optionalChain([routedInfo, 'optionalAccess', _368 => _368.actualModelId]) || options.model;
|
|
3926
5457
|
const provider = await this.getProvider(actualProviderId);
|
|
3927
5458
|
if (!provider) {
|
|
3928
5459
|
return { success: false, error: `Provider not found: ${actualProviderId}` };
|
|
@@ -3955,7 +5486,7 @@ var CompletionService = (_class5 = class {
|
|
|
3955
5486
|
this.apiKeyPool.reportSuccess(options.sessionId);
|
|
3956
5487
|
}
|
|
3957
5488
|
if (result.success && result.usage && options.sessionId) {
|
|
3958
|
-
_optionalChain([this, 'access',
|
|
5489
|
+
_optionalChain([this, 'access', _369 => _369.usageEventSink, 'optionalAccess', _370 => _370.emit, 'call', _371 => _371({
|
|
3959
5490
|
sessionId: options.sessionId,
|
|
3960
5491
|
modelId: actualModel,
|
|
3961
5492
|
usage: result.usage,
|
|
@@ -3984,8 +5515,8 @@ var CompletionService = (_class5 = class {
|
|
|
3984
5515
|
options.model
|
|
3985
5516
|
);
|
|
3986
5517
|
this.logger.debug("Resolved routed model", { routedInfo });
|
|
3987
|
-
const actualProviderId = _optionalChain([routedInfo, 'optionalAccess',
|
|
3988
|
-
const actualModel = _optionalChain([routedInfo, 'optionalAccess',
|
|
5518
|
+
const actualProviderId = _optionalChain([routedInfo, 'optionalAccess', _372 => _372.actualProviderId]) || options.providerId;
|
|
5519
|
+
const actualModel = _optionalChain([routedInfo, 'optionalAccess', _373 => _373.actualModelId]) || options.model;
|
|
3989
5520
|
this.logger.debug("Resolved provider and model", { actualProviderId, actualModel });
|
|
3990
5521
|
const provider = await this.getProvider(actualProviderId);
|
|
3991
5522
|
this.logger.debug("Retrieved provider", provider ? {
|
|
@@ -3997,22 +5528,22 @@ var CompletionService = (_class5 = class {
|
|
|
3997
5528
|
enabled: provider.enabled
|
|
3998
5529
|
} : { error: "Provider not found" });
|
|
3999
5530
|
if (!provider) {
|
|
4000
|
-
_optionalChain([callbacks, 'access',
|
|
5531
|
+
_optionalChain([callbacks, 'access', _374 => _374.onError, 'optionalCall', _375 => _375(`Provider not found: ${actualProviderId}`)]);
|
|
4001
5532
|
return;
|
|
4002
5533
|
}
|
|
4003
5534
|
if (!provider.enabled) {
|
|
4004
|
-
_optionalChain([callbacks, 'access',
|
|
5535
|
+
_optionalChain([callbacks, 'access', _376 => _376.onError, 'optionalCall', _377 => _377(`Provider is disabled: ${provider.name}`)]);
|
|
4005
5536
|
return;
|
|
4006
5537
|
}
|
|
4007
5538
|
const apiKey = await this.resolveApiKeyForRequest(provider, actualProviderId, options.sessionId);
|
|
4008
5539
|
if (!apiKey) {
|
|
4009
|
-
_optionalChain([callbacks, 'access',
|
|
5540
|
+
_optionalChain([callbacks, 'access', _378 => _378.onError, 'optionalCall', _379 => _379("API key not configured")]);
|
|
4010
5541
|
return;
|
|
4011
5542
|
}
|
|
4012
5543
|
const apiFormat = _chunkA2YMUCBTcjs.resolveApiFormat.call(void 0, provider);
|
|
4013
5544
|
this.logger.info("Using API format for stream", { apiFormat });
|
|
4014
5545
|
const messageId = `msg_${Date.now()}`;
|
|
4015
|
-
_optionalChain([callbacks, 'access',
|
|
5546
|
+
_optionalChain([callbacks, 'access', _380 => _380.onStart, 'optionalCall', _381 => _381(messageId)]);
|
|
4016
5547
|
const resolvedOptions = { ...options, model: actualModel };
|
|
4017
5548
|
if (options.sessionId) {
|
|
4018
5549
|
const sid = options.sessionId;
|
|
@@ -4021,14 +5552,14 @@ var CompletionService = (_class5 = class {
|
|
|
4021
5552
|
...callbacks,
|
|
4022
5553
|
onDone: (message, usage, metrics) => {
|
|
4023
5554
|
if (usage) {
|
|
4024
|
-
_optionalChain([this, 'access',
|
|
5555
|
+
_optionalChain([this, 'access', _382 => _382.usageEventSink, 'optionalAccess', _383 => _383.emit, 'call', _384 => _384({
|
|
4025
5556
|
sessionId: sid,
|
|
4026
5557
|
modelId: actualModel,
|
|
4027
5558
|
usage,
|
|
4028
5559
|
engineOrigin: "completion"
|
|
4029
5560
|
})]);
|
|
4030
5561
|
}
|
|
4031
|
-
_optionalChain([userOnDone, 'optionalCall',
|
|
5562
|
+
_optionalChain([userOnDone, 'optionalCall', _385 => _385(message, usage, metrics)]);
|
|
4032
5563
|
}
|
|
4033
5564
|
};
|
|
4034
5565
|
}
|
|
@@ -4044,11 +5575,11 @@ var CompletionService = (_class5 = class {
|
|
|
4044
5575
|
retryState.error = { status, message: error };
|
|
4045
5576
|
return;
|
|
4046
5577
|
}
|
|
4047
|
-
_optionalChain([callbacks, 'access',
|
|
5578
|
+
_optionalChain([callbacks, 'access', _386 => _386.onError, 'optionalCall', _387 => _387(error)]);
|
|
4048
5579
|
},
|
|
4049
5580
|
onDone: (message, usage, metrics) => {
|
|
4050
5581
|
this.apiKeyPool.reportSuccess(options.sessionId);
|
|
4051
|
-
_optionalChain([callbacks, 'access',
|
|
5582
|
+
_optionalChain([callbacks, 'access', _388 => _388.onDone, 'optionalCall', _389 => _389(message, usage, metrics)]);
|
|
4052
5583
|
}
|
|
4053
5584
|
};
|
|
4054
5585
|
await this.callStreamHandler(apiFormat, provider, apiKey, resolvedOptions, messageId, interceptCallbacks);
|
|
@@ -4069,7 +5600,7 @@ var CompletionService = (_class5 = class {
|
|
|
4069
5600
|
// don't fire onStart again
|
|
4070
5601
|
});
|
|
4071
5602
|
} else {
|
|
4072
|
-
_optionalChain([callbacks, 'access',
|
|
5603
|
+
_optionalChain([callbacks, 'access', _390 => _390.onError, 'optionalCall', _391 => _391(retryState.error.message)]);
|
|
4073
5604
|
}
|
|
4074
5605
|
}
|
|
4075
5606
|
} else {
|
|
@@ -4082,7 +5613,7 @@ var CompletionService = (_class5 = class {
|
|
|
4082
5613
|
} catch (error) {
|
|
4083
5614
|
const message = error instanceof Error ? error.message : "Unknown error";
|
|
4084
5615
|
this.logger.error("Stream completion error", error instanceof Error ? error : void 0, { message });
|
|
4085
|
-
_optionalChain([callbacks, 'access',
|
|
5616
|
+
_optionalChain([callbacks, 'access', _392 => _392.onError, 'optionalCall', _393 => _393(message)]);
|
|
4086
5617
|
}
|
|
4087
5618
|
}
|
|
4088
5619
|
/**
|
|
@@ -4122,7 +5653,7 @@ var CompletionService = (_class5 = class {
|
|
|
4122
5653
|
return {
|
|
4123
5654
|
success: true,
|
|
4124
5655
|
message: "Connection successful",
|
|
4125
|
-
response: _optionalChain([result, 'access',
|
|
5656
|
+
response: _optionalChain([result, 'access', _394 => _394.message, 'optionalAccess', _395 => _395.content]) || "",
|
|
4126
5657
|
model: modelId,
|
|
4127
5658
|
durationMs
|
|
4128
5659
|
};
|
|
@@ -4187,7 +5718,7 @@ ${description}`;
|
|
|
4187
5718
|
* 3. Legacy single key from provider config
|
|
4188
5719
|
*/
|
|
4189
5720
|
async resolveApiKeyForRequest(provider, providerId, sessionId) {
|
|
4190
|
-
if (_optionalChain([provider, 'access',
|
|
5721
|
+
if (_optionalChain([provider, 'access', _396 => _396.codingPlan, 'optionalAccess', _397 => _397.enabled]) && provider.codingPlan.apiKey) {
|
|
4191
5722
|
return this.resolveApiKey(provider.codingPlan.apiKey);
|
|
4192
5723
|
}
|
|
4193
5724
|
if (this.apiKeyPool) {
|
|
@@ -4352,7 +5883,46 @@ ${description}`;
|
|
|
4352
5883
|
builtinExecutor
|
|
4353
5884
|
);
|
|
4354
5885
|
}
|
|
4355
|
-
},
|
|
5886
|
+
}, _class13);
|
|
5887
|
+
|
|
5888
|
+
|
|
5889
|
+
|
|
5890
|
+
|
|
5891
|
+
|
|
5892
|
+
|
|
5893
|
+
|
|
5894
|
+
|
|
5895
|
+
|
|
5896
|
+
|
|
5897
|
+
|
|
5898
|
+
|
|
5899
|
+
|
|
5900
|
+
|
|
5901
|
+
|
|
5902
|
+
|
|
5903
|
+
|
|
5904
|
+
|
|
5905
|
+
|
|
5906
|
+
|
|
5907
|
+
|
|
5908
|
+
|
|
5909
|
+
|
|
5910
|
+
|
|
5911
|
+
|
|
5912
|
+
|
|
5913
|
+
|
|
5914
|
+
|
|
5915
|
+
|
|
5916
|
+
|
|
5917
|
+
|
|
5918
|
+
|
|
5919
|
+
|
|
5920
|
+
|
|
5921
|
+
|
|
5922
|
+
|
|
5923
|
+
|
|
5924
|
+
|
|
5925
|
+
|
|
4356
5926
|
|
|
4357
5927
|
|
|
4358
5928
|
|
|
@@ -4397,4 +5967,4 @@ ${description}`;
|
|
|
4397
5967
|
|
|
4398
5968
|
|
|
4399
5969
|
|
|
4400
|
-
exports.CompletionService = CompletionService; exports.register = register; exports.emit = emit; exports.attach = attach; exports.release = release; exports.convertMessageToOpenAI = convertMessageToOpenAI; exports.convertMessageToAnthropic = convertMessageToAnthropic; exports.convertMessageToGemini = convertMessageToGemini; exports.getOpenRouterProviderConfig = getOpenRouterProviderConfig; exports.addOpenRouterProviderToRequest = addOpenRouterProviderToRequest; exports.DEFAULT_ROUTE_IDLE_MS = DEFAULT_ROUTE_IDLE_MS; exports.ProviderProxyRouteMap = ProviderProxyRouteMap; exports.getSharedExecutor = getSharedExecutor; exports.getResponsesEndpointTransformer = getResponsesEndpointTransformer; exports.getAnthropicEndpointTransformer = getAnthropicEndpointTransformer; exports.getGeminiEndpointTransformer = getGeminiEndpointTransformer; exports.readBody = readBody; exports.relayResponse = relayResponse; exports.writeError = writeError; exports.resolvePoolBoundKey = resolvePoolBoundKey; exports.extractRouteToken = extractRouteToken; exports.isLoopbackAddress = isLoopbackAddress; exports.ProviderProxy = ProviderProxy; exports.getProviderProxy = getProviderProxy; exports.__resetProviderProxyForTests = __resetProviderProxyForTests; exports.
|
|
5970
|
+
exports.CompletionService = CompletionService; exports.register = register; exports.emit = emit; exports.attach = attach; exports.release = release; exports.convertMessageToOpenAI = convertMessageToOpenAI; exports.convertMessageToAnthropic = convertMessageToAnthropic; exports.convertMessageToGemini = convertMessageToGemini; exports.getOpenRouterProviderConfig = getOpenRouterProviderConfig; exports.addOpenRouterProviderToRequest = addOpenRouterProviderToRequest; exports.DEFAULT_ROUTE_IDLE_MS = DEFAULT_ROUTE_IDLE_MS; exports.ProviderProxyRouteMap = ProviderProxyRouteMap; exports.getSharedExecutor = getSharedExecutor; exports.getResponsesEndpointTransformer = getResponsesEndpointTransformer; exports.getAnthropicEndpointTransformer = getAnthropicEndpointTransformer; exports.getGeminiEndpointTransformer = getGeminiEndpointTransformer; exports.readBody = readBody; exports.relayResponse = relayResponse; exports.writeError = writeError; exports.resolvePoolBoundKey = resolvePoolBoundKey; exports.extractRouteToken = extractRouteToken; exports.isLoopbackAddress = isLoopbackAddress; exports.ProviderProxy = ProviderProxy; exports.getProviderProxy = getProviderProxy; exports.__resetProviderProxyForTests = __resetProviderProxyForTests; exports.KeyedMutex = KeyedMutex; exports.OUTBOUND_API_SERVER_CONFIG_KEY = OUTBOUND_API_SERVER_CONFIG_KEY; exports.DEFAULT_USER_MESSAGE_QUEUE = DEFAULT_USER_MESSAGE_QUEUE; exports.DEFAULT_CONCURRENCY_QUEUE = DEFAULT_CONCURRENCY_QUEUE; exports.DEFAULT_ACCOUNT_PROBE = DEFAULT_ACCOUNT_PROBE; exports.normalizeAccountProbe = normalizeAccountProbe; exports.normalizeAudit = normalizeAudit; exports.normalizeBilling = normalizeBilling; exports.DEFAULT_FINGERPRINT = DEFAULT_FINGERPRINT; exports.normalizeFingerprint = normalizeFingerprint; exports.normalizeVoucher = normalizeVoucher; exports.normalizeProxyConfig = normalizeProxyConfig; exports.normalizeProxySegment = normalizeProxySegment; exports.normalizeWebhookDestination = normalizeWebhookDestination; exports.normalizeWebhookSegment = normalizeWebhookSegment; exports.normalizeQueueSegments = normalizeQueueSegments; exports.normalizePrefixTargets = normalizePrefixTargets; exports.defaultServerConfig = defaultServerConfig; exports.normalizeServerConfig = normalizeServerConfig; exports.loadServerConfig = loadServerConfig; exports.saveServerConfig = saveServerConfig; exports.mergeServerConfig = mergeServerConfig; exports.computeKeyExpiry = computeKeyExpiry; exports.checkKeyQuota = checkKeyQuota; exports.randomBase62 = randomBase62; exports.hashKey = hashKey; exports.createNamedKey = createNamedKey; exports.verifyKey = verifyKey; exports.verifyPresentedKey = verifyPresentedKey; exports.ConcurrencyQueueFullError = ConcurrencyQueueFullError; exports.ConcurrencyWaitTimeoutError = ConcurrencyWaitTimeoutError; exports.ConcurrencyWaitCancelledError = ConcurrencyWaitCancelledError; exports.isConcurrencyRejection = isConcurrencyRejection; exports.OutboundConcurrencyGate = OutboundConcurrencyGate; exports.OutboundRateLimiter = OutboundRateLimiter; exports.isUserMessageRequest = isUserMessageRequest; exports.SerialQueueTimeoutError = SerialQueueTimeoutError; exports.isSerialQueueTimeout = isSerialQueueTimeout; exports.UserMessageSerialQueue = UserMessageSerialQueue; exports.generateVoucherCode = generateVoucherCode; exports.hashVoucherCode = hashVoucherCode; exports.voucherCodePrefix = voucherCodePrefix; exports.newVoucherId = newVoucherId; exports.computeVoucherGrant = computeVoucherGrant; exports.toVoucherInfo = toVoucherInfo; exports.isRedeemRequest = isRedeemRequest; exports.handleVoucherRedeem = handleVoucherRedeem; exports.DEFAULT_OUTBOUND_PORT = DEFAULT_OUTBOUND_PORT; exports.OutboundApiConfigError = OutboundApiConfigError; exports.OutboundApiServer = OutboundApiServer; exports.formatUrls = formatUrls; exports.startOfLocalDay = startOfLocalDay; exports.startOfLocalWeek = startOfLocalWeek; exports.KeySpendTracker = KeySpendTracker; exports.getOutboundApiServer = getOutboundApiServer; exports.__resetOutboundApiServerForTests = __resetOutboundApiServerForTests;
|