Skip to content

fix(frontend/copilot): load older chat messages reliably and preserve scrollback across turns - #12792

Merged
kcze merged 6 commits into
devfrom
kpczerwinski/secrt-2226-chat-history-fails-to-load-when-last-response-fits-entirely
Apr 15, 2026
Merged

fix(frontend/copilot): load older chat messages reliably and preserve scrollback across turns#12792
kcze merged 6 commits into
devfrom
kpczerwinski/secrt-2226-chat-history-fails-to-load-when-last-response-fits-entirely

Conversation

@kcze

@kcze kcze commented Apr 15, 2026

Copy link
Copy Markdown
Contributor

Why / What / How

Fixes two SECRT-2226 bugs in copilot chat pagination.

Bug 1 — can't load older messages when the newest page fits on screen. The IntersectionObserver in LoadMoreSentinel bailed when scrollHeight <= clientHeight, which happens routinely once reasoning + tool groups collapse. With no scrollbar and no button, users were stuck. Fix: remove the guard, cap auto-fill at 3 non-scrollable rounds (keeps the original anti-loop intent), and add a manual "Load older messages" button as the always-available escape hatch.

Bug 2 — older loaded pages vanish after a new turn, then reloading them produces duplicates. After each stream useCopilotStream invalidates the session query; the refetch returns a shifted oldest_sequence, which useLoadMoreMessages used as a signal to wipe olderRawMessages and reset the local cursor. Scroll-back history was lost on every turn, and the next load fetched a page that overlapped with AI SDK's retained currentMessages — the "loops" users reported. Fix: once any older page is loaded, preserve olderRawMessages and the local cursor across same-session refetches. Only reset on session change. The gap between the new initial window and older pages is covered by AI SDK's retained state.

Changes 🏗️

  • ChatMessagesContainer.tsx: drop the scrollability guard; add MAX_AUTO_FILL_ROUNDS = 3 counter; add "Load older messages" button (ghost/small); distinguish observer-triggered vs. button-triggered loads so the button bypasses the cap; export LoadMoreSentinel for testing.
  • useLoadMoreMessages.ts: remove the wipe-and-reset branch on initialOldestSequence change; preserve local state mid-session; still mirror parent's cursor while no older page is loaded.
  • New integration test __tests__/LoadMoreSentinel.test.tsx.

No backend changes.

Checklist 📋

For code changes:

  • I have clearly listed my changes in the PR description
  • I have made a test plan
  • I have tested my changes according to the test plan:
    • Short/collapsed newest page: "Load older messages" button loads older pages, preserves scroll
    • Full-viewport newest page: scroll-to-top auto-pagination still works (no regression)
    • has_more_messages=false hides the button; isLoadingMore=true shows spinner instead
    • Bug 2 reproduced locally with temporary limit=5: before fix older page vanished and next load duplicated AI SDK messages; after fix older page stays and next load fetches cleanly further back
    • pnpm format, pnpm lint, pnpm types, pnpm test:unit all pass (1208/1208)

For configuration changes:

  • .env.default is updated or already compatible with my changes
  • docker-compose.yml is updated or already compatible with my changes
  • I have included a list of my configuration changes in the PR description (under Changes) — N/A

kcze and others added 2 commits April 15, 2026 17:29
… viewport

The IntersectionObserver guard (scrollHeight <= clientHeight) prevented
pagination whenever the rendered page collapsed below viewport height
(common after reasoning + tool groups fold into CollapsedToolGroup /
ReasoningCollapse), leaving users unable to access older history.

Remove the guard, cap auto-fill at 3 consecutive non-scrollable rounds,
and add a manual "Load older messages" button as the always-available
escape hatch.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
…6-chat-history-fails-to-load-when-last-response-fits-entirely
@kcze
kcze requested a review from a team as a code owner April 15, 2026 08:37
@kcze
kcze requested review from Pwuts and majdyz and removed request for a team April 15, 2026 08:37
@github-project-automation github-project-automation Bot moved this to 🆕 Needs initial review in AutoGPT development kanban Apr 15, 2026
@github-actions github-actions Bot added the platform/frontend AutoGPT Platform - Front end label Apr 15, 2026
@coderabbitai

coderabbitai Bot commented Apr 15, 2026

Copy link
Copy Markdown
Contributor

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 8a69a4a4-e140-4123-8908-400e350a4157

📥 Commits

Reviewing files that changed from the base of the PR and between 00cadee and c89069a.

📒 Files selected for processing (1)
  • autogpt_platform/frontend/src/app/(platform)/copilot/components/ChatMessagesContainer/__tests__/LoadMoreSentinel.test.tsx
🚧 Files skipped from review as they are similar to previous changes (1)
  • autogpt_platform/frontend/src/app/(platform)/copilot/components/ChatMessagesContainer/tests/LoadMoreSentinel.test.tsx
📜 Recent review details
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (2)
  • GitHub Check: end-to-end tests
  • GitHub Check: Check PR Status

Walkthrough

Adds a manual "Load older messages" button and exports LoadMoreSentinel; implements capped observer-triggered auto-fill with scroll-metric snapshotting and updated scroll-restoration logic; adds comprehensive tests for sentinel behavior; and changes useLoadMoreMessages to avoid clearing paged state when initialOldestSequence shifts while pages exist.

Changes

Cohort / File(s) Summary
ChatMessagesContainer / LoadMoreSentinel
autogpt_platform/frontend/src/app/(platform)/copilot/components/ChatMessagesContainer/ChatMessagesContainer.tsx
Exported LoadMoreSentinel; added manual "Load older messages" Button; sentinel now renders spinner vs button based on isLoading/hasMore; introduced MAX_AUTO_FILL_ROUNDS and autoFillRoundsRef; replaced DOM-based non-scrollable detection with captureAndLoad(fromObserver) that snapshots scrollHeight/scrollTop before invoking onLoadMore; updated post-prepend useLayoutEffect to reset/increment auto-fill counters, clear snapshot and observer flag.
LoadMoreSentinel Tests
autogpt_platform/frontend/src/app/(platform)/copilot/components/ChatMessagesContainer/__tests__/LoadMoreSentinel.test.tsx
Added Vitest suite that mocks use-stick-to-bottom and IntersectionObserver; verifies conditional rendering (button vs spinner vs hidden), click behavior, observer-driven triggers, scrollTop restoration after prepend, and auto-fill backoff after consecutive non-scrollable rounds; cleans up stubs per test.
useLoadMoreMessages hook
autogpt_platform/frontend/src/app/(platform)/copilot/useLoadMoreMessages.ts
Changed sync effect: when initialOldestSequence changes for the same sessionId, do not wipe existing paged olderRawMessages; always track latest initialOldestSequence, and only mirror initialOldestSequence/initialHasMore into local oldestSequence/hasMore when olderRawMessages.length === 0.

Sequence Diagram(s)

sequenceDiagram
    participant Observer as Intersection Observer
    participant Sentinel as LoadMoreSentinel
    participant Scroll as Scroll Container
    participant Loader as onLoadMore Callback

    Observer->>Sentinel: sentinel intersects viewport
    Sentinel->>Sentinel: captureAndLoad(fromObserver=true)
    Sentinel->>Scroll: read scrollHeight & clientHeight (snapshot)
    Sentinel->>Loader: call onLoadMore()
    Loader->>Scroll: prepend older messages to DOM
    Scroll->>Sentinel: useLayoutEffect runs after DOM update
    Sentinel->>Sentinel: compare new scrollHeight vs clientHeight
    alt scrollHeight > clientHeight
        Sentinel->>Sentinel: reset autoFillRoundsRef (allow auto-trigger)
    else still non-scrollable
        Sentinel->>Sentinel: increment autoFillRoundsRef (backoff)
    end
    alt autoFillRoundsRef < MAX_AUTO_FILL_ROUNDS
        Sentinel->>Observer: keep observer auto-trigger enabled
    else
        Sentinel->>Observer: stop auto-triggering (manual button only)
    end
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Possibly related PRs

Suggested reviewers

  • 0ubbe
  • Pwuts
  • majdyz

Poem

🐰 I nudged the sentinel by the scrolling rim,
A button to fetch the old threads on a whim,
I counted my hops and capped them at three,
Kept the scroll steady so history stayed free,
Hooray — older messages, but gentle as a nibble!

🚥 Pre-merge checks | ✅ 2 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 50.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (2 passed)
Check name Status Explanation
Title check ✅ Passed The title accurately and concisely summarizes the main changes: fixing chat message loading reliability and preserving scrollback history across conversation turns, which directly aligns with the core objectives of addressing the two SECRT-2226 pagination bugs.
Description check ✅ Passed The description clearly explains both bugs being fixed, provides detailed rationale for each fix, lists all code changes, mentions testing, and confirms passing checks—all directly related to the changeset.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch kpczerwinski/secrt-2226-chat-history-fails-to-load-when-last-response-fits-entirely

Warning

Review ran into problems

🔥 Problems

Timed out fetching pipeline failures after 30000ms


Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@github-actions

github-actions Bot commented Apr 15, 2026

Copy link
Copy Markdown
Contributor

🔍 PR Overlap Detection

This check compares your PR against all other open PRs targeting the same branch to detect potential merge conflicts early.

🔴 Merge Conflicts Detected

The following PRs have been tested and will have merge conflicts if merged after this PR. Consider coordinating with the authors.

🟢 Low Risk — File Overlap Only

These PRs touch the same files but different sections (click to expand)

Summary: 1 conflict(s), 0 medium risk, 2 low risk (out of 3 PRs with file overlap)


Auto-generated on push. Ignores: openapi.json, lock files.

@kcze
kcze requested a review from 0ubbe April 15, 2026 08:37

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick comments (2)
autogpt_platform/frontend/src/app/(platform)/copilot/components/ChatMessagesContainer/__tests__/LoadMoreSentinel.test.tsx (2)

14-17: Redundant cleanup call.

Modern @testing-library/react (v13+) automatically runs cleanup after each test when using Vitest. The explicit cleanup() in afterEach is unnecessary and can be removed.

