feat(backend/copilot): AutoPilot task queue with 5 running + 15 in-flight caps - #13069
Conversation
…caps)
SECRT-2339: when a user submits beyond the soft running cap (5), persist
the turn into a FIFO queue (DB-backed, on the existing ``ChatMessage``
table via a sparse ``queueStatus`` column) instead of returning 429.
Hard cap at 15 in-flight (running + queued) preserves the abuse
safeguard from SECRT-2335.
The queued task IS the user's chat message — when the dispatcher
promotes it back into the running pool the queue columns clear and the
row becomes an ordinary chat message. Cancelled / blocked queued rows
stay visible to the user with a reason instead of silently disappearing.
Backend changes:
- New ``turn_queue`` module: enqueue / cancel / list / claim / dispatch
ops over ``ChatMessage`` with the new ``queueStatus``,
``queueBlockedReason``, ``queueMetadata``, ``queueStartedAt`` columns.
- ``acquire_turn_slot`` now reads the *running* cap (5, configurable via
``Settings.config.max_running_copilot_turns_per_user``); the existing
``max_concurrent_copilot_turns_per_user`` (default 15) is repurposed
as the in-flight cap.
- ``stream_chat_post``: on running-cap rejection, falls through to the
queue if in-flight < 15, else returns 429 with the new in-flight
message (``running + queued``).
- ``mark_session_completed``: after releasing a running slot, kicks
``dispatch_next_for_user`` to promote the user's oldest queued turn
(with pre-start re-validation: paywall + per-window USD cap).
- New endpoints: ``GET /chat/queued-tasks`` (list queued + blocked +
caps), ``DELETE /chat/queued-tasks/{message_id}`` (cancel).
- 7 unit tests for the queue module's state-transition logic.
Migration adds 4 nullable columns + a partial index
``WHERE queueStatus IS NOT NULL`` so the dispatcher's FIFO scan stays
tiny on the hot ChatMessage table.
Frontend wiring follows in a follow-up commit on this branch.
|
Note Reviews pausedIt 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 Use the following commands to manage reviews:
Use the checkboxes below for quick actions:
WalkthroughAdds a DB-backed per-user FIFO queue for AutoPilot chat turns, separates running vs in‑flight caps, enqueues requests when inflight capacity allows, exposes list/cancel API endpoints, auto-promotes queued turns on slot release, and surfaces queued/blocked badges and cancel actions in the UI. ChangesChat Turn Queueing Feature
Sequence Diagram(s)sequenceDiagram
participant Client
participant ChatAPI
participant DB
participant Dispatcher
Client->>ChatAPI: POST /chat
ChatAPI->>DB: count_running + count_queued (compute inflight)
alt inflight < limit
ChatAPI->>DB: try_enqueue_turn (queueStatus=queued, queueMetadata)
ChatAPI-->>Client: empty SSE (queued)
else inflight >= limit
ChatAPI-->>Client: 429
end
Note over Dispatcher,DB: On session completion
Dispatcher->>DB: dispatch_next_for_user (claim head, validate)
alt validation passes
Dispatcher->>DB: clear queueStatus, set queueStartedAt, schedule dispatch
else validation fails
Dispatcher->>DB: mark_queued_turn_blocked
end
Estimated code review effort🎯 4 (Complex) | ⏱️ ~45 minutes Possibly related PRs
Suggested labels
Suggested reviewers
🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches🧪 Generate unit tests (beta)
Tip 💬 Introducing Slack Agent: The best way for teams to turn conversations into code.Slack Agent is built on CodeRabbit's deep understanding of your code, so your team can collaborate across the entire SDLC without losing context.
Built for teams:
One agent for your entire SDLC. Right inside Slack. 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 |
🔍 PR Overlap DetectionThis check compares your PR against all other open PRs targeting the same branch to detect potential merge conflicts early. 🔴 Merge Conflicts DetectedThe following PRs have been tested and will have merge conflicts if merged after this PR. Consider coordinating with the authors.
🟢 Low Risk — File Overlap OnlyThese PRs touch the same files but different sections (click to expand)
Summary: 4 conflict(s), 0 medium risk, 8 low risk (out of 12 PRs with file overlap) Auto-generated on push. Ignores: |
Codecov Report❌ Patch coverage is Additional details and impacted files@@ Coverage Diff @@
## dev #13069 +/- ##
==========================================
+ Coverage 70.57% 70.64% +0.07%
==========================================
Files 2194 2197 +3
Lines 164859 165365 +506
Branches 16841 16902 +61
==========================================
+ Hits 116341 116824 +483
- Misses 45154 45156 +2
- Partials 3364 3385 +21
Flags with carried forward coverage won't be shown. Click here to find out more.
🚀 New features to boost your workflow:
|
The dispatcher claimed a queued ChatMessage row and then routed through ``schedule_chat_turn`` to schedule it. That helper always runs ``append_and_save_message`` inside the slot context — which hit a PK collision on the queued row's existing id, returned None, and silently dropped the dispatch. Net effect: a queued turn could be claimed (queueStatus cleared, slot acquired) without ever actually enqueuing the executor task. Fix: ``dispatch_next_for_user`` now uses ``acquire_turn_slot`` + ``dispatch_turn`` directly, skipping the redundant message-save since the row is already in the DB. Also invalidate the chat session cache on enqueue / dispatch so the frontend's 'Queued' badge appears + clears in step with the row's queueStatus.
There was a problem hiding this comment.
Actionable comments posted: 9
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/util/settings.py (1)
177-202:⚠️ Potential issue | 🟠 Major | ⚡ Quick winValidate that the running cap never exceeds the in-flight cap.
The new description says
max_running_copilot_turns_per_usermust be<= max_concurrent_copilot_turns_per_user, but nothing enforces it. If ops setsrunning=20andinflight=15,acquire_turn_slot()will still admit 20 running turns and the hard 15-task safeguard disappears.Suggested fix
-from pydantic import ( +from pydantic import ( AliasChoices, BaseModel, Field, PrivateAttr, ValidationInfo, field_validator, + model_validator, )class Config(UpdateTrackingModel["Config"], BaseSettings): @@ max_running_copilot_turns_per_user: int = Field( default=5, ge=1, le=1000, description=( @@ ), ) + + `@model_validator`(mode="after") + def validate_copilot_turn_caps(self) -> "Config": + if ( + self.max_running_copilot_turns_per_user + > self.max_concurrent_copilot_turns_per_user + ): + raise ValueError( + "max_running_copilot_turns_per_user must be <= " + "max_concurrent_copilot_turns_per_user" + ) + return self🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@autogpt_platform/backend/backend/util/settings.py` around lines 177 - 202, Add a Pydantic root validator to enforce that max_running_copilot_turns_per_user <= max_concurrent_copilot_turns_per_user at model validation time: in the Settings class (where max_concurrent_copilot_turns_per_user and max_running_copilot_turns_per_user are defined) implement a `@root_validator`(pre=False) that reads both fields and raises a ValueError with a clear message if max_running_copilot_turns_per_user is greater than max_concurrent_copilot_turns_per_user so misconfigured ops settings are rejected during startup.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@autogpt_platform/backend/backend/api/features/chat/routes.py`:
- Around line 1216-1242: The route does a TOCTOU by calling
turn_queue.count_inflight_turns() then _enqueue_chat_turn(); instead, implement
an atomic enqueue operation in the queue layer (e.g.,
turn_queue.enqueue_with_hard_cap or similar) that performs the inflight count
check, sequence generation (get_next_sequence), and the insert inside one DB
transaction/lock so the hard-cap admission and per-session sequence assignment
cannot race; update this route to call that new atomic method and remove the
separate count/check logic (keep using get_inflight_turn_limit() only inside the
queue implementation) and ensure the new method returns an explicit
error/exception you translate to HTTP 429 when the hard cap is exceeded.
In `@autogpt_platform/backend/backend/copilot/stream_registry.py`:
- Around line 877-893: The dispatch is happening while the session's
executor/SDK stream locks may still be held; change the call site so
dispatch_next_for_user(user_id) runs only after those session locks are fully
cleared — e.g., ensure release_turn_slot(session_id) actually releases executor
and SDK stream locks or, more robustly, defer the dispatch by scheduling it
(asyncio.create_task) or invoking it from a callback that runs after the locks
are released. Update stream_registry so that release_turn_slot completes lock
teardown before calling dispatch_next_for_user, referencing the functions
release_turn_slot and dispatch_next_for_user to locate and modify the code path.
In `@autogpt_platform/backend/backend/copilot/turn_queue_test.py`:
- Around line 9-13: The test file has import sorting/spacing issues; run the
project's formatter (poetry run format) on
autogpt_platform/backend/backend/copilot/turn_queue_test.py to fix import order
and spacing, then re-check imports (from unittest.mock import AsyncMock,
MagicMock, patch and import pytest / from backend.copilot import turn_queue) are
in the correct sorted groups and commit the formatted file; ensure the commit
passes CI formatting checks before merging.
In `@autogpt_platform/backend/backend/copilot/turn_queue.py`:
- Around line 108-157: The public enqueue_turn signature accepts user_id but
never uses it; fix by either removing the user_id parameter from enqueue_turn
and all callers, or enforce ownership by querying ChatSession (e.g.,
ChatSession.find_first) for a session with id == session_id and userId ==
user_id before creating the ChatMessage; if no session is found, raise an
appropriate error (e.g., ValueError or custom exception) and return early so the
message insert cannot proceed without confirmed ownership. Ensure the check
happens at the start of enqueue_turn (before ChatMessage.prisma().create) and
keep the rest of the function logic unchanged if ownership is confirmed.
- Around line 74-76: The current count_inflight_turns calls count_running_turns
then count_queued_turns which creates a TOCTOU window where a queued→running
promotion can be missed; change the order to call count_queued_turns first and
then count_running_turns so a concurrent promotion is at worst double-counted
(never under-counted), and update the count_inflight_turns docstring to state
the count may briefly be conservatively high but will never read lower than the
true in-flight total (so the hard cap is enforced). Ensure you only modify the
body and docstring of count_inflight_turns and keep calling the existing
count_queued_turns and count_running_turns helpers.
- Around line 350-362: The two helper functions _generate_id and _utcnow
currently perform stdlib imports inside the function body; hoist the imports for
uuid and datetime/timezone to module top-level instead and remove the inner
imports so _generate_id simply returns str(uuid.uuid4()) and _utcnow returns
datetime.now(timezone.utc); keep the local imports in dispatch_next_for_user
(executor/rate-limit pipeline) untouched as they are intentionally guarded.
- Around line 178-191: mark_queued_turn_blocked currently unconditionally
updates the row and can overwrite a user-set "cancelled" status; change the
update to an atomic guarded update by using
ChatMessage.prisma().update_many(where={"id": message_id, "queueStatus":
STATUS_QUEUED}, data={"queueStatus": STATUS_BLOCKED, "queueBlockedReason":
reason}) so the transition only occurs if the row is still queued, remove the
except RecordNotFoundError branch (it becomes unnecessary), and delete the
now-unused RecordNotFoundError import; this preserves user cancellations (see
mark_queued_turn_blocked and related cancel_queued_turn/dispatch_next_for_user
flows).
- Around line 311-333: The rollback after schedule_chat_turn can re-queue a
ChatMessage even when enqueue_copilot_turn already published a RabbitMQ task,
causing duplicate execution; to fix, add a message_id field to
CoPilotExecutionEntry and propagate the ChatMessage.id when calling
enqueue_copilot_turn/dispatch_turn/schedule_chat_turn so the worker can use that
message_id as an idempotency key (store it in CoPilotExecutionEntry and check it
against active/completed entries before starting work), and tighten the rollback
only to cases before publish by ensuring enqueue_copilot_turn returns
success/failure deterministically (or throw a clearly documented
PrePublishError) so the exception handler only retries on true pre-publish
failures; update ChatMessage.prisma().update_many usage only for genuine
pre-publish exceptions.
In
`@autogpt_platform/backend/migrations/20260509120000_add_chat_message_queue_status/migration.sql`:
- Around line 1-13: The migration fails on fresh DB because it alters
"platform"."ChatMessage" before ensuring the platform schema exists; update
migration.sql to first create the schema if it doesn't exist (e.g., run a CREATE
SCHEMA IF NOT EXISTS "platform" or equivalent) before the ALTER TABLE
"platform"."ChatMessage" statement and before creating the
"ChatMessage_queue_dispatch_idx" index so both the table alteration and index
creation succeed on an empty DB.
---
Outside diff comments:
In `@autogpt_platform/backend/backend/util/settings.py`:
- Around line 177-202: Add a Pydantic root validator to enforce that
max_running_copilot_turns_per_user <= max_concurrent_copilot_turns_per_user at
model validation time: in the Settings class (where
max_concurrent_copilot_turns_per_user and max_running_copilot_turns_per_user are
defined) implement a `@root_validator`(pre=False) that reads both fields and
raises a ValueError with a clear message if max_running_copilot_turns_per_user
is greater than max_concurrent_copilot_turns_per_user so misconfigured ops
settings are rejected during startup.
🪄 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: 0f457917-b25c-4b61-9ba5-76b4995a1bd3
📒 Files selected for processing (10)
autogpt_platform/backend/backend/api/features/chat/routes.pyautogpt_platform/backend/backend/copilot/active_turns.pyautogpt_platform/backend/backend/copilot/model.pyautogpt_platform/backend/backend/copilot/stream_registry.pyautogpt_platform/backend/backend/copilot/turn_queue.pyautogpt_platform/backend/backend/copilot/turn_queue_test.pyautogpt_platform/backend/backend/executor/billing.pyautogpt_platform/backend/backend/util/settings.pyautogpt_platform/backend/migrations/20260509120000_add_chat_message_queue_status/migration.sqlautogpt_platform/backend/schema.prisma
📜 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). (1)
- GitHub Check: Seer Code Review
🧰 Additional context used
📓 Path-based instructions (6)
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: Usepoetry run ...command for executing Python package dependencies
Use top-level imports only — avoid 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 are acceptable for sibling modules within the same package; avoid double-dot relative imports
Do not use duck typing — avoidhasattr/getattr/isinstancefor 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%sfor deferred interpolation indebuglog statements for efficiency; use f-strings elsewhere for readability (e.g.,logger.debug("Processing %s items", count)vslogger.info(f"Processing {count} items"))
Sanitize error paths by usingos.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
Usetransaction=Truefor Redis pipelines to ensure atomicity on multi-step 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 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/executor/billing.pyautogpt_platform/backend/backend/copilot/stream_registry.pyautogpt_platform/backend/backend/copilot/model.pyautogpt_platform/backend/backend/copilot/turn_queue_test.pyautogpt_platform/backend/backend/copilot/turn_queue.pyautogpt_platform/backend/backend/api/features/chat/routes.pyautogpt_platform/backend/backend/util/settings.pyautogpt_platform/backend/backend/copilot/active_turns.py
autogpt_platform/{backend,autogpt_libs}/**/*.py
📄 CodeRabbit inference engine (AGENTS.md)
Format Python code with
poetry run format
Files:
autogpt_platform/backend/backend/executor/billing.pyautogpt_platform/backend/backend/copilot/stream_registry.pyautogpt_platform/backend/backend/copilot/model.pyautogpt_platform/backend/backend/copilot/turn_queue_test.pyautogpt_platform/backend/backend/copilot/turn_queue.pyautogpt_platform/backend/backend/api/features/chat/routes.pyautogpt_platform/backend/backend/util/settings.pyautogpt_platform/backend/backend/copilot/active_turns.py
autogpt_platform/backend/**/*_test.py
📄 CodeRabbit inference engine (autogpt_platform/backend/AGENTS.md)
autogpt_platform/backend/**/*_test.py: Use pytest with snapshot testing for API responses
Colocate test files with source files using*_test.pynaming convention
Mock at boundaries — mock where the symbol is used, not where it's defined; after refactoring, update mock targets to match new module paths
UseAsyncMockfromunittest.mockfor async functions in tests
When writing tests, use Test-Driven Development (TDD): write failing tests marked with@pytest.mark.xfailbefore implementation, then remove the marker once the implementation is complete
When creating snapshots in tests, usepoetry run pytest path/to/test.py --snapshot-update; always review snapshot changes withgit diffbefore committing
Files:
autogpt_platform/backend/backend/copilot/turn_queue_test.py
autogpt_platform/backend/schema.prisma
📄 CodeRabbit inference engine (.github/copilot-instructions.md)
Run database migrations with 'poetry run prisma migrate dev' and 'poetry run prisma generate' after schema changes in backend
Files:
autogpt_platform/backend/schema.prisma
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: UseSecurity()instead ofDepends()for authentication dependencies to get proper OpenAPI security specification
Follow SSE (Server-Sent Events) protocol: usedata:lines for frontend-parsed events (must match Zod schema) and: commentlines for heartbeats/status
Files:
autogpt_platform/backend/backend/api/features/chat/routes.py
🧠 Learnings (10)
📚 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/migrations/20260509120000_add_chat_message_queue_status/migration.sqlautogpt_platform/backend/backend/executor/billing.pyautogpt_platform/backend/backend/copilot/stream_registry.pyautogpt_platform/backend/backend/copilot/model.pyautogpt_platform/backend/backend/copilot/turn_queue_test.pyautogpt_platform/backend/backend/copilot/turn_queue.pyautogpt_platform/backend/schema.prismaautogpt_platform/backend/backend/api/features/chat/routes.pyautogpt_platform/backend/backend/util/settings.pyautogpt_platform/backend/backend/copilot/active_turns.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/executor/billing.pyautogpt_platform/backend/backend/copilot/stream_registry.pyautogpt_platform/backend/backend/copilot/model.pyautogpt_platform/backend/backend/copilot/turn_queue_test.pyautogpt_platform/backend/backend/copilot/turn_queue.pyautogpt_platform/backend/backend/api/features/chat/routes.pyautogpt_platform/backend/backend/util/settings.pyautogpt_platform/backend/backend/copilot/active_turns.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/executor/billing.pyautogpt_platform/backend/backend/copilot/stream_registry.pyautogpt_platform/backend/backend/copilot/model.pyautogpt_platform/backend/backend/copilot/turn_queue_test.pyautogpt_platform/backend/backend/copilot/turn_queue.pyautogpt_platform/backend/backend/api/features/chat/routes.pyautogpt_platform/backend/backend/util/settings.pyautogpt_platform/backend/backend/copilot/active_turns.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/executor/billing.pyautogpt_platform/backend/backend/copilot/stream_registry.pyautogpt_platform/backend/backend/copilot/model.pyautogpt_platform/backend/backend/copilot/turn_queue_test.pyautogpt_platform/backend/backend/copilot/turn_queue.pyautogpt_platform/backend/backend/api/features/chat/routes.pyautogpt_platform/backend/backend/util/settings.pyautogpt_platform/backend/backend/copilot/active_turns.py
📚 Learning: 2026-04-15T02:43:36.890Z
Learnt from: ntindle
Repo: Significant-Gravitas/AutoGPT PR: 12780
File: autogpt_platform/backend/backend/copilot/tools/workspace_files.py:0-0
Timestamp: 2026-04-15T02:43:36.890Z
Learning: When reviewing Python exception handlers, do not flag `isinstance(e, X)` checks as dead/unreachable if the caught exception `X` is a subclass of the exception type being handled. For example, if `X` (e.g., `VirusScanError`) inherits from `ValueError` (directly or via an intermediate class) and it can be raised within an `except ValueError:` block, then `isinstance(e, X)` inside that handler is reachable and should not be treated as dead code.
Applied to files:
autogpt_platform/backend/backend/executor/billing.pyautogpt_platform/backend/backend/copilot/stream_registry.pyautogpt_platform/backend/backend/copilot/model.pyautogpt_platform/backend/backend/copilot/turn_queue_test.pyautogpt_platform/backend/backend/copilot/turn_queue.pyautogpt_platform/backend/backend/api/features/chat/routes.pyautogpt_platform/backend/backend/util/settings.pyautogpt_platform/backend/backend/copilot/active_turns.py
📚 Learning: 2026-04-22T11:46:04.431Z
Learnt from: majdyz
Repo: Significant-Gravitas/AutoGPT PR: 12881
File: autogpt_platform/backend/backend/copilot/config.py:0-0
Timestamp: 2026-04-22T11:46:04.431Z
Learning: Do not flag the Claude Sonnet 4.6 model ID as incorrect when it uses the project’s established hyphenated convention: `anthropic/claude-sonnet-4-6`. This hyphen form is the intentional, production convention and should be treated as valid (including in files like llm.py, blocks tests, reasoning.py, `_is_anthropic_model` tests, and config defaults). Note that OpenRouter also accepts the dot variant `anthropic/claude-sonnet-4.6`, so either form may be tolerated, but `anthropic/claude-sonnet-4-6` should be considered the standard to match project usage.
Applied to files:
autogpt_platform/backend/backend/executor/billing.pyautogpt_platform/backend/backend/copilot/stream_registry.pyautogpt_platform/backend/backend/copilot/model.pyautogpt_platform/backend/backend/copilot/turn_queue_test.pyautogpt_platform/backend/backend/copilot/turn_queue.pyautogpt_platform/backend/backend/api/features/chat/routes.pyautogpt_platform/backend/backend/util/settings.pyautogpt_platform/backend/backend/copilot/active_turns.py
📚 Learning: 2026-04-22T11:46:12.892Z
Learnt from: majdyz
Repo: Significant-Gravitas/AutoGPT PR: 12881
File: autogpt_platform/backend/backend/copilot/baseline/service.py:322-332
Timestamp: 2026-04-22T11:46:12.892Z
Learning: In this codebase (Significant-Gravitas/AutoGPT), OpenRouter-routed Anthropic model IDs should use the hyphen-separated convention (e.g., `anthropic/claude-sonnet-4-6`, `anthropic/claude-opus-4-6`). Although OpenRouter may accept both hyphen and dot variants, treat the hyphen-separated form as the intended, correct codebase-wide convention and do not flag it as an error. Only flag the dot-separated variant (e.g., `anthropic/claude-sonnet-4.6`) as incorrect when reviewing/validating model ID strings for OpenRouter-routed Anthropic models.
Applied to files:
autogpt_platform/backend/backend/executor/billing.pyautogpt_platform/backend/backend/copilot/stream_registry.pyautogpt_platform/backend/backend/copilot/model.pyautogpt_platform/backend/backend/copilot/turn_queue_test.pyautogpt_platform/backend/backend/copilot/turn_queue.pyautogpt_platform/backend/backend/api/features/chat/routes.pyautogpt_platform/backend/backend/util/settings.pyautogpt_platform/backend/backend/copilot/active_turns.py
📚 Learning: 2026-05-07T18:48:14.242Z
Learnt from: majdyz
Repo: Significant-Gravitas/AutoGPT PR: 13040
File: autogpt_platform/backend/backend/blocks/llm.py:0-0
Timestamp: 2026-05-07T18:48:14.242Z
Learning: In this repository, isort may split imports from the same module into separate blocks when some imports are aliased (e.g., `from module import X as Y`) and others are not. Preserve the two-block layout when it results from isort (such as keeping `from openai.types.chat import ChatCompletion as OpenAIChatCompletion` separate from non-aliased imports from `openai.types.chat`). Do not treat that split as a style issue during review; merging them into a single block can fail CI with `Imports are incorrectly sorted and/or formatted`.
Applied to files:
autogpt_platform/backend/backend/executor/billing.pyautogpt_platform/backend/backend/copilot/stream_registry.pyautogpt_platform/backend/backend/copilot/model.pyautogpt_platform/backend/backend/copilot/turn_queue_test.pyautogpt_platform/backend/backend/copilot/turn_queue.pyautogpt_platform/backend/backend/api/features/chat/routes.pyautogpt_platform/backend/backend/util/settings.pyautogpt_platform/backend/backend/copilot/active_turns.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.pyautogpt_platform/backend/backend/copilot/model.pyautogpt_platform/backend/backend/copilot/turn_queue_test.pyautogpt_platform/backend/backend/copilot/turn_queue.pyautogpt_platform/backend/backend/copilot/active_turns.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.pyautogpt_platform/backend/backend/copilot/model.pyautogpt_platform/backend/backend/copilot/turn_queue_test.pyautogpt_platform/backend/backend/copilot/turn_queue.pyautogpt_platform/backend/backend/copilot/active_turns.py
🪛 GitHub Actions: AutoGPT Platform - Backend CI / 3_test (3.11).txt
autogpt_platform/backend/schema.prisma
[error] 1-1: Prisma migrate deploy failed with error P3018. Migration 20260509120000_add_chat_message_queue_status could not be applied because the PostgreSQL schema "platform" does not exist (Database error code: 3F000; ERROR: schema "platform" does not exist; detail from Postgres namespace.c line 3096).
🪛 GitHub Actions: AutoGPT Platform - Backend CI / 6_lint.txt
autogpt_platform/backend/backend/copilot/turn_queue_test.py
[error] 11-12: Imports are incorrectly sorted and/or formatted (linting failure). Lint tool reported a formatting/sorting diff near a removed blank line after 'from backend.copilot import turn_queue'.
🪛 GitHub Actions: AutoGPT Platform - Backend CI / lint
autogpt_platform/backend/backend/copilot/turn_queue_test.py
[error] 11-11: Lint failed: file has incorrectly sorted and/or formatted imports (isort/ruff formatting).
🔇 Additional comments (1)
autogpt_platform/backend/backend/executor/billing.py (1)
27-27: Import cleanup looks correct.
discord_send_alertremoval is safe here, and keepingDiscordChannelis required by its usages in the alert paths.
Two concurrent submits to the same chat session could race on get_next_sequence (a SELECT MAX + 1) and PK-collide on (sessionId, sequence) because enqueue_turn was bypassing the Redis NX session lock that append_and_save_message uses for exactly this reason. Take the lock + re-fetch the sequence inside it, matching the existing ordering guarantee. Drop the sequence parameter on enqueue_turn since the caller's pre-fetch is now redundant (authoritative value is whatever the lock holder sees).
There was a problem hiding this comment.
Actionable comments posted: 2
🧹 Nitpick comments (1)
autogpt_platform/frontend/src/app/(platform)/copilot/components/ChatMessagesContainer/components/QueueBadge.tsx (1)
40-54: 💤 Low valueConsider deduplicating session query invalidation logic.
Both the 204 and 404 branches conditionally invalidate the session query with identical logic (lines 40-44 and 50-54). Extract into a helper or unconditionally invalidate after the status checks to reduce duplication.
♻️ Optional refactor
onSuccess: (response) => { + const shouldInvalidateSession = response.status === 204 || response.status === 404; + if (response.status === 204) { - if (sessionID) { - queryClient.invalidateQueries({ - queryKey: getGetV2GetSessionQueryKey(sessionID), - }); - } queryClient.invalidateQueries({ queryKey: ["/api/chat/queued-tasks"], }); - } else if (response.status === 404) { - // Already promoted / not owned — refetch to sync UI with reality. - if (sessionID) { - queryClient.invalidateQueries({ - queryKey: getGetV2GetSessionQueryKey(sessionID), - }); - } } + + if (shouldInvalidateSession && sessionID) { + queryClient.invalidateQueries({ + queryKey: getGetV2GetSessionQueryKey(sessionID), + }); + } },🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@autogpt_platform/frontend/src/app/`(platform)/copilot/components/ChatMessagesContainer/components/QueueBadge.tsx around lines 40 - 54, Duplicate conditional invalidation of the session query appears in the 204 and 404 response branches in QueueBadge.tsx; consolidate by extracting the logic that calls queryClient.invalidateQueries({ queryKey: getGetV2GetSessionQueryKey(sessionID) }) into a small helper (e.g., invalidateSessionIfPresent(sessionID)) or by moving a single conditional invalidate after the response.status checks so you only call queryClient.invalidateQueries once; update uses in both branches to call the helper (or remove the branch-specific calls) and keep the call to queryClient.invalidateQueries({ queryKey: ["/api/chat/queued-tasks"] }) where appropriate.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In
`@autogpt_platform/frontend/src/app/`(platform)/copilot/components/ChatMessagesContainer/components/__tests__/QueueBadge.test.tsx:
- Around line 32-33: Remove the redundant cleanup() call from the test file's
afterEach block (the afterEach wrapper calling cleanup); testing-library/react
cleanup is already run globally so simply delete that afterEach(...) or its
cleanup() invocation and only add a local afterEach teardown when you need to
restore resources not handled globally (e.g., clear/fake timers with
vi.useFakeTimers()/vi.restoreAllMocks() or vi.clearAllTimers()).
In
`@autogpt_platform/frontend/src/app/`(platform)/copilot/components/ChatMessagesContainer/components/QueueBadge.tsx:
- Line 14: In QueueBadge (QueueBadge.tsx) replace the deprecated bare Phosphor
imports with the -Icon suffixed aliases: change imports of Hourglass,
WarningCircle, and XCircle from "@phosphor-icons/react" to HourglassIcon,
WarningCircleIcon, and XCircleIcon respectively, and update all JSX usages of
<Hourglass>, <WarningCircle>, and <XCircle> to <HourglassIcon>,
<WarningCircleIcon>, and <XCircleIcon> (retain the same props/attributes).
---
Nitpick comments:
In
`@autogpt_platform/frontend/src/app/`(platform)/copilot/components/ChatMessagesContainer/components/QueueBadge.tsx:
- Around line 40-54: Duplicate conditional invalidation of the session query
appears in the 204 and 404 response branches in QueueBadge.tsx; consolidate by
extracting the logic that calls queryClient.invalidateQueries({ queryKey:
getGetV2GetSessionQueryKey(sessionID) }) into a small helper (e.g.,
invalidateSessionIfPresent(sessionID)) or by moving a single conditional
invalidate after the response.status checks so you only call
queryClient.invalidateQueries once; update uses in both branches to call the
helper (or remove the branch-specific calls) and keep the call to
queryClient.invalidateQueries({ queryKey: ["/api/chat/queued-tasks"] }) where
appropriate.
🪄 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: 1a45a47b-fcf0-4bde-a2f7-3acd405ff02d
📒 Files selected for processing (9)
autogpt_platform/backend/backend/api/features/chat/routes.pyautogpt_platform/backend/backend/copilot/turn_queue.pyautogpt_platform/backend/backend/copilot/turn_queue_test.pyautogpt_platform/frontend/src/app/(platform)/copilot/components/ChatMessagesContainer/ChatMessagesContainer.tsxautogpt_platform/frontend/src/app/(platform)/copilot/components/ChatMessagesContainer/__tests__/ChatMessagesContainer.test.tsxautogpt_platform/frontend/src/app/(platform)/copilot/components/ChatMessagesContainer/components/QueueBadge.tsxautogpt_platform/frontend/src/app/(platform)/copilot/components/ChatMessagesContainer/components/__tests__/QueueBadge.test.tsxautogpt_platform/frontend/src/app/(platform)/copilot/helpers/__tests__/convertChatSessionToUiMessages.test.tsautogpt_platform/frontend/src/app/(platform)/copilot/helpers/convertChatSessionToUiMessages.ts
✅ Files skipped from review due to trivial changes (1)
- autogpt_platform/backend/backend/copilot/turn_queue_test.py
🚧 Files skipped from review as they are similar to previous changes (2)
- autogpt_platform/backend/backend/api/features/chat/routes.py
- autogpt_platform/backend/backend/copilot/turn_queue.py
📜 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). (9)
- GitHub Check: check API types
- GitHub Check: integration_test
- GitHub Check: end-to-end tests
- GitHub Check: Seer Code Review
- GitHub Check: test (3.11)
- GitHub Check: test (3.13)
- GitHub Check: test (3.12)
- GitHub Check: Check PR Status
- GitHub Check: Analyze (python)
🧰 Additional context used
📓 Path-based instructions (16)
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 developmentFormat frontend code using
pnpm format
autogpt_platform/frontend/**/*.{ts,tsx,js,jsx}: Fully capitalize acronyms in symbols, e.g.graphID,useBackendAPI
No linter suppressors (//@ts-ignore``,// eslint-disable) — fix the actual issue
Files:
autogpt_platform/frontend/src/app/(platform)/copilot/components/ChatMessagesContainer/components/__tests__/QueueBadge.test.tsxautogpt_platform/frontend/src/app/(platform)/copilot/components/ChatMessagesContainer/__tests__/ChatMessagesContainer.test.tsxautogpt_platform/frontend/src/app/(platform)/copilot/helpers/convertChatSessionToUiMessages.tsautogpt_platform/frontend/src/app/(platform)/copilot/components/ChatMessagesContainer/ChatMessagesContainer.tsxautogpt_platform/frontend/src/app/(platform)/copilot/components/ChatMessagesContainer/components/QueueBadge.tsxautogpt_platform/frontend/src/app/(platform)/copilot/helpers/__tests__/convertChatSessionToUiMessages.test.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/ChatMessagesContainer/components/__tests__/QueueBadge.test.tsxautogpt_platform/frontend/src/app/(platform)/copilot/components/ChatMessagesContainer/__tests__/ChatMessagesContainer.test.tsxautogpt_platform/frontend/src/app/(platform)/copilot/helpers/convertChatSessionToUiMessages.tsautogpt_platform/frontend/src/app/(platform)/copilot/components/ChatMessagesContainer/ChatMessagesContainer.tsxautogpt_platform/frontend/src/app/(platform)/copilot/components/ChatMessagesContainer/components/QueueBadge.tsxautogpt_platform/frontend/src/app/(platform)/copilot/helpers/__tests__/convertChatSessionToUiMessages.test.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}: Use function declarations (not arrow functions) for components/handlers
Noanytypes unless the value genuinely can be anything
Keep render functions and hooks under ~50 lines; extract named helpers or sub-components when they grow longer
Files:
autogpt_platform/frontend/src/app/(platform)/copilot/components/ChatMessagesContainer/components/__tests__/QueueBadge.test.tsxautogpt_platform/frontend/src/app/(platform)/copilot/components/ChatMessagesContainer/__tests__/ChatMessagesContainer.test.tsxautogpt_platform/frontend/src/app/(platform)/copilot/helpers/convertChatSessionToUiMessages.tsautogpt_platform/frontend/src/app/(platform)/copilot/components/ChatMessagesContainer/ChatMessagesContainer.tsxautogpt_platform/frontend/src/app/(platform)/copilot/components/ChatMessagesContainer/components/QueueBadge.tsxautogpt_platform/frontend/src/app/(platform)/copilot/helpers/__tests__/convertChatSessionToUiMessages.test.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 patternuse{Method}{Version}{OperationName}, and regenerate withpnpm 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/componentsfolder
Use function declarations for components and handlers, use arrow functions only for callbacks
Do not useuseCallbackoruseMemounless asked to optimise a given function
autogpt_platform/frontend/src/**/*.{ts,tsx}: Keep files under ~200 lines; extract sub-components or hooks into their own files when a file grows beyond this
Use generated API hooks from@/app/api/__generated__/endpoints/with patternuse{Method}{Version}{OperationName}
Always import the-Icon-suffixed alias from@phosphor-icons/react(e.g.TrashIcon,PlusIcon,SquareIcon) — bare exports are deprecated
Do not useuseCallbackoruseMemounless asked to optimize a given function
Never usesrc/components/__legacy__/*— use design system components fromsrc/components/
Files:
autogpt_platform/frontend/src/app/(platform)/copilot/components/ChatMessagesContainer/components/__tests__/QueueBadge.test.tsxautogpt_platform/frontend/src/app/(platform)/copilot/components/ChatMessagesContainer/__tests__/ChatMessagesContainer.test.tsxautogpt_platform/frontend/src/app/(platform)/copilot/helpers/convertChatSessionToUiMessages.tsautogpt_platform/frontend/src/app/(platform)/copilot/components/ChatMessagesContainer/ChatMessagesContainer.tsxautogpt_platform/frontend/src/app/(platform)/copilot/components/ChatMessagesContainer/components/QueueBadge.tsxautogpt_platform/frontend/src/app/(platform)/copilot/helpers/__tests__/convertChatSessionToUiMessages.test.ts
autogpt_platform/frontend/**/*.{tsx,css}
📄 CodeRabbit inference engine (AGENTS.md)
Use Tailwind CSS only for styling, use design tokens, and use Phosphor Icons only
Files:
autogpt_platform/frontend/src/app/(platform)/copilot/components/ChatMessagesContainer/components/__tests__/QueueBadge.test.tsxautogpt_platform/frontend/src/app/(platform)/copilot/components/ChatMessagesContainer/__tests__/ChatMessagesContainer.test.tsxautogpt_platform/frontend/src/app/(platform)/copilot/components/ChatMessagesContainer/ChatMessagesContainer.tsxautogpt_platform/frontend/src/app/(platform)/copilot/components/ChatMessagesContainer/components/QueueBadge.tsx
autogpt_platform/frontend/src/**/*.tsx
📄 CodeRabbit inference engine (AGENTS.md)
Component props should use
interface Props { ... }(not exported) unless the interface needs to be used outside the component
Files:
autogpt_platform/frontend/src/app/(platform)/copilot/components/ChatMessagesContainer/components/__tests__/QueueBadge.test.tsxautogpt_platform/frontend/src/app/(platform)/copilot/components/ChatMessagesContainer/__tests__/ChatMessagesContainer.test.tsxautogpt_platform/frontend/src/app/(platform)/copilot/components/ChatMessagesContainer/ChatMessagesContainer.tsxautogpt_platform/frontend/src/app/(platform)/copilot/components/ChatMessagesContainer/components/QueueBadge.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/ChatMessagesContainer/components/__tests__/QueueBadge.test.tsxautogpt_platform/frontend/src/app/(platform)/copilot/components/ChatMessagesContainer/__tests__/ChatMessagesContainer.test.tsxautogpt_platform/frontend/src/app/(platform)/copilot/helpers/convertChatSessionToUiMessages.tsautogpt_platform/frontend/src/app/(platform)/copilot/components/ChatMessagesContainer/ChatMessagesContainer.tsxautogpt_platform/frontend/src/app/(platform)/copilot/components/ChatMessagesContainer/components/QueueBadge.tsxautogpt_platform/frontend/src/app/(platform)/copilot/helpers/__tests__/convertChatSessionToUiMessages.test.ts
autogpt_platform/frontend/**/*.{test,spec}.{ts,tsx}
📄 CodeRabbit inference engine (AGENTS.md)
autogpt_platform/frontend/**/*.{test,spec}.{ts,tsx}: Use Vitest + RTL + MSW for integration tests as the primary testing approach (~90%, page-level), use Playwright for E2E critical flows, and use Storybook for design system components
Run frontend integration tests withpnpm test:unit(Vitest + RTL + MSW)
Files:
autogpt_platform/frontend/src/app/(platform)/copilot/components/ChatMessagesContainer/components/__tests__/QueueBadge.test.tsxautogpt_platform/frontend/src/app/(platform)/copilot/components/ChatMessagesContainer/__tests__/ChatMessagesContainer.test.tsxautogpt_platform/frontend/src/app/(platform)/copilot/helpers/__tests__/convertChatSessionToUiMessages.test.ts
autogpt_platform/frontend/**/*.{tsx,jsx}
📄 CodeRabbit inference engine (autogpt_platform/frontend/AGENTS.md)
autogpt_platform/frontend/**/*.{tsx,jsx}: Nodark:Tailwind classes — the design system handles dark mode
Use Next.js<Link>for internal navigation — never raw<a>tags
Use Tailwind CSS only for styling with design tokens and Phosphor Icons only
Files:
autogpt_platform/frontend/src/app/(platform)/copilot/components/ChatMessagesContainer/components/__tests__/QueueBadge.test.tsxautogpt_platform/frontend/src/app/(platform)/copilot/components/ChatMessagesContainer/__tests__/ChatMessagesContainer.test.tsxautogpt_platform/frontend/src/app/(platform)/copilot/components/ChatMessagesContainer/ChatMessagesContainer.tsxautogpt_platform/frontend/src/app/(platform)/copilot/components/ChatMessagesContainer/components/QueueBadge.tsx
autogpt_platform/frontend/src/**/components/**/*.{tsx,jsx}
📄 CodeRabbit inference engine (autogpt_platform/frontend/AGENTS.md)
Put sub-components in local
components/folder; component props should betype Props = { ... }(not exported) unless used outside the component
Files:
autogpt_platform/frontend/src/app/(platform)/copilot/components/ChatMessagesContainer/components/__tests__/QueueBadge.test.tsxautogpt_platform/frontend/src/app/(platform)/copilot/components/ChatMessagesContainer/__tests__/ChatMessagesContainer.test.tsxautogpt_platform/frontend/src/app/(platform)/copilot/components/ChatMessagesContainer/ChatMessagesContainer.tsxautogpt_platform/frontend/src/app/(platform)/copilot/components/ChatMessagesContainer/components/QueueBadge.tsx
autogpt_platform/frontend/src/**/components/**/*.{ts,tsx}
📄 CodeRabbit inference engine (autogpt_platform/frontend/AGENTS.md)
Structure components as
ComponentName/ComponentName.tsx+useComponentName.ts+helpers.ts
Files:
autogpt_platform/frontend/src/app/(platform)/copilot/components/ChatMessagesContainer/components/__tests__/QueueBadge.test.tsxautogpt_platform/frontend/src/app/(platform)/copilot/components/ChatMessagesContainer/__tests__/ChatMessagesContainer.test.tsxautogpt_platform/frontend/src/app/(platform)/copilot/components/ChatMessagesContainer/ChatMessagesContainer.tsxautogpt_platform/frontend/src/app/(platform)/copilot/components/ChatMessagesContainer/components/QueueBadge.tsx
autogpt_platform/frontend/src/app/**/__tests__/**/*.{test,spec}.{ts,tsx}
📄 CodeRabbit inference engine (autogpt_platform/frontend/AGENTS.md)
Write integration tests in
__tests__/next topage.tsxusing Vitest + RTL + MSW for new pages/features
Files:
autogpt_platform/frontend/src/app/(platform)/copilot/components/ChatMessagesContainer/components/__tests__/QueueBadge.test.tsxautogpt_platform/frontend/src/app/(platform)/copilot/components/ChatMessagesContainer/__tests__/ChatMessagesContainer.test.tsxautogpt_platform/frontend/src/app/(platform)/copilot/helpers/__tests__/convertChatSessionToUiMessages.test.ts
autogpt_platform/frontend/src/**/__tests__/**/*.{test,spec}.{ts,tsx}
📄 CodeRabbit inference engine (autogpt_platform/frontend/AGENTS.md)
Use Orval-generated MSW handlers from
@/app/api/__generated__/endpoints/{tag}/{tag}.msw.tsfor API mocking
Files:
autogpt_platform/frontend/src/app/(platform)/copilot/components/ChatMessagesContainer/components/__tests__/QueueBadge.test.tsxautogpt_platform/frontend/src/app/(platform)/copilot/components/ChatMessagesContainer/__tests__/ChatMessagesContainer.test.tsxautogpt_platform/frontend/src/app/(platform)/copilot/helpers/__tests__/convertChatSessionToUiMessages.test.ts
autogpt_platform/frontend/src/**/*.{ts,tsx,js,jsx}
📄 CodeRabbit inference engine (autogpt_platform/frontend/AGENTS.md)
Avoid index and barrel files
Files:
autogpt_platform/frontend/src/app/(platform)/copilot/components/ChatMessagesContainer/components/__tests__/QueueBadge.test.tsxautogpt_platform/frontend/src/app/(platform)/copilot/components/ChatMessagesContainer/__tests__/ChatMessagesContainer.test.tsxautogpt_platform/frontend/src/app/(platform)/copilot/helpers/convertChatSessionToUiMessages.tsautogpt_platform/frontend/src/app/(platform)/copilot/components/ChatMessagesContainer/ChatMessagesContainer.tsxautogpt_platform/frontend/src/app/(platform)/copilot/components/ChatMessagesContainer/components/QueueBadge.tsxautogpt_platform/frontend/src/app/(platform)/copilot/helpers/__tests__/convertChatSessionToUiMessages.test.ts
autogpt_platform/frontend/**/*.ts
📄 CodeRabbit inference engine (AGENTS.md)
No barrel files or
index.tsre-exports in the frontend
Files:
autogpt_platform/frontend/src/app/(platform)/copilot/helpers/convertChatSessionToUiMessages.tsautogpt_platform/frontend/src/app/(platform)/copilot/helpers/__tests__/convertChatSessionToUiMessages.test.ts
autogpt_platform/frontend/src/**/*.ts
📄 CodeRabbit inference engine (AGENTS.md)
Do not type hook returns, let Typescript infer as much as possible
autogpt_platform/frontend/src/**/*.ts: Extract component logic into custom hooks grouped by concern, not by component, with 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/helpers/convertChatSessionToUiMessages.tsautogpt_platform/frontend/src/app/(platform)/copilot/helpers/__tests__/convertChatSessionToUiMessages.test.ts
🧠 Learnings (11)
📚 Learning: 2026-02-27T10:45:49.499Z
Learnt from: majdyz
Repo: Significant-Gravitas/AutoGPT PR: 12213
File: autogpt_platform/frontend/src/app/(platform)/copilot/tools/RunMCPTool/helpers.tsx:23-24
Timestamp: 2026-02-27T10:45:49.499Z
Learning: Prefer using generated OpenAPI types from '@/app/api/__generated__/' for payloads defined in openapi.json (e.g., MCPToolsDiscoveredResponse, MCPToolOutputResponse). Use inline TypeScript interfaces only for payloads that are SSE-stream-only and not exposed via OpenAPI. Apply this pattern to frontend tool components (e.g., RunMCPTool) and related areas where similar SSE/openapi-discrepancies occur; avoid re-implementing types when a generated type is available.
Applied to files:
autogpt_platform/frontend/src/app/(platform)/copilot/components/ChatMessagesContainer/components/__tests__/QueueBadge.test.tsxautogpt_platform/frontend/src/app/(platform)/copilot/components/ChatMessagesContainer/__tests__/ChatMessagesContainer.test.tsxautogpt_platform/frontend/src/app/(platform)/copilot/components/ChatMessagesContainer/ChatMessagesContainer.tsxautogpt_platform/frontend/src/app/(platform)/copilot/components/ChatMessagesContainer/components/QueueBadge.tsx
📚 Learning: 2026-03-24T02:05:04.672Z
Learnt from: majdyz
Repo: Significant-Gravitas/AutoGPT PR: 12526
File: autogpt_platform/frontend/src/app/(platform)/copilot/CopilotPage.tsx:0-0
Timestamp: 2026-03-24T02:05:04.672Z
Learning: When gating React component logic on a React Query result (e.g., hooks like `useQuery` / `useGetV2GetCopilotUsage`), prefer destructuring and checking `isSuccess` (or aliasing it to a meaningful boolean like `isSuccess: hasUsage`) instead of relying on `!isLoading`. Reason: `isLoading` can be `false` in error/idle states where `data` may still be `undefined`, while `isSuccess` indicates the query completed successfully and `data` is populated.
Applied to files:
autogpt_platform/frontend/src/app/(platform)/copilot/components/ChatMessagesContainer/components/__tests__/QueueBadge.test.tsxautogpt_platform/frontend/src/app/(platform)/copilot/components/ChatMessagesContainer/__tests__/ChatMessagesContainer.test.tsxautogpt_platform/frontend/src/app/(platform)/copilot/components/ChatMessagesContainer/ChatMessagesContainer.tsxautogpt_platform/frontend/src/app/(platform)/copilot/components/ChatMessagesContainer/components/QueueBadge.tsx
📚 Learning: 2026-03-24T02:23:31.305Z
Learnt from: majdyz
Repo: Significant-Gravitas/AutoGPT PR: 12526
File: autogpt_platform/frontend/src/app/(platform)/copilot/components/RateLimitResetDialog/RateLimitResetDialog.tsx:0-0
Timestamp: 2026-03-24T02:23:31.305Z
Learning: In the Copilot platform UI code, follow the established Orval hook `onError` error-handling convention: first explicitly detect/handle `ApiError`, then read `error.response?.detail` (if present) as the primary message; if not available, fall back to `error.message`; and finally fall back to a generic string message. This convention should be used for generated Orval hooks even if the custom Orval mutator already maps details into `ApiError.message`, to keep consistency across hooks/components (e.g., `useCronSchedulerDialog.ts`, `useRunGraph.ts`, and rate-limit/reset flows).
Applied to files:
autogpt_platform/frontend/src/app/(platform)/copilot/components/ChatMessagesContainer/components/__tests__/QueueBadge.test.tsxautogpt_platform/frontend/src/app/(platform)/copilot/components/ChatMessagesContainer/__tests__/ChatMessagesContainer.test.tsxautogpt_platform/frontend/src/app/(platform)/copilot/helpers/convertChatSessionToUiMessages.tsautogpt_platform/frontend/src/app/(platform)/copilot/components/ChatMessagesContainer/ChatMessagesContainer.tsxautogpt_platform/frontend/src/app/(platform)/copilot/components/ChatMessagesContainer/components/QueueBadge.tsxautogpt_platform/frontend/src/app/(platform)/copilot/helpers/__tests__/convertChatSessionToUiMessages.test.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/ChatMessagesContainer/components/__tests__/QueueBadge.test.tsxautogpt_platform/frontend/src/app/(platform)/copilot/components/ChatMessagesContainer/__tests__/ChatMessagesContainer.test.tsxautogpt_platform/frontend/src/app/(platform)/copilot/components/ChatMessagesContainer/ChatMessagesContainer.tsxautogpt_platform/frontend/src/app/(platform)/copilot/components/ChatMessagesContainer/components/QueueBadge.tsx
📚 Learning: 2026-04-01T18:54:16.035Z
Learnt from: Bentlybro
Repo: Significant-Gravitas/AutoGPT PR: 12633
File: autogpt_platform/frontend/src/app/(platform)/library/components/AgentFilterMenu/AgentFilterMenu.tsx:3-10
Timestamp: 2026-04-01T18:54:16.035Z
Learning: In the frontend, the legacy Select component at `@/components/__legacy__/ui/select` is an intentional, codebase-wide visual-consistency pattern. During code reviews, do not flag or block PRs merely for continuing to use this legacy Select. If a migration to the newer design-system Select is desired, bundle it into a single dedicated cleanup/migration PR that updates all Select usages together (e.g., avoid piecemeal replacements).
Applied to files:
autogpt_platform/frontend/src/app/(platform)/copilot/components/ChatMessagesContainer/components/__tests__/QueueBadge.test.tsxautogpt_platform/frontend/src/app/(platform)/copilot/components/ChatMessagesContainer/__tests__/ChatMessagesContainer.test.tsxautogpt_platform/frontend/src/app/(platform)/copilot/helpers/convertChatSessionToUiMessages.tsautogpt_platform/frontend/src/app/(platform)/copilot/components/ChatMessagesContainer/ChatMessagesContainer.tsxautogpt_platform/frontend/src/app/(platform)/copilot/components/ChatMessagesContainer/components/QueueBadge.tsxautogpt_platform/frontend/src/app/(platform)/copilot/helpers/__tests__/convertChatSessionToUiMessages.test.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/components/ChatMessagesContainer/components/__tests__/QueueBadge.test.tsxautogpt_platform/frontend/src/app/(platform)/copilot/components/ChatMessagesContainer/__tests__/ChatMessagesContainer.test.tsxautogpt_platform/frontend/src/app/(platform)/copilot/helpers/convertChatSessionToUiMessages.tsautogpt_platform/frontend/src/app/(platform)/copilot/components/ChatMessagesContainer/ChatMessagesContainer.tsxautogpt_platform/frontend/src/app/(platform)/copilot/components/ChatMessagesContainer/components/QueueBadge.tsxautogpt_platform/frontend/src/app/(platform)/copilot/helpers/__tests__/convertChatSessionToUiMessages.test.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/ChatMessagesContainer/components/__tests__/QueueBadge.test.tsxautogpt_platform/frontend/src/app/(platform)/copilot/components/ChatMessagesContainer/__tests__/ChatMessagesContainer.test.tsxautogpt_platform/frontend/src/app/(platform)/copilot/helpers/convertChatSessionToUiMessages.tsautogpt_platform/frontend/src/app/(platform)/copilot/components/ChatMessagesContainer/ChatMessagesContainer.tsxautogpt_platform/frontend/src/app/(platform)/copilot/components/ChatMessagesContainer/components/QueueBadge.tsxautogpt_platform/frontend/src/app/(platform)/copilot/helpers/__tests__/convertChatSessionToUiMessages.test.ts
📚 Learning: 2026-04-13T13:11:07.445Z
Learnt from: 0ubbe
Repo: Significant-Gravitas/AutoGPT PR: 12764
File: autogpt_platform/frontend/src/app/(platform)/library/components/SitrepItem/SitrepItem.tsx:143-145
Timestamp: 2026-04-13T13:11:07.445Z
Learning: In `autogpt_platform/frontend`, do not flag direct interpolation of `executionID` UUID strings into URL query parameters (e.g., `activeItem=${executionID}` in JSX/Next links). If the value is a UUID string matching `[0-9a-f-]`, it contains no reserved URL characters, so additional `encodeURIComponent` or Next.js object-based `href` encoding is unnecessary. Only treat it as an encoding issue if the query-param value is not guaranteed to be UUID-formatted (i.e., may include characters outside `[0-9a-f-]`).
Applied to files:
autogpt_platform/frontend/src/app/(platform)/copilot/components/ChatMessagesContainer/components/__tests__/QueueBadge.test.tsxautogpt_platform/frontend/src/app/(platform)/copilot/components/ChatMessagesContainer/__tests__/ChatMessagesContainer.test.tsxautogpt_platform/frontend/src/app/(platform)/copilot/components/ChatMessagesContainer/ChatMessagesContainer.tsxautogpt_platform/frontend/src/app/(platform)/copilot/components/ChatMessagesContainer/components/QueueBadge.tsx
📚 Learning: 2026-04-15T22:49:06.896Z
Learnt from: ntindle
Repo: Significant-Gravitas/AutoGPT PR: 11235
File: autogpt_platform/frontend/src/app/(platform)/admin/diagnostics/components/ExecutionsTable.tsx:0-0
Timestamp: 2026-04-15T22:49:06.896Z
Learning: In the AutoGPT frontend (React Query + toast/ErrorCard patterns), do not require `Sentry.captureException` in React Query mutation `catch` blocks. React Query handles error propagation for mutation paths, so follow the established pattern: show toast notifications for mutation errors and use `ErrorCard` for render/fetch errors. Only add `Sentry.captureException` for truly manual/unexpected exception paths that are outside React Query’s control (e.g., standalone async utilities or event handlers not wired through React Query).
Applied to files:
autogpt_platform/frontend/src/app/(platform)/copilot/components/ChatMessagesContainer/components/__tests__/QueueBadge.test.tsxautogpt_platform/frontend/src/app/(platform)/copilot/components/ChatMessagesContainer/__tests__/ChatMessagesContainer.test.tsxautogpt_platform/frontend/src/app/(platform)/copilot/components/ChatMessagesContainer/ChatMessagesContainer.tsxautogpt_platform/frontend/src/app/(platform)/copilot/components/ChatMessagesContainer/components/QueueBadge.tsx
📚 Learning: 2026-04-20T13:17:39.951Z
Learnt from: 0ubbe
Repo: Significant-Gravitas/AutoGPT PR: 12854
File: autogpt_platform/frontend/src/app/(platform)/library/__tests__/briefing.test.tsx:84-84
Timestamp: 2026-04-20T13:17:39.951Z
Learning: In the AutoGPT frontend, `testing-library/react` cleanup is already handled globally after each test via `src/tests/integrations/vitest.setup.tsx`. Therefore, for integration test files under `__tests__/`, do NOT add redundant `afterEach(() => cleanup())`. Only add local `afterEach` teardown for resources that are not covered globally—specifically, when using fake timers, add `afterEach(() => vi.useRealTimers())` (or equivalent) to restore real timers and prevent cross-test interference.
Applied to files:
autogpt_platform/frontend/src/app/(platform)/copilot/components/ChatMessagesContainer/components/__tests__/QueueBadge.test.tsxautogpt_platform/frontend/src/app/(platform)/copilot/components/ChatMessagesContainer/__tests__/ChatMessagesContainer.test.tsx
📚 Learning: 2026-04-20T20:07:22.981Z
Learnt from: ntindle
Repo: Significant-Gravitas/AutoGPT PR: 11235
File: autogpt_platform/frontend/src/app/(platform)/admin/diagnostics/__tests__/ExecutionsTable.test.tsx:27-76
Timestamp: 2026-04-20T20:07:22.981Z
Learning: In this codebase, Orval-generated API modules under `src/app/api/__generated__/` are not committed to git and must be generated via `pnpm generate:api` (requires a running backend). In integration tests, it’s acceptable—and expected—to stub generated hooks/modules by mocking them with `vi.mock("@/app/api/__generated__/endpoints/{tag}/{tag}")`. Do not treat `vi.mock` of these generated hook modules as a violation of the MSW handler guideline, since the corresponding MSW handlers cannot be imported at test time when generated files are absent.
Applied to files:
autogpt_platform/frontend/src/app/(platform)/copilot/components/ChatMessagesContainer/components/__tests__/QueueBadge.test.tsxautogpt_platform/frontend/src/app/(platform)/copilot/components/ChatMessagesContainer/__tests__/ChatMessagesContainer.test.tsxautogpt_platform/frontend/src/app/(platform)/copilot/helpers/__tests__/convertChatSessionToUiMessages.test.ts
🔇 Additional comments (7)
autogpt_platform/frontend/src/app/(platform)/copilot/helpers/convertChatSessionToUiMessages.ts (3)
7-17: LGTM! Queue lifecycle fields are well-typed and documented.The new
TurnStatsfields (queueStatus,queueBlockedReason,rawMessageId) are properly nullable and include clear JSDoc explaining their purpose for rendering queue badges in the UI.
279-284: LGTM! Cancelled message filtering preserves audit trail while cleaning up UI.Filtering
queue_status: "cancelled"messages from the conversation view is the correct behavior—they remain in the DB for audit/logging, but don't clutter the chat after the user clicks cancel.
424-431: LGTM! Queue stats correctly scoped to user messages.Queue lifecycle fields (
queueStatus,queueBlockedReason,rawMessageId) are only populated for user-role messages, which matches the design—only user messages can be queued.autogpt_platform/frontend/src/app/(platform)/copilot/helpers/__tests__/convertChatSessionToUiMessages.test.ts (1)
388-466: LGTM! Comprehensive test coverage for queue lifecycle.The new test suite validates all queue states:
- Queued messages populate
queueStatusandrawMessageId- Blocked messages include
queueBlockedReason- Cancelled messages are filtered from the conversation view
- Normal messages leave queue fields null
autogpt_platform/frontend/src/app/(platform)/copilot/components/ChatMessagesContainer/ChatMessagesContainer.tsx (1)
565-585: LGTM! Clean QueueBadge integration for user messages.The conditional rendering correctly:
- Checks
queueStatusfromturnStatsusing an IIFE- Only renders for "queued" or "blocked" states
- Passes all required props (
queueStatus,queueBlockedReason,rawMessageId,sessionID)- Wraps in
MessageActionswithdata-testidfor test coverageautogpt_platform/frontend/src/app/(platform)/copilot/components/ChatMessagesContainer/__tests__/ChatMessagesContainer.test.tsx (1)
541-642: LGTM! Comprehensive test coverage for queue badge integration.The new test suite validates:
- Queued badge renders with correct
queueStatusandrawMessageIdattributes- Blocked badge includes
queueBlockedReason- No badge renders for normal (non-queued) user messages
The mock QueueBadge exposes props as data attributes for easy assertion.
autogpt_platform/frontend/src/app/(platform)/copilot/components/ChatMessagesContainer/components/QueueBadge.tsx (1)
38-55: Endpoint not found in OpenAPI spec.The
useDeleteV2CancelQueuedTaskhook references an endpoint that does not appear in the OpenAPI specification (autogpt_platform/frontend/src/app/api/openapi.json). No DELETE endpoint exists for canceling queued tasks. The test file mocks the response with{ status: number }, but without the actual endpoint definition or generated hook, the actual response shape cannot be verified. Add the endpoint to the OpenAPI spec and regenerate hooks withpnpm generate:apito ensure the response type is correctly typed.
OnboardingProvider in the integration test wrapper calls useToast(), so the partial mock that only exported `toast` was failing the suite with "No 'useToast' export is defined". Add the missing export.
- atomic try_enqueue_turn with optimistic post-insert recount + rollback closes the inflight-cap TOCTOU window from the route check + insert - mark_queued_turn_blocked guards on queueStatus='queued' so a parallel user cancel isn't silently overwritten with 'blocked' - count_inflight_turns counts queued first then running, biasing toward conservative over-count under burst load (cap never reads low) - enqueue_turn: drop unused user_id; route validates session ownership upstream - stream_registry: dispatch_next_for_user fires AFTER cluster + SDK stream lock cleanup so the promoted turn doesn't race stale locks - hoist uuid + datetime imports to module top - minor: clean up the awkward two-string concat in the paywall reason
There was a problem hiding this comment.
Actionable comments posted: 1
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@autogpt_platform/backend/backend/copilot/turn_queue.py`:
- Around line 244-277: Both cancel_queued_turn and mark_queued_turn_blocked
update queueStatus but do not call invalidate_session_cache, causing stale UI
state; fix cancel_queued_turn to obtain the affected sessionId (either accept
session_id as a parameter from the route or perform an update-then-read inside a
transaction that updates via ChatMessage.prisma().update_many / update and
returns the Session.id) and then call invalidate_session_cache(session_id) when
the update actually affected rows, and fix mark_queued_turn_blocked to read the
row after the update (or use an update that returns the Session.id) to get
sessionId and call invalidate_session_cache(session_id) whenever the update
changes queueStatus from STATUS_QUEUED to STATUS_BLOCKED; keep existing guard on
STATUS_QUEUED and only invalidate when updated_count > 0.
🪄 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: 82017b5f-b498-4227-911e-811a50e425ae
📒 Files selected for processing (4)
autogpt_platform/backend/backend/api/features/chat/routes.pyautogpt_platform/backend/backend/copilot/stream_registry.pyautogpt_platform/backend/backend/copilot/turn_queue.pyautogpt_platform/backend/backend/copilot/turn_queue_test.py
✅ Files skipped from review due to trivial changes (1)
- autogpt_platform/backend/backend/copilot/turn_queue_test.py
🚧 Files skipped from review as they are similar to previous changes (2)
- autogpt_platform/backend/backend/copilot/stream_registry.py
- autogpt_platform/backend/backend/api/features/chat/routes.py
📜 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: lint
- GitHub Check: integration_test
- GitHub Check: Seer Code Review
- GitHub Check: test (3.12)
- GitHub Check: type-check (3.13)
- GitHub Check: type-check (3.11)
- GitHub Check: test (3.11)
- GitHub Check: type-check (3.12)
- GitHub Check: test (3.13)
- GitHub Check: Analyze (python)
- GitHub Check: end-to-end tests
- GitHub Check: Analyze (typescript)
- GitHub Check: Check PR Status
🧰 Additional context used
📓 Path-based instructions (2)
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: Usepoetry run ...command for executing Python package dependencies
Use top-level imports only — avoid 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 are acceptable for sibling modules within the same package; avoid double-dot relative imports
Do not use duck typing — avoidhasattr/getattr/isinstancefor 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%sfor deferred interpolation indebuglog statements for efficiency; use f-strings elsewhere for readability (e.g.,logger.debug("Processing %s items", count)vslogger.info(f"Processing {count} items"))
Sanitize error paths by usingos.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
Usetransaction=Truefor Redis pipelines to ensure atomicity on multi-step 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 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/turn_queue.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/turn_queue.py
🧠 Learnings (10)
📚 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/turn_queue.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/turn_queue.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/turn_queue.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/turn_queue.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/turn_queue.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/turn_queue.py
📚 Learning: 2026-04-15T02:43:36.890Z
Learnt from: ntindle
Repo: Significant-Gravitas/AutoGPT PR: 12780
File: autogpt_platform/backend/backend/copilot/tools/workspace_files.py:0-0
Timestamp: 2026-04-15T02:43:36.890Z
Learning: When reviewing Python exception handlers, do not flag `isinstance(e, X)` checks as dead/unreachable if the caught exception `X` is a subclass of the exception type being handled. For example, if `X` (e.g., `VirusScanError`) inherits from `ValueError` (directly or via an intermediate class) and it can be raised within an `except ValueError:` block, then `isinstance(e, X)` inside that handler is reachable and should not be treated as dead code.
Applied to files:
autogpt_platform/backend/backend/copilot/turn_queue.py
📚 Learning: 2026-04-22T11:46:04.431Z
Learnt from: majdyz
Repo: Significant-Gravitas/AutoGPT PR: 12881
File: autogpt_platform/backend/backend/copilot/config.py:0-0
Timestamp: 2026-04-22T11:46:04.431Z
Learning: Do not flag the Claude Sonnet 4.6 model ID as incorrect when it uses the project’s established hyphenated convention: `anthropic/claude-sonnet-4-6`. This hyphen form is the intentional, production convention and should be treated as valid (including in files like llm.py, blocks tests, reasoning.py, `_is_anthropic_model` tests, and config defaults). Note that OpenRouter also accepts the dot variant `anthropic/claude-sonnet-4.6`, so either form may be tolerated, but `anthropic/claude-sonnet-4-6` should be considered the standard to match project usage.
Applied to files:
autogpt_platform/backend/backend/copilot/turn_queue.py
📚 Learning: 2026-04-22T11:46:12.892Z
Learnt from: majdyz
Repo: Significant-Gravitas/AutoGPT PR: 12881
File: autogpt_platform/backend/backend/copilot/baseline/service.py:322-332
Timestamp: 2026-04-22T11:46:12.892Z
Learning: In this codebase (Significant-Gravitas/AutoGPT), OpenRouter-routed Anthropic model IDs should use the hyphen-separated convention (e.g., `anthropic/claude-sonnet-4-6`, `anthropic/claude-opus-4-6`). Although OpenRouter may accept both hyphen and dot variants, treat the hyphen-separated form as the intended, correct codebase-wide convention and do not flag it as an error. Only flag the dot-separated variant (e.g., `anthropic/claude-sonnet-4.6`) as incorrect when reviewing/validating model ID strings for OpenRouter-routed Anthropic models.
Applied to files:
autogpt_platform/backend/backend/copilot/turn_queue.py
📚 Learning: 2026-05-07T18:48:14.242Z
Learnt from: majdyz
Repo: Significant-Gravitas/AutoGPT PR: 13040
File: autogpt_platform/backend/backend/blocks/llm.py:0-0
Timestamp: 2026-05-07T18:48:14.242Z
Learning: In this repository, isort may split imports from the same module into separate blocks when some imports are aliased (e.g., `from module import X as Y`) and others are not. Preserve the two-block layout when it results from isort (such as keeping `from openai.types.chat import ChatCompletion as OpenAIChatCompletion` separate from non-aliased imports from `openai.types.chat`). Do not treat that split as a style issue during review; merging them into a single block can fail CI with `Imports are incorrectly sorted and/or formatted`.
Applied to files:
autogpt_platform/backend/backend/copilot/turn_queue.py
… session-busy check - acquire_turn_slot accepts a `capacity` parameter; HTTP keeps the running cap (5) so it falls through to the queue, non-HTTP callers (schedule_turn / run_sub_session / AutoPilotBlock) pass the inflight cap (15) to preserve the prior #13064 behaviour - ConcurrentTurnLimitError default message now describes the running cap; the back-compat shim points at running_turn_limit_message so uncaught raises on non-HTTP paths surface the right number - dispatch_next_for_user skips queued heads whose session already has a running turn — otherwise acquire_turn_slot returns REFRESHED, two turns share a slot, and the first turn's release frees both - frontend QueueBadge: switch to `*Icon`-suffixed Phosphor imports; drop redundant testing-library cleanup() (already global)
…ueue migration Other ChatMessage migrations (20260115081736_add_chat_tables, 20260326120000_add_chat_message_duration_ms) target unqualified "ChatMessage", and 97c6516 explicitly removed the multiSchema / @@Schema("platform") pattern from this codebase. Keeping the prefix caused P3018 / "schema platform does not exist" on every test run.
There was a problem hiding this comment.
Actionable comments posted: 2
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@autogpt_platform/backend/backend/copilot/active_turns.py`:
- Around line 159-199: The current Redis-exception handling in
get_running_session_ids and count_running_turns collapses "unknown" into empty
results; change their error-path behavior to surface failure explicitly by
returning None instead of set() / 0 and update their type hints to
Optional[set[str]] and Optional[int] (and update the docstrings) so callers can
detect an unknown state; in the except block for
RedisError/RedisClusterException/ConnectionError/OSError, keep the
logger.warning with the exception details but return None, and then update the
dispatcher/queue code that calls get_running_session_ids and count_running_turns
to treat None as "unknown — skip promoting/adjust enforcing" rather than
treating it as zero.
In `@autogpt_platform/backend/backend/copilot/executor/utils.py`:
- Around line 330-332: The current use of acquire_turn_slot(user_id, session_id,
capacity=get_inflight_turn_limit()) only expands the running-slot budget and
ignores queued turns, so replace this admission logic with the same
running+queued check used by the chat route (or add an explicit check against
the user's running set + queued set in Redis) before entering acquire_turn_slot;
specifically, call the chat-route admission function (or replicate its Redis
queries) to compute current_running + current_queued and deny/schedule
accordingly, and only call acquire_turn_slot when that combined count is below
get_inflight_turn_limit(); update schedule_turn and any non-HTTP callers to use
this same admission check to enforce the global per-user hard cap.
🪄 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: 0a96ce93-0e0a-407e-ae1b-8a8b8d72bbed
📒 Files selected for processing (5)
autogpt_platform/backend/backend/copilot/active_turns.pyautogpt_platform/backend/backend/copilot/executor/utils.pyautogpt_platform/backend/backend/copilot/turn_queue.pyautogpt_platform/frontend/src/app/(platform)/copilot/components/ChatMessagesContainer/components/QueueBadge.tsxautogpt_platform/frontend/src/app/(platform)/copilot/components/ChatMessagesContainer/components/__tests__/QueueBadge.test.tsx
🚧 Files skipped from review as they are similar to previous changes (3)
- autogpt_platform/frontend/src/app/(platform)/copilot/components/ChatMessagesContainer/components/tests/QueueBadge.test.tsx
- autogpt_platform/frontend/src/app/(platform)/copilot/components/ChatMessagesContainer/components/QueueBadge.tsx
- autogpt_platform/backend/backend/copilot/turn_queue.py
📜 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: integration_test
- GitHub Check: lint
- GitHub Check: check API types
- GitHub Check: Seer Code Review
- GitHub Check: end-to-end tests
- GitHub Check: Analyze (typescript)
- GitHub Check: type-check (3.13)
- GitHub Check: Analyze (python)
- GitHub Check: test (3.11)
- GitHub Check: type-check (3.12)
- GitHub Check: test (3.12)
- GitHub Check: type-check (3.11)
- GitHub Check: test (3.13)
- GitHub Check: Check PR Status
🧰 Additional context used
📓 Path-based instructions (2)
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: Usepoetry run ...command for executing Python package dependencies
Use top-level imports only — avoid 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 are acceptable for sibling modules within the same package; avoid double-dot relative imports
Do not use duck typing — avoidhasattr/getattr/isinstancefor 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%sfor deferred interpolation indebuglog statements for efficiency; use f-strings elsewhere for readability (e.g.,logger.debug("Processing %s items", count)vslogger.info(f"Processing {count} items"))
Sanitize error paths by usingos.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
Usetransaction=Truefor Redis pipelines to ensure atomicity on multi-step 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 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/executor/utils.pyautogpt_platform/backend/backend/copilot/active_turns.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/executor/utils.pyautogpt_platform/backend/backend/copilot/active_turns.py
🧠 Learnings (10)
📚 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/executor/utils.pyautogpt_platform/backend/backend/copilot/active_turns.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/executor/utils.pyautogpt_platform/backend/backend/copilot/active_turns.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/executor/utils.pyautogpt_platform/backend/backend/copilot/active_turns.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/executor/utils.pyautogpt_platform/backend/backend/copilot/active_turns.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/executor/utils.pyautogpt_platform/backend/backend/copilot/active_turns.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/executor/utils.pyautogpt_platform/backend/backend/copilot/active_turns.py
📚 Learning: 2026-04-15T02:43:36.890Z
Learnt from: ntindle
Repo: Significant-Gravitas/AutoGPT PR: 12780
File: autogpt_platform/backend/backend/copilot/tools/workspace_files.py:0-0
Timestamp: 2026-04-15T02:43:36.890Z
Learning: When reviewing Python exception handlers, do not flag `isinstance(e, X)` checks as dead/unreachable if the caught exception `X` is a subclass of the exception type being handled. For example, if `X` (e.g., `VirusScanError`) inherits from `ValueError` (directly or via an intermediate class) and it can be raised within an `except ValueError:` block, then `isinstance(e, X)` inside that handler is reachable and should not be treated as dead code.
Applied to files:
autogpt_platform/backend/backend/copilot/executor/utils.pyautogpt_platform/backend/backend/copilot/active_turns.py
📚 Learning: 2026-04-22T11:46:04.431Z
Learnt from: majdyz
Repo: Significant-Gravitas/AutoGPT PR: 12881
File: autogpt_platform/backend/backend/copilot/config.py:0-0
Timestamp: 2026-04-22T11:46:04.431Z
Learning: Do not flag the Claude Sonnet 4.6 model ID as incorrect when it uses the project’s established hyphenated convention: `anthropic/claude-sonnet-4-6`. This hyphen form is the intentional, production convention and should be treated as valid (including in files like llm.py, blocks tests, reasoning.py, `_is_anthropic_model` tests, and config defaults). Note that OpenRouter also accepts the dot variant `anthropic/claude-sonnet-4.6`, so either form may be tolerated, but `anthropic/claude-sonnet-4-6` should be considered the standard to match project usage.
Applied to files:
autogpt_platform/backend/backend/copilot/executor/utils.pyautogpt_platform/backend/backend/copilot/active_turns.py
📚 Learning: 2026-04-22T11:46:12.892Z
Learnt from: majdyz
Repo: Significant-Gravitas/AutoGPT PR: 12881
File: autogpt_platform/backend/backend/copilot/baseline/service.py:322-332
Timestamp: 2026-04-22T11:46:12.892Z
Learning: In this codebase (Significant-Gravitas/AutoGPT), OpenRouter-routed Anthropic model IDs should use the hyphen-separated convention (e.g., `anthropic/claude-sonnet-4-6`, `anthropic/claude-opus-4-6`). Although OpenRouter may accept both hyphen and dot variants, treat the hyphen-separated form as the intended, correct codebase-wide convention and do not flag it as an error. Only flag the dot-separated variant (e.g., `anthropic/claude-sonnet-4.6`) as incorrect when reviewing/validating model ID strings for OpenRouter-routed Anthropic models.
Applied to files:
autogpt_platform/backend/backend/copilot/executor/utils.pyautogpt_platform/backend/backend/copilot/active_turns.py
📚 Learning: 2026-05-07T18:48:14.242Z
Learnt from: majdyz
Repo: Significant-Gravitas/AutoGPT PR: 13040
File: autogpt_platform/backend/backend/blocks/llm.py:0-0
Timestamp: 2026-05-07T18:48:14.242Z
Learning: In this repository, isort may split imports from the same module into separate blocks when some imports are aliased (e.g., `from module import X as Y`) and others are not. Preserve the two-block layout when it results from isort (such as keeping `from openai.types.chat import ChatCompletion as OpenAIChatCompletion` separate from non-aliased imports from `openai.types.chat`). Do not treat that split as a style issue during review; merging them into a single block can fail CI with `Imports are incorrectly sorted and/or formatted`.
Applied to files:
autogpt_platform/backend/backend/copilot/executor/utils.pyautogpt_platform/backend/backend/copilot/active_turns.py
…heck on schedule_turn - cancel_queued_turn / mark_queued_turn_blocked now invalidate the session cache after a successful status transition so the frontend drops the 'Queued' badge on its next refetch - schedule_turn pre-checks running + queued against the inflight cap so non-HTTP callers (run_sub_session / AutoPilotBlock) honour the per-user 15-task ceiling — passing capacity to acquire_turn_slot alone only widens the running-slot budget, queued turns from the HTTP route would still be invisible to the slot pool
…dundant index Round 4 review caught a real Prisma leak: the slot-free hook in ``mark_session_completed`` is invoked from ``backend/copilot/executor/processor.py:91, 578`` — the CoPilotExecutor subprocess, which has NO direct Prisma connection. The dispatcher chain ``mark_session_completed → dispatch_next_for_user → list_queued_sessions → copilot_db.list_chat_sessions_by_status`` hit a raw ``PrismaChatSession.prisma()`` call in that subprocess and threw, so queued sessions never promoted when the completion fired from the executor side (i.e. most turns). Fix: ``list_chat_sessions_by_status`` now returns ``list[ChatSessionInfo]`` (``from_db``-converted) so the response serializer can pass it across the DatabaseManager RPC boundary. The function is re-exposed on ``DatabaseManager`` / ``DatabaseManagerAsyncClient``. ``turn_queue.list_queued_sessions`` and ``active_turns.get_running_session_ids`` route through ``chat_db()`` again and read ``.session_id`` (the Pydantic field) instead of ``.id``. Index consolidation (per review): drop the redundant ``[userId, updatedAt]`` 2-col index and let ``[userId, chatStatus, updatedAt]`` cover all three ChatSession query shapes — cap-count, queue-list with ORDER BY, and the sidebar list ``WHERE userId ORDER BY updatedAt``. The sidebar path sorts in memory across chatStatus sub-buckets per user; at typical per-user N (≤100s of sessions) the in-memory sort is negligible compared to maintaining a parallel index. Migration drops the existing index in the same migration that adds the 3-col one. Tests: ``turn_queue_test``'s ``_patch_queued_list`` now patches ``list_queued_sessions`` directly (independent of how chat_db() resolves); ``_mock_session`` uses ChatSessionInfo's ``.session_id`` / ``.updated_at`` field names. ``db_test`` constructs real ``PrismaChatSession`` rows and asserts on the converted app-model fields. 180 tests pass; pyright clean.
/pr-test --fix Round 2 — Post-Polish VerificationCommit tested: Scenarios
Scenario 1 — RPC type safetyInvoked Scenario 2 — Real queue + dispatcher liveSent two HTTP
Final DB state: all 3 sessions back to Scenario 3 — Dispatcher path stays RPC-safeThe dispatcher chain ( Summary
|
Replace the manual reverse for-loop with ``messages.findLastIndex`` (ES2023, already in use in ``useCopilotPage`` and ``ChatMessagesContainer/helpers``). Same behaviour, one line. Also widen the root .gitignore: ``.ign/*`` only caught contents of an ``.ign/`` directory; the test convention also uses tee'd files like ``.ign.application.logs`` and lock files like ``.ign.testing.lock``. Replaced with ``.ign*`` + ``**/.ign*`` so any path component starting with ``.ign`` is ignored.
The lazy-import comment in ``mark_session_completed`` claimed the chain ``turn_queue → executor.utils → stream_registry`` would be circular at module load. It's not: ``turn_queue``'s only path back into ``stream_registry``-adjacent code is via its own lazy import of ``executor.utils.dispatch_turn`` (line 247) — that's call-time, not import-time. Top-leveling the import simplifies the slot-free hook and matches the style of the other queue-related imports in the file. Tests rebind the patch target from ``backend.copilot.turn_queue.dispatch_next_for_user`` to ``backend.copilot.stream_registry.dispatch_next_for_user`` so the mock catches the new binding.
…lure When ``dispatch_turn`` succeeds at ``create_session`` (Redis meta written, status='running') but then the RabbitMQ ``enqueue_copilot_turn`` fails, the dispatcher's exception handler rolled back the DB ``chatStatus`` (running → queued) but left the Redis session meta in place. ``is_turn_in_flight`` reads both Redis status and DB chatStatus, so the half-failed session kept reporting in-flight even though no executor would ever pick the turn up — new submits got pending-buffered indefinitely until the meta key's TTL expired. Add ``stream_registry.delete_session_meta`` (a tiny ``redis.delete`` on the meta key) and call it in the dispatcher's rollback path alongside the DB restore. Best-effort: a Redis error here only delays cleanup to TTL expiry, which is the prior failure mode. Test extension: ``test_dispatch_rolls_claim_back_on_dispatch_failure`` now asserts ``delete_session_meta`` is awaited once with the failed session id. Resolves r3216996658.
Design recap — what lives where after this PRThe queue feature touches two independent layers that I want to be explicit about, since the recent dispatcher-rollback fix sits across both. Layer 1 — the queue + cap (this PR)Storage: 100% Postgres. No Redis involved.
Single compound index Layer 2 — the stream registry (existing, predates this PR)Storage: Redis (hash per active session at This is the streaming layer, not the queue layer. It exists because SSE streams need:
This layer was already in place. The queue PR doesn't change its storage. Where the two layers couple — and what the dispatcher rollback fixes
If step 2 fails (RabbitMQ blip, network glitch), step 1's Redis meta is orphaned. The dispatcher already rolled back the Postgres The fix in Dispatcher triggersOnly ONE: CAS safety against double-promotion
Cross-process RPC safetyTwo paths reach the DB:
Every PR-added |
Audit pass after PR-test surfaced multiple "DB chatStatus=running but no executor actually running it" failure modes. Every one fixed here; nothing deferred. Full table in the PR description. **1. Cancel route no longer leaves orphan DB state.** When ``get_active_session`` returns None on the running branch, also call ``release_turn_slot`` so the sidebar's green dot doesn't persist after the executor crashed mid-turn and the Redis meta TTL'd out. **2. ``get_session`` route resets DB-only orphans on chat-open.** If the user opens a chat whose DB says ``running`` but Redis has no live stream, force-release the slot — opening the chat is a strong "show me the current state" signal. **3. ``dispatch_turn`` cleans Redis on EVERY non-happy-path exit.** Switched from ``except Exception`` (which misses ``CancelledError``) to ``try/finally`` on a ``committed`` flag. Cleanup lives inside ``dispatch_turn`` so the HTTP ``schedule_chat_turn`` path and the queue dispatcher path are both covered; removed the duplicate delete-meta call from ``dispatch_next_for_user``. **4. Dispatcher rollback uses ``except BaseException``.** A task cancellation mid-dispatch now still rolls back the DB claim from ``running`` back to ``queued`` — the previous ``except Exception`` let cancellations leak. **5. New periodic sweep ``cleanup_stuck_copilot_sessions``.** Default: every 5 min, threshold 30 min. Finds sessions stuck ``running`` beyond the threshold, checks Redis for a live stream, force-releases when there isn't one. Catches the no-user-interaction case (#1/#2 only fire on cancel/chat-open). **6. ``chatStatus`` is now a Postgres enum, not open TEXT.** Added ``ChatSessionStatus`` Prisma enum (``idle | queued | running``); the DB rejects typos / invalid values at the column-type layer. Future states need a tiny ``ALTER TYPE ADD VALUE`` migration (cheap on PG 12+). Settings: ``copilot_stuck_session_max_age_secs`` (default 30 min, 1m–24h) and ``copilot_stuck_session_sweep_interval_secs`` (default 5 min, 30s–1h) drive the new sweep. Tests: ``test_cancel_session_no_active_task`` pins the new ``release_turn_slot`` call; the dispatcher-rollback test no longer asserts on Redis cleanup (now lives in ``dispatch_turn``).
The reactive cleanups in the previous commit catch every user-visible path: clicking Cancel and opening the chat both reset the orphan. The inline stale-CAS in ``get_active_session`` (6h+5min) remains the ultimate backstop. An extra per-pod APScheduler sweep only ever helped the "user has stuck sessions but never opens them, never cancels, and keeps submitting new chats until the cap fills" case — too narrow to justify the constant operational surface. Drops: - ``cleanup_stuck_copilot_sessions`` job in executor scheduler - ``list_stuck_running_sessions`` in db.py + its DB-manager exposures - ``copilot_stuck_session_max_age_secs`` / ``..._sweep_interval_secs`` config knobs
…ilable Sentry r3217196828 caught `is_turn_in_flight` letting Prisma / DB-down exceptions bubble as a raw 500 from the HTTP layer. Redis errors in the same function are already mapped to typed `StreamRegistryUnavailable` so the chat-route pre-flight chain returns 503 + Retry-After — DB errors now follow the same fail-closed path for symmetry. Test: `test_is_turn_in_flight_raises_when_chat_status_lookup_fails` pins the new exception mapping.
Locks the contract for the new chat_status='running' + empty-Redis fixup added in 2de3469. Mirrors test_cancel_session_no_active_task on the sibling cancel-route fixup so a future change that drops the cleanup fails both tests instead of silently regressing the sidebar UX. Resolves r3217265328.
… paths Sentry r3217251053: when dispatch_next_for_user rolls back the session status (either the pending is None corrupted-state branch or the dispatch_turn failure branch), the DB chatStatus flip isn't paired with invalidate_session_cache. Cached reads (sidebar, chat-page) keep showing the stale running indicator until the session cache TTLs out or another write touches it. Both rollback paths now call invalidate_session_cache immediately after the status flip, matching what the happy path does at the end of dispatch_next_for_user.
…atch race Sentry r3217310172: the previous orphan-reset (``get_session`` and ``cancel_session_task``) fired whenever DB ``chatStatus='running'`` + no Redis meta — but those two states ALSO match the sub-millisecond window between ``acquire_turn_slot`` (DB flip ``idle → running``) and ``dispatch_turn.create_session`` (Redis meta write). A get/cancel landing in that gap would force-release the slot while ``dispatch_turn`` keeps going, leaving DB ``idle`` while RabbitMQ-published work executes — and worse, lets the user start a second concurrent turn past the cap. Fix: gate the reset on session age — ``_try_release_orphan_running`` only fires if the row's ``updatedAt`` is older than ``_ORPHAN_RUNNING_RESET_THRESHOLD_SECONDS`` (30s). Anything newer is treated as an in-flight admit, not an orphan. Threshold is a generous safety margin: the acquire→create_session window is a few ms in practice. Cancel route now distinguishes the two outcomes in its response: ``reason="orphan_released"`` when the age-gated release fires, ``"no_active_session"`` when it doesn't (already idle, or fresh admit racing the read). Tests: - ``test_cancel_session_releases_orphan_running`` — pins the orphan branch with a stale ``updatedAt``. - ``test_cancel_session_skips_orphan_release_within_race_window`` — pins the race-window skip with a 1s-old admit. - ``test_get_session_releases_orphan_when_redis_empty_and_db_running`` — updated to use stale ``updatedAt`` and to mock the new ``get_chat_session_metadata`` lookup.
isort wanted datetime to sort before typing — fixed. Sentry r3217397817 flagged a TypeError risk if meta.updated_at came back timezone-naive (Prisma returns tz-aware UTC today, but a schema tweak could change that). Normalise to UTC defensively before subtracting so the orphan-reset path can't ever blow up on the arithmetic.
/pr-test --fix Round 3 — Stuck-running fixes verified liveCommit tested: Scenarios
EvidenceScenario 1 — stale orphan cancel returns
|
Why
We hard-capped concurrent AutoPilot turns at 15 per user as a hotfix, which rejected the 16th request with HTTP 429 — blunt UX, easy to hit by accident. This PR keeps the safeguard but introduces a soft running cap of 5 with a FIFO queue up to 15 in-flight (running + queued). The user can submit beyond 5; the dispatcher auto-promotes queued sessions as running slots free.
What
max_running_copilot_turns_per_user).ChatSession.chatStatusis a single text enum:idle(default) |queued|running(open enum). The user's pending message is just a normalChatMessagerow; the session carries the lifecycle.POST /sessions/{session_id}/cancelhandles both states uniformly. Queued sessions flip back toidle(no executor cancel needed); running sessions publish a RabbitMQ cancel event as before. No dedicated/queued-tasks/*endpoints.chat_status === 'queued'. Sidebar shows a green pulsing dot forrunningand a purple hourglass forqueuedso the user can see at a glance which of their chats are in flight. Cancel button on the badge calls the same session-cancel endpoint.How
ChatSession.chatStatus(this PR)running) + queue (countqueued), single source of truthChatMessage.metadataJSONB (this PR)file_ids/mode/model/permissions/context/request_arrival_atstashed on the queued user row so promotion can replay the turn faithfullyQueue lifecycle — where it lives, who clears it
Storage. The queue lives entirely in Postgres (no Redis sorted set, no Lua). Per session: a single
chatStatustext column (idle | queued | running, open enum), plus the user's pending message persisted as a normalChatMessagerow with the dispatcher's submit-time payload stashed inmetadataJSONB.Submission path (
backend/copilot/turn_queue.py:enqueue_turn):acquire_turn_slot. If user is at the 5-running cap,ConcurrentTurnLimitErroris raised.try_enqueue_turnwhich: checks the 15 in-flight hard cap, persists the user message + metadata, then CAS-flipsChatSession.chatStatusidle→queued. Returns an empty-stream response so the SSE client knows the message landed.Promotion path (
backend/copilot/turn_queue.py:dispatch_next_for_user) — fires per-user, not globally:mark_session_completed(instream_registry.py) — after every turn completes (success / failure / cancel), the session'suser_idis read from Redis meta anddispatch_next_for_user(user_id)is invoked. The dispatcher errors are swallowed with a loud log so a queue hiccup never breaks the completion path.list_chat_sessions_by_status(user_id, queued)ordered byupdatedAt.queuedfor the next tick.queued→running. Recovers the user message + submit-timemetadata, builds aTurnSlot, callsdispatch_turn. On any error during dispatch, rolls the session back toqueued.Cancellation (
POST /sessions/{id}/cancel): single endpoint handles both lifecycle states — queued sessions flip back toidle(no executor cancel needed); running sessions publish a RabbitMQ cancel event as before.The cap and queue queries are both
count/find_manyonChatSessionbychatStatus. Both running-turn tracking and queue admission are non-locked CAS-then-count — same TOCTOU tolerance the graph-execution credit rate-limit accepts on its INCRBY path. Going briefly to 16/17 in-flight under burst is acceptable; the cap is a safeguard, not a budget.The DB-manager surface is 4 generic ChatSession primitives (
count_chat_sessions_by_status,list_chat_sessions_by_status,update_chat_session_statuswith optionalexpect_statusCAS gate,get_chat_session_status) plus the existingadd_chat_messageextended with optionalmessage_id+metadata. Adding a new lifecycle state is a code-only change at call sites. DB access goes throughbackend.data.db_accessors.chat_db()so the dispatcher works from both the HTTP server (Prisma directly) and the CoPilotExecutor subprocess (RPC viaDatabaseManager).Route gates (
is_turn_in_flight,acquire_turn_slot) treat bothqueuedandrunningas "in flight", so a resubmit to a queued session lands in the pending buffer or falls through to the cross-session queue rather than racing the dispatcher.Test plan
active_turns_test.py,turn_queue_test.py,db_test.py(60+ tests covering admission, refresh, release, queued-collision, cap-rollback, dispatcher branches: paywall/rate-limited stays queued, rate-limit unavailable, happy path, dispatch failure → restore).stream_registry_test.py: pin the per-user slot-free dispatcher invocation onmark_session_completed, plus the error-swallowing behaviour so a queue hiccup never breaks the turn completion path.Stuck-running bugs found and fixed in this PR
Audit during review surfaced multiple "DB says running, executor isn't actually running it" failure modes. Every one fixed in this PR; none deferred.
chatStatusstaysrunningcancel_session_tasknow callsrelease_turn_sloton the no-active-session branch — the user clicking Cancel always clears the orphan.get_sessionroute also resets when DB saysrunningbut Redis is empty, so just opening the stuck chat clears it.acquire_turn_slotflips DBidle → runningbut the request aborts beforedispatch_turnrunsdispatch_turnsucceeds atcreate_session(Redis meta written) but fails at the RabbitMQ enqueuestatus='running'until TTL;is_turn_in_flightkeeps reporting in-flightdispatch_turnnow usestry/finallyon acommittedflag — Redis meta is deleted on ANY non-happy-path exit includingCancelledError(whichexcept Exceptionwould miss). Cleanup runs insidedispatch_turnitself so both the HTTPschedule_chat_turnpath and the queue dispatcher path are covered.mark_session_completeditself fails mid-completion (Redis blip during the CAS)idleexcept Exception, leaking onCancelledErrorrunningexcept BaseExceptionindispatch_next_for_userso cancellation still rolls back the DB claim. Pairs with thetry/finallyindispatch_turnfor full Redis+DB symmetry.chatStatuswas an openTEXTcolumn with no DB-level validation"runnin"could persist and break the cap-countChatSessionStatus(`idleWhy no periodic sweep. The reactive cleanups (rows 1 and 2) catch every user-visible path: clicking Cancel and opening the chat both reset the orphan. The existing 6h+5min inline stale-CAS in
get_active_sessionremains the ultimate backstop. Adding a per-pod APScheduler job would chase the narrow "user has stuck sessions but never opens them and never cancels" case at the cost of constant operational surface — not worth it for this rare scenario.All paths that mutate
chatStatusnow also clean the matching Redis state (either inline or via the sweep) — the two layers stay in sync.Cap + queue safety against double-promotion (carry-over from earlier review)
mark_session_completeddoesrelease_turn_slot(running → idle) BEFOREdispatch_next_for_user. Two concurrent completions release two slots first, then race the CAS on the same head — only one wins per slot, so at most N promotions for N releases. Cap holds.claim_queued_sessionis an atomic PostgresUPDATE … WHERE chatStatus='queued' AND id=…: keyed to the specific head row, only one CAS matches.DatabaseManagerreturn primitives or DTOs (ChatSessionInfo,ChatMessage) — no raw Prisma rows cross the RPC boundary, so the executor subprocess can safely route throughchat_db().