import { useEffect, useRef, useState } from 'react' import { AlertTriangle, Brain, CheckCircle2, ChevronDown, LoaderCircle, Wrench } from 'lucide-react' import { sanitizeAssistantText } from '../lib/chat' import type { ToolNestedEvent, ToolSegment } from '../types' import { AnimatedDisclosure } from './AnimatedDisclosure' import { StreamingMarkdown } from './StreamingMarkdown' interface ToolCallCardProps { activity: ToolSegment } function statusLabel(status: ToolSegment['status']): string { if (status === 'running') { return 'Running' } if (status === 'completed') { return 'Completed' } if (status === 'error') { return 'Failed' } return 'Queued' } function StatusIcon({ status }: { status: ToolSegment['status'] }) { if (status === 'running' || status === 'pending') { return } if (status === 'completed') { return } return } function nestedStatusLabel(status: ToolNestedEvent['status']): string { if (status === 'running') { return 'Running' } if (status === 'completed') { return 'Done' } if (status === 'error') { return 'Failed' } return 'Info' } function nestedEventVariant(event: ToolNestedEvent): string { const label = event.detailLabel.trim().toLowerCase() if (label === 'reasoning') { return 'reasoning' } if (label === 'response') { return 'response' } if (label === 'error') { return 'error' } if (label === 'result') { return 'result' } if (label === 'progress') { return 'progress' } return 'detail' } function isNarrativeNestedEvent(event: ToolNestedEvent): boolean { const variant = nestedEventVariant(event) return variant === 'response' || variant === 'reasoning' } function NestedToolCard({ event }: { event: ToolNestedEvent }) { const variant = nestedEventVariant(event) const isRunning = event.status === 'running' const [isOpen, setIsOpen] = useState(isRunning) const previousStatusRef = useRef(event.status) useEffect(() => { if (isRunning) { setIsOpen(true) } else if (previousStatusRef.current === 'running' && event.status !== 'running') { setIsOpen(false) } previousStatusRef.current = event.status }, [event.status, isRunning]) return ( {event.title}
{nestedStatusLabel(event.status)}
} summaryClassName="tool-nested-summary" > {event.argumentsPreview ? (
Arguments
{event.argumentsPreview}
) : null} {event.detailPreview ? (
{event.detailLabel}
{event.detailPreview}
) : null}
) } function InlineReasoningCard({ title, text, autoOpen }: { title: string; text: string; autoOpen: boolean }) { const [isOpen, setIsOpen] = useState(autoOpen) useEffect(() => { if (autoOpen) { setIsOpen(true) } }, [autoOpen]) return ( {title} } summaryClassName="reasoning-card-summary" > ) } export function ToolCallCard({ activity }: ToolCallCardProps) { const isRunning = activity.status === 'pending' || activity.status === 'running' const [isOpen, setIsOpen] = useState(isRunning) useEffect(() => { if (isRunning) { setIsOpen(true) } }, [isRunning]) return (
{statusLabel(activity.status)}
{activity.toolName}
} summaryClassName="tool-card-summary" > {activity.argumentsPreview ? (
Arguments
{activity.argumentsPreview}
) : null} {activity.nestedEvents.length ? (
Subagent Trace
{activity.nestedEvents.map((event) => { const variant = nestedEventVariant(event) if (isNarrativeNestedEvent(event)) { const rawText = variant === 'response' ? sanitizeAssistantText(event.detailPreview) : event.detailPreview.trim() if (!rawText) { return null } if (variant === 'reasoning') { return ( ) } return (
{event.title}
) } return })}
) : null} {activity.detailPreview ? (
{activity.status === 'error' ? 'Error' : 'Result'}
{activity.detailPreview}
) : null}
) }