@trazum/core 1.82.0 → 1.83.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,270 @@
1
+ /**
2
+ * LangSmith's run export, read as a usage log.
3
+ *
4
+ * The fifth converter in the pattern `from-claude-code` started: a pure
5
+ * function turns one tool's export into Trazum's usage-log records, and every
6
+ * door prices it from there. LangSmith is the tracing product most LangChain
7
+ * teams already run, so the export exists before Trazum does.
8
+ *
9
+ * **The format is derived, not guessed.** Every field below is `RunBase` and
10
+ * `Run` in `python/langsmith/schemas.py` in langchain-ai/langsmith-sdk. A
11
+ * converter written from memory of an API is a converter that silently
12
+ * mis-reads somebody's bill.
13
+ *
14
+ * ## A run is not a call, and that is the whole difficulty
15
+ *
16
+ * LangSmith records a **run**, and a trace is a tree of them: chains, tools and
17
+ * retrievers alongside the model calls. Only `run_type: "llm"` carries token
18
+ * counts, and summing the tree would count the same tokens once per level. So
19
+ * everything else is skipped and **counted out loud** — a converter that
20
+ * quietly dropped two thirds of a file would look like one that read it.
21
+ *
22
+ * ## The model, and why it is refused rather than inferred
23
+ *
24
+ * There is no model column. The name lives in `extra.metadata.ls_model_name`,
25
+ * or in the invocation parameters the SDK records beside it, and a run whose
26
+ * metadata carries neither cannot be priced. The obvious guess is the run's
27
+ * own `name` — LangChain names them after the class, `ChatOpenAI`, which is a
28
+ * client and not a model. Pricing a call by the class that made it would be a
29
+ * figure attributed to something it does not describe, which is the fault this
30
+ * repository keeps finding in itself. Such a run is counted in `unnamedModel`
31
+ * and dropped.
32
+ *
33
+ * ## What deliberately does not cross
34
+ *
35
+ * `inputs` and `outputs` are the prompt and the completion, on every single
36
+ * run. **Neither is read.** `extra.metadata` is read for two named keys and
37
+ * nothing else, because it is a free-form bag the operator fills and the next
38
+ * thing they put in it might be a credential. The converter names the fields
39
+ * it takes and takes nothing else, and a fixture plants a marker in each and
40
+ * greps the whole output.
41
+ *
42
+ * ## What it refuses to invent
43
+ *
44
+ * There is no cache-token split. `prompt_cost_details` looks like one and is
45
+ * not: it is LangSmith's own priced breakdown in dollars, computed from
46
+ * LangSmith's price table. It never enters a record, and neither does
47
+ * `total_cost` — `reportedCostUsd` returns it on its own, the way
48
+ * `from-litellm` keeps the gateway's arithmetic apart from Trazum's. Two price
49
+ * tables, two figures; merging them is how a report becomes quietly wrong.
50
+ */
51
+ const asObject = (value) => typeof value === 'object' && value !== null && !Array.isArray(value)
52
+ ? value
53
+ : null;
54
+ const tryParse = (text) => {
55
+ try {
56
+ return JSON.parse(text);
57
+ }
58
+ catch {
59
+ return undefined;
60
+ }
61
+ };
62
+ const asCount = (value) => {
63
+ const n = typeof value === 'string' ? Number(value) : value;
64
+ return typeof n === 'number' && Number.isFinite(n) && n >= 0 ? n : undefined;
65
+ };
66
+ const asName = (value) => typeof value === 'string' && value.trim() !== '' ? value.trim() : null;
67
+ /** `extra.metadata`, which is where LangSmith documents everything user-set. */
68
+ function metadataOf(run) {
69
+ const extra = asObject(run.extra);
70
+ return extra === null ? asObject(run.metadata) : (asObject(extra.metadata) ?? asObject(run.metadata));
71
+ }
72
+ /**
73
+ * The model, from the two named places it is recorded and nowhere else.
74
+ *
75
+ * `ls_model_name` is what the SDK writes; `model` and `model_name` are what a
76
+ * team writes by hand when they set metadata themselves. The run's `name` is
77
+ * deliberately not consulted: LangChain names a run after the client class,
78
+ * and `ChatOpenAI` is not a model anybody can price.
79
+ */
80
+ function modelOf(run) {
81
+ const metadata = metadataOf(run);
82
+ if (metadata !== null) {
83
+ for (const key of ['ls_model_name', 'model_name', 'model']) {
84
+ const found = asName(metadata[key]);
85
+ if (found !== null)
86
+ return found;
87
+ }
88
+ // The invocation parameters, where the SDK also records it.
89
+ const params = asObject(metadata.invocation_params);
90
+ if (params !== null) {
91
+ for (const key of ['model', 'model_name']) {
92
+ const found = asName(params[key]);
93
+ if (found !== null)
94
+ return found;
95
+ }
96
+ }
97
+ }
98
+ return null;
99
+ }
100
+ /**
101
+ * The label, from the tags a team already puts on its traces.
102
+ *
103
+ * `tags` is LangSmith's own list and the first entry wins, because a workload
104
+ * has one name in a bill. Then the two metadata keys a team would plausibly
105
+ * name a workload by. Never joined, never invented.
106
+ */
107
+ function labelOf(run) {
108
+ if (Array.isArray(run.tags)) {
109
+ for (const tag of run.tags) {
110
+ const found = asName(tag);
111
+ if (found !== null)
112
+ return found;
113
+ }
114
+ }
115
+ const metadata = metadataOf(run);
116
+ if (metadata !== null) {
117
+ for (const key of ['label', 'workload']) {
118
+ const found = asName(metadata[key]);
119
+ if (found !== null)
120
+ return found;
121
+ }
122
+ }
123
+ return undefined;
124
+ }
125
+ /** The run's start time as an ISO instant, or undefined. */
126
+ function timeOf(run) {
127
+ const raw = run.start_time ?? run.startTime;
128
+ if (typeof raw !== 'string' && typeof raw !== 'number')
129
+ return undefined;
130
+ const ms = typeof raw === 'number' ? raw : Date.parse(raw);
131
+ if (!Number.isFinite(ms))
132
+ return undefined;
133
+ return new Date(ms).toISOString();
134
+ }
135
+ /**
136
+ * The token counts, from the two shapes LangSmith has written them in.
137
+ *
138
+ * `prompt_tokens` and `completion_tokens` sit on the run; newer exports also
139
+ * carry a nested `usage_metadata` with `input_tokens` and `output_tokens`.
140
+ * Both are read because both are in the wild, and an export from last year is
141
+ * still somebody's bill.
142
+ */
143
+ function tokensOf(run) {
144
+ const nested = asObject(run.usage_metadata);
145
+ return {
146
+ input: asCount(run.prompt_tokens) ?? asCount(nested?.input_tokens),
147
+ output: asCount(run.completion_tokens) ?? asCount(nested?.output_tokens),
148
+ };
149
+ }
150
+ /**
151
+ * Convert a LangSmith run export.
152
+ *
153
+ * Accepts a JSON array of runs, a single run, `{ runs: [...] }` as the list
154
+ * endpoint returns it, or newline-delimited runs. Pure over its input.
155
+ */
156
+ export function langsmithRecords(text) {
157
+ const out = {
158
+ records: [],
159
+ rows: 0,
160
+ notModelCalls: 0,
161
+ unnamedModel: 0,
162
+ noTokens: 0,
163
+ reportedCostUsd: null,
164
+ unparseable: 0,
165
+ };
166
+ const runs = [];
167
+ const whole = tryParse(text);
168
+ if (whole !== undefined) {
169
+ if (Array.isArray(whole))
170
+ runs.push(...whole);
171
+ else {
172
+ const doc = asObject(whole);
173
+ if (doc !== null && Array.isArray(doc.runs))
174
+ runs.push(...doc.runs);
175
+ else if (doc !== null)
176
+ runs.push(doc);
177
+ }
178
+ }
179
+ else {
180
+ for (const line of text.split('\n')) {
181
+ if (line.trim() === '')
182
+ continue;
183
+ const parsed = tryParse(line);
184
+ if (parsed === undefined)
185
+ out.unparseable += 1;
186
+ else if (Array.isArray(parsed))
187
+ runs.push(...parsed);
188
+ else
189
+ runs.push(parsed);
190
+ }
191
+ }
192
+ let cost = 0;
193
+ let sawCost = false;
194
+ for (const raw of runs) {
195
+ const run = asObject(raw);
196
+ if (run === null)
197
+ continue;
198
+ /*
199
+ A run is only a call when LangSmith says it is one. The tree carries
200
+ chains, tools, retrievers and prompts alongside the model calls, and the
201
+ parent chain of an llm run repeats its child's tokens: summing the tree
202
+ would bill the same tokens once per level. `run_type` is the field that
203
+ settles it, and a run with no run_type at all is not a run.
204
+ */
205
+ const type = asName(run.run_type);
206
+ if (type === null)
207
+ continue;
208
+ if (type !== 'llm') {
209
+ out.notModelCalls += 1;
210
+ continue;
211
+ }
212
+ out.rows += 1;
213
+ const reported = asCount(run.total_cost);
214
+ if (reported !== undefined) {
215
+ cost += reported;
216
+ sawCost = true;
217
+ }
218
+ const model = modelOf(run);
219
+ if (model === null) {
220
+ out.unnamedModel += 1;
221
+ continue;
222
+ }
223
+ const { input, output } = tokensOf(run);
224
+ if (input === undefined && output === undefined) {
225
+ out.noTokens += 1;
226
+ continue;
227
+ }
228
+ if (input === 0 && output === 0)
229
+ out.noTokens += 1;
230
+ const ts = timeOf(run);
231
+ const label = labelOf(run);
232
+ /*
233
+ The trace is the conversation and the run id is one call. `trace_id`
234
+ spans the calls a single request made, which is the identity Trazum's
235
+ conversation findings need; answering them from `id` would report every
236
+ call as a conversation of one.
237
+ */
238
+ const session = asName(run.trace_id);
239
+ out.records.push({
240
+ model,
241
+ ...(ts !== undefined ? { ts } : {}),
242
+ ...(label !== undefined ? { label } : {}),
243
+ ...(session !== null ? { session } : {}),
244
+ usage: { input_tokens: input ?? 0, output_tokens: output ?? 0 },
245
+ });
246
+ }
247
+ // Rounded because these are dollars summed in floating point, and a total
248
+ // printed to eight decimal places reads as a precision nobody has.
249
+ if (sawCost)
250
+ out.reportedCostUsd = Math.round(cost * 1e6) / 1e6;
251
+ return out;
252
+ }
253
+ /**
254
+ * Whether a file looks like a LangSmith run export, by shape.
255
+ *
256
+ * Deliberately narrow: `run_type` beside one of the trace fields only
257
+ * LangSmith writes. A looser test would claim a Helicone export or a LiteLLM
258
+ * spend log — both carry `prompt_tokens` — and refuse it in this file's words
259
+ * instead of letting the code that can read it try.
260
+ */
261
+ export function looksLikeLangsmith(text, prefixBytes = 8192) {
262
+ const head = text.slice(0, prefixBytes);
263
+ if (!head.includes('"run_type"'))
264
+ return false;
265
+ return (head.includes('"trace_id"') ||
266
+ head.includes('"dotted_order"') ||
267
+ head.includes('"start_time"') ||
268
+ head.includes('"session_id"'));
269
+ }
270
+ //# sourceMappingURL=langsmith.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"langsmith.js","sourceRoot":"","sources":["../src/langsmith.ts"],"names":[],"mappings":"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"}
package/dist/levers.d.ts CHANGED
@@ -18,7 +18,7 @@ import type { UsageProfileReport } from './usage.js';
18
18
  *
