@rayadesu/dsh-llm-billing 0.2.2 → 0.2.4

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.
@@ -27,6 +27,14 @@ const _rayadesu_dsh_llm_billing_billing_getSessionSpend_result$schema = z.object
27
27
  'outputCost': z.number(),
28
28
  })),
29
29
  })
30
+ const _rayadesu_dsh_llm_billing_billing_getTodaySessionsSpend_parameter_0$schema = z.union([z.undefined(), z.literal(false), z.literal(true)])
31
+ const _rayadesu_dsh_llm_billing_billing_getTodaySessionsSpend_result$schema = z.object({
32
+ 'sessions': z.array(z.object({
33
+ 'sessionId': z.intersection(z.string(), z.unknown()),
34
+ 'title': z.union([z.literal(null), z.string()]),
35
+ 'total': z.number(),
36
+ })),
37
+ })
30
38
  const _rayadesu_dsh_llm_billing_billing_getTodaySpend_parameter_0$schema = z.union([z.undefined(), z.literal(false), z.literal(true)])
31
39
  const _rayadesu_dsh_llm_billing_billing_getTodaySpend_result$schema = z.object({
32
40
  'total': z.number(),
@@ -44,6 +52,11 @@ const _rayadesu_dsh_llm_billing_billing_getTodaySpend_result$schema = z.object({
44
52
  'outputCost': z.number(),
45
53
  })),
46
54
  })
55
+ const _rayadesu_dsh_llm_billing_billing_getTurnSpend_parameter_0$schema = z.intersection(z.string(), z.unknown())
56
+ const _rayadesu_dsh_llm_billing_billing_getTurnSpend_parameter_1$schema = z.string()
57
+ const _rayadesu_dsh_llm_billing_billing_getTurnSpend_result$schema = z.object({
58
+ 'total': z.number(),
59
+ })
47
60
 
48
61
  export const TYPERT = {
49
62
  package: '@rayadesu/dsh-llm-billing',
@@ -64,7 +77,7 @@ export const TYPERT = {
64
77
  typeSymbol: '@rayadesu/dsh-llm-billing/types#DeepSeekBalance',
65
78
  schema: _rayadesu_dsh_llm_billing_billing_getBalance_result$schema,
66
79
  },
67
- sourceLocation: {"file":"packages/llm-billing/src/balance.ts","line":143,"column":3},
80
+ sourceLocation: {"file":"packages/llm-billing/src/balance.ts","line":154,"column":3},
68
81
  },
69
82
  {
70
83
  id: '@rayadesu/dsh-llm-billing#billing/getSessionSpend',
@@ -89,7 +102,33 @@ export const TYPERT = {
89
102
  typeSymbol: '@rayadesu/dsh-llm-billing/types#DeepSeekSessionSpend',
90
103
  schema: _rayadesu_dsh_llm_billing_billing_getSessionSpend_result$schema,
91
104
  },
92
- sourceLocation: {"file":"packages/llm-billing/src/balance.ts","line":154,"column":3},
105
+ sourceLocation: {"file":"packages/llm-billing/src/balance.ts","line":165,"column":3},
106
+ },
107
+ {
108
+ id: '@rayadesu/dsh-llm-billing#billing/getTodaySessionsSpend',
109
+ service: 'billing',
110
+ namespace: 'billing',
111
+ method: 'getTodaySessionsSpend',
112
+ invocation: { kind: 'direct' },
113
+ parameters: [
114
+ {
115
+ name: 'force',
116
+ wire: 'force',
117
+ source: 'json',
118
+ acceptsUndefined: true,
119
+ codec: {
120
+ mode: 'strict',
121
+ typeSymbol: '@rayadesu/dsh-llm-billing#billing/getTodaySessionsSpend:force',
122
+ schema: _rayadesu_dsh_llm_billing_billing_getTodaySessionsSpend_parameter_0$schema,
123
+ },
124
+ },
125
+ ],
126
+ result: {
127
+ mode: 'strict',
128
+ typeSymbol: '@rayadesu/dsh-llm-billing/types#DeepSeekTodaySessionsSpend',
129
+ schema: _rayadesu_dsh_llm_billing_billing_getTodaySessionsSpend_result$schema,
130
+ },
131
+ sourceLocation: {"file":"packages/llm-billing/src/balance.ts","line":192,"column":3},
93
132
  },
