import React, { useMemo } from 'react'; import { Puzzle } from 'lucide-react-native'; import type { SuperagentToolRendererProps } from '../../types'; import { ToolWidgetRow } from '../primitives/ToolWidgetRow'; import { getFailureReason, getSuggestedSkillName, isDeclinedResolution } from '../skillsAndConnectionsUtils'; import { getSettledWidgetStatus, getStringArg, parseToolArgs } from '../toolWidgetUtils'; /** * suggest_skill_installation — settled states of the web * SuggestSkillInstallation card. The install/dismiss form (waiting state) * stays with the timeline's ToolApprovalCard. */ export function SuggestSkillInstallationWidget({ isLastAssistantMessage, toolCall }: SuperagentToolRendererProps) { const args = useMemo(() => parseToolArgs(toolCall), [toolCall]); // Settled status keeps stale rows on old turns from spinning forever. const status = getSettledWidgetStatus(toolCall, isLastAssistantMessage); // Always render a chip — web parity: SuggestSkillInstallation shows // `skill.displayName || query`, where query itself falls back to 'skill'. A // declined suggestion with no enriched skill/query args must still read as // "Suggested skill · skill · dismissed", never an empty row. const chipText = getSuggestedSkillName(args) || getStringArg(args, ['query']) || 'skill'; // error means the search/install actually failed (no catalog match, store // load error, approved install failed) — never a dismissal (stopped). const title = status === 'running' ? 'Searching skills for' : status === 'success' ? 'Installed skill' : status === 'error' ? 'Skill suggestion failed' : 'Suggested skill'; const dismissed = isDeclinedResolution(status, toolCall); return ( ); }