Skip to content

feat(backend/copilot-bot): let users upload files to AutoPilot via Discord - #13427

Merged
Bentlybro merged 12 commits into
devfrom
feat/copilot-bot-file-upload
Jun 30, 2026
Merged

feat(backend/copilot-bot): let users upload files to AutoPilot via Discord#13427
Bentlybro merged 12 commits into
devfrom
feat/copilot-bot-file-upload

Conversation

@Bentlybro

Copy link
Copy Markdown
Member

Why / What / How

Why: The Discord copilot bot could send files (workspace artifacts → Discord) but couldn't receive them. Users wanted to attach a file to a message and have AutoPilot read it — the natural counterpart to the download path, and a common ask once people started using the bot.

What: Attach a file to a Discord message (DM, @mention, or thread) and AutoPilot reads it during the turn. Works for images, PDFs, text, etc., and a file-only message (no text) is handled too.

How: It reuses the exact web-upload machinery — no new upload/scan/storage logic:

  • The Discord adapter downloads attachment bytes up-front (bounded by the per-file size cap and a max count).
  • bot_backend.upload_workspace_files sends each file over RPC to the linker.
  • The linker's upload_chat_file resolves the conversation owner (same as a chat turn) and calls WorkspaceManager.write_file() — the same function the web POST /files/upload endpoint runs: ClamAV scan → quota/size checks → storage → a workspace file_id. Virus/scan/size failures map to stable error codes.
  • The handler uploads the attachments, passes the resulting file_ids to the turn (BotChatRequest.file_ids → enqueue_copilot_turn, already consumed by the executor's attachment resolver), and tells the user about any rejected files.

The file is referenced by file_id, not inlined into the message — exactly how the web copilot does it. Storage backend is config-driven (MEDIA_GCS_BUCKET_NAME), so dev/prod write to the real GCS bucket automatically. Uploads are tagged origin: "user-upload", so a Discord-uploaded file also appears in the user's Files/Artifacts page in their workspace.

Uploads use a unique sub-path (uploads/<uuid>/<filename>) so re-sending a file with the same name is a fresh file rather than a path conflict.

Changes 🏗️

  • adapters/base.py: InboundAttachment model + MessageContext.attachments.
  • Discord adapter.py: _extract_attachments — downloads attachment bytes (skips oversized / failed / over the count cap).
  • bot_backend.py: upload_workspace_files (RPC per file → linker), stream_chat now threads file_ids.
  • platform_linking/chat.py: upload_chat_file (owner resolution + write_file + error mapping); start_chat_turn passes file_ids to enqueue_copilot_turn.
  • platform_linking/manager.py: @expose upload_workspace_file + client method.
  • platform_linking/models.py: WorkspaceUploadRequest / WorkspaceUploadResult + BotChatRequest.file_ids.
  • handler.py: upload attachments → file_ids; surface rejected files; process file-only messages.
  • Tests across adapter, bot_backend, handler, and chat (extraction, RPC forwarding, upload+failure+file-only, virus/size error mapping).

Checklist 📋

For code changes:

  • I have clearly listed my changes in the PR description
  • I have made a test plan
  • I have tested my changes according to the test plan:
    • Unit/integration: ~360 backend tests pass (bot + platform_linking suites)
    • Local end-to-end against the live gateway: attached a test.txt in Discord, AutoPilot read the file's contents and replied accordingly; verified the file is stored in the workspace via the same write_file/ClamAV path the web uses
    • Verified failure handling: virus/scan/size failures surface a per-file "couldn't be attached" note while clean files still flow to the turn; a file-only message (no text) is processed instead of dropped

For configuration changes:

  • No committed config changes (local-only docker-compose.override.yml is untracked)

…scord

Users can attach a file to a Discord message and AutoPilot reads it during the
turn. Mirrors the web upload path: the file goes through the same
WorkspaceManager.write_file machinery (ClamAV scan, storage, workspace file id)
and is referenced by file_id — no content inlining.

- adapter: download message attachments (bounded by size/count) into the context
- bot_backend.upload_workspace_files: RPC per file to the linker
- linker upload_chat_file: resolve the conversation owner, write_file (AV scan),
  map virus/scan/size failures to stable error codes
- handler: upload attachments, pass file_ids to the turn, report rejected files,
  and process file-only messages (previously dropped as empty)
- BotChatRequest.file_ids -> enqueue_copilot_turn (already consumed by executor)

Uploads use a unique path so re-sending the same filename is a fresh file, not
a path conflict.
@Bentlybro
Bentlybro requested a review from a team as a code owner June 24, 2026 13:43
@Bentlybro
Bentlybro requested review from kcze and majdyz and removed request for a team June 24, 2026 13:43
@github-project-automation github-project-automation Bot moved this to 🆕 Needs initial review in AutoGPT development kanban Jun 24, 2026
@github-actions github-actions Bot added platform/backend AutoGPT Platform - Back end size/xl labels Jun 24, 2026
@coderabbitai

coderabbitai Bot commented Jun 24, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 414e8235-bdbf-4831-a85f-f2a6f00d376b

📥 Commits

Reviewing files that changed from the base of the PR and between a70608a and 4e82773.

📒 Files selected for processing (2)
  • autogpt_platform/backend/backend/copilot/bot/bot_backend.py
  • autogpt_platform/backend/backend/copilot/bot/bot_backend_test.py
🚧 Files skipped from review as they are similar to previous changes (2)
  • autogpt_platform/backend/backend/copilot/bot/bot_backend.py
  • autogpt_platform/backend/backend/copilot/bot/bot_backend_test.py
📜 Recent review details
⏰ Context from checks skipped due to timeout. (11)
  • GitHub Check: check API types
  • GitHub Check: Seer Code Review
  • GitHub Check: type-check (3.11)
  • GitHub Check: test (3.12)
  • GitHub Check: test (3.11)
  • GitHub Check: test (3.13)
  • GitHub Check: type-check (3.13)
  • GitHub Check: end-to-end tests
  • GitHub Check: Check PR Status
  • GitHub Check: Analyze (python)
  • GitHub Check: Analyze (typescript)

Walkthrough

Adds inbound attachment support from Discord download through workspace upload and file ID propagation into streamed chat turns.

Changes

Inbound Attachment Flow

Layer / File(s) Summary
Attachment and upload contracts
autogpt_platform/backend/backend/copilot/bot/adapters/base.py, autogpt_platform/backend/backend/platform_linking/models.py
InboundAttachment, MessageContext.attachments, MessageContext.skipped_attachments, BotChatRequest.file_ids, WorkspaceUploadRequest, and WorkspaceUploadResult are added.
Discord attachment extraction
autogpt_platform/backend/backend/copilot/bot/adapters/discord/adapter.py, autogpt_platform/backend/backend/copilot/bot/adapters/discord/adapter_test.py
DiscordAdapter downloads inbound Discord attachments into InboundAttachment objects, caps the number processed, skips oversized or failed downloads, and passes them into MessageContext.
Workspace upload RPC
autogpt_platform/backend/backend/platform_linking/chat.py, autogpt_platform/backend/backend/platform_linking/manager.py, autogpt_platform/backend/backend/platform_linking/chat_test.py
upload_workspace_file resolves chat ownership, stores uploaded files in the workspace, and returns upload results; the manager exposes upload_workspace_file, and start_chat_turn forwards file_ids. Tests cover success, mapped failures, sanitization, and missing ownership.
BotBackend attachment upload and file IDs
autogpt_platform/backend/backend/copilot/bot/bot_backend.py, autogpt_platform/backend/backend/copilot/bot/bot_backend_test.py
BotBackend.upload_workspace_files uploads each inbound attachment separately and returns per-file results. stream_chat now accepts file_ids and includes them in the chat-turn request.
Handler attachment flow and streaming
autogpt_platform/backend/backend/copilot/bot/handler.py, autogpt_platform/backend/backend/copilot/bot/handler_test.py
MessageHandler uploads attachments, accepts file-only messages, tracks pending file IDs, drains them into streaming, and formats upload failures into user-visible notes.

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60 minutes

Possibly related PRs

Suggested reviewers

  • 0ubbe
  • ntindle
  • Swiftyos

Poem

🐇 I sniffed some files, then gave a hop,
From Discord drops to workspace shop.
File IDs danced into the stream,
And chat went rolling like a dream.
Hoppity-hum, the bytes are sung,
With whiskers twitching, task well done.

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 22.54% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly states the main change: Discord file uploads for AutoPilot.
Description check ✅ Passed The description directly matches the PR's file-upload support and test coverage.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feat/copilot-bot-file-upload

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

❤️ Share

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

@github-actions

github-actions Bot commented Jun 24, 2026

Copy link
Copy Markdown
Contributor

🔍 PR Overlap Detection

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

🔴 Merge Conflicts Detected

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

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


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

Comment thread autogpt_platform/backend/backend/copilot/bot/handler.py Outdated
@codecov

codecov Bot commented Jun 24, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 98.82075% with 5 lines in your changes missing coverage. Please review.
✅ Project coverage is 74.74%. Comparing base (b6438a2) to head (4e82773).

Additional details and impacted files
@@            Coverage Diff             @@
##              dev   #13427      +/-   ##
==========================================
+ Coverage   74.71%   74.74%   +0.02%     
==========================================
  Files        2537     2534       -3     
  Lines      192322   192638     +316     
  Branches    18928    18929       +1     
==========================================
+ Hits       143690   143978     +288     
- Misses      44500    44534      +34     
+ Partials     4132     4126       -6     
Flag Coverage Δ
platform-backend 82.03% <98.82%> (+0.04%) ⬆️
platform-frontend-e2e 31.85% <ø> (-0.29%) ⬇️

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

Components Coverage Δ
Platform Backend 82.03% <98.82%> (+0.04%) ⬆️
Platform Frontend 47.25% <ø> (-0.24%) ⬇️
AutoGPT Libs ∅ <ø> (∅)
Classic AutoGPT 28.43% <ø> (-0.01%) ⬇️
🚀 New features to boost your workflow:
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Actionable comments posted: 4

🧹 Nitpick comments (3)
autogpt_platform/backend/backend/copilot/bot/adapters/discord/adapter_test.py (1)

1425-1470: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Add a regression test for the attachment-count cap.

Please add a test with MAX_INBOUND_ATTACHMENTS + 1 attachments asserting only the first MAX_INBOUND_ATTACHMENTS are returned/read. This locks the cap behavior and prevents accidental regressions.

🤖 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/copilot/bot/adapters/discord/adapter_test.py`
around lines 1425 - 1470, Add a regression test in TestExtractAttachments for
the attachment-count cap: construct a message with MAX_INBOUND_ATTACHMENTS + 1
attachments and assert that _extract_attachments only reads/returns the first
MAX_INBOUND_ATTACHMENTS items. Reuse the existing _discord_attachment helper and
verify the extra attachment is ignored so the cap behavior stays enforced.
autogpt_platform/backend/backend/platform_linking/chat_test.py (2)

264-297: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Cover the remaining stable error-code branches.

upload_chat_file() also returns scan_unavailable and upload_failed, and handler.py maps both to user-facing attachment-failure text. Adding one test for each branch would lock down the full contract this PR introduces.

🤖 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/platform_linking/chat_test.py` around lines
264 - 297, The current test coverage in upload_chat_file only exercises
virus_detected, rejected, and the unlinked-user NotFoundError path; add two more
async tests in chat_test.py to cover the remaining stable error-code branches,
scan_unavailable and upload_failed. Use the same upload_chat_file entry point
and the existing _patches/AsyncMock setup to force each branch, then assert the
returned result.error matches the expected code so the handler.py mapping stays
locked down.

224-225: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Move these imports to module scope.

The new suite pulls WorkspaceUploadRequest, upload_chat_file, and VirusDetectedError inside helpers/tests, but backend Python files here require top-level imports unless they're lazy imports for heavy optional dependencies.

As per coding guidelines, "Use top-level imports only — avoid local/inner imports except for lazy imports of heavy optional dependencies like openpyxl".

Also applies to: 255-289

🤖 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/platform_linking/chat_test.py` around lines
224 - 225, Move the `WorkspaceUploadRequest`, `upload_chat_file`, and
`VirusDetectedError` imports out of the helper/test bodies and into module scope
in `chat_test.py`. Update the affected helpers/tests (including `_req` and the
cases around the referenced test block) to use those top-level imports directly,
keeping local imports only for true lazy optional dependencies.

Source: Coding guidelines

🤖 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/bot/adapters/discord/adapter.py`:
- Line 479: The Discord attachment handling in the adapter currently truncates
attachments at MAX_INBOUND_ATTACHMENTS without any notice, so add explicit
logging and a user-facing note when message.attachments is capped. Update the
attachment processing path in the Discord adapter’s message handling logic to
detect when more than MAX_INBOUND_ATTACHMENTS are present, log that extra files
were dropped, and propagate a clear downstream note through the existing
user/message flow so users know some attachments were skipped.

In `@autogpt_platform/backend/backend/copilot/bot/bot_backend.py`:
- Around line 339-350: In bot_backend.py, the upload loop in
self._client.upload_workspace_file currently lets one exception abort all
remaining attachments. Update the attachment-processing path in the bot backend
to catch per-file upload failures inside the for attachment in attachments loop,
and convert each failure into a WorkspaceUploadResult with error="upload_failed"
while still appending successful results. Keep the existing
upload_workspace_file call and result accumulation intact, but ensure the
handler continues processing later attachments after a single failure.

In `@autogpt_platform/backend/backend/copilot/bot/handler.py`:
- Around line 111-117: The handler in bot/handler.py should not enqueue a turn
when the message is file-only and _upload_attachments returns no successful
file_ids. Add a guard around the _enqueue_and_process flow in the same block
that checks message_text, file_ids, and the file-only case so it exits early
after the rejection notice instead of sending a blank prompt. Keep the existing
fallback text only for the path where there is at least one uploaded attachment
and leave _upload_attachments, _message_text, and _enqueue_and_process as the
key symbols to update.

In `@autogpt_platform/backend/backend/platform_linking/chat.py`:
- Around line 82-88: The upload path in chat.py currently lets request.filename
influence the workspace path via the path argument passed to
WorkspaceManager.write_file. Update the upload flow so the path uses only a
sanitized basename or an opaque generated identifier, and keep request.filename
only for user-facing metadata/display fields; use the existing write_file call
site in the upload handler to make this change.

---

Nitpick comments:
In
`@autogpt_platform/backend/backend/copilot/bot/adapters/discord/adapter_test.py`:
- Around line 1425-1470: Add a regression test in TestExtractAttachments for the
attachment-count cap: construct a message with MAX_INBOUND_ATTACHMENTS + 1
attachments and assert that _extract_attachments only reads/returns the first
MAX_INBOUND_ATTACHMENTS items. Reuse the existing _discord_attachment helper and
verify the extra attachment is ignored so the cap behavior stays enforced.

In `@autogpt_platform/backend/backend/platform_linking/chat_test.py`:
- Around line 264-297: The current test coverage in upload_chat_file only
exercises virus_detected, rejected, and the unlinked-user NotFoundError path;
add two more async tests in chat_test.py to cover the remaining stable
error-code branches, scan_unavailable and upload_failed. Use the same
upload_chat_file entry point and the existing _patches/AsyncMock setup to force
each branch, then assert the returned result.error matches the expected code so
the handler.py mapping stays locked down.
- Around line 224-225: Move the `WorkspaceUploadRequest`, `upload_chat_file`,
and `VirusDetectedError` imports out of the helper/test bodies and into module
scope in `chat_test.py`. Update the affected helpers/tests (including `_req` and
the cases around the referenced test block) to use those top-level imports
directly, keeping local imports only for true lazy optional dependencies.
🪄 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: e12b72b9-b163-4510-9b6d-8a728284c4e7

📥 Commits

Reviewing files that changed from the base of the PR and between 2053485 and b8edc14.

📒 Files selected for processing (11)
  • autogpt_platform/backend/backend/copilot/bot/adapters/base.py
  • autogpt_platform/backend/backend/copilot/bot/adapters/discord/adapter.py
  • autogpt_platform/backend/backend/copilot/bot/adapters/discord/adapter_test.py
  • autogpt_platform/backend/backend/copilot/bot/bot_backend.py
  • autogpt_platform/backend/backend/copilot/bot/bot_backend_test.py
  • autogpt_platform/backend/backend/copilot/bot/handler.py
  • autogpt_platform/backend/backend/copilot/bot/handler_test.py
  • autogpt_platform/backend/backend/platform_linking/chat.py
  • autogpt_platform/backend/backend/platform_linking/chat_test.py
  • autogpt_platform/backend/backend/platform_linking/manager.py
  • autogpt_platform/backend/backend/platform_linking/models.py
📜 Review details
⏰ Context from checks skipped due to timeout. (10)
  • GitHub Check: check API types
  • GitHub Check: Seer Code Review
  • GitHub Check: test (3.13)
  • GitHub Check: test (3.12)
  • GitHub Check: test (3.11)
  • GitHub Check: type-check (3.11)
  • GitHub Check: type-check (3.13)
  • GitHub Check: end-to-end tests
  • GitHub Check: Check PR Status
  • GitHub Check: Analyze (python)
🧰 Additional context used
📓 Path-based instructions (3)
autogpt_platform/backend/**/*.py

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

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

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

Files:

  • autogpt_platform/backend/backend/platform_linking/manager.py
  • autogpt_platform/backend/backend/copilot/bot/adapters/base.py
  • autogpt_platform/backend/backend/copilot/bot/adapters/discord/adapter.py
  • autogpt_platform/backend/backend/copilot/bot/adapters/discord/adapter_test.py
  • autogpt_platform/backend/backend/platform_linking/chat_test.py
  • autogpt_platform/backend/backend/platform_linking/chat.py
  • autogpt_platform/backend/backend/copilot/bot/bot_backend_test.py
  • autogpt_platform/backend/backend/copilot/bot/bot_backend.py
  • autogpt_platform/backend/backend/platform_linking/models.py
  • autogpt_platform/backend/backend/copilot/bot/handler.py
  • autogpt_platform/backend/backend/copilot/bot/handler_test.py
autogpt_platform/{backend,autogpt_libs}/**/*.py

📄 CodeRabbit inference engine (AGENTS.md)

Format Python code with poetry run format

Files:

  • autogpt_platform/backend/backend/platform_linking/manager.py
  • autogpt_platform/backend/backend/copilot/bot/adapters/base.py
  • autogpt_platform/backend/backend/copilot/bot/adapters/discord/adapter.py
  • autogpt_platform/backend/backend/copilot/bot/adapters/discord/adapter_test.py
  • autogpt_platform/backend/backend/platform_linking/chat_test.py
  • autogpt_platform/backend/backend/platform_linking/chat.py
  • autogpt_platform/backend/backend/copilot/bot/bot_backend_test.py
  • autogpt_platform/backend/backend/copilot/bot/bot_backend.py
  • autogpt_platform/backend/backend/platform_linking/models.py
  • autogpt_platform/backend/backend/copilot/bot/handler.py
  • autogpt_platform/backend/backend/copilot/bot/handler_test.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.py naming 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
Use AsyncMock from unittest.mock for async functions in tests
When writing tests, use Test-Driven Development (TDD): write failing tests marked with @pytest.mark.xfail before implementation, then remove the marker once the implementation is complete
When creating snapshots in tests, use poetry run pytest path/to/test.py --snapshot-update; always review snapshot changes with git diff before committing

Files:

  • autogpt_platform/backend/backend/copilot/bot/adapters/discord/adapter_test.py
  • autogpt_platform/backend/backend/platform_linking/chat_test.py
  • autogpt_platform/backend/backend/copilot/bot/bot_backend_test.py
  • autogpt_platform/backend/backend/copilot/bot/handler_test.py
🧠 Learnings (14)
📚 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/platform_linking/manager.py
  • autogpt_platform/backend/backend/copilot/bot/adapters/base.py
  • autogpt_platform/backend/backend/copilot/bot/adapters/discord/adapter.py
  • autogpt_platform/backend/backend/copilot/bot/adapters/discord/adapter_test.py
  • autogpt_platform/backend/backend/platform_linking/chat_test.py
  • autogpt_platform/backend/backend/platform_linking/chat.py
  • autogpt_platform/backend/backend/copilot/bot/bot_backend_test.py
  • autogpt_platform/backend/backend/copilot/bot/bot_backend.py
  • autogpt_platform/backend/backend/platform_linking/models.py
  • autogpt_platform/backend/backend/copilot/bot/handler.py
  • autogpt_platform/backend/backend/copilot/bot/handler_test.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/platform_linking/manager.py
  • autogpt_platform/backend/backend/copilot/bot/adapters/base.py
  • autogpt_platform/backend/backend/copilot/bot/adapters/discord/adapter.py
  • autogpt_platform/backend/backend/copilot/bot/adapters/discord/adapter_test.py
  • autogpt_platform/backend/backend/platform_linking/chat_test.py
  • autogpt_platform/backend/backend/platform_linking/chat.py
  • autogpt_platform/backend/backend/copilot/bot/bot_backend_test.py
  • autogpt_platform/backend/backend/copilot/bot/bot_backend.py
  • autogpt_platform/backend/backend/platform_linking/models.py
  • autogpt_platform/backend/backend/copilot/bot/handler.py
  • autogpt_platform/backend/backend/copilot/bot/handler_test.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/platform_linking/manager.py
  • autogpt_platform/backend/backend/copilot/bot/adapters/base.py
  • autogpt_platform/backend/backend/copilot/bot/adapters/discord/adapter.py
  • autogpt_platform/backend/backend/copilot/bot/adapters/discord/adapter_test.py
  • autogpt_platform/backend/backend/platform_linking/chat_test.py
  • autogpt_platform/backend/backend/platform_linking/chat.py
  • autogpt_platform/backend/backend/copilot/bot/bot_backend_test.py
  • autogpt_platform/backend/backend/copilot/bot/bot_backend.py
  • autogpt_platform/backend/backend/platform_linking/models.py
  • autogpt_platform/backend/backend/copilot/bot/handler.py
  • autogpt_platform/backend/backend/copilot/bot/handler_test.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/platform_linking/manager.py
  • autogpt_platform/backend/backend/copilot/bot/adapters/base.py
  • autogpt_platform/backend/backend/copilot/bot/adapters/discord/adapter.py
  • autogpt_platform/backend/backend/copilot/bot/adapters/discord/adapter_test.py
  • autogpt_platform/backend/backend/platform_linking/chat_test.py
  • autogpt_platform/backend/backend/platform_linking/chat.py
  • autogpt_platform/backend/backend/copilot/bot/bot_backend_test.py
  • autogpt_platform/backend/backend/copilot/bot/bot_backend.py
  • autogpt_platform/backend/backend/platform_linking/models.py
  • autogpt_platform/backend/backend/copilot/bot/handler.py
  • autogpt_platform/backend/backend/copilot/bot/handler_test.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/platform_linking/manager.py
  • autogpt_platform/backend/backend/copilot/bot/adapters/base.py
  • autogpt_platform/backend/backend/copilot/bot/adapters/discord/adapter.py
  • autogpt_platform/backend/backend/copilot/bot/adapters/discord/adapter_test.py
  • autogpt_platform/backend/backend/platform_linking/chat_test.py
  • autogpt_platform/backend/backend/platform_linking/chat.py
  • autogpt_platform/backend/backend/copilot/bot/bot_backend_test.py
  • autogpt_platform/backend/backend/copilot/bot/bot_backend.py
  • autogpt_platform/backend/backend/platform_linking/models.py
  • autogpt_platform/backend/backend/copilot/bot/handler.py
  • autogpt_platform/backend/backend/copilot/bot/handler_test.py
📚 Learning: 2026-05-23T05:29:43.085Z
Learnt from: majdyz
Repo: Significant-Gravitas/AutoGPT PR: 13200
File: autogpt_platform/backend/backend/executor/scheduler.py:590-593
Timestamp: 2026-05-23T05:29:43.085Z
Learning: When reviewing Python code that uses Pydantic discriminated/tagged unions (e.g., `Annotated[Union[...], Field(discriminator="kind")]`), recognize that using `isinstance(x, SomeVariantInfo)` to narrow the union is an intentional and correct runtime guard and should also enable static type narrowing in tools like Pyright. Do not recommend replacing such `isinstance`-based narrowing with `cast(...)` when the check already proves the variant at runtime.

Applied to files:

  • autogpt_platform/backend/backend/platform_linking/manager.py
  • autogpt_platform/backend/backend/copilot/bot/adapters/base.py
  • autogpt_platform/backend/backend/copilot/bot/adapters/discord/adapter.py
  • autogpt_platform/backend/backend/copilot/bot/adapters/discord/adapter_test.py
  • autogpt_platform/backend/backend/platform_linking/chat_test.py
  • autogpt_platform/backend/backend/platform_linking/chat.py
  • autogpt_platform/backend/backend/copilot/bot/bot_backend_test.py
  • autogpt_platform/backend/backend/copilot/bot/bot_backend.py
  • autogpt_platform/backend/backend/platform_linking/models.py
  • autogpt_platform/backend/backend/copilot/bot/handler.py
  • autogpt_platform/backend/backend/copilot/bot/handler_test.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/platform_linking/manager.py
  • autogpt_platform/backend/backend/copilot/bot/adapters/base.py
  • autogpt_platform/backend/backend/copilot/bot/adapters/discord/adapter.py
  • autogpt_platform/backend/backend/copilot/bot/adapters/discord/adapter_test.py
  • autogpt_platform/backend/backend/platform_linking/chat_test.py
  • autogpt_platform/backend/backend/platform_linking/chat.py
  • autogpt_platform/backend/backend/copilot/bot/bot_backend_test.py
  • autogpt_platform/backend/backend/copilot/bot/bot_backend.py
  • autogpt_platform/backend/backend/platform_linking/models.py
  • autogpt_platform/backend/backend/copilot/bot/handler.py
  • autogpt_platform/backend/backend/copilot/bot/handler_test.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/platform_linking/manager.py
  • autogpt_platform/backend/backend/copilot/bot/adapters/base.py
  • autogpt_platform/backend/backend/copilot/bot/adapters/discord/adapter.py
  • autogpt_platform/backend/backend/copilot/bot/adapters/discord/adapter_test.py
  • autogpt_platform/backend/backend/platform_linking/chat_test.py
  • autogpt_platform/backend/backend/platform_linking/chat.py
  • autogpt_platform/backend/backend/copilot/bot/bot_backend_test.py
  • autogpt_platform/backend/backend/copilot/bot/bot_backend.py
  • autogpt_platform/backend/backend/platform_linking/models.py
  • autogpt_platform/backend/backend/copilot/bot/handler.py
  • autogpt_platform/backend/backend/copilot/bot/handler_test.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/platform_linking/manager.py
  • autogpt_platform/backend/backend/copilot/bot/adapters/base.py
  • autogpt_platform/backend/backend/copilot/bot/adapters/discord/adapter.py
  • autogpt_platform/backend/backend/copilot/bot/adapters/discord/adapter_test.py
  • autogpt_platform/backend/backend/platform_linking/chat_test.py
  • autogpt_platform/backend/backend/platform_linking/chat.py
  • autogpt_platform/backend/backend/copilot/bot/bot_backend_test.py
  • autogpt_platform/backend/backend/copilot/bot/bot_backend.py
  • autogpt_platform/backend/backend/platform_linking/models.py
  • autogpt_platform/backend/backend/copilot/bot/handler.py
  • autogpt_platform/backend/backend/copilot/bot/handler_test.py
📚 Learning: 2026-05-26T14:24:34.866Z
Learnt from: Abhi1992002
Repo: Significant-Gravitas/AutoGPT PR: 13217
File: autogpt_platform/backend/backend/api/features/search/service.py:137-137
Timestamp: 2026-05-26T14:24:34.866Z
Learning: In the Significant-Gravitas/AutoGPT backend, treat `user_id` (an opaque UUID used only for correlation/tracing) as non-PII. Do not flag direct logging of `user_id` in `logger.warning`/`logger.info` statements as a PII exposure issue, as the established convention is to log `user_id` for tracing while reserving PII for fields like email or display name.

Applied to files:

  • autogpt_platform/backend/backend/platform_linking/manager.py
  • autogpt_platform/backend/backend/copilot/bot/adapters/base.py
  • autogpt_platform/backend/backend/copilot/bot/adapters/discord/adapter.py
  • autogpt_platform/backend/backend/copilot/bot/adapters/discord/adapter_test.py
  • autogpt_platform/backend/backend/platform_linking/chat_test.py
  • autogpt_platform/backend/backend/platform_linking/chat.py
  • autogpt_platform/backend/backend/copilot/bot/bot_backend_test.py
  • autogpt_platform/backend/backend/copilot/bot/bot_backend.py
  • autogpt_platform/backend/backend/platform_linking/models.py
  • autogpt_platform/backend/backend/copilot/bot/handler.py
  • autogpt_platform/backend/backend/copilot/bot/handler_test.py
📚 Learning: 2026-06-11T19:39:10.493Z
Learnt from: ntindle
Repo: Significant-Gravitas/AutoGPT PR: 13337
File: autogpt_platform/backend/backend/copilot/graphiti/reranker.py:0-0
Timestamp: 2026-06-11T19:39:10.493Z
Learning: In the Significant-Gravitas/AutoGPT Python backend, when calling the OpenAI Python client `chat.completions.create`, construct the `messages` payload using the concrete typed-dict variants from `openai.types.chat` (e.g., `ChatCompletionSystemMessageParam`, `ChatCompletionUserMessageParam`, etc.) rather than trying to instantiate `ChatCompletionMessageParam` directly. `ChatCompletionMessageParam` is a `Union` alias and is not constructible, so `ChatCompletionMessageParam(role=..., content=...)` should fail type checking. Build each message element with the appropriate concrete typed dict and then annotate the resulting list as `list[ChatCompletionMessageParam]` (e.g., `messages: list[ChatCompletionMessageParam] = [ChatCompletionSystemMessageParam(...), ...]`).

Applied to files:

  • autogpt_platform/backend/backend/platform_linking/manager.py
  • autogpt_platform/backend/backend/copilot/bot/adapters/base.py
  • autogpt_platform/backend/backend/copilot/bot/adapters/discord/adapter.py
  • autogpt_platform/backend/backend/copilot/bot/adapters/discord/adapter_test.py
  • autogpt_platform/backend/backend/platform_linking/chat_test.py
  • autogpt_platform/backend/backend/platform_linking/chat.py
  • autogpt_platform/backend/backend/copilot/bot/bot_backend_test.py
  • autogpt_platform/backend/backend/copilot/bot/bot_backend.py
  • autogpt_platform/backend/backend/platform_linking/models.py
  • autogpt_platform/backend/backend/copilot/bot/handler.py
  • autogpt_platform/backend/backend/copilot/bot/handler_test.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/bot/adapters/base.py
  • autogpt_platform/backend/backend/copilot/bot/adapters/discord/adapter.py
  • autogpt_platform/backend/backend/copilot/bot/adapters/discord/adapter_test.py
  • autogpt_platform/backend/backend/copilot/bot/bot_backend_test.py
  • autogpt_platform/backend/backend/copilot/bot/bot_backend.py
  • autogpt_platform/backend/backend/copilot/bot/handler.py
  • autogpt_platform/backend/backend/copilot/bot/handler_test.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/bot/adapters/base.py
  • autogpt_platform/backend/backend/copilot/bot/adapters/discord/adapter.py
  • autogpt_platform/backend/backend/copilot/bot/adapters/discord/adapter_test.py
  • autogpt_platform/backend/backend/copilot/bot/bot_backend_test.py
  • autogpt_platform/backend/backend/copilot/bot/bot_backend.py
  • autogpt_platform/backend/backend/copilot/bot/handler.py
  • autogpt_platform/backend/backend/copilot/bot/handler_test.py
📚 Learning: 2026-06-06T12:22:37.648Z
Learnt from: anvyle
Repo: Significant-Gravitas/AutoGPT PR: 13302
File: autogpt_platform/backend/backend/copilot/tools/agent_search.py:579-583
Timestamp: 2026-06-06T12:22:37.648Z
Learning: When writing LLM-facing instruction strings that trigger tool calls in this AutoGPT codebase, use the exact registered tool name `view_agent_output` (as defined in `backend/copilot/tools/agent_output.py` via its `name` property and exported via `TOOL_REGISTRY`). Do not reference the bare name `agent_output`, since it is not a valid tool name and will cause tool invocation to fail.

Applied to files:

  • autogpt_platform/backend/backend/copilot/bot/adapters/base.py
  • autogpt_platform/backend/backend/copilot/bot/adapters/discord/adapter.py
  • autogpt_platform/backend/backend/copilot/bot/adapters/discord/adapter_test.py
  • autogpt_platform/backend/backend/copilot/bot/bot_backend_test.py
  • autogpt_platform/backend/backend/copilot/bot/bot_backend.py
  • autogpt_platform/backend/backend/copilot/bot/handler.py
  • autogpt_platform/backend/backend/copilot/bot/handler_test.py
🔇 Additional comments (4)
autogpt_platform/backend/backend/copilot/bot/adapters/discord/adapter.py (1)

24-24: LGTM!

Also applies to: 58-61, 465-467, 469-478, 480-500

autogpt_platform/backend/backend/copilot/bot/adapters/base.py (1)

63-73: LGTM!

Also applies to: 124-126

autogpt_platform/backend/backend/copilot/bot/bot_backend_test.py (1)

412-452: LGTM!

autogpt_platform/backend/backend/copilot/bot/handler_test.py (1)

9-49: LGTM!

Also applies to: 80-80, 403-428, 930-1008

Comment thread autogpt_platform/backend/backend/copilot/bot/bot_backend.py
Comment thread autogpt_platform/backend/backend/copilot/bot/handler.py Outdated
Comment thread autogpt_platform/backend/backend/platform_linking/chat.py
…path safety, edge cases)

