fix(copilot): prevent 524 timeout on chat deletion by deferring cleanup - #12668
fix(copilot): prevent 524 timeout on chat deletion by deferring cleanup#12668Otto-AGPT wants to merge 15 commits into
Conversation
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>
WalkthroughThis 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
Sequence DiagramssequenceDiagram
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
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
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
Estimated code review effort🎯 5 (Critical) | ⏱️ ~120 minutes Possibly related PRs
Suggested labels
Suggested reviewers
Poem
🚥 Pre-merge checks | ✅ 2 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (2 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches📝 Generate docstrings
🧪 Generate unit tests (beta)
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. Comment |
Codecov Report❌ Patch coverage is ❌ 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
Flags with carried forward coverage won't be shown. Click here to find out more.
🚀 New features to boost your workflow:
|
| 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)) |
There was a problem hiding this comment.
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.
There was a problem hiding this comment.
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 | 🟠 MajorMove 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_sessionis 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
📒 Files selected for processing (4)
autogpt_platform/backend/backend/api/features/chat/routes.pyautogpt_platform/backend/backend/copilot/model.pyautogpt_platform/frontend/src/app/(platform)/copilot/components/ChatSidebar/ChatSidebar.tsxautogpt_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.tsxautogpt_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.tsxautogpt_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
Nodark:Tailwind classes — the design system handles dark mode
Noanytypes 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.tsxautogpt_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 usingpnpm format
Never use components fromsrc/components/__legacy__/*Refer to
@frontend/CLAUDE.mdfor frontend-specific commands, architecture, and development patterns
Files:
autogpt_platform/frontend/src/app/(platform)/copilot/components/ChatSidebar/ChatSidebar.tsxautogpt_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 asComponentName/ComponentName.tsx+useComponentName.ts+helpers.tsand use design system components fromsrc/components/(atoms, molecules, organisms)
Use generated API hooks from@/app/api/__generated__/endpoints/with patternuse{Method}{Version}{OperationName}and regenerate withpnpm 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/componentsfolder
Avoid large hooks, abstract logic intohelpers.tsfiles 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 useuseCallbackoruseMemounless asked to optimize a given function
Files:
autogpt_platform/frontend/src/app/(platform)/copilot/components/ChatSidebar/ChatSidebar.tsxautogpt_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.tsxautogpt_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 useunknown
Files:
autogpt_platform/frontend/src/app/(platform)/copilot/components/ChatSidebar/ChatSidebar.tsxautogpt_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 localcomponents/folder; component props should betype Props = { ... }(not exported) unless it needs to be used outside the component
Use design system components fromsrc/components/(atoms, molecules, organisms); never usesrc/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.tsxautogpt_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 developmentRefer to
@backend/CLAUDE.mdfor 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 likeopenpyxl
Use absolute imports withfrom 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 withhasattr(),getattr(), orisinstance()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: ignorecomments — 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%sfor deferred interpolation indebuglog 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 usingos.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 withtransaction=Truefor atomicity on multi-step Redis operations
Usemax(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.pyautogpt_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.pyautogpt_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: UseSecurity()instead ofDepends()for authentication dependencies to ensure proper OpenAPI security specification
Follow SSE (Server-Sent Events) protocol: usedata:lines for frontend-parsed events (must match Zod schema), use: commentlines 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.tsfile
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.tsxautogpt_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.tsxautogpt_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.tsxautogpt_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.tsxautogpt_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.tsxautogpt_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.pyautogpt_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.pyautogpt_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.pyautogpt_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.pyautogpt_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
sessionToDeletebeforesetSessionId(null)should make the UI feel much more immediate when the active chat is removed.
| # 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]) |
There was a problem hiding this comment.
🧩 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/backendRepository: 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.pyRepository: 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.pyRepository: 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 -40Repository: 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 -50Repository: 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.
| 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); | ||
| } |
There was a problem hiding this comment.
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.
| 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); | ||
| } |
There was a problem hiding this comment.
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.
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 sandboxkill_sandbox()intoasyncio.create_task()so the 204 response returns immediately after the DB delete succeedsmodel.py: Moveclose_browser_session()intoasyncio.create_task()for the same reasonFrontend — improve resilience:
onSuccess: close the dialog (setSessionToDelete(null)) before clearing the selected session (setSessionId(null)), so the UI updates instantly before the chat-view teardown cascade runsonErrorto 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
Resolves SECRT-2215