@company-semantics/contracts 93.3.0 → 95.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +1 -1
- package/src/api/generated-spec-hash.ts +2 -2
- package/src/api/generated.ts +32 -7
- package/src/billing/README.md +55 -3
- package/src/billing/__tests__/price-list-tiers.test.ts +129 -0
- package/src/billing/__tests__/processing-modes.test.ts +19 -0
- package/src/billing/__tests__/schemas.test.ts +44 -21
- package/src/billing/index.ts +16 -0
- package/src/billing/schemas.ts +145 -24
- package/src/billing/types.ts +23 -1
- package/src/billing/vocabulary.ts +37 -0
- package/src/chat/README.md +26 -0
- package/src/chat/__tests__/chat-exports.test.ts +61 -0
- package/src/chat/__tests__/message-actions.test.ts +208 -0
- package/src/chat/__tests__/message-mentions.test.ts +4 -0
- package/src/chat/__tests__/multi-party.test.ts +3 -0
- package/src/chat/__tests__/stream-metadata.test.ts +73 -0
- package/src/chat/__tests__/turn-kind.test.ts +34 -0
- package/src/chat/__tests__/turn-wire.test.ts +93 -0
- package/src/chat/index.ts +17 -0
- package/src/chat/message-actions.ts +143 -0
- package/src/chat/schemas.ts +30 -0
- package/src/chat/stream-metadata.ts +40 -0
- package/src/chat/turn-kind.ts +43 -0
package/package.json
CHANGED
|
@@ -1,3 +1,3 @@
|
|
|
1
1
|
// AUTO-GENERATED — do not edit. Run pnpm generate:spec-hash to regenerate.
|
|
2
|
-
export const SPEC_HASH = '
|
|
3
|
-
export const SPEC_HASH_FULL = '
|
|
2
|
+
export const SPEC_HASH = 'd4db95eeefb4' as const;
|
|
3
|
+
export const SPEC_HASH_FULL = 'd4db95eeefb4bf7a97541fcefdcb90c1804e1e39508fe0b98e6389ce001a6f16' as const;
|
package/src/api/generated.ts
CHANGED
|
@@ -5569,6 +5569,10 @@ export interface components {
|
|
|
5569
5569
|
requestId: string;
|
|
5570
5570
|
questionId: string;
|
|
5571
5571
|
};
|
|
5572
|
+
presentationGroupId: string | null;
|
|
5573
|
+
/** @enum {string} */
|
|
5574
|
+
turnKind: "conversation" | "workflow_launch" | "workflow_settlement" | "input_request_launch" | "proactive" | "refusal";
|
|
5575
|
+
myFeedback: ("up" | "down") | null;
|
|
5572
5576
|
}[];
|
|
5573
5577
|
};
|
|
5574
5578
|
SuccessResponse: {
|
|
@@ -10125,17 +10129,38 @@ export interface components {
|
|
|
10125
10129
|
hostedSurchargeBps: number;
|
|
10126
10130
|
byoFeeBps: number;
|
|
10127
10131
|
priceBookVersion: string;
|
|
10132
|
+
/** Format: date-time */
|
|
10133
|
+
priceBookEffectiveAt: string;
|
|
10128
10134
|
models: {
|
|
10129
10135
|
/** @enum {string} */
|
|
10130
10136
|
provider: "openai" | "anthropic";
|
|
10131
10137
|
modelId: string;
|
|
10132
|
-
|
|
10133
|
-
|
|
10134
|
-
|
|
10135
|
-
|
|
10136
|
-
|
|
10137
|
-
|
|
10138
|
-
|
|
10138
|
+
aliases: string[];
|
|
10139
|
+
sourceUrl: string | null;
|
|
10140
|
+
retrievedOn: string | null;
|
|
10141
|
+
promptTierMeasure: ("input_incl_cache" | "input_excl_cache") | null;
|
|
10142
|
+
promptTokensCeiling: number | null;
|
|
10143
|
+
tiers: {
|
|
10144
|
+
/** @enum {string} */
|
|
10145
|
+
processingMode: "standard" | "batch" | "flex" | "fast" | "ultrafast";
|
|
10146
|
+
promptTokensAbove: number;
|
|
10147
|
+
reference: {
|
|
10148
|
+
inputPerMMicros: string;
|
|
10149
|
+
outputPerMMicros: string | null;
|
|
10150
|
+
cacheReadPerMMicros: string | null;
|
|
10151
|
+
cacheWritePerMMicros: string | null;
|
|
10152
|
+
cacheWrite1hPerMMicros: string | null;
|
|
10153
|
+
reasoningPerMMicros: string | null;
|
|
10154
|
+
};
|
|
10155
|
+
hosted: {
|
|
10156
|
+
inputPerMMicros: string;
|
|
10157
|
+
outputPerMMicros: string | null;
|
|
10158
|
+
cacheReadPerMMicros: string | null;
|
|
10159
|
+
cacheWritePerMMicros: string | null;
|
|
10160
|
+
cacheWrite1hPerMMicros: string | null;
|
|
10161
|
+
reasoningPerMMicros: string | null;
|
|
10162
|
+
};
|
|
10163
|
+
}[];
|
|
10139
10164
|
}[];
|
|
10140
10165
|
};
|
|
10141
10166
|
SourceSyncDiscoveryRunResponse: {
|
package/src/billing/README.md
CHANGED
|
@@ -18,7 +18,8 @@ What it publishes:
|
|
|
18
18
|
- **Closed enums**, each an `as const` tuple with a union type and a `z.enum`
|
|
19
19
|
built from the same tuple: credential source, funding mode, platform status,
|
|
20
20
|
AI pause reason, ledger entry type, reservation state, settlement basis,
|
|
21
|
-
top-up kind and status, token dimension, principal kind,
|
|
21
|
+
top-up kind and status, token dimension, principal kind, provider, processing
|
|
22
|
+
mode and prompt tier measure.
|
|
22
23
|
- **Derived tables.** `SEAT_BILLABILITY`, the mapping from principal kind to
|
|
23
24
|
seat billability, and `TokenDimensionsSchema`, one integer count per token
|
|
24
25
|
dimension.
|
|
@@ -99,6 +100,41 @@ owner is always its owner contradicts ADR-BE-296, and nothing imported them.
|
|
|
99
100
|
who paid and was never credited, and `succeeded` and `credited` stay distinct
|
|
100
101
|
in `TOP_UP_STATUSES` so that gap is visible to an operator.
|
|
101
102
|
|
|
103
|
+
## Price list card (ADR slug price-list-tiers)
|
|
104
|
+
|
|
105
|
+
`PriceListSchema` publishes one card per model (`PriceListModelSchema`), not one
|
|
106
|
+
flat rate row. The card mirrors the provider's own pricing structure, so a
|
|
107
|
+
customer can check every charge against the provider's published page.
|
|
108
|
+
|
|
109
|
+
- **A card is `tiers[]`**: one `PriceListTierSchema` entry per
|
|
110
|
+
(`processingMode`, `promptTokensAbove`). Each tier carries the provider's
|
|
111
|
+
`reference` rates and the `hosted` rates derived from them, both as
|
|
112
|
+
`PriceListRatesSchema` (micro-USD per million tokens). Every priced model has a
|
|
113
|
+
`standard` tier at `promptTokensAbove: 0`; a request whose prompt is above a
|
|
114
|
+
tier's threshold pays that tier's rates on every dimension.
|
|
115
|
+
- **A processing mode is an explicit provider rate set, never a multiplier we
|
|
116
|
+
derive.** `PROCESSING_MODES` names the sets (standard, batch, flex, fast,
|
|
117
|
+
ultrafast); a mode's rates are the provider's published numbers, because
|
|
118
|
+
providers do not price modes by a clean factor (OpenAI gpt-4o Fast is 1.7x
|
|
119
|
+
Standard).
|
|
120
|
+
- **`null` means the provider publishes no separate rate** for that dimension —
|
|
121
|
+
never `"0"`. An input-side null (cache read, cache write) bills at the tier's
|
|
122
|
+
input rate, which is what the provider charges. `cacheWrite1hPerMMicros` is
|
|
123
|
+
published for transparency; the backend refuses 1-hour-TTL requests until a
|
|
124
|
+
usage axis exists for it (`TokenDimensionsSchema` is unchanged).
|
|
125
|
+
- **A model with more than one tier names its `promptTierMeasure`**
|
|
126
|
+
(`PROMPT_TIER_MEASURES`): what the provider counts to choose the tier. An
|
|
127
|
+
ambiguous provider rule is never guessed; the long tier stays unpublished and
|
|
128
|
+
`promptTokensCeiling` refuses prompts above the published range.
|
|
129
|
+
- **An id is listed once** per price list: as a card's `modelId` or as one
|
|
130
|
+
card's `aliases` entry, never both.
|
|
131
|
+
- **Corrections publish a new price-book version; history is never
|
|
132
|
+
recomputed.** `priceBookEffectiveAt` says when a version took effect,
|
|
133
|
+
`PriceBookVersionListSchema` lists every version that has ever priced a
|
|
134
|
+
charge, and `PriceListQuerySchema` selects one by label (omit for the active
|
|
135
|
+
version). The query schema is the one request-side shape here, published
|
|
136
|
+
because the version label is part of the price list's public promise.
|
|
137
|
+
|
|
102
138
|
<!-- BEGIN GENERATED: readme-public-api — derived from code by `pnpm readme-api`. Do not edit. -->
|
|
103
139
|
|
|
104
140
|
## Public API
|
|
@@ -169,14 +205,30 @@ owner is always its owner contradicts ADR-BE-296, and nothing imported them.
|
|
|
169
205
|
- `OrgBillingOverview` _(type)_ — Everything the org's billing page needs, in one response.
|
|
170
206
|
- `OrgBillingOverviewSchema` — Everything the org's billing page needs, in ONE response.
|
|
171
207
|
- `PRINCIPAL_KINDS` — WHAT KIND of thing an org membership represents.
|
|
208
|
+
- `PROCESSING_MODES` — How a provider processes a request, which selects the rate set it is billed at.
|
|
209
|
+
- `PROMPT_TIER_MEASURES` — What a provider counts to decide which prompt-length tier a request pays.
|
|
172
210
|
- `PortalSessionResponse` _(type)_ — A Stripe customer-portal session to send the customer to.
|
|
173
211
|
- `PortalSessionResponseSchema` — A Stripe customer-portal session to send the customer to.
|
|
212
|
+
- `PriceBookVersionList` _(type)_ — The price book's version history, newest first.
|
|
213
|
+
- `PriceBookVersionListSchema` — The price book's version history, newest first.
|
|
214
|
+
- `PriceBookVersionSummary` _(type)_ — One published price-book version.
|
|
215
|
+
- `PriceBookVersionSummarySchema` — One published price-book version, newest first in the list.
|
|
174
216
|
- `PriceList` _(type)_ — The published price book, versioned.
|
|
175
|
-
- `PriceListModel` _(type)_ — One priced model.
|
|
176
|
-
- `PriceListModelSchema` — One priced model.
|
|
217
|
+
- `PriceListModel` _(type)_ — One priced model's card: provenance, aliases and tiers per mode.
|
|
218
|
+
- `PriceListModelSchema` — One priced model's card: its provenance, the ids it serves, and its tiers per processing mode.
|
|
219
|
+
- `PriceListQuery` _(type)_ — The price-list query: an optional version label, else the active one.
|
|
220
|
+
- `PriceListQuerySchema` — `GET /api/billing/price-list?version=<label>` — omit for the active version.
|
|
221
|
+
- `PriceListRates` _(type)_ — One rate set, micro-USD per million tokens; null = no separate rate.
|
|
222
|
+
- `PriceListRatesSchema` — One rate set, micro-USD PER MILLION tokens.
|
|
177
223
|
- `PriceListSchema` — The published price book, versioned.
|
|
224
|
+
- `PriceListTier` _(type)_ — One tier of one processing mode: reference and hosted rates.
|
|
225
|
+
- `PriceListTierSchema` — One tier of one processing mode.
|
|
178
226
|
- `PrincipalKind` _(type)_ — What kind of thing an org membership represents.
|
|
179
227
|
- `PrincipalKindSchema`
|
|
228
|
+
- `ProcessingMode` _(type)_
|
|
229
|
+
- `ProcessingModeSchema`
|
|
230
|
+
- `PromptTierMeasure` _(type)_
|
|
231
|
+
- `PromptTierMeasureSchema`
|
|
180
232
|
- `ProviderKeyList` _(type)_ — Every provider the org could configure a key for.
|
|
181
233
|
- `ProviderKeyListSchema` — Every provider the org could configure a key for, configured or not.
|
|
182
234
|
- `ProviderKeyStatus` _(type)_ — What an org may see about one of its own provider keys.
|
|
@@ -0,0 +1,129 @@
|
|
|
1
|
+
import { describe, it, expect } from "vitest";
|
|
2
|
+
import {
|
|
3
|
+
PriceListModelSchema,
|
|
4
|
+
PriceListSchema,
|
|
5
|
+
PriceBookVersionListSchema,
|
|
6
|
+
} from "../schemas";
|
|
7
|
+
import { PROCESSING_MODES, PROMPT_TIER_MEASURES } from "../vocabulary";
|
|
8
|
+
|
|
9
|
+
const rates = (input: string) => ({
|
|
10
|
+
inputPerMMicros: input,
|
|
11
|
+
outputPerMMicros: "500000",
|
|
12
|
+
cacheReadPerMMicros: "10000",
|
|
13
|
+
cacheWritePerMMicros: "125000",
|
|
14
|
+
cacheWrite1hPerMMicros: "200000",
|
|
15
|
+
reasoningPerMMicros: "500000",
|
|
16
|
+
});
|
|
17
|
+
const haiku55 = {
|
|
18
|
+
provider: "anthropic",
|
|
19
|
+
modelId: "claude-haiku-5-5",
|
|
20
|
+
aliases: [],
|
|
21
|
+
sourceUrl: "https://platform.claude.com/docs/en/about-claude/pricing",
|
|
22
|
+
retrievedOn: "2026-10-09",
|
|
23
|
+
promptTierMeasure: "input_incl_cache",
|
|
24
|
+
promptTokensCeiling: null,
|
|
25
|
+
tiers: [
|
|
26
|
+
{
|
|
27
|
+
processingMode: "standard",
|
|
28
|
+
promptTokensAbove: 0,
|
|
29
|
+
reference: rates("100000"),
|
|
30
|
+
hosted: rates("120000"),
|
|
31
|
+
},
|
|
32
|
+
{
|
|
33
|
+
processingMode: "standard",
|
|
34
|
+
promptTokensAbove: 100000,
|
|
35
|
+
reference: rates("500000"),
|
|
36
|
+
hosted: rates("600000"),
|
|
37
|
+
},
|
|
38
|
+
],
|
|
39
|
+
};
|
|
40
|
+
|
|
41
|
+
describe("price list tiers", () => {
|
|
42
|
+
it("accepts a two-tier model that names its measure", () => {
|
|
43
|
+
expect(PriceListModelSchema.safeParse(haiku55).success).toBe(true);
|
|
44
|
+
});
|
|
45
|
+
it("refuses two tiers without a promptTierMeasure", () => {
|
|
46
|
+
expect(
|
|
47
|
+
PriceListModelSchema.safeParse({ ...haiku55, promptTierMeasure: null })
|
|
48
|
+
.success,
|
|
49
|
+
).toBe(false);
|
|
50
|
+
});
|
|
51
|
+
it("refuses a model with no standard base tier", () => {
|
|
52
|
+
expect(
|
|
53
|
+
PriceListModelSchema.safeParse({ ...haiku55, tiers: [haiku55.tiers[1]] })
|
|
54
|
+
.success,
|
|
55
|
+
).toBe(false);
|
|
56
|
+
});
|
|
57
|
+
it("accepts a null cache read as not separately priced", () => {
|
|
58
|
+
const t = {
|
|
59
|
+
...haiku55.tiers[0],
|
|
60
|
+
reference: { ...rates("500000"), cacheReadPerMMicros: null },
|
|
61
|
+
};
|
|
62
|
+
expect(
|
|
63
|
+
PriceListModelSchema.safeParse({
|
|
64
|
+
...haiku55,
|
|
65
|
+
promptTierMeasure: null,
|
|
66
|
+
tiers: [t],
|
|
67
|
+
}).success,
|
|
68
|
+
).toBe(true);
|
|
69
|
+
});
|
|
70
|
+
it("accepts a pre-catalog card with no source", () => {
|
|
71
|
+
expect(
|
|
72
|
+
PriceListModelSchema.safeParse({
|
|
73
|
+
...haiku55,
|
|
74
|
+
sourceUrl: null,
|
|
75
|
+
retrievedOn: null,
|
|
76
|
+
}).success,
|
|
77
|
+
).toBe(true);
|
|
78
|
+
});
|
|
79
|
+
it("refuses an alias that is also listed as its own model", () => {
|
|
80
|
+
const dated = { ...haiku55, modelId: "claude-haiku-5-5-20261001" };
|
|
81
|
+
expect(
|
|
82
|
+
PriceListSchema.safeParse({
|
|
83
|
+
seatPriceMicros: null,
|
|
84
|
+
hostedSurchargeBps: 2000,
|
|
85
|
+
byoFeeBps: 500,
|
|
86
|
+
priceBookVersion: "pb-2026-10-v3",
|
|
87
|
+
priceBookEffectiveAt: "2026-10-10T00:00:00Z",
|
|
88
|
+
models: [{ ...haiku55, aliases: ["claude-haiku-5-5-20261001"] }, dated],
|
|
89
|
+
}).success,
|
|
90
|
+
).toBe(false);
|
|
91
|
+
});
|
|
92
|
+
it("names the closed processing modes and tier measures", () => {
|
|
93
|
+
expect(PROCESSING_MODES).toEqual([
|
|
94
|
+
"standard",
|
|
95
|
+
"batch",
|
|
96
|
+
"flex",
|
|
97
|
+
"fast",
|
|
98
|
+
"ultrafast",
|
|
99
|
+
]);
|
|
100
|
+
expect(PROMPT_TIER_MEASURES).toEqual([
|
|
101
|
+
"input_incl_cache",
|
|
102
|
+
"input_excl_cache",
|
|
103
|
+
]);
|
|
104
|
+
});
|
|
105
|
+
it("requires the effective-at on the list and the version history shape", () => {
|
|
106
|
+
expect(
|
|
107
|
+
PriceListSchema.safeParse({
|
|
108
|
+
seatPriceMicros: null,
|
|
109
|
+
hostedSurchargeBps: 2000,
|
|
110
|
+
byoFeeBps: 500,
|
|
111
|
+
priceBookVersion: "pb-2026-10-v3",
|
|
112
|
+
models: [haiku55],
|
|
113
|
+
}).success,
|
|
114
|
+
).toBe(false);
|
|
115
|
+
expect(
|
|
116
|
+
PriceBookVersionListSchema.safeParse({
|
|
117
|
+
versions: [
|
|
118
|
+
{
|
|
119
|
+
versionLabel: "pb-2026-10-v3",
|
|
120
|
+
effectiveAt: "2026-10-10T00:00:00Z",
|
|
121
|
+
source: "catalog",
|
|
122
|
+
notes: null,
|
|
123
|
+
active: true,
|
|
124
|
+
},
|
|
125
|
+
],
|
|
126
|
+
}).success,
|
|
127
|
+
).toBe(true);
|
|
128
|
+
});
|
|
129
|
+
});
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { describe, it, expect } from "vitest";
|
|
2
|
+
import {
|
|
3
|
+
PROCESSING_MODES,
|
|
4
|
+
ProcessingModeSchema,
|
|
5
|
+
PROMPT_TIER_MEASURES,
|
|
6
|
+
PromptTierMeasureSchema,
|
|
7
|
+
} from "../index";
|
|
8
|
+
|
|
9
|
+
describe("processing modes and prompt tier measures", () => {
|
|
10
|
+
it("exports the processing modes through the billing index", () => {
|
|
11
|
+
expect(PROCESSING_MODES).toContain("fast");
|
|
12
|
+
expect(PROMPT_TIER_MEASURES).toContain("input_excl_cache");
|
|
13
|
+
// "priority" was renamed to "fast"; the closed vocabulary refuses it.
|
|
14
|
+
expect(ProcessingModeSchema.safeParse("priority").success).toBe(false);
|
|
15
|
+
expect(PromptTierMeasureSchema.safeParse("input_incl_cache").success).toBe(
|
|
16
|
+
true,
|
|
17
|
+
);
|
|
18
|
+
});
|
|
19
|
+
});
|
|
@@ -179,27 +179,50 @@ describe("the billing response schemas", () => {
|
|
|
179
179
|
});
|
|
180
180
|
|
|
181
181
|
it("rejects a price list whose per-million rate is a number", () => {
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
182
|
+
const rates = {
|
|
183
|
+
inputPerMMicros: "15000000",
|
|
184
|
+
outputPerMMicros: "75000000",
|
|
185
|
+
cacheReadPerMMicros: "1500000",
|
|
186
|
+
cacheWritePerMMicros: "18750000",
|
|
187
|
+
cacheWrite1hPerMMicros: "30000000",
|
|
188
|
+
reasoningPerMMicros: "75000000",
|
|
189
|
+
};
|
|
190
|
+
const priceList = (inputPerMMicros: string | number) => ({
|
|
191
|
+
seatPriceMicros: null,
|
|
192
|
+
hostedSurchargeBps: 2000,
|
|
193
|
+
byoFeeBps: 500,
|
|
194
|
+
priceBookVersion: "2026-09-01",
|
|
195
|
+
priceBookEffectiveAt: "2026-09-01T00:00:00Z",
|
|
196
|
+
models: [
|
|
197
|
+
{
|
|
198
|
+
provider: "anthropic",
|
|
199
|
+
modelId: "claude-opus-5",
|
|
200
|
+
aliases: [],
|
|
201
|
+
sourceUrl:
|
|
202
|
+
"https://platform.claude.com/docs/en/about-claude/pricing",
|
|
203
|
+
retrievedOn: "2026-09-01",
|
|
204
|
+
promptTierMeasure: null,
|
|
205
|
+
promptTokensCeiling: null,
|
|
206
|
+
tiers: [
|
|
207
|
+
{
|
|
208
|
+
processingMode: "standard",
|
|
209
|
+
promptTokensAbove: 0,
|
|
210
|
+
reference: { ...rates, inputPerMMicros },
|
|
211
|
+
hosted: { ...rates, inputPerMMicros: "18000000" },
|
|
212
|
+
},
|
|
213
|
+
],
|
|
214
|
+
},
|
|
215
|
+
],
|
|
216
|
+
});
|
|
217
|
+
|
|
218
|
+
// The same list with the rate as a string parses, so the only defect is
|
|
219
|
+
// the JSON number.
|
|
220
|
+
expect(PriceListSchema.safeParse(priceList("15000000")).success).toBe(
|
|
221
|
+
true,
|
|
222
|
+
);
|
|
223
|
+
expect(PriceListSchema.safeParse(priceList(15000000)).success).toBe(
|
|
224
|
+
false,
|
|
225
|
+
);
|
|
203
226
|
});
|
|
204
227
|
});
|
|
205
228
|
|
package/src/billing/index.ts
CHANGED
|
@@ -30,6 +30,8 @@ export type {
|
|
|
30
30
|
TokenDimension,
|
|
31
31
|
PrincipalKind,
|
|
32
32
|
BillingProvider,
|
|
33
|
+
ProcessingMode,
|
|
34
|
+
PromptTierMeasure,
|
|
33
35
|
SeatBillability,
|
|
34
36
|
} from "./vocabulary";
|
|
35
37
|
|
|
@@ -60,6 +62,10 @@ export {
|
|
|
60
62
|
PrincipalKindSchema,
|
|
61
63
|
BILLING_PROVIDERS,
|
|
62
64
|
BillingProviderSchema,
|
|
65
|
+
PROCESSING_MODES,
|
|
66
|
+
ProcessingModeSchema,
|
|
67
|
+
PROMPT_TIER_MEASURES,
|
|
68
|
+
PromptTierMeasureSchema,
|
|
63
69
|
SEAT_BILLABILITY,
|
|
64
70
|
TokenDimensionsSchema,
|
|
65
71
|
} from "./vocabulary";
|
|
@@ -102,8 +108,13 @@ export {
|
|
|
102
108
|
ModelAllowlistSchema,
|
|
103
109
|
OrgBillingOverviewSchema,
|
|
104
110
|
PortalSessionResponseSchema,
|
|
111
|
+
PriceBookVersionListSchema,
|
|
112
|
+
PriceBookVersionSummarySchema,
|
|
105
113
|
PriceListModelSchema,
|
|
114
|
+
PriceListQuerySchema,
|
|
115
|
+
PriceListRatesSchema,
|
|
106
116
|
PriceListSchema,
|
|
117
|
+
PriceListTierSchema,
|
|
107
118
|
ProviderKeyListSchema,
|
|
108
119
|
ProviderKeyStatusSchema,
|
|
109
120
|
SpendingControlsSchema,
|
|
@@ -144,8 +155,13 @@ export type {
|
|
|
144
155
|
ModelAllowlist,
|
|
145
156
|
OrgBillingOverview,
|
|
146
157
|
PortalSessionResponse,
|
|
158
|
+
PriceBookVersionList,
|
|
159
|
+
PriceBookVersionSummary,
|
|
147
160
|
PriceList,
|
|
148
161
|
PriceListModel,
|
|
162
|
+
PriceListQuery,
|
|
163
|
+
PriceListRates,
|
|
164
|
+
PriceListTier,
|
|
149
165
|
ProviderKeyList,
|
|
150
166
|
ProviderKeyStatus,
|
|
151
167
|
SpendingControls,
|
package/src/billing/schemas.ts
CHANGED
|
@@ -19,7 +19,11 @@
|
|
|
19
19
|
* - EVERY percentage is {@link BpsSchema} — an integer number of basis points.
|
|
20
20
|
* `effectiveMarkupBps: 20.5` is not a fine-grained markup, it is a bug.
|
|
21
21
|
* - EVERY timestamp is {@link IsoDateTime}, the package's single definition
|
|
22
|
-
* site for a `format: date-time` field (ADR-CONTRACTS-156)
|
|
22
|
+
* site for a `format: date-time` field (ADR-CONTRACTS-156); the price book's
|
|
23
|
+
* effective-at timestamps use its offset-tolerant sibling.
|
|
24
|
+
* - A price-list rate that is `null` means the provider publishes no separate
|
|
25
|
+
* rate for it — never `"0"`. A processing mode is an explicit rate set, never
|
|
26
|
+
* a multiplier (ADR slug price-list-tiers).
|
|
23
27
|
* - EVERY token count is a non-negative integer, reported per dimension via
|
|
24
28
|
* {@link TokenDimensionsSchema} and never collapsed into one total
|
|
25
29
|
* (INV-BILL-RAW-TOKENS-ALWAYS-VISIBLE).
|
|
@@ -35,7 +39,7 @@
|
|
|
35
39
|
*/
|
|
36
40
|
import { z } from "zod";
|
|
37
41
|
|
|
38
|
-
import { IsoDateTime } from "../api/primitives";
|
|
42
|
+
import { IsoDateTime, IsoDateTimeWithOffset } from "../api/primitives";
|
|
39
43
|
import {
|
|
40
44
|
AI_PAUSE_REASONS,
|
|
41
45
|
BILLING_PLATFORM_STATUSES,
|
|
@@ -45,6 +49,9 @@ import {
|
|
|
45
49
|
FUNDING_MODES,
|
|
46
50
|
LEDGER_ENTRY_TYPES,
|
|
47
51
|
MoneyMicrosSchema,
|
|
52
|
+
PROCESSING_MODES,
|
|
53
|
+
ProcessingModeSchema,
|
|
54
|
+
PromptTierMeasureSchema,
|
|
48
55
|
TOP_UP_KINDS,
|
|
49
56
|
TOP_UP_STATUSES,
|
|
50
57
|
TokenDimensionsSchema,
|
|
@@ -412,37 +419,151 @@ export const ProviderKeyListSchema = z.object({
|
|
|
412
419
|
/* -------------------------------------------------------------------------- */
|
|
413
420
|
|
|
414
421
|
/**
|
|
415
|
-
* One
|
|
416
|
-
*
|
|
417
|
-
*
|
|
418
|
-
*
|
|
422
|
+
* One rate set, micro-USD PER MILLION tokens. `null` means the provider publishes
|
|
423
|
+
* no separate rate for that dimension: an input-side dimension (cache read,
|
|
424
|
+
* cache write) is then billed at the tier's input rate, which is what the
|
|
425
|
+
* provider charges; an output-side null on a model is refused at the gate when
|
|
426
|
+
* the call could produce output. `cacheWritePerMMicros` is the provider's default
|
|
427
|
+
* (Anthropic: 5-minute) write; `cacheWrite1hPerMMicros` the Anthropic 1-hour write.
|
|
419
428
|
*
|
|
420
|
-
*
|
|
421
|
-
*
|
|
422
|
-
* and this platform charges `byoFeeBps` on it, not a per-token rate.
|
|
429
|
+
* Null is never encoded as `"0"`: zero would be a price (free), not the absence
|
|
430
|
+
* of one.
|
|
423
431
|
*/
|
|
424
|
-
export const
|
|
425
|
-
provider: z.enum(BILLING_PROVIDERS),
|
|
426
|
-
modelId: z.string(),
|
|
432
|
+
export const PriceListRatesSchema = z.object({
|
|
427
433
|
inputPerMMicros: MoneyMicrosSchema,
|
|
428
|
-
outputPerMMicros: MoneyMicrosSchema,
|
|
429
|
-
cacheReadPerMMicros: MoneyMicrosSchema,
|
|
430
|
-
cacheWritePerMMicros: MoneyMicrosSchema,
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
hostedOutputPerMMicros: MoneyMicrosSchema,
|
|
434
|
+
outputPerMMicros: MoneyMicrosSchema.nullable(),
|
|
435
|
+
cacheReadPerMMicros: MoneyMicrosSchema.nullable(),
|
|
436
|
+
cacheWritePerMMicros: MoneyMicrosSchema.nullable(),
|
|
437
|
+
cacheWrite1hPerMMicros: MoneyMicrosSchema.nullable(),
|
|
438
|
+
reasoningPerMMicros: MoneyMicrosSchema.nullable(),
|
|
434
439
|
});
|
|
435
440
|
|
|
441
|
+
/**
|
|
442
|
+
* One tier of one processing mode. `promptTokensAbove` is 0 for the base tier;
|
|
443
|
+
* a request whose prompt (per the model's `promptTierMeasure`) is ABOVE it pays
|
|
444
|
+
* this tier's rates on EVERY dimension. `reference` is the provider's list
|
|
445
|
+
* rate; `hosted` is what a hosted call is charged per million (reference plus
|
|
446
|
+
* the surcharge, same rounding as settlement, null preserved).
|
|
447
|
+
*
|
|
448
|
+
* A processing mode is its own explicit rate set, never a multiplier on the
|
|
449
|
+
* standard one: the providers do not publish clean multipliers.
|
|
450
|
+
*/
|
|
451
|
+
export const PriceListTierSchema = z.object({
|
|
452
|
+
processingMode: ProcessingModeSchema,
|
|
453
|
+
promptTokensAbove: z.number().int().min(0),
|
|
454
|
+
reference: PriceListRatesSchema,
|
|
455
|
+
hosted: PriceListRatesSchema,
|
|
456
|
+
});
|
|
457
|
+
|
|
458
|
+
/**
|
|
459
|
+
* One priced model's card: its provenance, the ids it serves, and its tiers
|
|
460
|
+
* per processing mode. Every model has a `standard` base tier; a model with
|
|
461
|
+
* more than one tier in any mode names the {@link PromptTierMeasureSchema} that
|
|
462
|
+
* decides which tier a request falls in.
|
|
463
|
+
*
|
|
464
|
+
* There is no BYO rate: a BYO call is billed by the provider directly and this
|
|
465
|
+
* platform charges `byoFeeBps` on it, not a per-token rate.
|
|
466
|
+
*/
|
|
467
|
+
export const PriceListModelSchema = z
|
|
468
|
+
.object({
|
|
469
|
+
provider: z.enum(BILLING_PROVIDERS),
|
|
470
|
+
modelId: z.string().min(1),
|
|
471
|
+
/**
|
|
472
|
+
* Ids this version records as served by the same card; [] when the version
|
|
473
|
+
* records none. An id appears once in a price list, as a modelId or as an
|
|
474
|
+
* alias, never both.
|
|
475
|
+
*/
|
|
476
|
+
aliases: z.array(z.string().min(1)),
|
|
477
|
+
/**
|
|
478
|
+
* The provider's official pricing page the card was authored from. Null for
|
|
479
|
+
* a price-book version authored before the catalog recorded provenance.
|
|
480
|
+
*/
|
|
481
|
+
sourceUrl: z.string().url().nullable(),
|
|
482
|
+
/**
|
|
483
|
+
* ISO date (YYYY-MM-DD) the source was last read. Null for a price-book
|
|
484
|
+
* version authored before the catalog recorded provenance.
|
|
485
|
+
*/
|
|
486
|
+
retrievedOn: z
|
|
487
|
+
.string()
|
|
488
|
+
.regex(/^\d{4}-\d{2}-\d{2}$/)
|
|
489
|
+
.nullable(),
|
|
490
|
+
promptTierMeasure: PromptTierMeasureSchema.nullable(),
|
|
491
|
+
/** Prompts above this many tokens are refused (a tier we have not published). Null = no ceiling. */
|
|
492
|
+
promptTokensCeiling: z.number().int().positive().nullable(),
|
|
493
|
+
tiers: z.array(PriceListTierSchema).min(1),
|
|
494
|
+
})
|
|
495
|
+
.superRefine((m, ctx) => {
|
|
496
|
+
const standardBase = m.tiers.some(
|
|
497
|
+
(t) => t.processingMode === "standard" && t.promptTokensAbove === 0,
|
|
498
|
+
);
|
|
499
|
+
if (!standardBase) {
|
|
500
|
+
ctx.addIssue("every priced model has a standard base tier");
|
|
501
|
+
}
|
|
502
|
+
for (const mode of PROCESSING_MODES) {
|
|
503
|
+
const above = m.tiers
|
|
504
|
+
.filter((t) => t.processingMode === mode)
|
|
505
|
+
.map((t) => t.promptTokensAbove);
|
|
506
|
+
if (above.length > 1 && m.promptTierMeasure === null) {
|
|
507
|
+
ctx.addIssue(
|
|
508
|
+
"a model with more than one tier names its promptTierMeasure",
|
|
509
|
+
);
|
|
510
|
+
}
|
|
511
|
+
if (new Set(above).size !== above.length) {
|
|
512
|
+
ctx.addIssue(`duplicate tier threshold in mode ${mode}`);
|
|
513
|
+
}
|
|
514
|
+
}
|
|
515
|
+
});
|
|
516
|
+
|
|
436
517
|
/**
|
|
437
518
|
* The published price book, versioned. Read by the app to show what a model
|
|
438
519
|
* costs before it is used, and by control to audit what it charged after.
|
|
520
|
+
* A correction is a new version; a published version is never recomputed.
|
|
439
521
|
*/
|
|
440
|
-
export const PriceListSchema = z
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
522
|
+
export const PriceListSchema = z
|
|
523
|
+
.object({
|
|
524
|
+
seatPriceMicros: MoneyMicrosSchema.nullable(),
|
|
525
|
+
hostedSurchargeBps: BpsSchema,
|
|
526
|
+
byoFeeBps: BpsSchema,
|
|
527
|
+
priceBookVersion: z.string(),
|
|
528
|
+
/** When this version became the one calls are priced against (ISO timestamp). */
|
|
529
|
+
priceBookEffectiveAt: IsoDateTimeWithOffset,
|
|
530
|
+
models: z.array(PriceListModelSchema),
|
|
531
|
+
})
|
|
532
|
+
.superRefine((list, ctx) => {
|
|
533
|
+
// An id is listed once: as a card's modelId or as one card's alias, never both.
|
|
534
|
+
const seen = new Set<string>();
|
|
535
|
+
for (const m of list.models) {
|
|
536
|
+
for (const id of [m.modelId, ...m.aliases]) {
|
|
537
|
+
if (seen.has(id)) {
|
|
538
|
+
ctx.addIssue(`model id ${id} is listed more than once`);
|
|
539
|
+
}
|
|
540
|
+
seen.add(id);
|
|
541
|
+
}
|
|
542
|
+
}
|
|
543
|
+
});
|
|
544
|
+
|
|
545
|
+
/**
|
|
546
|
+
* `GET /api/billing/price-list?version=<label>` — omit for the active version.
|
|
547
|
+
* A request shape published here by exception (ADR slug price-list-tiers): the
|
|
548
|
+
* app and the backend must agree on how a past version is addressed.
|
|
549
|
+
*/
|
|
550
|
+
export const PriceListQuerySchema = z.object({
|
|
551
|
+
version: z.string().min(1).optional(),
|
|
552
|
+
});
|
|
553
|
+
|
|
554
|
+
/** One published price-book version, newest first in the list. */
|
|
555
|
+
export const PriceBookVersionSummarySchema = z.object({
|
|
556
|
+
versionLabel: z.string(),
|
|
557
|
+
effectiveAt: IsoDateTimeWithOffset,
|
|
558
|
+
source: z.string(),
|
|
559
|
+
notes: z.string().nullable(),
|
|
560
|
+
/** True for exactly the version calls are priced against now. */
|
|
561
|
+
active: z.boolean(),
|
|
562
|
+
});
|
|
563
|
+
|
|
564
|
+
/** The price book's version history, newest first. */
|
|
565
|
+
export const PriceBookVersionListSchema = z.object({
|
|
566
|
+
versions: z.array(PriceBookVersionSummarySchema),
|
|
446
567
|
});
|
|
447
568
|
|
|
448
569
|
/**
|