agent-trace 0.2.7 → 0.2.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.
Files changed (2) hide show
  1. package/agent-trace.cjs +92 -13
  2. package/package.json +1 -1
package/agent-trace.cjs CHANGED
@@ -24225,10 +24225,10 @@ function parseReplay(val) {
24225
24225
  var ev=asRec(e);if(!ev)return null;
24226
24226
  var id=readStr(ev,'id'),type=readStr(ev,'type'),ts=readStr(ev,'timestamp');if(!id||!type||!ts)return null;
24227
24227
  var d=asRec(ev.details),tok=asRec(ev.tokens);
24228
- return{id:id,type:type,timestamp:ts,promptId:readStr(ev,'promptId'),status:readStr(ev,'status'),costUsd:readNum(ev,'costUsd'),toolName:d?readStr(d,'toolName'):undefined,toolDurationMs:d?readNum(d,'toolDurationMs'):undefined,inputTokens:tok?readNum(tok,'input'):undefined,outputTokens:tok?readNum(tok,'output'):undefined,details:d};
24228
+ return{id:id,type:type,timestamp:ts,promptId:readStr(ev,'promptId'),status:readStr(ev,'status'),costUsd:readNum(ev,'costUsd'),toolName:d?readStr(d,'toolName'):undefined,toolDurationMs:d?readNum(d,'toolDurationMs'):undefined,inputTokens:tok?readNum(tok,'input'):undefined,outputTokens:tok?readNum(tok,'output'):undefined,cacheReadTokens:tok?readNum(tok,'cacheRead'):undefined,cacheWriteTokens:tok?readNum(tok,'cacheWrite'):undefined,details:d};
24229
24229
  }).filter(Boolean);
24230
24230
  return{sessionId:sid,startedAt:sa,endedAt:readStr(r,'endedAt'),gitBranch:gitBranch,
24231
- metrics:{promptCount:readNum(m,'promptCount')||0,toolCallCount:readNum(m,'toolCallCount')||0,totalCostUsd:readNum(m,'totalCostUsd')||0,totalInputTokens:readNum(m,'totalInputTokens')||0,totalOutputTokens:readNum(m,'totalOutputTokens')||0,linesAdded:readNum(m,'linesAdded')||0,linesRemoved:readNum(m,'linesRemoved')||0,modelsUsed:readArr(m,'modelsUsed').filter(function(x){return typeof x==='string'}),toolsUsed:readArr(m,'toolsUsed').filter(function(x){return typeof x==='string'}),filesTouched:readArr(m,'filesTouched').filter(function(x){return typeof x==='string'})},
24231
+ metrics:{promptCount:readNum(m,'promptCount')||0,toolCallCount:readNum(m,'toolCallCount')||0,totalCostUsd:readNum(m,'totalCostUsd')||0,totalInputTokens:readNum(m,'totalInputTokens')||0,totalOutputTokens:readNum(m,'totalOutputTokens')||0,totalCacheReadTokens:readNum(m,'totalCacheReadTokens')||0,totalCacheWriteTokens:readNum(m,'totalCacheWriteTokens')||0,linesAdded:readNum(m,'linesAdded')||0,linesRemoved:readNum(m,'linesRemoved')||0,modelsUsed:readArr(m,'modelsUsed').filter(function(x){return typeof x==='string'}),toolsUsed:readArr(m,'toolsUsed').filter(function(x){return typeof x==='string'}),filesTouched:readArr(m,'filesTouched').filter(function(x){return typeof x==='string'})},
24232
24232
  commits:commits,pullRequests:prs,timeline:timeline};
24233
24233
  }
24234
24234
 
@@ -24298,7 +24298,7 @@ function buildPromptGroups(timeline, commits) {
24298
24298
  map[ev.promptId].push(ev);
24299
24299
  });
