(progressMessages: ProgressMessage<Progress>[], tools: Tools)
| 786 | return getAgentColor(input.subagent_type) as keyof Theme | undefined; |
| 787 | } |
| 788 | export function extractLastToolInfo(progressMessages: ProgressMessage<Progress>[], tools: Tools): string | null { |
| 789 | // Build tool_use lookup from all progress messages (needed for reverse iteration) |
| 790 | const toolUseByID = new Map<string, ToolUseBlockParam>(); |
| 791 | for (const pm of progressMessages) { |
| 792 | if (!hasProgressMessage(pm.data)) { |
| 793 | continue; |
| 794 | } |
| 795 | if (pm.data.message.type === 'assistant') { |
| 796 | for (const c of pm.data.message.message.content) { |
| 797 | if (c.type === 'tool_use') { |
| 798 | toolUseByID.set(c.id, c as ToolUseBlockParam); |
| 799 | } |
| 800 | } |
| 801 | } |
| 802 | } |
| 803 | |
| 804 | // Count trailing consecutive search/read operations from the end |
| 805 | let searchCount = 0; |
| 806 | let readCount = 0; |
| 807 | for (let i = progressMessages.length - 1; i >= 0; i--) { |
| 808 | const msg = progressMessages[i]!; |
| 809 | if (!hasProgressMessage(msg.data)) { |
| 810 | continue; |
| 811 | } |
| 812 | const info = getSearchOrReadInfo(msg, tools, toolUseByID); |
| 813 | if (info && (info.isSearch || info.isRead)) { |
| 814 | // Only count tool_result messages to avoid double counting |
| 815 | if (msg.data.message.type === 'user') { |
| 816 | if (info.isSearch) { |
| 817 | searchCount++; |
| 818 | } else if (info.isRead) { |
| 819 | readCount++; |
| 820 | } |
| 821 | } |
| 822 | } else { |
| 823 | break; |
| 824 | } |
| 825 | } |
| 826 | if (searchCount + readCount >= 2) { |
| 827 | return getSearchReadSummaryText(searchCount, readCount, true); |
| 828 | } |
| 829 | |
| 830 | // Find the last tool_result message |
| 831 | const lastToolResult = progressMessages.findLast((msg): msg is ProgressMessage<AgentToolProgress> => { |
| 832 | if (!hasProgressMessage(msg.data)) { |
| 833 | return false; |
| 834 | } |
| 835 | const message = msg.data.message; |
| 836 | return message.type === 'user' && message.message.content.some(c => c.type === 'tool_result'); |
| 837 | }); |
| 838 | if (lastToolResult?.data.message.type === 'user') { |
| 839 | const toolResultBlock = lastToolResult.data.message.message.content.find(c => c.type === 'tool_result'); |
| 840 | if (toolResultBlock?.type === 'tool_result') { |
| 841 | // Look up the corresponding tool_use — already indexed above |
| 842 | const toolUseBlock = toolUseByID.get(toolResultBlock.tool_use_id); |
| 843 | if (toolUseBlock) { |
| 844 | const tool = findToolByName(tools, toolUseBlock.name); |
| 845 | if (!tool) { |
no test coverage detected