@rulvar/openai 1.19.0 → 1.21.0
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/index.d.ts +71 -18
- package/dist/index.js +132 -24
- package/package.json +3 -3
package/dist/index.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import OpenAI, { ClientOptions } from "openai";
|
|
2
|
-
import { CanonicalId, ChatEvent, ChatRequest, Effort, ModelCaps, PriceTable, ProviderAdapter, Usage, WireError } from "@rulvar/core";
|
|
2
|
+
import { CanonicalId, ChatEvent, ChatRequest, Effort, JournalEntry, ModelCaps, ModelRef, PriceTable, ProviderAdapter, Usage, WireError } from "@rulvar/core";
|
|
3
3
|
|
|
4
4
|
//#region src/caps.d.ts
|
|
5
5
|
interface OpenAiModelInfo {
|
|
@@ -8,11 +8,13 @@ interface OpenAiModelInfo {
|
|
|
8
8
|
/** Reasoning models reject non-default sampling parameters. */
|
|
9
9
|
reasoning: boolean;
|
|
10
10
|
/**
|
|
11
|
-
* The model accepts wire `reasoning.effort: "max"` (GPT-5.6
|
|
12
|
-
* the official model
|
|
13
|
-
*
|
|
14
|
-
*
|
|
15
|
-
* either way.
|
|
11
|
+
* The model accepts wire `reasoning.effort: "max"` (the whole GPT-5.6
|
|
12
|
+
* family per the official model guidance, each sibling verified live
|
|
13
|
+
* 2026-07-18). When false, canonical max downmaps to wire xhigh; the
|
|
14
|
+
* downmap is recorded in providerMetadata and the journal identity
|
|
15
|
+
* keeps max, so caps accept the full canonical set either way. Flip
|
|
16
|
+
* this to true ONLY on a per-model live verification, never from the
|
|
17
|
+
* family page alone.
|
|
16
18
|
*/
|
|
17
19
|
wireMaxEffort: boolean;
|
|
18
20
|
}
|
|
@@ -108,6 +110,41 @@ interface OpenAiCompatibleConfig {
|
|
|
108
110
|
/** Creates a Chat Completions dialect adapter for a compatible endpoint. */
|
|
109
111
|
declare function openaiCompatible(cfg: OpenAiCompatibleConfig): ProviderAdapter;
|
|
110
112
|
//#endregion
|
|
113
|
+
//#region src/audit.d.ts
|
|
114
|
+
/**
|
|
115
|
+
* The exact inverse of the v1.19.0 double count for one usage:
|
|
116
|
+
* subtracts `cacheWriteTokens` back out of `inputTokens` and leaves
|
|
117
|
+
* every other field untouched. A usage without cache writes is returned
|
|
118
|
+
* unchanged (v1.19.0 recorded those correctly). Throws a typed
|
|
119
|
+
* ConfigError when the arithmetic cannot be the v1.19.0 shape (the
|
|
120
|
+
* recorded input has no room for the subtraction), which means the
|
|
121
|
+
* usage was NOT recorded by the affected adapter; do not guess.
|
|
122
|
+
*/
|
|
123
|
+
declare function undoV1190CacheDoubleCount(usage: Usage): Usage;
|
|
124
|
+
/** One journal's sidecar reconciliation; see auditV1190CacheJournal. */
|
|
125
|
+
interface V1190CacheAudit {
|
|
126
|
+
/** Entries whose usage carried the affected shape and were inverted. */
|
|
127
|
+
affectedEntries: number;
|
|
128
|
+
/** The fold as recorded (what reports and budgets saw). */
|
|
129
|
+
recordedUsd: number;
|
|
130
|
+
/** The fold with every affected usage inverted to the true wire shape. */
|
|
131
|
+
correctedUsd: number;
|
|
132
|
+
}
|
|
133
|
+
/**
|
|
134
|
+
* Folds a journal twice with the SAME price function: once as recorded
|
|
135
|
+
* and once with every affected OpenAI usage passed through
|
|
136
|
+
* `undoV1190CacheDoubleCount`, returning both totals and the affected
|
|
137
|
+
* entry count. An entry (or per-model slice) counts as affected when it
|
|
138
|
+
* was served by the `openai` adapter, carries cache writes, and has no
|
|
139
|
+
* `usageSemantics` stamp; stamped entries are already correct and fold
|
|
140
|
+
* identically in both totals. The journal itself is never touched.
|
|
141
|
+
* `recordedUsd - correctedUsd` is the exact overcharge IF the journal
|
|
142
|
+
* was recorded by v1.19.0; for a v1.20.0 journal the same shape folds
|
|
143
|
+
* to a smaller `correctedUsd` that does NOT correspond to any real
|
|
144
|
+
* charge, so version provenance stays the caller's responsibility.
|
|
145
|
+
*/
|
|
146
|
+
declare function auditV1190CacheJournal(entries: readonly JournalEntry[], priceUsd: (servedBy: ModelRef, usage: Usage) => number | undefined): V1190CacheAudit;
|
|
147
|
+
//#endregion
|
|
111
148
|
//#region src/wire.d.ts
|
|
112
149
|
/** Bijective canonical-to-wire (call_*) id map. */
|
|
113
150
|
declare class OpenAiIdMap {
|
|
@@ -121,9 +158,10 @@ declare class OpenAiIdMap {
|
|
|
121
158
|
/**
|
|
122
159
|
* Canonical-to-wire effort: low through xhigh pass through. Canonical
|
|
123
160
|
* max passes through unchanged on models whose caps declare wire max
|
|
124
|
-
* support (GPT-5.6
|
|
125
|
-
*
|
|
126
|
-
*
|
|
161
|
+
* support (the whole GPT-5.6 family, each sibling verified live
|
|
162
|
+
* 2026-07-18; v1.20.0 review P2-3); elsewhere it downmaps to xhigh
|
|
163
|
+
* (documented lossy; recorded in providerMetadata). Provider 'none' is
|
|
164
|
+
* reachable only via providerOptions.openai.reasoningEffort.
|
|
127
165
|
*/
|
|
128
166
|
declare function mapOpenAiEffort(effort: Effort, options?: {
|
|
129
167
|
wireMaxEffort?: boolean;
|
|
@@ -150,14 +188,29 @@ type ResponsesStreamEvent = Record<string, unknown> & {
|
|
|
150
188
|
};
|
|
151
189
|
/**
|
|
152
190
|
* Normalizes Responses usage into the canonical Usage invariant, where
|
|
153
|
-
* `inputTokens` is the FULL prompt
|
|
154
|
-
*
|
|
155
|
-
* `input_tokens_details.cache_write_tokens` (GPT-5.6 and later
|
|
156
|
-
*
|
|
157
|
-
*
|
|
158
|
-
*
|
|
159
|
-
*
|
|
160
|
-
*
|
|
191
|
+
* `inputTokens` is the FULL prompt. On the OpenAI wire `input_tokens`
|
|
192
|
+
* is ALREADY that full count: `input_tokens_details.cached_tokens` and
|
|
193
|
+
* `input_tokens_details.cache_write_tokens` (GPT-5.6 and later
|
|
194
|
+
* families) are priced SUBSETS of it, never additional tokens, so both
|
|
195
|
+
* pass through untouched and nothing is added. Verified on the live
|
|
196
|
+
* wire 2026-07-18: two identical long prompts report the SAME
|
|
197
|
+
* `input_tokens` while the details flip from write to read, and
|
|
198
|
+
* `total_tokens` equals `input_tokens + output_tokens` on both calls.
|
|
199
|
+
* Adding writes on top (the v1.19.0 reading of the field) double-billed
|
|
200
|
+
* every written token at 1x + 1.25x and inflated budget debits
|
|
201
|
+
* (v1.19.0 review P1-1). Contrast with the Anthropic adapter, whose
|
|
202
|
+
* wire genuinely EXCLUDES both cache counts from `input_tokens`, so
|
|
203
|
+
* that adapter adds them; the two wires differ, the canonical Usage
|
|
204
|
+
* invariant does not.
|
|
205
|
+
*
|
|
206
|
+
* Numeric hygiene is deliberately NOT this function's job: any `number`
|
|
207
|
+
* the wire (or an injected client) reports passes through, and the core
|
|
208
|
+
* enforces the full telemetry invariant at the adapter boundary for
|
|
209
|
+
* every adapter uniformly, failing the call loud on non-finite,
|
|
210
|
+
* negative, or fractional counts while accounting only sanitized values
|
|
211
|
+
* (`usageViolations`/`sanitizeUsage` in @rulvar/core; v1.20.0 review
|
|
212
|
+
* P1-1). Real wires report whole nonnegative integers; a violation here
|
|
213
|
+
* means a broken transport, never plausible provider data.
|
|
161
214
|
*/
|
|
162
215
|
declare function normalizeOpenAiUsage(raw: Record<string, unknown> | undefined): Usage;
|
|
163
216
|
/**
|
|
@@ -189,4 +242,4 @@ declare function buildChatCompletionsParams(req: ChatRequest, ids: OpenAiIdMap):
|
|
|
189
242
|
*/
|
|
190
243
|
declare function mapChatCompletionsStream(stream: AsyncIterable<Record<string, unknown>>, ids: OpenAiIdMap): AsyncGenerator<ChatEvent, void>;
|
|
191
244
|
//#endregion
|
|
192
|
-
export { CONSERVATIVE_COMPATIBLE_CAPS, OPENAI_MODELS, OPENAI_PRICING, type OpenAiAdapterOptions, type OpenAiClientLike, type OpenAiCompatibleConfig, OpenAiIdMap, type OpenAiModelInfo, type OpenAiSdkOptions, type ResponsesStreamEvent, buildChatCompletionsParams, buildResponsesParams, mapChatCompletionsStream, mapOpenAiEffort, mapResponsesStream, normalizeOpenAiUsage, openAiErrorToWire, openAiModelInfo, openai, openaiCompatible };
|
|
245
|
+
export { CONSERVATIVE_COMPATIBLE_CAPS, OPENAI_MODELS, OPENAI_PRICING, type OpenAiAdapterOptions, type OpenAiClientLike, type OpenAiCompatibleConfig, OpenAiIdMap, type OpenAiModelInfo, type OpenAiSdkOptions, type ResponsesStreamEvent, type V1190CacheAudit, auditV1190CacheJournal, buildChatCompletionsParams, buildResponsesParams, mapChatCompletionsStream, mapOpenAiEffort, mapResponsesStream, normalizeOpenAiUsage, openAiErrorToWire, openAiModelInfo, openai, openaiCompatible, undoV1190CacheDoubleCount };
|
package/dist/index.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import OpenAI from "openai";
|
|
2
|
-
import { ConfigError, createCanonicalIdMinter, isStrictCompatibleSchema } from "@rulvar/core";
|
|
2
|
+
import { ConfigError, createCanonicalIdMinter, entryUsageSlices, isStrictCompatibleSchema } from "@rulvar/core";
|
|
3
3
|
//#region src/caps.ts
|
|
4
4
|
const REASONING_EFFORTS = [
|
|
5
5
|
"low",
|
|
@@ -34,7 +34,13 @@ const GPT_56_TIERS = [{
|
|
|
34
34
|
* .../gpt-5.6-terra, .../gpt-5.6-luna; rates verified 2026-07-18). All
|
|
35
35
|
* three: prompts strictly above 272K input tokens price the FULL
|
|
36
36
|
* request at 2x input and 1.5x output; cache writes bill at 1.25x
|
|
37
|
-
* uncached input.
|
|
37
|
+
* uncached input. All three accept wire reasoning effort `max`
|
|
38
|
+
* (v1.20.0 review P2-3; verified live per sibling 2026-07-18: a
|
|
39
|
+
* Responses call with `reasoning.effort: "max"` returns HTTP 200 with
|
|
40
|
+
* the effort echoed on Terra and Luna alike, and the API's own 400
|
|
41
|
+
* validator for an invalid effort enumerates `max` among the supported
|
|
42
|
+
* values, so acceptance is enforcement, not silence). Earlier families
|
|
43
|
+
* keep the conservative downmap until verified the same way.
|
|
38
44
|
*/
|
|
39
45
|
const GPT_56_SOL = responses(105e4, 128e3, {
|
|
40
46
|
inputUsdPerMTok: 5,
|
|
@@ -52,14 +58,14 @@ const OPENAI_MODELS = {
|
|
|
52
58
|
cacheReadUsdPerMTok: .25,
|
|
53
59
|
cacheWriteUsdPerMTok: 3.125,
|
|
54
60
|
tiers: GPT_56_TIERS
|
|
55
|
-
}),
|
|
61
|
+
}, { wireMaxEffort: true }),
|
|
56
62
|
"gpt-5.6-luna": responses(105e4, 128e3, {
|
|
57
63
|
inputUsdPerMTok: 1,
|
|
58
64
|
outputUsdPerMTok: 6,
|
|
59
65
|
cacheReadUsdPerMTok: .1,
|
|
60
66
|
cacheWriteUsdPerMTok: 1.25,
|
|
61
67
|
tiers: GPT_56_TIERS
|
|
62
|
-
}),
|
|
68
|
+
}, { wireMaxEffort: true }),
|
|
63
69
|
"gpt-5.6": GPT_56_SOL,
|
|
64
70
|
"gpt-5.5": responses(4e5, 128e3, {
|
|
65
71
|
inputUsdPerMTok: 5,
|
|
@@ -168,9 +174,10 @@ var OpenAiIdMap = class {
|
|
|
168
174
|
/**
|
|
169
175
|
* Canonical-to-wire effort: low through xhigh pass through. Canonical
|
|
170
176
|
* max passes through unchanged on models whose caps declare wire max
|
|
171
|
-
* support (GPT-5.6
|
|
172
|
-
*
|
|
173
|
-
*
|
|
177
|
+
* support (the whole GPT-5.6 family, each sibling verified live
|
|
178
|
+
* 2026-07-18; v1.20.0 review P2-3); elsewhere it downmaps to xhigh
|
|
179
|
+
* (documented lossy; recorded in providerMetadata). Provider 'none' is
|
|
180
|
+
* reachable only via providerOptions.openai.reasoningEffort.
|
|
174
181
|
*/
|
|
175
182
|
function mapOpenAiEffort(effort, options) {
|
|
176
183
|
if (effort === "max" && options?.wireMaxEffort !== true) return {
|
|
@@ -298,25 +305,58 @@ function buildResponsesParams(req, ids, options) {
|
|
|
298
305
|
};
|
|
299
306
|
}
|
|
300
307
|
/**
|
|
308
|
+
* Clamps the cache detail counts into the subset domain the pricing
|
|
309
|
+
* fold relies on (`reads + writes <= input`, everything nonnegative).
|
|
310
|
+
* The provider contract already guarantees it; impossible telemetry is
|
|
311
|
+
* clamped rather than rejected because a rejection would discard PAID
|
|
312
|
+
* evidence, and clamping is the conservative direction for the budget:
|
|
313
|
+
* dropped detail tokens price at the FULL input rate instead of the
|
|
314
|
+
* cache-read discount. Reads keep priority over writes, so a violation
|
|
315
|
+
* shrinks the write premium, never the base charge.
|
|
316
|
+
*/
|
|
317
|
+
function clampCacheSubsets(inputTokens, rawRead, rawWrite) {
|
|
318
|
+
const cacheReadTokens = Math.min(Math.max(0, rawRead), Math.max(0, inputTokens));
|
|
319
|
+
return {
|
|
320
|
+
cacheReadTokens,
|
|
321
|
+
cacheWriteTokens: Math.min(Math.max(0, rawWrite), Math.max(0, inputTokens) - cacheReadTokens)
|
|
322
|
+
};
|
|
323
|
+
}
|
|
324
|
+
/**
|
|
301
325
|
* Normalizes Responses usage into the canonical Usage invariant, where
|
|
302
|
-
* `inputTokens` is the FULL prompt
|
|
303
|
-
*
|
|
304
|
-
* `input_tokens_details.cache_write_tokens` (GPT-5.6 and later
|
|
305
|
-
*
|
|
306
|
-
*
|
|
307
|
-
*
|
|
308
|
-
*
|
|
309
|
-
*
|
|
326
|
+
* `inputTokens` is the FULL prompt. On the OpenAI wire `input_tokens`
|
|
327
|
+
* is ALREADY that full count: `input_tokens_details.cached_tokens` and
|
|
328
|
+
* `input_tokens_details.cache_write_tokens` (GPT-5.6 and later
|
|
329
|
+
* families) are priced SUBSETS of it, never additional tokens, so both
|
|
330
|
+
* pass through untouched and nothing is added. Verified on the live
|
|
331
|
+
* wire 2026-07-18: two identical long prompts report the SAME
|
|
332
|
+
* `input_tokens` while the details flip from write to read, and
|
|
333
|
+
* `total_tokens` equals `input_tokens + output_tokens` on both calls.
|
|
334
|
+
* Adding writes on top (the v1.19.0 reading of the field) double-billed
|
|
335
|
+
* every written token at 1x + 1.25x and inflated budget debits
|
|
336
|
+
* (v1.19.0 review P1-1). Contrast with the Anthropic adapter, whose
|
|
337
|
+
* wire genuinely EXCLUDES both cache counts from `input_tokens`, so
|
|
338
|
+
* that adapter adds them; the two wires differ, the canonical Usage
|
|
339
|
+
* invariant does not.
|
|
340
|
+
*
|
|
341
|
+
* Numeric hygiene is deliberately NOT this function's job: any `number`
|
|
342
|
+
* the wire (or an injected client) reports passes through, and the core
|
|
343
|
+
* enforces the full telemetry invariant at the adapter boundary for
|
|
344
|
+
* every adapter uniformly, failing the call loud on non-finite,
|
|
345
|
+
* negative, or fractional counts while accounting only sanitized values
|
|
346
|
+
* (`usageViolations`/`sanitizeUsage` in @rulvar/core; v1.20.0 review
|
|
347
|
+
* P1-1). Real wires report whole nonnegative integers; a violation here
|
|
348
|
+
* means a broken transport, never plausible provider data.
|
|
310
349
|
*/
|
|
311
350
|
function normalizeOpenAiUsage(raw) {
|
|
312
351
|
const inputDetails = raw?.input_tokens_details;
|
|
313
352
|
const outputDetails = raw?.output_tokens_details;
|
|
314
|
-
const
|
|
353
|
+
const inputTokens = typeof raw?.input_tokens === "number" ? raw.input_tokens : 0;
|
|
354
|
+
const clamped = clampCacheSubsets(inputTokens, typeof inputDetails?.cached_tokens === "number" ? inputDetails.cached_tokens : 0, typeof inputDetails?.cache_write_tokens === "number" ? inputDetails.cache_write_tokens : 0);
|
|
315
355
|
const usage = {
|
|
316
|
-
inputTokens
|
|
356
|
+
inputTokens,
|
|
317
357
|
outputTokens: typeof raw?.output_tokens === "number" ? raw.output_tokens : 0,
|
|
318
|
-
cacheReadTokens:
|
|
319
|
-
cacheWriteTokens:
|
|
358
|
+
cacheReadTokens: clamped.cacheReadTokens,
|
|
359
|
+
cacheWriteTokens: clamped.cacheWriteTokens
|
|
320
360
|
};
|
|
321
361
|
const reasoning = outputDetails?.reasoning_tokens;
|
|
322
362
|
if (typeof reasoning === "number" && reasoning > 0) usage.reasoningTokens = reasoning;
|
|
@@ -644,12 +684,13 @@ async function* mapChatCompletionsStream(stream, ids) {
|
|
|
644
684
|
const chunkUsage = chunk.usage;
|
|
645
685
|
if (chunkUsage !== void 0 && chunkUsage !== null) {
|
|
646
686
|
const promptDetails = chunkUsage.prompt_tokens_details;
|
|
647
|
-
const
|
|
687
|
+
const promptTokens = typeof chunkUsage.prompt_tokens === "number" ? chunkUsage.prompt_tokens : 0;
|
|
688
|
+
const clamped = clampCacheSubsets(promptTokens, typeof promptDetails?.cached_tokens === "number" ? promptDetails.cached_tokens : 0, typeof promptDetails?.cache_write_tokens === "number" ? promptDetails.cache_write_tokens : 0);
|
|
648
689
|
usage = {
|
|
649
|
-
inputTokens:
|
|
690
|
+
inputTokens: promptTokens,
|
|
650
691
|
outputTokens: typeof chunkUsage.completion_tokens === "number" ? chunkUsage.completion_tokens : 0,
|
|
651
|
-
cacheReadTokens:
|
|
652
|
-
cacheWriteTokens:
|
|
692
|
+
cacheReadTokens: clamped.cacheReadTokens,
|
|
693
|
+
cacheWriteTokens: clamped.cacheWriteTokens
|
|
653
694
|
};
|
|
654
695
|
}
|
|
655
696
|
}
|
|
@@ -715,6 +756,7 @@ function openai(options = {}) {
|
|
|
715
756
|
return {
|
|
716
757
|
id: "openai",
|
|
717
758
|
provider: "openai",
|
|
759
|
+
usageSemantics: "openai-cache-subsets-v2",
|
|
718
760
|
caps(model) {
|
|
719
761
|
return openAiModelInfo(model).caps;
|
|
720
762
|
},
|
|
@@ -785,6 +827,7 @@ function openaiCompatible(cfg) {
|
|
|
785
827
|
return {
|
|
786
828
|
id: cfg.id,
|
|
787
829
|
provider: "openai",
|
|
830
|
+
usageSemantics: "openai-cache-subsets-v2",
|
|
788
831
|
caps(model) {
|
|
789
832
|
const overrides = cfg.caps?.(model);
|
|
790
833
|
return overrides === void 0 ? CONSERVATIVE_COMPATIBLE_CAPS : {
|
|
@@ -810,4 +853,69 @@ function openaiCompatible(cfg) {
|
|
|
810
853
|
};
|
|
811
854
|
}
|
|
812
855
|
//#endregion
|
|
813
|
-
|
|
856
|
+
//#region src/audit.ts
|
|
857
|
+
/**
|
|
858
|
+
* The exact inverse of the v1.19.0 double count for one usage:
|
|
859
|
+
* subtracts `cacheWriteTokens` back out of `inputTokens` and leaves
|
|
860
|
+
* every other field untouched. A usage without cache writes is returned
|
|
861
|
+
* unchanged (v1.19.0 recorded those correctly). Throws a typed
|
|
862
|
+
* ConfigError when the arithmetic cannot be the v1.19.0 shape (the
|
|
863
|
+
* recorded input has no room for the subtraction), which means the
|
|
864
|
+
* usage was NOT recorded by the affected adapter; do not guess.
|
|
865
|
+
*/
|
|
866
|
+
function undoV1190CacheDoubleCount(usage) {
|
|
867
|
+
if (usage.cacheWriteTokens <= 0) return usage;
|
|
868
|
+
const trueInput = usage.inputTokens - usage.cacheWriteTokens;
|
|
869
|
+
if (trueInput < usage.cacheReadTokens + usage.cacheWriteTokens) throw new ConfigError(`not a v1.19.0-inflated usage: subtracting cacheWriteTokens (${String(usage.cacheWriteTokens)}) out of inputTokens (${String(usage.inputTokens)}) leaves less than the cache subsets; this usage was not recorded by the affected adapter`);
|
|
870
|
+
return {
|
|
871
|
+
...usage,
|
|
872
|
+
inputTokens: trueInput
|
|
873
|
+
};
|
|
874
|
+
}
|
|
875
|
+
/**
|
|
876
|
+
* Folds a journal twice with the SAME price function: once as recorded
|
|
877
|
+
* and once with every affected OpenAI usage passed through
|
|
878
|
+
* `undoV1190CacheDoubleCount`, returning both totals and the affected
|
|
879
|
+
* entry count. An entry (or per-model slice) counts as affected when it
|
|
880
|
+
* was served by the `openai` adapter, carries cache writes, and has no
|
|
881
|
+
* `usageSemantics` stamp; stamped entries are already correct and fold
|
|
882
|
+
* identically in both totals. The journal itself is never touched.
|
|
883
|
+
* `recordedUsd - correctedUsd` is the exact overcharge IF the journal
|
|
884
|
+
* was recorded by v1.19.0; for a v1.20.0 journal the same shape folds
|
|
885
|
+
* to a smaller `correctedUsd` that does NOT correspond to any real
|
|
886
|
+
* charge, so version provenance stays the caller's responsibility.
|
|
887
|
+
*/
|
|
888
|
+
function auditV1190CacheJournal(entries, priceUsd) {
|
|
889
|
+
let affectedEntries = 0;
|
|
890
|
+
let recordedUsd = 0;
|
|
891
|
+
let correctedUsd = 0;
|
|
892
|
+
for (const entry of entries) {
|
|
893
|
+
let entryAffected = false;
|
|
894
|
+
for (const slice of entryUsageSlices(entry)) {
|
|
895
|
+
const recorded = priceUsd(slice.servedBy, slice.usage);
|
|
896
|
+
if (recorded === void 0) continue;
|
|
897
|
+
recordedUsd += recorded;
|
|
898
|
+
if (entry.usageSemantics === void 0 && slice.servedBy.startsWith("openai:") && slice.usage.cacheWriteTokens > 0) {
|
|
899
|
+
let corrected;
|
|
900
|
+
try {
|
|
901
|
+
corrected = undoV1190CacheDoubleCount(slice.usage);
|
|
902
|
+
} catch {
|
|
903
|
+
corrected = void 0;
|
|
904
|
+
}
|
|
905
|
+
if (corrected === void 0) correctedUsd += recorded;
|
|
906
|
+
else {
|
|
907
|
+
entryAffected = true;
|
|
908
|
+
correctedUsd += priceUsd(slice.servedBy, corrected) ?? 0;
|
|
909
|
+
}
|
|
910
|
+
} else correctedUsd += recorded;
|
|
911
|
+
}
|
|
912
|
+
if (entryAffected) affectedEntries += 1;
|
|
913
|
+
}
|
|
914
|
+
return {
|
|
915
|
+
affectedEntries,
|
|
916
|
+
recordedUsd,
|
|
917
|
+
correctedUsd
|
|
918
|
+
};
|
|
919
|
+
}
|
|
920
|
+
//#endregion
|
|
921
|
+
export { CONSERVATIVE_COMPATIBLE_CAPS, OPENAI_MODELS, OPENAI_PRICING, OpenAiIdMap, auditV1190CacheJournal, buildChatCompletionsParams, buildResponsesParams, mapChatCompletionsStream, mapOpenAiEffort, mapResponsesStream, normalizeOpenAiUsage, openAiErrorToWire, openAiModelInfo, openai, openaiCompatible, undoV1190CacheDoubleCount };
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@rulvar/openai",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.21.0",
|
|
4
4
|
"description": "Rulvar first-class provider adapter for the OpenAI Responses API, plus the openaiCompatible factory.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"license": "Apache-2.0",
|
|
@@ -23,13 +23,13 @@
|
|
|
23
23
|
},
|
|
24
24
|
"dependencies": {
|
|
25
25
|
"openai": "^6.45.0",
|
|
26
|
-
"@rulvar/core": "1.
|
|
26
|
+
"@rulvar/core": "1.21.0"
|
|
27
27
|
},
|
|
28
28
|
"devDependencies": {
|
|
29
29
|
"@types/node": "^22.20.0",
|
|
30
30
|
"tsdown": "^0.22.3",
|
|
31
31
|
"typescript": "~6.0.3",
|
|
32
|
-
"@rulvar/testing": "1.
|
|
32
|
+
"@rulvar/testing": "1.21.0"
|
|
33
33
|
},
|
|
34
34
|
"repository": {
|
|
35
35
|
"type": "git",
|