diff --git a/frontend/src/components/thread/tool-call-side-panel.tsx b/frontend/src/components/thread/tool-call-side-panel.tsx index 9ac62a30..cc255e12 100644 --- a/frontend/src/components/thread/tool-call-side-panel.tsx +++ b/frontend/src/components/thread/tool-call-side-panel.tsx @@ -1,10 +1,21 @@ import { Button } from "@/components/ui/button"; -import { X, SkipBack, SkipForward } from "lucide-react"; +import { X } from "lucide-react"; import { Project } from "@/lib/api"; import { getToolIcon } from "@/components/thread/utils"; import React from "react"; import { Slider } from "@/components/ui/slider"; +// 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 { CreateFileToolView } from "./tool-views/CreateFileToolView"; +import { FileRewriteToolView } from "./tool-views/FileRewriteToolView"; +import { DeleteFileToolView } from "./tool-views/DeleteFileToolView"; +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: { @@ -19,85 +30,119 @@ export interface ToolCallInput { }; } -// Helper function to format timestamp -function formatTimestamp(isoString?: string): string { - if (!isoString) return ''; - try { - const date = new Date(isoString); - return isNaN(date.getTime()) ? 'Invalid date' : date.toLocaleString(); - } catch (e) { - return 'Invalid date'; - } -} - -// Simplified generic tool view -function GenericToolView({ - name, - assistantContent, - toolContent, - isSuccess = true, - assistantTimestamp, - toolTimestamp -}: { - name?: string; - assistantContent?: string; - toolContent?: string; - isSuccess?: boolean; - assistantTimestamp?: string; - toolTimestamp?: string; -}) { - const toolName = name || 'Unknown Tool'; +// 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 +) { + if (!toolName) return null; - return ( -
-
-
-
- {React.createElement(getToolIcon(toolName), { className: "h-4 w-4" })} -
-
-

{toolName}

-
-
- - {toolContent && ( -
- {isSuccess ? 'Success' : 'Failed'} -
- )} -
+ const normalizedToolName = toolName.toLowerCase(); + + switch (normalizedToolName) { + case 'execute-command': + return ( + + ); + case 'str-replace': + return ( + + ); + case 'create-file': + return ( + + ); + case 'full-file-rewrite': + return ( + + ); + case 'delete-file': + return ( + + ); + case 'web-search': + return ( + + ); + case 'crawl-webpage': + return ( + + ); + default: + // Check if it's a browser operation + if (normalizedToolName.startsWith('browser-')) { + return ( + + ); + } - {/* Assistant Message */} -
-
-
Assistant Message
- {assistantTimestamp && ( -
{formatTimestamp(assistantTimestamp)}
- )} -
-
-
{assistantContent}
-
-
- - {/* Tool Result */} - {toolContent && ( -
-
-
Tool Result
- {toolTimestamp && ( -
{formatTimestamp(toolTimestamp)}
- )} -
-
-
{toolContent}
-
-
- )} -
- ); + // Fallback to generic view + return ( + + ); + } } interface ToolCallSidePanelProps { @@ -133,22 +178,22 @@ export function ToolCallSidePanel({ ); } - return ( - + // Get the specific tool view based on the tool name + return getToolView( + currentToolCall.assistantCall.name, + currentToolCall.assistantCall.content, + currentToolCall.toolResult?.content, + currentToolCall.assistantCall.timestamp, + currentToolCall.toolResult?.timestamp, + currentToolCall.toolResult?.isSuccess ?? true, + project ); }; return (
-

Tool Details

+

Suna's Computer

diff --git a/frontend/src/components/thread/tool-views/BrowserToolView.tsx b/frontend/src/components/thread/tool-views/BrowserToolView.tsx new file mode 100644 index 00000000..deca3911 --- /dev/null +++ b/frontend/src/components/thread/tool-views/BrowserToolView.tsx @@ -0,0 +1,110 @@ +import React from "react"; +import { Globe, MonitorPlay, ExternalLink, CheckCircle, AlertTriangle } from "lucide-react"; +import { BrowserToolViewProps } from "./types"; +import { extractBrowserUrl, extractBrowserOperation, formatTimestamp } from "./utils"; + +export function BrowserToolView({ + name, + assistantContent, + toolContent, + assistantTimestamp, + toolTimestamp, + isSuccess = true, + project +}: BrowserToolViewProps) { + const url = extractBrowserUrl(assistantContent); + const operation = extractBrowserOperation(name); + + // Check if we have a VNC preview URL from the project + const vncPreviewUrl = project?.sandbox?.vnc_preview ? + `${project.sandbox.vnc_preview}/vnc_lite.html?password=${project?.sandbox?.pass}` : + undefined; + + return ( +
+
+
+
+ +
+
+

{operation}

+
+
+ + {toolContent && ( +
+ {isSuccess ? 'Success' : 'Failed'} +
+ )} +
+ +
+
+
+ + Browser Window +
+ {url && ( +
+ {url} +
+ )} +
+ + {vncPreviewUrl ? ( +
+