import React, { useState } from 'react'; import { Terminal, CheckCircle, AlertTriangle, CircleDashed, Clock, TerminalIcon, Play, Square, } from 'lucide-react'; import { ToolViewProps } from '../types'; import { formatTimestamp, getToolTitle } from '../utils'; import { cn } from '@/lib/utils'; import { useTheme } from 'next-themes'; import { Card, CardContent, CardHeader, CardTitle } from '@/components/ui/card'; import { Badge } from '@/components/ui/badge'; import { ScrollArea } from "@/components/ui/scroll-area"; import { LoadingState } from '../shared/LoadingState'; interface CheckCommandOutputData { sessionName: string | null; output: string | null; status: string | null; success: boolean; timestamp?: string; } function extractCheckCommandOutputData( assistantContent: any, toolContent: any, isSuccess: boolean, toolTimestamp?: string, assistantTimestamp?: string ): CheckCommandOutputData { let sessionName: string | null = null; let output: string | null = null; let status: string | null = null; let actualIsSuccess = isSuccess; let actualTimestamp = toolTimestamp || assistantTimestamp; // Parse content to extract data const parseContent = (content: any): any => { if (typeof content === 'string') { try { return JSON.parse(content); } catch (e) { return content; } } return content; }; // Try to extract from tool content first (most likely to have the result) const toolParsed = parseContent(toolContent); if (toolParsed && typeof toolParsed === 'object') { // Handle the case where content is a JSON string if (toolParsed.content && typeof toolParsed.content === 'string') { try { const contentParsed = JSON.parse(toolParsed.content); if (contentParsed.tool_execution) { const toolExecution = contentParsed.tool_execution; if (toolExecution.result && toolExecution.result.output) { if (typeof toolExecution.result.output === 'object') { // This is the nested format: { output: { output: "...", session_name: "...", status: "..." } } const nestedOutput = toolExecution.result.output; output = nestedOutput.output || null; sessionName = nestedOutput.session_name || null; status = nestedOutput.status || null; } else if (typeof toolExecution.result.output === 'string') { // Direct string output output = toolExecution.result.output; } actualIsSuccess = toolExecution.result.success !== undefined ? toolExecution.result.success : actualIsSuccess; } // Extract session name from arguments if not found in output if (!sessionName && toolExecution.arguments) { sessionName = toolExecution.arguments.session_name || null; } } } catch (e) { console.error('Failed to parse toolContent.content:', e); } } // Check for frontend_content first (this is the actual data structure) else if (toolParsed.frontend_content && toolParsed.frontend_content.tool_execution) { const toolExecution = toolParsed.frontend_content.tool_execution; if (toolExecution.result && toolExecution.result.output) { if (typeof toolExecution.result.output === 'object') { // This is the nested format: { output: { output: "...", session_name: "...", status: "..." } } const nestedOutput = toolExecution.result.output; output = nestedOutput.output || null; sessionName = nestedOutput.session_name || null; status = nestedOutput.status || null; } else if (typeof toolExecution.result.output === 'string') { // Direct string output output = toolExecution.result.output; } actualIsSuccess = toolExecution.result.success !== undefined ? toolExecution.result.success : actualIsSuccess; } // Extract session name from arguments if not found in output if (!sessionName && toolExecution.arguments) { sessionName = toolExecution.arguments.session_name || null; } } // Fallback to content.content structure else if (toolParsed.content && typeof toolParsed.content === 'object') { if (toolParsed.content.content && typeof toolParsed.content.content === 'string') { try { const contentParsed = JSON.parse(toolParsed.content.content); if (contentParsed.tool_execution) { const toolExecution = contentParsed.tool_execution; if (toolExecution.result && toolExecution.result.output) { if (typeof toolExecution.result.output === 'object') { const nestedOutput = toolExecution.result.output; output = nestedOutput.output || null; sessionName = nestedOutput.session_name || null; status = nestedOutput.status || null; } else if (typeof toolExecution.result.output === 'string') { output = toolExecution.result.output; } actualIsSuccess = toolExecution.result.success !== undefined ? toolExecution.result.success : actualIsSuccess; } if (!sessionName && toolExecution.arguments) { sessionName = toolExecution.arguments.session_name || null; } } } catch (e) { console.error('Failed to parse content.content:', e); } } } } // Fallback to assistant content if no data found in tool content if (!output && !sessionName) { const assistantParsed = parseContent(assistantContent); if (assistantParsed && typeof assistantParsed === 'object') { // Check for frontend_content first if (assistantParsed.frontend_content && assistantParsed.frontend_content.tool_execution) { const toolExecution = assistantParsed.frontend_content.tool_execution; if (toolExecution.result && toolExecution.result.output) { if (typeof toolExecution.result.output === 'object') { const nestedOutput = toolExecution.result.output; output = nestedOutput.output || null; sessionName = nestedOutput.session_name || null; status = nestedOutput.status || null; } else if (typeof toolExecution.result.output === 'string') { output = toolExecution.result.output; } } if (!sessionName && toolExecution.arguments) { sessionName = toolExecution.arguments.session_name || null; } } // Fallback to content.content structure else if (assistantParsed.content && typeof assistantParsed.content === 'object') { if (assistantParsed.content.content && typeof assistantParsed.content.content === 'string') { try { const contentParsed = JSON.parse(assistantParsed.content.content); if (contentParsed.tool_execution) { const toolExecution = contentParsed.tool_execution; if (toolExecution.result && toolExecution.result.output) { if (typeof toolExecution.result.output === 'object') { const nestedOutput = toolExecution.result.output; output = nestedOutput.output || null; sessionName = nestedOutput.session_name || null; status = nestedOutput.status || null; } else if (typeof toolExecution.result.output === 'string') { output = toolExecution.result.output; } } if (!sessionName && toolExecution.arguments) { sessionName = toolExecution.arguments.session_name || null; } } } catch (e) { console.error('Failed to parse assistant content.content:', e); } } } } } return { sessionName, output, status, success: actualIsSuccess, timestamp: actualTimestamp }; } export function CheckCommandOutputToolView({ name = 'check-command-output', assistantContent, toolContent, assistantTimestamp, toolTimestamp, isSuccess = true, isStreaming = false, }: ToolViewProps) { const { resolvedTheme } = useTheme(); const isDarkTheme = resolvedTheme === 'dark'; const [showFullOutput, setShowFullOutput] = useState(true); const { sessionName, output, status, success: actualIsSuccess, timestamp: actualTimestamp } = extractCheckCommandOutputData( assistantContent, toolContent, isSuccess, toolTimestamp, assistantTimestamp ); const toolTitle = getToolTitle(name); const formattedOutput = React.useMemo(() => { if (!output) return []; let processedOutput = output; // Handle case where output is already an object if (typeof output === 'object' && output !== null) { try { processedOutput = JSON.stringify(output, null, 2); } catch (e) { processedOutput = String(output); } } else if (typeof output === 'string') { // Try to parse as JSON first try { if (output.trim().startsWith('{') || output.trim().startsWith('[')) { const parsed = JSON.parse(output); if (parsed && typeof parsed === 'object') { // If it's a complex object, stringify it nicely processedOutput = JSON.stringify(parsed, null, 2); } else { processedOutput = String(parsed); } } else { processedOutput = output; } } catch (e) { // If parsing fails, use as plain text processedOutput = output; } } else { processedOutput = String(output); } // Clean up escape sequences processedOutput = processedOutput.replace(/\\\\/g, '\\'); processedOutput = processedOutput .replace(/\\n/g, '\n') .replace(/\\t/g, '\t') .replace(/\\"/g, '"') .replace(/\\'/g, "'"); processedOutput = processedOutput.replace(/\\u([0-9a-fA-F]{4})/g, (_match, group) => { return String.fromCharCode(parseInt(group, 16)); }); return processedOutput.split('\n'); }, [output]); const hasMoreLines = formattedOutput.length > 10; const previewLines = formattedOutput.slice(0, 10); const linesToShow = showFullOutput ? formattedOutput : previewLines; const isSessionRunning = status?.includes('still running') || status?.includes('running'); return (
{toolTitle}
{!isStreaming && ( {actualIsSuccess ? ( ) : ( )} {actualIsSuccess ? 'Output retrieved successfully' : 'Failed to retrieve output'} )}
{isStreaming ? ( ) : sessionName ? (
Terminal Session ({sessionName})
                                            {linesToShow.map((line, index) => (
                                                
{line}
))} {!showFullOutput && hasMoreLines && (
+ {formattedOutput.length - 10} more lines
)}
{!output && !isStreaming && (

No output received

)}
) : (

No Session Found

No session name was detected. Please provide a valid session name to check.

)}
{!isStreaming && sessionName && ( Session )}
{actualTimestamp && !isStreaming ? formatTimestamp(actualTimestamp) : ''}
); }