@omnicross/core 0.1.3 → 0.1.5

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.
Files changed (141) hide show
  1. package/LICENSE +21 -21
  2. package/NOTICE +57 -57
  3. package/README.md +15 -15
  4. package/dist/auth/GeminiCodeAssistProjectResolver.cjs +6 -5
  5. package/dist/auth/GeminiCodeAssistProjectResolver.js +6 -5
  6. package/dist/{chunk-2DCNB7DF.cjs → chunk-3Q6Z6JTO.cjs} +154 -26
  7. package/dist/chunk-3QFXFCHG.js +33 -0
  8. package/dist/chunk-3Z5BQZFM.cjs +52 -0
  9. package/dist/{chunk-4VAVYUZS.cjs → chunk-4XMYPW46.cjs} +9 -9
  10. package/dist/chunk-4YINUUKQ.cjs +33 -0
  11. package/dist/{chunk-S4WBV25P.js → chunk-6QZGDLL4.js} +106 -23
  12. package/dist/{chunk-C72S6TTV.cjs → chunk-7FEBOPJO.cjs} +5 -4
  13. package/dist/chunk-APYG5QD7.cjs +50 -0
  14. package/dist/{chunk-5HTVET6E.js → chunk-BODMAL6G.js} +143 -15
  15. package/dist/{chunk-CWM2ZDU5.js → chunk-BPKCU575.js} +3 -10
  16. package/dist/{chunk-2FMI2B6V.cjs → chunk-CGKLE6IW.cjs} +350 -461
  17. package/dist/{chunk-BO4RFWBR.js → chunk-D3TDKWRP.js} +84 -3
  18. package/dist/{chunk-RSJ3TWJQ.cjs → chunk-DDMRUL76.cjs} +5 -5
  19. package/dist/chunk-FCR77GYM.cjs +33 -0
  20. package/dist/{chunk-4DECIFU7.js → chunk-FH2P4OCD.js} +178 -289
  21. package/dist/{chunk-N5QFKSDO.js → chunk-HRRYG2AX.js} +2 -1
  22. package/dist/{chunk-KUU2RNG6.cjs → chunk-HYN75H6G.cjs} +3 -0
  23. package/dist/{chunk-Z7LUNECE.js → chunk-IB3FDI4O.js} +5 -4
  24. package/dist/chunk-IFXJ2BG7.js +109 -0
  25. package/dist/{chunk-JO5NLTLY.js → chunk-IK3KE3AU.js} +3 -0
  26. package/dist/{chunk-C7PSERMH.js → chunk-IWQAX3CS.js} +1 -1
  27. package/dist/{chunk-YGXJGRFI.cjs → chunk-JWVTXXPX.cjs} +106 -23
  28. package/dist/{chunk-7YN22L2H.cjs → chunk-K52THW2C.cjs} +5 -5
  29. package/dist/chunk-K5NM7VAH.js +33 -0
  30. package/dist/{chunk-Y6OM7EV7.cjs → chunk-KFI44N2R.cjs} +2 -1
  31. package/dist/{chunk-Z7Y2NPHY.js → chunk-MFZ5437A.js} +1 -1
  32. package/dist/chunk-OE6TDIWW.js +22 -0
  33. package/dist/{chunk-MQNDWYPN.js → chunk-OQWKZCXP.js} +13 -6
  34. package/dist/chunk-OZFM4X3S.js +18 -0
  35. package/dist/chunk-PG7PS2NN.cjs +170 -0
  36. package/dist/{chunk-3QOSDDNI.cjs → chunk-SNYBEXLB.cjs} +6 -13
  37. package/dist/chunk-SYQF7OIR.js +52 -0
  38. package/dist/{chunk-CZHZGRU7.js → chunk-UHGVBFU3.js} +2 -0
  39. package/dist/chunk-UIBD2YY5.cjs +22 -0
  40. package/dist/chunk-UNWKG6EI.cjs +109 -0
  41. package/dist/{chunk-SVXC36MU.cjs → chunk-VACWOIRE.cjs} +2 -0
  42. package/dist/chunk-WLYIIEAF.js +50 -0
  43. package/dist/chunk-XSVNC2UD.cjs +18 -0
  44. package/dist/{chunk-FFALUUZZ.cjs → chunk-ZCIQ3L3R.cjs} +18 -11
  45. package/dist/completion/CompletionService.cjs +26 -19
  46. package/dist/completion/CompletionService.js +25 -18
  47. package/dist/completion.cjs +28 -21
  48. package/dist/completion.js +27 -20
  49. package/dist/index.cjs +35 -25
  50. package/dist/index.d.cts +7 -3
  51. package/dist/index.d.ts +7 -3
  52. package/dist/index.js +44 -34
  53. package/dist/keyPolicy-Cp0FntZl.d.cts +90 -0
  54. package/dist/keyPolicy-Cp0FntZl.d.ts +90 -0
  55. package/dist/outbound-api/auditCapture.cjs +9 -0
  56. package/dist/outbound-api/auditCapture.d.cts +54 -0
  57. package/dist/outbound-api/auditCapture.d.ts +54 -0
  58. package/dist/outbound-api/auditCapture.js +9 -0
  59. package/dist/outbound-api/auditRedact.cjs +8 -0
  60. package/dist/outbound-api/auditRedact.d.cts +30 -0
  61. package/dist/outbound-api/auditRedact.d.ts +30 -0
  62. package/dist/outbound-api/auditRedact.js +8 -0
  63. package/dist/outbound-api/billingCapture.cjs +8 -0
  64. package/dist/outbound-api/billingCapture.d.cts +61 -0
  65. package/dist/outbound-api/billingCapture.d.ts +61 -0
  66. package/dist/outbound-api/billingCapture.js +8 -0
  67. package/dist/outbound-api/quotaWarn.cjs +12 -0
  68. package/dist/outbound-api/quotaWarn.d.cts +43 -0
  69. package/dist/outbound-api/quotaWarn.d.ts +43 -0
  70. package/dist/outbound-api/quotaWarn.js +12 -0
  71. package/dist/outbound-api/routeResolver.cjs +2 -2
  72. package/dist/outbound-api/routeResolver.d.cts +3 -2
  73. package/dist/outbound-api/routeResolver.d.ts +3 -2
  74. package/dist/outbound-api/routeResolver.js +1 -1
  75. package/dist/outbound-api/types.d.cts +2 -1
  76. package/dist/outbound-api/types.d.ts +2 -1
  77. package/dist/outbound-api.cjs +33 -23
  78. package/dist/outbound-api.d.cts +9 -140
  79. package/dist/outbound-api.d.ts +9 -140
  80. package/dist/outbound-api.js +32 -22
  81. package/dist/pipeline/AuthSource.d.cts +6 -0
  82. package/dist/pipeline/AuthSource.d.ts +6 -0
  83. package/dist/pipeline/SubscriptionAuthSource.cjs +2 -2
  84. package/dist/pipeline/SubscriptionAuthSource.js +1 -1
  85. package/dist/pipeline/SubscriptionAuthStrategy.d.cts +6 -0
  86. package/dist/pipeline/SubscriptionAuthStrategy.d.ts +6 -0
  87. package/dist/pipeline/auditUsageStash.cjs +10 -0
  88. package/dist/pipeline/auditUsageStash.d.cts +37 -0
  89. package/dist/pipeline/auditUsageStash.d.ts +37 -0
  90. package/dist/pipeline/auditUsageStash.js +10 -0
  91. package/dist/pipeline/executeProviderCall.cjs +2 -2
  92. package/dist/pipeline/executeProviderCall.js +1 -1
  93. package/dist/pipeline/upstreamFetch.cjs +15 -0
  94. package/dist/pipeline/upstreamFetch.d.cts +89 -0
  95. package/dist/pipeline/upstreamFetch.d.ts +89 -0
  96. package/dist/pipeline/upstreamFetch.js +15 -0
  97. package/dist/pipeline/upstreamTrace.cjs +14 -0
  98. package/dist/pipeline/upstreamTrace.d.cts +85 -0
  99. package/dist/pipeline/upstreamTrace.d.ts +85 -0
  100. package/dist/pipeline/upstreamTrace.js +14 -0
  101. package/dist/pipeline/webhookEmit.cjs +10 -0
  102. package/dist/pipeline/webhookEmit.d.cts +36 -0
  103. package/dist/pipeline/webhookEmit.d.ts +36 -0
  104. package/dist/pipeline/webhookEmit.js +10 -0
  105. package/dist/ports.d.cts +2 -1
  106. package/dist/ports.d.ts +2 -1
  107. package/dist/provider-proxy/ProviderProxy.cjs +26 -19
  108. package/dist/provider-proxy/ProviderProxy.js +25 -18
  109. package/dist/provider-proxy/ingress/providerProxyShared.cjs +28 -19
  110. package/dist/provider-proxy/ingress/providerProxyShared.d.cts +17 -1
  111. package/dist/provider-proxy/ingress/providerProxyShared.d.ts +17 -1
  112. package/dist/provider-proxy/ingress/providerProxyShared.js +27 -18
  113. package/dist/provider-proxy/types.d.cts +7 -0
  114. package/dist/provider-proxy/types.d.ts +7 -0
  115. package/dist/provider-proxy.cjs +26 -19
  116. package/dist/provider-proxy.js +25 -18
  117. package/dist/{routeResolver-B1NglTfe.d.ts → routeResolver-C4T7yClx.d.ts} +1 -1
  118. package/dist/{routeResolver-CbG5uBgm.d.cts → routeResolver-CB3tvJKy.d.cts} +1 -1
  119. package/dist/transformer/transformers/AnthropicTransformer.cjs +2 -2
  120. package/dist/transformer/transformers/AnthropicTransformer.js +1 -1
  121. package/dist/transformer/transformers/GeminiCodeAssistTransformer.cjs +3 -3
  122. package/dist/transformer/transformers/GeminiCodeAssistTransformer.js +2 -2
  123. package/dist/transformer/transformers/GeminiTransformer.cjs +3 -3
  124. package/dist/transformer/transformers/GeminiTransformer.js +2 -2
  125. package/dist/transformer/transformers/OpenAIResponseTransformer.cjs +2 -2
  126. package/dist/transformer/transformers/OpenAIResponseTransformer.js +1 -1
  127. package/dist/transformer/transformers/OpenCodeGoTransformer.cjs +2 -2
  128. package/dist/transformer/transformers/OpenCodeGoTransformer.js +1 -1
  129. package/dist/transformer/transformers.cjs +8 -8
  130. package/dist/transformer/transformers.js +7 -7
  131. package/dist/transformer.cjs +8 -8
  132. package/dist/transformer.js +7 -7
  133. package/dist/{types-aBFFXoBz.d.cts → types-B8Arpxn0.d.cts} +14 -90
  134. package/dist/{types-6OUY_xfA.d.ts → types-lgPYQuZS.d.ts} +14 -90
  135. package/dist/usage/usage-recorder.cjs +3 -2
  136. package/dist/usage/usage-recorder.js +2 -1
  137. package/dist/usage.cjs +3 -2
  138. package/dist/usage.js +2 -1
  139. package/package.json +64 -64
  140. package/dist/chunk-S6JGLF3G.cjs +0 -89
  141. package/dist/{chunk-FTQ7IQUC.js → chunk-C6OV7GCC.js} +8 -8
