Skip to content

fix(copilot): prevent 524 timeout on chat deletion by deferring cleanup - #12668

Closed
Otto-AGPT wants to merge 15 commits into
devfrom
otto/secrt-2215-copilot-deleting-currently-selected-chat-never-completes
Closed

fix(copilot): prevent 524 timeout on chat deletion by deferring cleanup#12668
Otto-AGPT wants to merge 15 commits into
devfrom
otto/secrt-2215-copilot-deleting-currently-selected-chat-never-completes

Conversation

@Otto-AGPT

Copy link
Copy Markdown
Contributor

Requested by @Pwuts

Why

Deleting a currently-selected CoPilot chat causes the delete dialog to hang indefinitely. The network inspector shows the DELETE request returning HTTP 524 (Cloudflare timeout) because the endpoint awaits slow cleanup operations (browser daemon shutdown ~10s, E2B sandbox teardown ~10s) before responding. The backend does delete the session, but the client never gets the 204 back in time.

What

Backend — defer slow cleanup to background tasks:

  • routes.py: Move E2B sandbox kill_sandbox() into asyncio.create_task() so the 204 response returns immediately after the DB delete succeeds
  • model.py: Move close_browser_session() into asyncio.create_task() for the same reason

Frontend — improve resilience:

  • Reorder onSuccess: close the dialog (setSessionToDelete(null)) before clearing the selected session (setSessionId(null)), so the UI updates instantly before the chat-view teardown cascade runs
  • Improve onError to also refresh the session list and navigate away from the deleted chat — the server may have completed the delete even when the client receives a timeout error (524)

Testing

  1. Select a chat → delete → dialog closes immediately, chat gone from sidebar
  2. Delete a non-selected chat → still works (no regression)
  3. Delete a chat with active E2B sandbox → response is fast, sandbox cleaned up in background
  4. Check server logs to confirm background cleanup tasks complete successfully

Resolves SECRT-2215

The delete_session endpoint awaited browser daemon shutdown (~10s) and
E2B sandbox teardown (~10s) before returning 204. When routed through
Cloudflare, this exceeded the connection timeout and returned 524 to the
client — leaving the delete dialog stuck in loading state.

Backend:
- Move E2B sandbox kill to an asyncio background task so the 204 response
  returns immediately after the DB delete succeeds.
- Move browser session cleanup to a background task in the model layer
  for the same reason.

Frontend:
- Reorder onSuccess: close the dialog (setSessionToDelete(null)) before
  clearing the selected session (setSessionId(null)), so the UI updates
  instantly before the chat-view teardown cascade runs.
- Improve onError to also refresh the session list and navigate away from
  the deleted chat — the server may have completed the delete even when
  the client receives a timeout error.

Resolves SECRT-2215

Co-authored-by: Reinier van der Leer <pwuts@agpt.co>
@github-project-automation github-project-automation Bot moved this to 🆕 Needs initial review in AutoGPT development kanban Apr 3, 2026
@Otto-AGPT
Otto-AGPT requested a review from a team as a code owner April 3, 2026 13:24
@Otto-AGPT
Otto-AGPT requested review from 0ubbe and ntindle and removed request for a team April 3, 2026 13:24
@github-actions github-actions Bot added platform/frontend AutoGPT Platform - Front end platform/backend AutoGPT Platform - Back end labels Apr 3, 2026
@coderabbitai

coderabbitai Bot commented Apr 3, 2026

Copy link
Copy Markdown
Contributor

Walkthrough

This PR introduces substantial refactoring across session management, transcript handling, billing infrastructure, and library functionality. It adds background cleanup for E2B sandboxes and browser sessions, refactors transcript restoration with gap detection and context extraction, hardens subscription/Stripe integration with idempotency and error handling, optimizes library agent execution count fetching, adds Grok 4.20 LLM models, improves cache handling for None values, and updates frontend session deletion UI coordination.

Changes

