codex-multi-auth 2.11.0 → 2.13.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/.codex-plugin/plugin.json +1 -1
- package/README.md +7 -1
- package/dist/lib/accounts.d.ts +75 -0
- package/dist/lib/accounts.d.ts.map +1 -1
- package/dist/lib/accounts.js +213 -42
- package/dist/lib/capability-policy.d.ts.map +1 -1
- package/dist/lib/capability-policy.js +2 -1
- package/dist/lib/codex-manager/account-manager-commands.d.ts.map +1 -1
- package/dist/lib/codex-manager/account-manager-commands.js +1 -0
- package/dist/lib/codex-manager/commands/limits.d.ts +21 -0
- package/dist/lib/codex-manager/commands/limits.d.ts.map +1 -0
- package/dist/lib/codex-manager/commands/limits.js +158 -0
- package/dist/lib/codex-manager/help.d.ts.map +1 -1
- package/dist/lib/codex-manager/help.js +1 -0
- package/dist/lib/codex-manager/persist-selected-account.d.ts.map +1 -1
- package/dist/lib/codex-manager/persist-selected-account.js +14 -0
- package/dist/lib/codex-manager.d.ts.map +1 -1
- package/dist/lib/codex-manager.js +12 -0
- package/dist/lib/config.d.ts.map +1 -1
- package/dist/lib/config.js +2 -1
- package/dist/lib/constants.d.ts +9 -0
- package/dist/lib/constants.d.ts.map +1 -1
- package/dist/lib/constants.js +29 -0
- package/dist/lib/entitlement-cache.d.ts.map +1 -1
- package/dist/lib/entitlement-cache.js +2 -1
- package/dist/lib/forecast.d.ts.map +1 -1
- package/dist/lib/forecast.js +1 -14
- package/dist/lib/policy/runtime-policy.d.ts +9 -1
- package/dist/lib/policy/runtime-policy.d.ts.map +1 -1
- package/dist/lib/policy/runtime-policy.js +1 -0
- package/dist/lib/preemptive-quota-scheduler.d.ts +12 -0
- package/dist/lib/preemptive-quota-scheduler.d.ts.map +1 -1
- package/dist/lib/preemptive-quota-scheduler.js +21 -0
- package/dist/lib/redaction.d.ts +17 -0
- package/dist/lib/redaction.d.ts.map +1 -0
- package/dist/lib/redaction.js +28 -0
- package/dist/lib/request/error-classification.js +2 -2
- package/dist/lib/runtime/rotation-storage-meta.d.ts.map +1 -1
- package/dist/lib/runtime/rotation-storage-meta.js +4 -1
- package/dist/lib/runtime-rotation-proxy.d.ts +13 -0
- package/dist/lib/runtime-rotation-proxy.d.ts.map +1 -1
- package/dist/lib/runtime-rotation-proxy.js +47 -7
- package/dist/lib/storage.d.ts +20 -2
- package/dist/lib/storage.d.ts.map +1 -1
- package/dist/lib/storage.js +69 -25
- package/dist/lib/usage/ledger.d.ts +1 -1
- package/dist/lib/usage/ledger.d.ts.map +1 -1
- package/dist/lib/usage/ledger.js +9 -0
- package/dist/lib/usage/pricing.d.ts +16 -1
- package/dist/lib/usage/pricing.d.ts.map +1 -1
- package/dist/lib/usage/pricing.js +46 -8
- package/dist/lib/usage/redaction.d.ts +1 -1
- package/dist/lib/usage/redaction.d.ts.map +1 -1
- package/dist/lib/usage/redaction.js +13 -0
- package/dist/lib/usage/types.d.ts +33 -0
- package/dist/lib/usage/types.d.ts.map +1 -1
- package/dist/lib/usage/types.js +28 -1
- package/dist/lib/usage/usage-extraction.d.ts +2 -1
- package/dist/lib/usage/usage-extraction.d.ts.map +1 -1
- package/dist/lib/usage/usage-extraction.js +44 -4
- package/package.json +1 -1
- package/scripts/codex-routing.js +1 -0
- package/scripts/codex.js +157 -2
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"runtime-rotation-proxy.d.ts","sourceRoot":"","sources":["../../lib/runtime-rotation-proxy.ts"],"names":[],"mappings":"AAGA,OAAO,EAIN,KAAK,cAAc,EACnB,MAAM,eAAe,CAAC;AAkCvB,OAAO,EAAkB,KAAK,WAAW,EAAE,MAAM,oBAAoB,CAAC;AAkDtE,OAAO,KAAK,EAKX,2BAA2B,EAC3B,0BAA0B,EAE1B,MAAM,oCAAoC,CAAC;AAe5C,YAAY,EACX,2BAA2B,EAC3B,0BAA0B,EAC1B,0BAA0B,GAC1B,MAAM,oCAAoC,CAAC;AAC5C,OAAO,EACN,+BAA+B,EAC/B,0BAA0B,GAC1B,MAAM,kCAAkC,CAAC;AAC1C,YAAY,EAAE,0BAA0B,EAAE,MAAM,kCAAkC,CAAC;AACnF,OAAO,EAAE,aAAa,EAAE,MAAM,yCAAyC,CAAC;AACxE,OAAO,EACN,+BAA+B,EAC/B,8BAA8B,EAC9B,uBAAuB,EACvB,uBAAuB,GACvB,MAAM,oCAAoC,CAAC;AAC5C,YAAY,EAAE,WAAW,EAAE,MAAM,oCAAoC,CAAC;AA8DtE,kFAAkF;AAClF,wBAAgB,qBAAqB,CACpC,OAAO,EAAE,IAAI,CAAC,cAAc,EAAE,WAAW,GAAG,OAAO,GAAG,cAAc,CAAC,GAAG;IACvE,gFAAgF;IAChF,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,QAAQ,CAAC,EAAE,MAAM,CAAC;CAClB,EACD,MAAM,EAAE,WAAW,EACnB,KAAK,CAAC,EAAE,MAAM,GAAG,IAAI,GACnB,MAAM,
|
|
1
|
+
{"version":3,"file":"runtime-rotation-proxy.d.ts","sourceRoot":"","sources":["../../lib/runtime-rotation-proxy.ts"],"names":[],"mappings":"AAGA,OAAO,EAIN,KAAK,cAAc,EACnB,MAAM,eAAe,CAAC;AAkCvB,OAAO,EAAkB,KAAK,WAAW,EAAE,MAAM,oBAAoB,CAAC;AAkDtE,OAAO,KAAK,EAKX,2BAA2B,EAC3B,0BAA0B,EAE1B,MAAM,oCAAoC,CAAC;AAe5C,YAAY,EACX,2BAA2B,EAC3B,0BAA0B,EAC1B,0BAA0B,GAC1B,MAAM,oCAAoC,CAAC;AAC5C,OAAO,EACN,+BAA+B,EAC/B,0BAA0B,GAC1B,MAAM,kCAAkC,CAAC;AAC1C,YAAY,EAAE,0BAA0B,EAAE,MAAM,kCAAkC,CAAC;AACnF,OAAO,EAAE,aAAa,EAAE,MAAM,yCAAyC,CAAC;AACxE,OAAO,EACN,+BAA+B,EAC/B,8BAA8B,EAC9B,uBAAuB,EACvB,uBAAuB,GACvB,MAAM,oCAAoC,CAAC;AAC5C,YAAY,EAAE,WAAW,EAAE,MAAM,oCAAoC,CAAC;AA8DtE,kFAAkF;AAClF;;;;;;;GAOG;AACH,wBAAgB,+BAA+B,CAC9C,OAAO,EAAE,IAAI,CAAC,cAAc,EAAE,WAAW,GAAG,OAAO,GAAG,cAAc,CAAC,GAAG;IACvE,gFAAgF;IAChF,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,QAAQ,CAAC,EAAE,MAAM,CAAC;CAClB,GACC,MAAM,CAmBR;AAED,wBAAgB,qBAAqB,CACpC,OAAO,EAAE,IAAI,CAAC,cAAc,EAAE,WAAW,GAAG,OAAO,GAAG,cAAc,CAAC,GAAG;IACvE,gFAAgF;IAChF,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,QAAQ,CAAC,EAAE,MAAM,CAAC;CAClB,EACD,MAAM,EAAE,WAAW,EACnB,KAAK,CAAC,EAAE,MAAM,GAAG,IAAI,GACnB,MAAM,CAER;AA8gBD;;;;;;;;GAQG;AACH,wBAAgB,2BAA2B,CAC1C,KAAK,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,GAAG,SAAS,GACvC,MAAM,GAAG,IAAI,CAUf;AAED,wBAAsB,yBAAyB,CAC9C,OAAO,EAAE,2BAA2B,GAClC,OAAO,CAAC,0BAA0B,CAAC,CAmLrC"}
|
|
@@ -80,7 +80,15 @@ const PINNED_PERMANENT_SKIP_REASONS = new Set([
|
|
|
80
80
|
]);
|
|
81
81
|
const DEFAULT_QUOTA_REMAINING_THRESHOLD = 10;
|
|
82
82
|
/** @internal Stable identity key for in-memory quota snapshots across reloads. */
|
|
83
|
-
|
|
83
|
+
/**
|
|
84
|
+
* Quota-scheduler key prefix identifying ONE account across every family and
|
|
85
|
+
* model key it owns.
|
|
86
|
+
*
|
|
87
|
+
* The trailing separator is part of the contract: without it the prefix
|
|
88
|
+
* `account:email:foo` also matches `account:email:foobar:codex`, so clearing
|
|
89
|
+
* one account's observations would silently clear a neighbour's.
|
|
90
|
+
*/
|
|
91
|
+
export function buildQuotaScheduleAccountPrefix(account) {
|
|
84
92
|
const emailKey = normalizeEmailKey(account.email);
|
|
85
93
|
const accountId = account.accountId?.trim();
|
|
86
94
|
const refreshToken = account.refreshToken?.trim() ?? "";
|
|
@@ -97,7 +105,10 @@ export function buildQuotaScheduleKey(account, family, model) {
|
|
|
97
105
|
: accountId
|
|
98
106
|
? `id:${accountId}${recordDiscriminator}`
|
|
99
107
|
: `refresh:${createHash("sha256").update(refreshToken).digest("hex")}${recordDiscriminator}`;
|
|
100
|
-
return `account:${accountIdentity}
|
|
108
|
+
return `account:${accountIdentity}:`;
|
|
109
|
+
}
|
|
110
|
+
export function buildQuotaScheduleKey(account, family, model) {
|
|
111
|
+
return `${buildQuotaScheduleAccountPrefix(account)}${model ?? family}`;
|
|
101
112
|
}
|
|
102
113
|
const DEFAULT_MAX_RUNTIME_ACCOUNT_ATTEMPTS = 4;
|
|
103
114
|
// This is a hard safety ceiling over every pinned selection pass, including
|
|
@@ -862,7 +873,37 @@ async function handleRequestInner(state, req, res, traceId) {
|
|
|
862
873
|
// otherwise glue an in-flight chat thread to the previously selected
|
|
863
874
|
// account. The proxy itself never bumps the generation, so its own
|
|
864
875
|
// debounced disk writes do not clear affinity. See issue #474.
|
|
865
|
-
|
|
876
|
+
/** Reconcile once before selection or recording a new upstream observation. */
|
|
877
|
+
const reconcileManualSelection = () => {
|
|
878
|
+
const meta = readStorageMetaFromDisk();
|
|
879
|
+
for (const manager of state.knownAccountManagers) {
|
|
880
|
+
manager.applyManualSelection(meta);
|
|
881
|
+
}
|
|
882
|
+
if (meta.affinityGeneration > state.lastObservedAffinityGeneration) {
|
|
883
|
+
const switchedAccount = meta.pinnedAccountIndex === null
|
|
884
|
+
? null
|
|
885
|
+
: accountManager.getAccountByIndex(meta.pinnedAccountIndex);
|
|
886
|
+
if (switchedAccount) {
|
|
887
|
+
state.preemptiveQuotaScheduler.clearByPrefix(buildQuotaScheduleAccountPrefix(switchedAccount));
|
|
888
|
+
}
|
|
889
|
+
else if (meta.pinnedAccountIndex !== null) {
|
|
890
|
+
// A pin we cannot resolve: this long-lived proxy re-reads only
|
|
891
|
+
// pin/gen, never the account list, so a `login` that appended an
|
|
892
|
+
// account before the `switch` leaves the new index out of range
|
|
893
|
+
// here. The generation only bumps on the NEXT user-initiated
|
|
894
|
+
// switch, so skipping the clear and advancing anyway would strand
|
|
895
|
+
// the pre-switch quota observation forever, which is the exact
|
|
896
|
+
// deferral this reconciliation exists to end. Drop every cached
|
|
897
|
+
// observation instead: it only costs a re-probe, and real 429
|
|
898
|
+
// windows live on the accounts themselves, not in this cache.
|
|
899
|
+
state.preemptiveQuotaScheduler.clearAll();
|
|
900
|
+
}
|
|
901
|
+
state.sessionAffinityStore?.clearAll();
|
|
902
|
+
state.lastObservedAffinityGeneration = meta.affinityGeneration;
|
|
903
|
+
}
|
|
904
|
+
return meta;
|
|
905
|
+
};
|
|
906
|
+
const storageMeta = reconcileManualSelection();
|
|
866
907
|
// The ephemeral --account pin (issue #623) takes precedence over the
|
|
867
908
|
// persisted `switch` pin for this invocation, without ever mutating disk
|
|
868
909
|
// state. Use `??` (not `||`) so a forced index of 0 is honored. When set,
|
|
@@ -899,10 +940,6 @@ async function handleRequestInner(state, req, res, traceId) {
|
|
|
899
940
|
if (isPinned) {
|
|
900
941
|
transientAttemptLimit = Math.max(1, Math.min(state.maxRuntimeAccountAttempts, MAX_PINNED_TRANSIENT_ATTEMPTS));
|
|
901
942
|
}
|
|
902
|
-
if (storageMeta.affinityGeneration > state.lastObservedAffinityGeneration) {
|
|
903
|
-
state.sessionAffinityStore?.clearAll();
|
|
904
|
-
state.lastObservedAffinityGeneration = storageMeta.affinityGeneration;
|
|
905
|
-
}
|
|
906
943
|
let runtimeSelectionIterations = 0;
|
|
907
944
|
while ((isPinned || attemptedIndexes.size < accountCount) &&
|
|
908
945
|
transientAttempts < transientAttemptLimit &&
|
|
@@ -1153,6 +1190,7 @@ async function handleRequestInner(state, req, res, traceId) {
|
|
|
1153
1190
|
noteRotation();
|
|
1154
1191
|
continue;
|
|
1155
1192
|
}
|
|
1193
|
+
reconcileManualSelection();
|
|
1156
1194
|
const quotaSnapshot = readQuotaSchedulerSnapshot(upstream.headers, upstream.status, state.now());
|
|
1157
1195
|
if (quotaSnapshot) {
|
|
1158
1196
|
state.preemptiveQuotaScheduler.update(quotaScheduleKey, quotaSnapshot);
|
|
@@ -1162,6 +1200,8 @@ async function handleRequestInner(state, req, res, traceId) {
|
|
|
1162
1200
|
const retryAfterMs = parseRetryAfterHeaderMs(upstream.headers, state.now()) ??
|
|
1163
1201
|
parseRetryAfterBodyMs(bodyText, state.now()) ??
|
|
1164
1202
|
60_000;
|
|
1203
|
+
// Reading the body awaited I/O; a switch may have landed meanwhile.
|
|
1204
|
+
reconcileManualSelection();
|
|
1165
1205
|
state.preemptiveQuotaScheduler.markRateLimited(quotaScheduleKey, retryAfterMs, state.now());
|
|
1166
1206
|
// A 429 is the upstream quota signal for the attempted account, so
|
|
1167
1207
|
// keep the consumed runtime token drained.
|
package/dist/lib/storage.d.ts
CHANGED
|
@@ -109,9 +109,27 @@ export declare function bumpStorageAffinityGeneration(storage: {
|
|
|
109
109
|
* persisting routine state (rate-limit hits, cooldowns, etc.) so a CLI
|
|
110
110
|
* `switch`/`unpin` that landed between proxy startup and the save is not
|
|
111
111
|
* clobbered. Returns `pinnedAccountIndex: undefined` and
|
|
112
|
-
* `affinityGeneration: 0` on any failure. See issue #474.
|
|
112
|
+
* `affinityGeneration: 0` on any failure by default. See issue #474.
|
|
113
|
+
*
|
|
114
|
+
* `strict` callers additionally need to know when the metadata could not be
|
|
115
|
+
* OBSERVED AT ALL, because persisting a stale in-memory pin over a newer disk
|
|
116
|
+
* pin is exactly the #474 regression. Strict mode therefore throws for the two
|
|
117
|
+
* cases where a newer selection may be hiding behind the failure:
|
|
118
|
+
* - the file exists but cannot be read (EBUSY/EPERM/EACCES: on Windows an AV
|
|
119
|
+
* scanner or indexer can hold accounts.json open), and
|
|
120
|
+
* - the bytes are not valid JSON (a torn read of a concurrent atomic write).
|
|
121
|
+
*
|
|
122
|
+
* A MISSING file and a successfully parsed file with INVALID field values are
|
|
123
|
+
* deliberately not failures, in either mode. Neither can be concealing a newer
|
|
124
|
+
* pin (there is no file, or we can see the whole file and the field is
|
|
125
|
+
* unusable), and both are self-repaired by the very write that follows. Making
|
|
126
|
+
* them throw would wedge persistence permanently, since recreating or repairing
|
|
127
|
+
* storage goes through the same save path, and it would take every rate-limit
|
|
128
|
+
* window, cooldown and rotated refresh token in memory down with it.
|
|
113
129
|
*/
|
|
114
|
-
export declare function readPinAndGenFromDisk(path: string
|
|
130
|
+
export declare function readPinAndGenFromDisk(path: string, options?: {
|
|
131
|
+
strict?: boolean;
|
|
132
|
+
}): {
|
|
115
133
|
pinnedAccountIndex: number | undefined;
|
|
116
134
|
affinityGeneration: number;
|
|
117
135
|
};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"storage.d.ts","sourceRoot":"","sources":["../../lib/storage.ts"],"names":[],"mappings":"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
|
|
1
|
+
{"version":3,"file":"storage.d.ts","sourceRoot":"","sources":["../../lib/storage.ts"],"names":[],"mappings":"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"}
|
package/dist/lib/storage.js
CHANGED
|
@@ -898,7 +898,8 @@ export function normalizeAccountStorage(data) {
|
|
|
898
898
|
return undefined;
|
|
899
899
|
if (typeof raw !== "number" ||
|
|
900
900
|
!Number.isFinite(raw) ||
|
|
901
|
-
|
|
901
|
+
// See readAffinityGenerationFromDisk: an unsafe integer wedges the bump.
|
|
902
|
+
!Number.isSafeInteger(raw) ||
|
|
902
903
|
raw < 0) {
|
|
903
904
|
log.warn("Dropping invalid affinityGeneration from storage", {
|
|
904
905
|
value: raw,
|
|
@@ -941,7 +942,11 @@ export function readAffinityGenerationFromDisk(path) {
|
|
|
941
942
|
const generation = parsed.affinityGeneration;
|
|
942
943
|
if (typeof generation === "number" &&
|
|
943
944
|
Number.isFinite(generation) &&
|
|
944
|
-
|
|
945
|
+
// Safe, not merely integral: past 2^53 `Math.max(gen, disk) + 1 === gen`,
|
|
946
|
+
// so `bumpStorageAffinityGeneration` silently stops advancing and no
|
|
947
|
+
// running proxy ever observes another `switch`. Rejecting the value
|
|
948
|
+
// lets the next bump write 1 and repair the file.
|
|
949
|
+
Number.isSafeInteger(generation) &&
|
|
945
950
|
generation >= 0) {
|
|
946
951
|
return generation;
|
|
947
952
|
}
|
|
@@ -978,7 +983,12 @@ export function bumpStorageAffinityGeneration(storage, storagePath) {
|
|
|
978
983
|
// No resolvable storage path (never configured). The in-memory counter
|
|
979
984
|
// is still bumped below; only the lost-update guard is unavailable.
|
|
980
985
|
}
|
|
981
|
-
|
|
986
|
+
// Guard the in-memory side too, not just the disk read. Past 2^53
|
|
987
|
+
// `Math.max(gen, disk) + 1 === gen`, so an unsafe value here would write the
|
|
988
|
+
// same generation forever and no running proxy would observe another
|
|
989
|
+
// `switch`. Treating it as 0 makes the next write repair the counter.
|
|
990
|
+
const rawInMemory = storage.affinityGeneration ?? 0;
|
|
991
|
+
const inMemoryGeneration = Number.isSafeInteger(rawInMemory) && rawInMemory >= 0 ? rawInMemory : 0;
|
|
982
992
|
const next = Math.max(inMemoryGeneration, diskGeneration) + 1;
|
|
983
993
|
storage.affinityGeneration = next;
|
|
984
994
|
return next;
|
|
@@ -990,34 +1000,68 @@ export function bumpStorageAffinityGeneration(storage, storagePath) {
|
|
|
990
1000
|
* persisting routine state (rate-limit hits, cooldowns, etc.) so a CLI
|
|
991
1001
|
* `switch`/`unpin` that landed between proxy startup and the save is not
|
|
992
1002
|
* clobbered. Returns `pinnedAccountIndex: undefined` and
|
|
993
|
-
* `affinityGeneration: 0` on any failure. See issue #474.
|
|
1003
|
+
* `affinityGeneration: 0` on any failure by default. See issue #474.
|
|
1004
|
+
*
|
|
1005
|
+
* `strict` callers additionally need to know when the metadata could not be
|
|
1006
|
+
* OBSERVED AT ALL, because persisting a stale in-memory pin over a newer disk
|
|
1007
|
+
* pin is exactly the #474 regression. Strict mode therefore throws for the two
|
|
1008
|
+
* cases where a newer selection may be hiding behind the failure:
|
|
1009
|
+
* - the file exists but cannot be read (EBUSY/EPERM/EACCES: on Windows an AV
|
|
1010
|
+
* scanner or indexer can hold accounts.json open), and
|
|
1011
|
+
* - the bytes are not valid JSON (a torn read of a concurrent atomic write).
|
|
1012
|
+
*
|
|
1013
|
+
* A MISSING file and a successfully parsed file with INVALID field values are
|
|
1014
|
+
* deliberately not failures, in either mode. Neither can be concealing a newer
|
|
1015
|
+
* pin (there is no file, or we can see the whole file and the field is
|
|
1016
|
+
* unusable), and both are self-repaired by the very write that follows. Making
|
|
1017
|
+
* them throw would wedge persistence permanently, since recreating or repairing
|
|
1018
|
+
* storage goes through the same save path, and it would take every rate-limit
|
|
1019
|
+
* window, cooldown and rotated refresh token in memory down with it.
|
|
994
1020
|
*/
|
|
995
|
-
export function readPinAndGenFromDisk(path) {
|
|
1021
|
+
export function readPinAndGenFromDisk(path, options) {
|
|
1022
|
+
const unselected = {
|
|
1023
|
+
pinnedAccountIndex: undefined,
|
|
1024
|
+
affinityGeneration: 0,
|
|
1025
|
+
};
|
|
996
1026
|
if (!existsSync(path)) {
|
|
997
|
-
return {
|
|
1027
|
+
return { ...unselected };
|
|
998
1028
|
}
|
|
1029
|
+
let parsed;
|
|
999
1030
|
try {
|
|
1000
|
-
|
|
1001
|
-
const parsed = JSON.parse(bytes.toString("utf8"));
|
|
1002
|
-
const rawPin = parsed.pinnedAccountIndex;
|
|
1003
|
-
const pinnedAccountIndex = typeof rawPin === "number" &&
|
|
1004
|
-
Number.isFinite(rawPin) &&
|
|
1005
|
-
Number.isInteger(rawPin) &&
|
|
1006
|
-
rawPin >= 0
|
|
1007
|
-
? rawPin
|
|
1008
|
-
: undefined;
|
|
1009
|
-
const rawGen = parsed.affinityGeneration;
|
|
1010
|
-
const affinityGeneration = typeof rawGen === "number" &&
|
|
1011
|
-
Number.isFinite(rawGen) &&
|
|
1012
|
-
Number.isInteger(rawGen) &&
|
|
1013
|
-
rawGen >= 0
|
|
1014
|
-
? rawGen
|
|
1015
|
-
: 0;
|
|
1016
|
-
return { pinnedAccountIndex, affinityGeneration };
|
|
1031
|
+
parsed = JSON.parse(readFileSync(path, "utf8"));
|
|
1017
1032
|
}
|
|
1018
|
-
catch {
|
|
1019
|
-
|
|
1033
|
+
catch (error) {
|
|
1034
|
+
// The file was deleted or renamed between existsSync and the read; same
|
|
1035
|
+
// reasoning as the missing-file branch above.
|
|
1036
|
+
if (error.code === "ENOENT") {
|
|
1037
|
+
return { ...unselected };
|
|
1038
|
+
}
|
|
1039
|
+
if (options?.strict) {
|
|
1040
|
+
throw new Error("Unable to read account selection metadata", {
|
|
1041
|
+
cause: error,
|
|
1042
|
+
});
|
|
1043
|
+
}
|
|
1044
|
+
return { ...unselected };
|
|
1045
|
+
}
|
|
1046
|
+
if (!isRecord(parsed)) {
|
|
1047
|
+
return { ...unselected };
|
|
1020
1048
|
}
|
|
1049
|
+
const rawPin = parsed.pinnedAccountIndex;
|
|
1050
|
+
const pinnedAccountIndex = typeof rawPin === "number" &&
|
|
1051
|
+
Number.isFinite(rawPin) &&
|
|
1052
|
+
Number.isInteger(rawPin) &&
|
|
1053
|
+
rawPin >= 0
|
|
1054
|
+
? rawPin
|
|
1055
|
+
: undefined;
|
|
1056
|
+
const rawGen = parsed.affinityGeneration;
|
|
1057
|
+
const affinityGeneration = typeof rawGen === "number" &&
|
|
1058
|
+
Number.isFinite(rawGen) &&
|
|
1059
|
+
// See readAffinityGenerationFromDisk: an unsafe integer wedges the bump.
|
|
1060
|
+
Number.isSafeInteger(rawGen) &&
|
|
1061
|
+
rawGen >= 0
|
|
1062
|
+
? rawGen
|
|
1063
|
+
: 0;
|
|
1064
|
+
return { pinnedAccountIndex, affinityGeneration };
|
|
1021
1065
|
}
|
|
1022
1066
|
/**
|
|
1023
1067
|
* Loads OAuth accounts from disk storage.
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type
|
|
1
|
+
import { type UsageLedgerAppendInput, type UsageLedgerPaths, type UsageLedgerQuery, type UsageLedgerRow, type UsageSummary, type UsageSummaryQuery } from "./types.js";
|
|
2
2
|
export declare function getUsageLedgerPaths(): UsageLedgerPaths;
|
|
3
3
|
export declare function appendUsageLedgerRow(input: UsageLedgerAppendInput): Promise<UsageLedgerRow>;
|
|
4
4
|
export declare function readUsageLedgerRows(query?: UsageLedgerQuery): Promise<UsageLedgerRow[]>;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ledger.d.ts","sourceRoot":"","sources":["../../../lib/usage/ledger.ts"],"names":[],"mappings":"AASA,OAAO,KAAK,
|
|
1
|
+
{"version":3,"file":"ledger.d.ts","sourceRoot":"","sources":["../../../lib/usage/ledger.ts"],"names":[],"mappings":"AASA,OAAO,EAEN,KAAK,sBAAsB,EAE3B,KAAK,gBAAgB,EACrB,KAAK,gBAAgB,EAErB,KAAK,cAAc,EAEnB,KAAK,YAAY,EAGjB,KAAK,iBAAiB,EAEtB,MAAM,YAAY,CAAC;AAqOpB,wBAAgB,mBAAmB,IAAI,gBAAgB,CAMtD;AAED,wBAAsB,oBAAoB,CACzC,KAAK,EAAE,sBAAsB,GAC3B,OAAO,CAAC,cAAc,CAAC,CASzB;AAuKD,wBAAsB,mBAAmB,CACxC,KAAK,GAAE,gBAAqB,GAC1B,OAAO,CAAC,cAAc,EAAE,CAAC,CAc3B;AAuDD,wBAAgB,kBAAkB,CACjC,IAAI,EAAE,cAAc,EAAE,EACtB,KAAK,GAAE,iBAAsB,GAC3B,YAAY,CAwBd;AAED,wBAAsB,oBAAoB,CACzC,KAAK,GAAE,iBAAsB,GAC3B,OAAO,CAAC,YAAY,CAAC,CAEvB;AAED,wBAAsB,iBAAiB,CAAC,OAAO,GAAE;IAChD,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,iBAAiB,CAAC,EAAE,MAAM,CAAC;CACtB,GAAG,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CA2B9B;AAED,wBAAgB,6BAA6B,IAAI,IAAI,CAEpD"}
|
package/dist/lib/usage/ledger.js
CHANGED
|
@@ -4,6 +4,7 @@ import { getCodexMultiAuthDir } from "../runtime-paths.js";
|
|
|
4
4
|
import { logWarn } from "../logger.js";
|
|
5
5
|
import { isRecord, sleep } from "../utils.js";
|
|
6
6
|
import { normalizeUsageLedgerRow, usageRowToJsonLine, } from "./redaction.js";
|
|
7
|
+
import { isKnownServiceTier, } from "./types.js";
|
|
7
8
|
const USAGE_DIR_NAME = "usage";
|
|
8
9
|
const USAGE_LEDGER_FILE_NAME = "usage-ledger.jsonl";
|
|
9
10
|
const RETRYABLE_FS_CODES = new Set(["EBUSY", "EPERM"]);
|
|
@@ -287,6 +288,14 @@ function normalizeParsedUsageRow(value) {
|
|
|
287
288
|
Number.isFinite(value.tokens.totalTokens)
|
|
288
289
|
? Math.max(0, Math.trunc(value.tokens.totalTokens))
|
|
289
290
|
: 0,
|
|
291
|
+
// Validated against the union rather than passed through: the file is
|
|
292
|
+
// on disk and can be edited, and an unrecognised string would reach the
|
|
293
|
+
// pricer as a tier it has no rate for. Rebuilding only the numeric
|
|
294
|
+
// fields dropped this entirely, so a persisted Fast row read back as
|
|
295
|
+
// standard in `usage` reports.
|
|
296
|
+
...(isKnownServiceTier(value.tokens.serviceTier)
|
|
297
|
+
? { serviceTier: value.tokens.serviceTier }
|
|
298
|
+
: {}),
|
|
290
299
|
};
|
|
291
300
|
const account = isRecord(value.account)
|
|
292
301
|
? {
|
|
@@ -1,9 +1,24 @@
|
|
|
1
|
-
import type { UsageTokenCounts } from "./types.js";
|
|
1
|
+
import type { UsageServiceTier, UsageTokenCounts } from "./types.js";
|
|
2
2
|
export interface UsageModelPricing {
|
|
3
3
|
inputUsdPerMillion: number;
|
|
4
4
|
outputUsdPerMillion: number;
|
|
5
5
|
cachedInputUsdPerMillion?: number;
|
|
6
6
|
reasoningUsdPerMillion?: number;
|
|
7
|
+
/**
|
|
8
|
+
* Rates for non-standard service tiers, keyed by `UsageServiceTier`.
|
|
9
|
+
*
|
|
10
|
+
* Every entry in `MODEL_PRICING` is a STANDARD-tier rate. OpenAI's Fast tier
|
|
11
|
+
* costs more (2x for GPT-6 Astra), so pricing a Fast session off the standard
|
|
12
|
+
* row under-counts it by half and lets a `maxCostUsd` cap overrun.
|
|
13
|
+
*
|
|
14
|
+
* A tier absent from this map is deliberately NOT approximated from the
|
|
15
|
+
* standard rate. Only Astra's Fast multiplier is published; inventing one for
|
|
16
|
+
* the rest would move a budget's trip point on a guess, which is the failure
|
|
17
|
+
* this file exists to avoid. `estimateUsageCostUsd` reports an unlisted tier
|
|
18
|
+
* as unknown cost instead, so a budget fails closed the same way it does for
|
|
19
|
+
* an unpriced model.
|
|
20
|
+
*/
|
|
21
|
+
serviceTiers?: Partial<Record<UsageServiceTier, UsageModelPricing>>;
|
|
7
22
|
}
|
|
8
23
|
/**
|
|
9
24
|
* Models the router can normalize to that have no published rate here yet.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"pricing.d.ts","sourceRoot":"","sources":["../../../lib/usage/pricing.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,YAAY,CAAC;
|
|
1
|
+
{"version":3,"file":"pricing.d.ts","sourceRoot":"","sources":["../../../lib/usage/pricing.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,gBAAgB,EAAE,gBAAgB,EAAE,MAAM,YAAY,CAAC;AAErE,MAAM,WAAW,iBAAiB;IACjC,kBAAkB,EAAE,MAAM,CAAC;IAC3B,mBAAmB,EAAE,MAAM,CAAC;IAC5B,wBAAwB,CAAC,EAAE,MAAM,CAAC;IAClC,sBAAsB,CAAC,EAAE,MAAM,CAAC;IAChC;;;;;;;;;;;;;OAaG;IACH,YAAY,CAAC,EAAE,OAAO,CAAC,MAAM,CAAC,gBAAgB,EAAE,iBAAiB,CAAC,CAAC,CAAC;CACpE;AAyFD;;;;;;;;;;;;;GAaG;AACH,eAAO,MAAM,wBAAwB,0MAkB3B,CAAC;AAOX,wBAAgB,oBAAoB,CACnC,KAAK,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,GAC9B,iBAAiB,GAAG,IAAI,CAiB1B;AAmBD,wBAAgB,oBAAoB,CACnC,KAAK,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,EAChC,MAAM,EAAE,gBAAgB,GACtB,MAAM,GAAG,IAAI,CA8Bf;AAED,wBAAgB,qBAAqB,IAAI,MAAM,CAAC,MAAM,EAAE,iBAAiB,CAAC,CAEzE"}
|
|
@@ -1,16 +1,33 @@
|
|
|
1
1
|
const MODEL_PRICING = {
|
|
2
2
|
// GPT-6 Astra, published at the 2026-09-03 launch: $10 / 1M input,
|
|
3
|
-
// $50 / 1M output on the standard service tier
|
|
4
|
-
//
|
|
5
|
-
//
|
|
6
|
-
// input rate
|
|
7
|
-
//
|
|
8
|
-
//
|
|
9
|
-
//
|
|
3
|
+
// $50 / 1M output on the standard service tier, and $20 / $100 on Fast,
|
|
4
|
+
// carried in `serviceTiers` below.
|
|
5
|
+
//
|
|
6
|
+
// The cached-input rate is the platform-wide 90% cached discount, which every
|
|
7
|
+
// other row in this table already encodes at exactly input/10. It shipped
|
|
8
|
+
// absent at first, on the reasoning that no Astra-specific cached figure was
|
|
9
|
+
// published; that made Astra the only model billing cached tokens at the FULL
|
|
10
|
+
// input rate, over-stating a cache-heavy session tenfold and tripping a
|
|
11
|
+
// `maxCostUsd` cap far too early. Over-stating is the safer direction than
|
|
12
|
+
// under-stating, but a 10x error blocks legitimate work, and the discount is
|
|
13
|
+
// a uniform platform rate rather than a per-model guess.
|
|
10
14
|
"gpt-6-astra": {
|
|
11
15
|
inputUsdPerMillion: 10,
|
|
12
16
|
outputUsdPerMillion: 50,
|
|
17
|
+
cachedInputUsdPerMillion: 1,
|
|
13
18
|
reasoningUsdPerMillion: 50,
|
|
19
|
+
serviceTiers: {
|
|
20
|
+
// Published at launch alongside the standard rate: Fast mode is up to
|
|
21
|
+
// 2.5x the speed at 2x the price, $20 / $100 per 1M. This is the only
|
|
22
|
+
// tier multiplier OpenAI has published for any model in this table,
|
|
23
|
+
// which is why it is the only one listed anywhere in this file.
|
|
24
|
+
priority: {
|
|
25
|
+
inputUsdPerMillion: 20,
|
|
26
|
+
outputUsdPerMillion: 100,
|
|
27
|
+
cachedInputUsdPerMillion: 2,
|
|
28
|
+
reasoningUsdPerMillion: 100,
|
|
29
|
+
},
|
|
30
|
+
},
|
|
14
31
|
},
|
|
15
32
|
"gpt-5-codex": {
|
|
16
33
|
inputUsdPerMillion: 1.25,
|
|
@@ -122,8 +139,29 @@ export function getUsageModelPricing(model) {
|
|
|
122
139
|
}
|
|
123
140
|
return MODEL_PRICING[normalized] ?? null;
|
|
124
141
|
}
|
|
142
|
+
/**
|
|
143
|
+
* Pick the rate that applies to a response's service tier.
|
|
144
|
+
*
|
|
145
|
+
* Returns `null` when the tier is real but this table has no rate for it, which
|
|
146
|
+
* the caller turns into an unknown cost. `standard` and an absent tier both use
|
|
147
|
+
* the base row, because every entry in `MODEL_PRICING` is a standard-tier rate.
|
|
148
|
+
*/
|
|
149
|
+
function resolveServiceTierPricing(pricing, serviceTier) {
|
|
150
|
+
if (!serviceTier || serviceTier === "standard") {
|
|
151
|
+
return pricing;
|
|
152
|
+
}
|
|
153
|
+
return pricing.serviceTiers?.[serviceTier] ?? null;
|
|
154
|
+
}
|
|
125
155
|
export function estimateUsageCostUsd(model, tokens) {
|
|
126
|
-
const
|
|
156
|
+
const basePricing = getUsageModelPricing(model);
|
|
157
|
+
if (!basePricing) {
|
|
158
|
+
return null;
|
|
159
|
+
}
|
|
160
|
+
// Resolve the tier BEFORE any arithmetic. A response billed at a tier this
|
|
161
|
+
// table has no rate for must report unknown cost, not a standard-tier
|
|
162
|
+
// figure: under-counting is what lets a `maxCostUsd` cap overrun, and
|
|
163
|
+
// `evaluateBudgetGuard` already knows how to fail closed on `null`.
|
|
164
|
+
const pricing = resolveServiceTierPricing(basePricing, tokens.serviceTier);
|
|
127
165
|
if (!pricing) {
|
|
128
166
|
return null;
|
|
129
167
|
}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type
|
|
1
|
+
import { type UsageLedgerAccountRef, type UsageLedgerAppendInput, type UsageLedgerRow } from "./types.js";
|
|
2
2
|
export declare function hashUsageIdentifier(value: string): string;
|
|
3
3
|
export declare function createUsageAccountRef(input: {
|
|
4
4
|
accountId?: string | null;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"redaction.d.ts","sourceRoot":"","sources":["../../../lib/usage/redaction.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,
|
|
1
|
+
{"version":3,"file":"redaction.d.ts","sourceRoot":"","sources":["../../../lib/usage/redaction.ts"],"names":[],"mappings":"AACA,OAAO,EAEN,KAAK,qBAAqB,EAC1B,KAAK,sBAAsB,EAG3B,KAAK,cAAc,EAGnB,MAAM,YAAY,CAAC;AA2EpB,wBAAgB,mBAAmB,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAEzD;AAED,wBAAgB,qBAAqB,CAAC,KAAK,EAAE;IAC5C,SAAS,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC1B,KAAK,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACtB,YAAY,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;CAC7B,GAAG,qBAAqB,GAAG,IAAI,CAkB/B;AAkCD,wBAAgB,uBAAuB,CACtC,KAAK,EAAE,sBAAsB,GAC3B,cAAc,CA0BhB;AAED,wBAAgB,kBAAkB,CAAC,GAAG,EAAE,cAAc,GAAG,MAAM,CAE9D"}
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { createHash, randomUUID } from "node:crypto";
|
|
2
|
+
import { isKnownServiceTier, } from "./types.js";
|
|
2
3
|
import { estimateUsageCostUsd } from "./pricing.js";
|
|
3
4
|
const VALID_SOURCES = new Set([
|
|
4
5
|
"runtime-proxy",
|
|
@@ -98,6 +99,18 @@ function normalizeTokens(input) {
|
|
|
98
99
|
totalTokens: providedTotal === null
|
|
99
100
|
? computedTotal
|
|
100
101
|
: Math.max(0, Math.trunc(providedTotal)),
|
|
102
|
+
// Carried through so `estimateUsageCostUsd` below can refuse to price a
|
|
103
|
+
// tier it has no rate for. Dropping it here would silently restore the
|
|
104
|
+
// standard-rate under-count this field exists to prevent.
|
|
105
|
+
//
|
|
106
|
+
// Validated, not passed through on truthiness. Every other field in this
|
|
107
|
+
// normaliser is checked against its allowed set (`normalizeSource`,
|
|
108
|
+
// `normalizeOperation`, `normalizeOutcome`), and the ledger READ path
|
|
109
|
+
// already rejects an unknown tier. Accepting one here made the write
|
|
110
|
+
// path the only unvalidated way onto a row.
|
|
111
|
+
...(isKnownServiceTier(input.serviceTier)
|
|
112
|
+
? { serviceTier: input.serviceTier }
|
|
113
|
+
: {}),
|
|
101
114
|
};
|
|
102
115
|
}
|
|
103
116
|
export function normalizeUsageLedgerRow(input) {
|
|
@@ -1,12 +1,40 @@
|
|
|
1
1
|
export type UsageLedgerSource = "runtime-proxy" | "plugin-host" | "local-bridge" | "cli" | "unknown";
|
|
2
2
|
export type UsageLedgerOperation = "responses" | "models" | "thread-goal" | "auth-refresh" | "diagnostic" | "unknown";
|
|
3
3
|
export type UsageLedgerOutcome = "success" | "failure" | "blocked" | "cancelled";
|
|
4
|
+
/**
|
|
5
|
+
* The service tier a response was actually billed at.
|
|
6
|
+
*
|
|
7
|
+
* OpenAI's Fast/priority tier costs more than standard (2x for GPT-6 Astra), so
|
|
8
|
+
* a rate table with no tier dimension under-counts such a session. `standard`
|
|
9
|
+
* and `default` are the same thing on the wire; anything this union does not
|
|
10
|
+
* name is normalised to `unknown`, which is treated as unpriced rather than
|
|
11
|
+
* assumed cheap.
|
|
12
|
+
*/
|
|
13
|
+
export declare const USAGE_SERVICE_TIERS: readonly ["standard", "priority", "flex", "batch", "scale", "unknown"];
|
|
14
|
+
export type UsageServiceTier = (typeof USAGE_SERVICE_TIERS)[number];
|
|
15
|
+
/**
|
|
16
|
+
* Narrow an unvalidated value to a known tier.
|
|
17
|
+
*
|
|
18
|
+
* The ledger is JSONL on disk and can be hand-edited, so a value read back from
|
|
19
|
+
* it is untrusted. An unrecognised string reaching the pricer would be treated
|
|
20
|
+
* as a tier with no rate and silently make every affected row unpriced.
|
|
21
|
+
*/
|
|
22
|
+
export declare function isKnownServiceTier(value: unknown): value is UsageServiceTier;
|
|
4
23
|
export interface UsageTokenCounts {
|
|
5
24
|
inputTokens: number;
|
|
6
25
|
outputTokens: number;
|
|
7
26
|
cachedInputTokens: number;
|
|
8
27
|
reasoningTokens: number;
|
|
9
28
|
totalTokens: number;
|
|
29
|
+
/**
|
|
30
|
+
* Rides on the token counts rather than a separate parameter so it reaches
|
|
31
|
+
* the ledger through every existing path: the `onUsage` callback in
|
|
32
|
+
* `response-handler.ts` carries this shape, and both the streaming scanner
|
|
33
|
+
* and the non-streaming branch already funnel through
|
|
34
|
+
* `extractResponsesUsage`. Absent when the response did not report one,
|
|
35
|
+
* which is the common case and is priced as `standard`.
|
|
36
|
+
*/
|
|
37
|
+
serviceTier?: UsageServiceTier;
|
|
10
38
|
}
|
|
11
39
|
export interface UsageLedgerAccountRef {
|
|
12
40
|
accountHash?: string;
|
|
@@ -50,6 +78,11 @@ export interface UsageLedgerAppendInput {
|
|
|
50
78
|
cachedInputTokens?: number | null;
|
|
51
79
|
reasoningTokens?: number | null;
|
|
52
80
|
totalTokens?: number | null;
|
|
81
|
+
/**
|
|
82
|
+
* The tier the response reported. Absent means standard, which is what every
|
|
83
|
+
* rate in `MODEL_PRICING` is quoted at.
|
|
84
|
+
*/
|
|
85
|
+
serviceTier?: UsageServiceTier;
|
|
53
86
|
costUsd?: number | null;
|
|
54
87
|
}
|
|
55
88
|
export type UsageSummaryGroupBy = "model" | "account" | "project" | "outcome" | "day";
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../../lib/usage/types.ts"],"names":[],"mappings":"AAAA,MAAM,MAAM,iBAAiB,GAC1B,eAAe,GACf,aAAa,GACb,cAAc,GACd,KAAK,GACL,SAAS,CAAC;AAEb,MAAM,MAAM,oBAAoB,GAC7B,WAAW,GACX,QAAQ,GACR,aAAa,GACb,cAAc,GACd,YAAY,GACZ,SAAS,CAAC;AAEb,MAAM,MAAM,kBAAkB,GAC3B,SAAS,GACT,SAAS,GACT,SAAS,GACT,WAAW,CAAC;AAEf,MAAM,WAAW,gBAAgB;IAChC,WAAW,EAAE,MAAM,CAAC;IACpB,YAAY,EAAE,MAAM,CAAC;IACrB,iBAAiB,EAAE,MAAM,CAAC;IAC1B,eAAe,EAAE,MAAM,CAAC;IACxB,WAAW,EAAE,MAAM,CAAC;
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../../lib/usage/types.ts"],"names":[],"mappings":"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"}
|
package/dist/lib/usage/types.js
CHANGED
|
@@ -1 +1,28 @@
|
|
|
1
|
-
|
|
1
|
+
/**
|
|
2
|
+
* The service tier a response was actually billed at.
|
|
3
|
+
*
|
|
4
|
+
* OpenAI's Fast/priority tier costs more than standard (2x for GPT-6 Astra), so
|
|
5
|
+
* a rate table with no tier dimension under-counts such a session. `standard`
|
|
6
|
+
* and `default` are the same thing on the wire; anything this union does not
|
|
7
|
+
* name is normalised to `unknown`, which is treated as unpriced rather than
|
|
8
|
+
* assumed cheap.
|
|
9
|
+
*/
|
|
10
|
+
export const USAGE_SERVICE_TIERS = [
|
|
11
|
+
"standard",
|
|
12
|
+
"priority",
|
|
13
|
+
"flex",
|
|
14
|
+
"batch",
|
|
15
|
+
"scale",
|
|
16
|
+
"unknown",
|
|
17
|
+
];
|
|
18
|
+
/**
|
|
19
|
+
* Narrow an unvalidated value to a known tier.
|
|
20
|
+
*
|
|
21
|
+
* The ledger is JSONL on disk and can be hand-edited, so a value read back from
|
|
22
|
+
* it is untrusted. An unrecognised string reaching the pricer would be treated
|
|
23
|
+
* as a tier with no rate and silently make every affected row unpriced.
|
|
24
|
+
*/
|
|
25
|
+
export function isKnownServiceTier(value) {
|
|
26
|
+
return (typeof value === "string" &&
|
|
27
|
+
USAGE_SERVICE_TIERS.includes(value));
|
|
28
|
+
}
|
|
@@ -17,7 +17,8 @@ import type { UsageTokenCounts } from "./types.js";
|
|
|
17
17
|
export declare function extractUsageTokenCounts(usage: unknown): UsageTokenCounts | null;
|
|
18
18
|
/**
|
|
19
19
|
* Pull the `usage` object out of a Responses payload, whether it arrived as a
|
|
20
|
-
* bare response object (non-streaming) or wrapped in a stream event envelope
|
|
20
|
+
* bare response object (non-streaming) or wrapped in a stream event envelope,
|
|
21
|
+
* and attach the tier it was billed at.
|
|
21
22
|
*/
|
|
22
23
|
export declare function extractResponsesUsage(payload: unknown): UsageTokenCounts | null;
|
|
23
24
|
export interface UsageStreamScanner {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"usage-extraction.d.ts","sourceRoot":"","sources":["../../../lib/usage/usage-extraction.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,
|
|
1
|
+
{"version":3,"file":"usage-extraction.d.ts","sourceRoot":"","sources":["../../../lib/usage/usage-extraction.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAoB,gBAAgB,EAAE,MAAM,YAAY,CAAC;AA+BrE;;;;;;;;;;;;;;GAcG;AACH,wBAAgB,uBAAuB,CACtC,KAAK,EAAE,OAAO,GACZ,gBAAgB,GAAG,IAAI,CA+BzB;AAoCD;;;;GAIG;AACH,wBAAgB,qBAAqB,CAAC,OAAO,EAAE,OAAO,GAAG,gBAAgB,GAAG,IAAI,CAa/E;AAED,MAAM,WAAW,kBAAkB;IAClC,8CAA8C;IAC9C,IAAI,EAAE,CAAC,KAAK,EAAE,UAAU,KAAK,IAAI,CAAC;IAClC,2EAA2E;IAC3E,MAAM,EAAE,MAAM,gBAAgB,GAAG,IAAI,CAAC;CACtC;AAED;;;;;;;;;GASG;AACH,wBAAgB,wBAAwB,CAAC,OAAO,EAAE;IACjD,WAAW,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;CAC5B,GAAG,kBAAkB,CA6ErB"}
|