@cjhyy/code-shell-capability-coding 0.9.22 → 0.9.25

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.
@@ -37,6 +37,10 @@ export declare class CodexEventTranslator {
37
37
  private readonly codeshellServer;
38
38
  private turnNumber;
39
39
  private activeTurnId;
40
+ private usageTurnId;
41
+ private cumulativeUsage;
42
+ private turnUsageBaseline;
43
+ private turnUsage;
40
44
  /** Turns that reached a terminal state. Late events for these are dropped. */
41
45
  private readonly finishedTurns;
42
46
  /**
@@ -64,6 +68,8 @@ export declare class CodexEventTranslator {
64
68
  private onError;
65
69
  private onAgentDelta;
66
70
  private onReasoningDelta;
71
+ private resetTurnUsage;
72
+ private updateTurnUsage;
67
73
  private onTokenUsage;
68
74
  /**
69
75
  * A CodeShell Host Tool call must not produce a card here — `ToolExecutor`
@@ -70,6 +70,10 @@ export class CodexEventTranslator {
70
70
  codeshellServer;
71
71
  turnNumber = 0;
72
72
  activeTurnId;
73
+ usageTurnId;
74
+ cumulativeUsage = {};
75
+ turnUsageBaseline = {};
76
+ turnUsage = {};
73
77
  /** Turns that reached a terminal state. Late events for these are dropped. */
74
78
  finishedTurns = new Set();
75
79
  /**
@@ -157,7 +161,13 @@ export class CodexEventTranslator {
157
161
  // must not reactivate the session.
158
162
  if (turnId && this.finishedTurns.has(turnId))
159
163
  return [];
164
+ if (turnId && turnId === this.activeTurnId)
165
+ return [];
160
166
  this.activeTurnId = turnId;
167
+ // Usage may arrive before turn/started. Keep the counts already attributed
168
+ // to this turn, and reset only when a different user turn begins.
169
+ if (!turnId || turnId !== this.usageTurnId)
170
+ this.resetTurnUsage(turnId);
161
171
  this.turnNumber += 1;
162
172
  return [{ type: "stream_request_start", turnNumber: this.turnNumber }];
163
173
  }
@@ -214,8 +224,40 @@ export class CodexEventTranslator {
214
224
  const delta = str(params.delta);
215
225
  return delta ? [{ type: "thinking_delta", text: delta }] : [];
216
226
  }
227
+ resetTurnUsage(turnId) {
228
+ this.usageTurnId = turnId;
229
+ this.turnUsageBaseline = { ...this.cumulativeUsage };
230
+ this.turnUsage = {};
231
+ }
232
+ updateTurnUsage(key, last, total) {
233
+ if (total !== undefined) {
234
+ if (this.turnUsage[key] === undefined &&
235
+ this.turnUsageBaseline[key] !== undefined &&
236
+ total < this.turnUsageBaseline[key]) {
237
+ // A provider accounting window can restart between turns. Rebase the
238
+ // first update only: a lower snapshot during the same turn may instead
239
+ // be an out-of-order delivery, which must not count as fresh work.
240
+ this.turnUsageBaseline[key] = 0;
241
+ this.cumulativeUsage[key] = 0;
242
+ }
243
+ // A resumed thread has history, but no local baseline yet. Its first
244
+ // update identifies that history as total - last. Subsequent updates use
245
+ // cumulative differences, so repeated notifications never add usage twice
246
+ // and intermediate model requests remain counted throughout the turn.
247
+ this.turnUsageBaseline[key] ??= Math.max(0, total - (last ?? 0));
248
+ this.turnUsage[key] = Math.max(this.turnUsage[key] ?? 0, total - this.turnUsageBaseline[key]);
249
+ this.cumulativeUsage[key] = Math.max(this.cumulativeUsage[key] ?? 0, total);
250
+ }
251
+ else if (last !== undefined) {
252
+ // Older/partial notifications have no reliable request identity. Preserve
253
+ // the snapshot without adding it repeatedly as if each delivery were work.
254
+ this.turnUsage[key] = Math.max(this.turnUsage[key] ?? 0, last);
255
+ }
256
+ return this.turnUsage[key];
257
+ }
217
258
  onTokenUsage(params) {
218
- if (this.isStale(str(params.turnId)))
259
+ const turnId = str(params.turnId) ?? this.activeTurnId;
260
+ if (this.isStale(turnId))
219
261
  return [];
220
262
  const usage = asRecord(params.tokenUsage);
221
263
  const total = asRecord(usage?.total);
@@ -224,6 +266,8 @@ export class CodexEventTranslator {
224
266
  const promptTokens = number(last?.inputTokens);
225
267
  if (promptTokens === undefined)
226
268
  return [];
269
+ if (turnId && turnId !== this.usageTurnId)
270
+ this.resetTurnUsage(turnId);
227
271
  const cacheReadTokens = number(last?.cachedInputTokens);
228
272
  const cumulativePromptTokens = number(total?.inputTokens);
229
273
  const cumulativeCacheReadTokens = number(total?.cachedInputTokens);
@@ -231,6 +275,9 @@ export class CodexEventTranslator {
231
275
  const cumulativeCacheCreationTokens = number(total?.cacheWriteInputTokens);
232
276
  const completionTokens = number(last?.outputTokens);
233
277
  const cumulativeCompletionTokens = number(total?.outputTokens);
278
+ const singleTurnPromptTokens = this.updateTurnUsage("promptTokens", promptTokens, cumulativePromptTokens);
279
+ const singleTurnCacheReadTokens = this.updateTurnUsage("cacheReadTokens", cacheReadTokens, cumulativeCacheReadTokens);
280
+ const singleTurnCacheCreationTokens = this.updateTurnUsage("cacheCreationTokens", cacheCreationTokens, cumulativeCacheCreationTokens);
234
281
  return [
235
282
  {
236
283
  type: "usage_update",
@@ -239,11 +286,9 @@ export class CodexEventTranslator {
239
286
  promptTokensConfidence: "high",
240
287
  ...(cacheReadTokens !== undefined ? { cacheReadTokens } : {}),
241
288
  ...(cacheCreationTokens !== undefined ? { cacheCreationTokens } : {}),
242
- singleTurnPromptTokens: promptTokens,
243
- ...(cacheReadTokens !== undefined ? { singleTurnCacheReadTokens: cacheReadTokens } : {}),
244
- ...(cacheCreationTokens !== undefined
245
- ? { singleTurnCacheCreationTokens: cacheCreationTokens }
246
- : {}),
289
+ singleTurnPromptTokens,
290
+ ...(singleTurnCacheReadTokens !== undefined ? { singleTurnCacheReadTokens } : {}),
291
+ ...(singleTurnCacheCreationTokens !== undefined ? { singleTurnCacheCreationTokens } : {}),
247
292
  ...(cumulativePromptTokens !== undefined ? { cumulativePromptTokens } : {}),
248
293
  ...(cumulativeCacheReadTokens !== undefined ? { cumulativeCacheReadTokens } : {}),
249
294
  ...(cumulativeCacheCreationTokens !== undefined ? { cumulativeCacheCreationTokens } : {}),
@@ -49,20 +49,6 @@ export function threadIdFromMeta(params) {
49
49
  }
50
50
  return undefined;
51
51
  }
52
- function turnIdFromMeta(params) {
53
- if (!params || typeof params !== "object")
54
- return undefined;
55
- const meta = params._meta;
56
- if (!meta || typeof meta !== "object")
57
- return undefined;
58
- const turn = meta["x-codex-turn-metadata"];
59
- if (turn && typeof turn === "object") {
60
- const id = turn.turn_id;
61
- if (typeof id === "string" && id)
62
- return id;
63
- }
64
- return undefined;
65
- }
66
52
  /** Model-facing text for a routing refusal. Says what happened without leaking
67
53
  * which other sessions exist. */
68
54
  function missMessage(reason) {
@@ -271,7 +257,10 @@ export async function startLoopbackMcpBridge(options) {
271
257
  const started = Date.now();
272
258
  // The host is the authorization boundary; the bridge only routes.
273
259
  const outcome = await resolved.host.execute({
274
- id: turnIdFromMeta(message.params) ?? `mcp-${randomBytes(6).toString("hex")}`,
260
+ // One turn can contain many calls, including parallel ones. A turn id
261
+ // aliases their transcript/UI entries and overwrites navigate with a
262
+ // later observe error. Mint a host identity for each actual invocation.
263
+ id: `mcp-${randomBytes(12).toString("hex")}`,
275
264
  name,
276
265
  input: params?.arguments ?? {},
277
266
  });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@cjhyy/code-shell-capability-coding",
3
- "version": "0.9.22",
3
+ "version": "0.9.25",
4
4
  "description": "Coding capability pack for the generic code-shell agent core.",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",
@@ -39,7 +39,7 @@
39
39
  "clean": "node -e \"require('node:fs').rmSync('dist',{recursive:true,force:true})\""
40
40
  },
41
41
  "dependencies": {
42
- "@cjhyy/code-shell-core": "0.9.22"
42
+ "@cjhyy/code-shell-core": "0.9.25"
43
43
  },
44
44
  "engines": {
45
45
  "node": ">=20.10"