1import React, { useState } from "react";
2import { LLMContent } from "../types";
3
4interface BrowserNavigateToolProps {
5 toolInput?: unknown; // { url: string }
6 isRunning?: boolean;
7 toolResult?: LLMContent[];
8 hasError?: boolean;
9 executionTime?: string;
10}
11
12function BrowserNavigateTool({
13 toolInput,
14 isRunning,
15 toolResult,
16 hasError,
17 executionTime,
18}: BrowserNavigateToolProps) {
19 const [isExpanded, setIsExpanded] = useState(false);
20
21 // Extract URL from toolInput
22 const url =
23 typeof toolInput === "object" &&
24 toolInput !== null &&
25 "url" in toolInput &&
26 typeof toolInput.url === "string"
27 ? toolInput.url
28 : typeof toolInput === "string"
29 ? toolInput
30 : "";
31
32 // Extract output from toolResult
33 const output =
34 toolResult && toolResult.length > 0 && toolResult[0].Text ? toolResult[0].Text : "";
35
36 // Truncate URL for display
37 const truncateUrl = (urlStr: string, maxLen: number = 300) => {
38 if (urlStr.length <= maxLen) return urlStr;
39 return urlStr.substring(0, maxLen) + "...";
40 };
41
42 const displayUrl = truncateUrl(url);
43 const isComplete = !isRunning && toolResult !== undefined;
44
45 return (
46 <div className="tool" data-testid={isComplete ? "tool-call-completed" : "tool-call-running"}>
47 <div className="tool-header" onClick={() => setIsExpanded(!isExpanded)}>
48 <div className="tool-summary">
49 <span className={`tool-emoji ${isRunning ? "running" : ""}`}>🌐</span>
50 <span className="tool-command">{displayUrl}</span>
51 {isComplete && hasError && <span className="tool-error">✗</span>}
52 {isComplete && !hasError && <span className="tool-success">✓</span>}
53 </div>
54 <button
55 className="tool-toggle"
56 aria-label={isExpanded ? "Collapse" : "Expand"}
57 aria-expanded={isExpanded}
58 >
59 <svg
60 width="12"
61 height="12"
62 viewBox="0 0 12 12"
63 fill="none"
64 xmlns="http://www.w3.org/2000/svg"
65 style={{
66 transform: isExpanded ? "rotate(90deg)" : "rotate(0deg)",
67 transition: "transform 0.2s",
68 }}
69 >
70 <path
71 d="M4.5 3L7.5 6L4.5 9"
72 stroke="currentColor"
73 strokeWidth="1.5"
74 strokeLinecap="round"
75 strokeLinejoin="round"
76 />
77 </svg>
78 </button>
79 </div>
80
81 {isExpanded && (
82 <div className="tool-details">
83 <div className="tool-section">
84 <div className="tool-label">URL:</div>
85 <div className="tool-code">
86 <a href={url} target="_blank" rel="noopener noreferrer">
87 {url}
88 </a>
89 </div>
90 </div>
91
92 {isComplete && output && (
93 <div className="tool-section">
94 <div className="tool-label">
95 Output{hasError ? " (Error)" : ""}:
96 {executionTime && <span className="tool-time">{executionTime}</span>}
97 </div>
98 <pre className={`tool-code ${hasError ? "error" : ""}`}>{output}</pre>
99 </div>
100 )}
101 </div>
102 )}
103 </div>
104 );
105}
106
107export default BrowserNavigateTool;