diff --git a/ui/desktop/src/components/sessions/SessionHistoryView.tsx b/ui/desktop/src/components/sessions/SessionHistoryView.tsx index 95d781c94e2b..f90e706b7cdb 100644 --- a/ui/desktop/src/components/sessions/SessionHistoryView.tsx +++ b/ui/desktop/src/components/sessions/SessionHistoryView.tsx @@ -38,7 +38,9 @@ const isUserMessage = (message: Message): boolean => { if (message.role === 'assistant') { return false; } - return !message.content.every((c) => c.type === 'toolConfirmationRequest'); + return !message.content.every( + (c) => c.type === 'actionRequired' && c.data.actionType === 'toolConfirmation' + ); }; const filterMessagesForDisplay = (messages: Message[]): Message[] => { diff --git a/ui/desktop/src/components/settings/permission/PermissionModal.tsx b/ui/desktop/src/components/settings/permission/PermissionModal.tsx index 2ac07593a6f2..58fcd9229bf8 100644 --- a/ui/desktop/src/components/settings/permission/PermissionModal.tsx +++ b/ui/desktop/src/components/settings/permission/PermissionModal.tsx @@ -1,6 +1,6 @@ import { useEffect, useMemo, useState } from 'react'; import { Button } from '../../ui/button'; -import { ChevronDownIcon, SlidersHorizontal } from 'lucide-react'; +import { ChevronDownIcon, SlidersHorizontal, AlertCircle } from 'lucide-react'; import { getTools, PermissionLevel, ToolInfo, upsertPermissions } from '../../../api'; import { Dialog, DialogContent, DialogFooter, DialogHeader, DialogTitle } from '../../ui/dialog'; import { @@ -33,6 +33,8 @@ export default function PermissionModal({ extensionName, onClose }: PermissionMo const [tools, setTools] = useState([]); const [updatedPermissions, setUpdatedPermissions] = useState>({}); + const [isLoading, setIsLoading] = useState(true); + const [loadError, setLoadError] = useState(null); const hasChanges = useMemo(() => { return Object.keys(updatedPermissions).some( @@ -43,12 +45,22 @@ export default function PermissionModal({ extensionName, onClose }: PermissionMo useEffect(() => { const fetchTools = async () => { + if (!sessionId) { + setIsLoading(false); + setLoadError('no_session'); + return; + } + + setIsLoading(true); + setLoadError(null); + try { const response = await getTools({ query: { extension_name: extensionName, session_id: sessionId }, }); if (response.error) { - console.error('Failed to get tools'); + console.error('Failed to get tools:', response.error); + setLoadError('fetch_failed'); } else { const filteredTools = (response.data || []).filter( (tool: ToolInfo) => @@ -58,6 +70,9 @@ export default function PermissionModal({ extensionName, onClose }: PermissionMo } } catch (err) { console.error('Error fetching tools:', err); + setLoadError('fetch_failed'); + } finally { + setIsLoading(false); } }; @@ -121,9 +136,8 @@ export default function PermissionModal({ extensionName, onClose }: PermissionMo
- {tools.length === 0 ? ( -
- {/* Loading spinner */} + {isLoading ? ( +
+ ) : loadError === 'no_session' ? ( +
+ +

No active session

+

+ Start a chat session first to configure tool permissions for this extension. Tool + permissions are loaded from the active session's extensions. +

+
+ ) : loadError === 'fetch_failed' ? ( +
+ +

Failed to load tools

+

+ Could not load tools for this extension. The extension may not be loaded in the + current session. +

+
+ ) : tools.length === 0 ? ( +
+

No tools available for this extension.

+
) : (
{tools.map((tool) => ( @@ -187,11 +223,13 @@ export default function PermissionModal({ extensionName, onClose }: PermissionMo - + {!loadError && ( + + )} diff --git a/ui/desktop/src/hooks/useChatStream.ts b/ui/desktop/src/hooks/useChatStream.ts index 8cf0fe6bf822..efbccdbdd2c8 100644 --- a/ui/desktop/src/hooks/useChatStream.ts +++ b/ui/desktop/src/hooks/useChatStream.ts @@ -257,7 +257,8 @@ async function streamFromResponse( currentMessages = pushMessage(currentMessages, msg); const hasToolConfirmation = msg.content.some( - (content) => content.type === 'toolConfirmationRequest' + (content) => + content.type === 'actionRequired' && content.data.actionType === 'toolConfirmation' ); const hasElicitation = msg.content.some(