@@ -6,16 +6,13 @@ import {
6
6
  } from "./chunk-G2UTNSGU.js";
7
7
  import {
8
8
  AnthropicTransformer
9
- } from "./chunk-FTQ7IQUC.js";
9
+ } from "./chunk-C6OV7GCC.js";
10
10
  import {
11
11
  GeminiTransformer
12
- } from "./chunk-C7PSERMH.js";
12
+ } from "./chunk-IWQAX3CS.js";
13
13
  import {
14
14
  OpenAIResponseTransformer
15
- } from "./chunk-5HTVET6E.js";
16
- import {
17
- readAuditUsage
18
- } from "./chunk-CWM2ZDU5.js";
15
+ } from "./chunk-BODMAL6G.js";
19
16
  import {
20
17
  injectExtendedContextBeta
21
18
  } from "./chunk-MZNPGW5Q.js";
@@ -31,32 +28,14 @@ import {
31
28
  deriveSubscriptionSessionKey
32
29
  } from "./chunk-IAXWICZU.js";
33
30
  import {
34
- resolveSubscriptionChain
35
- } from "./chunk-5ERIZW3D.js";
36
- import {
37
- getSharedAccountHealth,
38
- resolveResetSeconds
39
- } from "./chunk-5ENKBSWO.js";
40
- import {
41
- SubscriptionAuthSource
42
- } from "./chunk-N5QFKSDO.js";
43
- import {
44
- serializeError
45
- } from "./chunk-AVYJ4YBN.js";
31
+ emitWebhookEvent
32
+ } from "./chunk-OE6TDIWW.js";
46
33
  import {
47
34
  getGeminiCodeAssistResolver
48
35
  } from "./chunk-DRWHTIIZ.js";
