Skip to content

feat(backend/copilot): TodoWrite for baseline copilot - #12879

Merged
majdyz merged 10 commits into
devfrom
feat/copilot-baseline-todowrite-task
Apr 22, 2026
Merged

feat(backend/copilot): TodoWrite for baseline copilot#12879
majdyz merged 10 commits into
devfrom
feat/copilot-baseline-todowrite-task

Conversation

@majdyz

@majdyz majdyz commented Apr 22, 2026

Copy link
Copy Markdown
Contributor

Summary

Add TodoWrite to baseline copilot so the "task checklist" UI works on non-Claude models (Kimi, GPT, Grok, etc.) the same way it works on the SDK path. Baseline previously had no TodoWrite tool at all — only SDK mode did via the Claude Code CLI's built-in — so models on baseline just couldn't reach for a planning checklist.

This closes the last clear feature gap blocking baseline from being the primary copilot path without giving up model flexibility.

What ships

  • New MCP tool TodoWrite in TOOL_REGISTRY, schema matching the one the frontend's GenericTool.helpers.ts (getToolCategory → "todo") already renders as the Steps accordion. The tool is a stateless echo — the canonical list lives in the model's latest tool-call args and replays from transcript on subsequent turns.
  • Prompt guidance in SHARED_TOOL_NOTES teaching the model when to use it (3+ step tasks; always send the full list; exactly one in_progress at a time).
  • Sharpened run_sub_session guidance in the same prompt section — framed explicitly as the context-isolation primitive for baseline. Clearer for the model, no dual-primitive confusion.

How the SDK path stays untouched

  • SDK mode keeps using the CLI-native TodoWrite built-in.
  • BASELINE_ONLY_MCP_TOOLS = {"TodoWrite"} in sdk/tool_adapter.py filters the baseline MCP wrapper out of SDK's allowed_tools — no name shadowing.
  • SDK_BUILTIN_TOOL_NAMES is now an explicit allowlist (not auto-derived from capitalization) so the classification stays coherent when a capitalized tool is platform-owned.

Files

File Change
backend/copilot/tools/todo_write.py new — TodoWriteTool
backend/copilot/tools/__init__.py register in TOOL_REGISTRY
backend/copilot/tools/models.py add TodoItem + TodoWriteResponse + ResponseType.TODO_WRITE
backend/copilot/permissions.py explicit SDK_BUILTIN_TOOL_NAMES; apply_tool_permissions maps baseline-only tools to CLI name for SDK
backend/copilot/sdk/tool_adapter.py BASELINE_ONLY_MCP_TOOLS filter
backend/copilot/prompting.py TodoWrite + sharpened run_sub_session guidance
backend/api/features/chat/routes.py add TodoWriteResponse to ToolResponseUnion
backend/copilot/tools/todo_write_test.py new — schema + execute tests
frontend/src/app/api/openapi.json regenerated
tools/tool_schema_test.py budget bumped 32_800 → 34_000 (actual 33_865, +1_065 headroom)

Test plan

  • poetry run pytest backend/copilot/ backend/api/features/chat/routes_test.py1010 passing
  • Tool schema char budget regression gate passes
  • _assert_tool_names_consistent passes
  • E2E on local native stack (Kimi K2.6 via OpenRouter, CHAT_USE_CLAUDE_AGENT_SDK=false): baseline called TodoWrite on a 3-step prompt, SSE stream carried the exact {content, activeForm, status} shape the UI expects, "Steps" dialog renders Task list — 0/3 completed with all three items (see test-report comment below).
  • Negative cases covered: two in_progress → rejected, missing activeForm → rejected, non-list todos → rejected.

Close the two SDK-vs-baseline parity gaps that matter for baseline to
become the primary copilot path without losing model flexibility.

**TodoWrite**: a stateless checklist tool registered under the exact
capitalized name so the existing frontend accordion (`GenericTool`
`getToolCategory("TodoWrite") === "todo"`) renders baseline-emitted todo
updates identically to SDK-emitted ones.

**Task**: an in-process sub-agent that runs a fresh ``tool_call_loop``
inside the current session with an isolated message history.  Only the
sub-agent's final summary reaches the parent context — its intermediate
tool calls, reasoning, and text deltas stay hidden.  Depth is capped via
ContextVar (``_MAX_TASK_DEPTH=2``), iteration count via
``_MAX_TASK_ITERATIONS=15``; token and cost usage roll up to the parent
state so billing is preserved.  ``Task`` is stripped from the inner tool
list so a sub-agent can't re-enter this path (belt-and-braces with the
depth cap).

SDK mode keeps using the Claude Code CLI's native ``Task`` /
``TodoWrite`` — the MCP-wrapped baseline copies are filtered out of
``get_copilot_tool_names`` via ``_BASELINE_ONLY_MCP_TOOLS`` to avoid
name shadowing.  ``permissions.py`` reclassifies both as platform
tools and ``apply_tool_permissions`` maps them back to the CLI built-in
name when SDK permissions reference them.

Prompt guidance lives in ``SHARED_TOOL_NOTES`` so both paths see it.

Schema budget bumped 32_800 → 34_200 to absorb the two new tool
skeletons (~1.2k chars); descriptions already trimmed to the minimum
viable copy.
@majdyz
majdyz requested a review from a team as a code owner April 22, 2026 05:19
@majdyz
majdyz requested review from Bentlybro and Pwuts and removed request for a team April 22, 2026 05:19
@github-project-automation github-project-automation Bot moved this to 🆕 Needs initial review in AutoGPT development kanban Apr 22, 2026
@github-actions github-actions Bot added platform/backend AutoGPT Platform - Back end size/xl labels Apr 22, 2026
@coderabbitai

coderabbitai Bot commented Apr 22, 2026

Copy link
Copy Markdown
Contributor

Note

Reviews paused

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

Use the following commands to manage reviews:

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

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review

Walkthrough

Adds an in-process Task sub-agent execution path to the baseline service with depth/iteration caps, usage roll-up, and inner-event isolation; introduces Task and TodoWrite tools, response models, prompting docs, SDK/permissions adjustments to exclude baseline-only tools, and accompanying tests and OpenAPI updates.

Changes

Cohort / File(s) Summary
Baseline Task execution
autogpt_platform/backend/backend/copilot/baseline/service.py
Adds _run_task_subagent and _baseline_tool_executor handling for Task, depth/iteration caps (_MAX_TASK_DEPTH, _MAX_TASK_ITERATIONS), _TASK_DEPTH_VAR ContextVar, preflight/error helpers, inner-conversation updater, and _absorb_inner_usage.
Baseline Task tests
autogpt_platform/backend/backend/copilot/baseline/service_unit_test.py
Adds async tests for _run_task_subagent: success path, prompt validation, depth-cap enforcement, inner-event isolation, usage aggregation, context-var cleanup, and inner-tools transformation.
Tool schemas & registry
autogpt_platform/backend/backend/copilot/tools/models.py, autogpt_platform/backend/backend/copilot/tools/__init__.py
Adds ResponseType values TASK/TODO_WRITE, models TaskResponse, TodoWriteResponse, TodoItem, and registers Task/TodoWrite in TOOL_REGISTRY.
Task tool & tests
autogpt_platform/backend/backend/copilot/tools/task.py, autogpt_platform/backend/backend/copilot/tools/task_test.py
Introduces TaskTool with OpenAI tool schema and a fallback _execute returning an ErrorResponse when invoked outside baseline service; tests verify schema and fallback message.
TodoWrite tool & tests
autogpt_platform/backend/backend/copilot/tools/todo_write.py, autogpt_platform/backend/backend/copilot/tools/todo_write_test.py
Adds TodoWriteTool with todos schema, validation (single in_progress), canonicalization to TodoItems, success/error handling, and tests for schema and behavior.
SDK allowlist & adapter
autogpt_platform/backend/backend/copilot/sdk/tool_adapter.py
Adds BASELINE_ONLY_MCP_TOOLS and _registry_mcp_tools() to exclude baseline-only tools (Task, TodoWrite) from MCP-wrapped SDK allowlists.
Permissions & builtin names
autogpt_platform/backend/backend/copilot/permissions.py, autogpt_platform/backend/backend/copilot/permissions_test.py
Makes SDK_BUILTIN_TOOL_NAMES an explicit set excluding Task/TodoWrite; adjusts to_sdk_names to preserve baseline-only names; tests updated to assert exclusion.
Prompting docs
autogpt_platform/backend/backend/copilot/prompting.py
Rewrites Task sub-agent guidance and adds TodoWrite planning/checklist guidance and constraints.
Schema budget test
autogpt_platform/backend/backend/copilot/tools/tool_schema_test.py
Increases _CHAR_BUDGET to account for added tool schemas and updates explanatory comment.
API schemas / frontend
autogpt_platform/frontend/src/app/api/openapi.json, autogpt_platform/backend/backend/api/features/chat/routes.py
Adds todo_write and task to ResponseType, includes TodoWriteResponse/TaskResponse in tool-response unions and OpenAPI schemas.

Sequence Diagram(s)

sequenceDiagram
    participant ParentLoop as Parent LLM Loop
    participant Baseline as Baseline Service
    participant InnerLoop as Inner Task Loop
    participant InnerLLM as Inner LLM
    participant Tools as Tool Executor

    ParentLoop->>Baseline: tool_call(name="Task", prompt=...)
    Baseline->>Baseline: check _TASK_DEPTH_VAR vs _MAX_TASK_DEPTH
    alt depth exceeded
        Baseline-->>ParentLoop: TaskResponse (error: depth)
    else depth ok
        Baseline->>Baseline: validate prompt (non-empty)
        alt prompt invalid
            Baseline-->>ParentLoop: TaskResponse (error: prompt)
        else prompt valid
            Baseline->>Baseline: increment _TASK_DEPTH_VAR
            Baseline->>InnerLoop: start _run_task_subagent(prompt, tools without Task)
            loop up to _MAX_TASK_ITERATIONS
                InnerLoop->>InnerLLM: chat completion with inner messages + tools
                InnerLLM-->>InnerLoop: response (+ tool_calls)
                InnerLoop->>Tools: execute tool_calls
                Tools-->>InnerLoop: tool results
                alt more iterations needed
                    InnerLoop->>InnerLLM: append results, continue
                else finished or max reached
                    InnerLoop-->>Baseline: final summary + usage + iterations + tool_calls
                end
            end
            Baseline->>Baseline: _absorb_inner_usage()
            Baseline-->>ParentLoop: TaskResponse (completed or max_iterations)
        end
    end
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~55 minutes

Possibly related PRs

Suggested labels

Review effort 4/5

Suggested reviewers

  • Swiftyos
  • Bentlybro
  • Pwuts

Poem

🐰 I hopped into code with a checklist bright,
nested Task loops bounded by depth and light,
TodoWrite keeps items tidy, one in progress at a time,
inner tokens folded home — the parent ledger's fine.

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 46.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
Title check ✅ Passed The title 'feat(backend/copilot): TodoWrite for baseline copilot' accurately describes a main component of this PR but omits the equally significant Task sub-agent feature, making it partially related rather than fully comprehensive.
Description check ✅ Passed The description comprehensively details both the TodoWrite and Task features, explains how the SDK path remains untouched, lists all affected files, and includes test results and verification steps, directly relating to all major changes in the changeset.

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

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feat/copilot-baseline-todowrite-task

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

❤️ Share

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

@github-actions

github-actions Bot commented Apr 22, 2026

Copy link
Copy Markdown
Contributor

🔍 PR Overlap Detection

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

🔴 Merge Conflicts Detected

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

  • fix(copilot): prevent 524 timeout on chat deletion by deferring cleanup #12668 (Otto-AGPT · updated 5d ago)

    • autogpt_platform/backend/backend/api/features/library/db.py (5 conflicts, ~67 lines)
    • autogpt_platform/backend/backend/api/features/library/model.py (1 conflict, ~4 lines)
    • autogpt_platform/backend/backend/api/features/subscription_routes_test.py (5 conflicts, ~376 lines)
    • autogpt_platform/backend/backend/api/features/v1.py (9 conflicts, ~88 lines)
    • autogpt_platform/backend/backend/copilot/baseline/service.py (2 conflicts, ~15 lines)
    • autogpt_platform/backend/backend/copilot/model_test.py (1 conflict, ~5 lines)
    • autogpt_platform/backend/backend/copilot/sdk/service.py (3 conflicts, ~51 lines)
    • autogpt_platform/backend/backend/copilot/transcript.py (1 conflict, ~11 lines)
    • autogpt_platform/backend/backend/data/credit.py (5 conflicts, ~727 lines)
    • autogpt_platform/backend/backend/data/credit_subscription_test.py (14 conflicts, ~1333 lines)
    • autogpt_platform/frontend/src/app/(platform)/copilot/components/PulseChips/usePulseChips.ts (1 conflict, ~13 lines)
    • autogpt_platform/frontend/src/app/(platform)/copilot/components/usageHelpers.ts (1 conflict, ~9 lines)
    • autogpt_platform/frontend/src/app/(platform)/library/components/AgentBriefingPanel/BriefingTabContent.tsx (9 conflicts, ~147 lines)
    • autogpt_platform/frontend/src/app/(platform)/library/components/AgentBriefingPanel/StatsGrid.tsx (2 conflicts, ~9 lines)
    • autogpt_platform/frontend/src/app/(platform)/library/components/ContextualActionButton/ContextualActionButton.tsx (2 conflicts, ~12 lines)
    • autogpt_platform/frontend/src/app/(platform)/library/components/SitrepItem/SitrepItem.tsx (2 conflicts, ~15 lines)
    • autogpt_platform/frontend/src/app/(platform)/library/components/SitrepItem/useSitrepItems.ts (4 conflicts, ~97 lines)
    • autogpt_platform/frontend/src/app/(platform)/library/hooks/useAgentStatus.ts (2 conflicts, ~10 lines)
    • autogpt_platform/frontend/src/app/(platform)/library/hooks/useLibraryFleetSummary.ts (7 conflicts, ~57 lines)
    • autogpt_platform/frontend/src/app/(platform)/library/types.ts (1 conflict, ~4 lines)
    • autogpt_platform/frontend/src/app/(platform)/profile/(user)/credits/components/SubscriptionTierSection/SubscriptionTierSection.tsx (9 conflicts, ~159 lines)
    • autogpt_platform/frontend/src/app/(platform)/profile/(user)/credits/components/SubscriptionTierSection/__tests__/SubscriptionTierSection.test.tsx (7 conflicts, ~256 lines)
    • autogpt_platform/frontend/src/app/(platform)/profile/(user)/credits/components/SubscriptionTierSection/useSubscriptionTierSection.ts (2 conflicts, ~48 lines)
    • autogpt_platform/frontend/src/app/api/openapi.json (1 conflict, ~23 lines)
    • docs/integrations/block-integrations/misc.md (1 conflict, ~5 lines)
  • feat(platform): Trigger On Anything #12740 (Pwuts · updated 11h ago)

    • 📁 autogpt_platform/
      • backend/backend/copilot/tools/tool_schema_test.py (1 conflict, ~28 lines)
      • frontend/src/app/api/openapi.json (2 conflicts, ~174 lines)
  • feat(platform): estimate CoPilot turn cost and require approval for high-cost requests #12877 (Rushi-Balapure · updated 6h ago)

    • 📁 autogpt_platform/backend/backend/
      • api/features/chat/routes.py (2 conflicts, ~32 lines)
      • util/feature_flag.py (1 conflict, ~8 lines)
  • feat(copilot): add goal decomposition step before agent building #12731 (anvyle · updated 51m ago)

    • 📁 autogpt_platform/backend/backend/
      • api/features/chat/routes.py (1 conflict, ~5 lines)
      • copilot/tools/tool_schema_test.py (1 conflict, ~18 lines)
  • feat(backend/api): External API v2 #12206 (Pwuts · updated 12d ago)

