diff --git a/ui/desktop/src/components/GooseMessage.tsx b/ui/desktop/src/components/GooseMessage.tsx index 66c58074a414..cbcf47fee236 100644 --- a/ui/desktop/src/components/GooseMessage.tsx +++ b/ui/desktop/src/components/GooseMessage.tsx @@ -10,6 +10,7 @@ import { getToolResponses, getToolConfirmationContent, getElicitationContent, + getPendingToolConfirmationIds, NotificationEvent, } from '../types/message'; import { Message } from '../api'; @@ -99,6 +100,8 @@ export default function GooseMessage({ return responseMap; }, [messages, messageIndex, toolRequests]); + const pendingConfirmationIds = getPendingToolConfirmationIds(messages); + return (
@@ -157,6 +160,7 @@ export default function GooseMessage({ toolResponse={toolResponsesMap.get(toolRequest.id)} notifications={toolCallNotifications.get(toolRequest.id)} isStreamingMessage={isStreaming} + isPendingApproval={pendingConfirmationIds.has(toolRequest.id)} append={append} />
diff --git a/ui/desktop/src/components/ToolCallWithResponse.tsx b/ui/desktop/src/components/ToolCallWithResponse.tsx index bfe8baeab788..58ba03be3a8f 100644 --- a/ui/desktop/src/components/ToolCallWithResponse.tsx +++ b/ui/desktop/src/components/ToolCallWithResponse.tsx @@ -55,6 +55,7 @@ interface ToolCallWithResponseProps { toolResponse?: ToolResponseMessageContent; notifications?: NotificationEvent[]; isStreamingMessage?: boolean; + isPendingApproval: boolean; append?: (value: string) => void; } @@ -106,10 +107,8 @@ function McpAppWrapper({ ? requestWithMeta.toolCall.value.arguments : undefined; - // Memoize toolInput to prevent unnecessary re-renders const toolInput = useMemo(() => ({ arguments: toolArguments || {} }), [toolArguments]); - // Memoize toolResult to prevent unnecessary re-renders const toolResult = useMemo(() => { if (!toolResponse) return undefined; const resultWithMeta = toolResponse.toolResult as ToolResultWithMeta; @@ -149,6 +148,7 @@ export default function ToolCallWithResponse({ toolResponse, notifications, isStreamingMessage, + isPendingApproval, append, }: ToolCallWithResponseProps) { // Handle both the wrapped ToolResult format and the unwrapped format @@ -169,6 +169,8 @@ export default function ToolCallWithResponse({ requestWithMeta._meta?.ui?.resourceUri || resultWithMeta?.value?._meta?.ui?.resourceUri ); + const shouldShowMcpContent = !isPendingApproval; + return ( <>
{/* MCP UI — Inline */} - {!hasMcpAppResourceURI && + {shouldShowMcpContent && + !hasMcpAppResourceURI && toolResponse?.toolResult && getToolResultContent(toolResponse.toolResult).map((content, index) => { const resourceContent = isEmbeddedResource(content) @@ -210,7 +213,8 @@ export default function ToolCallWithResponse({ } })} - {hasMcpAppResourceURI && sessionId && ( + {/* MCP App */} + {shouldShowMcpContent && hasMcpAppResourceURI && sessionId && ( = ({ isCancelledMessage={ toolResponsesMap.get(toolRequest.id) == undefined } + isPendingApproval={false} key={toolRequest.id} toolRequest={toolRequest} toolResponse={toolResponsesMap.get(toolRequest.id)} diff --git a/ui/desktop/src/types/message.ts b/ui/desktop/src/types/message.ts index fcb9b0cbd271..ba4425fddeaf 100644 --- a/ui/desktop/src/types/message.ts +++ b/ui/desktop/src/types/message.ts @@ -73,6 +73,39 @@ export function getToolConfirmationContent( ); } +export function getToolConfirmationId( + content: ActionRequired & { type: 'actionRequired' } +): string | undefined { + if (content.data.actionType === 'toolConfirmation') { + return content.data.id; + } + return undefined; +} + +export function getPendingToolConfirmationIds(messages: Message[]): Set { + const pendingIds = new Set(); + const respondedIds = new Set(); + + for (const message of messages) { + const responses = getToolResponses(message); + for (const response of responses) { + respondedIds.add(response.id); + } + } + + for (const message of messages) { + const confirmation = getToolConfirmationContent(message); + if (confirmation) { + const confirmationId = getToolConfirmationId(confirmation); + if (confirmationId && !respondedIds.has(confirmationId)) { + pendingIds.add(confirmationId); + } + } + } + + return pendingIds; +} + export function getElicitationContent( message: Message ): (ActionRequired & { type: 'actionRequired' }) | undefined {