94
133
  {
95
134
  id: '@rayadesu/dsh-llm-billing#billing/getTodaySpend',
@@ -115,7 +154,42 @@ export const TYPERT = {
115
154
  typeSymbol: '@rayadesu/dsh-llm-billing/types#DeepSeekTodaySpend',
116
155
  schema: _rayadesu_dsh_llm_billing_billing_getTodaySpend_result$schema,
117
156
  },
118
- sourceLocation: {"file":"packages/llm-billing/src/balance.ts","line":167,"column":3},
157
+ sourceLocation: {"file":"packages/llm-billing/src/balance.ts","line":178,"column":3},
158
+ },
159
+ {
160
+ id: '@rayadesu/dsh-llm-billing#billing/getTurnSpend',
161
+ service: 'billing',
162
+ namespace: 'billing',
163
+ method: 'getTurnSpend',
164
+ invocation: { kind: 'direct' },
165
+ parameters: [
166
+ {
167
+ name: 'sessionId',
168
+ wire: 'sessionId',
169
+ source: 'json',
170
+ codec: {
171
+ mode: 'strict',
172
+ typeSymbol: '@rayadesu/dsh-llm-billing#billing/getTurnSpend:sessionId',
173
+ schema: _rayadesu_dsh_llm_billing_billing_getTurnSpend_parameter_0$schema,
174
+ },
175
+ },
176
+ {
177
+ name: 'messageId',
178
+ wire: 'messageId',
179
+ source: 'json',
180
+ codec: {
181
+ mode: 'strict',
182
+ typeSymbol: '@rayadesu/dsh-llm-billing#billing/getTurnSpend:messageId',
183
+ schema: _rayadesu_dsh_llm_billing_billing_getTurnSpend_parameter_1$schema,
184
+ },
185
+ },
186
+ ],
187
+ result: {
188
+ mode: 'strict',
189
+ typeSymbol: '@rayadesu/dsh-llm-billing/types#DeepSeekTurnSpend',
190
+ schema: _rayadesu_dsh_llm_billing_billing_getTurnSpend_result$schema,
191
+ },
192
+ sourceLocation: {"file":"packages/llm-billing/src/balance.ts","line":205,"column":3},
119
193
  },
120
194
  ],