19
19
  * | lever | what it moves |
20
20
  * |---|---|
21
- * | which model the call goes to | Opus 5 → Sonnet 5 is 40% off; → Haiku 4.5 is 80% |
21
+ * | which model the call goes to | Opus 5 → Sonnet 5 is 60% off; → Haiku 4.5 is 80% |
22
22
  * | the Batch API | 50% flat, on input and output |
23
23
  * | prompt caching | 3–4x the rules |
24
24
  * | shortening the prompt | ~1% |
package/dist/levers.js CHANGED
@@ -1,4 +1,4 @@
1
- import { effectivePricing, multipliersFor } from './pricing.js';
1
+ import { effectivePricing, isOffered, multipliersFor } from './pricing.js';
2
2
  import { UNLABELLED } from './usage.js';
3
3
  /**
4
4
  * Weakest first. A step *down* this ladder is what a route offers.
@@ -63,7 +63,7 @@ function candidateFor(model, breakdown, catalogue, on) {
63
63
  const candidates = catalogue.models.filter((m) => m.id !== model.id &&
64
64
  m.capability === target &&
65
65
  m.provider === model.provider &&
66
- m.recommendable !== false &&
66
+ isOffered(m) &&
67
67
  m.contextWindow >= avgInput);
68
68
  if (candidates.length === 0)
69
69
  return null;
@@ -1 +1 @@
1
- {"version":3,"file":"levers.js","sourceRoot":"","sources":["../src/levers.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,gBAAgB,EAAE,cAAc,EAAE,MAAM,cAAc,CAAC;AAChE,OAAO,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC;AA2HxC;;;;;;GAMG;AACH,MAAM,iBAAiB,GAAiB,CAAC,OAAO,EAAE,KAAK,EAAE,OAAO,EAAE,UAAU,CAAC,CAAC;AAE9E;;;;;;;GAOG;AACH,SAAS,QAAQ,CAAC,UAAsB;IACtC,MAAM,EAAE,GAAG,iBAAiB,CAAC,OAAO,CAAC,UAAU,CAAC,CAAC;IACjD,OAAO,EAAE,IAAI,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,iBAAiB,CAAC,EAAE,GAAG,CAAC,CAAE,CAAC;AACrD,CAAC;AAED,yFAAyF;AACzF,SAAS,SAAS,CAChB,SAAyB,EACzB,KAAmB,EACnB,EAAQ;IAER,MAAM,EAAE,YAAY,EAAE,aAAa,EAAE,GAAG,gBAAgB,CAAC,KAAK,EAAE,EAAE,CAAC,CAAC;IACpE,MAAM,KAAK,GAAG,cAAc,CAAC,KAAK,CAAC,CAAC;IACpC,MAAM,GAAG,GAAG,CAAC,MAAc,EAAE,IAAY,EAAU,EAAE,CAAC,CAAC,MAAM,GAAG,SAAS,CAAC,GAAG,IAAI,CAAC;IAElF,MAAM,QAAQ,GAAG,GAAG,CAAC,SAAS,CAAC,WAAW,EAAE,YAAY,CAAC,CAAC;IAC1D,MAAM,SAAS,GAAG,GAAG,CAAC,SAAS,CAAC,YAAY,EAAE,aAAa,CAAC,CAAC;IAC7D;;;;;;OAMG;IACH,MAAM,QAAQ,GACZ,GAAG,CAAC,SAAS,CAAC,eAAe,EAAE,YAAY,GAAG,KAAK,CAAC,SAAS,CAAC;QAC9D,GAAG,CAAC,SAAS,CAAC,gBAAgB,EAAE,YAAY,GAAG,KAAK,CAAC,YAAY,CAAC,CAAC;IAErE,OAAO,EAAE,QAAQ,EAAE,SAAS,EAAE,QAAQ,EAAE,QAAQ,EAAE,QAAQ,GAAG,SAAS,GAAG,QAAQ,EAAE,CAAC;AACtF,CAAC;AAED;;;;;;GAMG;AACH,SAAS,YAAY,CACnB,KAAmB,EACnB,SAAyB,EACzB,SAA2B,EAC3B,EAAQ;IAER,MAAM,MAAM,GAAG,QAAQ,CAAC,KAAK,CAAC,UAAU,CAAC,CAAC;IAC1C,IAAI,MAAM,KAAK,IAAI;QAAE,OAAO,IAAI,CAAC;IAEjC;;;;;;OAMG;IACH,MAAM,QAAQ,GACZ,SAAS,CAAC,KAAK,KAAK,CAAC;QACnB,CAAC,CAAC,CAAC;QACH,CAAC,CAAC,CAAC,SAAS,CAAC,WAAW,GAAG,SAAS,CAAC,eAAe,GAAG,SAAS,CAAC,gBAAgB,CAAC;YAChF,SAAS,CAAC,KAAK,CAAC;IAEtB,MAAM,UAAU,GAAG,SAAS,CAAC,MAAM,CAAC,MAAM,CACxC,CAAC,CAAC,EAAE,EAAE,CACJ,CAAC,CAAC,EAAE,KAAK,KAAK,CAAC,EAAE;QACjB,CAAC,CAAC,UAAU,KAAK,MAAM;QACvB,CAAC,CAAC,QAAQ,KAAK,KAAK,CAAC,QAAQ;QAC7B,CAAC,CAAC,aAAa,KAAK,KAAK;QACzB,CAAC,CAAC,aAAa,IAAI,QAAQ,CAC9B,CAAC;IACF,IAAI,UAAU,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO,IAAI,CAAC;IAEzC,OAAO,UAAU,CAAC,MAAM,CAAC,CAAC,IAAI,EAAE,CAAC,EAAE,EAAE,CACnC,SAAS,CAAC,SAAS,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,QAAQ,GAAG,SAAS,CAAC,SAAS,EAAE,IAAI,EAAE,EAAE,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAC1F,CAAC;AACJ,CAAC;AAgBD;;;;;;;;GAQG;AACH,MAAM,UAAU,UAAU,CACxB,MAA0B,EAC1B,OAAyB;IAEzB,MAAM,EAAE,SAAS,EAAE,EAAE,GAAG,IAAI,IAAI,EAAE,EAAE,QAAQ,GAAG,IAAI,EAAE,GAAG,OAAO,CAAC;IAChE,MAAM,QAAQ,GAAG,MAAM,CAAC,KAAK,CAAC,QAAQ,CAAC;IAEvC,MAAM,gBAAgB,GACpB,MAAM,CAAC,KAAK,CAAC,QAAQ,GAAG,MAAM,CAAC,KAAK,CAAC,YAAY,GAAG,MAAM,CAAC,KAAK,CAAC,aAAa,CAAC;IAEjF,IAAI,QAAQ,IAAI,CAAC,EAAE,CAAC;QAClB,OAAO,EAAE,MAAM,EAAE,EAAE,EAAE,gBAAgB,EAAE,kBAAkB,EAAE,CAAC,EAAE,QAAQ,EAAE,CAAC;IAC3E,CAAC;IAED,MAAM,MAAM,GAAkB,EAAE,CAAC;IAEjC,KAAK,MAAM,EAAE,KAAK,EAAE,KAAK,EAAE,OAAO,EAAE,SAAS,EAAE,IAAI,MAAM,CAAC,eAAe,EAAE,CAAC;QAC1E,MAAM,KAAK,GAAG,SAAS,CAAC,IAAI,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC;QAC1C,4EAA4E;QAC5E,iEAAiE;QACjE,IAAI,CAAC,KAAK,IAAI,SAAS,CAAC,QAAQ,IAAI,CAAC;YAAE,SAAS;QAEhD,MAAM,SAAS,GAAG,YAAY,CAAC,KAAK,EAAE,SAAS,EAAE,SAAS,EAAE,EAAE,CAAC,CAAC;QAChE,MAAM,MAAM,GAAG,SAAS,CAAC,CAAC,CAAC,SAAS,CAAC,SAAS,EAAE,SAAS,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC;QACtE,MAAM,KAAK,GACT,SAAS,IAAI,MAAM,IAAI,SAAS,CAAC,QAAQ,GAAG,MAAM,CAAC,QAAQ,GAAG,CAAC;YAC7D,CAAC,CAAC;gBACE,SAAS,EAAE,EAAE,EAAE,EAAE,SAAS,CAAC,EAAE,EAAE,WAAW,EAAE,SAAS,CAAC,WAAW,EAAE;gBACnE,SAAS,EAAE,SAAS,CAAC,QAAQ,GAAG,MAAM,CAAC,QAAQ;aAChD;YACH,CAAC,CAAC,IAAI,CAAC;QAEX;;;;;;;;WAQG;QACH,MAAM,SAAS,GAAG,cAAc,CAAC,KAAK,CAAC,CAAC,KAAK,CAAC;QAC9C,MAAM,SAAS,GAAG,SAAS,KAAK,IAAI,IAAI,SAAS,GAAG,CAAC,CAAC;QACtD,MAAM,KAAK,GAAG,SAAS;YACrB,CAAC,CAAC,EAAE,SAAS,EAAE,CAAC,SAAS,CAAC,QAAQ,GAAG,SAAS,CAAC,SAAS,CAAC,GAAG,CAAC,CAAC,GAAG,SAAU,CAAC,EAAE;YAC9E,CAAC,CAAC,IAAI,CAAC;QAET;;;;;;WAMG;QACH,MAAM,SAAS,GAAG,MAAM,IAAI;YAC1B,QAAQ,EAAE,SAAS,CAAC,QAAQ;YAC5B,SAAS,EAAE,SAAS,CAAC,SAAS;YAC9B,QAAQ,EAAE,SAAS,CAAC,YAAY,GAAG,SAAS,CAAC,aAAa;YAC1D,QAAQ,EAAE,SAAS,CAAC,QAAQ;SAC7B,CAAC;QACF,MAAM,YAAY,GAAG,SAAS;YAC5B,CAAC,CAAC,SAAS,CAAC,QAAQ,GAAG,CAAC,SAAS,CAAC,QAAQ,GAAG,SAAS,CAAC,SAAS,CAAC,GAAG,CAAC,CAAC,GAAG,SAAU,CAAC;YACpF,CAAC,CAAC,SAAS,CAAC,QAAQ,CAAC;QACvB,MAAM,WAAW,GAAG,SAAS,CAAC,QAAQ,GAAG,YAAY,CAAC;QAEtD,IAAI,WAAW,IAAI,CAAC;YAAE,SAAS;QAC/B,MAAM,WAAW,GAAG,WAAW,GAAG,QAAQ,CAAC;QAC3C,IAAI,WAAW,GAAG,QAAQ;YAAE,SAAS;QAErC,MAAM,CAAC,IAAI,CAAC;YACV,KAAK;YACL,KAAK,EAAE,OAAO;YACd,SAAS,EAAE,KAAK,CAAC,WAAW;YAC5B,KAAK,EAAE,SAAS,CAAC,KAAK;YACtB,QAAQ,EAAE,SAAS,CAAC,QAAQ;YAC5B,KAAK;YACL,KAAK;YACL,WAAW;YACX,WAAW;SACZ,CAAC,CAAC;IACL,CAAC;IAED,OAAO;QACL,MAAM,EAAE,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,WAAW,GAAG,CAAC,CAAC,WAAW,CAAC;QAC5D,gBAAgB;QAChB,kBAAkB,EAAE,gBAAgB,GAAG,QAAQ;QAC/C,QAAQ;KACT,CAAC;AACJ,CAAC;AAED,uEAAuE;AACvE,OAAO,EAAE,UAAU,EAAE,CAAC"}
1
+ {"version":3,"file":"levers.js","sourceRoot":"","sources":["../src/levers.ts"],"names":[],"mappings":"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"}
package/dist/pricing.d.ts CHANGED
@@ -7,7 +7,33 @@ import type { ModelPricing } from './types.js';
7
7
  * Amazon Bedrock and Vertex AI pricing is set by each partner and is NOT the
8
8
  * pricing in this table.
9
9
  */
