(lines, logEntries, toolUsePairs)
| 501 | } |
| 502 | |
| 503 | function appendStatistics(lines, logEntries, toolUsePairs) { |
| 504 | const lastEntry = logEntries[logEntries.length - 1]; |
| 505 | lines.push("Statistics:"); |
| 506 | if (lastEntry?.num_turns) { |
| 507 | lines.push(` Turns: ${lastEntry.num_turns}`); |
| 508 | } |
| 509 | if (lastEntry?.duration_ms) { |
| 510 | const duration = formatDuration(lastEntry.duration_ms); |
| 511 | if (duration) { |
| 512 | lines.push(` Duration: ${duration}`); |
| 513 | } |
| 514 | } |
| 515 | |
| 516 | let toolCounts = { total: 0, success: 0, error: 0 }; |
| 517 | for (const entry of logEntries) { |
| 518 | if (entry.type === "assistant" && entry.message?.content) { |
| 519 | for (const content of entry.message.content) { |
| 520 | if (content.type === "tool_use") { |
| 521 | const toolName = content.name; |
| 522 | if (INTERNAL_TOOLS.includes(toolName)) { |
| 523 | continue; |
| 524 | } |
| 525 | toolCounts.total++; |
| 526 | const toolResult = toolUsePairs.get(content.id); |
| 527 | const isError = toolResult?.is_error === true; |
| 528 | if (isError) { |
| 529 | toolCounts.error++; |
| 530 | } else { |
| 531 | toolCounts.success++; |
| 532 | } |
| 533 | } |
| 534 | } |
| 535 | } |
| 536 | } |
| 537 | |
| 538 | if (toolCounts.total > 0) { |
| 539 | lines.push(` Tools: ${toolCounts.success}/${toolCounts.total} succeeded`); |
| 540 | } |
| 541 | if (lastEntry?.usage) { |
| 542 | const usage = lastEntry.usage; |
| 543 | if (usage.input_tokens || usage.output_tokens) { |
| 544 | const inputTokens = usage.input_tokens || 0; |
| 545 | const outputTokens = usage.output_tokens || 0; |
| 546 | const cacheCreationTokens = usage.cache_creation_input_tokens || 0; |
| 547 | const cacheReadTokens = usage.cache_read_input_tokens || 0; |
| 548 | const totalTokens = inputTokens + outputTokens + cacheCreationTokens + cacheReadTokens; |
| 549 | |
| 550 | lines.push(` Tokens: ${totalTokens.toLocaleString()} total (${inputTokens.toLocaleString()} in / ${outputTokens.toLocaleString()} out)`); |
| 551 | } |
| 552 | } |
| 553 | if (lastEntry?.total_cost_usd) { |
| 554 | lines.push(` Cost: $${lastEntry.total_cost_usd.toFixed(4)}`); |
| 555 | } |
| 556 | } |
| 557 | |
| 558 | function generateSummaryLines(logEntries) { |
| 559 | const renderEntries = normalizeEntriesForRendering(logEntries); |
no test coverage detected