121
195
  model: {
@@ -3,18 +3,22 @@ import type {
3
3
  RemoteResult,
4
4
  TypertRemoteContribution,
5
5
  } from '@deepseek-ai/dsh-typert-protocol'
6
- import type { DeepSeekBalance, DeepSeekSessionSpend, DeepSeekTodaySpend } from '@rayadesu/dsh-llm-billing/types'
6
+ import type { DeepSeekBalance, DeepSeekSessionSpend, DeepSeekTodaySessionsSpend, DeepSeekTodaySpend, DeepSeekTurnSpend } from '@rayadesu/dsh-llm-billing/types'
7
7
 
8
8
  declare module '@deepseek-ai/dsh-typert-protocol' {
9
9
  interface TypertRemoteNamespace$62696c6c696e67 {
10
10
  getBalance: () => Promise<RemoteResult<DeepSeekBalance>>
11
11
  getSessionSpend: (sessionId: SessionId) => Promise<RemoteResult<DeepSeekSessionSpend>>
12
+ getTodaySessionsSpend: (force?: boolean) => Promise<RemoteResult<DeepSeekTodaySessionsSpend>>
12
13
  getTodaySpend: (force?: boolean) => Promise<RemoteResult<DeepSeekTodaySpend>>
14
+ getTurnSpend: (sessionId: SessionId, messageId: string) => Promise<RemoteResult<DeepSeekTurnSpend>>
13
15
  }
14
16
  interface TypertRemoteMap {
15
17
  'billing/getBalance': () => Promise<RemoteResult<DeepSeekBalance>>
16
18
  'billing/getSessionSpend': (sessionId: SessionId) => Promise<RemoteResult<DeepSeekSessionSpend>>
19
+ 'billing/getTodaySessionsSpend': (force?: boolean) => Promise<RemoteResult<DeepSeekTodaySessionsSpend>>
17
20
  'billing/getTodaySpend': (force?: boolean) => Promise<RemoteResult<DeepSeekTodaySpend>>
21
+ 'billing/getTurnSpend': (sessionId: SessionId, messageId: string) => Promise<RemoteResult<DeepSeekTurnSpend>>
18
22
  }
19
23
  interface TypertRemoteNamespaceMap {
20
24
  'billing': TypertRemoteNamespace$62696c6c696e67
@@ -27,6 +27,14 @@ const _rayadesu_dsh_llm_billing_billing_getSessionSpend_result$schema = z.object
27
27
  'outputCost': z.number(),
28
28
  })),
29
29
  })
30
+ const _rayadesu_dsh_llm_billing_billing_getTodaySessionsSpend_parameter_0$schema = z.union([z.undefined(), z.literal(false), z.literal(true)])
31
+ const _rayadesu_dsh_llm_billing_billing_getTodaySessionsSpend_result$schema = z.object({
32
+ 'sessions': z.array(z.object({
33
+ 'sessionId': z.intersection(z.string(), z.unknown()),
34
+ 'title': z.union([z.literal(null), z.string()]),
35
+ 'total': z.number(),
36
+ })),
37
+ })
30
38
  const _rayadesu_dsh_llm_billing_billing_getTodaySpend_parameter_0$schema = z.union([z.undefined(), z.literal(false), z.literal(true)])
31
39
  const _rayadesu_dsh_llm_billing_billing_getTodaySpend_result$schema = z.object({
32
40
  'total': z.number(),
@@ -44,6 +52,11 @@ const _rayadesu_dsh_llm_billing_billing_getTodaySpend_result$schema = z.object({
44
52
  'outputCost': z.number(),
45
53
  })),
46
54
  })
55
+ const _rayadesu_dsh_llm_billing_billing_getTurnSpend_parameter_0$schema = z.intersection(z.string(), z.unknown())
56
+ const _rayadesu_dsh_llm_billing_billing_getTurnSpend_parameter_1$schema = z.string()
57
+ const _rayadesu_dsh_llm_billing_billing_getTurnSpend_result$schema = z.object({
58
+ 'total': z.number(),
59
+ })
47
60
 
48
61
  export const TYPERT_REMOTE = {
49
62
  package: '@rayadesu/dsh-llm-billing',
@@ -61,7 +74,7 @@ export const TYPERT_REMOTE = {
61
74
  typeSymbol: '@rayadesu/dsh-llm-billing/types#DeepSeekBalance',
62
75
  schema: _rayadesu_dsh_llm_billing_billing_getBalance_result$schema,
63
76
  },
64
- sourceLocation: {"file":"packages/llm-billing/src/balance.ts","line":143,"column":3},
77
+ sourceLocation: {"file":"packages/llm-billing/src/balance.ts","line":154,"column":3},
65
78
  },