10
- export declare const PRICING_LAST_REVIEWED = "2026-06-24";
10
+ /**
11
+ * When each provider's prices were last checked against that provider's own
12
+ * published table.
13
+ *
14
+ * One date for the whole catalogue was the wrong shape, and it cost a real
15
+ * error. Seven providers publish independently and are checked independently;
16
+ * a single date forces a partial review to either overstate itself by moving
17
+ * the date for everyone, or throw itself away by leaving it. What happened is
18
+ * the second: this constant was written on 2026-08-04 already reading
19
+ * 2026-06-24, and never moved again.
20
+ *
21
+ * Meanwhile Anthropic cancelled the increase that was going to take Sonnet 5
22
+ * from its 2/10 introductory price to 3/15 on 2026-09-01, and made 2/10
23
+ * standard. The catalogue still carried the promotion with its end date, so on
24
+ * 2026-09-01 every Sonnet 5 figure this tool printed would have risen 50% with
25
+ * no code change and no way for a reader to tell. A price nobody charges is
26
+ * the one error this product cannot make, and it was four days out on a timer.
27
+ *
28
+ * So: a date per provider, checked against that provider's own page, and the
29
+ * catalogue's headline date derived as the oldest of them rather than typed.
30
+ */
31
+ export declare const PROVIDER_REVIEWED: Readonly<Record<string, string>>;
32
+ /**
33
+ * The catalogue's age is its oldest provider's, because a reader asking how
34
+ * old this table is wants the answer for the worst part of it, not the best.
35
+ */
36
+ export declare const PRICING_LAST_REVIEWED: string;
11
37
  /** Cost multipliers relative to the input price. */
