@omnicross/core 0.1.6 → 0.1.7

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (131) hide show
  1. package/dist/ApiConverter.cjs +2 -2
  2. package/dist/ApiConverter.js +1 -1
  3. package/dist/auth/GeminiCodeAssistProjectResolver.cjs +4 -3
  4. package/dist/auth/GeminiCodeAssistProjectResolver.js +3 -2
  5. package/dist/{chunk-3Z5BQZFM.cjs → chunk-235MXAGX.cjs} +3 -1
  6. package/dist/{chunk-DLXZEZWO.cjs → chunk-2E42SAW3.cjs} +42 -4
  7. package/dist/{chunk-7AK7B36B.cjs → chunk-2Z4XM3H5.cjs} +6 -6
  8. package/dist/{chunk-OEWZUX4G.js → chunk-32O35CIF.js} +9 -20
  9. package/dist/chunk-3SCOLIPT.cjs +63 -0
  10. package/dist/{chunk-SYQF7OIR.js → chunk-3WD4HTR2.js} +2 -0
  11. package/dist/{chunk-SQYVORNP.cjs → chunk-4BB343BI.cjs} +527 -267
  12. package/dist/{chunk-AT7B7SOZ.js → chunk-5NJLQ6T6.js} +21 -10
  13. package/dist/chunk-5RSZYQJH.cjs +62 -0
  14. package/dist/{chunk-IFXJ2BG7.js → chunk-7C7DET6S.js} +51 -6
  15. package/dist/{chunk-UDCC7EMR.js → chunk-E3COOKUP.js} +307 -47
  16. package/dist/chunk-FU7EAR73.js +62 -0
  17. package/dist/{chunk-UX7VWA46.js → chunk-FXR6N3SR.js} +39 -1
  18. package/dist/{chunk-WYTEQ4Q5.cjs → chunk-GDIXXKF2.cjs} +21 -10
  19. package/dist/{chunk-WB6PH56J.js → chunk-GFIZ6LQI.js} +12 -8
  20. package/dist/chunk-GL6XM527.js +61 -0
  21. package/dist/{chunk-EJLH6NFT.cjs → chunk-J3QQ6JS5.cjs} +12 -8
  22. package/dist/{chunk-VRFBB5DB.js → chunk-MYYR3HZL.js} +4 -4
  23. package/dist/{chunk-YJVHCHQX.js → chunk-N7OOJI5V.js} +46 -2
  24. package/dist/chunk-NKVZ6Z3Y.cjs +61 -0
  25. package/dist/{chunk-SNYBEXLB.cjs → chunk-OJGQKHN5.cjs} +3 -1
  26. package/dist/chunk-OTZC4TNH.cjs +79 -0
  27. package/dist/{chunk-6VUQPOV3.cjs → chunk-OVQBNVSV.cjs} +10 -21
  28. package/dist/{chunk-4VLRHHFE.cjs → chunk-OXHNSZ53.cjs} +9 -11
  29. package/dist/{chunk-6CL5HTPQ.js → chunk-PEGTIPB3.js} +8 -10
  30. package/dist/chunk-PO3XB56Z.js +79 -0
  31. package/dist/{chunk-SIZQQD6T.js → chunk-RJ5ZGNI3.js} +42 -5
  32. package/dist/{chunk-KCVJWJST.cjs → chunk-RJUONLUQ.cjs} +47 -10
  33. package/dist/{chunk-BPKCU575.js → chunk-SOO562NM.js} +3 -1
  34. package/dist/{chunk-UNWKG6EI.cjs → chunk-XPIOJQS2.cjs} +51 -6
  35. package/dist/chunk-XXFYLL7R.js +63 -0
  36. package/dist/{chunk-YK57NMIF.cjs → chunk-YWL7YZWS.cjs} +47 -3
  37. package/dist/completion/CompletionService.cjs +23 -19
  38. package/dist/completion/CompletionService.d.cts +1 -0
  39. package/dist/completion/CompletionService.d.ts +1 -0
  40. package/dist/completion/CompletionService.js +22 -18
  41. package/dist/completion.cjs +23 -19
  42. package/dist/completion.d.cts +1 -0
  43. package/dist/completion.d.ts +1 -0
  44. package/dist/completion.js +22 -18
  45. package/dist/index.cjs +26 -22
  46. package/dist/index.d.cts +2 -2
  47. package/dist/index.d.ts +2 -2
  48. package/dist/index.js +26 -22
  49. package/dist/outbound-api/auditCapture.cjs +2 -2
  50. package/dist/outbound-api/auditCapture.d.cts +3 -4
  51. package/dist/outbound-api/auditCapture.d.ts +3 -4
  52. package/dist/outbound-api/auditCapture.js +1 -1
  53. package/dist/outbound-api/routeResolver.d.cts +3 -2
  54. package/dist/outbound-api/routeResolver.d.ts +3 -2
  55. package/dist/outbound-api/subscriptionRegistryPort.d.cts +1 -0
  56. package/dist/outbound-api/subscriptionRegistryPort.d.ts +1 -0
  57. package/dist/outbound-api/types.d.cts +2 -1
  58. package/dist/outbound-api/types.d.ts +2 -1
  59. package/dist/outbound-api.cjs +23 -19
  60. package/dist/outbound-api.d.cts +7 -5
  61. package/dist/outbound-api.d.ts +7 -5
  62. package/dist/outbound-api.js +22 -18
  63. package/dist/pipeline/AccountAllowanceScheduling.d.cts +2 -1
  64. package/dist/pipeline/AccountAllowanceScheduling.d.ts +2 -1
  65. package/dist/pipeline/AccountRouteActivity.cjs +10 -0
  66. package/dist/pipeline/AccountRouteActivity.d.cts +61 -0
  67. package/dist/pipeline/AccountRouteActivity.d.ts +61 -0
  68. package/dist/pipeline/AccountRouteActivity.js +10 -0
  69. package/dist/pipeline/ServerOverloadCounter.cjs +16 -0
  70. package/dist/pipeline/ServerOverloadCounter.d.cts +77 -0
  71. package/dist/pipeline/ServerOverloadCounter.d.ts +77 -0
  72. package/dist/pipeline/ServerOverloadCounter.js +16 -0
  73. package/dist/pipeline/SubscriptionAccountHealth.cjs +4 -2
  74. package/dist/pipeline/SubscriptionAccountHealth.d.cts +32 -3
  75. package/dist/pipeline/SubscriptionAccountHealth.d.ts +32 -3
  76. package/dist/pipeline/SubscriptionAccountHealth.js +3 -1
  77. package/dist/pipeline/upstreamFetch.cjs +4 -3
  78. package/dist/pipeline/upstreamFetch.d.cts +35 -6
  79. package/dist/pipeline/upstreamFetch.d.ts +35 -6
  80. package/dist/pipeline/upstreamFetch.js +3 -2
  81. package/dist/pipeline/upstreamTrace.cjs +4 -2
  82. package/dist/pipeline/upstreamTrace.d.cts +22 -8
  83. package/dist/pipeline/upstreamTrace.d.ts +22 -8
  84. package/dist/pipeline/upstreamTrace.js +3 -1
  85. package/dist/ports.d.cts +1 -1
  86. package/dist/ports.d.ts +1 -1
  87. package/dist/provider-proxy/ProviderProxy.cjs +23 -19
  88. package/dist/provider-proxy/ProviderProxy.d.cts +1 -0
  89. package/dist/provider-proxy/ProviderProxy.d.ts +1 -0
  90. package/dist/provider-proxy/ProviderProxy.js +22 -18
  91. package/dist/provider-proxy/identity/codexCliHeaders.cjs +10 -0
  92. package/dist/provider-proxy/identity/codexCliHeaders.d.cts +45 -0
  93. package/dist/provider-proxy/identity/codexCliHeaders.d.ts +45 -0
  94. package/dist/provider-proxy/identity/codexCliHeaders.js +10 -0
  95. package/dist/provider-proxy/ingress/providerProxyShared.cjs +23 -19
  96. package/dist/provider-proxy/ingress/providerProxyShared.d.cts +11 -1
  97. package/dist/provider-proxy/ingress/providerProxyShared.d.ts +11 -1
  98. package/dist/provider-proxy/ingress/providerProxyShared.js +22 -18
  99. package/dist/provider-proxy/matchText.cjs +2 -2
  100. package/dist/provider-proxy/matchText.d.cts +1 -3
  101. package/dist/provider-proxy/matchText.d.ts +1 -3
  102. package/dist/provider-proxy/matchText.js +1 -1
  103. package/dist/provider-proxy/types.d.cts +5 -0
  104. package/dist/provider-proxy/types.d.ts +5 -0
  105. package/dist/provider-proxy.cjs +23 -19
  106. package/dist/provider-proxy.d.cts +1 -0
  107. package/dist/provider-proxy.d.ts +1 -0
  108. package/dist/provider-proxy.js +22 -18
  109. package/dist/{routeResolver-CHTv_Bs5.d.ts → routeResolver-BxOfunbm.d.ts} +1 -1
  110. package/dist/{routeResolver-kepxnfcC.d.cts → routeResolver-D5OzD0iM.d.cts} +1 -1
  111. package/dist/transformer/transformers/AnthropicTransformer.cjs +3 -2
  112. package/dist/transformer/transformers/AnthropicTransformer.js +2 -1
  113. package/dist/transformer/transformers/OpenAIResponseTransformer.cjs +3 -2
  114. package/dist/transformer/transformers/OpenAIResponseTransformer.js +2 -1
  115. package/dist/transformer/transformers.cjs +7 -6
  116. package/dist/transformer/transformers.js +6 -5
  117. package/dist/transformer.cjs +9 -8
  118. package/dist/transformer.js +8 -7
  119. package/dist/{types-hsoKrVQS.d.ts → types-CqZD77rS.d.ts} +39 -0
  120. package/dist/{types-H3wGZSOo.d.cts → types-gjJ5lJ5n.d.cts} +39 -0
  121. package/dist/usage/pricing-engine.cjs +2 -2
  122. package/dist/usage/pricing-engine.d.cts +20 -0
  123. package/dist/usage/pricing-engine.d.ts +20 -0
  124. package/dist/usage/pricing-engine.js +1 -1
  125. package/dist/usage/usage-recorder.cjs +2 -2
  126. package/dist/usage/usage-recorder.d.cts +5 -1
  127. package/dist/usage/usage-recorder.d.ts +5 -1
  128. package/dist/usage/usage-recorder.js +1 -1
  129. package/dist/usage.cjs +3 -3
  130. package/dist/usage.js +2 -2
  131. package/package.json +1 -1