66
79
  {
67
80
  id: '@rayadesu/dsh-llm-billing#billing/getSessionSpend',
@@ -86,7 +99,33 @@ export const TYPERT_REMOTE = {
86
99
  typeSymbol: '@rayadesu/dsh-llm-billing/types#DeepSeekSessionSpend',
87
100
  schema: _rayadesu_dsh_llm_billing_billing_getSessionSpend_result$schema,
88
101
  },
89
- sourceLocation: {"file":"packages/llm-billing/src/balance.ts","line":154,"column":3},
102
+ sourceLocation: {"file":"packages/llm-billing/src/balance.ts","line":165,"column":3},
103
+ },
104
+ {
105
+ id: '@rayadesu/dsh-llm-billing#billing/getTodaySessionsSpend',
106
+ service: 'billing',
107
+ namespace: 'billing',
108
+ method: 'getTodaySessionsSpend',
109
+ invocation: { kind: 'direct' },
110
+ parameters: [
111
+ {
112
+ name: 'force',
113
+ wire: 'force',
114
+ source: 'json',
115
+ acceptsUndefined: true,
116
+ codec: {
117
+ mode: 'strict',
118
+ typeSymbol: '@rayadesu/dsh-llm-billing#billing/getTodaySessionsSpend:force',
119
+ schema: _rayadesu_dsh_llm_billing_billing_getTodaySessionsSpend_parameter_0$schema,
120
+ },
121
+ },
122
+ ],
123
+ result: {
124
+ mode: 'strict',
125
+ typeSymbol: '@rayadesu/dsh-llm-billing/types#DeepSeekTodaySessionsSpend',
126
+ schema: _rayadesu_dsh_llm_billing_billing_getTodaySessionsSpend_result$schema,
127
+ },
128
+ sourceLocation: {"file":"packages/llm-billing/src/balance.ts","line":192,"column":3},
90
129
  },
91
130
  {
92
131
  id: '@rayadesu/dsh-llm-billing#billing/getTodaySpend',
@@ -112,7 +151,42 @@ export const TYPERT_REMOTE = {
112
151
  typeSymbol: '@rayadesu/dsh-llm-billing/types#DeepSeekTodaySpend',
113
152
  schema: _rayadesu_dsh_llm_billing_billing_getTodaySpend_result$schema,
114
153
  },
115
- sourceLocation: {"file":"packages/llm-billing/src/balance.ts","line":167,"column":3},
154
+ sourceLocation: {"file":"packages/llm-billing/src/balance.ts","line":178,"column":3},
155
+ },
156
+ {
157
+ id: '@rayadesu/dsh-llm-billing#billing/getTurnSpend',
158
+ service: 'billing',
159
+ namespace: 'billing',
160
+ method: 'getTurnSpend',
161
+ invocation: { kind: 'direct' },
162
+ parameters: [
163
+ {
164
+ name: 'sessionId',
165
+ wire: 'sessionId',
166
+ source: 'json',
167
+ codec: {
168
+ mode: 'strict',
169
+ typeSymbol: '@rayadesu/dsh-llm-billing#billing/getTurnSpend:sessionId',
170
+ schema: _rayadesu_dsh_llm_billing_billing_getTurnSpend_parameter_0$schema,
171
+ },
172
+ },
173
+ {
174
+ name: 'messageId',
175
+ wire: 'messageId',
176
+ source: 'json',
177
+ codec: {
178
+ mode: 'strict',
179
+ typeSymbol: '@rayadesu/dsh-llm-billing#billing/getTurnSpend:messageId',
180
+ schema: _rayadesu_dsh_llm_billing_billing_getTurnSpend_parameter_1$schema,
181
+ },
182
+ },
183
+ ],
184
+ result: {
185
+ mode: 'strict',
186
+ typeSymbol: '@rayadesu/dsh-llm-billing/types#DeepSeekTurnSpend',
187
+ schema: _rayadesu_dsh_llm_billing_billing_getTurnSpend_result$schema,
188
+ },
189
+ sourceLocation: {"file":"packages/llm-billing/src/balance.ts","line":205,"column":3},
116
190
  },
117
191
  ],
118
192
  }
@@ -9,7 +9,7 @@
9
9
  import type { Context } from '@deepseek-ai/cordis';