12
38
  /**
13
39
  * The defaults, which are Anthropic's numbers.
@@ -75,6 +101,25 @@ export interface PricingCatalogue {
75
101
  export declare function indexModels(models: ModelPricing[]): Map<string, ModelPricing>;
76
102
  /** The prices compiled into this release. */
77
103
  export declare const BUNDLED_CATALOGUE: PricingCatalogue;
104
+ /**
105
+ * Whether this model may be offered to a reader as something to move to.
106
+ *
107
+ * One home for a two-part rule that used to be written in four places as one
108
+ * part. `recommendable: false` — a private programme, a waitlist — was honoured
109
+ * at every one of them. `retired` is the stronger statement: the provider
110
+ * answered a real request for the id with an error, so a switch to it is not a
111
+ * worse recommendation, it is one that cannot be carried out at all.
112
+ *
113
+ * Written as a function rather than as a second `&&` at four call sites,
114
+ * because the fifth call site is always the one that gets written with only the
115
+ * first half. `pricing.test.js` fails a source file that filters on
116
+ * `recommendable` without coming through here, and that guard was proved by
117
+ * planting exactly that filter.
118
+ *
119
+ * Pricing is a separate question and stays answered: a retired model keeps its
120
+ * price, because a log full of its calls records money that was really spent.
121
+ */
122
+ export declare function isOffered(model: ModelPricing): boolean;
78
123
  /** Looks a model up in a specific catalogue. */
