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 '../../components/design-system/Byline.js'; import { Message as MessageComponent } from '../../components/Message.js'; import { MessageResponse } from '../../components/MessageResponse.js'; import { Box, Text } from '../../ink.js'; 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 })} ; }