diff --git a/autogpt_platform/frontend/src/app/(platform)/build/components/BuilderChatPanel/__tests__/useBuilderChatPanel.test.ts b/autogpt_platform/frontend/src/app/(platform)/build/components/BuilderChatPanel/__tests__/useBuilderChatPanel.test.ts index d1d4504df4..7711314fc2 100644 --- a/autogpt_platform/frontend/src/app/(platform)/build/components/BuilderChatPanel/__tests__/useBuilderChatPanel.test.ts +++ b/autogpt_platform/frontend/src/app/(platform)/build/components/BuilderChatPanel/__tests__/useBuilderChatPanel.test.ts @@ -359,6 +359,39 @@ describe("useBuilderChatPanel – flowID reset", () => { expect(result.current.sessionError).toBe(false); }); + + it("always clears messages on flowID change even when a cached session exists (prevents applied/unapplied mismatch)", async () => { + mockPostV2CreateSession.mockResolvedValue({ + status: 200, + data: { id: "sess-cached" }, + }); + mockFlowID = "flow-1"; + + const { result, rerender } = renderHook(() => useBuilderChatPanel()); + + await openAndFlush(() => result.current.handleToggle()); + expect(result.current.sessionId).toBe("sess-cached"); + + // Simulate chat messages from the first session + mockChatMessages = [ + { + id: "msg-1", + role: "assistant", + parts: [{ type: "text", text: "Hello from session 1" }], + }, + ]; + mockSetMessages.mockClear(); + + // Navigate away and back to the same graph — cached session should be restored + // but messages must be cleared to stay in sync with the reset appliedActionKeys + mockFlowID = "flow-2"; + rerender(); + mockFlowID = "flow-1"; + rerender(); + + // setMessages([]) must be called unconditionally regardless of cached session + expect(mockSetMessages).toHaveBeenCalledWith([]); + }); }); describe("useBuilderChatPanel – apply does not trigger cache refetch", () => { diff --git a/autogpt_platform/frontend/src/app/(platform)/build/components/BuilderChatPanel/useBuilderChatPanel.ts b/autogpt_platform/frontend/src/app/(platform)/build/components/BuilderChatPanel/useBuilderChatPanel.ts index 8a6a89efd4..099fe10edf 100644 --- a/autogpt_platform/frontend/src/app/(platform)/build/components/BuilderChatPanel/useBuilderChatPanel.ts +++ b/autogpt_platform/frontend/src/app/(platform)/build/components/BuilderChatPanel/useBuilderChatPanel.ts @@ -122,8 +122,10 @@ export function useBuilderChatPanel({ const setEdges = useEdgeStore((s) => s.setEdges); // When the user navigates to a different graph: restore the cached session for - // that graph (preserving conversation history) and reset per-session UI state. - // Messages are only cleared when there is no prior session for the new graph. + // that graph (preserving the backend session) and reset all per-session UI state. + // Messages are always cleared on navigation — appliedActionKeys cannot be persisted + // so restoring messages while resetting action state would show previously applied + // actions as unapplied, allowing them to be re-applied and creating duplicate undo entries. useEffect(() => { const cachedSessionId = flowID ? (graphSessionCache.get(flowID) ?? null) @@ -136,9 +138,7 @@ export function useBuilderChatPanel({ isCreatingSessionRef.current = false; processedToolCallsRef.current = new Set(); hasSentSeedMessageRef.current = false; - if (!cachedSessionId) { - setMessages([]); - } + setMessages([]); // setMessages is a stable function from useChat; excluding from deps is safe. // eslint-disable-next-line react-hooks/exhaustive-deps }, [flowID]);