From 538253197079e92117943a6e18021094ddda76fa Mon Sep 17 00:00:00 2001 From: Suguru Inoue Date: Fri, 4 Apr 2025 11:07:35 +0200 Subject: [PATCH] fix(editor): Memory getting rendered in chat on workflow load (#14346) --- .../components/CanvasChat/CanvasChat.test.ts | 49 +++++++------------ .../composables/useChatMessaging.ts | 46 ++--------------- .../CanvasChat/composables/useChatState.ts | 9 +--- 3 files changed, 22 insertions(+), 82 deletions(-) diff --git a/packages/frontend/editor-ui/src/components/CanvasChat/CanvasChat.test.ts b/packages/frontend/editor-ui/src/components/CanvasChat/CanvasChat.test.ts index 689af763c2..0e33ce42cf 100644 --- a/packages/frontend/editor-ui/src/components/CanvasChat/CanvasChat.test.ts +++ b/packages/frontend/editor-ui/src/components/CanvasChat/CanvasChat.test.ts @@ -315,12 +315,15 @@ describe('CanvasChat', () => { ]; beforeEach(() => { - vi.spyOn(useChatMessaging, 'useChatMessaging').mockReturnValue({ - getChatMessages: vi.fn().mockReturnValue(mockMessages), - sendMessage: vi.fn(), - extractResponseMessage: vi.fn(), - previousMessageIndex: ref(0), - isLoading: computed(() => false), + vi.spyOn(useChatMessaging, 'useChatMessaging').mockImplementation(({ messages }) => { + messages.value.push(...mockMessages); + + return { + sendMessage: vi.fn(), + extractResponseMessage: vi.fn(), + previousMessageIndex: ref(0), + isLoading: computed(() => false), + }; }); }); @@ -381,7 +384,6 @@ describe('CanvasChat', () => { describe('file handling', () => { beforeEach(() => { vi.spyOn(useChatMessaging, 'useChatMessaging').mockReturnValue({ - getChatMessages: vi.fn().mockReturnValue([]), sendMessage: vi.fn(), extractResponseMessage: vi.fn(), previousMessageIndex: ref(0), @@ -478,12 +480,15 @@ describe('CanvasChat', () => { createdAt: new Date().toISOString(), }, ]; - vi.spyOn(useChatMessaging, 'useChatMessaging').mockReturnValue({ - getChatMessages: vi.fn().mockReturnValue(mockMessages), - sendMessage: sendMessageSpy, - extractResponseMessage: vi.fn(), - previousMessageIndex: ref(0), - isLoading: computed(() => false), + vi.spyOn(useChatMessaging, 'useChatMessaging').mockImplementation(({ messages }) => { + messages.value.push(...mockMessages); + + return { + sendMessage: sendMessageSpy, + extractResponseMessage: vi.fn(), + previousMessageIndex: ref(0), + isLoading: computed(() => false), + }; }); workflowsStore.messages = mockMessages; }); @@ -584,22 +589,4 @@ describe('CanvasChat', () => { expect(input).toHaveValue('Line 1\nLine 2'); }); }); - - describe('chat synchronization', () => { - it('should load initial chat history when first opening panel', async () => { - const getChatMessagesSpy = vi.fn().mockReturnValue(['Previous message']); - vi.spyOn(useChatMessaging, 'useChatMessaging').mockReturnValue({ - ...vi.fn()(), - getChatMessages: getChatMessagesSpy, - }); - - workflowsStore.chatPanelState = LOGS_PANEL_STATE.CLOSED; - const { rerender } = renderComponent(); - - workflowsStore.chatPanelState = LOGS_PANEL_STATE.ATTACHED; - await rerender({}); - - expect(getChatMessagesSpy).toHaveBeenCalled(); - }); - }); }); diff --git a/packages/frontend/editor-ui/src/components/CanvasChat/composables/useChatMessaging.ts b/packages/frontend/editor-ui/src/components/CanvasChat/composables/useChatMessaging.ts index 128a82fdfb..07ea360002 100644 --- a/packages/frontend/editor-ui/src/components/CanvasChat/composables/useChatMessaging.ts +++ b/packages/frontend/editor-ui/src/components/CanvasChat/composables/useChatMessaging.ts @@ -1,8 +1,8 @@ import type { ComputedRef, Ref } from 'vue'; import { computed, ref } from 'vue'; import { v4 as uuid } from 'uuid'; -import type { ChatMessage, ChatMessageText } from '@n8n/chat/types'; -import { NodeConnectionTypes, CHAT_TRIGGER_NODE_TYPE } from 'n8n-workflow'; +import type { ChatMessage } from '@n8n/chat/types'; +import { CHAT_TRIGGER_NODE_TYPE } from 'n8n-workflow'; import type { ITaskData, INodeExecutionData, @@ -10,16 +10,14 @@ import type { IDataObject, IBinaryData, BinaryFileType, - Workflow, IRunExecutionData, } from 'n8n-workflow'; import { useToast } from '@/composables/useToast'; import { useMessage } from '@/composables/useMessage'; import { usePinnedData } from '@/composables/usePinnedData'; -import { get, isEmpty, last } from 'lodash-es'; +import { get, isEmpty } from 'lodash-es'; import { MANUAL_CHAT_TRIGGER_NODE_TYPE, MODAL_CONFIRM } from '@/constants'; import { useI18n } from '@/composables/useI18n'; -import type { MemoryOutput } from '../types/chat'; import type { IExecutionPushResponse, INodeUi } from '@/Interface'; export type RunWorkflowChatPayload = { @@ -30,12 +28,9 @@ export type RunWorkflowChatPayload = { }; export interface ChatMessagingDependencies { chatTrigger: Ref; - connectedNode: Ref; messages: Ref; sessionId: Ref; - workflow: ComputedRef; executionResultData: ComputedRef; - getWorkflowResultDataByNodeName: (nodeName: string) => ITaskData[] | null; onRunChatWorkflow: ( payload: RunWorkflowChatPayload, ) => Promise; @@ -43,12 +38,9 @@ export interface ChatMessagingDependencies { export function useChatMessaging({ chatTrigger, - connectedNode, messages, sessionId, - workflow, executionResultData, - getWorkflowResultDataByNodeName, onRunChatWorkflow, }: ChatMessagingDependencies) { const locale = useI18n(); @@ -247,42 +239,10 @@ export function useChatMessaging({ await startWorkflowWithMessage(newMessage.text, files); } - function getChatMessages(): ChatMessageText[] { - if (!connectedNode.value) return []; - - const connectedMemoryInputs = - workflow.value.connectionsByDestinationNode?.[connectedNode.value.name]?.[ - NodeConnectionTypes.AiMemory - ]; - if (!connectedMemoryInputs) return []; - - const memoryConnection = (connectedMemoryInputs ?? []).find((i) => (i ?? []).length > 0)?.[0]; - - if (!memoryConnection) return []; - - const nodeResultData = getWorkflowResultDataByNodeName(memoryConnection.node); - - const memoryOutputData = (nodeResultData ?? []) - .map( - (data) => get(data, ['data', NodeConnectionTypes.AiMemory, 0, 0, 'json']) as MemoryOutput, - ) - .find((data) => data && data.action === 'saveContext'); - - return (memoryOutputData?.chatHistory ?? []).map((message, index) => { - return { - createdAt: new Date().toISOString(), - text: message.kwargs.content, - id: `preload__${index}`, - sender: last(message.id) === 'HumanMessage' ? 'user' : 'bot', - }; - }); - } - return { previousMessageIndex, isLoading: computed(() => isLoading.value), sendMessage, extractResponseMessage, - getChatMessages, }; } diff --git a/packages/frontend/editor-ui/src/components/CanvasChat/composables/useChatState.ts b/packages/frontend/editor-ui/src/components/CanvasChat/composables/useChatState.ts index dce6a9d810..46412a8f8b 100644 --- a/packages/frontend/editor-ui/src/components/CanvasChat/composables/useChatState.ts +++ b/packages/frontend/editor-ui/src/components/CanvasChat/composables/useChatState.ts @@ -60,14 +60,11 @@ export function useChatState(isDisabled: Ref, onWindowResize: () => voi getNodeType: nodeTypesStore.getNodeType, }); - const { sendMessage, getChatMessages, isLoading } = useChatMessaging({ + const { sendMessage, isLoading } = useChatMessaging({ chatTrigger: chatTriggerNode, - connectedNode, messages, sessionId: currentSessionId, - workflow, executionResultData: computed(() => workflowsStore.getWorkflowExecution?.data?.resultData), - getWorkflowResultDataByNodeName: workflowsStore.getWorkflowResultDataByNodeName, onRunChatWorkflow, }); @@ -134,10 +131,6 @@ export function useChatState(isDisabled: Ref, onWindowResize: () => voi setChatTriggerNode(); setConnectedNode(); - if (messages.value.length === 0) { - messages.value = getChatMessages(); - } - setTimeout(() => { onWindowResize(); chatEventBus.emit('focusInput');