Cohort / File(s) Summary
Background Cleanup Scheduling
autogpt_platform/backend/backend/api/features/chat/routes.py, autogpt_platform/backend/backend/copilot/model.py, autogpt_platform/backend/backend/copilot/model_test.py
Moved E2B sandbox and browser teardown from blocking in-request calls to scheduled background tasks via asyncio.create_task(), returning immediately while cleanup proceeds asynchronously. Added internal _cleanup_sandbox() and _cleanup_browser_session() helpers with exception handling.
Session Deletion UI Coordination
autogpt_platform/frontend/src/app/(platform)/copilot/useCopilotPage.ts
Updated delete-session mutation handlers to coordinate UI state with query refresh: clear sessionToDelete before sessionId, invalidate session list query on both success and error, and only clear sessionId when the deleted session was selected.
Chat Route Tests
autogpt_platform/backend/backend/api/features/chat/routes_test.py
Added tests for async sandbox cleanup behavior, verifying asyncio.create_task scheduling with E2B enabled/disabled and HTTP 204 responses.
Library Agent Execution Counts
autogpt_platform/backend/backend/api/features/library/db.py, autogpt_platform/backend/backend/api/features/library/db_test.py, autogpt_platform/backend/backend/api/features/library/model.py, autogpt_platform/backend/backend/api/features/library/model_test.py
Added batched _fetch_execution_counts() helper and injected execution_count_override parameter into LibraryAgent.from_db() to optimize per-agent execution count lookup and prevent computation when executions list is empty.
Transcript Restoration & Context Extraction
autogpt_platform/backend/backend/copilot/baseline/service.py, autogpt_platform/backend/backend/copilot/baseline/transcript_integration_test.py, autogpt_platform/backend/backend/copilot/transcript.py, autogpt_platform/backend/backend/copilot/transcript_test.py
Refactored transcript handling: replaced staleness checks with should_upload_transcript(user_id, upload_safe), added detect_gap() and extract_context_messages() helpers for gap detection and context building, updated _load_prior_transcript() signature to accept full session messages and return (upload_safe, TranscriptDownload), changed storage to bytes + meta-JSON pairs.
SDK Transcript Integration
autogpt_platform/backend/backend/copilot/sdk/service.py, autogpt_platform/backend/backend/copilot/sdk/service_helpers_test.py, autogpt_platform/backend/backend/copilot/sdk/test_transcript_watermark.py, autogpt_platform/backend/backend/copilot/sdk/transcript.py, autogpt_platform/backend/backend/copilot/sdk/transcript_test.py, autogpt_platform/backend/backend/copilot/sdk/retry_scenarios_test.py, autogpt_platform/backend/backend/copilot/sdk/mode_switch_context_test.py
Overhauled SDK/baseline transcript restore flow: added process_cli_restore() and read_cli_session_from_disk() helpers, new _restore_cli_session_for_turn() to unify restore logic with mode-aware resume gating, updated _build_query_message() to use optimized prior messages from transcript+gap, modified upload logic to use stripped CLI-native session bytes with mode tracking.
Subscription & Billing Hardening
autogpt_platform/backend/backend/api/features/v1.py, autogpt_platform/backend/backend/api/features/subscription_routes_test.py, autogpt_platform/backend/backend/data/credit.py, autogpt_platform/backend/backend/data/credit_subscription_test.py
Added Stripe integration improvements: cached price lookups, idempotency guards, proration credit computation, subscription modification in-place vs downgrade logic, payment failure handler, open-redirect URL validation, webhook hardening (reject empty secrets, defensive data extraction), and enhanced error handling (422/502 differentiation).
Cache Improvements
autogpt_platform/backend/backend/util/cache.py, autogpt_platform/backend/backend/util/cache_test.py
Extended @cached decorator with cache_none: bool parameter to optionally skip caching None results; introduced _MISSING sentinel to distinguish cache misses from cached None values.
LLM Model Additions
autogpt_platform/backend/backend/blocks/llm.py, autogpt_platform/backend/backend/data/block_cost_config.py
Added Grok 4.20 model enum entries (GROK_4_20, GROK_4_20_MULTI_AGENT) with corresponding metadata and cost mappings.
Feature Flag & Helper Updates
autogpt_platform/backend/backend/util/feature_flag.py, autogpt_platform/backend/backend/copilot/context.py, autogpt_platform/backend/backend/copilot/prompting.py, autogpt_platform/backend/backend/copilot/sdk/security_hooks.py, autogpt_platform/backend/backend/copilot/service_test.py
Added UUID validation in feature flag context fetching, updated function references (_projects_base()projects_base()), added GitHub CLI guidance to E2B tool notes, refactored transcript validation in service tests.
Transcript Watermark Tests
autogpt_platform/backend/test/copilot/test_transcript_watermark.py
Added unit tests for watermark computation and gap-fill triggering in _build_query_message with varying transcript staleness scenarios.
Download Transcripts & Dependencies
autogpt_platform/backend/scripts/download_transcripts.py, autogpt_platform/frontend/package.json
Normalized transcript content to UTF-8 string for file writing and bytes for upload; added agentation dev dependency.

Sequence Diagrams

sequenceDiagram
    participant Client
    participant ChatRoute
    participant Redis
    participant E2B as E2B<br/>Sandbox
    participant Task as Async<br/>Task

    Client->>ChatRoute: DELETE /sessions/{id}
    ChatRoute->>Redis: Check & remove session
    ChatRoute->>Task: asyncio.create_task<br/>(_cleanup_sandbox)
    ChatRoute-->>Client: 204 No Content
    
    Task->>E2B: kill_sandbox(session_id)
    Task->>Task: Log on failure
    Note over Task: Cleanup continues<br/>in background
Loading
sequenceDiagram
    participant SDK as SDK<br/>Service
    participant GCS as GCS<br/>Storage
    participant Restore as Restore<br/>Flow
    participant Builder as Transcript<br/>Builder
    participant DB as Chat DB

    SDK->>GCS: download_transcript
    alt Download Success
        GCS-->>SDK: TranscriptDownload<br/>(bytes, meta)
        SDK->>Restore: process_cli_restore
        Restore->>Builder: validate & load
        SDK->>Builder: detect_gap(download,<br/>session_messages)
        alt Gap Detected
            SDK->>DB: Fetch missing messages
            SDK->>Builder: _append_gap_to_builder
        end
        Builder-->>SDK: Complete context
    else Download Failed
        GCS-->>SDK: None
        SDK->>Builder: extract_context_messages<br/>(None, session_messages)
        Builder-->>SDK: DB messages only
    end
Loading
sequenceDiagram
    participant Client
    participant SubscriptionRoute as Subscription<br/>Route
    participant Stripe
    participant DB as User DB
    participant Credits as Credit<br/>System

    Client->>SubscriptionRoute: POST /credits/subscription<br/>(new_tier, redirect_urls)
    SubscriptionRoute->>SubscriptionRoute: Validate URLs
    alt URLs Invalid
        SubscriptionRoute-->>Client: 422
    else URLs Valid
        alt User ENTERPRISE
            SubscriptionRoute-->>Client: 403
        else User Normal
            SubscriptionRoute->>Stripe: Modify/Create subscription
            alt Stripe Success
                Stripe-->>SubscriptionRoute: session/confirmation
                SubscriptionRoute->>DB: Update tier
                alt Downgrade + Payment Fails
                    Stripe-->>SubscriptionRoute: Error
                    SubscriptionRoute->>Credits: Attempt credit deduction
                    Credits-->>SubscriptionRoute: Success/Failure
                end
            else Stripe Error
                SubscriptionRoute-->>Client: 502
            end
        end
    end
Loading

Estimated code review effort

🎯 5 (Critical) | ⏱️ ~120 minutes