- bot_backend: isolate each upload so one transport/owner-resolution failure
  becomes an upload_failed result instead of crashing the handler (Sentry HIGH)
- handler: don't enqueue a blank turn when a file-only message's every upload
  was rejected — the user already got the rejection note
- chat: sanitize the filename's path component so it can't traverse the
  workspace path; keep the raw name only for display
- adapter: log when attachments are dropped by the per-message cap
- tests: per-file failure resilience, count cap, scan_unavailable/upload_failed
  error branches, path-traversal sanitization, file-only all-rejected
Comment thread autogpt_platform/backend/backend/platform_linking/chat.py Outdated
… just the path

write_file passes filename through to the storage backend (GCS blob names), so
the raw filename could still leak ../ and path separators there. Use safe_name
for the filename arg too, matching the web upload endpoint.
Comment thread autogpt_platform/backend/backend/copilot/bot/handler.py
Batching several file-heavy messages can accumulate more than
BotChatRequest.file_ids allows (max_length=20), which would fail validation and
surface a vague error. Cap the drained file_ids to MAX_TURN_FILE_IDS (with a
log) so the turn still runs.
Comment thread autogpt_platform/backend/backend/copilot/bot/handler.py Outdated

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Caution

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

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

135-140: 🩺 Stability & Availability | 🟠 Major | ⚡ Quick win