🟢 Low Risk — File Overlap Only

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

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


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

Comment thread autogpt_platform/backend/backend/copilot/baseline/service.py Outdated
Comment thread autogpt_platform/backend/backend/copilot/baseline/service.py Outdated
Comment thread autogpt_platform/backend/backend/copilot/baseline/service.py Outdated
Comment thread autogpt_platform/backend/backend/copilot/permissions.py Outdated

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Actionable comments posted: 4

🧹 Nitpick comments (1)
autogpt_platform/backend/backend/copilot/baseline/service_unit_test.py (1)

2017-2020: Move the new local imports to the module level.

ChatSession and json are lightweight/non-optional imports, so the new test helper and assertions should use top-level imports instead of local imports.

♻️ Proposed cleanup
+import json
 from unittest.mock import AsyncMock, MagicMock, patch
@@
-from backend.copilot.model import ChatMessage
+from backend.copilot.model import ChatMessage, ChatSession
@@
 def _task_session():
-    from backend.copilot.model import ChatSession
-
     return ChatSession.new(user_id="task-user", dry_run=False)
@@
         assert result.toolName == "Task"
         assert result.success is True
-        import json
-
         payload = json.loads(result.output)
@@
-        import json
-
         payload = json.loads(result.output)
@@
-        import json
-
         payload = json.loads(result.output)

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

Also applies to: 2056-2082, 2115-2117

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@autogpt_platform/backend/backend/copilot/baseline/service_unit_test.py`
around lines 2017 - 2020, The test file uses local imports inside the helper
_task_session() (and similar helpers/assertions around lines 2056-2082 and
2115-2117) — move those to module-level imports so lightweight non-optional
symbols like ChatSession and json are imported at the top of the file; update
_task_session(), related helper functions, and assertions to reference the
top-level ChatSession and json imports instead of performing local imports.
🤖 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/baseline/service.py`:
- Around line 970-1015: The try/except/else block that sets token =
_TASK_DEPTH_VAR.set(depth + 1) must always reset the token even on BaseException
(e.g., CancelledError); move _TASK_DEPTH_VAR.reset(token) into a finally block
so it always runs, remove the "# noqa: BLE001" suppressor, and keep the existing
error handling: in the except path still call logger.error(..., exc_info=True),
_absorb_inner_usage(parent_state, inner_state), construct TaskResponse and
return StreamToolOutputAvailable; ensure the else branch behavior (setting
final_response_text and other vars) is preserved before the finally executes and
that the finally only performs the reset.

In `@autogpt_platform/backend/backend/copilot/prompting.py`:
- Around line 162-177: Update the Task tool documentation paragraph in
prompting.py to explicitly state that while the sub-agent uses the same tool
set, the Task tool itself is removed from the inner tool list so sub-agents
cannot call Task recursively; mention that nested Task calls are rejected by the
baseline and advise using run_sub_session for durable or queued work and that
run_in_background must not be set. Reference the existing symbols "Task",
"run_in_background", and "run_sub_session" so the change is applied to the same
explanatory block.

In `@autogpt_platform/backend/backend/copilot/tools/models.py`:
- Around line 868-902: The ToolResponseUnion is missing the newly defined
TodoWriteResponse and TaskResponse types; update the ToolResponseUnion
declaration to include | TodoWriteResponse and | TaskResponse so the
/api/chat/schema/tool-responses endpoint exposes them. Locate the
ToolResponseUnion symbol (current union of AgentsFoundResponse,
NoResultsResponse, etc.) and append TodoWriteResponse and TaskResponse to the
union expression, then run the OpenAPI/typegen to verify the frontend types
include the new responses.

In `@autogpt_platform/backend/backend/copilot/tools/tool_schema_test.py`:
- Around line 28-33: Update the test docstring in test_total_schema_char_budget
to reflect the new _CHAR_BUDGET value (34_200) instead of the old "32000 chars ≈
8000 tokens"; locate the docstring or comment inside the
test_total_schema_char_budget function and change the numeric char budget and
approximate token estimate to match _CHAR_BUDGET (34_200) so the documentation
stays accurate when the constant is changed.

---

Nitpick comments:
In `@autogpt_platform/backend/backend/copilot/baseline/service_unit_test.py`:
- Around line 2017-2020: The test file uses local imports inside the helper
_task_session() (and similar helpers/assertions around lines 2056-2082 and
2115-2117) — move those to module-level imports so lightweight non-optional
symbols like ChatSession and json are imported at the top of the file; update
_task_session(), related helper functions, and assertions to reference the
top-level ChatSession and json imports instead of performing local imports.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: fd8b71b5-91e7-429f-a602-118856717198

📥 Commits

Reviewing files that changed from the base of the PR and between e3f6d36 and a47de8a.

📒 Files selected for processing (13)
  • autogpt_platform/backend/backend/copilot/baseline/service.py
  • autogpt_platform/backend/backend/copilot/baseline/service_unit_test.py
  • autogpt_platform/backend/backend/copilot/permissions.py
  • autogpt_platform/backend/backend/copilot/permissions_test.py
  • autogpt_platform/backend/backend/copilot/prompting.py
  • autogpt_platform/backend/backend/copilot/sdk/tool_adapter.py
  • autogpt_platform/backend/backend/copilot/tools/__init__.py
  • autogpt_platform/backend/backend/copilot/tools/models.py
  • autogpt_platform/backend/backend/copilot/tools/task.py
  • autogpt_platform/backend/backend/copilot/tools/task_test.py
  • autogpt_platform/backend/backend/copilot/tools/todo_write.py
  • autogpt_platform/backend/backend/copilot/tools/todo_write_test.py
  • autogpt_platform/backend/backend/copilot/tools/tool_schema_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). (9)
  • GitHub Check: check API types
  • GitHub Check: Seer Code Review
  • GitHub Check: test (3.13)
  • GitHub Check: Analyze (typescript)
  • GitHub Check: Analyze (python)
  • GitHub Check: end-to-end tests
  • GitHub Check: test (3.12)
  • GitHub Check: test (3.11)
  • GitHub Check: Check PR Status
🧰 Additional context used
📓 Path-based instructions (3)
autogpt_platform/backend/**/*.py

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

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

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

Files:

  • autogpt_platform/backend/backend/copilot/tools/tool_schema_test.py
  • autogpt_platform/backend/backend/copilot/permissions_test.py
  • autogpt_platform/backend/backend/copilot/sdk/tool_adapter.py
  • autogpt_platform/backend/backend/copilot/tools/__init__.py
  • autogpt_platform/backend/backend/copilot/tools/task_test.py
  • autogpt_platform/backend/backend/copilot/permissions.py
  • autogpt_platform/backend/backend/copilot/prompting.py
  • autogpt_platform/backend/backend/copilot/tools/todo_write_test.py
  • autogpt_platform/backend/backend/copilot/tools/todo_write.py
  • autogpt_platform/backend/backend/copilot/baseline/service_unit_test.py
  • autogpt_platform/backend/backend/copilot/tools/task.py
  • autogpt_platform/backend/backend/copilot/tools/models.py
  • autogpt_platform/backend/backend/copilot/baseline/service.py
autogpt_platform/{backend,autogpt_libs}/**/*.py

📄 CodeRabbit inference engine (AGENTS.md)

Format Python code with poetry run format

Files:

  • autogpt_platform/backend/backend/copilot/tools/tool_schema_test.py
  • autogpt_platform/backend/backend/copilot/permissions_test.py
  • autogpt_platform/backend/backend/copilot/sdk/tool_adapter.py
  • autogpt_platform/backend/backend/copilot/tools/__init__.py
  • autogpt_platform/backend/backend/copilot/tools/task_test.py
  • autogpt_platform/backend/backend/copilot/permissions.py
  • autogpt_platform/backend/backend/copilot/prompting.py
  • autogpt_platform/backend/backend/copilot/tools/todo_write_test.py
  • autogpt_platform/backend/backend/copilot/tools/todo_write.py
  • autogpt_platform/backend/backend/copilot/baseline/service_unit_test.py
  • autogpt_platform/backend/backend/copilot/tools/task.py
  • autogpt_platform/backend/backend/copilot/tools/models.py
  • autogpt_platform/backend/backend/copilot/baseline/service.py
autogpt_platform/backend/**/*_test.py

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

autogpt_platform/backend/**/*_test.py: Use pytest with snapshot testing for API responses
Colocate test files with source files using *_test.py naming convention
Mock at boundaries — mock where the symbol is used, not where it's defined; after refactoring, update mock targets to match new module paths
Use AsyncMock from unittest.mock for async functions in tests
When writing tests, use Test-Driven Development (TDD): write failing tests marked with @pytest.mark.xfail before implementation, then remove the marker once the implementation is complete
When creating snapshots in tests, use poetry run pytest path/to/test.py --snapshot-update; always review snapshot changes with git diff before committing

Files:

  • autogpt_platform/backend/backend/copilot/tools/tool_schema_test.py
  • autogpt_platform/backend/backend/copilot/permissions_test.py
  • autogpt_platform/backend/backend/copilot/tools/task_test.py
  • autogpt_platform/backend/backend/copilot/tools/todo_write_test.py
  • autogpt_platform/backend/backend/copilot/baseline/service_unit_test.py
🧠 Learnings (35)
📓 Common learnings
Learnt from: majdyz
Repo: Significant-Gravitas/AutoGPT PR: 12632
File: autogpt_platform/backend/backend/copilot/tools/workspace_files.py:0-0
Timestamp: 2026-04-01T04:17:43.495Z
Learning: In autogpt_platform/backend/backend/copilot/sdk/tool_adapter.py (PR `#12632`, commit 12ae03c), the per-tool `BaseTool.read_only` property approach was removed. Instead, `readOnlyHint=True` (via `ToolAnnotations`) is applied unconditionally to ALL tools — including side-effect tools like `bash_exec` and `write_workspace_file` — to enable fully parallel dispatch by the Anthropic SDK/CLI. Do not flag tools with mutating operations (e.g. save_to_path, write operations) for having `readOnlyHint=True`; this is intentional and E2E validated (3x bash_exec(sleep 3) completed in 3.3s vs 9s sequential).
Learnt from: Pwuts
Repo: Significant-Gravitas/AutoGPT PR: 12740
File: autogpt_platform/frontend/src/app/api/openapi.json:0-0
Timestamp: 2026-04-13T14:19:19.341Z
Learning: Repo: Significant-Gravitas/AutoGPT — autogpt_platform
When adding new CoPilot tool response models (e.g., ScheduleListResponse, ScheduleDeletedResponse), update backend/api/features/chat/routes.py to include them in the ToolResponseUnion so the frontend’s autogenerated openapi.json dummy export (/api/chat/schema/tool-responses) exposes them for codegen. Do not hand-edit frontend/src/app/api/openapi.json.
Learnt from: majdyz
Repo: Significant-Gravitas/AutoGPT PR: 12773
File: autogpt_platform/backend/backend/blocks/autopilot.py:631-638
Timestamp: 2026-04-14T07:35:11.464Z
Learning: In `autogpt_platform/backend/backend/copilot/executor/utils.py`, `CoPilotExecutionEntry` includes a `permissions: CopilotPermissions | None` field (added in PR `#12773` / commit a0184c87b9). `enqueue_copilot_turn` accepts and serializes this field into the queue entry, `_enqueue_for_recovery` in `autopilot.py` accepts and forwards `permissions` to `enqueue_copilot_turn`, and `_execute_async` in `processor.py` restores `entry.permissions` and passes it into `stream_chat_completion_sdk`/`stream_chat_completion_baseline` via `set_execution_context`. This ensures recovered sub-agent turns respect the same tool/block permission ceiling as the original in-process execution (mirroring `_merge_inherited_permissions`). Do NOT flag recovered turns as losing their permission ceiling — it is now fully propagated through the queue.
Learnt from: majdyz
Repo: Significant-Gravitas/AutoGPT PR: 0
File: :0-0
Timestamp: 2026-04-21T11:41:05.877Z
Learning: In `autogpt_platform/backend/backend/copilot/baseline/service.py` (PR `#12870`, commits 080d42b9d and 3d7b38162), the `_close_reasoning_block_if_open(state)` helper centralises all four reasoning-block-close call sites (text branch, tool_calls branch, stream-end, exception path). The outer `finally` block of `_baseline_llm_caller` calls this helper plus stripper flush + `StreamTextEnd` to guarantee matched end events are emitted before `StreamFinishStep` on both normal and exception paths. Do NOT flag duplicated close logic or missing reasoning-end-on-exception as issues in this function.
Learnt from: majdyz
Repo: Significant-Gravitas/AutoGPT PR: 12797
File: autogpt_platform/backend/backend/copilot/sdk/service.py:1991-2021
Timestamp: 2026-04-15T13:44:34.273Z
Learning: In `autogpt_platform/backend/backend/copilot/sdk/service.py` (`_run_stream_attempt`), the pre-create block (PR `#12797`) intentionally does NOT call `state.transcript_builder.append_assistant(...)` when inserting the empty assistant placeholder into `ctx.session.messages`. The transcript is left ending at the `tool_result` entry (N entries) while `message_count` metadata is N+1. This mismatch is benign and deliberate: on the next `--resume`, the SDK sees the transcript ending at `tool_result` and correctly regenerates the assistant response. Pre-appending the assistant turn to the transcript would suppress regeneration while leaving `session.messages[-1].content = ""` permanently (worse outcome). On the gap-fallback path, `transcript_msg_count (N+1) >= msg_count-1 (N)` means no gap is injected for the empty placeholder, which is correct because injecting an empty assistant message as context would mislead the SDK. Do NOT flag this transcript/message_count discrepancy as a bug.
Learnt from: majdyz
Repo: Significant-Gravitas/AutoGPT PR: 12440
File: autogpt_platform/backend/backend/copilot/workflow_import/converter.py:0-0
Timestamp: 2026-03-17T10:57:12.953Z
Learning: In Significant-Gravitas/AutoGPT PR `#12440`, `autogpt_platform/backend/backend/copilot/workflow_import/converter.py` was fully rewritten (commit 732960e2d) to no longer make direct LLM/OpenAI API calls. The converter now builds a structured text prompt for AutoPilot/CoPilot instead. There is no `response.choices` access or any direct LLM client usage in this file. Do not flag `response.choices` access or LLM client initialization patterns as issues in this file.
Learnt from: majdyz
Repo: Significant-Gravitas/AutoGPT PR: 12213
File: autogpt_platform/frontend/src/app/api/openapi.json:9983-9995
Timestamp: 2026-02-27T15:59:00.370Z
Learning: Repo: Significant-Gravitas/AutoGPT PR: 12213 — Backend/frontend OpenAPI codegen
Learning: For MCP schema models, required OpenAPI fields must have no defaults in Pydantic. Specifically, MCPToolInfo.input_schema must be required (no Field(default_factory=dict)) so openapi.json emits it in "required", ensuring generated TS types treat input_schema as non-optional.
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: 12213
File: autogpt_platform/frontend/src/app/api/openapi.json:9983-9995
Timestamp: 2026-02-27T15:59:00.370Z
Learning: Repo: Significant-Gravitas/AutoGPT PR: 12213 — OpenAPI/codegen
Learning: Ensuring a field is required in generated TS types needs two sides: (1) no default value on the Pydantic field, and (2) the OpenAPI model's "required" array must list it. For MCPToolInfo, making input_schema required in OpenAPI and removing Field(default_factory=dict) in the backend prevents optional typing drift.
Learnt from: Pwuts
Repo: Significant-Gravitas/AutoGPT PR: 12284
File: autogpt_platform/frontend/src/app/api/openapi.json:11897-11900
Timestamp: 2026-03-04T23:58:18.476Z
Learning: Repo: Significant-Gravitas/AutoGPT — PR `#12284`
Backend/frontend OpenAPI codegen convention: In backend/api/features/store/model.py, the StoreSubmission and StoreSubmissionAdminView models define submitted_at: datetime | None, changes_summary: str | None, and instructions: str | None with no default. This is intentional to produce “required but nullable” fields in OpenAPI (properties appear in required[] and use anyOf [type, null]). This matches Prisma’s submittedAt DateTime? and changesSummary String?. Do not flag this as a required/nullable mismatch.
📚 Learning: 2026-02-27T15:59:00.370Z
Learnt from: majdyz
Repo: Significant-Gravitas/AutoGPT PR: 12213
File: autogpt_platform/frontend/src/app/api/openapi.json:9983-9995
Timestamp: 2026-02-27T15:59:00.370Z
Learning: Repo: Significant-Gravitas/AutoGPT PR: 12213 — Backend/frontend OpenAPI codegen
Learning: For MCP schema models, required OpenAPI fields must have no defaults in Pydantic. Specifically, MCPToolInfo.input_schema must be required (no Field(default_factory=dict)) so openapi.json emits it in "required", ensuring generated TS types treat input_schema as non-optional.

