feat: integrate tool call icons with status indicators and daisy chaining (#4279)

Co-authored-by: dianed-square <73617011+dianed-square@users.noreply.github.com>
Co-authored-by: Zane <75694352+zanesq@users.noreply.github.com>
Co-authored-by: Taylor Ho <taylorkmho@gmail.com>
This commit is contained in:
Spence
2025-08-29 08:39:38 -04:00
committed by GitHub
parent 7599a3e56b
commit 69c29a0870
24 changed files with 920 additions and 73 deletions
@@ -1,12 +1,14 @@
import { ToolIconWithStatus, ToolCallStatus } from './ToolCallStatusIndicator';
import { getToolCallIcon } from '../utils/toolIconMapping';
import React, { useEffect, useRef, useState } from 'react';
import { Button } from './ui/button';
import { ToolCallArguments, ToolCallArgumentValue } from './ToolCallArguments';
import MarkdownContent from './MarkdownContent';
import { Content, ToolRequestMessageContent, ToolResponseMessageContent } from '../types/message';
import { cn, snakeToTitleCase } from '../utils';
import Dot, { LoadingStatus } from './ui/Dot';
import { LoadingStatus } from './ui/Dot';
import { NotificationEvent } from '../hooks/useMessageStream';
import { ChevronRight, FlaskConical, LoaderCircle } from 'lucide-react';
import { ChevronRight, FlaskConical } from 'lucide-react';
import { TooltipWrapper } from './settings/providers/subcomponents/buttons/TooltipWrapper';
import MCPUIResourceRenderer from './MCPUIResourceRenderer';
import { isUIResource } from '@mcp-ui/client';
@@ -173,16 +175,13 @@ function ToolCallView({
}: ToolCallViewProps) {
const [responseStyle, setResponseStyle] = useState(() => localStorage.getItem('response_style'));
// Listen for localStorage changes to update the response style
useEffect(() => {
const handleStorageChange = () => {
setResponseStyle(localStorage.getItem('response_style'));
};
// Listen for storage events (changes from other tabs/windows)
window.addEventListener('storage', handleStorageChange);
// Listen for custom events (changes from same tab)
window.addEventListener('responseStyleChanged', handleStorageChange);
return () => {
@@ -283,12 +282,10 @@ function ToolCallView({
const args = toolCall.arguments as Record<string, ToolCallArgumentValue>;
const toolName = toolCall.name.substring(toolCall.name.lastIndexOf('__') + 2);
// Helper function to get string value safely
const getStringValue = (value: ToolCallArgumentValue): string => {
return typeof value === 'string' ? value : JSON.stringify(value);
};
// Helper function to truncate long values
const truncate = (str: string, maxLength: number = 50): string => {
return str.length > maxLength ? str.substring(0, maxLength) + '...' : str;
};
@@ -442,34 +439,45 @@ function ToolCallView({
// Fallback tool name formatting
return snakeToTitleCase(toolCall.name.substring(toolCall.name.lastIndexOf('__') + 2));
};
// Map LoadingStatus to ToolCallStatus
const getToolCallStatus = (loadingStatus: LoadingStatus): ToolCallStatus => {
switch (loadingStatus) {
case 'success':
return 'success';
case 'error':
return 'error';
case 'loading':
return 'loading';
default:
return 'pending';
}
};
const toolCallStatus = getToolCallStatus(loadingStatus);
const toolLabel = (
<span className={cn('ml-2', extensionTooltip && 'cursor-pointer hover:opacity-80')}>
{getToolLabelContent()}
<span
className={cn(
'flex items-center gap-2',
extensionTooltip && 'cursor-pointer hover:opacity-80'
)}
>
<ToolIconWithStatus ToolIcon={getToolCallIcon(toolCall.name)} status={toolCallStatus} />
<span>{getToolLabelContent()}</span>
</span>
);
return (
<ToolCallExpandable
isStartExpanded={isRenderingProgress}
isForceExpand={isShouldExpand}
label={
<>
<div className="w-2 flex items-center justify-center">
{loadingStatus === 'loading' ? (
<LoaderCircle className="animate-spin text-text-muted" size={3} />
) : (
<Dot size={2} loadingStatus={loadingStatus} />
)}
</div>
{extensionTooltip ? (
<TooltipWrapper tooltipContent={extensionTooltip} side="top" align="start">
{toolLabel}
</TooltipWrapper>
) : (
toolLabel
)}
</>
extensionTooltip ? (
<TooltipWrapper tooltipContent={extensionTooltip} side="top" align="start">
{toolLabel}
</TooltipWrapper>
) : (
toolLabel
)
}
>
{/* Tool Details */}