[Obs AI Assistant] Fix error when opening an old conversation (#197745)

Closes https://github.com/elastic/kibana/issues/176299

## Summary

### Problem

When a chat is started from contextual insights, `initialMessages` are
being populated from the temp conversation created from the error.
Because the `initialMessages` are present, when an old conversation is
clicked, the conversation ID of that conversation and the
`initalMessages` from the temp chat are passed to the conversation. This
throws an error, as there is a condition which restricts both of these
being passed to `useConversation` which is used by the `ChatBody`.
- Only one of these should be passed (not both)

### Solution
With the current implementation, even though not passing
`initialMessages` allows the user to open previous conversations
successfully, it doesn't allow the user to start a new chat because as
long as initial messages are set, they will be loaded when the New Chat
button is clicked instead of showing a blank conversation. Clearing
initial messages requires re-architecting how the Chat uses the
conversation.

Therefore, as the solution, when a chat is opened from contextual
insights, the ConversationList will be hidden. The user can interact
with the AI Assistant on the opened chat with initial messages from
contextual insights.
This commit is contained in:
Viduni Wickramarachchi 2024-10-31 15:16:52 -04:00 committed by GitHub
parent be51fac02f
commit 287c1ec62e
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
5 changed files with 101 additions and 72 deletions

View file

@ -47,6 +47,7 @@ export function ChatFlyout({
isOpen,
onClose,
navigateToConversation,
hideConversationList,
}: {
initialTitle: string;
initialMessages: Message[];
@ -54,6 +55,7 @@ export function ChatFlyout({
isOpen: boolean;
onClose: () => void;
navigateToConversation?: (conversationId?: string) => void;
hideConversationList?: boolean;
}) {
const { euiTheme } = useEuiTheme();
const breakpoint = useCurrentEuiBreakpoint();
@ -174,84 +176,86 @@ export function ChatFlyout({
}}
>
<EuiFlexGroup gutterSize="none" className={containerClassName}>
<EuiFlexItem className={breakpoint === 'xs' ? hideClassName : sidebarClass}>
<EuiPopover
anchorPosition="downLeft"
className={expandButtonContainerClassName}
button={
<EuiToolTip
content={
conversationsExpanded
? i18n.translate(
'xpack.aiAssistant.chatFlyout.euiToolTip.collapseConversationListLabel',
{ defaultMessage: 'Collapse conversation list' }
)
: i18n.translate(
'xpack.aiAssistant.chatFlyout.euiToolTip.expandConversationListLabel',
{ defaultMessage: 'Expand conversation list' }
)
}
display="block"
>
<EuiButtonIcon
aria-label={i18n.translate(
'xpack.aiAssistant.chatFlyout.euiButtonIcon.expandConversationListLabel',
{ defaultMessage: 'Expand conversation list' }
)}
className={expandButtonClassName}
color="text"
data-test-subj="observabilityAiAssistantChatFlyoutButton"
iconType={conversationsExpanded ? 'transitionLeftIn' : 'transitionLeftOut'}
onClick={() => setConversationsExpanded(!conversationsExpanded)}
/>
</EuiToolTip>
}
/>
{conversationsExpanded ? (
<ConversationList
conversations={conversationList.conversations}
isLoading={conversationList.isLoading}
selectedConversationId={conversationId}
onConversationDeleteClick={(deletedConversationId) => {
conversationList.deleteConversation(deletedConversationId).then(() => {
if (deletedConversationId === conversationId) {
setConversationId(undefined);
}
});
}}
onConversationSelect={(nextConversationId) => {
setConversationId(nextConversationId);
}}
/>
) : (
{!hideConversationList ? (
<EuiFlexItem className={breakpoint === 'xs' ? hideClassName : sidebarClass}>
<EuiPopover
anchorPosition="downLeft"
className={expandButtonContainerClassName}
button={
<EuiToolTip
content={i18n.translate(
'xpack.aiAssistant.chatFlyout.euiToolTip.newChatLabel',
{ defaultMessage: 'New chat' }
)}
content={
conversationsExpanded
? i18n.translate(
'xpack.aiAssistant.chatFlyout.euiToolTip.collapseConversationListLabel',
{ defaultMessage: 'Collapse conversation list' }
)
: i18n.translate(
'xpack.aiAssistant.chatFlyout.euiToolTip.expandConversationListLabel',
{ defaultMessage: 'Expand conversation list' }
)
}
display="block"
>
<NewChatButton
<EuiButtonIcon
aria-label={i18n.translate(
'xpack.aiAssistant.chatFlyout.euiButtonIcon.newChatLabel',
{ defaultMessage: 'New chat' }
'xpack.aiAssistant.chatFlyout.euiButtonIcon.expandConversationListLabel',
{ defaultMessage: 'Expand conversation list' }
)}
collapsed
data-test-subj="observabilityAiAssistantNewChatFlyoutButton"
onClick={() => {
setConversationId(undefined);
}}
className={expandButtonClassName}
color="text"
data-test-subj="observabilityAiAssistantChatFlyoutButton"
iconType={conversationsExpanded ? 'transitionLeftIn' : 'transitionLeftOut'}
onClick={() => setConversationsExpanded(!conversationsExpanded)}
/>
</EuiToolTip>
}
className={newChatButtonClassName}
/>
)}
</EuiFlexItem>
{conversationsExpanded ? (
<ConversationList
conversations={conversationList.conversations}
isLoading={conversationList.isLoading}
selectedConversationId={conversationId}
onConversationDeleteClick={(deletedConversationId) => {
conversationList.deleteConversation(deletedConversationId).then(() => {
if (deletedConversationId === conversationId) {
setConversationId(undefined);
}
});
}}
onConversationSelect={(nextConversationId) => {
setConversationId(nextConversationId);
}}
/>
) : (
<EuiPopover
anchorPosition="downLeft"
button={
<EuiToolTip
content={i18n.translate(
'xpack.aiAssistant.chatFlyout.euiToolTip.newChatLabel',
{ defaultMessage: 'New chat' }
)}
display="block"
>
<NewChatButton
aria-label={i18n.translate(
'xpack.aiAssistant.chatFlyout.euiButtonIcon.newChatLabel',
{ defaultMessage: 'New chat' }
)}
collapsed
data-test-subj="observabilityAiAssistantNewChatFlyoutButton"
onClick={() => {
setConversationId(undefined);
}}
/>
</EuiToolTip>
}
className={newChatButtonClassName}
/>
)}
</EuiFlexItem>
) : null}
<EuiFlexItem className={chatBodyContainerClassName}>
<ChatBody

View file

@ -128,6 +128,7 @@ function ChatContent({
service.conversations.openNewConversation({
messages,
title: defaultTitle,
hideConversationList: true,
});
}}
/>

View file

@ -36,7 +36,11 @@ export function createService({
const screenContexts$ = new BehaviorSubject<ObservabilityAIAssistantScreenContext[]>([
{ starterPrompts: defaultStarterPrompts },
]);
const predefinedConversation$ = new Subject<{ messages: Message[]; title?: string }>();
const predefinedConversation$ = new Subject<{
messages: Message[];
title?: string;
hideConversationList?: boolean;
}>();
const scope$ = new BehaviorSubject<AssistantScope[]>(scopes);
@ -104,8 +108,16 @@ export function createService({
);
},
conversations: {
openNewConversation: ({ messages, title }: { messages: Message[]; title?: string }) => {
predefinedConversation$.next({ messages, title });
openNewConversation: ({
messages,
title,
hideConversationList = false,
}: {
messages: Message[];
title?: string;
hideConversationList?: boolean;
}) => {
predefinedConversation$.next({ messages, title, hideConversationList });
},
predefinedConversation$: predefinedConversation$.asObservable(),
},

View file

@ -91,8 +91,16 @@ export interface ObservabilityAIAssistantChatService {
}
export interface ObservabilityAIAssistantConversationService {
openNewConversation: ({}: { messages: Message[]; title?: string }) => void;
predefinedConversation$: Observable<{ messages: Message[]; title?: string }>;
openNewConversation: ({}: {
messages: Message[];
title?: string;
hideConversationList?: boolean;
}) => void;
predefinedConversation$: Observable<{
messages: Message[];
title?: string;
hideConversationList?: boolean;
}>;
}
export interface ObservabilityAIAssistantService {

View file

@ -103,9 +103,12 @@ export function NavControl() {
};
}, [service.conversations.predefinedConversation$]);
const { messages, title } = useObservable(service.conversations.predefinedConversation$) ?? {
const { messages, title, hideConversationList } = useObservable(
service.conversations.predefinedConversation$
) ?? {
messages: [],
title: undefined,
hideConversationList: false,
};
const theme = useTheme();
@ -171,6 +174,7 @@ export function NavControl() {
)
);
}}
hideConversationList={hideConversationList}
/>
</ObservabilityAIAssistantChatServiceContext.Provider>
) : undefined}