@yeaft/webchat-agent 0.1.1028 → 0.1.1029

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@yeaft/webchat-agent",
3
- "version": "0.1.1028",
3
+ "version": "0.1.1029",
4
4
  "description": "Remote agent for Yeaft WebChat — connects worker machines to the central server",
5
5
  "main": "index.js",
6
6
  "type": "module",
@@ -449,6 +449,25 @@ export class DebugTrace {
449
449
  try { return JSON.parse(s); }
450
450
  catch { return null; }
451
451
  };
452
+ const normalizeUsage = (usage, row) => {
453
+ const inputTokens = Number.isFinite(Number(usage?.inputTokens)) ? Number(usage.inputTokens) : (row.input_tokens || 0);
454
+ const outputTokens = Number.isFinite(Number(usage?.outputTokens)) ? Number(usage.outputTokens) : (row.output_tokens || 0);
455
+ const cacheReadTokens = Number.isFinite(Number(usage?.cacheReadTokens)) ? Number(usage.cacheReadTokens) : (row.cache_read_tokens || 0);
456
+ const cacheWriteTokens = Number.isFinite(Number(usage?.cacheWriteTokens)) ? Number(usage.cacheWriteTokens) : (row.cache_write_tokens || 0);
457
+ const totalInputTokens = Number.isFinite(Number(usage?.totalInputTokens))
458
+ ? Number(usage.totalInputTokens)
459
+ : inputTokens + cacheReadTokens + cacheWriteTokens;
460
+ return {
461
+ inputTokens,
462
+ outputTokens,
463
+ cacheReadTokens,
464
+ cacheWriteTokens,
465
+ totalInputTokens,
466
+ totalTokens: Number.isFinite(Number(usage?.totalTokens))
467
+ ? Number(usage.totalTokens)
468
+ : totalInputTokens + outputTokens,
469
+ };
470
+ };
452
471
  // Group rows by (turnId, threadId, sessionId, vpId) → frontend Turn
453
472
  // record. Each row is also surfaced as a Loop.
454
473
  const turnsById = new Map();
@@ -463,11 +482,7 @@ export class DebugTrace {
463
482
  messages: parsedMessages,
464
483
  response: r.response_text || '',
465
484
  toolCalls: parseJsonSafe(r.tool_calls_json) || [],
466
- usage: parsedUsage || {
467
- inputTokens: r.input_tokens || 0,
468
- outputTokens: r.output_tokens || 0,
469
- totalTokens: (r.input_tokens || 0) + (r.output_tokens || 0),
470
- },
485
+ usage: normalizeUsage(parsedUsage, r),
471
486
  latencyMs: r.latency_ms || 0,
472
487
  ttfbMs: r.ttfb_ms || null,
473
488
  stopReason: r.stop_reason || null,
@@ -504,10 +519,7 @@ export class DebugTrace {
504
519
  // Aggregate per-loop latency / tokens so the Turn header shows the
505
520
  // same totals the live `turn_close` event would have stamped.
506
521
  t.totalMs += r.latency_ms || 0;
507
- const usageTokens = parsedUsage && Number.isFinite(parsedUsage.totalTokens)
508
- ? parsedUsage.totalTokens
509
- : (r.input_tokens || 0) + (r.output_tokens || 0);
510
- t.totalTokens += usageTokens;
522
+ t.totalTokens += loop.usage.totalTokens || 0;
511
523
  if (r.ended_at && (!t.closedAt || r.ended_at > t.closedAt)) t.closedAt = r.ended_at;
512
524
  return loop;
513
525
  });
