Fix tool call allow still showing initial state in chat after navigating back (#3498)
This commit is contained in:
@@ -220,7 +220,7 @@ export default function GooseMessage({
|
|||||||
{hasToolConfirmation && (
|
{hasToolConfirmation && (
|
||||||
<ToolCallConfirmation
|
<ToolCallConfirmation
|
||||||
isCancelledMessage={messageIndex == messageHistoryIndex - 1}
|
isCancelledMessage={messageIndex == messageHistoryIndex - 1}
|
||||||
isClicked={messageIndex < messageHistoryIndex - 1}
|
isClicked={messageIndex < messageHistoryIndex}
|
||||||
toolConfirmationId={toolConfirmationContent.id}
|
toolConfirmationId={toolConfirmationContent.id}
|
||||||
toolName={toolConfirmationContent.toolName}
|
toolName={toolConfirmationContent.toolName}
|
||||||
/>
|
/>
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import { useState } from 'react';
|
import { useState, useEffect } from 'react';
|
||||||
import { snakeToTitleCase } from '../utils';
|
import { snakeToTitleCase } from '../utils';
|
||||||
import PermissionModal from './settings/permission/PermissionModal';
|
import PermissionModal from './settings/permission/PermissionModal';
|
||||||
import { ChevronRight } from 'lucide-react';
|
import { ChevronRight } from 'lucide-react';
|
||||||
@@ -9,6 +9,17 @@ const ALWAYS_ALLOW = 'always_allow';
|
|||||||
const ALLOW_ONCE = 'allow_once';
|
const ALLOW_ONCE = 'allow_once';
|
||||||
const DENY = 'deny';
|
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 {
|
interface ToolConfirmationProps {
|
||||||
isCancelledMessage: boolean;
|
isCancelledMessage: boolean;
|
||||||
isClicked: boolean;
|
isClicked: boolean;
|
||||||
@@ -22,30 +33,75 @@ export default function ToolConfirmation({
|
|||||||
toolConfirmationId,
|
toolConfirmationId,
|
||||||
toolName,
|
toolName,
|
||||||
}: ToolConfirmationProps) {
|
}: ToolConfirmationProps) {
|
||||||
const [clicked, setClicked] = useState(isClicked);
|
// Check if we have a stored state for this tool confirmation
|
||||||
const [status, setStatus] = useState('unknown');
|
const storedState = toolConfirmationState.get(toolConfirmationId);
|
||||||
const [actionDisplay, setActionDisplay] = useState('');
|
|
||||||
|
// 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);
|
const [isModalOpen, setIsModalOpen] = useState(false);
|
||||||
|
|
||||||
const handleButtonClick = async (action: string) => {
|
// Sync internal state with stored state and props
|
||||||
setClicked(true);
|
useEffect(() => {
|
||||||
setStatus(action);
|
const currentStoredState = toolConfirmationState.get(toolConfirmationId);
|
||||||
if (action === ALWAYS_ALLOW) {
|
|
||||||
setActionDisplay('always allowed');
|
// If we have stored state, use it
|
||||||
} else if (action === ALLOW_ONCE) {
|
if (currentStoredState) {
|
||||||
setActionDisplay('allowed once');
|
setClicked(currentStoredState.clicked);
|
||||||
} else {
|
setStatus(currentStoredState.status);
|
||||||
setActionDisplay('denied');
|
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 {
|
try {
|
||||||
const response = await confirmPermission({
|
const response = await confirmPermission({
|
||||||
body: { id: toolConfirmationId, action, principal_type: 'Tool' },
|
body: { id: toolConfirmationId, action, principal_type: 'Tool' },
|
||||||
});
|
});
|
||||||
if (response.error) {
|
if (response.error) {
|
||||||
console.error('Failed to confirm permission: ', response.error);
|
console.error('Failed to confirm permission:', response.error);
|
||||||
}
|
}
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
console.error('Error fetching tools:', err);
|
console.error('Error confirming permission:', err);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -106,6 +162,18 @@ export default function ToolConfirmation({
|
|||||||
<path strokeLinecap="round" strokeLinejoin="round" d="M6 18L18 6M6 6l12 12" />
|
<path strokeLinecap="round" strokeLinejoin="round" d="M6 18L18 6M6 6l12 12" />
|
||||||
</svg>
|
</svg>
|
||||||
)}
|
)}
|
||||||
|
{status === 'confirmed' && (
|
||||||
|
<svg
|
||||||
|
className="w-5 h-5 text-gray-500"
|
||||||
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
|
fill="none"
|
||||||
|
viewBox="0 0 24 24"
|
||||||
|
stroke="currentColor"
|
||||||
|
strokeWidth={2}
|
||||||
|
>
|
||||||
|
<path strokeLinecap="round" strokeLinejoin="round" d="M5 13l4 4L19 7" />
|
||||||
|
</svg>
|
||||||
|
)}
|
||||||
<span className="ml-2 text-textStandard">
|
<span className="ml-2 text-textStandard">
|
||||||
{isClicked
|
{isClicked
|
||||||
? 'Tool confirmation is not available'
|
? 'Tool confirmation is not available'
|
||||||
|
|||||||
Reference in New Issue
Block a user