79
124
  export declare function modelFrom(catalogue: PricingCatalogue, id: string): ModelPricing;
80
125
  /**
@@ -93,11 +138,46 @@ export declare function cheapestOfTierIn(catalogue: PricingCatalogue, tier: Mode
93
138
  provider?: string): ModelPricing;
94
139
  export declare function getModel(id: string): ModelPricing;
95
140
  export declare function listModels(): ModelPricing[];
96
- export declare function effectivePricing(model: ModelPricing, on?: Date): {
141
+ /** Effective price on a given date, applying any live promotion. */
142
+ /**
143
+ * Memoised per model, because this runs once per record when a usage log is
144
+ * priced: a 200k-line profile called it 200k times, and the `new Date(...)`
145
+ * parse of the promo's end date alone was 0.7 of the 2.4 seconds the whole
146
+ * profile took — measured with --cpu-prof, not guessed. The cache keys on
147
+ * the model object (a WeakMap, so an overlay's models are collected with
148
+ * the overlay) and stores the parsed end-of-promo instant plus the two
149
+ * possible answers; `on` still decides which answer applies on every call,
150
+ * so behaviour is unchanged to the millisecond.
151
+ */
152
+ interface Rates {
97
153
  inputPerMTok: number;
98
154
  outputPerMTok: number;
99
155
  promoApplied: boolean;
100
- };
156
+ tier: {
157
+ applied: string | null;
158
+ decided: boolean;
159
+ because: string;
160
+ } | null;
161
+ }
162
+ /**
163
+ * What one call is billed at, and what decided it.
164
+ *
165
+ * `tier` is the field this grew for, and it carries three states rather than
166
+ * two. A model with no tiers gets `null`. A model whose condition could be
167
+ * evaluated gets the tier that applied, or the base rate with `applied: null`
168
+ * and `decided: true`. A model whose condition could **not** be evaluated —
169
+ * a size tier priced without a token count — gets `decided: false`, the
170
+ * **dearer** of the candidate rates, and `because` naming what would settle it.
171
+ *
172
+ * The dearer one is not a shrug. A cost figure that is a ceiling can prove
173
+ * "under budget" and can never surprise a bill; a floor chosen for looking
174
+ * better is the flattering direction this product spends its time refusing.
175
+ * The reader still has to be told, which is what `decided: false` is for, and
176
+ * `pricing.test.js` fails a tiered model whose report drops it.
177
+ */
178
+ export declare function effectivePricing(model: ModelPricing, on?: Date, context?: {
179
+ inputTokens?: number;
180
+ }): Rates;
101
181
  /** Cheapest model of each capability tier, for recommendations. */
