diff --git a/server/__tests__/ui-audit-routes.test.js b/server/__tests__/ui-audit-routes.test.js index b4a9c24e..fefecedb 100644 --- a/server/__tests__/ui-audit-routes.test.js +++ b/server/__tests__/ui-audit-routes.test.js @@ -93,6 +93,12 @@ describe("GET /api/sessions/:id/stats tool totals", () => { assert.equal(body.tool_call_count, 2); assert.equal(body.distinct_tool_count, 1); }); + it("counts each call once in tools_used, not its Pre and Post events", async () => { + const one = (await get("/api/sessions/ua-1/stats")).body.tools_used; + assert.ok(one.every((t) => t.count === 1)); + const two = (await get("/api/sessions/ua-2/stats")).body.tools_used; + assert.deepEqual(two, [{ tool_name: "Read", count: 2 }]); + }); }); describe("GET /api/events labels", () => { diff --git a/server/db.js b/server/db.js index e406a818..47dc4baf 100644 --- a/server/db.js +++ b/server/db.js @@ -2547,10 +2547,16 @@ const stmts = { FROM events WHERE session_id = ? AND tool_name IS NOT NULL `), + // One row per call, like sessionToolCallTotals: a call is its PreToolUse, + // or its PostToolUse in a session that has none (imported). Counting every + // event with a tool_name counted each call twice. sessionToolUsageCounts: db.prepare(` SELECT tool_name, COUNT(*) as count FROM events WHERE session_id = ? AND tool_name IS NOT NULL + AND event_type = CASE + WHEN EXISTS (SELECT 1 FROM events WHERE session_id = ? AND event_type = 'PreToolUse') + THEN 'PreToolUse' ELSE 'PostToolUse' END GROUP BY tool_name ORDER BY count DESC LIMIT 15 diff --git a/server/routes/sessions.js b/server/routes/sessions.js index fcad8186..9c053682 100644 --- a/server/routes/sessions.js +++ b/server/routes/sessions.js @@ -702,7 +702,7 @@ router.get("/:id/file", async (req, res) => { function sessionStats(sessionId) { const totalEvents = stmts.sessionEventCount.get(sessionId)?.count ?? 0; const eventsByType = stmts.sessionEventTypeCounts.all(sessionId); - const tools = stmts.sessionToolUsageCounts.all(sessionId); + const tools = stmts.sessionToolUsageCounts.all(sessionId, sessionId); // Exact totals: `tools_used` is a top-15 list, so its sum is not the count. // A tool call is a PreToolUse; a session with none (imported) counts PostToolUse. const toolTotals = stmts.sessionToolCallTotals.get(sessionId) || {};