feat: improved UX for tool calls via execute_code (#6205)
This commit is contained in:
@@ -17,6 +17,12 @@ import MCPUIResourceRenderer from './MCPUIResourceRenderer';
|
||||
import { isUIResource } from '@mcp-ui/client';
|
||||
import { CallToolResponse, Content, EmbeddedResource } from '../api';
|
||||
|
||||
interface ToolGraphNode {
|
||||
tool: string;
|
||||
description: string;
|
||||
depends_on: number[];
|
||||
}
|
||||
|
||||
interface ToolCallWithResponseProps {
|
||||
isCancelledMessage: boolean;
|
||||
toolRequest: ToolRequestMessageContent;
|
||||
@@ -410,6 +416,20 @@ function ToolCallView({
|
||||
case 'computer_control':
|
||||
return `poking around...`;
|
||||
|
||||
case 'execute_code': {
|
||||
const toolGraph = args.tool_graph as unknown as ToolGraphNode[] | undefined;
|
||||
if (toolGraph && Array.isArray(toolGraph) && toolGraph.length > 0) {
|
||||
if (toolGraph.length === 1) {
|
||||
return `${toolGraph[0].description}`;
|
||||
}
|
||||
if (toolGraph.length === 2) {
|
||||
return `${toolGraph[0].tool}, ${toolGraph[1].tool}`;
|
||||
}
|
||||
return `${toolGraph.length} tools used`;
|
||||
}
|
||||
return 'executing code';
|
||||
}
|
||||
|
||||
default: {
|
||||
// Generic fallback for unknown tools: ToolName + CompactArguments
|
||||
// This ensures any MCP tool works without explicit handling
|
||||
@@ -489,12 +509,34 @@ function ToolCallView({
|
||||
)
|
||||
}
|
||||
>
|
||||
{/* Tool Details */}
|
||||
{isToolDetails && (
|
||||
<div className="border-t border-borderSubtle">
|
||||
<ToolDetailsView toolCall={toolCall} isStartExpanded={isExpandToolDetails} />
|
||||
</div>
|
||||
)}
|
||||
{(() => {
|
||||
const toolName = toolCall.name.substring(toolCall.name.lastIndexOf('__') + 2);
|
||||
const toolGraph = toolCall.arguments?.tool_graph as unknown as ToolGraphNode[] | undefined;
|
||||
const code = toolCall.arguments?.code as unknown as string | undefined;
|
||||
const hasToolGraph =
|
||||
toolName === 'execute_code' &&
|
||||
toolGraph &&
|
||||
Array.isArray(toolGraph) &&
|
||||
toolGraph.length > 0;
|
||||
|
||||
if (hasToolGraph) {
|
||||
return (
|
||||
<div className="border-t border-borderSubtle">
|
||||
<ToolGraphView toolGraph={toolGraph} code={code} />
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
if (isToolDetails) {
|
||||
return (
|
||||
<div className="border-t border-borderSubtle">
|
||||
<ToolDetailsView toolCall={toolCall} isStartExpanded={isExpandToolDetails} />
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
return null;
|
||||
})()}
|
||||
|
||||
{logs && logs.length > 0 && (
|
||||
<div className="border-t border-borderSubtle">
|
||||
@@ -553,6 +595,45 @@ function ToolDetailsView({ toolCall, isStartExpanded }: ToolDetailsViewProps) {
|
||||
);
|
||||
}
|
||||
|
||||
interface ToolGraphViewProps {
|
||||
toolGraph: ToolGraphNode[];
|
||||
code?: string;
|
||||
}
|
||||
|
||||
function ToolGraphView({ toolGraph, code }: ToolGraphViewProps) {
|
||||
const renderGraph = () => {
|
||||
if (toolGraph.length === 0) return null;
|
||||
|
||||
const lines: string[] = [];
|
||||
|
||||
toolGraph.forEach((node, index) => {
|
||||
const deps =
|
||||
node.depends_on.length > 0 ? ` (uses ${node.depends_on.map((d) => d + 1).join(', ')})` : '';
|
||||
lines.push(`${index + 1}. ${node.tool}: ${node.description}${deps}`);
|
||||
});
|
||||
|
||||
return lines.join('\n');
|
||||
};
|
||||
|
||||
return (
|
||||
<div className="px-4 py-2">
|
||||
<pre className="font-mono text-xs text-textSubtle whitespace-pre-wrap">{renderGraph()}</pre>
|
||||
{code && (
|
||||
<div className="border-t border-borderSubtle -mx-4 mt-2">
|
||||
<ToolCallExpandable
|
||||
label={<span className="pl-4 font-sans text-sm">Code</span>}
|
||||
isStartExpanded={false}
|
||||
>
|
||||
<pre className="font-mono text-xs text-textSubtle whitespace-pre-wrap overflow-x-auto px-4 py-2">
|
||||
{code}
|
||||
</pre>
|
||||
</ToolCallExpandable>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
interface ToolResultViewProps {
|
||||
result: Content;
|
||||
isStartExpanded: boolean;
|
||||
|
||||
Reference in New Issue
Block a user