Handle upload RPC failures before continuing the turn.

Line 135 can raise before the rejection-result path runs, which drops the whole message without user feedback; for text + attachment messages it also prevents the text turn from being enqueued.

Suggested fix
-        results = await self._api.upload_workspace_files(
-            platform=ctx.platform,
-            platform_user_id=ctx.user_id,
-            platform_server_id=ctx.server_id,
-            attachments=ctx.attachments,
-        )
+        try:
+            results = await self._api.upload_workspace_files(
+                platform=ctx.platform,
+                platform_user_id=ctx.user_id,
+                platform_server_id=ctx.server_id,
+                attachments=ctx.attachments,
+            )
+        except Exception:
+            logger.exception(
+                "Failed to upload inbound attachment(s) for target %s", target_id
+            )
+            await adapter.send_message(
+                target_id,
+                "I couldn't upload the attached file(s). Please try again in a moment.",
+            )
+            return []
🤖 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/copilot/bot/handler.py` around lines 135 -
140, The upload step in the bot turn flow can fail before the rejection-result
path is reached, which causes the message to be dropped and can block the text
turn from being enqueued. Update the handler logic around
self._api.upload_workspace_files in the bot handler so upload RPC errors are
caught and converted into the existing rejection handling before any further
processing continues. Keep the fix localized to the turn-processing path that
uses ctx.attachments so text-only continuation still proceeds when 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.

Outside diff comments:
In `@autogpt_platform/backend/backend/copilot/bot/handler.py`:
- Around line 135-140: The upload step in the bot turn flow can fail before the
rejection-result path is reached, which causes the message to be dropped and can
block the text turn from being enqueued. Update the handler logic around
self._api.upload_workspace_files in the bot handler so upload RPC errors are
caught and converted into the existing rejection handling before any further
processing continues. Keep the fix localized to the turn-processing path that
uses ctx.attachments so text-only continuation still proceeds when appropriate.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: b63cad0c-3870-492f-8b74-d43b0c3661b9

📥 Commits

Reviewing files that changed from the base of the PR and between 966b1de and 8396a97.

📒 Files selected for processing (2)
  • autogpt_platform/backend/backend/copilot/bot/handler.py
  • autogpt_platform/backend/backend/copilot/bot/handler_test.py
🚧 Files skipped from review as they are similar to previous changes (1)
  • autogpt_platform/backend/backend/copilot/bot/handler_test.py
📜 Review details
⏰ Context from checks skipped due to timeout. (13)
  • GitHub Check: check API types
  • GitHub Check: type-check (3.11)
  • GitHub Check: test (3.11)
  • GitHub Check: test (3.13)
  • GitHub Check: type-check (3.13)
  • GitHub Check: lint
  • GitHub Check: type-check (3.12)
  • GitHub Check: test (3.12)
  • GitHub Check: Seer Code Review
  • GitHub Check: Check PR Status
  • GitHub Check: Analyze (typescript)
  • GitHub Check: end-to-end tests
  • GitHub Check: Analyze (python)
🧰 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: Use poetry run ... command for executing Python package dependencies
Use top-level imports only — avoid local/inner imports except for lazy imports of heavy optional dependencies like openpyxl
Use absolute imports with from backend.module import ... for cross-package imports; single-dot relative imports are acceptable for sibling modules within the same package; avoid double-dot relative imports
Do not use duck typing — avoid hasattr/getattr/isinstance for type dispatch; use typed interfaces/unions/protocols instead
Use Pydantic models over dataclass/namedtuple/dict for structured data
Do not use linter suppressors — no # type: ignore, # noqa, # pyright: ignore; fix the type/code instead
Prefer list comprehensions over manual loop-and-append patterns
Use early return with guard clauses first to avoid deep nesting
Use %s for deferred interpolation in debug log statements for efficiency; use f-strings elsewhere for readability (e.g., logger.debug("Processing %s items", count) vs logger.info(f"Processing {count} items"))
Sanitize error paths by using os.path.basename() in error messages to avoid leaking directory structure
Be aware of TOCTOU (Time-Of-Check-Time-Of-Use) issues — avoid check-then-act patterns for file access and credit charging
Use transaction=True for Redis pipelines to ensure atomicity on multi-step operations
Use max(0, value) guards for computed values that should never be negative
Keep files under ~300 lines; if a file grows beyond this, split by responsibility (extract helpers, models, or a sub-module into a new file)
Keep functions under ~40 lines; extract named helpers when a function grows longer
...

Files:

  • autogpt_platform/backend/backend/copilot/bot/handler.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/bot/handler.py
🧠 Learnings (14)
📚 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/bot/handler.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/bot/handler.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/bot/handler.py
📚 Learning: 2026-06-06T12:22:37.648Z
Learnt from: anvyle
Repo: Significant-Gravitas/AutoGPT PR: 13302
File: autogpt_platform/backend/backend/copilot/tools/agent_search.py:579-583
Timestamp: 2026-06-06T12:22:37.648Z
Learning: When writing LLM-facing instruction strings that trigger tool calls in this AutoGPT codebase, use the exact registered tool name `view_agent_output` (as defined in `backend/copilot/tools/agent_output.py` via its `name` property and exported via `TOOL_REGISTRY`). Do not reference the bare name `agent_output`, since it is not a valid tool name and will cause tool invocation to fail.

Applied to files:

  • autogpt_platform/backend/backend/copilot/bot/handler.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/bot/handler.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/bot/handler.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/bot/handler.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/bot/handler.py
📚 Learning: 2026-05-23T05:29:43.085Z
Learnt from: majdyz
Repo: Significant-Gravitas/AutoGPT PR: 13200
File: autogpt_platform/backend/backend/executor/scheduler.py:590-593
Timestamp: 2026-05-23T05:29:43.085Z
Learning: When reviewing Python code that uses Pydantic discriminated/tagged unions (e.g., `Annotated[Union[...], Field(discriminator="kind")]`), recognize that using `isinstance(x, SomeVariantInfo)` to narrow the union is an intentional and correct runtime guard and should also enable static type narrowing in tools like Pyright. Do not recommend replacing such `isinstance`-based narrowing with `cast(...)` when the check already proves the variant at runtime.

Applied to files:

  • autogpt_platform/backend/backend/copilot/bot/handler.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/bot/handler.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/bot/handler.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/bot/handler.py
📚 Learning: 2026-05-26T14:24:34.866Z
Learnt from: Abhi1992002
Repo: Significant-Gravitas/AutoGPT PR: 13217
File: autogpt_platform/backend/backend/api/features/search/service.py:137-137
Timestamp: 2026-05-26T14:24:34.866Z
Learning: In the Significant-Gravitas/AutoGPT backend, treat `user_id` (an opaque UUID used only for correlation/tracing) as non-PII. Do not flag direct logging of `user_id` in `logger.warning`/`logger.info` statements as a PII exposure issue, as the established convention is to log `user_id` for tracing while reserving PII for fields like email or display name.

Applied to files:

  • autogpt_platform/backend/backend/copilot/bot/handler.py
📚 Learning: 2026-06-11T19:39:10.493Z
Learnt from: ntindle
Repo: Significant-Gravitas/AutoGPT PR: 13337
File: autogpt_platform/backend/backend/copilot/graphiti/reranker.py:0-0
Timestamp: 2026-06-11T19:39:10.493Z
Learning: In the Significant-Gravitas/AutoGPT Python backend, when calling the OpenAI Python client `chat.completions.create`, construct the `messages` payload using the concrete typed-dict variants from `openai.types.chat` (e.g., `ChatCompletionSystemMessageParam`, `ChatCompletionUserMessageParam`, etc.) rather than trying to instantiate `ChatCompletionMessageParam` directly. `ChatCompletionMessageParam` is a `Union` alias and is not constructible, so `ChatCompletionMessageParam(role=..., content=...)` should fail type checking. Build each message element with the appropriate concrete typed dict and then annotate the resulting list as `list[ChatCompletionMessageParam]` (e.g., `messages: list[ChatCompletionMessageParam] = [ChatCompletionSystemMessageParam(...), ...]`).

Applied to files:

  • autogpt_platform/backend/backend/copilot/bot/handler.py
🔇 Additional comments (1)
autogpt_platform/backend/backend/copilot/bot/handler.py (1)

45-49: LGTM!

Also applies to: 77-84, 116-126, 141-145, 220-225, 239-248, 375-381, 470-480

…channel message has no usable uploads

A channel @mention creates and subscribes a thread before uploads run. If the
message is file-only and every upload fails, we early-return without a turn —
which left the thread subscribed (and lingering for 7 days). Unsubscribe the
just-created thread on that path.
…load path errors

bot_backend already turns per-file failures into results, but a total failure of
the upload call (e.g. RPC transport down) could still raise and drop the whole
message — including the text turn. Catch it in _upload_attachments, notify the
user, and return no file_ids so any text still goes through.
Comment thread autogpt_platform/backend/backend/copilot/bot/handler.py Outdated
… message text

The 'nothing to enqueue' guard checked message_text, which includes thread
history on the first @-into an unowned thread — so a file-only message whose
uploads all failed slipped past and enqueued a turn that answered only old
context. Gate on actual new input (ctx.text + file_ids) instead, and pass a
file-only nudge as the current-message body via _message_text.
Comment thread autogpt_platform/backend/backend/platform_linking/chat.py
…' upload

NotFoundError subclasses ValueError, so the broad 'except ValueError' (meant for
write_file's size/quota errors) would mislabel a missing user/workspace as a
storage rejection. Re-raise NotFoundError before the ValueError catch so it
surfaces as a linking error.
ntindle
ntindle previously approved these changes Jun 24, 2026
Comment thread autogpt_platform/backend/backend/copilot/bot/adapters/discord/adapter.py Outdated
@github-project-automation github-project-automation Bot moved this from 🆕 Needs initial review to 👍🏼 Mergeable in AutoGPT development kanban Jun 24, 2026
…attachments

Files that couldn't be ingested were silently dropped — the model assumed it
had read them. Now both stages are surfaced: adapter-stage skips (too large,
failed download, over the per-message cap) ride on MessageContext, and combined
with upload-stage rejections (virus/quota) they produce a user note plus a
'[Note: these attachments are unavailable to you — do not claim to have read
them]' line injected into the turn so AutoPilot won't hallucinate having read a
dropped file.
ntindle
ntindle previously approved these changes Jun 25, 2026
Comment thread autogpt_platform/backend/backend/platform_linking/manager.py
…space_file

Align the chat.py helper name with the RPC method, models, and bot_backend
wrapper (all already 'workspace'), so the manager method delegates to a
same-named function — mirroring the existing start_chat_turn pattern.
Addresses review feedback on the chat<->workspace naming swap.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

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/platform_linking/chat.py (1)

81-95: 🔒 Security & Privacy | 🟡 Minor | ⚡ Quick win

Reject "." and ".." after basename stripping.

rsplit("/", 1)[-1] still yields "." or ".." for inputs like ".", "..", or "dir/..". That value then flows into uploads/{uuid}/{safe_name}, which reintroduces a special path segment into the stored workspace path.

Suggested fix
+import os
+
 ...
-    safe_name = request.filename.replace("\\", "/").rsplit("/", 1)[-1] or "file"
+    safe_name = os.path.basename(request.filename.replace("\\", "/"))
+    if safe_name in {"", ".", ".."}:
+        safe_name = "file"
🤖 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/platform_linking/chat.py` around lines 81 -
95, The filename sanitization in chat.py still allows "." and ".." to survive
basename stripping, which can reintroduce special path segments into the stored
upload path. Update the safe_name handling in the upload flow around
request.filename and WorkspaceManager.write_file so that after the existing
basename extraction, "." and ".." are rejected and replaced with the fallback
name (or otherwise invalidated) before building
uploads/{uuid4().hex}/{safe_name}. Keep the fix localized to the
request.filename sanitization logic used for stored and uploaded filenames.
🤖 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.