Applied to files:

  • autogpt_platform/backend/backend/copilot/tools/tool_schema_test.py
  • autogpt_platform/backend/backend/copilot/sdk/tool_adapter.py
  • autogpt_platform/backend/backend/copilot/tools/task_test.py
  • autogpt_platform/backend/backend/copilot/permissions.py
📚 Learning: 2026-02-27T15:59:00.370Z
Learnt from: majdyz
Repo: Significant-Gravitas/AutoGPT PR: 12213
File: autogpt_platform/frontend/src/app/api/openapi.json:9983-9995
Timestamp: 2026-02-27T15:59:00.370Z
Learning: Repo: Significant-Gravitas/AutoGPT PR: 12213 — OpenAPI/codegen
Learning: Ensuring a field is required in generated TS types needs two sides: (1) no default value on the Pydantic field, and (2) the OpenAPI model's "required" array must list it. For MCPToolInfo, making input_schema required in OpenAPI and removing Field(default_factory=dict) in the backend prevents optional typing drift.

Applied to files:

  • autogpt_platform/backend/backend/copilot/tools/tool_schema_test.py
  • autogpt_platform/backend/backend/copilot/sdk/tool_adapter.py
  • autogpt_platform/backend/backend/copilot/tools/task_test.py
  • autogpt_platform/backend/backend/copilot/permissions.py
📚 Learning: 2026-04-01T04:17:41.600Z
Learnt from: majdyz
Repo: Significant-Gravitas/AutoGPT PR: 12632
File: autogpt_platform/backend/backend/copilot/tools/workspace_files.py:0-0
Timestamp: 2026-04-01T04:17:41.600Z
Learning: When reviewing AutoGPT Copilot tool implementations, accept that `readOnlyHint=True` (provided via `ToolAnnotations`) may be applied unconditionally to *all* tools—even tools that have side effects (e.g., `bash_exec`, `write_workspace_file`, or other write/save operations). Do **not** flag these tools for having `readOnlyHint=True`; this is intentional to enable fully-parallel dispatch by the Anthropic SDK/CLI and has been E2E validated. Only flag `readOnlyHint` issues if they conflict with the established `ToolAnnotations` behavior (e.g., missing/incorrect propagation relative to the intended annotation mechanism).

Applied to files:

  • autogpt_platform/backend/backend/copilot/tools/tool_schema_test.py
  • autogpt_platform/backend/backend/copilot/permissions_test.py
  • autogpt_platform/backend/backend/copilot/sdk/tool_adapter.py
  • autogpt_platform/backend/backend/copilot/tools/__init__.py
  • autogpt_platform/backend/backend/copilot/tools/task_test.py
  • autogpt_platform/backend/backend/copilot/permissions.py
  • autogpt_platform/backend/backend/copilot/prompting.py
  • autogpt_platform/backend/backend/copilot/tools/todo_write_test.py
  • autogpt_platform/backend/backend/copilot/tools/todo_write.py
  • autogpt_platform/backend/backend/copilot/baseline/service_unit_test.py
  • autogpt_platform/backend/backend/copilot/tools/task.py
  • autogpt_platform/backend/backend/copilot/tools/models.py
  • autogpt_platform/backend/backend/copilot/baseline/service.py
📚 Learning: 2026-03-01T07:59:02.311Z
Learnt from: majdyz
Repo: Significant-Gravitas/AutoGPT PR: 12213
File: autogpt_platform/frontend/src/app/api/openapi.json:10030-10037
Timestamp: 2026-03-01T07:59:02.311Z
Learning: Repo: Significant-Gravitas/AutoGPT PR: 12213 — For MCP manual token storage, backend model autogpt_platform/backend/backend/api/features/mcp/routes.py defines MCPStoreTokenRequest.token as Pydantic SecretStr with a min length constraint, which generates OpenAPI schema metadata (format: "password", writeOnly: true, minLength: 1) in autogpt_platform/frontend/src/app/api/openapi.json. Prefer SecretStr (with length constraints) for sensitive request fields so generated TS clients and docs treat them as secrets.

Applied to files:

  • autogpt_platform/backend/backend/copilot/tools/tool_schema_test.py
📚 Learning: 2026-04-01T04:17:38.279Z
Learnt from: majdyz
Repo: Significant-Gravitas/AutoGPT PR: 12632
File: autogpt_platform/backend/backend/copilot/sdk/tool_adapter.py:530-535
Timestamp: 2026-04-01T04:17:38.279Z
Learning: In `autogpt_platform/backend/backend/copilot/sdk/tool_adapter.py`, the `ToolAnnotations(readOnlyHint=True)` annotation (stored as `_PARALLEL_ANNOTATION`) is intentionally applied to ALL registered MCP tools — including E2B write/edit tools (e.g., `write_file`, `edit_file`). This is a parallel-dispatch hint to the Claude Agent SDK CLI, not a semantic read-only contract. The `_READ_ONLY_E2B_TOOLS` set was dead code and was removed in commit `12ae03c`; the constant was renamed from `_READONLY_ANNOTATION` to `_PARALLEL_ANNOTATION` in commit `c88ca88` to avoid confusion. Do not flag this as a correctness issue.

Applied to files:

  • autogpt_platform/backend/backend/copilot/tools/tool_schema_test.py
  • autogpt_platform/backend/backend/copilot/permissions_test.py
  • autogpt_platform/backend/backend/copilot/sdk/tool_adapter.py
  • autogpt_platform/backend/backend/copilot/tools/__init__.py
  • autogpt_platform/backend/backend/copilot/permissions.py
  • autogpt_platform/backend/backend/copilot/tools/todo_write.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/tool_schema_test.py
  • autogpt_platform/backend/backend/copilot/permissions_test.py
  • autogpt_platform/backend/backend/copilot/sdk/tool_adapter.py
  • autogpt_platform/backend/backend/copilot/tools/__init__.py
  • autogpt_platform/backend/backend/copilot/tools/task_test.py
  • autogpt_platform/backend/backend/copilot/permissions.py
  • autogpt_platform/backend/backend/copilot/prompting.py
  • autogpt_platform/backend/backend/copilot/tools/todo_write_test.py
  • autogpt_platform/backend/backend/copilot/tools/todo_write.py
  • autogpt_platform/backend/backend/copilot/baseline/service_unit_test.py
  • autogpt_platform/backend/backend/copilot/tools/task.py
  • autogpt_platform/backend/backend/copilot/tools/models.py
  • autogpt_platform/backend/backend/copilot/baseline/service.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/tool_schema_test.py
  • autogpt_platform/backend/backend/copilot/permissions_test.py
  • autogpt_platform/backend/backend/copilot/sdk/tool_adapter.py
  • autogpt_platform/backend/backend/copilot/tools/__init__.py
  • autogpt_platform/backend/backend/copilot/tools/task_test.py
  • autogpt_platform/backend/backend/copilot/permissions.py
  • autogpt_platform/backend/backend/copilot/prompting.py
  • autogpt_platform/backend/backend/copilot/tools/todo_write_test.py
  • autogpt_platform/backend/backend/copilot/tools/todo_write.py
  • autogpt_platform/backend/backend/copilot/baseline/service_unit_test.py
  • autogpt_platform/backend/backend/copilot/tools/task.py
  • autogpt_platform/backend/backend/copilot/tools/models.py
  • autogpt_platform/backend/backend/copilot/baseline/service.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/tool_schema_test.py
  • autogpt_platform/backend/backend/copilot/tools/__init__.py
  • autogpt_platform/backend/backend/copilot/tools/task_test.py
  • autogpt_platform/backend/backend/copilot/tools/todo_write_test.py
  • autogpt_platform/backend/backend/copilot/tools/todo_write.py
  • autogpt_platform/backend/backend/copilot/tools/task.py
  • autogpt_platform/backend/backend/copilot/tools/models.py
📚 Learning: 2026-03-31T14:22:26.566Z
Learnt from: majdyz
Repo: Significant-Gravitas/AutoGPT PR: 12622
File: autogpt_platform/backend/backend/copilot/tools/agent_search.py:223-236
Timestamp: 2026-03-31T14:22:26.566Z
Learning: In files under autogpt_platform/backend/backend/copilot/tools/, ensure agent graph enrichment uses the typed Pydantic model `backend.data.graph.Graph` for `AgentInfo.graph` (i.e., `Graph | None`), not `dict[str, Any]`. When enriching with graph data (e.g., `_enrich_agents_with_graph`), prefer calling `graph_db().get_graph(graph_id, version=None, user_id=user_id)` directly to retrieve the typed `Graph` object rather than routing through JSON conversions like `get_agent_as_json()` / `graph_to_json()`.

Applied to files:

  • autogpt_platform/backend/backend/copilot/tools/tool_schema_test.py
  • autogpt_platform/backend/backend/copilot/tools/__init__.py
  • autogpt_platform/backend/backend/copilot/tools/task_test.py
  • autogpt_platform/backend/backend/copilot/tools/todo_write_test.py
  • autogpt_platform/backend/backend/copilot/tools/todo_write.py
  • autogpt_platform/backend/backend/copilot/tools/task.py
  • autogpt_platform/backend/backend/copilot/tools/models.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/tool_schema_test.py
  • autogpt_platform/backend/backend/copilot/permissions_test.py
  • autogpt_platform/backend/backend/copilot/sdk/tool_adapter.py
  • autogpt_platform/backend/backend/copilot/tools/__init__.py
  • autogpt_platform/backend/backend/copilot/tools/task_test.py
  • autogpt_platform/backend/backend/copilot/permissions.py
  • autogpt_platform/backend/backend/copilot/prompting.py
  • autogpt_platform/backend/backend/copilot/tools/todo_write_test.py
  • autogpt_platform/backend/backend/copilot/tools/todo_write.py
  • autogpt_platform/backend/backend/copilot/baseline/service_unit_test.py
  • autogpt_platform/backend/backend/copilot/tools/task.py
  • autogpt_platform/backend/backend/copilot/tools/models.py
  • autogpt_platform/backend/backend/copilot/baseline/service.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/tool_schema_test.py
  • autogpt_platform/backend/backend/copilot/permissions_test.py
  • autogpt_platform/backend/backend/copilot/sdk/tool_adapter.py
  • autogpt_platform/backend/backend/copilot/tools/__init__.py
  • autogpt_platform/backend/backend/copilot/tools/task_test.py
  • autogpt_platform/backend/backend/copilot/permissions.py
  • autogpt_platform/backend/backend/copilot/prompting.py
  • autogpt_platform/backend/backend/copilot/tools/todo_write_test.py
  • autogpt_platform/backend/backend/copilot/tools/todo_write.py
  • autogpt_platform/backend/backend/copilot/baseline/service_unit_test.py
  • autogpt_platform/backend/backend/copilot/tools/task.py
  • autogpt_platform/backend/backend/copilot/tools/models.py
  • autogpt_platform/backend/backend/copilot/baseline/service.py
📚 Learning: 2026-03-31T15:37:38.626Z
Learnt from: majdyz
Repo: Significant-Gravitas/AutoGPT PR: 12623
File: autogpt_platform/backend/backend/copilot/tools/agent_generator/fixer.py:37-47
Timestamp: 2026-03-31T15:37:38.626Z
Learning: When validating/constructing Anthropic API model IDs in Significant-Gravitas/AutoGPT, allow the hyphen-separated Claude Opus 4.6 model ID `claude-opus-4-6` (it corresponds to `LlmModel.CLAUDE_4_6_OPUS` in `autogpt_platform/backend/backend/blocks/llm.py`). Do NOT require the dot-separated form in Anthropic contexts. Only OpenRouter routing variants should use the dot separator (e.g., `anthropic/claude-opus-4.6`); `claude-opus-4-6` should be treated as correct when passed to Anthropic, and flagged only if it’s used in the OpenRouter path where the dot form is expected.

