@cat-factory/contracts 0.276.0 → 0.278.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.
@@ -0,0 +1,207 @@
1
+ import * as v from 'valibot';
2
+ // ---------------------------------------------------------------------------
3
+ // Public spend analytics (`GET /api/v1/usage/spend`): the workspace's money sliced by the
4
+ // dimension a budget is actually kept against.
5
+ //
6
+ // `GET /api/v1/usage` answers "how much has this board spent THIS PERIOD, and is it paused",
7
+ // grouped by `(billing, vendor, provider, model)`. That is the budget question. It cannot
8
+ // answer the TCO one (what did this repository cost us last quarter, what did that ticket
9
+ // cost, what did one pipeline run cost), because it carries no board-shape axis and no window
10
+ // but the current calendar month. Inside the product those answers already exist (the Reports
11
+ // panel reads them account-wide behind the admin gate, served for the long windows from the
12
+ // durable `spend_days` rollup); outside it there was nothing, so an external cost dashboard
13
+ // had to re-derive attribution it could not see.
14
+ //
15
+ // The shapes here are deliberately their OWN projection rather than the internal report rows,
16
+ // exactly as `publicUsageRow` is a projection of `UsageBreakdownRow`: everything on this page
17
+ // is frozen by the public-API stability contract, and an internal analytics shape must stay
18
+ // free to change. That covers the VOCABULARIES too, which are declared below rather than
19
+ // aliased off `reports.ts`: an alias makes an internal rename a silent `/api/v1` break, where a
20
+ // declaration turns the same edit into a failing assertion in `public-spend.test.ts` naming
21
+ // this file as the thing that has to decide.
22
+ // ---------------------------------------------------------------------------
23
+ /**
24
+ * The time window a breakdown aggregates over, measured back from `generatedAt` and snapped
25
+ * DOWN to a bucket edge (see {@link publicSpendSchema}'s `since`).
26
+ *
27
+ * Same members as the internal `reportWindowSchema` in `reports.ts`, and `public-spend.test.ts`
28
+ * asserts the two stay in step, but this is the FROZEN copy: adding a
29
+ * window internally does not publish it, and removing one internally has to arrive here as a
30
+ * deliberate `/api/v1` decision rather than as a member that quietly stopped being accepted.
31
+ */
32
+ export const publicSpendWindowSchema = v.picklist(['24h', '7d', '30d', '90d']);
33
+ /**
34
+ * Which store answered a breakdown. Frozen here for the same reason the window is: this is a
35
+ * value an external consumer branches on, so the internal spelling of it is not free to move.
36
+ */
37
+ export const publicSpendSourceSchema = v.picklist(['ledger', 'daily-rollup']);
38
+ /**
39
+ * Hard ceiling on the slices one response may carry.
40
+ *
41
+ * A real bound rather than a suggestion: two of the published dimensions grow with ACTIVITY
42
+ * rather than with a catalog (`run` is one row per pipeline execution, `ticket` one per issue
43
+ * a run touched), so an unbounded `90d` breakdown on a busy board is a response nobody sized.
44
+ * The rows are heaviest first, so the cap is a prefix by cost: the slice a cost question is
45
+ * about, with {@link publicSpendSchema}'s `truncated` saying when there was a tail.
46
+ */
47
+ export const PUBLIC_SPEND_MAX_ROWS = 500;
48
+ /**
49
+ * What a public spend breakdown groups by.
50
+ *
51
+ * The two axes this surface exists for are `repo` and `ticket`: what an organisation budgets
52
+ * against, and the pair no other public read can produce. `run` is the finest of the three
53
+ * (one pipeline execution, end to end), and the rest are the same slices the usage read
54
+ * already implies, offered here because they come from one grouped query rather than four.
55
+ */
56
+ export const publicSpendDimensionSchema = v.picklist([
57
+ 'model',
58
+ 'agentKind',
59
+ 'service',
60
+ 'repo',
61
+ 'taskType',
62
+ 'ticket',
63
+ 'run',
64
+ ]);
65
+ /**
66
+ * The spend dimensions this surface deliberately does NOT offer, each with the reason.
67
+ *
68
+ * Stated rather than left as an absence, and paired with a test asserting every internal
69
+ * `reportSpendDimensionSchema` member is EXACTLY ONCE across the two lists: a dimension
70
+ * added internally then has to be either published or explained, instead of silently missing
71
+ * from the surface that four SDKs are generated against.
72
+ */
73
+ export const PUBLIC_SPEND_DIMENSIONS_OMITTED = {
74
+ workspace: 'Every key is bound to one workspace, so this axis would return a single row naming the ' +
75
+ 'board the caller already addressed. The account-wide view it exists for is admin-gated ' +
76
+ 'and cross-workspace, which is exactly what a workspace-scoped key must never reach.',
77
+ };
78
+ /**
79
+ * One slice of a spend breakdown.
80
+ *
81
+ * `key` is the raw dimension value and the row's identity; the EMPTY string is a real bucket
82
+ * meaning UNATTRIBUTED (a call whose run, service, repository or ticket could not be resolved),
83
+ * never a dropped row. Dropping it would under-report the window while the breakdown still
84
+ * looked complete, which is the one thing `totals` and `truncated` exist to prevent.
85
+ *
86
+ * The two costs are separate on purpose and must never be summed: only `meteredCost` is money.
87
+ * `subscriptionCost` is what the same tokens WOULD have cost on the metered API, which is what
88
+ * a flat-rate harness plan (Claude Code, Codex, …) spends nothing per token on, and it is why
89
+ * the spend budget excludes it.
90
+ */
91
+ export const publicSpendRowSchema = v.object({
92
+ key: v.string(),
93
+ /**
94
+ * A display name for `key` where the store can resolve one (a service's frame title, a
95
+ * repository's `owner/name`, the title of the block a run targets); null where the key is
96
+ * self-describing (a model id, an agent kind, a task type) or where nothing could be joined
97
+ * (a repository this board holds no projection row for keeps its money and loses its name).
98
+ */
99
+ label: v.nullable(v.string()),
100
+ inputTokens: v.number(),
101
+ outputTokens: v.number(),
102
+ /** Recorded LLM calls in this slice, both billing kinds. */
103
+ calls: v.number(),
104
+ /** Real per-token cost, in the response's `currency`. */
105
+ meteredCost: v.number(),
106
+ /** Illustrative equivalent-API cost of flat-rate subscription usage. Never real spend. */
107
+ subscriptionCost: v.number(),
108
+ });
109
+ /**
110
+ * Window-wide totals, over EVERY slice the window holds rather than only the ones `rows`
111
+ * carries. So a `truncated` breakdown still reports what the board actually spent, the same
112
+ * rule the run LLM export states about its own rollups, and a caller reading the top twenty
113
+ * repositories can still say what share of the bill they are. On an untruncated response the
114
+ * rows sum to exactly this.
115
+ */
116
+ export const publicSpendTotalsSchema = v.object({
117
+ inputTokens: v.number(),
118
+ outputTokens: v.number(),
119
+ calls: v.number(),
120
+ meteredCost: v.number(),
121
+ subscriptionCost: v.number(),
122
+ });
123
+ /** Query of `GET /api/v1/usage/spend`. */
124
+ export const publicSpendQuerySchema = v.object({
125
+ dimension: publicSpendDimensionSchema,
126
+ /** Defaults to `7d`, the widest window served live off the ledger. */
127
+ window: v.optional(publicSpendWindowSchema),
128
+ /**
129
+ * How many SLICES to return, 1..{@link PUBLIC_SPEND_MAX_ROWS} (default 100), heaviest first.
130
+ * `totals` is unaffected: it aggregates the whole window whatever this says, so a capped
131
+ * response still reports what the board spent.
132
+ *
133
+ * Digit-checked before the numeric coercion, like every other query number on this API:
134
+ * bare `Number()` also accepts `1e9`, `0x64` and `' '`, which read as plausible values
135
+ * rather than as the 400 a malformed request has earned.
136
+ */
137
+ limit: v.optional(v.pipe(v.string(), v.regex(/^\d+$/, 'Must be a whole number'), v.transform(Number), v.number(), v.integer(), v.minValue(1), v.maxValue(PUBLIC_SPEND_MAX_ROWS))),
138
+ });
139
+ /**
140
+ * The workspace's spend over a window, sliced one way.
141
+ *
142
+ * ONE dimension per request rather than every dimension at once (the shape the internal
143
+ * Reports panel reads): a panel renders all of them together, where a caller asks a question
144
+ * and each dimension is its own grouped query. Serving seven would make the common request
145
+ * seven times the work and the response mostly rows nobody asked for.
146
+ */
147
+ export const publicSpendSchema = v.object({
148
+ /** Echoes the requested dimension, so a stored response says what it grouped by. */
149
+ dimension: publicSpendDimensionSchema,
150
+ window: publicSpendWindowSchema,
151
+ /** When the breakdown was computed (epoch ms). */
152
+ generatedAt: v.number(),
153
+ /**
154
+ * Start of the window (epoch ms): `generatedAt - window`, snapped DOWN to a bucket edge, and
155
+ * the real span every number here was computed over. A window therefore covers up to one
156
+ * bucket more than its nominal length, which is why this is reported rather than left to be
157
+ * re-derived from `window`.
158
+ */
159
+ since: v.number(),
160
+ /** ISO 4217 currency both costs are denominated in (the deployment's base currency). */
161
+ currency: v.string(),
162
+ /**
163
+ * Which store answered: a live scan of the metered ledger (`ledger`, the `24h`/`7d` windows)
164
+ * or the durable daily cost-attribution rollup (`daily-rollup`, `30d`/`90d`).
165
+ *
166
+ * They differ in more than freshness. The ledger resolves a repository or a ticket through
167
+ * the LIVE links, so it re-attributes history whenever a service is re-pointed or an issue
168
+ * re-imported, and it forgets whatever retention has pruned. The rollup froze that
169
+ * attribution while the money was being spent and is never pruned, at the cost of being only
170
+ * as current as the last sweep. A reader comparing two windows has to know which is talking.
171
+ */
172
+ source: publicSpendSourceSchema,
173
+ /**
174
+ * On a `daily-rollup` window: the newest UTC day (epoch ms, midnight) the rollup sweep has
175
+ * covered, or null when no pass has ever completed. Always null on a `ledger` window, where
176
+ * there is no rollup in the path to be behind.
177
+ *
178
+ * Null is why the field exists: a rollup that has never run and a board that spent nothing
179
+ * produce the same empty breakdown, and they call for opposite reactions. Read it before
180
+ * reporting a quiet quarter.
181
+ */
182
+ rolledUpThrough: v.nullable(v.number()),
183
+ totals: publicSpendTotalsSchema,
184
+ /**
185
+ * True when the window holds more slices than `limit`, so `rows` is the heaviest prefix of
186
+ * them rather than all of them. STATED rather than left to be inferred from
187
+ * `rows.length === limit`, which cannot tell a board with exactly `limit` slices from one
188
+ * with a tail, and which is the reading that turns a capped list into a complete one.
189
+ *
190
+ * `totals` above is unaffected, so the share the returned rows account for is computable:
191
+ * what a truncated breakdown loses is the identity of the long tail, never its money.
192
+ */
193
+ truncated: v.boolean(),
194
+ /**
195
+ * The slices, heaviest by metered cost first, capped at `limit`.
196
+ *
197
+ * Capped rather than served whole because two of the published dimensions grow with
198
+ * ACTIVITY rather than with a catalog: `run` is one row per pipeline execution and `ticket`
199
+ * one per issue a run touched, so a busy board over `90d` is thousands of rows on a
200
+ * response nobody sized. (`model`, `agentKind`, `service`, `repo` and `taskType` all key on
201
+ * a catalog and stay small on their own.) The order is what makes the cap honest: a cost
202
+ * question is about the heavy end, `truncated` says when there was a tail, and `totals`
203
+ * still covers all of it.
204
+ */
205
+ rows: v.array(publicSpendRowSchema),
206
+ });
207
+ //# sourceMappingURL=public-spend.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"public-spend.js","sourceRoot":"","sources":["../src/public-spend.ts"],"names":[],"mappings":"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"}
@@ -551,6 +551,192 @@ export declare const getDebugLlmCallContract: {
551
551
  } & {
552
552
  readonly minScope: "read";
553
553
  };
