@agent-finops/core 0.9.4 → 0.9.6
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/actionVerification.d.ts +2 -2
- package/dist/activitySnapshot.js +12 -3
- package/dist/glance.js +10 -6
- package/dist/localAgentLogs.d.ts +19 -3
- package/dist/localAgentLogs.js +112 -18
- package/dist/modelPricing.d.ts +17 -4
- package/dist/modelPricing.js +114 -22
- package/dist/projectIndexStore.d.ts +20 -18
- package/dist/qualitativeIndexCache.d.ts +18 -16
- package/dist/qualitativeIndexCache.js +5 -0
- package/package.json +1 -1
- package/dist/emailAddress.d.ts +0 -7
- package/dist/emailAddress.js +0 -16
|
@@ -673,10 +673,10 @@ declare const experimentBodySchema: z.ZodObject<{
|
|
|
673
673
|
}, z.core.$strict>>;
|
|
674
674
|
invalidation: z.ZodOptional<z.ZodObject<{
|
|
675
675
|
reason: z.ZodEnum<{
|
|
676
|
-
manual: "manual";
|
|
677
676
|
scope_changed: "scope_changed";
|
|
678
677
|
source_semantics_changed: "source_semantics_changed";
|
|
679
678
|
concurrent_change: "concurrent_change";
|
|
679
|
+
manual: "manual";
|
|
680
680
|
}>;
|
|
681
681
|
invalidatedAt: z.ZodPipe<z.ZodString, z.ZodTransform<string, string>>;
|
|
682
682
|
}, z.core.$strict>>;
|
|
@@ -1115,10 +1115,10 @@ declare const experimentObjectSchema: z.ZodObject<{
|
|
|
1115
1115
|
}, z.core.$strict>>;
|
|
1116
1116
|
invalidation: z.ZodOptional<z.ZodObject<{
|
|
1117
1117
|
reason: z.ZodEnum<{
|
|
1118
|
-
manual: "manual";
|
|
1119
1118
|
scope_changed: "scope_changed";
|
|
1120
1119
|
source_semantics_changed: "source_semantics_changed";
|
|
1121
1120
|
concurrent_change: "concurrent_change";
|
|
1121
|
+
manual: "manual";
|
|
1122
1122
|
}>;
|
|
1123
1123
|
invalidatedAt: z.ZodPipe<z.ZodString, z.ZodTransform<string, string>>;
|
|
1124
1124
|
}, z.core.$strict>>;
|
package/dist/activitySnapshot.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { z } from "zod";
|
|
2
2
|
import { aggregateCalls, dedupeCumulativeSessionCalls } from "./localAgentLogs.js";
|
|
3
3
|
import { localAgentFormatDescriptors } from "./localAgentFormats/registry.js";
|
|
4
|
-
import { canPriceTokenUsageAtScope,
|
|
4
|
+
import { canPriceTokenUsageAtScope, estimateTokenCostsUsd, PRICING_TABLE_AS_OF } from "./modelPricing.js";
|
|
5
5
|
import { subscriptionPlans } from "./planMath.js";
|
|
6
6
|
import { isBundledSampleUsage } from "./schema.js";
|
|
7
7
|
import { sourceValidationCoverageValues } from "./sourceStatus.js";
|
|
@@ -937,13 +937,22 @@ function apiEquivalentObservations(records, calls, trustedProviderIds) {
|
|
|
937
937
|
}
|
|
938
938
|
return observations;
|
|
939
939
|
}
|
|
940
|
+
/**
|
|
941
|
+
* One call's API-equivalent cost with its tier taken from the largest single
|
|
942
|
+
* request it contains, matching the report's aggregation. Weighting a
|
|
943
|
+
* session-cumulative slice at its own cache-inflated prompt would put it on the
|
|
944
|
+
* wrong tier and skew the allocation.
|
|
945
|
+
*/
|
|
946
|
+
function callAmountUsd(call) {
|
|
947
|
+
return estimateTokenCostsUsd(call.model, [call.usage], [call.maxRequestPromptTokens]);
|
|
948
|
+
}
|
|
940
949
|
function allocateAggregateAmount(amountUsd, calls) {
|
|
941
950
|
if (amountUsd === null)
|
|
942
951
|
return calls.map(() => null);
|
|
943
|
-
const priceable = calls.map((call) => canPriceTokenUsageAtScope(call.model, call.usage, call.usageScope === "turn" ? "request" : "aggregate") &&
|
|
952
|
+
const priceable = calls.map((call) => canPriceTokenUsageAtScope(call.model, call.usage, call.usageScope === "turn" ? "request" : "aggregate", call.maxRequestPromptTokens) && callAmountUsd(call) !== undefined);
|
|
944
953
|
if (priceable.some((supported) => !supported))
|
|
945
954
|
return calls.map(() => null);
|
|
946
|
-
const weights = calls.map((call) =>
|
|
955
|
+
const weights = calls.map((call) => callAmountUsd(call) ?? 0);
|
|
947
956
|
const totalWeight = weights.reduce((sum, weight) => sum + weight, 0);
|
|
948
957
|
if (totalWeight <= 0) {
|
|
949
958
|
return amountUsd === 0 ? calls.map(() => 0) : calls.map(() => null);
|
package/dist/glance.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { dedupeCumulativeSessionCalls, sanitizeLocalActivityText } from "./localAgentLogs.js";
|
|
2
|
-
import { canPriceTokenUsageAtScope,
|
|
2
|
+
import { canPriceTokenUsageAtScope, estimateTokenCostsUsd, PRICING_TABLE_AS_OF } from "./modelPricing.js";
|
|
3
3
|
import { subscriptionPlans } from "./planMath.js";
|
|
4
4
|
import { buildContextHealth } from "./contextHealth.js";
|
|
5
5
|
import { localAgentFormatDescriptors, localAgentFormatSupports } from "./localAgentFormats/registry.js";
|
|
@@ -106,7 +106,7 @@ export function buildUsageGlance(calls, options = {}) {
|
|
|
106
106
|
"Claude Code transcripts do not report plan headroom. Missing limits remain unavailable instead of being inferred.",
|
|
107
107
|
"Cursor and GitHub Copilot require their provider connections because their local chat stores are not treated as authoritative billing transcripts.",
|
|
108
108
|
...(qualitativeComplete ? [] : [
|
|
109
|
-
"Main focus, anomaly, and context-change handoff are unavailable because
|
|
109
|
+
"Main focus, anomaly, and context-change handoff are unavailable because some session transcripts have not been read yet; no global driver was inferred from a partly-read subset."
|
|
110
110
|
])
|
|
111
111
|
];
|
|
112
112
|
return {
|
|
@@ -202,10 +202,10 @@ function buildCoverageLimitedPrimaryAction(input) {
|
|
|
202
202
|
kind: "session_handoff",
|
|
203
203
|
intent: "inspect_current_work",
|
|
204
204
|
label: project ? `Refresh evidence · ${project}` : "Refresh evidence",
|
|
205
|
-
detail: `Main focus unavailable ·
|
|
205
|
+
detail: `Main focus unavailable · session transcripts ${status === "partial" ? "only partly read" : "not available"}`,
|
|
206
206
|
...(project ? { project } : {}),
|
|
207
207
|
agentPrompt: [
|
|
208
|
-
"
|
|
208
|
+
"Some coding-agent session transcripts have not been read yet.",
|
|
209
209
|
"Do not infer a global main focus, waste cause, or context change from the selected subset.",
|
|
210
210
|
`Run \`${aibillImproveCommandV0()}\` from the exact project root to refresh the private index, then review the new evidence before editing.`
|
|
211
211
|
].join("\n"),
|
|
@@ -793,9 +793,13 @@ function limitActionName(limit) {
|
|
|
793
793
|
function callCost(call) {
|
|
794
794
|
if (call.usageSupport === "unsupported_token_shape")
|
|
795
795
|
return undefined;
|
|
796
|
-
if (!canPriceTokenUsageAtScope(call.model, call.usage, call.usageScope === "turn" ? "request" : "aggregate"))
|
|
796
|
+
if (!canPriceTokenUsageAtScope(call.model, call.usage, call.usageScope === "turn" ? "request" : "aggregate", call.maxRequestPromptTokens))
|
|
797
797
|
return undefined;
|
|
798
|
-
|
|
798
|
+
// Tier must come from the largest single request, exactly as the report's
|
|
799
|
+
// aggregation does — otherwise the statusline and the receipt disagree on
|
|
800
|
+
// the same session (a cache-heavy Codex session voided here while the
|
|
801
|
+
// receipt prices it, or priced here at 2x).
|
|
802
|
+
return estimateTokenCostsUsd(call.model, [call.usage], [call.maxRequestPromptTokens]);
|
|
799
803
|
}
|
|
800
804
|
function inputSideTokens(call) {
|
|
801
805
|
return call.usage.inputTokens +
|
package/dist/localAgentLogs.d.ts
CHANGED
|
@@ -49,6 +49,16 @@ export type LocalAgentCall = {
|
|
|
49
49
|
latestTurnUsage?: LocalAgentTurnUsage;
|
|
50
50
|
/** Whether `usage` is one model turn or the session's cumulative financial total. */
|
|
51
51
|
usageScope?: "turn" | "session_cumulative";
|
|
52
|
+
/**
|
|
53
|
+
* Largest single-request prompt (effective input, cache reads included)
|
|
54
|
+
* observed within a `session_cumulative` `usage`. Tiered per-request pricing
|
|
55
|
+
* is selected per request, never from a cumulative sum: a cache-heavy session
|
|
56
|
+
* routinely clears a per-request tier threshold in aggregate while no single
|
|
57
|
+
* request did. This evidence lets pricing keep such a total on the base tier
|
|
58
|
+
* (exact) instead of failing closed to "missing". Absent for turn-scoped
|
|
59
|
+
* calls, which are already a single request.
|
|
60
|
+
*/
|
|
61
|
+
maxRequestPromptTokens?: number;
|
|
52
62
|
/**
|
|
53
63
|
* Whether the transcript exposed the input/output components required for
|
|
54
64
|
* pricing. A total-only snapshot is still usage evidence, but pricing it as
|
|
@@ -374,7 +384,7 @@ export type LocalAgentStreamCheckpointAdapter = {
|
|
|
374
384
|
writeStreamCheckpoint: (agent: LocalAgentFormatId, pathHash: string, checkpoint: Readonly<LocalAgentStreamCheckpointRecord>) => Promise<void>;
|
|
375
385
|
deleteStreamCheckpoint: (agent: LocalAgentFormatId, pathHash: string) => Promise<void>;
|
|
376
386
|
};
|
|
377
|
-
export declare const localAgentFinancialParserVersion =
|
|
387
|
+
export declare const localAgentFinancialParserVersion = 3;
|
|
378
388
|
/**
|
|
379
389
|
* Qualitative parser contract version. Bumped to 2 with the checkpointed
|
|
380
390
|
* streaming path (A4b): entries and checkpoints written by the pre-streaming
|
|
@@ -385,9 +395,15 @@ export declare const localAgentFinancialParserVersion = 1;
|
|
|
385
395
|
* cross-file completion evidence (`subagentCompletions`, from both Task tool
|
|
386
396
|
* results and background task-notifications): entries persisted by the
|
|
387
397
|
* collapsing parser must re-parse rather than silently keep merging subagent
|
|
388
|
-
* runs into their parent session.
|
|
398
|
+
* runs into their parent session. Bumped to 5 when Codex reducer checkpoints
|
|
399
|
+
* gained `maxTurnPromptTokens` (largest single request): a checkpoint written
|
|
400
|
+
* by v4 lacks the running per-request maximum, so restoring it could under-read
|
|
401
|
+
* the tier evidence for a cumulative session that crossed the boundary — a
|
|
402
|
+
* version mismatch discards it and re-parses from scratch instead. Bumped to 6
|
|
403
|
+
* with the user-fork inherited-baseline fix: v5 entries and checkpoints treated
|
|
404
|
+
* a fork's replayed parent history as the child's own usage and activity.
|
|
389
405
|
*/
|
|
390
|
-
export declare const localAgentQualitativeParserVersion =
|
|
406
|
+
export declare const localAgentQualitativeParserVersion = 6;
|
|
391
407
|
/**
|
|
392
408
|
* Conservative launch defaults for action-capable qualitative evidence.
|
|
393
409
|
* Callers must still inspect `qualitativeCoverage` before deriving a finding:
|
package/dist/localAgentLogs.js
CHANGED
|
@@ -22,7 +22,15 @@ export function latestObservedWorkingDirectory(calls) {
|
|
|
22
22
|
.sort((left, right) => right.timestamp.localeCompare(left.timestamp))[0]
|
|
23
23
|
?.workingDirectory;
|
|
24
24
|
}
|
|
25
|
-
|
|
25
|
+
// Bumped to 2 when session-cumulative Codex calls gained `maxRequestPromptTokens`
|
|
26
|
+
// (largest single request in the session). Financial caches written by v1 lack
|
|
27
|
+
// this per-request tier evidence, so a >272K-cumulative Codex session would
|
|
28
|
+
// stay voided to "missing" on reuse; a version mismatch re-parses instead.
|
|
29
|
+
// Bumped to 3 when user forks (`forked_from_id`) started resetting their
|
|
30
|
+
// inherited baseline: v2 entries priced a fork's replayed parent history as
|
|
31
|
+
// the child's own usage, so those cached amounts are overstated and must not
|
|
32
|
+
// be reused.
|
|
33
|
+
export const localAgentFinancialParserVersion = 3;
|
|
26
34
|
/**
|
|
27
35
|
* Qualitative parser contract version. Bumped to 2 with the checkpointed
|
|
28
36
|
* streaming path (A4b): entries and checkpoints written by the pre-streaming
|
|
@@ -33,9 +41,15 @@ export const localAgentFinancialParserVersion = 1;
|
|
|
33
41
|
* cross-file completion evidence (`subagentCompletions`, from both Task tool
|
|
34
42
|
* results and background task-notifications): entries persisted by the
|
|
35
43
|
* collapsing parser must re-parse rather than silently keep merging subagent
|
|
36
|
-
* runs into their parent session.
|
|
44
|
+
* runs into their parent session. Bumped to 5 when Codex reducer checkpoints
|
|
45
|
+
* gained `maxTurnPromptTokens` (largest single request): a checkpoint written
|
|
46
|
+
* by v4 lacks the running per-request maximum, so restoring it could under-read
|
|
47
|
+
* the tier evidence for a cumulative session that crossed the boundary — a
|
|
48
|
+
* version mismatch discards it and re-parses from scratch instead. Bumped to 6
|
|
49
|
+
* with the user-fork inherited-baseline fix: v5 entries and checkpoints treated
|
|
50
|
+
* a fork's replayed parent history as the child's own usage and activity.
|
|
37
51
|
*/
|
|
38
|
-
export const localAgentQualitativeParserVersion =
|
|
52
|
+
export const localAgentQualitativeParserVersion = 6;
|
|
39
53
|
/**
|
|
40
54
|
* Conservative launch defaults for action-capable qualitative evidence.
|
|
41
55
|
* Callers must still inspect `qualitativeCoverage` before deriving a finding:
|
|
@@ -384,6 +398,42 @@ function parseCodexTurnUsage(value) {
|
|
|
384
398
|
}
|
|
385
399
|
};
|
|
386
400
|
}
|
|
401
|
+
/**
|
|
402
|
+
* The tier-relevant prompt size of one Codex `last_token_usage` turn: its full
|
|
403
|
+
* request input (Codex `input_tokens` already includes cached input), which is
|
|
404
|
+
* exactly `effectivePromptTokens` of the parsed turn usage. Returned only when
|
|
405
|
+
* the field parses to a non-negative number, so an unreadable turn never lowers
|
|
406
|
+
* a running maximum. Used to prove whether any single request in a cumulative
|
|
407
|
+
* session crossed a per-request tier threshold.
|
|
408
|
+
*/
|
|
409
|
+
function codexTurnPromptTokens(turn) {
|
|
410
|
+
const input = tokenComponentOf(turn.input_tokens);
|
|
411
|
+
return input === undefined ? undefined : input;
|
|
412
|
+
}
|
|
413
|
+
/**
|
|
414
|
+
* Whether a Codex rollout replays another session's history before its own
|
|
415
|
+
* work, so the cumulative counter at its first real task is an inherited
|
|
416
|
+
* baseline rather than this session's usage.
|
|
417
|
+
*
|
|
418
|
+
* TWO kinds of rollout do this, and only the first was recognized before:
|
|
419
|
+
* - subagent rollouts (`thread_source: "subagent"`, or a `source.subagent`);
|
|
420
|
+
* - USER FORKS (`forked_from_id`), which carry `thread_source: "user"` and
|
|
421
|
+
* replay the parent transcript verbatim. Observed: a forked rollout whose
|
|
422
|
+
* first 9,051 of 9,442 token_count events are byte-identical copies of the
|
|
423
|
+
* parent's, all with earlier parent timestamps, carrying 1,204,265,192 of
|
|
424
|
+
* its 1,256,637,395 final cumulative input tokens (95.9%) — parent usage
|
|
425
|
+
* that was being billed again under the child, and again down each fork
|
|
426
|
+
* chain.
|
|
427
|
+
*
|
|
428
|
+
* This is deliberately NOT folded into `isSubagent`: that flag also drives
|
|
429
|
+
* activity attribution and checkpoint identity, where a user fork is a normal
|
|
430
|
+
* user session and must not be relabelled a subagent.
|
|
431
|
+
*/
|
|
432
|
+
function codexHasInheritedHistory(payload) {
|
|
433
|
+
return stringOf(payload.thread_source) === "subagent" ||
|
|
434
|
+
isRecord(payload.source) && "subagent" in payload.source ||
|
|
435
|
+
stringOf(payload.forked_from_id) !== undefined;
|
|
436
|
+
}
|
|
387
437
|
/** Parse one Claude Code transcript (JSONL). Exported for tests. */
|
|
388
438
|
export function parseClaudeCodeTranscript(content, filePath = "", sinceMs, onDiagnostic) {
|
|
389
439
|
const calls = [];
|
|
@@ -634,6 +684,7 @@ function createCodexRolloutParserState() {
|
|
|
634
684
|
fileCounts: new Map(),
|
|
635
685
|
toolCallCount: 0,
|
|
636
686
|
isSubagent: false,
|
|
687
|
+
hasInheritedHistory: false,
|
|
637
688
|
malformedLines: 0
|
|
638
689
|
};
|
|
639
690
|
}
|
|
@@ -666,6 +717,7 @@ function consumeCodexRolloutLine(state, line, onEntry) {
|
|
|
666
717
|
state.rootStartedAtMs = timestampMilliseconds(payload.timestamp ?? entry.timestamp);
|
|
667
718
|
state.isSubagent = stringOf(payload.thread_source) === "subagent" ||
|
|
668
719
|
isRecord(payload.source) && "subagent" in payload.source;
|
|
720
|
+
state.hasInheritedHistory = codexHasInheritedHistory(payload);
|
|
669
721
|
state.parentSessionId = stringOf(payload.parent_thread_id);
|
|
670
722
|
}
|
|
671
723
|
if (entry.type === "turn_context" && payload) {
|
|
@@ -677,7 +729,7 @@ function consumeCodexRolloutLine(state, line, onEntry) {
|
|
|
677
729
|
state.rootCwd = stringOf(payload.cwd);
|
|
678
730
|
}
|
|
679
731
|
}
|
|
680
|
-
if (state.
|
|
732
|
+
if (state.hasInheritedHistory &&
|
|
681
733
|
!state.rootTaskStarted &&
|
|
682
734
|
payload?.type === "task_started" &&
|
|
683
735
|
isRootSpecificTaskStart(payload.started_at, state.rootStartedAtMs)) {
|
|
@@ -688,6 +740,11 @@ function consumeCodexRolloutLine(state, line, onEntry) {
|
|
|
688
740
|
// prompts/files cannot become the child's focus. Restored checkpoint
|
|
689
741
|
// evidence predating the boundary is parent history too and resets with
|
|
690
742
|
// it (the raw session cwd deliberately survives, exactly as rootCwd).
|
|
743
|
+
//
|
|
744
|
+
// Replayed task_started events keep the PARENT's original started_at, so
|
|
745
|
+
// `isRootSpecificTaskStart` rejects them and the first accepted task is
|
|
746
|
+
// this session's own — which is why the boundary lands exactly at the end
|
|
747
|
+
// of the replay.
|
|
691
748
|
state.inheritedUsageBaseline = state.lastTotal;
|
|
692
749
|
state.lastTotal = undefined;
|
|
693
750
|
state.rootTaskStarted = true;
|
|
@@ -699,10 +756,11 @@ function consumeCodexRolloutLine(state, line, onEntry) {
|
|
|
699
756
|
state.toolCallCount = 0;
|
|
700
757
|
state.model = undefined;
|
|
701
758
|
state.lastTurn = undefined;
|
|
759
|
+
state.maxTurnPromptTokens = undefined;
|
|
702
760
|
state.lastRateLimits = undefined;
|
|
703
761
|
state.lastActivityAt = toIso(stringOf(entry.timestamp)) ?? state.startedAt;
|
|
704
762
|
}
|
|
705
|
-
if (payload?.type === "task_started" && (!state.
|
|
763
|
+
if (payload?.type === "task_started" && (!state.hasInheritedHistory || state.rootTaskStarted)) {
|
|
706
764
|
state.pendingTaskTurnId = stringOf(payload.turn_id);
|
|
707
765
|
state.completedTask = undefined;
|
|
708
766
|
}
|
|
@@ -757,6 +815,10 @@ function consumeCodexRolloutLine(state, line, onEntry) {
|
|
|
757
815
|
if (turn) {
|
|
758
816
|
state.lastTurn = turn;
|
|
759
817
|
state.lastActivityAt = eventTimestamp;
|
|
818
|
+
const turnPrompt = codexTurnPromptTokens(turn);
|
|
819
|
+
if (turnPrompt !== undefined) {
|
|
820
|
+
state.maxTurnPromptTokens = Math.max(state.maxTurnPromptTokens ?? 0, turnPrompt);
|
|
821
|
+
}
|
|
760
822
|
}
|
|
761
823
|
const rateLimits = parseCodexRateLimits(payload.rate_limits, eventTimestamp);
|
|
762
824
|
if (rateLimits) {
|
|
@@ -774,7 +836,7 @@ function finishCodexRolloutParse(state, onDiagnostic) {
|
|
|
774
836
|
if (state.malformedLines > 0) {
|
|
775
837
|
onDiagnostic?.({ code: "malformed_jsonl", count: state.malformedLines });
|
|
776
838
|
}
|
|
777
|
-
if (!state.lastTotal || state.
|
|
839
|
+
if (!state.lastTotal || state.hasInheritedHistory && !state.rootTaskStarted)
|
|
778
840
|
return [];
|
|
779
841
|
const parsedUsage = parseCodexCumulativeUsage(state.lastTotal, state.inheritedUsageBaseline);
|
|
780
842
|
const parsedTurn = state.lastTurn
|
|
@@ -834,6 +896,9 @@ function finishCodexRolloutParse(state, onDiagnostic) {
|
|
|
834
896
|
: {}),
|
|
835
897
|
usageScope: "session_cumulative",
|
|
836
898
|
usageSupport,
|
|
899
|
+
...(usageSupport === "complete" && state.maxTurnPromptTokens !== undefined
|
|
900
|
+
? { maxRequestPromptTokens: state.maxTurnPromptTokens }
|
|
901
|
+
: {}),
|
|
837
902
|
...(parsedUsage.reportedTotalTokens !== undefined
|
|
838
903
|
? { reportedTotalTokens: parsedUsage.reportedTotalTokens }
|
|
839
904
|
: {}),
|
|
@@ -1999,6 +2064,7 @@ function serializeCodexReducerState(state) {
|
|
|
1999
2064
|
...(state.rootStartedAtMs !== undefined ? { rootStartedAtMs: state.rootStartedAtMs } : {}),
|
|
2000
2065
|
rootTaskStarted: state.rootTaskStarted,
|
|
2001
2066
|
isSubagent: state.isSubagent,
|
|
2067
|
+
hasInheritedHistory: state.hasInheritedHistory,
|
|
2002
2068
|
...(state.parentSessionId !== undefined ? { parentSessionId: state.parentSessionId } : {}),
|
|
2003
2069
|
...(state.pendingTaskTurnId !== undefined ? { pendingTaskTurnId: state.pendingTaskTurnId } : {}),
|
|
2004
2070
|
...(state.completedTask !== undefined ? { completedTask: state.completedTask } : {}),
|
|
@@ -2006,6 +2072,9 @@ function serializeCodexReducerState(state) {
|
|
|
2006
2072
|
...(state.lastActivityAt !== undefined ? { lastActivityAt: state.lastActivityAt } : {}),
|
|
2007
2073
|
...(state.lastTotal !== undefined ? { lastTotal: state.lastTotal } : {}),
|
|
2008
2074
|
...(state.lastTurn !== undefined ? { lastTurn: state.lastTurn } : {}),
|
|
2075
|
+
...(state.maxTurnPromptTokens !== undefined
|
|
2076
|
+
? { maxTurnPromptTokens: state.maxTurnPromptTokens }
|
|
2077
|
+
: {}),
|
|
2009
2078
|
...(state.inheritedUsageBaseline !== undefined
|
|
2010
2079
|
? { inheritedUsageBaseline: state.inheritedUsageBaseline }
|
|
2011
2080
|
: {}),
|
|
@@ -2050,6 +2119,8 @@ function isPersistedCodexReducerState(value) {
|
|
|
2050
2119
|
return typeof value.rootSessionMetaSeen === "boolean" &&
|
|
2051
2120
|
typeof value.rootTaskStarted === "boolean" &&
|
|
2052
2121
|
typeof value.isSubagent === "boolean" &&
|
|
2122
|
+
(value.hasInheritedHistory === undefined ||
|
|
2123
|
+
typeof value.hasInheritedHistory === "boolean") &&
|
|
2053
2124
|
optionalString(value.model) &&
|
|
2054
2125
|
optionalString(value.sessionId) &&
|
|
2055
2126
|
optionalString(value.sourceVersion) &&
|
|
@@ -2062,6 +2133,7 @@ function isPersistedCodexReducerState(value) {
|
|
|
2062
2133
|
optionalString(value.lastActivityAt) &&
|
|
2063
2134
|
optionalRecord(value.lastTotal) &&
|
|
2064
2135
|
optionalRecord(value.lastTurn) &&
|
|
2136
|
+
optionalFinite(value.maxTurnPromptTokens) &&
|
|
2065
2137
|
optionalRecord(value.inheritedUsageBaseline) &&
|
|
2066
2138
|
validRateLimits &&
|
|
2067
2139
|
validRootCwd &&
|
|
@@ -2084,6 +2156,10 @@ function restoreCodexReducerState(persisted) {
|
|
|
2084
2156
|
state.rootStartedAtMs = persisted.rootStartedAtMs;
|
|
2085
2157
|
state.rootTaskStarted = persisted.rootTaskStarted;
|
|
2086
2158
|
state.isSubagent = persisted.isSubagent;
|
|
2159
|
+
// Pre-fork-fix checkpoints carry no flag; fall back to the subagent bit so a
|
|
2160
|
+
// restored subagent keeps its boundary (a restored user fork re-parses, its
|
|
2161
|
+
// parser version having changed).
|
|
2162
|
+
state.hasInheritedHistory = persisted.hasInheritedHistory ?? persisted.isSubagent;
|
|
2087
2163
|
state.parentSessionId = persisted.parentSessionId;
|
|
2088
2164
|
state.pendingTaskTurnId = persisted.pendingTaskTurnId;
|
|
2089
2165
|
state.completedTask = persisted.completedTask;
|
|
@@ -2091,6 +2167,7 @@ function restoreCodexReducerState(persisted) {
|
|
|
2091
2167
|
state.lastActivityAt = persisted.lastActivityAt;
|
|
2092
2168
|
state.lastTotal = persisted.lastTotal;
|
|
2093
2169
|
state.lastTurn = persisted.lastTurn;
|
|
2170
|
+
state.maxTurnPromptTokens = persisted.maxTurnPromptTokens;
|
|
2094
2171
|
state.inheritedUsageBaseline = persisted.inheritedUsageBaseline;
|
|
2095
2172
|
state.lastRateLimits = persisted.lastRateLimits;
|
|
2096
2173
|
state.restoredRootCwd = persisted.rootCwd;
|
|
@@ -2726,8 +2803,11 @@ async function readCodexFinancialFile(file) {
|
|
|
2726
2803
|
const rootPayload = rootEntry?.type === "session_meta" && isRecord(rootEntry.payload)
|
|
2727
2804
|
? rootEntry.payload
|
|
2728
2805
|
: undefined;
|
|
2729
|
-
|
|
2730
|
-
|
|
2806
|
+
// A rollout that replays another session's history must be read WHOLE:
|
|
2807
|
+
// its inherited-baseline boundary sits mid-file, and a proof-complete tail
|
|
2808
|
+
// would never reach it. User forks need this exactly as subagents do.
|
|
2809
|
+
const hasInheritedHistory = rootPayload !== undefined &&
|
|
2810
|
+
codexHasInheritedHistory(rootPayload);
|
|
2731
2811
|
const entriesReverse = [];
|
|
2732
2812
|
let malformedLines = 0;
|
|
2733
2813
|
let prefilteredLines = 0;
|
|
@@ -2738,7 +2818,7 @@ async function readCodexFinancialFile(file) {
|
|
|
2738
2818
|
let suffixPartsReverse = [];
|
|
2739
2819
|
let stoppedEarly = false;
|
|
2740
2820
|
let bytesSkipped = 0;
|
|
2741
|
-
const proof = createCodexReverseProof(
|
|
2821
|
+
const proof = createCodexReverseProof(hasInheritedHistory, !rootPayload);
|
|
2742
2822
|
while (position > 0 && !stoppedEarly) {
|
|
2743
2823
|
const chunkStart = Math.max(0, position - FINANCIAL_REVERSE_CHUNK_BYTES);
|
|
2744
2824
|
const length = position - chunkStart;
|
|
@@ -2979,9 +3059,9 @@ function skipJsonWhitespace(input, start) {
|
|
|
2979
3059
|
index += 1;
|
|
2980
3060
|
return index;
|
|
2981
3061
|
}
|
|
2982
|
-
function createCodexReverseProof(
|
|
3062
|
+
function createCodexReverseProof(hasInheritedHistory, forceFullScan) {
|
|
2983
3063
|
return {
|
|
2984
|
-
|
|
3064
|
+
hasInheritedHistory,
|
|
2985
3065
|
forceFullScan,
|
|
2986
3066
|
totalSeen: false,
|
|
2987
3067
|
turnSeen: false,
|
|
@@ -2990,7 +3070,7 @@ function createCodexReverseProof(isSubagent, forceFullScan) {
|
|
|
2990
3070
|
};
|
|
2991
3071
|
}
|
|
2992
3072
|
function observeCodexReverseProof(proof, entry) {
|
|
2993
|
-
if (proof.forceFullScan || proof.
|
|
3073
|
+
if (proof.forceFullScan || proof.hasInheritedHistory)
|
|
2994
3074
|
return false;
|
|
2995
3075
|
const payload = isRecord(entry.payload) ? entry.payload : undefined;
|
|
2996
3076
|
const info = payload?.type === "token_count" && isRecord(payload.info)
|
|
@@ -3007,7 +3087,7 @@ function observeCodexReverseProof(proof, entry) {
|
|
|
3007
3087
|
if (entry.type === "turn_context" && stringOf(payload?.model)) {
|
|
3008
3088
|
proof.modelSeen = true;
|
|
3009
3089
|
}
|
|
3010
|
-
return !proof.
|
|
3090
|
+
return !proof.hasInheritedHistory &&
|
|
3011
3091
|
proof.totalSeen &&
|
|
3012
3092
|
proof.turnSeen &&
|
|
3013
3093
|
proof.rateLimitsSeen &&
|
|
@@ -3112,7 +3192,8 @@ function createCodexFinancialStreamState() {
|
|
|
3112
3192
|
return {
|
|
3113
3193
|
rootSessionMetaSeen: false,
|
|
3114
3194
|
rootTaskStarted: false,
|
|
3115
|
-
isSubagent: false
|
|
3195
|
+
isSubagent: false,
|
|
3196
|
+
hasInheritedHistory: false
|
|
3116
3197
|
};
|
|
3117
3198
|
}
|
|
3118
3199
|
function consumeCodexFinancialEntry(state, entry) {
|
|
@@ -3126,12 +3207,13 @@ function consumeCodexFinancialEntry(state, entry) {
|
|
|
3126
3207
|
state.rootStartedAtMs = timestampMilliseconds(payload.timestamp ?? entry.timestamp);
|
|
3127
3208
|
state.isSubagent = stringOf(payload.thread_source) === "subagent" ||
|
|
3128
3209
|
isRecord(payload.source) && "subagent" in payload.source;
|
|
3210
|
+
state.hasInheritedHistory = codexHasInheritedHistory(payload);
|
|
3129
3211
|
}
|
|
3130
3212
|
if (entry.type === "turn_context" && payload) {
|
|
3131
3213
|
state.model = stringOf(payload.model) ?? state.model;
|
|
3132
3214
|
state.rootCwd ??= stringOf(payload.cwd);
|
|
3133
3215
|
}
|
|
3134
|
-
if (state.
|
|
3216
|
+
if (state.hasInheritedHistory &&
|
|
3135
3217
|
!state.rootTaskStarted &&
|
|
3136
3218
|
payload?.type === "task_started" &&
|
|
3137
3219
|
isRootSpecificTaskStart(payload.started_at, state.rootStartedAtMs)) {
|
|
@@ -3140,6 +3222,7 @@ function consumeCodexFinancialEntry(state, entry) {
|
|
|
3140
3222
|
state.rootTaskStarted = true;
|
|
3141
3223
|
state.model = undefined;
|
|
3142
3224
|
state.lastTurn = undefined;
|
|
3225
|
+
state.maxTurnPromptTokens = undefined;
|
|
3143
3226
|
state.lastRateLimits = undefined;
|
|
3144
3227
|
state.lastActivityAt = toIso(stringOf(entry.timestamp)) ?? state.startedAt;
|
|
3145
3228
|
}
|
|
@@ -3162,13 +3245,17 @@ function consumeCodexFinancialEntry(state, entry) {
|
|
|
3162
3245
|
if (turn) {
|
|
3163
3246
|
state.lastTurn = turn;
|
|
3164
3247
|
state.lastActivityAt = eventTimestamp;
|
|
3248
|
+
const turnPrompt = codexTurnPromptTokens(turn);
|
|
3249
|
+
if (turnPrompt !== undefined) {
|
|
3250
|
+
state.maxTurnPromptTokens = Math.max(state.maxTurnPromptTokens ?? 0, turnPrompt);
|
|
3251
|
+
}
|
|
3165
3252
|
}
|
|
3166
3253
|
const rateLimits = parseCodexRateLimits(payload.rate_limits, eventTimestamp);
|
|
3167
3254
|
if (rateLimits)
|
|
3168
3255
|
state.lastRateLimits = rateLimits;
|
|
3169
3256
|
}
|
|
3170
3257
|
function finishCodexFinancialStream(state, onDiagnostic) {
|
|
3171
|
-
if (!state.lastTotal || state.
|
|
3258
|
+
if (!state.lastTotal || state.hasInheritedHistory && !state.rootTaskStarted)
|
|
3172
3259
|
return undefined;
|
|
3173
3260
|
const parsedUsage = parseCodexCumulativeUsage(state.lastTotal, state.inheritedUsageBaseline);
|
|
3174
3261
|
const parsedTurn = state.lastTurn
|
|
@@ -3196,6 +3283,9 @@ function finishCodexFinancialStream(state, onDiagnostic) {
|
|
|
3196
3283
|
: {}),
|
|
3197
3284
|
usageScope: "session_cumulative",
|
|
3198
3285
|
usageSupport,
|
|
3286
|
+
...(usageSupport === "complete" && state.maxTurnPromptTokens !== undefined
|
|
3287
|
+
? { maxRequestPromptTokens: state.maxTurnPromptTokens }
|
|
3288
|
+
: {}),
|
|
3199
3289
|
...(parsedUsage.reportedTotalTokens !== undefined
|
|
3200
3290
|
? { reportedTotalTokens: parsedUsage.reportedTotalTokens }
|
|
3201
3291
|
: {}),
|
|
@@ -3234,10 +3324,14 @@ export function aggregateCallsForFormats(calls, descriptors) {
|
|
|
3234
3324
|
const usageSupported = groupCalls.every((call) => call.usageSupport !== "unsupported_token_shape");
|
|
3235
3325
|
const sourceVersions = [...new Set(groupCalls.flatMap((call) => call.sourceVersion ? [call.sourceVersion] : []))].sort().slice(0, 8);
|
|
3236
3326
|
const tieredPricingEvidenceSupported = !usesPromptTieredPricing(model) ||
|
|
3237
|
-
groupCalls.every((call) => canPriceTokenUsageAtScope(model, call.usage, call.usageScope === "turn" ? "request" : "aggregate") && (agent !== "gemini-cli" || hasCompleteGeminiPromptEvidence(call)));
|
|
3327
|
+
groupCalls.every((call) => canPriceTokenUsageAtScope(model, call.usage, call.usageScope === "turn" ? "request" : "aggregate", call.maxRequestPromptTokens) && (agent !== "gemini-cli" || hasCompleteGeminiPromptEvidence(call)));
|
|
3238
3328
|
const amountUsd = usageSupported && tieredPricingEvidenceSupported && format
|
|
3239
3329
|
? usesPromptTieredPricing(model)
|
|
3240
|
-
? estimateTokenCostsUsd(model, groupCalls.map((call) => call.usage)
|
|
3330
|
+
? estimateTokenCostsUsd(model, groupCalls.map((call) => call.usage),
|
|
3331
|
+
// Fix each cumulative slice's tier from its largest single request
|
|
3332
|
+
// rather than its cache-inflated sum. Turn-scoped slices carry no
|
|
3333
|
+
// such evidence and keep selecting their tier from their own prompt.
|
|
3334
|
+
groupCalls.map((call) => call.maxRequestPromptTokens))
|
|
3241
3335
|
: estimateTokenCostUsd(model, usage)
|
|
3242
3336
|
: undefined;
|
|
3243
3337
|
const priced = usageSupported && typeof amountUsd === "number";
|
package/dist/modelPricing.d.ts
CHANGED
|
@@ -50,8 +50,17 @@ export declare function estimateTokenCostUsd(model: string, usage: TokenUsage):
|
|
|
50
50
|
* models whose entire request moves to a higher rate above a prompt-size
|
|
51
51
|
* threshold; pricing a daily token sum would incorrectly treat many small
|
|
52
52
|
* requests as one large request.
|
|
53
|
+
*
|
|
54
|
+
* `tierPromptTokens[i]`, when provided, fixes the tier of `usages[i]` from
|
|
55
|
+
* request-level evidence instead of the slice's own prompt total. A
|
|
56
|
+
* session-cumulative slice is a sum of many requests whose prompt total
|
|
57
|
+
* routinely clears a per-request threshold on cache reads alone, even though no
|
|
58
|
+
* single request did; supplying the largest single request's prompt keeps such
|
|
59
|
+
* a slice on the base tier (and pricing it there is exact, since the base rate
|
|
60
|
+
* distributes over the sum). Omitting the array preserves single-request
|
|
61
|
+
* behaviour: each slice's own prompt selects its tier.
|
|
53
62
|
*/
|
|
54
|
-
export declare function estimateTokenCostsUsd(model: string, usages: readonly TokenUsage[]): number | undefined;
|
|
63
|
+
export declare function estimateTokenCostsUsd(model: string, usages: readonly TokenUsage[], tierPromptTokens?: readonly (number | undefined)[]): number | undefined;
|
|
55
64
|
/** Whether this model's rate selection depends on each request's prompt size. */
|
|
56
65
|
export declare function usesPromptTieredPricing(model: string): boolean;
|
|
57
66
|
/** Prompt-size threshold for tiered request pricing, when one is published. */
|
|
@@ -60,9 +69,13 @@ export declare function promptTierThreshold(model: string): number | undefined;
|
|
|
60
69
|
* Tiered prices are selected per request, never from a multi-request sum.
|
|
61
70
|
* An aggregate is still unambiguous when its entire non-negative prompt-side
|
|
62
71
|
* total is at or below the threshold; then no constituent request can have
|
|
63
|
-
* crossed it.
|
|
64
|
-
*
|
|
72
|
+
* crossed it. It is also unambiguous when request-level evidence
|
|
73
|
+
* (`maxRequestPromptTokens`, the largest single request the aggregate contains)
|
|
74
|
+
* proves that no constituent request crossed the threshold: every request was
|
|
75
|
+
* base-tier, so the whole sum is base-tier and prices exactly at the base rate.
|
|
76
|
+
* Larger aggregates without such evidence fail closed to keep an unpriceable
|
|
77
|
+
* total honestly "missing" rather than guessing a tier.
|
|
65
78
|
*/
|
|
66
|
-
export declare function canPriceTokenUsageAtScope(model: string, usage: TokenUsage, scope: "request" | "aggregate"): boolean;
|
|
79
|
+
export declare function canPriceTokenUsageAtScope(model: string, usage: TokenUsage, scope: "request" | "aggregate", maxRequestPromptTokens?: number): boolean;
|
|
67
80
|
export {};
|
|
68
81
|
//# sourceMappingURL=modelPricing.d.ts.map
|
package/dist/modelPricing.js
CHANGED
|
@@ -20,21 +20,38 @@ const pricingRules = [
|
|
|
20
20
|
{ match: /^claude-haiku-4/i, inputPerM: 1, outputPerM: 5 },
|
|
21
21
|
{ match: /^claude-3-7-sonnet|^claude-3-5-sonnet/i, inputPerM: 3, outputPerM: 15 },
|
|
22
22
|
{ match: /^claude-3-5-haiku/i, inputPerM: 0.8, outputPerM: 4 },
|
|
23
|
-
// OpenAI (newer and more specific families must precede the GPT-5 fallback)
|
|
23
|
+
// OpenAI (newer and more specific families must precede the GPT-5 fallback).
|
|
24
|
+
// Rates from developers.openai.com/api/docs/pricing cross-checked against each
|
|
25
|
+
// model's own doc page, both fetched 2026-08-25.
|
|
26
|
+
//
|
|
27
|
+
// GPT-5.6 ships exactly three API models — sol, terra, luna
|
|
28
|
+
// (developers.openai.com/api/docs/models, 2026-08-25). Each 5.6/5.5/5.4 rule
|
|
29
|
+
// below is END-ANCHORED on purpose: an undocumented or future sibling
|
|
30
|
+
// (gpt-5.6-cyber, gpt-5.5-pro, gpt-5.7-sol) must fall through to
|
|
31
|
+
// honest-unpriced rather than inherit a neighbour's rate. That is the 0.9.4
|
|
32
|
+
// `^kimi-k2` mistake one family up, and it is the expensive direction here —
|
|
33
|
+
// the pre-0.9.6 `^gpt-5.6(?:-sol)?$` rule carried GPT-5.5's numbers, so every
|
|
34
|
+
// gpt-5.6-sol record was overstated by 25% on input and 50% on output.
|
|
35
|
+
//
|
|
36
|
+
// Long context, published identically on all three 5.6 pages plus 5.5/5.4:
|
|
37
|
+
// "Prompts with >272K input tokens are priced at 2x input and 1.5x output for
|
|
38
|
+
// the full request." Cached input scales with the 2x input leg.
|
|
24
39
|
{
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
40
|
+
// developers.openai.com/api/docs/models/gpt-5.6-sol, 2026-08-25
|
|
41
|
+
match: /^gpt-5\.6-sol$/i,
|
|
42
|
+
inputPerM: 4,
|
|
43
|
+
outputPerM: 20,
|
|
44
|
+
cacheReadPerM: 0.4,
|
|
29
45
|
abovePromptTokens: {
|
|
30
46
|
threshold: 272_000,
|
|
31
|
-
inputPerM:
|
|
32
|
-
outputPerM:
|
|
33
|
-
cacheReadPerM:
|
|
47
|
+
inputPerM: 8,
|
|
48
|
+
outputPerM: 30,
|
|
49
|
+
cacheReadPerM: 0.8
|
|
34
50
|
}
|
|
35
51
|
},
|
|
36
52
|
{
|
|
37
|
-
|
|
53
|
+
// developers.openai.com/api/docs/models/gpt-5.6-terra, 2026-08-25
|
|
54
|
+
match: /^gpt-5\.6-terra$/i,
|
|
38
55
|
inputPerM: 2,
|
|
39
56
|
outputPerM: 12,
|
|
40
57
|
cacheReadPerM: 0.2,
|
|
@@ -46,7 +63,8 @@ const pricingRules = [
|
|
|
46
63
|
}
|
|
47
64
|
},
|
|
48
65
|
{
|
|
49
|
-
|
|
66
|
+
// developers.openai.com/api/docs/models/gpt-5.6-luna, 2026-08-25
|
|
67
|
+
match: /^gpt-5\.6-luna$/i,
|
|
50
68
|
inputPerM: 0.2,
|
|
51
69
|
outputPerM: 1.2,
|
|
52
70
|
cacheReadPerM: 0.02,
|
|
@@ -57,15 +75,50 @@ const pricingRules = [
|
|
|
57
75
|
cacheReadPerM: 0.04
|
|
58
76
|
}
|
|
59
77
|
},
|
|
60
|
-
{
|
|
78
|
+
{
|
|
79
|
+
// developers.openai.com/api/docs/models/gpt-5.5, 2026-08-25
|
|
80
|
+
match: /^gpt-5\.5$/i,
|
|
81
|
+
inputPerM: 5,
|
|
82
|
+
outputPerM: 30,
|
|
83
|
+
cacheReadPerM: 0.5,
|
|
84
|
+
abovePromptTokens: {
|
|
85
|
+
threshold: 272_000,
|
|
86
|
+
inputPerM: 10,
|
|
87
|
+
outputPerM: 45,
|
|
88
|
+
cacheReadPerM: 1
|
|
89
|
+
}
|
|
90
|
+
},
|
|
91
|
+
// gpt-5.5-codex bills at the 5.5 base rate but is absent from the published
|
|
92
|
+
// long-context list, so it deliberately carries no >272K tier.
|
|
93
|
+
{ match: /^gpt-5\.5-codex$/i, inputPerM: 5, outputPerM: 30, cacheReadPerM: 0.5 },
|
|
61
94
|
{ match: /^gpt-5\.4-mini/i, inputPerM: 0.75, outputPerM: 4.5, cacheReadPerM: 0.075 },
|
|
62
95
|
{ match: /^gpt-5\.4-nano/i, inputPerM: 0.2, outputPerM: 1.25, cacheReadPerM: 0.02 },
|
|
63
|
-
{
|
|
96
|
+
{
|
|
97
|
+
// developers.openai.com/api/docs/models/gpt-5.4, 2026-08-25
|
|
98
|
+
match: /^gpt-5\.4$/i,
|
|
99
|
+
inputPerM: 2.5,
|
|
100
|
+
outputPerM: 15,
|
|
101
|
+
cacheReadPerM: 0.25,
|
|
102
|
+
abovePromptTokens: {
|
|
103
|
+
threshold: 272_000,
|
|
104
|
+
inputPerM: 5,
|
|
105
|
+
outputPerM: 22.5,
|
|
106
|
+
cacheReadPerM: 0.5
|
|
107
|
+
}
|
|
108
|
+
},
|
|
64
109
|
{ match: /^gpt-5\.3-codex/i, inputPerM: 1.75, outputPerM: 14, cacheReadPerM: 0.175 },
|
|
65
110
|
{ match: /^gpt-5\.2(?:-codex)?/i, inputPerM: 1.75, outputPerM: 14, cacheReadPerM: 0.175 },
|
|
66
111
|
{ match: /^gpt-5(?:\.1)?-codex/i, inputPerM: 1.25, outputPerM: 10, cacheReadPerM: 0.125 },
|
|
67
112
|
{ match: /^gpt-5(?:\.1)?-mini/i, inputPerM: 0.25, outputPerM: 2, cacheReadPerM: 0.025 },
|
|
68
|
-
|
|
113
|
+
// developers.openai.com/api/docs/models/gpt-5-nano, 2026-08-25. Before 0.9.6
|
|
114
|
+
// this fell through to the ^gpt-5 fallback and billed at $1.25/$10 — 25x the
|
|
115
|
+
// real rate in both directions. No published long-context tier.
|
|
116
|
+
{ match: /^gpt-5-nano/i, inputPerM: 0.05, outputPerM: 0.4, cacheReadPerM: 0.005 },
|
|
117
|
+
// GPT-5 base and its dash-suffixed snapshots only. The `-|$` boundary stops
|
|
118
|
+
// this fallback from swallowing dot-minor families it knows nothing about:
|
|
119
|
+
// gpt-5.7-*, gpt-5.6-cyber and any future gpt-5.6-<variant> now return
|
|
120
|
+
// undefined -> "missing" instead of silently billing at GPT-5's $1.25/$10.
|
|
121
|
+
{ match: /^gpt-5(?:-|$)/i, inputPerM: 1.25, outputPerM: 10, cacheReadPerM: 0.125 },
|
|
69
122
|
{ match: /^gpt-4\.1-nano/i, inputPerM: 0.1, outputPerM: 0.4 },
|
|
70
123
|
{ match: /^gpt-4\.1-mini/i, inputPerM: 0.4, outputPerM: 1.6 },
|
|
71
124
|
{ match: /^gpt-4\.1/i, inputPerM: 2, outputPerM: 8, cacheReadPerM: 0.5 },
|
|
@@ -122,6 +175,23 @@ const pricingRules = [
|
|
|
122
175
|
// - deepseek-v4-* (api-docs.deepseek.com/quick_start/pricing): published
|
|
123
176
|
// rates are time-of-day (off-peak = half price, up to 2x swing), so any
|
|
124
177
|
// flat number here would be dishonest; needs timestamp-aware pricing.
|
|
178
|
+
//
|
|
179
|
+
// Deliberate deferrals (2026-08-25 OpenAI review), same honest path:
|
|
180
|
+
// - gpt-5.6-cyber / gpt-5.5-cyber ($12.50/$1.25/$75 on the pricing page):
|
|
181
|
+
// the two canonical sources disagree on whether the >272K tier applies —
|
|
182
|
+
// the pricing page omits cyber from its long-context list while
|
|
183
|
+
// developers.openai.com/api/docs/models/gpt-5.6-cyber states the 2x/1.5x
|
|
184
|
+
// rule does apply. Access is gated behind the Daybreak program, so the
|
|
185
|
+
// cost of leaving it unpriced is near zero and a coin-flip on the tier
|
|
186
|
+
// would be a real number that is wrong on long requests.
|
|
187
|
+
// - gpt-5.5-pro / gpt-5.4-pro: listed as long-context-capable but no
|
|
188
|
+
// per-model rate is published on either canonical source.
|
|
189
|
+
// - bare gpt-5.1 / gpt-5.3: the pricing page quotes the 5/5.1/5.2 group as a
|
|
190
|
+
// RANGE ($1.25-$1.75) and neither has a resolved per-model figure. Their
|
|
191
|
+
// -codex and -mini variants keep their own verified rules above.
|
|
192
|
+
// - gpt-5.6-codex / gpt-5.5-mini: NOT OpenAI model ids (both 404 on the model
|
|
193
|
+
// docs and are absent from developers.openai.com/api/docs/models). They
|
|
194
|
+
// appear only in this repo's fixtures and sample CSVs.
|
|
125
195
|
];
|
|
126
196
|
export function findPricingRule(model) {
|
|
127
197
|
return pricingRules.find((rule) => rule.match.test(model));
|
|
@@ -139,11 +209,20 @@ export function estimateTokenCostUsd(model, usage) {
|
|
|
139
209
|
* models whose entire request moves to a higher rate above a prompt-size
|
|
140
210
|
* threshold; pricing a daily token sum would incorrectly treat many small
|
|
141
211
|
* requests as one large request.
|
|
212
|
+
*
|
|
213
|
+
* `tierPromptTokens[i]`, when provided, fixes the tier of `usages[i]` from
|
|
214
|
+
* request-level evidence instead of the slice's own prompt total. A
|
|
215
|
+
* session-cumulative slice is a sum of many requests whose prompt total
|
|
216
|
+
* routinely clears a per-request threshold on cache reads alone, even though no
|
|
217
|
+
* single request did; supplying the largest single request's prompt keeps such
|
|
218
|
+
* a slice on the base tier (and pricing it there is exact, since the base rate
|
|
219
|
+
* distributes over the sum). Omitting the array preserves single-request
|
|
220
|
+
* behaviour: each slice's own prompt selects its tier.
|
|
142
221
|
*/
|
|
143
|
-
export function estimateTokenCostsUsd(model, usages) {
|
|
222
|
+
export function estimateTokenCostsUsd(model, usages, tierPromptTokens) {
|
|
144
223
|
let total = 0;
|
|
145
|
-
for (
|
|
146
|
-
const usd = rawTokenCostUsd(model,
|
|
224
|
+
for (let index = 0; index < usages.length; index += 1) {
|
|
225
|
+
const usd = rawTokenCostUsd(model, usages[index], tierPromptTokens?.[index]);
|
|
147
226
|
if (usd === undefined)
|
|
148
227
|
return undefined;
|
|
149
228
|
total += usd;
|
|
@@ -162,21 +241,34 @@ export function promptTierThreshold(model) {
|
|
|
162
241
|
* Tiered prices are selected per request, never from a multi-request sum.
|
|
163
242
|
* An aggregate is still unambiguous when its entire non-negative prompt-side
|
|
164
243
|
* total is at or below the threshold; then no constituent request can have
|
|
165
|
-
* crossed it.
|
|
166
|
-
*
|
|
244
|
+
* crossed it. It is also unambiguous when request-level evidence
|
|
245
|
+
* (`maxRequestPromptTokens`, the largest single request the aggregate contains)
|
|
246
|
+
* proves that no constituent request crossed the threshold: every request was
|
|
247
|
+
* base-tier, so the whole sum is base-tier and prices exactly at the base rate.
|
|
248
|
+
* Larger aggregates without such evidence fail closed to keep an unpriceable
|
|
249
|
+
* total honestly "missing" rather than guessing a tier.
|
|
167
250
|
*/
|
|
168
|
-
export function canPriceTokenUsageAtScope(model, usage, scope) {
|
|
251
|
+
export function canPriceTokenUsageAtScope(model, usage, scope, maxRequestPromptTokens) {
|
|
169
252
|
const threshold = promptTierThreshold(model);
|
|
170
253
|
if (threshold === undefined || scope === "request")
|
|
171
254
|
return true;
|
|
172
|
-
|
|
255
|
+
if (effectivePromptTokens(usage) <= threshold)
|
|
256
|
+
return true;
|
|
257
|
+
return maxRequestPromptTokens !== undefined && maxRequestPromptTokens <= threshold;
|
|
173
258
|
}
|
|
174
|
-
|
|
259
|
+
/**
|
|
260
|
+
* @param tierPromptTokens Prompt size used ONLY to select the request tier,
|
|
261
|
+
* when it differs from the priced slice's own prompt total (e.g. a
|
|
262
|
+
* session-cumulative slice whose tier is fixed by its largest single
|
|
263
|
+
* request). Component pricing always uses `usage`; defaults to the slice's
|
|
264
|
+
* own effective prompt so single-request callers are unchanged.
|
|
265
|
+
*/
|
|
266
|
+
function rawTokenCostUsd(model, usage, tierPromptTokens) {
|
|
175
267
|
const rule = findPricingRule(model);
|
|
176
268
|
if (!rule) {
|
|
177
269
|
return undefined;
|
|
178
270
|
}
|
|
179
|
-
const promptTokens = effectivePromptTokens(usage);
|
|
271
|
+
const promptTokens = tierPromptTokens ?? effectivePromptTokens(usage);
|
|
180
272
|
const rates = rule.abovePromptTokens &&
|
|
181
273
|
promptTokens > rule.abovePromptTokens.threshold
|
|
182
274
|
? rule.abovePromptTokens
|
|
@@ -7,7 +7,7 @@ export declare const projectIndexStoreLockFileName = ".project-index-v2.lock";
|
|
|
7
7
|
export declare const projectIndexMaxDocumentBytes: number;
|
|
8
8
|
/** Null-window variant plus the newest bounded windows (BLOCKER-2 option i). */
|
|
9
9
|
export declare const projectIndexMaxWindowedVariants = 4;
|
|
10
|
-
export declare const projectIndexFinancialParserVersion =
|
|
10
|
+
export declare const projectIndexFinancialParserVersion = 3;
|
|
11
11
|
declare const financialKeySchema: z.ZodObject<{
|
|
12
12
|
schemaVersion: z.ZodLiteral<2>;
|
|
13
13
|
section: z.ZodLiteral<"financial">;
|
|
@@ -18,7 +18,7 @@ declare const financialKeySchema: z.ZodObject<{
|
|
|
18
18
|
}>;
|
|
19
19
|
pathHash: z.ZodString;
|
|
20
20
|
fileIdentity: z.ZodString;
|
|
21
|
-
financialParserVersion: z.ZodLiteral<
|
|
21
|
+
financialParserVersion: z.ZodLiteral<3>;
|
|
22
22
|
}, z.core.$strict>;
|
|
23
23
|
/**
|
|
24
24
|
* Header-pass ownership evidence (A4a consumer). "unknown" is a first-class
|
|
@@ -53,7 +53,7 @@ declare const documentSchema: z.ZodObject<{
|
|
|
53
53
|
qualitative: z.ZodArray<z.ZodObject<{
|
|
54
54
|
key: z.ZodObject<{
|
|
55
55
|
schemaVersion: z.ZodLiteral<1>;
|
|
56
|
-
parserVersion: z.ZodLiteral<
|
|
56
|
+
parserVersion: z.ZodLiteral<6>;
|
|
57
57
|
agent: z.ZodEnum<{
|
|
58
58
|
"claude-code": "claude-code";
|
|
59
59
|
codex: "codex";
|
|
@@ -89,19 +89,20 @@ declare const documentSchema: z.ZodObject<{
|
|
|
89
89
|
contextTokens: z.ZodNumber;
|
|
90
90
|
totalTokens: z.ZodNumber;
|
|
91
91
|
source: z.ZodEnum<{
|
|
92
|
-
transcript_last_token_usage: "transcript_last_token_usage";
|
|
93
92
|
assistant_message_usage: "assistant_message_usage";
|
|
93
|
+
transcript_last_token_usage: "transcript_last_token_usage";
|
|
94
94
|
call_usage: "call_usage";
|
|
95
95
|
}>;
|
|
96
96
|
}, z.core.$strict>>;
|
|
97
97
|
usageScope: z.ZodOptional<z.ZodEnum<{
|
|
98
|
-
session_cumulative: "session_cumulative";
|
|
99
98
|
turn: "turn";
|
|
99
|
+
session_cumulative: "session_cumulative";
|
|
100
100
|
}>>;
|
|
101
101
|
usageSupport: z.ZodOptional<z.ZodEnum<{
|
|
102
102
|
complete: "complete";
|
|
103
103
|
unsupported_token_shape: "unsupported_token_shape";
|
|
104
104
|
}>>;
|
|
105
|
+
maxRequestPromptTokens: z.ZodOptional<z.ZodNumber>;
|
|
105
106
|
reportedTotalTokens: z.ZodOptional<z.ZodNumber>;
|
|
106
107
|
tokenComponentEvidence: z.ZodOptional<z.ZodObject<{
|
|
107
108
|
inputTokens: z.ZodLiteral<"observed">;
|
|
@@ -150,8 +151,8 @@ declare const documentSchema: z.ZodObject<{
|
|
|
150
151
|
total: z.ZodOptional<z.ZodNumber>;
|
|
151
152
|
cacheAccounting: z.ZodEnum<{
|
|
152
153
|
unknown: "unknown";
|
|
153
|
-
none: "none";
|
|
154
154
|
included: "included";
|
|
155
|
+
none: "none";
|
|
155
156
|
}>;
|
|
156
157
|
}, z.core.$strict>>;
|
|
157
158
|
usage: z.ZodObject<{
|
|
@@ -190,12 +191,11 @@ declare const documentSchema: z.ZodObject<{
|
|
|
190
191
|
kind: z.ZodEnum<{
|
|
191
192
|
file: "file";
|
|
192
193
|
agent: "agent";
|
|
193
|
-
task: "task";
|
|
194
194
|
project: "project";
|
|
195
|
+
task: "task";
|
|
195
196
|
automation: "automation";
|
|
196
197
|
}>;
|
|
197
198
|
action: z.ZodEnum<{
|
|
198
|
-
working: "working";
|
|
199
199
|
building: "building";
|
|
200
200
|
refining: "refining";
|
|
201
201
|
fixing: "fixing";
|
|
@@ -205,11 +205,12 @@ declare const documentSchema: z.ZodObject<{
|
|
|
205
205
|
configuring: "configuring";
|
|
206
206
|
publishing: "publishing";
|
|
207
207
|
running: "running";
|
|
208
|
+
working: "working";
|
|
208
209
|
}>;
|
|
209
210
|
source: z.ZodEnum<{
|
|
210
|
-
user_prompts: "user_prompts";
|
|
211
211
|
project: "project";
|
|
212
212
|
agent_title: "agent_title";
|
|
213
|
+
user_prompts: "user_prompts";
|
|
213
214
|
file_activity: "file_activity";
|
|
214
215
|
}>;
|
|
215
216
|
promptCount: z.ZodNumber;
|
|
@@ -261,9 +262,9 @@ declare const documentSchema: z.ZodObject<{
|
|
|
261
262
|
}, z.core.$strict>>;
|
|
262
263
|
diagnostics: z.ZodArray<z.ZodObject<{
|
|
263
264
|
code: z.ZodEnum<{
|
|
265
|
+
unsupported_token_shape: "unsupported_token_shape";
|
|
264
266
|
malformed_jsonl: "malformed_jsonl";
|
|
265
267
|
malformed_session_file: "malformed_session_file";
|
|
266
|
-
unsupported_token_shape: "unsupported_token_shape";
|
|
267
268
|
}>;
|
|
268
269
|
count: z.ZodNumber;
|
|
269
270
|
}, z.core.$strict>>;
|
|
@@ -280,7 +281,7 @@ declare const documentSchema: z.ZodObject<{
|
|
|
280
281
|
}>;
|
|
281
282
|
pathHash: z.ZodString;
|
|
282
283
|
fileIdentity: z.ZodString;
|
|
283
|
-
financialParserVersion: z.ZodLiteral<
|
|
284
|
+
financialParserVersion: z.ZodLiteral<3>;
|
|
284
285
|
}, z.core.$strict>;
|
|
285
286
|
storedAt: z.ZodString;
|
|
286
287
|
value: z.ZodObject<{
|
|
@@ -307,19 +308,20 @@ declare const documentSchema: z.ZodObject<{
|
|
|
307
308
|
contextTokens: z.ZodNumber;
|
|
308
309
|
totalTokens: z.ZodNumber;
|
|
309
310
|
source: z.ZodEnum<{
|
|
310
|
-
transcript_last_token_usage: "transcript_last_token_usage";
|
|
311
311
|
assistant_message_usage: "assistant_message_usage";
|
|
312
|
+
transcript_last_token_usage: "transcript_last_token_usage";
|
|
312
313
|
call_usage: "call_usage";
|
|
313
314
|
}>;
|
|
314
315
|
}, z.core.$strict>>;
|
|
315
316
|
usageScope: z.ZodOptional<z.ZodEnum<{
|
|
316
|
-
session_cumulative: "session_cumulative";
|
|
317
317
|
turn: "turn";
|
|
318
|
+
session_cumulative: "session_cumulative";
|
|
318
319
|
}>>;
|
|
319
320
|
usageSupport: z.ZodOptional<z.ZodEnum<{
|
|
320
321
|
complete: "complete";
|
|
321
322
|
unsupported_token_shape: "unsupported_token_shape";
|
|
322
323
|
}>>;
|
|
324
|
+
maxRequestPromptTokens: z.ZodOptional<z.ZodNumber>;
|
|
323
325
|
reportedTotalTokens: z.ZodOptional<z.ZodNumber>;
|
|
324
326
|
tokenComponentEvidence: z.ZodOptional<z.ZodObject<{
|
|
325
327
|
inputTokens: z.ZodLiteral<"observed">;
|
|
@@ -368,8 +370,8 @@ declare const documentSchema: z.ZodObject<{
|
|
|
368
370
|
total: z.ZodOptional<z.ZodNumber>;
|
|
369
371
|
cacheAccounting: z.ZodEnum<{
|
|
370
372
|
unknown: "unknown";
|
|
371
|
-
none: "none";
|
|
372
373
|
included: "included";
|
|
374
|
+
none: "none";
|
|
373
375
|
}>;
|
|
374
376
|
}, z.core.$strict>>;
|
|
375
377
|
usage: z.ZodObject<{
|
|
@@ -408,12 +410,11 @@ declare const documentSchema: z.ZodObject<{
|
|
|
408
410
|
kind: z.ZodEnum<{
|
|
409
411
|
file: "file";
|
|
410
412
|
agent: "agent";
|
|
411
|
-
task: "task";
|
|
412
413
|
project: "project";
|
|
414
|
+
task: "task";
|
|
413
415
|
automation: "automation";
|
|
414
416
|
}>;
|
|
415
417
|
action: z.ZodEnum<{
|
|
416
|
-
working: "working";
|
|
417
418
|
building: "building";
|
|
418
419
|
refining: "refining";
|
|
419
420
|
fixing: "fixing";
|
|
@@ -423,11 +424,12 @@ declare const documentSchema: z.ZodObject<{
|
|
|
423
424
|
configuring: "configuring";
|
|
424
425
|
publishing: "publishing";
|
|
425
426
|
running: "running";
|
|
427
|
+
working: "working";
|
|
426
428
|
}>;
|
|
427
429
|
source: z.ZodEnum<{
|
|
428
|
-
user_prompts: "user_prompts";
|
|
429
430
|
project: "project";
|
|
430
431
|
agent_title: "agent_title";
|
|
432
|
+
user_prompts: "user_prompts";
|
|
431
433
|
file_activity: "file_activity";
|
|
432
434
|
}>;
|
|
433
435
|
promptCount: z.ZodNumber;
|
|
@@ -479,9 +481,9 @@ declare const documentSchema: z.ZodObject<{
|
|
|
479
481
|
}, z.core.$strict>>;
|
|
480
482
|
diagnostics: z.ZodArray<z.ZodObject<{
|
|
481
483
|
code: z.ZodEnum<{
|
|
484
|
+
unsupported_token_shape: "unsupported_token_shape";
|
|
482
485
|
malformed_jsonl: "malformed_jsonl";
|
|
483
486
|
malformed_session_file: "malformed_session_file";
|
|
484
|
-
unsupported_token_shape: "unsupported_token_shape";
|
|
485
487
|
}>;
|
|
486
488
|
count: z.ZodNumber;
|
|
487
489
|
}, z.core.$strict>>;
|
|
@@ -25,7 +25,7 @@ export declare class QualitativeIndexCacheError extends Error {
|
|
|
25
25
|
}
|
|
26
26
|
declare const keySchema: z.ZodObject<{
|
|
27
27
|
schemaVersion: z.ZodLiteral<1>;
|
|
28
|
-
parserVersion: z.ZodLiteral<
|
|
28
|
+
parserVersion: z.ZodLiteral<6>;
|
|
29
29
|
agent: z.ZodEnum<{
|
|
30
30
|
"claude-code": "claude-code";
|
|
31
31
|
codex: "codex";
|
|
@@ -60,19 +60,20 @@ declare const valueSchema: z.ZodObject<{
|
|
|
60
60
|
contextTokens: z.ZodNumber;
|
|
61
61
|
totalTokens: z.ZodNumber;
|
|
62
62
|
source: z.ZodEnum<{
|
|
63
|
-
transcript_last_token_usage: "transcript_last_token_usage";
|
|
64
63
|
assistant_message_usage: "assistant_message_usage";
|
|
64
|
+
transcript_last_token_usage: "transcript_last_token_usage";
|
|
65
65
|
call_usage: "call_usage";
|
|
66
66
|
}>;
|
|
67
67
|
}, z.core.$strict>>;
|
|
68
68
|
usageScope: z.ZodOptional<z.ZodEnum<{
|
|
69
|
-
session_cumulative: "session_cumulative";
|
|
70
69
|
turn: "turn";
|
|
70
|
+
session_cumulative: "session_cumulative";
|
|
71
71
|
}>>;
|
|
72
72
|
usageSupport: z.ZodOptional<z.ZodEnum<{
|
|
73
73
|
complete: "complete";
|
|
74
74
|
unsupported_token_shape: "unsupported_token_shape";
|
|
75
75
|
}>>;
|
|
76
|
+
maxRequestPromptTokens: z.ZodOptional<z.ZodNumber>;
|
|
76
77
|
reportedTotalTokens: z.ZodOptional<z.ZodNumber>;
|
|
77
78
|
tokenComponentEvidence: z.ZodOptional<z.ZodObject<{
|
|
78
79
|
inputTokens: z.ZodLiteral<"observed">;
|
|
@@ -121,8 +122,8 @@ declare const valueSchema: z.ZodObject<{
|
|
|
121
122
|
total: z.ZodOptional<z.ZodNumber>;
|
|
122
123
|
cacheAccounting: z.ZodEnum<{
|
|
123
124
|
unknown: "unknown";
|
|
124
|
-
none: "none";
|
|
125
125
|
included: "included";
|
|
126
|
+
none: "none";
|
|
126
127
|
}>;
|
|
127
128
|
}, z.core.$strict>>;
|
|
128
129
|
usage: z.ZodObject<{
|
|
@@ -161,12 +162,11 @@ declare const valueSchema: z.ZodObject<{
|
|
|
161
162
|
kind: z.ZodEnum<{
|
|
162
163
|
file: "file";
|
|
163
164
|
agent: "agent";
|
|
164
|
-
task: "task";
|
|
165
165
|
project: "project";
|
|
166
|
+
task: "task";
|
|
166
167
|
automation: "automation";
|
|
167
168
|
}>;
|
|
168
169
|
action: z.ZodEnum<{
|
|
169
|
-
working: "working";
|
|
170
170
|
building: "building";
|
|
171
171
|
refining: "refining";
|
|
172
172
|
fixing: "fixing";
|
|
@@ -176,11 +176,12 @@ declare const valueSchema: z.ZodObject<{
|
|
|
176
176
|
configuring: "configuring";
|
|
177
177
|
publishing: "publishing";
|
|
178
178
|
running: "running";
|
|
179
|
+
working: "working";
|
|
179
180
|
}>;
|
|
180
181
|
source: z.ZodEnum<{
|
|
181
|
-
user_prompts: "user_prompts";
|
|
182
182
|
project: "project";
|
|
183
183
|
agent_title: "agent_title";
|
|
184
|
+
user_prompts: "user_prompts";
|
|
184
185
|
file_activity: "file_activity";
|
|
185
186
|
}>;
|
|
186
187
|
promptCount: z.ZodNumber;
|
|
@@ -232,9 +233,9 @@ declare const valueSchema: z.ZodObject<{
|
|
|
232
233
|
}, z.core.$strict>>;
|
|
233
234
|
diagnostics: z.ZodArray<z.ZodObject<{
|
|
234
235
|
code: z.ZodEnum<{
|
|
236
|
+
unsupported_token_shape: "unsupported_token_shape";
|
|
235
237
|
malformed_jsonl: "malformed_jsonl";
|
|
236
238
|
malformed_session_file: "malformed_session_file";
|
|
237
|
-
unsupported_token_shape: "unsupported_token_shape";
|
|
238
239
|
}>;
|
|
239
240
|
count: z.ZodNumber;
|
|
240
241
|
}, z.core.$strict>>;
|
|
@@ -250,7 +251,7 @@ type PersistedValue = PersistedQualitativeValue;
|
|
|
250
251
|
*/
|
|
251
252
|
export declare const qualitativeEntryKeySchema: z.ZodObject<{
|
|
252
253
|
schemaVersion: z.ZodLiteral<1>;
|
|
253
|
-
parserVersion: z.ZodLiteral<
|
|
254
|
+
parserVersion: z.ZodLiteral<6>;
|
|
254
255
|
agent: z.ZodEnum<{
|
|
255
256
|
"claude-code": "claude-code";
|
|
256
257
|
codex: "codex";
|
|
@@ -285,19 +286,20 @@ export declare const qualitativeEntryValueSchema: z.ZodObject<{
|
|
|
285
286
|
contextTokens: z.ZodNumber;
|
|
286
287
|
totalTokens: z.ZodNumber;
|
|
287
288
|
source: z.ZodEnum<{
|
|
288
|
-
transcript_last_token_usage: "transcript_last_token_usage";
|
|
289
289
|
assistant_message_usage: "assistant_message_usage";
|
|
290
|
+
transcript_last_token_usage: "transcript_last_token_usage";
|
|
290
291
|
call_usage: "call_usage";
|
|
291
292
|
}>;
|
|
292
293
|
}, z.core.$strict>>;
|
|
293
294
|
usageScope: z.ZodOptional<z.ZodEnum<{
|
|
294
|
-
session_cumulative: "session_cumulative";
|
|
295
295
|
turn: "turn";
|
|
296
|
+
session_cumulative: "session_cumulative";
|
|
296
297
|
}>>;
|
|
297
298
|
usageSupport: z.ZodOptional<z.ZodEnum<{
|
|
298
299
|
complete: "complete";
|
|
299
300
|
unsupported_token_shape: "unsupported_token_shape";
|
|
300
301
|
}>>;
|
|
302
|
+
maxRequestPromptTokens: z.ZodOptional<z.ZodNumber>;
|
|
301
303
|
reportedTotalTokens: z.ZodOptional<z.ZodNumber>;
|
|
302
304
|
tokenComponentEvidence: z.ZodOptional<z.ZodObject<{
|
|
303
305
|
inputTokens: z.ZodLiteral<"observed">;
|
|
@@ -346,8 +348,8 @@ export declare const qualitativeEntryValueSchema: z.ZodObject<{
|
|
|
346
348
|
total: z.ZodOptional<z.ZodNumber>;
|
|
347
349
|
cacheAccounting: z.ZodEnum<{
|
|
348
350
|
unknown: "unknown";
|
|
349
|
-
none: "none";
|
|
350
351
|
included: "included";
|
|
352
|
+
none: "none";
|
|
351
353
|
}>;
|
|
352
354
|
}, z.core.$strict>>;
|
|
353
355
|
usage: z.ZodObject<{
|
|
@@ -386,12 +388,11 @@ export declare const qualitativeEntryValueSchema: z.ZodObject<{
|
|
|
386
388
|
kind: z.ZodEnum<{
|
|
387
389
|
file: "file";
|
|
388
390
|
agent: "agent";
|
|
389
|
-
task: "task";
|
|
390
391
|
project: "project";
|
|
392
|
+
task: "task";
|
|
391
393
|
automation: "automation";
|
|
392
394
|
}>;
|
|
393
395
|
action: z.ZodEnum<{
|
|
394
|
-
working: "working";
|
|
395
396
|
building: "building";
|
|
396
397
|
refining: "refining";
|
|
397
398
|
fixing: "fixing";
|
|
@@ -401,11 +402,12 @@ export declare const qualitativeEntryValueSchema: z.ZodObject<{
|
|
|
401
402
|
configuring: "configuring";
|
|
402
403
|
publishing: "publishing";
|
|
403
404
|
running: "running";
|
|
405
|
+
working: "working";
|
|
404
406
|
}>;
|
|
405
407
|
source: z.ZodEnum<{
|
|
406
|
-
user_prompts: "user_prompts";
|
|
407
408
|
project: "project";
|
|
408
409
|
agent_title: "agent_title";
|
|
410
|
+
user_prompts: "user_prompts";
|
|
409
411
|
file_activity: "file_activity";
|
|
410
412
|
}>;
|
|
411
413
|
promptCount: z.ZodNumber;
|
|
@@ -457,9 +459,9 @@ export declare const qualitativeEntryValueSchema: z.ZodObject<{
|
|
|
457
459
|
}, z.core.$strict>>;
|
|
458
460
|
diagnostics: z.ZodArray<z.ZodObject<{
|
|
459
461
|
code: z.ZodEnum<{
|
|
462
|
+
unsupported_token_shape: "unsupported_token_shape";
|
|
460
463
|
malformed_jsonl: "malformed_jsonl";
|
|
461
464
|
malformed_session_file: "malformed_session_file";
|
|
462
|
-
unsupported_token_shape: "unsupported_token_shape";
|
|
463
465
|
}>;
|
|
464
466
|
count: z.ZodNumber;
|
|
465
467
|
}, z.core.$strict>>;
|
|
@@ -129,6 +129,11 @@ const callSchema = z.object({
|
|
|
129
129
|
latestTurnUsage: turnUsageSchema.optional(),
|
|
130
130
|
usageScope: z.enum(["turn", "session_cumulative"]).optional(),
|
|
131
131
|
usageSupport: z.enum(["complete", "unsupported_token_shape"]).optional(),
|
|
132
|
+
// Per-request tier evidence for session-cumulative slices. The strict schema
|
|
133
|
+
// must carry it: without this key the entry fails validation on write, the
|
|
134
|
+
// failure is swallowed by the caller, and every run re-parses the whole
|
|
135
|
+
// corpus instead of reusing the cache.
|
|
136
|
+
maxRequestPromptTokens: finiteNonnegativeInteger.optional(),
|
|
132
137
|
reportedTotalTokens: finiteNonnegativeInteger.optional(),
|
|
133
138
|
tokenComponentEvidence: tokenComponentEvidenceSchema.optional(),
|
|
134
139
|
sourceVersion: z.string().min(1).max(64).optional(),
|
package/package.json
CHANGED
package/dist/emailAddress.d.ts
DELETED
|
@@ -1,7 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* One intentionally pragmatic normalizer for waitlist and receipt-email
|
|
3
|
-
* boundaries. It prevents header/control injection without pretending to be
|
|
4
|
-
* a mailbox-verification system; ownership still requires an explicit flow.
|
|
5
|
-
*/
|
|
6
|
-
export declare function normalizeAibillEmailAddress(value: string): string | undefined;
|
|
7
|
-
//# sourceMappingURL=emailAddress.d.ts.map
|
package/dist/emailAddress.js
DELETED
|
@@ -1,16 +0,0 @@
|
|
|
1
|
-
const controlCharacters = /[\u0000-\u001F\u007F]/u;
|
|
2
|
-
const pragmaticEmailAddress = /^[^\s@]+@[^\s@]+\.[^\s@]+$/u;
|
|
3
|
-
/**
|
|
4
|
-
* One intentionally pragmatic normalizer for waitlist and receipt-email
|
|
5
|
-
* boundaries. It prevents header/control injection without pretending to be
|
|
6
|
-
* a mailbox-verification system; ownership still requires an explicit flow.
|
|
7
|
-
*/
|
|
8
|
-
export function normalizeAibillEmailAddress(value) {
|
|
9
|
-
const normalized = value.trim().toLowerCase();
|
|
10
|
-
if (normalized.length < 3 || normalized.length > 254)
|
|
11
|
-
return undefined;
|
|
12
|
-
if (controlCharacters.test(normalized))
|
|
13
|
-
return undefined;
|
|
14
|
-
return pragmaticEmailAddress.test(normalized) ? normalized : undefined;
|
|
15
|
-
}
|
|
16
|
-
//# sourceMappingURL=emailAddress.js.map
|