Applied to files:

  • autogpt_platform/backend/backend/copilot/tools/tool_schema_test.py
  • autogpt_platform/backend/backend/copilot/permissions_test.py
  • autogpt_platform/backend/backend/copilot/sdk/tool_adapter.py
  • autogpt_platform/backend/backend/copilot/tools/__init__.py
  • autogpt_platform/backend/backend/copilot/tools/task_test.py
  • autogpt_platform/backend/backend/copilot/permissions.py
  • autogpt_platform/backend/backend/copilot/prompting.py
  • autogpt_platform/backend/backend/copilot/tools/todo_write_test.py
  • autogpt_platform/backend/backend/copilot/tools/todo_write.py
  • autogpt_platform/backend/backend/copilot/baseline/service_unit_test.py
  • autogpt_platform/backend/backend/copilot/tools/task.py
  • autogpt_platform/backend/backend/copilot/tools/models.py
  • autogpt_platform/backend/backend/copilot/baseline/service.py
📚 Learning: 2026-04-15T02:43:36.890Z
Learnt from: ntindle
Repo: Significant-Gravitas/AutoGPT PR: 12780
File: autogpt_platform/backend/backend/copilot/tools/workspace_files.py:0-0
Timestamp: 2026-04-15T02:43:36.890Z
Learning: When reviewing Python exception handlers, do not flag `isinstance(e, X)` checks as dead/unreachable if the caught exception `X` is a subclass of the exception type being handled. For example, if `X` (e.g., `VirusScanError`) inherits from `ValueError` (directly or via an intermediate class) and it can be raised within an `except ValueError:` block, then `isinstance(e, X)` inside that handler is reachable and should not be treated as dead code.

Applied to files:

  • autogpt_platform/backend/backend/copilot/tools/tool_schema_test.py
  • autogpt_platform/backend/backend/copilot/permissions_test.py
  • autogpt_platform/backend/backend/copilot/sdk/tool_adapter.py
  • autogpt_platform/backend/backend/copilot/tools/__init__.py
  • autogpt_platform/backend/backend/copilot/tools/task_test.py
  • autogpt_platform/backend/backend/copilot/permissions.py
  • autogpt_platform/backend/backend/copilot/prompting.py
  • autogpt_platform/backend/backend/copilot/tools/todo_write_test.py
  • autogpt_platform/backend/backend/copilot/tools/todo_write.py
  • autogpt_platform/backend/backend/copilot/baseline/service_unit_test.py
  • autogpt_platform/backend/backend/copilot/tools/task.py
  • autogpt_platform/backend/backend/copilot/tools/models.py
  • autogpt_platform/backend/backend/copilot/baseline/service.py
📚 Learning: 2026-04-14T07:35:11.464Z
Learnt from: majdyz
Repo: Significant-Gravitas/AutoGPT PR: 12773
File: autogpt_platform/backend/backend/blocks/autopilot.py:631-638
Timestamp: 2026-04-14T07:35:11.464Z
Learning: In `autogpt_platform/backend/backend/copilot/executor/utils.py`, `CoPilotExecutionEntry` includes a `permissions: CopilotPermissions | None` field (added in PR `#12773` / commit a0184c87b9). `enqueue_copilot_turn` accepts and serializes this field into the queue entry, `_enqueue_for_recovery` in `autopilot.py` accepts and forwards `permissions` to `enqueue_copilot_turn`, and `_execute_async` in `processor.py` restores `entry.permissions` and passes it into `stream_chat_completion_sdk`/`stream_chat_completion_baseline` via `set_execution_context`. This ensures recovered sub-agent turns respect the same tool/block permission ceiling as the original in-process execution (mirroring `_merge_inherited_permissions`). Do NOT flag recovered turns as losing their permission ceiling — it is now fully propagated through the queue.

Applied to files:

  • autogpt_platform/backend/backend/copilot/permissions_test.py
  • autogpt_platform/backend/backend/copilot/permissions.py
  • autogpt_platform/backend/backend/copilot/prompting.py
  • autogpt_platform/backend/backend/copilot/baseline/service_unit_test.py
  • autogpt_platform/backend/backend/copilot/tools/task.py
  • autogpt_platform/backend/backend/copilot/baseline/service.py
📚 Learning: 2026-04-13T14:19:19.341Z
Learnt from: Pwuts
Repo: Significant-Gravitas/AutoGPT PR: 12740
File: autogpt_platform/frontend/src/app/api/openapi.json:0-0
Timestamp: 2026-04-13T14:19:19.341Z
Learning: Repo: Significant-Gravitas/AutoGPT — autogpt_platform
When adding new CoPilot tool response models (e.g., ScheduleListResponse, ScheduleDeletedResponse), update backend/api/features/chat/routes.py to include them in the ToolResponseUnion so the frontend’s autogenerated openapi.json dummy export (/api/chat/schema/tool-responses) exposes them for codegen. Do not hand-edit frontend/src/app/api/openapi.json.

Applied to files:

  • autogpt_platform/backend/backend/copilot/permissions_test.py
  • autogpt_platform/backend/backend/copilot/tools/__init__.py
  • autogpt_platform/backend/backend/copilot/tools/task_test.py
  • autogpt_platform/backend/backend/copilot/permissions.py
  • autogpt_platform/backend/backend/copilot/prompting.py
  • autogpt_platform/backend/backend/copilot/tools/todo_write_test.py
  • autogpt_platform/backend/backend/copilot/tools/todo_write.py
  • autogpt_platform/backend/backend/copilot/baseline/service_unit_test.py
  • autogpt_platform/backend/backend/copilot/tools/task.py
  • autogpt_platform/backend/backend/copilot/tools/models.py
📚 Learning: 2026-04-08T17:27:45.740Z
Learnt from: CR
Repo: Significant-Gravitas/AutoGPT PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-04-08T17:27:45.740Z
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/permissions_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/sdk/tool_adapter.py
  • autogpt_platform/backend/backend/copilot/tools/models.py
📚 Learning: 2026-03-17T10:57:12.953Z
Learnt from: majdyz
Repo: Significant-Gravitas/AutoGPT PR: 12440
File: autogpt_platform/backend/backend/copilot/workflow_import/converter.py:0-0
Timestamp: 2026-03-17T10:57:12.953Z
Learning: In Significant-Gravitas/AutoGPT PR `#12440`, `autogpt_platform/backend/backend/copilot/workflow_import/converter.py` was fully rewritten (commit 732960e2d) to no longer make direct LLM/OpenAI API calls. The converter now builds a structured text prompt for AutoPilot/CoPilot instead. There is no `response.choices` access or any direct LLM client usage in this file. Do not flag `response.choices` access or LLM client initialization patterns as issues in this file.

Applied to files:

  • autogpt_platform/backend/backend/copilot/tools/__init__.py
  • autogpt_platform/backend/backend/copilot/tools/task_test.py
  • autogpt_platform/backend/backend/copilot/permissions.py
  • autogpt_platform/backend/backend/copilot/prompting.py
  • autogpt_platform/backend/backend/copilot/baseline/service_unit_test.py
  • autogpt_platform/backend/backend/copilot/tools/task.py
  • autogpt_platform/backend/backend/copilot/tools/models.py
📚 Learning: 2026-04-08T17:28:23.439Z
Learnt from: CR
Repo: Significant-Gravitas/AutoGPT PR: 0
File: autogpt_platform/backend/AGENTS.md:0-0
Timestamp: 2026-04-08T17:28:23.439Z
Learning: Applies to autogpt_platform/backend/**/*_test.py : When creating snapshots in tests, use `poetry run pytest path/to/test.py --snapshot-update`; always review snapshot changes with `git diff` before committing

Applied to files:

  • autogpt_platform/backend/backend/copilot/tools/task_test.py
  • autogpt_platform/backend/backend/copilot/tools/todo_write_test.py
📚 Learning: 2026-04-08T17:28:23.439Z
Learnt from: CR
Repo: Significant-Gravitas/AutoGPT PR: 0
File: autogpt_platform/backend/AGENTS.md:0-0
Timestamp: 2026-04-08T17:28:23.439Z
Learning: Applies to autogpt_platform/backend/**/*_test.py : Mock at boundaries — mock where the symbol is **used**, not where it's **defined**; after refactoring, update mock targets to match new module paths

Applied to files:

  • autogpt_platform/backend/backend/copilot/tools/task_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/task_test.py
📚 Learning: 2026-04-08T17:28:23.439Z
Learnt from: CR
Repo: Significant-Gravitas/AutoGPT PR: 0
File: autogpt_platform/backend/AGENTS.md:0-0
Timestamp: 2026-04-08T17:28:23.439Z
Learning: Applies to autogpt_platform/backend/**/*_test.py : Colocate test files with source files using `*_test.py` naming convention

Applied to files:

  • autogpt_platform/backend/backend/copilot/tools/task_test.py
  • autogpt_platform/backend/backend/copilot/tools/todo_write_test.py
📚 Learning: 2026-04-08T17:28:23.439Z
Learnt from: CR
Repo: Significant-Gravitas/AutoGPT PR: 0
File: autogpt_platform/backend/AGENTS.md:0-0
Timestamp: 2026-04-08T17:28:23.439Z
Learning: Applies to autogpt_platform/backend/**/*_test.py : When writing tests, use Test-Driven Development (TDD): write failing tests marked with `pytest.mark.xfail` before implementation, then remove the marker once the implementation is complete

Applied to files:

  • autogpt_platform/backend/backend/copilot/tools/task_test.py
  • autogpt_platform/backend/backend/copilot/tools/todo_write_test.py
📚 Learning: 2026-04-08T17:26:41.549Z
Learnt from: CR
Repo: Significant-Gravitas/AutoGPT PR: 0
File: classic/CLAUDE.md:0-0
Timestamp: 2026-04-08T17:26:41.549Z
Learning: Applies to classic/.autogpt/agents/*/permissions.yaml : Agent-specific permission overrides in {workspace}/.autogpt/agents/{id}/permissions.yaml should use same pattern syntax as workspace permissions

Applied to files:

  • autogpt_platform/backend/backend/copilot/permissions.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/permissions.py
📚 Learning: 2026-04-15T13:44:34.273Z
Learnt from: majdyz
Repo: Significant-Gravitas/AutoGPT PR: 12797
File: autogpt_platform/backend/backend/copilot/sdk/service.py:1991-2021
Timestamp: 2026-04-15T13:44:34.273Z
Learning: In `autogpt_platform/backend/backend/copilot/sdk/service.py` (`_run_stream_attempt`), the pre-create block (PR `#12797`) intentionally does NOT call `state.transcript_builder.append_assistant(...)` when inserting the empty assistant placeholder into `ctx.session.messages`. The transcript is left ending at the `tool_result` entry (N entries) while `message_count` metadata is N+1. This mismatch is benign and deliberate: on the next `--resume`, the SDK sees the transcript ending at `tool_result` and correctly regenerates the assistant response. Pre-appending the assistant turn to the transcript would suppress regeneration while leaving `session.messages[-1].content = ""` permanently (worse outcome). On the gap-fallback path, `transcript_msg_count (N+1) >= msg_count-1 (N)` means no gap is injected for the empty placeholder, which is correct because injecting an empty assistant message as context would mislead the SDK. Do NOT flag this transcript/message_count discrepancy as a bug.

Applied to files:

  • autogpt_platform/backend/backend/copilot/prompting.py
  • autogpt_platform/backend/backend/copilot/baseline/service_unit_test.py
  • autogpt_platform/backend/backend/copilot/baseline/service.py
📚 Learning: 2026-04-08T17:26:23.306Z
Learnt from: CR
Repo: Significant-Gravitas/AutoGPT PR: 0
File: autogpt_platform/frontend/CLAUDE.md:0-0
Timestamp: 2026-04-08T17:26:23.306Z
Learning: Applies to autogpt_platform/frontend/**/AGENTS.md : Document agent responsibilities and capabilities in AGENTS.md with clear descriptions of what each agent does

Applied to files:

  • autogpt_platform/backend/backend/copilot/prompting.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/todo_write_test.py
📚 Learning: 2026-04-08T17:27:57.501Z
Learnt from: CR
Repo: Significant-Gravitas/AutoGPT PR: 0
File: autogpt_platform/AGENTS.md:0-0
Timestamp: 2026-04-08T17:27:57.501Z
Learning: Applies to autogpt_platform/backend/**/test_*.py : Create a failing test first using `pytest.mark.xfail` decorator (backend) when fixing a bug or adding a feature, then implement the fix and remove the xfail marker

Applied to files:

  • autogpt_platform/backend/backend/copilot/tools/todo_write_test.py
📚 Learning: 2026-03-18T14:03:32.534Z
Learnt from: majdyz
Repo: Significant-Gravitas/AutoGPT PR: 12473
File: autogpt_platform/backend/backend/copilot/tools/agent_browser_integration_test.py:86-195
Timestamp: 2026-03-18T14:03:32.534Z
Learning: In Significant-Gravitas/AutoGPT, the integration tests in `autogpt_platform/backend/backend/copilot/tools/agent_browser_integration_test.py` intentionally use real external URLs (example.com, httpbin.org). They are gated with `pytest.mark.skipif(shutil.which("agent-browser") is None, ...)`, so they are automatically skipped in standard CI where agent-browser is not installed. They are designed to be run explicitly inside the Docker environment to verify that system Chromium (AGENT_BROWSER_EXECUTABLE_PATH=/usr/bin/chromium) actually launches and can fetch pages end-to-end. Do not flag the use of real network calls in these tests as a flakiness concern.

Applied to files:

  • autogpt_platform/backend/backend/copilot/baseline/service_unit_test.py
📚 Learning: 2026-04-21T11:41:05.877Z
Learnt from: majdyz
Repo: Significant-Gravitas/AutoGPT PR: 0
File: :0-0
Timestamp: 2026-04-21T11:41:05.877Z
Learning: In `autogpt_platform/backend/backend/copilot/baseline/service.py` (PR `#12870`, commits 080d42b9d and 3d7b38162), the `_close_reasoning_block_if_open(state)` helper centralises all four reasoning-block-close call sites (text branch, tool_calls branch, stream-end, exception path). The outer `finally` block of `_baseline_llm_caller` calls this helper plus stripper flush + `StreamTextEnd` to guarantee matched end events are emitted before `StreamFinishStep` on both normal and exception paths. Do NOT flag duplicated close logic or missing reasoning-end-on-exception as issues in this function.

Applied to files:

  • autogpt_platform/backend/backend/copilot/baseline/service_unit_test.py
  • autogpt_platform/backend/backend/copilot/baseline/service.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/api/features/**/*.py : Update routes in '/backend/backend/api/features/' and add/update Pydantic models in the same directory for API development

Applied to files:

  • autogpt_platform/backend/backend/copilot/tools/models.py
📚 Learning: 2026-03-04T23:58:18.476Z
Learnt from: Pwuts
Repo: Significant-Gravitas/AutoGPT PR: 12284
File: autogpt_platform/frontend/src/app/api/openapi.json:11897-11900
Timestamp: 2026-03-04T23:58:18.476Z
Learning: Repo: Significant-Gravitas/AutoGPT — PR `#12284`
Backend/frontend OpenAPI codegen convention: In backend/api/features/store/model.py, the StoreSubmission and StoreSubmissionAdminView models define submitted_at: datetime | None, changes_summary: str | None, and instructions: str | None with no default. This is intentional to produce “required but nullable” fields in OpenAPI (properties appear in required[] and use anyOf [type, null]). This matches Prisma’s submittedAt DateTime? and changesSummary String?. Do not flag this as a required/nullable mismatch.