Possibly related PRs

Suggested labels

size/m, Review effort 4-5/5

Suggested reviewers

  • 0ubbe
  • ntindle
  • Pwuts

Poem

🐰 The sessions now vanish with grace,
Transcripts restored at a speedy pace,
Grok 4 arrives on the scene so bright,
While Stripe keeps billing done right,
Cache misses dance, none shall escape! ✨

🚥 Pre-merge checks | ✅ 2 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 72.35% 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 PR title clearly and specifically describes the main change: deferring slow cleanup operations to background tasks to prevent HTTP 524 timeouts on chat deletion.
Description check ✅ Passed The PR description is comprehensive and directly related to the changeset, explaining the problem, the backend and frontend solutions, testing approach, and issue resolution.

✏️ 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 otto/secrt-2215-copilot-deleting-currently-selected-chat-never-completes

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 added the size/m label Apr 3, 2026
@codecov

codecov Bot commented Apr 3, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 79.97568% with 494 lines in your changes missing coverage. Please review.
✅ Project coverage is 65.30%. Comparing base (bd2efed) to head (c13e49e).
⚠️ Report is 12 commits behind head on dev.

❌ Your patch check has failed because the patch coverage (45.02%) is below the target coverage (80.00%). You can increase the patch coverage or adjust the target coverage.

Additional details and impacted files
@@            Coverage Diff             @@
##              dev   #12668      +/-   ##
==========================================
+ Coverage   65.03%   65.30%   +0.26%     
==========================================
  Files        1830     1850      +20     
  Lines      135576   137310    +1734     
  Branches    14516    14711     +195     
==========================================
+ Hits        88173    89668    +1495     
- Misses      44695    44873     +178     
- Partials     2708     2769      +61     
Flag Coverage Δ
platform-backend 76.01% <91.53%> (+0.27%) ⬆️
platform-frontend 20.04% <39.96%> (+0.68%) ⬆️
platform-frontend-e2e 30.25% <35.31%> (+0.09%) ⬆️

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

Components Coverage Δ
Platform Backend 76.01% <91.53%> (+0.27%) ⬆️
Platform Frontend 27.84% <45.02%> (+0.52%) ⬆️
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.

logger.warning(
"[E2B] Failed to kill sandbox for session %s", session_id[:12]
)
asyncio.create_task(_cleanup_sandbox(session_id, e2b_cfg.e2b_api_key))

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Bug: Background cleanup tasks created with asyncio.create_task are not referenced, risking premature garbage collection and resource leaks before they can complete.
Severity: MEDIUM

Suggested Fix

To ensure cleanup tasks complete, store a reference to them in a module-level _background_tasks: set[asyncio.Task]. Also, add a task.add_done_callback(_background_tasks.discard) to remove the task from the set upon completion. This matches the established, correct pattern used in other parts of the codebase like agent_browser.py.

Prompt for AI Agent
Review the code at the location below. A potential bug has been identified by an AI
agent.
Verify if this is a real issue. If it is, propose a fix; if not, explain why it's not
valid.

Location: autogpt_platform/backend/backend/api/features/chat/routes.py#L340

Potential issue: The new code introduces background cleanup tasks using
`asyncio.create_task` in `chat/routes.py` and `copilot/model.py` without maintaining a
strong reference to them. This can lead to the Python garbage collector prematurely
terminating these tasks before they finish, especially since they are long-running
(e.g., 10+ seconds). This silent failure will result in resource leaks, such as dangling
E2B sandboxes and zombie browser daemon processes, as the cleanup logic will not
reliably complete. This approach deviates from an established pattern elsewhere in the
codebase that correctly manages background task lifecycles to prevent this exact issue.

Did we get this right? 👍 / 👎 to inform future reviews.

@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: 3

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
autogpt_platform/backend/backend/copilot/model.py (1)

724-739: 🛠️ Refactor suggestion | 🟠 Major

Move the browser cleanup import to the module level by breaking the import cycle.

The lazy import at line 735 violates the guideline "Import only at the top level; no local/inner imports except for lazy imports of heavy optional dependencies like openpyxl" — close_browser_session is neither optional nor a heavy dependency. If this import path breaks, browser teardown silently fails in the background where it's hard to observe. Extract a cycle-free cleanup entrypoint so the import can move back to the module scope.

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