Outside diff comments:
In `@autogpt_platform/backend/backend/platform_linking/chat.py`:
- Around line 81-95: The filename sanitization in chat.py still allows "." and
".." to survive basename stripping, which can reintroduce special path segments
into the stored upload path. Update the safe_name handling in the upload flow
around request.filename and WorkspaceManager.write_file so that after the
existing basename extraction, "." and ".." are rejected and replaced with the
fallback name (or otherwise invalidated) before building
uploads/{uuid4().hex}/{safe_name}. Keep the fix localized to the
request.filename sanitization logic used for stored and uploaded filenames.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 2d1cb779-a9bb-4dc5-b089-264c12da5f23

📥 Commits

Reviewing files that changed from the base of the PR and between ade6bcc and 3e60438.

📒 Files selected for processing (3)
  • autogpt_platform/backend/backend/platform_linking/chat.py
  • autogpt_platform/backend/backend/platform_linking/chat_test.py
  • autogpt_platform/backend/backend/platform_linking/manager.py
🚧 Files skipped from review as they are similar to previous changes (1)
  • autogpt_platform/backend/backend/platform_linking/manager.py
📜 Review details
⏰ Context from checks skipped due to timeout. (12)
  • GitHub Check: check API types
  • GitHub Check: Seer Code Review
  • GitHub Check: type-check (3.11)
  • GitHub Check: type-check (3.12)
  • GitHub Check: test (3.12)
  • GitHub Check: test (3.13)
  • GitHub Check: type-check (3.13)
  • GitHub Check: Check PR Status
  • GitHub Check: test (3.11)
  • GitHub Check: Analyze (typescript)
  • GitHub Check: Analyze (python)
  • GitHub Check: end-to-end tests
