@zvada/agent-server 0.3.7 → 0.3.8

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/CHANGELOG.md CHANGED
@@ -1,5 +1,9 @@
1
1
  # Changelog
2
2
 
3
+ ## 0.3.8
4
+
5
+ - Report each Claude turn's cost as the increase in the SDK's cumulative query cost. Preserve the native total in raw diagnostics, reset the baseline with a fresh query or conversation reset, and keep unknown cost distinct from reported zero.
6
+
3
7
  ## 0.3.7
4
8
 
5
9
  - Retain Claude's reported 5-minute and 1-hour cache-creation token counts in the existing token usage contract. Missing durations stay absent and reported zeroes are preserved.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@zvada/agent-server",
3
- "version": "0.3.7",
3
+ "version": "0.3.8",
4
4
  "description": "Harness-agnostic agent execution engine: run Claude Code, Codex (SDK/CLI + app-server), and any ACP agent behind one interface with a normalized event stream, multi-turn sessions, and resume. Root export is the wire contract; /core, /server, /client are the seats.",
5
5
  "license": "MIT",
6
6
  "type": "module",
@@ -93,6 +93,8 @@ type ClaudeMessage =
93
93
  usage?: RawUsage;
94
94
  modelUsage?: Record<string, { contextWindow?: number }>;
95
95
  total_cost_usd?: number;
96
+ /** Per-turn delta from the generator tap; null means unreported. */
97
+ turn_cost_usd?: number | null;
96
98
  stop_reason?: string | null;
97
99
  is_error?: boolean;
98
100
  };
@@ -519,7 +521,7 @@ export class ClaudeCodeTransformer implements EventTransformer<unknown> {
519
521
  },
520
522
  };
521
523
  }
522
- if (typeof msg.total_cost_usd === "number") this.cost = msg.total_cost_usd;
524
+ this.cost = "turn_cost_usd" in msg ? (msg.turn_cost_usd ?? undefined) : msg.total_cost_usd;
523
525
  this.finishReason = msg.stop_reason ?? msg.subtype ?? this.finishReason;
524
526
  this.stopReason = mapClaudeStopReason(msg.stop_reason, msg.subtype);
525
527
  if (msg.subtype && msg.subtype !== "success") {
@@ -100,6 +100,8 @@ export class ClaudeGeneratorSession {
100
100
  /** Resolved once at spawn; re-merged into every hot-swap. */
101
101
  private sdkServers?: SdkMcpServers;
102
102
  private nativeSessionId: string | null = null;
103
+ /** SDK cost is cumulative within this query; token usage is already per turn. */
104
+ private cumulativeCost: number | undefined = 0;
103
105
 
104
106
  private currentTap: AsyncQueue<SDKMessage> | null = null;
105
107
  private readonly idleWaiters: Array<() => void> = [];
@@ -284,8 +286,26 @@ export class ClaudeGeneratorSession {
284
286
  if (event.type === "system" && event.subtype === "init" && event.session_id) {
285
287
  this.nativeSessionId = event.session_id;
286
288
  }
287
- this.currentTap?.push(event);
288
- if (event.type === "result") this.onTurnComplete();
289
+ if (event.type === "conversation_reset") this.cumulativeCost = 0;
290
+ if (event.type === "result") {
291
+ // Keep the native total intact for raw diagnostics. A crash can
292
+ // report a zeroed total; that does not establish this turn's cost.
293
+ const result = {
294
+ ...event,
295
+ turn_cost_usd:
296
+ this.cumulativeCost !== undefined && event.total_cost_usd >= this.cumulativeCost
297
+ ? event.total_cost_usd - this.cumulativeCost
298
+ : null,
299
+ };
300
+ this.cumulativeCost =
301
+ this.cumulativeCost !== undefined && event.total_cost_usd < this.cumulativeCost
302
+ ? undefined
303
+ : event.total_cost_usd;
304
+ this.currentTap?.push(result);
305
+ this.onTurnComplete();
306
+ } else {
307
+ this.currentTap?.push(event);
308
+ }
289
309
  }
290
310
  } catch (err) {
291
311
  this.currentTap?.fail(err);