From 2f6a02a7fa2804dd28900a71fb933bdc9fe40fd9 Mon Sep 17 00:00:00 2001 From: Zamil Majdy Date: Thu, 16 Apr 2026 00:11:26 +0700 Subject: [PATCH] fix(frontend/copilot): skip extraToolOutputs extraction for forward pagination --- .../__tests__/useLoadMoreMessages.test.ts | 34 +++++++++++++++++-- .../(platform)/copilot/useLoadMoreMessages.ts | 12 +++---- 2 files changed, 38 insertions(+), 8 deletions(-) diff --git a/autogpt_platform/frontend/src/app/(platform)/copilot/__tests__/useLoadMoreMessages.test.ts b/autogpt_platform/frontend/src/app/(platform)/copilot/__tests__/useLoadMoreMessages.test.ts index a196b5cfca..c8d8f0d074 100644 --- a/autogpt_platform/frontend/src/app/(platform)/copilot/__tests__/useLoadMoreMessages.test.ts +++ b/autogpt_platform/frontend/src/app/(platform)/copilot/__tests__/useLoadMoreMessages.test.ts @@ -395,7 +395,37 @@ describe("useLoadMoreMessages", () => { }); describe("pagedMessages — initialPageRawMessages extraToolOutputs", () => { - it("calls extractToolOutputsFromRaw when initialPageRawMessages is non-empty", async () => { + it("calls extractToolOutputsFromRaw for backward pagination with non-empty initialPageRawMessages", async () => { + const { extractToolOutputsFromRaw } = await import( + "../helpers/convertChatSessionToUiMessages" + ); + + const rawMsg = { role: "user", content: "old", sequence: 0 }; + mockGetV2GetSession.mockResolvedValueOnce( + makeSuccessResponse({ + messages: [rawMsg], + has_more_messages: false, + oldest_sequence: 0, + }), + ); + + const { result } = renderHook(() => + useLoadMoreMessages({ + ...BASE_ARGS, + forwardPaginated: false, + initialOldestSequence: 50, + initialPageRawMessages: [{ role: "assistant", content: "response" }], + }), + ); + + await act(async () => { + await result.current.loadMore(); + }); + + expect(extractToolOutputsFromRaw).toHaveBeenCalled(); + }); + + it("does NOT call extractToolOutputsFromRaw for forward pagination", async () => { const { extractToolOutputsFromRaw } = await import( "../helpers/convertChatSessionToUiMessages" ); @@ -421,7 +451,7 @@ describe("useLoadMoreMessages", () => { await result.current.loadMore(); }); - expect(extractToolOutputsFromRaw).toHaveBeenCalled(); + expect(extractToolOutputsFromRaw).not.toHaveBeenCalled(); }); }); diff --git a/autogpt_platform/frontend/src/app/(platform)/copilot/useLoadMoreMessages.ts b/autogpt_platform/frontend/src/app/(platform)/copilot/useLoadMoreMessages.ts index f9d2e0cad8..340cecfa06 100644 --- a/autogpt_platform/frontend/src/app/(platform)/copilot/useLoadMoreMessages.ts +++ b/autogpt_platform/frontend/src/app/(platform)/copilot/useLoadMoreMessages.ts @@ -102,15 +102,15 @@ export function useLoadMoreMessages({ // Convert all accumulated raw messages in one pass so tool outputs // are matched across inter-page boundaries. - // Initial page tool outputs are included via extraToolOutputs for both - // backward pagination (older paged pages may contain calls whose outputs - // are in the initial/streaming page) and forward pagination (paged pages - // may contain outputs whose calls are in the initial page at the boundary). + // For backward pagination only: include initial page tool outputs so older + // paged pages can match tool calls whose outputs landed in the initial page. + // For forward pagination this is unnecessary — tool calls in newer paged + // pages cannot have their outputs in the older initial page. const pagedMessages: UIMessage[] = useMemo(() => { if (!sessionId || pagedRawMessages.length === 0) return []; const extraToolOutputs = - initialPageRawMessages.length > 0 + !forwardPaginated && initialPageRawMessages.length > 0 ? extractToolOutputsFromRaw(initialPageRawMessages) : undefined; return convertChatSessionMessagesToUiMessages( @@ -118,7 +118,7 @@ export function useLoadMoreMessages({ pagedRawMessages, { isComplete: true, extraToolOutputs }, ).messages; - }, [sessionId, pagedRawMessages, initialPageRawMessages]); + }, [sessionId, pagedRawMessages, initialPageRawMessages, forwardPaginated]); async function loadMore() { if (!sessionId || !hasMore || isLoadingMoreRef.current) return;