🧰 Additional context used
📓 Path-based instructions (3)
autogpt_platform/backend/**/*.py

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

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

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

Files:

  • autogpt_platform/backend/backend/platform_linking/chat_test.py
  • autogpt_platform/backend/backend/platform_linking/chat.py
autogpt_platform/{backend,autogpt_libs}/**/*.py

📄 CodeRabbit inference engine (AGENTS.md)

Format Python code with poetry run format

Files:

  • autogpt_platform/backend/backend/platform_linking/chat_test.py
  • autogpt_platform/backend/backend/platform_linking/chat.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.py naming 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
Use AsyncMock from unittest.mock for async functions in tests
When writing tests, use Test-Driven Development (TDD): write failing tests marked with @pytest.mark.xfail before implementation, then remove the marker once the implementation is complete
When creating snapshots in tests, use poetry run pytest path/to/test.py --snapshot-update; always review snapshot changes with git diff before committing

Files:

  • autogpt_platform/backend/backend/platform_linking/chat_test.py
🧠 Learnings (11)
📚 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/platform_linking/chat_test.py
  • autogpt_platform/backend/backend/platform_linking/chat.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/platform_linking/chat_test.py
  • autogpt_platform/backend/backend/platform_linking/chat.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/platform_linking/chat_test.py
  • autogpt_platform/backend/backend/platform_linking/chat.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/platform_linking/chat_test.py
  • autogpt_platform/backend/backend/platform_linking/chat.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/platform_linking/chat_test.py
  • autogpt_platform/backend/backend/platform_linking/chat.py
