Skip to content

fix(copilot): abort SSE stream and disconnect backend listeners on session switch#12766

Merged
0ubbe merged 10 commits intodevfrom
fix/copilot-stream-disconnect-on-session-switch
Apr 15, 2026
Merged

fix(copilot): abort SSE stream and disconnect backend listeners on session switch#12766
0ubbe merged 10 commits intodevfrom
fix/copilot-stream-disconnect-on-session-switch

Conversation

@0ubbe
Copy link
Copy Markdown
Contributor

@0ubbe 0ubbe commented Apr 13, 2026

Summary

Fixes stream disconnection bugs where the UI shows "running" with no output when users switch between copilot chat sessions. The root cause is that the old SSE fetch is not aborted and backend XREAD listeners keep running until timeout when switching sessions.

Changes

Frontend (useCopilotStream.ts, helpers.ts)

  • Call sdkStop() on session switch to abort the in-flight SSE fetch from the old session's transport
  • Fire-and-forget DELETE to new backend disconnect endpoint so server-side listeners release immediately
  • Store resumeStream and sdkStop in refs to fix stale closure bugs in:
    • Wake re-sync visibility handler (could call stale resumeStream after tab sleep)
    • Reconnect timer callback (could target wrong session's transport)
    • Resume effect (captured stale resumeStream during rapid session switches)

Backend (stream_registry.py, routes.py)

  • Add disconnect_all_listeners(session_id) to stream registry — iterates active listener tasks, cancels any matching the session
  • Add DELETE /sessions/{session_id}/stream endpoint — auth-protected, calls disconnect_all_listeners, returns 204

Why

Reported by multiple team members: when using Autopilot for anything serious, the frontend loses the SSE connection — particularly when switching between conversations. The backend completes fine (refreshing shows full output), but the UI gets stuck showing "running". This is the worst UX bug we have right now because real users will never know to refresh.

How to test

  1. Start a long-running autopilot task (e.g., "build a snake game")
  2. While it's streaming, switch to a different chat session
  3. Switch back — the UI should correctly show the completed output or resume the stream
  4. Verify no "stuck running" state

Test plan

  • Manual: switch sessions during active stream — no stuck "running" state
  • Manual: background tab for >30s during stream, return — wake re-sync works
  • Manual: trigger reconnect (kill network briefly) — reconnects to correct session
  • Verify: pnpm lint, pnpm types, poetry run lint all pass

🤖 Generated with Claude Code

…ssion switch

When users switch between chat sessions, the old SSE fetch was not being
aborted and backend XREAD listeners were left running until timeout. This
caused the UI to show "running" with no output — refreshing revealed the
backend had completed fine.

Frontend:
- Call sdkStop() on session switch to abort the old transport's fetch
- Fire-and-forget DELETE to new disconnect endpoint for the old session
- Store resumeStream/sdkStop in refs to prevent stale closures in the
  wake re-sync handler, reconnect timer, and resume effect

Backend:
- Add disconnect_all_listeners() to stream_registry that cancels all
  active XREAD listener tasks for a given session
- Add DELETE /sessions/{id}/stream endpoint for frontend to signal
  session switch, so listeners are released immediately

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
@0ubbe 0ubbe requested a review from a team as a code owner April 13, 2026 15:16
Copilot AI review requested due to automatic review settings April 13, 2026 15:16
@0ubbe 0ubbe requested review from Pwuts and majdyz and removed request for a team April 13, 2026 15:16
@github-project-automation github-project-automation bot moved this to 🆕 Needs initial review in AutoGPT development kanban Apr 13, 2026
@github-actions github-actions bot added platform/frontend AutoGPT Platform - Front end platform/backend AutoGPT Platform - Back end labels Apr 13, 2026
@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai bot commented Apr 13, 2026

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review

Walkthrough

Adds a DELETE API to disconnect all SSE listeners for a chat session, implements pod-local logic to cancel per-session stream listener tasks, provides a fire-and-forget frontend helper, and updates the frontend stream hook to call the helper during session switches.

Changes

Cohort / File(s) Summary
Backend: chat route
autogpt_platform/backend/backend/api/features/chat/routes.py
Added authenticated DELETE /sessions/{session_id}/stream handler that verifies session ownership and calls stream registry to disconnect listeners; returns 204 on success and 404 if session not found or access denied.
Backend: stream registry
autogpt_platform/backend/backend/copilot/stream_registry.py
Added disconnect_all_listeners(session_id: str) -> int which finds, removes, cancels, and awaits termination of matching per-session listener tasks (best-effort, awaits with timeouts), returning the count processed.
Frontend: API spec
autogpt_platform/frontend/src/app/api/openapi.json
Added DELETE /api/chat/sessions/{session_id}/stream operation (operationId: deleteV2DisconnectSessionStream) with 204/401/422 responses.
Frontend: helper
autogpt_platform/frontend/src/app/(platform)/copilot/helpers.ts
Added disconnectSessionStream(sessionId: string) — fire-and-forget call to the new DELETE endpoint that swallows errors; minor comment tweak for deduplication wording.
Frontend: hook
autogpt_platform/frontend/src/app/(platform)/copilot/useCopilotStream.ts
Introduced stable refs (sdkStopRef, resumeStreamRef, prevStreamSessionRef); replaced direct resumeStream calls with ref invocations; on session change aborts prior stream via sdkStopRef.current() and calls disconnectSessionStream for the previous session.
Tests
autogpt_platform/backend/backend/api/features/chat/routes_test.py
Added tests verifying 204 flow when session exists (and that disconnect_all_listeners is awaited once) and 404 when session lookup returns None (and disconnect not called).

Sequence Diagram(s)

sequenceDiagram
  autonumber
  participant FE as Frontend Hook
  participant Helper as disconnectSessionStream
  participant API as Backend API
  participant Registry as StreamRegistry
  participant Listener as SSE Listener Task

  FE->>Helper: fire-and-forget DELETE /api/chat/sessions/{sessionId}/stream
  Helper->>API: authenticated DELETE request
  API->>Registry: disconnect_all_listeners(sessionId)
  Registry->>Listener: identify & cancel matching listener tasks
  Registry-->>API: return count disconnected
  API-->>Helper: 204 No Content
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Possibly related PRs

Suggested reviewers

  • ntindle
  • Pwuts
  • majdyz

Poem

🐰 I nudge old listeners to sleep tonight,
a gentle DELETE, then soft goodnight,
refs hold steady, streams release their ties,
previous sessions close with quiet sighs,
hop on — fresh data waits in morning light.

🚥 Pre-merge checks | ✅ 2 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 50.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (2 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly and concisely describes the main change: aborting SSE streams and disconnecting backend listeners when switching sessions, which directly addresses the root cause of the bug described in the PR.
Description check ✅ Passed The description is well-structured and directly related to the changeset, explaining the bug, the specific changes across frontend/backend files, the rationale, and test instructions.

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

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch fix/copilot-stream-disconnect-on-session-switch

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
Copy link
Copy Markdown
Contributor

github-actions bot commented Apr 13, 2026

🔍 PR Overlap Detection

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

🔴 Merge Conflicts Detected

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

🟡 Medium Risk — Some Line Overlap

These PRs have some overlapping changes:

🟢 Low Risk — File Overlap Only

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

Summary: 1 conflict(s), 1 medium risk, 6 low risk (out of 8 PRs with file overlap)


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

@codecov
Copy link
Copy Markdown

codecov bot commented Apr 13, 2026

Codecov Report

❌ Patch coverage is 86.46617% with 18 lines in your changes missing coverage. Please review.
✅ Project coverage is 64.38%. Comparing base (b06648d) to head (4ac231c).
⚠️ Report is 7 commits behind head on dev.

Additional details and impacted files
@@            Coverage Diff             @@
##              dev   #12766      +/-   ##
==========================================
+ Coverage   64.30%   64.38%   +0.08%     
==========================================
  Files        1815     1817       +2     
  Lines      132920   133155     +235     
  Branches    14379    14421      +42     
==========================================
+ Hits        85468    85730     +262     
+ Misses      44783    44734      -49     
- Partials     2669     2691      +22     
Flag Coverage Δ
platform-backend 75.25% <98.23%> (+0.01%) ⬆️
platform-frontend 18.91% <0.00%> (+0.76%) ⬆️
platform-frontend-e2e 29.81% <50.00%> (-0.67%) ⬇️

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

Components Coverage Δ
Platform Backend 75.25% <98.23%> (+0.01%) ⬆️
Platform Frontend 26.78% <20.00%> (+0.48%) ⬆️
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.

Comment thread autogpt_platform/frontend/src/app/(platform)/copilot/useCopilotStream.ts Outdated
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

Fixes Copilot SSE stream “stuck running” behavior when switching chat sessions by ensuring old client streams are stopped and backend Redis XREAD listener tasks are explicitly disconnected.

Changes:

  • Frontend: adds session-switch cleanup (stop old stream + request backend disconnect) and uses refs to avoid stale-closure reconnect/resume callbacks.
  • Frontend: adds a fire-and-forget helper to call the backend stream disconnect endpoint.
  • Backend: introduces listener cancellation (disconnect_all_listeners) and a new DELETE /sessions/{session_id}/stream route.

Reviewed changes

Copilot reviewed 4 out of 4 changed files in this pull request and generated 2 comments.

File Description
autogpt_platform/frontend/src/app/(platform)/copilot/useCopilotStream.ts Adds ref-based callbacks and session-switch cleanup to stop/disconnect old streams.
autogpt_platform/frontend/src/app/(platform)/copilot/helpers.ts Adds disconnectSessionStream() helper to call new backend DELETE disconnect endpoint.
autogpt_platform/backend/backend/copilot/stream_registry.py Adds disconnect_all_listeners(session_id) to cancel active listener tasks for a session.
autogpt_platform/backend/backend/api/features/chat/routes.py Adds DELETE /sessions/{session_id}/stream endpoint to trigger listener disconnects.

Comment thread autogpt_platform/frontend/src/app/(platform)/copilot/useCopilotStream.ts Outdated
Comment thread autogpt_platform/backend/backend/api/features/chat/routes.py
Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 2

🧹 Nitpick comments (1)
autogpt_platform/frontend/src/app/(platform)/copilot/helpers.ts (1)

165-173: Use the generated chat client for this new endpoint.

This ad-hoc fetch bypasses the repo’s generated API surface, so the new DELETE /sessions/{session_id}/stream route won’t be represented alongside the rest of the chat mutations. Please regenerate the chat client and call the generated function here instead of adding another direct backend request path.

As per coding guidelines "Use generated API hooks from '@/app/api/generated/endpoints/' instead of deprecated 'BackendAPI' or 'src/lib/autogpt-server-api/*'" and "Regenerate API hooks with 'pnpm generate:api' after backend OpenAPI spec changes in frontend development".

🤖 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/helpers.ts around lines
165 - 173, The disconnectSessionStream function currently issues a raw fetch to
DELETE /api/chat/sessions/{sessionId}/stream; replace this with the generated
chat client function (after running pnpm generate:api) and call that generated
endpoint instead of fetch. Import the appropriate generated function from
'@/app/api/__generated__/endpoints/' (the mutation for deleting session stream),
invoke it with sessionId and the existing auth headers (or use the generated
client's auth flow), and propagate or swallow errors consistently (keeping the
existing .catch behavior if desired). Update the import and remove
getCopilotAuthHeaders()/fetch usage in disconnectSessionStream so the new
generated API surface is used.
🤖 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/copilot/stream_registry.py`:
- Around line 1163-1181: The current disconnect logic in stream_registry.py
inspects only the in-memory _listener_sessions keyed by session_id, so DELETE
/sessions/{session_id}/stream is pod-local and tears down all subscribers for
that session; change this to a subscriber-scoped, cross-pod signal by
introducing a per-subscriber listener token (returned to clients) and a
Redis-backed fan-out: store subscriber entries (token ->
worker/session/listener-id) in Redis when creating listeners, have workers
subscribe to a Redis pub/sub channel, and when DELETE is called publish an
unsubscribe message with that listener token; update the cancel code to match on
the token (not just sid==session_id) and have each worker on receiving the
publish find the corresponding local task in _listener_sessions and cancel it
(keeping the current safe await/wait_for handling for task shutdown).

In `@autogpt_platform/frontend/src/app/`(platform)/copilot/useCopilotStream.ts:
- Around line 430-433: When switching sessions, set isUserStoppingRef.current =
true before calling sdkStopRef.current() and disconnectSessionStream(prevSid) so
the previous stream's onError handler (which captures the old sessionId) won't
treat the resulting AbortError as an unexpected disconnect and enqueue a
reconnect; modify the cleanup branch that checks prevSid !== sessionId to set
isUserStoppingRef.current = true, then call sdkStopRef.current() and
disconnectSessionStream(prevSid) (mirroring how stop() sets isUserStoppingRef
before calling sdkStop), ensuring the same guard used to prevent reconnects is
applied during session switches.

---

Nitpick comments:
In `@autogpt_platform/frontend/src/app/`(platform)/copilot/helpers.ts:
- Around line 165-173: The disconnectSessionStream function currently issues a
raw fetch to DELETE /api/chat/sessions/{sessionId}/stream; replace this with the
generated chat client function (after running pnpm generate:api) and call that
generated endpoint instead of fetch. Import the appropriate generated function
from '@/app/api/__generated__/endpoints/' (the mutation for deleting session
stream), invoke it with sessionId and the existing auth headers (or use the
generated client's auth flow), and propagate or swallow errors consistently
(keeping the existing .catch behavior if desired). Update the import and remove
getCopilotAuthHeaders()/fetch usage in disconnectSessionStream so the new
generated API surface is used.
🪄 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: 42c2ae11-fa3e-4475-b56c-eb7ad23cf86e

📥 Commits

Reviewing files that changed from the base of the PR and between b319c26 and ba8513d.

📒 Files selected for processing (4)
  • autogpt_platform/backend/backend/api/features/chat/routes.py
  • autogpt_platform/backend/backend/copilot/stream_registry.py
  • autogpt_platform/frontend/src/app/(platform)/copilot/helpers.ts
  • autogpt_platform/frontend/src/app/(platform)/copilot/useCopilotStream.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). (14)
  • GitHub Check: check API types
  • GitHub Check: integration_test
  • GitHub Check: lint
  • GitHub Check: Agent
  • GitHub Check: Seer Code Review
  • GitHub Check: end-to-end tests
  • GitHub Check: type-check (3.11)
  • GitHub Check: type-check (3.12)
  • GitHub Check: test (3.13)
  • GitHub Check: type-check (3.13)
  • GitHub Check: test (3.12)
  • GitHub Check: test (3.11)
  • GitHub Check: Analyze (python)
  • GitHub Check: Check PR Status
🧰 Additional context used
📓 Path-based instructions (11)
autogpt_platform/frontend/**/*.{ts,tsx,js,jsx}

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

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

Format frontend code using pnpm format

Files:

  • autogpt_platform/frontend/src/app/(platform)/copilot/helpers.ts
  • autogpt_platform/frontend/src/app/(platform)/copilot/useCopilotStream.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/helpers.ts
  • autogpt_platform/frontend/src/app/(platform)/copilot/useCopilotStream.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
Use Next.js <Link> for internal navigation — never raw <a> tags
No any types unless the value genuinely can be anything
No linter suppressors (// @ts-ignore``, // eslint-disable) — fix the actual issue
Keep files under ~200 lines; extract sub-components or hooks into their own files when a file grows beyond this
Keep render functions and hooks under ~50 lines; extract named helpers or sub-components when they grow longer
Use generated API hooks from `@/app/api/generated/endpoints/` with pattern `use{Method}{Version}{OperationName}` and regenerate with `pnpm generate:api`
Do not use `useCallback` or `useMemo` unless asked to optimise a given function
Separate render logic (`.tsx`) from business logic (`use*.ts` hooks)
Use ErrorCard for render errors, toast for mutations, and Sentry for exceptions in the frontend

Files:

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

📄 CodeRabbit inference engine (AGENTS.md)

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

Files:

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

📄 CodeRabbit inference engine (AGENTS.md)

No barrel files or index.ts re-exports in the frontend

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

Files:

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

📄 CodeRabbit inference engine (AGENTS.md)

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

Extract component logic into custom hooks grouped by concern, not by component. Each hook should represent a cohesive domain of functionality (e.g., useSearch, useFilters, usePagination) rather than bundling all state into one useComponentState hook. Put each hook in its own .ts file.

Files:

  • autogpt_platform/frontend/src/app/(platform)/copilot/helpers.ts
  • autogpt_platform/frontend/src/app/(platform)/copilot/useCopilotStream.ts
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/helpers.ts
  • autogpt_platform/frontend/src/app/(platform)/copilot/useCopilotStream.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

autogpt_platform/backend/**/*.py: Use poetry run ... command for executing Python package dependencies
Use top-level imports only — avoid 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 are acceptable for sibling modules within the same package; avoid double-dot relative imports
Do not use duck typing — avoid hasattr/getattr/isinstance for type dispatch; use typed interfaces/unions/protocols instead
Use Pydantic models over dataclass/namedtuple/dict for structured data
Do not use linter suppressors — no # type: ignore, # noqa, # pyright: ignore; fix the type/code instead
Prefer list comprehensions over manual loop-and-append patterns
Use early return with guard clauses first to avoid deep nesting
Use %s for deferred interpolation in debug log statements for efficiency; use f-strings elsewhere for readability (e.g., logger.debug("Processing %s items", count) vs logger.info(f"Processing {count} items"))
Sanitize error paths by using os.path.basename() in error messages to avoid leaking directory structure
Be aware of TOCTOU (Time-Of-Check-Time-Of-Use) issues — avoid check-then-act patterns for file access and credit charging
Use transaction=True for Redis pipelines to ensure atomicity on multi-step 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 helpers, models, or a sub-module into a new file)
Keep functions under ~40 lines; extract named helpers when a function grows longer
...

Files:

  • autogpt_platform/backend/backend/copilot/stream_registry.py
  • autogpt_platform/backend/backend/api/features/chat/routes.py
autogpt_platform/{backend,autogpt_libs}/**/*.py

📄 CodeRabbit inference engine (AGENTS.md)

Format Python code with poetry run format

Files:

  • autogpt_platform/backend/backend/copilot/stream_registry.py
  • autogpt_platform/backend/backend/api/features/chat/routes.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/backend/**/api/**/*.py

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

autogpt_platform/backend/**/api/**/*.py: Use Security() instead of Depends() for authentication dependencies to get proper OpenAPI security specification
Follow SSE (Server-Sent Events) protocol: use data: lines for frontend-parsed events (must match Zod schema) and : comment lines for heartbeats/status

Files:

  • autogpt_platform/backend/backend/api/features/chat/routes.py
🧠 Learnings (15)
📓 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.
Learnt from: majdyz
Repo: Significant-Gravitas/AutoGPT PR: 12356
File: autogpt_platform/backend/backend/copilot/constants.py:9-12
Timestamp: 2026-03-10T08:39:22.025Z
Learning: In Significant-Gravitas/AutoGPT PR `#12356`, the `COPILOT_SYNTHETIC_ID_PREFIX = "copilot-"` check in `create_auto_approval_record` (human_review.py) is intentional and safe. The `graph_exec_id` passed to this function comes from server-side `PendingHumanReview` DB records (not from user input); the API only accepts `node_exec_id` from users. Synthetic `copilot-*` IDs are only ever created server-side in `run_block.py`. The prefix skip avoids a DB lookup for a `AgentGraphExecution` record that legitimately does not exist for CoPilot sessions, while `user_id` scoping is enforced at the auth layer and on the resulting auto-approval record.
Learnt from: majdyz
Repo: Significant-Gravitas/AutoGPT PR: 12604
File: autogpt_platform/backend/backend/copilot/sdk/security_hooks.py:165-171
Timestamp: 2026-03-30T11:49:37.770Z
Learning: In `autogpt_platform/backend/backend/copilot/sdk/security_hooks.py`, the `web_search_count` and `total_tool_call_count` circuit-breaker counters in `create_security_hooks` are intentionally per-turn (closure-local), not per-session. Hooks are recreated per stream invocation in `service.py`, so counters reset each turn. This is an accepted v1 design: it caps a single runaway turn (incident d2f7cba3: 179 WebSearch calls, $20.66). True per-session persistence via Redis is deferred to a later iteration. Do not flag these as a per-session vs. per-turn mismatch bug.
📚 Learning: 2026-04-08T17:28:40.824Z
Learnt from: CR
Repo: Significant-Gravitas/AutoGPT PR: 0
File: autogpt_platform/frontend/AGENTS.md:0-0
Timestamp: 2026-04-08T17:28:40.824Z
Learning: Applies to autogpt_platform/frontend/**/*.{ts,tsx} : Fully capitalize acronyms in symbols, e.g. `graphID`, `useBackendAPI`

Applied to files:

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

Applied to files:

  • autogpt_platform/frontend/src/app/(platform)/copilot/helpers.ts
  • autogpt_platform/frontend/src/app/(platform)/copilot/useCopilotStream.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/helpers.ts
  • autogpt_platform/frontend/src/app/(platform)/copilot/useCopilotStream.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/copilot/stream_registry.py
  • autogpt_platform/backend/backend/api/features/chat/routes.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/stream_registry.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/stream_registry.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/copilot/stream_registry.py
  • autogpt_platform/backend/backend/api/features/chat/routes.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/copilot/stream_registry.py
  • autogpt_platform/backend/backend/api/features/chat/routes.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/copilot/stream_registry.py
  • autogpt_platform/backend/backend/api/features/chat/routes.py
📚 Learning: 2026-03-07T07:43:15.754Z
Learnt from: kcze
Repo: Significant-Gravitas/AutoGPT PR: 12328
File: autogpt_platform/frontend/src/app/api/openapi.json:1116-1118
Timestamp: 2026-03-07T07:43:15.754Z
Learning: In Significant-Gravitas/AutoGPT, v2 chat endpoints often declare HTTPBearerJWT at the router level while using Depends(auth.get_user_id) that returns None for unauthenticated users; effective behavior is optional auth. Keep this convention unless doing a repo-wide OpenAPI update; prefer clarifying descriptions over per-operation security changes.

Applied to files:

  • autogpt_platform/backend/backend/api/features/chat/routes.py
📚 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/useCopilotStream.ts
📚 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/useCopilotStream.ts
🔇 Additional comments (2)
autogpt_platform/backend/backend/api/features/chat/routes.py (1)

357-379: Looks good.

The new endpoint revalidates session ownership before disconnecting, so it doesn’t let one user tear down another user’s stream listeners.

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

249-255: Good stale-closure fix.

Keeping sdkStop and resumeStream in refs here makes the wake/reconnect/session-switch callbacks call the latest SDK functions instead of whichever render created the callback.

Comment thread autogpt_platform/backend/backend/copilot/stream_registry.py Outdated
Comment thread autogpt_platform/frontend/src/app/(platform)/copilot/useCopilotStream.ts Outdated
ntindle
ntindle previously approved these changes Apr 13, 2026
@github-actions
Copy link
Copy Markdown
Contributor

This pull request has conflicts with the base branch, please resolve those so we can evaluate the pull request.

0ubbe added 2 commits April 14, 2026 21:16
…reconnect strip, test DELETE

- useCopilotStream: set isUserStoppingRef=true BEFORE sdkStop on session
  switch so the old stream's async onError (AbortError) short-circuits
  the reconnect path instead of queuing a reconnect for the new session.
- useCopilotStream: restore stale-partial-assistant-message strip in the
  reconnect-timer callback — backend replays from 0-0 on resume and the
  strip was only present on the hydration path.
- stream_registry: document pod-local / session-scoped cancellation
  limitation for disconnect_all_listeners; XREAD timeout bounds worst
  case in multi-pod deployments.
- routes_test: add 204 and 404 coverage for DELETE /sessions/{id}/stream.
Comment thread autogpt_platform/frontend/src/app/(platform)/copilot/useCopilotStream.ts Outdated
…, use generated client

- useCopilotStream: schedule reset of isUserStoppingRef via setTimeout(0)
  so the old stream's async onError sees it as true, but the new session
  is not left permanently flagged (was blocking hydration-triggered
  auto-resume on switch-back). Fixes false-positive flagged by sentry.
- helpers: switch disconnectSessionStream to the generated
  deleteV2DisconnectSessionStream client, removing the raw fetch /
  environment import — addresses coderabbit nitpick.
- openapi.json: regenerate to include DELETE /sessions/{id}/stream.
@0ubbe 0ubbe requested review from majdyz and ntindle April 14, 2026 15:14
Comment thread autogpt_platform/backend/backend/copilot/stream_registry.py
Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

🧹 Nitpick comments (1)
autogpt_platform/frontend/src/app/(platform)/copilot/useCopilotStream.ts (1)

257-263: Consider extracting the stream lifecycle state machine into a smaller hook.

useCopilotStream now owns transport setup, reconnect backoff, wake re-sync, hydration merge, cancellation, and session-switch cleanup in one file. Pulling the reconnect/session-switch logic into a focused helper hook would make this easier to reason about and keep closer to the repo’s size guidance.

As per coding guidelines, keep files under ~200 lines and keep hooks under ~50 lines; extract named helpers or hooks when they grow longer.

Also applies to: 430-473

🤖 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/useCopilotStream.ts
around lines 257 - 263, Extract the stream lifecycle/state-machine logic out of
useCopilotStream into a focused hook (e.g., useCopilotStreamLifecycle or
useStreamLifecycle) that owns reconnect/backoff, wake re-sync, hydration merge,
cancellation, and session-switch cleanup; move the related code currently
co-located with sdkStopRef and resumeStreamRef (and the logic around lines
~430-473) into that new hook, keep useCopilotStream responsible only for
transport setup and high-level orchestration, wire the new hook to accept stable
refs (sdkStopRef, resumeStreamRef) and callbacks from useCopilotStream, and
export the lifecycle hook as a named function so tests or callers can import it
independently.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Nitpick comments:
In `@autogpt_platform/frontend/src/app/`(platform)/copilot/useCopilotStream.ts:
- Around line 257-263: Extract the stream lifecycle/state-machine logic out of
useCopilotStream into a focused hook (e.g., useCopilotStreamLifecycle or
useStreamLifecycle) that owns reconnect/backoff, wake re-sync, hydration merge,
cancellation, and session-switch cleanup; move the related code currently
co-located with sdkStopRef and resumeStreamRef (and the logic around lines
~430-473) into that new hook, keep useCopilotStream responsible only for
transport setup and high-level orchestration, wire the new hook to accept stable
refs (sdkStopRef, resumeStreamRef) and callbacks from useCopilotStream, and
export the lifecycle hook as a named function so tests or callers can import it
independently.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: c858ab00-2391-4439-9cd9-3af4c8fe5e6d

📥 Commits

Reviewing files that changed from the base of the PR and between 1f3ebaf and e42f228.

📒 Files selected for processing (3)
  • autogpt_platform/frontend/src/app/(platform)/copilot/helpers.ts
  • autogpt_platform/frontend/src/app/(platform)/copilot/useCopilotStream.ts
  • autogpt_platform/frontend/src/app/api/openapi.json
📜 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). (6)
  • GitHub Check: end-to-end tests
  • GitHub Check: test (3.13)
  • GitHub Check: test (3.11)
  • GitHub Check: test (3.12)
  • GitHub Check: Seer Code Review
  • GitHub Check: Check PR Status
🧰 Additional context used
📓 Path-based instructions (7)
autogpt_platform/frontend/**/*.{ts,tsx,js,jsx}

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

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

Format frontend code using pnpm format

Files:

  • autogpt_platform/frontend/src/app/(platform)/copilot/helpers.ts
  • autogpt_platform/frontend/src/app/(platform)/copilot/useCopilotStream.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/helpers.ts
  • autogpt_platform/frontend/src/app/(platform)/copilot/useCopilotStream.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
Use Next.js <Link> for internal navigation — never raw <a> tags
No any types unless the value genuinely can be anything
No linter suppressors (// @ts-ignore``, // eslint-disable) — fix the actual issue
Keep files under ~200 lines; extract sub-components or hooks into their own files when a file grows beyond this
Keep render functions and hooks under ~50 lines; extract named helpers or sub-components when they grow longer
Use generated API hooks from `@/app/api/generated/endpoints/` with pattern `use{Method}{Version}{OperationName}` and regenerate with `pnpm generate:api`
Do not use `useCallback` or `useMemo` unless asked to optimise a given function
Separate render logic (`.tsx`) from business logic (`use*.ts` hooks)
Use ErrorCard for render errors, toast for mutations, and Sentry for exceptions in the frontend

Files:

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

📄 CodeRabbit inference engine (AGENTS.md)

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

Files:

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

📄 CodeRabbit inference engine (AGENTS.md)

No barrel files or index.ts re-exports in the frontend

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

Files:

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

📄 CodeRabbit inference engine (AGENTS.md)

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

Extract component logic into custom hooks grouped by concern, not by component. Each hook should represent a cohesive domain of functionality (e.g., useSearch, useFilters, usePagination) rather than bundling all state into one useComponentState hook. Put each hook in its own .ts file.

Files:

  • autogpt_platform/frontend/src/app/(platform)/copilot/helpers.ts
  • autogpt_platform/frontend/src/app/(platform)/copilot/useCopilotStream.ts
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/helpers.ts
  • autogpt_platform/frontend/src/app/(platform)/copilot/useCopilotStream.ts
🧠 Learnings (27)
📓 Common learnings
Learnt from: 0ubbe
Repo: Significant-Gravitas/AutoGPT PR: 12766
File: autogpt_platform/backend/backend/copilot/stream_registry.py:1175-1193
Timestamp: 2026-04-14T14:45:38.639Z
Learning: In `autogpt_platform/backend/backend/copilot/stream_registry.py`, `disconnect_all_listeners(session_id)` is intentionally pod-local (inspects in-memory `_listener_sessions`) and session-scoped (not subscriber-scoped). It cancels all listener tasks for the session on the current pod only. If the DELETE request hits a different pod, nothing is cancelled on that pod — the XREAD timeout (5 s block + status poll) bounds the worst-case release time. In the rare two-tabs-same-session case both listeners on the same pod would be torn down. A subscriber-scoped cross-pod fan-out (per-listener tokens + Redis pub/sub) is deferred as a follow-up. Do NOT re-flag this as a blocking issue; the limitation is explicitly documented in the function's docstring (PR `#12766`, commit 1f3ebafd5).
Learnt from: majdyz
Repo: Significant-Gravitas/AutoGPT PR: 12773
File: autogpt_platform/backend/backend/copilot/pending_messages.py:52-64
Timestamp: 2026-04-14T14:36:22.396Z
Learning: In `autogpt_platform/backend/backend/copilot` (PR `#12773`, commit d7bced0c6): when draining pending messages into `session.messages`, each message's text is sanitized via `strip_user_context_tags` before persistence to prevent user-controlled `<user_context>` injection from bypassing the trusted server-side context prefix. Additionally, if `upsert_chat_session` fails after draining, the drained `PendingMessage` objects are requeued back to Redis to avoid silent message loss. Do NOT flag the drain-then-requeue pattern as redundant — it is the intentional failure-resilience strategy for the pending buffer.
Learnt from: majdyz
Repo: Significant-Gravitas/AutoGPT PR: 12445
File: autogpt_platform/backend/backend/copilot/sdk/service.py:1071-1072
Timestamp: 2026-03-17T06:48:26.471Z
Learning: In Significant-Gravitas/AutoGPT (autogpt_platform), the AI SDK enforces `z.strictObject({type, errorText})` on SSE `StreamError` responses, so additional fields like `retryable: bool` cannot be added to `StreamError` or serialized via `to_sse()`. Instead, retry signaling for transient Anthropic API errors is done via the `COPILOT_RETRYABLE_ERROR_PREFIX` constant prepended to persisted session messages (in `ChatMessage.content`). The frontend detects retryable errors by checking `markerType === "retryable_error"` from `parseSpecialMarkers()` — no SSE schema changes and no string matching on error text. This pattern was established in PR `#12445`, commit 64d82797b.
Learnt from: majdyz
Repo: Significant-Gravitas/AutoGPT PR: 12604
File: autogpt_platform/backend/backend/copilot/sdk/security_hooks.py:165-171
Timestamp: 2026-03-30T11:49:37.770Z
Learning: In `autogpt_platform/backend/backend/copilot/sdk/security_hooks.py`, the `web_search_count` and `total_tool_call_count` circuit-breaker counters in `create_security_hooks` are intentionally per-turn (closure-local), not per-session. Hooks are recreated per stream invocation in `service.py`, so counters reset each turn. This is an accepted v1 design: it caps a single runaway turn (incident d2f7cba3: 179 WebSearch calls, $20.66). True per-session persistence via Redis is deferred to a later iteration. Do not flag these as a per-session vs. per-turn mismatch bug.
📚 Learning: 2026-04-14T14:36:22.396Z
Learnt from: majdyz
Repo: Significant-Gravitas/AutoGPT PR: 12773
File: autogpt_platform/backend/backend/copilot/pending_messages.py:52-64
Timestamp: 2026-04-14T14:36:22.396Z
Learning: In `autogpt_platform/backend/backend/copilot` (PR `#12773`, commit d7bced0c6): when draining pending messages into `session.messages`, each message's text is sanitized via `strip_user_context_tags` before persistence to prevent user-controlled `<user_context>` injection from bypassing the trusted server-side context prefix. Additionally, if `upsert_chat_session` fails after draining, the drained `PendingMessage` objects are requeued back to Redis to avoid silent message loss. Do NOT flag the drain-then-requeue pattern as redundant — it is the intentional failure-resilience strategy for the pending buffer.

Applied to files:

  • autogpt_platform/frontend/src/app/(platform)/copilot/helpers.ts
  • autogpt_platform/frontend/src/app/(platform)/copilot/useCopilotStream.ts
📚 Learning: 2026-04-14T14:45:38.639Z
Learnt from: 0ubbe
Repo: Significant-Gravitas/AutoGPT PR: 12766
File: autogpt_platform/backend/backend/copilot/stream_registry.py:1175-1193
Timestamp: 2026-04-14T14:45:38.639Z
Learning: In `autogpt_platform/backend/backend/copilot/stream_registry.py`, `disconnect_all_listeners(session_id)` is intentionally pod-local (inspects in-memory `_listener_sessions`) and session-scoped (not subscriber-scoped). It cancels all listener tasks for the session on the current pod only. If the DELETE request hits a different pod, nothing is cancelled on that pod — the XREAD timeout (5 s block + status poll) bounds the worst-case release time. In the rare two-tabs-same-session case both listeners on the same pod would be torn down. A subscriber-scoped cross-pod fan-out (per-listener tokens + Redis pub/sub) is deferred as a follow-up. Do NOT re-flag this as a blocking issue; the limitation is explicitly documented in the function's docstring (PR `#12766`, commit 1f3ebafd5).

Applied to files:

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

Applied to files:

  • autogpt_platform/frontend/src/app/(platform)/copilot/helpers.ts
  • autogpt_platform/frontend/src/app/(platform)/copilot/useCopilotStream.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/helpers.ts
  • autogpt_platform/frontend/src/app/(platform)/copilot/useCopilotStream.ts
📚 Learning: 2026-03-24T21:25:15.983Z
Learnt from: ntindle
Repo: Significant-Gravitas/AutoGPT PR: 12536
File: autogpt_platform/frontend/src/app/api/openapi.json:5770-5790
Timestamp: 2026-03-24T21:25:15.983Z
Learning: Repo: Significant-Gravitas/AutoGPT — PR `#12536`
File: autogpt_platform/frontend/src/app/api/openapi.json
Learning: The OpenAPI spec file is auto-generated; per established convention, endpoints generally declare only 200/201, 401, and 422 responses. Do not suggest adding explicit 403/404 response entries for single operations unless planning a repo-wide spec update. Prefer clarifying such behaviors in endpoint descriptions/docstrings instead of altering response maps.

Applied to files:

  • autogpt_platform/frontend/src/app/api/openapi.json
📚 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/api/openapi.json
  • autogpt_platform/frontend/src/app/(platform)/copilot/useCopilotStream.ts
📚 Learning: 2026-03-01T07:58:56.207Z
Learnt from: majdyz
Repo: Significant-Gravitas/AutoGPT PR: 12213
File: autogpt_platform/frontend/src/app/api/openapi.json:10030-10037
Timestamp: 2026-03-01T07:58:56.207Z
Learning: When a backend field represents sensitive data, use a secret type (e.g., Pydantic SecretStr with length constraints) so OpenAPI marks it as a password/writeOnly field. Apply this pattern to similar sensitive request fields across API schemas so generated TypeScript clients and docs treat them as secrets and do not mishandle sensitivity. Review all openapi.jsons where sensitive inputs are defined and replace plain strings with SecretStr-like semantics with appropriate minLength constraints.

Applied to files:

  • autogpt_platform/frontend/src/app/api/openapi.json
📚 Learning: 2026-04-14T06:39:49.111Z
Learnt from: majdyz
Repo: Significant-Gravitas/AutoGPT PR: 12773
File: autogpt_platform/frontend/src/app/api/openapi.json:12803-12806
Timestamp: 2026-04-14T06:39:49.111Z
Learning: In OpenAPI specs, ensure the schema/message length caps for the StreamChatRequest.message and QueuePendingMessageRequest.message fields are set to the intended values: StreamChatRequest.message maxLength must be 64000 and QueuePendingMessageRequest.message maxLength must be 32000. Keep QueuePendingMessageRequest.message consistent with PendingMessage.content, and ensure the pending (queue) ceiling never exceeds the stream ceiling because both ultimately feed the same LLM context window. Update any legacy smaller limits (e.g., 4000/16000) to these newer ceilings.

Applied to files:

  • autogpt_platform/frontend/src/app/api/openapi.json
📚 Learning: 2026-03-07T07:43:09.871Z
Learnt from: kcze
Repo: Significant-Gravitas/AutoGPT PR: 12328
File: autogpt_platform/frontend/src/app/api/openapi.json:1116-1118
Timestamp: 2026-03-07T07:43:09.871Z
Learning: For autogpt_platform/frontend/src/app/api/openapi.json, preserve the existing behavior: HTTPBearerJWT is declared at the router level with Depends(auth.get_user_id) returning None for unauthenticated users; treat as optional auth. Do not change per-operation security descriptions unless you plan a repo-wide OpenAPI update. If you change this file, prefer clarifying operation descriptions rather than altering security requirements.

Applied to files:

  • autogpt_platform/frontend/src/app/api/openapi.json
📚 Learning: 2026-02-04T16:49:42.490Z
Learnt from: CR
Repo: Significant-Gravitas/AutoGPT PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2026-02-04T16:49:42.490Z
Learning: Applies to autogpt_platform/frontend/**/*.{tsx,ts} : Use generated API hooks from '@/app/api/__generated__/endpoints/' instead of deprecated 'BackendAPI' or 'src/lib/autogpt-server-api/*'

Applied to files:

  • autogpt_platform/frontend/src/app/(platform)/copilot/useCopilotStream.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/useCopilotStream.ts
📚 Learning: 2026-03-30T11:49:37.770Z
Learnt from: majdyz
Repo: Significant-Gravitas/AutoGPT PR: 12604
File: autogpt_platform/backend/backend/copilot/sdk/security_hooks.py:165-171
Timestamp: 2026-03-30T11:49:37.770Z
Learning: In `autogpt_platform/backend/backend/copilot/sdk/security_hooks.py`, the `web_search_count` and `total_tool_call_count` circuit-breaker counters in `create_security_hooks` are intentionally per-turn (closure-local), not per-session. Hooks are recreated per stream invocation in `service.py`, so counters reset each turn. This is an accepted v1 design: it caps a single runaway turn (incident d2f7cba3: 179 WebSearch calls, $20.66). True per-session persistence via Redis is deferred to a later iteration. Do not flag these as a per-session vs. per-turn mismatch bug.

Applied to files:

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

Applied to files:

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

Applied to files:

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

Applied to files:

  • autogpt_platform/frontend/src/app/(platform)/copilot/useCopilotStream.ts
📚 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/useCopilotStream.ts
📚 Learning: 2026-04-03T11:14:45.569Z
Learnt from: majdyz
Repo: Significant-Gravitas/AutoGPT PR: 12623
File: autogpt_platform/backend/backend/copilot/baseline/service.py:0-0
Timestamp: 2026-04-03T11:14:45.569Z
Learning: In `autogpt_platform/backend/backend/copilot/baseline/service.py`, `transcript_builder.append_user(content=message)` is called unconditionally even when the message is a duplicate that was suppressed by the `is_new_message` guard. This is intentional: the downloaded transcript may be stale (uploaded before the previous attempt persisted the message), so always appending the current user turn prevents a malformed assistant-after-assistant transcript structure. The `is_user_message` flag is still checked (`if message and is_user_message:`), so assistant-role inputs are excluded. Do NOT flag this as a bug.

Applied to files:

  • autogpt_platform/frontend/src/app/(platform)/copilot/useCopilotStream.ts
📚 Learning: 2026-04-09T09:07:11.551Z
Learnt from: ntindle
Repo: Significant-Gravitas/AutoGPT PR: 12720
File: autogpt_platform/backend/backend/copilot/tools/graphiti_delete.py:63-69
Timestamp: 2026-04-09T09:07:11.551Z
Learning: In Significant-Gravitas/AutoGPT, gating `graphiti_delete_user_data` (and similar Graphiti memory tools) on the `is_enabled_for_user` / `graphiti-memory` LaunchDarkly flag in the delete path is intentional and acceptable. The scenario where a user has existing Graphiti data but the flag is later disabled (preventing deletion) is not a concern for the team. Do not flag this pattern as an issue.

Applied to files:

  • autogpt_platform/frontend/src/app/(platform)/copilot/useCopilotStream.ts
📚 Learning: 2026-03-19T11:25:27.842Z
Learnt from: Pwuts
Repo: Significant-Gravitas/AutoGPT PR: 12471
File: autogpt_platform/frontend/src/app/(platform)/admin/users/useAdminUsersPage.ts:48-55
Timestamp: 2026-03-19T11:25:27.842Z
Learning: In `autogpt_platform/frontend/src/app/(platform)/admin/users/useAdminUsersPage.ts`, the debounced search pattern uses `useRef(debounce(...))` (lodash) rather than `useEffect`+`setTimeout`. The debounced callback atomically applies `setDebouncedSearch(value.trim())` and `setCurrentPage(1)`, so the page reset is deferred along with the filter change and never races ahead. The query is driven by `debouncedSearch` (not the raw `searchQuery`), so no stale-filter fetch occurs on the first keystroke. Do not flag this pattern as incorrect in future reviews.

Applied to files:

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

Applied to files:

  • autogpt_platform/frontend/src/app/(platform)/copilot/useCopilotStream.ts
📚 Learning: 2026-04-01T14:54:01.937Z
Learnt from: majdyz
Repo: Significant-Gravitas/AutoGPT PR: 12636
File: autogpt_platform/backend/backend/copilot/sdk/service.py:0-0
Timestamp: 2026-04-01T14:54:01.937Z
Learning: In Significant-Gravitas/AutoGPT (autogpt_platform), `claude_agent_max_transient_retries` (default=3) in `ChatConfig` counts **total attempts including the initial one**, not the number of extra retries. With the pre-incremented `transient_retries >= max_transient` guard in `service.py`, a value of 3 yields 3 total stream attempts (initial + 2 retries with exponential backoff: 1s, 2s). Do NOT flag this as an off-by-one — the `>=` check is intentional.

Applied to files:

  • autogpt_platform/frontend/src/app/(platform)/copilot/useCopilotStream.ts
📚 Learning: 2026-03-10T08:39:22.025Z
Learnt from: majdyz
Repo: Significant-Gravitas/AutoGPT PR: 12356
File: autogpt_platform/backend/backend/copilot/constants.py:9-12
Timestamp: 2026-03-10T08:39:22.025Z
Learning: In Significant-Gravitas/AutoGPT PR `#12356`, the `COPILOT_SYNTHETIC_ID_PREFIX = "copilot-"` check in `create_auto_approval_record` (human_review.py) is intentional and safe. The `graph_exec_id` passed to this function comes from server-side `PendingHumanReview` DB records (not from user input); the API only accepts `node_exec_id` from users. Synthetic `copilot-*` IDs are only ever created server-side in `run_block.py`. The prefix skip avoids a DB lookup for a `AgentGraphExecution` record that legitimately does not exist for CoPilot sessions, while `user_id` scoping is enforced at the auth layer and on the resulting auto-approval record.

Applied to files:

  • autogpt_platform/frontend/src/app/(platform)/copilot/useCopilotStream.ts
📚 Learning: 2026-04-07T18:08:03.548Z
Learnt from: majdyz
Repo: Significant-Gravitas/AutoGPT PR: 12701
File: .claude/skills/orchestrate/scripts/verify-complete.sh:120-121
Timestamp: 2026-04-07T18:08:03.548Z
Learning: In Significant-Gravitas/AutoGPT, verify-complete.sh (`.claude/skills/orchestrate/scripts/verify-complete.sh`) uses `commits[-1].committedDate` (not `updatedAt`) to identify stale CHANGES_REQUESTED reviews. This is intentional: `updatedAt` changes on any PR activity (bot comments, label changes, description edits), which would falsely classify a reviewer's CHANGES_REQUESTED as stale — a silent false negative. The `committedDate` edge case (commit created locally before a review but pushed after) only causes a false positive (unnecessary re-brief), which is the safer failure mode. Do not suggest switching to `updatedAt` for this comparison.

Applied to files:

  • autogpt_platform/frontend/src/app/(platform)/copilot/useCopilotStream.ts
🔇 Additional comments (3)
autogpt_platform/frontend/src/app/api/openapi.json (1)

1609-1637: Looks good — endpoint schema is consistent and complete.

DELETE /api/chat/sessions/{session_id}/stream is correctly modeled with auth, required session_id, and appropriate 204/401/422 responses for this generated spec.

Based on learnings: The OpenAPI spec file is auto-generated; endpoints generally declare only 200/201, 401, and 422 responses, and per-operation 403/404 additions are not expected unless doing a repo-wide spec update.

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

159-167: Nice use of the generated disconnect client.

Keeping the backend disconnect behind a tiny helper preserves the intended fire-and-forget behavior without adding another bespoke fetch path.

As per coding guidelines, use generated API hooks from @/app/api/__generated__/endpoints/ instead of deprecated BackendAPI or src/lib/autogpt-server-api/*.

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

257-263: Good race fix.

Keeping sdkStop/resumeStream in refs and using them from the reconnect, wake-resync, hydration, and session-switch paths removes the stale-closure edge cases this PR is targeting.

Also applies to: 391-414, 438-453, 531-532

…or is raised

The cancelled counter was incrementing for both asyncio.CancelledError and
asyncio.TimeoutError. Tasks that don't respond to cancellation within 5s now
correctly report as not cancelled. Also adds a test covering the timeout path.
@github-project-automation github-project-automation bot moved this from 🚧 Needs work to 👍🏼 Mergeable in AutoGPT development kanban Apr 15, 2026
@0ubbe 0ubbe added this pull request to the merge queue Apr 15, 2026
Merged via the queue into dev with commit 0284614 Apr 15, 2026
40 checks passed
@0ubbe 0ubbe deleted the fix/copilot-stream-disconnect-on-session-switch branch April 15, 2026 10:02
@github-project-automation github-project-automation bot moved this to Done in Frontend Apr 15, 2026
@github-project-automation github-project-automation bot moved this from 👍🏼 Mergeable to ✅ Done in AutoGPT development kanban Apr 15, 2026
@sentry
Copy link
Copy Markdown

sentry bot commented Apr 16, 2026

Issues attributed to commits in this pull request

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

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

Labels

platform/backend AutoGPT Platform - Back end platform/frontend AutoGPT Platform - Front end size/l

Projects

Status: ✅ Done
Status: Done

Development

Successfully merging this pull request may close these issues.

4 participants