🧹 Proposed cleanup
 describe("LoadMoreSentinel", () => {
-  afterEach(() => {
-    cleanup();
-  });
-
   it("renders 'Load older messages' button when hasMore is true and not loading", () => {
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In
`@autogpt_platform/frontend/src/app/`(platform)/copilot/components/ChatMessagesContainer/__tests__/LoadMoreSentinel.test.tsx
around lines 14 - 17, Remove the redundant explicit cleanup call in the
LoadMoreSentinel test suite: delete the afterEach(() => { cleanup(); }) block in
the __tests__/LoadMoreSentinel.test.tsx file since `@testing-library/react` (v13+)
with Vitest auto-runs cleanup; leave the describe("LoadMoreSentinel", ...) and
tests intact, ensuring no other references to cleanup() remain.

49-61: Test description mentions spinner but doesn't verify it.

The test name "hides the button and shows a spinner while loading" promises two assertions, but only the button absence is verified. Consider adding a check for the spinner element to ensure the loading state renders correctly.

🔧 Suggested addition
   it("hides the button and shows a spinner while loading", () => {
     render(
       <LoadMoreSentinel
         hasMore={true}
         isLoading={true}
         messageCount={5}
         onLoadMore={vi.fn()}
       />,
     );
     expect(
       screen.queryByRole("button", { name: /load older messages/i }),
     ).toBeNull();
+    // Verify spinner is rendered (adjust query based on LoadingSpinner's DOM structure)
+    expect(screen.getByRole("status")).toBeDefined();
   });
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In
`@autogpt_platform/frontend/src/app/`(platform)/copilot/components/ChatMessagesContainer/__tests__/LoadMoreSentinel.test.tsx
around lines 49 - 61, The test for LoadMoreSentinel currently verifies the
button is hidden but doesn't assert the spinner is shown; update the test "hides
the button and shows a spinner while loading" to also assert the loading
indicator is rendered when isLoading={true} by adding an assertion such as
checking for a spinner by role or label (e.g., screen.getByRole("status") or
screen.getByLabelText(/loading/i) or a known test id like "spinner") after
rendering the <LoadMoreSentinel ... isLoading={true} /> so the loading state is
fully verified.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Nitpick comments:
In
`@autogpt_platform/frontend/src/app/`(platform)/copilot/components/ChatMessagesContainer/__tests__/LoadMoreSentinel.test.tsx:
- Around line 14-17: Remove the redundant explicit cleanup call in the
LoadMoreSentinel test suite: delete the afterEach(() => { cleanup(); }) block in
the __tests__/LoadMoreSentinel.test.tsx file since `@testing-library/react` (v13+)
with Vitest auto-runs cleanup; leave the describe("LoadMoreSentinel", ...) and
tests intact, ensuring no other references to cleanup() remain.
- Around line 49-61: The test for LoadMoreSentinel currently verifies the button
is hidden but doesn't assert the spinner is shown; update the test "hides the
button and shows a spinner while loading" to also assert the loading indicator
is rendered when isLoading={true} by adding an assertion such as checking for a
spinner by role or label (e.g., screen.getByRole("status") or
screen.getByLabelText(/loading/i) or a known test id like "spinner") after
rendering the <LoadMoreSentinel ... isLoading={true} /> so the loading state is
fully verified.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: eb986964-f9c0-44ab-89ed-18c00c54cefb

📥 Commits

Reviewing files that changed from the base of the PR and between da18f37 and e03f436.

📒 Files selected for processing (2)
  • autogpt_platform/frontend/src/app/(platform)/copilot/components/ChatMessagesContainer/ChatMessagesContainer.tsx
  • autogpt_platform/frontend/src/app/(platform)/copilot/components/ChatMessagesContainer/__tests__/LoadMoreSentinel.test.tsx
📜 Review details
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (7)
  • GitHub Check: integration_test
  • GitHub Check: lint
  • GitHub Check: check API types
  • GitHub Check: Seer Code Review
  • GitHub Check: end-to-end tests
  • GitHub Check: Analyze (python)
  • GitHub Check: Check PR Status
🧰 Additional context used
📓 Path-based instructions (12)
autogpt_platform/frontend/**/*.{ts,tsx,js,jsx}

📄 CodeRabbit inference engine (.github/copilot-instructions.md)

autogpt_platform/frontend/**/*.{ts,tsx,js,jsx}: Use Node.js 21+ with pnpm package manager for frontend development
Always run 'pnpm format' for formatting and linting code in frontend development

Format frontend code using pnpm format

Files:

  • autogpt_platform/frontend/src/app/(platform)/copilot/components/ChatMessagesContainer/ChatMessagesContainer.tsx
  • autogpt_platform/frontend/src/app/(platform)/copilot/components/ChatMessagesContainer/__tests__/LoadMoreSentinel.test.tsx
autogpt_platform/frontend/**/*.{tsx,ts}

📄 CodeRabbit inference engine (.github/copilot-instructions.md)

autogpt_platform/frontend/**/*.{tsx,ts}: Use function declarations for components and handlers (not arrow functions) in React components
Only use arrow functions for small inline lambdas (map, filter, etc.) in React components
Use PascalCase for component names and camelCase with 'use' prefix for hook names in React
Use Tailwind CSS utilities only for styling in frontend components
Use design system components from 'src/components/' (atoms, molecules, organisms) in frontend development
Never use 'src/components/legacy/' in frontend code
Only use Phosphor Icons (@phosphor-icons/react) for icons in frontend components
Use generated API hooks from '@/app/api/generated/endpoints/' instead of deprecated 'BackendAPI' or 'src/lib/autogpt-server-api/
'
Use React Query for server state (via generated hooks) in frontend development
Default to client components ('use client') in Next.js; only use server components for SEO or extreme TTFB needs
Use '' component for rendering errors in frontend UI; use toast notifications for mutation errors; use 'Sentry.captureException()' for manual exceptions
Separate render logic from data/behavior in React components; keep comments minimal (code should be self-documenting)

Files:

  • autogpt_platform/frontend/src/app/(platform)/copilot/components/ChatMessagesContainer/ChatMessagesContainer.tsx
  • autogpt_platform/frontend/src/app/(platform)/copilot/components/ChatMessagesContainer/__tests__/LoadMoreSentinel.test.tsx
autogpt_platform/frontend/**/*.{ts,tsx}

📄 CodeRabbit inference engine (.github/copilot-instructions.md)

autogpt_platform/frontend/**/*.{ts,tsx}: No barrel files or 'index.ts' re-exports in frontend code
Regenerate API hooks with 'pnpm generate:api' after backend OpenAPI spec changes in frontend development

autogpt_platform/frontend/**/*.{ts,tsx}: Fully capitalize acronyms in symbols, e.g. graphID, useBackendAPI
Use function declarations (not arrow functions) for components and handlers
No dark: Tailwind classes — the design system handles dark mode
Use Next.js <Link> for internal navigation — never raw <a> tags
No any types unless the value genuinely can be anything
No linter suppressors (// @ts-ignore``, // eslint-disable) — fix the actual issue
Keep files under ~200 lines; extract sub-components or hooks into their own files when a file grows beyond this
Keep render functions and hooks under ~50 lines; extract named helpers or sub-components when they grow longer
Use generated API hooks from `@/app/api/generated/endpoints/` with pattern `use{Method}{Version}{OperationName}` and regenerate with `pnpm generate:api`
Do not use `useCallback` or `useMemo` unless asked to optimise a given function
Separate render logic (`.tsx`) from business logic (`use*.ts` hooks)
Use ErrorCard for render errors, toast for mutations, and Sentry for exceptions in the frontend

Files:

  • autogpt_platform/frontend/src/app/(platform)/copilot/components/ChatMessagesContainer/ChatMessagesContainer.tsx
  • autogpt_platform/frontend/src/app/(platform)/copilot/components/ChatMessagesContainer/__tests__/LoadMoreSentinel.test.tsx
autogpt_platform/frontend/src/**/*.{ts,tsx}

📄 CodeRabbit inference engine (AGENTS.md)

autogpt_platform/frontend/src/**/*.{ts,tsx}: Use generated API hooks from @/app/api/__generated__/endpoints/ following the pattern use{Method}{Version}{OperationName}, and regenerate with pnpm generate:api
Separate render logic from business logic using component.tsx + useComponent.ts + helpers.ts pattern, colocate state when possible and avoid creating large components, use sub-components in local /components folder
Use function declarations for components and handlers, use arrow functions only for callbacks
Do not use useCallback or useMemo unless asked to optimise a given function

Files:

  • autogpt_platform/frontend/src/app/(platform)/copilot/components/ChatMessagesContainer/ChatMessagesContainer.tsx
  • autogpt_platform/frontend/src/app/(platform)/copilot/components/ChatMessagesContainer/__tests__/LoadMoreSentinel.test.tsx
autogpt_platform/frontend/**/*.{tsx,css}

📄 CodeRabbit inference engine (AGENTS.md)

Use Tailwind CSS only for styling, use design tokens, and use Phosphor Icons only

Files:

  • autogpt_platform/frontend/src/app/(platform)/copilot/components/ChatMessagesContainer/ChatMessagesContainer.tsx
  • autogpt_platform/frontend/src/app/(platform)/copilot/components/ChatMessagesContainer/__tests__/LoadMoreSentinel.test.tsx
autogpt_platform/frontend/src/**/*.tsx

📄 CodeRabbit inference engine (AGENTS.md)

Component props should use interface Props { ... } (not exported) unless the interface needs to be used outside the component

Files:

  • autogpt_platform/frontend/src/app/(platform)/copilot/components/ChatMessagesContainer/ChatMessagesContainer.tsx
  • autogpt_platform/frontend/src/app/(platform)/copilot/components/ChatMessagesContainer/__tests__/LoadMoreSentinel.test.tsx
autogpt_platform/**/*.{ts,tsx}

📄 CodeRabbit inference engine (AGENTS.md)

Never type with any, if no types available use unknown

Files:

  • autogpt_platform/frontend/src/app/(platform)/copilot/components/ChatMessagesContainer/ChatMessagesContainer.tsx
  • autogpt_platform/frontend/src/app/(platform)/copilot/components/ChatMessagesContainer/__tests__/LoadMoreSentinel.test.tsx
autogpt_platform/frontend/src/app/(platform)/**/components/**/*.tsx

📄 CodeRabbit inference engine (autogpt_platform/frontend/AGENTS.md)

Put sub-components in local components/ folder

Files:

  • autogpt_platform/frontend/src/app/(platform)/copilot/components/ChatMessagesContainer/ChatMessagesContainer.tsx
  • autogpt_platform/frontend/src/app/(platform)/copilot/components/ChatMessagesContainer/__tests__/LoadMoreSentinel.test.tsx
autogpt_platform/frontend/**/*.tsx

📄 CodeRabbit inference engine (autogpt_platform/frontend/AGENTS.md)

autogpt_platform/frontend/**/*.tsx: Component props should be type Props = { ... } (not exported) unless it needs to be used outside the component
Use design system components from src/components/ (atoms, molecules, organisms)
Never use src/components/__legacy__/*
Tailwind CSS only for styling, use design tokens, Phosphor Icons only

Files:

  • autogpt_platform/frontend/src/app/(platform)/copilot/components/ChatMessagesContainer/ChatMessagesContainer.tsx
  • autogpt_platform/frontend/src/app/(platform)/copilot/components/ChatMessagesContainer/__tests__/LoadMoreSentinel.test.tsx
autogpt_platform/frontend/**/*.{test,spec}.{ts,tsx}

📄 CodeRabbit inference engine (AGENTS.md)

autogpt_platform/frontend/**/*.{test,spec}.{ts,tsx}: Use Vitest + RTL + MSW for integration tests as the primary testing approach (~90%, page-level), use Playwright for E2E critical flows, and use Storybook for design system components
Run frontend integration tests with pnpm test:unit (Vitest + RTL + MSW)

Files:

  • autogpt_platform/frontend/src/app/(platform)/copilot/components/ChatMessagesContainer/__tests__/LoadMoreSentinel.test.tsx
autogpt_platform/frontend/src/app/(platform)/**/__tests__/**/*.test.{ts,tsx}

📄 CodeRabbit inference engine (autogpt_platform/frontend/AGENTS.md)

Write integration tests in __tests__/ next to page.tsx using Vitest + RTL + MSW for new pages/features

Files:

  • autogpt_platform/frontend/src/app/(platform)/copilot/components/ChatMessagesContainer/__tests__/LoadMoreSentinel.test.tsx
autogpt_platform/frontend/src/**/__tests__/**/*.test.{ts,tsx}

📄 CodeRabbit inference engine (autogpt_platform/frontend/AGENTS.md)

Use Orval-generated MSW handlers from @/app/api/__generated__/endpoints/{tag}/{tag}.msw.ts for API mocking

Files:

  • autogpt_platform/frontend/src/app/(platform)/copilot/components/ChatMessagesContainer/__tests__/LoadMoreSentinel.test.tsx
🧠 Learnings (28)
📓 Common learnings
Learnt from: kcze
Repo: Significant-Gravitas/AutoGPT PR: 12328
File: autogpt_platform/frontend/src/app/(platform)/copilot/useLoadMoreMessages.ts:49-61
Timestamp: 2026-03-11T08:40:59.673Z
Learning: In `autogpt_platform/frontend/src/app/(platform)/copilot/useLoadMoreMessages.ts`, clearing `olderMessages` (and resetting `oldestSequence`/`hasMore`) when `initialOldestSequence` shifts on the same session is intentional. Pages already fetched were based on a now-stale cursor; retaining them risks sequence gaps or duplicates. `ScrollPreserver` keeps the currently visible viewport intact, so only unvisited older pages are dropped. This is a deliberate safe-refetch design tradeoff.
Learnt from: majdyz
Repo: Significant-Gravitas/AutoGPT PR: 12773
File: autogpt_platform/backend/backend/copilot/pending_messages.py:52-64
Timestamp: 2026-04-14T14:36:22.396Z
Learning: In `autogpt_platform/backend/backend/copilot` (PR `#12773`, commit d7bced0c6): when draining pending messages into `session.messages`, each message's text is sanitized via `strip_user_context_tags` before persistence to prevent user-controlled `<user_context>` injection from bypassing the trusted server-side context prefix. Additionally, if `upsert_chat_session` fails after draining, the drained `PendingMessage` objects are requeued back to Redis to avoid silent message loss. Do NOT flag the drain-then-requeue pattern as redundant — it is the intentional failure-resilience strategy for the pending buffer.
Learnt from: majdyz
Repo: Significant-Gravitas/AutoGPT PR: 12445
File: autogpt_platform/backend/backend/copilot/sdk/service.py:1071-1072
Timestamp: 2026-03-17T06:48:26.471Z
Learning: In Significant-Gravitas/AutoGPT (autogpt_platform), the AI SDK enforces `z.strictObject({type, errorText})` on SSE `StreamError` responses, so additional fields like `retryable: bool` cannot be added to `StreamError` or serialized via `to_sse()`. Instead, retry signaling for transient Anthropic API errors is done via the `COPILOT_RETRYABLE_ERROR_PREFIX` constant prepended to persisted session messages (in `ChatMessage.content`). The frontend detects retryable errors by checking `markerType === "retryable_error"` from `parseSpecialMarkers()` — no SSE schema changes and no string matching on error text. This pattern was established in PR `#12445`, commit 64d82797b.
Learnt from: majdyz
Repo: Significant-Gravitas/AutoGPT PR: 12445
File: autogpt_platform/frontend/src/app/(platform)/copilot/components/ChatContainer/ChatContainer.tsx:55-67
Timestamp: 2026-03-17T06:18:51.570Z
Learning: In `autogpt_platform/frontend/src/app/(platform)/copilot/components/ChatContainer/ChatContainer.tsx`, an explicit `isBusy` guard on the retry handler (`handleRetry`) is not needed. Once `onSend` is invoked, the chat status immediately transitions to "submitted", which causes the `ErrorCard` (containing the retry button) to unmount before a second click can register, making double-send impossible by design.
📚 Learning: 2026-03-11T08:40:59.673Z
Learnt from: kcze
Repo: Significant-Gravitas/AutoGPT PR: 12328
File: autogpt_platform/frontend/src/app/(platform)/copilot/useLoadMoreMessages.ts:49-61
Timestamp: 2026-03-11T08:40:59.673Z
Learning: In `autogpt_platform/frontend/src/app/(platform)/copilot/useLoadMoreMessages.ts`, clearing `olderMessages` (and resetting `oldestSequence`/`hasMore`) when `initialOldestSequence` shifts on the same session is intentional. Pages already fetched were based on a now-stale cursor; retaining them risks sequence gaps or duplicates. `ScrollPreserver` keeps the currently visible viewport intact, so only unvisited older pages are dropped. This is a deliberate safe-refetch design tradeoff.

Applied to files:

  • autogpt_platform/frontend/src/app/(platform)/copilot/components/ChatMessagesContainer/ChatMessagesContainer.tsx
  • autogpt_platform/frontend/src/app/(platform)/copilot/components/ChatMessagesContainer/__tests__/LoadMoreSentinel.test.tsx
📚 Learning: 2026-03-17T06:18:51.570Z
Learnt from: majdyz
Repo: Significant-Gravitas/AutoGPT PR: 12445
File: autogpt_platform/frontend/src/app/(platform)/copilot/components/ChatContainer/ChatContainer.tsx:55-67
Timestamp: 2026-03-17T06:18:51.570Z
Learning: In `autogpt_platform/frontend/src/app/(platform)/copilot/components/ChatContainer/ChatContainer.tsx`, an explicit `isBusy` guard on the retry handler (`handleRetry`) is not needed. Once `onSend` is invoked, the chat status immediately transitions to "submitted", which causes the `ErrorCard` (containing the retry button) to unmount before a second click can register, making double-send impossible by design.

Applied to files:

  • autogpt_platform/frontend/src/app/(platform)/copilot/components/ChatMessagesContainer/ChatMessagesContainer.tsx
📚 Learning: 2026-04-14T14:36:22.396Z
Learnt from: majdyz
Repo: Significant-Gravitas/AutoGPT PR: 12773
File: autogpt_platform/backend/backend/copilot/pending_messages.py:52-64
Timestamp: 2026-04-14T14:36:22.396Z
Learning: In `autogpt_platform/backend/backend/copilot` (PR `#12773`, commit d7bced0c6): when draining pending messages into `session.messages`, each message's text is sanitized via `strip_user_context_tags` before persistence to prevent user-controlled `<user_context>` injection from bypassing the trusted server-side context prefix. Additionally, if `upsert_chat_session` fails after draining, the drained `PendingMessage` objects are requeued back to Redis to avoid silent message loss. Do NOT flag the drain-then-requeue pattern as redundant — it is the intentional failure-resilience strategy for the pending buffer.

Applied to files:

  • autogpt_platform/frontend/src/app/(platform)/copilot/components/ChatMessagesContainer/ChatMessagesContainer.tsx
📚 Learning: 2026-03-17T06:48:26.471Z
Learnt from: majdyz
Repo: Significant-Gravitas/AutoGPT PR: 12445
File: autogpt_platform/backend/backend/copilot/sdk/service.py:1071-1072
Timestamp: 2026-03-17T06:48:26.471Z
Learning: In Significant-Gravitas/AutoGPT (autogpt_platform), the AI SDK enforces `z.strictObject({type, errorText})` on SSE `StreamError` responses, so additional fields like `retryable: bool` cannot be added to `StreamError` or serialized via `to_sse()`. Instead, retry signaling for transient Anthropic API errors is done via the `COPILOT_RETRYABLE_ERROR_PREFIX` constant prepended to persisted session messages (in `ChatMessage.content`). The frontend detects retryable errors by checking `markerType === "retryable_error"` from `parseSpecialMarkers()` — no SSE schema changes and no string matching on error text. This pattern was established in PR `#12445`, commit 64d82797b.

Applied to files:

  • autogpt_platform/frontend/src/app/(platform)/copilot/components/ChatMessagesContainer/ChatMessagesContainer.tsx
📚 Learning: 2026-04-14T06:39:49.111Z
Learnt from: majdyz
Repo: Significant-Gravitas/AutoGPT PR: 12773
File: autogpt_platform/frontend/src/app/api/openapi.json:12803-12806
Timestamp: 2026-04-14T06:39:49.111Z
Learning: Repo: Significant-Gravitas/AutoGPT — autogpt_platform
Intentional message length caps:
- StreamChatRequest.message maxLength = 64000.
- QueuePendingMessageRequest.message maxLength = 32000 (matches PendingMessage.content).
Rationale: both feed the same LLM context window; pending must not exceed stream, and larger ceilings replace legacy 4000/16000.

Applied to files:

  • autogpt_platform/frontend/src/app/(platform)/copilot/components/ChatMessagesContainer/ChatMessagesContainer.tsx
📚 Learning: 2026-04-08T17:28:40.841Z
Learnt from: CR
Repo: Significant-Gravitas/AutoGPT PR: 0
File: autogpt_platform/frontend/AGENTS.md:0-0
Timestamp: 2026-04-08T17:28:40.841Z
Learning: Applies to autogpt_platform/frontend/**/*.tsx : Use design system components from `src/components/` (atoms, molecules, organisms)

Applied to files:

  • autogpt_platform/frontend/src/app/(platform)/copilot/components/ChatMessagesContainer/ChatMessagesContainer.tsx
📚 Learning: 2026-02-04T16:49:42.490Z
Learnt from: CR
Repo: Significant-Gravitas/AutoGPT PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2026-02-04T16:49:42.490Z
Learning: Applies to autogpt_platform/frontend/**/*.{tsx,ts} : Use design system components from 'src/components/' (atoms, molecules, organisms) in frontend development

Applied to files:

  • autogpt_platform/frontend/src/app/(platform)/copilot/components/ChatMessagesContainer/ChatMessagesContainer.tsx
📚 Learning: 2026-04-13T13:10:33.180Z
Learnt from: 0ubbe
Repo: Significant-Gravitas/AutoGPT PR: 12764
File: autogpt_platform/frontend/src/app/(platform)/library/components/LibraryAgentList/useLibraryAgentList.ts:264-294
Timestamp: 2026-04-13T13:10:33.180Z
Learning: In `autogpt_platform/frontend/src/app/(platform)/library/components/LibraryAgentList/useLibraryAgentList.ts`, the `consecutiveEmptyPagesRef` and `prevFilteredLengthRef` refs used to track filtered-pagination exhaustion are intentional. The one-render lag in `filteredExhausted` (which reads `consecutiveEmptyPagesRef.current` synchronously) is by design — refs are preferred here to avoid triggering extra re-renders for internal fetch-state bookkeeping. Do not flag this as a stale-ref bug in future reviews.

Applied to files:

  • autogpt_platform/frontend/src/app/(platform)/copilot/components/ChatMessagesContainer/ChatMessagesContainer.tsx
📚 Learning: 2026-02-27T10:45:49.499Z
Learnt from: majdyz
Repo: Significant-Gravitas/AutoGPT PR: 12213
File: autogpt_platform/frontend/src/app/(platform)/copilot/tools/RunMCPTool/helpers.tsx:23-24
Timestamp: 2026-02-27T10:45:49.499Z
Learning: Prefer using generated OpenAPI types from '@/app/api/__generated__/' for payloads defined in openapi.json (e.g., MCPToolsDiscoveredResponse, MCPToolOutputResponse). Use inline TypeScript interfaces only for payloads that are SSE-stream-only and not exposed via OpenAPI. Apply this pattern to frontend tool components (e.g., RunMCPTool) and related areas where similar SSE/openapi-discrepancies occur; avoid re-implementing types when a generated type is available.

Applied to files:

  • autogpt_platform/frontend/src/app/(platform)/copilot/components/ChatMessagesContainer/ChatMessagesContainer.tsx
  • autogpt_platform/frontend/src/app/(platform)/copilot/components/ChatMessagesContainer/__tests__/LoadMoreSentinel.test.tsx
📚 Learning: 2026-03-24T02:05:04.672Z
Learnt from: majdyz
Repo: Significant-Gravitas/AutoGPT PR: 12526
File: autogpt_platform/frontend/src/app/(platform)/copilot/CopilotPage.tsx:0-0
Timestamp: 2026-03-24T02:05:04.672Z
Learning: When gating React component logic on a React Query result (e.g., hooks like `useQuery` / `useGetV2GetCopilotUsage`), prefer destructuring and checking `isSuccess` (or aliasing it to a meaningful boolean like `isSuccess: hasUsage`) instead of relying on `!isLoading`. Reason: `isLoading` can be `false` in error/idle states where `data` may still be `undefined`, while `isSuccess` indicates the query completed successfully and `data` is populated.

Applied to files:

  • autogpt_platform/frontend/src/app/(platform)/copilot/components/ChatMessagesContainer/ChatMessagesContainer.tsx
  • autogpt_platform/frontend/src/app/(platform)/copilot/components/ChatMessagesContainer/__tests__/LoadMoreSentinel.test.tsx
📚 Learning: 2026-03-24T02:23:31.305Z
Learnt from: majdyz
Repo: Significant-Gravitas/AutoGPT PR: 12526
File: autogpt_platform/frontend/src/app/(platform)/copilot/components/RateLimitResetDialog/RateLimitResetDialog.tsx:0-0
Timestamp: 2026-03-24T02:23:31.305Z
Learning: In the Copilot platform UI code, follow the established Orval hook `onError` error-handling convention: first explicitly detect/handle `ApiError`, then read `error.response?.detail` (if present) as the primary message; if not available, fall back to `error.message`; and finally fall back to a generic string message. This convention should be used for generated Orval hooks even if the custom Orval mutator already maps details into `ApiError.message`, to keep consistency across hooks/components (e.g., `useCronSchedulerDialog.ts`, `useRunGraph.ts`, and rate-limit/reset flows).

Applied to files:

  • autogpt_platform/frontend/src/app/(platform)/copilot/components/ChatMessagesContainer/ChatMessagesContainer.tsx
  • autogpt_platform/frontend/src/app/(platform)/copilot/components/ChatMessagesContainer/__tests__/LoadMoreSentinel.test.tsx
📚 Learning: 2026-03-31T14:04:42.444Z
Learnt from: majdyz
Repo: Significant-Gravitas/AutoGPT PR: 12623
File: autogpt_platform/frontend/src/app/(platform)/copilot/components/ChatInput/ChatInput.tsx:172-177
Timestamp: 2026-03-31T14:04:42.444Z
Learning: In the Copilot frontend components under autogpt_platform/frontend/src/app/(platform)/copilot/, Tailwind dark mode variants (e.g., `dark:*`) are intentional and should be allowed. Do not flag `dark:` utilities in these Copilot UI components as incorrect; they are used to ensure proper contrast and correct behavior in both light and dark themes.

Applied to files:

  • autogpt_platform/frontend/src/app/(platform)/copilot/components/ChatMessagesContainer/ChatMessagesContainer.tsx
  • autogpt_platform/frontend/src/app/(platform)/copilot/components/ChatMessagesContainer/__tests__/LoadMoreSentinel.test.tsx
📚 Learning: 2026-04-01T18:54:16.035Z
Learnt from: Bentlybro
Repo: Significant-Gravitas/AutoGPT PR: 12633
File: autogpt_platform/frontend/src/app/(platform)/library/components/AgentFilterMenu/AgentFilterMenu.tsx:3-10
Timestamp: 2026-04-01T18:54:16.035Z
Learning: In the frontend, the legacy Select component at `@/components/__legacy__/ui/select` is an intentional, codebase-wide visual-consistency pattern. During code reviews, do not flag or block PRs merely for continuing to use this legacy Select. If a migration to the newer design-system Select is desired, bundle it into a single dedicated cleanup/migration PR that updates all Select usages together (e.g., avoid piecemeal replacements).

Applied to files:

  • autogpt_platform/frontend/src/app/(platform)/copilot/components/ChatMessagesContainer/ChatMessagesContainer.tsx
  • autogpt_platform/frontend/src/app/(platform)/copilot/components/ChatMessagesContainer/__tests__/LoadMoreSentinel.test.tsx
📚 Learning: 2026-04-07T09:24:16.582Z
Learnt from: 0ubbe
Repo: Significant-Gravitas/AutoGPT PR: 12686
File: autogpt_platform/frontend/src/app/(no-navbar)/onboarding/steps/__tests__/PainPointsStep.test.tsx:1-19
Timestamp: 2026-04-07T09:24:16.582Z
Learning: In Significant-Gravitas/AutoGPT’s `autogpt_platform/frontend` (Vite + `vitejs/plugin-react` with the automatic JSX transform), do not flag usages of React types/components (e.g., `React.ReactNode`) in `.ts`/`.tsx` files as missing `React` imports. Since the React namespace is made available by the project’s TS/Vite setup, an explicit `import React from 'react'` or `import type { ReactNode } ...` is not required; only treat it as missing if typechecking (e.g., `pnpm types`) would actually fail.

Applied to files:

  • autogpt_platform/frontend/src/app/(platform)/copilot/components/ChatMessagesContainer/ChatMessagesContainer.tsx
  • autogpt_platform/frontend/src/app/(platform)/copilot/components/ChatMessagesContainer/__tests__/LoadMoreSentinel.test.tsx
📚 Learning: 2026-04-02T05:43:49.128Z
Learnt from: 0ubbe
Repo: Significant-Gravitas/AutoGPT PR: 12640
File: autogpt_platform/frontend/src/app/(no-navbar)/onboarding/steps/WelcomeStep.tsx:13-13
Timestamp: 2026-04-02T05:43:49.128Z
Learning: Do not flag `import { Question } from "phosphor-icons/react"` as an invalid import. `Question` is a valid named export from `phosphor-icons/react` (as reflected in the package’s generated `.d.ts` files and re-exports via `dist/index.d.ts`), so it should be treated as a supported named export during code reviews.

Applied to files:

  • autogpt_platform/frontend/src/app/(platform)/copilot/components/ChatMessagesContainer/ChatMessagesContainer.tsx
  • autogpt_platform/frontend/src/app/(platform)/copilot/components/ChatMessagesContainer/__tests__/LoadMoreSentinel.test.tsx
📚 Learning: 2026-04-13T13:11:07.445Z
Learnt from: 0ubbe
Repo: Significant-Gravitas/AutoGPT PR: 12764
File: autogpt_platform/frontend/src/app/(platform)/library/components/SitrepItem/SitrepItem.tsx:143-145
Timestamp: 2026-04-13T13:11:07.445Z
Learning: In `autogpt_platform/frontend`, do not flag direct interpolation of `executionID` UUID strings into URL query parameters (e.g., `activeItem=${executionID}` in JSX/Next links). If the value is a UUID string matching `[0-9a-f-]`, it contains no reserved URL characters, so additional `encodeURIComponent` or Next.js object-based `href` encoding is unnecessary. Only treat it as an encoding issue if the query-param value is not guaranteed to be UUID-formatted (i.e., may include characters outside `[0-9a-f-]`).

Applied to files:

  • autogpt_platform/frontend/src/app/(platform)/copilot/components/ChatMessagesContainer/ChatMessagesContainer.tsx
  • autogpt_platform/frontend/src/app/(platform)/copilot/components/ChatMessagesContainer/__tests__/LoadMoreSentinel.test.tsx
📚 Learning: 2026-04-08T17:28:40.841Z
Learnt from: CR
Repo: Significant-Gravitas/AutoGPT PR: 0
File: autogpt_platform/frontend/AGENTS.md:0-0
Timestamp: 2026-04-08T17:28:40.841Z
Learning: Applies to autogpt_platform/frontend/src/app/(platform)/**/__tests__/**/*.test.{ts,tsx} : Write integration tests in `__tests__/` next to `page.tsx` using Vitest + RTL + MSW for new pages/features

Applied to files:

  • autogpt_platform/frontend/src/app/(platform)/copilot/components/ChatMessagesContainer/__tests__/LoadMoreSentinel.test.tsx
📚 Learning: 2026-04-08T17:28:55.678Z
Learnt from: CR
Repo: Significant-Gravitas/AutoGPT PR: 0
File: autogpt_platform/frontend/src/tests/AGENTS.md:0-0
Timestamp: 2026-04-08T17:28:55.678Z
Learning: Applies to autogpt_platform/frontend/src/tests/**/__tests__/main.test.tsx : Start integration tests at page level with a `main.test.tsx` file before splitting into smaller test files

Applied to files:

  • autogpt_platform/frontend/src/app/(platform)/copilot/components/ChatMessagesContainer/__tests__/LoadMoreSentinel.test.tsx
📚 Learning: 2026-04-08T17:27:45.740Z
Learnt from: CR
Repo: Significant-Gravitas/AutoGPT PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-04-08T17:27:45.740Z
Learning: Applies to autogpt_platform/frontend/**/*.{test,spec}.{ts,tsx} : Use Vitest + RTL + MSW for integration tests as the primary testing approach (~90%, page-level), use Playwright for E2E critical flows, and use Storybook for design system components

Applied to files:

  • autogpt_platform/frontend/src/app/(platform)/copilot/components/ChatMessagesContainer/__tests__/LoadMoreSentinel.test.tsx
📚 Learning: 2026-04-08T17:27:45.740Z
Learnt from: CR
Repo: Significant-Gravitas/AutoGPT PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-04-08T17:27:45.740Z
Learning: Applies to autogpt_platform/frontend/**/*.{test,spec}.{ts,tsx} : Run frontend integration tests with `pnpm test:unit` (Vitest + RTL + MSW)

Applied to files:

  • autogpt_platform/frontend/src/app/(platform)/copilot/components/ChatMessagesContainer/__tests__/LoadMoreSentinel.test.tsx
📚 Learning: 2026-04-08T17:28:55.678Z
Learnt from: CR
Repo: Significant-Gravitas/AutoGPT PR: 0
File: autogpt_platform/frontend/src/tests/AGENTS.md:0-0
Timestamp: 2026-04-08T17:28:55.678Z
Learning: Applies to autogpt_platform/frontend/src/tests/**/*.test.{ts,tsx} : Place unit tests co-located with the file being tested: `Component.test.tsx` next to `Component.tsx`

Applied to files:

  • autogpt_platform/frontend/src/app/(platform)/copilot/components/ChatMessagesContainer/__tests__/LoadMoreSentinel.test.tsx
📚 Learning: 2026-04-08T17:28:40.841Z
Learnt from: CR
Repo: Significant-Gravitas/AutoGPT PR: 0
File: autogpt_platform/frontend/AGENTS.md:0-0
Timestamp: 2026-04-08T17:28:40.841Z
Learning: Applies to autogpt_platform/frontend/src/**/__tests__/**/*.test.{ts,tsx} : Use Orval-generated MSW handlers from `@/app/api/__generated__/endpoints/{tag}/{tag}.msw.ts` for API mocking

Applied to files:

  • autogpt_platform/frontend/src/app/(platform)/copilot/components/ChatMessagesContainer/__tests__/LoadMoreSentinel.test.tsx
📚 Learning: 2026-04-08T17:28:55.678Z
Learnt from: CR
Repo: Significant-Gravitas/AutoGPT PR: 0
File: autogpt_platform/frontend/src/tests/AGENTS.md:0-0
Timestamp: 2026-04-08T17:28:55.678Z
Learning: Applies to autogpt_platform/frontend/src/tests/**/__tests__/**/*.test.{ts,tsx} : Place integration tests in a `__tests__` folder next to the component being tested

Applied to files:

  • autogpt_platform/frontend/src/app/(platform)/copilot/components/ChatMessagesContainer/__tests__/LoadMoreSentinel.test.tsx
📚 Learning: 2026-04-08T17:28:55.678Z
Learnt from: CR
Repo: Significant-Gravitas/AutoGPT PR: 0
File: autogpt_platform/frontend/src/tests/AGENTS.md:0-0
Timestamp: 2026-04-08T17:28:55.678Z
Learning: Applies to autogpt_platform/frontend/src/tests/src/tests/**/*.spec.ts : Import `test` and `expect` from `./coverage-fixture` instead of `playwright/test` in E2E tests to auto-collect V8 coverage per test for Codecov reporting

Applied to files:

  • autogpt_platform/frontend/src/app/(platform)/copilot/components/ChatMessagesContainer/__tests__/LoadMoreSentinel.test.tsx
📚 Learning: 2026-04-08T17:28:55.678Z
Learnt from: CR
Repo: Significant-Gravitas/AutoGPT PR: 0
File: autogpt_platform/frontend/src/tests/AGENTS.md:0-0
Timestamp: 2026-04-08T17:28:55.678Z
Learning: Applies to autogpt_platform/frontend/src/tests/**/__tests__/**/*.test.{ts,tsx} : Use `findBy...` methods in integration tests instead of `getBy...` methods to avoid flaky tests by waiting for elements to appear asynchronously

Applied to files:

  • autogpt_platform/frontend/src/app/(platform)/copilot/components/ChatMessagesContainer/__tests__/LoadMoreSentinel.test.tsx
📚 Learning: 2026-04-08T17:28:55.678Z
Learnt from: CR
Repo: Significant-Gravitas/AutoGPT PR: 0
File: autogpt_platform/frontend/src/tests/AGENTS.md:0-0
Timestamp: 2026-04-08T17:28:55.678Z
Learning: Use unit tests for isolated components, pure utility functions, component rendering with various props, component state changes, and custom hooks

Applied to files:

  • autogpt_platform/frontend/src/app/(platform)/copilot/components/ChatMessagesContainer/__tests__/LoadMoreSentinel.test.tsx
📚 Learning: 2026-04-08T17:28:55.678Z
Learnt from: CR
Repo: Significant-Gravitas/AutoGPT PR: 0
File: autogpt_platform/frontend/src/tests/AGENTS.md:0-0
Timestamp: 2026-04-08T17:28:55.678Z
Learning: Use integration tests for page-level behavior with mocked API responses, components that fetch data, user interactions triggering API calls, and feature flows within a single page

Applied to files:

  • autogpt_platform/frontend/src/app/(platform)/copilot/components/ChatMessagesContainer/__tests__/LoadMoreSentinel.test.tsx
🔇 Additional comments (3)
autogpt_platform/frontend/src/app/(platform)/copilot/components/ChatMessagesContainer/ChatMessagesContainer.tsx (3)

115-119: Well-designed auto-fill capping mechanism.

The ref-based tracking cleanly separates auto-triggered loads from manual button clicks. The captureAndLoad(fromObserver) pattern elegantly captures scroll metrics while tracking the trigger source. Good use of refs to avoid unnecessary re-renders.

Also applies to: 150-166


197-205: Counter management logic is correct.

The conditional increment/reset based on scrollHeight > clientHeight properly detects when the container becomes scrollable. Resetting to 0 when scrollable allows the observer to resume auto-loading in subsequent sessions where content fits.

One edge case to note: if the user manually loads messages that make the container scrollable, the counter won't reset (since autoTriggeredRef is false). This means the observer stays disabled until the component remounts. This appears intentional per the PR description, but worth documenting if the behavior should differ.


208-226: Button implementation follows design system correctly.

Using Button from @/components/atoms/Button/Button with variant="ghost" and size="small" aligns with the design system guidelines. The conditional rendering logic (isLoading ? spinner : hasMore && button) is clear and handles all states properly.

@codecov

codecov Bot commented Apr 15, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 85.18519% with 4 lines in your changes missing coverage. Please review.
✅ Project coverage is 64.66%. Comparing base (da18f37) to head (eae1bf3).
⚠️ Report is 6 commits behind head on dev.

Additional details and impacted files
@@            Coverage Diff             @@
##              dev   #12792      +/-   ##
==========================================
+ Coverage   64.64%   64.66%   +0.01%     
==========================================
  Files        1819     1820       +1     
  Lines      133985   134034      +49     
  Branches    14428    14451      +23     
==========================================
+ Hits        86615    86671      +56     
+ Misses      44671    44669       -2     
+ Partials     2699     2694       -5     
Flag Coverage Δ
platform-frontend 19.19% <81.48%> (+0.27%) ⬆️
platform-frontend-e2e 29.92% <9.09%> (-0.57%) ⬇️

Flags with carried forward coverage won't be shown. Click here to find out more.

Components Coverage Δ
Platform Backend 75.45% <ø> (ø)
Platform Frontend 27.12% <85.18%> (+0.16%) ⬆️
AutoGPT Libs ∅ <ø> (∅)
Classic AutoGPT 28.43% <ø> (ø)
🚀 New features to boost your workflow:
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

…refetches

When the session query refetched after a stream completed, the newest
page's `oldest_sequence` shifted forward. `useLoadMoreMessages` treated
that as a signal to wipe `olderRawMessages` and reset the local cursor
to the new initial value. Users who had scrolled back lost their
loaded history on every new turn, and the next "Load older messages"
click fetched a page that overlapped with AI SDK's retained state in
`currentMessages`, producing visible duplicates — the "loop of the
same past messages" reported in SECRT-2226.

Preserve `olderRawMessages` and the local cursor across same-session
refetches. The cursor still points to the oldest message we have
explicitly loaded, so the next `loadMore` fetches cleanly before it.
The gap between the refetched initial window and the older pages is
covered by AI SDK's retained state in `currentMessages`.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
@kcze kcze changed the title fix(frontend/copilot): load older chat messages when newest page fits viewport fix(frontend/copilot): load older chat messages reliably and preserve scrollback across turns Apr 15, 2026
If auto-fill hit the 3-round cap, the counter could only be reset when
another auto-triggered load became scrollable — but the observer stops
firing at the cap, so auto-fill would never run again. Clicking the
manual button successfully made the container scrollable, but the
reset was gated on `autoTriggeredRef.current` and skipped, leaving the
counter stuck at the cap for the rest of the session.

Always reset the counter when the container becomes scrollable. Only
increment it when a non-scrollable outcome was itself auto-triggered.

Also add a data-testid to the load-more spinner and assert it in the
loading-state test (caught by reviewers).

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
@kcze

kcze commented Apr 15, 2026

Copy link
Copy Markdown
Contributor Author

@coderabbitai re nitpicks on LoadMoreSentinel.test.tsx:

  • Spinner assertion — addressed in 00cadee11. Added a data-testid="load-more-spinner" to the spinner and getByTestId assertion in the loading-state test.
  • Redundant cleanup() — declining. Our vitest.config.mts does not set globals: true and src/tests/integrations/vitest.setup.tsx does not register the testing-library cleanup hook, so auto-cleanup does not run. Without the explicit afterEach(cleanup) the suite fails with "multiple elements found" from the prior test's DOM. Verified by running the suite.

@coderabbitai

coderabbitai Bot commented Apr 15, 2026

Copy link
Copy Markdown
Contributor

Tip

For best results, initiate chat on the files or code changes.

@kcze: Thanks for the follow-ups!

  • Spinner assertion — The data-testid="load-more-spinner" approach is a solid fix. Confirmed addressed. ✅
  • Redundant cleanup() — Understood and acknowledged. Since vitest.config.mts doesn't set globals: true and the integration test setup file doesn't register the Testing Library auto-cleanup hook, the explicit afterEach(cleanup) is indeed necessary to prevent DOM bleed-through between tests. My comment was incorrect — noting this for future reviews.

✏️ Learnings added
Learnt from: kcze
URL: https://github.com/Significant-Gravitas/AutoGPT/pull/12792

Timestamp: 2026-04-15T10:17:08.698Z
Learning: In `Significant-Gravitas/AutoGPT` (`autogpt_platform/frontend`), `vitest.config.mts` does NOT set `globals: true`, and `src/tests/integrations/vitest.setup.tsx` does NOT register the `testing-library/react` auto-cleanup hook. Therefore, integration test files (e.g., under `__tests__/`) MUST include an explicit `afterEach(cleanup)` call from `testing-library/react` to reset the DOM between tests — without it, tests fail with "multiple elements found" errors from the prior test's DOM. Do NOT flag `afterEach(cleanup)` as redundant in this codebase.

Note: Learnings are effective only in the context of similar code segments. To apply general coding guidelines, please configure review instructions. You can manage existing learnings in the app.


🧠 Learnings used
Learnt from: CR
Repo: Significant-Gravitas/AutoGPT PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-04-08T17:27:45.740Z
Learning: Applies to autogpt_platform/frontend/**/*.{test,spec}.{ts,tsx} : Use Vitest + RTL + MSW for integration tests as the primary testing approach (~90%, page-level), use Playwright for E2E critical flows, and use Storybook for design system components

Learnt from: CR
Repo: Significant-Gravitas/AutoGPT PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-04-08T17:27:45.740Z
Learning: Applies to autogpt_platform/frontend/**/*.{test,spec}.{ts,tsx} : Run frontend integration tests with `pnpm test:unit` (Vitest + RTL + MSW)

Learnt from: CR
Repo: Significant-Gravitas/AutoGPT PR: 0
File: autogpt_platform/frontend/src/tests/AGENTS.md:0-0
Timestamp: 2026-04-08T17:28:55.678Z
Learning: Applies to autogpt_platform/frontend/src/tests/**/__tests__/main.test.tsx : Start integration tests at page level with a `main.test.tsx` file before splitting into smaller test files

Learnt from: majdyz
Repo: Significant-Gravitas/AutoGPT PR: 12526
File: autogpt_platform/frontend/src/app/(platform)/copilot/CopilotPage.tsx:0-0
Timestamp: 2026-03-24T02:05:08.144Z
Learning: In `Significant-Gravitas/AutoGPT` (autogpt_platform frontend), when gating logic on a React Query result being available (e.g., `useGetV2GetCopilotUsage`), prefer destructuring `isSuccess` (e.g., `const { data, isSuccess: hasUsage } = useQuery(...)`) over checking `!isLoading`. `isLoading` can be `false` in error/idle states where `data` is still `undefined`, while `isSuccess` guarantees the query completed successfully and `data` is populated. This pattern was established in `CopilotPage.tsx` (PR `#12526`, commit e9dfd1f76).

Learnt from: CR
Repo: Significant-Gravitas/AutoGPT PR: 0
File: autogpt_platform/frontend/src/tests/AGENTS.md:0-0
Timestamp: 2026-04-08T17:28:55.678Z
Learning: Applies to autogpt_platform/frontend/src/tests/src/tests/**/*.spec.ts : Import `test` and `expect` from `./coverage-fixture` instead of `playwright/test` in E2E tests to auto-collect V8 coverage per test for Codecov reporting

Learnt from: CR
Repo: Significant-Gravitas/AutoGPT PR: 0
File: autogpt_platform/frontend/src/tests/AGENTS.md:0-0
Timestamp: 2026-04-08T17:28:55.678Z
Learning: Applies to autogpt_platform/frontend/src/tests/**/__tests__/**/*.test.{ts,tsx} : Use `findBy...` methods in integration tests instead of `getBy...` methods to avoid flaky tests by waiting for elements to appear asynchronously

Learnt from: CR
Repo: Significant-Gravitas/AutoGPT PR: 0
File: autogpt_platform/AGENTS.md:0-0
Timestamp: 2026-04-08T17:27:57.501Z
Learning: Applies to autogpt_platform/frontend/**/*.spec.{ts,tsx} : Create a failing test first using `.fixme` marker (Playwright) when fixing a bug or adding a feature, then implement the fix and remove the fixme marker

Learnt from: CR
Repo: Significant-Gravitas/AutoGPT PR: 0
File: autogpt_platform/frontend/AGENTS.md:0-0
Timestamp: 2026-04-08T17:28:40.841Z
Learning: Applies to autogpt_platform/frontend/src/app/(platform)/**/__tests__/**/*.test.{ts,tsx} : Write integration tests in `__tests__/` next to `page.tsx` using Vitest + RTL + MSW for new pages/features

Learnt from: 0ubbe
Repo: Significant-Gravitas/AutoGPT PR: 12764
File: autogpt_platform/frontend/src/app/(platform)/library/components/LibraryAgentList/useLibraryAgentList.ts:264-294
Timestamp: 2026-04-13T13:10:33.180Z
Learning: In `autogpt_platform/frontend/src/app/(platform)/library/components/LibraryAgentList/useLibraryAgentList.ts`, the `consecutiveEmptyPagesRef` and `prevFilteredLengthRef` refs used to track filtered-pagination exhaustion are intentional. The one-render lag in `filteredExhausted` (which reads `consecutiveEmptyPagesRef.current` synchronously) is by design — refs are preferred here to avoid triggering extra re-renders for internal fetch-state bookkeeping. Do not flag this as a stale-ref bug in future reviews.

Learnt from: 0ubbe
Repo: Significant-Gravitas/AutoGPT PR: 12764
File: autogpt_platform/frontend/src/app/(platform)/copilot/components/EmptySession/EmptySession.tsx:41-42
Timestamp: 2026-04-13T13:11:00.401Z
Learning: In Significant-Gravitas/AutoGPT `autogpt_platform/frontend`, unconditional React Query hook calls (e.g. `usePulseChips()` in `EmptySession.tsx`) are intentional when the underlying data is expected to be cached from prior page visits. The team considers the fetch cost acceptable in these cases and does not require `enabled` gating purely for feature-flag-disabled paths. Do not flag unconditional query hooks as wasteful when caching makes the cost negligible.

Learnt from: Bentlybro
Repo: Significant-Gravitas/AutoGPT PR: 0
File: :0-0
Timestamp: 2026-03-05T19:50:36.724Z
Learning: In `autogpt_platform/frontend/src/app/api/helpers.ts`, the `getPaginationNextPageNumber()` function includes an intentional defensive null check (`if (!pagination) return undefined`) after destructuring `lastPage.data.pagination`. This was proven necessary in production because React Query calls `getNextPageParam` even with error responses (e.g., 401s) that lack the expected pagination structure. Returning `undefined` signals React Query to treat it as "no next page" and stop pagination instead of throwing a TypeError. This is valid and should not be flagged in future reviews.

Learnt from: kcze
Repo: Significant-Gravitas/AutoGPT PR: 12328
File: autogpt_platform/frontend/src/app/(platform)/copilot/useLoadMoreMessages.ts:49-61
Timestamp: 2026-03-11T08:40:59.673Z
Learning: In `autogpt_platform/frontend/src/app/(platform)/copilot/useLoadMoreMessages.ts`, clearing `olderMessages` (and resetting `oldestSequence`/`hasMore`) when `initialOldestSequence` shifts on the same session is intentional. Pages already fetched were based on a now-stale cursor; retaining them risks sequence gaps or duplicates. `ScrollPreserver` keeps the currently visible viewport intact, so only unvisited older pages are dropped. This is a deliberate safe-refetch design tradeoff.

Learnt from: majdyz
Repo: Significant-Gravitas/AutoGPT PR: 12773
File: autogpt_platform/backend/backend/copilot/pending_messages.py:52-64
Timestamp: 2026-04-14T14:36:22.396Z
Learning: In `autogpt_platform/backend/backend/copilot` (PR `#12773`, commit d7bced0c6): when draining pending messages into `session.messages`, each message's text is sanitized via `strip_user_context_tags` before persistence to prevent user-controlled `<user_context>` injection from bypassing the trusted server-side context prefix. Additionally, if `upsert_chat_session` fails after draining, the drained `PendingMessage` objects are requeued back to Redis to avoid silent message loss. Do NOT flag the drain-then-requeue pattern as redundant — it is the intentional failure-resilience strategy for the pending buffer.

Learnt from: majdyz
Repo: Significant-Gravitas/AutoGPT PR: 12445
File: autogpt_platform/backend/backend/copilot/sdk/service.py:1071-1072
Timestamp: 2026-03-17T06:48:26.471Z
Learning: In Significant-Gravitas/AutoGPT (autogpt_platform), the AI SDK enforces `z.strictObject({type, errorText})` on SSE `StreamError` responses, so additional fields like `retryable: bool` cannot be added to `StreamError` or serialized via `to_sse()`. Instead, retry signaling for transient Anthropic API errors is done via the `COPILOT_RETRYABLE_ERROR_PREFIX` constant prepended to persisted session messages (in `ChatMessage.content`). The frontend detects retryable errors by checking `markerType === "retryable_error"` from `parseSpecialMarkers()` — no SSE schema changes and no string matching on error text. This pattern was established in PR `#12445`, commit 64d82797b.

Learnt from: majdyz
Repo: Significant-Gravitas/AutoGPT PR: 12773
File: autogpt_platform/frontend/src/app/api/openapi.json:12803-12806
Timestamp: 2026-04-14T06:39:49.111Z
Learning: Repo: Significant-Gravitas/AutoGPT — autogpt_platform
Intentional message length caps:
- StreamChatRequest.message maxLength = 64000.
- QueuePendingMessageRequest.message maxLength = 32000 (matches PendingMessage.content).
Rationale: both feed the same LLM context window; pending must not exceed stream, and larger ceilings replace legacy 4000/16000.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🧹 Nitpick comments (1)
autogpt_platform/frontend/src/app/(platform)/copilot/components/ChatMessagesContainer/ChatMessagesContainer.tsx (1)

134-233: Extract LoadMoreSentinel into a local component/hook.

It is now exported, directly tested, and carries its own observer/backoff/scroll-preservation state. Keeping that in a ~485-line container makes this file harder to reason about and test than necessary.

As per coding guidelines "Separate render logic from business logic using component.tsx + useComponent.ts + helpers.ts pattern, colocate state when possible and avoid creating large components, use sub-components in local /components folder" and "Keep files under ~200 lines; extract sub-components or hooks into their own files when a file grows beyond this".

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In
`@autogpt_platform/frontend/src/app/`(platform)/copilot/components/ChatMessagesContainer/ChatMessagesContainer.tsx
around lines 134 - 233, The LoadMoreSentinel component (including
captureAndLoad, sentinelRef, scrollSnapshotRef, autoFillRoundsRef,
autoTriggeredRef, useEffect/ useLayoutEffect logic and MAX_AUTO_FILL_ROUNDS
usage) should be extracted out of the large ChatMessagesContainer file into its
own local component/hook pair under the components folder: create a
LoadMoreSentinel.tsx that contains the JSX and effects and a
useLoadMoreSentinel.ts (or keep helper functions) to encapsulate
observer/backoff/scroll-preservation state; ensure it imports
useStickToBottomContext and accepts the same props (hasMore, isLoading,
messageCount, onLoadMore) and preserve behavior (captureAndLoad semantics,
observer rootMargin, and scroll adjustment in useLayoutEffect), update the
original ChatMessagesContainer to import and render the new component and run
tests to confirm no behavioral changes.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In
`@autogpt_platform/frontend/src/app/`(platform)/copilot/components/ChatMessagesContainer/ChatMessagesContainer.tsx:
- Around line 156-176: Add a same-frame re-entry guard around onLoadMore by
introducing a pendingLoadRef boolean (e.g., const pendingLoadRef =
useRef(false)); update captureAndLoad to return early if pendingLoadRef.current
is true (in addition to existing isLoading checks), and set
pendingLoadRef.current = true immediately before calling
onLoadMoreRef.current(). Then clear pendingLoadRef.current = false when the load
cycle completes (watch isLoading in a useEffect and clear when isLoading becomes
false). Apply the same pending-load guard in the manual load handler referenced
around the 221-225 region so observer and button cannot both trigger a duplicate
load.

---

Nitpick comments:
In
`@autogpt_platform/frontend/src/app/`(platform)/copilot/components/ChatMessagesContainer/ChatMessagesContainer.tsx:
- Around line 134-233: The LoadMoreSentinel component (including captureAndLoad,
sentinelRef, scrollSnapshotRef, autoFillRoundsRef, autoTriggeredRef, useEffect/
useLayoutEffect logic and MAX_AUTO_FILL_ROUNDS usage) should be extracted out of
the large ChatMessagesContainer file into its own local component/hook pair
under the components folder: create a LoadMoreSentinel.tsx that contains the JSX
and effects and a useLoadMoreSentinel.ts (or keep helper functions) to
encapsulate observer/backoff/scroll-preservation state; ensure it imports
useStickToBottomContext and accepts the same props (hasMore, isLoading,
messageCount, onLoadMore) and preserve behavior (captureAndLoad semantics,
observer rootMargin, and scroll adjustment in useLayoutEffect), update the
original ChatMessagesContainer to import and render the new component and run
tests to confirm no behavioral changes.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: abc4da2f-cec5-4a55-a20b-8ae08bad0b70

📥 Commits

Reviewing files that changed from the base of the PR and between 1877916 and 00cadee.

📒 Files selected for processing (2)
  • autogpt_platform/frontend/src/app/(platform)/copilot/components/ChatMessagesContainer/ChatMessagesContainer.tsx
  • autogpt_platform/frontend/src/app/(platform)/copilot/components/ChatMessagesContainer/__tests__/LoadMoreSentinel.test.tsx
✅ Files skipped from review due to trivial changes (1)
  • autogpt_platform/frontend/src/app/(platform)/copilot/components/ChatMessagesContainer/tests/LoadMoreSentinel.test.tsx
📜 Review details
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (2)
  • GitHub Check: end-to-end tests
  • GitHub Check: Check PR Status
🧰 Additional context used
📓 Path-based instructions (9)
autogpt_platform/frontend/**/*.{ts,tsx,js,jsx}

📄 CodeRabbit inference engine (.github/copilot-instructions.md)

autogpt_platform/frontend/**/*.{ts,tsx,js,jsx}: Use Node.js 21+ with pnpm package manager for frontend development
Always run 'pnpm format' for formatting and linting code in frontend development

Format frontend code using pnpm format

Files:

  • autogpt_platform/frontend/src/app/(platform)/copilot/components/ChatMessagesContainer/ChatMessagesContainer.tsx
autogpt_platform/frontend/**/*.{tsx,ts}

📄 CodeRabbit inference engine (.github/copilot-instructions.md)

autogpt_platform/frontend/**/*.{tsx,ts}: Use function declarations for components and handlers (not arrow functions) in React components
Only use arrow functions for small inline lambdas (map, filter, etc.) in React components
Use PascalCase for component names and camelCase with 'use' prefix for hook names in React
Use Tailwind CSS utilities only for styling in frontend components
Use design system components from 'src/components/' (atoms, molecules, organisms) in frontend development
Never use 'src/components/legacy/' in frontend code
Only use Phosphor Icons (@phosphor-icons/react) for icons in frontend components
Use generated API hooks from '@/app/api/generated/endpoints/' instead of deprecated 'BackendAPI' or 'src/lib/autogpt-server-api/
'
Use React Query for server state (via generated hooks) in frontend development
Default to client components ('use client') in Next.js; only use server components for SEO or extreme TTFB needs
Use '' component for rendering errors in frontend UI; use toast notifications for mutation errors; use 'Sentry.captureException()' for manual exceptions
Separate render logic from data/behavior in React components; keep comments minimal (code should be self-documenting)

Files:

  • autogpt_platform/frontend/src/app/(platform)/copilot/components/ChatMessagesContainer/ChatMessagesContainer.tsx
autogpt_platform/frontend/**/*.{ts,tsx}

📄 CodeRabbit inference engine (.github/copilot-instructions.md)

autogpt_platform/frontend/**/*.{ts,tsx}: No barrel files or 'index.ts' re-exports in frontend code
Regenerate API hooks with 'pnpm generate:api' after backend OpenAPI spec changes in frontend development

autogpt_platform/frontend/**/*.{ts,tsx}: Fully capitalize acronyms in symbols, e.g. graphID, useBackendAPI
Use function declarations (not arrow functions) for components and handlers
No dark: Tailwind classes — the design system handles dark mode
Use Next.js <Link> for internal navigation — never raw <a> tags
No any types unless the value genuinely can be anything
No linter suppressors (// @ts-ignore``, // eslint-disable) — fix the actual issue
Keep files under ~200 lines; extract sub-components or hooks into their own files when a file grows beyond this
Keep render functions and hooks under ~50 lines; extract named helpers or sub-components when they grow longer
Use generated API hooks from `@/app/api/generated/endpoints/` with pattern `use{Method}{Version}{OperationName}` and regenerate with `pnpm generate:api`
Do not use `useCallback` or `useMemo` unless asked to optimise a given function
Separate render logic (`.tsx`) from business logic (`use*.ts` hooks)
Use ErrorCard for render errors, toast for mutations, and Sentry for exceptions in the frontend

Files:

  • autogpt_platform/frontend/src/app/(platform)/copilot/components/ChatMessagesContainer/ChatMessagesContainer.tsx
autogpt_platform/frontend/src/**/*.{ts,tsx}

📄 CodeRabbit inference engine (AGENTS.md)

autogpt_platform/frontend/src/**/*.{ts,tsx}: Use generated API hooks from @/app/api/__generated__/endpoints/ following the pattern use{Method}{Version}{OperationName}, and regenerate with pnpm generate:api
Separate render logic from business logic using component.tsx + useComponent.ts + helpers.ts pattern, colocate state when possible and avoid creating large components, use sub-components in local /components folder
Use function declarations for components and handlers, use arrow functions only for callbacks
Do not use useCallback or useMemo unless asked to optimise a given function

Files:

  • autogpt_platform/frontend/src/app/(platform)/copilot/components/ChatMessagesContainer/ChatMessagesContainer.tsx
autogpt_platform/frontend/**/*.{tsx,css}

📄 CodeRabbit inference engine (AGENTS.md)

Use Tailwind CSS only for styling, use design tokens, and use Phosphor Icons only

Files:

  • autogpt_platform/frontend/src/app/(platform)/copilot/components/ChatMessagesContainer/ChatMessagesContainer.tsx
autogpt_platform/frontend/src/**/*.tsx

📄 CodeRabbit inference engine (AGENTS.md)

Component props should use interface Props { ... } (not exported) unless the interface needs to be used outside the component

Files:

  • autogpt_platform/frontend/src/app/(platform)/copilot/components/ChatMessagesContainer/ChatMessagesContainer.tsx
autogpt_platform/**/*.{ts,tsx}

📄 CodeRabbit inference engine (AGENTS.md)

Never type with any, if no types available use unknown

Files:

  • autogpt_platform/frontend/src/app/(platform)/copilot/components/ChatMessagesContainer/ChatMessagesContainer.tsx
autogpt_platform/frontend/src/app/(platform)/**/components/**/*.tsx

📄 CodeRabbit inference engine (autogpt_platform/frontend/AGENTS.md)

Put sub-components in local components/ folder

Files:

  • autogpt_platform/frontend/src/app/(platform)/copilot/components/ChatMessagesContainer/ChatMessagesContainer.tsx
autogpt_platform/frontend/**/*.tsx

📄 CodeRabbit inference engine (autogpt_platform/frontend/AGENTS.md)

autogpt_platform/frontend/**/*.tsx: Component props should be type Props = { ... } (not exported) unless it needs to be used outside the component
Use design system components from src/components/ (atoms, molecules, organisms)
Never use src/components/__legacy__/*
Tailwind CSS only for styling, use design tokens, Phosphor Icons only

Files:

  • autogpt_platform/frontend/src/app/(platform)/copilot/components/ChatMessagesContainer/ChatMessagesContainer.tsx
🧠 Learnings (21)
📓 Common learnings
Learnt from: kcze
Repo: Significant-Gravitas/AutoGPT PR: 12328
File: autogpt_platform/frontend/src/app/(platform)/copilot/useLoadMoreMessages.ts:49-61
Timestamp: 2026-03-11T08:40:59.673Z
Learning: In `autogpt_platform/frontend/src/app/(platform)/copilot/useLoadMoreMessages.ts`, clearing `olderMessages` (and resetting `oldestSequence`/`hasMore`) when `initialOldestSequence` shifts on the same session is intentional. Pages already fetched were based on a now-stale cursor; retaining them risks sequence gaps or duplicates. `ScrollPreserver` keeps the currently visible viewport intact, so only unvisited older pages are dropped. This is a deliberate safe-refetch design tradeoff.
Learnt from: majdyz
Repo: Significant-Gravitas/AutoGPT PR: 12773
File: autogpt_platform/backend/backend/copilot/pending_messages.py:52-64
Timestamp: 2026-04-14T14:36:22.396Z
Learning: In `autogpt_platform/backend/backend/copilot` (PR `#12773`, commit d7bced0c6): when draining pending messages into `session.messages`, each message's text is sanitized via `strip_user_context_tags` before persistence to prevent user-controlled `<user_context>` injection from bypassing the trusted server-side context prefix. Additionally, if `upsert_chat_session` fails after draining, the drained `PendingMessage` objects are requeued back to Redis to avoid silent message loss. Do NOT flag the drain-then-requeue pattern as redundant — it is the intentional failure-resilience strategy for the pending buffer.
Learnt from: majdyz
Repo: Significant-Gravitas/AutoGPT PR: 12445
File: autogpt_platform/backend/backend/copilot/sdk/service.py:1071-1072
Timestamp: 2026-03-17T06:48:26.471Z
Learning: In Significant-Gravitas/AutoGPT (autogpt_platform), the AI SDK enforces `z.strictObject({type, errorText})` on SSE `StreamError` responses, so additional fields like `retryable: bool` cannot be added to `StreamError` or serialized via `to_sse()`. Instead, retry signaling for transient Anthropic API errors is done via the `COPILOT_RETRYABLE_ERROR_PREFIX` constant prepended to persisted session messages (in `ChatMessage.content`). The frontend detects retryable errors by checking `markerType === "retryable_error"` from `parseSpecialMarkers()` — no SSE schema changes and no string matching on error text. This pattern was established in PR `#12445`, commit 64d82797b.
Learnt from: majdyz
Repo: Significant-Gravitas/AutoGPT PR: 12445
File: autogpt_platform/frontend/src/app/(platform)/copilot/components/ChatContainer/ChatContainer.tsx:55-67
Timestamp: 2026-03-17T06:18:51.570Z
Learning: In `autogpt_platform/frontend/src/app/(platform)/copilot/components/ChatContainer/ChatContainer.tsx`, an explicit `isBusy` guard on the retry handler (`handleRetry`) is not needed. Once `onSend` is invoked, the chat status immediately transitions to "submitted", which causes the `ErrorCard` (containing the retry button) to unmount before a second click can register, making double-send impossible by design.
📚 Learning: 2026-03-11T08:40:59.673Z
Learnt from: kcze
Repo: Significant-Gravitas/AutoGPT PR: 12328
File: autogpt_platform/frontend/src/app/(platform)/copilot/useLoadMoreMessages.ts:49-61
Timestamp: 2026-03-11T08:40:59.673Z
Learning: In `autogpt_platform/frontend/src/app/(platform)/copilot/useLoadMoreMessages.ts`, clearing `olderMessages` (and resetting `oldestSequence`/`hasMore`) when `initialOldestSequence` shifts on the same session is intentional. Pages already fetched were based on a now-stale cursor; retaining them risks sequence gaps or duplicates. `ScrollPreserver` keeps the currently visible viewport intact, so only unvisited older pages are dropped. This is a deliberate safe-refetch design tradeoff.

Applied to files:

  • autogpt_platform/frontend/src/app/(platform)/copilot/components/ChatMessagesContainer/ChatMessagesContainer.tsx
📚 Learning: 2026-03-17T06:18:51.570Z
Learnt from: majdyz
Repo: Significant-Gravitas/AutoGPT PR: 12445
File: autogpt_platform/frontend/src/app/(platform)/copilot/components/ChatContainer/ChatContainer.tsx:55-67
Timestamp: 2026-03-17T06:18:51.570Z
Learning: In `autogpt_platform/frontend/src/app/(platform)/copilot/components/ChatContainer/ChatContainer.tsx`, an explicit `isBusy` guard on the retry handler (`handleRetry`) is not needed. Once `onSend` is invoked, the chat status immediately transitions to "submitted", which causes the `ErrorCard` (containing the retry button) to unmount before a second click can register, making double-send impossible by design.

Applied to files:

  • autogpt_platform/frontend/src/app/(platform)/copilot/components/ChatMessagesContainer/ChatMessagesContainer.tsx
📚 Learning: 2026-04-14T14:36:22.396Z
Learnt from: majdyz
Repo: Significant-Gravitas/AutoGPT PR: 12773
File: autogpt_platform/backend/backend/copilot/pending_messages.py:52-64
Timestamp: 2026-04-14T14:36:22.396Z
Learning: In `autogpt_platform/backend/backend/copilot` (PR `#12773`, commit d7bced0c6): when draining pending messages into `session.messages`, each message's text is sanitized via `strip_user_context_tags` before persistence to prevent user-controlled `<user_context>` injection from bypassing the trusted server-side context prefix. Additionally, if `upsert_chat_session` fails after draining, the drained `PendingMessage` objects are requeued back to Redis to avoid silent message loss. Do NOT flag the drain-then-requeue pattern as redundant — it is the intentional failure-resilience strategy for the pending buffer.

Applied to files:

  • autogpt_platform/frontend/src/app/(platform)/copilot/components/ChatMessagesContainer/ChatMessagesContainer.tsx
📚 Learning: 2026-03-17T06:48:26.471Z
Learnt from: majdyz
Repo: Significant-Gravitas/AutoGPT PR: 12445
File: autogpt_platform/backend/backend/copilot/sdk/service.py:1071-1072
Timestamp: 2026-03-17T06:48:26.471Z
Learning: In Significant-Gravitas/AutoGPT (autogpt_platform), the AI SDK enforces `z.strictObject({type, errorText})` on SSE `StreamError` responses, so additional fields like `retryable: bool` cannot be added to `StreamError` or serialized via `to_sse()`. Instead, retry signaling for transient Anthropic API errors is done via the `COPILOT_RETRYABLE_ERROR_PREFIX` constant prepended to persisted session messages (in `ChatMessage.content`). The frontend detects retryable errors by checking `markerType === "retryable_error"` from `parseSpecialMarkers()` — no SSE schema changes and no string matching on error text. This pattern was established in PR `#12445`, commit 64d82797b.

Applied to files:

  • autogpt_platform/frontend/src/app/(platform)/copilot/components/ChatMessagesContainer/ChatMessagesContainer.tsx
📚 Learning: 2026-04-14T06:39:49.111Z
Learnt from: majdyz
Repo: Significant-Gravitas/AutoGPT PR: 12773
File: autogpt_platform/frontend/src/app/api/openapi.json:12803-12806
Timestamp: 2026-04-14T06:39:49.111Z
Learning: Repo: Significant-Gravitas/AutoGPT — autogpt_platform
Intentional message length caps:
- StreamChatRequest.message maxLength = 64000.
- QueuePendingMessageRequest.message maxLength = 32000 (matches PendingMessage.content).
Rationale: both feed the same LLM context window; pending must not exceed stream, and larger ceilings replace legacy 4000/16000.

Applied to files:

  • autogpt_platform/frontend/src/app/(platform)/copilot/components/ChatMessagesContainer/ChatMessagesContainer.tsx
📚 Learning: 2026-04-13T13:10:33.180Z
Learnt from: 0ubbe
Repo: Significant-Gravitas/AutoGPT PR: 12764
File: autogpt_platform/frontend/src/app/(platform)/library/components/LibraryAgentList/useLibraryAgentList.ts:264-294
Timestamp: 2026-04-13T13:10:33.180Z
Learning: In `autogpt_platform/frontend/src/app/(platform)/library/components/LibraryAgentList/useLibraryAgentList.ts`, the `consecutiveEmptyPagesRef` and `prevFilteredLengthRef` refs used to track filtered-pagination exhaustion are intentional. The one-render lag in `filteredExhausted` (which reads `consecutiveEmptyPagesRef.current` synchronously) is by design — refs are preferred here to avoid triggering extra re-renders for internal fetch-state bookkeeping. Do not flag this as a stale-ref bug in future reviews.

Applied to files:

  • autogpt_platform/frontend/src/app/(platform)/copilot/components/ChatMessagesContainer/ChatMessagesContainer.tsx
📚 Learning: 2026-03-05T19:50:36.724Z
Learnt from: Bentlybro
Repo: Significant-Gravitas/AutoGPT PR: 0
File: :0-0
Timestamp: 2026-03-05T19:50:36.724Z
Learning: In `autogpt_platform/frontend/src/app/api/helpers.ts`, the `getPaginationNextPageNumber()` function includes an intentional defensive null check (`if (!pagination) return undefined`) after destructuring `lastPage.data.pagination`. This was proven necessary in production because React Query calls `getNextPageParam` even with error responses (e.g., 401s) that lack the expected pagination structure. Returning `undefined` signals React Query to treat it as "no next page" and stop pagination instead of throwing a TypeError. This is valid and should not be flagged in future reviews.

Applied to files:

  • autogpt_platform/frontend/src/app/(platform)/copilot/components/ChatMessagesContainer/ChatMessagesContainer.tsx
📚 Learning: 2026-03-19T12:07:49.237Z
Learnt from: 0ubbe
Repo: Significant-Gravitas/AutoGPT PR: 12462
File: autogpt_platform/frontend/src/app/(platform)/marketplace/components/AgentImages/AgentImage.tsx:17-21
Timestamp: 2026-03-19T12:07:49.237Z
Learning: In `autogpt_platform/frontend/src/app/(platform)/marketplace/components/AgentImages/AgentImage.tsx`, the `images` array passed to `AgentImages` is static per agent detail page and does not change after mount. Therefore, index-based keying of `loadedThumbs` (a `Set<number>`) is sufficient and will not produce stale entries. Do not flag this as a potential stale-state issue due to index reuse.

Applied to files:

  • autogpt_platform/frontend/src/app/(platform)/copilot/components/ChatMessagesContainer/ChatMessagesContainer.tsx
📚 Learning: 2026-04-15T10:17:08.698Z
Learnt from: kcze
Repo: Significant-Gravitas/AutoGPT PR: 0
File: :0-0
Timestamp: 2026-04-15T10:17:08.698Z
Learning: In `Significant-Gravitas/AutoGPT` (`autogpt_platform/frontend`), `vitest.config.mts` does NOT set `globals: true`, and `src/tests/integrations/vitest.setup.tsx` does NOT register the `testing-library/react` auto-cleanup hook. Therefore, integration test files (e.g., under `__tests__/`) MUST include an explicit `afterEach(cleanup)` call from `testing-library/react` to reset the DOM between tests — without it, tests fail with "multiple elements found" errors from the prior test's DOM. Do NOT flag `afterEach(cleanup)` as redundant in this codebase.

Applied to files:

  • autogpt_platform/frontend/src/app/(platform)/copilot/components/ChatMessagesContainer/ChatMessagesContainer.tsx
📚 Learning: 2026-04-08T17:28:40.841Z
Learnt from: CR
Repo: Significant-Gravitas/AutoGPT PR: 0
File: autogpt_platform/frontend/AGENTS.md:0-0
Timestamp: 2026-04-08T17:28:40.841Z
Learning: Applies to autogpt_platform/frontend/**/*.{ts,tsx} : No linter suppressors (`// ts-ignore`, `// eslint-disable`) — fix the actual issue

Applied to files:

  • autogpt_platform/frontend/src/app/(platform)/copilot/components/ChatMessagesContainer/ChatMessagesContainer.tsx
📚 Learning: 2026-04-08T17:28:40.841Z
Learnt from: CR
Repo: Significant-Gravitas/AutoGPT PR: 0
File: autogpt_platform/frontend/AGENTS.md:0-0
Timestamp: 2026-04-08T17:28:40.841Z
Learning: Applies to autogpt_platform/frontend/**/*.tsx : Use design system components from `src/components/` (atoms, molecules, organisms)

Applied to files:

  • autogpt_platform/frontend/src/app/(platform)/copilot/components/ChatMessagesContainer/ChatMessagesContainer.tsx
📚 Learning: 2026-02-04T16:49:42.490Z
Learnt from: CR
Repo: Significant-Gravitas/AutoGPT PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2026-02-04T16:49:42.490Z
Learning: Applies to autogpt_platform/frontend/**/*.{tsx,ts} : Use design system components from 'src/components/' (atoms, molecules, organisms) in frontend development

Applied to files:

  • autogpt_platform/frontend/src/app/(platform)/copilot/components/ChatMessagesContainer/ChatMessagesContainer.tsx
📚 Learning: 2026-02-27T10:45:49.499Z
Learnt from: majdyz
Repo: Significant-Gravitas/AutoGPT PR: 12213
File: autogpt_platform/frontend/src/app/(platform)/copilot/tools/RunMCPTool/helpers.tsx:23-24
Timestamp: 2026-02-27T10:45:49.499Z
Learning: Prefer using generated OpenAPI types from '@/app/api/__generated__/' for payloads defined in openapi.json (e.g., MCPToolsDiscoveredResponse, MCPToolOutputResponse). Use inline TypeScript interfaces only for payloads that are SSE-stream-only and not exposed via OpenAPI. Apply this pattern to frontend tool components (e.g., RunMCPTool) and related areas where similar SSE/openapi-discrepancies occur; avoid re-implementing types when a generated type is available.

Applied to files:

  • autogpt_platform/frontend/src/app/(platform)/copilot/components/ChatMessagesContainer/ChatMessagesContainer.tsx
📚 Learning: 2026-03-24T02:05:04.672Z
Learnt from: majdyz
Repo: Significant-Gravitas/AutoGPT PR: 12526
File: autogpt_platform/frontend/src/app/(platform)/copilot/CopilotPage.tsx:0-0
Timestamp: 2026-03-24T02:05:04.672Z
Learning: When gating React component logic on a React Query result (e.g., hooks like `useQuery` / `useGetV2GetCopilotUsage`), prefer destructuring and checking `isSuccess` (or aliasing it to a meaningful boolean like `isSuccess: hasUsage`) instead of relying on `!isLoading`. Reason: `isLoading` can be `false` in error/idle states where `data` may still be `undefined`, while `isSuccess` indicates the query completed successfully and `data` is populated.

Applied to files:

  • autogpt_platform/frontend/src/app/(platform)/copilot/components/ChatMessagesContainer/ChatMessagesContainer.tsx
📚 Learning: 2026-03-24T02:23:31.305Z
Learnt from: majdyz
Repo: Significant-Gravitas/AutoGPT PR: 12526
File: autogpt_platform/frontend/src/app/(platform)/copilot/components/RateLimitResetDialog/RateLimitResetDialog.tsx:0-0
Timestamp: 2026-03-24T02:23:31.305Z
Learning: In the Copilot platform UI code, follow the established Orval hook `onError` error-handling convention: first explicitly detect/handle `ApiError`, then read `error.response?.detail` (if present) as the primary message; if not available, fall back to `error.message`; and finally fall back to a generic string message. This convention should be used for generated Orval hooks even if the custom Orval mutator already maps details into `ApiError.message`, to keep consistency across hooks/components (e.g., `useCronSchedulerDialog.ts`, `useRunGraph.ts`, and rate-limit/reset flows).

Applied to files:

  • autogpt_platform/frontend/src/app/(platform)/copilot/components/ChatMessagesContainer/ChatMessagesContainer.tsx
📚 Learning: 2026-03-31T14:04:42.444Z
Learnt from: majdyz
Repo: Significant-Gravitas/AutoGPT PR: 12623
File: autogpt_platform/frontend/src/app/(platform)/copilot/components/ChatInput/ChatInput.tsx:172-177
Timestamp: 2026-03-31T14:04:42.444Z
Learning: In the Copilot frontend components under autogpt_platform/frontend/src/app/(platform)/copilot/, Tailwind dark mode variants (e.g., `dark:*`) are intentional and should be allowed. Do not flag `dark:` utilities in these Copilot UI components as incorrect; they are used to ensure proper contrast and correct behavior in both light and dark themes.

Applied to files:

  • autogpt_platform/frontend/src/app/(platform)/copilot/components/ChatMessagesContainer/ChatMessagesContainer.tsx
📚 Learning: 2026-04-01T18:54:16.035Z
Learnt from: Bentlybro
Repo: Significant-Gravitas/AutoGPT PR: 12633
File: autogpt_platform/frontend/src/app/(platform)/library/components/AgentFilterMenu/AgentFilterMenu.tsx:3-10
Timestamp: 2026-04-01T18:54:16.035Z
Learning: In the frontend, the legacy Select component at `@/components/__legacy__/ui/select` is an intentional, codebase-wide visual-consistency pattern. During code reviews, do not flag or block PRs merely for continuing to use this legacy Select. If a migration to the newer design-system Select is desired, bundle it into a single dedicated cleanup/migration PR that updates all Select usages together (e.g., avoid piecemeal replacements).

Applied to files:

  • autogpt_platform/frontend/src/app/(platform)/copilot/components/ChatMessagesContainer/ChatMessagesContainer.tsx
📚 Learning: 2026-04-07T09:24:16.582Z
Learnt from: 0ubbe
Repo: Significant-Gravitas/AutoGPT PR: 12686
File: autogpt_platform/frontend/src/app/(no-navbar)/onboarding/steps/__tests__/PainPointsStep.test.tsx:1-19
Timestamp: 2026-04-07T09:24:16.582Z
Learning: In Significant-Gravitas/AutoGPT’s `autogpt_platform/frontend` (Vite + `vitejs/plugin-react` with the automatic JSX transform), do not flag usages of React types/components (e.g., `React.ReactNode`) in `.ts`/`.tsx` files as missing `React` imports. Since the React namespace is made available by the project’s TS/Vite setup, an explicit `import React from 'react'` or `import type { ReactNode } ...` is not required; only treat it as missing if typechecking (e.g., `pnpm types`) would actually fail.

Applied to files:

  • autogpt_platform/frontend/src/app/(platform)/copilot/components/ChatMessagesContainer/ChatMessagesContainer.tsx
📚 Learning: 2026-04-02T05:43:49.128Z
Learnt from: 0ubbe
Repo: Significant-Gravitas/AutoGPT PR: 12640
File: autogpt_platform/frontend/src/app/(no-navbar)/onboarding/steps/WelcomeStep.tsx:13-13
Timestamp: 2026-04-02T05:43:49.128Z
Learning: Do not flag `import { Question } from "phosphor-icons/react"` as an invalid import. `Question` is a valid named export from `phosphor-icons/react` (as reflected in the package’s generated `.d.ts` files and re-exports via `dist/index.d.ts`), so it should be treated as a supported named export during code reviews.

Applied to files:

  • autogpt_platform/frontend/src/app/(platform)/copilot/components/ChatMessagesContainer/ChatMessagesContainer.tsx
📚 Learning: 2026-04-13T13:11:07.445Z
Learnt from: 0ubbe
Repo: Significant-Gravitas/AutoGPT PR: 12764
File: autogpt_platform/frontend/src/app/(platform)/library/components/SitrepItem/SitrepItem.tsx:143-145
Timestamp: 2026-04-13T13:11:07.445Z
Learning: In `autogpt_platform/frontend`, do not flag direct interpolation of `executionID` UUID strings into URL query parameters (e.g., `activeItem=${executionID}` in JSX/Next links). If the value is a UUID string matching `[0-9a-f-]`, it contains no reserved URL characters, so additional `encodeURIComponent` or Next.js object-based `href` encoding is unnecessary. Only treat it as an encoding issue if the query-param value is not guaranteed to be UUID-formatted (i.e., may include characters outside `[0-9a-f-]`).

Applied to files:

  • autogpt_platform/frontend/src/app/(platform)/copilot/components/ChatMessagesContainer/ChatMessagesContainer.tsx

kcze and others added 2 commits April 15, 2026 20:26
…fect paths

Mock IntersectionObserver and useStickToBottomContext's scrollRef so the
observer callback, scroll-restore math, auto-fill round counter and cap,
and the counter-reset-on-scrollable path are all exercised by tests.
Brings codecov patch coverage on ChatMessagesContainer.tsx over the
80% threshold on the lines changed in this PR.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
…ntry

The parent's isLoading flag lags the trigger by a render, so the
observer (or manual button, or both) could fire captureAndLoad more
than once in the same frame. That issued duplicate page requests for
the same cursor and overwrote the preserved scroll snapshot.

Add a ref-based pending-load latch set synchronously in captureAndLoad
and cleared via useEffect when isLoading transitions to false.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
@github-project-automation github-project-automation Bot moved this from 🆕 Needs initial review to 👍🏼 Mergeable in AutoGPT development kanban Apr 15, 2026
@kcze
kcze added this pull request to the merge queue Apr 15, 2026
Merged via the queue into dev with commit c955b39 Apr 15, 2026
34 checks passed
@kcze
kcze deleted the kpczerwinski/secrt-2226-chat-history-fails-to-load-when-last-response-fits-entirely branch April 15, 2026 13:33
@github-project-automation github-project-automation Bot moved this from 👍🏼 Mergeable to ✅ Done in AutoGPT development kanban Apr 15, 2026
@github-project-automation github-project-automation Bot moved this to Done in Frontend Apr 15, 2026
@sentry

sentry Bot commented Apr 16, 2026

Copy link
Copy Markdown

Issues attributed to commits in this pull request

This pull request was merged and Sentry observed the following issues:

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

platform/frontend AutoGPT Platform - Front end size/l

Projects

Status: ✅ Done
Status: Done

Development

Successfully merging this pull request may close these issues.

2 participants