Skip to content
Merged
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions changelogs/fragments/10918.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
fix:
- Suggested actions not appearing with tool calls ([#10918](https://github.com/opensearch-project/OpenSearch-Dashboards/pull/10918))
27 changes: 21 additions & 6 deletions src/plugins/chat/public/components/chat_messages.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
* SPDX-License-Identifier: Apache-2.0
*/

import React, { useRef, useEffect } from 'react';
import React, { useRef, useEffect, useMemo } from 'react';
import { EuiIcon, EuiText } from '@elastic/eui';
import { ChatLayoutMode } from './chat_header_button';
import { MessageRow } from './message_row';
Expand Down Expand Up @@ -54,9 +54,21 @@ export const ChatMessages: React.FC<ChatMessagesProps> = ({

// Context is now handled by RFC hooks - no subscriptions needed

// Only show suggestion on llm outputs after last user input
const showSuggestions =
!isStreaming && timeline.length > 0 && timeline[timeline.length - 1].role === 'assistant';
const lastAssistantMessageIndex = useMemo(
() => timeline.findLastIndex((message) => message.role === 'assistant'),
[timeline]
);
// Only enable suggestion on llm outputs after last user input
const suggestionsEnabled = useMemo(() => {
if (isStreaming) {
return false;
}
if (timeline.length === 0) {
return false;
}
const lastUserMessageIndex = timeline.findLastIndex((message) => message.role === 'user');
return lastAssistantMessageIndex > lastUserMessageIndex;
}, [timeline, isStreaming, lastAssistantMessageIndex]);

return (
<>
Expand All @@ -76,7 +88,7 @@ export const ChatMessages: React.FC<ChatMessagesProps> = ({
</div>
)}

{timeline.map((message) => {
{timeline.map((message, index) => {
// Handle different message types
if (message.role === 'user') {
return <MessageRow key={message.id} message={message} onResend={onResendMessage} />;
Expand Down Expand Up @@ -106,6 +118,10 @@ export const ChatMessages: React.FC<ChatMessagesProps> = ({
<MessageRow message={assistantMsg} />
)}

{suggestionsEnabled && lastAssistantMessageIndex === index && (
<ChatSuggestions messages={timeline} currentMessage={message} />
)}

{/* Tool calls below the message */}
{assistantMsg.toolCalls?.map((toolCall) => {
// Find corresponding tool result
Expand Down Expand Up @@ -144,7 +160,6 @@ export const ChatMessages: React.FC<ChatMessagesProps> = ({

return null;
})}
{showSuggestions && <ChatSuggestions messages={timeline} />}

{/* Loading indicator - waiting for agent response */}
{isStreaming && timeline.length === 0 && (
Expand Down
12 changes: 9 additions & 3 deletions src/plugins/chat/public/components/chat_suggestions.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,13 @@ const SuggestionBubble: React.FC<SuggestionBubbleProps> = ({
);
};

export const ChatSuggestions = ({ messages }: { messages: Message[] }) => {
export const ChatSuggestions = ({
messages,
currentMessage,
}: {
messages: Message[];
currentMessage: Message;
}) => {
const { suggestedActionsService, chatService } = useChatContext();

const [customSuggestions, setCustomSuggestions] = useState<SuggestedActions[]>([]);
Expand All @@ -93,7 +99,7 @@ export const ChatSuggestions = ({ messages }: { messages: Message[] }) => {
// Create ChatContext object from current chat state
const context: ChatContext = {
conversationId: chatService.getThreadId(),
currentMessage: messages[messages.length - 1],
currentMessage,
messageHistory: messages,
};

Expand All @@ -109,7 +115,7 @@ export const ChatSuggestions = ({ messages }: { messages: Message[] }) => {
};

loadCustomSuggestions();
}, [suggestedActionsService, chatService, messages]);
}, [suggestedActionsService, chatService, messages, currentMessage]);

if (isLoadingCustomSuggestions || customSuggestions.length === 0) {
return null;
Expand Down
Loading