fix(sessions): Top tools counts each tool call once

The session analysis page's Top tools list counted every event carrying a
tool_name, so each call was counted twice (its PreToolUse and its
PostToolUse) while the Tool calls total beside it counted once — a session
with 840 calls showed Bash at 1,533. The list now counts the same way as
the total: PreToolUse, or PostToolUse in a session with none (imported).
This commit is contained in:
2026-10-29 14:53:45 +07:00
parent 6099841cef
commit d060d288fb
3 changed files with 13 additions and 1 deletions
+6
View File
@@ -93,6 +93,12 @@ describe("GET /api/sessions/:id/stats tool totals", () => {
assert.equal(body.tool_call_count, 2); assert.equal(body.tool_call_count, 2);
assert.equal(body.distinct_tool_count, 1); 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", () => { describe("GET /api/events labels", () => {
+6
View File
@@ -2547,10 +2547,16 @@ const stmts = {
FROM events FROM events
WHERE session_id = ? AND tool_name IS NOT NULL 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(` sessionToolUsageCounts: db.prepare(`
SELECT tool_name, COUNT(*) as count SELECT tool_name, COUNT(*) as count
FROM events FROM events
WHERE session_id = ? AND tool_name IS NOT NULL 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 GROUP BY tool_name
ORDER BY count DESC ORDER BY count DESC
LIMIT 15 LIMIT 15
+1 -1
View File
@@ -702,7 +702,7 @@ router.get("/:id/file", async (req, res) => {
function sessionStats(sessionId) { function sessionStats(sessionId) {
const totalEvents = stmts.sessionEventCount.get(sessionId)?.count ?? 0; const totalEvents = stmts.sessionEventCount.get(sessionId)?.count ?? 0;
const eventsByType = stmts.sessionEventTypeCounts.all(sessionId); 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. // 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. // A tool call is a PreToolUse; a session with none (imported) counts PostToolUse.
const toolTotals = stmts.sessionToolCallTotals.get(sessionId) || {}; const toolTotals = stmts.sessionToolCallTotals.get(sessionId) || {};