import { useState, useEffect } from 'react'; import { snakeToTitleCase } from '../utils'; import PermissionModal from './settings/permission/PermissionModal'; import { ChevronRight } from 'lucide-react'; import { confirmToolAction, ActionRequired } from '../api'; import { Button } from './ui/button'; const ALLOW_ONCE = 'allow_once'; const ALWAYS_ALLOW = 'always_allow'; const DENY = 'deny'; // Global state to track tool confirmation decisions // This persists across navigation within the same session const toolConfirmationState = new Map< string, { clicked: boolean; status: string; actionDisplay: string; } >(); type ToolConfirmationData = Extract; interface ToolConfirmationProps { sessionId: string; isCancelledMessage: boolean; isClicked: boolean; actionRequiredContent: ActionRequired & { type: 'actionRequired' }; } export default function ToolConfirmation({ sessionId, isCancelledMessage, isClicked, actionRequiredContent, }: ToolConfirmationProps) { const data = actionRequiredContent.data as ToolConfirmationData; const { id: toolConfirmationId, toolName, prompt } = data; // Check if we have a stored state for this tool confirmation const storedState = toolConfirmationState.get(toolConfirmationId); // Initialize state from stored state if available, otherwise use props/defaults const [clicked, setClicked] = useState(storedState?.clicked ?? isClicked); const [status, setStatus] = useState(storedState?.status ?? 'unknown'); const [actionDisplay, setActionDisplay] = useState(storedState?.actionDisplay ?? ''); const [isModalOpen, setIsModalOpen] = useState(false); // Sync internal state with stored state and props useEffect(() => { const currentStoredState = toolConfirmationState.get(toolConfirmationId); // If we have stored state, use it if (currentStoredState) { setClicked(currentStoredState.clicked); setStatus(currentStoredState.status); setActionDisplay(currentStoredState.actionDisplay); } else if (isClicked && !clicked) { // Fallback to prop-based logic for historical confirmations setClicked(isClicked); if (status === 'unknown') { setStatus('confirmed'); setActionDisplay('confirmed'); // Store this state for future renders toolConfirmationState.set(toolConfirmationId, { clicked: true, status: 'confirmed', actionDisplay: 'confirmed', }); } } }, [isClicked, clicked, status, toolName, toolConfirmationId]); const handleButtonClick = async (newStatus: string) => { let newActionDisplay; if (newStatus === ALWAYS_ALLOW) { newActionDisplay = 'always allowed'; } else if (newStatus === ALLOW_ONCE) { newActionDisplay = 'allowed once'; } else if (newStatus === DENY) { newActionDisplay = 'denied'; } else { newActionDisplay = 'denied'; } // Update local state setClicked(true); setStatus(newStatus); setActionDisplay(newActionDisplay); // Store in global state for persistence across navigation toolConfirmationState.set(toolConfirmationId, { clicked: true, status: newStatus, actionDisplay: newActionDisplay, }); try { const response = await confirmToolAction({ body: { sessionId: sessionId, id: toolConfirmationId, action: newStatus, principalType: 'Tool', }, }); if (response.error) { console.error('Failed to confirm tool action:', response.error); } } catch (err) { console.error('Error confirming tool action:', err); } }; const handleModalClose = () => { setIsModalOpen(false); }; function getExtensionName(toolName: string): string { const parts = toolName.split('__'); return parts.length > 1 ? parts[0] : ''; } return isCancelledMessage ? (
Tool call confirmation is cancelled.
) : ( <> {/* Display security message if present */} {prompt && (
{prompt}
)}
{prompt ? 'Do you allow this tool call?' : 'Goose would like to call the above tool. Allow?'}
{clicked ? (
{(status === 'allow_once' || status === 'always_allow') && ( )} {status === 'deny' && ( )} {status === 'confirmed' && ( )} {isClicked ? 'Tool confirmation is not available' : `${snakeToTitleCase(toolName.substring(toolName.lastIndexOf('__') + 2))} is ${actionDisplay}`}
setIsModalOpen(true)}> Change
) : (
{/* Only show "Always Allow" if there's no security message (no security finding) */} {!prompt && ( )}
)} {/* Modal for updating tool permission */} {isModalOpen && ( )} ); }