@@ -21,6 +21,15 @@ var PricingEngine = class {
21
21
  * non-wildcard entry per model wins.
22
22
  */
23
23
  cacheByModel = /* @__PURE__ */ new Map();
24
+ /**
25
+ * Last-resort fuzzy index: `[normalizedModelId, entry]` pairs over the same
26
+ * non-wildcard, non-openrouter rows as `cacheByModel`. Used when even the
27
+ * model-name fallback misses — e.g. usage recorded under a bare model id
28
+ * (`glm-5.2`) while the catalog only knows prefixed slugs
29
+ * (`cloudflare/@cf/zai-org/glm-5.2`). This is an ESTIMATE: the matched row
30
+ * may be an aggregate-route price rather than the direct-vendor rate.
31
+ */
32
+ fuzzyEntries = [];
24
33
  cacheLoaded = false;
25
34
  /** Coalesce manual and background refreshes to prevent a catalog stampede. */
26
35
  refreshInFlight = null;
@@ -31,9 +40,11 @@ var PricingEngine = class {
31
40
  const rows = await this.store.getAll();
32
41
  this.cache = new Map(rows.map((r) => [keyOf(r.providerId, r.modelId), r]));
33
42
  this.cacheByModel = /* @__PURE__ */ new Map();
43
+ this.fuzzyEntries = [];
34
44
  for (const r of rows) {
35
45
  if (r.providerId === "*" || r.providerId === "openrouter" || r.source === "openrouter") continue;
36
46
  if (!this.cacheByModel.has(r.modelId)) this.cacheByModel.set(r.modelId, r);
47
+ this.fuzzyEntries.push([normalizeModelId(r.modelId), r]);
37
48
  }
38
49
  this.cacheLoaded = true;
39
50
  }
@@ -53,10 +64,36 @@ var PricingEngine = class {
53
64
  * 2. wildcard provider ('*', modelId)
54
65
  * 3. model name alone (any provider) — tolerates a runtime-alias vs
55
66
  * canonical provider-id mismatch for the same model.
67
+ * 4. normalized fuzzy match (last resort) — matches a bare id like
68
+ * `glm-5.2` against prefixed catalog slugs like
69
+ * `cloudflare/@cf/zai-org/glm-5.2`. ESTIMATE only: the matched row may
70
+ * be an aggregate-route price, not the direct-vendor rate.
56
71
  */
57
72
  async getEntry(providerId, modelId) {
58
73
  await this.ensureCache();
59
- return this.cache.get(keyOf(providerId, modelId)) ?? this.cache.get(keyOf("*", modelId)) ?? this.cacheByModel.get(modelId) ?? null;
74
+ const exact = this.cache.get(keyOf(providerId, modelId)) ?? this.cache.get(keyOf("*", modelId)) ?? this.cacheByModel.get(modelId) ?? null;
75
+ if (exact) return exact;
76
+ return this.fuzzyMatch(modelId);
77
+ }
78
+ /**
79
+ * Normalized substring match over the catalog's non-openrouter rows. Lowercases
80
+ * and strips all non-alphanumerics, then matches bidirectionally, preferring
81
+ * the shortest catalog key (tightest match) to reduce over-matching version
82
+ * variants. Returns null when nothing matches.
83
+ */
84
+ fuzzyMatch(modelId) {
85
+ const normQuery = normalizeModelId(modelId);
86
+ if (!normQuery) return null;
87
+ let best = null;
88
+ let bestLen = Infinity;
89
+ for (const [key, entry] of this.fuzzyEntries) {
90
+ if (!key || !key.includes(normQuery) && !normQuery.includes(key)) continue;
91
+ if (key.length < bestLen) {
92
+ best = entry;
93
+ bestLen = key.length;
94
+ }
95
+ }
96
+ return best;
60
97
  }
61
98
  // ===== Cost calculation =====
62
99
  /**
@@ -187,6 +224,7 @@ var PricingEngine = class {
187
224
  }
188
225
  };
189
226
  var keyOf = (providerId, modelId) => `${providerId}::${modelId}`;
227
+ var normalizeModelId = (modelId) => (modelId ?? "").toLowerCase().replace(/[^a-z0-9]/g, "");
190
228
  var PROVIDER_ALIASES = {
191
229
  vertex_ai: "gemini",
192
230
  google: "gemini",
@@ -81,6 +81,20 @@ function flattenToolResultContent(content) {
81
81
  }
82
82
 
83
83
  // src/api-converter/anthropic-to-openai.ts
84
+ function anthropicUsageToChatUsage(usage) {
85
+ const input = usage.input_tokens || 0;
86
+ const output = usage.output_tokens || 0;
87
+ const cacheRead = usage.cache_read_input_tokens || 0;
88
+ const cacheCreation = usage.cache_creation_input_tokens || 0;
89
+ const promptTokens = input + cacheRead + cacheCreation;
90
+ const out = {
91
+ prompt_tokens: promptTokens,
92
+ completion_tokens: output,
93
+ total_tokens: promptTokens + output
94
+ };
95
+ if (cacheRead > 0) out.prompt_tokens_details = { cached_tokens: cacheRead };
96
+ return out;
97
+ }
84
98
  function convertAnthropicToOpenAI(response) {
85
99
  const content = [];
86
100
  const toolCalls = [];
@@ -118,11 +132,7 @@ function convertAnthropicToOpenAI(response) {
118
132
  finish_reason: finishReason
119
133
  }
120
134
  ],
121
- usage: {
122
- prompt_tokens: response.usage.input_tokens,
123
- completion_tokens: response.usage.output_tokens,
124
- total_tokens: response.usage.input_tokens + response.usage.output_tokens
125
- }
135
+ usage: anthropicUsageToChatUsage(response.usage)
126
136
  };
127
137
  if (reasoningContent) {
128
138
  result.reasoning_content = reasoningContent;
@@ -352,11 +362,12 @@ async function* convertAnthropicStreamToOpenAI(anthropicStream) {
352
362
  delta: {},
353
363
  finish_reason: finishReason
354
364
  }],
355
- usage: event.usage ? {
356
- prompt_tokens: event.usage.input_tokens || 0,
357
- completion_tokens: event.usage.output_tokens || 0,
358
- total_tokens: (event.usage.input_tokens || 0) + (event.usage.output_tokens || 0)
359
- } : void 0
365
+ usage: event.usage ? anthropicUsageToChatUsage({
366
+ input_tokens: event.usage.input_tokens || 0,
367
+ output_tokens: event.usage.output_tokens || 0,
368
+ cache_read_input_tokens: event.usage.cache_read_input_tokens,
369
+ cache_creation_input_tokens: event.usage.cache_creation_input_tokens
370
+ }) : void 0
360
371
  })}
361
372
 
362
373
  `;
@@ -1,4 +1,5 @@
1
1
  // src/provider-proxy/matchText.ts
2
+ import { createHash } from "crypto";
2
3
  var MATCH_TEXT_PER_MESSAGE_CAP = 8192;
3
4
  var MATCH_TEXT_RECENT_MESSAGES = 6;
4
5
  function flattenMatchText(value) {
@@ -55,39 +56,42 @@ var SESSION_ID_CAP = 1024;
55
56
  function deriveGatewaySessionKey(body, headers = {}, options = {}) {
56
57
  const sessionHeader = firstHeaderValue(headers, ["session-id", "session_id", "x-session-id"]);
57
58
  if (sessionHeader) {
58
- return { key: fnv1a(sessionHeader), source: "session-header" };
59
+ return { key: stableSessionDigest(sessionHeader), source: "session-header" };
59
60
  }
60
61
  const threadHeader = firstHeaderValue(headers, ["thread-id", "thread_id", "x-thread-id"]);
61
62
  if (threadHeader) {
62
- return { key: fnv1a(threadHeader), source: "thread-header" };
63
+ return { key: stableSessionDigest(threadHeader), source: "thread-header" };
63
64
  }
64
65
  const bodySessionId = scalarSessionValue(body.session_id);
65
66
  if (bodySessionId) {
66
- return { key: fnv1a(bodySessionId), source: "body-session-id" };
67
+ return { key: stableSessionDigest(bodySessionId), source: "body-session-id" };
67
68
  }
68
69
  const bodyThreadId = scalarSessionValue(body.thread_id ?? body.threadId);
69
70
  if (bodyThreadId) {
70
- return { key: fnv1a(bodyThreadId), source: "body-thread-id" };
71
+ return { key: stableSessionDigest(bodyThreadId), source: "body-thread-id" };
71
72
  }
72
73
  const conversationId = scalarSessionValue(body.conversation_id);
73
74
  if (conversationId) {
74
- return { key: fnv1a(conversationId), source: "body-session-id" };
75
+ return { key: stableSessionDigest(conversationId), source: "body-session-id" };
75
76
  }
76
77
  const promptCacheKey = scalarSessionValue(body.prompt_cache_key);
77
78
  if (promptCacheKey) {
78
- return { key: fnv1a(promptCacheKey), source: "prompt-cache-key" };
79
+ return { key: stableSessionDigest(promptCacheKey), source: "prompt-cache-key" };
79
80
  }
80
81
  const fingerprint = deriveResponsesContentFingerprint(body);
81
82
  if (fingerprint) {
82
- return { key: fnv1a(fingerprint), source: "content-fingerprint" };
83
+ return { key: stableSessionDigest(fingerprint), source: "content-fingerprint" };
83
84
  }
84
85
  const endpoint = options.endpoint?.trim() || "responses";
85
86
  const fallback = options.fallbackKey?.trim() || "anonymous";
86
87
  return {
87
- key: fnv1a(`${endpoint}\0${fallback}`),
88
+ key: stableSessionDigest(`${endpoint}\0${fallback}`),
88
89
  source: "api-key-fallback"
89
90
  };
90
91
  }
92
+ function stableSessionDigest(value) {
93
+ return createHash("sha256").update(value, "utf8").digest("hex").slice(0, 32);
94
+ }
91
95
  function firstHeaderValue(headers, names) {
92
96
  const byLower = /* @__PURE__ */ new Map();
93
97
  for (const [name, value] of Object.entries(headers)) {
@@ -0,0 +1,61 @@
1
+ // src/pipeline/AccountRouteActivity.ts
2
+ var ACCOUNT_ROUTE_ACTIVITY_LIMIT = 300;
3
+ function boundedLimit(value) {
4
+ if (!Number.isFinite(value)) return 100;
5
+ return Math.max(1, Math.min(ACCOUNT_ROUTE_ACTIVITY_LIMIT, Math.trunc(value)));
6
+ }
7
+ var AccountRouteActivityStore = class {
8
+ records = [];
9
+ sequence = 0;
10
+ record(input) {
11
+ const ts = input.ts ?? Date.now();
12
+ const sessionKey = input.sessionKey?.trim() || void 0;
13
+ const previous = sessionKey ? this.records.find((record2) => record2.providerId === input.providerId && record2.endpoint === input.endpoint && record2.sessionKey === sessionKey) : void 0;
14
+ const affinity = !sessionKey ? "untracked" : !previous ? "new" : previous.accountId === input.accountId ? "sticky" : "switched";
15
+ const record = {
16
+ ...input,
17
+ id: `${ts.toString(36)}-${(this.sequence++).toString(36)}`,
18
+ ts,
19
+ sessionKey,
20
+ affinity,
21
+ ...affinity === "switched" && previous ? { previousAccountId: previous.accountId } : {}
22
+ };
23
+ this.records.unshift(record);
24
+ if (this.records.length > ACCOUNT_ROUTE_ACTIVITY_LIMIT) {
25
+ this.records.length = ACCOUNT_ROUTE_ACTIVITY_LIMIT;
26
+ }
27
+ return { ...record };
28
+ }
29
+ list(query = {}) {
30
+ const providerId = query.providerId?.trim();
31
+ const accountId = query.accountId?.trim();
32
+ const sessionKey = query.sessionKey?.trim();
33
+ return this.records.filter((record) => !providerId || record.providerId === providerId).filter((record) => !accountId || record.accountId === accountId).filter((record) => !sessionKey || record.sessionKey === sessionKey).slice(0, boundedLimit(query.limit)).map((record) => ({ ...record }));
34
+ }
35
+ clear() {
36
+ this.records.length = 0;
37
+ this.sequence = 0;
38
+ }
39
+ /**
40
+ * Backfill a field on an already-recorded entry. Used to annotate a record
41
+ * AFTER the upstream body streams — e.g. a `200` whose SSE body carries a
42
+ * `response.failed` overload event is only detectable mid-relay, long after
43
+ * `record()` stamped the 200 status. `patch` is intentionally narrow: only
44
+ * post-hoc-observable fields belong here, never the routing-decision fields.
45
+ * No-op when the id has already aged out of the bounded ring.
46
+ */
47
+ amend(id, patch) {
48
+ const record = this.records.find((r) => r.id === id);
49
+ if (record) Object.assign(record, patch);
50
+ }
51
+ };
52
+ var sharedAccountRouteActivity = new AccountRouteActivityStore();
53
+ function getSharedAccountRouteActivity() {
54
+ return sharedAccountRouteActivity;
55
+ }
56
+
57
+ export {
58
+ ACCOUNT_ROUTE_ACTIVITY_LIMIT,
59
+ AccountRouteActivityStore,
60
+ getSharedAccountRouteActivity
61
+ };
@@ -1,4 +1,5 @@
1
1
  "use strict";Object.defineProperty(exports, "__esModule", {value: true}); 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; }// src/provider-proxy/matchText.ts
2
+ var _crypto = require('crypto');
2
3
  var MATCH_TEXT_PER_MESSAGE_CAP = 8192;
3
4
  var MATCH_TEXT_RECENT_MESSAGES = 6;
4
5
  function flattenMatchText(value) {
@@ -55,39 +56,42 @@ var SESSION_ID_CAP = 1024;
55
56
  function deriveGatewaySessionKey(body, headers = {}, options = {}) {
56
57
  const sessionHeader = firstHeaderValue(headers, ["session-id", "session_id", "x-session-id"]);
57
58
  if (sessionHeader) {
58
- return { key: fnv1a(sessionHeader), source: "session-header" };
59
+ return { key: stableSessionDigest(sessionHeader), source: "session-header" };
59
60
  }
60
61
  const threadHeader = firstHeaderValue(headers, ["thread-id", "thread_id", "x-thread-id"]);
61
62
  if (threadHeader) {
62
- return { key: fnv1a(threadHeader), source: "thread-header" };
63
+ return { key: stableSessionDigest(threadHeader), source: "thread-header" };
63
64
  }
64
65
  const bodySessionId = scalarSessionValue(body.session_id);
65
66
  if (bodySessionId) {
66
- return { key: fnv1a(bodySessionId), source: "body-session-id" };
67
+ return { key: stableSessionDigest(bodySessionId), source: "body-session-id" };
67
68
  }
68
69
  const bodyThreadId = scalarSessionValue(_nullishCoalesce(body.thread_id, () => ( body.threadId)));
69
70
  if (bodyThreadId) {
70
- return { key: fnv1a(bodyThreadId), source: "body-thread-id" };
71
+ return { key: stableSessionDigest(bodyThreadId), source: "body-thread-id" };
71
72
  }
72
73
  const conversationId = scalarSessionValue(body.conversation_id);
73
74
  if (conversationId) {
74
- return { key: fnv1a(conversationId), source: "body-session-id" };
75
+ return { key: stableSessionDigest(conversationId), source: "body-session-id" };
75
76
  }
76
77
  const promptCacheKey = scalarSessionValue(body.prompt_cache_key);
77
78
  if (promptCacheKey) {
78
- return { key: fnv1a(promptCacheKey), source: "prompt-cache-key" };
79
+ return { key: stableSessionDigest(promptCacheKey), source: "prompt-cache-key" };
79
80
  }
80
81
  const fingerprint = deriveResponsesContentFingerprint(body);
81
82
  if (fingerprint) {
82
- return { key: fnv1a(fingerprint), source: "content-fingerprint" };
83
+ return { key: stableSessionDigest(fingerprint), source: "content-fingerprint" };
83
84
  }
84
85
  const endpoint = _optionalChain([options, 'access', _ => _.endpoint, 'optionalAccess', _2 => _2.trim, 'call', _3 => _3()]) || "responses";
85
86
  const fallback = _optionalChain([options, 'access', _4 => _4.fallbackKey, 'optionalAccess', _5 => _5.trim, 'call', _6 => _6()]) || "anonymous";
86
87
  return {
87
- key: fnv1a(`${endpoint}\0${fallback}`),
88
+ key: stableSessionDigest(`${endpoint}\0${fallback}`),
88
89
  source: "api-key-fallback"
89
90
  };
90
91
  }
92
+ function stableSessionDigest(value) {
93
+ return _crypto.createHash.call(void 0, "sha256").update(value, "utf8").digest("hex").slice(0, 32);
94
+ }
91
95
  function firstHeaderValue(headers, names) {
92
96
  const byLower = /* @__PURE__ */ new Map();
93
97
  for (const [name, value] of Object.entries(headers)) {
@@ -1,15 +1,15 @@
1
+ import {
2
+ AnthropicTransformer
3
+ } from "./chunk-PEGTIPB3.js";
1
4
  import {
2
5
  GeminiTransformer
3
6
  } from "./chunk-LVUCAWMK.js";
4
7
  import {
5
8
  OpenAIResponseTransformer
6
- } from "./chunk-OEWZUX4G.js";
9
+ } from "./chunk-32O35CIF.js";
7
10
  import {
8
11
  OpenAITransformer
9
12
  } from "./chunk-LB6EBS6Y.js";
10
- import {
11
- AnthropicTransformer
12
- } from "./chunk-6CL5HTPQ.js";
13
13
  import {
14
14
  GeminiCodeAssistTransformer
15
15
  } from "./chunk-N5T4M4GU.js";
@@ -3,6 +3,7 @@ var OVERLOAD_TTL_MS = 10 * 6e4;
3
3
  var OVERLOAD_ENABLED_DEFAULT = true;
4
4
  var AUTH_ERROR_TTL_MS = 30 * 6e4;
5
5
  var SERVER_ERROR_TTL_MS = 5 * 6e4;
6
+ var MAX_QUOTA_COOLDOWN_MS = 7 * 24 * 60 * 6e4;
6
7
  var BAN_BODY_MARKERS = [
7
8
  "this organization has been disabled",
8
9
  "oauth authentication is currently not allowed"
@@ -38,7 +39,7 @@ function isBanBody(bodyText) {
38
39
  return BAN_BODY_MARKERS.some((marker) => lower.includes(marker));
39
40
  }
40
41
  function isRecordEmpty(record) {
41
- return record.rateLimitEndAt === void 0 && record.overloadUntil === void 0 && record.tempUnavailableUntil === void 0 && !record.blocked;
42
+ return record.rateLimitEndAt === void 0 && record.overloadUntil === void 0 && record.tempUnavailableUntil === void 0 && record.quotaExhaustedUntil === void 0 && !record.blocked;
42
43
  }
43
44
  var KEY_SEP = "\0";
44
45
  var SubscriptionAccountHealth = class {
@@ -159,12 +160,47 @@ var SubscriptionAccountHealth = class {
159
160
  this.emitAnomaly(anomaly);
160
161
  }
161
162
  }
163
+ /**
164
+ * Mark an account quota/usage-exhausted until `untilEpochMs` (the Codex weekly
165
+ * usage-limit wall). Unlike the status-driven timers set by
166
+ * {@link recordUpstreamOutcome}, this mark is NOT cleared by a 2xx: in-flight
167
+ * sessions on the same account keep succeeding after the window is exhausted,
168
+ * so a traffic-driven clear would re-strand every NEW session onto this
169
+ * account. It excludes the account from NEW-session selection until the
170
+ * deadline elapses (existing sessions are unaffected — they already hold their
171
+ * token). Self-heals lazily on read and via {@link sweepRecoveries}.
172
+ * `untilEpochMs` is clamped to {@link MAX_QUOTA_COOLDOWN_MS}; an already-elapsed
173
+ * deadline is a no-op. Emits a `quota_exhausted` anomaly on the healthy→
174
+ * unhealthy edge.
175
+ */
176
+ markQuotaExhausted(providerId, accountId, untilEpochMs, now = this.now()) {
177
+ if (!Number.isFinite(untilEpochMs)) return;
178
+ const clamped = Math.min(untilEpochMs, now + MAX_QUOTA_COOLDOWN_MS);
179
+ if (clamped <= now) return;
180
+ const key = this.key(providerId, accountId);
181
+ const preExisting = this.records.get(key);
182
+ const record = preExisting ?? {};
183
+ const wasUnhealthyBefore = preExisting ? this.isUnhealthyAt(preExisting, now) : false;
184
+ record.quotaExhaustedUntil = clamped;
185
+ this.records.set(key, record);
186
+ if (!wasUnhealthyBefore) {
187
+ const anomaly = {
188
+ providerId,
189
+ accountId,
190
+ at: now,
191
+ state: "quota_exhausted"
192
+ };
193
+ this.recordDiagnostic({ kind: "health-anomaly", ...anomaly });
194
+ this.emitAnomaly(anomaly);
195
+ }
196
+ }
162
197
  /** Whether a record is unhealthy at `now`: blocked, or any timer still future. */
163
198
  isUnhealthyAt(record, now) {
164
199
  if (record.blocked) return true;
165
200
  if (record.rateLimitEndAt !== void 0 && now < record.rateLimitEndAt) return true;
166
201
  if (record.overloadUntil !== void 0 && now < record.overloadUntil) return true;
167
202
  if (record.tempUnavailableUntil !== void 0 && now < record.tempUnavailableUntil) return true;
203
+ if (record.quotaExhaustedUntil !== void 0 && now < record.quotaExhaustedUntil) return true;
168
204
  return false;
169
205
  }
170
206
  /**
@@ -201,7 +237,7 @@ var SubscriptionAccountHealth = class {
201
237
  const recovered = [];
202
238
  for (const [key, record] of this.records) {
203
239
  if (record.blocked) continue;
204
- const hadTimer = record.rateLimitEndAt !== void 0 || record.overloadUntil !== void 0 || record.tempUnavailableUntil !== void 0;
240
+ const hadTimer = record.rateLimitEndAt !== void 0 || record.overloadUntil !== void 0 || record.tempUnavailableUntil !== void 0 || record.quotaExhaustedUntil !== void 0;
205
241
  const active = this.clearExpired(record, now);
206
242
  if (hadTimer && !active && isRecordEmpty(record)) {
207
243
  const [pid, aid] = this.parseKey(key);
@@ -225,6 +261,9 @@ var SubscriptionAccountHealth = class {
225
261
  const record = this.records.get(this.key(providerId, accountId));
226
262
  if (!record) return { state: "healthy" };
227
263
  if (record.blocked) return { state: "blocked" };
264
+ if (record.quotaExhaustedUntil !== void 0 && now < record.quotaExhaustedUntil) {
265
+ return { state: "quota_exhausted", cooldownUntil: record.quotaExhaustedUntil };
266
+ }
228
267
  if (record.rateLimitEndAt !== void 0 && now < record.rateLimitEndAt) {
229
268
  return { state: "rate_limited", cooldownUntil: record.rateLimitEndAt };
230
269
  }
@@ -311,6 +350,10 @@ var SubscriptionAccountHealth = class {
311
350
  if (now >= record.tempUnavailableUntil) delete record.tempUnavailableUntil;
312
351
  else active = true;
313
352
  }
353
+ if (record.quotaExhaustedUntil !== void 0) {
354
+ if (now >= record.quotaExhaustedUntil) delete record.quotaExhaustedUntil;
355
+ else active = true;
356
+ }
314
357
  return active;
315
358
  }
316
359
  key(providerId, accountId) {
@@ -338,6 +381,7 @@ export {
338
381
  OVERLOAD_ENABLED_DEFAULT,
339
382
  AUTH_ERROR_TTL_MS,
340
383
  SERVER_ERROR_TTL_MS,
384
+ MAX_QUOTA_COOLDOWN_MS,
341
385
  ACCOUNT_HEALTH_DIAGNOSTIC_LIMIT,
342
386
  resolveResetSeconds,
343
387
  SubscriptionAccountHealth,
@@ -0,0 +1,61 @@
1
+ "use strict";Object.defineProperty(exports, "__esModule", {value: true}); 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;// src/pipeline/AccountRouteActivity.ts
2
+ var ACCOUNT_ROUTE_ACTIVITY_LIMIT = 300;
3
+ function boundedLimit(value) {
4
+ if (!Number.isFinite(value)) return 100;
5
+ return Math.max(1, Math.min(ACCOUNT_ROUTE_ACTIVITY_LIMIT, Math.trunc(value)));
6
+ }
7
+ var AccountRouteActivityStore = (_class = class {constructor() { _class.prototype.__init.call(this);_class.prototype.__init2.call(this); }
8
+ __init() {this.records = []}
9
+ __init2() {this.sequence = 0}
10
+ record(input) {
11
+ const ts = _nullishCoalesce(input.ts, () => ( Date.now()));
12
+ const sessionKey = _optionalChain([input, 'access', _ => _.sessionKey, 'optionalAccess', _2 => _2.trim, 'call', _3 => _3()]) || void 0;
13
+ const previous = sessionKey ? this.records.find((record2) => record2.providerId === input.providerId && record2.endpoint === input.endpoint && record2.sessionKey === sessionKey) : void 0;
14
+ const affinity = !sessionKey ? "untracked" : !previous ? "new" : previous.accountId === input.accountId ? "sticky" : "switched";
15
+ const record = {
16
+ ...input,
17
+ id: `${ts.toString(36)}-${(this.sequence++).toString(36)}`,
18
+ ts,
19
+ sessionKey,
20
+ affinity,
21
+ ...affinity === "switched" && previous ? { previousAccountId: previous.accountId } : {}
22
+ };
23
+ this.records.unshift(record);
24
+ if (this.records.length > ACCOUNT_ROUTE_ACTIVITY_LIMIT) {
25
+ this.records.length = ACCOUNT_ROUTE_ACTIVITY_LIMIT;
26
+ }
27
+ return { ...record };
28
+ }
29
+ list(query = {}) {
30
+ const providerId = _optionalChain([query, 'access', _4 => _4.providerId, 'optionalAccess', _5 => _5.trim, 'call', _6 => _6()]);
31
+ const accountId = _optionalChain([query, 'access', _7 => _7.accountId, 'optionalAccess', _8 => _8.trim, 'call', _9 => _9()]);
32
+ const sessionKey = _optionalChain([query, 'access', _10 => _10.sessionKey, 'optionalAccess', _11 => _11.trim, 'call', _12 => _12()]);
33
+ return this.records.filter((record) => !providerId || record.providerId === providerId).filter((record) => !accountId || record.accountId === accountId).filter((record) => !sessionKey || record.sessionKey === sessionKey).slice(0, boundedLimit(query.limit)).map((record) => ({ ...record }));
34
+ }
35
+ clear() {
36
+ this.records.length = 0;
37
+ this.sequence = 0;
38
+ }
39
+ /**
40
+ * Backfill a field on an already-recorded entry. Used to annotate a record
41
+ * AFTER the upstream body streams — e.g. a `200` whose SSE body carries a
42
+ * `response.failed` overload event is only detectable mid-relay, long after
43
+ * `record()` stamped the 200 status. `patch` is intentionally narrow: only
44
+ * post-hoc-observable fields belong here, never the routing-decision fields.
45
+ * No-op when the id has already aged out of the bounded ring.
46
+ */
47
+ amend(id, patch) {
48
+ const record = this.records.find((r) => r.id === id);
49
+ if (record) Object.assign(record, patch);
50
+ }
51
+ }, _class);
52
+ var sharedAccountRouteActivity = new AccountRouteActivityStore();
53
+ function getSharedAccountRouteActivity() {
54
+ return sharedAccountRouteActivity;
55
+ }
56
+
57
+
58
+
59
+
60
+
61
+ exports.ACCOUNT_ROUTE_ACTIVITY_LIMIT = ACCOUNT_ROUTE_ACTIVITY_LIMIT; exports.AccountRouteActivityStore = AccountRouteActivityStore; exports.getSharedAccountRouteActivity = getSharedAccountRouteActivity;
@@ -78,7 +78,9 @@ var UsageRecorder = class {
78
78
  costSavedByCacheUsd,
79
79
  rawUsage: input.rawUsage != null ? safeStringify(input.rawUsage) : null,
80
80
  runId: _nullishCoalesce(input.runId, () => ( null)),
81
- eventId: _nullishCoalesce(input.eventId, () => ( null))
81
+ eventId: _nullishCoalesce(input.eventId, () => ( null)),
82
+ ...input.cacheKeySource !== void 0 ? { cacheKeySource: input.cacheKeySource } : {},
83
+ ...input.cacheKeyInjected !== void 0 ? { cacheKeyInjected: input.cacheKeyInjected } : {}
82
84
  };
83
85
  try {
84
86
  return await this.store.insert(row);
@@ -0,0 +1,79 @@
1
+ "use strict";Object.defineProperty(exports, "__esModule", {value: true}); 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;// src/pipeline/ServerOverloadCounter.ts
2
+ var OVERLOAD_RECENT_LIMIT = 64;
3
+ var OVERLOAD_ENTRY_TTL_MS = 24 * 60 * 6e4;
4
+ function entryKey(providerId, accountId, endpoint) {
5
+ return `${providerId}\0${accountId}\0${endpoint}`;
6
+ }
7
+ var ServerOverloadCounterStore = (_class = class {constructor() { _class.prototype.__init.call(this); }
8
+ __init() {this.entries = /* @__PURE__ */ new Map()}
9
+ /**
10
+ * Record one overload event. Creates the entry on first sight, then bumps
11
+ * `count`, `lastTs`, and prepends the event to the bounded `recent` ring.
12
+ */
13
+ recordOverload(input, now = Date.now()) {
14
+ const key = entryKey(input.providerId, input.accountId, input.endpoint);
15
+ const existing = this.entries.get(key);
16
+ if (existing) {
17
+ existing.count += 1;
18
+ existing.lastTs = now;
19
+ existing.recent.unshift(now);
20
+ if (existing.recent.length > OVERLOAD_RECENT_LIMIT) {
21
+ existing.recent.length = OVERLOAD_RECENT_LIMIT;
22
+ }
23
+ return { ...existing, recent: [...existing.recent] };
24
+ }
25
+ const entry = {
26
+ providerId: input.providerId,
27
+ accountId: input.accountId,
28
+ endpoint: input.endpoint,
29
+ count: 1,
30
+ firstTs: now,
31
+ lastTs: now,
32
+ recent: [now]
33
+ };
34
+ this.entries.set(key, entry);
35
+ return { ...entry, recent: [...entry.recent] };
36
+ }
37
+ /**
38
+ * Snapshot all (optionally filtered) entries, pruning stale ones first. Returns
39
+ * copies — callers (admin API → JSON) never see the live mutable entries.
40
+ */
41
+ list(query = {}, now = Date.now()) {
42
+ const providerId = _optionalChain([query, 'access', _ => _.providerId, 'optionalAccess', _2 => _2.trim, 'call', _3 => _3()]);
43
+ const accountId = _optionalChain([query, 'access', _4 => _4.accountId, 'optionalAccess', _5 => _5.trim, 'call', _6 => _6()]);
44
+ const out = [];
45
+ for (const [key, entry] of this.entries) {
46
+ if (now - entry.lastTs > OVERLOAD_ENTRY_TTL_MS) {
47
+ this.entries.delete(key);
48
+ continue;
49
+ }
50
+ if (providerId && entry.providerId !== providerId) continue;
51
+ if (accountId && entry.accountId !== accountId) continue;
52
+ out.push({ ...entry, recent: [...entry.recent] });
53
+ }
54
+ return out;
55
+ }
56
+ clear() {
57
+ this.entries.clear();
58
+ }
59
+ }, _class);
60
+ var sharedStore = null;
61
+ function getSharedOverloadCounter() {
62
+ if (!sharedStore) sharedStore = new ServerOverloadCounterStore();
63
+ return sharedStore;
64
+ }
65
+ function setSharedOverloadCounter(instance) {
66
+ sharedStore = instance;
67
+ }
68
+ function __resetSharedOverloadCounterForTests() {
69
+ sharedStore = null;
70
+ }
71
+
72
+
73
+
74
+
75
+
76
+
77
+
78
+
79
+ exports.OVERLOAD_RECENT_LIMIT = OVERLOAD_RECENT_LIMIT; exports.OVERLOAD_ENTRY_TTL_MS = OVERLOAD_ENTRY_TTL_MS; exports.ServerOverloadCounterStore = ServerOverloadCounterStore; exports.getSharedOverloadCounter = getSharedOverloadCounter; exports.setSharedOverloadCounter = setSharedOverloadCounter; exports.__resetSharedOverloadCounterForTests = __resetSharedOverloadCounterForTests;
@@ -1,4 +1,9 @@
1
- "use strict";Object.defineProperty(exports, "__esModule", {value: true}); 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;// src/transformer/transformers/OpenAIResponseTransformer.ts
1
+ "use strict";Object.defineProperty(exports, "__esModule", {value: true}); 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;
2
+
3
+
4
+ var _chunk5RSZYQJHcjs = require('./chunk-5RSZYQJH.cjs');
5
+
6
+ // src/transformer/transformers/OpenAIResponseTransformer.ts
2
7
  var OpenAIResponseTransformer = (_class = class {constructor() { _class.prototype.__init.call(this);_class.prototype.__init2.call(this); }
3
8
  static __initStatic() {this.TransformerName = "openai-response"}
4
9
  __init() {this.name = "openai-response"}
@@ -433,11 +438,7 @@ function convertResponseApiJsonToOpenAI(data) {
433
438
  finish_reason: toolCalls.length > 0 ? "tool_calls" : "stop"
434
439
  }
435
440
  ],
436
- usage: usage ? {
437
- prompt_tokens: usage.input_tokens || 0,
438
- completion_tokens: usage.output_tokens || 0,
439
- total_tokens: (usage.input_tokens || 0) + (usage.output_tokens || 0)
440
- } : void 0
441
+ usage: _chunk5RSZYQJHcjs.responsesUsageToChatUsage.call(void 0, usage)
441
442
  };
442
443
  }
443
444
  function convertOpenAIJsonToResponseApi(data, codexTools) {
@@ -475,11 +476,7 @@ function convertOpenAIJsonToResponseApi(data, codexTools) {
475
476
  status: "completed",
476
477
  model: data.model || "unknown",
477
478
  output,
478
- usage: usage ? {
479
- input_tokens: usage.prompt_tokens || 0,
480
- output_tokens: usage.completion_tokens || 0,
481
- total_tokens: usage.total_tokens || (usage.prompt_tokens || 0) + (usage.completion_tokens || 0)
482
- } : void 0
479
+ usage: _chunk5RSZYQJHcjs.chatUsageToResponsesUsage.call(void 0, usage)
483
480
  };
484
481
  }
485
482
  function convertResponseApiStreamToOpenAI(responseApiStream) {
@@ -589,11 +586,7 @@ function convertResponseApiStreamToOpenAI(responseApiStream) {
589
586
  case "response.completed": {
590
587
  const resp = event.response;
591
588
  const respUsage = _optionalChain([resp, 'optionalAccess', _32 => _32.usage]);
592
- const usage = respUsage ? {
593
- prompt_tokens: respUsage.input_tokens || 0,
594
- completion_tokens: respUsage.output_tokens || 0,
595
- total_tokens: (respUsage.input_tokens || 0) + (respUsage.output_tokens || 0)
596
- } : void 0;
589
+ const usage = _chunk5RSZYQJHcjs.responsesUsageToChatUsage.call(void 0, respUsage);
597
590
  emitChunk([{ index: 0, delta: {}, finish_reason: hasToolCalls ? "tool_calls" : "stop" }], usage);
598
591
  safeEnqueue("data: [DONE]\n\n");
599
592
  break;
@@ -801,11 +794,7 @@ function convertOpenAIStreamToResponseApi(openaiStream, codexTools) {
801
794
  status: "completed",
802
795
  model,
803
796
  output,
804
- usage: chunk.usage ? {
805
- input_tokens: chunk.usage.prompt_tokens || 0,
806
- output_tokens: chunk.usage.completion_tokens || 0,
807
- total_tokens: chunk.usage.total_tokens || 0
808
- } : void 0
797
+ usage: _chunk5RSZYQJHcjs.chatUsageToResponsesUsage.call(void 0, chunk.usage)
809
798
  }
810
799
  });
811
800
  }