Applied to files:

  • autogpt_platform/backend/backend/copilot/tools/models.py
📚 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/baseline/service.py
🔇 Additional comments (3)
autogpt_platform/backend/backend/copilot/permissions.py (1)

127-135: ⚠️ Potential issue | 🟠 Major

Normalize WebSearch to the MCP web_search tool in permission filtering.

WebSearch remains a valid permission name, but SDK mode disallows the native built-in and exposes mcp__copilot__web_search instead. As written, whitelisting WebSearch filters search out, while blacklisting WebSearch still leaves web_search allowed.

🛠️ Proposed fix
-    effective = permissions.effective_allowed_tools(all_tools)
+    effective = set(permissions.effective_allowed_tools(all_tools))
+
+    # WebSearch is accepted as the familiar SDK built-in name, but SDK mode
+    # routes it through the MCP-backed platform tool.
+    if "WebSearch" in permissions.tools:
+        if permissions.tools_exclude:
+            effective.discard("web_search")
+        else:
+            effective.add("web_search")

Consider adding paired tests for whitelist and blacklist behavior:

+    def test_whitelist_websearch_alias_keeps_mcp_web_search(self, mocker):
+        ...
+        perms = CopilotPermissions(tools=["WebSearch"], tools_exclude=False)
+        allowed, _ = apply_tool_permissions(perms, use_e2b=False)
+        assert "mcp__copilot__web_search" in allowed
+
+    def test_blacklist_websearch_alias_removes_mcp_web_search(self, mocker):
+        ...
+        perms = CopilotPermissions(tools=["WebSearch"], tools_exclude=True)
+        allowed, _ = apply_tool_permissions(perms, use_e2b=False)
+        assert "mcp__copilot__web_search" not in allowed

Also applies to: 400-451

⛔ Skipped due to learnings
Learnt from: majdyz
Repo: Significant-Gravitas/AutoGPT PR: 12632
File: autogpt_platform/backend/backend/copilot/sdk/tool_adapter.py:530-535
Timestamp: 2026-04-01T04:17:38.279Z
Learning: In `autogpt_platform/backend/backend/copilot/sdk/tool_adapter.py`, the `ToolAnnotations(readOnlyHint=True)` annotation (stored as `_PARALLEL_ANNOTATION`) is intentionally applied to ALL registered MCP tools — including E2B write/edit tools (e.g., `write_file`, `edit_file`). This is a parallel-dispatch hint to the Claude Agent SDK CLI, not a semantic read-only contract. The `_READ_ONLY_E2B_TOOLS` set was dead code and was removed in commit `12ae03c`; the constant was renamed from `_READONLY_ANNOTATION` to `_PARALLEL_ANNOTATION` in commit `c88ca88` to avoid confusion. Do not flag this as a correctness issue.
Learnt from: majdyz
Repo: Significant-Gravitas/AutoGPT PR: 12632
File: autogpt_platform/backend/backend/copilot/tools/workspace_files.py:0-0
Timestamp: 2026-04-01T04:17:43.495Z
Learning: In autogpt_platform/backend/backend/copilot/sdk/tool_adapter.py (PR `#12632`, commit 12ae03c), the per-tool `BaseTool.read_only` property approach was removed. Instead, `readOnlyHint=True` (via `ToolAnnotations`) is applied unconditionally to ALL tools — including side-effect tools like `bash_exec` and `write_workspace_file` — to enable fully parallel dispatch by the Anthropic SDK/CLI. Do not flag tools with mutating operations (e.g. save_to_path, write operations) for having `readOnlyHint=True`; this is intentional and E2E validated (3x bash_exec(sleep 3) completed in 3.3s vs 9s sequential).
Learnt from: majdyz
Repo: Significant-Gravitas/AutoGPT PR: 12750
File: autogpt_platform/backend/backend/copilot/sdk/file_tools.py:0-0
Timestamp: 2026-04-11T23:51:20.769Z
Learning: In `autogpt_platform/backend/backend/copilot/sdk/file_tools.py`, the TOCTOU gap between `is_allowed_local_path(resolved, sdk_cwd)` and the subsequent `open()` in `_handle_write_non_e2b` (and analogous read/edit handlers) is an accepted trade-off. In non-E2B mode the SDK working directory is ephemeral and user-scoped (created per session under `/tmp`), making the practical attack surface minimal. The E2B sandbox already uses `readlink -f` for defense-in-depth. Additional TOCTOU hardening (e.g., `O_NOFOLLOW`) should be reconsidered only if/when persistent workspaces are introduced. Do not flag this as a blocking issue for non-E2B ephemeral workspace paths.
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: 12773
File: autogpt_platform/backend/backend/blocks/autopilot.py:631-638
Timestamp: 2026-04-14T07:35:11.464Z
Learning: In `autogpt_platform/backend/backend/copilot/executor/utils.py`, `CoPilotExecutionEntry` includes a `permissions: CopilotPermissions | None` field (added in PR `#12773` / commit a0184c87b9). `enqueue_copilot_turn` accepts and serializes this field into the queue entry, `_enqueue_for_recovery` in `autopilot.py` accepts and forwards `permissions` to `enqueue_copilot_turn`, and `_execute_async` in `processor.py` restores `entry.permissions` and passes it into `stream_chat_completion_sdk`/`stream_chat_completion_baseline` via `set_execution_context`. This ensures recovered sub-agent turns respect the same tool/block permission ceiling as the original in-process execution (mirroring `_merge_inherited_permissions`). Do NOT flag recovered turns as losing their permission ceiling — it is now fully propagated through the queue.
autogpt_platform/backend/backend/copilot/tools/task.py (1)

36-105: LGTM — baseline-only Task stub is explicit.

The schema is clear, and the generic dispatch path fails loudly instead of silently bypassing the baseline sub-agent runner.

autogpt_platform/backend/backend/copilot/tools/todo_write.py (1)

29-120: LGTM — TodoWrite canonicalization looks consistent.

The implementation validates the latest checklist payload, enforces the single-active-item invariant, and returns the parsed canonical list.

Comment thread autogpt_platform/backend/backend/copilot/baseline/service.py Outdated
Comment thread autogpt_platform/backend/backend/copilot/prompting.py Outdated
Comment thread autogpt_platform/backend/backend/copilot/tools/models.py Outdated
Comment thread autogpt_platform/backend/backend/copilot/tools/tool_schema_test.py Outdated
- Move ``_TASK_DEPTH_VAR.reset`` into ``finally`` so a ``CancelledError``
  (or any ``BaseException``) can't leak an elevated depth into the next
  Task call on the same asyncio context.  The except branch now captures
  the exception, the finally resets the counter, and a non-``Exception``
  is re-raised after cleanup so asyncio cancellation still propagates.
- Re-apply ``_mark_tools_with_cache_control`` to ``inner_tools`` on
  Anthropic routes after the ``Task`` filter — without this the last
  schema entry loses its cache breakpoint and every sub-agent round
  re-sends ~8 KB of tool descriptions uncached.  No-op for non-Anthropic
  providers (they reject ``cache_control``).
- Document the intentional cross-contamination of the
  ``session.announce_inflight_tool_call`` set between parent and
  sub-agent — future readers will now see why ``session=session`` is
  reused even though message history and streaming events are isolated.
- Rename ``_BASELINE_ONLY_MCP_TOOLS`` → ``BASELINE_ONLY_MCP_TOOLS``; it's
  a deliberate cross-module constant (permissions.py imports it from
  sdk/tool_adapter.py) so the leading underscore was misleading.

New regression tests for each: depth reset on exception, depth reset on
CancelledError propagation, cache-control marker on Anthropic, no marker
on non-Anthropic.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🧹 Nitpick comments (1)
autogpt_platform/backend/backend/copilot/baseline/service_unit_test.py (1)

2014-2421: LGTM — comprehensive coverage of the Task sub-agent contract.

The new TestBaselineTaskSubagent class hits all the important invariants: depth-cap short-circuit (no LLM call), ContextVar reset on both Exception and CancelledError paths (matches the commit-message hardening), pending_events isolation, usage roll-up, Task-strip from inner tools, and Anthropic vs non-Anthropic cache_control application. Happy path / empty-prompt / iteration-count assertions also pin down the documented TaskResponse schema.

One optional tightening: test_depth_var_reset_on_exception (lines 2190–2222) asserts the error payload but not result.success is False, unlike the sibling error-path tests (test_empty_prompt_returns_error, test_depth_cap_refuses_deeper_spawn). Adding that one line would keep the assertion style consistent.

✏️ Optional consistency tweak
         assert _TASK_DEPTH_VAR.get() == depth_before
         import json
 
         payload = json.loads(result.output)
+        assert result.success is False
         assert payload["status"] == "error"
         assert "boom" in payload["error"]
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@autogpt_platform/backend/backend/copilot/baseline/service_unit_test.py`
around lines 2014 - 2421, The test test_depth_var_reset_on_exception is missing
an assertion that the returned result indicates failure; update that test (in
TestBaselineTaskSubagent) to assert result.success is False after calling
_run_task_subagent so it matches the other error-path tests (e.g.,
test_empty_prompt_returns_error and test_depth_cap_refuses_deeper_spawn) and
still verifies the payload contents from json.loads(result.output).
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Nitpick comments:
In `@autogpt_platform/backend/backend/copilot/baseline/service_unit_test.py`:
- Around line 2014-2421: The test test_depth_var_reset_on_exception is missing
an assertion that the returned result indicates failure; update that test (in
TestBaselineTaskSubagent) to assert result.success is False after calling
_run_task_subagent so it matches the other error-path tests (e.g.,
test_empty_prompt_returns_error and test_depth_cap_refuses_deeper_spawn) and
still verifies the payload contents from json.loads(result.output).

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: fc85bbbc-d7b4-4b9a-997f-d89217235f59

📥 Commits

Reviewing files that changed from the base of the PR and between a47de8a and 7dab66d.

📒 Files selected for processing (4)
  • autogpt_platform/backend/backend/copilot/baseline/service.py
  • autogpt_platform/backend/backend/copilot/baseline/service_unit_test.py
  • autogpt_platform/backend/backend/copilot/permissions.py
  • autogpt_platform/backend/backend/copilot/sdk/tool_adapter.py
🚧 Files skipped from review as they are similar to previous changes (3)
  • autogpt_platform/backend/backend/copilot/sdk/tool_adapter.py
  • autogpt_platform/backend/backend/copilot/permissions.py
  • autogpt_platform/backend/backend/copilot/baseline/service.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). (12)
  • GitHub Check: check API types
  • GitHub Check: end-to-end tests
  • GitHub Check: test (3.13)
  • GitHub Check: type-check (3.12)
  • GitHub Check: test (3.12)
  • GitHub Check: test (3.11)
  • GitHub Check: type-check (3.11)
  • GitHub Check: type-check (3.13)
  • GitHub Check: Seer Code Review
  • GitHub Check: Check PR Status
  • GitHub Check: Analyze (python)
  • GitHub Check: Analyze (typescript)
🧰 Additional context used
📓 Path-based instructions (3)
autogpt_platform/backend/**/*.py

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

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

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

Files:

  • autogpt_platform/backend/backend/copilot/baseline/service_unit_test.py
autogpt_platform/{backend,autogpt_libs}/**/*.py

📄 CodeRabbit inference engine (AGENTS.md)

Format Python code with poetry run format

Files:

  • autogpt_platform/backend/backend/copilot/baseline/service_unit_test.py
autogpt_platform/backend/**/*_test.py

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

autogpt_platform/backend/**/*_test.py: Use pytest with snapshot testing for API responses
Colocate test files with source files using *_test.py naming convention
Mock at boundaries — mock where the symbol is used, not where it's defined; after refactoring, update mock targets to match new module paths
Use AsyncMock from unittest.mock for async functions in tests
When writing tests, use Test-Driven Development (TDD): write failing tests marked with @pytest.mark.xfail before implementation, then remove the marker once the implementation is complete
When creating snapshots in tests, use poetry run pytest path/to/test.py --snapshot-update; always review snapshot changes with git diff before committing

Files:

  • autogpt_platform/backend/backend/copilot/baseline/service_unit_test.py
🧠 Learnings (15)
📓 Common learnings
Learnt from: majdyz
Repo: Significant-Gravitas/AutoGPT PR: 12632
File: autogpt_platform/backend/backend/copilot/tools/workspace_files.py:0-0
Timestamp: 2026-04-01T04:17:43.495Z
Learning: In autogpt_platform/backend/backend/copilot/sdk/tool_adapter.py (PR `#12632`, commit 12ae03c), the per-tool `BaseTool.read_only` property approach was removed. Instead, `readOnlyHint=True` (via `ToolAnnotations`) is applied unconditionally to ALL tools — including side-effect tools like `bash_exec` and `write_workspace_file` — to enable fully parallel dispatch by the Anthropic SDK/CLI. Do not flag tools with mutating operations (e.g. save_to_path, write operations) for having `readOnlyHint=True`; this is intentional and E2E validated (3x bash_exec(sleep 3) completed in 3.3s vs 9s sequential).
Learnt from: majdyz
Repo: Significant-Gravitas/AutoGPT PR: 0
File: :0-0
Timestamp: 2026-04-21T11:41:05.877Z
Learning: In `autogpt_platform/backend/backend/copilot/baseline/service.py` (PR `#12870`, commits 080d42b9d and 3d7b38162), the `_close_reasoning_block_if_open(state)` helper centralises all four reasoning-block-close call sites (text branch, tool_calls branch, stream-end, exception path). The outer `finally` block of `_baseline_llm_caller` calls this helper plus stripper flush + `StreamTextEnd` to guarantee matched end events are emitted before `StreamFinishStep` on both normal and exception paths. Do NOT flag duplicated close logic or missing reasoning-end-on-exception as issues in this function.
Learnt from: majdyz
Repo: Significant-Gravitas/AutoGPT PR: 12773
File: autogpt_platform/backend/backend/blocks/autopilot.py:631-638
Timestamp: 2026-04-14T07:35:11.464Z
Learning: In `autogpt_platform/backend/backend/copilot/executor/utils.py`, `CoPilotExecutionEntry` includes a `permissions: CopilotPermissions | None` field (added in PR `#12773` / commit a0184c87b9). `enqueue_copilot_turn` accepts and serializes this field into the queue entry, `_enqueue_for_recovery` in `autopilot.py` accepts and forwards `permissions` to `enqueue_copilot_turn`, and `_execute_async` in `processor.py` restores `entry.permissions` and passes it into `stream_chat_completion_sdk`/`stream_chat_completion_baseline` via `set_execution_context`. This ensures recovered sub-agent turns respect the same tool/block permission ceiling as the original in-process execution (mirroring `_merge_inherited_permissions`). Do NOT flag recovered turns as losing their permission ceiling — it is now fully propagated through the queue.
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: Pwuts
Repo: Significant-Gravitas/AutoGPT PR: 12740
File: autogpt_platform/frontend/src/app/api/openapi.json:0-0
Timestamp: 2026-04-13T14:19:19.341Z
Learning: Repo: Significant-Gravitas/AutoGPT — autogpt_platform
When adding new CoPilot tool response models (e.g., ScheduleListResponse, ScheduleDeletedResponse), update backend/api/features/chat/routes.py to include them in the ToolResponseUnion so the frontend’s autogenerated openapi.json dummy export (/api/chat/schema/tool-responses) exposes them for codegen. Do not hand-edit frontend/src/app/api/openapi.json.
Learnt from: majdyz
Repo: Significant-Gravitas/AutoGPT PR: 12797
File: autogpt_platform/backend/backend/copilot/sdk/service.py:1991-2021
Timestamp: 2026-04-15T13:44:34.273Z
Learning: In `autogpt_platform/backend/backend/copilot/sdk/service.py` (`_run_stream_attempt`), the pre-create block (PR `#12797`) intentionally does NOT call `state.transcript_builder.append_assistant(...)` when inserting the empty assistant placeholder into `ctx.session.messages`. The transcript is left ending at the `tool_result` entry (N entries) while `message_count` metadata is N+1. This mismatch is benign and deliberate: on the next `--resume`, the SDK sees the transcript ending at `tool_result` and correctly regenerates the assistant response. Pre-appending the assistant turn to the transcript would suppress regeneration while leaving `session.messages[-1].content = ""` permanently (worse outcome). On the gap-fallback path, `transcript_msg_count (N+1) >= msg_count-1 (N)` means no gap is injected for the empty placeholder, which is correct because injecting an empty assistant message as context would mislead the SDK. Do NOT flag this transcript/message_count discrepancy as a bug.
Learnt from: majdyz
Repo: Significant-Gravitas/AutoGPT PR: 12440
File: autogpt_platform/backend/backend/copilot/workflow_import/converter.py:0-0
Timestamp: 2026-03-17T10:57:12.953Z
Learning: In Significant-Gravitas/AutoGPT PR `#12440`, `autogpt_platform/backend/backend/copilot/workflow_import/converter.py` was fully rewritten (commit 732960e2d) to no longer make direct LLM/OpenAI API calls. The converter now builds a structured text prompt for AutoPilot/CoPilot instead. There is no `response.choices` access or any direct LLM client usage in this file. Do not flag `response.choices` access or LLM client initialization patterns as issues in this file.
Learnt from: majdyz
Repo: Significant-Gravitas/AutoGPT PR: 12773
File: autogpt_platform/backend/backend/copilot/pending_messages.py:52-64
Timestamp: 2026-04-14T14:36:25.545Z
Learning: In `autogpt_platform/backend/backend/copilot` (PR `#12773`, commit d7bced0c6): when draining pending messages into `session.messages`, each message's text is sanitized via `strip_user_context_tags` before persistence to prevent user-controlled `<user_context>` injection from bypassing the trusted server-side context prefix. Additionally, if `upsert_chat_session` fails after draining, the drained `PendingMessage` objects are requeued back to Redis to avoid silent message loss. Do NOT flag the drain-then-requeue pattern as redundant — it is the intentional failure-resilience strategy for the pending buffer.
Learnt from: majdyz
Repo: Significant-Gravitas/AutoGPT PR: 12213
File: autogpt_platform/frontend/src/app/api/openapi.json:9983-9995
Timestamp: 2026-02-27T15:59:00.370Z
Learning: Repo: Significant-Gravitas/AutoGPT PR: 12213 — Backend/frontend OpenAPI codegen
Learning: For MCP schema models, required OpenAPI fields must have no defaults in Pydantic. Specifically, MCPToolInfo.input_schema must be required (no Field(default_factory=dict)) so openapi.json emits it in "required", ensuring generated TS types treat input_schema as non-optional.
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-04-14T07:35:11.464Z
Learnt from: majdyz
Repo: Significant-Gravitas/AutoGPT PR: 12773
File: autogpt_platform/backend/backend/blocks/autopilot.py:631-638
Timestamp: 2026-04-14T07:35:11.464Z
Learning: In `autogpt_platform/backend/backend/copilot/executor/utils.py`, `CoPilotExecutionEntry` includes a `permissions: CopilotPermissions | None` field (added in PR `#12773` / commit a0184c87b9). `enqueue_copilot_turn` accepts and serializes this field into the queue entry, `_enqueue_for_recovery` in `autopilot.py` accepts and forwards `permissions` to `enqueue_copilot_turn`, and `_execute_async` in `processor.py` restores `entry.permissions` and passes it into `stream_chat_completion_sdk`/`stream_chat_completion_baseline` via `set_execution_context`. This ensures recovered sub-agent turns respect the same tool/block permission ceiling as the original in-process execution (mirroring `_merge_inherited_permissions`). Do NOT flag recovered turns as losing their permission ceiling — it is now fully propagated through the queue.

