Skip to content

Commit 7df6b95

Browse files
committed
feat(tarko-agent-ui): add clickable url links in terminal renderer json output
1 parent 2fb6c8f commit 7df6b95

File tree

1 file changed

+73
-2
lines changed

1 file changed

+73
-2
lines changed

multimodal/tarko/agent-ui/src/standalone/workspace/renderers/TerminalRenderer.tsx

Lines changed: 73 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,39 @@ interface TerminalRendererProps {
1111
displayMode?: FileDisplayMode;
1212
}
1313

14+
/**
15+
* URL regex pattern to detect URLs in text
16+
*/
17+
const URL_REGEX = /(https?:\/\/[^\s<>"{}|\\^`\[\]]+)/g;
18+
19+
/**
20+
* Convert text with URLs to JSX with clickable links
21+
*/
22+
function linkifyText(text: string): React.ReactNode {
23+
if (!text || typeof text !== 'string') {
24+
return text;
25+
}
26+
27+
const parts = text.split(URL_REGEX);
28+
return parts.map((part, index) => {
29+
if (URL_REGEX.test(part)) {
30+
return (
31+
<a
32+
key={index}
33+
href={part}
34+
target="_blank"
35+
rel="noopener noreferrer"
36+
className="text-blue-400 hover:text-blue-300 underline cursor-pointer"
37+
onClick={(e) => e.stopPropagation()}
38+
>
39+
{part}
40+
</a>
41+
);
42+
}
43+
return part;
44+
});
45+
}
46+
1447
/**
1548
* Format tool arguments as JSON string
1649
*/
@@ -21,6 +54,44 @@ function formatArguments(args: Record<string, any>): string {
2154
return JSON.stringify(args, null, 2);
2255
}
2356

57+
/**
58+
* Custom CodeHighlight wrapper that makes URLs clickable in JSON
59+
*/
60+
function CodeHighlightWithLinks({ code, language }: { code: string; language: string }) {
61+
const [processedCode, setProcessedCode] = React.useState<string>(code);
62+
63+
React.useEffect(() => {
64+
if (language === 'json') {
65+
// Replace URLs in JSON strings with clickable links
66+
const urlRegex = /"(https?:\/\/[^"\s]+)"/g;
67+
const linkedCode = code.replace(urlRegex, (match, url) => {
68+
return `"<span class='json-url-link text-blue-400 hover:text-blue-300 underline cursor-pointer' data-url='${url}'>${url}</span>"`;
69+
});
70+
setProcessedCode(linkedCode);
71+
} else {
72+
setProcessedCode(code);
73+
}
74+
}, [code, language]);
75+
76+
const handleClick = React.useCallback((e: React.MouseEvent) => {
77+
const target = e.target as HTMLElement;
78+
if (target.classList.contains('json-url-link')) {
79+
e.preventDefault();
80+
e.stopPropagation();
81+
const url = target.getAttribute('data-url');
82+
if (url) {
83+
window.open(url, '_blank', 'noopener,noreferrer');
84+
}
85+
}
86+
}, []);
87+
88+
return (
89+
<div onClick={handleClick}>
90+
<CodeHighlight code={processedCode} language={language} />
91+
</div>
92+
);
93+
}
94+
2495
/**
2596
* Format tool output as JSON string when applicable
2697
*/
@@ -139,14 +210,14 @@ export const TerminalRenderer: React.FC<TerminalRendererProps> = ({
139210
{/* Arguments section */}
140211
{argumentsJson && (
141212
<div className="p-3 pb-0 bg-[#121212] rounded m-3 mb-0 max-h-[40vh] overflow-auto">
142-
<CodeHighlight code={argumentsJson} language="json" />
213+
<CodeHighlightWithLinks code={argumentsJson} language="json" />
143214
</div>
144215
)}
145216

146217
{/* Output section */}
147218
{output && (
148219
<div className="p-3 bg-[#121212] rounded m-3 max-h-[80vh] overflow-auto">
149-
<CodeHighlight code={output} language="json" />
220+
<CodeHighlightWithLinks code={output} language="json" />
150221
</div>
151222
)}
152223
</div>

0 commit comments

Comments
 (0)