( blocks: ContentBlock[] | undefined, )
| 585 | * Includes both executed tools (str_replace, write_file) and proposed tools. |
| 586 | */ |
| 587 | export function buildActivityTimeline( |
| 588 | blocks: ContentBlock[] | undefined, |
| 589 | ): TimelineItem[] { |
| 590 | if (!blocks || blocks.length === 0) return [] |
| 591 | |
| 592 | const timeline: TimelineItem[] = [] |
| 593 | |
| 594 | for (const block of blocks) { |
| 595 | if (block.type === 'text' && block.textType !== 'reasoning') { |
| 596 | const content = block.content.trim() |
| 597 | if (content) { |
| 598 | timeline.push({ type: 'commentary', content }) |
| 599 | } |
| 600 | } else if ( |
| 601 | block.type === 'tool' && |
| 602 | ALL_EDIT_TOOL_NAMES.includes( |
| 603 | block.toolName as (typeof ALL_EDIT_TOOL_NAMES)[number], |
| 604 | ) |
| 605 | ) { |
| 606 | if (isFailedEditToolBlock(block)) continue |
| 607 | |
| 608 | const filePath = extractFilePath(block) |
| 609 | const diff = extractDiff(block) |
| 610 | const isCreate = isCreateFile(block) |
| 611 | |
| 612 | timeline.push({ |
| 613 | type: 'edit', |
| 614 | content: filePath || 'unknown file', |
| 615 | diff: diff || undefined, |
| 616 | isCreate, |
| 617 | }) |
| 618 | } |
| 619 | } |
| 620 | |
| 621 | return timeline |
| 622 | } |
| 623 | |
| 624 | /** |
| 625 | * Truncate text to fit within maxWidth, adding ellipsis if needed. |
no test coverage detected