[8.x] [Security Assistant] Fix error handling on new chat (#195507) (#196215)

# Backport

This will backport the following commits from `main` to `8.x`:
- [[Security Assistant] Fix error handling on new chat
(#195507)](https://github.com/elastic/kibana/pull/195507)

<!--- Backport version: 9.4.3 -->

### Questions ?
Please refer to the [Backport tool
documentation](https://github.com/sqren/backport)

<!--BACKPORT [{"author":{"name":"Steph
Milovic","email":"stephanie.milovic@elastic.co"},"sourceCommit":{"committedDate":"2024-10-14T22:10:43Z","message":"[Security
Assistant] Fix error handling on new chat
(#195507)","sha":"a15940d9b939dbf29f74dbde28a2a543b8849cc1","branchLabelMapping":{"^v9.0.0$":"main","^v8.16.0$":"8.x","^v(\\d+).(\\d+).\\d+$":"$1.$2"}},"sourcePullRequest":{"labels":["release_note:skip","v9.0.0","Team:
SecuritySolution","backport:prev-minor","Team:Security Generative
AI","v8.16.0"],"title":"[Security Assistant] Fix error handling on new
chat","number":195507,"url":"https://github.com/elastic/kibana/pull/195507","mergeCommit":{"message":"[Security
Assistant] Fix error handling on new chat
(#195507)","sha":"a15940d9b939dbf29f74dbde28a2a543b8849cc1"}},"sourceBranch":"main","suggestedTargetBranches":["8.x"],"targetPullRequestStates":[{"branch":"main","label":"v9.0.0","branchLabelMappingKey":"^v9.0.0$","isSourceBranch":true,"state":"MERGED","url":"https://github.com/elastic/kibana/pull/195507","number":195507,"mergeCommit":{"message":"[Security
Assistant] Fix error handling on new chat
(#195507)","sha":"a15940d9b939dbf29f74dbde28a2a543b8849cc1"}},{"branch":"8.x","label":"v8.16.0","branchLabelMappingKey":"^v8.16.0$","isSourceBranch":false,"state":"NOT_CREATED"}]}]
BACKPORT-->

Co-authored-by: Steph Milovic <stephanie.milovic@elastic.co>
This commit is contained in:
Kibana Machine 2024-10-15 10:54:33 +11:00 committed by GitHub
parent db28b89f61
commit 65cff56aa4
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
9 changed files with 77 additions and 33 deletions

View file

@ -147,7 +147,13 @@ export class ActionsClientChatOpenAI extends ChatOpenAI {
const actionResult = await this.#actionsClient.execute(requestBody);
if (actionResult.status === 'error') {
throw new Error(`${LLM_TYPE}: ${actionResult?.message} - ${actionResult?.serviceMessage}`);
const error = new Error(
`${LLM_TYPE}: ${actionResult?.message} - ${actionResult?.serviceMessage}`
);
if (actionResult?.serviceMessage) {
error.name = actionResult?.serviceMessage;
}
throw error;
}
if (!this.streaming) {

View file

@ -98,11 +98,14 @@ export class ActionsClientChatVertexAI extends ChatVertexAI {
};
const actionResult = await this.#actionsClient.execute(requestBody);
if (actionResult.status === 'error') {
throw new Error(
const error = new Error(
`ActionsClientChatVertexAI: action result status is error: ${actionResult?.message} - ${actionResult?.serviceMessage}`
);
if (actionResult?.serviceMessage) {
error.name = actionResult?.serviceMessage;
}
throw error;
}
const readable = get('data', actionResult) as Readable;

View file

@ -93,9 +93,13 @@ export class ActionsClientChatConnection<Auth> extends ChatConnection<Auth> {
};
if (actionResult.status === 'error') {
throw new Error(
const error = new Error(
`ActionsClientChatVertexAI: action result status is error: ${actionResult?.message} - ${actionResult?.serviceMessage}`
);
if (actionResult?.serviceMessage) {
error.name = actionResult?.serviceMessage;
}
throw error;
}
if (actionResult.data.candidates && actionResult.data.candidates.length > 0) {

View file

@ -87,9 +87,13 @@ export class ActionsClientGeminiChatModel extends ChatGoogleGenerativeAI {
};
if (actionResult.status === 'error') {
throw new Error(
const error = new Error(
`ActionsClientGeminiChatModel: action result status is error: ${actionResult?.message} - ${actionResult?.serviceMessage}`
);
if (actionResult?.serviceMessage) {
error.name = actionResult?.serviceMessage;
}
throw error;
}
if (actionResult.data.candidates && actionResult.data.candidates.length > 0) {
@ -162,9 +166,13 @@ export class ActionsClientGeminiChatModel extends ChatGoogleGenerativeAI {
const actionResult = await this.#actionsClient.execute(requestBody);
if (actionResult.status === 'error') {
throw new Error(
const error = new Error(
`ActionsClientGeminiChatModel: action result status is error: ${actionResult?.message} - ${actionResult?.serviceMessage}`
);
if (actionResult?.serviceMessage) {
error.name = actionResult?.serviceMessage;
}
throw error;
}
const readable = get('data', actionResult) as Readable;

View file

@ -108,9 +108,13 @@ export class ActionsClientLlm extends LLM {
const actionResult = await this.#actionsClient.execute(requestBody);
if (actionResult.status === 'error') {
throw new Error(
const error = new Error(
`${LLM_TYPE}: action result status is error: ${actionResult?.message} - ${actionResult?.serviceMessage}`
);
if (actionResult?.serviceMessage) {
error.name = actionResult?.serviceMessage;
}
throw error;
}
const content = get('data.message', actionResult);

View file

@ -127,9 +127,13 @@ export class ActionsClientSimpleChatModel extends SimpleChatModel {
const actionResult = await this.#actionsClient.execute(requestBody);
if (actionResult.status === 'error') {
throw new Error(
const error = new Error(
`ActionsClientSimpleChatModel: action result status is error: ${actionResult?.message} - ${actionResult?.serviceMessage}`
);
if (actionResult?.serviceMessage) {
error.name = actionResult?.serviceMessage;
}
throw error;
}
if (!this.streaming) {
@ -217,9 +221,13 @@ export class ActionsClientSimpleChatModel extends SimpleChatModel {
const actionResult = await this.#actionsClient.execute(requestBody);
if (actionResult.status === 'error') {
throw new Error(
const error = new Error(
`ActionsClientSimpleChatModel: action result status is error: ${actionResult?.message} - ${actionResult?.serviceMessage}`
);
if (actionResult?.serviceMessage) {
error.name = actionResult?.serviceMessage;
}
throw error;
}
const readable = get('data', actionResult) as Readable;

View file

@ -58,22 +58,31 @@ export async function generateChatTitle({
state,
model,
}: GenerateChatTitleParams): Promise<Partial<AgentState>> {
logger.debug(
() => `${NodeType.GENERATE_CHAT_TITLE}: Node state:\n${JSON.stringify(state, null, 2)}`
);
try {
logger.debug(
() => `${NodeType.GENERATE_CHAT_TITLE}: Node state:\n${JSON.stringify(state, null, 2)}`
);
const outputParser = new StringOutputParser();
const graph = GENERATE_CHAT_TITLE_PROMPT(state.responseLanguage, state.llmType)
.pipe(model)
.pipe(outputParser);
const outputParser = new StringOutputParser();
const graph = GENERATE_CHAT_TITLE_PROMPT(state.responseLanguage, state.llmType)
.pipe(model)
.pipe(outputParser);
const chatTitle = await graph.invoke({
input: JSON.stringify(state.input, null, 2),
});
logger.debug(`chatTitle: ${chatTitle}`);
const chatTitle = await graph.invoke({
input: JSON.stringify(state.input, null, 2),
});
logger.debug(`chatTitle: ${chatTitle}`);
return {
chatTitle,
lastNode: NodeType.GENERATE_CHAT_TITLE,
};
return {
chatTitle,
lastNode: NodeType.GENERATE_CHAT_TITLE,
};
} catch (e) {
return {
// generate a chat title if there is an error in order to complete the graph
// limit title to 60 characters
chatTitle: (e.name ?? e.message ?? e.toString()).slice(0, 60),
lastNode: NodeType.GENERATE_CHAT_TITLE,
};
}
}

View file

@ -19,6 +19,7 @@ import {
createNewChat,
selectConversation,
assertMessageSent,
assertConversationTitle,
typeAndSendMessage,
assertErrorResponse,
selectRule,
@ -145,18 +146,16 @@ describe('AI Assistant Conversations', { tags: ['@ess', '@serverless'] }, () =>
assertConnectorSelected(bedrockConnectorAPIPayload.name);
assertMessageSent('goodbye');
});
// This test is flakey due to the issue linked below and will be skipped until it is fixed
it.skip('Only allows one conversation called "New chat" at a time', () => {
it('Correctly titles new conversations, and only allows one conversation called "New chat" at a time', () => {
visitGetStartedPage();
openAssistant();
createNewChat();
assertNewConversation(false, 'New chat');
assertConnectorSelected(azureConnectorAPIPayload.name);
typeAndSendMessage('hello');
// TODO fix bug with new chat and error message
// https://github.com/elastic/kibana/issues/191025
// assertMessageSent('hello');
assertErrorResponse();
assertMessageSent('hello');
assertConversationTitle('Unexpected API Error: - Connection error.');
updateConversationTitle('New chat');
selectConversation('Welcome');
createNewChat();
assertErrorToastShown('Error creating conversation with title New chat');

View file

@ -86,7 +86,7 @@ export const resetConversation = () => {
export const selectConversation = (conversationName: string) => {
cy.get(FLYOUT_NAV_TOGGLE).click();
cy.get(CONVERSATION_SELECT(conversationName)).click();
cy.get(CONVERSATION_TITLE + ' h2').should('have.text', conversationName);
assertConversationTitle(conversationName);
cy.get(FLYOUT_NAV_TOGGLE).click();
};
@ -95,7 +95,7 @@ export const updateConversationTitle = (newTitle: string) => {
cy.get(CONVERSATION_TITLE + ' input').clear();
cy.get(CONVERSATION_TITLE + ' input').type(newTitle);
cy.get(CONVERSATION_TITLE + ' input').type('{enter}');
cy.get(CONVERSATION_TITLE + ' h2').should('have.text', newTitle);
assertConversationTitle(newTitle);
};
export const typeAndSendMessage = (message: string) => {
@ -171,9 +171,12 @@ export const assertNewConversation = (isWelcome: boolean, title: string) => {
} else {
cy.get(EMPTY_CONVO).should('be.visible');
}
cy.get(CONVERSATION_TITLE + ' h2').should('have.text', title);
assertConversationTitle(title);
};
export const assertConversationTitle = (title: string) =>
cy.get(CONVERSATION_TITLE + ' h2').should('have.text', title);
export const assertSystemPromptSent = (message: string) => {
cy.get(CONVERSATION_MESSAGE).eq(0).should('contain', message);
};