10
10
  import type { SessionId } from '@deepseek-ai/dsh-session';
11
11
  import { TypertRemoteService } from '@deepseek-ai/dsh-typert-protocol';
12
- import type { DeepSeekBalance, DeepSeekSessionSpend, DeepSeekTodaySpend } from './types.ts';
12
+ import type { DeepSeekBalance, DeepSeekSessionSpend, DeepSeekTodaySessionsSpend, DeepSeekTodaySpend, DeepSeekTurnSpend } from './types.ts';
13
13
  /**
14
14
  * Parse and validate the DeepSeek balance response at the wire boundary.
15
15
  * @param body - decoded JSON response body.
@@ -38,6 +38,17 @@ export interface DeepSeekBalanceGatewayOptions {
38
38
  * refresh path); a `force` miss still reuses revision-gated increments.
39
39
  */
40
40
  fetchTodaySpend: (force?: boolean) => Promise<DeepSeekTodaySpend>;
41
+ /**
42
+ * Compute today's billed spend per session through the plugin's resolved
43
+ * facts, sorted by cost descending. `force` bypasses the host-side time
44
+ * window like {@link fetchTodaySpend}.
45
+ */
46
+ fetchTodaySessionsSpend: (force?: boolean) => Promise<DeepSeekTodaySessionsSpend>;
47
+ /**
48
+ * Compute one completed Turn's billed spend through the plugin's resolved
49
+ * facts, identified by its closing assistant message id.
50
+ */
51
+ fetchTurnSpend: (sessionId: SessionId, messageId: string) => Promise<DeepSeekTurnSpend>;
41
52
  }
42
53
  /**
43
54
  * Remote-only service exposing the DeepSeek account balance and session spend.
@@ -74,6 +85,25 @@ export declare class DeepSeekBalanceGateway extends TypertRemoteService {
74
85
  * @returns today's total cost plus one row per priced model.
75
86
  */
76
87
  getTodaySpend(force?: boolean): Promise<DeepSeekTodaySpend>;
88
+ /**
89
+ * Read today's billed spend per session, priced per event by its
90
+ * Beijing-time calendar day, hour, and weekday (weekends are always
91
+ * off-peak). Rows carry the session's durable title and sort by cost
92
+ * descending; sessions with no priced usage on the day are omitted.
93
+ * @param force - bypass the host-side 60s cache (manual refresh); omitted
94
+ * means a cached read.
95
+ * @returns today's per-session rows, highest first.
96
+ */
97
+ getTodaySessionsSpend(force?: boolean): Promise<DeepSeekTodaySessionsSpend>;
98
+ /**
99
+ * Read one completed Turn's billed spend, priced per event by its
100
+ * Beijing-time hour and weekday (weekends are always off-peak).
101
+ * @param sessionId - the session owning the Turn.
102
+ * @param messageId - the closing assistant message's durable id, which
103
+ * locates the Turn in the session log.
104
+ * @returns the Turn's total cost in CNY.
105
+ */
106
+ getTurnSpend(sessionId: SessionId, messageId: string): Promise<DeepSeekTurnSpend>;
77
107
  }
78
108
  export default DeepSeekBalanceGateway;
79
109
  //# sourceMappingURL=balance.d.ts.map