In `@autogpt_platform/backend/backend/copilot/model.py` around lines 724 - 739,
The lazy import of close_browser_session inside _cleanup_browser_session hides
import failures and violates the top-level import guideline; create a cycle-free
cleanup entrypoint so you can import close_browser_session at module scope.
Refactor tools.agent_browser to expose a thin, dependency-free function (e.g.,
close_browser_session_clean(session_id, user_id) or a small adapter) that does
not import ChatSession or other modules that cause the cycle, move the import of
that new function to the top of model.py, and update _cleanup_browser_session to
call the module-level function (keep _cleanup_browser_session and its signature
unchanged).
🤖 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/backend/backend/api/features/chat/routes.py`:
- Around line 334-350: The fire-and-forget
asyncio.create_task(_cleanup_sandbox(...)) call abandons cleanup on shutdown;
introduce a module-level set _background_tasks and, when creating the task for
_cleanup_sandbox(session_id, e2b_cfg.e2b_api_key), add it to _background_tasks
and call task.add_done_callback(_background_tasks.discard) so the task is
tracked; update the application's lifespan shutdown logic (follow the v1.py
pattern used by rest_api.py) to await/cleanup any remaining tasks in
_background_tasks before exit to prevent orphaned sandboxes and stale Redis
pointers.

In
`@autogpt_platform/frontend/src/app/`(platform)/copilot/components/ChatSidebar/ChatSidebar.tsx:
- Around line 74-91: The onError handler for the delete flow is clearing
sessionId indiscriminately (sessionToDelete?.id === sessionId ->
setSessionId(null)), which navigates away even when the delete actually failed;
remove the immediate setSessionId(null) from the onError and instead clear
selection only after confirming the session is gone: either perform the
invalidate/refetch (queryClient.invalidateQueries/getQueryData or a follow-up
fetch for getGetV2ListSessionsQueryKey) and then check whether the session ID
exists in the refreshed list before calling setSessionId(null), or narrow the
fallback to only clear for specific transport/timeout errors by checking the
error type/message (e.g., Cloudflare 524/timeout) before clearing; update the
onError block and/or move this logic into the mutation's onSettled/onSuccess
handler to perform the existence check against the refreshed query before
clearing sessionId.

In `@autogpt_platform/frontend/src/app/`(platform)/copilot/useCopilotPage.ts:
- Around line 87-104: The onError handler currently treats every delete failure
as if the session might be gone and immediately clears the UI selection;
instead, only clear selection after confirming the session is actually missing.
Change the onError logic in the delete callback (the function using
sessionToDelete, sessionId, setSessionToDelete, setSessionId,
queryClient.invalidateQueries and getGetV2ListSessionsQueryKey) so that after
invalidating/refreshing the sessions list you check whether the session still
exists (e.g. refetch or inspect the refreshed query result for the deleted
session id) and only call setSessionId(null) when the session is absent or the
error is a transient/network/timeout type; for 4xx/5xx server errors leave the
selection intact and still clear sessionToDelete and show the toast.

---

Outside diff comments:
In `@autogpt_platform/backend/backend/copilot/model.py`:
- Around line 724-739: The lazy import of close_browser_session inside
_cleanup_browser_session hides import failures and violates the top-level import
guideline; create a cycle-free cleanup entrypoint so you can import
close_browser_session at module scope. Refactor tools.agent_browser to expose a
thin, dependency-free function (e.g., close_browser_session_clean(session_id,
user_id) or a small adapter) that does not import ChatSession or other modules
that cause the cycle, move the import of that new function to the top of
model.py, and update _cleanup_browser_session to call the module-level function
(keep _cleanup_browser_session and its signature unchanged).
🪄 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: 36e603a9-fe25-4053-a946-31bb0ac1fe86

📥 Commits

Reviewing files that changed from the base of the PR and between 3ccaa5e and 67db7c3.

📒 Files selected for processing (4)
  • autogpt_platform/backend/backend/api/features/chat/routes.py
  • autogpt_platform/backend/backend/copilot/model.py
  • autogpt_platform/frontend/src/app/(platform)/copilot/components/ChatSidebar/ChatSidebar.tsx
  • autogpt_platform/frontend/src/app/(platform)/copilot/useCopilotPage.ts
📜 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). (15)
  • GitHub Check: integration_test
  • GitHub Check: lint
  • GitHub Check: check API types
  • GitHub Check: Seer Code Review
  • GitHub Check: Check PR Status
  • GitHub Check: end-to-end tests
  • GitHub Check: test (3.12)
  • GitHub Check: test (3.13)
  • GitHub Check: type-check (3.12)
  • GitHub Check: type-check (3.13)
  • GitHub Check: test (3.11)
  • GitHub Check: lint
  • GitHub Check: type-check (3.11)
  • GitHub Check: Analyze (typescript)
  • GitHub Check: Analyze (python)
🧰 Additional context used
📓 Path-based instructions (17)
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

Files:

  • autogpt_platform/frontend/src/app/(platform)/copilot/components/ChatSidebar/ChatSidebar.tsx
  • autogpt_platform/frontend/src/app/(platform)/copilot/useCopilotPage.ts
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/ChatSidebar/ChatSidebar.tsx
  • autogpt_platform/frontend/src/app/(platform)/copilot/useCopilotPage.ts
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
No any types unless the value genuinely can be anything
No linter suppressors (// @ts-ignore``, // eslint-disable) — fix the actual issue instead
Keep files under ~200 lines; extract sub-components or hooks into their own files when a file grows beyond this threshold
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/` following the pattern `use{Method}{Version}{OperationName}`; regenerate with `pnpm generate:api`
Use Tailwind CSS only for styling; use design tokens and Phosphor Icons only (no other icon libraries)
Do not use `useCallback` or `useMemo` unless asked to optimize a given function

Files:

  • autogpt_platform/frontend/src/app/(platform)/copilot/components/ChatSidebar/ChatSidebar.tsx
  • autogpt_platform/frontend/src/app/(platform)/copilot/useCopilotPage.ts
autogpt_platform/frontend/**/*.{js,jsx,ts,tsx}

📄 CodeRabbit inference engine (AGENTS.md)

autogpt_platform/frontend/**/*.{js,jsx,ts,tsx}: Format frontend code using pnpm format
Never use components from src/components/__legacy__/*

Refer to @frontend/CLAUDE.md for frontend-specific commands, architecture, and development patterns

Files:

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

📄 CodeRabbit inference engine (AGENTS.md)

autogpt_platform/frontend/src/**/*.{ts,tsx}: Structure components as ComponentName/ComponentName.tsx + useComponentName.ts + helpers.ts and use design system components from src/components/ (atoms, molecules, organisms)
Use generated API hooks from @/app/api/__generated__/endpoints/ with pattern use{Method}{Version}{OperationName} and regenerate with pnpm generate:api
Use function declarations (not arrow functions) for components and handlers
Separate render logic from business logic with component.tsx + useComponent.ts + helpers.ts structure
Colocate state when possible, avoid creating large components, use sub-components in local /components folder
Avoid large hooks, abstract logic into helpers.ts files when sensible
Use arrow functions only for callbacks, not for component declarations
Avoid comments at all times unless the code is very complex
Do not use useCallback or useMemo unless asked to optimize a given function