📚 Learning: 2026-05-23T05:29:43.085Z
Learnt from: majdyz
Repo: Significant-Gravitas/AutoGPT PR: 13200
File: autogpt_platform/backend/backend/executor/scheduler.py:590-593
Timestamp: 2026-05-23T05:29:43.085Z
Learning: When reviewing Python code that uses Pydantic discriminated/tagged unions (e.g., `Annotated[Union[...], Field(discriminator="kind")]`), recognize that using `isinstance(x, SomeVariantInfo)` to narrow the union is an intentional and correct runtime guard and should also enable static type narrowing in tools like Pyright. Do not recommend replacing such `isinstance`-based narrowing with `cast(...)` when the check already proves the variant at runtime.

Applied to files:

  • autogpt_platform/backend/backend/platform_linking/chat_test.py
  • autogpt_platform/backend/backend/platform_linking/chat.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/platform_linking/chat_test.py
  • autogpt_platform/backend/backend/platform_linking/chat.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/platform_linking/chat_test.py
  • autogpt_platform/backend/backend/platform_linking/chat.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/platform_linking/chat_test.py
  • autogpt_platform/backend/backend/platform_linking/chat.py
📚 Learning: 2026-05-26T14:24:34.866Z
Learnt from: Abhi1992002
Repo: Significant-Gravitas/AutoGPT PR: 13217
File: autogpt_platform/backend/backend/api/features/search/service.py:137-137
Timestamp: 2026-05-26T14:24:34.866Z
Learning: In the Significant-Gravitas/AutoGPT backend, treat `user_id` (an opaque UUID used only for correlation/tracing) as non-PII. Do not flag direct logging of `user_id` in `logger.warning`/`logger.info` statements as a PII exposure issue, as the established convention is to log `user_id` for tracing while reserving PII for fields like email or display name.

