'use client'; import { Project } from "@/lib/api"; import { getToolIcon } from "@/components/thread/utils"; import React from "react"; import { Slider } from "@/components/ui/slider"; import { ApiMessageType } from '@/components/thread/types'; import { CircleDashed } from "lucide-react"; import { cn } from "@/lib/utils"; // Import tool view components from the tool-views directory import { CommandToolView } from "./tool-views/CommandToolView"; import { StrReplaceToolView } from "./tool-views/StrReplaceToolView"; import { GenericToolView } from "./tool-views/GenericToolView"; import { FileOperationToolView } from "./tool-views/FileOperationToolView"; import { BrowserToolView } from "./tool-views/BrowserToolView"; import { WebSearchToolView } from "./tool-views/WebSearchToolView"; import { WebCrawlToolView } from "./tool-views/WebCrawlToolView"; // Simple input interface export interface ToolCallInput { assistantCall: { content?: string; name?: string; timestamp?: string; }; toolResult?: { content?: string; isSuccess?: boolean; timestamp?: string; }; messages?: ApiMessageType[]; } // Get the specialized tool view component based on the tool name function getToolView( toolName: string | undefined, assistantContent: string | undefined, toolContent: string | undefined, assistantTimestamp: string | undefined, toolTimestamp: string | undefined, isSuccess: boolean = true, project?: Project, messages?: ApiMessageType[], agentStatus?: string, currentIndex?: number, totalCalls?: number, isStreaming?: boolean ) { if (!toolName) return null; const normalizedToolName = toolName.toLowerCase(); switch (normalizedToolName) { case 'execute-command': return ( ); case 'str-replace': return ( ); case 'create-file': case 'full-file-rewrite': case 'delete-file': return ( ); case 'browser-navigate': case 'browser-click': case 'browser-extract': case 'browser-fill': case 'browser-wait': return ( ); case 'web-search': return ( ); case 'web-crawl': return ( ); default: // Check if it's a browser operation if (normalizedToolName.startsWith('browser-')) { return ( ); } // Fallback to generic view return ( ); } } interface ToolCallSidePanelProps { isOpen: boolean; onClose: () => void; toolCalls: ToolCallInput[]; currentIndex: number; onNavigate: (newIndex: number) => void; messages?: ApiMessageType[]; agentStatus: string; project?: Project; renderAssistantMessage?: (assistantContent?: string, toolContent?: string) => React.ReactNode; renderToolResult?: (toolContent?: string, isSuccess?: boolean) => React.ReactNode; } export function ToolCallSidePanel({ isOpen, onClose, toolCalls, currentIndex, onNavigate, messages, agentStatus, project, renderAssistantMessage, renderToolResult }: ToolCallSidePanelProps) { // Move hooks outside of conditional const [dots, setDots] = React.useState(''); const currentToolCall = toolCalls[currentIndex]; const totalCalls = toolCalls.length; const currentToolName = currentToolCall?.assistantCall?.name || 'Tool Call'; const CurrentToolIcon = getToolIcon(currentToolName === 'Tool Call' ? 'unknown' : currentToolName); const isStreaming = currentToolCall?.toolResult?.content === "STREAMING"; const isSuccess = currentToolCall?.toolResult?.isSuccess ?? true; React.useEffect(() => { if (!isStreaming) return; // Create a loading animation with dots const interval = setInterval(() => { setDots(prev => { if (prev === '...') return ''; return prev + '.'; }); }, 500); return () => clearInterval(interval); }, [isStreaming]); if (!isOpen) return null; const renderContent = () => { if (!currentToolCall) { return (

No tool call details available.

); } const toolView = getToolView( currentToolCall.assistantCall.name, currentToolCall.assistantCall.content, currentToolCall.toolResult?.content, currentToolCall.assistantCall.timestamp, currentToolCall.toolResult?.timestamp, isStreaming ? true : (currentToolCall.toolResult?.isSuccess ?? true), project, messages, agentStatus, currentIndex, totalCalls, isStreaming ); if (!toolView) return null; return (

Suna's Computer

{/*
{currentToolName} */}
{currentToolCall.toolResult?.content && !isStreaming && (
{currentToolName}
{isSuccess ? 'Success' : 'Failed'}
)} {isStreaming && (
Running
)}
{toolView}
); }; return (
{renderContent()}
{totalCalls > 1 && (
{currentToolName} {isStreaming && `(Running${dots})`}
Step {currentIndex + 1} of {totalCalls}
onNavigate(newValue)} className="w-full [&>span:first-child]:h-1 [&>span:first-child]:bg-zinc-200 dark:[&>span:first-child]:bg-zinc-800 [&>span:first-child>span]:bg-zinc-500 dark:[&>span:first-child>span]:bg-zinc-400 [&>span:first-child>span]:h-1" />
)}
); }