feat(backend/blocks): register 13 paid blocks + document credit/microdollar wallet boundary - #12876
Conversation
…e-limit counter ## Why Investigation `test-results/investigations/block-cost-tracking.md` found that copilot `run_block` invocations could burn unbounded upstream inference without touching either the credit wallet or the microdollar rate-limit counter. PerplexityBlock was the cleanest leak: no `BlockCost` entry, no `provider_cost` populated, and no copilot microdollar pipe-through. ## What Three fixes, shipped together as the minimum needed to close the gap: - **Registration (A):** add missing `BlockCost` entries for `PerplexityBlock` (Sonar / Sonar Pro / Sonar Deep Research priced distinctly) and `FactCheckerBlock` so `spend_credits` stops silently no-op'ing during copilot `run_block` calls. - **Microdollar pipe-through (B):** in `copilot/tools/helpers::execute_block`, after a successful block run, read the block's typed `NodeExecutionStats.provider_cost` (USD) and funnel it into `record_cost_usage` as microdollars. When `provider_cost` is absent, fall back to converting the flat credit charge at the wallet's cents-per-credit convention so the counter still moves — an under-estimate beats a bypass. Direct-run agent graph executions are unaffected (they never enter `execute_block`). BYOK runs skip the microdollar charge entirely since the user is paying the provider. - **Boundary docs (C):** module-level docstrings on `rate_limit.py` and `block_cost_config.py` now spell out that credits are the user-facing wallet and microdollars meter AutoGPT's operator-side infra spend — so the next reader can't be surprised that the two accounting paths exist side-by-side. ## How - Added `PerplexityBlock` + `FactCheckerBlock` to `BLOCK_COSTS`. - Populated `PerplexityBlock.execution_stats.provider_cost` from OpenRouter's `x-total-cost` response header so the pipe-through gets a real USD figure instead of falling back to the flat credit value. - Extracted `_uses_only_system_credentials` and `_record_block_microdollar_cost` as typed helpers on `execute_block`'s success path. Both the happy-path and test suite stay typed — no `hasattr` / `getattr` / duck typing. - Fixed pre-existing test fixtures in `run_block_test.py` and `continue_run_block_test.py` to seed a real `NodeExecutionStats` on mocked blocks (otherwise MagicMock poisons the new `provider_cost` read). ## Tests - `TestExecuteBlockMicrodollarPipeThrough` — asserts the pipe-through on real provider_cost, the credit-based fallback, BYOK skip, zero-cost skip, and record_cost_usage failure containment. - `TestNewlyRegisteredBlockCosts` — regression lock-in so a future refactor can't silently drop the new BlockCost entries. - `TestExecuteBlockCreditCharging` already covered the direct-credit path; unchanged.
|
Note Reviews pausedIt looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the Use the following commands to manage reviews:
Use the checkboxes below for quick actions:
WalkthroughPer-run provider cost is now extracted from OpenRouter responses in the Perplexity block; token counters are reset before token-based updates when response.usage may be missing. New block cost entries were added (Perplexity, FactChecker, memory/screenshot/nvidia/smartlead/validate-email/ClaudeCode), tests added for block-cost behavior, copilot rate-limit docstring expanded, and docs allow Changes
Estimated code review effort🎯 4 (Complex) | ⏱️ ~45 minutes Possibly related PRs
Suggested labels
Suggested reviewers
Poem
🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
🔍 PR Overlap DetectionThis check compares your PR against all other open PRs targeting the same branch to detect potential merge conflicts early. 🔴 Merge Conflicts DetectedThe following PRs have been tested and will have merge conflicts if merged after this PR. Consider coordinating with the authors.
🟢 Low Risk — File Overlap OnlyThese PRs touch the same files but different sections (click to expand)
Summary: 2 conflict(s), 0 medium risk, 4 low risk (out of 6 PRs with file overlap) Auto-generated on push. Ignores: |
There was a problem hiding this comment.
Actionable comments posted: 2
🤖 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/blocks/perplexity.py`:
- Around line 249-257: The code only sets self.execution_stats.provider_cost
when extract_openrouter_cost(response) returns a value, leaving prior
provider_cost intact; update the block around extract_openrouter_cost(response)
(the logic that reads the OpenRouter header in perplexity.py, e.g., where cost =
extract_openrouter_cost(response) is called) so that when cost is None you
explicitly clear the stored value (set self.execution_stats.provider_cost = None
or 0 depending on how provider_cost is typed) instead of leaving the previous
value; ensure you still set the real cost when cost is present.
In `@autogpt_platform/backend/backend/copilot/tools/helpers.py`:
- Around line 398-412: The microdollar recording call
(_record_block_microdollar_cost) is only executed on the normal success branch
and is skipped on the cancellation/timeout recovery path, allowing run_block to
leak infra spend; modify the control flow so the shielded await of
_record_block_microdollar_cost is executed both on the success path and inside
the cancellation/finally recovery path (the same change for the other occurrence
around the 448-469 region), ensuring it runs even when the block hits the wait
cap or is cancelled, and add a regression test duplicating the existing “output
then timeout” credit test that asserts record_cost_usage (or the async call that
records microdollars) is awaited exactly once.
🪄 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: 5572537e-a1df-4342-bfcc-a3311645e250
📒 Files selected for processing (7)
autogpt_platform/backend/backend/blocks/perplexity.pyautogpt_platform/backend/backend/copilot/rate_limit.pyautogpt_platform/backend/backend/copilot/tools/continue_run_block_test.pyautogpt_platform/backend/backend/copilot/tools/helpers.pyautogpt_platform/backend/backend/copilot/tools/helpers_test.pyautogpt_platform/backend/backend/copilot/tools/run_block_test.pyautogpt_platform/backend/backend/data/block_cost_config.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). (10)
- GitHub Check: check API types
- GitHub Check: Seer Code Review
- GitHub Check: test (3.12)
- GitHub Check: test (3.11)
- GitHub Check: test (3.13)
- GitHub Check: type-check (3.12)
- GitHub Check: Analyze (python)
- GitHub Check: Analyze (typescript)
- GitHub Check: Check PR Status
- GitHub Check: end-to-end tests
🧰 Additional context used
📓 Path-based instructions (6)
autogpt_platform/backend/**/*.py
📄 CodeRabbit inference engine (.github/copilot-instructions.md)
autogpt_platform/backend/**/*.py: Use Python 3.11 (required; managed by Poetry via pyproject.toml) for backend development
Always run 'poetry run format' (Black + isort) before linting in backend development
Always run 'poetry run lint' (ruff) after formatting in backend development
autogpt_platform/backend/**/*.py: Usepoetry run ...command for executing Python package dependencies
Use top-level imports only — avoid local/inner imports except for lazy imports of heavy optional dependencies likeopenpyxl
Use absolute imports withfrom backend.module import ...for cross-package imports; single-dot relative imports are acceptable for sibling modules within the same package; avoid double-dot relative imports
Do not use duck typing — avoidhasattr/getattr/isinstancefor type dispatch; use typed interfaces/unions/protocols instead
Use Pydantic models over dataclass/namedtuple/dict for structured data
Do not use linter suppressors — no# type: ignore,# noqa,# pyright: ignore; fix the type/code instead
Prefer list comprehensions over manual loop-and-append patterns
Use early return with guard clauses first to avoid deep nesting
Use%sfor deferred interpolation indebuglog statements for efficiency; use f-strings elsewhere for readability (e.g.,logger.debug("Processing %s items", count)vslogger.info(f"Processing {count} items"))
Sanitize error paths by usingos.path.basename()in error messages to avoid leaking directory structure
Be aware of TOCTOU (Time-Of-Check-Time-Of-Use) issues — avoid check-then-act patterns for file access and credit charging
Usetransaction=Truefor Redis pipelines to ensure atomicity on multi-step operations
Usemax(0, value)guards for computed values that should never be negative
Keep files under ~300 lines; if a file grows beyond this, split by responsibility (extract helpers, models, or a sub-module into a new file)
Keep functions under ~40 lines; extract named helpers when a function grows longer
...
Files:
autogpt_platform/backend/backend/copilot/tools/run_block_test.pyautogpt_platform/backend/backend/blocks/perplexity.pyautogpt_platform/backend/backend/copilot/tools/continue_run_block_test.pyautogpt_platform/backend/backend/data/block_cost_config.pyautogpt_platform/backend/backend/copilot/rate_limit.pyautogpt_platform/backend/backend/copilot/tools/helpers.pyautogpt_platform/backend/backend/copilot/tools/helpers_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/tools/run_block_test.pyautogpt_platform/backend/backend/blocks/perplexity.pyautogpt_platform/backend/backend/copilot/tools/continue_run_block_test.pyautogpt_platform/backend/backend/data/block_cost_config.pyautogpt_platform/backend/backend/copilot/rate_limit.pyautogpt_platform/backend/backend/copilot/tools/helpers.pyautogpt_platform/backend/backend/copilot/tools/helpers_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.pynaming convention
Mock at boundaries — mock where the symbol is used, not where it's defined; after refactoring, update mock targets to match new module paths
UseAsyncMockfromunittest.mockfor async functions in tests
When writing tests, use Test-Driven Development (TDD): write failing tests marked with@pytest.mark.xfailbefore implementation, then remove the marker once the implementation is complete
When creating snapshots in tests, usepoetry run pytest path/to/test.py --snapshot-update; always review snapshot changes withgit diffbefore committing
Files:
autogpt_platform/backend/backend/copilot/tools/run_block_test.pyautogpt_platform/backend/backend/copilot/tools/continue_run_block_test.pyautogpt_platform/backend/backend/copilot/tools/helpers_test.py
autogpt_platform/backend/backend/blocks/**/*.py
📄 CodeRabbit inference engine (.github/copilot-instructions.md)
autogpt_platform/backend/backend/blocks/**/*.py: Inherit from 'Block' base class with input/output schemas when adding new blocks in backend
Implement 'run' method with proper error handling in backend blocks
Generate block UUID using 'uuid.uuid4()' when creating new blocks in backend
Write tests alongside block implementation when adding new blocks in backend
autogpt_platform/backend/backend/blocks/**/*.py: For blocks handling files, usestore_media_file()withreturn_format="for_local_processing"when processing with local tools (ffmpeg, MoviePy, PIL)
For blocks handling files, usestore_media_file()withreturn_format="for_external_api"when sending content to external APIs (Replicate, OpenAI)
For blocks returning files, usestore_media_file()withreturn_format="for_block_output"to enable auto-adaptation to execution context (workspace:// in CoPilot, data URI in graphs)
When creating new blocks, inherit fromBlockbase class, define input/output schemas usingBlockSchema, implement asyncrunmethod, and generate unique block ID usinguuid.uuid4()
Files:
autogpt_platform/backend/backend/blocks/perplexity.py
autogpt_platform/backend/backend/data/**/*.py
📄 CodeRabbit inference engine (.github/copilot-instructions.md)
All data access in backend requires user ID checks; verify this for any 'data/*.py' changes
Files:
autogpt_platform/backend/backend/data/block_cost_config.py
autogpt_platform/**/data/**/*.py
📄 CodeRabbit inference engine (AGENTS.md)
For changes touching
data/*.py, validate user ID checks or explain why not needed
Files:
autogpt_platform/backend/backend/data/block_cost_config.py
🧠 Learnings (36)
📓 Common learnings
Learnt from: majdyz
Repo: Significant-Gravitas/AutoGPT PR: 12385
File: autogpt_platform/backend/backend/copilot/tools/helpers.py:149-185
Timestamp: 2026-03-15T15:30:09.706Z
Learning: In autogpt_platform/backend/backend/copilot/tools/helpers.py, within execute_block, when InsufficientBalanceError occurs after post-execution credit charging (concurrent balance drain after pre-check passed), this is treated as a non-fatal billing leak: log at ERROR level with structured JSON fields `{"billing_leak": True, "user_id": ..., "cost": ...}` for monitoring/alerting, then return BlockOutputResponse normally. Discarding the output would worsen UX since the block already executed with potential side effects. Reuse the credit_model obtained during the pre-execution balance check (guarded by `if cost > 0 and credit_model:`) for the post-execution charge; do not perform a second get_user_credit_model call.
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: 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.
📚 Learning: 2026-02-04T16:49:42.490Z
Learnt from: CR
Repo: Significant-Gravitas/AutoGPT PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2026-02-04T16:49:42.490Z
Learning: Applies to autogpt_platform/backend/backend/blocks/**/*.py : Implement 'run' method with proper error handling in backend blocks
Applied to files:
autogpt_platform/backend/backend/copilot/tools/run_block_test.py
📚 Learning: 2026-02-04T16:49:42.490Z
Learnt from: CR
Repo: Significant-Gravitas/AutoGPT PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2026-02-04T16:49:42.490Z
Learning: Applies to autogpt_platform/backend/backend/blocks/**/*.py : Write tests alongside block implementation when adding new blocks in backend
Applied to files:
autogpt_platform/backend/backend/copilot/tools/run_block_test.pyautogpt_platform/backend/backend/copilot/tools/continue_run_block_test.pyautogpt_platform/backend/backend/copilot/tools/helpers_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/run_block_test.pyautogpt_platform/backend/backend/copilot/tools/continue_run_block_test.pyautogpt_platform/backend/backend/copilot/tools/helpers_test.py
📚 Learning: 2026-02-04T16:49:42.490Z
Learnt from: CR
Repo: Significant-Gravitas/AutoGPT PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2026-02-04T16:49:42.490Z
Learning: Applies to autogpt_platform/backend/**/test/**/*.py : Use snapshot testing with '--snapshot-update' flag in backend tests when output changes; always review with 'git diff'
Applied to files:
autogpt_platform/backend/backend/copilot/tools/run_block_test.pyautogpt_platform/backend/backend/copilot/tools/continue_run_block_test.pyautogpt_platform/backend/backend/copilot/tools/helpers_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 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/run_block_test.pyautogpt_platform/backend/backend/copilot/tools/continue_run_block_test.pyautogpt_platform/backend/backend/copilot/tools/helpers_test.py
📚 Learning: 2026-03-19T15:10:53.815Z
Learnt from: majdyz
Repo: Significant-Gravitas/AutoGPT PR: 12483
File: autogpt_platform/backend/backend/copilot/tools/test_dry_run.py:298-303
Timestamp: 2026-03-19T15:10:53.815Z
Learning: In Python unittest.mock, the correct patch target depends on whether an import is eager (module-level) or lazy (inside a function/branch):
- **Module-level import** (`from foo.bar import baz` at top of file): patch where the name is used, e.g. `patch("mymodule.baz")`.
- **Lazy import** (`from foo.bar import baz` inside a function/branch, executed at call time): patch the source module, e.g. `patch("foo.bar.baz")`, because the fresh `from ... import` at call time will look up the (now-patched) name in the source module's dict.
This pattern appears in `autogpt_platform/backend/backend/copilot/tools/helpers.py` where `simulate_block` is lazily imported inside the `if dry_run:` block, making `patch("backend.executor.simulator.simulate_block")` the correct target in tests.
Applied to files:
autogpt_platform/backend/backend/copilot/tools/run_block_test.pyautogpt_platform/backend/backend/copilot/tools/continue_run_block_test.pyautogpt_platform/backend/backend/copilot/tools/helpers_test.py
📚 Learning: 2026-03-10T08:38:33.249Z
Learnt from: majdyz
Repo: Significant-Gravitas/AutoGPT PR: 12356
File: autogpt_platform/backend/backend/copilot/tools/run_block.py:297-300
Timestamp: 2026-03-10T08:38:33.249Z
Learning: In autogpt_platform/backend/backend/copilot/tools/run_block.py, the auto-approval key for sensitive block HITL review uses graph_exec_id (copilot-session-{session_id}) + node_id (copilot-node-{block_id}). This is intentional: approving a block type within a CoPilot session auto-approves all future invocations of that same block type within the same session, mirroring how auto-approve works in normal graph execution. The user explicitly opts into this session-scoped behavior via an auto-approve toggle. Without the toggle (default), each individual invocation requires its own approval.
Applied to files:
autogpt_platform/backend/backend/copilot/tools/run_block_test.pyautogpt_platform/backend/backend/copilot/tools/continue_run_block_test.py
📚 Learning: 2026-03-16T16:30:30.764Z
Learnt from: Abhi1992002
Repo: Significant-Gravitas/AutoGPT PR: 12417
File: autogpt_platform/backend/backend/blocks/agent_mail/pods.py:62-74
Timestamp: 2026-03-16T16:30:30.764Z
Learning: In autogpt_platform/backend/backend/blocks/**/*.py, explicit try/except in the `run()` method is NOT required for standard error handling. The block framework's `_execute()` method in `_base.py` catches unhandled exceptions and re-raises them as `BlockExecutionError` or `BlockUnknownError`. Additionally, when a block yields `("error", message)`, `_execute()` immediately raises `BlockExecutionError` — so the `error` output port never propagates downstream. Explicit try/except is only needed when partial output must be controlled (e.g., attachment blocks that must skip yielding `content_base64` on failure).
Applied to files:
autogpt_platform/backend/backend/copilot/tools/run_block_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/tools/run_block_test.pyautogpt_platform/backend/backend/blocks/perplexity.pyautogpt_platform/backend/backend/copilot/tools/continue_run_block_test.pyautogpt_platform/backend/backend/data/block_cost_config.pyautogpt_platform/backend/backend/copilot/rate_limit.pyautogpt_platform/backend/backend/copilot/tools/helpers.pyautogpt_platform/backend/backend/copilot/tools/helpers_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/tools/run_block_test.pyautogpt_platform/backend/backend/copilot/tools/continue_run_block_test.pyautogpt_platform/backend/backend/copilot/rate_limit.pyautogpt_platform/backend/backend/copilot/tools/helpers.pyautogpt_platform/backend/backend/copilot/tools/helpers_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/tools/run_block_test.pyautogpt_platform/backend/backend/copilot/tools/continue_run_block_test.pyautogpt_platform/backend/backend/copilot/rate_limit.pyautogpt_platform/backend/backend/copilot/tools/helpers.pyautogpt_platform/backend/backend/copilot/tools/helpers_test.py
📚 Learning: 2026-03-04T12:19:39.243Z
Learnt from: majdyz
Repo: Significant-Gravitas/AutoGPT PR: 12279
File: autogpt_platform/backend/backend/copilot/tools/base.py:184-188
Timestamp: 2026-03-04T12:19:39.243Z
Learning: In autogpt_platform/backend/backend/copilot/tools/, ensure that anonymous users always pass user_id=None to tool execution methods. The anon_ prefix (e.g., anon_123) is used only for PostHog/analytics distinct_id and must not be used as an actual user_id. Use a simple truthiness check on user_id (e.g., if user_id: ... else: ... or a dedicated is_authenticated flag) to distinguish anonymous from authenticated users, and review all tool execution call sites within this directory to prevent accidentally forwarding an anon_ user_id to tools.
Applied to files:
autogpt_platform/backend/backend/copilot/tools/run_block_test.pyautogpt_platform/backend/backend/copilot/tools/continue_run_block_test.pyautogpt_platform/backend/backend/copilot/tools/helpers.pyautogpt_platform/backend/backend/copilot/tools/helpers_test.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/run_block_test.pyautogpt_platform/backend/backend/copilot/tools/continue_run_block_test.pyautogpt_platform/backend/backend/copilot/tools/helpers.pyautogpt_platform/backend/backend/copilot/tools/helpers_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/tools/run_block_test.pyautogpt_platform/backend/backend/blocks/perplexity.pyautogpt_platform/backend/backend/copilot/tools/continue_run_block_test.pyautogpt_platform/backend/backend/data/block_cost_config.pyautogpt_platform/backend/backend/copilot/rate_limit.pyautogpt_platform/backend/backend/copilot/tools/helpers.pyautogpt_platform/backend/backend/copilot/tools/helpers_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/tools/run_block_test.pyautogpt_platform/backend/backend/blocks/perplexity.pyautogpt_platform/backend/backend/copilot/tools/continue_run_block_test.pyautogpt_platform/backend/backend/data/block_cost_config.pyautogpt_platform/backend/backend/copilot/rate_limit.pyautogpt_platform/backend/backend/copilot/tools/helpers.pyautogpt_platform/backend/backend/copilot/tools/helpers_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/tools/run_block_test.pyautogpt_platform/backend/backend/blocks/perplexity.pyautogpt_platform/backend/backend/copilot/tools/continue_run_block_test.pyautogpt_platform/backend/backend/data/block_cost_config.pyautogpt_platform/backend/backend/copilot/rate_limit.pyautogpt_platform/backend/backend/copilot/tools/helpers.pyautogpt_platform/backend/backend/copilot/tools/helpers_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/tools/run_block_test.pyautogpt_platform/backend/backend/blocks/perplexity.pyautogpt_platform/backend/backend/copilot/tools/continue_run_block_test.pyautogpt_platform/backend/backend/data/block_cost_config.pyautogpt_platform/backend/backend/copilot/rate_limit.pyautogpt_platform/backend/backend/copilot/tools/helpers.pyautogpt_platform/backend/backend/copilot/tools/helpers_test.py
📚 Learning: 2026-02-04T16:49:42.490Z
Learnt from: CR
Repo: Significant-Gravitas/AutoGPT PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2026-02-04T16:49:42.490Z
Learning: Applies to autogpt_platform/backend/backend/blocks/**/*.py : Inherit from 'Block' base class with input/output schemas when adding new blocks in backend
Applied to files:
autogpt_platform/backend/backend/blocks/perplexity.pyautogpt_platform/backend/backend/data/block_cost_config.py
📚 Learning: 2026-02-05T04:11:00.596Z
Learnt from: ntindle
Repo: Significant-Gravitas/AutoGPT PR: 11796
File: autogpt_platform/backend/backend/blocks/video/concat.py:3-4
Timestamp: 2026-02-05T04:11:00.596Z
Learning: In autogpt_platform/backend/backend/blocks/**/*.py, when creating a new block, generate a UUID once with uuid.uuid4() and hard-code the resulting string as the block's id parameter. Do not call uuid.uuid4() at runtime; IDs must be constant across all imports and runs to ensure stability.
Applied to files:
autogpt_platform/backend/backend/blocks/perplexity.py
📚 Learning: 2026-03-16T16:32:21.686Z
Learnt from: Abhi1992002
Repo: Significant-Gravitas/AutoGPT PR: 12417
File: autogpt_platform/backend/backend/blocks/agent_mail/pods.py:62-74
Timestamp: 2026-03-16T16:32:21.686Z
Learning: In autogpt_platform/backend/backend/blocks/, the Block base class execute() already wraps run() in a try/except to convert uncaught exceptions into BlockExecutionError/BlockUnknownError. Do not add per-block try/except in individual block run() methods, as this is not the established pattern (e.g., Gmail, Slack, Todoist blocks omit it). Only use explicit try/except within blocks that need to distinguish between success and error yield paths inside a generator (e.g., attachment blocks). This guidance applies to all Python files under autogpt_platform/backend/backend/blocks/ and similar block implementations; avoid duplicating error handling in run() unless a block requires generator-based branching.
Applied to files:
autogpt_platform/backend/backend/blocks/perplexity.py
📚 Learning: 2026-03-16T16:30:11.452Z
Learnt from: Abhi1992002
Repo: Significant-Gravitas/AutoGPT PR: 12417
File: autogpt_platform/backend/backend/blocks/agent_mail/threads.py:80-102
Timestamp: 2026-03-16T16:30:11.452Z
Learning: In autogpt_platform/backend/backend/blocks/ (and related blocks under autogpt_platform/backend/backend/blocks/), do not add try/except blocks around a block's run() method for standard error propagation. The block executor framework (backend/executor/manager.py) catches uncaught exceptions from run() and emits them on the 'error' output. Only add explicit try/except blocks when you need to control partial outputs in failure cases (e.g., certain outputs must not be yielded on error, as in attachment blocks). This is the standard pattern across the codebase; apply it broadly to blocks' run() implementations.
Applied to files:
autogpt_platform/backend/backend/blocks/perplexity.py
📚 Learning: 2026-03-16T16:30:23.196Z
Learnt from: Abhi1992002
Repo: Significant-Gravitas/AutoGPT PR: 12417
File: autogpt_platform/backend/backend/blocks/agent_mail/pods.py:62-74
Timestamp: 2026-03-16T16:30:23.196Z
Learning: In any Python file under autogpt_platform/backend/backend/blocks, do not add a try/except around run() solely for standard error handling. The block framework’s _execute() in _base.py already catches unhandled exceptions and re-raises as BlockExecutionError or BlockUnknownError. If you yield ("error", message), _execute() raises BlockExecutionError immediately, so the error port will not propagate downstream. Reserve explicit try/except for scenarios where you must control partial output (e.g., attachment blocks that must skip yielding content_base64 on failure).
Applied to files:
autogpt_platform/backend/backend/blocks/perplexity.py
📚 Learning: 2026-03-16T16:30:11.452Z
Learnt from: Abhi1992002
Repo: Significant-Gravitas/AutoGPT PR: 12417
File: autogpt_platform/backend/backend/blocks/agent_mail/threads.py:80-102
Timestamp: 2026-03-16T16:30:11.452Z
Learning: Do not wrap synchronous AgentMail SDK calls with asyncio.to_thread() in blocks under autogpt_platform/backend/backend/blocks (and across the codebase). The block executor runs node execution in dedicated threads via asyncio.run_coroutine_threadsafe (see manager.py around lines ~745-752 and ~1079). The existing pattern avoids using asyncio.to_thread for SDK calls inside async run() methods, so maintain that approach and do not add to_thread usage in these code paths.
Applied to files:
autogpt_platform/backend/backend/blocks/perplexity.py
📚 Learning: 2026-03-10T08:39:22.025Z
Learnt from: majdyz
Repo: Significant-Gravitas/AutoGPT PR: 12356
File: autogpt_platform/backend/backend/copilot/constants.py:9-12
Timestamp: 2026-03-10T08:39:22.025Z
Learning: In Significant-Gravitas/AutoGPT PR `#12356`, the `COPILOT_SYNTHETIC_ID_PREFIX = "copilot-"` check in `create_auto_approval_record` (human_review.py) is intentional and safe. The `graph_exec_id` passed to this function comes from server-side `PendingHumanReview` DB records (not from user input); the API only accepts `node_exec_id` from users. Synthetic `copilot-*` IDs are only ever created server-side in `run_block.py`. The prefix skip avoids a DB lookup for a `AgentGraphExecution` record that legitimately does not exist for CoPilot sessions, while `user_id` scoping is enforced at the auth layer and on the resulting auto-approval record.
Applied to files:
autogpt_platform/backend/backend/copilot/tools/continue_run_block_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/backend/blocks/**/_config.py : When adding a new block, configure the provider using `ProviderBuilder` in `_config.py`
Applied to files:
autogpt_platform/backend/backend/data/block_cost_config.py
📚 Learning: 2026-03-15T15:30:09.706Z
Learnt from: majdyz
Repo: Significant-Gravitas/AutoGPT PR: 12385
File: autogpt_platform/backend/backend/copilot/tools/helpers.py:149-185
Timestamp: 2026-03-15T15:30:09.706Z
Learning: In autogpt_platform/backend/backend/copilot/tools/helpers.py, within execute_block, when InsufficientBalanceError occurs after post-execution credit charging (concurrent balance drain after pre-check passed), this is treated as a non-fatal billing leak: log at ERROR level with structured JSON fields `{"billing_leak": True, "user_id": ..., "cost": ...}` for monitoring/alerting, then return BlockOutputResponse normally. Discarding the output would worsen UX since the block already executed with potential side effects. Reuse the credit_model obtained during the pre-execution balance check (guarded by `if cost > 0 and credit_model:`) for the post-execution charge; do not perform a second get_user_credit_model call.
Applied to files:
autogpt_platform/backend/backend/data/block_cost_config.pyautogpt_platform/backend/backend/copilot/rate_limit.pyautogpt_platform/backend/backend/copilot/tools/helpers_test.py
📚 Learning: 2026-04-21T04:35:34.710Z
Learnt from: majdyz
Repo: Significant-Gravitas/AutoGPT PR: 12865
File: autogpt_platform/backend/backend/data/credit.py:1584-1584
Timestamp: 2026-04-21T04:35:34.710Z
Learning: When reviewing this codebase, don’t flag snake_case attribute names (e.g., `subscription_tier`, `stripe_customer_id`, `top_up_config`) on the app-layer Pydantic `User` model as “wrong” field names. These are correct for the app-layer model and are expected to be mapped from the Prisma-layer camelCase fields (e.g., `subscriptionTier`, `stripeCustomerId`) inside methods like `User.from_db()`. Only Prisma-returned/raw objects would use camelCase, but functions like `get_user_by_id(user_id: str)` are expected to return the Pydantic app-layer model.
Applied to files:
autogpt_platform/backend/backend/data/block_cost_config.py
📚 Learning: 2026-04-03T13:50:29.037Z
Learnt from: Pwuts
Repo: Significant-Gravitas/AutoGPT PR: 12206
File: autogpt_platform/backend/backend/api/external/v2/rate_limit.py:24-56
Timestamp: 2026-04-03T13:50:29.037Z
Learning: In `autogpt_platform/backend/backend/api/external/v2/rate_limit.py`, the `RateLimiter` class uses in-process (per-worker) memory for sliding-window rate limiting. This is intentionally documented as a known limitation via WARNING comments in the module and class docstrings. A full Redis-backed migration (using ZADD/ZREMRANGEBYSCORE/ZCARD with TTL/Lua for atomic multi-replica enforcement) is deferred to a later PR. Do not re-flag the in-memory implementation as a blocking bug — the limitation is documented and accepted for the initial v2 external API release.
Applied to files:
autogpt_platform/backend/backend/copilot/rate_limit.py
📚 Learning: 2026-03-13T15:49:44.961Z
Learnt from: majdyz
Repo: Significant-Gravitas/AutoGPT PR: 12385
File: autogpt_platform/backend/backend/copilot/rate_limit.py:0-0
Timestamp: 2026-03-13T15:49:44.961Z
Learning: In `autogpt_platform/backend/backend/copilot/rate_limit.py`, the original per-session token window (with a TTL-based reset) was replaced with fixed daily and weekly windows. `resets_at` is now derived from `_daily_reset_time()` (midnight UTC) and `_weekly_reset_time()` (next Monday 00:00 UTC) — deterministic fixed-boundary calculations that require no Redis TTL introspection.
Applied to files:
autogpt_platform/backend/backend/copilot/rate_limit.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/rate_limit.pyautogpt_platform/backend/backend/copilot/tools/helpers.py
📚 Learning: 2026-03-15T15:30:02.282Z
Learnt from: majdyz
Repo: Significant-Gravitas/AutoGPT PR: 12385
File: autogpt_platform/backend/backend/copilot/tools/helpers.py:149-185
Timestamp: 2026-03-15T15:30:02.282Z
Learning: In autogpt_platform/backend/backend/copilot/tools/helpers.py, inside execute_block: when InsufficientBalanceError occurs after post-execution credit charging (i.e., balance drained concurrently after pre-check passed), treat as a non-fatal billing leak. Log at ERROR level with structured JSON: {"billing_leak": True, "user_id": ..., "cost": ...} for monitoring/alerting, then return BlockOutputResponse normally (do not discard the output). Do not perform a second get_user_credit_model call; reuse the credit_model obtained during the pre-execution balance check (guarded by if cost > 0 and credit_model:). This guidance improves UX by not discarding results and provides observable billing leak signals.
Applied to files:
autogpt_platform/backend/backend/copilot/tools/helpers.py
📚 Learning: 2026-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/tools/helpers.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/tools/helpers.py
📚 Learning: 2026-03-19T15:16:40.106Z
Learnt from: majdyz
Repo: Significant-Gravitas/AutoGPT PR: 12483
File: autogpt_platform/backend/backend/copilot/tools/helpers.py:81-103
Timestamp: 2026-03-19T15:16:40.106Z
Learning: In `autogpt_platform/backend/backend/copilot/tools/helpers.py`, `execute_block()` calls `block.execute()` directly (NOT `block._execute()`). Because of this, a real block CAN yield `("error", "some message")` alongside other output pins, and all outputs are collected. A non-empty `error` pin does NOT mean the block run failed from the caller's perspective — callers see all outputs. Only `[SIMULATOR ERROR ...]` (the dry-run sentinel, distinct from a simulated block logic failure) should map to `ErrorResponse`. Treating any non-empty `error` pin as `ErrorResponse` in dry-run would diverge from real `block.execute()` semantics.
Applied to files:
autogpt_platform/backend/backend/copilot/tools/helpers.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/backend/blocks/**/*.py : When creating new blocks, inherit from `Block` base class, define input/output schemas using `BlockSchema`, implement async `run` method, and generate unique block ID using `uuid.uuid4()`
Applied to files:
autogpt_platform/backend/backend/copilot/tools/helpers_test.py
🔇 Additional comments (5)
autogpt_platform/backend/backend/copilot/tools/run_block_test.py (1)
10-10: LGTM — mocked blocks now match the execution-stat contract.Using real
NodeExecutionStats()on these mocks keeps the new provider-cost path deterministic and avoids MagicMock values leaking into cost comparisons.Also applies to: 39-39, 72-72, 679-679, 826-826
autogpt_platform/backend/backend/copilot/tools/continue_run_block_test.py (1)
8-8: LGTM — continue-run block mocks include execution stats.This keeps the approval-resume path aligned with the new cost accounting contract in
execute_block.Also applies to: 140-140
autogpt_platform/backend/backend/data/block_cost_config.py (1)
297-313: LGTM — cost registration and boundary docs are consistent.The new entries close the wallet-charge gap for Perplexity and FactChecker, and the comments clearly separate credit-wallet accounting from microdollar rate-limit accounting.
Also applies to: 736-788
autogpt_platform/backend/backend/copilot/rate_limit.py (1)
9-36: LGTM — the accounting boundary is documented clearly.The docstring now captures the provider-cost pipe-through and the BYOK exception without changing runtime behavior.
autogpt_platform/backend/backend/copilot/tools/helpers_test.py (1)
29-49: LGTM — the normal-path microdollar pipe-through is well covered.The tests verify real provider cost, fallback credit conversion, BYOK exclusion, no-cost no-op behavior, and resilience when accounting fails.
Also applies to: 89-103, 242-496, 524-529
Codecov Report❌ Patch coverage is Additional details and impacted files@@ Coverage Diff @@
## dev #12876 +/- ##
==========================================
+ Coverage 67.05% 67.09% +0.03%
==========================================
Files 1897 1897
Lines 144978 145047 +69
Branches 15263 15265 +2
==========================================
+ Hits 97215 97313 +98
+ Misses 44843 44809 -34
- Partials 2920 2925 +5
Flags with carried forward coverage won't be shown. Click here to find out more.
🚀 New features to boost your workflow:
|
…— credits-only path Block execution invoked from copilot ``run_block`` is already gated by the credit wallet via ``spend_credits``. Routing the same run through the microdollar rate-limit counter doubled the accounting path and conflated two budgets with different semantics: credits are the user-facing prepaid wallet, microdollars meter AutoGPT's operator-side LLM-turn spend (baseline / SDK / web_search / simulator). The microdollar counter now stays scoped to copilot LLM turns, and block execution lives entirely on the credit wallet path — the same flow every other block run uses. Kept from PR #12876: - ``BlockCost`` entries for ``PerplexityBlock`` (Sonar / Sonar Pro / Sonar Deep Research) and ``FactCheckerBlock``. These close the credit-wallet leak on their own — ``spend_credits`` no longer silently no-ops for these blocks. - The rate_limit.py module docstring clarifying the boundary between credits and microdollars, reworded to match the new scope (no pipe-through reference). - The ``PerplexityBlock`` ``provider_cost`` population from OpenRouter's ``x-total-cost`` header. Still valuable: the direct-run ``PlatformCostLog`` flow (``executor.cost_tracking::log_system_credential_cost``) uses it to record real operator-side spend for agent graph executions. Removed: - ``_record_block_microdollar_cost`` helper and its ``_uses_only_system_credentials`` gate from ``backend/copilot/tools/helpers.py``. - ``asyncio.shield(_record_block_microdollar_cost(...))`` call in ``execute_block``. - Unused imports (``record_cost_usage``, ``usd_to_microdollars``, ``is_system_credential``) and the ``NodeExecutionStats`` test fixtures that only existed to keep MagicMock from poisoning the removed ``provider_cost`` read. - ``TestExecuteBlockMicrodollarPipeThrough`` test class and the ``_no_real_redis`` autouse fixture. Added ``TestUnregisteredBlockRunsFree`` — regression lock-in that an unregistered block (missing from ``BLOCK_COSTS``) still runs, deducts zero credits, and never touches ``spend_credits`` or ``get_credits``. Prevents a future refactor from accidentally billing free blocks.
There was a problem hiding this comment.
♻️ Duplicate comments (1)
autogpt_platform/backend/backend/blocks/perplexity.py (1)
254-256:⚠️ Potential issue | 🟠 MajorClear stale
provider_costwhen the header is absent.Line 255 only updates
provider_costwhenextract_openrouter_cost(response)returns a value. Sinceself.execution_statsis instance state, a later response withoutx-total-costcan reuse a previous run’s cost and over-log operator spend.Proposed fix
- cost = extract_openrouter_cost(response) - if cost is not None: - self.execution_stats.provider_cost = cost + self.execution_stats.provider_cost = extract_openrouter_cost(response)🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@autogpt_platform/backend/backend/blocks/perplexity.py` around lines 254 - 256, The code only assigns self.execution_stats.provider_cost when extract_openrouter_cost(response) returns a value, leaving prior provider_cost stale if the header is absent; change the logic in the block using extract_openrouter_cost(response) so that when cost is None you explicitly clear the saved value (e.g., set self.execution_stats.provider_cost = None or 0) instead of leaving it unchanged, keeping the existing assignment when cost is present; update the code around the extract_openrouter_cost call in perplexity.py to handle both branches.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Duplicate comments:
In `@autogpt_platform/backend/backend/blocks/perplexity.py`:
- Around line 254-256: The code only assigns self.execution_stats.provider_cost
when extract_openrouter_cost(response) returns a value, leaving prior
provider_cost stale if the header is absent; change the logic in the block using
extract_openrouter_cost(response) so that when cost is None you explicitly clear
the saved value (e.g., set self.execution_stats.provider_cost = None or 0)
instead of leaving it unchanged, keeping the existing assignment when cost is
present; update the code around the extract_openrouter_cost call in
perplexity.py to handle both branches.
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro
Run ID: 7571b851-14e7-45e8-802e-bd60a145bf8e
📒 Files selected for processing (3)
autogpt_platform/backend/backend/blocks/perplexity.pyautogpt_platform/backend/backend/copilot/rate_limit.pyautogpt_platform/backend/backend/copilot/tools/helpers_test.py
✅ Files skipped from review due to trivial changes (1)
- autogpt_platform/backend/backend/copilot/rate_limit.py
🚧 Files skipped from review as they are similar to previous changes (1)
- autogpt_platform/backend/backend/copilot/tools/helpers_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). (11)
- GitHub Check: CodeQL
- GitHub Check: check API types
- GitHub Check: Seer Code Review
- GitHub Check: end-to-end tests
- GitHub Check: test (3.11)
- GitHub Check: type-check (3.12)
- GitHub Check: test (3.12)
- GitHub Check: test (3.13)
- GitHub Check: Check PR Status
- GitHub Check: Analyze (typescript)
- GitHub Check: Analyze (python)
🧰 Additional context used
📓 Path-based instructions (3)
autogpt_platform/backend/**/*.py
📄 CodeRabbit inference engine (.github/copilot-instructions.md)
autogpt_platform/backend/**/*.py: Use Python 3.11 (required; managed by Poetry via pyproject.toml) for backend development
Always run 'poetry run format' (Black + isort) before linting in backend development
Always run 'poetry run lint' (ruff) after formatting in backend development
autogpt_platform/backend/**/*.py: Usepoetry run ...command for executing Python package dependencies
Use top-level imports only — avoid local/inner imports except for lazy imports of heavy optional dependencies likeopenpyxl
Use absolute imports withfrom backend.module import ...for cross-package imports; single-dot relative imports are acceptable for sibling modules within the same package; avoid double-dot relative imports
Do not use duck typing — avoidhasattr/getattr/isinstancefor type dispatch; use typed interfaces/unions/protocols instead
Use Pydantic models over dataclass/namedtuple/dict for structured data
Do not use linter suppressors — no# type: ignore,# noqa,# pyright: ignore; fix the type/code instead
Prefer list comprehensions over manual loop-and-append patterns
Use early return with guard clauses first to avoid deep nesting
Use%sfor deferred interpolation indebuglog statements for efficiency; use f-strings elsewhere for readability (e.g.,logger.debug("Processing %s items", count)vslogger.info(f"Processing {count} items"))
Sanitize error paths by usingos.path.basename()in error messages to avoid leaking directory structure
Be aware of TOCTOU (Time-Of-Check-Time-Of-Use) issues — avoid check-then-act patterns for file access and credit charging
Usetransaction=Truefor Redis pipelines to ensure atomicity on multi-step operations
Usemax(0, value)guards for computed values that should never be negative
Keep files under ~300 lines; if a file grows beyond this, split by responsibility (extract helpers, models, or a sub-module into a new file)
Keep functions under ~40 lines; extract named helpers when a function grows longer
...
Files:
autogpt_platform/backend/backend/blocks/perplexity.py
autogpt_platform/backend/backend/blocks/**/*.py
📄 CodeRabbit inference engine (.github/copilot-instructions.md)
autogpt_platform/backend/backend/blocks/**/*.py: Inherit from 'Block' base class with input/output schemas when adding new blocks in backend
Implement 'run' method with proper error handling in backend blocks
Generate block UUID using 'uuid.uuid4()' when creating new blocks in backend
Write tests alongside block implementation when adding new blocks in backend
autogpt_platform/backend/backend/blocks/**/*.py: For blocks handling files, usestore_media_file()withreturn_format="for_local_processing"when processing with local tools (ffmpeg, MoviePy, PIL)
For blocks handling files, usestore_media_file()withreturn_format="for_external_api"when sending content to external APIs (Replicate, OpenAI)
For blocks returning files, usestore_media_file()withreturn_format="for_block_output"to enable auto-adaptation to execution context (workspace:// in CoPilot, data URI in graphs)
When creating new blocks, inherit fromBlockbase class, define input/output schemas usingBlockSchema, implement asyncrunmethod, and generate unique block ID usinguuid.uuid4()
Files:
autogpt_platform/backend/backend/blocks/perplexity.py
autogpt_platform/{backend,autogpt_libs}/**/*.py
📄 CodeRabbit inference engine (AGENTS.md)
Format Python code with
poetry run format
Files:
autogpt_platform/backend/backend/blocks/perplexity.py
🧠 Learnings (14)
📓 Common learnings
Learnt from: majdyz
Repo: Significant-Gravitas/AutoGPT PR: 12385
File: autogpt_platform/backend/backend/copilot/tools/helpers.py:149-185
Timestamp: 2026-03-15T15:30:09.706Z
Learning: In autogpt_platform/backend/backend/copilot/tools/helpers.py, within execute_block, when InsufficientBalanceError occurs after post-execution credit charging (concurrent balance drain after pre-check passed), this is treated as a non-fatal billing leak: log at ERROR level with structured JSON fields `{"billing_leak": True, "user_id": ..., "cost": ...}` for monitoring/alerting, then return BlockOutputResponse normally. Discarding the output would worsen UX since the block already executed with potential side effects. Reuse the credit_model obtained during the pre-execution balance check (guarded by `if cost > 0 and credit_model:`) for the post-execution charge; do not perform a second get_user_credit_model call.
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: 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: 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.
📚 Learning: 2026-03-09T10:50:43.907Z
Learnt from: Bentlybro
Repo: Significant-Gravitas/AutoGPT PR: 0
File: :0-0
Timestamp: 2026-03-09T10:50:43.907Z
Learning: Repo: Significant-Gravitas/AutoGPT — File: autogpt_platform/backend/backend/blocks/llm.py
For xAI Grok models accessed via OpenRouter, the API returns `null` for `max_completion_tokens`. The convention in this codebase is to use the model's context window size as the `max_output_tokens` value in ModelMetadata. For example, Grok 3 uses 131072 (128k) and Grok 4 uses 262144 (256k). Do not flag these as incorrect max output token values.
Applied to files:
autogpt_platform/backend/backend/blocks/perplexity.py
📚 Learning: 2026-03-15T15:30:09.706Z
Learnt from: majdyz
Repo: Significant-Gravitas/AutoGPT PR: 12385
File: autogpt_platform/backend/backend/copilot/tools/helpers.py:149-185
Timestamp: 2026-03-15T15:30:09.706Z
Learning: In autogpt_platform/backend/backend/copilot/tools/helpers.py, within execute_block, when InsufficientBalanceError occurs after post-execution credit charging (concurrent balance drain after pre-check passed), this is treated as a non-fatal billing leak: log at ERROR level with structured JSON fields `{"billing_leak": True, "user_id": ..., "cost": ...}` for monitoring/alerting, then return BlockOutputResponse normally. Discarding the output would worsen UX since the block already executed with potential side effects. Reuse the credit_model obtained during the pre-execution balance check (guarded by `if cost > 0 and credit_model:`) for the post-execution charge; do not perform a second get_user_credit_model call.
Applied to files:
autogpt_platform/backend/backend/blocks/perplexity.py
📚 Learning: 2026-02-04T16:49:42.490Z
Learnt from: CR
Repo: Significant-Gravitas/AutoGPT PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2026-02-04T16:49:42.490Z
Learning: Applies to autogpt_platform/backend/backend/blocks/**/*.py : Inherit from 'Block' base class with input/output schemas when adding new blocks in backend
Applied to files:
autogpt_platform/backend/backend/blocks/perplexity.py
📚 Learning: 2026-02-05T04:11:00.596Z
Learnt from: ntindle
Repo: Significant-Gravitas/AutoGPT PR: 11796
File: autogpt_platform/backend/backend/blocks/video/concat.py:3-4
Timestamp: 2026-02-05T04:11:00.596Z
Learning: In autogpt_platform/backend/backend/blocks/**/*.py, when creating a new block, generate a UUID once with uuid.uuid4() and hard-code the resulting string as the block's id parameter. Do not call uuid.uuid4() at runtime; IDs must be constant across all imports and runs to ensure stability.
Applied to files:
autogpt_platform/backend/backend/blocks/perplexity.py
📚 Learning: 2026-03-16T16:32:21.686Z
Learnt from: Abhi1992002
Repo: Significant-Gravitas/AutoGPT PR: 12417
File: autogpt_platform/backend/backend/blocks/agent_mail/pods.py:62-74
Timestamp: 2026-03-16T16:32:21.686Z
Learning: In autogpt_platform/backend/backend/blocks/, the Block base class execute() already wraps run() in a try/except to convert uncaught exceptions into BlockExecutionError/BlockUnknownError. Do not add per-block try/except in individual block run() methods, as this is not the established pattern (e.g., Gmail, Slack, Todoist blocks omit it). Only use explicit try/except within blocks that need to distinguish between success and error yield paths inside a generator (e.g., attachment blocks). This guidance applies to all Python files under autogpt_platform/backend/backend/blocks/ and similar block implementations; avoid duplicating error handling in run() unless a block requires generator-based branching.
Applied to files:
autogpt_platform/backend/backend/blocks/perplexity.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/blocks/perplexity.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/blocks/perplexity.py
📚 Learning: 2026-03-16T16:30:11.452Z
Learnt from: Abhi1992002
Repo: Significant-Gravitas/AutoGPT PR: 12417
File: autogpt_platform/backend/backend/blocks/agent_mail/threads.py:80-102
Timestamp: 2026-03-16T16:30:11.452Z
Learning: In autogpt_platform/backend/backend/blocks/ (and related blocks under autogpt_platform/backend/backend/blocks/), do not add try/except blocks around a block's run() method for standard error propagation. The block executor framework (backend/executor/manager.py) catches uncaught exceptions from run() and emits them on the 'error' output. Only add explicit try/except blocks when you need to control partial outputs in failure cases (e.g., certain outputs must not be yielded on error, as in attachment blocks). This is the standard pattern across the codebase; apply it broadly to blocks' run() implementations.
Applied to files:
autogpt_platform/backend/backend/blocks/perplexity.py
📚 Learning: 2026-03-16T16:30:23.196Z
Learnt from: Abhi1992002
Repo: Significant-Gravitas/AutoGPT PR: 12417
File: autogpt_platform/backend/backend/blocks/agent_mail/pods.py:62-74
Timestamp: 2026-03-16T16:30:23.196Z
Learning: In any Python file under autogpt_platform/backend/backend/blocks, do not add a try/except around run() solely for standard error handling. The block framework’s _execute() in _base.py already catches unhandled exceptions and re-raises as BlockExecutionError or BlockUnknownError. If you yield ("error", message), _execute() raises BlockExecutionError immediately, so the error port will not propagate downstream. Reserve explicit try/except for scenarios where you must control partial output (e.g., attachment blocks that must skip yielding content_base64 on failure).
Applied to files:
autogpt_platform/backend/backend/blocks/perplexity.py
📚 Learning: 2026-03-16T16:30:11.452Z
Learnt from: Abhi1992002
Repo: Significant-Gravitas/AutoGPT PR: 12417
File: autogpt_platform/backend/backend/blocks/agent_mail/threads.py:80-102
Timestamp: 2026-03-16T16:30:11.452Z
Learning: Do not wrap synchronous AgentMail SDK calls with asyncio.to_thread() in blocks under autogpt_platform/backend/backend/blocks (and across the codebase). The block executor runs node execution in dedicated threads via asyncio.run_coroutine_threadsafe (see manager.py around lines ~745-752 and ~1079). The existing pattern avoids using asyncio.to_thread for SDK calls inside async run() methods, so maintain that approach and do not add to_thread usage in these code paths.
Applied to files:
autogpt_platform/backend/backend/blocks/perplexity.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/blocks/perplexity.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/blocks/perplexity.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/blocks/perplexity.py
🔇 Additional comments (1)
autogpt_platform/backend/backend/blocks/perplexity.py (1)
16-16: LGTM — import is in the right place.
extract_openrouter_costis imported at module scope using an absolute backend import, which fits this file’s existing style. As per coding guidelines, "Use top-level imports only" and "Use absolute imports withfrom backend.module import ...for cross-package imports".
- Clear `provider_cost` unconditionally in PerplexityBlock so an OpenRouter response without `x-total-cost` cannot reuse a prior run's cost (`execution_stats` is instance state). Flagged by CodeRabbit. - Update `block_cost_config.py` BLOCK_COSTS docstring to state copilot `run_block` decrements only the credit wallet — the microdollar pipe-through was reverted in 16ae0f7. Flagged by Seer. - Regenerate `docs/integrations/block-integrations/misc.md` to unblock `check-docs-sync` (new `web_search` tool entry in AutoPilot tools list).
There was a problem hiding this comment.
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
autogpt_platform/backend/backend/blocks/perplexity.py (1)
243-256:⚠️ Potential issue | 🟠 MajorClear token stats when
usageis missing too.
provider_costis now safely overwritten per request, butinput_token_countandoutput_token_countstill retain prior values whenresponse.usageis absent. Sinceexecution_statsis instance state, that can leak stale token counts into laterPlatformCostLogrows.Proposed fix
# Update execution stats + self.execution_stats.input_token_count = 0 + self.execution_stats.output_token_count = 0 if response.usage: self.execution_stats.input_token_count = response.usage.prompt_tokens self.execution_stats.output_token_count = ( response.usage.completion_tokens )🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@autogpt_platform/backend/backend/blocks/perplexity.py` around lines 243 - 256, The code only updates execution_stats.input_token_count and output_token_count when response.usage exists, which can leave stale values when usage is missing; update the block in the method that handles the response so that if response.usage is falsy you explicitly clear/zero execution_stats.input_token_count and execution_stats.output_token_count (e.g., set to 0 or None), while still always assigning execution_stats.provider_cost via extract_openrouter_cost(response); modify the conditional around response.usage in the function in perplexity.py that updates execution_stats to handle the "else" case and clear those two fields.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Outside diff comments:
In `@autogpt_platform/backend/backend/blocks/perplexity.py`:
- Around line 243-256: The code only updates execution_stats.input_token_count
and output_token_count when response.usage exists, which can leave stale values
when usage is missing; update the block in the method that handles the response
so that if response.usage is falsy you explicitly clear/zero
execution_stats.input_token_count and execution_stats.output_token_count (e.g.,
set to 0 or None), while still always assigning execution_stats.provider_cost
via extract_openrouter_cost(response); modify the conditional around
response.usage in the function in perplexity.py that updates execution_stats to
handle the "else" case and clear those two fields.
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro
Run ID: fd3d876f-cb80-4234-b559-335e668513e3
📒 Files selected for processing (3)
autogpt_platform/backend/backend/blocks/perplexity.pyautogpt_platform/backend/backend/data/block_cost_config.pydocs/integrations/block-integrations/misc.md
🚧 Files skipped from review as they are similar to previous changes (1)
- autogpt_platform/backend/backend/data/block_cost_config.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). (11)
- GitHub Check: check API types
- GitHub Check: test (3.11)
- GitHub Check: test (3.12)
- GitHub Check: test (3.13)
- GitHub Check: type-check (3.12)
- GitHub Check: type-check (3.13)
- GitHub Check: type-check (3.11)
- GitHub Check: end-to-end tests
- GitHub Check: Check PR Status
- GitHub Check: Analyze (python)
- GitHub Check: Analyze (typescript)
🧰 Additional context used
📓 Path-based instructions (4)
autogpt_platform/backend/**/*.py
📄 CodeRabbit inference engine (.github/copilot-instructions.md)
autogpt_platform/backend/**/*.py: Use Python 3.11 (required; managed by Poetry via pyproject.toml) for backend development
Always run 'poetry run format' (Black + isort) before linting in backend development
Always run 'poetry run lint' (ruff) after formatting in backend development
autogpt_platform/backend/**/*.py: Usepoetry run ...command for executing Python package dependencies
Use top-level imports only — avoid local/inner imports except for lazy imports of heavy optional dependencies likeopenpyxl
Use absolute imports withfrom backend.module import ...for cross-package imports; single-dot relative imports are acceptable for sibling modules within the same package; avoid double-dot relative imports
Do not use duck typing — avoidhasattr/getattr/isinstancefor type dispatch; use typed interfaces/unions/protocols instead
Use Pydantic models over dataclass/namedtuple/dict for structured data
Do not use linter suppressors — no# type: ignore,# noqa,# pyright: ignore; fix the type/code instead
Prefer list comprehensions over manual loop-and-append patterns
Use early return with guard clauses first to avoid deep nesting
Use%sfor deferred interpolation indebuglog statements for efficiency; use f-strings elsewhere for readability (e.g.,logger.debug("Processing %s items", count)vslogger.info(f"Processing {count} items"))
Sanitize error paths by usingos.path.basename()in error messages to avoid leaking directory structure
Be aware of TOCTOU (Time-Of-Check-Time-Of-Use) issues — avoid check-then-act patterns for file access and credit charging
Usetransaction=Truefor Redis pipelines to ensure atomicity on multi-step operations
Usemax(0, value)guards for computed values that should never be negative
Keep files under ~300 lines; if a file grows beyond this, split by responsibility (extract helpers, models, or a sub-module into a new file)
Keep functions under ~40 lines; extract named helpers when a function grows longer
...
Files:
autogpt_platform/backend/backend/blocks/perplexity.py
autogpt_platform/backend/backend/blocks/**/*.py
📄 CodeRabbit inference engine (.github/copilot-instructions.md)
autogpt_platform/backend/backend/blocks/**/*.py: Inherit from 'Block' base class with input/output schemas when adding new blocks in backend
Implement 'run' method with proper error handling in backend blocks
Generate block UUID using 'uuid.uuid4()' when creating new blocks in backend
Write tests alongside block implementation when adding new blocks in backend
autogpt_platform/backend/backend/blocks/**/*.py: For blocks handling files, usestore_media_file()withreturn_format="for_local_processing"when processing with local tools (ffmpeg, MoviePy, PIL)
For blocks handling files, usestore_media_file()withreturn_format="for_external_api"when sending content to external APIs (Replicate, OpenAI)
For blocks returning files, usestore_media_file()withreturn_format="for_block_output"to enable auto-adaptation to execution context (workspace:// in CoPilot, data URI in graphs)
When creating new blocks, inherit fromBlockbase class, define input/output schemas usingBlockSchema, implement asyncrunmethod, and generate unique block ID usinguuid.uuid4()
Files:
autogpt_platform/backend/backend/blocks/perplexity.py
autogpt_platform/{backend,autogpt_libs}/**/*.py
📄 CodeRabbit inference engine (AGENTS.md)
Format Python code with
poetry run format
Files:
autogpt_platform/backend/backend/blocks/perplexity.py
docs/integrations/**/*.md
📄 CodeRabbit inference engine (docs/AGENTS.md)
docs/integrations/**/*.md: Block documentationhow_it_worksmanual section should provide a technical explanation of the block's processing logic in 1-2 paragraphs, mention validation/error handling/edge cases, and use code examples with backticks
Block documentationuse_casemanual section should provide exactly 3 practical use cases in bold heading format with short one-sentence descriptions
Documentation descriptions should be concise and action-oriented, focusing on practical real-world scenarios with consistent terminology and avoiding overly technical jargon
Files:
docs/integrations/block-integrations/misc.md
🧠 Learnings (21)
📓 Common learnings
Learnt from: majdyz
Repo: Significant-Gravitas/AutoGPT PR: 12876
File: autogpt_platform/backend/backend/copilot/tools/helpers.py:0-0
Timestamp: 2026-04-22T04:01:32.723Z
Learning: In `autogpt_platform/backend/backend/copilot/tools/helpers.py`, the `run_block` copilot path charges ONLY the user credit wallet (via `spend_credits` / `_charge_block_credits`). The microdollar rate-limit counter (`record_cost_usage`) is NOT incremented for `run_block` block executions — the `_record_block_microdollar_cost` helper was explicitly reverted (commit 16ae0f7b5, PR `#12876`) to avoid double-accounting. Do NOT flag missing microdollar recording in `execute_block` as a bug; the credit wallet is the sole billing mechanism for copilot `run_block` calls.
Learnt from: majdyz
Repo: Significant-Gravitas/AutoGPT PR: 12385
File: autogpt_platform/backend/backend/copilot/tools/helpers.py:149-185
Timestamp: 2026-03-15T15:30:09.706Z
Learning: In autogpt_platform/backend/backend/copilot/tools/helpers.py, within execute_block, when InsufficientBalanceError occurs after post-execution credit charging (concurrent balance drain after pre-check passed), this is treated as a non-fatal billing leak: log at ERROR level with structured JSON fields `{"billing_leak": True, "user_id": ..., "cost": ...}` for monitoring/alerting, then return BlockOutputResponse normally. Discarding the output would worsen UX since the block already executed with potential side effects. Reuse the credit_model obtained during the pre-execution balance check (guarded by `if cost > 0 and credit_model:`) for the post-execution charge; do not perform a second get_user_credit_model call.
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.
📚 Learning: 2026-04-22T04:01:32.723Z
Learnt from: majdyz
Repo: Significant-Gravitas/AutoGPT PR: 12876
File: autogpt_platform/backend/backend/copilot/tools/helpers.py:0-0
Timestamp: 2026-04-22T04:01:32.723Z
Learning: In `autogpt_platform/backend/backend/copilot/tools/helpers.py`, the `run_block` copilot path charges ONLY the user credit wallet (via `spend_credits` / `_charge_block_credits`). The microdollar rate-limit counter (`record_cost_usage`) is NOT incremented for `run_block` block executions — the `_record_block_microdollar_cost` helper was explicitly reverted (commit 16ae0f7b5, PR `#12876`) to avoid double-accounting. Do NOT flag missing microdollar recording in `execute_block` as a bug; the credit wallet is the sole billing mechanism for copilot `run_block` calls.
Applied to files:
autogpt_platform/backend/backend/blocks/perplexity.py
📚 Learning: 2026-03-15T15:30:09.706Z
Learnt from: majdyz
Repo: Significant-Gravitas/AutoGPT PR: 12385
File: autogpt_platform/backend/backend/copilot/tools/helpers.py:149-185
Timestamp: 2026-03-15T15:30:09.706Z
Learning: In autogpt_platform/backend/backend/copilot/tools/helpers.py, within execute_block, when InsufficientBalanceError occurs after post-execution credit charging (concurrent balance drain after pre-check passed), this is treated as a non-fatal billing leak: log at ERROR level with structured JSON fields `{"billing_leak": True, "user_id": ..., "cost": ...}` for monitoring/alerting, then return BlockOutputResponse normally. Discarding the output would worsen UX since the block already executed with potential side effects. Reuse the credit_model obtained during the pre-execution balance check (guarded by `if cost > 0 and credit_model:`) for the post-execution charge; do not perform a second get_user_credit_model call.
Applied to files:
autogpt_platform/backend/backend/blocks/perplexity.py
📚 Learning: 2026-04-02T14:27:41.807Z
Learnt from: majdyz
Repo: Significant-Gravitas/AutoGPT PR: 12651
File: autogpt_platform/frontend/src/app/api/openapi.json:8653-8696
Timestamp: 2026-04-02T14:27:41.807Z
Learning: Repo: Significant-Gravitas/AutoGPT — Platform costs
The PlatformCostLog.duration is stored in DB but intentionally omitted from the CostLogRow API response to keep the raw logs compact. Do not flag this omission; suggest documenting the intent in the route description if needed.
Applied to files:
autogpt_platform/backend/backend/blocks/perplexity.py
📚 Learning: 2026-02-04T16:49:42.490Z
Learnt from: CR
Repo: Significant-Gravitas/AutoGPT PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2026-02-04T16:49:42.490Z
Learning: Applies to autogpt_platform/backend/backend/blocks/**/*.py : Inherit from 'Block' base class with input/output schemas when adding new blocks in backend
Applied to files:
autogpt_platform/backend/backend/blocks/perplexity.py
📚 Learning: 2026-02-05T04:11:00.596Z
Learnt from: ntindle
Repo: Significant-Gravitas/AutoGPT PR: 11796
File: autogpt_platform/backend/backend/blocks/video/concat.py:3-4
Timestamp: 2026-02-05T04:11:00.596Z
Learning: In autogpt_platform/backend/backend/blocks/**/*.py, when creating a new block, generate a UUID once with uuid.uuid4() and hard-code the resulting string as the block's id parameter. Do not call uuid.uuid4() at runtime; IDs must be constant across all imports and runs to ensure stability.
Applied to files:
autogpt_platform/backend/backend/blocks/perplexity.py
📚 Learning: 2026-03-16T16:32:21.686Z
Learnt from: Abhi1992002
Repo: Significant-Gravitas/AutoGPT PR: 12417
File: autogpt_platform/backend/backend/blocks/agent_mail/pods.py:62-74
Timestamp: 2026-03-16T16:32:21.686Z
Learning: In autogpt_platform/backend/backend/blocks/, the Block base class execute() already wraps run() in a try/except to convert uncaught exceptions into BlockExecutionError/BlockUnknownError. Do not add per-block try/except in individual block run() methods, as this is not the established pattern (e.g., Gmail, Slack, Todoist blocks omit it). Only use explicit try/except within blocks that need to distinguish between success and error yield paths inside a generator (e.g., attachment blocks). This guidance applies to all Python files under autogpt_platform/backend/backend/blocks/ and similar block implementations; avoid duplicating error handling in run() unless a block requires generator-based branching.
Applied to files:
autogpt_platform/backend/backend/blocks/perplexity.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/blocks/perplexity.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/blocks/perplexity.py
📚 Learning: 2026-03-16T16:30:11.452Z
Learnt from: Abhi1992002
Repo: Significant-Gravitas/AutoGPT PR: 12417
File: autogpt_platform/backend/backend/blocks/agent_mail/threads.py:80-102
Timestamp: 2026-03-16T16:30:11.452Z
Learning: In autogpt_platform/backend/backend/blocks/ (and related blocks under autogpt_platform/backend/backend/blocks/), do not add try/except blocks around a block's run() method for standard error propagation. The block executor framework (backend/executor/manager.py) catches uncaught exceptions from run() and emits them on the 'error' output. Only add explicit try/except blocks when you need to control partial outputs in failure cases (e.g., certain outputs must not be yielded on error, as in attachment blocks). This is the standard pattern across the codebase; apply it broadly to blocks' run() implementations.
Applied to files:
autogpt_platform/backend/backend/blocks/perplexity.py
📚 Learning: 2026-03-16T16:30:23.196Z
Learnt from: Abhi1992002
Repo: Significant-Gravitas/AutoGPT PR: 12417
File: autogpt_platform/backend/backend/blocks/agent_mail/pods.py:62-74
Timestamp: 2026-03-16T16:30:23.196Z
Learning: In any Python file under autogpt_platform/backend/backend/blocks, do not add a try/except around run() solely for standard error handling. The block framework’s _execute() in _base.py already catches unhandled exceptions and re-raises as BlockExecutionError or BlockUnknownError. If you yield ("error", message), _execute() raises BlockExecutionError immediately, so the error port will not propagate downstream. Reserve explicit try/except for scenarios where you must control partial output (e.g., attachment blocks that must skip yielding content_base64 on failure).
Applied to files:
autogpt_platform/backend/backend/blocks/perplexity.py
📚 Learning: 2026-03-16T16:30:11.452Z
Learnt from: Abhi1992002
Repo: Significant-Gravitas/AutoGPT PR: 12417
File: autogpt_platform/backend/backend/blocks/agent_mail/threads.py:80-102
Timestamp: 2026-03-16T16:30:11.452Z
Learning: Do not wrap synchronous AgentMail SDK calls with asyncio.to_thread() in blocks under autogpt_platform/backend/backend/blocks (and across the codebase). The block executor runs node execution in dedicated threads via asyncio.run_coroutine_threadsafe (see manager.py around lines ~745-752 and ~1079). The existing pattern avoids using asyncio.to_thread for SDK calls inside async run() methods, so maintain that approach and do not add to_thread usage in these code paths.
Applied to files:
autogpt_platform/backend/backend/blocks/perplexity.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/blocks/perplexity.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/blocks/perplexity.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/blocks/perplexity.py
📚 Learning: 2026-03-08T23:28:21.675Z
Learnt from: majdyz
Repo: Significant-Gravitas/AutoGPT PR: 12334
File: docs/integrations/block-integrations/github/repo.md:11-40
Timestamp: 2026-03-08T23:28:21.675Z
Learning: In Significant-Gravitas/AutoGPT, new GitHub block documentation stubs in `docs/integrations/block-integrations/github/` are auto-generated by a docs script with placeholder text (`_Add technical explanation here._` / `_Add practical use case examples here._`) inside `<!-- MANUAL: how_it_works
Applied to files:
docs/integrations/block-integrations/misc.md
📚 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:
docs/integrations/block-integrations/misc.md
📚 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:
docs/integrations/block-integrations/misc.md
📚 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:
docs/integrations/block-integrations/misc.md
📚 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:
docs/integrations/block-integrations/misc.md
📚 Learning: 2026-03-10T08:38:33.249Z
Learnt from: majdyz
Repo: Significant-Gravitas/AutoGPT PR: 12356
File: autogpt_platform/backend/backend/copilot/tools/run_block.py:297-300
Timestamp: 2026-03-10T08:38:33.249Z
Learning: In autogpt_platform/backend/backend/copilot/tools/run_block.py, the auto-approval key for sensitive block HITL review uses graph_exec_id (copilot-session-{session_id}) + node_id (copilot-node-{block_id}). This is intentional: approving a block type within a CoPilot session auto-approves all future invocations of that same block type within the same session, mirroring how auto-approve works in normal graph execution. The user explicitly opts into this session-scoped behavior via an auto-approve toggle. Without the toggle (default), each individual invocation requires its own approval.
Applied to files:
docs/integrations/block-integrations/misc.md
🔇 Additional comments (2)
docs/integrations/block-integrations/misc.md (1)
61-61: LGTM - Documentation sync update.The addition of
"web_search"to the AutoPilot tools list is correctly formatted and alphabetically positioned. This appears to be part of the automated docs-sync regeneration mentioned in the PR objectives.autogpt_platform/backend/backend/blocks/perplexity.py (1)
16-16: LGTM — shared cost extraction helper is wired in cleanly.The import is top-level and uses the backend absolute-import style.
`execution_stats` is instance state on `PerplexityBlock`. When the response lacks `usage`, prior `input_token_count` / `output_token_count` values would leak into the `PlatformCostLog` row for the current run. Reset both to 0 before the conditional assignment, mirroring the unconditional `provider_cost` reset in the previous commit. Flagged by CodeRabbit.
|
🤖 Addressed CodeRabbit's outside-diff comment in 59d94d5ea: |
Adds BLOCK_COSTS entries for paid system-credential blocks that were previously running for free from the credit wallet's perspective. - mem0: Add/Search/GetAll/GetLatestMemoryBlock — 1 credit each (raw $0.0004-0.004/call from $19/mo Starter tier) - screenshotone: ScreenshotWebPageBlock — 2 credits ($0.0085/call) - nvidia: NvidiaDeepfakeDetectBlock — 2 credits (no public per-call SKU, estimate based on peer deepfake APIs ~$0.005-0.01) - smartlead: CreateCampaignBlock 2c, AddLeadToCampaignBlock 1c, SaveCampaignSequencesBlock 1c - zerobounce: ValidateEmailsBlock — 2 credits per email (raw $0.008) - claude_code: ClaudeCodeBlock — 100 credits ($1.00) flat. Real cost is dominated by in-sandbox Claude spend ($0.50-$2/run typical), not E2B compute. Filter on `e2b_credentials` (not `credentials`). Adds regression tests in TestNewlyRegisteredBlockCosts that lock in each entry. Note: Exa/Linear/Airtable/Bannerbear/Wolfram/Firecrawl/Wordpress/ Baas/Stagehand/Dataforseo are not in this list — they register cost via the new SDK ProviderBuilder.with_base_cost() pattern in their respective _config.py.
There was a problem hiding this comment.
Actionable comments posted: 2
🧹 Nitpick comments (1)
autogpt_platform/backend/backend/copilot/tools/helpers_test.py (1)
268-269: Move these repeated imports to module scope.These are normal backend modules, not heavy optional dependencies, so keeping them as top-level imports better matches the backend style guide and avoids repeated import boilerplate across tests. 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: 278-279, 285-291, 303-304, 310-311, 317-322, 329-330, 343-344
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@autogpt_platform/backend/backend/copilot/tools/helpers_test.py` around lines 268 - 269, The test file contains repeated local imports like PerplexityBlock and BLOCK_COSTS inside test functions; move these repeated imports to the module top-level so they are imported once for the whole file (add top-level "from backend.blocks.perplexity import PerplexityBlock" and "from backend.data.block_cost_config import BLOCK_COSTS" near other module imports), then remove the in-function/local import statements (also apply the same change for the other repeated backend imports referenced in the comment) so tests use the module-scope symbols.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@autogpt_platform/backend/backend/copilot/tools/helpers_test.py`:
- Around line 267-275: The test currently only asserts cost amounts for
PerplexityBlock; modify test_perplexity_block_registered to import
PerplexityModel and assert a model-to-cost mapping instead of just amounts:
fetch entries = BLOCK_COSTS[PerplexityBlock], build a dict mapping each
entry.model (or entry.perplexity_model) to entry.cost_amount, and assert that
mapping equals the expected mapping {PerplexityModel.SONAR:1,
PerplexityModel.SONAR_PRO:5, PerplexityModel.SONAR_DEEP_RESEARCH:10} (use the
actual enum member names in your codebase) so swapped prices will fail the test.
In `@autogpt_platform/backend/backend/data/block_cost_config.py`:
- Around line 757-761: Update the PerplexityBlock comment in
block_cost_config.py to remove the claim that Perplexity costs are "piped into
the copilot microdollar counter" (this causes confusion/double-accounting);
instead state that Perplexity provider charges are recorded via provider_cost
and PlatformCostLog and that the copilot run_block path (see
autogpt_platform/backend/backend/copilot/tools/helpers.py run_block) only
charges the user credit wallet and does not increment the microdollar rate-limit
counter.
---
Nitpick comments:
In `@autogpt_platform/backend/backend/copilot/tools/helpers_test.py`:
- Around line 268-269: The test file contains repeated local imports like
PerplexityBlock and BLOCK_COSTS inside test functions; move these repeated
imports to the module top-level so they are imported once for the whole file
(add top-level "from backend.blocks.perplexity import PerplexityBlock" and "from
backend.data.block_cost_config import BLOCK_COSTS" near other module imports),
then remove the in-function/local import statements (also apply the same change
for the other repeated backend imports referenced in the comment) so tests use
the module-scope symbols.
🪄 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: a250b343-853a-45dd-ac14-3bfab45fb3d2
📒 Files selected for processing (2)
autogpt_platform/backend/backend/copilot/tools/helpers_test.pyautogpt_platform/backend/backend/data/block_cost_config.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: Seer Code Review
- GitHub Check: type-check (3.12)
- GitHub Check: test (3.13)
- GitHub Check: test (3.11)
- GitHub Check: type-check (3.13)
- GitHub Check: type-check (3.11)
- GitHub Check: test (3.12)
- GitHub Check: end-to-end tests
- GitHub Check: Analyze (python)
- GitHub Check: Analyze (typescript)
- GitHub Check: Check PR Status
🧰 Additional context used
📓 Path-based instructions (5)
autogpt_platform/backend/**/*.py
📄 CodeRabbit inference engine (.github/copilot-instructions.md)
autogpt_platform/backend/**/*.py: Use Python 3.11 (required; managed by Poetry via pyproject.toml) for backend development
Always run 'poetry run format' (Black + isort) before linting in backend development
Always run 'poetry run lint' (ruff) after formatting in backend development
autogpt_platform/backend/**/*.py: Usepoetry run ...command for executing Python package dependencies
Use top-level imports only — avoid local/inner imports except for lazy imports of heavy optional dependencies likeopenpyxl
Use absolute imports withfrom backend.module import ...for cross-package imports; single-dot relative imports are acceptable for sibling modules within the same package; avoid double-dot relative imports
Do not use duck typing — avoidhasattr/getattr/isinstancefor type dispatch; use typed interfaces/unions/protocols instead
Use Pydantic models over dataclass/namedtuple/dict for structured data
Do not use linter suppressors — no# type: ignore,# noqa,# pyright: ignore; fix the type/code instead
Prefer list comprehensions over manual loop-and-append patterns
Use early return with guard clauses first to avoid deep nesting
Use%sfor deferred interpolation indebuglog statements for efficiency; use f-strings elsewhere for readability (e.g.,logger.debug("Processing %s items", count)vslogger.info(f"Processing {count} items"))
Sanitize error paths by usingos.path.basename()in error messages to avoid leaking directory structure
Be aware of TOCTOU (Time-Of-Check-Time-Of-Use) issues — avoid check-then-act patterns for file access and credit charging
Usetransaction=Truefor Redis pipelines to ensure atomicity on multi-step operations
Usemax(0, value)guards for computed values that should never be negative
Keep files under ~300 lines; if a file grows beyond this, split by responsibility (extract helpers, models, or a sub-module into a new file)
Keep functions under ~40 lines; extract named helpers when a function grows longer
...
Files:
autogpt_platform/backend/backend/copilot/tools/helpers_test.pyautogpt_platform/backend/backend/data/block_cost_config.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/helpers_test.pyautogpt_platform/backend/backend/data/block_cost_config.py
autogpt_platform/backend/**/*_test.py
📄 CodeRabbit inference engine (autogpt_platform/backend/AGENTS.md)
autogpt_platform/backend/**/*_test.py: Use pytest with snapshot testing for API responses
Colocate test files with source files using*_test.pynaming convention
Mock at boundaries — mock where the symbol is used, not where it's defined; after refactoring, update mock targets to match new module paths
UseAsyncMockfromunittest.mockfor async functions in tests
When writing tests, use Test-Driven Development (TDD): write failing tests marked with@pytest.mark.xfailbefore implementation, then remove the marker once the implementation is complete
When creating snapshots in tests, usepoetry run pytest path/to/test.py --snapshot-update; always review snapshot changes withgit diffbefore committing
Files:
autogpt_platform/backend/backend/copilot/tools/helpers_test.py
autogpt_platform/backend/backend/data/**/*.py
📄 CodeRabbit inference engine (.github/copilot-instructions.md)
All data access in backend requires user ID checks; verify this for any 'data/*.py' changes
Files:
autogpt_platform/backend/backend/data/block_cost_config.py
autogpt_platform/**/data/**/*.py
📄 CodeRabbit inference engine (AGENTS.md)
For changes touching
data/*.py, validate user ID checks or explain why not needed
Files:
autogpt_platform/backend/backend/data/block_cost_config.py
🧠 Learnings (25)
📓 Common learnings
Learnt from: majdyz
Repo: Significant-Gravitas/AutoGPT PR: 12876
File: autogpt_platform/backend/backend/copilot/tools/helpers.py:0-0
Timestamp: 2026-04-22T04:01:32.723Z
Learning: In `autogpt_platform/backend/backend/copilot/tools/helpers.py`, the `run_block` copilot path charges ONLY the user credit wallet (via `spend_credits` / `_charge_block_credits`). The microdollar rate-limit counter (`record_cost_usage`) is NOT incremented for `run_block` block executions — the `_record_block_microdollar_cost` helper was explicitly reverted (commit 16ae0f7b5, PR `#12876`) to avoid double-accounting. Do NOT flag missing microdollar recording in `execute_block` as a bug; the credit wallet is the sole billing mechanism for copilot `run_block` calls.
Learnt from: majdyz
Repo: Significant-Gravitas/AutoGPT PR: 12385
File: autogpt_platform/backend/backend/copilot/tools/helpers.py:149-185
Timestamp: 2026-03-15T15:30:09.706Z
Learning: In autogpt_platform/backend/backend/copilot/tools/helpers.py, within execute_block, when InsufficientBalanceError occurs after post-execution credit charging (concurrent balance drain after pre-check passed), this is treated as a non-fatal billing leak: log at ERROR level with structured JSON fields `{"billing_leak": True, "user_id": ..., "cost": ...}` for monitoring/alerting, then return BlockOutputResponse normally. Discarding the output would worsen UX since the block already executed with potential side effects. Reuse the credit_model obtained during the pre-execution balance check (guarded by `if cost > 0 and credit_model:`) for the post-execution charge; do not perform a second get_user_credit_model call.
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: 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.
📚 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/helpers_test.py
📚 Learning: 2026-04-22T04:01:32.723Z
Learnt from: majdyz
Repo: Significant-Gravitas/AutoGPT PR: 12876
File: autogpt_platform/backend/backend/copilot/tools/helpers.py:0-0
Timestamp: 2026-04-22T04:01:32.723Z
Learning: In `autogpt_platform/backend/backend/copilot/tools/helpers.py`, the `run_block` copilot path charges ONLY the user credit wallet (via `spend_credits` / `_charge_block_credits`). The microdollar rate-limit counter (`record_cost_usage`) is NOT incremented for `run_block` block executions — the `_record_block_microdollar_cost` helper was explicitly reverted (commit 16ae0f7b5, PR `#12876`) to avoid double-accounting. Do NOT flag missing microdollar recording in `execute_block` as a bug; the credit wallet is the sole billing mechanism for copilot `run_block` calls.
Applied to files:
autogpt_platform/backend/backend/copilot/tools/helpers_test.pyautogpt_platform/backend/backend/data/block_cost_config.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/backend/blocks/**/*.py : When creating new blocks, inherit from `Block` base class, define input/output schemas using `BlockSchema`, implement async `run` method, and generate unique block ID using `uuid.uuid4()`
Applied to files:
autogpt_platform/backend/backend/copilot/tools/helpers_test.pyautogpt_platform/backend/backend/data/block_cost_config.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/helpers_test.py
📚 Learning: 2026-02-04T16:49:42.490Z
Learnt from: CR
Repo: Significant-Gravitas/AutoGPT PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2026-02-04T16:49:42.490Z
Learning: Applies to autogpt_platform/backend/backend/blocks/**/*.py : Implement 'run' method with proper error handling in backend blocks
Applied to files:
autogpt_platform/backend/backend/copilot/tools/helpers_test.py
📚 Learning: 2026-03-15T15:30:09.706Z
Learnt from: majdyz
Repo: Significant-Gravitas/AutoGPT PR: 12385
File: autogpt_platform/backend/backend/copilot/tools/helpers.py:149-185
Timestamp: 2026-03-15T15:30:09.706Z
Learning: In autogpt_platform/backend/backend/copilot/tools/helpers.py, within execute_block, when InsufficientBalanceError occurs after post-execution credit charging (concurrent balance drain after pre-check passed), this is treated as a non-fatal billing leak: log at ERROR level with structured JSON fields `{"billing_leak": True, "user_id": ..., "cost": ...}` for monitoring/alerting, then return BlockOutputResponse normally. Discarding the output would worsen UX since the block already executed with potential side effects. Reuse the credit_model obtained during the pre-execution balance check (guarded by `if cost > 0 and credit_model:`) for the post-execution charge; do not perform a second get_user_credit_model call.
Applied to files:
autogpt_platform/backend/backend/copilot/tools/helpers_test.pyautogpt_platform/backend/backend/data/block_cost_config.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/helpers_test.py
📚 Learning: 2026-02-04T16:49:42.490Z
Learnt from: CR
Repo: Significant-Gravitas/AutoGPT PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2026-02-04T16:49:42.490Z
Learning: Applies to autogpt_platform/backend/**/test/**/*.py : Use snapshot testing with '--snapshot-update' flag in backend tests when output changes; always review with 'git diff'
Applied to files:
autogpt_platform/backend/backend/copilot/tools/helpers_test.py
📚 Learning: 2026-03-16T16:30:30.764Z
Learnt from: Abhi1992002
Repo: Significant-Gravitas/AutoGPT PR: 12417
File: autogpt_platform/backend/backend/blocks/agent_mail/pods.py:62-74
Timestamp: 2026-03-16T16:30:30.764Z
Learning: In autogpt_platform/backend/backend/blocks/**/*.py, explicit try/except in the `run()` method is NOT required for standard error handling. The block framework's `_execute()` method in `_base.py` catches unhandled exceptions and re-raises them as `BlockExecutionError` or `BlockUnknownError`. Additionally, when a block yields `("error", message)`, `_execute()` immediately raises `BlockExecutionError` — so the `error` output port never propagates downstream. Explicit try/except is only needed when partial output must be controlled (e.g., attachment blocks that must skip yielding `content_base64` on failure).
Applied to files:
autogpt_platform/backend/backend/copilot/tools/helpers_test.py
📚 Learning: 2026-02-05T04:11:15.945Z
Learnt from: ntindle
Repo: Significant-Gravitas/AutoGPT PR: 11796
File: autogpt_platform/backend/backend/blocks/video/concat.py:3-4
Timestamp: 2026-02-05T04:11:15.945Z
Learning: Block IDs in autogpt_platform/backend/backend/blocks/**/*.py must be stable, hard-coded UUID strings. When initially creating a new block, generate a UUID once using `uuid.uuid4()` and then hard-code that UUID string as the block's `id` parameter. Do not call uuid.uuid4() dynamically at runtime, as block IDs must remain constant across all imports and runs.
Applied to files:
autogpt_platform/backend/backend/copilot/tools/helpers_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/tools/helpers_test.pyautogpt_platform/backend/backend/data/block_cost_config.py
📚 Learning: 2026-03-04T08:04:35.881Z
Learnt from: majdyz
Repo: Significant-Gravitas/AutoGPT PR: 12273
File: autogpt_platform/backend/backend/copilot/tools/workspace_files.py:216-220
Timestamp: 2026-03-04T08:04:35.881Z
Learning: In the AutoGPT Copilot backend, ensure that SVG images are not treated as vision image types by excluding 'image/svg+xml' from INLINEABLE_MIME_TYPES and MULTIMODAL_TYPES in tool_adapter.py; the Claude API supports PNG, JPEG, GIF, and WebP for vision. SVGs (XML text) should be handled via the text path instead, not the vision path.
Applied to files:
autogpt_platform/backend/backend/copilot/tools/helpers_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/tools/helpers_test.py
📚 Learning: 2026-03-04T12:19:39.243Z
Learnt from: majdyz
Repo: Significant-Gravitas/AutoGPT PR: 12279
File: autogpt_platform/backend/backend/copilot/tools/base.py:184-188
Timestamp: 2026-03-04T12:19:39.243Z
Learning: In autogpt_platform/backend/backend/copilot/tools/, ensure that anonymous users always pass user_id=None to tool execution methods. The anon_ prefix (e.g., anon_123) is used only for PostHog/analytics distinct_id and must not be used as an actual user_id. Use a simple truthiness check on user_id (e.g., if user_id: ... else: ... or a dedicated is_authenticated flag) to distinguish anonymous from authenticated users, and review all tool execution call sites within this directory to prevent accidentally forwarding an anon_ user_id to tools.
Applied to files:
autogpt_platform/backend/backend/copilot/tools/helpers_test.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/helpers_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/tools/helpers_test.pyautogpt_platform/backend/backend/data/block_cost_config.py
📚 Learning: 2026-03-16T16:35:40.236Z
Learnt from: majdyz
Repo: Significant-Gravitas/AutoGPT PR: 12440
File: autogpt_platform/backend/backend/api/features/workflow_import.py:54-63
Timestamp: 2026-03-16T16:35:40.236Z
Learning: Avoid using the word 'competitor' in public-facing identifiers and text. Use neutral naming for API paths, model names, function names, and UI text. Examples: rename 'CompetitorFormat' to 'SourcePlatform', 'convert_competitor_workflow' to 'convert_workflow', '/competitor-workflow' to '/workflow'. Apply this guideline to files under autogpt_platform/backend and autogpt_platform/frontend.
Applied to files:
autogpt_platform/backend/backend/copilot/tools/helpers_test.pyautogpt_platform/backend/backend/data/block_cost_config.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/helpers_test.pyautogpt_platform/backend/backend/data/block_cost_config.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/helpers_test.pyautogpt_platform/backend/backend/data/block_cost_config.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/data/block_cost_config.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/data/block_cost_config.py
📚 Learning: 2026-02-04T16:49:42.490Z
Learnt from: CR
Repo: Significant-Gravitas/AutoGPT PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2026-02-04T16:49:42.490Z
Learning: Applies to autogpt_platform/backend/backend/blocks/**/*.py : Inherit from 'Block' base class with input/output schemas when adding new blocks in backend
Applied to files:
autogpt_platform/backend/backend/data/block_cost_config.py
📚 Learning: 2026-04-08T17:27:07.646Z
Learnt from: CR
Repo: Significant-Gravitas/AutoGPT PR: 0
File: classic/forge/CLAUDE.md:0-0
Timestamp: 2026-04-08T17:27:07.646Z
Learning: Applies to classic/forge/**/forge/llm/providers/**/*.py : Supported model names include OpenAI (GPT3, GPT3_16k, GPT4, GPT4_32k, GPT4_TURBO, GPT4_O), Anthropic (CLAUDE3_OPUS, CLAUDE3_SONNET, CLAUDE3_HAIKU, CLAUDE3_5_SONNET, CLAUDE3_5_SONNET_v2, CLAUDE3_5_HAIKU, CLAUDE4_SONNET, CLAUDE4_OPUS, CLAUDE4_5_OPUS), and Groq (LLAMA3_8B, LLAMA3_70B, MIXTRAL_8X7B)
Applied to files:
autogpt_platform/backend/backend/data/block_cost_config.py
📚 Learning: 2026-04-21T04:35:34.710Z
Learnt from: majdyz
Repo: Significant-Gravitas/AutoGPT PR: 12865
File: autogpt_platform/backend/backend/data/credit.py:1584-1584
Timestamp: 2026-04-21T04:35:34.710Z
Learning: When reviewing this codebase, don’t flag snake_case attribute names (e.g., `subscription_tier`, `stripe_customer_id`, `top_up_config`) on the app-layer Pydantic `User` model as “wrong” field names. These are correct for the app-layer model and are expected to be mapped from the Prisma-layer camelCase fields (e.g., `subscriptionTier`, `stripeCustomerId`) inside methods like `User.from_db()`. Only Prisma-returned/raw objects would use camelCase, but functions like `get_user_by_id(user_id: str)` are expected to return the Pydantic app-layer model.
Applied to files:
autogpt_platform/backend/backend/data/block_cost_config.py
🔇 Additional comments (5)
autogpt_platform/backend/backend/data/block_cost_config.py (2)
318-334: Good boundary documentation.This clearly documents that
BLOCK_COSTSdrives the user credit wallet and that copilot microdollars stay scoped to LLM turns, which matches the intended accounting split.
798-969: New paid-block registrations look aligned with the credit-wallet gate.The added entries cover the newly billed provider-backed blocks with positive
cost_amountvalues and credential-scoped filters, including the speciale2b_credentialsfield forClaudeCodeBlock.autogpt_platform/backend/backend/copilot/tools/helpers_test.py (3)
29-32: LGTM.The helper signature reformat is clean and behavior-preserving.
216-250: Good regression coverage for free unregistered blocks.This locks in the intended behavior that missing
BLOCK_COSTSentries execute at zero cost without touching credit-wallet endpoints.
277-350: Good coverage for the newly registered paid blocks.The tests pin the expected credit amounts for the newly registered providers and include the important
e2b_credentialsfilter check forClaudeCodeBlock.
Address review feedback: - block_cost_config.py: rewrite the PerplexityBlock comment so it no longer claims block execution pipes into the microdollar counter. run_block decrements only the credit wallet via spend_credits; provider spend is logged separately as PlatformCostLog.provider_cost. - helpers_test.py: pin Perplexity model->cost mapping in the regression test so swapped SONAR / SONAR_PRO / SONAR_DEEP_RESEARCH prices fail rather than silently passing on equal cost-amount sets.
… web_search + simulator cost tracking + reconnect fixes (#12873) ### Why / What / How **Why.** Three problems on the baseline copilot path that compound: extended-thinking turns froze the UI for minutes because Kimi K2.6 events were buffered in `state.pending_events: list` until the full `tool_call_loop` iteration finished (reasoning arrived in one lump at the end); the SSE stream replayed 1000 events on every reconnect and the frontend opened multiple SSE streams in quick succession on tab-focus thrash (reconnect storm → UI flickers, tab freezes); the `web_search` tool hit Anthropic's server-side beta directly via a dispatch-model round-trip that fed entire page contents back through the model for a second inference pass (observed $0.072 on a 74K-token call); and the simulator dry-run path ran on Gemini Flash without any cost tracking at all, so every dry-run was free on the platform's microdollar ledger. **What.** Grouped deltas, all targeting reliability, cost, and UX of the copilot live-answer pipeline: - **Live per-token baseline streaming.** `state.pending_events` is now an `asyncio.Queue` drained concurrently by the outer async generator. The tool-call loop runs as a background task; reasoning / text / tool events reach the SSE wire during the upstream OpenRouter stream, not after it. `None` is the close sentinel; inner-task exceptions are re-raised via `await loop_task` once the sentinel arrives. An `emitted_events: list` mirror preserves post-hoc test inspection. Coalescing widened 32/40 → 64/50 ms to halve the React re-render rate on extended-thinking turns while staying under the ~100 ms perceptual threshold. - **Reasoning render flag** — `ChatConfig.render_reasoning_in_ui: bool = True` wired through both `BaselineReasoningEmitter` and `SDKResponseAdapter`. When False the wire `StreamReasoning*` events are suppressed while the persisted `ChatMessage(role='reasoning')` rows always survive (decoupled from the render flag so audit/replay is unaffected); the service-layer yield filter does the gating. Tokens are still billed upstream; operator kill-switch for UI-level flicker investigations. - **Reconnect storm mitigations** — `ChatConfig.stream_replay_count: int = 200` (was hard-coded 1000) caps `stream_registry.subscribe_to_session` XREAD size. Frontend `useCopilotStream::handleReconnect` adds a 1500 ms debounce via `lastReconnectResumeAtRef`, so tab-focus thrash doesn't fan out into 5–6 parallel replays in the same second. - **web_search rewritten to Perplexity Sonar via OpenRouter** — single unified credential, real `usage.cost` flows through `persist_and_record_usage(provider='open_router')`. Two tiers via a `deep` param: `perplexity/sonar` (~$0.005/call quick) and `perplexity/sonar-deep-research` (~$0.50–$1.30/call multi-step research). Replaces the Anthropic-native + server-tool dispatches; drops the hardcoded pricing constants entirely. - **Synthesised answer surfaced end-to-end** — Sonar already writes a web-grounded answer on the same call we pay for; the new `WebSearchResponse.answer` field passes it through and the accordion UI renders it above citations so the agent doesn't re-fetch URLs that are usually bot-protected anyway. - **Deep-tier cost warning + UI affordances** — `deep` param description is explicit that it's ~100× pricier; UI labels read "Researching / Researched / N research sources" when `deep=true` so users know what's running. - **Simulator cost tracking + cheaper default** — `google/gemini-2.5-flash` → `google/gemini-2.5-flash-lite` (3× cheaper tokens) and every dry-run now hits `persist_and_record_usage(provider='open_router')` with real `usage.cost`. Previously each sim was free against the user's microdollar budget. - **Typed access everywhere** — cost extractors now use `openai.types.CompletionUsage.model_extra["cost"]` and `openai.types.chat.ChatCompletion` / `Annotation` / `AnnotationURLCitation` with no `getattr` / duck typing. Mirrors the baseline service's `_extract_usage_cost` pattern; keep in sync. **How.** Key file touches: 1. `copilot/config.py` — `render_reasoning_in_ui`, `stream_replay_count`, `simulation_model` default. 2. `copilot/baseline/service.py` — `_BaselineStreamState.pending_events: asyncio.Queue`, `_emit` / `_emit_all` helpers, outer generator runs `tool_call_loop` as a background task + yields from queue concurrently. 3. `copilot/baseline/reasoning.py` — `BaselineReasoningEmitter(render_in_ui=...)`, coalescing bumped to 64 chars / 50 ms. 4. `copilot/sdk/service.py` — `state.adapter.render_reasoning_in_ui` threaded through every adapter construction. 5. `copilot/sdk/response_adapter.py` — `render_reasoning_in_ui` wiring + service-layer yield filter gating for wire suppression while persistence stays intact. 6. `copilot/stream_registry.py` — `count=config.stream_replay_count`. 7. `frontend/.../useCopilotStream.ts::handleReconnect` — 1500 ms debounce. 8. `copilot/tools/web_search.py` + `models.py` — Sonar quick/deep paths, `WebSearchResponse.answer` + typed extractors. 9. `frontend/.../GenericTool/*` — `answer` render + deep-aware labels / accordion titles. 10. `executor/simulator.py` + `executor/manager.py` + `copilot/config.py` — cost tracking + model swap + `user_id` threading. ### Changes - `copilot/config.py` — new `render_reasoning_in_ui`, `stream_replay_count`; `simulation_model` default flipped to Flash-Lite. - `copilot/baseline/service.py` — `pending_events: asyncio.Queue` refactor; outer gen runs loop as task, yields from queue live. - `copilot/baseline/reasoning.py` — `BaselineReasoningEmitter(render_in_ui=...)` + 64/50 coalesce. - `copilot/sdk/service.py` + `response_adapter.py` — `render_reasoning_in_ui` wire suppression (persistence preserved). - `copilot/stream_registry.py` — replay cap from config. - `copilot/tools/web_search.py` + `models.py` — Sonar quick/deep + `answer` field + typed extractors. - `copilot/tools/helpers.py` — tool description tightens `deep=true` cost warning. - `frontend/.../useCopilotStream.ts` — reconnect debounce. - `frontend/.../GenericTool/GenericTool.tsx` + `helpers.ts` + tests — render `answer`, deep-aware verbs / titles. - `executor/simulator.py` + `simulator_test.py` + `executor/manager.py` — cost tracking + model swap + user_id plumbing. ### Follow-up (deferred to a separate PR) SDK per-token streaming via `include_partial_messages=True` was attempted (commits `599e83543` + `530fa8f95`) and reverted here. The two-signal model (StreamEvent partial deltas + AssistantMessage summary) needs proper per-block diff tracking — when the partial stream delivers a subset of the final block content, emit only `summary.text[len(already_emitted):]` from the summary rather than gating on a binary flag. Binary gating truncated replies in the field when the partial stream delivered less than the summary (observed: "The analysis template you" cut off mid-sentence because partial had streamed that much and the rest only lived in the summary). SDK reasoning still renders end-of-phase (as today); this PR's baseline per-token streaming is unaffected. ### Checklist For code changes: - [x] Changes listed above - [x] Test plan below - [x] Tested according to the test plan: - [x] `poetry run pytest backend/copilot/baseline/ backend/copilot/sdk/ backend/copilot/tools/web_search_test.py backend/executor/simulator_test.py` — all pass (155 baseline + 927 SDK + web_search + simulator) - [x] `pnpm types && pnpm vitest run src/app/(platform)/copilot/tools/GenericTool/` — pass - [x] Manual: baseline live-streaming — Kimi K2.6 reasoning arrives token-by-token, coalesced (no end-of-stream burst). - [x] Manual: quick web_search via copilot UI — ~$0.005/call, answer + citations rendered, cost logged as `provider=open_router`. - [x] Manual: deep web_search — dispatched only on explicit research phrasing; `sonar-deep-research` billed, UI labels say "Researched" / "N research sources". - [x] Manual: simulator dry-run — Gemini Flash-Lite, `[simulator] Turn usage` log entry, PlatformCostLog row visible. - [x] Manual: reconnect debounce — tab-focus thrash no longer produces parallel XREADs in backend log. - [ ] Manual: `CHAT_RENDER_REASONING_IN_UI=false` smoke-check — reasoning collapse absent, no persisted reasoning row on reload. For configuration changes: - [x] `.env.default` — new config knobs fall back to pydantic defaults; existing `CHAT_MODEL`/`CHAT_FAST_MODEL`/`CHAT_ADVANCED_MODEL` legacy envs still honored upstream (unchanged by this PR). ### Companion PR PR #12876 closes the `run_block`-via-copilot cost-leak gap (registers `PerplexityBlock` / `FactCheckerBlock` in `BLOCK_COSTS`; documents the credit/microdollar wallet boundary). Separate because the credit-wallet side is orthogonal to the copilot microdollar / rate-limit surface this PR ships.
…al streaming with #12873 Incoming changes from dev: - #12876: paid-blocks registration (no conflict) - #12873: baseline live streaming + render_reasoning_in_ui flag + stream_replay_count — lands on response_adapter.py and config_test.py Conflicts and resolution: - config_test.py _ENV_VARS_TO_CLEAR: took the union — our model-alias additions (CHAT_FAST_* / CHAT_THINKING_* / CHAT_CLAUDE_AGENT_FALLBACK_MODEL) and dev's render-flag additions (CHAT_RENDER_REASONING_IN_UI / CHAT_STREAM_REPLAY_COUNT) are independent. - config_test.py test classes: both sides appended; kept our TestSdkModelVendorCompatibility next to dev's TestRenderReasoningInUi / TestStreamReplayCount. - response_adapter.py ThinkingBlock summary branch: our diff-based tail emission (_thinking_tail_for_block) and dev's explanatory comment about render_reasoning_in_ui-gated persistence both apply — kept the comment since it accurately describes the persistence behaviour, and adopted the tail-emit logic since it's what makes partial+summary reconcile work. render_reasoning_in_ui is enforced at the service yield layer (service.py:2463) not in the adapter, so there's no behaviour conflict between the two changes. EOF )
Why / What / How
Why. Audit of
BLOCK_COSTSagainstcredentials_store.pysystem credentials revealed 13 paid blocks running for free from the credit wallet's perspective —BLOCK_COSTS.get(type(block))returnedNone,cost = 0, nospend_creditsdeduction. Users without their own API key consumed system credentials with zero credit drain. Separately, the credit wallet (user-facing prepaid balance) and the copilot microdollar counter (operator-side meter that gatesdaily_cost_limit_microdollars) were never documented as separate systems, so future readers kept tripping on the "why isn't this block charging my limit?" question.What. Three deltas, all credit-wallet-side:
BLOCK_COSTSwith reasonable per-call credit prices (1 credit = $0.01). Pricing researched against the providers' published rates with ~2-3x markup.copilot/rate_limit.py: credits = user-facing prepaid wallet with marketplace-creator charging; microdollars = operator-side meter that only ticks on copilot LLM turns (baseline / SDK / web_search / simulator). Block execution bills credits, not microdollars — explicit contract.provider_coston PerplexityBlock so PlatformCostLog rows carry the real OpenRouterx-total-costvalue via the existingexecutor/cost_tracking.log_system_credential_costpath (separate flow from credit deduction).Block costs registered
Not in scope — already covered via the SDK
ProviderBuilder.with_base_cost()pattern in their respective_config.py: Exa, Linear, Airtable, Bannerbear, Wolfram, Firecrawl, Wordpress, Baas, Stagehand, Dataforseo.How
backend/data/block_cost_config.py— 13 newBlockCostentries (3 Perplexity models + Fact Checker + 11 from this round).backend/copilot/rate_limit.py— boundary docstring.backend/blocks/perplexity.py— populateNodeExecutionStats.provider_costso PlatformCostLog rows carry the real OpenRouterx-total-costvalue.TestUnregisteredBlockRunsFreeregression +TestNewlyRegisteredBlockCostspinning every new entry bycost_amountso a future refactor can't quietly drop one.The companion Notion "Platform System Credentials" database has been updated with a new
Platform Credit Costcolumn populated across all 30 provider rows.Scope trim
An earlier revision piped block execution cost into the copilot microdollar counter via
_record_block_microdollar_costincopilot/tools/helpers.py::execute_block. That was reverted in16ae0f7b5— the microdollar counter stays scoped to copilot LLM turns only, credit wallet handles block execution. The pipe-through crossed a boundary we explicitly want to keep.Changes
backend/data/block_cost_config.py— 13 ×BlockCostentries across 7 providers.backend/blocks/perplexity.py— populateprovider_coston the execution stats (feeds PlatformCostLog).backend/copilot/rate_limit.py— boundary docstring only (no behaviour change).backend/copilot/tools/helpers_test.py—TestUnregisteredBlockRunsFree+TestNewlyRegisteredBlockCosts(8 new regression tests).backend/blocks/block_cost_tracking_test.py— provider-cost extraction pins.Checklist
For code changes:
poetry run pytest backend/copilot/tools/helpers_test.py backend/copilot/tools/run_block_test.py backend/copilot/tools/continue_run_block_test.py backend/blocks/block_cost_tracking_test.py backend/blocks/test/test_perplexity.py— passespoetry run pytest backend/executor/manager_cost_tracking_test.py backend/copilot/rate_limit_test.py backend/copilot/token_tracking_test.py— passes (confirms docstring edits didn't regress the LLM-turn microdollar path)run_block— credits deduct, PlatformCostLog row visible withprovider_cost, no microdollar-counter tick.Companion PR
PR #12873 ships the copilot microdollar / rate-limit work (web_search cost, simulator cost, reasoning / reconnect fixes). This PR is credit-wallet only.