@@ -136,15 +136,21 @@ let DeepSeekBalanceGateway = (() => {
136
136
  let _getBalance_decorators;
137
137
  let _getSessionSpend_decorators;
138
138
  let _getTodaySpend_decorators;
139
+ let _getTodaySessionsSpend_decorators;
140
+ let _getTurnSpend_decorators;
139
141
  return class DeepSeekBalanceGateway extends _classSuper {
140
142
  static {
141
143
  const _metadata = typeof Symbol === "function" && Symbol.metadata ? Object.create(_classSuper[Symbol.metadata] ?? null) : void 0;
142
144
  _getBalance_decorators = [Remote('getBalance')];
143
145
  _getSessionSpend_decorators = [Remote('getSessionSpend')];
144
146
  _getTodaySpend_decorators = [Remote('getTodaySpend')];
147
+ _getTodaySessionsSpend_decorators = [Remote('getTodaySessionsSpend')];
148
+ _getTurnSpend_decorators = [Remote('getTurnSpend')];
145
149
  __esDecorate(this, null, _getBalance_decorators, { kind: "method", name: "getBalance", static: false, private: false, access: { has: obj => "getBalance" in obj, get: obj => obj.getBalance }, metadata: _metadata }, null, _instanceExtraInitializers);
146
150
  __esDecorate(this, null, _getSessionSpend_decorators, { kind: "method", name: "getSessionSpend", static: false, private: false, access: { has: obj => "getSessionSpend" in obj, get: obj => obj.getSessionSpend }, metadata: _metadata }, null, _instanceExtraInitializers);
147
151
  __esDecorate(this, null, _getTodaySpend_decorators, { kind: "method", name: "getTodaySpend", static: false, private: false, access: { has: obj => "getTodaySpend" in obj, get: obj => obj.getTodaySpend }, metadata: _metadata }, null, _instanceExtraInitializers);
152
+ __esDecorate(this, null, _getTodaySessionsSpend_decorators, { kind: "method", name: "getTodaySessionsSpend", static: false, private: false, access: { has: obj => "getTodaySessionsSpend" in obj, get: obj => obj.getTodaySessionsSpend }, metadata: _metadata }, null, _instanceExtraInitializers);
153
+ __esDecorate(this, null, _getTurnSpend_decorators, { kind: "method", name: "getTurnSpend", static: false, private: false, access: { has: obj => "getTurnSpend" in obj, get: obj => obj.getTurnSpend }, metadata: _metadata }, null, _instanceExtraInitializers);
148
154
  if (_metadata) Object.defineProperty(this, Symbol.metadata, { enumerable: true, configurable: true, writable: true, value: _metadata });
149
155
  }
150
156
  options = __runInitializers(this, _instanceExtraInitializers);
@@ -184,6 +190,29 @@ let DeepSeekBalanceGateway = (() => {
184
190
  getTodaySpend(force) {
185
191
  return this.options.fetchTodaySpend(force ?? false);
186
192
  }
193
+ /**
194
+ * Read today's billed spend per session, priced per event by its
195
+ * Beijing-time calendar day, hour, and weekday (weekends are always
196
+ * off-peak). Rows carry the session's durable title and sort by cost
197
+ * descending; sessions with no priced usage on the day are omitted.
198
+ * @param force - bypass the host-side 60s cache (manual refresh); omitted
199
+ * means a cached read.
200
+ * @returns today's per-session rows, highest first.
201
+ */
202
+ getTodaySessionsSpend(force) {
203
+ return this.options.fetchTodaySessionsSpend(force ?? false);
204
+ }
205
+ /**
206
+ * Read one completed Turn's billed spend, priced per event by its
207
+ * Beijing-time hour and weekday (weekends are always off-peak).
208
+ * @param sessionId - the session owning the Turn.
209
+ * @param messageId - the closing assistant message's durable id, which
210
+ * locates the Turn in the session log.
211
+ * @returns the Turn's total cost in CNY.
212
+ */
213
+ getTurnSpend(sessionId, messageId) {
214
+ return this.options.fetchTurnSpend(sessionId, messageId);
215
+ }
187
216
  };
188
217
  })();
189
218
  export { DeepSeekBalanceGateway };
@@ -4,15 +4,16 @@
4
4
  * Remote gateway stays transport-free and the whole spend is testable without
5
5
  * a key.
6
6
  *
7
- * The per-event pricing lives in {@link priceEvent}, the one shared fold
8
- * primitive: the events-scan paths ({@link computeSessionSpend},
9
- * {@link computeTodaySpend}) and the session-projection unit
10
- * (`billingTodaySpend` in projection.ts) all fold the same contribution, so a
11
- * pricing-table change cannot drift one path from the others.
7
+ * The per-event pricing lives in {@link priceEvent} and the fold in the
8
+ * {@link SpendAccumulator}: the events-scan paths ({@link computeSessionSpend},
9
+ * {@link computeTodaySpend}), the session-projection unit (`billingTodaySpend`
10
+ * in projection.ts), and the scanner's single-pass events path all price
11
+ * through the same primitives, so a pricing-table change cannot drift one path
12
+ * from the others.
12
13
  * @module @rayadesu/dsh-llm-billing/billing
13
14
  */
14
15
  import type { SessionEvent } from '@deepseek-ai/dsh-session';
15
- import type { DeepSeekSessionSpend, DeepSeekTodaySpend } from './types.ts';
16
+ import type { DeepSeekSessionSpend, DeepSeekTodaySpend, DeepSeekTurnSpend } from './types.ts';
16
17
  /** One token price point, in CNY per 1M tokens. */
17
18
  export interface DeepSeekTokenPrice {
18
19
  /** 1M input cache-hit tokens. */
@@ -143,6 +144,22 @@ export interface BillingEventContribution {
143
144
  export declare function priceEvent(event: SessionEvent, billing: ResolvedBilling, names: ReadonlyMap<string, string>): BillingEventContribution | undefined;
144
145
  /** A spend with no priced usage. */
145
146
  export declare function emptyTodaySpend(): DeepSeekTodaySpend;
147
+ /**
148
+ * Mutable model-row accumulator behind every spend fold. Rows keep first-seen
149
+ * model order — the same shape a pure `addEventContribution` chain produces —
150
+ * so the single-pass scan path and the pure public paths cannot diverge. One
151
+ * `Map` lookup per contribution instead of a per-event array copy: the huge
152
+ * event-log folds allocate one row object per model, not one intermediate
153
+ * array per event.
154
+ */
155
+ export declare class SpendAccumulator {
156
+ private readonly rows;
157
+ private total;
158
+ /** Add one priced contribution. */
159
+ add(priced: BillingEventContribution): void;
160
+ /** The folded spend; the accumulator stays usable afterwards. */
161
+ finish(): DeepSeekTodaySpend;
162
+ }
146
163
  /**
147
164
  * Merge one priced event's contribution into an accumulator spend (pure:
148
165
  * returns a new spend, never mutates its input).
@@ -170,6 +187,24 @@ export declare function computeSessionSpend(events: readonly SessionEvent[], bil
170
187
  id: string;
171
188
  name: string;
172
189
  }[]): DeepSeekSessionSpend;
190
+ /**
191
+ * Price one completed Turn's billed usage at the official per-model rates,
192
+ * identified by its closing assistant message id. The turn's events are those
193
+ * between its `turn/start` and `turn/end` (both matched by the message's own
194
+ * turn coordinate); each priced event applies the peak/off-peak table by its
195
+ * Beijing-time hour and weekday. A message that cannot be located, a turn
196
+ * without bracketing `turn/start` / `turn/end` events (for example after
197
+ * compaction), or a session with no priced usage prices to zero.
198
+ * @param events - one session's complete event log.
199
+ * @param billing - resolved pricing with peak-hour windows.
200
+ * @param catalog - model display rows, in presentation order.
201
+ * @param messageId - the closing assistant message's durable id.
202
+ * @returns the turn's total cost in CNY.
203
+ */
204
+ export declare function computeTurnSpend(events: readonly SessionEvent[], billing: ResolvedBilling, catalog: readonly {
205
+ id: string;
206
+ name: string;
207
+ }[], messageId: string): DeepSeekTurnSpend;
173
208
  /**
174
209
  * Price every event whose Beijing-time calendar day is the day of `now`,
175
210
  * aggregating across every session's event log. Events from other Beijing