Applied to files:

  • autogpt_platform/backend/backend/copilot/baseline/service_unit_test.py
📚 Learning: 2026-04-21T11:41:05.877Z
Learnt from: majdyz
Repo: Significant-Gravitas/AutoGPT PR: 0
File: :0-0
Timestamp: 2026-04-21T11:41:05.877Z
Learning: In `autogpt_platform/backend/backend/copilot/baseline/service.py` (PR `#12870`, commits 080d42b9d and 3d7b38162), the `_close_reasoning_block_if_open(state)` helper centralises all four reasoning-block-close call sites (text branch, tool_calls branch, stream-end, exception path). The outer `finally` block of `_baseline_llm_caller` calls this helper plus stripper flush + `StreamTextEnd` to guarantee matched end events are emitted before `StreamFinishStep` on both normal and exception paths. Do NOT flag duplicated close logic or missing reasoning-end-on-exception as issues in this function.

Applied to files:

  • autogpt_platform/backend/backend/copilot/baseline/service_unit_test.py
📚 Learning: 2026-03-17T10:57:12.953Z
Learnt from: majdyz
Repo: Significant-Gravitas/AutoGPT PR: 12440
File: autogpt_platform/backend/backend/copilot/workflow_import/converter.py:0-0
Timestamp: 2026-03-17T10:57:12.953Z
Learning: In Significant-Gravitas/AutoGPT PR `#12440`, `autogpt_platform/backend/backend/copilot/workflow_import/converter.py` was fully rewritten (commit 732960e2d) to no longer make direct LLM/OpenAI API calls. The converter now builds a structured text prompt for AutoPilot/CoPilot instead. There is no `response.choices` access or any direct LLM client usage in this file. Do not flag `response.choices` access or LLM client initialization patterns as issues in this file.

Applied to files:

  • autogpt_platform/backend/backend/copilot/baseline/service_unit_test.py
📚 Learning: 2026-04-13T14:19:19.341Z
Learnt from: Pwuts
Repo: Significant-Gravitas/AutoGPT PR: 12740
File: autogpt_platform/frontend/src/app/api/openapi.json:0-0
Timestamp: 2026-04-13T14:19:19.341Z
Learning: Repo: Significant-Gravitas/AutoGPT — autogpt_platform
When adding new CoPilot tool response models (e.g., ScheduleListResponse, ScheduleDeletedResponse), update backend/api/features/chat/routes.py to include them in the ToolResponseUnion so the frontend’s autogenerated openapi.json dummy export (/api/chat/schema/tool-responses) exposes them for codegen. Do not hand-edit frontend/src/app/api/openapi.json.

Applied to files:

  • autogpt_platform/backend/backend/copilot/baseline/service_unit_test.py
📚 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/baseline/service_unit_test.py
📚 Learning: 2026-03-18T14:03:32.534Z
Learnt from: majdyz
Repo: Significant-Gravitas/AutoGPT PR: 12473
File: autogpt_platform/backend/backend/copilot/tools/agent_browser_integration_test.py:86-195
Timestamp: 2026-03-18T14:03:32.534Z
Learning: In Significant-Gravitas/AutoGPT, the integration tests in `autogpt_platform/backend/backend/copilot/tools/agent_browser_integration_test.py` intentionally use real external URLs (example.com, httpbin.org). They are gated with `pytest.mark.skipif(shutil.which("agent-browser") is None, ...)`, so they are automatically skipped in standard CI where agent-browser is not installed. They are designed to be run explicitly inside the Docker environment to verify that system Chromium (AGENT_BROWSER_EXECUTABLE_PATH=/usr/bin/chromium) actually launches and can fetch pages end-to-end. Do not flag the use of real network calls in these tests as a flakiness concern.

Applied to files:

  • autogpt_platform/backend/backend/copilot/baseline/service_unit_test.py
📚 Learning: 2026-04-15T13:44:34.273Z
Learnt from: majdyz
Repo: Significant-Gravitas/AutoGPT PR: 12797
File: autogpt_platform/backend/backend/copilot/sdk/service.py:1991-2021
Timestamp: 2026-04-15T13:44:34.273Z
Learning: In `autogpt_platform/backend/backend/copilot/sdk/service.py` (`_run_stream_attempt`), the pre-create block (PR `#12797`) intentionally does NOT call `state.transcript_builder.append_assistant(...)` when inserting the empty assistant placeholder into `ctx.session.messages`. The transcript is left ending at the `tool_result` entry (N entries) while `message_count` metadata is N+1. This mismatch is benign and deliberate: on the next `--resume`, the SDK sees the transcript ending at `tool_result` and correctly regenerates the assistant response. Pre-appending the assistant turn to the transcript would suppress regeneration while leaving `session.messages[-1].content = ""` permanently (worse outcome). On the gap-fallback path, `transcript_msg_count (N+1) >= msg_count-1 (N)` means no gap is injected for the empty placeholder, which is correct because injecting an empty assistant message as context would mislead the SDK. Do NOT flag this transcript/message_count discrepancy as a bug.

Applied to files:

  • autogpt_platform/backend/backend/copilot/baseline/service_unit_test.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/baseline/service_unit_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/baseline/service_unit_test.py
📚 Learning: 2026-04-01T04:17:41.600Z
Learnt from: majdyz
Repo: Significant-Gravitas/AutoGPT PR: 12632
File: autogpt_platform/backend/backend/copilot/tools/workspace_files.py:0-0
Timestamp: 2026-04-01T04:17:41.600Z
Learning: When reviewing AutoGPT Copilot tool implementations, accept that `readOnlyHint=True` (provided via `ToolAnnotations`) may be applied unconditionally to *all* tools—even tools that have side effects (e.g., `bash_exec`, `write_workspace_file`, or other write/save operations). Do **not** flag these tools for having `readOnlyHint=True`; this is intentional to enable fully-parallel dispatch by the Anthropic SDK/CLI and has been E2E validated. Only flag `readOnlyHint` issues if they conflict with the established `ToolAnnotations` behavior (e.g., missing/incorrect propagation relative to the intended annotation mechanism).

Applied to files:

  • autogpt_platform/backend/backend/copilot/baseline/service_unit_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/baseline/service_unit_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/baseline/service_unit_test.py
📚 Learning: 2026-03-31T15:37:38.626Z
Learnt from: majdyz
Repo: Significant-Gravitas/AutoGPT PR: 12623
File: autogpt_platform/backend/backend/copilot/tools/agent_generator/fixer.py:37-47
Timestamp: 2026-03-31T15:37:38.626Z
Learning: When validating/constructing Anthropic API model IDs in Significant-Gravitas/AutoGPT, allow the hyphen-separated Claude Opus 4.6 model ID `claude-opus-4-6` (it corresponds to `LlmModel.CLAUDE_4_6_OPUS` in `autogpt_platform/backend/backend/blocks/llm.py`). Do NOT require the dot-separated form in Anthropic contexts. Only OpenRouter routing variants should use the dot separator (e.g., `anthropic/claude-opus-4.6`); `claude-opus-4-6` should be treated as correct when passed to Anthropic, and flagged only if it’s used in the OpenRouter path where the dot form is expected.

Applied to files:

  • autogpt_platform/backend/backend/copilot/baseline/service_unit_test.py
📚 Learning: 2026-04-15T02:43:36.890Z
Learnt from: ntindle
Repo: Significant-Gravitas/AutoGPT PR: 12780
File: autogpt_platform/backend/backend/copilot/tools/workspace_files.py:0-0
Timestamp: 2026-04-15T02:43:36.890Z
Learning: When reviewing Python exception handlers, do not flag `isinstance(e, X)` checks as dead/unreachable if the caught exception `X` is a subclass of the exception type being handled. For example, if `X` (e.g., `VirusScanError`) inherits from `ValueError` (directly or via an intermediate class) and it can be raised within an `except ValueError:` block, then `isinstance(e, X)` inside that handler is reachable and should not be treated as dead code.

Applied to files:

  • autogpt_platform/backend/backend/copilot/baseline/service_unit_test.py

@codecov

codecov Bot commented Apr 22, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 94.55782% with 8 lines in your changes missing coverage. Please review.
✅ Project coverage is 67.16%. Comparing base (33a608e) to head (1a917d9).
⚠️ Report is 1 commits behind head on dev.

Additional details and impacted files
@@            Coverage Diff             @@
##              dev   #12879      +/-   ##
==========================================
+ Coverage   67.14%   67.16%   +0.02%     
==========================================
  Files        1897     1899       +2     
  Lines      145365   145501     +136     
  Branches    15293    15300       +7     
==========================================
+ Hits        97610    97732     +122     
- Misses      44816    44831      +15     
+ Partials     2939     2938       -1     
Flag Coverage Δ
platform-backend 77.18% <94.55%> (+0.03%) ⬆️
platform-frontend 23.84% <ø> (ø)
platform-frontend-e2e 29.98% <ø> (-0.13%) ⬇️

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

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

- Re-export API schema so the frontend openapi.json carries the two new
  ResponseType enum values (``todo_write`` + ``task``) introduced by the
  new platform tools.  CI's ``check API types`` gate compares committed
  vs freshly-generated and was failing on this drift.
- Fix isort order in ``apply_tool_permissions`` — after renaming
  ``_BASELINE_ONLY_MCP_TOOLS`` to ``BASELINE_ONLY_MCP_TOOLS`` the
  underscore-prefixed ``_READ_TOOL_NAME`` now sorts first under black
  profile rules.