Applied to files:

  • autogpt_platform/backend/backend/platform_linking/chat_test.py
  • autogpt_platform/backend/backend/platform_linking/chat.py
📚 Learning: 2026-06-11T19:39:10.493Z
Learnt from: ntindle
Repo: Significant-Gravitas/AutoGPT PR: 13337
File: autogpt_platform/backend/backend/copilot/graphiti/reranker.py:0-0
Timestamp: 2026-06-11T19:39:10.493Z
Learning: In the Significant-Gravitas/AutoGPT Python backend, when calling the OpenAI Python client `chat.completions.create`, construct the `messages` payload using the concrete typed-dict variants from `openai.types.chat` (e.g., `ChatCompletionSystemMessageParam`, `ChatCompletionUserMessageParam`, etc.) rather than trying to instantiate `ChatCompletionMessageParam` directly. `ChatCompletionMessageParam` is a `Union` alias and is not constructible, so `ChatCompletionMessageParam(role=..., content=...)` should fail type checking. Build each message element with the appropriate concrete typed dict and then annotate the resulting list as `list[ChatCompletionMessageParam]` (e.g., `messages: list[ChatCompletionMessageParam] = [ChatCompletionSystemMessageParam(...), ...]`).

Applied to files:

  • autogpt_platform/backend/backend/platform_linking/chat_test.py
  • autogpt_platform/backend/backend/platform_linking/chat.py