24300
24300
  return order.map(function(pid){
24301
- var evts = map[pid] || [], promptText, responseText, cost=0,tools=0,inTok=0,outTok=0,dur=0;
24301
+ var evts = map[pid] || [], promptText, responseText, cost=0,tools=0,inTok=0,outTok=0,cacheRTok=0,cacheWTok=0,dur=0;
24302
24302
  var filesR={},filesW={},toolEvts=[];
24303
24303
  evts.forEach(function(ev){
24304
24304
  var d = ev.details;
@@ -24306,7 +24306,7 @@ function buildPromptGroups(timeline, commits) {
24306
24306
  if(ev.type==='assistant_response'||ev.type==='api_call'||ev.type==='api_response'){
24307
24307
  if(d){var rt=readStr(d,'responseText')||readStr(d,'lastAssistantMessage');if(rt)responseText=rt;}
24308
24308
  }
24309
- cost+=(ev.costUsd||0);inTok+=(ev.inputTokens||0);outTok+=(ev.outputTokens||0);
24309
+ cost+=(ev.costUsd||0);inTok+=(ev.inputTokens||0);outTok+=(ev.outputTokens||0);cacheRTok+=(ev.cacheReadTokens||0);cacheWTok+=(ev.cacheWriteTokens||0);
24310
24310
  if(ev.toolName||(ev.type==='tool_call'||ev.type==='tool_result')){
24311
24311
  toolEvts.push(ev);tools++;dur+=(ev.toolDurationMs||0);
24312
24312
  var dd=ev.details,rti=dd?(dd.toolInput||dd.tool_input):undefined,inp=asRec(rti),tiStr=typeof rti==='string'?rti:undefined;
@@ -24327,7 +24327,7 @@ function buildPromptGroups(timeline, commits) {
24327
24327
  }
24328
24328
  deduped.push(ev);
24329
24329
  });
24330
- return{promptId:pid,promptText:promptText,responseText:responseText,toolEvents:deduped,commits:byPrompt[pid]||[],totalCostUsd:cost,totalToolCalls:tools,totalInputTokens:inTok,totalOutputTokens:outTok,totalDurationMs:dur,filesRead:Object.keys(filesR),filesWritten:Object.keys(filesW)};
24330
+ return{promptId:pid,promptText:promptText,responseText:responseText,toolEvents:deduped,commits:byPrompt[pid]||[],totalCostUsd:cost,totalToolCalls:tools,totalInputTokens:inTok,totalOutputTokens:outTok,totalCacheReadTokens:cacheRTok,totalCacheWriteTokens:cacheWTok,totalDurationMs:dur,filesRead:Object.keys(filesR),filesWritten:Object.keys(filesW)};
24331
24331
  }).filter(function(g){return g.promptText||g.toolEvents.length>0||g.responseText;});
24332
24332
  }
24333
24333
 
@@ -24450,6 +24450,7 @@ function renderReplay() {
24450
24450
  h += '<div class="tm">';
24451
24451
  h += '<span class="tmi">Cost <span class="badge orange">' + fmt$4(replay.metrics.totalCostUsd) + '</span></span>';
24452
24452
  h += '<span class="tmi">Tokens <span class="badge cyan">' + replay.metrics.totalInputTokens + ' in / ' + replay.metrics.totalOutputTokens + ' out</span></span>';
24453
+ if (replay.metrics.totalCacheReadTokens > 0 || replay.metrics.totalCacheWriteTokens > 0) h += '<span class="tmi">Cache <span class="badge purple">' + replay.metrics.totalCacheReadTokens + ' read / ' + replay.metrics.totalCacheWriteTokens + ' write</span></span>';
24453
24454
  if (replay.metrics.linesAdded > 0 || replay.metrics.linesRemoved > 0) h += '<span class="tmi">Lines <span class="badge green">+' + replay.metrics.linesAdded + '</span> <span class="badge red">-' + replay.metrics.linesRemoved + '</span></span>';
24454
24455
  if (replay.metrics.modelsUsed.length > 0) h += '<span class="tmi">' + esc(replay.metrics.modelsUsed.join(', ')) + '</span>';
24455
24456
  if (replay.metrics.filesTouched.length > 0) h += '<span class="tmi">' + replay.metrics.filesTouched.length + ' files</span>';
@@ -24776,6 +24777,8 @@ async function fetchSessionReplayFromApi(apiBaseUrl, sessionId) {
24776
24777
  totalCostUsd: typeof metrics["totalCostUsd"] === "number" ? metrics["totalCostUsd"] : 0,
24777
24778
  totalInputTokens: typeof metrics["totalInputTokens"] === "number" ? metrics["totalInputTokens"] : 0,
24778
24779
  totalOutputTokens: typeof metrics["totalOutputTokens"] === "number" ? metrics["totalOutputTokens"] : 0,
24780
+ totalCacheReadTokens: typeof metrics["totalCacheReadTokens"] === "number" ? metrics["totalCacheReadTokens"] : 0,
24781
+ totalCacheWriteTokens: typeof metrics["totalCacheWriteTokens"] === "number" ? metrics["totalCacheWriteTokens"] : 0,
24779
24782
  linesAdded: typeof metrics["linesAdded"] === "number" ? metrics["linesAdded"] : 0,
24780
24783
  linesRemoved: typeof metrics["linesRemoved"] === "number" ? metrics["linesRemoved"] : 0,
24781
24784
  modelsUsed,
@@ -25003,6 +25006,8 @@ CREATE TABLE IF NOT EXISTS agent_events (
25003
25006
  cost_usd REAL,
25004
25007
  input_tokens INTEGER,
25005
25008
  output_tokens INTEGER,
25009
+ cache_read_tokens INTEGER,
25010
+ cache_write_tokens INTEGER,
25006
25011
  api_duration_ms REAL,
25007
25012
  lines_added INTEGER,
25008
25013
  lines_removed INTEGER,
@@ -25028,6 +25033,8 @@ CREATE TABLE IF NOT EXISTS session_traces (
25028
25033
  total_cost_usd REAL NOT NULL DEFAULT 0,
25029
25034
  total_input_tokens INTEGER NOT NULL DEFAULT 0,
25030
25035
  total_output_tokens INTEGER NOT NULL DEFAULT 0,
25036
+ total_cache_read_tokens INTEGER NOT NULL DEFAULT 0,
25037
+ total_cache_write_tokens INTEGER NOT NULL DEFAULT 0,
25031
25038
  lines_added INTEGER NOT NULL DEFAULT 0,
25032
25039
  lines_removed INTEGER NOT NULL DEFAULT 0,
25033
25040
  models_used TEXT NOT NULL DEFAULT '[]',
@@ -25100,6 +25107,7 @@ var SqliteClient = class {
25100
25107
  this.db = new import_better_sqlite3.default(dbPath);
25101
25108
  this.db.pragma("journal_mode = WAL");
25102
25109
  this.db.pragma("synchronous = NORMAL");
25110
+ this.migrateCacheTokenColumns();
25103
25111
  this.migrateDeduplicateEvents();
25104
25112
  this.db.exec(SCHEMA_SQL);
25105
25113
  this.migrateRebuildBrokenTraces();
@@ -25116,10 +25124,11 @@ var SqliteClient = class {
25116
25124
  INSERT INTO session_traces
25117
25125
  (session_id, version, started_at, ended_at, user_id, git_repo, git_branch,
25118
25126
  prompt_count, tool_call_count, api_call_count, total_cost_usd,
25119
- total_input_tokens, total_output_tokens, lines_added, lines_removed,
25127
+ total_input_tokens, total_output_tokens, total_cache_read_tokens, total_cache_write_tokens,
25128
+ lines_added, lines_removed,
25120
25129
  models_used, tools_used, files_touched, commit_count, updated_at)
25121
25130
  VALUES
25122
- (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
25131
+ (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
25123
25132
  ON CONFLICT(session_id) DO UPDATE SET
25124
25133
  version = excluded.version,
25125
25134
  started_at = excluded.started_at,
@@ -25133,6 +25142,8 @@ var SqliteClient = class {
25133
25142
  total_cost_usd = excluded.total_cost_usd,
25134
25143
  total_input_tokens = excluded.total_input_tokens,
25135
25144
  total_output_tokens = excluded.total_output_tokens,
25145
+ total_cache_read_tokens = excluded.total_cache_read_tokens,
25146
+ total_cache_write_tokens = excluded.total_cache_write_tokens,
25136
25147
  lines_added = excluded.lines_added,
25137
25148
  lines_removed = excluded.lines_removed,
25138
25149
  models_used = excluded.models_used,
@@ -25157,6 +25168,8 @@ var SqliteClient = class {
25157
25168
  row.total_cost_usd,
25158
25169
  row.total_input_tokens,
25159
25170
  row.total_output_tokens,
25171
+ row.total_cache_read_tokens,
25172
+ row.total_cache_write_tokens,
25160
25173
  row.lines_added,
25161
25174
  row.lines_removed,
25162
25175
  toJsonArray(row.models_used),
@@ -25266,6 +25279,8 @@ var SqliteClient = class {
25266
25279
  total_cost_usd: raw["total_cost_usd"],
25267
25280
  total_input_tokens: raw["total_input_tokens"],
25268
25281
  total_output_tokens: raw["total_output_tokens"],
25282
+ total_cache_read_tokens: raw["total_cache_read_tokens"] ?? 0,
25283
+ total_cache_write_tokens: raw["total_cache_write_tokens"] ?? 0,
25269
25284
  lines_added: raw["lines_added"],
25270
25285
  lines_removed: raw["lines_removed"],
25271
25286
  models_used: fromJsonArray(raw["models_used"]),
@@ -25279,7 +25294,7 @@ var SqliteClient = class {
25279
25294
  const rows = this.db.prepare(
25280
25295
  `SELECT event_id, event_type, event_timestamp, session_id, prompt_id,
25281
25296
  tool_success, tool_name, tool_duration_ms, model, cost_usd,
25282
- input_tokens, output_tokens, attributes
25297
+ input_tokens, output_tokens, cache_read_tokens, cache_write_tokens, attributes
25283
25298
  FROM agent_events
25284
25299
  WHERE session_id = ?
25285
25300
  ORDER BY event_timestamp ASC
@@ -25298,6 +25313,8 @@ var SqliteClient = class {
25298
25313
  cost_usd: raw["cost_usd"],
25299
25314
  input_tokens: raw["input_tokens"],
25300
25315
  output_tokens: raw["output_tokens"],
25316
+ cache_read_tokens: raw["cache_read_tokens"] ?? null,
25317
+ cache_write_tokens: raw["cache_write_tokens"] ?? null,
25301
25318
  attributes: fromJsonObject(raw["attributes"])
25302
25319
  }));
25303
25320
  }
@@ -25321,6 +25338,31 @@ var SqliteClient = class {
25321
25338
  close() {
25322
25339
  this.db.close();
25323
25340
  }
25341
+ /**
25342
+ * Migration: add cache_read_tokens / cache_write_tokens columns to existing databases.
25343
+ */
25344
+ migrateCacheTokenColumns() {
25345
+ const addColumnIfMissing = (table, column, definition) => {
25346
+ const cols = this.db.prepare(`PRAGMA table_info('${table}')`).all();
25347
+ if (!cols.some((c) => c.name === column)) {
25348
+ this.db.exec(`ALTER TABLE ${table} ADD COLUMN ${column} ${definition}`);
25349
+ }
25350
+ };
25351
+ const eventsExist = this.db.prepare(
25352
+ "SELECT 1 FROM sqlite_master WHERE type='table' AND name='agent_events'"
25353
+ ).get();
25354
+ if (eventsExist !== void 0) {
25355
+ addColumnIfMissing("agent_events", "cache_read_tokens", "INTEGER");
25356
+ addColumnIfMissing("agent_events", "cache_write_tokens", "INTEGER");
25357
+ }
25358
+ const tracesExist = this.db.prepare(
25359
+ "SELECT 1 FROM sqlite_master WHERE type='table' AND name='session_traces'"
25360
+ ).get();
25361
+ if (tracesExist !== void 0) {
25362
+ addColumnIfMissing("session_traces", "total_cache_read_tokens", "INTEGER NOT NULL DEFAULT 0");
25363
+ addColumnIfMissing("session_traces", "total_cache_write_tokens", "INTEGER NOT NULL DEFAULT 0");
25364
+ }
25365
+ }
25324
25366
  /**
25325
25367
  * Migration: deduplicate agent_events rows from older schemas that lacked a UNIQUE constraint.
25326
25368
  * Runs once — if the old table exists without a unique index, it rebuilds it.
@@ -25376,6 +25418,8 @@ var SqliteClient = class {
25376
25418
  cost_usd REAL,
25377
25419
  input_tokens INTEGER,
25378
25420
  output_tokens INTEGER,
25421
+ cache_read_tokens INTEGER,
25422
+ cache_write_tokens INTEGER,
25379
25423
  api_duration_ms REAL,
25380
25424
  lines_added INTEGER,
25381
25425
  lines_removed INTEGER,
@@ -25438,7 +25482,8 @@ var SqliteClient = class {
25438
25482
  INSERT OR REPLACE INTO session_traces
25439
25483
  (session_id, version, started_at, ended_at, user_id, git_repo, git_branch,
25440
25484
  prompt_count, tool_call_count, api_call_count, total_cost_usd,
25441
- total_input_tokens, total_output_tokens, lines_added, lines_removed,
25485
+ total_input_tokens, total_output_tokens, total_cache_read_tokens, total_cache_write_tokens,
25486
+ lines_added, lines_removed,
25442
25487
  models_used, tools_used, files_touched, commit_count, updated_at)
25443
25488
  SELECT
25444
25489
  session_id,
@@ -25454,6 +25499,8 @@ var SqliteClient = class {
25454
25499
  COALESCE(SUM(cost_usd), 0),
25455
25500
  COALESCE(SUM(input_tokens), 0),
25456
25501
  COALESCE(SUM(output_tokens), 0),
25502
+ COALESCE(SUM(cache_read_tokens), 0),
25503
+ COALESCE(SUM(cache_write_tokens), 0),
25457
25504
  COALESCE(SUM(lines_added), 0),
25458
25505
  COALESCE(SUM(lines_removed), 0),
25459
25506
  '[]',
@@ -25498,9 +25545,10 @@ var SqliteClient = class {
25498
25545
  INSERT OR IGNORE INTO agent_events
25499
25546
  (event_id, event_type, event_timestamp, session_id, prompt_id, user_id, source, agent_type,
25500
25547
  tool_name, tool_success, tool_duration_ms, model, cost_usd, input_tokens, output_tokens,
25548
+ cache_read_tokens, cache_write_tokens,
25501
25549
  api_duration_ms, lines_added, lines_removed, files_changed, commit_sha, attributes)
25502
25550
  VALUES
25503
- (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
25551
+ (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
25504
25552
  `);
25505
25553
  const transaction = this.db.transaction((eventRows) => {
25506
25554
  for (const row of eventRows) {
@@ -25520,6 +25568,8 @@ var SqliteClient = class {
25520
25568
  row.cost_usd,
25521
25569
  row.input_tokens,
25522
25570
  row.output_tokens,
25571
+ row.cache_read_tokens,
25572
+ row.cache_write_tokens,
25523
25573
  row.api_duration_ms,
25524
25574
  row.lines_added,
25525
25575
  row.lines_removed,
@@ -25734,6 +25784,8 @@ function toClickHouseAgentEventRow(event) {
25734
25784
  cost_usd: pickNumber(payload, "cost_usd", "costUsd") ?? null,
25735
25785
  input_tokens: pickNumber(payload, "input_tokens", "inputTokens") ?? null,
25736
25786
  output_tokens: pickNumber(payload, "output_tokens", "outputTokens") ?? null,
25787
+ cache_read_tokens: pickNumber(payload, "cache_read_tokens", "cacheReadTokens") ?? pickNumber(payload, "cache_read_input_tokens", "cacheReadInputTokens") ?? null,
25788
+ cache_write_tokens: pickNumber(payload, "cache_write_tokens", "cacheWriteTokens") ?? pickNumber(payload, "cache_creation_input_tokens", "cacheCreationInputTokens") ?? null,
25737
25789
  api_duration_ms: pickNumber(payload, "api_duration_ms", "apiDurationMs") ?? null,
25738
25790
  lines_added: pickNumber(payload, "lines_added", "linesAdded") ?? null,
25739
25791
  lines_removed: pickNumber(payload, "lines_removed", "linesRemoved") ?? null,
@@ -25823,6 +25875,8 @@ function toClickHouseSessionTraceRow(trace, version, updatedAt) {
25823
25875
  total_cost_usd: Number.isFinite(trace.metrics.totalCostUsd) ? trace.metrics.totalCostUsd : 0,
25824
25876
  total_input_tokens: toNonNegativeInteger(trace.metrics.totalInputTokens),
25825
25877
  total_output_tokens: toNonNegativeInteger(trace.metrics.totalOutputTokens),
25878
+ total_cache_read_tokens: toNonNegativeInteger(trace.metrics.totalCacheReadTokens),
25879
+ total_cache_write_tokens: toNonNegativeInteger(trace.metrics.totalCacheWriteTokens),
25826
25880
  lines_added: Math.trunc(trace.metrics.linesAdded),
25827
25881
  lines_removed: Math.trunc(trace.metrics.linesRemoved),
25828
25882
  models_used: toUniqueStringArray(trace.metrics.modelsUsed),
@@ -25974,6 +26028,8 @@ var SESSION_TRACE_SELECT_COLUMNS = [
25974
26028
  "total_cost_usd",
25975
26029
  "total_input_tokens",
25976
26030
  "total_output_tokens",
26031
+ "total_cache_read_tokens",
26032
+ "total_cache_write_tokens",
25977
26033
  "lines_added",
25978
26034
  "lines_removed",
25979
26035
  "models_used",
@@ -26045,6 +26101,8 @@ function toAgentSessionTraceFromClickHouseRow(row) {
26045
26101
  totalCostUsd: Number.isFinite(row.total_cost_usd) ? row.total_cost_usd : 0,
26046
26102
  totalInputTokens: toNonNegativeInteger3(row.total_input_tokens),
26047
26103
  totalOutputTokens: toNonNegativeInteger3(row.total_output_tokens),
26104
+ totalCacheReadTokens: toNonNegativeInteger3(row.total_cache_read_tokens),
26105
+ totalCacheWriteTokens: toNonNegativeInteger3(row.total_cache_write_tokens),
26048
26106
  linesAdded: Math.trunc(row.lines_added),
26049
26107
  linesRemoved: Math.trunc(row.lines_removed),
26050
26108
  filesTouched: toUniqueStrings(row.files_touched),
@@ -26072,6 +26130,8 @@ var EVENT_SELECT_COLUMNS = [
26072
26130
  "cost_usd",
26073
26131
  "input_tokens",
26074
26132
  "output_tokens",
26133
+ "cache_read_tokens",
26134
+ "cache_write_tokens",
26075
26135
  "attributes"
26076
26136
  ].join(", ");
26077
26137
  function toNumber(value) {
@@ -26120,6 +26180,8 @@ function toTimelineEventFromClickHouseRow(row) {
26120
26180
  const costUsd = toNumber(row.cost_usd);
26121
26181
  const inputTokens = toNumber(row.input_tokens);
26122
26182
  const outputTokens = toNumber(row.output_tokens);
26183
+ const cacheReadTokens = toNumber(row.cache_read_tokens);
26184
+ const cacheWriteTokens = toNumber(row.cache_write_tokens);
26123
26185
  const status2 = readStatus(row);
26124
26186
  const details = {};
26125
26187
  if (row.tool_name !== null) {
@@ -26186,7 +26248,9 @@ function toTimelineEventFromClickHouseRow(row) {
26186
26248
  ...inputTokens !== void 0 && outputTokens !== void 0 ? {
26187
26249
  tokens: {
26188
26250
  input: inputTokens,
26189
- output: outputTokens
26251
+ output: outputTokens,
26252
+ ...cacheReadTokens !== void 0 ? { cacheRead: cacheReadTokens } : {},
26253
+ ...cacheWriteTokens !== void 0 ? { cacheWrite: cacheWriteTokens } : {}
26190
26254
  }
26191
26255
  } : {},
26192
26256
  ...Object.keys(details).length > 0 ? { details } : {}
@@ -28358,6 +28422,8 @@ function toTimelineEvent(envelope) {
28358
28422
  const payload = asRecord5(envelope.payload);
28359
28423
  const inputTokens = readNumber3(payload, ["input_tokens", "inputTokens"]);
28360
28424
  const outputTokens = readNumber3(payload, ["output_tokens", "outputTokens"]);
28425
+ const cacheReadTokens = readNumber3(payload, ["cache_read_tokens", "cacheReadTokens", "cache_read_input_tokens"]);
28426
+ const cacheWriteTokens = readNumber3(payload, ["cache_write_tokens", "cacheWriteTokens", "cache_creation_input_tokens"]);
28361
28427
  const costUsd = computeEventCost(payload);
28362
28428
  const details = buildNormalizedDetails(envelope.payload);
28363
28429
  return {
@@ -28369,7 +28435,9 @@ function toTimelineEvent(envelope) {
28369
28435
  ...inputTokens !== void 0 && outputTokens !== void 0 ? {
28370
28436
  tokens: {
28371
28437
  input: inputTokens,
28372
- output: outputTokens
28438
+ output: outputTokens,
28439
+ ...cacheReadTokens !== void 0 ? { cacheRead: cacheReadTokens } : {},
28440
+ ...cacheWriteTokens !== void 0 ? { cacheWrite: cacheWriteTokens } : {}
28373
28441
  }
28374
28442
  } : {},
28375
28443
  ...details !== void 0 ? { details } : {}
@@ -28402,6 +28470,8 @@ function toBaseTrace(envelope) {
28402
28470
  totalCostUsd: 0,
28403
28471
  totalInputTokens: 0,
28404
28472
  totalOutputTokens: 0,
28473
+ totalCacheReadTokens: 0,
28474
+ totalCacheWriteTokens: 0,
28405
28475
  linesAdded: 0,
28406
28476
  linesRemoved: 0,
28407
28477
  filesTouched: [],
@@ -28443,6 +28513,8 @@ function toUpdatedTrace(existing, envelope) {
28443
28513
  const cost = computeEventCost(payload) ?? 0;
28444
28514
  const inputTokens = readNumber3(payload, ["input_tokens", "inputTokens"]) ?? 0;
28445
28515
  const outputTokens = readNumber3(payload, ["output_tokens", "outputTokens"]) ?? 0;
28516
+ const cacheReadTokens = readNumber3(payload, ["cache_read_tokens", "cacheReadTokens", "cache_read_input_tokens"]) ?? 0;
28517
+ const cacheWriteTokens = readNumber3(payload, ["cache_write_tokens", "cacheWriteTokens", "cache_creation_input_tokens"]) ?? 0;
28446
28518
  const linesAdded = readNumber3(payload, ["lines_added", "linesAdded"]) ?? 0;
28447
28519
  const linesRemoved = readNumber3(payload, ["lines_removed", "linesRemoved"]) ?? 0;
28448
28520
  const model = readString4(payload, ["model"]);
@@ -28496,6 +28568,8 @@ function toUpdatedTrace(existing, envelope) {
28496
28568
  totalCostUsd: Number((existing.metrics.totalCostUsd + cost).toFixed(6)),
28497
28569
  totalInputTokens: existing.metrics.totalInputTokens + inputTokens,
28498
28570
  totalOutputTokens: existing.metrics.totalOutputTokens + outputTokens,
28571
+ totalCacheReadTokens: existing.metrics.totalCacheReadTokens + cacheReadTokens,
28572
+ totalCacheWriteTokens: existing.metrics.totalCacheWriteTokens + cacheWriteTokens,
28499
28573
  linesAdded: existing.metrics.linesAdded + linesAdded,
28500
28574
  linesRemoved: existing.metrics.linesRemoved + linesRemoved,
28501
28575
  filesTouched,
@@ -28693,12 +28767,15 @@ var SqlitePersistence = class {
28693
28767
  }
28694
28768
  async persistAcceptedEvent(event, trace) {
28695
28769
  const eventWrite = this.eventWriter.writeEvent(event).catch((error) => {
28770
+ console.error(`[agent-trace] sqlite_events write failed: ${String(error)}`);
28696
28771
  this.writeFailures.push(`sqlite_events: ${String(error)}`);
28697
28772
  });
28698
28773
  const traceWrite = this.sessionTraceWriter.writeTrace(trace).catch((error) => {
28774
+ console.error(`[agent-trace] sqlite_traces write failed: ${String(error)}`);
28699
28775
  this.writeFailures.push(`sqlite_traces: ${String(error)}`);
28700
28776
  });
28701
28777
  const sessionWrite = this.postgresWriter.writeTrace(trace).catch((error) => {
28778
+ console.error(`[agent-trace] sqlite_sessions write failed: ${String(error)}`);
28702
28779
  this.writeFailures.push(`sqlite_sessions: ${String(error)}`);
28703
28780
  });
28704
28781
  await Promise.all([eventWrite, traceWrite, sessionWrite]);
@@ -28760,7 +28837,9 @@ function hydrateFromSqlite(runtime, sqlite, limit, eventLimit) {
28760
28837
  const recalculated = calculateCostUsd({
28761
28838
  model,
28762
28839
  inputTokens: hydratedTrace.metrics.totalInputTokens,
28763
- outputTokens: hydratedTrace.metrics.totalOutputTokens
28840
+ outputTokens: hydratedTrace.metrics.totalOutputTokens,
28841
+ cacheReadTokens: hydratedTrace.metrics.totalCacheReadTokens,
28842
+ cacheWriteTokens: hydratedTrace.metrics.totalCacheWriteTokens
28764
28843
  });
28765
28844
  if (recalculated > 0) {
28766
28845
  hydratedTrace = {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "agent-trace",
3
- "version": "0.2.7",
3
+ "version": "0.2.9",
4
4
  "description": "Self-hosted observability for AI coding agents. One command, zero config.",
5
5
  "license": "Apache-2.0",
6
6
  "bin": {