import type { ToolResultBlockParam } from '@anthropic-ai/sdk/resources/index.mjs' import * as React from 'react' import { SubAgentProvider } from 'src/components/CtrlOToExpand.js' import { FallbackToolUseErrorMessage } from 'src/components/FallbackToolUseErrorMessage.js' import { FallbackToolUseRejectedMessage } from 'src/components/FallbackToolUseRejectedMessage.js' import type { z } from 'zod/v4' import type { Command } from '../../commands.js' import { Byline } from '@anthropic/ink' import { Message as MessageComponent } from '../../components/Message.js' import { MessageResponse } from '../../components/MessageResponse.js' import { Box, Text } from '@anthropic/ink' import type { Tools } from '../../Tool.js' import type { ProgressMessage } from '../../types/message.js' import { buildSubagentLookups, EMPTY_LOOKUPS } from '../../utils/messages.js' import { plural } from '../../utils/stringUtils.js' import type { inputSchema, Output, Progress } from './SkillTool.js' type Input = z.infer> const MAX_PROGRESS_MESSAGES_TO_SHOW = 3 const INITIALIZING_TEXT = 'Initializing…' export function renderToolResultMessage(output: Output): React.ReactNode { // Handle forked skill result if ('status' in output && output.status === 'forked') { return ( {['Done']} ) } const parts: string[] = ['Successfully loaded skill'] // Show tools count (only for inline skills) if ( 'allowedTools' in output && output.allowedTools && output.allowedTools.length > 0 ) { const count = output.allowedTools.length parts.push(`${count} ${plural(count, 'tool')} allowed`) } // Show model if non-default (only for inline skills) if ('model' in output && output.model) { parts.push(output.model) } return ( {parts} ) } export function renderToolUseMessage( { skill }: Partial, { commands }: { commands?: Command[] }, ): React.ReactNode { if (!skill) { return null } // Look up the command to check if it came from the legacy /commands folder const command = commands?.find(c => c.name === skill) const displayName = command?.loadedFrom === 'commands_DEPRECATED' ? `/${skill}` : skill return displayName } export function renderToolUseProgressMessage( progressMessages: ProgressMessage[], { tools, verbose, }: { tools: Tools verbose: boolean }, ): React.ReactNode { if (!progressMessages.length) { return ( {INITIALIZING_TEXT} ) } // Take only the last few messages for display in non-verbose mode const displayedMessages = verbose ? progressMessages : progressMessages.slice(-MAX_PROGRESS_MESSAGES_TO_SHOW) const hiddenCount = progressMessages.length - displayedMessages.length const { inProgressToolUseIDs } = buildSubagentLookups( progressMessages.map(pm => pm.data), ) return ( {displayedMessages.map(progressMessage => ( ))} {hiddenCount > 0 && ( +{hiddenCount} more tool {plural(hiddenCount, 'use')} )} ) } export function renderToolUseRejectedMessage( _input: Input, { progressMessagesForMessage, tools, verbose, }: { progressMessagesForMessage: ProgressMessage[] tools: Tools verbose: boolean }, ): React.ReactNode { return ( <> {renderToolUseProgressMessage(progressMessagesForMessage, { tools, verbose, })} ) } export function renderToolUseErrorMessage( result: ToolResultBlockParam['content'], { progressMessagesForMessage, tools, verbose, }: { progressMessagesForMessage: ProgressMessage[] tools: Tools verbose: boolean }, ): React.ReactNode { return ( <> {renderToolUseProgressMessage(progressMessagesForMessage, { tools, verbose, })} ) }