@github-actions github-actions Bot added the platform/frontend AutoGPT Platform - Front end label Apr 22, 2026

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🤖 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/frontend/src/app/api/openapi.json`:
- Around line 14574-14575: ToolResponseUnion is missing TodoWriteResponse and
TaskResponse which causes the OpenAPI export to omit their schemas; update the
union definition in autogpt_platform/backend/backend/api/features/chat/routes.py
(look for ToolResponseUnion around the current definition near line ~1396) to
include TodoWriteResponse and TaskResponse (the response model classes defined
in autogpt_platform/backend/backend/copilot/tools/models.py), then re-run the
backend schema export endpoint (/api/chat/schema/tool-responses) or the
project's schema generation command to regenerate
autogpt_platform/frontend/src/app/api/openapi.json rather than editing the JSON
by hand.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: e9c203b9-b8b8-447d-869f-709cc46722b7

📥 Commits

Reviewing files that changed from the base of the PR and between 7dab66d and d06258b.

📒 Files selected for processing (2)
  • autogpt_platform/backend/backend/copilot/permissions.py
  • autogpt_platform/frontend/src/app/api/openapi.json
📜 Review details
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (11)
  • GitHub Check: check API types
  • GitHub Check: integration_test
  • GitHub Check: Seer Code Review
  • GitHub Check: test (3.13)
  • GitHub Check: test (3.12)
  • GitHub Check: type-check (3.12)
  • GitHub Check: test (3.11)
  • GitHub Check: end-to-end tests
  • GitHub Check: Check PR Status
  • GitHub Check: Analyze (typescript)
  • GitHub Check: Analyze (python)
🧰 Additional context used
📓 Path-based instructions (2)
autogpt_platform/backend/**/*.py

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

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

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

Files:

  • autogpt_platform/backend/backend/copilot/permissions.py
autogpt_platform/{backend,autogpt_libs}/**/*.py

📄 CodeRabbit inference engine (AGENTS.md)

Format Python code with poetry run format

Files:

  • autogpt_platform/backend/backend/copilot/permissions.py
🧠 Learnings (19)
📓 Common learnings
Learnt from: majdyz
Repo: Significant-Gravitas/AutoGPT PR: 12632
File: autogpt_platform/backend/backend/copilot/tools/workspace_files.py:0-0
Timestamp: 2026-04-01T04:17:43.495Z
Learning: In autogpt_platform/backend/backend/copilot/sdk/tool_adapter.py (PR `#12632`, commit 12ae03c), the per-tool `BaseTool.read_only` property approach was removed. Instead, `readOnlyHint=True` (via `ToolAnnotations`) is applied unconditionally to ALL tools — including side-effect tools like `bash_exec` and `write_workspace_file` — to enable fully parallel dispatch by the Anthropic SDK/CLI. Do not flag tools with mutating operations (e.g. save_to_path, write operations) for having `readOnlyHint=True`; this is intentional and E2E validated (3x bash_exec(sleep 3) completed in 3.3s vs 9s sequential).
Learnt from: Pwuts
Repo: Significant-Gravitas/AutoGPT PR: 12740
File: autogpt_platform/frontend/src/app/api/openapi.json:0-0
Timestamp: 2026-04-13T14:19:19.341Z
Learning: Repo: Significant-Gravitas/AutoGPT — autogpt_platform
When adding new CoPilot tool response models (e.g., ScheduleListResponse, ScheduleDeletedResponse), update backend/api/features/chat/routes.py to include them in the ToolResponseUnion so the frontend’s autogenerated openapi.json dummy export (/api/chat/schema/tool-responses) exposes them for codegen. Do not hand-edit frontend/src/app/api/openapi.json.
Learnt from: majdyz
Repo: Significant-Gravitas/AutoGPT PR: 0
File: :0-0
Timestamp: 2026-04-21T11:41:05.877Z
Learning: In `autogpt_platform/backend/backend/copilot/baseline/service.py` (PR `#12870`, commits 080d42b9d and 3d7b38162), the `_close_reasoning_block_if_open(state)` helper centralises all four reasoning-block-close call sites (text branch, tool_calls branch, stream-end, exception path). The outer `finally` block of `_baseline_llm_caller` calls this helper plus stripper flush + `StreamTextEnd` to guarantee matched end events are emitted before `StreamFinishStep` on both normal and exception paths. Do NOT flag duplicated close logic or missing reasoning-end-on-exception as issues in this function.
Learnt from: majdyz
Repo: Significant-Gravitas/AutoGPT PR: 12773
File: autogpt_platform/backend/backend/blocks/autopilot.py:631-638
Timestamp: 2026-04-14T07:35:11.464Z
Learning: In `autogpt_platform/backend/backend/copilot/executor/utils.py`, `CoPilotExecutionEntry` includes a `permissions: CopilotPermissions | None` field (added in PR `#12773` / commit a0184c87b9). `enqueue_copilot_turn` accepts and serializes this field into the queue entry, `_enqueue_for_recovery` in `autopilot.py` accepts and forwards `permissions` to `enqueue_copilot_turn`, and `_execute_async` in `processor.py` restores `entry.permissions` and passes it into `stream_chat_completion_sdk`/`stream_chat_completion_baseline` via `set_execution_context`. This ensures recovered sub-agent turns respect the same tool/block permission ceiling as the original in-process execution (mirroring `_merge_inherited_permissions`). Do NOT flag recovered turns as losing their permission ceiling — it is now fully propagated through the queue.
Learnt from: majdyz
Repo: Significant-Gravitas/AutoGPT PR: 12213
File: autogpt_platform/frontend/src/app/api/openapi.json:9983-9995
Timestamp: 2026-02-27T15:59:00.370Z
Learning: Repo: Significant-Gravitas/AutoGPT PR: 12213 — Backend/frontend OpenAPI codegen
Learning: For MCP schema models, required OpenAPI fields must have no defaults in Pydantic. Specifically, MCPToolInfo.input_schema must be required (no Field(default_factory=dict)) so openapi.json emits it in "required", ensuring generated TS types treat input_schema as non-optional.
Learnt from: Pwuts
Repo: Significant-Gravitas/AutoGPT PR: 12284
File: autogpt_platform/frontend/src/app/api/openapi.json:11897-11900
Timestamp: 2026-03-04T23:58:18.476Z
Learning: Repo: Significant-Gravitas/AutoGPT — PR `#12284`
Backend/frontend OpenAPI codegen convention: In backend/api/features/store/model.py, the StoreSubmission and StoreSubmissionAdminView models define submitted_at: datetime | None, changes_summary: str | None, and instructions: str | None with no default. This is intentional to produce “required but nullable” fields in OpenAPI (properties appear in required[] and use anyOf [type, null]). This matches Prisma’s submittedAt DateTime? and changesSummary String?. Do not flag this as a required/nullable mismatch.
Learnt from: majdyz
Repo: Significant-Gravitas/AutoGPT PR: 12213
File: autogpt_platform/frontend/src/app/api/openapi.json:9983-9995
Timestamp: 2026-02-27T15:59:00.370Z
Learning: Repo: Significant-Gravitas/AutoGPT PR: 12213 — OpenAPI/codegen
Learning: Ensuring a field is required in generated TS types needs two sides: (1) no default value on the Pydantic field, and (2) the OpenAPI model's "required" array must list it. For MCPToolInfo, making input_schema required in OpenAPI and removing Field(default_factory=dict) in the backend prevents optional typing drift.
Learnt from: majdyz
Repo: Significant-Gravitas/AutoGPT PR: 12440
File: autogpt_platform/backend/backend/copilot/workflow_import/converter.py:0-0
Timestamp: 2026-03-17T10:57:12.953Z
Learning: In Significant-Gravitas/AutoGPT PR `#12440`, `autogpt_platform/backend/backend/copilot/workflow_import/converter.py` was fully rewritten (commit 732960e2d) to no longer make direct LLM/OpenAI API calls. The converter now builds a structured text prompt for AutoPilot/CoPilot instead. There is no `response.choices` access or any direct LLM client usage in this file. Do not flag `response.choices` access or LLM client initialization patterns as issues in this file.
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.
📚 Learning: 2026-04-13T14:19:19.341Z
Learnt from: Pwuts
Repo: Significant-Gravitas/AutoGPT PR: 12740
File: autogpt_platform/frontend/src/app/api/openapi.json:0-0
Timestamp: 2026-04-13T14:19:19.341Z
Learning: Repo: Significant-Gravitas/AutoGPT — autogpt_platform
When adding new CoPilot tool response models (e.g., ScheduleListResponse, ScheduleDeletedResponse), update backend/api/features/chat/routes.py to include them in the ToolResponseUnion so the frontend’s autogenerated openapi.json dummy export (/api/chat/schema/tool-responses) exposes them for codegen. Do not hand-edit frontend/src/app/api/openapi.json.

Applied to files:

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

Applied to files:

  • autogpt_platform/frontend/src/app/api/openapi.json
📚 Learning: 2026-03-26T00:32:06.673Z
Learnt from: majdyz
Repo: Significant-Gravitas/AutoGPT PR: 12566
File: autogpt_platform/frontend/src/lib/autogpt-server-api/types.ts:968-974
Timestamp: 2026-03-26T00:32:06.673Z
Learning: In Significant-Gravitas/AutoGPT, the admin-facing methods in `autogpt_platform/frontend/src/lib/autogpt-server-api/client.ts` (e.g., `addUserCredits`, `getUsersHistory`, `getUserRateLimit`, `resetUserRateLimit`) intentionally follow the legacy `BackendAPI` pattern with manually defined types in `autogpt_platform/frontend/src/lib/autogpt-server-api/types.ts`. Migrating these admin endpoints to the generated OpenAPI hooks (`@/app/api/__generated__/endpoints/`) is a planned separate effort covering all admin endpoints together, not done piecemeal per PR. Do not flag individual admin type additions in `types.ts` as blocking issues.

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

Applied to files:

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

Applied to files:

  • autogpt_platform/frontend/src/app/api/openapi.json
📚 Learning: 2026-04-01T04:17:41.600Z
Learnt from: majdyz
Repo: Significant-Gravitas/AutoGPT PR: 12632
File: autogpt_platform/backend/backend/copilot/tools/workspace_files.py:0-0
Timestamp: 2026-04-01T04:17:41.600Z
Learning: When reviewing AutoGPT Copilot tool implementations, accept that `readOnlyHint=True` (provided via `ToolAnnotations`) may be applied unconditionally to *all* tools—even tools that have side effects (e.g., `bash_exec`, `write_workspace_file`, or other write/save operations). Do **not** flag these tools for having `readOnlyHint=True`; this is intentional to enable fully-parallel dispatch by the Anthropic SDK/CLI and has been E2E validated. Only flag `readOnlyHint` issues if they conflict with the established `ToolAnnotations` behavior (e.g., missing/incorrect propagation relative to the intended annotation mechanism).

Applied to files:

  • autogpt_platform/backend/backend/copilot/permissions.py
📚 Learning: 2026-04-01T04:17:38.279Z
Learnt from: majdyz
Repo: Significant-Gravitas/AutoGPT PR: 12632
File: autogpt_platform/backend/backend/copilot/sdk/tool_adapter.py:530-535
Timestamp: 2026-04-01T04:17:38.279Z
Learning: In `autogpt_platform/backend/backend/copilot/sdk/tool_adapter.py`, the `ToolAnnotations(readOnlyHint=True)` annotation (stored as `_PARALLEL_ANNOTATION`) is intentionally applied to ALL registered MCP tools — including E2B write/edit tools (e.g., `write_file`, `edit_file`). This is a parallel-dispatch hint to the Claude Agent SDK CLI, not a semantic read-only contract. The `_READ_ONLY_E2B_TOOLS` set was dead code and was removed in commit `12ae03c`; the constant was renamed from `_READONLY_ANNOTATION` to `_PARALLEL_ANNOTATION` in commit `c88ca88` to avoid confusion. Do not flag this as a correctness issue.

Applied to files:

  • autogpt_platform/backend/backend/copilot/permissions.py
📚 Learning: 2026-04-14T07:35:11.464Z
Learnt from: majdyz
Repo: Significant-Gravitas/AutoGPT PR: 12773
File: autogpt_platform/backend/backend/blocks/autopilot.py:631-638
Timestamp: 2026-04-14T07:35:11.464Z
Learning: In `autogpt_platform/backend/backend/copilot/executor/utils.py`, `CoPilotExecutionEntry` includes a `permissions: CopilotPermissions | None` field (added in PR `#12773` / commit a0184c87b9). `enqueue_copilot_turn` accepts and serializes this field into the queue entry, `_enqueue_for_recovery` in `autopilot.py` accepts and forwards `permissions` to `enqueue_copilot_turn`, and `_execute_async` in `processor.py` restores `entry.permissions` and passes it into `stream_chat_completion_sdk`/`stream_chat_completion_baseline` via `set_execution_context`. This ensures recovered sub-agent turns respect the same tool/block permission ceiling as the original in-process execution (mirroring `_merge_inherited_permissions`). Do NOT flag recovered turns as losing their permission ceiling — it is now fully propagated through the queue.

Applied to files:

  • autogpt_platform/backend/backend/copilot/permissions.py
📚 Learning: 2026-03-17T10:57:12.953Z
Learnt from: majdyz
Repo: Significant-Gravitas/AutoGPT PR: 12440
File: autogpt_platform/backend/backend/copilot/workflow_import/converter.py:0-0
Timestamp: 2026-03-17T10:57:12.953Z
Learning: In Significant-Gravitas/AutoGPT PR `#12440`, `autogpt_platform/backend/backend/copilot/workflow_import/converter.py` was fully rewritten (commit 732960e2d) to no longer make direct LLM/OpenAI API calls. The converter now builds a structured text prompt for AutoPilot/CoPilot instead. There is no `response.choices` access or any direct LLM client usage in this file. Do not flag `response.choices` access or LLM client initialization patterns as issues in this file.

Applied to files:

  • autogpt_platform/backend/backend/copilot/permissions.py
📚 Learning: 2026-02-27T15:59:00.370Z
Learnt from: majdyz
Repo: Significant-Gravitas/AutoGPT PR: 12213
File: autogpt_platform/frontend/src/app/api/openapi.json:9983-9995
Timestamp: 2026-02-27T15:59:00.370Z
Learning: Repo: Significant-Gravitas/AutoGPT PR: 12213 — OpenAPI/codegen
Learning: Ensuring a field is required in generated TS types needs two sides: (1) no default value on the Pydantic field, and (2) the OpenAPI model's "required" array must list it. For MCPToolInfo, making input_schema required in OpenAPI and removing Field(default_factory=dict) in the backend prevents optional typing drift.

Applied to files:

  • autogpt_platform/backend/backend/copilot/permissions.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/permissions.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/permissions.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/permissions.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/permissions.py
📚 Learning: 2026-03-31T15:37:38.626Z
Learnt from: majdyz
Repo: Significant-Gravitas/AutoGPT PR: 12623
File: autogpt_platform/backend/backend/copilot/tools/agent_generator/fixer.py:37-47
Timestamp: 2026-03-31T15:37:38.626Z
Learning: When validating/constructing Anthropic API model IDs in Significant-Gravitas/AutoGPT, allow the hyphen-separated Claude Opus 4.6 model ID `claude-opus-4-6` (it corresponds to `LlmModel.CLAUDE_4_6_OPUS` in `autogpt_platform/backend/backend/blocks/llm.py`). Do NOT require the dot-separated form in Anthropic contexts. Only OpenRouter routing variants should use the dot separator (e.g., `anthropic/claude-opus-4.6`); `claude-opus-4-6` should be treated as correct when passed to Anthropic, and flagged only if it’s used in the OpenRouter path where the dot form is expected.

