@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.
- package/dist/ApiConverter.cjs +2 -2
- package/dist/ApiConverter.js +1 -1
- package/dist/{ProviderProxy-C-xqrkKi.d.ts → ProviderProxy--ROec6VI.d.ts} +22 -3
- package/dist/{ProviderProxy-CnMQYN59.d.cts → ProviderProxy-QdwNV6l1.d.cts} +22 -3
- package/dist/auth/GeminiCodeAssistProjectResolver.cjs +4 -3
- package/dist/auth/GeminiCodeAssistProjectResolver.js +3 -2
- package/dist/{chunk-3Z5BQZFM.cjs → chunk-235MXAGX.cjs} +3 -1
- package/dist/{chunk-SQYVORNP.cjs → chunk-26K6T2YS.cjs} +1520 -523
- package/dist/{chunk-DLXZEZWO.cjs → chunk-2E42SAW3.cjs} +42 -4
- package/dist/{chunk-7AK7B36B.cjs → chunk-2Z4XM3H5.cjs} +6 -6
- package/dist/{chunk-OEWZUX4G.js → chunk-32O35CIF.js} +9 -20
- package/dist/chunk-3SCOLIPT.cjs +63 -0
- package/dist/{chunk-SYQF7OIR.js → chunk-3WD4HTR2.js} +2 -0
- package/dist/{chunk-AT7B7SOZ.js → chunk-5NJLQ6T6.js} +21 -10
- package/dist/chunk-5RSZYQJH.cjs +62 -0
- package/dist/{chunk-IFXJ2BG7.js → chunk-7C7DET6S.js} +51 -6
- package/dist/{chunk-SNYBEXLB.cjs → chunk-EPN67EGP.cjs} +6 -1
- package/dist/chunk-FU7EAR73.js +62 -0
- package/dist/{chunk-UX7VWA46.js → chunk-FXR6N3SR.js} +39 -1
- package/dist/{chunk-WYTEQ4Q5.cjs → chunk-GDIXXKF2.cjs} +21 -10
- package/dist/{chunk-WB6PH56J.js → chunk-GFIZ6LQI.js} +12 -8
- package/dist/chunk-GL6XM527.js +61 -0
- package/dist/{chunk-EJLH6NFT.cjs → chunk-J3QQ6JS5.cjs} +12 -8
- package/dist/{chunk-VRFBB5DB.js → chunk-MYYR3HZL.js} +4 -4
- package/dist/{chunk-YJVHCHQX.js → chunk-N7OOJI5V.js} +46 -2
- package/dist/chunk-NKVZ6Z3Y.cjs +61 -0
- package/dist/chunk-OTZC4TNH.cjs +79 -0
- package/dist/{chunk-6VUQPOV3.cjs → chunk-OVQBNVSV.cjs} +10 -21
- package/dist/{chunk-4VLRHHFE.cjs → chunk-OXHNSZ53.cjs} +9 -11
- package/dist/{chunk-6CL5HTPQ.js → chunk-PEGTIPB3.js} +8 -10
- package/dist/chunk-PO3XB56Z.js +79 -0
- package/dist/{chunk-UDCC7EMR.js → chunk-QYC54PMG.js} +1242 -245
- package/dist/{chunk-SIZQQD6T.js → chunk-RJ5ZGNI3.js} +42 -5
- package/dist/{chunk-KCVJWJST.cjs → chunk-RJUONLUQ.cjs} +47 -10
- package/dist/{chunk-BPKCU575.js → chunk-UAPBLNN2.js} +6 -1
- package/dist/{chunk-UNWKG6EI.cjs → chunk-XPIOJQS2.cjs} +51 -6
- package/dist/chunk-XXFYLL7R.js +63 -0
- package/dist/{chunk-YK57NMIF.cjs → chunk-YWL7YZWS.cjs} +47 -3
- package/dist/completion/ApiKeyPoolService.cjs +32 -1
- package/dist/completion/ApiKeyPoolService.d.cts +17 -1
- package/dist/completion/ApiKeyPoolService.d.ts +17 -1
- package/dist/completion/ApiKeyPoolService.js +31 -0
- package/dist/completion/CompletionService.cjs +23 -19
- package/dist/completion/CompletionService.d.cts +1 -0
- package/dist/completion/CompletionService.d.ts +1 -0
- package/dist/completion/CompletionService.js +22 -18
- package/dist/completion.cjs +23 -19
- package/dist/completion.d.cts +1 -0
- package/dist/completion.d.ts +1 -0
- package/dist/completion.js +22 -18
- package/dist/index.cjs +81 -21
- package/dist/index.d.cts +5 -5
- package/dist/index.d.ts +5 -5
- package/dist/index.js +82 -22
- package/dist/outbound-api/auditCapture.cjs +2 -2
- package/dist/outbound-api/auditCapture.d.cts +3 -4
- package/dist/outbound-api/auditCapture.d.ts +3 -4
- package/dist/outbound-api/auditCapture.js +1 -1
- package/dist/outbound-api/routeResolver.d.cts +4 -3
- package/dist/outbound-api/routeResolver.d.ts +4 -3
- package/dist/outbound-api/subscriptionRegistryPort.d.cts +1 -0
- package/dist/outbound-api/subscriptionRegistryPort.d.ts +1 -0
- package/dist/outbound-api/types.d.cts +3 -2
- package/dist/outbound-api/types.d.ts +3 -2
- package/dist/outbound-api.cjs +23 -19
- package/dist/outbound-api.d.cts +8 -6
- package/dist/outbound-api.d.ts +8 -6
- package/dist/outbound-api.js +22 -18
- package/dist/pipeline/AccountAllowanceScheduling.d.cts +3 -2
- package/dist/pipeline/AccountAllowanceScheduling.d.ts +3 -2
- package/dist/pipeline/AccountRouteActivity.cjs +10 -0
- package/dist/pipeline/AccountRouteActivity.d.cts +61 -0
- package/dist/pipeline/AccountRouteActivity.d.ts +61 -0
- package/dist/pipeline/AccountRouteActivity.js +10 -0
- package/dist/pipeline/ServerOverloadCounter.cjs +16 -0
- package/dist/pipeline/ServerOverloadCounter.d.cts +77 -0
- package/dist/pipeline/ServerOverloadCounter.d.ts +77 -0
- package/dist/pipeline/ServerOverloadCounter.js +16 -0
- package/dist/pipeline/SubscriptionAccountHealth.cjs +4 -2
- package/dist/pipeline/SubscriptionAccountHealth.d.cts +32 -3
- package/dist/pipeline/SubscriptionAccountHealth.d.ts +32 -3
- package/dist/pipeline/SubscriptionAccountHealth.js +3 -1
- package/dist/pipeline/upstreamFetch.cjs +4 -3
- package/dist/pipeline/upstreamFetch.d.cts +35 -6
- package/dist/pipeline/upstreamFetch.d.ts +35 -6
- package/dist/pipeline/upstreamFetch.js +3 -2
- package/dist/pipeline/upstreamTrace.cjs +4 -2
- package/dist/pipeline/upstreamTrace.d.cts +22 -8
- package/dist/pipeline/upstreamTrace.d.ts +22 -8
- package/dist/pipeline/upstreamTrace.js +3 -1
- package/dist/ports.d.cts +2 -2
- package/dist/ports.d.ts +2 -2
- package/dist/provider-proxy/ProviderProxy.cjs +23 -19
- package/dist/provider-proxy/ProviderProxy.d.cts +2 -1
- package/dist/provider-proxy/ProviderProxy.d.ts +2 -1
- package/dist/provider-proxy/ProviderProxy.js +22 -18
- package/dist/provider-proxy/identity/codexCliHeaders.cjs +10 -0
- package/dist/provider-proxy/identity/codexCliHeaders.d.cts +45 -0
- package/dist/provider-proxy/identity/codexCliHeaders.d.ts +45 -0
- package/dist/provider-proxy/identity/codexCliHeaders.js +10 -0
- package/dist/provider-proxy/ingress/providerProxyShared.cjs +23 -19
- package/dist/provider-proxy/ingress/providerProxyShared.d.cts +11 -1
- package/dist/provider-proxy/ingress/providerProxyShared.d.ts +11 -1
- package/dist/provider-proxy/ingress/providerProxyShared.js +22 -18
- package/dist/provider-proxy/matchText.cjs +2 -2
- package/dist/provider-proxy/matchText.d.cts +1 -3
- package/dist/provider-proxy/matchText.d.ts +1 -3
- package/dist/provider-proxy/matchText.js +1 -1
- package/dist/provider-proxy/types.d.cts +20 -1
- package/dist/provider-proxy/types.d.ts +20 -1
- package/dist/provider-proxy.cjs +79 -19
- package/dist/provider-proxy.d.cts +255 -8
- package/dist/provider-proxy.d.ts +255 -8
- package/dist/provider-proxy.js +80 -20
- package/dist/{routeResolver-CHTv_Bs5.d.ts → routeResolver-C0mkkZaM.d.ts} +1 -1
- package/dist/{routeResolver-kepxnfcC.d.cts → routeResolver-CVFE8KKe.d.cts} +1 -1
- package/dist/transformer/transformers/AnthropicTransformer.cjs +3 -2
- package/dist/transformer/transformers/AnthropicTransformer.js +2 -1
- package/dist/transformer/transformers/OpenAIResponseTransformer.cjs +3 -2
- package/dist/transformer/transformers/OpenAIResponseTransformer.js +2 -1
- package/dist/transformer/transformers.cjs +7 -6
- package/dist/transformer/transformers.js +6 -5
- package/dist/transformer.cjs +9 -8
- package/dist/transformer.js +8 -7
- package/dist/{types-hsoKrVQS.d.ts → types-BB8pxk_3.d.ts} +40 -1
- package/dist/{types-H3wGZSOo.d.cts → types-C2MwkLah.d.cts} +40 -1
- package/dist/usage/pricing-engine.cjs +2 -2
- package/dist/usage/pricing-engine.d.cts +20 -0
- package/dist/usage/pricing-engine.d.ts +20 -0
- package/dist/usage/pricing-engine.js +1 -1
- package/dist/usage/usage-recorder.cjs +2 -2
- package/dist/usage/usage-recorder.d.cts +11 -1
- package/dist/usage/usage-recorder.d.ts +11 -1
- package/dist/usage/usage-recorder.js +1 -1
- package/dist/usage.cjs +3 -3
- package/dist/usage.js +2 -2
- 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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
|
3
|
+
var _chunkOXHNSZ53cjs = require('./chunk-OXHNSZ53.cjs');
|
|
4
4
|
|
|
5
5
|
|
|
6
|
-
var
|
|
6
|
+
var _chunkV4TXMEJScjs = require('./chunk-V4TXMEJS.cjs');
|
|
7
7
|
|
|
8
8
|
|
|
9
|
-
var
|
|
9
|
+
var _chunkOVQBNVSVcjs = require('./chunk-OVQBNVSV.cjs');
|
|
10
10
|
|
|
11
11
|
|
|
12
|
-
var
|
|
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:
|
|
23
|
-
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
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
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
|
|
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)
|
|
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 (
|
|
73
|
-
record.requestBody =
|
|
116
|
+
if (requestBody != null && requestBody.length > 0) {
|
|
117
|
+
record.requestBody = requestBody;
|
|
74
118
|
}
|
|
75
119
|
if (responseChunks.length > 0) {
|
|
76
|
-
const
|
|
77
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
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
|
`;
|