Files:

  • autogpt_platform/frontend/src/app/(platform)/copilot/components/ChatSidebar/ChatSidebar.tsx
  • autogpt_platform/frontend/src/app/(platform)/copilot/useCopilotPage.ts
autogpt_platform/frontend/**/*.{js,jsx,ts,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/ChatSidebar/ChatSidebar.tsx
  • autogpt_platform/frontend/src/app/(platform)/copilot/useCopilotPage.ts
autogpt_platform/frontend/src/**/*.tsx

📄 CodeRabbit inference engine (AGENTS.md)

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

Files:

  • autogpt_platform/frontend/src/app/(platform)/copilot/components/ChatSidebar/ChatSidebar.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/ChatSidebar/ChatSidebar.tsx
  • autogpt_platform/frontend/src/app/(platform)/copilot/useCopilotPage.ts
autogpt_platform/frontend/src/app/(platform)/**/*.tsx

📄 CodeRabbit inference engine (AGENTS.md)

If adding protected frontend routes, update frontend/lib/supabase/middleware.ts

Files:

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

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

autogpt_platform/frontend/**/*.tsx: Use Next.js <Link> for internal navigation — never raw <a> tags
Put sub-components in local components/ folder; 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__/*

Files:

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

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

Avoid index and barrel files

Files:

  • autogpt_platform/frontend/src/app/(platform)/copilot/components/ChatSidebar/ChatSidebar.tsx
  • autogpt_platform/frontend/src/app/(platform)/copilot/useCopilotPage.ts
autogpt_platform/backend/**/*.py

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

autogpt_platform/backend/**/*.py: Use Python 3.11 (required; managed by Poetry via pyproject.toml) for backend development
Always run 'poetry run format' (Black + isort) before linting in backend development
Always run 'poetry run lint' (ruff) after formatting in backend development

Refer to @backend/CLAUDE.md for backend-specific commands, architecture, and development tasks

autogpt_platform/backend/**/*.py: Import only at the top level; no local/inner imports except for lazy imports of heavy optional dependencies like openpyxl
Use absolute imports with from backend.module import ... for cross-package imports; single-dot relative imports (from .sibling import ...) are acceptable for sibling modules within the same package; avoid double-dot relative imports (from ..parent import ...)
Do not use duck typing with hasattr(), getattr(), or isinstance() for type dispatch; use typed interfaces, unions, or protocols instead
Use Pydantic models for structured data instead of dataclasses, namedtuples, or dicts
Do not use linter suppressors; no # type: ignore, # noqa, or # pyright: ignore comments — fix the underlying type/code issue instead
Use list comprehensions instead of manual loop-and-append patterns
Use early return guard clauses to avoid deep nesting
Use %s for deferred interpolation in debug log statements; use f-strings for readability in other log levels (e.g., logger.debug("Processing %s items", count), logger.info(f"Processing {count} items"))
Sanitize error paths using os.path.basename() in error messages to avoid leaking directory structure
Avoid TOCTOU (time-of-check-time-of-use) patterns; do not use check-then-act patterns for file access and credit charging operations
Use Redis pipelines with transaction=True for atomicity on multi-step Redis operations
Use max(0, value) guards for computed values that should never be negative
Keep files under ~300 lines; if a file grows beyond this, split by responsibility (extract h...

Files:

  • autogpt_platform/backend/backend/api/features/chat/routes.py
  • autogpt_platform/backend/backend/copilot/model.py
autogpt_platform/backend/backend/api/features/**/*.py

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

Update routes in '/backend/backend/api/features/' and add/update Pydantic models in the same directory for API development

Files:

  • autogpt_platform/backend/backend/api/features/chat/routes.py
autogpt_platform/**/*.py

📄 CodeRabbit inference engine (AGENTS.md)

Format Python code with poetry run format

Files:

  • autogpt_platform/backend/backend/api/features/chat/routes.py
  • autogpt_platform/backend/backend/copilot/model.py
autogpt_platform/backend/backend/api/**/*.py

📄 CodeRabbit inference engine (autogpt_platform/backend/CLAUDE.md)

autogpt_platform/backend/backend/api/**/*.py: Use Security() instead of Depends() for authentication dependencies to ensure proper OpenAPI security specification
Follow SSE (Server-Sent Events) protocol: use data: lines for frontend-parsed events (must match Zod schema), use : comment lines for heartbeats/status
Cache-protected endpoints must not contain sensitive data (auth tokens, API keys, user data); only static assets, health checks, public store pages, and documentation should be in the cacheable paths

Files:

  • autogpt_platform/backend/backend/api/features/chat/routes.py
autogpt_platform/frontend/src/**/*.ts

📄 CodeRabbit inference engine (AGENTS.md)

Do not type hook returns, let Typescript infer as much as possible

Files:

  • autogpt_platform/frontend/src/app/(platform)/copilot/useCopilotPage.ts
autogpt_platform/frontend/**/*.ts

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

autogpt_platform/frontend/**/*.ts: Extract component logic into custom hooks grouped by concern, not by component; put each hook in its own .ts file
Do not type hook returns; let TypeScript infer as much as possible

Files:

  • autogpt_platform/frontend/src/app/(platform)/copilot/useCopilotPage.ts
🧠 Learnings (20)
📓 Common learnings
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.
📚 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/ChatSidebar/ChatSidebar.tsx
  • autogpt_platform/frontend/src/app/(platform)/copilot/useCopilotPage.ts
📚 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/ChatSidebar/ChatSidebar.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/ChatSidebar/ChatSidebar.tsx
  • autogpt_platform/frontend/src/app/(platform)/copilot/useCopilotPage.ts
📚 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/ChatSidebar/ChatSidebar.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/ChatSidebar/ChatSidebar.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/ChatSidebar/ChatSidebar.tsx
  • autogpt_platform/frontend/src/app/(platform)/copilot/useCopilotPage.ts
📚 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/ChatSidebar/ChatSidebar.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/ChatSidebar/ChatSidebar.tsx
  • autogpt_platform/frontend/src/app/(platform)/copilot/useCopilotPage.ts
📚 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/ChatSidebar/ChatSidebar.tsx
  • autogpt_platform/frontend/src/app/(platform)/copilot/useCopilotPage.ts
📚 Learning: 2026-02-26T17:02:22.448Z
Learnt from: Pwuts
Repo: Significant-Gravitas/AutoGPT PR: 12211
File: .pre-commit-config.yaml:160-179
Timestamp: 2026-02-26T17:02:22.448Z
Learning: Keep the pre-commit hook pattern broad for autogpt_platform/backend to ensure OpenAPI schema changes are captured. Do not narrow to backend/api/ alone, since the generated schema depends on Pydantic models across multiple directories (backend/data/, backend/blocks/, backend/copilot/, backend/integrations/, backend/util/). Narrowing could miss schema changes and cause frontend type desynchronization.

Applied to files:

  • autogpt_platform/backend/backend/api/features/chat/routes.py
  • autogpt_platform/backend/backend/copilot/model.py
📚 Learning: 2026-03-05T15:42:08.207Z
Learnt from: ntindle
Repo: Significant-Gravitas/AutoGPT PR: 12297
File: .claude/skills/backend-check/SKILL.md:14-16
Timestamp: 2026-03-05T15:42:08.207Z
Learning: In Python files under autogpt_platform/backend (recursively), rely on poetry run format to perform formatting (Black + isort) and linting (ruff). Do not run poetry run lint as a separate step after poetry run format, since format already includes linting checks.

Applied to files:

  • autogpt_platform/backend/backend/api/features/chat/routes.py
  • autogpt_platform/backend/backend/copilot/model.py
📚 Learning: 2026-03-16T16:35:40.236Z
Learnt from: majdyz
Repo: Significant-Gravitas/AutoGPT PR: 12440
File: autogpt_platform/backend/backend/api/features/workflow_import.py:54-63
Timestamp: 2026-03-16T16:35:40.236Z
Learning: Avoid using the word 'competitor' in public-facing identifiers and text. Use neutral naming for API paths, model names, function names, and UI text. Examples: rename 'CompetitorFormat' to 'SourcePlatform', 'convert_competitor_workflow' to 'convert_workflow', '/competitor-workflow' to '/workflow'. Apply this guideline to files under autogpt_platform/backend and autogpt_platform/frontend.

Applied to files:

  • autogpt_platform/backend/backend/api/features/chat/routes.py
  • autogpt_platform/backend/backend/copilot/model.py
📚 Learning: 2026-03-31T15:37:38.626Z
Learnt from: majdyz
Repo: Significant-Gravitas/AutoGPT PR: 12623
File: autogpt_platform/backend/backend/copilot/tools/agent_generator/fixer.py:37-47
Timestamp: 2026-03-31T15:37:38.626Z
Learning: When validating/constructing Anthropic API model IDs in Significant-Gravitas/AutoGPT, allow the hyphen-separated Claude Opus 4.6 model ID `claude-opus-4-6` (it corresponds to `LlmModel.CLAUDE_4_6_OPUS` in `autogpt_platform/backend/backend/blocks/llm.py`). Do NOT require the dot-separated form in Anthropic contexts. Only OpenRouter routing variants should use the dot separator (e.g., `anthropic/claude-opus-4.6`); `claude-opus-4-6` should be treated as correct when passed to Anthropic, and flagged only if it’s used in the OpenRouter path where the dot form is expected.

Applied to files:

  • autogpt_platform/backend/backend/api/features/chat/routes.py
  • autogpt_platform/backend/backend/copilot/model.py
📚 Learning: 2026-03-17T10:57:12.953Z
Learnt from: majdyz
Repo: Significant-Gravitas/AutoGPT PR: 12440
File: autogpt_platform/backend/backend/copilot/workflow_import/converter.py:0-0
Timestamp: 2026-03-17T10:57:12.953Z
Learning: In Significant-Gravitas/AutoGPT PR `#12440`, `autogpt_platform/backend/backend/copilot/workflow_import/converter.py` was fully rewritten (commit 732960e2d) to no longer make direct LLM/OpenAI API calls. The converter now builds a structured text prompt for AutoPilot/CoPilot instead. There is no `response.choices` access or any direct LLM client usage in this file. Do not flag `response.choices` access or LLM client initialization patterns as issues in this file.

Applied to files:

  • autogpt_platform/backend/backend/copilot/model.py
📚 Learning: 2026-03-04T08:04:35.881Z
Learnt from: majdyz
Repo: Significant-Gravitas/AutoGPT PR: 12273
File: autogpt_platform/backend/backend/copilot/tools/workspace_files.py:216-220
Timestamp: 2026-03-04T08:04:35.881Z
Learning: In the AutoGPT Copilot backend, ensure that SVG images are not treated as vision image types by excluding 'image/svg+xml' from INLINEABLE_MIME_TYPES and MULTIMODAL_TYPES in tool_adapter.py; the Claude API supports PNG, JPEG, GIF, and WebP for vision. SVGs (XML text) should be handled via the text path instead, not the vision path.

Applied to files:

  • autogpt_platform/backend/backend/copilot/model.py
📚 Learning: 2026-04-01T04:17:41.600Z
Learnt from: majdyz
Repo: Significant-Gravitas/AutoGPT PR: 12632
File: autogpt_platform/backend/backend/copilot/tools/workspace_files.py:0-0
Timestamp: 2026-04-01T04:17:41.600Z
Learning: When reviewing AutoGPT Copilot tool implementations, accept that `readOnlyHint=True` (provided via `ToolAnnotations`) may be applied unconditionally to *all* tools—even tools that have side effects (e.g., `bash_exec`, `write_workspace_file`, or other write/save operations). Do **not** flag these tools for having `readOnlyHint=True`; this is intentional to enable fully-parallel dispatch by the Anthropic SDK/CLI and has been E2E validated. Only flag `readOnlyHint` issues if they conflict with the established `ToolAnnotations` behavior (e.g., missing/incorrect propagation relative to the intended annotation mechanism).

Applied to files:

  • autogpt_platform/backend/backend/copilot/model.py
📚 Learning: 2026-03-24T02:05:08.144Z
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).

Applied to files:

  • autogpt_platform/frontend/src/app/(platform)/copilot/useCopilotPage.ts
📚 Learning: 2026-03-20T09:30:38.372Z
Learnt from: CR
Repo: Significant-Gravitas/AutoGPT PR: 0
File: autogpt_platform/frontend/CLAUDE.md:0-0
Timestamp: 2026-03-20T09:30:38.372Z
Learning: Applies to autogpt_platform/frontend/**/*.{ts,tsx} : No linter suppressors (`// ts-ignore`, `// eslint-disable`) — fix the actual issue instead

Applied to files:

  • autogpt_platform/frontend/src/app/(platform)/copilot/useCopilotPage.ts
📚 Learning: 2026-03-20T09:30:38.372Z
Learnt from: CR
Repo: Significant-Gravitas/AutoGPT PR: 0
File: autogpt_platform/frontend/CLAUDE.md:0-0
Timestamp: 2026-03-20T09:30:38.372Z
Learning: Applies to autogpt_platform/frontend/**/*.{ts,tsx} : Use function declarations (not arrow functions) for components and handlers

Applied to files:

  • autogpt_platform/frontend/src/app/(platform)/copilot/useCopilotPage.ts
🔇 Additional comments (2)
autogpt_platform/frontend/src/app/(platform)/copilot/components/ChatSidebar/ChatSidebar.tsx (1)

62-72: Good call closing the dialog before clearing the selected session.

That ordering should prevent the delete modal from lingering while the selected chat view tears down.

autogpt_platform/frontend/src/app/(platform)/copilot/useCopilotPage.ts (1)

75-85: Nice improvement on the success-path ordering.

Clearing sessionToDelete before setSessionId(null) should make the UI feel much more immediate when the active chat is removed.

Comment on lines 334 to +350
# Best-effort cleanup of the E2B sandbox (if any).
# sandbox_id is in Redis; kill_sandbox() fetches it from there.
# Runs in a background task so the 204 response is returned immediately —
# sandbox teardown can take 10+ seconds which risks Cloudflare 524 timeouts.
e2b_cfg = ChatConfig()
if e2b_cfg.e2b_active:
assert e2b_cfg.e2b_api_key # guaranteed by e2b_active check
try:
await kill_sandbox(session_id, e2b_cfg.e2b_api_key)
except Exception:
logger.warning(
"[E2B] Failed to kill sandbox for session %s", session_id[:12]
)
asyncio.create_task(_cleanup_sandbox(session_id, e2b_cfg.e2b_api_key))

return Response(status_code=204)


async def _cleanup_sandbox(session_id: str, api_key: str) -> None:
"""Best-effort E2B sandbox teardown — runs as a background task."""
try:
await kill_sandbox(session_id, api_key)
except Exception:
logger.warning("[E2B] Failed to kill sandbox for session %s", session_id[:12])

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.

⚠️ Potential issue | 🟠 Major

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Verify whether backend fire-and-forget tasks are registered anywhere for shutdown handling.
rg -n --type=py 'create_task\(' autogpt_platform/backend
rg -n --type=py 'TaskGroup|BackgroundTasks|lifespan|shutdown|add_done_callback|pending_tasks' autogpt_platform/backend

Repository: Significant-Gravitas/AutoGPT

Length of output: 13358


🏁 Script executed:

# Check the imports and setup in chat/routes.py to see if background task tracking exists
head -80 autogpt_platform/backend/backend/api/features/chat/routes.py

# Look for _background_tasks or similar task tracking mechanism in chat/routes.py
rg -n '_background_tasks|_cleanup_sandbox' autogpt_platform/backend/backend/api/features/chat/routes.py

# Check if there's any lifespan or shutdown handling in the REST API
rg -A 20 'async def lifespan_context' autogpt_platform/backend/backend/api/rest_api.py

Repository: Significant-Gravitas/AutoGPT

Length of output: 3630


🏁 Script executed:

# Look for any background task set/tracking in chat/routes.py
grep -n 'set\|Set\|background\|task' autogpt_platform/backend/backend/api/features/chat/routes.py | head -30

# Check the full lifespan_context function and any background task tracking
rg -A 50 'async def lifespan_context' autogpt_platform/backend/backend/api/rest_api.py | head -80

# Check if there's a global background_tasks in rest_api.py
rg -B 5 -A 5 '_background_tasks\s*=' autogpt_platform/backend/backend/api/rest_api.py

Repository: Significant-Gravitas/AutoGPT

Length of output: 3681


🏁 Script executed:

# Check if lifespan_context in rest_api.py waits for pending tasks on shutdown
rg -A 100 'async def lifespan_context' autogpt_platform/backend/backend/api/rest_api.py | tail -50

# Check if there's explicit task collection or cleanup on shutdown
rg -n 'asyncio.all_tasks\|gather.*pending\|wait.*tasks' autogpt_platform/backend/backend/api/rest_api.py

# Compare to how other modules handle background task cleanup (e.g., v1.py which uses _tally_background_tasks)
rg -B 5 -A 15 '_tally_background_tasks' autogpt_platform/backend/backend/api/features/v1.py | head -40

Repository: Significant-Gravitas/AutoGPT

Length of output: 2894


🏁 Script executed:

# Check if lifespan_context or the app has any mechanism to wait for pending tasks on shutdown
rg -n 'all_tasks\|gather\|wait\|cancel' autogpt_platform/backend/backend/api/rest_api.py

# Verify the full lifespan_context to see if it does any task cleanup
cat autogpt_platform/backend/backend/api/rest_api.py | sed -n '91,150p'

# Check if there's any graceful shutdown handling for asyncio tasks elsewhere
rg -B 3 -A 10 'asyncio.all_tasks\|pending.*tasks' autogpt_platform/backend/backend/util/service.py | head -50

Repository: Significant-Gravitas/AutoGPT

Length of output: 2295


Track background E2B cleanup with task callbacks instead of fire-and-forget.

The asyncio.create_task(_cleanup_sandbox(...)) on line 340 has no tracking mechanism. The lifespan context in rest_api.py does not wait for pending tasks on shutdown, so a worker reload after the 204 response but before cleanup completes will abandon the sandbox with a stale Redis pointer. Use the pattern already established in v1.py — add a _background_tasks set at module level, track the task with .add_done_callback(_background_tasks.discard), and ensure the lifespan waits for these tasks before shutdown.

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

In `@autogpt_platform/backend/backend/api/features/chat/routes.py` around lines
334 - 350, The fire-and-forget asyncio.create_task(_cleanup_sandbox(...)) call
abandons cleanup on shutdown; introduce a module-level set _background_tasks
and, when creating the task for _cleanup_sandbox(session_id,
e2b_cfg.e2b_api_key), add it to _background_tasks and call
task.add_done_callback(_background_tasks.discard) so the task is tracked; update
the application's lifespan shutdown logic (follow the v1.py pattern used by
rest_api.py) to await/cleanup any remaining tasks in _background_tasks before
exit to prevent orphaned sandboxes and stale Redis pointers.

