From bb071a9c88edcdbb69335d1426229504c7ab5dcf Mon Sep 17 00:00:00 2001 From: majdyz Date: Sat, 11 Apr 2026 00:03:10 +0700 Subject: [PATCH] refactor(frontend/builder): address review comments in BuilderChatPanel - Remove useCallback from handleApplyAction (violates AGENTS.md) - Import TEXTAREA_MAX_LENGTH from PanelInput instead of duplicating constant - Remove dead @tanstack/react-query mock and associated invalidateQueries test --- .../__tests__/useBuilderChatPanel.test.ts | 29 --------- .../BuilderChatPanel/useBuilderChatPanel.ts | 64 +++++++++---------- 2 files changed, 29 insertions(+), 64 deletions(-) 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 d324392cb2..4ebb5a5841 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 @@ -52,11 +52,6 @@ vi.mock("@/services/environment", () => ({ environment: { getAGPTServerBaseUrl: () => "http://localhost:8000" }, })); -const mockInvalidateQueries = vi.fn(); -vi.mock("@tanstack/react-query", () => ({ - useQueryClient: () => ({ invalidateQueries: mockInvalidateQueries }), -})); - const mockToast = vi.fn(); vi.mock("@/components/molecules/Toast/use-toast", () => ({ useToast: () => ({ toast: mockToast }), @@ -108,7 +103,6 @@ beforeEach(() => { mockSetNodes.mockClear(); mockSetEdges.mockClear(); mockPostV2CreateSession.mockClear(); - mockInvalidateQueries.mockClear(); mockSendMessage.mockClear(); mockSetMessages.mockClear(); mockToast.mockClear(); @@ -428,29 +422,6 @@ describe("useBuilderChatPanel – flowID reset", () => { }); }); -describe("useBuilderChatPanel – apply does not trigger cache refetch", () => { - it("does NOT call invalidateQueries after applying an update_node_input action (prevents refetch overwriting local state)", () => { - mockNodes.push({ - id: "n1", - data: { hardcodedValues: { existing: "val" } }, - }); - mockFlowID = "flow-cache"; - - const { result } = renderHook(() => useBuilderChatPanel()); - - act(() => { - result.current.handleApplyAction({ - type: "update_node_input", - nodeId: "n1", - key: "query", - value: "new val", - }); - }); - - expect(mockInvalidateQueries).not.toHaveBeenCalled(); - }); -}); - describe("useBuilderChatPanel – handleApplyAction", () => { it("update_node_input: calls setNodes with merged hardcodedValues (bypasses history)", () => { mockNodes.push({ 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 bfb64c6a2d..0290e710a8 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 @@ -7,7 +7,6 @@ import { DefaultChatTransport } from "ai"; import { type KeyboardEvent, type RefObject, - useCallback, useEffect, useMemo, useRef, @@ -31,12 +30,10 @@ import { parseGraphActions, serializeGraphForChat, } from "./helpers"; +import { TEXTAREA_MAX_LENGTH } from "./components/PanelInput"; type SendMessageFn = ReturnType["sendMessage"]; -/** Maximum characters accepted by `sendRawMessage`, mirroring the textarea `maxLength`. */ -const MAX_RAW_MESSAGE_LENGTH = 4000; - /** * Per-graph session cache with a simple LRU cap. * Maps flowID → sessionId so the same chat session is reused each time the @@ -452,35 +449,32 @@ export function useBuilderChatPanel({ } } - const handleApplyAction = useCallback( - (action: GraphAction) => { - const deps: ApplyActionDeps = { - toast, - setNodes, - setEdges, - setUndoStack, - setAppliedActionKeys, - }; - let applied = false; - if (action.type === "update_node_input") { - applied = applyUpdateNodeInput(action, deps); - } else if (action.type === "connect_nodes") { - applied = applyConnectNodes(action, deps); - } else { - // Exhaustiveness guard — TypeScript ensures all GraphAction types are handled above. - const _: never = action; - void _; - } - if (applied) { - setAppliedActionKeys((prev) => { - const next = new Set(prev); - next.add(getActionKey(action)); - return next; - }); - } - }, - [toast, setNodes, setEdges], - ); + function handleApplyAction(action: GraphAction) { + const deps: ApplyActionDeps = { + toast, + setNodes, + setEdges, + setUndoStack, + setAppliedActionKeys, + }; + let applied = false; + if (action.type === "update_node_input") { + applied = applyUpdateNodeInput(action, deps); + } else if (action.type === "connect_nodes") { + applied = applyConnectNodes(action, deps); + } else { + // Exhaustiveness guard — TypeScript ensures all GraphAction types are handled above. + const _: never = action; + void _; + } + if (applied) { + setAppliedActionKeys((prev) => { + const next = new Set(prev); + next.add(getActionKey(action)); + return next; + }); + } + } function handleUndoLastAction() { // Read the current stack directly rather than inside the setUndoStack updater. @@ -502,8 +496,8 @@ export function useBuilderChatPanel({ function sendRawMessage(text: string) { if (!text || !canSend) return; const trimmed = - text.length > MAX_RAW_MESSAGE_LENGTH - ? text.slice(0, MAX_RAW_MESSAGE_LENGTH) + text.length > TEXTAREA_MAX_LENGTH + ? text.slice(0, TEXTAREA_MAX_LENGTH) : text; sendMessage({ text: trimmed }); }