49
- import {
50
- getAuditCaptureConfig,
51
- recordAudit
52
- } from "./chunk-WNY4WMRF.js";
53
- import {
54
- getBillingCaptureConfig,
55
- publishBillingEvent
56
- } from "./chunk-TKJMZBAH.js";
57
36
  import {
58
37
  executeProviderCall
59
- } from "./chunk-JO5NLTLY.js";
38
+ } from "./chunk-IK3KE3AU.js";
60
39
  import {
61
40
  LlmConfigProviderAuth,
62
41
  getProviderHeaders
@@ -65,10 +44,25 @@ import {
65
44
  resolveProviderChain
66
45
  } from "./chunk-JWC6APFQ.js";
67
46
  import {
68
- buildProviderApiUrl,
69
- resolveApiFormat,
70
- resolveProviderEndpoint
71
- } from "./chunk-H5JUT3KV.js";
47
+ resolveSubscriptionChain
48
+ } from "./chunk-5ERIZW3D.js";
49
+ import {
50
+ getSharedAccountHealth,
51
+ resolveResetSeconds
52
+ } from "./chunk-5ENKBSWO.js";
53
+ import {
54
+ SubscriptionAuthSource
55
+ } from "./chunk-HRRYG2AX.js";
56
+ import {
57
+ serializeError
58
+ } from "./chunk-AVYJ4YBN.js";
59
+ import {
60
+ beginBillingCapture
61
+ } from "./chunk-WLYIIEAF.js";
62
+ import {
63
+ computeQuotaWarnings,
64
+ markQuotaWarnedOnce
65
+ } from "./chunk-3QFXFCHG.js";
72
66
  import {
73
67
  detectRequestRole,
74
68
  endpointToIngressFormat,
@@ -78,14 +72,22 @@ import {
78
72
  parseModelRef,
79
73
  resolveRoute,
80
74
  validateServerModelConfig
81
- } from "./chunk-CZHZGRU7.js";
75
+ } from "./chunk-UHGVBFU3.js";
76
+ import {
77
+ buildProviderApiUrl,
78
+ resolveApiFormat,
79
+ resolveProviderEndpoint
80
+ } from "./chunk-H5JUT3KV.js";
81
+ import {
82
+ beginAuditCapture
83
+ } from "./chunk-IFXJ2BG7.js";
82
84
  import {
83
85
  convertAnthropicToOpenAI,
84
86
  convertOpenAIToAnthropic
85
87
  } from "./chunk-5ZQBEOMD.js";
86
88
  import {
87
89
  fetchUpstream
88
- } from "./chunk-BO4RFWBR.js";
90
+ } from "./chunk-D3TDKWRP.js";
89
91
  import {
90
92
  applyAugmentation
91
93
  } from "./chunk-Y7FO65VT.js";
@@ -649,6 +651,95 @@ async function relayResponse(res, providerResponse, isStream, rewriteModel) {
649
651
  res.end(clientText);
650
652
  return bodyText;
651
653
  }
