'use client'; import { useState } from 'react'; import { IconChevronDown, IconChevronRight, IconTool } from '@tabler/icons-react'; import { ActionIcon, Code, Collapse, Group, Paper, Text, useMantineTheme } from '@mantine/core'; import { useThemeContext } from '@/components/DynamicThemeProvider'; import classes from './ToolCallDisplay.module.css'; export interface ToolCall { toolName: string; args: Record; result: string; } interface ToolCallDisplayProps { toolName: string; args: Record; result: string; nested?: boolean; } interface ToolCallGroupProps { toolCalls: ToolCall[]; } // Friendly tool names const toolDisplayNames: Record = { calculator: 'Calculator', get_current_datetime: 'Date/Time', fetch_url: 'Fetch URL', web_search: 'Web Search', execute_code: 'Code Execution', read_file: 'Read File', write_file: 'Write File', get_weather: 'Weather', generate_image: 'Image Generation', }; function getDisplayName(toolName: string): string { return toolDisplayNames[toolName] || toolName; } /** * Display a single tool call (can be standalone or nested inside a group) */ export function ToolCallDisplay({ toolName, args, result, nested = false }: ToolCallDisplayProps) { const [opened, setOpened] = useState(false); const { primaryColor } = useThemeContext(); const theme = useMantineTheme(); const displayName = getDisplayName(toolName); const isError = result.startsWith('Error:'); // Format args for display const argsDisplay = Object.entries(args) .map(([key, value]) => `${key}: ${JSON.stringify(value)}`) .join(', '); const containerClass = nested ? classes.nestedContainer : classes.container; const headerClass = nested ? classes.nestedHeader : classes.header; const contentClass = nested ? classes.nestedContent : classes.content; return ( setOpened(!opened)} gap="xs" wrap="nowrap" p="xs" style={{ cursor: 'pointer' }} > {opened ? : } {displayName} {!opened && argsDisplay && ( {argsDisplay} )}
{Object.keys(args).length > 0 && (
Arguments: {JSON.stringify(args, null, 2)}
)}
Result: {result}
); } /** * Display a group of consecutive tool calls in a single collapsible container */ export function ToolCallGroup({ toolCalls }: ToolCallGroupProps) { const [opened, setOpened] = useState(false); const { primaryColor } = useThemeContext(); const theme = useMantineTheme(); if (toolCalls.length === 0) { return null; } // If only one tool call, render it directly without the group wrapper if (toolCalls.length === 1) { const tc = toolCalls[0]; return ; } // Get summary of tool names const toolNames = toolCalls.map((tc) => getDisplayName(tc.toolName)); const uniqueTools = Array.from(new Set(toolNames)); const summary = uniqueTools.length <= 2 ? uniqueTools.join(', ') : `${uniqueTools.slice(0, 2).join(', ')} +${uniqueTools.length - 2} more`; return ( setOpened(!opened)} gap="xs" wrap="nowrap" p="xs" style={{ cursor: 'pointer' }} > {opened ? : } {toolCalls.length} Tool Calls {summary}
{toolCalls.map((tc, index) => ( ))}
); }