(entry: TranscriptEntry)
| 1734 | // ========================================================================= |
| 1735 | |
| 1736 | private createTranscriptComponent(entry: TranscriptEntry): Component | null { |
| 1737 | if (entry.compactionData !== undefined) { |
| 1738 | const data = entry.compactionData; |
| 1739 | const block = new CompactionComponent(this.state.ui, data.instruction); |
| 1740 | if (data.result === 'cancelled') { |
| 1741 | block.markCanceled(); |
| 1742 | } else { |
| 1743 | block.markDone(data.tokensBefore, data.tokensAfter); |
| 1744 | } |
| 1745 | return block; |
| 1746 | } |
| 1747 | |
| 1748 | switch (entry.kind) { |
| 1749 | case 'user': { |
| 1750 | const images = entry.imageAttachmentIds |
| 1751 | ?.map((id) => this.imageStore.get(id)) |
| 1752 | .filter((a): a is ImageAttachment => a?.kind === 'image'); |
| 1753 | return new UserMessageComponent(entry.content, images, entry.bullet); |
| 1754 | } |
| 1755 | case 'skill_activation': |
| 1756 | return new SkillActivationComponent( |
| 1757 | entry.skillName ?? entry.content, |
| 1758 | entry.skillArgs, |
| 1759 | entry.skillTrigger, |
| 1760 | ); |
| 1761 | case 'plugin_command': { |
| 1762 | const data = entry.pluginCommandData; |
| 1763 | if (data === undefined) return null; |
| 1764 | return new PluginCommandComponent(data.pluginId, data.commandName, data.args); |
| 1765 | } |
| 1766 | case 'cron': |
| 1767 | return new CronMessageComponent(entry.content, entry.cronData ?? {}); |
| 1768 | case 'goal': |
| 1769 | if (entry.goalData?.kind === 'created') { |
| 1770 | return new GoalSetMessageComponent(); |
| 1771 | } |
| 1772 | if (entry.goalData?.kind === 'lifecycle') { |
| 1773 | return buildGoalMarker(entry.goalData.change, this.state.toolOutputExpanded); |
| 1774 | } |
| 1775 | return null; |
| 1776 | case 'assistant': { |
| 1777 | if (entry.content.trimStart().startsWith('✓ Goal complete')) { |
| 1778 | return new GoalCompletionMessageComponent(entry.content); |
| 1779 | } |
| 1780 | const component = new AssistantMessageComponent(); |
| 1781 | component.updateContent(entry.content); |
| 1782 | return component; |
| 1783 | } |
| 1784 | case 'thinking': { |
| 1785 | const thinking = new ThinkingComponent(entry.content, true); |
| 1786 | if (this.state.toolOutputExpanded) thinking.setExpanded(true); |
| 1787 | return thinking; |
| 1788 | } |
| 1789 | case 'tool_call': |
| 1790 | if (entry.toolCallData) { |
| 1791 | const tc = new ToolCallComponent( |
| 1792 | entry.toolCallData, |
| 1793 | entry.toolCallData.result, |
no test coverage detected