@cruxy/cli 1.0.2 → 1.0.3
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/agent/loop.js +3 -0
- package/dist/agent/session.js +2 -1
- package/dist/theme/tokens.d.ts +6 -0
- package/dist/theme/tokens.js +3 -0
- package/dist/usage/collect.d.ts +13 -0
- package/dist/usage/collect.js +41 -2
- package/dist/usage/index.d.ts +1 -1
- package/dist/usage/index.js +1 -1
- package/dist/usage/summary.js +19 -0
- package/dist/usage/types.d.ts +63 -0
- package/dist/usage/types.js +9 -0
- package/package.json +1 -1
package/dist/agent/loop.js
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { CruxyError, providerUnsupported } from "../errors/index.js";
|
|
2
2
|
import { resolveTaskModel, } from "../routing/index.js";
|
|
3
|
+
import { accumulateCacheTokens } from "../usage/collect.js";
|
|
3
4
|
import { buildSystemPrompt } from "./prompts.js";
|
|
4
5
|
import { resolveShell } from "../tools/shell/resolve-shell.js";
|
|
5
6
|
/** Tools whose successful call is a file change (drives the `on-file-change`
|
|
@@ -155,12 +156,14 @@ async function driveLoop(args, renderer, routed) {
|
|
|
155
156
|
case "usage":
|
|
156
157
|
usage.input_tokens = ev.usage.input_tokens || usage.input_tokens;
|
|
157
158
|
usage.output_tokens += ev.usage.output_tokens;
|
|
159
|
+
accumulateCacheTokens(usage, ev.usage);
|
|
158
160
|
// Mirror the accumulation into the per-request figure the telemetry
|
|
159
161
|
// callback reports (same last-non-zero-in / summed-out semantics).
|
|
160
162
|
sawUsage = true;
|
|
161
163
|
reqUsage.input_tokens =
|
|
162
164
|
ev.usage.input_tokens || reqUsage.input_tokens;
|
|
163
165
|
reqUsage.output_tokens += ev.usage.output_tokens;
|
|
166
|
+
accumulateCacheTokens(reqUsage, ev.usage);
|
|
164
167
|
break;
|
|
165
168
|
case "message_stop":
|
|
166
169
|
// Turn complete; the stream ends after this.
|
package/dist/agent/session.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { randomUUID } from "node:crypto";
|
|
2
2
|
import { loadProjectInstructions } from "../config/index.js";
|
|
3
3
|
import { resolveTaskModel } from "../routing/index.js";
|
|
4
|
-
import { UsageCollector, } from "../usage/index.js";
|
|
4
|
+
import { UsageCollector, accumulateCacheTokens, } from "../usage/index.js";
|
|
5
5
|
import { Budget } from "./budget.js";
|
|
6
6
|
import { runAgent, } from "./loop.js";
|
|
7
7
|
import { SUMMARY_SYSTEM, COMPACTION_MARKER } from "./prompts.js";
|
|
@@ -345,6 +345,7 @@ export class Session {
|
|
|
345
345
|
case "usage":
|
|
346
346
|
usage.input_tokens = ev.usage.input_tokens || usage.input_tokens;
|
|
347
347
|
usage.output_tokens += ev.usage.output_tokens;
|
|
348
|
+
accumulateCacheTokens(usage, ev.usage);
|
|
348
349
|
sawUsage = true;
|
|
349
350
|
break;
|
|
350
351
|
case "error":
|
package/dist/theme/tokens.d.ts
CHANGED
|
@@ -43,6 +43,12 @@ export interface ThemeGlyphs {
|
|
|
43
43
|
arrow: string;
|
|
44
44
|
caretUp: string;
|
|
45
45
|
caretDown: string;
|
|
46
|
+
/**
|
|
47
|
+
* Cache-hit marker for the usage line (`cached ↻N`). Decorative — the word
|
|
48
|
+
* "cached" carries the meaning, so it degrades to empty on ASCII / screen
|
|
49
|
+
* reader rather than a cryptic symbol.
|
|
50
|
+
*/
|
|
51
|
+
cached: string;
|
|
46
52
|
/** Text-cursor bar in the fuzzy query line. */
|
|
47
53
|
cursorBar: string;
|
|
48
54
|
bullet: string;
|
package/dist/theme/tokens.js
CHANGED
|
@@ -20,6 +20,7 @@ export const UNICODE_GLYPHS = {
|
|
|
20
20
|
arrow: "→",
|
|
21
21
|
caretUp: "↑",
|
|
22
22
|
caretDown: "↓",
|
|
23
|
+
cached: "↻",
|
|
23
24
|
cursorBar: "▏",
|
|
24
25
|
bullet: "•",
|
|
25
26
|
sep: "·",
|
|
@@ -42,6 +43,7 @@ export const ASCII_GLYPHS = {
|
|
|
42
43
|
arrow: "->",
|
|
43
44
|
caretUp: "^",
|
|
44
45
|
caretDown: "v",
|
|
46
|
+
cached: "",
|
|
45
47
|
cursorBar: "|",
|
|
46
48
|
bullet: "*",
|
|
47
49
|
sep: "-",
|
|
@@ -68,6 +70,7 @@ export const SCREEN_READER_GLYPHS = {
|
|
|
68
70
|
arrow: "->",
|
|
69
71
|
caretUp: "up",
|
|
70
72
|
caretDown: "down",
|
|
73
|
+
cached: "",
|
|
71
74
|
cursorBar: "",
|
|
72
75
|
bullet: "-",
|
|
73
76
|
sep: "-",
|
package/dist/usage/collect.d.ts
CHANGED
|
@@ -11,6 +11,19 @@ import type { UsageRecord } from "./types.js";
|
|
|
11
11
|
* `Usage` and is stored as `0`. Nothing is estimated, re-tokenized, or
|
|
12
12
|
* zero-filled, and this module makes ZERO network calls.
|
|
13
13
|
*/
|
|
14
|
+
/**
|
|
15
|
+
* Fold a streamed {@link Usage} event's cache counters into an accumulator.
|
|
16
|
+
*
|
|
17
|
+
* Phase-A prompt caching (Anthropic dev path only) reports `cache_read_*` /
|
|
18
|
+
* `cache_creation_*` ONCE per request but echoes the same value on both the
|
|
19
|
+
* `message_start` and terminal `message_delta` usage events — so we ASSIGN
|
|
20
|
+
* (never `+=`) to avoid double-counting within a request. `undefined` is left
|
|
21
|
+
* untouched: a provider that doesn't cache (the cruxy gateway, OpenAI-compat)
|
|
22
|
+
* never sets these, so the accumulator's fields stay `undefined` — the honest
|
|
23
|
+
* "unknown", never a fabricated `0`. A real reported `0` (cache in play, no read
|
|
24
|
+
* this request) is captured as `0`.
|
|
25
|
+
*/
|
|
26
|
+
export declare function accumulateCacheTokens(acc: Usage, ev: Usage): void;
|
|
14
27
|
/** What the loop hands over for one completed request. */
|
|
15
28
|
export interface RequestUsage {
|
|
16
29
|
/** The routing tier (C.30) the request ran on, if routing was active. */
|
package/dist/usage/collect.js
CHANGED
|
@@ -1,3 +1,32 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Usage collection (C.22). Accumulates per-request usage exactly as the agent
|
|
3
|
+
* loop reports it — one {@link UsageEntry} per completed model request — and
|
|
4
|
+
* emits a {@link UsageRecord} for the run.
|
|
5
|
+
*
|
|
6
|
+
* The one honesty invariant: `usage: undefined` (the loop's signal that the
|
|
7
|
+
* provider returned NO usage event for a request) is recorded as `undefined`
|
|
8
|
+
* token counts — the honest "unknown". A provider-reported `0` arrives as a real
|
|
9
|
+
* `Usage` and is stored as `0`. Nothing is estimated, re-tokenized, or
|
|
10
|
+
* zero-filled, and this module makes ZERO network calls.
|
|
11
|
+
*/
|
|
12
|
+
/**
|
|
13
|
+
* Fold a streamed {@link Usage} event's cache counters into an accumulator.
|
|
14
|
+
*
|
|
15
|
+
* Phase-A prompt caching (Anthropic dev path only) reports `cache_read_*` /
|
|
16
|
+
* `cache_creation_*` ONCE per request but echoes the same value on both the
|
|
17
|
+
* `message_start` and terminal `message_delta` usage events — so we ASSIGN
|
|
18
|
+
* (never `+=`) to avoid double-counting within a request. `undefined` is left
|
|
19
|
+
* untouched: a provider that doesn't cache (the cruxy gateway, OpenAI-compat)
|
|
20
|
+
* never sets these, so the accumulator's fields stay `undefined` — the honest
|
|
21
|
+
* "unknown", never a fabricated `0`. A real reported `0` (cache in play, no read
|
|
22
|
+
* this request) is captured as `0`.
|
|
23
|
+
*/
|
|
24
|
+
export function accumulateCacheTokens(acc, ev) {
|
|
25
|
+
if (ev.cache_read_input_tokens !== undefined)
|
|
26
|
+
acc.cache_read_input_tokens = ev.cache_read_input_tokens;
|
|
27
|
+
if (ev.cache_creation_input_tokens !== undefined)
|
|
28
|
+
acc.cache_creation_input_tokens = ev.cache_creation_input_tokens;
|
|
29
|
+
}
|
|
1
30
|
const systemClock = () => new Date().toISOString();
|
|
2
31
|
export class UsageCollector {
|
|
3
32
|
now;
|
|
@@ -11,10 +40,20 @@ export class UsageCollector {
|
|
|
11
40
|
* nothing. A real reported `0` is preserved as `0`.
|
|
12
41
|
*/
|
|
13
42
|
record(req) {
|
|
43
|
+
const u = req.usage;
|
|
14
44
|
this.entries.push({
|
|
15
45
|
tier: req.tier,
|
|
16
|
-
inputTokens:
|
|
17
|
-
outputTokens:
|
|
46
|
+
inputTokens: u?.input_tokens,
|
|
47
|
+
outputTokens: u?.output_tokens,
|
|
48
|
+
// Cache counters are conditionally spread so an unreported field stays
|
|
49
|
+
// absent from the persisted entry (undefined ≠ 0) — only the Anthropic
|
|
50
|
+
// dev path ever populates them.
|
|
51
|
+
...(u?.cache_read_input_tokens !== undefined
|
|
52
|
+
? { cacheReadTokens: u.cache_read_input_tokens }
|
|
53
|
+
: {}),
|
|
54
|
+
...(u?.cache_creation_input_tokens !== undefined
|
|
55
|
+
? { cacheCreationTokens: u.cache_creation_input_tokens }
|
|
56
|
+
: {}),
|
|
18
57
|
at: this.now(),
|
|
19
58
|
});
|
|
20
59
|
}
|
package/dist/usage/index.d.ts
CHANGED
|
@@ -9,7 +9,7 @@
|
|
|
9
9
|
* ships nothing that sends. Asserted by the runtime + static no-phone-home tests.
|
|
10
10
|
*/
|
|
11
11
|
export * from "./types.js";
|
|
12
|
-
export { UsageCollector, type RequestUsage, type Clock } from "./collect.js";
|
|
12
|
+
export { UsageCollector, accumulateCacheTokens, type RequestUsage, type Clock, } from "./collect.js";
|
|
13
13
|
export { costFor, priceForTier } from "./cost.js";
|
|
14
14
|
export { loadUsage, appendRun, usageStorePath } from "./store.js";
|
|
15
15
|
export { summarizeRuns, renderSummary, formatCost, type SummarizeOptions, } from "./summary.js";
|
package/dist/usage/index.js
CHANGED
|
@@ -9,7 +9,7 @@
|
|
|
9
9
|
* ships nothing that sends. Asserted by the runtime + static no-phone-home tests.
|
|
10
10
|
*/
|
|
11
11
|
export * from "./types.js";
|
|
12
|
-
export { UsageCollector } from "./collect.js";
|
|
12
|
+
export { UsageCollector, accumulateCacheTokens, } from "./collect.js";
|
|
13
13
|
export { costFor, priceForTier } from "./cost.js";
|
|
14
14
|
export { loadUsage, appendRun, usageStorePath } from "./store.js";
|
|
15
15
|
export { summarizeRuns, renderSummary, formatCost, } from "./summary.js";
|
package/dist/usage/summary.js
CHANGED
|
@@ -5,6 +5,8 @@ export function summarizeRuns(runs, opts) {
|
|
|
5
5
|
const byTier = new Map();
|
|
6
6
|
let totalInputTokens;
|
|
7
7
|
let totalOutputTokens;
|
|
8
|
+
let totalCacheReadTokens;
|
|
9
|
+
let totalCacheCreationTokens;
|
|
8
10
|
let requests = 0;
|
|
9
11
|
let requestsWithoutUsage = 0;
|
|
10
12
|
const addKnown = (acc, v) => (v === undefined ? acc : (acc ?? 0) + v);
|
|
@@ -16,6 +18,8 @@ export function summarizeRuns(runs, opts) {
|
|
|
16
18
|
requestsWithoutUsage++;
|
|
17
19
|
totalInputTokens = addKnown(totalInputTokens, e.inputTokens);
|
|
18
20
|
totalOutputTokens = addKnown(totalOutputTokens, e.outputTokens);
|
|
21
|
+
totalCacheReadTokens = addKnown(totalCacheReadTokens, e.cacheReadTokens);
|
|
22
|
+
totalCacheCreationTokens = addKnown(totalCacheCreationTokens, e.cacheCreationTokens);
|
|
19
23
|
// Per-tier attribution only for entries that carry a tier. Untiered
|
|
20
24
|
// requests (routing inert) still count toward totals — the total stays
|
|
21
25
|
// honest — but there is no tier label to bucket them under.
|
|
@@ -29,6 +33,8 @@ export function summarizeRuns(runs, opts) {
|
|
|
29
33
|
b.requestsWithoutUsage++;
|
|
30
34
|
b.inputTokens = addKnown(b.inputTokens, e.inputTokens);
|
|
31
35
|
b.outputTokens = addKnown(b.outputTokens, e.outputTokens);
|
|
36
|
+
b.cacheReadTokens = addKnown(b.cacheReadTokens, e.cacheReadTokens);
|
|
37
|
+
b.cacheCreationTokens = addKnown(b.cacheCreationTokens, e.cacheCreationTokens);
|
|
32
38
|
byTier.set(e.tier, b);
|
|
33
39
|
}
|
|
34
40
|
}
|
|
@@ -37,6 +43,8 @@ export function summarizeRuns(runs, opts) {
|
|
|
37
43
|
tier,
|
|
38
44
|
inputTokens: b.inputTokens,
|
|
39
45
|
outputTokens: b.outputTokens,
|
|
46
|
+
cacheReadTokens: b.cacheReadTokens,
|
|
47
|
+
cacheCreationTokens: b.cacheCreationTokens,
|
|
40
48
|
requests: b.requests,
|
|
41
49
|
requestsWithoutUsage: b.requestsWithoutUsage,
|
|
42
50
|
cost: costFor(tier, b.inputTokens, b.outputTokens, opts.prices),
|
|
@@ -50,6 +58,8 @@ export function summarizeRuns(runs, opts) {
|
|
|
50
58
|
perTier,
|
|
51
59
|
totalInputTokens,
|
|
52
60
|
totalOutputTokens,
|
|
61
|
+
totalCacheReadTokens,
|
|
62
|
+
totalCacheCreationTokens,
|
|
53
63
|
totalCost,
|
|
54
64
|
priced,
|
|
55
65
|
currency: opts.currency,
|
|
@@ -106,6 +116,15 @@ export function renderSummary(summary, t) {
|
|
|
106
116
|
parts.push(totalKnown
|
|
107
117
|
? `${t.strong("total")} ${tokenText(summary.totalInputTokens, summary.totalOutputTokens, t)}${t.muted(totalCost)}`
|
|
108
118
|
: `${t.strong("total")} —`);
|
|
119
|
+
// Cache reads (phase-A caching, Anthropic dev path): shown ONLY when the
|
|
120
|
+
// provider actually reported cache usage — `undefined` on the cruxy gateway
|
|
121
|
+
// and every OpenAI-compat path, so normal users never see this segment. A
|
|
122
|
+
// reported 0 IS shown (`cached ↻0`): honest proof the counter is flowing,
|
|
123
|
+
// e.g. the first request of a run that writes the cache but reads nothing.
|
|
124
|
+
if (summary.totalCacheReadTokens !== undefined) {
|
|
125
|
+
const glyph = t.glyph.cached;
|
|
126
|
+
parts.push(t.muted(`cached ${glyph}${formatTokens(summary.totalCacheReadTokens)}`));
|
|
127
|
+
}
|
|
109
128
|
// The honesty guard on display: a visible note whenever any request went
|
|
110
129
|
// unreported, so the total above is never read as the whole story.
|
|
111
130
|
if (summary.requestsWithoutUsage > 0) {
|
package/dist/usage/types.d.ts
CHANGED
|
@@ -22,6 +22,15 @@ export declare const UsageEntrySchema: z.ZodObject<{
|
|
|
22
22
|
inputTokens: z.ZodOptional<z.ZodNumber>;
|
|
23
23
|
/** Provider-reported completion tokens; `undefined` ⇔ no usage was reported. */
|
|
24
24
|
outputTokens: z.ZodOptional<z.ZodNumber>;
|
|
25
|
+
/**
|
|
26
|
+
* Prompt-cache tokens READ from a warm cache (phase-A caching, Anthropic dev
|
|
27
|
+
* path). `undefined` ⇔ the provider doesn't cache / reported nothing (the
|
|
28
|
+
* cruxy gateway today) — never zero-filled. Optional, so older on-disk
|
|
29
|
+
* entries without the field still parse.
|
|
30
|
+
*/
|
|
31
|
+
cacheReadTokens: z.ZodOptional<z.ZodNumber>;
|
|
32
|
+
/** Prompt-cache tokens WRITTEN this request (the ~1.25× write premium); same `undefined`-≠-0 rule. */
|
|
33
|
+
cacheCreationTokens: z.ZodOptional<z.ZodNumber>;
|
|
25
34
|
/** ISO-8601 timestamp the request completed. */
|
|
26
35
|
at: z.ZodString;
|
|
27
36
|
}, "strict", z.ZodTypeAny, {
|
|
@@ -29,11 +38,15 @@ export declare const UsageEntrySchema: z.ZodObject<{
|
|
|
29
38
|
tier?: string | undefined;
|
|
30
39
|
inputTokens?: number | undefined;
|
|
31
40
|
outputTokens?: number | undefined;
|
|
41
|
+
cacheReadTokens?: number | undefined;
|
|
42
|
+
cacheCreationTokens?: number | undefined;
|
|
32
43
|
}, {
|
|
33
44
|
at: string;
|
|
34
45
|
tier?: string | undefined;
|
|
35
46
|
inputTokens?: number | undefined;
|
|
36
47
|
outputTokens?: number | undefined;
|
|
48
|
+
cacheReadTokens?: number | undefined;
|
|
49
|
+
cacheCreationTokens?: number | undefined;
|
|
37
50
|
}>;
|
|
38
51
|
export type UsageEntry = z.infer<typeof UsageEntrySchema>;
|
|
39
52
|
/** One run's usage: an ordered list of per-request entries. */
|
|
@@ -51,6 +64,15 @@ export declare const UsageRecordSchema: z.ZodObject<{
|
|
|
51
64
|
inputTokens: z.ZodOptional<z.ZodNumber>;
|
|
52
65
|
/** Provider-reported completion tokens; `undefined` ⇔ no usage was reported. */
|
|
53
66
|
outputTokens: z.ZodOptional<z.ZodNumber>;
|
|
67
|
+
/**
|
|
68
|
+
* Prompt-cache tokens READ from a warm cache (phase-A caching, Anthropic dev
|
|
69
|
+
* path). `undefined` ⇔ the provider doesn't cache / reported nothing (the
|
|
70
|
+
* cruxy gateway today) — never zero-filled. Optional, so older on-disk
|
|
71
|
+
* entries without the field still parse.
|
|
72
|
+
*/
|
|
73
|
+
cacheReadTokens: z.ZodOptional<z.ZodNumber>;
|
|
74
|
+
/** Prompt-cache tokens WRITTEN this request (the ~1.25× write premium); same `undefined`-≠-0 rule. */
|
|
75
|
+
cacheCreationTokens: z.ZodOptional<z.ZodNumber>;
|
|
54
76
|
/** ISO-8601 timestamp the request completed. */
|
|
55
77
|
at: z.ZodString;
|
|
56
78
|
}, "strict", z.ZodTypeAny, {
|
|
@@ -58,11 +80,15 @@ export declare const UsageRecordSchema: z.ZodObject<{
|
|
|
58
80
|
tier?: string | undefined;
|
|
59
81
|
inputTokens?: number | undefined;
|
|
60
82
|
outputTokens?: number | undefined;
|
|
83
|
+
cacheReadTokens?: number | undefined;
|
|
84
|
+
cacheCreationTokens?: number | undefined;
|
|
61
85
|
}, {
|
|
62
86
|
at: string;
|
|
63
87
|
tier?: string | undefined;
|
|
64
88
|
inputTokens?: number | undefined;
|
|
65
89
|
outputTokens?: number | undefined;
|
|
90
|
+
cacheReadTokens?: number | undefined;
|
|
91
|
+
cacheCreationTokens?: number | undefined;
|
|
66
92
|
}>, "many">;
|
|
67
93
|
}, "strict", z.ZodTypeAny, {
|
|
68
94
|
entries: {
|
|
@@ -70,6 +96,8 @@ export declare const UsageRecordSchema: z.ZodObject<{
|
|
|
70
96
|
tier?: string | undefined;
|
|
71
97
|
inputTokens?: number | undefined;
|
|
72
98
|
outputTokens?: number | undefined;
|
|
99
|
+
cacheReadTokens?: number | undefined;
|
|
100
|
+
cacheCreationTokens?: number | undefined;
|
|
73
101
|
}[];
|
|
74
102
|
runId: string;
|
|
75
103
|
startedAt: string;
|
|
@@ -80,6 +108,8 @@ export declare const UsageRecordSchema: z.ZodObject<{
|
|
|
80
108
|
tier?: string | undefined;
|
|
81
109
|
inputTokens?: number | undefined;
|
|
82
110
|
outputTokens?: number | undefined;
|
|
111
|
+
cacheReadTokens?: number | undefined;
|
|
112
|
+
cacheCreationTokens?: number | undefined;
|
|
83
113
|
}[];
|
|
84
114
|
runId: string;
|
|
85
115
|
startedAt: string;
|
|
@@ -103,6 +133,15 @@ export declare const UsageFileSchema: z.ZodObject<{
|
|
|
103
133
|
inputTokens: z.ZodOptional<z.ZodNumber>;
|
|
104
134
|
/** Provider-reported completion tokens; `undefined` ⇔ no usage was reported. */
|
|
105
135
|
outputTokens: z.ZodOptional<z.ZodNumber>;
|
|
136
|
+
/**
|
|
137
|
+
* Prompt-cache tokens READ from a warm cache (phase-A caching, Anthropic dev
|
|
138
|
+
* path). `undefined` ⇔ the provider doesn't cache / reported nothing (the
|
|
139
|
+
* cruxy gateway today) — never zero-filled. Optional, so older on-disk
|
|
140
|
+
* entries without the field still parse.
|
|
141
|
+
*/
|
|
142
|
+
cacheReadTokens: z.ZodOptional<z.ZodNumber>;
|
|
143
|
+
/** Prompt-cache tokens WRITTEN this request (the ~1.25× write premium); same `undefined`-≠-0 rule. */
|
|
144
|
+
cacheCreationTokens: z.ZodOptional<z.ZodNumber>;
|
|
106
145
|
/** ISO-8601 timestamp the request completed. */
|
|
107
146
|
at: z.ZodString;
|
|
108
147
|
}, "strict", z.ZodTypeAny, {
|
|
@@ -110,11 +149,15 @@ export declare const UsageFileSchema: z.ZodObject<{
|
|
|
110
149
|
tier?: string | undefined;
|
|
111
150
|
inputTokens?: number | undefined;
|
|
112
151
|
outputTokens?: number | undefined;
|
|
152
|
+
cacheReadTokens?: number | undefined;
|
|
153
|
+
cacheCreationTokens?: number | undefined;
|
|
113
154
|
}, {
|
|
114
155
|
at: string;
|
|
115
156
|
tier?: string | undefined;
|
|
116
157
|
inputTokens?: number | undefined;
|
|
117
158
|
outputTokens?: number | undefined;
|
|
159
|
+
cacheReadTokens?: number | undefined;
|
|
160
|
+
cacheCreationTokens?: number | undefined;
|
|
118
161
|
}>, "many">;
|
|
119
162
|
}, "strict", z.ZodTypeAny, {
|
|
120
163
|
entries: {
|
|
@@ -122,6 +165,8 @@ export declare const UsageFileSchema: z.ZodObject<{
|
|
|
122
165
|
tier?: string | undefined;
|
|
123
166
|
inputTokens?: number | undefined;
|
|
124
167
|
outputTokens?: number | undefined;
|
|
168
|
+
cacheReadTokens?: number | undefined;
|
|
169
|
+
cacheCreationTokens?: number | undefined;
|
|
125
170
|
}[];
|
|
126
171
|
runId: string;
|
|
127
172
|
startedAt: string;
|
|
@@ -132,6 +177,8 @@ export declare const UsageFileSchema: z.ZodObject<{
|
|
|
132
177
|
tier?: string | undefined;
|
|
133
178
|
inputTokens?: number | undefined;
|
|
134
179
|
outputTokens?: number | undefined;
|
|
180
|
+
cacheReadTokens?: number | undefined;
|
|
181
|
+
cacheCreationTokens?: number | undefined;
|
|
135
182
|
}[];
|
|
136
183
|
runId: string;
|
|
137
184
|
startedAt: string;
|
|
@@ -145,6 +192,8 @@ export declare const UsageFileSchema: z.ZodObject<{
|
|
|
145
192
|
tier?: string | undefined;
|
|
146
193
|
inputTokens?: number | undefined;
|
|
147
194
|
outputTokens?: number | undefined;
|
|
195
|
+
cacheReadTokens?: number | undefined;
|
|
196
|
+
cacheCreationTokens?: number | undefined;
|
|
148
197
|
}[];
|
|
149
198
|
runId: string;
|
|
150
199
|
startedAt: string;
|
|
@@ -158,6 +207,8 @@ export declare const UsageFileSchema: z.ZodObject<{
|
|
|
158
207
|
tier?: string | undefined;
|
|
159
208
|
inputTokens?: number | undefined;
|
|
160
209
|
outputTokens?: number | undefined;
|
|
210
|
+
cacheReadTokens?: number | undefined;
|
|
211
|
+
cacheCreationTokens?: number | undefined;
|
|
161
212
|
}[];
|
|
162
213
|
runId: string;
|
|
163
214
|
startedAt: string;
|
|
@@ -191,6 +242,10 @@ export interface TierUsage {
|
|
|
191
242
|
inputTokens?: number;
|
|
192
243
|
/** Sum of KNOWN output tokens; `undefined` if none reported. */
|
|
193
244
|
outputTokens?: number;
|
|
245
|
+
/** Sum of KNOWN cache-read tokens on this tier; `undefined` if none reported. */
|
|
246
|
+
cacheReadTokens?: number;
|
|
247
|
+
/** Sum of KNOWN cache-creation tokens on this tier; `undefined` if none reported. */
|
|
248
|
+
cacheCreationTokens?: number;
|
|
194
249
|
/** Requests attributed to this tier. */
|
|
195
250
|
requests: number;
|
|
196
251
|
/** How many of those reported no usage (surfaced, never silently dropped). */
|
|
@@ -205,6 +260,14 @@ export interface UsageSummary {
|
|
|
205
260
|
totalInputTokens?: number;
|
|
206
261
|
/** Sum of KNOWN output tokens across all runs; `undefined` if none known. */
|
|
207
262
|
totalOutputTokens?: number;
|
|
263
|
+
/**
|
|
264
|
+
* Sum of KNOWN cache-read tokens across all runs; `undefined` if none known
|
|
265
|
+
* (i.e. every request ran on a non-caching provider). Drives the `cached ↻N`
|
|
266
|
+
* figure, which is the observable proof that phase-A caching is working.
|
|
267
|
+
*/
|
|
268
|
+
totalCacheReadTokens?: number;
|
|
269
|
+
/** Sum of KNOWN cache-creation tokens across all runs; `undefined` if none known. */
|
|
270
|
+
totalCacheCreationTokens?: number;
|
|
208
271
|
/** Sum of per-tier costs; `undefined` unless ≥1 tier was priced. */
|
|
209
272
|
totalCost?: number;
|
|
210
273
|
/** True iff at least one tier had a configured price (cost is shown). */
|
package/dist/usage/types.js
CHANGED
|
@@ -22,6 +22,15 @@ export const UsageEntrySchema = z
|
|
|
22
22
|
inputTokens: z.number().int().nonnegative().optional(),
|
|
23
23
|
/** Provider-reported completion tokens; `undefined` ⇔ no usage was reported. */
|
|
24
24
|
outputTokens: z.number().int().nonnegative().optional(),
|
|
25
|
+
/**
|
|
26
|
+
* Prompt-cache tokens READ from a warm cache (phase-A caching, Anthropic dev
|
|
27
|
+
* path). `undefined` ⇔ the provider doesn't cache / reported nothing (the
|
|
28
|
+
* cruxy gateway today) — never zero-filled. Optional, so older on-disk
|
|
29
|
+
* entries without the field still parse.
|
|
30
|
+
*/
|
|
31
|
+
cacheReadTokens: z.number().int().nonnegative().optional(),
|
|
32
|
+
/** Prompt-cache tokens WRITTEN this request (the ~1.25× write premium); same `undefined`-≠-0 rule. */
|
|
33
|
+
cacheCreationTokens: z.number().int().nonnegative().optional(),
|
|
25
34
|
/** ISO-8601 timestamp the request completed. */
|
|
26
35
|
at: z.string(),
|
|
27
36
|
})
|