Applied to files:

  • autogpt_platform/backend/backend/copilot/permissions.py
📚 Learning: 2026-04-15T02:43:36.890Z
Learnt from: ntindle
Repo: Significant-Gravitas/AutoGPT PR: 12780
File: autogpt_platform/backend/backend/copilot/tools/workspace_files.py:0-0
Timestamp: 2026-04-15T02:43:36.890Z
Learning: When reviewing Python exception handlers, do not flag `isinstance(e, X)` checks as dead/unreachable if the caught exception `X` is a subclass of the exception type being handled. For example, if `X` (e.g., `VirusScanError`) inherits from `ValueError` (directly or via an intermediate class) and it can be raised within an `except ValueError:` block, then `isinstance(e, X)` inside that handler is reachable and should not be treated as dead code.

Applied to files:

  • autogpt_platform/backend/backend/copilot/permissions.py
🔇 Additional comments (2)
autogpt_platform/backend/backend/copilot/permissions.py (2)

127-135: LGTM — explicit allowlist is clearer than the prior derived set.

Making SDK_BUILTIN_TOOL_NAMES an explicit frozenset and excluding Task/TodoWrite correctly aligns with the baseline-only MCP wrapping in tools/task.py and tools/todo_write.py, while SDK mode still routes to the CLI-native originals. The docstring clearly captures the intent.


426-442: to_sdk_names branch for baseline-only tools looks correct for SDK path.

Since apply_tool_permissions targets ClaudeAgentOptions (SDK mode) and get_copilot_tool_names filters out the MCP wrappers for Task/TodoWrite, permitting the CLI-native short name here ensures filtered_allowed retains the built-ins. The comment on lines 429–433 makes the subtlety explicit, which is helpful.

Comment thread autogpt_platform/frontend/src/app/api/openapi.json Outdated
- Add ``TodoWriteResponse`` and ``TaskResponse`` to ``ToolResponseUnion``
  in ``chat/routes.py`` so the ``/api/chat/schema/tool-responses``
  codegen endpoint surfaces both schemas to the frontend.  Regenerated
  openapi.json + orval client accordingly.
- Restructure the Task sub-agent error handling as nested
  ``try/except Exception`` inside a ``try/finally``.  ``CancelledError``
  / ``KeyboardInterrupt`` / ``SystemExit`` now propagate naturally
  through the outer finally — which both resets the depth ContextVar
  and rolls up inner usage — so the ``except BaseException`` +
  ``# noqa: BLE001`` suppressor pair is no longer needed.  The
  existing regression tests (cancellation + exception) still cover it.
- Prompt guidance (``SHARED_TOOL_NOTES``) now explicitly states that
  sub-agents inherit the parent tool set "except ``Task`` itself"; the
  "plan at most one level deep" bit saves the parent model from
  attempting nested delegation the baseline will refuse.
- Replace the stale ``(budget of 32000 chars ≈ 8000 tokens)`` note in
  ``test_total_schema_char_budget`` with a reference to ``_CHAR_BUDGET``
  above so future budget bumps don't desync the docstring again.
@github-actions

Copy link
Copy Markdown
Contributor

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

@github-actions github-actions Bot added the conflicts Automatically applied to PRs with merge conflicts label Apr 22, 2026
Resolved two conflicts:
- baseline/service.py: dev's queue-based _emit() refactor of
  pending_events + dev's added Iterable import kept; my Task
  short-circuit now funnels through _emit(state, result) too.
  Inner-state drain switched from list.clear() to a queue drain
  + emitted_events.clear() to match the new shape.
- tools/tool_schema_test.py: budget resolution chained dev's
  32800→33200 bump (web_search deep mode, PR #12873) with my
  33200→34600 bump for baseline TodoWrite/Task.  Actual size is 34492.
Also regenerated openapi.json against the merged backend to pick up
dev's concurrent schema changes.
@github-actions

Copy link
Copy Markdown
Contributor

Conflicts have been resolved! 🎉 A maintainer will review the pull request shortly.

@github-actions github-actions Bot removed the conflicts Automatically applied to PRs with merge conflicts label Apr 22, 2026
@majdyz

majdyz commented Apr 22, 2026

Copy link
Copy Markdown
Contributor Author

🧪 E2E Test Report

E2E Test Report: PR #12879 — baseline TodoWrite + in-process Task sub-agent

Date: 2026-04-22
Branch: feat/copilot-baseline-todowrite-task @ 38ac6e3 (merge of dev)
Mode: native (poetry run app + pnpm dev) against local supabase/redis/rabbit
Copilot: baseline path forced via CHAT_USE_CLAUDE_AGENT_SDK=false, CHAT_USE_CLAUDE_CODE_SUBSCRIPTION=false
Model: moonshotai/kimi-k2.6 (default fast_standard_model) via OpenRouter

Summary

# Scenario Result
1 Baseline (Kimi) calls TodoWrite — API stream + UI ✅ PASS
2 Baseline (Kimi) calls Task, parent context stays clean ✅ PASS
3 Sub-agent's inner tool list strips Task (recursion guard) ✅ PASS
4 Negative: 2× in_progress rejected ✅ PASS
5 Negative: missing activeForm rejected ✅ PASS
6 Negative: non-list todos rejected ✅ PASS
7 Negative: Task empty prompt rejected ✅ PASS
8 Fallback: TaskTool._execute via generic dispatch returns loud error ✅ PASS

Total: 8 / 8 PASS. No regressions, no bugs found. --fix loop did not need to fire.


Scenario 1 — TodoWrite via baseline

Prompt (session 41f264f1):

Please plan out (use TodoWrite) the steps you would take to: (1) find a web-search block, (2) run it for the query "AutoGPT release notes", (3) summarize the top 3 results. Create the plan FIRST with TodoWrite, then stop (do not execute the steps).

Stream events captured (s1-stream.txt):

  • tool-input-starttool-input-availabletool-output-available for toolName: "TodoWrite"
  • input.todos was a 3-item array with the exact {content, activeForm, status} shape expected by the frontend renderer:
[
  {"content": "Find a web-search block in the platform",        "activeForm": "Finding a web-search block",        "status": "pending"},
  {"content": "Run the web-search block with query 'AutoGPT release notes'", "activeForm": "Running the web-search block", "status": "pending"},
  {"content": "Summarize the top 3 results from the search output",          "activeForm": "Summarizing the top 3 results", "status": "pending"}
]

UI render — chat page shows the "Show steps" accordion (the StepsCollapse component) for the TodoWrite turn. Clicking it opens the Steps dialog with "Task list — 0/3 completed" and all three items rendered with radio-circle checkboxes — identical to the SDK path's rendering.

Chat render with Show steps button

Steps dialog expanded


Scenario 2 — Task isolation

Prompt (session d46bca5c):

Use the Task tool to spawn an in-process sub-agent. Give it description="count to five" and prompt="Count from 1 to 5, one line per number, then stop." Do NOT count yourself — delegate via Task and report only the final summary the sub-agent returns.

Parent stream event counts (s2-stream.txt):

Event Count Note
tool-input-start 1 Only the outer Task
tool-output-available 1 Only the outer Task
start-step / finish-step 2 / 2 One pair for the parent's opening step before Task, one for the closing step after

The sub-agent's own streaming envelopes (its own start-step, text deltas for "1"/"2"/"3"/"4"/"5", its finish-step) did not leak into the parent stream. The parent only saw ONE tool-input-*tool-output-* triple and then its own text summary that faithfully quoted the inner response ("1\n2\n3\n4\n5"). Context isolation works.

Task tool output payload (decoded):

{"type":"task","message":"Task completed.","description":"count to five","response":"1\n2\n3\n4\n5","iterations":1,"tool_calls":[],"status":"completed"}

Task sub-agent UI


Scenario 3 — inner tool list excludes Task (recursion guard)

Prompt (session 876f3711): asked the sub-agent to list every tool it has access to. The sub-agent's reply (44 tools) includes TodoWrite, run_sub_session, find_block, bash_exec, etc. — but does NOT include Task. Confirms inner_tools = [t for t in tools if ... != "Task"] strips the entry as intended.

Combined with the _MAX_TASK_DEPTH = 2 ContextVar (already unit-tested in test_depth_cap_refuses_deeper_spawn, test_depth_var_reset_on_exception, test_depth_var_reset_on_cancellation), the recursion guard is defence-in-depth: the LLM path can't even attempt a nested Task call, and if something else somehow bypassed that, the depth cap refuses it.


Negative tests

Executed via direct tool invocation (poetry run python ...):

Input Result Error message
TodoWrite with 2× status=in_progress ErrorResponse Only one todo may be 'in_progress' at a time (found 2).
TodoWrite with missing activeForm ErrorResponse Invalid todo entry: 1 validation error for TodoItem — activeForm: Field required
TodoWrite with todos="nope" (string) ErrorResponse `todos` must be an array.
TaskTool._execute (stub path) ErrorResponse Task is a baseline-only in-process sub-agent tool and must be dispatched by the baseline service loop…
_run_task_subagent with prompt=" " status="error" Task requires a non-empty `prompt`.

All five reject cleanly with actionable messages.


Observations / non-blockers

  • Model behaviour. Kimi K2.6 picked up TodoWrite and Task on the first turn without special coaxing — the new SHARED_TOOL_NOTES guidance is working. No tweaks needed.
  • UI rendering. The StepsCollapse accordion is the primary render surface for TodoWrite; the existing SDK-mode path and the baseline path produce identical UI. No frontend changes needed.
  • Cost tracking. Usage tokens visible in logs after each turn; the sub-agent's inner LLM calls rolled up into the parent state (per _absorb_inner_usage), so billing stays coherent.
  • One minor UX note (not a bug, not in scope for this PR): the Task tool's output card on the chat page currently collapses almost entirely — the "final summary" text from the parent LLM is what the user reads. The sub-agent's response is available inside the collapsed accordion but isn't the headline. That's a rendering/UX design call for a follow-up, not a correctness issue; the data flow is correct.

…e same role

The in-process baseline ``Task`` sub-agent and ``run_sub_session`` both
existed to isolate self-contained work from the parent context, but
``run_sub_session`` already does this more robustly — queue-backed, can
outlive a single turn, watchable via ``get_sub_session_result``, and
already wired for baseline.  Keeping both just created "which do I use"
confusion without a clear wins column for ``Task``.

Removed:
- ``tools/task.py`` + ``tools/task_test.py``
- ``TaskResponse`` + ``ResponseType.TASK``
- ``TaskResponse`` entry in ``ToolResponseUnion``
- ``_run_task_subagent`` + ``_task_error_output`` +
  ``_inner_task_conversation_updater`` + ``_absorb_inner_usage`` +
  depth/iteration constants + ``_TASK_DEPTH_VAR`` + Task short-circuit
  in ``_baseline_tool_executor``
- ``TestBaselineTaskSubagent`` (10 cases)
- Task-specific prompt section in ``SHARED_TOOL_NOTES``

Retained:
- ``TodoWrite`` platform tool (useful parity gap — checklist UI).
- SDK path still uses the CLI-native ``Task`` built-in; restored ``Task``
  to ``SDK_BUILTIN_TOOL_NAMES`` and dropped it from
  ``BASELINE_ONLY_MCP_TOOLS`` which now filters only ``TodoWrite`` out of
  SDK's allowed_tools.

Sharpened:
- ``SHARED_TOOL_NOTES`` for ``run_sub_session`` now explicitly frames it
  as the context-isolation primitive (was previously described only as
  "delegate to another autopilot").

Schema char budget retuned ``34_600 → 34_000`` (actual 33_865).
Regenerated ``openapi.json`` to drop ``TaskResponse`` schema.
@github-actions github-actions Bot added size/l and removed size/xl labels Apr 22, 2026
@majdyz majdyz changed the title feat(backend/copilot): baseline TodoWrite + in-process Task sub-agent feat(backend/copilot): add TodoWrite platform tool for baseline Apr 22, 2026
@majdyz majdyz changed the title feat(backend/copilot): add TodoWrite platform tool for baseline feat(backend/copilot): TodoWrite for baseline copilot Apr 22, 2026
majdyz added 2 commits April 22, 2026 16:29
Hide tools whose backing capability isn't available to the current user
so the model doesn't reach for them and then hit opaque runtime errors.
First concrete use: the Graphiti memory tools (``memory_*``) when the
``graphiti-memory`` LaunchDarkly flag is off — the prompt already
already gates the memory-system instructions on this flag, the tool
schema now matches.

Extension point is a ``ToolGroup`` Literal + a central ``TOOL_GROUPS``
map in ``backend/copilot/tools/__init__.py``.  Add a new group by
extending the Literal and registering its members; services pass a
``disabled_groups`` list to ``get_available_tools`` / ``apply_tool_
permissions`` / ``get_copilot_tool_names``.  Keeps the hiding
mechanism generic and extensible — next candidates will likely be
``agents`` (run_agent / run_block / run_sub_session) and ``workspace``
(list/read/write/delete workspace files) when we start rolling out
tool-set variants per user tier.

Baseline and SDK paths both compute ``disabled_tool_groups`` from the
existing ``graphiti_enabled = await is_enabled_for_user(user_id)`` they
already do and thread it through the tool-list builders.
@github-actions github-actions Bot added size/xl and removed size/l labels Apr 22, 2026
…guidance

The tool schemas already carry the parameter docs; the prompt only needs
to tell the model WHEN to reach for them.  Collapse both sections to a
three-line workflow cue — 'use TodoWrite when the plan has 3+ steps,
delegate isolated subtasks to run_sub_session' — and drop the
parameter-by-parameter re-explanation that duplicated
run_sub_session.py's schema.
…ule-level imports

The inline from backend.copilot.tools import ... inside the SDK
service + tool_adapter call sites was defensive against a circular
import that doesn't actually exist — sdk/service.py already pulls
from ..tools.e2b_sandbox / ..tools.sandbox so the tools package
is initialised before the sub-module runs, and sdk/tool_adapter.py
already imports TOOL_REGISTRY at the top.  Standard module imports
are clearer.
majdyz added a commit that referenced this pull request Apr 22, 2026
Same pattern as the ToolGroup hoist in #12879 — the inline
from backend.copilot.model_router import resolve_model inside
_resolve_baseline_model and _resolve_thinking_model_for_user was
defensive but unnecessary.  model_router depends only on
ChatConfig + the LD helper, both of which are already at module
top in the callers, so there's no circular-import risk.
@majdyz
majdyz merged commit 4f11867 into dev Apr 22, 2026
44 checks passed
@majdyz
majdyz deleted the feat/copilot-baseline-todowrite-task branch April 22, 2026 10:28
@github-project-automation github-project-automation Bot moved this to Done in Frontend Apr 22, 2026
@github-project-automation github-project-automation Bot moved this from 🆕 Needs initial review to ✅ Done in AutoGPT development kanban Apr 22, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

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

Projects

Status: ✅ Done
Status: Done

Development

Successfully merging this pull request may close these issues.

1 participant