554
+ /**
555
+ * The run's model activity as one self-describing bundle: the complete SQL rollups plus a
556
+ * bounded window of the calls behind them. The external counterpart of the app's own export
557
+ * button, and the one call a caller with a fixed context budget makes instead of the overview
558
+ * plus a walk of the call list.
559
+ */
560
+ export declare const getDebugLlmExportContract: {
561
+ readonly method: "get";
562
+ readonly requestPathParamsSchema: import("valibot").ObjectSchema<{
563
+ runId: import("valibot").StringSchema<undefined>;
564
+ }, undefined> & import("@toad-contracts/core").StandardObjectKeysV1<unknown, unknown>;
565
+ readonly pathResolver: ({ runId }: {
566
+ runId: string;
567
+ }) => string;
568
+ readonly requestQuerySchema: import("valibot").ObjectSchema<{
569
+ readonly limit: import("valibot").OptionalSchema<import("valibot").SchemaWithPipe<readonly [import("valibot").StringSchema<undefined>, import("valibot").RegexAction<string, "Must be a whole number">, import("valibot").TransformAction<any, number>, import("valibot").NumberSchema<undefined>, import("valibot").IntegerAction<number, undefined>, import("valibot").MinValueAction<number, 1, undefined>, import("valibot").MaxValueAction<number, 100, undefined>]>, undefined>;
570
+ readonly order: import("valibot").OptionalSchema<import("valibot").PicklistSchema<["oldest", "newest"], undefined>, undefined>;
571
+ readonly bodyChars: import("valibot").OptionalSchema<import("valibot").SchemaWithPipe<readonly [import("valibot").StringSchema<undefined>, import("valibot").RegexAction<string, "Must be a whole number">, import("valibot").TransformAction<any, number>, import("valibot").NumberSchema<undefined>, import("valibot").IntegerAction<number, undefined>, import("valibot").MinValueAction<number, 0, undefined>, import("valibot").MaxValueAction<number, 4000, undefined>]>, undefined>;
572
+ }, undefined>;
573
+ readonly responsesByStatusCode: {
574
+ readonly '4xx': import("valibot").ObjectSchema<{
575
+ readonly error: import("valibot").ObjectSchema<{
576
+ readonly code: import("valibot").StringSchema<undefined>;
577
+ readonly message: import("valibot").StringSchema<undefined>;
578
+ readonly details: import("valibot").OptionalSchema<import("valibot").UnknownSchema, undefined>;
579
+ readonly issues: import("valibot").OptionalSchema<import("valibot").ArraySchema<import("valibot").ObjectSchema<{
580
+ readonly path: import("valibot").OptionalSchema<import("valibot").StringSchema<undefined>, undefined>;
581
+ readonly message: import("valibot").StringSchema<undefined>;
582
+ }, undefined>, undefined>, undefined>;
583
+ }, undefined>;
584
+ }, undefined>;
585
+ readonly '5xx': import("valibot").ObjectSchema<{
586
+ readonly error: import("valibot").ObjectSchema<{
587
+ readonly code: import("valibot").StringSchema<undefined>;
588
+ readonly message: import("valibot").StringSchema<undefined>;
589
+ readonly details: import("valibot").OptionalSchema<import("valibot").UnknownSchema, undefined>;
590
+ readonly issues: import("valibot").OptionalSchema<import("valibot").ArraySchema<import("valibot").ObjectSchema<{
591
+ readonly path: import("valibot").OptionalSchema<import("valibot").StringSchema<undefined>, undefined>;
592
+ readonly message: import("valibot").StringSchema<undefined>;
593
+ }, undefined>, undefined>, undefined>;
594
+ }, undefined>;
595
+ }, undefined>;
596
+ readonly 200: import("valibot").ObjectSchema<{
597
+ readonly kind: import("valibot").LiteralSchema<"cat-factory.run-llm-export", undefined>;
598
+ readonly version: import("valibot").LiteralSchema<1, undefined>;
599
+ readonly runId: import("valibot").StringSchema<undefined>;
600
+ readonly generatedAt: import("valibot").NumberSchema<undefined>;
601
+ readonly available: import("valibot").BooleanSchema<undefined>;
602
+ readonly llm: import("valibot").ObjectSchema<{
603
+ readonly totals: import("valibot").ObjectSchema<{
604
+ readonly calls: import("valibot").NumberSchema<undefined>;
605
+ readonly promptTokens: import("valibot").NumberSchema<undefined>;
606
+ readonly cacheReadTokens: import("valibot").NumberSchema<undefined>;
607
+ readonly cacheWriteTokens: import("valibot").NumberSchema<undefined>;
608
+ readonly cacheHitRate: import("valibot").NullableSchema<import("valibot").NumberSchema<undefined>, undefined>;
609
+ readonly completionTokens: import("valibot").NumberSchema<undefined>;
610
+ readonly upstreamMs: import("valibot").NumberSchema<undefined>;
611
+ readonly overheadMs: import("valibot").NumberSchema<undefined>;
612
+ readonly transportOverheadRatio: import("valibot").NullableSchema<import("valibot").NumberSchema<undefined>, undefined>;
613
+ readonly errors: import("valibot").NumberSchema<undefined>;
614
+ readonly warnings: import("valibot").NumberSchema<undefined>;
615
+ readonly truncatedCalls: import("valibot").NumberSchema<undefined>;
616
+ readonly costEstimate: import("valibot").NullableSchema<import("valibot").NumberSchema<undefined>, undefined>;
617
+ }, undefined>;
618
+ readonly byAgentKind: import("valibot").ArraySchema<import("valibot").ObjectSchema<{
619
+ readonly agentKind: import("valibot").StringSchema<undefined>;
620
+ readonly calls: import("valibot").NumberSchema<undefined>;
621
+ readonly promptTokens: import("valibot").NumberSchema<undefined>;
622
+ readonly cacheReadTokens: import("valibot").NumberSchema<undefined>;
623
+ readonly cacheWriteTokens: import("valibot").NumberSchema<undefined>;
624
+ readonly cacheHitRate: import("valibot").NullableSchema<import("valibot").NumberSchema<undefined>, undefined>;
625
+ readonly completionTokens: import("valibot").NumberSchema<undefined>;
626
+ readonly peakCompletionTokens: import("valibot").NumberSchema<undefined>;
627
+ readonly maxOutputTokens: import("valibot").NullableSchema<import("valibot").NumberSchema<undefined>, undefined>;
628
+ readonly outputHeadroomRatio: import("valibot").NullableSchema<import("valibot").NumberSchema<undefined>, undefined>;
629
+ readonly truncatedCalls: import("valibot").NumberSchema<undefined>;
630
+ readonly upstreamMs: import("valibot").NumberSchema<undefined>;
631
+ readonly overheadMs: import("valibot").NumberSchema<undefined>;
632
+ readonly transportOverheadRatio: import("valibot").NullableSchema<import("valibot").NumberSchema<undefined>, undefined>;
633
+ readonly errors: import("valibot").NumberSchema<undefined>;
634
+ readonly warnings: import("valibot").NumberSchema<undefined>;
635
+ readonly costEstimate: import("valibot").NullableSchema<import("valibot").NumberSchema<undefined>, undefined>;
636
+ }, undefined>, undefined>;
637
+ readonly byPhase: import("valibot").ArraySchema<import("valibot").ObjectSchema<{
638
+ readonly phase: import("valibot").StringSchema<undefined>;
639
+ readonly calls: import("valibot").NumberSchema<undefined>;
640
+ readonly promptTokens: import("valibot").NumberSchema<undefined>;
641
+ readonly cacheReadTokens: import("valibot").NumberSchema<undefined>;
642
+ readonly cacheWriteTokens: import("valibot").NumberSchema<undefined>;
643
+ readonly cacheHitRate: import("valibot").NullableSchema<import("valibot").NumberSchema<undefined>, undefined>;
644
+ readonly completionTokens: import("valibot").NumberSchema<undefined>;
645
+ readonly carryCostTokens: import("valibot").NumberSchema<undefined>;
646
+ readonly carryCostShare: import("valibot").NullableSchema<import("valibot").NumberSchema<undefined>, undefined>;
647
+ readonly upstreamMs: import("valibot").NumberSchema<undefined>;
648
+ readonly overheadMs: import("valibot").NumberSchema<undefined>;
649
+ readonly errors: import("valibot").NumberSchema<undefined>;
650
+ readonly warnings: import("valibot").NumberSchema<undefined>;
651
+ readonly truncatedCalls: import("valibot").NumberSchema<undefined>;
652
+ readonly costEstimate: import("valibot").NullableSchema<import("valibot").NumberSchema<undefined>, undefined>;
653
+ }, undefined>, undefined>;
654
+ readonly costCurrency: import("valibot").NullableSchema<import("valibot").StringSchema<undefined>, undefined>;
655
+ }, undefined>;
656
+ readonly order: import("valibot").PicklistSchema<["oldest", "newest"], undefined>;
657
+ readonly truncated: import("valibot").BooleanSchema<undefined>;
658
+ readonly calls: import("valibot").ArraySchema<import("valibot").ObjectSchema<{
659
+ readonly callId: import("valibot").StringSchema<undefined>;
660
+ readonly runId: import("valibot").NullableSchema<import("valibot").StringSchema<undefined>, undefined>;
661
+ readonly agentKind: import("valibot").StringSchema<undefined>;
662
+ readonly provider: import("valibot").StringSchema<undefined>;
663
+ readonly model: import("valibot").StringSchema<undefined>;
664
+ readonly createdAt: import("valibot").NumberSchema<undefined>;
665
+ readonly outcome: import("valibot").PicklistSchema<["ok", "warning", "error"], undefined>;
666
+ readonly ok: import("valibot").BooleanSchema<undefined>;
667
+ readonly httpStatus: import("valibot").NullableSchema<import("valibot").NumberSchema<undefined>, undefined>;
668
+ readonly errorMessage: import("valibot").NullableSchema<import("valibot").StringSchema<undefined>, undefined>;
669
+ readonly finishReason: import("valibot").NullableSchema<import("valibot").StringSchema<undefined>, undefined>;
670
+ readonly streaming: import("valibot").BooleanSchema<undefined>;
671
+ readonly phase: import("valibot").StringSchema<undefined>;
672
+ readonly turnIndex: import("valibot").NullableSchema<import("valibot").NumberSchema<undefined>, undefined>;
673
+ readonly messageCount: import("valibot").NumberSchema<undefined>;
674
+ readonly toolCount: import("valibot").NumberSchema<undefined>;
675
+ readonly requestMaxTokens: import("valibot").NullableSchema<import("valibot").NumberSchema<undefined>, undefined>;
676
+ readonly promptTokens: import("valibot").NumberSchema<undefined>;
677
+ readonly cacheReadTokens: import("valibot").NumberSchema<undefined>;
678
+ readonly cacheWriteTokens: import("valibot").NumberSchema<undefined>;
679
+ readonly completionTokens: import("valibot").NumberSchema<undefined>;
680
+ readonly totalTokens: import("valibot").NumberSchema<undefined>;
681
+ readonly upstreamMs: import("valibot").NumberSchema<undefined>;
682
+ readonly overheadMs: import("valibot").NumberSchema<undefined>;
683
+ readonly totalMs: import("valibot").NumberSchema<undefined>;
684
+ readonly elidedLeadingMessages: import("valibot").NumberSchema<undefined>;
685
+ readonly prompt: import("valibot").ObjectSchema<{
686
+ readonly text: import("valibot").StringSchema<undefined>;
687
+ readonly chars: import("valibot").NumberSchema<undefined>;
688
+ readonly offset: import("valibot").NumberSchema<undefined>;
689
+ readonly totalChars: import("valibot").NumberSchema<undefined>;
690
+ readonly truncated: import("valibot").BooleanSchema<undefined>;
691
+ readonly matchOffset: import("valibot").OptionalSchema<import("valibot").NullableSchema<import("valibot").NumberSchema<undefined>, undefined>, undefined>;
692
+ }, undefined>;
693
+ readonly response: import("valibot").ObjectSchema<{
694
+ readonly text: import("valibot").StringSchema<undefined>;
695
+ readonly chars: import("valibot").NumberSchema<undefined>;
696
+ readonly offset: import("valibot").NumberSchema<undefined>;
697
+ readonly totalChars: import("valibot").NumberSchema<undefined>;
698
+ readonly truncated: import("valibot").BooleanSchema<undefined>;
699
+ readonly matchOffset: import("valibot").OptionalSchema<import("valibot").NullableSchema<import("valibot").NumberSchema<undefined>, undefined>, undefined>;
700
+ }, undefined>;
701
+ readonly reasoning: import("valibot").ObjectSchema<{
702
+ readonly text: import("valibot").StringSchema<undefined>;
703
+ readonly chars: import("valibot").NumberSchema<undefined>;
704
+ readonly offset: import("valibot").NumberSchema<undefined>;
705
+ readonly totalChars: import("valibot").NumberSchema<undefined>;
706
+ readonly truncated: import("valibot").BooleanSchema<undefined>;
707
+ readonly matchOffset: import("valibot").OptionalSchema<import("valibot").NullableSchema<import("valibot").NumberSchema<undefined>, undefined>, undefined>;
708
+ }, undefined>;
709
+ readonly promptMessages: import("valibot").OptionalSchema<import("valibot").NullableSchema<import("valibot").ArraySchema<import("valibot").ObjectSchema<{
710
+ readonly index: import("valibot").NumberSchema<undefined>;
711
+ readonly role: import("valibot").StringSchema<undefined>;
712
+ readonly name: import("valibot").NullableSchema<import("valibot").StringSchema<undefined>, undefined>;
713
+ readonly toolCallId: import("valibot").NullableSchema<import("valibot").StringSchema<undefined>, undefined>;
714
+ readonly toolCalls: import("valibot").ArraySchema<import("valibot").ObjectSchema<{
715
+ readonly name: import("valibot").StringSchema<undefined>;
716
+ readonly args: import("valibot").ObjectSchema<{
717
+ readonly text: import("valibot").StringSchema<undefined>;
718
+ readonly chars: import("valibot").NumberSchema<undefined>;
719
+ readonly offset: import("valibot").NumberSchema<undefined>;
720
+ readonly totalChars: import("valibot").NumberSchema<undefined>;
721
+ readonly truncated: import("valibot").BooleanSchema<undefined>;
722
+ readonly matchOffset: import("valibot").OptionalSchema<import("valibot").NullableSchema<import("valibot").NumberSchema<undefined>, undefined>, undefined>;
723
+ }, undefined>;
724
+ }, undefined>, undefined>;
725
+ readonly content: import("valibot").ObjectSchema<{
726
+ readonly text: import("valibot").StringSchema<undefined>;
727
+ readonly chars: import("valibot").NumberSchema<undefined>;
728
+ readonly offset: import("valibot").NumberSchema<undefined>;
729
+ readonly totalChars: import("valibot").NumberSchema<undefined>;
730
+ readonly truncated: import("valibot").BooleanSchema<undefined>;
731
+ readonly matchOffset: import("valibot").OptionalSchema<import("valibot").NullableSchema<import("valibot").NumberSchema<undefined>, undefined>, undefined>;
732
+ }, undefined>;
733
+ }, undefined>, undefined>, undefined>, undefined>;
734
+ }, undefined>, undefined>;
735
+ }, undefined>;
736
+ };
737
+ } & {
738
+ readonly minScope: "read";
739
+ };
554
740
  /** The run's captured agent-context dispatches, sizes only, keyset-paginated. */
