fix(editor): Ignore all node run messages after a success message is sent (no-changelog) (#11668)

This commit is contained in:
Ricardo Espinoza 2024-11-12 06:58:46 -05:00 committed by GitHub
parent b5cbf7566d
commit 7b20c1e93d
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
3 changed files with 80 additions and 2 deletions

View file

@ -224,6 +224,54 @@ describe('AI Assistant::enabled', () => {
.should('contain.text', 'item.json.myNewField = 1'); .should('contain.text', 'item.json.myNewField = 1');
}); });
it('Should ignore node execution success and error messages after the node run successfully once', () => {
const getParameter = () => ndv.getters.parameterInput('jsCode').should('be.visible');
const getEditor = () => getParameter().find('.cm-content').should('exist');
cy.intercept('POST', '/rest/ai/chat', {
statusCode: 200,
fixture: 'aiAssistant/responses/code_diff_suggestion_response.json',
}).as('chatRequest');
cy.createFixtureWorkflow('aiAssistant/workflows/test_workflow.json');
wf.actions.openNode('Code');
ndv.getters.nodeExecuteButton().click();
aiAssistant.getters.nodeErrorViewAssistantButton().click({ force: true });
cy.wait('@chatRequest');
cy.intercept('POST', '/rest/ai/chat', {
statusCode: 200,
fixture: 'aiAssistant/responses/node_execution_succeeded_response.json',
}).as('chatRequest2');
getEditor()
.type('{selectall}')
.paste(
'for (const item of $input.all()) {\n item.json.myNewField = 1;\n}\n\nreturn $input.all();',
);
ndv.getters.nodeExecuteButton().click();
getEditor()
.type('{selectall}')
.paste(
'for (const item of $input.all()) {\n item.json.myNewField = 1aaaa!;\n}\n\nreturn $input.all();',
);
ndv.getters.nodeExecuteButton().click();
aiAssistant.getters.chatMessagesAssistant().should('have.length', 3);
aiAssistant.getters
.chatMessagesAssistant()
.eq(2)
.should(
'contain.text',
'Code node ran successfully, did my solution help resolve your issue?\nQuick reply 👇Yes, thanksNo, I am still stuck',
);
});
it('should end chat session when `end_session` event is received', () => { it('should end chat session when `end_session` event is received', () => {
cy.intercept('POST', '/rest/ai/chat', { cy.intercept('POST', '/rest/ai/chat', {
statusCode: 200, statusCode: 200,

View file

@ -0,0 +1,22 @@
{
"sessionId": "1",
"messages": [
{
"role": "assistant",
"type": "message",
"text": "**Code** node ran successfully, did my solution help resolve your issue?",
"quickReplies": [
{
"text": "Yes, thanks",
"type": "all-good",
"isFeedback": true
},
{
"text": "No, I am still stuck",
"type": "still-stuck",
"isFeedback": true
}
]
}
]
}

View file

@ -72,13 +72,15 @@ export const useAssistantStore = defineStore(STORES.ASSISTANT, () => {
}; };
}>({}); }>({});
type NodeExecutionStatus = 'error' | 'not_executed' | 'success';
const chatSessionCredType = ref<ICredentialType | undefined>(); const chatSessionCredType = ref<ICredentialType | undefined>();
const chatSessionError = ref<ChatRequest.ErrorContext | undefined>(); const chatSessionError = ref<ChatRequest.ErrorContext | undefined>();
const currentSessionId = ref<string | undefined>(); const currentSessionId = ref<string | undefined>();
const currentSessionActiveExecutionId = ref<string | undefined>(); const currentSessionActiveExecutionId = ref<string | undefined>();
const currentSessionWorkflowId = ref<string | undefined>(); const currentSessionWorkflowId = ref<string | undefined>();
const lastUnread = ref<ChatUI.AssistantMessage | undefined>(); const lastUnread = ref<ChatUI.AssistantMessage | undefined>();
const nodeExecutionStatus = ref<'not_executed' | 'success' | 'error'>('not_executed'); const nodeExecutionStatus = ref<NodeExecutionStatus>('not_executed');
// This is used to show a message when the assistant is performing intermediate steps // This is used to show a message when the assistant is performing intermediate steps
// We use streaming for assistants that support it, and this for agents // We use streaming for assistants that support it, and this for agents
const assistantThinkingMessage = ref<string | undefined>(); const assistantThinkingMessage = ref<string | undefined>();
@ -536,10 +538,16 @@ export const useAssistantStore = defineStore(STORES.ASSISTANT, () => {
(e) => handleServiceError(e, id, async () => await sendEvent(eventName, error)), (e) => handleServiceError(e, id, async () => await sendEvent(eventName, error)),
); );
} }
async function onNodeExecution(pushEvent: PushPayload<'nodeExecuteAfter'>) { async function onNodeExecution(pushEvent: PushPayload<'nodeExecuteAfter'>) {
if (!chatSessionError.value || pushEvent.nodeName !== chatSessionError.value.node.name) { if (!chatSessionError.value || pushEvent.nodeName !== chatSessionError.value.node.name) {
return; return;
} }
if (nodeExecutionStatus.value === 'success') {
return;
}
if (pushEvent.data.error && nodeExecutionStatus.value !== 'error') { if (pushEvent.data.error && nodeExecutionStatus.value !== 'error') {
await sendEvent('node-execution-errored', pushEvent.data.error); await sendEvent('node-execution-errored', pushEvent.data.error);
nodeExecutionStatus.value = 'error'; nodeExecutionStatus.value = 'error';
@ -550,7 +558,7 @@ export const useAssistantStore = defineStore(STORES.ASSISTANT, () => {
}); });
} else if ( } else if (
pushEvent.data.executionStatus === 'success' && pushEvent.data.executionStatus === 'success' &&
nodeExecutionStatus.value !== 'success' ['error', 'not_executed'].includes(nodeExecutionStatus.value)
) { ) {
await sendEvent('node-execution-succeeded'); await sendEvent('node-execution-succeeded');
nodeExecutionStatus.value = 'success'; nodeExecutionStatus.value = 'success';