diff --git a/ui/desktop/src/components/ChatView.tsx b/ui/desktop/src/components/ChatView.tsx index b66a0657..e3e789e4 100644 --- a/ui/desktop/src/components/ChatView.tsx +++ b/ui/desktop/src/components/ChatView.tsx @@ -29,6 +29,9 @@ import { export interface ChatType { id: number; title: string; + // messages up to this index are presumed to be "history" from a resumed session, this is used to track older tool confirmation requests + // anything before this index should not render any buttons, but anything after should + messageHistoryIndex: number; messages: Message[]; } @@ -76,6 +79,7 @@ export default function ChatView({ return { id: Date.now(), title: resumedSession.metadata?.description || `ID: ${resumedSession.session_id}`, + messageHistoryIndex: convertedMessages.length, messages: convertedMessages, }; } catch (e) { @@ -98,6 +102,7 @@ export default function ChatView({ id: Date.now(), title: 'Chat 1', messages: [], + messageHistoryIndex: 0, }; }); const [messageMetadata, setMessageMetadata] = useState>({}); @@ -319,10 +324,15 @@ export default function ChatView({ ) : ( append(createUserMessage(text))} + appendMessage={(newMessage) => { + const updatedMessages = [...messages, newMessage]; + setMessages(updatedMessages); + }} /> )} diff --git a/ui/desktop/src/components/GooseMessage.tsx b/ui/desktop/src/components/GooseMessage.tsx index dfe1b9b6..3419be8b 100644 --- a/ui/desktop/src/components/GooseMessage.tsx +++ b/ui/desktop/src/components/GooseMessage.tsx @@ -1,4 +1,4 @@ -import React, { useMemo, useRef } from 'react'; +import React, { useEffect, useMemo, useRef } from 'react'; import LinkPreview from './LinkPreview'; import GooseResponseForm from './GooseResponseForm'; import { extractUrls } from '../utils/urlUtils'; @@ -10,18 +10,28 @@ import { getToolRequests, getToolResponses, getToolConfirmationContent, + createToolErrorResponseMessage, } from '../types/message'; import ToolCallConfirmation from './ToolCallConfirmation'; import MessageCopyLink from './MessageCopyLink'; interface GooseMessageProps { + messageHistoryIndex: number; message: Message; messages: Message[]; metadata?: string[]; append: (value: string) => void; + appendMessage: (message: Message) => void; } -export default function GooseMessage({ message, metadata, messages, append }: GooseMessageProps) { +export default function GooseMessage({ + messageHistoryIndex, + message, + metadata, + messages, + append, + appendMessage, +}: GooseMessageProps) { const contentRef = useRef(null); // Extract text content from the message @@ -64,6 +74,16 @@ export default function GooseMessage({ message, metadata, messages, append }: Go return responseMap; }, [messages, messageIndex, toolRequests]); + useEffect(() => { + // If the message is the last message in the resumed session and has tool confirmation, it means the tool confirmation + // is broken or cancelled, to contonue use the session, we need to append a tool response to avoid mismatch tool result error. + if (messageIndex == messageHistoryIndex - 1 && hasToolConfirmation) { + appendMessage( + createToolErrorResponseMessage(toolConfirmationContent.id, 'The tool call is cancelled.') + ); + } + }, []); + return (
@@ -86,17 +106,15 @@ export default function GooseMessage({ message, metadata, messages, append }: Go
)} - {hasToolConfirmation && ( - - )} - {toolRequests.length > 0 && (
{toolRequests.map((toolRequest) => ( )} + + {hasToolConfirmation && ( + + )}
{/* TODO(alexhancock): Re-enable link previews once styled well again */} diff --git a/ui/desktop/src/components/ToolCallConfirmation.tsx b/ui/desktop/src/components/ToolCallConfirmation.tsx index 68e26c60..7ea2181b 100644 --- a/ui/desktop/src/components/ToolCallConfirmation.tsx +++ b/ui/desktop/src/components/ToolCallConfirmation.tsx @@ -2,9 +2,14 @@ import React, { useState } from 'react'; import { ConfirmToolRequest } from '../utils/toolConfirm'; import { snakeToTitleCase } from '../utils'; -export default function ToolConfirmation({ toolConfirmationId, toolName }) { - const [clicked, setClicked] = useState(false); - const [status, setStatus] = useState(''); +export default function ToolConfirmation({ + isCancelledMessage, + isClicked, + toolConfirmationId, + toolName, +}) { + const [clicked, setClicked] = useState(isClicked); + const [status, setStatus] = useState('unknown'); const handleButtonClick = (confirmed) => { setClicked(true); @@ -12,7 +17,11 @@ export default function ToolConfirmation({ toolConfirmationId, toolName }) { ConfirmToolRequest(toolConfirmationId, confirmed); }; - return ( + return isCancelledMessage ? ( +
+ Tool call confirmation is cancelled. +
+ ) : ( <>
Goose would like to call the above tool. Allow? @@ -45,7 +54,9 @@ export default function ToolConfirmation({ toolConfirmationId, toolName }) { )} - {snakeToTitleCase(toolName.substring(toolName.lastIndexOf('__') + 2))} is {status} + {isClicked + ? 'Tool confirmation is not available' + : `${snakeToTitleCase(toolName.substring(toolName.lastIndexOf('__') + 2))} is ${status}`}
diff --git a/ui/desktop/src/components/ToolCallWithResponse.tsx b/ui/desktop/src/components/ToolCallWithResponse.tsx index b6e3e7f5..887c0c5f 100644 --- a/ui/desktop/src/components/ToolCallWithResponse.tsx +++ b/ui/desktop/src/components/ToolCallWithResponse.tsx @@ -9,11 +9,13 @@ import { Content, ToolRequestMessageContent, ToolResponseMessageContent } from ' import { snakeToTitleCase } from '../utils'; interface ToolCallWithResponseProps { + isCancelledMessage: boolean; toolRequest: ToolRequestMessageContent; toolResponse?: ToolResponseMessageContent; } export default function ToolCallWithResponse({ + isCancelledMessage, toolRequest, toolResponse, }: ToolCallWithResponseProps) { @@ -27,17 +29,19 @@ export default function ToolCallWithResponse({
- {toolResponse ? ( - - ) : ( - - )} + {!isCancelledMessage ? ( + toolResponse ? ( + + ) : ( + + ) + ) : undefined}
); diff --git a/ui/desktop/src/components/sessions/SessionHistoryView.tsx b/ui/desktop/src/components/sessions/SessionHistoryView.tsx index 33717974..fe272929 100644 --- a/ui/desktop/src/components/sessions/SessionHistoryView.tsx +++ b/ui/desktop/src/components/sessions/SessionHistoryView.tsx @@ -166,6 +166,11 @@ const SessionHistoryView: React.FC = ({
{toolRequests.map((toolRequest) => (