@omnicross/core 0.1.6 → 0.1.8

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 (137) hide show
  1. package/dist/ApiConverter.cjs +2 -2
  2. package/dist/ApiConverter.js +1 -1
  3. package/dist/{ProviderProxy-C-xqrkKi.d.ts → ProviderProxy--ROec6VI.d.ts} +22 -3
  4. package/dist/{ProviderProxy-CnMQYN59.d.cts → ProviderProxy-QdwNV6l1.d.cts} +22 -3
  5. package/dist/auth/GeminiCodeAssistProjectResolver.cjs +4 -3
  6. package/dist/auth/GeminiCodeAssistProjectResolver.js +3 -2
  7. package/dist/{chunk-3Z5BQZFM.cjs → chunk-235MXAGX.cjs} +3 -1
  8. package/dist/{chunk-SQYVORNP.cjs → chunk-26K6T2YS.cjs} +1520 -523
  9. package/dist/{chunk-DLXZEZWO.cjs → chunk-2E42SAW3.cjs} +42 -4
  10. package/dist/{chunk-7AK7B36B.cjs → chunk-2Z4XM3H5.cjs} +6 -6
  11. package/dist/{chunk-OEWZUX4G.js → chunk-32O35CIF.js} +9 -20
  12. package/dist/chunk-3SCOLIPT.cjs +63 -0
  13. package/dist/{chunk-SYQF7OIR.js → chunk-3WD4HTR2.js} +2 -0
  14. package/dist/{chunk-AT7B7SOZ.js → chunk-5NJLQ6T6.js} +21 -10
  15. package/dist/chunk-5RSZYQJH.cjs +62 -0
  16. package/dist/{chunk-IFXJ2BG7.js → chunk-7C7DET6S.js} +51 -6
  17. package/dist/{chunk-SNYBEXLB.cjs → chunk-EPN67EGP.cjs} +6 -1
  18. package/dist/chunk-FU7EAR73.js +62 -0
  19. package/dist/{chunk-UX7VWA46.js → chunk-FXR6N3SR.js} +39 -1
  20. package/dist/{chunk-WYTEQ4Q5.cjs → chunk-GDIXXKF2.cjs} +21 -10
  21. package/dist/{chunk-WB6PH56J.js → chunk-GFIZ6LQI.js} +12 -8
  22. package/dist/chunk-GL6XM527.js +61 -0
  23. package/dist/{chunk-EJLH6NFT.cjs → chunk-J3QQ6JS5.cjs} +12 -8
  24. package/dist/{chunk-VRFBB5DB.js → chunk-MYYR3HZL.js} +4 -4
  25. package/dist/{chunk-YJVHCHQX.js → chunk-N7OOJI5V.js} +46 -2
  26. package/dist/chunk-NKVZ6Z3Y.cjs +61 -0
  27. package/dist/chunk-OTZC4TNH.cjs +79 -0
  28. package/dist/{chunk-6VUQPOV3.cjs → chunk-OVQBNVSV.cjs} +10 -21
  29. package/dist/{chunk-4VLRHHFE.cjs → chunk-OXHNSZ53.cjs} +9 -11
  30. package/dist/{chunk-6CL5HTPQ.js → chunk-PEGTIPB3.js} +8 -10
  31. package/dist/chunk-PO3XB56Z.js +79 -0
  32. package/dist/{chunk-UDCC7EMR.js → chunk-QYC54PMG.js} +1242 -245
  33. package/dist/{chunk-SIZQQD6T.js → chunk-RJ5ZGNI3.js} +42 -5
  34. package/dist/{chunk-KCVJWJST.cjs → chunk-RJUONLUQ.cjs} +47 -10
  35. package/dist/{chunk-BPKCU575.js → chunk-UAPBLNN2.js} +6 -1
  36. package/dist/{chunk-UNWKG6EI.cjs → chunk-XPIOJQS2.cjs} +51 -6
  37. package/dist/chunk-XXFYLL7R.js +63 -0
  38. package/dist/{chunk-YK57NMIF.cjs → chunk-YWL7YZWS.cjs} +47 -3
  39. package/dist/completion/ApiKeyPoolService.cjs +32 -1
  40. package/dist/completion/ApiKeyPoolService.d.cts +17 -1
  41. package/dist/completion/ApiKeyPoolService.d.ts +17 -1
  42. package/dist/completion/ApiKeyPoolService.js +31 -0
  43. package/dist/completion/CompletionService.cjs +23 -19
  44. package/dist/completion/CompletionService.d.cts +1 -0
  45. package/dist/completion/CompletionService.d.ts +1 -0
  46. package/dist/completion/CompletionService.js +22 -18
  47. package/dist/completion.cjs +23 -19
  48. package/dist/completion.d.cts +1 -0
  49. package/dist/completion.d.ts +1 -0
  50. package/dist/completion.js +22 -18
  51. package/dist/index.cjs +81 -21
  52. package/dist/index.d.cts +5 -5
  53. package/dist/index.d.ts +5 -5
  54. package/dist/index.js +82 -22
  55. package/dist/outbound-api/auditCapture.cjs +2 -2
  56. package/dist/outbound-api/auditCapture.d.cts +3 -4
  57. package/dist/outbound-api/auditCapture.d.ts +3 -4
  58. package/dist/outbound-api/auditCapture.js +1 -1
  59. package/dist/outbound-api/routeResolver.d.cts +4 -3
  60. package/dist/outbound-api/routeResolver.d.ts +4 -3
  61. package/dist/outbound-api/subscriptionRegistryPort.d.cts +1 -0
  62. package/dist/outbound-api/subscriptionRegistryPort.d.ts +1 -0
  63. package/dist/outbound-api/types.d.cts +3 -2
  64. package/dist/outbound-api/types.d.ts +3 -2
  65. package/dist/outbound-api.cjs +23 -19
  66. package/dist/outbound-api.d.cts +8 -6
  67. package/dist/outbound-api.d.ts +8 -6
  68. package/dist/outbound-api.js +22 -18
  69. package/dist/pipeline/AccountAllowanceScheduling.d.cts +3 -2
  70. package/dist/pipeline/AccountAllowanceScheduling.d.ts +3 -2
  71. package/dist/pipeline/AccountRouteActivity.cjs +10 -0
  72. package/dist/pipeline/AccountRouteActivity.d.cts +61 -0
  73. package/dist/pipeline/AccountRouteActivity.d.ts +61 -0
  74. package/dist/pipeline/AccountRouteActivity.js +10 -0
  75. package/dist/pipeline/ServerOverloadCounter.cjs +16 -0
  76. package/dist/pipeline/ServerOverloadCounter.d.cts +77 -0
  77. package/dist/pipeline/ServerOverloadCounter.d.ts +77 -0
  78. package/dist/pipeline/ServerOverloadCounter.js +16 -0
  79. package/dist/pipeline/SubscriptionAccountHealth.cjs +4 -2
  80. package/dist/pipeline/SubscriptionAccountHealth.d.cts +32 -3
  81. package/dist/pipeline/SubscriptionAccountHealth.d.ts +32 -3
  82. package/dist/pipeline/SubscriptionAccountHealth.js +3 -1
  83. package/dist/pipeline/upstreamFetch.cjs +4 -3
  84. package/dist/pipeline/upstreamFetch.d.cts +35 -6
  85. package/dist/pipeline/upstreamFetch.d.ts +35 -6
  86. package/dist/pipeline/upstreamFetch.js +3 -2
  87. package/dist/pipeline/upstreamTrace.cjs +4 -2
  88. package/dist/pipeline/upstreamTrace.d.cts +22 -8
  89. package/dist/pipeline/upstreamTrace.d.ts +22 -8
  90. package/dist/pipeline/upstreamTrace.js +3 -1
  91. package/dist/ports.d.cts +2 -2
  92. package/dist/ports.d.ts +2 -2
  93. package/dist/provider-proxy/ProviderProxy.cjs +23 -19
  94. package/dist/provider-proxy/ProviderProxy.d.cts +2 -1
  95. package/dist/provider-proxy/ProviderProxy.d.ts +2 -1
  96. package/dist/provider-proxy/ProviderProxy.js +22 -18
  97. package/dist/provider-proxy/identity/codexCliHeaders.cjs +10 -0
  98. package/dist/provider-proxy/identity/codexCliHeaders.d.cts +45 -0
  99. package/dist/provider-proxy/identity/codexCliHeaders.d.ts +45 -0
  100. package/dist/provider-proxy/identity/codexCliHeaders.js +10 -0
  101. package/dist/provider-proxy/ingress/providerProxyShared.cjs +23 -19
  102. package/dist/provider-proxy/ingress/providerProxyShared.d.cts +11 -1
  103. package/dist/provider-proxy/ingress/providerProxyShared.d.ts +11 -1
  104. package/dist/provider-proxy/ingress/providerProxyShared.js +22 -18
  105. package/dist/provider-proxy/matchText.cjs +2 -2
  106. package/dist/provider-proxy/matchText.d.cts +1 -3
  107. package/dist/provider-proxy/matchText.d.ts +1 -3
  108. package/dist/provider-proxy/matchText.js +1 -1
  109. package/dist/provider-proxy/types.d.cts +20 -1
  110. package/dist/provider-proxy/types.d.ts +20 -1
  111. package/dist/provider-proxy.cjs +79 -19
  112. package/dist/provider-proxy.d.cts +255 -8
  113. package/dist/provider-proxy.d.ts +255 -8
  114. package/dist/provider-proxy.js +80 -20
  115. package/dist/{routeResolver-CHTv_Bs5.d.ts → routeResolver-C0mkkZaM.d.ts} +1 -1
  116. package/dist/{routeResolver-kepxnfcC.d.cts → routeResolver-CVFE8KKe.d.cts} +1 -1
  117. package/dist/transformer/transformers/AnthropicTransformer.cjs +3 -2
  118. package/dist/transformer/transformers/AnthropicTransformer.js +2 -1
  119. package/dist/transformer/transformers/OpenAIResponseTransformer.cjs +3 -2
  120. package/dist/transformer/transformers/OpenAIResponseTransformer.js +2 -1
  121. package/dist/transformer/transformers.cjs +7 -6
  122. package/dist/transformer/transformers.js +6 -5
  123. package/dist/transformer.cjs +9 -8
  124. package/dist/transformer.js +8 -7
  125. package/dist/{types-hsoKrVQS.d.ts → types-BB8pxk_3.d.ts} +40 -1
  126. package/dist/{types-H3wGZSOo.d.cts → types-C2MwkLah.d.cts} +40 -1
  127. package/dist/usage/pricing-engine.cjs +2 -2
  128. package/dist/usage/pricing-engine.d.cts +20 -0
  129. package/dist/usage/pricing-engine.d.ts +20 -0
  130. package/dist/usage/pricing-engine.js +1 -1
  131. package/dist/usage/usage-recorder.cjs +2 -2
  132. package/dist/usage/usage-recorder.d.cts +11 -1
  133. package/dist/usage/usage-recorder.d.ts +11 -1
  134. package/dist/usage/usage-recorder.js +1 -1
  135. package/dist/usage.cjs +3 -3
  136. package/dist/usage.js +2 -2
  137. package/package.json +1 -1