package/yeaft/engine.js CHANGED
@@ -1885,7 +1885,7 @@ export class Engine {
1885
1885
  const toolCalls = [];
1886
1886
  const thinkingBlocks = []; // task-327d: collected from adapter for round-trip
1887
1887
  let stopReason = 'end_turn';
1888
- const totalUsage = { inputTokens: 0, outputTokens: 0 };
1888
+ const totalUsage = { inputTokens: 0, outputTokens: 0, cacheReadTokens: 0, cacheWriteTokens: 0, cacheInputDeltaTokens: 0 };
1889
1889
  // task-344: capture redacted raw request / raw response for debug panel.
1890
1890
  let rawRequest = null;
1891
1891
  let rawResponse = null;
@@ -2080,13 +2080,22 @@ export class Engine {
2080
2080
  toolCalls.push(event);
2081
2081
  yield event;
2082
2082
  break;
2083
- case 'usage':
2084
- totalUsage.inputTokens += event.inputTokens;
2085
- totalUsage.outputTokens += event.outputTokens;
2086
- cumulativeInputTokens += event.inputTokens || 0;
2087
- cumulativeOutputTokens += event.outputTokens || 0;
2083
+ case 'usage': {
2084
+ const inputTokens = event.inputTokens || 0;
2085
+ const outputTokens = event.outputTokens || 0;
2086
+ const cacheReadTokens = event.cacheReadTokens || 0;
2087
+ const cacheWriteTokens = event.cacheWriteTokens || 0;
2088
+ const cacheInputDeltaTokens = event.cacheTokensAreIncludedInInput ? 0 : cacheReadTokens + cacheWriteTokens;
2089
+ totalUsage.inputTokens += inputTokens;
2090
+ totalUsage.outputTokens += outputTokens;
2091
+ totalUsage.cacheReadTokens += cacheReadTokens;
2092
+ totalUsage.cacheWriteTokens += cacheWriteTokens;
2093
+ totalUsage.cacheInputDeltaTokens += cacheInputDeltaTokens;
2094
+ cumulativeInputTokens += inputTokens + cacheInputDeltaTokens;
2095
+ cumulativeOutputTokens += outputTokens;
2088
2096
  yield event;
2089
2097
  break;
2098
+ }
2090
2099
  case 'stop':
2091
2100
  stopReason = event.stopReason;
2092
2101
  yield event;
@@ -2107,6 +2116,8 @@ export class Engine {
2107
2116
  model: currentModel,
2108
2117
  inputTokens: totalUsage.inputTokens,
2109
2118
  outputTokens: totalUsage.outputTokens,
2119
+ cacheReadTokens: totalUsage.cacheReadTokens,
2120
+ cacheWriteTokens: totalUsage.cacheWriteTokens,
2110
2121
  stopReason: 'error',
2111
2122
  latencyMs,
2112
2123
  responseText,
@@ -2119,7 +2130,10 @@ export class Engine {
2119
2130
  usage: {
2120
2131
  inputTokens: totalUsage.inputTokens || 0,
2121
2132
  outputTokens: totalUsage.outputTokens || 0,
2122
- totalTokens: (totalUsage.inputTokens || 0) + (totalUsage.outputTokens || 0),
2133
+ cacheReadTokens: totalUsage.cacheReadTokens || 0,
2134
+ cacheWriteTokens: totalUsage.cacheWriteTokens || 0,
2135
+ totalInputTokens: (totalUsage.inputTokens || 0) + (totalUsage.cacheInputDeltaTokens || 0),
2136
+ totalTokens: (totalUsage.inputTokens || 0) + (totalUsage.cacheInputDeltaTokens || 0) + (totalUsage.outputTokens || 0),
2123
2137
  },
2124
2138
  ttfbMs,
2125
2139
  rawRequest,
@@ -2127,7 +2141,7 @@ export class Engine {
2127
2141
  });
2128
2142
 
2129
2143
  // Emit `loop` event for error path too (was `debug_turn`).
2130
- const errLoopInputTokens = totalUsage.inputTokens || 0;
2144
+ const errLoopInputTokens = (totalUsage.inputTokens || 0) + (totalUsage.cacheInputDeltaTokens || 0);
2131
2145
  const errLoopOutputTokens = totalUsage.outputTokens || 0;
2132
2146
  yield {
2133
2147
  type: 'loop',
@@ -2140,8 +2154,11 @@ export class Engine {
2140
2154
  response: responseText || `Error: ${err.message}`,
2141
2155
  toolCalls: toolCalls.map(tc => ({ id: tc.id, name: tc.name, input: tc.input })),
2142
2156
  usage: {
2143
- inputTokens: errLoopInputTokens,
2157
+ inputTokens: totalUsage.inputTokens || 0,
2144
2158
  outputTokens: errLoopOutputTokens,
2159
+ cacheReadTokens: totalUsage.cacheReadTokens || 0,
2160
+ cacheWriteTokens: totalUsage.cacheWriteTokens || 0,
2161
+ totalInputTokens: errLoopInputTokens,
2145
2162
  totalTokens: errLoopInputTokens + errLoopOutputTokens,
2146
2163
  },
2147
2164
  latencyMs,
@@ -2250,11 +2267,16 @@ export class Engine {
2250
2267
 
2251
2268
  const latencyMs = Date.now() - startTime;
2252
2269
 
2270
+ const turnInputTokens = (totalUsage.inputTokens || 0) + (totalUsage.cacheInputDeltaTokens || 0);
2271
+ const turnOutputTokens = totalUsage.outputTokens || 0;
2272
+
2253
2273
  // Record turn in debug trace
2254
2274
  this.#trace.endTurn(turnId, {
2255
2275
  model: currentModel,
2256
2276
  inputTokens: totalUsage.inputTokens,
2257
2277
  outputTokens: totalUsage.outputTokens,
2278
+ cacheReadTokens: totalUsage.cacheReadTokens,
2279
+ cacheWriteTokens: totalUsage.cacheWriteTokens,
2258
2280
  stopReason,
2259
2281
  latencyMs,
2260
2282
  responseText,
@@ -2268,7 +2290,10 @@ export class Engine {
2268
2290
  usage: {
2269
2291
  inputTokens: totalUsage.inputTokens || 0,
2270
2292
  outputTokens: totalUsage.outputTokens || 0,
2271
- totalTokens: (totalUsage.inputTokens || 0) + (totalUsage.outputTokens || 0),
2293
+ cacheReadTokens: totalUsage.cacheReadTokens || 0,
2294
+ cacheWriteTokens: totalUsage.cacheWriteTokens || 0,
2295
+ totalInputTokens: turnInputTokens,
2296
+ totalTokens: turnInputTokens + turnOutputTokens,
2272
2297
  },
2273
2298
  ttfbMs,
2274
2299
  rawRequest,
@@ -2284,7 +2309,7 @@ export class Engine {
2284
2309
  // task-331: preserve toolCalls / toolCallId / isError on each message
2285
2310
  // so the panel can render function_call requests and their paired
2286
2311
  // tool_result responses across loops.
2287
- const loopInputTokens = totalUsage.inputTokens || 0;
2312
+ const loopInputTokens = (totalUsage.inputTokens || 0) + (totalUsage.cacheInputDeltaTokens || 0);
2288
2313
  const loopOutputTokens = totalUsage.outputTokens || 0;
2289
2314
  yield {
2290
2315
  type: 'loop',
@@ -2296,8 +2321,11 @@ export class Engine {
2296
2321
  response: responseText,
2297
2322
  toolCalls: toolCalls.map(tc => ({ id: tc.id, name: tc.name, input: tc.input })),
2298
2323
  usage: {
2299
- inputTokens: loopInputTokens,
2324
+ inputTokens: totalUsage.inputTokens || 0,
2300
2325
  outputTokens: loopOutputTokens,
2326
+ cacheReadTokens: totalUsage.cacheReadTokens || 0,
2327
+ cacheWriteTokens: totalUsage.cacheWriteTokens || 0,
2328
+ totalInputTokens: loopInputTokens,
2301
2329
  totalTokens: loopInputTokens + loopOutputTokens,
2302
2330
  },
2303
2331
  latencyMs,
@@ -42,7 +42,7 @@
42
42
  * @typedef {{ type: 'thinking_delta', text: string }} ThinkingDeltaEvent
43
43
  * @typedef {{ type: 'thinking_block_end', thinking: string, signature: string }} ThinkingBlockEndEvent
44
44
  * @typedef {{ type: 'tool_call', id: string, name: string, input: object }} ToolCallEvent
45
- * @typedef {{ type: 'usage', inputTokens: number, outputTokens: number, cacheReadTokens?: number, cacheWriteTokens?: number }} UsageEvent
45
+ * @typedef {{ type: 'usage', inputTokens: number, outputTokens: number, cacheReadTokens?: number, cacheWriteTokens?: number, cacheTokensAreIncludedInInput?: boolean }} UsageEvent
46
46
  * @typedef {{ type: 'stop', stopReason: 'end_turn' | 'tool_use' | 'max_tokens' }} StopEvent
47
47
  * @typedef {{ type: 'error', error: Error, retryable: boolean }} ErrorEvent
48
48
  *
@@ -508,6 +508,8 @@ export class AnthropicAdapter extends LLMAdapter {
508
508
  usage: {
509
509
  inputTokens: result.usage?.input_tokens || 0,
510
510
  outputTokens: result.usage?.output_tokens || 0,
511
+ cacheReadTokens: result.usage?.cache_read_input_tokens || 0,
512
+ cacheWriteTokens: result.usage?.cache_creation_input_tokens || 0,
511
513
  },
512
514
  };
513
515
  }
@@ -435,6 +435,7 @@ export class OpenAIResponsesAdapter extends LLMAdapter {
435
435
  outputTokens: usage.output_tokens || 0,
436
436
  cacheReadTokens: usage.input_tokens_details?.cached_tokens || 0,
437
437
  cacheWriteTokens: 0,
438
+ cacheTokensAreIncludedInInput: true,
438
439
  };
439
440
 
440
441
  yield {
@@ -2233,6 +2233,9 @@ function handleEngineEvent(event, hctx) {
2233
2233
  type: 'context_usage',
2234
2234
  inputTokens: event.inputTokens,
2235
2235
  outputTokens: event.outputTokens,
2236
+ cacheReadTokens: event.cacheReadTokens || 0,
2237
+ cacheWriteTokens: event.cacheWriteTokens || 0,
2238
+ totalInputTokens: (event.inputTokens || 0) + (event.cacheReadTokens || 0) + (event.cacheWriteTokens || 0),
2236
2239
  }, envelope);
2237
2240
  break;
2238
2241