agent-trace 0.2.6 → 0.2.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/agent-trace.cjs +155 -14
- 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 '[]',
|
|
@@ -25102,6 +25109,8 @@ var SqliteClient = class {
|
|
|
25102
25109
|
this.db.pragma("synchronous = NORMAL");
|
|
25103
25110
|
this.migrateDeduplicateEvents();
|
|
25104
25111
|
this.db.exec(SCHEMA_SQL);
|
|
25112
|
+
this.migrateCacheTokenColumns();
|
|
25113
|
+
this.migrateRebuildBrokenTraces();
|
|
25105
25114
|
}
|
|
25106
25115
|
async insertJsonEachRow(request) {
|
|
25107
25116
|
if (request.rows.length === 0) return;
|
|
@@ -25115,10 +25124,11 @@ var SqliteClient = class {
|
|
|
25115
25124
|
INSERT INTO session_traces
|
|
25116
25125
|
(session_id, version, started_at, ended_at, user_id, git_repo, git_branch,
|
|
25117
25126
|
prompt_count, tool_call_count, api_call_count, total_cost_usd,
|
|
25118
|
-
total_input_tokens, total_output_tokens,
|
|
25127
|
+
total_input_tokens, total_output_tokens, total_cache_read_tokens, total_cache_write_tokens,
|
|
25128
|
+
lines_added, lines_removed,
|
|
25119
25129
|
models_used, tools_used, files_touched, commit_count, updated_at)
|
|
25120
25130
|
VALUES
|
|
25121
|
-
(?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
|
|
25131
|
+
(?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
|
|
25122
25132
|
ON CONFLICT(session_id) DO UPDATE SET
|
|
25123
25133
|
version = excluded.version,
|
|
25124
25134
|
started_at = excluded.started_at,
|
|
@@ -25132,6 +25142,8 @@ var SqliteClient = class {
|
|
|
25132
25142
|
total_cost_usd = excluded.total_cost_usd,
|
|
25133
25143
|
total_input_tokens = excluded.total_input_tokens,
|
|
25134
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,
|
|
25135
25147
|
lines_added = excluded.lines_added,
|
|
25136
25148
|
lines_removed = excluded.lines_removed,
|
|
25137
25149
|
models_used = excluded.models_used,
|
|
@@ -25156,6 +25168,8 @@ var SqliteClient = class {
|
|
|
25156
25168
|
row.total_cost_usd,
|
|
25157
25169
|
row.total_input_tokens,
|
|
25158
25170
|
row.total_output_tokens,
|
|
25171
|
+
row.total_cache_read_tokens,
|
|
25172
|
+
row.total_cache_write_tokens,
|
|
25159
25173
|
row.lines_added,
|
|
25160
25174
|
row.lines_removed,
|
|
25161
25175
|
toJsonArray(row.models_used),
|
|
@@ -25265,6 +25279,8 @@ var SqliteClient = class {
|
|
|
25265
25279
|
total_cost_usd: raw["total_cost_usd"],
|
|
25266
25280
|
total_input_tokens: raw["total_input_tokens"],
|
|
25267
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,
|
|
25268
25284
|
lines_added: raw["lines_added"],
|
|
25269
25285
|
lines_removed: raw["lines_removed"],
|
|
25270
25286
|
models_used: fromJsonArray(raw["models_used"]),
|
|
@@ -25278,7 +25294,7 @@ var SqliteClient = class {
|
|
|
25278
25294
|
const rows = this.db.prepare(
|
|
25279
25295
|
`SELECT event_id, event_type, event_timestamp, session_id, prompt_id,
|
|
25280
25296
|
tool_success, tool_name, tool_duration_ms, model, cost_usd,
|
|
25281
|
-
input_tokens, output_tokens, attributes
|
|
25297
|
+
input_tokens, output_tokens, cache_read_tokens, cache_write_tokens, attributes
|
|
25282
25298
|
FROM agent_events
|
|
25283
25299
|
WHERE session_id = ?
|
|
25284
25300
|
ORDER BY event_timestamp ASC
|
|
@@ -25297,6 +25313,8 @@ var SqliteClient = class {
|
|
|
25297
25313
|
cost_usd: raw["cost_usd"],
|
|
25298
25314
|
input_tokens: raw["input_tokens"],
|
|
25299
25315
|
output_tokens: raw["output_tokens"],
|
|
25316
|
+
cache_read_tokens: raw["cache_read_tokens"] ?? null,
|
|
25317
|
+
cache_write_tokens: raw["cache_write_tokens"] ?? null,
|
|
25300
25318
|
attributes: fromJsonObject(raw["attributes"])
|
|
25301
25319
|
}));
|
|
25302
25320
|
}
|
|
@@ -25320,6 +25338,31 @@ var SqliteClient = class {
|
|
|
25320
25338
|
close() {
|
|
25321
25339
|
this.db.close();
|
|
25322
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
|
+
}
|
|
25323
25366
|
/**
|
|
25324
25367
|
* Migration: deduplicate agent_events rows from older schemas that lacked a UNIQUE constraint.
|
|
25325
25368
|
* Runs once — if the old table exists without a unique index, it rebuilds it.
|
|
@@ -25375,6 +25418,8 @@ var SqliteClient = class {
|
|
|
25375
25418
|
cost_usd REAL,
|
|
25376
25419
|
input_tokens INTEGER,
|
|
25377
25420
|
output_tokens INTEGER,
|
|
25421
|
+
cache_read_tokens INTEGER,
|
|
25422
|
+
cache_write_tokens INTEGER,
|
|
25378
25423
|
api_duration_ms REAL,
|
|
25379
25424
|
lines_added INTEGER,
|
|
25380
25425
|
lines_removed INTEGER,
|
|
@@ -25395,6 +25440,32 @@ var SqliteClient = class {
|
|
|
25395
25440
|
console.log(`[agent-trace] migration complete: ${afterCount.c} events after dedup (removed ${total - afterCount.c} duplicates)`);
|
|
25396
25441
|
this.rebuildSessionTracesFromEvents();
|
|
25397
25442
|
}
|
|
25443
|
+
/**
|
|
25444
|
+
* Migration v2: fix databases that ran v0.2.6's broken rebuild (models_used='[]' with data present).
|
|
25445
|
+
* Re-runs the rebuild if session_traces exist but have empty models_used while events have model data.
|
|
25446
|
+
*/
|
|
25447
|
+
migrateRebuildBrokenTraces() {
|
|
25448
|
+
const tracesExist = this.db.prepare(
|
|
25449
|
+
"SELECT 1 FROM sqlite_master WHERE type='table' AND name='session_traces'"
|
|
25450
|
+
).get();
|
|
25451
|
+
if (tracesExist === void 0) {
|
|
25452
|
+
return;
|
|
25453
|
+
}
|
|
25454
|
+
const broken = this.db.prepare(`
|
|
25455
|
+
SELECT 1 FROM session_traces st
|
|
25456
|
+
WHERE st.models_used = '[]'
|
|
25457
|
+
AND EXISTS (
|
|
25458
|
+
SELECT 1 FROM agent_events ae
|
|
25459
|
+
WHERE ae.session_id = st.session_id AND ae.model IS NOT NULL
|
|
25460
|
+
)
|
|
25461
|
+
LIMIT 1
|
|
25462
|
+
`).get();
|
|
25463
|
+
if (broken === void 0) {
|
|
25464
|
+
return;
|
|
25465
|
+
}
|
|
25466
|
+
console.log("[agent-trace] migrating: rebuilding session traces with correct models/tools");
|
|
25467
|
+
this.rebuildSessionTracesFromEvents();
|
|
25468
|
+
}
|
|
25398
25469
|
/**
|
|
25399
25470
|
* Rebuild session_traces by aggregating deduplicated agent_events.
|
|
25400
25471
|
* Called after dedup migration so the dashboard has correct metrics immediately.
|
|
@@ -25411,7 +25482,8 @@ var SqliteClient = class {
|
|
|
25411
25482
|
INSERT OR REPLACE INTO session_traces
|
|
25412
25483
|
(session_id, version, started_at, ended_at, user_id, git_repo, git_branch,
|
|
25413
25484
|
prompt_count, tool_call_count, api_call_count, total_cost_usd,
|
|
25414
|
-
total_input_tokens, total_output_tokens,
|
|
25485
|
+
total_input_tokens, total_output_tokens, total_cache_read_tokens, total_cache_write_tokens,
|
|
25486
|
+
lines_added, lines_removed,
|
|
25415
25487
|
models_used, tools_used, files_touched, commit_count, updated_at)
|
|
25416
25488
|
SELECT
|
|
25417
25489
|
session_id,
|
|
@@ -25427,6 +25499,8 @@ var SqliteClient = class {
|
|
|
25427
25499
|
COALESCE(SUM(cost_usd), 0),
|
|
25428
25500
|
COALESCE(SUM(input_tokens), 0),
|
|
25429
25501
|
COALESCE(SUM(output_tokens), 0),
|
|
25502
|
+
COALESCE(SUM(cache_read_tokens), 0),
|
|
25503
|
+
COALESCE(SUM(cache_write_tokens), 0),
|
|
25430
25504
|
COALESCE(SUM(lines_added), 0),
|
|
25431
25505
|
COALESCE(SUM(lines_removed), 0),
|
|
25432
25506
|
'[]',
|
|
@@ -25437,6 +25511,32 @@ var SqliteClient = class {
|
|
|
25437
25511
|
FROM agent_events
|
|
25438
25512
|
GROUP BY session_id
|
|
25439
25513
|
`);
|
|
25514
|
+
const sessionIds = this.db.prepare(
|
|
25515
|
+
"SELECT DISTINCT session_id FROM agent_events"
|
|
25516
|
+
).all();
|
|
25517
|
+
const updateArrays = this.db.prepare(
|
|
25518
|
+
"UPDATE session_traces SET models_used = ?, tools_used = ?, files_touched = ? WHERE session_id = ?"
|
|
25519
|
+
);
|
|
25520
|
+
const transaction = this.db.transaction((ids) => {
|
|
25521
|
+
for (const { session_id } of ids) {
|
|
25522
|
+
const models = this.db.prepare(
|
|
25523
|
+
"SELECT DISTINCT model FROM agent_events WHERE session_id = ? AND model IS NOT NULL"
|
|
25524
|
+
).all(session_id);
|
|
25525
|
+
const tools = this.db.prepare(
|
|
25526
|
+
"SELECT DISTINCT tool_name FROM agent_events WHERE session_id = ? AND tool_name IS NOT NULL"
|
|
25527
|
+
).all(session_id);
|
|
25528
|
+
const files = this.db.prepare(
|
|
25529
|
+
"SELECT DISTINCT commit_sha FROM agent_events WHERE session_id = ? AND commit_sha IS NOT NULL"
|
|
25530
|
+
).all(session_id);
|
|
25531
|
+
updateArrays.run(
|
|
25532
|
+
JSON.stringify(models.map((r) => r.model)),
|
|
25533
|
+
JSON.stringify(tools.map((r) => r.tool_name)),
|
|
25534
|
+
JSON.stringify(files.map((r) => r.commit_sha)),
|
|
25535
|
+
session_id
|
|
25536
|
+
);
|
|
25537
|
+
}
|
|
25538
|
+
});
|
|
25539
|
+
transaction(sessionIds);
|
|
25440
25540
|
const rebuilt = this.db.prepare("SELECT COUNT(*) as c FROM session_traces").get();
|
|
25441
25541
|
console.log(`[agent-trace] rebuilt ${rebuilt.c} session traces from deduplicated events`);
|
|
25442
25542
|
}
|
|
@@ -25445,9 +25545,10 @@ var SqliteClient = class {
|
|
|
25445
25545
|
INSERT OR IGNORE INTO agent_events
|
|
25446
25546
|
(event_id, event_type, event_timestamp, session_id, prompt_id, user_id, source, agent_type,
|
|
25447
25547
|
tool_name, tool_success, tool_duration_ms, model, cost_usd, input_tokens, output_tokens,
|
|
25548
|
+
cache_read_tokens, cache_write_tokens,
|
|
25448
25549
|
api_duration_ms, lines_added, lines_removed, files_changed, commit_sha, attributes)
|
|
25449
25550
|
VALUES
|
|
25450
|
-
(?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
|
|
25551
|
+
(?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
|
|
25451
25552
|
`);
|
|
25452
25553
|
const transaction = this.db.transaction((eventRows) => {
|
|
25453
25554
|
for (const row of eventRows) {
|
|
@@ -25467,6 +25568,8 @@ var SqliteClient = class {
|
|
|
25467
25568
|
row.cost_usd,
|
|
25468
25569
|
row.input_tokens,
|
|
25469
25570
|
row.output_tokens,
|
|
25571
|
+
row.cache_read_tokens,
|
|
25572
|
+
row.cache_write_tokens,
|
|
25470
25573
|
row.api_duration_ms,
|
|
25471
25574
|
row.lines_added,
|
|
25472
25575
|
row.lines_removed,
|
|
@@ -25681,6 +25784,8 @@ function toClickHouseAgentEventRow(event) {
|
|
|
25681
25784
|
cost_usd: pickNumber(payload, "cost_usd", "costUsd") ?? null,
|
|
25682
25785
|
input_tokens: pickNumber(payload, "input_tokens", "inputTokens") ?? null,
|
|
25683
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,
|
|
25684
25789
|
api_duration_ms: pickNumber(payload, "api_duration_ms", "apiDurationMs") ?? null,
|
|
25685
25790
|
lines_added: pickNumber(payload, "lines_added", "linesAdded") ?? null,
|
|
25686
25791
|
lines_removed: pickNumber(payload, "lines_removed", "linesRemoved") ?? null,
|
|
@@ -25770,6 +25875,8 @@ function toClickHouseSessionTraceRow(trace, version, updatedAt) {
|
|
|
25770
25875
|
total_cost_usd: Number.isFinite(trace.metrics.totalCostUsd) ? trace.metrics.totalCostUsd : 0,
|
|
25771
25876
|
total_input_tokens: toNonNegativeInteger(trace.metrics.totalInputTokens),
|
|
25772
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),
|
|
25773
25880
|
lines_added: Math.trunc(trace.metrics.linesAdded),
|
|
25774
25881
|
lines_removed: Math.trunc(trace.metrics.linesRemoved),
|
|
25775
25882
|
models_used: toUniqueStringArray(trace.metrics.modelsUsed),
|
|
@@ -25921,6 +26028,8 @@ var SESSION_TRACE_SELECT_COLUMNS = [
|
|
|
25921
26028
|
"total_cost_usd",
|
|
25922
26029
|
"total_input_tokens",
|
|
25923
26030
|
"total_output_tokens",
|
|
26031
|
+
"total_cache_read_tokens",
|
|
26032
|
+
"total_cache_write_tokens",
|
|
25924
26033
|
"lines_added",
|
|
25925
26034
|
"lines_removed",
|
|
25926
26035
|
"models_used",
|
|
@@ -25992,6 +26101,8 @@ function toAgentSessionTraceFromClickHouseRow(row) {
|
|
|
25992
26101
|
totalCostUsd: Number.isFinite(row.total_cost_usd) ? row.total_cost_usd : 0,
|
|
25993
26102
|
totalInputTokens: toNonNegativeInteger3(row.total_input_tokens),
|
|
25994
26103
|
totalOutputTokens: toNonNegativeInteger3(row.total_output_tokens),
|
|
26104
|
+
totalCacheReadTokens: toNonNegativeInteger3(row.total_cache_read_tokens),
|
|
26105
|
+
totalCacheWriteTokens: toNonNegativeInteger3(row.total_cache_write_tokens),
|
|
25995
26106
|
linesAdded: Math.trunc(row.lines_added),
|
|
25996
26107
|
linesRemoved: Math.trunc(row.lines_removed),
|
|
25997
26108
|
filesTouched: toUniqueStrings(row.files_touched),
|
|
@@ -26019,6 +26130,8 @@ var EVENT_SELECT_COLUMNS = [
|
|
|
26019
26130
|
"cost_usd",
|
|
26020
26131
|
"input_tokens",
|
|
26021
26132
|
"output_tokens",
|
|
26133
|
+
"cache_read_tokens",
|
|
26134
|
+
"cache_write_tokens",
|
|
26022
26135
|
"attributes"
|
|
26023
26136
|
].join(", ");
|
|
26024
26137
|
function toNumber(value) {
|
|
@@ -26067,6 +26180,8 @@ function toTimelineEventFromClickHouseRow(row) {
|
|
|
26067
26180
|
const costUsd = toNumber(row.cost_usd);
|
|
26068
26181
|
const inputTokens = toNumber(row.input_tokens);
|
|
26069
26182
|
const outputTokens = toNumber(row.output_tokens);
|
|
26183
|
+
const cacheReadTokens = toNumber(row.cache_read_tokens);
|
|
26184
|
+
const cacheWriteTokens = toNumber(row.cache_write_tokens);
|
|
26070
26185
|
const status2 = readStatus(row);
|
|
26071
26186
|
const details = {};
|
|
26072
26187
|
if (row.tool_name !== null) {
|
|
@@ -26133,7 +26248,9 @@ function toTimelineEventFromClickHouseRow(row) {
|
|
|
26133
26248
|
...inputTokens !== void 0 && outputTokens !== void 0 ? {
|
|
26134
26249
|
tokens: {
|
|
26135
26250
|
input: inputTokens,
|
|
26136
|
-
output: outputTokens
|
|
26251
|
+
output: outputTokens,
|
|
26252
|
+
...cacheReadTokens !== void 0 ? { cacheRead: cacheReadTokens } : {},
|
|
26253
|
+
...cacheWriteTokens !== void 0 ? { cacheWrite: cacheWriteTokens } : {}
|
|
26137
26254
|
}
|
|
26138
26255
|
} : {},
|
|
26139
26256
|
...Object.keys(details).length > 0 ? { details } : {}
|
|
@@ -28305,6 +28422,8 @@ function toTimelineEvent(envelope) {
|
|
|
28305
28422
|
const payload = asRecord5(envelope.payload);
|
|
28306
28423
|
const inputTokens = readNumber3(payload, ["input_tokens", "inputTokens"]);
|
|
28307
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"]);
|
|
28308
28427
|
const costUsd = computeEventCost(payload);
|
|
28309
28428
|
const details = buildNormalizedDetails(envelope.payload);
|
|
28310
28429
|
return {
|
|
@@ -28316,7 +28435,9 @@ function toTimelineEvent(envelope) {
|
|
|
28316
28435
|
...inputTokens !== void 0 && outputTokens !== void 0 ? {
|
|
28317
28436
|
tokens: {
|
|
28318
28437
|
input: inputTokens,
|
|
28319
|
-
output: outputTokens
|
|
28438
|
+
output: outputTokens,
|
|
28439
|
+
...cacheReadTokens !== void 0 ? { cacheRead: cacheReadTokens } : {},
|
|
28440
|
+
...cacheWriteTokens !== void 0 ? { cacheWrite: cacheWriteTokens } : {}
|
|
28320
28441
|
}
|
|
28321
28442
|
} : {},
|
|
28322
28443
|
...details !== void 0 ? { details } : {}
|
|
@@ -28349,6 +28470,8 @@ function toBaseTrace(envelope) {
|
|
|
28349
28470
|
totalCostUsd: 0,
|
|
28350
28471
|
totalInputTokens: 0,
|
|
28351
28472
|
totalOutputTokens: 0,
|
|
28473
|
+
totalCacheReadTokens: 0,
|
|
28474
|
+
totalCacheWriteTokens: 0,
|
|
28352
28475
|
linesAdded: 0,
|
|
28353
28476
|
linesRemoved: 0,
|
|
28354
28477
|
filesTouched: [],
|
|
@@ -28390,6 +28513,8 @@ function toUpdatedTrace(existing, envelope) {
|
|
|
28390
28513
|
const cost = computeEventCost(payload) ?? 0;
|
|
28391
28514
|
const inputTokens = readNumber3(payload, ["input_tokens", "inputTokens"]) ?? 0;
|
|
28392
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;
|
|
28393
28518
|
const linesAdded = readNumber3(payload, ["lines_added", "linesAdded"]) ?? 0;
|
|
28394
28519
|
const linesRemoved = readNumber3(payload, ["lines_removed", "linesRemoved"]) ?? 0;
|
|
28395
28520
|
const model = readString4(payload, ["model"]);
|
|
@@ -28443,6 +28568,8 @@ function toUpdatedTrace(existing, envelope) {
|
|
|
28443
28568
|
totalCostUsd: Number((existing.metrics.totalCostUsd + cost).toFixed(6)),
|
|
28444
28569
|
totalInputTokens: existing.metrics.totalInputTokens + inputTokens,
|
|
28445
28570
|
totalOutputTokens: existing.metrics.totalOutputTokens + outputTokens,
|
|
28571
|
+
totalCacheReadTokens: existing.metrics.totalCacheReadTokens + cacheReadTokens,
|
|
28572
|
+
totalCacheWriteTokens: existing.metrics.totalCacheWriteTokens + cacheWriteTokens,
|
|
28446
28573
|
linesAdded: existing.metrics.linesAdded + linesAdded,
|
|
28447
28574
|
linesRemoved: existing.metrics.linesRemoved + linesRemoved,
|
|
28448
28575
|
filesTouched,
|
|
@@ -28489,11 +28616,23 @@ async function close2(server) {
|
|
|
28489
28616
|
});
|
|
28490
28617
|
});
|
|
28491
28618
|
}
|
|
28619
|
+
function enrichEnvelopeWithCost(event) {
|
|
28620
|
+
const payload = event.payload;
|
|
28621
|
+
if (typeof payload["cost_usd"] === "number" && payload["cost_usd"] > 0) {
|
|
28622
|
+
return event;
|
|
28623
|
+
}
|
|
28624
|
+
const cost = computeEventCost(payload);
|
|
28625
|
+
if (cost === void 0 || cost <= 0) {
|
|
28626
|
+
return event;
|
|
28627
|
+
}
|
|
28628
|
+
return { ...event, payload: { ...payload, cost_usd: cost } };
|
|
28629
|
+
}
|
|
28492
28630
|
async function projectAndPersistEvent(event, sessionRepository, persistence) {
|
|
28493
28631
|
const current = sessionRepository.getBySessionId(event.sessionId);
|
|
28494
28632
|
const projected = projectEnvelopeToTrace(current, event);
|
|
28495
28633
|
sessionRepository.upsert(projected);
|
|
28496
|
-
|
|
28634
|
+
const enriched = enrichEnvelopeWithCost(event);
|
|
28635
|
+
await persistence.persistAcceptedEvent(enriched, projected);
|
|
28497
28636
|
}
|
|
28498
28637
|
function createRuntimeOtelSink(runtime) {
|
|
28499
28638
|
return runtime.collectorService.otelSink;
|
|
@@ -28695,7 +28834,9 @@ function hydrateFromSqlite(runtime, sqlite, limit, eventLimit) {
|
|
|
28695
28834
|
const recalculated = calculateCostUsd({
|
|
28696
28835
|
model,
|
|
28697
28836
|
inputTokens: hydratedTrace.metrics.totalInputTokens,
|
|
28698
|
-
outputTokens: hydratedTrace.metrics.totalOutputTokens
|
|
28837
|
+
outputTokens: hydratedTrace.metrics.totalOutputTokens,
|
|
28838
|
+
cacheReadTokens: hydratedTrace.metrics.totalCacheReadTokens,
|
|
28839
|
+
cacheWriteTokens: hydratedTrace.metrics.totalCacheWriteTokens
|
|
28699
28840
|
});
|
|
28700
28841
|
if (recalculated > 0) {
|
|
28701
28842
|
hydratedTrace = {
|