import { useState, useEffect } from 'react'; import { snakeToTitleCase } from '../utils'; import PermissionModal from './settings/permission/PermissionModal'; import { ChevronRight } from 'lucide-react'; import { confirmPermission } from '../api'; import { Button } from './ui/button'; const ALWAYS_ALLOW = 'always_allow'; const ALLOW_ONCE = 'allow_once'; 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; } >(); interface ToolConfirmationProps { isCancelledMessage: boolean; isClicked: boolean; toolConfirmationId: string; toolName: string; } export default function ToolConfirmation({ isCancelledMessage, isClicked, toolConfirmationId, toolName, }: ToolConfirmationProps) { // 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 (action: string) => { const newClicked = true; const newStatus = action; let newActionDisplay = ''; if (action === ALWAYS_ALLOW) { newActionDisplay = 'always allowed'; } else if (action === ALLOW_ONCE) { newActionDisplay = 'allowed once'; } else { newActionDisplay = 'denied'; } // Update local state setClicked(newClicked); setStatus(newStatus); setActionDisplay(newActionDisplay); // Store in global state for persistence across navigation toolConfirmationState.set(toolConfirmationId, { clicked: newClicked, status: newStatus, actionDisplay: newActionDisplay, }); try { const response = await confirmPermission({ body: { id: toolConfirmationId, action, principal_type: 'Tool' }, }); if (response.error) { console.error('Failed to confirm permission:', response.error); } } catch (err) { console.error('Error confirming permission:', 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.
) : ( <>
Goose would like to call the above tool. Allow?
{clicked ? (
{status === 'always_allow' && ( )} {status === 'allow_once' && ( )} {status === 'deny' && ( )} {status === 'confirmed' && ( )} {isClicked ? 'Tool confirmation is not available' : `${snakeToTitleCase(toolName.substring(toolName.lastIndexOf('__') + 2))} is ${actionDisplay}`}
setIsModalOpen(true)}> Change
) : (
)} {/* Modal for updating tool permission */} {isModalOpen && ( )} ); }