Dont show MCP UI/Apps until tool is approved (#6492)
Co-authored-by: Douwe Osinga <douwe@squareup.com>
This commit is contained in:
@@ -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 (
|
||||
<div className="goose-message flex w-[90%] justify-start min-w-0">
|
||||
<div className="flex flex-col w-full min-w-0">
|
||||
@@ -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}
|
||||
/>
|
||||
</div>
|
||||
|
||||
@@ -55,6 +55,7 @@ interface ToolCallWithResponseProps {
|
||||
toolResponse?: ToolResponseMessageContent;
|
||||
notifications?: NotificationEvent[];
|
||||
isStreamingMessage?: boolean;
|
||||
isPendingApproval: boolean;
|
||||
append?: (value: string) => void;
|
||||
}
|
||||
|
||||
@@ -110,10 +111,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;
|
||||
@@ -153,6 +152,7 @@ export default function ToolCallWithResponse({
|
||||
toolResponse,
|
||||
notifications,
|
||||
isStreamingMessage,
|
||||
isPendingApproval,
|
||||
append,
|
||||
}: ToolCallWithResponseProps) {
|
||||
// Handle both the wrapped ToolResult format and the unwrapped format
|
||||
@@ -173,6 +173,8 @@ export default function ToolCallWithResponse({
|
||||
requestWithMeta._meta?.ui?.resourceUri || resultWithMeta?.value?._meta?.ui?.resourceUri
|
||||
);
|
||||
|
||||
const shouldShowMcpContent = !isPendingApproval;
|
||||
|
||||
return (
|
||||
<>
|
||||
<div
|
||||
@@ -191,7 +193,8 @@ export default function ToolCallWithResponse({
|
||||
/>
|
||||
</div>
|
||||
{/* MCP UI — Inline */}
|
||||
{!hasMcpAppResourceURI &&
|
||||
{shouldShowMcpContent &&
|
||||
!hasMcpAppResourceURI &&
|
||||
toolResponse?.toolResult &&
|
||||
getToolResultContent(toolResponse.toolResult).map((content, index) => {
|
||||
const resourceContent = isEmbeddedResource(content)
|
||||
@@ -214,7 +217,8 @@ export default function ToolCallWithResponse({
|
||||
}
|
||||
})}
|
||||
|
||||
{hasMcpAppResourceURI && sessionId && (
|
||||
{/* MCP App */}
|
||||
{shouldShowMcpContent && hasMcpAppResourceURI && sessionId && (
|
||||
<McpAppWrapper
|
||||
toolRequest={toolRequest}
|
||||
toolResponse={toolResponse}
|
||||
|
||||
@@ -160,6 +160,7 @@ export const SessionMessages: React.FC<SessionMessagesProps> = ({
|
||||
isCancelledMessage={
|
||||
toolResponsesMap.get(toolRequest.id) == undefined
|
||||
}
|
||||
isPendingApproval={false}
|
||||
key={toolRequest.id}
|
||||
toolRequest={toolRequest}
|
||||
toolResponse={toolResponsesMap.get(toolRequest.id)}
|
||||
|
||||
@@ -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<string> {
|
||||
const pendingIds = new Set<string>();
|
||||
const respondedIds = new Set<string>();
|
||||
|
||||
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 {
|
||||
|
||||
Reference in New Issue
Block a user