🔇 Additional comments (2)
autogpt_platform/backend/backend/platform_linking/chat.py (1)

98-114: LGTM!

Also applies to: 175-175

autogpt_platform/backend/backend/platform_linking/chat_test.py (1)

11-11: LGTM!

Also applies to: 223-325

Basename stripping still let '.'/'..' through (e.g. filename '..' or
'dir/..'), reintroducing a special segment into uploads/<uuid>/<name> that
resolves back out of the unique subdir. Use os.path.basename and fall back to
'file' for ''/'.'/'..'. Addresses CodeRabbit review.
@Bentlybro
Bentlybro added this pull request to the merge queue Jun 30, 2026
Merged via the queue into dev with commit b107722 Jun 30, 2026
40 checks passed
@Bentlybro
Bentlybro deleted the feat/copilot-bot-file-upload branch June 30, 2026 13:29
@github-project-automation github-project-automation Bot moved this from 👍🏼 Mergeable to ✅ Done in AutoGPT development kanban Jun 30, 2026
gaurav0107 pushed a commit to gaurav0107/AutoGPT that referenced this pull request Jul 2, 2026
… can read them (Significant-Gravitas#13464)

## Why

The Discord CoPilot bot's file-upload feature
([Significant-Gravitas#13427](Significant-Gravitas#13427))
uploaded attachments with a **session-less** `WorkspaceManager`, storing
them at `uploads/<uuid>/<name>`. The web UI
(`api/features/workspace/routes.py`) uploads the same files
**session-scoped** to `/sessions/<session_id>/<name>`.

The copilot executor reads a turn's attachments through a
**session-scoped** manager, so it never found the bot's file. Symptom in
dev: AutoPilot saw the filename but couldn't read the contents ("saved
but the path doesn't exist") — while an identical file uploaded via the
web UI read fine (`Read test.txt from
workspace:/sessions/<id>/test.txt`).

Follow-up to Significant-Gravitas#13427, which shipped the upload pipeline but stored files
session-less.

## What

Store bot-uploaded attachments the same way the web endpoint does —
session-scoped — so AutoPilot reads them identically.

## How

- **`upload_workspace_file`** now uses `WorkspaceManager(owner,
workspace, session_id)` + `write_file(content, filename, …)` — the exact
documented pattern the web upload endpoint uses (`workspace/routes.py`).
Dropped the ad-hoc `uploads/<uuid>/` path (and the `os.path` usage —
workspace paths are POSIX).
- The bot resolves its session only when a turn *starts* (after the
upload), so a new **`ensure_chat_session`** RPC lets the handler
resolve/create the session **before** uploading, thread it into the
upload, and cache it so the turn reuses the same session.
`start_chat_turn` shares the same `_resolve_or_create_session` helper.
- Plumbing: `session_id` on `WorkspaceUploadRequest`;
`ensure_chat_session` exposed on the manager + client;
`bot_backend.ensure_session`; `sessions.get_session`.

No new storage/DB API — only the documented
`WorkspaceManager(session_id)` + `write_file`.

## Testing

- `poetry run pytest backend/platform_linking/chat_test.py
backend/copilot/bot/handler_test.py
backend/copilot/bot/bot_backend_test.py` — green (incl. new tests:
session-scoped upload, `ensure_chat_session` reuse/create/unlinked,
handler ensure-session flow).
- `ruff` / `black` / `isort` clean.
Aastha204 pushed a commit to Aastha204/AutoGPT that referenced this pull request Jul 3, 2026
…e, not a host path (Significant-Gravitas#13470)

## Why

Discord-bot file attachments upload correctly — AV-scanned (ClamAV via
`WorkspaceManager.write_file`), stored session-scoped at
`/sessions/<session_id>/<name>`
([Significant-Gravitas#13427](Significant-Gravitas#13427) +
[Significant-Gravitas#13464](Significant-Gravitas#13464) +
infra GCS perms) — but AutoPilot **still can't read them**. From the
model's own trace in dev:

> "The system says it was saved to `/tmp/copilot-804ca4e7-…/test.txt`
but it doesn't exist."

Root cause (`sdk/service.py::_prepare_file_attachments`): non-image
attachments are written to the **executor host's** `sdk_cwd` and the
model is told *"saved to `<host path>`. Use the Read tool."* Two
problems:

1. **In E2B mode (the prod/dev default — `use_e2b_sandbox=True`)** the
model's file tools operate on the **remote E2B sandbox filesystem**
(`e2b_file_tools.py` deliberately routes non-tool-result paths to
`sandbox.files.read`). The host-side `sdk_cwd` file doesn't exist there.
2. The built-in `Read` tool the hint names is **disallowed** in every
mode (`SDK_DISALLOWED_TOOLS`).

So the model is pointed at a path it cannot see, with a tool it cannot
use. Web-uploaded files work because the model reads them via
`read_workspace_file` (observed in production: `Read test.txt from
workspace:/sessions/<id>/test.txt`) — which resolves by `file_id` from
the workspace, independent of any local disk.

## What

Point the model at `read_workspace_file` with the `file_id` for
non-image attachments, instead of a host path + the disallowed `Read`
tool.

## How

In `_prepare_file_attachments`:
- Non-image file descriptions now carry `file_id: <id>` instead of the
host path.
- The hint instructs `read_workspace_file` (with `save_to_path`
mentioned for copying into the working directory) instead of "Use the
Read tool".
- The `sdk_cwd` copy is **still written**, preserving the
working-directory affordance for non-E2B tooling — the model just isn't
pointed at it.

Blast radius: this function only runs for turns with attached
`file_ids`. Web attachment turns get the same instruction that already
matches their observed working behaviour; everything else is untouched.

Completes the bot file-upload chain: Significant-Gravitas#13427 (upload pipeline) →
infra#348 (GCS write perms) → Significant-Gravitas#13464 (session-scoped storage) → **this**
(readable reference).

## Testing

- TDD: updated/added tests in
`sdk/service_test.py::TestPrepareFileAttachments` pinning the new hint
(file_id present, host path absent, `read_workspace_file` named, no "Use
the Read tool") — failed before the fix, 7/7 pass after.
- No-regression check: full `service_test.py` run compared against clean
`dev` — identical pre-existing failure set (env-dependent tests under
`--noconftest`), zero new failures.
- `ruff` / `black` / `isort` clean.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

platform/backend AutoGPT Platform - Back end size/xl

Projects

Status: ✅ Done

Development

Successfully merging this pull request may close these issues.

2 participants