555
741
  export declare const listDebugAgentContextContract: {
556
742
  readonly method: "get";
@@ -1 +1 @@
1
- {"version":3,"file":"debug-api.d.ts","sourceRoot":"","sources":["../../src/routes/debug-api.ts"],"names":[],"mappings":"AAuCA,8FAA8F;AAC9F,eAAO,MAAM,qBAAqB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAQjC,CAAA;AAED,6FAA6F;AAC7F,eAAO,MAAM,mBAAmB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAQ/B,CAAA;AAED,2FAA2F;AAC3F,eAAO,MAAM,yBAAyB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CASrC,CAAA;AAED,6FAA6F;AAC7F,eAAO,MAAM,uBAAuB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CASnC,CAAA;AAED,iFAAiF;AACjF,eAAO,MAAM,6BAA6B;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CASzC,CAAA;AAED,4FAA4F;AAC5F,eAAO,MAAM,4BAA4B;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CASxC,CAAA;AAED,qEAAqE;AACrE,eAAO,MAAM,8BAA8B;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAS1C,CAAA;AAED,mFAAmF;AACnF,eAAO,MAAM,0BAA0B;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAStC,CAAA;AAED,2FAA2F;AAC3F,eAAO,MAAM,qBAAqB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CASjC,CAAA"}
1
+ {"version":3,"file":"debug-api.d.ts","sourceRoot":"","sources":["../../src/routes/debug-api.ts"],"names":[],"mappings":"AAyCA,8FAA8F;AAC9F,eAAO,MAAM,qBAAqB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAQjC,CAAA;AAED,6FAA6F;AAC7F,eAAO,MAAM,mBAAmB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAQ/B,CAAA;AAED,2FAA2F;AAC3F,eAAO,MAAM,yBAAyB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CASrC,CAAA;AAED,6FAA6F;AAC7F,eAAO,MAAM,uBAAuB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CASnC,CAAA;AAED;;;;;GAKG;AACH,eAAO,MAAM,yBAAyB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CASrC,CAAA;AAED,iFAAiF;AACjF,eAAO,MAAM,6BAA6B;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CASzC,CAAA;AAED,4FAA4F;AAC5F,eAAO,MAAM,4BAA4B;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CASxC,CAAA;AAED,qEAAqE;AACrE,eAAO,MAAM,8BAA8B;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAS1C,CAAA;AAED,mFAAmF;AACnF,eAAO,MAAM,0BAA0B;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAStC,CAAA;AAED,2FAA2F;AAC3F,eAAO,MAAM,qBAAqB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CASjC,CAAA"}
@@ -1,5 +1,5 @@
1
1
  import { defineApiContract } from '@toad-contracts/valibot';
2
- import { debugAgentContextDetailSchema, debugAgentContextListSchema, debugLlmCallListSchema, debugLlmCallSchema, debugLogListSchema, debugRunListSchema, debugRunOverviewSchema, debugSearchQueryListSchema, debugToolCallListSchema, getDebugAgentContextQuerySchema, getDebugLlmCallQuerySchema, listDebugAgentContextQuerySchema, listDebugLlmCallsQuerySchema, listDebugPageQuerySchema, listDebugToolCallsQuerySchema, listDebugRunsQuerySchema, } from '../debug-api.js';
2
+ import { debugAgentContextDetailSchema, debugAgentContextListSchema, debugLlmCallListSchema, debugLlmCallSchema, debugLlmExportSchema, debugLogListSchema, debugRunListSchema, debugRunOverviewSchema, debugSearchQueryListSchema, debugToolCallListSchema, getDebugAgentContextQuerySchema, getDebugLlmCallQuerySchema, getDebugLlmExportQuerySchema, listDebugAgentContextQuerySchema, listDebugLlmCallsQuerySchema, listDebugPageQuerySchema, listDebugToolCallsQuerySchema, listDebugRunsQuerySchema, } from '../debug-api.js';
3
3
  import { errorResponses, singleStringParam, withMinScope } from './_shared.js';
4
4
  // ---------------------------------------------------------------------------
5
5
  // Route contracts for the REMOTE DEBUGGING surface (`/api/v1/debug/*`) — absolute paths,
@@ -47,6 +47,19 @@ export const getDebugLlmCallContract = withMinScope('read', defineApiContract({
47
47
  requestQuerySchema: getDebugLlmCallQuerySchema,
48
48
  responsesByStatusCode: { 200: debugLlmCallSchema, ...errorResponses },
49
49
  }));
50
+ /**
51
+ * The run's model activity as one self-describing bundle: the complete SQL rollups plus a
52
+ * bounded window of the calls behind them. The external counterpart of the app's own export
53
+ * button, and the one call a caller with a fixed context budget makes instead of the overview
54
+ * plus a walk of the call list.
55
+ */
56
+ export const getDebugLlmExportContract = withMinScope('read', defineApiContract({
57
+ method: 'get',
58
+ requestPathParamsSchema: runIdParams,
59
+ pathResolver: ({ runId }) => `/api/v1/debug/runs/${runId}/llm-export`,
60
+ requestQuerySchema: getDebugLlmExportQuerySchema,
61
+ responsesByStatusCode: { 200: debugLlmExportSchema, ...errorResponses },
62
+ }));
50
63
  /** The run's captured agent-context dispatches, sizes only, keyset-paginated. */
51
64
  export const listDebugAgentContextContract = withMinScope('read', defineApiContract({
52
65
  method: 'get',
@@ -1 +1 @@
1
- {"version":3,"file":"debug-api.js","sourceRoot":"","sources":["../../src/routes/debug-api.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"debug-api.js","sourceRoot":"","sources":["../../src/routes/debug-api.ts"],"names":[],"mappings":"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"}
@@ -1412,6 +1412,78 @@ export declare const getPublicUsageContract: {
1412
1412
  } & {
1413
1413
  readonly minScope: "read";
1414
1414
  };
1415
+ /**
1416
+ * The workspace's spend over a window, sliced by ONE dimension: the TCO read the period
1417
+ * breakdown above cannot produce: it groups by `(billing, vendor, provider, model)` within the
1418
+ * current calendar month, and carries no board-shape axis at all.
1419
+ *
1420
+ * A sub-resource of `/usage` rather than a surface of its own, because it is the same money
1421
+ * from the same ledger: `/usage` answers the budget question ("what has this period cost, and
1422
+ * are runs paused"), this answers the attribution one ("what did this repository / ticket /
1423
+ * run cost"). Scoped in SQL to the key's own workspace and its account, so `read` is the whole
1424
+ * scope story here too.
1425
+ */
1426
+ export declare const getPublicSpendContract: {
1427
+ readonly method: "get";
1428
+ readonly pathResolver: () => string;
1429
+ readonly requestQuerySchema: import("valibot").ObjectSchema<{
1430
+ readonly dimension: import("valibot").PicklistSchema<["model", "agentKind", "service", "repo", "taskType", "ticket", "run"], undefined>;
1431
+ readonly window: import("valibot").OptionalSchema<import("valibot").PicklistSchema<["24h", "7d", "30d", "90d"], undefined>, undefined>;
1432
+ readonly limit: import("valibot").OptionalSchema<import("valibot").SchemaWithPipe<readonly [import("valibot").StringSchema<undefined>, import("valibot").RegexAction<string, "Must be a whole number">, import("valibot").TransformAction<any, number>, import("valibot").NumberSchema<undefined>, import("valibot").IntegerAction<number, undefined>, import("valibot").MinValueAction<number, 1, undefined>, import("valibot").MaxValueAction<number, 500, undefined>]>, undefined>;
1433
+ }, undefined>;
1434
+ readonly responsesByStatusCode: {
1435
+ readonly '4xx': import("valibot").ObjectSchema<{
1436
+ readonly error: import("valibot").ObjectSchema<{
1437
+ readonly code: import("valibot").StringSchema<undefined>;
1438
+ readonly message: import("valibot").StringSchema<undefined>;
1439
+ readonly details: import("valibot").OptionalSchema<import("valibot").UnknownSchema, undefined>;
1440
+ readonly issues: import("valibot").OptionalSchema<import("valibot").ArraySchema<import("valibot").ObjectSchema<{
1441
+ readonly path: import("valibot").OptionalSchema<import("valibot").StringSchema<undefined>, undefined>;
1442
+ readonly message: import("valibot").StringSchema<undefined>;
1443
+ }, undefined>, undefined>, undefined>;
1444
+ }, undefined>;
1445
+ }, undefined>;
1446
+ readonly '5xx': import("valibot").ObjectSchema<{
1447
+ readonly error: import("valibot").ObjectSchema<{
1448
+ readonly code: import("valibot").StringSchema<undefined>;
1449
+ readonly message: import("valibot").StringSchema<undefined>;
1450
+ readonly details: import("valibot").OptionalSchema<import("valibot").UnknownSchema, undefined>;
1451
+ readonly issues: import("valibot").OptionalSchema<import("valibot").ArraySchema<import("valibot").ObjectSchema<{
1452
+ readonly path: import("valibot").OptionalSchema<import("valibot").StringSchema<undefined>, undefined>;
1453
+ readonly message: import("valibot").StringSchema<undefined>;
1454
+ }, undefined>, undefined>, undefined>;
1455
+ }, undefined>;
1456
+ }, undefined>;
1457
+ readonly 200: import("valibot").ObjectSchema<{
1458
+ readonly dimension: import("valibot").PicklistSchema<["model", "agentKind", "service", "repo", "taskType", "ticket", "run"], undefined>;
1459
+ readonly window: import("valibot").PicklistSchema<["24h", "7d", "30d", "90d"], undefined>;
1460
+ readonly generatedAt: import("valibot").NumberSchema<undefined>;
1461
+ readonly since: import("valibot").NumberSchema<undefined>;
1462
+ readonly currency: import("valibot").StringSchema<undefined>;
1463
+ readonly source: import("valibot").PicklistSchema<["ledger", "daily-rollup"], undefined>;
1464
+ readonly rolledUpThrough: import("valibot").NullableSchema<import("valibot").NumberSchema<undefined>, undefined>;
1465
+ readonly totals: import("valibot").ObjectSchema<{
1466
+ readonly inputTokens: import("valibot").NumberSchema<undefined>;
1467
+ readonly outputTokens: import("valibot").NumberSchema<undefined>;
1468
+ readonly calls: import("valibot").NumberSchema<undefined>;
1469
+ readonly meteredCost: import("valibot").NumberSchema<undefined>;
1470
+ readonly subscriptionCost: import("valibot").NumberSchema<undefined>;
1471
+ }, undefined>;
1472
+ readonly truncated: import("valibot").BooleanSchema<undefined>;
1473
+ readonly rows: import("valibot").ArraySchema<import("valibot").ObjectSchema<{
1474
+ readonly key: import("valibot").StringSchema<undefined>;
1475
+ readonly label: import("valibot").NullableSchema<import("valibot").StringSchema<undefined>, undefined>;
1476
+ readonly inputTokens: import("valibot").NumberSchema<undefined>;
1477
+ readonly outputTokens: import("valibot").NumberSchema<undefined>;
1478
+ readonly calls: import("valibot").NumberSchema<undefined>;
1479
+ readonly meteredCost: import("valibot").NumberSchema<undefined>;
1480
+ readonly subscriptionCost: import("valibot").NumberSchema<undefined>;
1481
+ }, undefined>, undefined>;
1482
+ }, undefined>;
1483
+ };
1484
+ } & {
1485
+ readonly minScope: "read";
1486
+ };
1415
1487
  /** List the workspace's live keys: metadata only; a secret is never readable back. */
1416
1488
  export declare const listPublicKeysContract: {
1417
1489
  readonly method: "get";
@@ -1 +1 @@
1
- {"version":3,"file":"public-api.d.ts","sourceRoot":"","sources":["../../src/routes/public-api.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"public-api.d.ts","sourceRoot":"","sources":["../../src/routes/public-api.ts"],"names":[],"mappings":"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"}
@@ -2,6 +2,7 @@ import { ContractNoBody, defineApiContract } from '@toad-contracts/valibot';
2
2
  import { createHeadlessPublicApiKeySchema, createPublicApiKeySchema, createdPublicApiKeySchema, HEADLESS_KEY_MINT_SCOPE, publicApiKeyListResultSchema, } from '../public-api-keys.js';
3
3
  import { notificationSchema } from '../notifications.js';
4
4
  import { createPublicJobSchema, createPublicTaskSchema, listPublicJobsQuerySchema, listPublicServiceTasksQuerySchema, publicJobAcceptedSchema, publicIdentitySchema, publicJobListSchema, publicJobSchema, publicNotificationListSchema, publicPipelineListSchema, publicRunSchema, publicServiceListSchema, publicTaskListSchema, publicTaskSchema, publicUsageSchema, startPublicTaskSchema, updatePublicTaskSchema, } from '../public-api.js';
5
+ import { publicSpendQuerySchema, publicSpendSchema } from '../public-spend.js';
5
6
  import { publicTaskTypeListSchema } from '../public-task-types.js';
6
7
  import { errorResponses, singleStringParam, withMinScope } from './_shared.js';
7
8
  // ---------------------------------------------------------------------------
@@ -236,6 +237,23 @@ export const getPublicUsageContract = withMinScope('read', defineApiContract({
236
237
  pathResolver: () => '/api/v1/usage',
237
238
  responsesByStatusCode: { 200: publicUsageSchema, ...errorResponses },
238
239
  }));
240
+ /**
241
+ * The workspace's spend over a window, sliced by ONE dimension: the TCO read the period
242
+ * breakdown above cannot produce: it groups by `(billing, vendor, provider, model)` within the
243
+ * current calendar month, and carries no board-shape axis at all.
244
+ *
245
+ * A sub-resource of `/usage` rather than a surface of its own, because it is the same money
246
+ * from the same ledger: `/usage` answers the budget question ("what has this period cost, and
247
+ * are runs paused"), this answers the attribution one ("what did this repository / ticket /
248
+ * run cost"). Scoped in SQL to the key's own workspace and its account, so `read` is the whole
249
+ * scope story here too.
250
+ */
251
+ export const getPublicSpendContract = withMinScope('read', defineApiContract({
252
+ method: 'get',
253
+ pathResolver: () => '/api/v1/usage/spend',
254
+ requestQuerySchema: publicSpendQuerySchema,
255
+ responsesByStatusCode: { 200: publicSpendSchema, ...errorResponses },
256
+ }));
239
257
  // ---- headless key provisioning (`admin` scope) -----------------------------
240
258
  // The external counterpart of the session-authed `/public-api-keys` routes above, and the same
241
259
  // class of gap the outbound webhook had: a deployment whose operator is headless could reach