102
182
  export declare function cheapestOfTier(tier: ModelPricing['tier']): ModelPricing;
103
183
  /**
@@ -116,5 +196,20 @@ export declare function cheapestOfTier(tier: ModelPricing['tier']): ModelPricing
116
196
  * a date — an overlay supplies this string, and a wrong one should read as
117
197
  * unknown rather than as a confident number computed from `NaN`.
118
198
  */
199
+ /**
200
+ * The age at which this product stops treating its own price table as current.
201
+ *
202
+ * Three surfaces warn a reader that the figures above may be off — `profile`,
203
+ * the MCP report, the browser's bill — and each of them had typed `45` into
204
+ * its own comparison, with four locale sentences stating it again in prose.
205
+ * Seven copies of one claim, and nothing that would notice when they
206
+ * disagreed; the sentence a reader sees names the number, so a drift between
207
+ * them would have been a surface telling the reader one threshold and applying
208
+ * another.
209
+ *
210
+ * The value is what those surfaces already published, not a new judgement.
211
+ */
212
+ export declare const STALE_PRICING_DAYS = 45;
119
213
  export declare function reviewAgeDays(lastReviewed: string, now: Date): number | null;
214
+ export {};
120
215
  //# sourceMappingURL=pricing.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"pricing.d.ts","sourceRoot":"","sources":["../src/pricing.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC;AAE/C;;;;;;;GAOG;AACH,eAAO,MAAM,qBAAqB,eAAe,CAAC;AAElD,oDAAoD;AACpD;;;;;;;;GAQG;AACH,eAAO,MAAM,gBAAgB;IAC3B,uCAAuC;aACvC,YAAY,EAAE,IAAI;IAClB,qCAAqC;aACrC,YAAY,EAAE,CAAG;IACjB,2CAA2C;aAC3C,SAAS,EAAE,GAAG;IACd,mDAAmD;aACnD,KAAK,EAAE,GAAG;CACF,CAAC;AAeX,wBAAgB,cAAc,CAAC,KAAK,EAAE,YAAY,GAAG;IACnD,YAAY,EAAE,MAAM,CAAC;IACrB,YAAY,EAAE,MAAM,CAAC;IACrB,SAAS,EAAE,MAAM,CAAC;IAClB,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;CACtB,CAYA;AAED,eAAO,MAAM,MAAM,EAAE,YAAY,EAqQhC,CAAC;AAEF,eAAO,MAAM,aAAa,kBAAkB,CAAC;AAE7C;;;;;;;;;;;;;GAaG;AACH,MAAM,WAAW,gBAAgB;IAC/B,MAAM,EAAE,YAAY,EAAE,CAAC;IACvB,IAAI,EAAE,GAAG,CAAC,MAAM,EAAE,YAAY,CAAC,CAAC;IAChC,+DAA+D;IAC/D,YAAY,EAAE,MAAM,CAAC;IACrB,+EAA+E;IAC/E,gBAAgB,EAAE,MAAM,EAAE,CAAC;IAC3B,0EAA0E;IAC1E,WAAW,EAAE,MAAM,EAAE,CAAC;CACvB;AAED;;;;;;;;;;;GAWG;AACH,wBAAgB,WAAW,CAAC,MAAM,EAAE,YAAY,EAAE,GAAG,GAAG,CAAC,MAAM,EAAE,YAAY,CAAC,CAK7E;AAiBD,6CAA6C;AAC7C,eAAO,MAAM,iBAAiB,EAAE,gBAA+D,CAAC;AAEhG,gDAAgD;AAChD,wBAAgB,SAAS,CAAC,SAAS,EAAE,gBAAgB,EAAE,EAAE,EAAE,MAAM,GAAG,YAAY,CAQ/E;AAED;;;;;GAKG;AACH,wBAAgB,gBAAgB,CAC9B,SAAS,EAAE,gBAAgB,EAC3B,IAAI,EAAE,YAAY,CAAC,MAAM,CAAC,EAC1B,EAAE,GAAE,IAAiB;AACrB;;;;;GAKG;AACH,QAAQ,CAAC,EAAE,MAAM,GAChB,YAAY,CAcd;AAED,wBAAgB,QAAQ,CAAC,EAAE,EAAE,MAAM,GAAG,YAAY,CAEjD;AAED,wBAAgB,UAAU,IAAI,YAAY,EAAE,CAE3C;AAsBD,wBAAgB,gBAAgB,CAC9B,KAAK,EAAE,YAAY,EACnB,EAAE,GAAE,IAAiB,GACpB;IAAE,YAAY,EAAE,MAAM,CAAC;IAAC,aAAa,EAAE,MAAM,CAAC;IAAC,YAAY,EAAE,OAAO,CAAA;CAAE,CAuBxE;AAED,mEAAmE;AACnE,wBAAgB,cAAc,CAAC,IAAI,EAAE,YAAY,CAAC,MAAM,CAAC,GAAG,YAAY,CAKvE;AAED;;;;;;;;;;;;;;;GAeG;AACH,wBAAgB,aAAa,CAAC,YAAY,EAAE,MAAM,EAAE,GAAG,EAAE,IAAI,GAAG,MAAM,GAAG,IAAI,CAU5E"}
1
+ {"version":3,"file":"pricing.d.ts","sourceRoot":"","sources":["../src/pricing.ts"],"names":[],"mappings":"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"}