( sessionId: string, project: string, turns: ClassifiedTurn[], mcpInventory?: string[], )
| 1270 | } |
| 1271 | |
| 1272 | function buildSessionSummary( |
| 1273 | sessionId: string, |
| 1274 | project: string, |
| 1275 | turns: ClassifiedTurn[], |
| 1276 | mcpInventory?: string[], |
| 1277 | ): SessionSummary { |
| 1278 | const modelBreakdown: SessionSummary['modelBreakdown'] = Object.create(null) |
| 1279 | const toolBreakdown: SessionSummary['toolBreakdown'] = Object.create(null) |
| 1280 | const mcpBreakdown: SessionSummary['mcpBreakdown'] = Object.create(null) |
| 1281 | const bashBreakdown: SessionSummary['bashBreakdown'] = Object.create(null) |
| 1282 | const categoryBreakdown: SessionSummary['categoryBreakdown'] = Object.create(null) |
| 1283 | const skillBreakdown: SessionSummary['skillBreakdown'] = Object.create(null) |
| 1284 | const subagentBreakdown: SessionSummary['subagentBreakdown'] = Object.create(null) |
| 1285 | |
| 1286 | let totalCost = 0 |
| 1287 | let totalSavings = 0 |
| 1288 | let totalInput = 0 |
| 1289 | let totalOutput = 0 |
| 1290 | let totalReasoning = 0 |
| 1291 | let totalCacheRead = 0 |
| 1292 | let totalCacheWrite = 0 |
| 1293 | let apiCalls = 0 |
| 1294 | let firstTs = '' |
| 1295 | let lastTs = '' |
| 1296 | |
| 1297 | for (const turn of turns) { |
| 1298 | const turnCost = turn.assistantCalls.reduce((s, c) => s + c.costUSD, 0) |
| 1299 | const turnSavings = turn.assistantCalls.reduce((s, c) => s + (c.savingsUSD ?? 0), 0) |
| 1300 | |
| 1301 | if (!categoryBreakdown[turn.category]) { |
| 1302 | categoryBreakdown[turn.category] = { turns: 0, costUSD: 0, savingsUSD: 0, retries: 0, editTurns: 0, oneShotTurns: 0 } |
| 1303 | } |
| 1304 | categoryBreakdown[turn.category].turns++ |
| 1305 | categoryBreakdown[turn.category].costUSD += turnCost |
| 1306 | categoryBreakdown[turn.category].savingsUSD += turnSavings |
| 1307 | if (turn.hasEdits) { |
| 1308 | categoryBreakdown[turn.category].editTurns++ |
| 1309 | categoryBreakdown[turn.category].retries += turn.retries |
| 1310 | if (turn.retries === 0) categoryBreakdown[turn.category].oneShotTurns++ |
| 1311 | } |
| 1312 | |
| 1313 | if (turn.subCategory) { |
| 1314 | const skillKey = turn.subCategory |
| 1315 | if (!skillBreakdown[skillKey]) { |
| 1316 | skillBreakdown[skillKey] = { turns: 0, costUSD: 0, savingsUSD: 0, editTurns: 0, oneShotTurns: 0 } |
| 1317 | } |
| 1318 | skillBreakdown[skillKey].turns++ |
| 1319 | skillBreakdown[skillKey].costUSD += turnCost |
| 1320 | skillBreakdown[skillKey].savingsUSD += turnSavings |
| 1321 | if (turn.hasEdits) { |
| 1322 | skillBreakdown[skillKey].editTurns++ |
| 1323 | if (turn.retries === 0) skillBreakdown[skillKey].oneShotTurns++ |
| 1324 | } |
| 1325 | } |
| 1326 | |
| 1327 | for (const call of turn.assistantCalls) { |
| 1328 | const callSavings = call.savingsUSD ?? 0 |
| 1329 | totalCost += call.costUSD |
no test coverage detected