File size: 4,902 Bytes
67c7241
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
import React from "react";
import { ToolViewProps } from "./types";
import { formatTimestamp, getToolTitle } from "./utils";
import { getToolIcon } from "../utils";
import { CircleDashed, CheckCircle, AlertTriangle } from "lucide-react";
import { Markdown } from "@/components/ui/markdown";
import { cn } from "@/lib/utils";

export function GenericToolView({ 
  name = 'unknown', 
  assistantContent, 
  toolContent, 
  isSuccess = true, 
  isStreaming = false,
  assistantTimestamp, 
  toolTimestamp 
}: ToolViewProps) {
  console.log('GenericToolView:', { 
    name, 
    assistantContent, 
    toolContent, 
    isSuccess, 
    isStreaming, 
    assistantTimestamp, 
    toolTimestamp 
  });
  
  const toolTitle = getToolTitle(name);
  const Icon = getToolIcon(name);
  
  // Format content for display
  const formatContent = (content: string | null) => {
    if (!content) return null;
    
    try {
      // Try to parse as JSON for pretty formatting
      const parsedJson = JSON.parse(content);
      return JSON.stringify(parsedJson, null, 2);
    } catch (e) {
      // If not valid JSON, return as is
      return content;
    }
  };
  
  // Format the contents
  const formattedAssistantContent = React.useMemo(() => formatContent(assistantContent), [assistantContent]);
  const formattedToolContent = React.useMemo(() => formatContent(toolContent), [toolContent]);
  
  return (
    <div className="flex flex-col h-full">
      <div className="flex-1 p-4 overflow-auto">
        {/* Assistant Content */}
        {assistantContent && !isStreaming && (
          <div className="space-y-1.5">
            <div className="flex justify-between items-center">
              <div className="text-xs font-medium text-zinc-500 dark:text-zinc-400">Input</div>
              {assistantTimestamp && (
                <div className="text-xs text-zinc-500 dark:text-zinc-400">{formatTimestamp(assistantTimestamp)}</div>
              )}
            </div>
            <div className="rounded-md border border-zinc-200 dark:border-zinc-800 bg-zinc-50 dark:bg-zinc-900 p-3">
              <Markdown className="text-xs text-zinc-800 dark:text-zinc-300">{formattedAssistantContent}</Markdown>
            </div>
          </div>
        )}
        
        {/* Tool Result */}
        {toolContent && (
          <div className="space-y-1.5 mt-4">
            <div className="flex justify-between items-center">
              <div className="text-xs font-medium text-zinc-500 dark:text-zinc-400">
                {isStreaming ? "Processing" : "Output"}
              </div>
              {toolTimestamp && !isStreaming && (
                <div className="text-xs text-zinc-500 dark:text-zinc-400">{formatTimestamp(toolTimestamp)}</div>
              )}
            </div>
            <div className={cn(
              "rounded-md border p-3",
              isStreaming 
                ? 'border-blue-200 bg-blue-50 dark:border-blue-800 dark:bg-blue-900/10' 
                : isSuccess 
                  ? 'border-zinc-200 bg-zinc-50 dark:border-zinc-800 dark:bg-zinc-900' 
                  : 'border-red-200 bg-red-50 dark:border-red-800 dark:bg-red-900/10'
            )}>
              {isStreaming ? (
                <div className="flex items-center gap-2 text-xs font-medium text-blue-700 dark:text-blue-400">
                  <CircleDashed className="h-3 w-3 animate-spin" />
                  <span>Executing {toolTitle.toLowerCase()}...</span>
                </div>
              ) : (
                <Markdown className="text-xs text-zinc-800 dark:text-zinc-300">{formattedToolContent}</Markdown>
              )}
            </div>
          </div>
        )}
      </div>
      
      {/* Footer */}
      <div className="p-4 border-t border-zinc-200 dark:border-zinc-800">
        <div className="flex items-center justify-between text-xs text-zinc-500 dark:text-zinc-400">
          {!isStreaming && (
            <div className="flex items-center gap-2">
              {isSuccess ? (
                <CheckCircle className="h-3.5 w-3.5 text-emerald-500" />
              ) : (
                <AlertTriangle className="h-3.5 w-3.5 text-red-500" />
              )}
              <span>
                {isSuccess ? 'Completed successfully' : 'Execution failed'}
              </span>
            </div>
          )}
          
          {isStreaming && (
            <div className="flex items-center gap-2">
              <CircleDashed className="h-3.5 w-3.5 text-blue-500 animate-spin" />
              <span>Processing...</span>
            </div>
          )}
          
          <div className="text-xs">
            {toolTimestamp && !isStreaming 
              ? formatTimestamp(toolTimestamp) 
              : assistantTimestamp 
                ? formatTimestamp(assistantTimestamp)
                : ''}
          </div>
        </div>
      </div>
    </div>
  );
}