feat(backend/copilot): parallel block execution via infrastructure-level pre-launch - #12472
Conversation
|
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 per-session background job tracking via a ContextVar, two async tools to start and retrieve background block executions, new job response models, helpers for prepare/HITL flows, refactors run_block to use preparation, and adds tests and OpenAPI enum updates. Changes
Sequence DiagramsequenceDiagram
autonumber
actor Client
participant RunBlockAsync as RunBlockAsyncTool
participant JobRegistry as BackgroundJobs (ContextVar)
participant Executor as BlockExecutor
participant GetResult as GetBlockResultTool
Client->>RunBlockAsync: execute(block_id, inputs)
RunBlockAsync->>RunBlockAsync: prepare_block_for_execution / check_hitl_review
RunBlockAsync->>Executor: schedule async Task (job_id)
RunBlockAsync->>JobRegistry: store Task under job_id
RunBlockAsync-->>Client: BlockJobStartedResponse(job_id)
Client->>GetResult: execute(job_id)
GetResult->>JobRegistry: lookup Task by job_id
GetResult->>Executor: await Task completion
Executor-->>GetResult: result or exception
GetResult->>JobRegistry: remove finished job
GetResult-->>Client: BlockJobResultResponse / ErrorResponse
Estimated code review effort🎯 4 (Complex) | ⏱️ ~60 minutes Possibly related PRs
Suggested labels
Suggested reviewers
Poem
🚥 Pre-merge checks | ✅ 2 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (2 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
🔍 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: 3 conflict(s), 0 medium risk, 3 low risk (out of 6 PRs with file overlap) Auto-generated on push. Ignores: |
There was a problem hiding this comment.
Actionable comments posted: 2
🧹 Nitpick comments (4)
autogpt_platform/backend/backend/copilot/tools/run_block_async_test.py (1)
100-149: Happy-path test doesn't verify task storage in jobs dict.The test patches
get_background_jobsto returnjobsdict but never asserts that a task was actually stored in it. Since the tool returnsBlockJobStartedResponseregardless of whetherjobsisNone(only logs a warning), this test would pass even if the task storage was broken.Consider adding an assertion that verifies a task was added to the
jobsdict:💡 Suggested addition after line 149
# Verify task was stored in background jobs assert len(jobs) == 1 assert result.job_id in jobs🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@autogpt_platform/backend/backend/copilot/tools/run_block_async_test.py` around lines 100 - 149, The test uses a mocked get_background_jobs returning the local jobs dict but never asserts that run_block_async_tool._execute actually stored the created task in that dict; add assertions after the call to _execute to verify the task was stored (e.g., assert len(jobs) == 1 and assert result.job_id in jobs) so the happy-path confirms background job registration when BlockJobStartedResponse is returned.autogpt_platform/backend/backend/copilot/tools/run_block_async.py (1)
324-337: Task exceptions are silently swallowed if never awaited.If
get_block_resultis never called for a job, exceptions fromexecute_blockwill be silently ignored when the task is garbage collected (Python logs "Task exception was never retrieved"). While not a bug, it can make debugging difficult.Consider adding a done callback to log unhandled exceptions:
💡 Optional improvement
task = asyncio.create_task(_run()) +task.add_done_callback( + lambda t: logger.error( + "Background block job failed: %s", t.exception() + ) if t.exception() else None +)🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@autogpt_platform/backend/backend/copilot/tools/run_block_async.py` around lines 324 - 337, The created background task (task from asyncio.create_task(_run())) can swallow exceptions if never awaited; add a done callback on the task (after creation, where job_id is stored and get_background_jobs() is used) that checks task.done() and if task.exception() is not None logs the exception and context (job_id, session_id, maybe block id) so unhandled exceptions from _run()/execute_block are surfaced; implement this in the same block that assigns jobs[job_id] = task using task.add_done_callback(...) to call a small handler that inspects task.exception() and calls logger.error with the error and identifiers.autogpt_platform/backend/backend/copilot/sdk/tool_adapter.py (1)
53-59: Consider cleanup for abandoned background jobs.If a session ends (client disconnects, timeout, etc.) before the user calls
get_block_result, background tasks remain in the dict and continue running to completion, but their results are never collected. While this doesn't leak memory indefinitely (the dict is per-session and GC'd when the session context is released), the tasks themselves run unsupervised.For robustness, consider cancelling pending tasks when the session ends, or at minimum logging a warning in a session-cleanup hook if orphaned tasks exist.
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@autogpt_platform/backend/backend/copilot/sdk/tool_adapter.py` around lines 53 - 59, Session background tasks stored in the ContextVar _background_jobs can be left running if a session ends before get_block_result is called; update the session cleanup logic (the code path that tears down set_execution_context()) to iterate over _background_jobs.get() and cancel any pending asyncio.Tasks created by run_block_async, optionally awaiting them with a short timeout and removing them from the dict, and if cancellation is skipped log a warning listing orphaned job_ids so operators can triage; ensure you reference and mutate the same ContextVar (_background_jobs) and keep behavior consistent with run_block_async and get_block_result.autogpt_platform/backend/backend/copilot/tools/get_block_result.py (1)
84-98: No timeout for awaiting background task.The
await taskon line 85 blocks indefinitely until the block execution completes. If a block hangs or takes an extremely long time, this call will never return, potentially causing client timeouts or resource exhaustion.Consider adding an optional timeout parameter or a reasonable default:
💡 Suggested improvement
+import asyncio + +# In parameters property: +"timeout": { + "type": "number", + "description": "Maximum seconds to wait for result (default: 300)", +} # In _execute: +timeout = kwargs.get("timeout", 300.0) try: - result = await task + result = await asyncio.wait_for(task, timeout=timeout) +except asyncio.TimeoutError: + return ErrorResponse( + message=f"Block execution timed out after {timeout}s. Job is still running.", + session_id=session_id, + ) except Exception as exc:Note: Don't pop the job on timeout since it's still running — the user may want to retry.
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@autogpt_platform/backend/backend/copilot/tools/get_block_result.py` around lines 84 - 98, The await on the background "task" can block indefinitely; wrap the await task in asyncio.wait_for with a configurable timeout (e.g., timeout_seconds parameter or a default like DEFAULT_BLOCK_TIMEOUT) inside the same function that references job_id, jobs, and BlockJobResultResponse, and handle asyncio.TimeoutError separately: on timeout, log a warning including job_id and timeout, do NOT pop the job from jobs (since it is still running), and return a BlockJobResultResponse indicating timeout (success=False, appropriate message and error string). Also keep the existing Exception handler for other errors to pop the job and return failure as before.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@autogpt_platform/backend/backend/copilot/tools/run_block_async.py`:
- Around line 329-337: The code currently logs when get_background_jobs()
returns None but still proceeds to return a BlockJobStartedResponse with job_id;
instead, in the run_block_async pathway that creates task and computes job_id
(variables job_id, task, session_id), detect when jobs is None and return an
ErrorResponse immediately (and keep the warning log) so callers won’t receive a
job_id that can’t be retrieved via get_block_result; modify the branch that
currently does "if jobs is None: logger.warning(...)" to return an ErrorResponse
with a clear message about the missing background job store, otherwise continue
to assign jobs[job_id] = task and return BlockJobStartedResponse as before.
In `@autogpt_platform/frontend/src/app/api/openapi.json`:
- Around line 11968-11969: The ResponseType enum was extended with
"block_job_started" and "block_job_result" but the OpenAPI spec lacks
corresponding schemas; add backend models BlockJobStartedResponse and
BlockJobResultResponse and include them in the tool-response export used by the
/api/chat/schema/tool-responses route (or the module that builds that response
union), update any model exports/imports so the tool-response union references
these new types, then regenerate the OpenAPI JSON (do not hand-edit
autogpt_platform/frontend/src/app/api/openapi.json) so the frontend typings
include the new async block response types.
---
Nitpick comments:
In `@autogpt_platform/backend/backend/copilot/sdk/tool_adapter.py`:
- Around line 53-59: Session background tasks stored in the ContextVar
_background_jobs can be left running if a session ends before get_block_result
is called; update the session cleanup logic (the code path that tears down
set_execution_context()) to iterate over _background_jobs.get() and cancel any
pending asyncio.Tasks created by run_block_async, optionally awaiting them with
a short timeout and removing them from the dict, and if cancellation is skipped
log a warning listing orphaned job_ids so operators can triage; ensure you
reference and mutate the same ContextVar (_background_jobs) and keep behavior
consistent with run_block_async and get_block_result.
In `@autogpt_platform/backend/backend/copilot/tools/get_block_result.py`:
- Around line 84-98: The await on the background "task" can block indefinitely;
wrap the await task in asyncio.wait_for with a configurable timeout (e.g.,
timeout_seconds parameter or a default like DEFAULT_BLOCK_TIMEOUT) inside the
same function that references job_id, jobs, and BlockJobResultResponse, and
handle asyncio.TimeoutError separately: on timeout, log a warning including
job_id and timeout, do NOT pop the job from jobs (since it is still running),
and return a BlockJobResultResponse indicating timeout (success=False,
appropriate message and error string). Also keep the existing Exception handler
for other errors to pop the job and return failure as before.
In `@autogpt_platform/backend/backend/copilot/tools/run_block_async_test.py`:
- Around line 100-149: The test uses a mocked get_background_jobs returning the
local jobs dict but never asserts that run_block_async_tool._execute actually
stored the created task in that dict; add assertions after the call to _execute
to verify the task was stored (e.g., assert len(jobs) == 1 and assert
result.job_id in jobs) so the happy-path confirms background job registration
when BlockJobStartedResponse is returned.
In `@autogpt_platform/backend/backend/copilot/tools/run_block_async.py`:
- Around line 324-337: The created background task (task from
asyncio.create_task(_run())) can swallow exceptions if never awaited; add a done
callback on the task (after creation, where job_id is stored and
get_background_jobs() is used) that checks task.done() and if task.exception()
is not None logs the exception and context (job_id, session_id, maybe block id)
so unhandled exceptions from _run()/execute_block are surfaced; implement this
in the same block that assigns jobs[job_id] = task using
task.add_done_callback(...) to call a small handler that inspects
task.exception() and calls logger.error with the error and identifiers.
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro
Run ID: 51892983-52f3-4cbc-bc13-c9d2b1fd43dd
📒 Files selected for processing (7)
autogpt_platform/backend/backend/copilot/sdk/tool_adapter.pyautogpt_platform/backend/backend/copilot/tools/__init__.pyautogpt_platform/backend/backend/copilot/tools/get_block_result.pyautogpt_platform/backend/backend/copilot/tools/models.pyautogpt_platform/backend/backend/copilot/tools/run_block_async.pyautogpt_platform/backend/backend/copilot/tools/run_block_async_test.pyautogpt_platform/frontend/src/app/api/openapi.json
📜 Review details
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (14)
- GitHub Check: check API types
- GitHub Check: integration_test
- GitHub Check: Seer Code Review
- GitHub Check: end-to-end tests
- GitHub Check: conflicts
- GitHub Check: type-check (3.11)
- GitHub Check: type-check (3.12)
- GitHub Check: type-check (3.13)
- GitHub Check: test (3.13)
- GitHub Check: test (3.11)
- GitHub Check: test (3.12)
- GitHub Check: Check PR Status
- GitHub Check: Analyze (python)
- GitHub Check: Analyze (typescript)
🧰 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
Files:
autogpt_platform/backend/backend/copilot/sdk/tool_adapter.pyautogpt_platform/backend/backend/copilot/tools/models.pyautogpt_platform/backend/backend/copilot/tools/__init__.pyautogpt_platform/backend/backend/copilot/tools/get_block_result.pyautogpt_platform/backend/backend/copilot/tools/run_block_async.pyautogpt_platform/backend/backend/copilot/tools/run_block_async_test.py
autogpt_platform/backend/**/*.{py,txt}
📄 CodeRabbit inference engine (autogpt_platform/backend/CLAUDE.md)
Use
poetry runprefix for all Python commands, including testing, linting, formatting, and migrations
Files:
autogpt_platform/backend/backend/copilot/sdk/tool_adapter.pyautogpt_platform/backend/backend/copilot/tools/models.pyautogpt_platform/backend/backend/copilot/tools/__init__.pyautogpt_platform/backend/backend/copilot/tools/get_block_result.pyautogpt_platform/backend/backend/copilot/tools/run_block_async.pyautogpt_platform/backend/backend/copilot/tools/run_block_async_test.py
autogpt_platform/backend/backend/**/*.py
📄 CodeRabbit inference engine (autogpt_platform/backend/CLAUDE.md)
Use Prisma ORM for database operations in PostgreSQL with pgvector for embeddings
Files:
autogpt_platform/backend/backend/copilot/sdk/tool_adapter.pyautogpt_platform/backend/backend/copilot/tools/models.pyautogpt_platform/backend/backend/copilot/tools/__init__.pyautogpt_platform/backend/backend/copilot/tools/get_block_result.pyautogpt_platform/backend/backend/copilot/tools/run_block_async.pyautogpt_platform/backend/backend/copilot/tools/run_block_async_test.py
autogpt_platform/**/*.py
📄 CodeRabbit inference engine (AGENTS.md)
Format Python code with
poetry run format
Files:
autogpt_platform/backend/backend/copilot/sdk/tool_adapter.pyautogpt_platform/backend/backend/copilot/tools/models.pyautogpt_platform/backend/backend/copilot/tools/__init__.pyautogpt_platform/backend/backend/copilot/tools/get_block_result.pyautogpt_platform/backend/backend/copilot/tools/run_block_async.pyautogpt_platform/backend/backend/copilot/tools/run_block_async_test.py
autogpt_platform/backend/**/*_test.py
📄 CodeRabbit inference engine (autogpt_platform/backend/CLAUDE.md)
autogpt_platform/backend/**/*_test.py: Always review snapshot changes withgit diffbefore committing when updating snapshots withpoetry run pytest --snapshot-update
Use pytest with snapshot testing for API responses in test files
Colocate test files with source files using the*_test.pynaming convention
Files:
autogpt_platform/backend/backend/copilot/tools/run_block_async_test.py
autogpt_platform/backend/**/*test*.py
📄 CodeRabbit inference engine (AGENTS.md)
Run
poetry run testfor backend testing (runs pytest with docker based postgres + prisma)
Files:
autogpt_platform/backend/backend/copilot/tools/run_block_async_test.py
🧠 Learnings (23)
📓 Common learnings
Learnt from: majdyz
Repo: Significant-Gravitas/AutoGPT PR: 12356
File: autogpt_platform/backend/backend/copilot/tools/run_block.py:297-300
Timestamp: 2026-03-10T08:38:33.249Z
Learning: In autogpt_platform/backend/backend/copilot/tools/run_block.py, the auto-approval key for sensitive block HITL review uses graph_exec_id (copilot-session-{session_id}) + node_id (copilot-node-{block_id}). This is intentional: approving a block type within a CoPilot session auto-approves all future invocations of that same block type within the same session, mirroring how auto-approve works in normal graph execution. The user explicitly opts into this session-scoped behavior via an auto-approve toggle. Without the toggle (default), each individual invocation requires its own approval.
Learnt from: Abhi1992002
Repo: Significant-Gravitas/AutoGPT PR: 12417
File: autogpt_platform/backend/backend/blocks/agent_mail/threads.py:80-102
Timestamp: 2026-03-16T16:30:20.657Z
Learning: In autogpt_platform/backend/backend/blocks/agent_mail/ blocks (and across the codebase), wrapping synchronous AgentMail SDK calls with `await asyncio.to_thread()` is NOT required. The block executor runs node execution in dedicated threads via `asyncio.run_coroutine_threadsafe` (manager.py lines ~745-752, ~1079), and the existing codebase pattern does not use `asyncio.to_thread` for SDK calls inside async `run()` methods.
Learnt from: majdyz
Repo: Significant-Gravitas/AutoGPT PR: 12439
File: autogpt_platform/backend/backend/blocks/autogpt_copilot.py:0-0
Timestamp: 2026-03-16T17:00:02.827Z
Learning: In autogpt_platform/backend/backend/blocks/autogpt_copilot.py, the recursion guard uses two module-level ContextVars: `_copilot_recursion_depth` (tracks current nesting depth) and `_copilot_recursion_limit` (stores the chain-wide ceiling). On the first invocation, `_copilot_recursion_limit` is set to `max_recursion_depth`; nested calls use `min(inherited_limit, max_recursion_depth)`, so they can only lower the cap, never raise it. The entry/exit logic is extracted into module-level helper functions. This is the approved pattern for preventing runaway sub-agent recursion in AutogptCopilotBlock (PR `#12439`, commits 348e9f8e2 and 3b70f61b1).
Learnt from: CR
Repo: Significant-Gravitas/AutoGPT PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2026-02-04T16:49:42.490Z
Learning: Applies to autogpt_platform/backend/backend/blocks/**/*.py : Implement 'run' method with proper error handling in backend blocks
Learnt from: majdyz
Repo: Significant-Gravitas/AutoGPT PR: 12356
File: autogpt_platform/backend/backend/copilot/constants.py:9-12
Timestamp: 2026-03-10T08:39:22.025Z
Learning: In Significant-Gravitas/AutoGPT PR `#12356`, the `COPILOT_SYNTHETIC_ID_PREFIX = "copilot-"` check in `create_auto_approval_record` (human_review.py) is intentional and safe. The `graph_exec_id` passed to this function comes from server-side `PendingHumanReview` DB records (not from user input); the API only accepts `node_exec_id` from users. Synthetic `copilot-*` IDs are only ever created server-side in `run_block.py`. The prefix skip avoids a DB lookup for a `AgentGraphExecution` record that legitimately does not exist for CoPilot sessions, while `user_id` scoping is enforced at the auth layer and on the resulting auto-approval record.
Learnt from: majdyz
Repo: Significant-Gravitas/AutoGPT PR: 12440
File: autogpt_platform/backend/backend/copilot/workflow_import/converter.py:0-0
Timestamp: 2026-03-17T10:57:10.126Z
Learning: In Significant-Gravitas/AutoGPT PR `#12440`, `autogpt_platform/backend/backend/copilot/workflow_import/converter.py` was fully rewritten (commit 732960e2d) to no longer make direct LLM/OpenAI API calls. The converter now builds a structured text prompt for AutoPilot/CoPilot instead. There is no `response.choices` access or any direct LLM client usage in this file. Do not flag `response.choices` access or LLM client initialization patterns as issues in this file.
Learnt from: CR
Repo: Significant-Gravitas/AutoGPT PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2026-02-04T16:49:42.490Z
Learning: Applies to autogpt_platform/backend/backend/blocks/**/*.py : Write tests alongside block implementation when adding new blocks in backend
Learnt from: majdyz
Repo: Significant-Gravitas/AutoGPT PR: 12173
File: autogpt_platform/backend/backend/copilot/sdk/tool_adapter.py:153-179
Timestamp: 2026-02-20T03:28:06.619Z
Learning: The copilot executor (`backend.copilot.executor`) runs in its own Docker container with Python 3.13, so Python 3.11+ features like `asyncio.timeout()` are available in copilot code even though the general backend pyproject.toml specifies `python = ">=3.10,<3.14"`.
📚 Learning: 2026-03-16T17:00:02.827Z
Learnt from: majdyz
Repo: Significant-Gravitas/AutoGPT PR: 12439
File: autogpt_platform/backend/backend/blocks/autogpt_copilot.py:0-0
Timestamp: 2026-03-16T17:00:02.827Z
Learning: In autogpt_platform/backend/backend/blocks/autogpt_copilot.py, the recursion guard uses two module-level ContextVars: `_copilot_recursion_depth` (tracks current nesting depth) and `_copilot_recursion_limit` (stores the chain-wide ceiling). On the first invocation, `_copilot_recursion_limit` is set to `max_recursion_depth`; nested calls use `min(inherited_limit, max_recursion_depth)`, so they can only lower the cap, never raise it. The entry/exit logic is extracted into module-level helper functions. This is the approved pattern for preventing runaway sub-agent recursion in AutogptCopilotBlock (PR `#12439`, commits 348e9f8e2 and 3b70f61b1).
Applied to files:
autogpt_platform/backend/backend/copilot/sdk/tool_adapter.py
📚 Learning: 2026-03-15T16:52:15.463Z
Learnt from: majdyz
Repo: Significant-Gravitas/AutoGPT PR: 12426
File: autogpt_platform/backend/backend/copilot/sdk/service.py:0-0
Timestamp: 2026-03-15T16:52:15.463Z
Learning: In Significant-Gravitas/AutoGPT (copilot backend), GitHub tokens (GH_TOKEN / GITHUB_TOKEN) for the `gh` CLI are injected lazily per-command in `autogpt_platform/backend/backend/copilot/tools/bash_exec._execute_on_e2b()` by calling `integration_creds.get_integration_env_vars(user_id)`, not on the global SDK subprocess environment in `sdk/service.py`. This scopes credentials to individual E2B sandbox command invocations and prevents token leakage into tool output streams or uploaded transcripts.
Applied to files:
autogpt_platform/backend/backend/copilot/sdk/tool_adapter.py
📚 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/sdk/tool_adapter.pyautogpt_platform/backend/backend/copilot/tools/models.pyautogpt_platform/backend/backend/copilot/tools/__init__.pyautogpt_platform/backend/backend/copilot/tools/get_block_result.pyautogpt_platform/backend/backend/copilot/tools/run_block_async.pyautogpt_platform/backend/backend/copilot/tools/run_block_async_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/sdk/tool_adapter.pyautogpt_platform/backend/backend/copilot/tools/models.pyautogpt_platform/backend/backend/copilot/tools/__init__.pyautogpt_platform/backend/backend/copilot/tools/get_block_result.pyautogpt_platform/backend/backend/copilot/tools/run_block_async.pyautogpt_platform/backend/backend/copilot/tools/run_block_async_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/copilot/sdk/tool_adapter.pyautogpt_platform/backend/backend/copilot/tools/models.pyautogpt_platform/backend/backend/copilot/tools/__init__.pyautogpt_platform/backend/backend/copilot/tools/get_block_result.pyautogpt_platform/backend/backend/copilot/tools/run_block_async.pyautogpt_platform/backend/backend/copilot/tools/run_block_async_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/copilot/sdk/tool_adapter.pyautogpt_platform/backend/backend/copilot/tools/models.pyautogpt_platform/backend/backend/copilot/tools/__init__.pyautogpt_platform/backend/backend/copilot/tools/get_block_result.pyautogpt_platform/backend/backend/copilot/tools/run_block_async.pyautogpt_platform/backend/backend/copilot/tools/run_block_async_test.py
📚 Learning: 2026-02-27T10:45:55.700Z
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:55.700Z
Learning: As of PR `#12213`, MCP tool response types (MCPToolsDiscoveredResponse, MCPToolOutputResponse) are defined in openapi.json and frontend code in autogpt_platform/frontend/src/app/(platform)/copilot/tools/RunMCPTool/helpers.tsx uses the generated types from `@/app/api/__generated__/`. Other tools like RunBlock still use inline TypeScript interfaces (e.g., BlockDetailsResponse) for SSE stream payloads that are not included in openapi.json schemas. The pattern is tool-specific: use generated types when available in openapi.json, use inline types only when the payload schema is truly SSE-stream-only and not exposed via OpenAPI.
Applied to files:
autogpt_platform/backend/backend/copilot/tools/models.pyautogpt_platform/backend/backend/copilot/tools/__init__.pyautogpt_platform/frontend/src/app/api/openapi.jsonautogpt_platform/backend/backend/copilot/tools/run_block_async.py
📚 Learning: 2026-03-17T10:57:10.126Z
Learnt from: majdyz
Repo: Significant-Gravitas/AutoGPT PR: 12440
File: autogpt_platform/backend/backend/copilot/workflow_import/converter.py:0-0
Timestamp: 2026-03-17T10:57:10.126Z
Learning: In Significant-Gravitas/AutoGPT PR `#12440`, `autogpt_platform/backend/backend/copilot/workflow_import/converter.py` was fully rewritten (commit 732960e2d) to no longer make direct LLM/OpenAI API calls. The converter now builds a structured text prompt for AutoPilot/CoPilot instead. There is no `response.choices` access or any direct LLM client usage in this file. Do not flag `response.choices` access or LLM client initialization patterns as issues in this file.
Applied to files:
autogpt_platform/backend/backend/copilot/tools/models.py
📚 Learning: 2026-03-04T12:19:39.243Z
Learnt from: majdyz
Repo: Significant-Gravitas/AutoGPT PR: 12279
File: autogpt_platform/backend/backend/copilot/tools/base.py:184-188
Timestamp: 2026-03-04T12:19:39.243Z
Learning: In autogpt_platform/backend/backend/copilot/tools/, ensure that anonymous users always pass user_id=None to tool execution methods. The anon_ prefix (e.g., anon_123) is used only for PostHog/analytics distinct_id and must not be used as an actual user_id. Use a simple truthiness check on user_id (e.g., if user_id: ... else: ... or a dedicated is_authenticated flag) to distinguish anonymous from authenticated users, and review all tool execution call sites within this directory to prevent accidentally forwarding an anon_ user_id to tools.
Applied to files:
autogpt_platform/backend/backend/copilot/tools/models.pyautogpt_platform/backend/backend/copilot/tools/__init__.pyautogpt_platform/backend/backend/copilot/tools/get_block_result.pyautogpt_platform/backend/backend/copilot/tools/run_block_async.pyautogpt_platform/backend/backend/copilot/tools/run_block_async_test.py
📚 Learning: 2026-03-16T16:35:20.978Z
Learnt from: Abhi1992002
Repo: Significant-Gravitas/AutoGPT PR: 12417
File: autogpt_platform/backend/backend/blocks/agent_mail/lists.py:96-116
Timestamp: 2026-03-16T16:35:20.978Z
Learning: In autogpt_platform/backend/backend/blocks/agent_mail/ (and any blocks using the AgentMail SDK via `from agentmail import AgentMail`), the SDK supports native async/await. SDK calls such as `client.lists.list(...)`, `client.lists.create(...)`, etc. should be called with `await` directly (e.g., `await client.lists.list(...)`). Do NOT use `asyncio.to_thread()` for these calls — the SDK is natively asynchronous.
Applied to files:
autogpt_platform/backend/backend/copilot/tools/__init__.py
📚 Learning: 2026-03-04T23:57:59.510Z
Learnt from: Pwuts
Repo: Significant-Gravitas/AutoGPT PR: 12284
File: autogpt_platform/frontend/src/app/api/openapi.json:5593-5593
Timestamp: 2026-03-04T23:57:59.510Z
Learning: In Significant-Gravitas/AutoGPT backend (FastAPI), openapi.json is autogenerated: descriptions come from route docstrings and schemas from response_model/type annotations. To prevent drift when models are renamed (e.g., AdminView variants), avoid embedding specific schema class names in route docstrings; instead describe behavior, or keep names synced via backend edits—never hand-edit frontend/src/app/api/openapi.json.
Applied to files:
autogpt_platform/frontend/src/app/api/openapi.json
📚 Learning: 2026-03-01T07:58:56.207Z
Learnt from: majdyz
Repo: Significant-Gravitas/AutoGPT PR: 12213
File: autogpt_platform/frontend/src/app/api/openapi.json:10030-10037
Timestamp: 2026-03-01T07:58:56.207Z
Learning: When a backend field represents sensitive data, use a secret type (e.g., Pydantic SecretStr with length constraints) so OpenAPI marks it as a password/writeOnly field. Apply this pattern to similar sensitive request fields across API schemas so generated TypeScript clients and docs treat them as secrets and do not mishandle sensitivity. Review all openapi.jsons where sensitive inputs are defined and replace plain strings with SecretStr-like semantics with appropriate minLength constraints.
Applied to files:
autogpt_platform/frontend/src/app/api/openapi.json
📚 Learning: 2026-03-07T07:43:09.871Z
Learnt from: kcze
Repo: Significant-Gravitas/AutoGPT PR: 12328
File: autogpt_platform/frontend/src/app/api/openapi.json:1116-1118
Timestamp: 2026-03-07T07:43:09.871Z
Learning: For autogpt_platform/frontend/src/app/api/openapi.json, preserve the existing behavior: HTTPBearerJWT is declared at the router level with Depends(auth.get_user_id) returning None for unauthenticated users; treat as optional auth. Do not change per-operation security descriptions unless you plan a repo-wide OpenAPI update. If you change this file, prefer clarifying operation descriptions rather than altering security requirements.
Applied to files:
autogpt_platform/frontend/src/app/api/openapi.json
📚 Learning: 2026-02-04T16:50:20.508Z
Learnt from: CR
Repo: Significant-Gravitas/AutoGPT PR: 0
File: autogpt_platform/backend/CLAUDE.md:0-0
Timestamp: 2026-02-04T16:50:20.508Z
Learning: Applies to autogpt_platform/backend/backend/blocks/*.py : When adding new blocks, analyze block interfaces to ensure inputs and outputs tie well together for productive graph-based editor connections
Applied to files:
autogpt_platform/backend/backend/copilot/tools/get_block_result.pyautogpt_platform/backend/backend/copilot/tools/run_block_async.py
📚 Learning: 2026-02-04T16:49:42.490Z
Learnt from: CR
Repo: Significant-Gravitas/AutoGPT PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2026-02-04T16:49:42.490Z
Learning: Applies to autogpt_platform/backend/backend/blocks/**/*.py : Implement 'run' method with proper error handling in backend blocks
Applied to files:
autogpt_platform/backend/backend/copilot/tools/get_block_result.pyautogpt_platform/backend/backend/copilot/tools/run_block_async.pyautogpt_platform/backend/backend/copilot/tools/run_block_async_test.py
📚 Learning: 2026-03-10T08:38:33.249Z
Learnt from: majdyz
Repo: Significant-Gravitas/AutoGPT PR: 12356
File: autogpt_platform/backend/backend/copilot/tools/run_block.py:297-300
Timestamp: 2026-03-10T08:38:33.249Z
Learning: In autogpt_platform/backend/backend/copilot/tools/run_block.py, the auto-approval key for sensitive block HITL review uses graph_exec_id (copilot-session-{session_id}) + node_id (copilot-node-{block_id}). This is intentional: approving a block type within a CoPilot session auto-approves all future invocations of that same block type within the same session, mirroring how auto-approve works in normal graph execution. The user explicitly opts into this session-scoped behavior via an auto-approve toggle. Without the toggle (default), each individual invocation requires its own approval.
Applied to files:
autogpt_platform/backend/backend/copilot/tools/run_block_async.py
📚 Learning: 2026-03-16T16:30:20.657Z
Learnt from: Abhi1992002
Repo: Significant-Gravitas/AutoGPT PR: 12417
File: autogpt_platform/backend/backend/blocks/agent_mail/threads.py:80-102
Timestamp: 2026-03-16T16:30:20.657Z
Learning: In autogpt_platform/backend/backend/blocks/agent_mail/ blocks (and across the codebase), wrapping synchronous AgentMail SDK calls with `await asyncio.to_thread()` is NOT required. The block executor runs node execution in dedicated threads via `asyncio.run_coroutine_threadsafe` (manager.py lines ~745-752, ~1079), and the existing codebase pattern does not use `asyncio.to_thread` for SDK calls inside async `run()` methods.
Applied to files:
autogpt_platform/backend/backend/copilot/tools/run_block_async.py
📚 Learning: 2026-02-04T16:49:42.490Z
Learnt from: CR
Repo: Significant-Gravitas/AutoGPT PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2026-02-04T16:49:42.490Z
Learning: Applies to autogpt_platform/backend/backend/blocks/**/*.py : Write tests alongside block implementation when adding new blocks in backend
Applied to files:
autogpt_platform/backend/backend/copilot/tools/run_block_async.pyautogpt_platform/backend/backend/copilot/tools/run_block_async_test.py
📚 Learning: 2026-02-04T16:49:42.490Z
Learnt from: CR
Repo: Significant-Gravitas/AutoGPT PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2026-02-04T16:49:42.490Z
Learning: Applies to autogpt_platform/backend/**/test/**/*.py : Use snapshot testing with '--snapshot-update' flag in backend tests when output changes; always review with 'git diff'
Applied to files:
autogpt_platform/backend/backend/copilot/tools/run_block_async_test.py
📚 Learning: 2026-03-16T16:30:30.764Z
Learnt from: Abhi1992002
Repo: Significant-Gravitas/AutoGPT PR: 12417
File: autogpt_platform/backend/backend/blocks/agent_mail/pods.py:62-74
Timestamp: 2026-03-16T16:30:30.764Z
Learning: In autogpt_platform/backend/backend/blocks/**/*.py, explicit try/except in the `run()` method is NOT required for standard error handling. The block framework's `_execute()` method in `_base.py` catches unhandled exceptions and re-raises them as `BlockExecutionError` or `BlockUnknownError`. Additionally, when a block yields `("error", message)`, `_execute()` immediately raises `BlockExecutionError` — so the `error` output port never propagates downstream. Explicit try/except is only needed when partial output must be controlled (e.g., attachment blocks that must skip yielding `content_base64` on failure).
Applied to files:
autogpt_platform/backend/backend/copilot/tools/run_block_async_test.py
📚 Learning: 2026-02-04T16:49:42.490Z
Learnt from: CR
Repo: Significant-Gravitas/AutoGPT PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2026-02-04T16:49:42.490Z
Learning: Run 'poetry run test' before committing backend changes to ensure all tests pass
Applied to files:
autogpt_platform/backend/backend/copilot/tools/run_block_async_test.py
📚 Learning: 2026-03-16T16:32:29.430Z
Learnt from: Abhi1992002
Repo: Significant-Gravitas/AutoGPT PR: 12417
File: autogpt_platform/backend/backend/blocks/agent_mail/pods.py:62-74
Timestamp: 2026-03-16T16:32:29.430Z
Learning: In autogpt_platform/backend/backend/blocks/**/*.py, the Block base class `execute()` method in `backend/blocks/_base.py` already wraps `run()` in a try/except that converts uncaught exceptions into `BlockExecutionError`/`BlockUnknownError`. Therefore, explicit try/except in individual block `run()` methods is redundant and not the established pattern (e.g., Gmail, Slack, Todoist blocks omit it). Exception: blocks like attachment blocks that need to distinguish between success and error yield paths within the generator use explicit try/except for branching control, not for the framework's error routing.
Applied to files:
autogpt_platform/backend/backend/copilot/tools/run_block_async_test.py
🔇 Additional comments (12)
autogpt_platform/backend/backend/copilot/tools/__init__.py (1)
25-25: LGTM!The new tool imports and registry entries are correctly added. The registry keys (
"run_block_async"and"get_block_result") match the correspondingnameproperties in their tool classes, ensuring proper tool lookup.Also applies to: 38-38, 74-75
autogpt_platform/backend/backend/copilot/sdk/tool_adapter.py (2)
53-59: Appropriate per-session isolation using ContextVar.The
_background_jobsContextVar pattern correctly mirrors the existing_pending_tool_outputsapproach, ensuring concurrent sessions do not share background-job state.Also applies to: 102-102
131-133: LGTM!The getter correctly returns
Nonewhen the ContextVar hasn't been initialized, allowing callers to handle the uninitialized state gracefully.autogpt_platform/backend/backend/copilot/tools/run_block_async_test.py (2)
169-202: LGTM!Good test coverage for the result retrieval path. The test correctly:
- Creates a completed task with mock output
- Verifies the response type and output values
- Confirms job cleanup after retrieval (line 202)
156-159: Patch location is correct forget_background_jobs.The patch targets
backend.copilot.sdk.tool_adapter.get_background_jobs, and since the import happens inside_execute(line 67) after the patch is already applied via thewithstatement, the import will retrieve the patched version. The patch location does not need adjustment.autogpt_platform/backend/backend/copilot/tools/models.py (2)
43-44: LGTM!New enum members follow existing naming patterns and are logically grouped under the "Block" section.
479-498: LGTM!Both response models are well-designed:
BlockJobStartedResponseincludes all necessary tracking fields (job_id, block_id, block_name)BlockJobResultResponseappropriately handles both success and failure cases with optionaloutputsanderrorfields- Models follow the established patterns in this file (extending
ToolResponseBase, usingResponseTypeenum)autogpt_platform/backend/backend/copilot/tools/run_block_async.py (2)
88-111: LGTM!Input validation is thorough:
- Empty block_id check
- Type check for input_data
- Authentication requirement enforced early
236-308: LGTM!The HITL review logic correctly:
- Reuses existing WAITING reviews to avoid duplicates
- Creates proper synthetic IDs for CoPilot context
- Returns
ReviewRequiredResponsewith actionable guidance for the LLMThis matches the documented pattern from retrieved learnings about auto-approval keys.
autogpt_platform/backend/backend/copilot/tools/get_block_result.py (3)
90-98: Error response lacks block metadata.When an exception occurs,
block_idandblock_nameare set to empty strings. Ifexecute_blockfails mid-execution, the task's exception doesn't carry block info. This is acceptable for now but reduces debuggability.
47-65: LGTM!Validation logic is correct:
- Validates job_id presence
- Enforces authentication
- Handles missing job store gracefully
103-110: Add type checking before accessing result attributes.The code at lines 103-110 assumes
resultis aBlockOutputResponseand accesses.block_id,.block_name,.outputs, and.successdirectly. However,execute_blockreturnsToolResponseBase, which can be eitherBlockOutputResponse(with those attributes) orErrorResponse(without them). Without checking the result type, accessing these attributes on anErrorResponsewill fail.Add an
isinstancecheck to verifyresultis aBlockOutputResponsebefore accessing these attributes, or handle both response types appropriately.
There was a problem hiding this comment.
Actionable comments posted: 3
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@autogpt_platform/backend/backend/copilot/tools/get_block_result.py`:
- Around line 58-64: Guard against non-string job_id before calling .strip():
retrieve job_id from kwargs, check isinstance(job_id, str) (or coerce safely)
and only call job_id.strip() when it's a string; if it's missing or not a
string, return the existing ErrorResponse with message "Please provide a job_id"
and session_id. Update the logic in get_block_result (the job_id handling near
the top of the function in get_block_result.py) to validate type first, then
strip, preserving current return behavior for invalid/missing values.
In `@autogpt_platform/backend/backend/copilot/tools/helpers.py`:
- Around line 332-366: The code is building missing_creds_dict from the raw
block.input_schema which can mismatch discriminated credential fields; instead
derive credentials_fields_info from the resolved input_schema (the input_schema
variable) that was generated with discriminator logic and use that when calling
build_missing_credentials_from_field_info; replace the call to
block.input_schema.get_credentials_fields_info() with logic that extracts
credential field info from input_schema (or call an existing helper like
get_credentials_fields_info_from_schema(input_schema) if available) and then
pass that result plus set(matched_credentials.keys()) into
build_missing_credentials_from_field_info to produce missing_creds_dict.
In `@autogpt_platform/backend/backend/copilot/tools/run_block_async.py`:
- Around line 94-111: The code currently calls .strip() on block_id immediately
which throws if block_id is None or non-string; update the validation in
run_block_async (around the block handling that sets block_id = kwargs.get(...))
to first check that block_id is a str (e.g., if not isinstance(block_id, str):
return ErrorResponse(...)) and only then call block_id = block_id.strip(); keep
the existing ErrorResponse for missing block_id and leave the input_data and
user_id checks (input_data dict check and Authentication required) unchanged so
invalid types are handled before any string operations.
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro
Run ID: be154b2c-156d-4521-b152-18cfc65c7700
📒 Files selected for processing (5)
autogpt_platform/backend/backend/copilot/tools/get_block_result.pyautogpt_platform/backend/backend/copilot/tools/helpers.pyautogpt_platform/backend/backend/copilot/tools/run_block.pyautogpt_platform/backend/backend/copilot/tools/run_block_async.pyautogpt_platform/backend/backend/copilot/tools/run_block_async_test.py
🚧 Files skipped from review as they are similar to previous changes (1)
- autogpt_platform/backend/backend/copilot/tools/run_block_async_test.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). (8)
- GitHub Check: check API types
- GitHub Check: end-to-end tests
- GitHub Check: test (3.11)
- GitHub Check: test (3.12)
- GitHub Check: test (3.13)
- GitHub Check: Seer Code Review
- GitHub Check: Check PR Status
- GitHub Check: Analyze (python)
🧰 Additional context used
📓 Path-based instructions (4)
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
Files:
autogpt_platform/backend/backend/copilot/tools/helpers.pyautogpt_platform/backend/backend/copilot/tools/run_block_async.pyautogpt_platform/backend/backend/copilot/tools/get_block_result.pyautogpt_platform/backend/backend/copilot/tools/run_block.py
autogpt_platform/backend/**/*.{py,txt}
📄 CodeRabbit inference engine (autogpt_platform/backend/CLAUDE.md)
Use
poetry runprefix for all Python commands, including testing, linting, formatting, and migrations
Files:
autogpt_platform/backend/backend/copilot/tools/helpers.pyautogpt_platform/backend/backend/copilot/tools/run_block_async.pyautogpt_platform/backend/backend/copilot/tools/get_block_result.pyautogpt_platform/backend/backend/copilot/tools/run_block.py
autogpt_platform/backend/backend/**/*.py
📄 CodeRabbit inference engine (autogpt_platform/backend/CLAUDE.md)
Use Prisma ORM for database operations in PostgreSQL with pgvector for embeddings
Files:
autogpt_platform/backend/backend/copilot/tools/helpers.pyautogpt_platform/backend/backend/copilot/tools/run_block_async.pyautogpt_platform/backend/backend/copilot/tools/get_block_result.pyautogpt_platform/backend/backend/copilot/tools/run_block.py
autogpt_platform/**/*.py
📄 CodeRabbit inference engine (AGENTS.md)
Format Python code with
poetry run format
Files:
autogpt_platform/backend/backend/copilot/tools/helpers.pyautogpt_platform/backend/backend/copilot/tools/run_block_async.pyautogpt_platform/backend/backend/copilot/tools/get_block_result.pyautogpt_platform/backend/backend/copilot/tools/run_block.py
🧠 Learnings (25)
📓 Common learnings
Learnt from: majdyz
Repo: Significant-Gravitas/AutoGPT PR: 12356
File: autogpt_platform/backend/backend/copilot/tools/run_block.py:297-300
Timestamp: 2026-03-10T08:38:33.249Z
Learning: In autogpt_platform/backend/backend/copilot/tools/run_block.py, the auto-approval key for sensitive block HITL review uses graph_exec_id (copilot-session-{session_id}) + node_id (copilot-node-{block_id}). This is intentional: approving a block type within a CoPilot session auto-approves all future invocations of that same block type within the same session, mirroring how auto-approve works in normal graph execution. The user explicitly opts into this session-scoped behavior via an auto-approve toggle. Without the toggle (default), each individual invocation requires its own approval.
Learnt from: Abhi1992002
Repo: Significant-Gravitas/AutoGPT PR: 12417
File: autogpt_platform/backend/backend/blocks/agent_mail/threads.py:80-102
Timestamp: 2026-03-16T16:30:20.657Z
Learning: In autogpt_platform/backend/backend/blocks/agent_mail/ blocks (and across the codebase), wrapping synchronous AgentMail SDK calls with `await asyncio.to_thread()` is NOT required. The block executor runs node execution in dedicated threads via `asyncio.run_coroutine_threadsafe` (manager.py lines ~745-752, ~1079), and the existing codebase pattern does not use `asyncio.to_thread` for SDK calls inside async `run()` methods.
Learnt from: CR
Repo: Significant-Gravitas/AutoGPT PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2026-02-04T16:49:42.490Z
Learning: Applies to autogpt_platform/backend/backend/blocks/**/*.py : Implement 'run' method with proper error handling in backend blocks
Learnt from: majdyz
Repo: Significant-Gravitas/AutoGPT PR: 12439
File: autogpt_platform/backend/backend/blocks/autogpt_copilot.py:0-0
Timestamp: 2026-03-16T17:00:02.827Z
Learning: In autogpt_platform/backend/backend/blocks/autogpt_copilot.py, the recursion guard uses two module-level ContextVars: `_copilot_recursion_depth` (tracks current nesting depth) and `_copilot_recursion_limit` (stores the chain-wide ceiling). On the first invocation, `_copilot_recursion_limit` is set to `max_recursion_depth`; nested calls use `min(inherited_limit, max_recursion_depth)`, so they can only lower the cap, never raise it. The entry/exit logic is extracted into module-level helper functions. This is the approved pattern for preventing runaway sub-agent recursion in AutogptCopilotBlock (PR `#12439`, commits 348e9f8e2 and 3b70f61b1).
Learnt from: majdyz
Repo: Significant-Gravitas/AutoGPT PR: 12440
File: autogpt_platform/backend/backend/copilot/workflow_import/converter.py:0-0
Timestamp: 2026-03-17T10:57:10.126Z
Learning: In Significant-Gravitas/AutoGPT PR `#12440`, `autogpt_platform/backend/backend/copilot/workflow_import/converter.py` was fully rewritten (commit 732960e2d) to no longer make direct LLM/OpenAI API calls. The converter now builds a structured text prompt for AutoPilot/CoPilot instead. There is no `response.choices` access or any direct LLM client usage in this file. Do not flag `response.choices` access or LLM client initialization patterns as issues in this file.
Learnt from: majdyz
Repo: Significant-Gravitas/AutoGPT PR: 12356
File: autogpt_platform/backend/backend/copilot/constants.py:9-12
Timestamp: 2026-03-10T08:39:22.025Z
Learning: In Significant-Gravitas/AutoGPT PR `#12356`, the `COPILOT_SYNTHETIC_ID_PREFIX = "copilot-"` check in `create_auto_approval_record` (human_review.py) is intentional and safe. The `graph_exec_id` passed to this function comes from server-side `PendingHumanReview` DB records (not from user input); the API only accepts `node_exec_id` from users. Synthetic `copilot-*` IDs are only ever created server-side in `run_block.py`. The prefix skip avoids a DB lookup for a `AgentGraphExecution` record that legitimately does not exist for CoPilot sessions, while `user_id` scoping is enforced at the auth layer and on the resulting auto-approval record.
Learnt from: CR
Repo: Significant-Gravitas/AutoGPT PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2026-02-04T16:49:42.490Z
Learning: Applies to autogpt_platform/backend/backend/blocks/**/*.py : Write tests alongside block implementation when adding new blocks in backend
📚 Learning: 2026-03-10T08:38:36.655Z
Learnt from: majdyz
Repo: Significant-Gravitas/AutoGPT PR: 12356
File: autogpt_platform/backend/backend/copilot/tools/run_block.py:349-370
Timestamp: 2026-03-10T08:38:36.655Z
Learning: In the AutoGPT CoPilot HITL (Human-In-The-Loop) flow (`autogpt_platform/backend/backend/copilot/tools/run_block.py`), the review card presented to users sets `editable: false`, meaning reviewers cannot modify the input payload. Therefore, credentials resolved before `is_block_exec_need_review()` remain valid and do not need to be recomputed after the review step — the original `input_data` is unchanged through the review lifecycle.
Applied to files:
autogpt_platform/backend/backend/copilot/tools/helpers.pyautogpt_platform/backend/backend/copilot/tools/run_block_async.py
📚 Learning: 2026-03-10T08:38:33.249Z
Learnt from: majdyz
Repo: Significant-Gravitas/AutoGPT PR: 12356
File: autogpt_platform/backend/backend/copilot/tools/run_block.py:297-300
Timestamp: 2026-03-10T08:38:33.249Z
Learning: In autogpt_platform/backend/backend/copilot/tools/run_block.py, the auto-approval key for sensitive block HITL review uses graph_exec_id (copilot-session-{session_id}) + node_id (copilot-node-{block_id}). This is intentional: approving a block type within a CoPilot session auto-approves all future invocations of that same block type within the same session, mirroring how auto-approve works in normal graph execution. The user explicitly opts into this session-scoped behavior via an auto-approve toggle. Without the toggle (default), each individual invocation requires its own approval.
Applied to files:
autogpt_platform/backend/backend/copilot/tools/helpers.pyautogpt_platform/backend/backend/copilot/tools/run_block_async.py
📚 Learning: 2026-03-10T08:39:22.025Z
Learnt from: majdyz
Repo: Significant-Gravitas/AutoGPT PR: 12356
File: autogpt_platform/backend/backend/copilot/constants.py:9-12
Timestamp: 2026-03-10T08:39:22.025Z
Learning: In Significant-Gravitas/AutoGPT PR `#12356`, the `COPILOT_SYNTHETIC_ID_PREFIX = "copilot-"` check in `create_auto_approval_record` (human_review.py) is intentional and safe. The `graph_exec_id` passed to this function comes from server-side `PendingHumanReview` DB records (not from user input); the API only accepts `node_exec_id` from users. Synthetic `copilot-*` IDs are only ever created server-side in `run_block.py`. The prefix skip avoids a DB lookup for a `AgentGraphExecution` record that legitimately does not exist for CoPilot sessions, while `user_id` scoping is enforced at the auth layer and on the resulting auto-approval record.
Applied to files:
autogpt_platform/backend/backend/copilot/tools/helpers.pyautogpt_platform/backend/backend/copilot/tools/run_block_async.py
📚 Learning: 2026-03-17T10:57:10.126Z
Learnt from: majdyz
Repo: Significant-Gravitas/AutoGPT PR: 12440
File: autogpt_platform/backend/backend/copilot/workflow_import/converter.py:0-0
Timestamp: 2026-03-17T10:57:10.126Z
Learning: In Significant-Gravitas/AutoGPT PR `#12440`, `autogpt_platform/backend/backend/copilot/workflow_import/converter.py` was fully rewritten (commit 732960e2d) to no longer make direct LLM/OpenAI API calls. The converter now builds a structured text prompt for AutoPilot/CoPilot instead. There is no `response.choices` access or any direct LLM client usage in this file. Do not flag `response.choices` access or LLM client initialization patterns as issues in this file.
Applied to files:
autogpt_platform/backend/backend/copilot/tools/helpers.pyautogpt_platform/backend/backend/copilot/tools/run_block.py
📚 Learning: 2026-02-04T16:50:20.508Z
Learnt from: CR
Repo: Significant-Gravitas/AutoGPT PR: 0
File: autogpt_platform/backend/CLAUDE.md:0-0
Timestamp: 2026-02-04T16:50:20.508Z
Learning: Applies to autogpt_platform/backend/backend/blocks/*.py : When adding new blocks, analyze block interfaces to ensure inputs and outputs tie well together for productive graph-based editor connections
Applied to files:
autogpt_platform/backend/backend/copilot/tools/helpers.pyautogpt_platform/backend/backend/copilot/tools/run_block_async.pyautogpt_platform/backend/backend/copilot/tools/run_block.py
📚 Learning: 2026-02-04T16:49:42.490Z
Learnt from: CR
Repo: Significant-Gravitas/AutoGPT PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2026-02-04T16:49:42.490Z
Learning: Applies to autogpt_platform/backend/backend/blocks/**/*.py : Implement 'run' method with proper error handling in backend blocks
Applied to files:
autogpt_platform/backend/backend/copilot/tools/helpers.pyautogpt_platform/backend/backend/copilot/tools/run_block_async.pyautogpt_platform/backend/backend/copilot/tools/get_block_result.pyautogpt_platform/backend/backend/copilot/tools/run_block.py
📚 Learning: 2026-03-15T15:30:02.282Z
Learnt from: majdyz
Repo: Significant-Gravitas/AutoGPT PR: 12385
File: autogpt_platform/backend/backend/copilot/tools/helpers.py:149-185
Timestamp: 2026-03-15T15:30:02.282Z
Learning: In autogpt_platform/backend/backend/copilot/tools/helpers.py, inside execute_block: when InsufficientBalanceError occurs after post-execution credit charging (i.e., balance drained concurrently after pre-check passed), treat as a non-fatal billing leak. Log at ERROR level with structured JSON: {"billing_leak": True, "user_id": ..., "cost": ...} for monitoring/alerting, then return BlockOutputResponse normally (do not discard the output). Do not perform a second get_user_credit_model call; reuse the credit_model obtained during the pre-execution balance check (guarded by if cost > 0 and credit_model:). This guidance improves UX by not discarding results and provides observable billing leak signals.
Applied to files:
autogpt_platform/backend/backend/copilot/tools/helpers.py
📚 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/tools/helpers.pyautogpt_platform/backend/backend/copilot/tools/run_block_async.pyautogpt_platform/backend/backend/copilot/tools/get_block_result.pyautogpt_platform/backend/backend/copilot/tools/run_block.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/tools/helpers.pyautogpt_platform/backend/backend/copilot/tools/run_block_async.pyautogpt_platform/backend/backend/copilot/tools/get_block_result.pyautogpt_platform/backend/backend/copilot/tools/run_block.py
📚 Learning: 2026-03-04T12:19:39.243Z
Learnt from: majdyz
Repo: Significant-Gravitas/AutoGPT PR: 12279
File: autogpt_platform/backend/backend/copilot/tools/base.py:184-188
Timestamp: 2026-03-04T12:19:39.243Z
Learning: In autogpt_platform/backend/backend/copilot/tools/, ensure that anonymous users always pass user_id=None to tool execution methods. The anon_ prefix (e.g., anon_123) is used only for PostHog/analytics distinct_id and must not be used as an actual user_id. Use a simple truthiness check on user_id (e.g., if user_id: ... else: ... or a dedicated is_authenticated flag) to distinguish anonymous from authenticated users, and review all tool execution call sites within this directory to prevent accidentally forwarding an anon_ user_id to tools.
Applied to files:
autogpt_platform/backend/backend/copilot/tools/helpers.pyautogpt_platform/backend/backend/copilot/tools/run_block_async.pyautogpt_platform/backend/backend/copilot/tools/get_block_result.pyautogpt_platform/backend/backend/copilot/tools/run_block.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/tools/helpers.pyautogpt_platform/backend/backend/copilot/tools/run_block_async.pyautogpt_platform/backend/backend/copilot/tools/get_block_result.pyautogpt_platform/backend/backend/copilot/tools/run_block.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/tools/helpers.pyautogpt_platform/backend/backend/copilot/tools/run_block_async.pyautogpt_platform/backend/backend/copilot/tools/get_block_result.pyautogpt_platform/backend/backend/copilot/tools/run_block.py
📚 Learning: 2026-03-16T16:30:20.657Z
Learnt from: Abhi1992002
Repo: Significant-Gravitas/AutoGPT PR: 12417
File: autogpt_platform/backend/backend/blocks/agent_mail/threads.py:80-102
Timestamp: 2026-03-16T16:30:20.657Z
Learning: In autogpt_platform/backend/backend/blocks/agent_mail/ blocks (and across the codebase), wrapping synchronous AgentMail SDK calls with `await asyncio.to_thread()` is NOT required. The block executor runs node execution in dedicated threads via `asyncio.run_coroutine_threadsafe` (manager.py lines ~745-752, ~1079), and the existing codebase pattern does not use `asyncio.to_thread` for SDK calls inside async `run()` methods.
Applied to files:
autogpt_platform/backend/backend/copilot/tools/run_block_async.py
📚 Learning: 2026-03-16T16:30:30.764Z
Learnt from: Abhi1992002
Repo: Significant-Gravitas/AutoGPT PR: 12417
File: autogpt_platform/backend/backend/blocks/agent_mail/pods.py:62-74
Timestamp: 2026-03-16T16:30:30.764Z
Learning: In autogpt_platform/backend/backend/blocks/**/*.py, explicit try/except in the `run()` method is NOT required for standard error handling. The block framework's `_execute()` method in `_base.py` catches unhandled exceptions and re-raises them as `BlockExecutionError` or `BlockUnknownError`. Additionally, when a block yields `("error", message)`, `_execute()` immediately raises `BlockExecutionError` — so the `error` output port never propagates downstream. Explicit try/except is only needed when partial output must be controlled (e.g., attachment blocks that must skip yielding `content_base64` on failure).
Applied to files:
autogpt_platform/backend/backend/copilot/tools/run_block_async.pyautogpt_platform/backend/backend/copilot/tools/get_block_result.pyautogpt_platform/backend/backend/copilot/tools/run_block.py
📚 Learning: 2026-03-16T16:32:29.430Z
Learnt from: Abhi1992002
Repo: Significant-Gravitas/AutoGPT PR: 12417
File: autogpt_platform/backend/backend/blocks/agent_mail/pods.py:62-74
Timestamp: 2026-03-16T16:32:29.430Z
Learning: In autogpt_platform/backend/backend/blocks/**/*.py, the Block base class `execute()` method in `backend/blocks/_base.py` already wraps `run()` in a try/except that converts uncaught exceptions into `BlockExecutionError`/`BlockUnknownError`. Therefore, explicit try/except in individual block `run()` methods is redundant and not the established pattern (e.g., Gmail, Slack, Todoist blocks omit it). Exception: blocks like attachment blocks that need to distinguish between success and error yield paths within the generator use explicit try/except for branching control, not for the framework's error routing.
Applied to files:
autogpt_platform/backend/backend/copilot/tools/run_block_async.pyautogpt_platform/backend/backend/copilot/tools/get_block_result.pyautogpt_platform/backend/backend/copilot/tools/run_block.py
📚 Learning: 2026-02-27T10:45:55.700Z
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:55.700Z
Learning: As of PR `#12213`, MCP tool response types (MCPToolsDiscoveredResponse, MCPToolOutputResponse) are defined in openapi.json and frontend code in autogpt_platform/frontend/src/app/(platform)/copilot/tools/RunMCPTool/helpers.tsx uses the generated types from `@/app/api/__generated__/`. Other tools like RunBlock still use inline TypeScript interfaces (e.g., BlockDetailsResponse) for SSE stream payloads that are not included in openapi.json schemas. The pattern is tool-specific: use generated types when available in openapi.json, use inline types only when the payload schema is truly SSE-stream-only and not exposed via OpenAPI.
Applied to files:
autogpt_platform/backend/backend/copilot/tools/run_block_async.pyautogpt_platform/backend/backend/copilot/tools/run_block.py
📚 Learning: 2026-02-04T16:49:42.490Z
Learnt from: CR
Repo: Significant-Gravitas/AutoGPT PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2026-02-04T16:49:42.490Z
Learning: Applies to autogpt_platform/backend/backend/blocks/**/*.py : Write tests alongside block implementation when adding new blocks in backend
Applied to files:
autogpt_platform/backend/backend/copilot/tools/run_block_async.py
📚 Learning: 2026-02-04T16:49:42.490Z
Learnt from: CR
Repo: Significant-Gravitas/AutoGPT PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2026-02-04T16:49:42.490Z
Learning: Applies to autogpt_platform/backend/backend/blocks/**/*.py : Inherit from 'Block' base class with input/output schemas when adding new blocks in backend
Applied to files:
autogpt_platform/backend/backend/copilot/tools/run_block_async.py
📚 Learning: 2026-02-04T16:50:20.508Z
Learnt from: CR
Repo: Significant-Gravitas/AutoGPT PR: 0
File: autogpt_platform/backend/CLAUDE.md:0-0
Timestamp: 2026-02-04T16:50:20.508Z
Learning: Applies to autogpt_platform/backend/backend/blocks/*.py : When creating new blocks, inherit from the `Block` base class and define input/output schemas using `BlockSchema`
Applied to files:
autogpt_platform/backend/backend/copilot/tools/run_block_async.pyautogpt_platform/backend/backend/copilot/tools/run_block.py
📚 Learning: 2026-02-05T04:11:15.945Z
Learnt from: ntindle
Repo: Significant-Gravitas/AutoGPT PR: 11796
File: autogpt_platform/backend/backend/blocks/video/concat.py:3-4
Timestamp: 2026-02-05T04:11:15.945Z
Learning: Block IDs in autogpt_platform/backend/backend/blocks/**/*.py must be stable, hard-coded UUID strings. When initially creating a new block, generate a UUID once using `uuid.uuid4()` and then hard-code that UUID string as the block's `id` parameter. Do not call uuid.uuid4() dynamically at runtime, as block IDs must remain constant across all imports and runs.
Applied to files:
autogpt_platform/backend/backend/copilot/tools/run_block_async.py
📚 Learning: 2026-03-15T15:30:09.706Z
Learnt from: majdyz
Repo: Significant-Gravitas/AutoGPT PR: 12385
File: autogpt_platform/backend/backend/copilot/tools/helpers.py:149-185
Timestamp: 2026-03-15T15:30:09.706Z
Learning: In autogpt_platform/backend/backend/copilot/tools/helpers.py, within execute_block, when InsufficientBalanceError occurs after post-execution credit charging (concurrent balance drain after pre-check passed), this is treated as a non-fatal billing leak: log at ERROR level with structured JSON fields `{"billing_leak": True, "user_id": ..., "cost": ...}` for monitoring/alerting, then return BlockOutputResponse normally. Discarding the output would worsen UX since the block already executed with potential side effects. Reuse the credit_model obtained during the pre-execution balance check (guarded by `if cost > 0 and credit_model:`) for the post-execution charge; do not perform a second get_user_credit_model call.
Applied to files:
autogpt_platform/backend/backend/copilot/tools/run_block_async.pyautogpt_platform/backend/backend/copilot/tools/get_block_result.pyautogpt_platform/backend/backend/copilot/tools/run_block.py
📚 Learning: 2026-03-16T16:30:20.657Z
Learnt from: Abhi1992002
Repo: Significant-Gravitas/AutoGPT PR: 12417
File: autogpt_platform/backend/backend/blocks/agent_mail/threads.py:80-102
Timestamp: 2026-03-16T16:30:20.657Z
Learning: In autogpt_platform/backend/backend/blocks/agent_mail/ (and other blocks under autogpt_platform/backend/backend/blocks/), the block executor framework (backend/executor/manager.py lines ~708-733) automatically catches all uncaught exceptions from a block's `run()` method and emits them on the `"error"` output. Explicit try/except blocks within `run()` are therefore not required for standard error propagation — they are only needed when partial output behaviour must be controlled (e.g., preventing some outputs from being yielded on failure, as in attachment blocks). This is the standard pattern across the codebase.
Applied to files:
autogpt_platform/backend/backend/copilot/tools/run_block_async.pyautogpt_platform/backend/backend/copilot/tools/get_block_result.py
📚 Learning: 2026-03-10T08:38:29.078Z
Learnt from: majdyz
Repo: Significant-Gravitas/AutoGPT PR: 12356
File: autogpt_platform/backend/backend/copilot/tools/run_block.py:297-300
Timestamp: 2026-03-10T08:38:29.078Z
Learning: In autogpt_platform/backend/backend/copilot/tools/run_block.py, the auto-approval key for sensitive block HITL review is session-scoped: it uses graph_exec_id (copilot-session-{session_id}) combined with node_id (copilot-node-{block_id}). If the user enables the auto-approve toggle for a CoPilot session, approving a block type in that session automatically approves all future invocations of that same block type within the same session. If the user does not toggle auto-approve (default), each individual invocation requires its own approval. This behavior should be clearly documented in code and comments, and tested to ensure the toggle reliably toggles between session-scoped auto-approval and per-invocation approval.
Applied to files:
autogpt_platform/backend/backend/copilot/tools/run_block.py
📚 Learning: 2026-03-10T08:38:30.834Z
Learnt from: majdyz
Repo: Significant-Gravitas/AutoGPT PR: 12356
File: autogpt_platform/backend/backend/copilot/tools/run_block.py:349-370
Timestamp: 2026-03-10T08:38:30.834Z
Learning: In the AutoGPT CoPilot HITL flow, the review card presents with editable: false, so the input payload cannot be modified. Therefore credentials resolved before is_block_exec_need_review() remain valid and do not need to be recomputed after the review step. Ensure run_block.py uses the original input_data for credential validation and that any credential caching relies on the pre-review input. If there is any logic that would recompute credentials post-review, guard it against input_data mutations and rely on the UI to enforce immutability. This guideline is specific to autogpt_platform/backend/backend/copilot/tools/run_block.py.
Applied to files:
autogpt_platform/backend/backend/copilot/tools/run_block.py
🔇 Additional comments (2)
autogpt_platform/backend/backend/copilot/tools/get_block_result.py (1)
108-121: Nice result-type guard.Returning non-
BlockOutputResponseresults directly avoids attribute-access failures whenexecute_block()surfaces anErrorResponse.autogpt_platform/backend/backend/copilot/tools/run_block.py (1)
119-177: Shared prep/HITL flow looks good.
RunBlockToolnow stays focused on the two-step schema-preview UX while validation and execution rules live in one place.
There was a problem hiding this comment.
Actionable comments posted: 3
♻️ Duplicate comments (2)
autogpt_platform/backend/backend/copilot/tools/run_block_async.py (1)
93-100:⚠️ Potential issue | 🟠 MajorGuard
block_idbefore calling.strip().Line 93 assumes
block_idis astr. Non-string inputs can fail before this path returns a validation error.Suggested fix
- block_id = kwargs.get("block_id", "").strip() + raw_block_id = kwargs.get("block_id", "") input_data = kwargs.get("input_data", {}) session_id = session.session_id + + if not isinstance(raw_block_id, str): + return ErrorResponse( + message="block_id must be a string", + session_id=session_id, + ) + block_id = raw_block_id.strip()🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@autogpt_platform/backend/backend/copilot/tools/run_block_async.py` around lines 93 - 100, The code calls .strip() on kwargs.get("block_id") assuming it's a string; first retrieve the raw value (e.g., raw_block_id = kwargs.get("block_id", None)) and validate its type before stripping: if raw_block_id is None or not isinstance(raw_block_id, str) return ErrorResponse(message="Please provide a block_id", session_id=session.session_id); otherwise set block_id = raw_block_id.strip() and continue. Update the logic around block_id, raw_block_id, ErrorResponse and session.session_id in run_block_async to avoid calling .strip() on non-strings.autogpt_platform/backend/backend/copilot/tools/get_block_result.py (1)
59-65:⚠️ Potential issue | 🟠 MajorGuard
job_idbefore calling.strip().Line 59 assumes
job_idis astr. Non-string inputs can fail before this tool returns its normal validation response.Suggested fix
- job_id = kwargs.get("job_id", "").strip() + raw_job_id = kwargs.get("job_id", "") session_id = session.session_id + + if not isinstance(raw_job_id, str): + return ErrorResponse( + message="job_id must be a string", + session_id=session_id, + ) + job_id = raw_job_id.strip()🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@autogpt_platform/backend/backend/copilot/tools/get_block_result.py` around lines 59 - 65, The code calls .strip() on kwargs.get("job_id", "") assuming a string; first retrieve the raw value (e.g., raw_job_id = kwargs.get("job_id")), then validate its type before stripping: if raw_job_id is None or not isinstance(raw_job_id, str) return the same ErrorResponse (using session.session_id) or convert non-string inputs safely (e.g., cast to str) per API contract; update the logic around job_id, the .strip() call, and the ErrorResponse return to use this guarded value so get_block_result (and the local job_id variable) never calls .strip() on a non-string.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@autogpt_platform/backend/backend/copilot/tools/get_block_result.py`:
- Around line 90-102: In get_block_result, protect awaiting the background task
by wrapping the await in asyncio.shield(task) so cancellation of the outer await
won't propagate into the underlying task; after the shielded await, only
pop/remove the task from the jobs registry (jobs.pop(job_id, None)) if the
actual task is cancelled or finished as intended (inspect task.cancelled() /
task.done()), and when handling asyncio.CancelledError return the
BlockJobResultResponse without having orphaned the real background task; update
references to task, jobs, job_id, and BlockJobResultResponse accordingly.
In `@autogpt_platform/backend/backend/copilot/tools/helpers_test.py`:
- Around line 711-733: The HITL test helper _make_hitl_prep currently generates
synthetic_graph_id and synthetic_node_id using underscore-based strings; update
it to match production CoPilot formatting by using the hyphenated keys (e.g.,
synthetic_graph_id = f"copilot-session-{session_id}" and synthetic_node_id =
f"copilot-node-{block_id}") or, if there are exportable CoPilot constants for
those formats, reference those constants instead so tests mirror runtime ID
semantics used by BlockPreparation and any assertions elsewhere.
- Line 720: The fixture helper _make_hitl_prep currently sets data = input_data
or {"action": "delete"}, which treats empty dicts as falsy and overwrites
intentionally empty inputs; change that to an explicit None check so that if
input_data is None you assign the default payload, otherwise use the provided
input_data (e.g., if input_data is None: data = {"action":"delete"} else: data =
input_data) — update the _make_hitl_prep helper to use this None-check with the
input_data parameter.
---
Duplicate comments:
In `@autogpt_platform/backend/backend/copilot/tools/get_block_result.py`:
- Around line 59-65: The code calls .strip() on kwargs.get("job_id", "")
assuming a string; first retrieve the raw value (e.g., raw_job_id =
kwargs.get("job_id")), then validate its type before stripping: if raw_job_id is
None or not isinstance(raw_job_id, str) return the same ErrorResponse (using
session.session_id) or convert non-string inputs safely (e.g., cast to str) per
API contract; update the logic around job_id, the .strip() call, and the
ErrorResponse return to use this guarded value so get_block_result (and the
local job_id variable) never calls .strip() on a non-string.
In `@autogpt_platform/backend/backend/copilot/tools/run_block_async.py`:
- Around line 93-100: The code calls .strip() on kwargs.get("block_id") assuming
it's a string; first retrieve the raw value (e.g., raw_block_id =
kwargs.get("block_id", None)) and validate its type before stripping: if
raw_block_id is None or not isinstance(raw_block_id, str) return
ErrorResponse(message="Please provide a block_id",
session_id=session.session_id); otherwise set block_id = raw_block_id.strip()
and continue. Update the logic around block_id, raw_block_id, ErrorResponse and
session.session_id in run_block_async to avoid calling .strip() on non-strings.
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro
Run ID: 3605fa3f-7a0d-4f01-ae74-ede9d51787c0
📒 Files selected for processing (4)
autogpt_platform/backend/backend/copilot/tools/get_block_result.pyautogpt_platform/backend/backend/copilot/tools/helpers_test.pyautogpt_platform/backend/backend/copilot/tools/run_block.pyautogpt_platform/backend/backend/copilot/tools/run_block_async.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). (5)
- GitHub Check: end-to-end tests
- GitHub Check: test (3.13)
- GitHub Check: test (3.12)
- GitHub Check: test (3.11)
- GitHub Check: Check PR Status
🧰 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
Files:
autogpt_platform/backend/backend/copilot/tools/run_block.pyautogpt_platform/backend/backend/copilot/tools/run_block_async.pyautogpt_platform/backend/backend/copilot/tools/helpers_test.pyautogpt_platform/backend/backend/copilot/tools/get_block_result.py
autogpt_platform/backend/**/*.{py,txt}
📄 CodeRabbit inference engine (autogpt_platform/backend/CLAUDE.md)
Use
poetry runprefix for all Python commands, including testing, linting, formatting, and migrations
Files:
autogpt_platform/backend/backend/copilot/tools/run_block.pyautogpt_platform/backend/backend/copilot/tools/run_block_async.pyautogpt_platform/backend/backend/copilot/tools/helpers_test.pyautogpt_platform/backend/backend/copilot/tools/get_block_result.py
autogpt_platform/backend/backend/**/*.py
📄 CodeRabbit inference engine (autogpt_platform/backend/CLAUDE.md)
Use Prisma ORM for database operations in PostgreSQL with pgvector for embeddings
Files:
autogpt_platform/backend/backend/copilot/tools/run_block.pyautogpt_platform/backend/backend/copilot/tools/run_block_async.pyautogpt_platform/backend/backend/copilot/tools/helpers_test.pyautogpt_platform/backend/backend/copilot/tools/get_block_result.py
autogpt_platform/**/*.py
📄 CodeRabbit inference engine (AGENTS.md)
Format Python code with
poetry run format
Files:
autogpt_platform/backend/backend/copilot/tools/run_block.pyautogpt_platform/backend/backend/copilot/tools/run_block_async.pyautogpt_platform/backend/backend/copilot/tools/helpers_test.pyautogpt_platform/backend/backend/copilot/tools/get_block_result.py
autogpt_platform/backend/**/*_test.py
📄 CodeRabbit inference engine (autogpt_platform/backend/CLAUDE.md)
autogpt_platform/backend/**/*_test.py: Always review snapshot changes withgit diffbefore committing when updating snapshots withpoetry run pytest --snapshot-update
Use pytest with snapshot testing for API responses in test files
Colocate test files with source files using the*_test.pynaming convention
Files:
autogpt_platform/backend/backend/copilot/tools/helpers_test.py
autogpt_platform/backend/**/*test*.py
📄 CodeRabbit inference engine (AGENTS.md)
Run
poetry run testfor backend testing (runs pytest with docker based postgres + prisma)
Files:
autogpt_platform/backend/backend/copilot/tools/helpers_test.py
🧠 Learnings (30)
📓 Common learnings
Learnt from: majdyz
Repo: Significant-Gravitas/AutoGPT PR: 12356
File: autogpt_platform/backend/backend/copilot/tools/run_block.py:297-300
Timestamp: 2026-03-10T08:38:33.249Z
Learning: In autogpt_platform/backend/backend/copilot/tools/run_block.py, the auto-approval key for sensitive block HITL review uses graph_exec_id (copilot-session-{session_id}) + node_id (copilot-node-{block_id}). This is intentional: approving a block type within a CoPilot session auto-approves all future invocations of that same block type within the same session, mirroring how auto-approve works in normal graph execution. The user explicitly opts into this session-scoped behavior via an auto-approve toggle. Without the toggle (default), each individual invocation requires its own approval.
Learnt from: Abhi1992002
Repo: Significant-Gravitas/AutoGPT PR: 12417
File: autogpt_platform/backend/backend/blocks/agent_mail/threads.py:80-102
Timestamp: 2026-03-16T16:30:20.657Z
Learning: In autogpt_platform/backend/backend/blocks/agent_mail/ blocks (and across the codebase), wrapping synchronous AgentMail SDK calls with `await asyncio.to_thread()` is NOT required. The block executor runs node execution in dedicated threads via `asyncio.run_coroutine_threadsafe` (manager.py lines ~745-752, ~1079), and the existing codebase pattern does not use `asyncio.to_thread` for SDK calls inside async `run()` methods.
Learnt from: majdyz
Repo: Significant-Gravitas/AutoGPT PR: 12439
File: autogpt_platform/backend/backend/blocks/autogpt_copilot.py:0-0
Timestamp: 2026-03-16T17:00:02.827Z
Learning: In autogpt_platform/backend/backend/blocks/autogpt_copilot.py, the recursion guard uses two module-level ContextVars: `_copilot_recursion_depth` (tracks current nesting depth) and `_copilot_recursion_limit` (stores the chain-wide ceiling). On the first invocation, `_copilot_recursion_limit` is set to `max_recursion_depth`; nested calls use `min(inherited_limit, max_recursion_depth)`, so they can only lower the cap, never raise it. The entry/exit logic is extracted into module-level helper functions. This is the approved pattern for preventing runaway sub-agent recursion in AutogptCopilotBlock (PR `#12439`, commits 348e9f8e2 and 3b70f61b1).
Learnt from: CR
Repo: Significant-Gravitas/AutoGPT PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2026-02-04T16:49:42.490Z
Learning: Applies to autogpt_platform/backend/backend/blocks/**/*.py : Implement 'run' method with proper error handling in backend blocks
Learnt from: majdyz
Repo: Significant-Gravitas/AutoGPT PR: 12440
File: autogpt_platform/backend/backend/copilot/workflow_import/converter.py:0-0
Timestamp: 2026-03-17T10:57:10.126Z
Learning: In Significant-Gravitas/AutoGPT PR `#12440`, `autogpt_platform/backend/backend/copilot/workflow_import/converter.py` was fully rewritten (commit 732960e2d) to no longer make direct LLM/OpenAI API calls. The converter now builds a structured text prompt for AutoPilot/CoPilot instead. There is no `response.choices` access or any direct LLM client usage in this file. Do not flag `response.choices` access or LLM client initialization patterns as issues in this file.
Learnt from: majdyz
Repo: Significant-Gravitas/AutoGPT PR: 12356
File: autogpt_platform/backend/backend/copilot/constants.py:9-12
Timestamp: 2026-03-10T08:39:22.025Z
Learning: In Significant-Gravitas/AutoGPT PR `#12356`, the `COPILOT_SYNTHETIC_ID_PREFIX = "copilot-"` check in `create_auto_approval_record` (human_review.py) is intentional and safe. The `graph_exec_id` passed to this function comes from server-side `PendingHumanReview` DB records (not from user input); the API only accepts `node_exec_id` from users. Synthetic `copilot-*` IDs are only ever created server-side in `run_block.py`. The prefix skip avoids a DB lookup for a `AgentGraphExecution` record that legitimately does not exist for CoPilot sessions, while `user_id` scoping is enforced at the auth layer and on the resulting auto-approval record.
📚 Learning: 2026-03-10T08:38:29.078Z
Learnt from: majdyz
Repo: Significant-Gravitas/AutoGPT PR: 12356
File: autogpt_platform/backend/backend/copilot/tools/run_block.py:297-300
Timestamp: 2026-03-10T08:38:29.078Z
Learning: In autogpt_platform/backend/backend/copilot/tools/run_block.py, the auto-approval key for sensitive block HITL review is session-scoped: it uses graph_exec_id (copilot-session-{session_id}) combined with node_id (copilot-node-{block_id}). If the user enables the auto-approve toggle for a CoPilot session, approving a block type in that session automatically approves all future invocations of that same block type within the same session. If the user does not toggle auto-approve (default), each individual invocation requires its own approval. This behavior should be clearly documented in code and comments, and tested to ensure the toggle reliably toggles between session-scoped auto-approval and per-invocation approval.
Applied to files:
autogpt_platform/backend/backend/copilot/tools/run_block.py
📚 Learning: 2026-03-17T10:57:10.126Z
Learnt from: majdyz
Repo: Significant-Gravitas/AutoGPT PR: 12440
File: autogpt_platform/backend/backend/copilot/workflow_import/converter.py:0-0
Timestamp: 2026-03-17T10:57:10.126Z
Learning: In Significant-Gravitas/AutoGPT PR `#12440`, `autogpt_platform/backend/backend/copilot/workflow_import/converter.py` was fully rewritten (commit 732960e2d) to no longer make direct LLM/OpenAI API calls. The converter now builds a structured text prompt for AutoPilot/CoPilot instead. There is no `response.choices` access or any direct LLM client usage in this file. Do not flag `response.choices` access or LLM client initialization patterns as issues in this file.
Applied to files:
autogpt_platform/backend/backend/copilot/tools/run_block.pyautogpt_platform/backend/backend/copilot/tools/helpers_test.py
📚 Learning: 2026-03-10T08:38:30.834Z
Learnt from: majdyz
Repo: Significant-Gravitas/AutoGPT PR: 12356
File: autogpt_platform/backend/backend/copilot/tools/run_block.py:349-370
Timestamp: 2026-03-10T08:38:30.834Z
Learning: In the AutoGPT CoPilot HITL flow, the review card presents with editable: false, so the input payload cannot be modified. Therefore credentials resolved before is_block_exec_need_review() remain valid and do not need to be recomputed after the review step. Ensure run_block.py uses the original input_data for credential validation and that any credential caching relies on the pre-review input. If there is any logic that would recompute credentials post-review, guard it against input_data mutations and rely on the UI to enforce immutability. This guideline is specific to autogpt_platform/backend/backend/copilot/tools/run_block.py.
Applied to files:
autogpt_platform/backend/backend/copilot/tools/run_block.py
📚 Learning: 2026-02-04T16:49:42.490Z
Learnt from: CR
Repo: Significant-Gravitas/AutoGPT PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2026-02-04T16:49:42.490Z
Learning: Applies to autogpt_platform/backend/backend/blocks/**/*.py : Implement 'run' method with proper error handling in backend blocks
Applied to files:
autogpt_platform/backend/backend/copilot/tools/run_block.pyautogpt_platform/backend/backend/copilot/tools/run_block_async.pyautogpt_platform/backend/backend/copilot/tools/helpers_test.pyautogpt_platform/backend/backend/copilot/tools/get_block_result.py
📚 Learning: 2026-03-16T16:30:30.764Z
Learnt from: Abhi1992002
Repo: Significant-Gravitas/AutoGPT PR: 12417
File: autogpt_platform/backend/backend/blocks/agent_mail/pods.py:62-74
Timestamp: 2026-03-16T16:30:30.764Z
Learning: In autogpt_platform/backend/backend/blocks/**/*.py, explicit try/except in the `run()` method is NOT required for standard error handling. The block framework's `_execute()` method in `_base.py` catches unhandled exceptions and re-raises them as `BlockExecutionError` or `BlockUnknownError`. Additionally, when a block yields `("error", message)`, `_execute()` immediately raises `BlockExecutionError` — so the `error` output port never propagates downstream. Explicit try/except is only needed when partial output must be controlled (e.g., attachment blocks that must skip yielding `content_base64` on failure).
Applied to files:
autogpt_platform/backend/backend/copilot/tools/run_block.pyautogpt_platform/backend/backend/copilot/tools/run_block_async.pyautogpt_platform/backend/backend/copilot/tools/helpers_test.pyautogpt_platform/backend/backend/copilot/tools/get_block_result.py
📚 Learning: 2026-02-27T10:45:55.700Z
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:55.700Z
Learning: As of PR `#12213`, MCP tool response types (MCPToolsDiscoveredResponse, MCPToolOutputResponse) are defined in openapi.json and frontend code in autogpt_platform/frontend/src/app/(platform)/copilot/tools/RunMCPTool/helpers.tsx uses the generated types from `@/app/api/__generated__/`. Other tools like RunBlock still use inline TypeScript interfaces (e.g., BlockDetailsResponse) for SSE stream payloads that are not included in openapi.json schemas. The pattern is tool-specific: use generated types when available in openapi.json, use inline types only when the payload schema is truly SSE-stream-only and not exposed via OpenAPI.
Applied to files:
autogpt_platform/backend/backend/copilot/tools/run_block.pyautogpt_platform/backend/backend/copilot/tools/run_block_async.py
📚 Learning: 2026-03-16T16:32:29.430Z
Learnt from: Abhi1992002
Repo: Significant-Gravitas/AutoGPT PR: 12417
File: autogpt_platform/backend/backend/blocks/agent_mail/pods.py:62-74
Timestamp: 2026-03-16T16:32:29.430Z
Learning: In autogpt_platform/backend/backend/blocks/**/*.py, the Block base class `execute()` method in `backend/blocks/_base.py` already wraps `run()` in a try/except that converts uncaught exceptions into `BlockExecutionError`/`BlockUnknownError`. Therefore, explicit try/except in individual block `run()` methods is redundant and not the established pattern (e.g., Gmail, Slack, Todoist blocks omit it). Exception: blocks like attachment blocks that need to distinguish between success and error yield paths within the generator use explicit try/except for branching control, not for the framework's error routing.
Applied to files:
autogpt_platform/backend/backend/copilot/tools/run_block.pyautogpt_platform/backend/backend/copilot/tools/run_block_async.pyautogpt_platform/backend/backend/copilot/tools/helpers_test.pyautogpt_platform/backend/backend/copilot/tools/get_block_result.py
📚 Learning: 2026-03-15T15:30:09.706Z
Learnt from: majdyz
Repo: Significant-Gravitas/AutoGPT PR: 12385
File: autogpt_platform/backend/backend/copilot/tools/helpers.py:149-185
Timestamp: 2026-03-15T15:30:09.706Z
Learning: In autogpt_platform/backend/backend/copilot/tools/helpers.py, within execute_block, when InsufficientBalanceError occurs after post-execution credit charging (concurrent balance drain after pre-check passed), this is treated as a non-fatal billing leak: log at ERROR level with structured JSON fields `{"billing_leak": True, "user_id": ..., "cost": ...}` for monitoring/alerting, then return BlockOutputResponse normally. Discarding the output would worsen UX since the block already executed with potential side effects. Reuse the credit_model obtained during the pre-execution balance check (guarded by `if cost > 0 and credit_model:`) for the post-execution charge; do not perform a second get_user_credit_model call.
Applied to files:
autogpt_platform/backend/backend/copilot/tools/run_block.pyautogpt_platform/backend/backend/copilot/tools/run_block_async.pyautogpt_platform/backend/backend/copilot/tools/get_block_result.py
📚 Learning: 2026-02-04T16:50:20.508Z
Learnt from: CR
Repo: Significant-Gravitas/AutoGPT PR: 0
File: autogpt_platform/backend/CLAUDE.md:0-0
Timestamp: 2026-02-04T16:50:20.508Z
Learning: Applies to autogpt_platform/backend/backend/blocks/*.py : When adding new blocks, analyze block interfaces to ensure inputs and outputs tie well together for productive graph-based editor connections
Applied to files:
autogpt_platform/backend/backend/copilot/tools/run_block.pyautogpt_platform/backend/backend/copilot/tools/run_block_async.py
📚 Learning: 2026-03-17T08:57:35.290Z
Learnt from: majdyz
Repo: Significant-Gravitas/AutoGPT PR: 12440
File: autogpt_platform/backend/backend/api/features/workflow_import.py:0-0
Timestamp: 2026-03-17T08:57:35.290Z
Learning: In Significant-Gravitas/AutoGPT PR `#12440`, the dedicated REST endpoint `/api/import/workflow` for competitor/external workflow import was removed (commit 30f801a5e). The frontend now redirects users to AutoPilot/CoPilot, which invokes the underlying conversion modules (format detector, describers, converter) directly via an `import_workflow` tool. Do not expect or require a standalone HTTP endpoint or route-level integration tests for workflow import in this repository — the functionality lives in the CoPilot tool layer.
Applied to files:
autogpt_platform/backend/backend/copilot/tools/run_block.py
📚 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/tools/run_block.pyautogpt_platform/backend/backend/copilot/tools/run_block_async.pyautogpt_platform/backend/backend/copilot/tools/helpers_test.pyautogpt_platform/backend/backend/copilot/tools/get_block_result.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/tools/run_block.pyautogpt_platform/backend/backend/copilot/tools/run_block_async.pyautogpt_platform/backend/backend/copilot/tools/helpers_test.pyautogpt_platform/backend/backend/copilot/tools/get_block_result.py
📚 Learning: 2026-03-04T12:19:39.243Z
Learnt from: majdyz
Repo: Significant-Gravitas/AutoGPT PR: 12279
File: autogpt_platform/backend/backend/copilot/tools/base.py:184-188
Timestamp: 2026-03-04T12:19:39.243Z
Learning: In autogpt_platform/backend/backend/copilot/tools/, ensure that anonymous users always pass user_id=None to tool execution methods. The anon_ prefix (e.g., anon_123) is used only for PostHog/analytics distinct_id and must not be used as an actual user_id. Use a simple truthiness check on user_id (e.g., if user_id: ... else: ... or a dedicated is_authenticated flag) to distinguish anonymous from authenticated users, and review all tool execution call sites within this directory to prevent accidentally forwarding an anon_ user_id to tools.
Applied to files:
autogpt_platform/backend/backend/copilot/tools/run_block.pyautogpt_platform/backend/backend/copilot/tools/run_block_async.pyautogpt_platform/backend/backend/copilot/tools/helpers_test.pyautogpt_platform/backend/backend/copilot/tools/get_block_result.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/tools/run_block.pyautogpt_platform/backend/backend/copilot/tools/run_block_async.pyautogpt_platform/backend/backend/copilot/tools/helpers_test.pyautogpt_platform/backend/backend/copilot/tools/get_block_result.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/tools/run_block.pyautogpt_platform/backend/backend/copilot/tools/run_block_async.pyautogpt_platform/backend/backend/copilot/tools/helpers_test.pyautogpt_platform/backend/backend/copilot/tools/get_block_result.py
📚 Learning: 2026-03-16T16:30:20.657Z
Learnt from: Abhi1992002
Repo: Significant-Gravitas/AutoGPT PR: 12417
File: autogpt_platform/backend/backend/blocks/agent_mail/threads.py:80-102
Timestamp: 2026-03-16T16:30:20.657Z
Learning: In autogpt_platform/backend/backend/blocks/agent_mail/ blocks (and across the codebase), wrapping synchronous AgentMail SDK calls with `await asyncio.to_thread()` is NOT required. The block executor runs node execution in dedicated threads via `asyncio.run_coroutine_threadsafe` (manager.py lines ~745-752, ~1079), and the existing codebase pattern does not use `asyncio.to_thread` for SDK calls inside async `run()` methods.
Applied to files:
autogpt_platform/backend/backend/copilot/tools/run_block_async.pyautogpt_platform/backend/backend/copilot/tools/get_block_result.py
📚 Learning: 2026-03-10T08:38:33.249Z
Learnt from: majdyz
Repo: Significant-Gravitas/AutoGPT PR: 12356
File: autogpt_platform/backend/backend/copilot/tools/run_block.py:297-300
Timestamp: 2026-03-10T08:38:33.249Z
Learning: In autogpt_platform/backend/backend/copilot/tools/run_block.py, the auto-approval key for sensitive block HITL review uses graph_exec_id (copilot-session-{session_id}) + node_id (copilot-node-{block_id}). This is intentional: approving a block type within a CoPilot session auto-approves all future invocations of that same block type within the same session, mirroring how auto-approve works in normal graph execution. The user explicitly opts into this session-scoped behavior via an auto-approve toggle. Without the toggle (default), each individual invocation requires its own approval.
Applied to files:
autogpt_platform/backend/backend/copilot/tools/run_block_async.pyautogpt_platform/backend/backend/copilot/tools/helpers_test.py
📚 Learning: 2026-02-04T16:49:42.490Z
Learnt from: CR
Repo: Significant-Gravitas/AutoGPT PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2026-02-04T16:49:42.490Z
Learning: Applies to autogpt_platform/backend/backend/blocks/**/*.py : Write tests alongside block implementation when adding new blocks in backend
Applied to files:
autogpt_platform/backend/backend/copilot/tools/run_block_async.pyautogpt_platform/backend/backend/copilot/tools/helpers_test.py
📚 Learning: 2026-02-04T16:49:42.490Z
Learnt from: CR
Repo: Significant-Gravitas/AutoGPT PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2026-02-04T16:49:42.490Z
Learning: Applies to autogpt_platform/backend/backend/blocks/**/*.py : Inherit from 'Block' base class with input/output schemas when adding new blocks in backend
Applied to files:
autogpt_platform/backend/backend/copilot/tools/run_block_async.pyautogpt_platform/backend/backend/copilot/tools/helpers_test.py
📚 Learning: 2026-02-04T16:50:20.508Z
Learnt from: CR
Repo: Significant-Gravitas/AutoGPT PR: 0
File: autogpt_platform/backend/CLAUDE.md:0-0
Timestamp: 2026-02-04T16:50:20.508Z
Learning: Applies to autogpt_platform/backend/backend/blocks/*.py : When creating new blocks, inherit from the `Block` base class and define input/output schemas using `BlockSchema`
Applied to files:
autogpt_platform/backend/backend/copilot/tools/run_block_async.pyautogpt_platform/backend/backend/copilot/tools/helpers_test.py
📚 Learning: 2026-02-05T04:11:15.945Z
Learnt from: ntindle
Repo: Significant-Gravitas/AutoGPT PR: 11796
File: autogpt_platform/backend/backend/blocks/video/concat.py:3-4
Timestamp: 2026-02-05T04:11:15.945Z
Learning: Block IDs in autogpt_platform/backend/backend/blocks/**/*.py must be stable, hard-coded UUID strings. When initially creating a new block, generate a UUID once using `uuid.uuid4()` and then hard-code that UUID string as the block's `id` parameter. Do not call uuid.uuid4() dynamically at runtime, as block IDs must remain constant across all imports and runs.
Applied to files:
autogpt_platform/backend/backend/copilot/tools/run_block_async.py
📚 Learning: 2026-03-16T16:30:20.657Z
Learnt from: Abhi1992002
Repo: Significant-Gravitas/AutoGPT PR: 12417
File: autogpt_platform/backend/backend/blocks/agent_mail/threads.py:80-102
Timestamp: 2026-03-16T16:30:20.657Z
Learning: In autogpt_platform/backend/backend/blocks/agent_mail/ (and other blocks under autogpt_platform/backend/backend/blocks/), the block executor framework (backend/executor/manager.py lines ~708-733) automatically catches all uncaught exceptions from a block's `run()` method and emits them on the `"error"` output. Explicit try/except blocks within `run()` are therefore not required for standard error propagation — they are only needed when partial output behaviour must be controlled (e.g., preventing some outputs from being yielded on failure, as in attachment blocks). This is the standard pattern across the codebase.
Applied to files:
autogpt_platform/backend/backend/copilot/tools/run_block_async.pyautogpt_platform/backend/backend/copilot/tools/get_block_result.py
📚 Learning: 2026-03-10T08:39:22.025Z
Learnt from: majdyz
Repo: Significant-Gravitas/AutoGPT PR: 12356
File: autogpt_platform/backend/backend/copilot/constants.py:9-12
Timestamp: 2026-03-10T08:39:22.025Z
Learning: In Significant-Gravitas/AutoGPT PR `#12356`, the `COPILOT_SYNTHETIC_ID_PREFIX = "copilot-"` check in `create_auto_approval_record` (human_review.py) is intentional and safe. The `graph_exec_id` passed to this function comes from server-side `PendingHumanReview` DB records (not from user input); the API only accepts `node_exec_id` from users. Synthetic `copilot-*` IDs are only ever created server-side in `run_block.py`. The prefix skip avoids a DB lookup for a `AgentGraphExecution` record that legitimately does not exist for CoPilot sessions, while `user_id` scoping is enforced at the auth layer and on the resulting auto-approval record.
Applied to files:
autogpt_platform/backend/backend/copilot/tools/run_block_async.pyautogpt_platform/backend/backend/copilot/tools/helpers_test.pyautogpt_platform/backend/backend/copilot/tools/get_block_result.py
📚 Learning: 2026-03-10T08:38:36.655Z
Learnt from: majdyz
Repo: Significant-Gravitas/AutoGPT PR: 12356
File: autogpt_platform/backend/backend/copilot/tools/run_block.py:349-370
Timestamp: 2026-03-10T08:38:36.655Z
Learning: In the AutoGPT CoPilot HITL (Human-In-The-Loop) flow (`autogpt_platform/backend/backend/copilot/tools/run_block.py`), the review card presented to users sets `editable: false`, meaning reviewers cannot modify the input payload. Therefore, credentials resolved before `is_block_exec_need_review()` remain valid and do not need to be recomputed after the review step — the original `input_data` is unchanged through the review lifecycle.
Applied to files:
autogpt_platform/backend/backend/copilot/tools/run_block_async.pyautogpt_platform/backend/backend/copilot/tools/helpers_test.py
📚 Learning: 2026-02-04T16:50:51.495Z
Learnt from: CR
Repo: Significant-Gravitas/AutoGPT PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-02-04T16:50:51.495Z
Learning: Applies to autogpt_platform/**/data/*.py : For changes touching `data/*.py`, validate user ID checks or explain why not needed
Applied to files:
autogpt_platform/backend/backend/copilot/tools/run_block_async.py
📚 Learning: 2026-02-04T16:49:42.490Z
Learnt from: CR
Repo: Significant-Gravitas/AutoGPT PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2026-02-04T16:49:42.490Z
Learning: Applies to autogpt_platform/backend/**/test/**/*.py : Use snapshot testing with '--snapshot-update' flag in backend tests when output changes; always review with 'git diff'
Applied to files:
autogpt_platform/backend/backend/copilot/tools/helpers_test.py
📚 Learning: 2026-02-04T16:50:20.508Z
Learnt from: CR
Repo: Significant-Gravitas/AutoGPT PR: 0
File: autogpt_platform/backend/CLAUDE.md:0-0
Timestamp: 2026-02-04T16:50:20.508Z
Learning: Applies to autogpt_platform/backend/**/*_test.py : Always review snapshot changes with `git diff` before committing when updating snapshots with `poetry run pytest --snapshot-update`
Applied to files:
autogpt_platform/backend/backend/copilot/tools/helpers_test.py
📚 Learning: 2026-02-04T16:50:20.508Z
Learnt from: CR
Repo: Significant-Gravitas/AutoGPT PR: 0
File: autogpt_platform/backend/CLAUDE.md:0-0
Timestamp: 2026-02-04T16:50:20.508Z
Learning: Applies to autogpt_platform/backend/**/*_test.py : Use pytest with snapshot testing for API responses in test files
Applied to files:
autogpt_platform/backend/backend/copilot/tools/helpers_test.py
📚 Learning: 2026-03-17T07:24:29.647Z
Learnt from: majdyz
Repo: Significant-Gravitas/AutoGPT PR: 12385
File: autogpt_platform/backend/backend/copilot/rate_limit.py:0-0
Timestamp: 2026-03-17T07:24:29.647Z
Learning: In `autogpt_platform/backend/backend/copilot/rate_limit.py`, all fail-open `except` blocks catch `(RedisError, ConnectionError, OSError)` specifically — not bare `except Exception`. This applies to `_session_reset_from_ttl`, `get_usage_status`, `check_rate_limit`, and `record_token_usage`. The narrowed tuple ensures only genuine Redis/network failures are swallowed; unexpected exceptions propagate normally.
Applied to files:
autogpt_platform/backend/backend/copilot/tools/get_block_result.py
🔇 Additional comments (7)
autogpt_platform/backend/backend/copilot/tools/helpers_test.py (2)
81-201: Strong coverage for credit-charging execution paths.Nice set of assertions across positive-cost charging, pre-exec insufficient credits, zero-cost bypass, and post-exec insufficient-balance behavior.
580-704: Preparation flow tests cover the important validation branches well.The cases for not-found/disabled blocks, unrecognized fields, missing credentials, and successful
BlockPreparationare well targeted.autogpt_platform/backend/backend/copilot/tools/run_block.py (5)
9-15: LGTM!The imports are well-organized and all imported symbols (
BlockPreparation,check_hitl_review,execute_block,prepare_block_for_execution,BlockDetails,BlockDetailsResponse,ErrorResponse,ToolResponseBase) are properly utilized throughout the file.
117-126: LGTM!The preparation flow correctly uses the new
prepare_block_for_executionhelper with proper error handling. Theisinstancecheck cleanly distinguishes between early-return responses and successfulBlockPreparationresults, and the type annotation at line 126 correctly narrows the type after the guard.
128-160: LGTM!The two-step UX logic is well-implemented:
- The set subset check (
required_non_credential_keys <= provided_input_keys) correctly determines when to show schema vs. execute.- Output schema generation has proper error handling with a descriptive error message.
- The
BlockDetailsResponseconstruction correctly uses allBlockPreparationfields, matching the dataclass definition.
162-175: LGTM!The HITL review integration is clean and correct:
- The
isinstancecheck properly guards againstReviewRequiredResponsereturns.- The tuple unpacking correctly handles the success case
(synthetic_node_exec_id, input_data).- The
execute_blockcall passes all required parameters matching the expected signature, including thematched_credentialsfrom the preparation step.Based on learnings, the credential validation performed before
is_block_exec_need_review()remains valid since the review card presents witheditable: false, soprep.matched_credentialsis correctly reused here.
20-73: LGTM!The
RunBlockToolclass structure is clean with well-defined properties. The description clearly documents the two-step flow and the requirement to callfind_blockfirst. Parameter definitions are comprehensive with helpful descriptions.
|
This pull request has conflicts with the base branch, please resolve those so we can evaluate the pull request. |
|
Addressed reviewer feedback from autogpt-pr-reviewer: Blockers (all 3 already resolved in prior commits):
Should Fix addressed in 663a11b:
Should Fix items no longer in PR scope (removed by rebase onto dev):
|
|
This pull request has conflicts with the base branch, please resolve those so we can evaluate the pull request. |
|
Conflicts have been resolved! 🎉 A maintainer will review the pull request shortly. |
|
This pull request has conflicts with the base branch, please resolve those so we can evaluate the pull request. |
Integrate block-level permission checking from #12482 into the refactored run_block that uses prepare_block_for_execution helper.
|
Conflicts have been resolved! 🎉 A maintainer will review the pull request shortly. |
Excellent work! This is a well-designed feature with thorough testing.Blocking issue:❌ Merge conflicts must be resolved - The PR has the After resolving conflicts:The PR will be ready to merge. The implementation is solid: ✅ Clear intent and comprehensive description - Root cause analysis and test plan are excellent ✅ Proper scope - ~90%+ of changes support the parallel execution feature; the ✅ Excellent test coverage - 10 new parallel infrastructure tests, integration tests, and E2E verification ✅ Clean architecture - DRY refactor with ✅ Proper error handling - Cancellation support, fallback paths, and arg-mismatch detection all present ✅ Conventional commit format - Title correctly follows Once conflicts are resolved, this will be a great addition to the codebase. |
The permission tests were patching 'run_block.get_block' but after the refactor, get_block is only imported in helpers.py. Update the patch targets to 'helpers.get_block'.
- Add 5s timeout to cancel_pending_tool_tasks gather to prevent hanging on stuck task cleanup - Await cancelled task on arg mismatch before falling through to direct execution, preventing duplicate concurrent side effects - Add debug logging when flattening legacy dict-format understanding data
Feedback❌ Out-of-scope change detectedYour PR includes a change to def _json_to_list(value: Any) -> list[str]:
# ... new handling for legacy dict-format rows from "reverted themed-prompts feature"This change handles data migration for a legacy feature and has nothing to do with the parallel execution infrastructure described in your PR. Required action:
✅ What's good
Once the out-of-scope change is addressed, this will be ready to merge. |
#12507) ## Summary - Adds `/pr-test` skill for automated E2E testing of PRs using docker compose, agent-browser, and API calls - Covers full environment setup (copy .env, configure copilot auth, ARM64 Docker fix) - Includes browser UI testing, direct API testing, screenshot capture, and test report generation - Has `--fix` mode for auto-fixing bugs found during testing (similar to `/pr-address`) - **Screenshot uploads use GitHub Git API** (blobs → tree → commit → ref) — no local git operations, safe for worktrees - **Subscription mode improvements:** - Extract subscription auth logic to `sdk/subscription.py` — uses SDK's bundled CLI binary instead of requiring `npm install -g @anthropic-ai/claude-code` - Auto-provision `~/.claude/.credentials.json` from `CLAUDE_CODE_OAUTH_TOKEN` env var on container startup — no `claude login` needed in Docker - Add `scripts/refresh_claude_token.sh` — cross-platform helper (macOS/Linux/Windows) to extract OAuth tokens from host and update `backend/.env` ## Test plan - [x] Validated skill on multiple PRs (#12482, #12483, #12499, #12500, #12501, #12440, #12472) — all test scenarios passed - [x] Confirmed screenshot upload via GitHub Git API renders correctly on all 7 PRs - [x] Verified subscription mode E2E in Docker: `refresh_claude_token.sh` → `docker compose up` → copilot chat responds correctly with no API keys (pure OAuth subscription) - [x] Verified auto-provisioning of credentials file inside container from `CLAUDE_CODE_OAUTH_TOKEN` env var - [x] Confirmed bundled CLI detection (`claude_agent_sdk._bundled/claude`) works without system-installed `claude` - [x] `poetry run pytest backend/copilot/sdk/service_test.py` — 24/24 tests pass
Summary
pre_launch_tool_call()totool_adapter.py: when anAssistantMessagewithToolUseBlocks arrives, all tools are immediately fired asasyncio.Tasks before the SDK dispatches MCP handlers. Each MCP handler then awaits its pre-launched task instead of executing fresh._tool_task_queuesContextVar(initialized per-session inset_execution_context()) so concurrent sessions never share task queues.prepare_block_for_execution(),check_hitl_review(), andBlockPreparationdataclass intohelpers.pyso the execution pipeline is reusable.CancelledErrorhandling, multi-same-tool FIFO ordering).Root cause
The Claude Agent SDK CLI sends MCP tool calls as sequential request-response pairs: it waits for each
control_responsebefore issuing the nextmcp_message. Even though Python dispatches handlers withstart_soon, the CLI never issues call B until call A's response is sent — blocks always ran sequentially. The pre-launch pattern fixes this at the infrastructure level by starting all tasks before the SDK even dispatches the first handler.Test plan
poetry run pytest backend/copilot/sdk/tool_adapter_test.py— 27 tests pass (10 new parallel infra tests)poetry run pytest backend/copilot/tools/helpers_test.py— 20 tests passpoetry run pytest backend/copilot/tools/run_block_test.py backend/copilot/tools/test_run_block_details.py— all pass