@thehammer/danx-session-telemetry 0.1.41 → 0.1.42

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/.source-hash CHANGED
@@ -1 +1 @@
1
- b066d72035e89bbf909f51f078f014e0b3910566bcb2d035c5f469b44573efa6
1
+ f4864e2bc2491a9df2c4f0c3ec86da8a35ad36225049696e9e2ca5b544931859
package/dist/pricing.d.ts CHANGED
@@ -114,15 +114,28 @@ export type PriceResult = {
114
114
  * cleanly, whatever its id looks like.
115
115
  */
116
116
  export declare function priceUsage(model: string, speed: string, tokens: PricedTokens): PriceResult;
117
+ /**
118
+ * The list price `priceUsage` charges for a model at a speed (a fast request on a model that bills fast at the standard rate reads the
119
+ * standard table), or `null` when the tables have none. The default `PriceLookup` of {@link priceLedgerCredit}.
120
+ */
121
+ export declare function listedPrice(model: string, speed: string): ModelPrice | null;
122
+ /**
123
+ * DX-4595 - dollars for `tokens` at `price` (USD per million tokens): each bucket with its own price. The ONE copy of the formula: `priceUsage`
124
+ * charges the list price with it, and spend pacing charges an account's own (editable) prices with it.
125
+ */
126
+ export declare function costOfTokens(tokens: PricedTokens, price: ModelPrice): number;
117
127
  /** True when `model` has a standard-speed price (used by tests + guards). */
118
128
  export declare function isPricedModel(model: string): boolean;
129
+ /** What a model costs at a speed, per million tokens; `null` when there is no price. */
130
+ export type PriceLookup = (model: string, speed: string) => ModelPrice | null;
119
131
  /**
120
132
  * DX-4508 — one ledger credit's cost, exactly as the server's usage-ledger writer stores it (moved here from
121
133
  * `src/dashboard/usage-ledger.ts` so the live sub-agent view, `subagent-live.ts`, prices a reply with the SAME rule
122
134
  * instead of a copy): a `<synthetic>` reply costs nothing and is never unpriced; a reply with no model is unpriced only
123
- * when it carries tokens; any other model goes through {@link priceUsage}, an unpriced one costing 0 and naming itself.
135
+ * when it carries tokens; any other model is priced by `priceOf` (the list prices by default, so as {@link priceUsage} does), an unpriced
136
+ * one costing 0 and naming itself. DX-4595: spend pacing passes an account's own prices as `priceOf` and so gets the same rule.
124
137
  */
125
- export declare function priceLedgerCredit(model: string | null, speed: string, tokens: PricedTokens): {
138
+ export declare function priceLedgerCredit(model: string | null, speed: string, tokens: PricedTokens, priceOf?: PriceLookup): {
126
139
  costUsd: number;
127
140
  unpriced: {
128
141
  model: string;
package/dist/pricing.js CHANGED
@@ -163,20 +163,29 @@ export function listListPrices() {
163
163
  * cleanly, whatever its id looks like.
164
164
  */
165
165
  export function priceUsage(model, speed, tokens) {
166
+ const price = listedPrice(model, speed);
167
+ return price === null ? { kind: "unpriced", model, speed } : { kind: "priced", costUsd: costOfTokens(tokens, price) };
168
+ }
169
+ /**
170
+ * The list price `priceUsage` charges for a model at a speed (a fast request on a model that bills fast at the standard rate reads the
171
+ * standard table), or `null` when the tables have none. The default `PriceLookup` of {@link priceLedgerCredit}.
172
+ */
173
+ export function listedPrice(model, speed) {
166
174
  const useFastTable = speed === FAST_SPEED && !FAST_BILLS_AT_STANDARD_RATE.has(model);
167
175
  const table = useFastTable ? FAST_PRICING : PRICING;
168
- if (!Object.hasOwn(table, model))
169
- return { kind: "unpriced", model, speed };
170
- const p = table[model];
171
- return {
172
- kind: "priced",
173
- costUsd: (tokens.input * p.input +
174
- tokens.output * p.output +
175
- tokens.cacheRead * p.cacheRead +
176
- tokens.cacheWrite5m * p.cacheWrite5m +
177
- tokens.cacheWrite1h * p.cacheWrite1h) /
178
- 1_000_000,
179
- };
176
+ return Object.hasOwn(table, model) ? table[model] : null;
177
+ }
178
+ /**
179
+ * DX-4595 - dollars for `tokens` at `price` (USD per million tokens): each bucket with its own price. The ONE copy of the formula: `priceUsage`
180
+ * charges the list price with it, and spend pacing charges an account's own (editable) prices with it.
181
+ */
182
+ export function costOfTokens(tokens, price) {
183
+ return ((tokens.input * price.input +
184
+ tokens.output * price.output +
185
+ tokens.cacheRead * price.cacheRead +
186
+ tokens.cacheWrite5m * price.cacheWrite5m +
187
+ tokens.cacheWrite1h * price.cacheWrite1h) /
188
+ 1_000_000);
180
189
  }
181
190
  /** True when `model` has a standard-speed price (used by tests + guards). */
182
191
  export function isPricedModel(model) {
@@ -188,15 +197,16 @@ export function isPricedModel(model) {
188
197
  * DX-4508 — one ledger credit's cost, exactly as the server's usage-ledger writer stores it (moved here from
189
198
  * `src/dashboard/usage-ledger.ts` so the live sub-agent view, `subagent-live.ts`, prices a reply with the SAME rule
190
199
  * instead of a copy): a `<synthetic>` reply costs nothing and is never unpriced; a reply with no model is unpriced only
191
- * when it carries tokens; any other model goes through {@link priceUsage}, an unpriced one costing 0 and naming itself.
200
+ * when it carries tokens; any other model is priced by `priceOf` (the list prices by default, so as {@link priceUsage} does), an unpriced
201
+ * one costing 0 and naming itself. DX-4595: spend pacing passes an account's own prices as `priceOf` and so gets the same rule.
192
202
  */
193
- export function priceLedgerCredit(model, speed, tokens) {
203
+ export function priceLedgerCredit(model, speed, tokens, priceOf = listedPrice) {
194
204
  if (model === SYNTHETIC_MODEL)
195
205
  return { costUsd: 0, unpriced: null };
196
206
  if (model === null) {
197
207
  const zero = tokens.input === 0 && tokens.output === 0 && tokens.cacheRead === 0 && tokens.cacheWrite5m === 0 && tokens.cacheWrite1h === 0;
198
208
  return zero ? { costUsd: 0, unpriced: null } : { costUsd: 0, unpriced: { model: "(none)", speed } };
199
209
  }
200
- const r = priceUsage(model, speed, tokens);
201
- return r.kind === "priced" ? { costUsd: r.costUsd, unpriced: null } : { costUsd: 0, unpriced: { model: r.model, speed: r.speed } };
210
+ const price = priceOf(model, speed);
211
+ return price === null ? { costUsd: 0, unpriced: { model, speed } } : { costUsd: costOfTokens(tokens, price), unpriced: null };
202
212
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@thehammer/danx-session-telemetry",
3
- "version": "0.1.41",
3
+ "version": "0.1.42",
4
4
  "description": "Shared Claude Code transcript collector (DX-2962) — incremental JSONL tailing for the danxbot worker and the danx-dashboard-mcp desktop bridge, so both run identical collector code.",
5
5
  "license": "MIT",
6
6
  "type": "module",
@@ -31,6 +31,7 @@
31
31
  "node": ">=20"
32
32
  },
33
33
  "scripts": {
34
+ "prepublishOnly": "bash ../../scripts/assert-tree-contains-origin-main.sh @thehammer/danx-session-telemetry",
34
35
  "build": "tsc -p tsconfig.json",
35
36
  "verify:boot": "bash scripts/verify-boot.sh",
36
37
  "test": "vitest run",