654
+ async function aggregateAnthropicSseToJsonBody(response, rewriteModel) {
655
+ const text = await response.text();
656
+ const message = {
657
+ type: "message",
658
+ role: "assistant",
659
+ content: [],
660
+ stop_reason: null,
661
+ stop_sequence: null,
662
+ usage: {}
663
+ };
664
+ const blocks = /* @__PURE__ */ new Map();
665
+ for (const raw of text.split("\n")) {
666
+ const line = raw.trim();
667
+ if (!line.startsWith("data:")) continue;
668
+ const payload = line.slice(5).trim();
669
+ if (!payload || payload === "[DONE]") continue;
670
+ let ev;
671
+ try {
672
+ ev = JSON.parse(payload);
673
+ } catch {
674
+ continue;
675
+ }
676
+ switch (ev["type"]) {
677
+ case "message_start": {
678
+ const m = ev["message"] ?? {};
679
+ if (typeof m["id"] === "string") message["id"] = m["id"];
680
+ if (typeof m["model"] === "string") message["model"] = m["model"];
681
+ if (m["usage"]) message["usage"] = { ...m["usage"] };
682
+ break;
683
+ }
684
+ case "content_block_start": {
685
+ const idx = Number(ev["index"]);
686
+ const cb = ev["content_block"] ?? {};
687
+ blocks.set(idx, {
688
+ type: typeof cb["type"] === "string" ? cb["type"] : "text",
689
+ text: typeof cb["text"] === "string" ? cb["text"] : "",
690
+ id: typeof cb["id"] === "string" ? cb["id"] : void 0,
691
+ name: typeof cb["name"] === "string" ? cb["name"] : void 0,
692
+ inputJson: ""
693
+ });
694
+ break;
695
+ }
696
+ case "content_block_delta": {
697
+ const b = blocks.get(Number(ev["index"]));
698
+ if (!b) break;
699
+ const d = ev["delta"] ?? {};
700
+ if (d["type"] === "text_delta" && typeof d["text"] === "string") b.text += d["text"];
701
+ else if (d["type"] === "input_json_delta" && typeof d["partial_json"] === "string")
702
+ b.inputJson += d["partial_json"];
703
+ else if (d["type"] === "thinking_delta" && typeof d["thinking"] === "string")
704
+ b.text += d["thinking"];
705
+ else if (d["type"] === "signature_delta" && typeof d["signature"] === "string")
706
+ b.signature = (b.signature || "") + d["signature"];
707
+ break;
708
+ }
709
+ case "message_delta": {
710
+ const d = ev["delta"] ?? {};
711
+ if (d["stop_reason"] !== void 0) message["stop_reason"] = d["stop_reason"];
712
+ if (d["stop_sequence"] !== void 0) message["stop_sequence"] = d["stop_sequence"];
713
+ if (ev["usage"])
714
+ message["usage"] = { ...message["usage"], ...ev["usage"] };
715
+ break;
716
+ }
717
+ default:
718
+ break;
719
+ }
720
+ }
721
+ message["content"] = [...blocks.keys()].sort((a, b) => a - b).map((idx) => {
722
+ const blk = blocks.get(idx);
723
+ if (!blk) return void 0;
724
+ if (blk.type === "tool_use") {
725
+ let input = {};
726
+ try {
727
+ input = blk.inputJson ? JSON.parse(blk.inputJson) : {};
728
+ } catch {
729
+ input = {};
730
+ }
731
+ return { type: "tool_use", id: blk.id ?? "", name: blk.name ?? "", input };
732
+ }
733
+ if (blk.type === "thinking") {
734
+ const out = { type: "thinking", thinking: blk.text };
735
+ if (blk.signature) out.signature = blk.signature;
736
+ return out;
737
+ }
738
+ return { type: blk.type || "text", text: blk.text };
739
+ }).filter((b) => b !== void 0);
740
+ if (rewriteModel) message["model"] = rewriteModel;
741
+ return JSON.stringify(message);
742
+ }
652
743
  function writeError(res, status, message) {
653
744
  if (res.headersSent) return;
654
745
  res.writeHead(status, { "Content-Type": "application/json" });
@@ -715,6 +806,7 @@ function buildSubscriptionIterationPlan(profile, route, deps, resolvedModel, isS
715
806
  };
716
807
  return {
717
808
  auth,
809
+ preferredAccountId: route.preferredAccountId,
718
810
  chain,
719
811
  transformerProvider,
720
812
  resolvedModel,
@@ -788,6 +880,7 @@ async function runPipeline(anthropicBody, plan, reportSelection) {
788
880
  upstreamUrl,
789
881
  model: resolvedModel,
790
882
  sessionKey: plan.sessionKey,
883
+ preferredAccountId: plan.preferredAccountId,
791
884
  reportSelection: (accountId, isActive) => {
792
885
  proxyAccountId = accountId;
793
886
  reportSelection?.(accountId, isActive);
@@ -833,6 +926,7 @@ async function runSubscriptionSameFormatFetch(rawBody, plan, reportSelection, op
833
926
  upstreamUrl: plan.upstreamUrl,
834
927
  model: plan.resolvedModel,
835
928
  sessionKey: plan.sessionKey,
929
+ preferredAccountId: plan.preferredAccountId,
836
930
  reportSelection: (accountId, isActive, remapped) => {
837
931
  proxyAccountId = accountId;
838
932
  remappedModel = remapped;
@@ -1021,7 +1115,21 @@ async function handleAnthropicMessagesByo(res, rawBody, route, deps, options = {
1021
1115
  if (!plan) return;
1022
1116
  anthropicBody.model = plan.resolvedModel;
1023
1117
  const providerResponse = route.authMode === "subscription" ? await runPipelineWithSubscriptionRetry(anthropicBody, rawBody, plan, route, deps, options) : await runPipelineWithPoolReporting(anthropicBody, rawBody, plan, options);
1024
- const bodyText = await relayResponse(res, providerResponse.response, isStream, route.requestedModel);
1118
+ const upstreamResponse = providerResponse.response;
1119
+ const upstreamSse = (upstreamResponse.headers.get("content-type") ?? "").includes(
1120
+ "text/event-stream"
1121
+ );
1122
+ let bodyText;
1123
+ if (!isStream && upstreamSse) {
1124
+ bodyText = await aggregateAnthropicSseToJsonBody(upstreamResponse, route.requestedModel);
1125
+ res.writeHead(
1126
+ upstreamResponse.status && upstreamResponse.status >= 100 ? upstreamResponse.status : 200,
1127
+ { "Content-Type": "application/json" }
1128
+ );
1129
+ res.end(bodyText);
1130
+ } else {
1131
+ bodyText = await relayResponse(res, upstreamResponse, isStream, route.requestedModel);
1132
+ }
1025
1133
  if (bodyText && deps.usageRecorder) {
1026
1134
  recordAnthropicNonStreamUsage(deps.usageRecorder, bodyText, {
1027
1135
  sessionId: route.sessionId,
@@ -1754,6 +1862,7 @@ async function buildSubscriptionPlan3(res, route, deps, resolvedModel, isStream)
1754
1862
  }
1755
1863
  return {
1756
1864
  auth,
1865
+ preferredAccountId: route.preferredAccountId,
1757
1866
  chain,
1758
1867
  transformerProvider,
1759
1868
  resolvedModel,
@@ -1785,6 +1894,7 @@ async function runPipeline4(responsesBody, plan) {
1785
1894
  await auth.applyHeaders(authHeaders, {
1786
1895
  upstreamUrl,
1787
1896
  model: resolvedModel,
1897
+ preferredAccountId: plan.preferredAccountId,
1788
1898
  reportSelection: (accountId) => {
1789
1899
  proxyAccountId = accountId;
1790
1900
  }
@@ -2044,17 +2154,6 @@ var KeyedMutex = class {
2044
2154
  // src/outbound-api/outboundApiRouter.ts
2045
2155
  import { Readable } from "stream";
2046
2156
 
2047
- // src/pipeline/webhookEmit.ts
2048
- var sink = null;
2049
- function emitWebhookEvent(event) {
2050
- const active = sink;
2051
- if (!active) return;
2052
- try {
2053
- active(event);
2054
- } catch {
2055
- }
2056
- }
2057
-
2058
2157
  // src/outbound-api/apiServerConfig.ts
2059
2158
  import { DEFAULT_AUDIT_CONFIG } from "@omnicross/contracts/audit-types";
2060
2159
  import { DEFAULT_BILLING_CONFIG } from "@omnicross/contracts/billing-types";
@@ -2291,6 +2390,9 @@ function normalizePrefixTargets(raw) {
2291
2390
  function normalizeEndpointConfig(e) {
2292
2391
  const endpoint = e.endpoint;
2293
2392
  const useSubscription = e.useSubscription === true;
2393
+ const boundAccountId = typeof e.boundAccountId === "string" && e.boundAccountId.trim() !== "" ? e.boundAccountId : void 0;
2394
+ const boundKeyId = typeof e.boundKeyId === "string" && e.boundKeyId.trim() !== "" ? e.boundKeyId : void 0;
2395
+ let config;
2294
2396
  if (isKindMappedEndpoint(endpoint)) {
2295
2397
  const rawMap = e.modelMap && typeof e.modelMap === "object" ? e.modelMap : {};
2296
2398
  const modelMap = {};
@@ -2298,27 +2400,28 @@ function normalizeEndpointConfig(e) {
2298
2400
  const v = rawMap[kind];
2299
2401
  modelMap[kind] = typeof v === "string" ? v : "";
2300
2402
  }
2301
- return { endpoint, modelMap, useSubscription };
2302
- }
2303
- if (endpoint === "chat") {
2403
+ config = { endpoint, modelMap, useSubscription };
2404
+ } else if (endpoint === "chat") {
2304
2405
  const models = Array.isArray(e.models) ? e.models.filter((m) => typeof m === "string" && m.trim() !== "") : [];
2305
- const config2 = { endpoint, models, useSubscription };
2406
+ config = { endpoint, models, useSubscription };
2306
2407
  if (e.dispatchMode === "prefix") {
2307
- config2.dispatchMode = "prefix";
2408
+ config.dispatchMode = "prefix";
2308
2409
  const targets = normalizePrefixTargets(e.prefixTargets);
2309
- if (targets) config2.prefixTargets = targets;
2410
+ if (targets) config.prefixTargets = targets;
2411
+ }
2412
+ } else {
2413
+ config = {
2414
+ endpoint,
2415
+ defaultModel: typeof e.defaultModel === "string" ? e.defaultModel : "",
2416
+ backgroundModel: typeof e.backgroundModel === "string" ? e.backgroundModel : "",
2417
+ useSubscription
2418
+ };
2419
+ if (Array.isArray(e.backgroundModelIds)) {
2420
+ config.backgroundModelIds = e.backgroundModelIds;
2310
2421
  }
2311
- return config2;
2312
- }
2313
- const config = {
2314
- endpoint,
2315
- defaultModel: typeof e.defaultModel === "string" ? e.defaultModel : "",
2316
- backgroundModel: typeof e.backgroundModel === "string" ? e.backgroundModel : "",
2317
- useSubscription
2318
- };
2319
- if (Array.isArray(e.backgroundModelIds)) {
2320
- config.backgroundModelIds = e.backgroundModelIds;
2321
2422
  }
2423
+ if (boundAccountId) config.boundAccountId = boundAccountId;
2424
+ if (boundKeyId) config.boundKeyId = boundKeyId;
2322
2425
  return config;
2323
2426
  }
2324
2427
  function defaultServerConfig() {
@@ -2406,204 +2509,6 @@ function mergeServerConfig(current, patch) {
2406
2509
  });
2407
2510
  }
2408
2511
 
2409
- // src/outbound-api/auditCapture.ts
2410
- import { randomUUID } from "crypto";
2411
-
2412
- // src/outbound-api/auditRedact.ts
2413
- var AUDIT_REDACTED = "***REDACTED***";
2414
- var RULES = [
2415
- // `sk-…` family (Anthropic sk-ant-, omnicross sk-omnicross-, OpenAI sk-proj-/sk-).
2416
- { re: /\bsk-[A-Za-z0-9_-]{6,}/g, replace: AUDIT_REDACTED },
2417
- // Google API keys.
2418
- { re: /\bAIza[A-Za-z0-9_-]{10,}/g, replace: AUDIT_REDACTED },
2419
- // `Bearer <token>` (auth headers echoed into a body / SSE error).
2420
- { re: /\bBearer\s+[A-Za-z0-9._~+/=-]{6,}/gi, replace: `Bearer ${AUDIT_REDACTED}` },
2421
- // Inline `x-api-key` / `api-key` / `authorization` label followed by a value.
2422
- {
2423
- re: /\b(x-api-key|api[_-]?key|authorization)(["']?\s*[:=]\s*["']?)[A-Za-z0-9._~+/=-]{6,}/gi,
2424
- replace: `$1$2${AUDIT_REDACTED}`
2425
- },
2426
- // `x-goog-api-key` header echoed inline.
2427
- {
2428
- re: /\b(x-goog-api-key)(["']?\s*[:=]\s*["']?)[A-Za-z0-9._~+/=-]{6,}/gi,
2429
- replace: `$1$2${AUDIT_REDACTED}`
2430
- }
2431
- ];
2432
- function redactAuditText(text) {
2433
- if (typeof text !== "string" || text.length === 0) return text ?? "";
2434
- let out = text;
2435
- for (const { re, replace } of RULES) {
2436
- out = out.replace(re, replace);
2437
- }
2438
- return out;
2439
- }
2440
-
2441
- // src/outbound-api/auditCapture.ts
2442
- function isStreamingContentType(res) {
2443
- const ct = res.getHeader("content-type");
2444
- const value = Array.isArray(ct) ? ct.join(";") : String(ct ?? "");
2445
- return value.toLowerCase().includes("text/event-stream");
2446
- }
2447
- function resolveClientIp(req, trustForwardedFor) {
2448
- if (trustForwardedFor) {
2449
- const xff = req.headers["x-forwarded-for"];
2450
- const raw = Array.isArray(xff) ? xff[0] : xff;
2451
- if (typeof raw === "string" && raw.trim()) {
2452
- const first = raw.split(",")[0]?.trim();
2453
- if (first) return first;
2454
- }
2455
- }
2456
- return req.socket?.remoteAddress ?? void 0;
2457
- }
2458
- function truncateToBytes(text, maxBytes) {
2459
- const buf = Buffer.from(text, "utf8");
2460
- if (buf.length <= maxBytes) return text;
2461
- return buf.subarray(0, maxBytes).toString("utf8");
2462
- }
2463
- function beginAuditCapture(req, res, now) {
2464
- const config = getAuditCaptureConfig();
2465
- if (!config) return null;
2466
- let rawRequestBody;
2467
- const responseChunks = [];
2468
- let responseBytes = 0;
2469
- let streamDetected = false;
2470
- let finished = false;
2471
- const ctx = {
2472
- setRequestBody(raw) {
2473
- if (config.captureBodies) rawRequestBody = raw;
2474
- }
2475
- };
2476
- if (config.captureBodies) {
2477
- installResponseCapture(res, config.maxBodyBytes, {
2478
- push(chunk) {
2479
- responseBytes += chunk.length;
2480
- responseChunks.push(chunk);
2481
- },
2482
- get bytes() {
2483
- return responseBytes;
2484
- },
2485
- markStream() {
2486
- streamDetected = true;
2487
- },
2488
- get isStream() {
2489
- return streamDetected;
2490
- }
2491
- });
2492
- }
2493
- const finalize = () => {
2494
- if (finished) return;
2495
- finished = true;
2496
- try {
2497
- const record = {
2498
- id: randomUUID(),
2499
- ts: now,
2500
- method: req.method ?? "",
2501
- path: (req.url ?? "").split("?")[0] ?? "",
2502
- status: res.statusCode,
2503
- latencyMs: Math.max(0, Date.now() - now)
2504
- };
2505
- if (ctx.keyId != null) record.keyId = ctx.keyId;
2506
- const ip = resolveClientIp(req, config.trustForwardedFor);
2507
- if (ip) record.ip = ip;
2508
- const ua = req.headers["user-agent"];
2509
- if (typeof ua === "string" && ua) record.ua = ua;
2510
- if (ctx.model) record.model = ctx.model;
2511
- if (ctx.provider) record.provider = ctx.provider;
2512
- const usage = readAuditUsage(res);
2513
- if (usage) {
2514
- if (typeof usage.inputTokens === "number") record.inputTokens = usage.inputTokens;
2515
- if (typeof usage.outputTokens === "number") record.outputTokens = usage.outputTokens;
2516
- if (typeof usage.costUsd === "number") record.costUsd = usage.costUsd;
2517
- if (!record.model && usage.model) record.model = usage.model;
2518
- if (!record.provider && usage.provider) record.provider = usage.provider;
2519
- }
2520
- if (ctx.error) record.error = redactAuditText(ctx.error);
2521
- if (config.captureBodies) {
2522
- if (rawRequestBody != null && rawRequestBody.length > 0) {
2523
- record.requestBody = redactAuditText(truncateToBytes(rawRequestBody, config.maxBodyBytes));
2524
- }
2525
- if (!streamDetected && responseChunks.length > 0) {
2526
- const body = Buffer.concat(responseChunks).toString("utf8");
2527
- record.responseBody = redactAuditText(body);
2528
- }
2529
- }
2530
- recordAudit(record);
2531
- } catch {
2532
- }
2533
- };
2534
- res.once("close", finalize);
2535
- return ctx;
2536
- }
2537
- function installResponseCapture(res, maxBodyBytes, sink2) {
2538
- let contentTypeChecked = false;
2539
- const capture = (chunk) => {
2540
- if (sink2.isStream) return;
2541
- if (!contentTypeChecked) {
2542
- contentTypeChecked = true;
2543
- if (isStreamingContentType(res)) {
2544
- sink2.markStream();
2545
- return;
2546
- }
2547
- }
2548
- if (sink2.bytes >= maxBodyBytes) return;
2549
- let buf = null;
2550
- if (Buffer.isBuffer(chunk)) buf = chunk;
2551
- else if (typeof chunk === "string") buf = Buffer.from(chunk, "utf8");
2552
- if (!buf || buf.length === 0) return;
2553
- const remaining = maxBodyBytes - sink2.bytes;
2554
- sink2.push(buf.length > remaining ? buf.subarray(0, remaining) : buf);
2555
- };
2556
- const originalWrite = res.write.bind(res);
2557
- const originalEnd = res.end.bind(res);
2558
- res.write = ((chunk, ...args) => {
2559
- if (chunk != null) capture(chunk);
2560
- return originalWrite(chunk, ...args);
2561
- });
2562
- res.end = ((chunk, ...args) => {
2563
- if (chunk != null && typeof chunk !== "function") capture(chunk);
2564
- return originalEnd(chunk, ...args);
2565
- });
2566
- }
2567
-
2568
- // src/outbound-api/billingCapture.ts
2569
- import { randomUUID as randomUUID2 } from "crypto";
2570
- var defaultDefer = (fn) => {
2571
- setTimeout(fn, 0);
2572
- };
2573
- function beginBillingCapture(_req, res, now, defer = defaultDefer) {
2574
- if (!getBillingCaptureConfig()) return null;
2575
- const ctx = {};
2576
- let finished = false;
2577
- const finalize = () => {
2578
- if (finished) return;
2579
- finished = true;
2580
- const status = res.statusCode;
2581
- defer(() => {
2582
- try {
2583
- const usage = readAuditUsage(res);
2584
- if (!usage) return;
2585
- const event = {
2586
- id: randomUUID2(),
2587
- ts: now,
2588
- model: ctx.model ?? usage.model ?? "",
2589
- authMode: ctx.authMode ?? "byo",
2590
- inputTokens: usage.inputTokens ?? 0,
2591
- outputTokens: usage.outputTokens ?? 0,
2592
- costUsd: usage.costUsd ?? 0,
2593
- status
2594
- };
2595
- if (ctx.keyId != null) event.keyId = ctx.keyId;
2596
- const provider = ctx.provider ?? usage.provider;
2597
- if (provider) event.provider = provider;
2598
- publishBillingEvent(event);
2599
- } catch {
2600
- }
2601
- });
2602
- };
2603
- res.once("close", finalize);
2604
- return ctx;
2605
- }
2606
-
2607
2512
  // src/outbound-api/outboundApiKeyAuth.ts
2608
2513
  import { createHash, randomBytes as randomBytes2 } from "crypto";
2609
2514
 
@@ -2752,30 +2657,6 @@ async function verifyPresentedKey(db, presentedKey) {
2752
2657
  return result.status === "ok" ? result.key : null;
2753
2658
  }
2754
2659
 
2755
- // src/outbound-api/quotaWarn.ts
2756
- var WEBHOOK_QUOTA_WARN_RATIO = 0.8;
2757
- function computeQuotaWarnings(limits, spend, ratio = WEBHOOK_QUOTA_WARN_RATIO) {
2758
- const out = [];
2759
- const consider = (scope, limit, spent, windowStart) => {
2760
- if (limit == null || limit <= 0) return;
2761
- if (spent >= limit) return;
2762
- if (spent >= ratio * limit) out.push({ scope, limitUsd: limit, spentUsd: spent, windowStart });
2763
- };
2764
- consider("daily", limits.dailyUsd, spend.dailyUsd, spend.dailyWindowStart);
2765
- consider("weekly", limits.weeklyUsd, spend.weeklyUsd, spend.weeklyWindowStart);
2766
- consider("total", limits.totalUsd, spend.totalUsd, 0);
2767
- return out;
2768
- }
2769
- var WARN_GUARD_MAX = 1e4;
2770
- var warned = /* @__PURE__ */ new Set();
2771
- function markQuotaWarnedOnce(keyId, scope, windowStart) {
2772
- const key = `${keyId}\0${scope}\0${windowStart}`;
2773
- if (warned.has(key)) return false;
2774
- if (warned.size >= WARN_GUARD_MAX) warned.clear();
2775
- warned.add(key);
2776
- return true;
2777
- }
2778
-
2779
2660
  // src/outbound-api/outboundConcurrencyGate.ts
2780
2661
  var ConcurrencyQueueFullError = class extends Error {
2781
2662
  constructor(apiKeyId, maxQueueSize) {
@@ -3817,6 +3698,7 @@ var OutboundApiServer = class {
3817
3698
  }
3818
3699
  /** Per-request handler. Auth is enforced on EVERY request (incl. loopback). */
3819
3700
  onRequest(req, res) {
3701
+ if (req.url) req.url = normalizeDoubledEndpointPath(req.url);
3820
3702
  if (this.deps.healthReportProvider && this.tryServeHealth(req, res)) return;
3821
3703
  handleOutboundRequest(
3822
3704
  req,
@@ -3939,6 +3821,16 @@ function firstLanIPv4() {
3939
3821
  }
3940
3822
  return null;
3941
3823
  }
3824
+ function normalizeDoubledEndpointPath(url) {
3825
+ const queryIdx = url.indexOf("?");
3826
+ const path = queryIdx === -1 ? url : url.slice(0, queryIdx);
3827
+ const query = queryIdx === -1 ? "" : url.slice(queryIdx);
3828
+ const collapsed = path.replace(
3829
+ /^(.*?)(\/v1\/(?:messages|responses|chat\/completions))\2$/,
3830
+ "$1$2"
3831
+ );
3832
+ return collapsed + query;
3833
+ }
3942
3834
 
3943
3835
  // src/outbound-api/keySpendTracker.ts
3944
3836
  function startOfLocalDay(ts) {
@@ -5646,8 +5538,8 @@ var CompletionService = class {
5646
5538
  * emission is unconditional in production. Optional — when unset (unit-test
5647
5539
  * constructors), the emit calls no-op, identical to `usageRecorder`.
5648
5540
  */
5649
- setUsageEventSink(sink2) {
5650
- this.usageEventSink = sink2;
5541
+ setUsageEventSink(sink) {
5542
+ this.usageEventSink = sink;
5651
5543
  }
5652
5544
  /**
5653
5545
  * Set the vision-fallback provider used by `applyVisionFallback` to describe
@@ -6126,6 +6018,7 @@ export {
6126
6018
  getGeminiEndpointTransformer,
6127
6019
  readBody,
6128
6020
  relayResponse,
6021
+ aggregateAnthropicSseToJsonBody,
6129
6022
  writeError,
6130
6023
  resolvePoolBoundKey,
6131
6024
  extractRouteToken,
@@ -6155,10 +6048,6 @@ export {
6155
6048
  loadServerConfig,
6156
6049
  saveServerConfig,
6157
6050
  mergeServerConfig,
6158
- AUDIT_REDACTED,
6159
- redactAuditText,
6160
- beginAuditCapture,
6161
- beginBillingCapture,
6162
6051
  computeKeyExpiry,
6163
6052
  checkKeyQuota,
6164
6053
  randomBase62,
@@ -33,7 +33,8 @@ var SubscriptionAuthSource = class {
33
33
  upstreamUrl: hints.upstreamUrl,
34
34
  resolvedModel: hints.model,
35
35
  sessionKey: hints.sessionKey,
36
- reportSelection: hints.reportSelection
36
+ reportSelection: hints.reportSelection,
37
+ preferredAccountId: hints.preferredAccountId
37
38
  });
38
39
  } catch (err) {
39
40
  console.warn("[SubscriptionAuthSource] authStrategy.applyHeaders threw:", serializeError(err));
@@ -23,6 +23,9 @@ async function executeProviderCall(ctx) {
23
23
  const finalBody = prepareBody ? await prepareBody(requestBody, config) : requestBody;
24
24
  const url = resolveUrl(config);
25
25
  const headers = buildHeaders(config);
26
+ if (!headers["content-type"] && !headers["Content-Type"]) {
27
+ headers["content-type"] = "application/json";
28
+ }
26
29
  const fetched = await fetchFn(url, headers, finalBody);
27
30
  let response = fetched;
28
31
  if (runResponseChain) {
@@ -15,10 +15,11 @@ var OpenCodeGoTransformer = class {
15
15
  async transformRequestIn(request, _provider, _context) {
16
16
  const messages = request.messages.map((m) => {
17
17
  const content = m.content;
18
- if (Array.isArray(content) && content.length === 1 && content[0]?.type === "text") {
19
- return { ...m, content: content[0].text };
20
- }
21
- return m;
18
+ const normalizedContent = Array.isArray(content) && content.length === 1 && content[0]?.type === "text" ? content[0].text : content;
19
+ const out2 = { role: m.role, content: normalizedContent };
20
+ if (m.tool_calls) out2.tool_calls = m.tool_calls;
21
+ if (m.tool_call_id) out2.tool_call_id = m.tool_call_id;
22
+ return out2;
22
23
  });
23
24
  const out = {
24
25
  model: request.model,