// ***************************************************************************** // Copyright (C) 2025 EclipseSource GmbH. // // This program and the accompanying materials are made available under the // terms of the Eclipse Public License v. 2.0 which is available at // http://www.eclipse.org/legal/epl-2.0. // // This Source Code may also be made available under the following Secondary // Licenses when the conditions for such availability set forth in the Eclipse // Public License v. 2.0 are satisfied: GNU General Public License, version 2 // with the GNU Classpath Exception which is available at // https://www.gnu.org/software/classpath/license.html. // // SPDX-License-Identifier: EPL-2.0 OR GPL-2.0-only WITH Classpath-exception-2.0 // ***************************************************************************** import { ChatResponsePartRenderer } from '@theia/ai-chat-ui/lib/browser/chat-response-part-renderer'; import { ResponseNode } from '@theia/ai-chat-ui/lib/browser/chat-tree-view'; import { ChatResponseContent, ToolCallChatResponseContent } from '@theia/ai-chat/lib/common'; import { codicon } from '@theia/core/lib/browser'; import { injectable } from '@theia/core/shared/inversify'; import * as React from '@theia/core/shared/react'; import { ReactNode } from '@theia/core/shared/react'; import { ClaudeCodeToolCallChatResponseContent } from '../claude-code-tool-call-content'; import { CollapsibleToolRenderer } from './collapsible-tool-renderer'; import { nls } from '@theia/core'; interface WebFetchToolInput { url: string; prompt: string; } @injectable() export class WebFetchToolRenderer implements ChatResponsePartRenderer { canHandle(response: ChatResponseContent): number { if (ClaudeCodeToolCallChatResponseContent.is(response) && response.name === 'WebFetch') { return 15; // Higher than default ToolCallPartRenderer (10) } return -1; } render(response: ToolCallChatResponseContent, parentNode: ResponseNode): ReactNode { try { const input = JSON.parse(response.arguments || '{}') as WebFetchToolInput; return ; } catch (error) { console.warn('Failed to parse WebFetch tool input:', error); return
{nls.localize('theia/ai/claude-code/failedToParseWebFetchToolData', 'Failed to parse WebFetch tool data')}
; } } } const WebFetchToolComponent: React.FC<{ input: WebFetchToolInput; }> = ({ input }) => { const getDomain = (url: string): string => { try { return new URL(url).hostname; } catch { return url; } }; const truncatePrompt = (prompt: string, maxLength: number = 100): string => { if (prompt.length <= maxLength) { return prompt; } return prompt.substring(0, maxLength) + '...'; }; const compactHeader = ( <>
{nls.localize('theia/ai/claude-code/fetching', 'Fetching')} {getDomain(input.url)} {truncatePrompt(input.prompt)}
{nls.localize('theia/ai/claude-code/webFetch', 'Web Fetch')}
); const expandedContent = (
{nls.localizeByDefault('URL')} {input.url}
{nls.localizeByDefault('Domain')} {getDomain(input.url)}
{nls.localizeByDefault('Prompt')} {input.prompt}
); return ( ); };