@@ -4,7 +4,7 @@
4
4
 
5
5
  var _pricingtypes = require('@omnicross/contracts/pricing-types');
6
6
  var PricingEngine = (_class = class {
7
- constructor(store, logger, options = {}) {;_class.prototype.__init.call(this);_class.prototype.__init2.call(this);_class.prototype.__init3.call(this);_class.prototype.__init4.call(this);
7
+ constructor(store, logger, options = {}) {;_class.prototype.__init.call(this);_class.prototype.__init2.call(this);_class.prototype.__init3.call(this);_class.prototype.__init4.call(this);_class.prototype.__init5.call(this);
8
8
  this.store = store;
9
9
  this.logger = logger;
10
10
  this.options = options;
@@ -21,9 +21,18 @@ var PricingEngine = (_class = class {
21
21
  * non-wildcard entry per model wins.
22
22
  */
23
23
  __init2() {this.cacheByModel = /* @__PURE__ */ new Map()}
24
- __init3() {this.cacheLoaded = false}
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
+ __init3() {this.fuzzyEntries = []}
33
+ __init4() {this.cacheLoaded = false}
25
34
  /** Coalesce manual and background refreshes to prevent a catalog stampede. */
26
- __init4() {this.refreshInFlight = null}
35
+ __init5() {this.refreshInFlight = null}
27
36
  // ===== Cache management =====
28
37
  /** Lazy-load and cache the full pricing table. */
29
38
  async ensureCache() {
@@ -31,9 +40,11 @@ var PricingEngine = (_class = 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 = 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 _nullishCoalesce(_nullishCoalesce(_nullishCoalesce(this.cache.get(keyOf(providerId, modelId)), () => ( this.cache.get(keyOf("*", modelId)))), () => ( this.cacheByModel.get(modelId))), () => ( null));
74
+ const exact = _nullishCoalesce(_nullishCoalesce(_nullishCoalesce(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 = class {
187
224
  }
188
225
  }, _class);
189
226
  var keyOf = (providerId, modelId) => `${providerId}::${modelId}`;
227
+ var normalizeModelId = (modelId) => (_nullishCoalesce(modelId, () => ( ""))).toLowerCase().replace(/[^a-z0-9]/g, "");
190
228
  var PROVIDER_ALIASES = {
191
229
  vertex_ai: "gemini",
192
230
  google: "gemini",
@@ -1,15 +1,15 @@
1
1
  "use strict";Object.defineProperty(exports, "__esModule", {value: true});
2
2
 
3
- var _chunkV4TXMEJScjs = require('./chunk-V4TXMEJS.cjs');
3
+ var _chunkOXHNSZ53cjs = require('./chunk-OXHNSZ53.cjs');
4
4
 
5
5
 
6
- var _chunk6VUQPOV3cjs = require('./chunk-6VUQPOV3.cjs');
6
+ var _chunkV4TXMEJScjs = require('./chunk-V4TXMEJS.cjs');
7
7
 
8
8
 
9
- var _chunkOF3BECU2cjs = require('./chunk-OF3BECU2.cjs');
9
+ var _chunkOVQBNVSVcjs = require('./chunk-OVQBNVSV.cjs');
10
10
 
11
11
 
12
- var _chunk4VLRHHFEcjs = require('./chunk-4VLRHHFE.cjs');
12
+ var _chunkOF3BECU2cjs = require('./chunk-OF3BECU2.cjs');
13
13
 
14
14
 
15
15
  var _chunkOKMJLEXXcjs = require('./chunk-OKMJLEXX.cjs');
@@ -19,8 +19,8 @@ var BuiltinTransformers = {
19
19
  OpenAITransformer: _chunkOF3BECU2cjs.OpenAITransformer,
20
20
  GeminiTransformer: _chunkV4TXMEJScjs.GeminiTransformer,
21
21
  GeminiCodeAssistTransformer: _chunkOKMJLEXXcjs.GeminiCodeAssistTransformer,
22
- AnthropicTransformer: _chunk4VLRHHFEcjs.AnthropicTransformer,
23
- OpenAIResponseTransformer: _chunk6VUQPOV3cjs.OpenAIResponseTransformer
22
+ AnthropicTransformer: _chunkOXHNSZ53cjs.AnthropicTransformer,
23
+ OpenAIResponseTransformer: _chunkOVQBNVSVcjs.OpenAIResponseTransformer
24
24
  };
25
25
  function getBuiltinTransformers() {
26
26
  return BuiltinTransformers;
@@ -1,3 +1,8 @@
1
+ import {
2
+ chatUsageToResponsesUsage,
3
+ responsesUsageToChatUsage
4
+ } from "./chunk-FU7EAR73.js";
5
+
1
6
  // src/transformer/transformers/OpenAIResponseTransformer.ts
2
7
  var OpenAIResponseTransformer = class {
3
8
  static TransformerName = "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: responsesUsageToChatUsage(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: chatUsageToResponsesUsage(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 = resp?.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 = responsesUsageToChatUsage(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: chatUsageToResponsesUsage(chunk.usage)
809
798
  }
810
799
  });
811
800
  }
@@ -0,0 +1,63 @@
1
+ "use strict";Object.defineProperty(exports, "__esModule", {value: true});// src/provider-proxy/identity/headerMerge.ts
2
+ function fillMissingHeaders(headers, source) {
3
+ const present = new Set(Object.keys(headers).map((k) => k.toLowerCase()));
4
+ for (const [key, value] of Object.entries(source)) {
5
+ const lower = key.toLowerCase();
6
+ if (present.has(lower)) continue;
7
+ headers[lower] = value;
8
+ present.add(lower);
9
+ }
10
+ }
11
+ function flattenHeaderValue(raw) {
12
+ if (raw === void 0) return void 0;
13
+ const value = Array.isArray(raw) ? raw.filter((v) => typeof v === "string").join(", ") : raw;
14
+ return typeof value === "string" && value.length > 0 ? value : void 0;
15
+ }
16
+ var NEVER_FORWARD_HEADERS = /* @__PURE__ */ new Set([
17
+ "authorization",
18
+ "x-api-key",
19
+ "cookie",
20
+ "proxy-authorization",
21
+ "host",
22
+ "connection",
23
+ "content-length",
24
+ "content-type",
25
+ "accept-encoding"
26
+ ]);
27
+
28
+ // src/provider-proxy/identity/codexCliHeaders.ts
29
+ var DEFAULT_CODEX_CLI_HEADERS = Object.freeze({
30
+ originator: "codex_cli_rs",
31
+ "user-agent": "codex_cli_rs/0.144.5",
32
+ version: "0.144.5"
33
+ });
34
+ var CODEX_FORWARD_ALLOWLIST = /* @__PURE__ */ new Set([
35
+ "version",
36
+ "openai-beta",
37
+ "session_id",
38
+ "originator",
39
+ "user-agent"
40
+ ]);
41
+ function extractCodexClientHeaders(reqHeaders) {
42
+ const out = {};
43
+ for (const [rawKey, rawVal] of Object.entries(reqHeaders)) {
44
+ const key = rawKey.toLowerCase();
45
+ if (NEVER_FORWARD_HEADERS.has(key)) continue;
46
+ if (!CODEX_FORWARD_ALLOWLIST.has(key)) continue;
47
+ const value = flattenHeaderValue(rawVal);
48
+ if (value !== void 0) out[key] = value;
49
+ }
50
+ return out;
51
+ }
52
+ function codexAcceptHeader(isStream) {
53
+ return isStream ? "text/event-stream" : "application/json";
54
+ }
55
+
56
+
57
+
58
+
59
+
60
+
61
+
62
+
63
+ exports.fillMissingHeaders = fillMissingHeaders; exports.flattenHeaderValue = flattenHeaderValue; exports.NEVER_FORWARD_HEADERS = NEVER_FORWARD_HEADERS; exports.DEFAULT_CODEX_CLI_HEADERS = DEFAULT_CODEX_CLI_HEADERS; exports.extractCodexClientHeaders = extractCodexClientHeaders; exports.codexAcceptHeader = codexAcceptHeader;
@@ -2,6 +2,7 @@
2
2
  import { appendFile, mkdir } from "fs/promises";
3
3
  import { dirname } from "path";
4
4
  var tracePath = null;
5
+ var REDACTED_BODY = "***REDACTED (credential exchange)***";
5
6
  var SECRET_HEADER_NAMES = /* @__PURE__ */ new Set([
6
7
  "authorization",
7
8
  "api-key",
@@ -44,6 +45,7 @@ function __resetUpstreamTraceForTests() {
44
45
  }
45
46
 
46
47
  export {
48
+ REDACTED_BODY,
47
49
  setUpstreamTracePath,
48
50
  getUpstreamTracePath,
49
51
  redactHeaders,
@@ -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
  `;
@@ -0,0 +1,62 @@
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; }// src/transformer/transformers/utils/usage-mapping.ts
2
+ function num(obj, key) {
3
+ const v = _optionalChain([obj, 'optionalAccess', _ => _[key]]);
4
+ return typeof v === "number" && Number.isFinite(v) ? v : 0;
5
+ }
6
+ function detailCachedTokens(obj, detailKey) {
7
+ const detail = _optionalChain([obj, 'optionalAccess', _2 => _2[detailKey]]);
8
+ return num(detail, "cached_tokens");
9
+ }
10
+ function anthropicUsageToChatUsage(usage) {
11
+ if (!usage) return void 0;
12
+ const input = num(usage, "input_tokens");
13
+ const output = num(usage, "output_tokens");
14
+ const cacheRead = num(usage, "cache_read_input_tokens");
15
+ const cacheCreation = num(usage, "cache_creation_input_tokens");
16
+ const promptTokens = input + cacheRead + cacheCreation;
17
+ const out = {
18
+ prompt_tokens: promptTokens,
19
+ completion_tokens: output,
20
+ total_tokens: promptTokens + output
21
+ };
22
+ if (cacheRead > 0) {
23
+ out.prompt_tokens_details = { cached_tokens: cacheRead };
24
+ }
25
+ return out;
26
+ }
27
+ function chatUsageToResponsesUsage(usage) {
28
+ if (!usage) return void 0;
29
+ const prompt = num(usage, "prompt_tokens");
30
+ const completion = num(usage, "completion_tokens");
31
+ const out = {
32
+ input_tokens: prompt,
33
+ output_tokens: completion,
34
+ total_tokens: num(usage, "total_tokens") || prompt + completion
35
+ };
36
+ const cacheRead = detailCachedTokens(usage, "prompt_tokens_details");
37
+ if (cacheRead > 0) {
38
+ out.input_tokens_details = { cached_tokens: cacheRead };
39
+ }
40
+ return out;
41
+ }
42
+ function responsesUsageToChatUsage(usage) {
43
+ if (!usage) return void 0;
44
+ const input = num(usage, "input_tokens");
45
+ const output = num(usage, "output_tokens");
46
+ const out = {
47
+ prompt_tokens: input,
48
+ completion_tokens: output,
49
+ total_tokens: num(usage, "total_tokens") || input + output
50
+ };
51
+ const cacheRead = detailCachedTokens(usage, "input_tokens_details");
52
+ if (cacheRead > 0) {
53
+ out.prompt_tokens_details = { cached_tokens: cacheRead };
54
+ }
55
+ return out;
56
+ }
57
+
58
+
59
+
60
+
61
+
62
+ exports.anthropicUsageToChatUsage = anthropicUsageToChatUsage; exports.chatUsageToResponsesUsage = chatUsageToResponsesUsage; exports.responsesUsageToChatUsage = responsesUsageToChatUsage;
@@ -11,6 +11,29 @@ import {
11
11
 
12
12
  // src/outbound-api/auditCapture.ts
13
13
  import { randomUUID } from "crypto";
14
+ function completeUtf8PrefixLength(buf) {
15
+ if (buf.length === 0) return 0;
16
+ let leadIndex = buf.length - 1;
17
+ while (leadIndex >= 0 && (buf[leadIndex] & 192) === 128) leadIndex -= 1;
18
+ if (leadIndex < 0) return 0;
19
+ const lead = buf[leadIndex];
20
+ let expectedLength = 1;
21
+ if ((lead & 224) === 192) expectedLength = 2;
22
+ else if ((lead & 240) === 224) expectedLength = 3;
23
+ else if ((lead & 248) === 240) expectedLength = 4;
24
+ return buf.length - leadIndex < expectedLength ? leadIndex : buf.length;
25
+ }
26
+ function truncateToBytes(text, maxBytes) {
27
+ if (maxBytes < 0) return text;
28
+ const buf = Buffer.from(text, "utf8");
29
+ if (buf.length <= maxBytes) return text;
30
+ const head = buf.subarray(0, maxBytes);
31
+ return head.subarray(0, completeUtf8PrefixLength(head)).toString("utf8");
32
+ }
33
+ function decodeCapturedBody(body, truncated) {
34
+ if (!truncated) return body.toString("utf8");
35
+ return body.subarray(0, completeUtf8PrefixLength(body)).toString("utf8");
36
+ }
14
37
  function resolveClientIp(req, trustForwardedFor) {
15
38
  if (trustForwardedFor) {
16
39
  const xff = req.headers["x-forwarded-for"];
@@ -25,18 +48,39 @@ function resolveClientIp(req, trustForwardedFor) {
25
48
  function beginAuditCapture(req, res, now) {
26
49
  const config = getAuditCaptureConfig();
27
50
  if (!config) return null;
28
- let rawRequestBody;
51
+ let requestBody;
29
52
  const responseChunks = [];
53
+ let responseBytes = 0;
54
+ let responseTruncated = false;
30
55
  let finished = false;
31
56
  const ctx = {
32
57
  setRequestBody(raw) {
33
- if (config.captureBodies) rawRequestBody = raw;
58
+ if (config.captureBodies) {
59
+ requestBody = truncateToBytes(redactAuditText(raw), config.maxBodyBytes);
60
+ }
34
61
  }
35
62
  };
36
63
  if (config.captureBodies) {
37
64
  installResponseCapture(res, {
38
65
  push(chunk) {
66
+ if (config.maxBodyBytes < 0) {
67
+ responseChunks.push(chunk);
68
+ responseBytes += chunk.length;
69
+ return;
70
+ }
71
+ const remaining = config.maxBodyBytes - responseBytes;
72
+ if (remaining <= 0) {
73
+ responseTruncated = true;
74
+ return;
75
+ }
76
+ if (chunk.length > remaining) {
77
+ responseChunks.push(chunk.subarray(0, remaining));
78
+ responseBytes += remaining;
79
+ responseTruncated = true;
80
+ return;
81
+ }
39
82
  responseChunks.push(chunk);
83
+ responseBytes += chunk.length;
40
84
  }
41
85
  });
42
86
  }
@@ -69,12 +113,13 @@ function beginAuditCapture(req, res, now) {
69
113
  }
70
114
  if (ctx.error) record.error = redactAuditText(ctx.error);
71
115
  if (config.captureBodies) {
72
- if (rawRequestBody != null && rawRequestBody.length > 0) {
73
- record.requestBody = redactAuditText(rawRequestBody);
116
+ if (requestBody != null && requestBody.length > 0) {
117
+ record.requestBody = requestBody;
74
118
  }
75
119
  if (responseChunks.length > 0) {
76
- const body = Buffer.concat(responseChunks).toString("utf8");
77
- record.responseBody = redactAuditText(body);
120
+ const captured = Buffer.concat(responseChunks, responseBytes);
121
+ const body = decodeCapturedBody(captured, responseTruncated);
122
+ record.responseBody = truncateToBytes(redactAuditText(body), config.maxBodyBytes);
78
123
  }
79
124
  }
80
125
  recordAudit(record);
@@ -78,7 +78,12 @@ 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
+ routeLeaseId: _nullishCoalesce(input.routeLeaseId, () => ( null)),
82
+ routeLeaseConsumer: _nullishCoalesce(input.routeLeaseConsumer, () => ( null)),
83
+ routeLeaseStageId: _nullishCoalesce(input.routeLeaseStageId, () => ( null)),
84
+ eventId: _nullishCoalesce(input.eventId, () => ( null)),
85
+ ...input.cacheKeySource !== void 0 ? { cacheKeySource: input.cacheKeySource } : {},
86
+ ...input.cacheKeyInjected !== void 0 ? { cacheKeyInjected: input.cacheKeyInjected } : {}
82
87
  };
83
88
  try {
84
89
  return await this.store.insert(row);
@@ -0,0 +1,62 @@
1
+ // src/transformer/transformers/utils/usage-mapping.ts
2
+ function num(obj, key) {
3
+ const v = obj?.[key];
4
+ return typeof v === "number" && Number.isFinite(v) ? v : 0;
5
+ }
6
+ function detailCachedTokens(obj, detailKey) {
7
+ const detail = obj?.[detailKey];
8
+ return num(detail, "cached_tokens");
9
+ }
10
+ function anthropicUsageToChatUsage(usage) {
11
+ if (!usage) return void 0;
12
+ const input = num(usage, "input_tokens");
13
+ const output = num(usage, "output_tokens");
14
+ const cacheRead = num(usage, "cache_read_input_tokens");
15
+ const cacheCreation = num(usage, "cache_creation_input_tokens");
16
+ const promptTokens = input + cacheRead + cacheCreation;
17
+ const out = {
18
+ prompt_tokens: promptTokens,
19
+ completion_tokens: output,
20
+ total_tokens: promptTokens + output
21
+ };
22
+ if (cacheRead > 0) {
23
+ out.prompt_tokens_details = { cached_tokens: cacheRead };
24
+ }
25
+ return out;
26
+ }
27
+ function chatUsageToResponsesUsage(usage) {
28
+ if (!usage) return void 0;
29
+ const prompt = num(usage, "prompt_tokens");
30
+ const completion = num(usage, "completion_tokens");
31
+ const out = {
32
+ input_tokens: prompt,
33
+ output_tokens: completion,
34
+ total_tokens: num(usage, "total_tokens") || prompt + completion
35
+ };
36
+ const cacheRead = detailCachedTokens(usage, "prompt_tokens_details");
37
+ if (cacheRead > 0) {
38
+ out.input_tokens_details = { cached_tokens: cacheRead };
39
+ }
40
+ return out;
41
+ }
42
+ function responsesUsageToChatUsage(usage) {
43
+ if (!usage) return void 0;
44
+ const input = num(usage, "input_tokens");
45
+ const output = num(usage, "output_tokens");
46
+ const out = {
47
+ prompt_tokens: input,
48
+ completion_tokens: output,
49
+ total_tokens: num(usage, "total_tokens") || input + output
50
+ };
51
+ const cacheRead = detailCachedTokens(usage, "input_tokens_details");
52
+ if (cacheRead > 0) {
53
+ out.prompt_tokens_details = { cached_tokens: cacheRead };
54
+ }
55
+ return out;
56
+ }
57
+
58
+ export {
59
+ anthropicUsageToChatUsage,
60
+ chatUsageToResponsesUsage,
61
+ responsesUsageToChatUsage
62
+ };
@@ -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
  `;