Comment on lines +74 to +91
onError: (error) => {
const wasSelected = sessionToDelete?.id === sessionId;
toast({
title: "Failed to delete chat",
description:
error instanceof Error ? error.message : "An error occurred",
variant: "destructive",
});
setSessionToDelete(null);
// The session may have been deleted server-side even if we got an
// error (e.g. Cloudflare 524 timeout). Refresh the list so stale
// entries disappear and navigate away from the deleted chat.
queryClient.invalidateQueries({
queryKey: getGetV2ListSessionsQueryKey(),
});
if (wasSelected) {
setSessionId(null);
}

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.

⚠️ Potential issue | 🟠 Major

Don't clear sessionId on every delete error.

If the delete fails before the row is actually removed, this still tears down the active chat view and navigates the user away from a session that still exists. Only clear the selection after the refetch confirms the deleted ID is gone, or narrow this fallback to ambiguous timeout/transport errors.

🤖 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/ChatSidebar/ChatSidebar.tsx
around lines 74 - 91, The onError handler for the delete flow is clearing
sessionId indiscriminately (sessionToDelete?.id === sessionId ->
setSessionId(null)), which navigates away even when the delete actually failed;
remove the immediate setSessionId(null) from the onError and instead clear
selection only after confirming the session is gone: either perform the
invalidate/refetch (queryClient.invalidateQueries/getQueryData or a follow-up
fetch for getGetV2ListSessionsQueryKey) and then check whether the session ID
exists in the refreshed list before calling setSessionId(null), or narrow the
fallback to only clear for specific transport/timeout errors by checking the
error type/message (e.g., Cloudflare 524/timeout) before clearing; update the
onError block and/or move this logic into the mutation's onSettled/onSuccess
handler to perform the existence check against the refreshed query before
clearing sessionId.

Comment on lines 87 to +104
onError: (error) => {
const wasSelected = sessionToDelete?.id === sessionId;
toast({
title: "Failed to delete chat",
description:
error instanceof Error ? error.message : "An error occurred",
variant: "destructive",
});
setSessionToDelete(null);
// The session may have been deleted server-side even if we got an
// error (e.g. Cloudflare 524 timeout). Refresh the list so stale
// entries disappear and navigate away from the deleted chat.
queryClient.invalidateQueries({
queryKey: getGetV2ListSessionsQueryKey(),
});
if (wasSelected) {
setSessionId(null);
}

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.

⚠️ Potential issue | 🟠 Major

Don't treat every delete error as "maybe deleted".

For genuine 4xx/5xx failures, setSessionId(null) still drops the user out of the selected chat even though the session remains. Gate the navigation on a confirmed post-refetch miss, or limit it to ambiguous timeout/network errors.

🤖 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/useCopilotPage.ts
around lines 87 - 104, The onError handler currently treats every delete failure
as if the session might be gone and immediately clears the UI selection;
instead, only clear selection after confirming the session is actually missing.
Change the onError logic in the delete callback (the function using
sessionToDelete, sessionId, setSessionToDelete, setSessionId,
queryClient.invalidateQueries and getGetV2ListSessionsQueryKey) so that after
invalidating/refreshing the sessions list you check whether the session still
exists (e.g. refetch or inspect the refreshed query result for the deleted
session id) and only call setSessionId(null) when the session is absent or the
error is a transient/network/timeout type; for 4xx/5xx server errors leave the
selection intact and still clear sessionToDelete and show the toast.

This was referenced Apr 23, 2026
@ntindle ntindle closed this May 7, 2026
@github-project-automation github-project-automation Bot moved this from 🆕 Needs initial review to ✅ Done in AutoGPT development kanban May 7, 2026
@github-project-automation github-project-automation Bot moved this to Done in Frontend May 7, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

conflicts Automatically applied to PRs with merge conflicts documentation Improvements or additions to documentation platform/backend AutoGPT Platform - Back end platform/blocks platform/frontend AutoGPT Platform - Front end size/xl

Projects

Status: ✅ Done
Status: Done

Development

Successfully merging this pull request may close these issues.

6 participants