@rayadesu/dsh-llm-billing 0.3.7 → 0.3.9
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/README.i18n.yaml +2 -2
- package/README.md +15 -11
- package/README.zh.md +15 -11
- package/lib/index.js +924 -382
- package/lib/typert.host.js +49 -5
- package/lib/typert.remote-client.d.ts +5 -3
- package/lib/typert.remote-client.js +49 -5
- package/lib/types/balance.d.ts +33 -15
- package/lib/types/balance.js +28 -13
- package/lib/types/billing.d.ts +217 -21
- package/lib/types/billing.js +445 -71
- package/lib/types/index.d.ts +14 -4
- package/lib/types/index.js +213 -70
- package/lib/types/projection.d.ts +24 -25
- package/lib/types/projection.js +30 -31
- package/lib/types/today-spend.d.ts +138 -62
- package/lib/types/today-spend.js +209 -261
- package/lib/types/types.d.ts +30 -5
- package/lib/types/types.js +8 -0
- package/package.json +5 -1
package/lib/types/billing.d.ts
CHANGED
|
@@ -12,8 +12,9 @@
|
|
|
12
12
|
* from the others.
|
|
13
13
|
* @module @rayadesu/dsh-llm-billing/billing
|
|
14
14
|
*/
|
|
15
|
+
import type { TokenUsage } from '@deepseek-ai/dsh-llm';
|
|
15
16
|
import type { SessionEvent } from '@deepseek-ai/dsh-session';
|
|
16
|
-
import type { DeepSeekSessionSpend, DeepSeekTodaySpend, DeepSeekTurnSpend } from './types.ts';
|
|
17
|
+
import type { DeepSeekSessionSpend, DeepSeekSessionTurnSpends, DeepSeekTodaySpend, DeepSeekTurnSpend } from './types.ts';
|
|
17
18
|
/** One token price point, in CNY per 1M tokens. */
|
|
18
19
|
export interface DeepSeekTokenPrice {
|
|
19
20
|
/** 1M input cache-hit tokens. */
|
|
@@ -53,7 +54,7 @@ export interface BillingConfig {
|
|
|
53
54
|
* only; weekends (Saturday and Sunday) are always off-peak.
|
|
54
55
|
*/
|
|
55
56
|
peakHours?: PeakHourWindow[];
|
|
56
|
-
/** Per-model pricing rows; omission uses the V4 Flash, V4 Pro, and V4 Flash Vision defaults. */
|
|
57
|
+
/** Per-model pricing rows; omission uses the V4 Flash, V4.1 Flash, V4 Pro, and V4 Flash Vision defaults. */
|
|
57
58
|
models?: BillingConfigModel[];
|
|
58
59
|
}
|
|
59
60
|
/**
|
|
@@ -61,12 +62,9 @@ export interface BillingConfig {
|
|
|
61
62
|
* applied on weekdays (Monday–Friday) only — weekends are always off-peak
|
|
62
63
|
* (effective 2026-08-23).
|
|
63
64
|
*/
|
|
64
|
-
export declare const DEFAULT_PEAK_HOURS:
|
|
65
|
-
start: number;
|
|
66
|
-
end: number;
|
|
67
|
-
}[];
|
|
65
|
+
export declare const DEFAULT_PEAK_HOURS: readonly PeakHourWindow[];
|
|
68
66
|
/** Official peak/off-peak rates (CNY per 1M tokens), effective 2026-08-17. */
|
|
69
|
-
export declare const DEFAULT_MODEL_PRICING: BillingConfigModel[];
|
|
67
|
+
export declare const DEFAULT_MODEL_PRICING: readonly BillingConfigModel[];
|
|
70
68
|
/** Resolved billing configuration: a pricing table plus peak-hour windows. */
|
|
71
69
|
export interface ResolvedBilling {
|
|
72
70
|
peakHours: readonly {
|
|
@@ -85,6 +83,27 @@ export interface ResolvedBilling {
|
|
|
85
83
|
* @returns the resolved table and peak-hour windows.
|
|
86
84
|
*/
|
|
87
85
|
export declare function resolveBilling(config: BillingConfig | undefined): ResolvedBilling;
|
|
86
|
+
/** One shifted-timestamp view of a Beijing (UTC+8, no DST) instant. */
|
|
87
|
+
export interface BeijingParts {
|
|
88
|
+
/** Beijing hour, `0`–`23`. */
|
|
89
|
+
hour: number;
|
|
90
|
+
/** Beijing weekday as `getUTCDay()`: `0` is Sunday, `6` is Saturday. */
|
|
91
|
+
weekday: number;
|
|
92
|
+
/** Beijing calendar-day key (`YYYY-MM-DD`). */
|
|
93
|
+
dayKey: string;
|
|
94
|
+
}
|
|
95
|
+
/**
|
|
96
|
+
* Derive the Beijing hour, weekday, and calendar-day key of one timestamp with
|
|
97
|
+
* pure integer arithmetic — every timezone-sensitive read shares this one
|
|
98
|
+
* implementation, so the pieces cannot drift apart. Callers that filter by
|
|
99
|
+
* day and then price the same event reuse the returned view, so each event is
|
|
100
|
+
* parsed exactly once. (The hot fold path runs this per committed event; the
|
|
101
|
+
* previous `Date` + `toISOString().slice()` version allocated a `Date` and a
|
|
102
|
+
* 24-character string per call.)
|
|
103
|
+
* @param time - epoch milliseconds.
|
|
104
|
+
* @throws {RangeError} when `time` is not a finite number.
|
|
105
|
+
*/
|
|
106
|
+
export declare function beijingPartsOf(time: number): BeijingParts;
|
|
88
107
|
/** The Beijing (Asia/Shanghai, UTC+8, no DST) calendar-day key of a timestamp. */
|
|
89
108
|
export declare function beijingDayKey(now: Date): string;
|
|
90
109
|
/**
|
|
@@ -183,14 +202,37 @@ export interface BillingEventContribution {
|
|
|
183
202
|
* only; weekends are off-peak). Each `assistant/message` event with usage
|
|
184
203
|
* contributes cache-hit input, cache-miss input (uncached input plus cache
|
|
185
204
|
* writes), and output (reasoning included) tokens at the rate of its own
|
|
186
|
-
* timestamp; a model with usage but no pricing row contributes nothing
|
|
187
|
-
* published table prices only the two V4 rows).
|
|
205
|
+
* timestamp; a model with usage but no pricing row contributes nothing.
|
|
188
206
|
* @param event - the event to price.
|
|
189
207
|
* @param billing - resolved pricing with peak-hour windows.
|
|
190
208
|
* @param names - model id → display label.
|
|
191
209
|
* @returns the priced contribution, or `undefined` when the event has no priced usage.
|
|
192
210
|
*/
|
|
193
211
|
export declare function priceEvent(event: SessionEvent, billing: ResolvedBilling, names: ReadonlyMap<string, string>): BillingEventContribution | undefined;
|
|
212
|
+
/**
|
|
213
|
+
* Price one event at the official per-model rates using a precomputed
|
|
214
|
+
* Beijing-time view — the day-filtering and pricing of one event share a
|
|
215
|
+
* single timezone parse (see {@link beijingPartsOf}). Semantics are identical
|
|
216
|
+
* to {@link priceEvent}.
|
|
217
|
+
* @param parts - the event's Beijing-time view.
|
|
218
|
+
* @param event - the event to price.
|
|
219
|
+
* @param billing - resolved pricing with peak-hour windows.
|
|
220
|
+
* @param names - model id → display label.
|
|
221
|
+
* @returns the priced contribution, or `undefined` when the event has no priced usage.
|
|
222
|
+
*/
|
|
223
|
+
export declare function priceEventAt(parts: BeijingParts, event: SessionEvent, billing: ResolvedBilling, names: ReadonlyMap<string, string>): BillingEventContribution | undefined;
|
|
224
|
+
/**
|
|
225
|
+
* Price one provider-reported usage sample for one model at the rates of the
|
|
226
|
+
* sample's own Beijing-time hour and weekday. `undefined` when the model has
|
|
227
|
+
* no pricing row.
|
|
228
|
+
* @param parts - the sample's Beijing-time view.
|
|
229
|
+
* @param usage - the reported token buckets.
|
|
230
|
+
* @param model - the wire model id the sample belongs to.
|
|
231
|
+
* @param billing - resolved pricing with peak-hour windows.
|
|
232
|
+
* @param names - model id → display label.
|
|
233
|
+
* @returns the priced contribution, or `undefined` when the model has no rate row.
|
|
234
|
+
*/
|
|
235
|
+
export declare function priceUsage(parts: BeijingParts, usage: TokenUsage, model: string, billing: ResolvedBilling, names: ReadonlyMap<string, string>): BillingEventContribution | undefined;
|
|
194
236
|
/** A spend with no priced usage. */
|
|
195
237
|
export declare function emptyTodaySpend(): DeepSeekTodaySpend;
|
|
196
238
|
/**
|
|
@@ -209,6 +251,96 @@ export declare class SpendAccumulator {
|
|
|
209
251
|
/** The folded spend; the accumulator stays usable afterwards. */
|
|
210
252
|
finish(): DeepSeekTodaySpend;
|
|
211
253
|
}
|
|
254
|
+
/** The additive inverse of one spend (pure): used to replace a priced sample. */
|
|
255
|
+
export declare function negateSpend(spend: DeepSeekTodaySpend): DeepSeekTodaySpend;
|
|
256
|
+
/**
|
|
257
|
+
* Subtract one spend from another (pure). Rows that cancel out completely are
|
|
258
|
+
* dropped so a replaced sample leaves no zero row behind.
|
|
259
|
+
* @param target - the spend to subtract from.
|
|
260
|
+
* @param source - the spend to remove.
|
|
261
|
+
* @returns the difference.
|
|
262
|
+
*/
|
|
263
|
+
export declare function subtractSpend(target: DeepSeekTodaySpend, source: DeepSeekTodaySpend): DeepSeekTodaySpend;
|
|
264
|
+
/**
|
|
265
|
+
* One priced attempt sample kept for same-step replacement: DSH can report the
|
|
266
|
+
* same `(turn, step)` twice (an `assistant/attempt` stream and the
|
|
267
|
+
* `assistant/message` that assembles from it), and a later sample replaces the
|
|
268
|
+
* earlier one instead of adding to it. `llm/retry-started` clears the slot, so
|
|
269
|
+
* a retried attempt adds rather than replaces (both requests were billed).
|
|
270
|
+
*/
|
|
271
|
+
export interface BillingFoldSample {
|
|
272
|
+
/** Turn of the producing attempt. */
|
|
273
|
+
turn: number;
|
|
274
|
+
/** Step of the producing attempt. */
|
|
275
|
+
step: number;
|
|
276
|
+
/** Beijing day of the sample's timestamp. */
|
|
277
|
+
dayKey: string;
|
|
278
|
+
/** The sample's contribution as a one-row spend (subtracted on replacement). */
|
|
279
|
+
spend: DeepSeekTodaySpend;
|
|
280
|
+
}
|
|
281
|
+
/**
|
|
282
|
+
* Plain-JSON fold state of one session's billed spend: the latest priced day,
|
|
283
|
+
* the whole-session total, the fork boundary, the model of the latest request
|
|
284
|
+
* (needed to price an `assistant/attempt`, which carries no route), and the
|
|
285
|
+
* last sample kept for replacement.
|
|
286
|
+
*/
|
|
287
|
+
export interface BillingFoldState {
|
|
288
|
+
/** Beijing-time calendar-day key of `spend`; `''` for no priced usage. */
|
|
289
|
+
dayKey: string;
|
|
290
|
+
/** The spend of the session's latest priced Beijing day (own events only). */
|
|
291
|
+
spend: DeepSeekTodaySpend;
|
|
292
|
+
/** The spend of the session's OWN events across every day. */
|
|
293
|
+
session: DeepSeekTodaySpend;
|
|
294
|
+
/** Fork-inherited prefix length; events below it belong to the source session. */
|
|
295
|
+
inheritedEventCount: number;
|
|
296
|
+
/** Wire model of the latest `request/header`; `''` before the first one. */
|
|
297
|
+
model: string;
|
|
298
|
+
/** Latest priced attempt sample, for same-step replacement. */
|
|
299
|
+
last: BillingFoldSample | null;
|
|
300
|
+
}
|
|
301
|
+
/** The empty fold state for one fork boundary. */
|
|
302
|
+
export declare function emptyBillingFoldState(inheritedEventCount?: number): BillingFoldState;
|
|
303
|
+
/**
|
|
304
|
+
* Fold one committed event into a session's billed-spend state.
|
|
305
|
+
*
|
|
306
|
+
* Priced samples come from `assistant/message` (its own reported usage, or the
|
|
307
|
+
* stream's last usage chunk) and `assistant/attempt` (the stream's last usage
|
|
308
|
+
* chunk, priced with the model of the latest `request/header`, since an
|
|
309
|
+
* attempt carries no route). A sample for the same `(turn, step)` replaces the
|
|
310
|
+
* previous one; `llm/retry-started` closes the replacement slot so a retried
|
|
311
|
+
* attempt adds. Every other event is inert and returns the same state
|
|
312
|
+
* reference.
|
|
313
|
+
* @param state - the previous fold state.
|
|
314
|
+
* @param event - the committed event.
|
|
315
|
+
* @param billing - resolved pricing with peak-hour windows.
|
|
316
|
+
* @param names - model id → display label.
|
|
317
|
+
* @returns the next state (the same reference when nothing was priced).
|
|
318
|
+
*/
|
|
319
|
+
export declare function applyBillingEvent(state: BillingFoldState, event: SessionEvent, billing: ResolvedBilling, names: ReadonlyMap<string, string>): BillingFoldState;
|
|
320
|
+
/**
|
|
321
|
+
* Mutable wrapper over {@link applyBillingEvent} for the pure pricing paths:
|
|
322
|
+
* feed events in order, read the folded spend.
|
|
323
|
+
*/
|
|
324
|
+
export declare class BillingFolder {
|
|
325
|
+
private readonly billing;
|
|
326
|
+
private state;
|
|
327
|
+
/**
|
|
328
|
+
* @param billing - resolved pricing with peak-hour windows.
|
|
329
|
+
* @param catalog - model display rows, in presentation order.
|
|
330
|
+
* @param inheritedEventCount - fork boundary to skip (default 0).
|
|
331
|
+
*/
|
|
332
|
+
constructor(billing: ResolvedBilling, catalog: readonly {
|
|
333
|
+
id: string;
|
|
334
|
+
name: string;
|
|
335
|
+
}[], inheritedEventCount?: number);
|
|
336
|
+
private readonly names;
|
|
337
|
+
/** Fold one event. */
|
|
338
|
+
add(event: SessionEvent): void;
|
|
339
|
+
/** Fold every event, in order. */
|
|
340
|
+
addAll(events: readonly SessionEvent[]): void;
|
|
341
|
+
/** The folded state (live reference; do not mutate). */
|
|
342
|
+
get fold(): BillingFoldState;
|
|
343
|
+
}
|
|
212
344
|
/**
|
|
213
345
|
* Merge one priced event's contribution into an accumulator spend (pure:
|
|
214
346
|
* returns a new spend, never mutates its input).
|
|
@@ -226,7 +358,11 @@ export declare function addEventContribution(spend: DeepSeekTodaySpend, priced:
|
|
|
226
358
|
*/
|
|
227
359
|
export declare function mergeTodaySpend(target: DeepSeekTodaySpend, source: DeepSeekTodaySpend): DeepSeekTodaySpend;
|
|
228
360
|
/**
|
|
229
|
-
* Price one session's complete event log at the official per-model rates
|
|
361
|
+
* Price one session's complete event log at the official per-model rates,
|
|
362
|
+
* with DSH's attempt semantics: every provider-reported sample (an
|
|
363
|
+
* `assistant/message`'s usage, or an `assistant/attempt`'s stream usage)
|
|
364
|
+
* contributes, a later sample for the same `(turn, step)` replaces the earlier
|
|
365
|
+
* one, and `llm/retry-started` makes the retried attempt add.
|
|
230
366
|
* @param events - one session's complete event log.
|
|
231
367
|
* @param billing - resolved pricing with peak-hour windows.
|
|
232
368
|
* @param catalog - model display rows, in presentation order.
|
|
@@ -241,13 +377,13 @@ export declare function computeSessionSpend(events: readonly SessionEvent[], bil
|
|
|
241
377
|
name: string;
|
|
242
378
|
}[], startSeq?: number): DeepSeekSessionSpend;
|
|
243
379
|
/**
|
|
244
|
-
* Price one completed Turn's billed usage
|
|
245
|
-
*
|
|
246
|
-
*
|
|
247
|
-
*
|
|
248
|
-
*
|
|
249
|
-
*
|
|
250
|
-
*
|
|
380
|
+
* Price one completed Turn's billed usage, identified by its closing
|
|
381
|
+
* assistant message id. The turn's events are those between its `turn/start`
|
|
382
|
+
* and `turn/end` (both matched by the message's own turn coordinate), priced
|
|
383
|
+
* with the same attempt semantics as {@link computeSessionSpend}. A message
|
|
384
|
+
* that cannot be located, a turn without bracketing `turn/start` / `turn/end`
|
|
385
|
+
* events (for example after compaction), or a session with no priced usage
|
|
386
|
+
* prices to zero.
|
|
251
387
|
* @param events - one session's complete event log.
|
|
252
388
|
* @param billing - resolved pricing with peak-hour windows.
|
|
253
389
|
* @param catalog - model display rows, in presentation order.
|
|
@@ -259,10 +395,70 @@ export declare function computeTurnSpend(events: readonly SessionEvent[], billin
|
|
|
259
395
|
name: string;
|
|
260
396
|
}[], messageId: string): DeepSeekTurnSpend;
|
|
261
397
|
/**
|
|
262
|
-
*
|
|
263
|
-
*
|
|
264
|
-
*
|
|
265
|
-
*
|
|
398
|
+
* Incremental single-pass fold of one session's completed-Turn costs, keyed by
|
|
399
|
+
* the id of every assistant message inside each Turn. Feeding the fold only
|
|
400
|
+
* the appended tail keeps a growing session's map current in O(new events)
|
|
401
|
+
* instead of re-scanning the whole log per message.
|
|
402
|
+
*
|
|
403
|
+
* Semantics are exactly {@link computeTurnSpend}'s: a Turn is the
|
|
404
|
+
* `turn/start`..`turn/end` range (matched by the event's own turn coordinate),
|
|
405
|
+
* every priced event inside it contributes at its own timestamp's rate, and a
|
|
406
|
+
* message outside any bracket contributes nothing.
|
|
407
|
+
*/
|
|
408
|
+
export declare class SessionTurnSpendFolder {
|
|
409
|
+
private readonly billing;
|
|
410
|
+
private readonly catalog;
|
|
411
|
+
private readonly rows;
|
|
412
|
+
private ids;
|
|
413
|
+
/** Events of the open Turn, folded with the shared attempt semantics on close. */
|
|
414
|
+
private events;
|
|
415
|
+
private open;
|
|
416
|
+
/** Events already fed; a shorter log resets the fold. */
|
|
417
|
+
private cursor;
|
|
418
|
+
/**
|
|
419
|
+
* @param billing - resolved pricing with peak-hour windows.
|
|
420
|
+
* @param catalog - model display rows, in presentation order.
|
|
421
|
+
*/
|
|
422
|
+
constructor(billing: ResolvedBilling, catalog: readonly {
|
|
423
|
+
id: string;
|
|
424
|
+
name: string;
|
|
425
|
+
}[]);
|
|
426
|
+
/** How many events have been folded so far (the host's incremental cursor). */
|
|
427
|
+
get processed(): number;
|
|
428
|
+
/**
|
|
429
|
+
* Fold every event from the cursor to the end of the log. A log shorter than
|
|
430
|
+
* the cursor (rewritten session) restarts the fold from an empty state.
|
|
431
|
+
* @param events - the session's complete event log, in seq order.
|
|
432
|
+
*/
|
|
433
|
+
feed(events: readonly SessionEvent[]): void;
|
|
434
|
+
/** The folded map; the fold stays usable afterwards. */
|
|
435
|
+
finish(): DeepSeekSessionTurnSpends;
|
|
436
|
+
/** Drop the fold state so the next feed starts from the log's beginning. */
|
|
437
|
+
private reset;
|
|
438
|
+
}
|
|
439
|
+
/**
|
|
440
|
+
* Price every completed Turn of one session in a single pass (the pure
|
|
441
|
+
* equivalent of {@link SessionTurnSpendFolder}).
|
|
442
|
+
* @param events - one session's complete event log.
|
|
443
|
+
* @param billing - resolved pricing with peak-hour windows.
|
|
444
|
+
* @param catalog - model display rows, in presentation order.
|
|
445
|
+
* @returns one row per assistant message inside a completed Turn, in log order.
|
|
446
|
+
*/
|
|
447
|
+
export declare function computeSessionTurnSpends(events: readonly SessionEvent[], billing: ResolvedBilling, catalog: readonly {
|
|
448
|
+
id: string;
|
|
449
|
+
name: string;
|
|
450
|
+
}[]): DeepSeekSessionTurnSpends;
|
|
451
|
+
/**
|
|
452
|
+
* Price one session's log for the Beijing-time calendar day of `now`. Events
|
|
453
|
+
* after the reference day are ignored; the fold's latest-day state then
|
|
454
|
+
* answers the query exactly (empty when the session's latest priced day is not
|
|
455
|
+
* the reference day). Pricing follows {@link applyBillingEvent} (attempt
|
|
456
|
+
* samples with same-step replacement).
|
|
457
|
+
*
|
|
458
|
+
* The fold's `(turn, step)` replacement slot is per session, so callers must
|
|
459
|
+
* pass ONE session's log; aggregate across sessions with
|
|
460
|
+
* {@link mergeTodaySpend}.
|
|
461
|
+
* @param events - one session's complete event log.
|
|
266
462
|
* @param billing - resolved pricing with peak-hour windows.
|
|
267
463
|
* @param catalog - model display rows, in presentation order.
|
|
268
464
|
* @param now - the reference moment whose Beijing-time calendar day is "today".
|