feat: add AgentBroker crypto trading blocks - #12502
Conversation
…s#12497) ## Summary ### Before <img width="500" height="501" alt="Screenshot 2026-03-20 at 21 50 31" src="https://github.com/user-attachments/assets/6154cffb-6772-4c3d-a703-527c8ca0daff" /> ### After <img width="500" height="581" alt="Screenshot 2026-03-20 at 21 33 12" src="https://github.com/user-attachments/assets/2f9bd69d-30c5-4d06-ad1e-ed76b184afe5" /> ### Other minor fixes - minor spacing adjustments in creator/search pages when empty and between sections ### Summary - Increase StoreCard height from 25rem to 26.5rem to prevent content overflow - Replace manual tooltip-based title truncation with `OverflowText` component in StoreCard - Adjust carousel indicator positioning and hide it on md+ when exactly 3 featured agents are shown ## Test plan - [x] Verify marketplace cards display without text overflow - [x] Verify featured section carousel indicators behave correctly - [x] Check responsive behavior at common breakpoints 🤖 Generated with [Claude Code](https://claude.com/claude-code) --------- Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
|
|
|
This PR targets the Automatically setting the base branch to |
WalkthroughA new module introducing four AgentBroker-backed trading blocks for Solana/Jupiter DEX interactions: price fetching, OHLCV candle retrieval, order placement, and balance queries. Each block includes async HTTP operations, input/output schemas, and test fixtures. Changes
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~20 minutes Poem
🚥 Pre-merge checks | ✅ 2 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (2 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment Tip CodeRabbit can approve the review once all CodeRabbit's comments are resolved.Enable the |
| api_key: str = SchemaField( | ||
| description="Your AgentBroker API key (get one at https://agentbroker.polsia.app)", | ||
| placeholder="ab_live_...", | ||
| ) |
There was a problem hiding this comment.
Bug: The api_key fields in AgentBroker blocks are not marked as secret, causing them to be stored and displayed in plaintext.
Severity: MEDIUM
Suggested Fix
Add the secret=True parameter to the SchemaField definition for the api_key in both AgentBrokerPlaceOrderBlock and AgentBrokerGetBalanceBlock. A more robust solution would be to integrate with the framework's credentials system by replacing the SchemaField with CredentialsField to ensure the API keys are properly encrypted and managed.
Prompt for AI Agent
Review the code at the location below. A potential bug has been identified by an AI
agent.
Verify if this is a real issue. If it is, propose a fix; if not, explain why it's not
valid.
Location: autogpt_platform/backend/backend/blocks/agentbroker.py#L181-L184
Potential issue: In the `AgentBrokerPlaceOrderBlock` and `AgentBrokerGetBalanceBlock`
classes, the `api_key` input field is defined as a standard `str` using `SchemaField`
without the `secret=True` parameter. This deviates from the established security pattern
for handling sensitive data within the platform, where credentials are typically managed
using `SecretField` or the `CredentialsField` system. As a result, the AgentBroker API
keys, which are used for financial transactions, will be stored and potentially
displayed in plaintext in the frontend UI, backend database, and logs, creating a
security vulnerability.
Did we get this right? 👍 / 👎 to inform future reviews.
There was a problem hiding this comment.
Actionable comments posted: 7
🧹 Nitpick comments (2)
autogpt_platform/backend/backend/blocks/agentbroker.py (2)
44-44: Generate a proper UUID usinguuid.uuid4().The ID
a1b2c3d4-e5f6-4a7b-8c9d-e0f1a2b3c4d5appears to be a manually-crafted placeholder. Per guidelines, generate a UUID once withuuid.uuid4()and hardcode the resulting string. Runpython -c "import uuid; print(uuid.uuid4())"to generate a proper ID.🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@autogpt_platform/backend/backend/blocks/agentbroker.py` at line 44, The hardcoded placeholder UUID "a1b2c3d4-e5f6-4a7b-8c9d-e0f1a2b3c4d5" should be replaced with a real UUID string generated via uuid.uuid4(); run python -c "import uuid; print(uuid.uuid4())", copy the produced value and replace the placeholder literal assigned to id in agentbroker.py (the UUID field in the relevant dict/object) so the file contains a valid hardcoded UUID string.
106-109: Consider validating or clampinglimitto enforce the documented maximum.The description states "max 1000" but there's no validation. Users could pass invalid values leading to API errors or unexpected behavior.
♻️ Proposed validation approach
Add a validator in the Input schema or clamp in
run():async def run(self, input_data: Input, **kwargs) -> BlockOutput: + limit = min(max(1, input_data.limit), 1000) # Clamp to valid range data = await self.fetch_candles( input_data.pair, input_data.interval.value, - input_data.limit, + limit, )🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@autogpt_platform/backend/backend/blocks/agentbroker.py` around lines 106 - 109, The SchemaField "limit" currently documents a max of 1000 but has no enforcement; add validation or clamping so callers cannot pass >1000 or <1. Implement this by adding a validator on the input schema for the "limit" field (or clamp it at the start of the run() method) to coerce values into the allowed range (e.g., min 1, max 1000) and return/log a clear error or warning when out-of-range values are adjusted; reference the "limit" SchemaField and the run() function in agentbroker.py when making the change.
🤖 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/agentbroker.py`:
- Around line 153-164: The run method in AgentBroker candle-fetching block
currently wraps the logic in a try/except and yields an "error" on exception;
remove that try/except so exceptions propagate to the block executor instead.
Edit the async def run(self, input_data: Input, **kwargs) -> BlockOutput in
agentbroker.py: drop the try: and except Exception as e: yield "error", str(e)
lines and keep the await self.fetch_candles call and subsequent yield
"pair"/"interval"/"candles" unchanged so errors bubble up to the executor.
- Around line 74-81: The run method currently wraps its logic in a try/except
that catches exceptions and yields an "error" output; remove that try/except so
exceptions propagate to the block executor instead. Specifically, in the async
def run(self, input_data: Input, **kwargs) method, delete the try: ... except
Exception as e: yield "error", str(e) wrapper and leave the body that awaits
self.fetch_price(input_data.pair) and yields "pair", "price_usdc", and
"change_24h_pct" (using data.get(...) and float(...)) so any exception from
fetch_price or the yield sequence bubbles to the executor.
- Around line 197-203: Validate that quantity is strictly positive by adding a
check in the order flow (e.g., in run()) that raises/returns an error if
quantity <= 0 and mention this validation alongside the SchemaField declaration
for quantity; for limit orders (when order_type == LIMIT) require price to be
provided and greater than 0 (do not rely on the default 0.0), i.e., add a guard
in run() that rejects limit orders with price <= 0 and update any logic that
omits the price field (currently around the code building the order at lines
creating the price payload) to only omit price for non-limit orders.
- Around line 275-291: Remove the try/except wrapper in the async run method so
exceptions propagate to the executor: in the run function (the async def
run(self, input_data: Input, **kwargs) -> BlockOutput) delete the surrounding
try/except block that catches Exception and yields "error", and retain the await
self.place_order(...) call and subsequent yield statements for "order_id",
"status", "filled_quantity", "fees", and "balance_usdc"; this ensures
place_order errors are not swallowed and partial outputs are not emitted before
failure.
- Around line 346-353: The run method currently wraps its logic in a try/except
and yields an "error" string on exception; remove that try/except so exceptions
propagate to the executor instead. Edit the async def run(self, input_data:
Input, **kwargs) -> BlockOutput implementation that calls await
self.fetch_balance(input_data.api_key) and yields "balance_usdc",
"total_portfolio_value", and "trade_count" to eliminate the surrounding
try/except/except block; do not change the yield keys or conversions, just let
exceptions from fetch_balance bubble up.
- Line 121: The placeholder sequential UUIDs used as the "id" values in the four
block definitions must be replaced with real UUID4s: generate four unique values
with uuid.uuid4() (one per block) and hard-code each generated string into the
corresponding block "id" field (the blocks defined around the existing id
attributes such as the one currently set to
"b2c3d4e5-f6a7-4b8c-9d0e-f1a2b3c4d5e6"); ensure you update all four block
definitions (the four block dicts/constructors in this file) so each uses its
own distinct UUID4 string instead of the placeholder pattern.
- Around line 180-184: Replace the plain SchemaField API key inputs with the
credentials pattern used elsewhere: change the Input inner classes in
AgentBrokerPlaceOrderBlock and AgentBrokerGetBalanceBlock to declare the key
using CredentialsField combined with CredentialsMetaInput so the framework
injects APIKeyCredentials into the block's run() method; update the run(self,
..., credentials: APIKeyCredentials) signature to consume credentials.key rather
than reading Input.api_key, and remove any direct SchemaField usage for the
api_key to avoid exposing secrets.
---
Nitpick comments:
In `@autogpt_platform/backend/backend/blocks/agentbroker.py`:
- Line 44: The hardcoded placeholder UUID "a1b2c3d4-e5f6-4a7b-8c9d-e0f1a2b3c4d5"
should be replaced with a real UUID string generated via uuid.uuid4(); run
python -c "import uuid; print(uuid.uuid4())", copy the produced value and
replace the placeholder literal assigned to id in agentbroker.py (the UUID field
in the relevant dict/object) so the file contains a valid hardcoded UUID string.
- Around line 106-109: The SchemaField "limit" currently documents a max of 1000
but has no enforcement; add validation or clamping so callers cannot pass >1000
or <1. Implement this by adding a validator on the input schema for the "limit"
field (or clamp it at the start of the run() method) to coerce values into the
allowed range (e.g., min 1, max 1000) and return/log a clear error or warning
when out-of-range values are adjusted; reference the "limit" SchemaField and the
run() function in agentbroker.py when making the change.
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro
Run ID: 5ccbd4f1-857e-428b-a80e-4b11de835c0a
📒 Files selected for processing (1)
autogpt_platform/backend/backend/blocks/agentbroker.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). (1)
- GitHub Check: Seer Code Review
🧰 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 ...for all Python package commands (install, migrations, tests, linting, formatting)
Use top-level imports only; avoid local/inner imports except for lazy imports of heavy optional dependencies likeopenpyxl
Do not use duck typing; avoidhasattr(),getattr(), orisinstance()for type dispatch; use typed interfaces, unions, or protocols instead
Use Pydantic models over dataclass, namedtuple, or dict for structured data
Do not use linter suppressors; no# type: ignore,# noqa, or# pyright: ignorecomments; fix the type or code instead
Use list comprehensions over manual loop-and-append patterns
Use early return with guard clauses first; avoid deep nesting
Use%sfor deferred interpolation inlogger.debug()statements; use f-strings elsewhere for readability (e.g.,logger.debug("Processing %s items", count),logger.info(f"Processing {count} items"))
Sanitize error paths usingos.path.basename()in error messages to avoid leaking directory structure
Be aware of TOCTOU (time-of-check-time-of-use) vulnerabilities; avoid check-then-act patterns for file access and credit charging
Usetransaction=Truein Redis pipelines for atomicity on multi-step operations
Usemax(0, value)guards for computed values that should never be negative
Keep files under ~300 lines; split by responsibility if a file grows beyond this (extract helpers, models, or sub-modules into new files). Never keep appending to a long file.
Keep functions under ~40 lines; extract named helpers when a function grows longer. Long functions indicate mixed concerns, not just complexity.
Use top-down ordering: define the main/public function or class f...
Files:
autogpt_platform/backend/backend/blocks/agentbroker.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: When creating a new block, follow the Block SDK Guide: useProviderBuilderfor provider configuration, inherit fromBlockbase class, define schemas usingBlockSchema, implement asyncrunmethod, generate unique ID withuuid.uuid4(), and analyze block interfaces for graph compatibility
When blocks work with files (images, videos, documents), usestore_media_file()frombackend.util.file. Usefor_local_processingfor local tools,for_external_apifor external APIs, andfor_block_outputfor block outputs.
Files:
autogpt_platform/backend/backend/blocks/agentbroker.py
autogpt_platform/**/*.py
📄 CodeRabbit inference engine (AGENTS.md)
Format Python code with
poetry run format
Files:
autogpt_platform/backend/backend/blocks/agentbroker.py
🧠 Learnings (12)
📓 Common learnings
Learnt from: Pwuts
Repo: Significant-Gravitas/AutoGPT PR: 12284
File: autogpt_platform/frontend/src/app/api/openapi.json:11897-11900
Timestamp: 2026-03-04T23:58:18.476Z
Learning: Repo: Significant-Gravitas/AutoGPT — PR `#12284`
Backend/frontend OpenAPI codegen convention: In backend/api/features/store/model.py, the StoreSubmission and StoreSubmissionAdminView models define submitted_at: datetime | None, changes_summary: str | None, and instructions: str | None with no default. This is intentional to produce “required but nullable” fields in OpenAPI (properties appear in required[] and use anyOf [type, null]). This matches Prisma’s submittedAt DateTime? and changesSummary String?. Do not flag this as a required/nullable mismatch.
📚 Learning: 2026-03-20T09:30:22.638Z
Learnt from: CR
Repo: Significant-Gravitas/AutoGPT PR: 0
File: autogpt_platform/backend/CLAUDE.md:0-0
Timestamp: 2026-03-20T09:30:22.638Z
Learning: Applies to autogpt_platform/backend/backend/blocks/**/*.py : When creating a new block, follow the Block SDK Guide: use `ProviderBuilder` for provider configuration, inherit from `Block` base class, define schemas using `BlockSchema`, implement async `run` method, generate unique ID with `uuid.uuid4()`, and analyze block interfaces for graph compatibility
Applied to files:
autogpt_platform/backend/backend/blocks/agentbroker.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/agentbroker.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/blocks/agentbroker.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/agentbroker.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/agentbroker.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/agentbroker.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/agentbroker.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/agentbroker.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/agentbroker.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/agentbroker.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/agentbroker.py
🔇 Additional comments (1)
autogpt_platform/backend/backend/blocks/agentbroker.py (1)
1-24: LGTM!Module docstring, imports, and base URL constant are well-structured and follow conventions.
| async def run(self, input_data: Input, **kwargs) -> BlockOutput: | ||
| try: | ||
| data = await self.fetch_price(input_data.pair) | ||
| yield "pair", data.get("pair", input_data.pair) | ||
| yield "price_usdc", float(data.get("price_usdc", 0)) | ||
| yield "change_24h_pct", float(data.get("change_24h_pct", 0)) | ||
| except Exception as e: | ||
| yield "error", str(e) |
There was a problem hiding this comment.
🛠️ Refactor suggestion | 🟠 Major
Remove try/except wrapper; let the executor handle exceptions.
The block executor framework automatically catches uncaught exceptions from run() and emits them on the error output. Adding explicit try/except here diverges from the established pattern (e.g., Gmail, Slack, Todoist blocks omit it) and can cause partial outputs to be yielded before the error. Based on learnings: "Do not add per-block try/except in individual block run() methods."
♻️ Proposed fix
async def run(self, input_data: Input, **kwargs) -> BlockOutput:
- try:
- data = await self.fetch_price(input_data.pair)
- yield "pair", data.get("pair", input_data.pair)
- yield "price_usdc", float(data.get("price_usdc", 0))
- yield "change_24h_pct", float(data.get("change_24h_pct", 0))
- except Exception as e:
- yield "error", str(e)
+ data = await self.fetch_price(input_data.pair)
+ yield "pair", data.get("pair", input_data.pair)
+ yield "price_usdc", float(data.get("price_usdc", 0))
+ yield "change_24h_pct", float(data.get("change_24h_pct", 0))📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| async def run(self, input_data: Input, **kwargs) -> BlockOutput: | |
| try: | |
| data = await self.fetch_price(input_data.pair) | |
| yield "pair", data.get("pair", input_data.pair) | |
| yield "price_usdc", float(data.get("price_usdc", 0)) | |
| yield "change_24h_pct", float(data.get("change_24h_pct", 0)) | |
| except Exception as e: | |
| yield "error", str(e) | |
| async def run(self, input_data: Input, **kwargs) -> BlockOutput: | |
| data = await self.fetch_price(input_data.pair) | |
| yield "pair", data.get("pair", input_data.pair) | |
| yield "price_usdc", float(data.get("price_usdc", 0)) | |
| yield "change_24h_pct", float(data.get("change_24h_pct", 0)) |
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@autogpt_platform/backend/backend/blocks/agentbroker.py` around lines 74 - 81,
The run method currently wraps its logic in a try/except that catches exceptions
and yields an "error" output; remove that try/except so exceptions propagate to
the block executor instead. Specifically, in the async def run(self, input_data:
Input, **kwargs) method, delete the try: ... except Exception as e: yield
"error", str(e) wrapper and leave the body that awaits
self.fetch_price(input_data.pair) and yields "pair", "price_usdc", and
"change_24h_pct" (using data.get(...) and float(...)) so any exception from
fetch_price or the yield sequence bubbles to the executor.
|
|
||
| def __init__(self): | ||
| super().__init__( | ||
| id="b2c3d4e5-f6a7-4b8c-9d0e-f1a2b3c4d5e6", |
There was a problem hiding this comment.
🛠️ Refactor suggestion | 🟠 Major
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash
# Generate 4 proper UUIDs for the blocks
echo "Replace the placeholder IDs with these:"
for i in 1 2 3 4; do
python3 -c "import uuid; print(f'Block {i}: {uuid.uuid4()}')"
doneRepository: Significant-Gravitas/AutoGPT
Length of output: 648
🏁 Script executed:
# First, locate and examine the agentbroker.py file
find . -name "agentbroker.py" -type fRepository: Significant-Gravitas/AutoGPT
Length of output: 128
🏁 Script executed:
# Read the agentbroker.py file to check the UUID patterns
cat -n autogpt_platform/backend/backend/blocks/agentbroker.py | grep -A 2 -B 2 "id=" | head -40Repository: Significant-Gravitas/AutoGPT
Length of output: 1092
🏁 Script executed:
# Check if these placeholder UUIDs are referenced elsewhere
rg "a1b2c3d4-e5f6-4a7b-8c9d-e0f1a2b3c4d5|b2c3d4e5-f6a7-4b8c-9d0e-f1a2b3c4d5e6|c3d4e5f6-a7b8-4c9d-0e1f-a2b3c4d5e6f7|d4e5f6a7-b8c9-4d0e-1f2a-b3c4d5e6f7a8" --type pyRepository: Significant-Gravitas/AutoGPT
Length of output: 511
Replace placeholder UUIDs with real ones in all four block definitions.
The four block IDs use a sequential placeholder pattern (a1b2c3d4→b2c3d4e5→c3d4e5f6→d4e5f6a7) that violates the block SDK requirement. Generate real UUIDs using uuid.uuid4() once for each block at lines 44, 121, 215, and 313, then hard-code the generated values.
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@autogpt_platform/backend/backend/blocks/agentbroker.py` at line 121, The
placeholder sequential UUIDs used as the "id" values in the four block
definitions must be replaced with real UUID4s: generate four unique values with
uuid.uuid4() (one per block) and hard-code each generated string into the
corresponding block "id" field (the blocks defined around the existing id
attributes such as the one currently set to
"b2c3d4e5-f6a7-4b8c-9d0e-f1a2b3c4d5e6"); ensure you update all four block
definitions (the four block dicts/constructors in this file) so each uses its
own distinct UUID4 string instead of the placeholder pattern.
| async def run(self, input_data: Input, **kwargs) -> BlockOutput: | ||
| try: | ||
| data = await self.fetch_candles( | ||
| input_data.pair, | ||
| input_data.interval.value, | ||
| input_data.limit, | ||
| ) | ||
| yield "pair", data.get("pair", input_data.pair) | ||
| yield "interval", data.get("interval", input_data.interval.value) | ||
| yield "candles", data.get("candles", []) | ||
| except Exception as e: | ||
| yield "error", str(e) |
There was a problem hiding this comment.
🛠️ Refactor suggestion | 🟠 Major
Remove try/except wrapper; let the executor handle exceptions.
Same issue as AgentBrokerGetPriceBlock. The block executor handles exceptions automatically.
♻️ Proposed fix
async def run(self, input_data: Input, **kwargs) -> BlockOutput:
- try:
- data = await self.fetch_candles(
- input_data.pair,
- input_data.interval.value,
- input_data.limit,
- )
- yield "pair", data.get("pair", input_data.pair)
- yield "interval", data.get("interval", input_data.interval.value)
- yield "candles", data.get("candles", [])
- except Exception as e:
- yield "error", str(e)
+ data = await self.fetch_candles(
+ input_data.pair,
+ input_data.interval.value,
+ input_data.limit,
+ )
+ yield "pair", data.get("pair", input_data.pair)
+ yield "interval", data.get("interval", input_data.interval.value)
+ yield "candles", data.get("candles", [])🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@autogpt_platform/backend/backend/blocks/agentbroker.py` around lines 153 -
164, The run method in AgentBroker candle-fetching block currently wraps the
logic in a try/except and yields an "error" on exception; remove that try/except
so exceptions propagate to the block executor instead. Edit the async def
run(self, input_data: Input, **kwargs) -> BlockOutput in agentbroker.py: drop
the try: and except Exception as e: yield "error", str(e) lines and keep the
await self.fetch_candles call and subsequent yield "pair"/"interval"/"candles"
unchanged so errors bubble up to the executor.
| class Input(BlockSchemaInput): | ||
| api_key: str = SchemaField( | ||
| description="Your AgentBroker API key (get one at https://agentbroker.polsia.app)", | ||
| placeholder="ab_live_...", | ||
| ) |
There was a problem hiding this comment.
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash
# Search for patterns of API key handling in existing blocks
rg -n "api_key|API_KEY|credentials" --type=py autogpt_platform/backend/backend/blocks/ -C3 | head -100Repository: Significant-Gravitas/AutoGPT
Length of output: 8292
🏁 Script executed:
cat -n autogpt_platform/backend/backend/blocks/agentbroker.py | sed -n '175,195p'Repository: Significant-Gravitas/AutoGPT
Length of output: 1007
🏁 Script executed:
# Also check how the api_key is used in the run method
sed -n '200,250p' autogpt_platform/backend/backend/blocks/agentbroker.py | cat -nRepository: Significant-Gravitas/AutoGPT
Length of output: 2514
🏁 Script executed:
# Check the run() method to see how api_key is used
sed -n '250,290p' autogpt_platform/backend/backend/blocks/agentbroker.py | cat -nRepository: Significant-Gravitas/AutoGPT
Length of output: 1754
🏁 Script executed:
# Check AgentBrokerGetBalanceBlock around line 298
sed -n '295,330p' autogpt_platform/backend/backend/blocks/agentbroker.py | cat -nRepository: Significant-Gravitas/AutoGPT
Length of output: 1936
🏁 Script executed:
# Check if there's a ProviderBuilder pattern or if CredentialsField is the standard approach
rg -n "ProviderBuilder|CredentialsField" --type=py autogpt_platform/backend/backend/blocks/ | head -20Repository: Significant-Gravitas/AutoGPT
Length of output: 2546
🏁 Script executed:
# Get the full import structure of a block using CredentialsField to understand the pattern
head -30 autogpt_platform/backend/backend/blocks/flux_kontext.py | cat -nRepository: Significant-Gravitas/AutoGPT
Length of output: 1140
🏁 Script executed:
# Check the complete agentbroker.py file structure to understand full scope
wc -l autogpt_platform/backend/backend/blocks/agentbroker.pyRepository: Significant-Gravitas/AutoGPT
Length of output: 130
🏁 Script executed:
# Check for ProviderName.AGENTBROKER or similar in the codebase
rg -n "AGENTBROKER|agentbroker" --type=py autogpt_platform/backend/backend/integrations/ 2>/dev/null || echo "Not found in integrations"Repository: Significant-Gravitas/AutoGPT
Length of output: 97
🏁 Script executed:
# Check how wolfram block uses ProviderBuilder
sed -n '1,50p' autogpt_platform/backend/backend/blocks/wolfram/llm_api.py | cat -nRepository: Significant-Gravitas/AutoGPT
Length of output: 1764
🏁 Script executed:
# Check if there's documentation on the proper pattern for credentials
find autogpt_platform/backend -name "*.md" -type f | xargs grep -l "credential\|CredentialsField" 2>/dev/null | head -5Repository: Significant-Gravitas/AutoGPT
Length of output: 251
Use CredentialsField instead of plain SchemaField for API keys.
Passing API keys as plain SchemaField inputs exposes them in logs, storage, and UI without protection. The established pattern in this codebase is to use CredentialsField with CredentialsMetaInput, which injects credentials securely into the run() method via the credentials: APIKeyCredentials parameter. See medium.py and enrichlayer/linkedin.py for examples.
This applies to both AgentBrokerPlaceOrderBlock (line 181) and AgentBrokerGetBalanceBlock (line 304).
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@autogpt_platform/backend/backend/blocks/agentbroker.py` around lines 180 -
184, Replace the plain SchemaField API key inputs with the credentials pattern
used elsewhere: change the Input inner classes in AgentBrokerPlaceOrderBlock and
AgentBrokerGetBalanceBlock to declare the key using CredentialsField combined
with CredentialsMetaInput so the framework injects APIKeyCredentials into the
block's run() method; update the run(self, ..., credentials: APIKeyCredentials)
signature to consume credentials.key rather than reading Input.api_key, and
remove any direct SchemaField usage for the api_key to avoid exposing secrets.
| quantity: float = SchemaField( | ||
| description="Amount in USDC to spend (buy) or tokens to sell", | ||
| ) | ||
| price: float = SchemaField( | ||
| description="Limit price in USDC per token (required for limit orders)", | ||
| default=0.0, | ||
| ) |
There was a problem hiding this comment.
Add validation for quantity and improve price handling for limit orders.
quantityshould be validated to be positive; placing orders withquantity <= 0would fail or behave unexpectedly.- For limit orders,
pricebeing exactly0.0(the default) would silently omit the price field (line 266-267), likely causing an API error. Consider makingpricerequired whenorder_type == LIMIT.
🛡️ Proposed validation in run()
async def run(self, input_data: Input, **kwargs) -> BlockOutput:
+ if input_data.quantity <= 0:
+ raise ValueError("Quantity must be positive")
+ if input_data.order_type == OrderType.LIMIT and input_data.price <= 0:
+ raise ValueError("Price must be positive for limit orders")
data = await self.place_order(🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@autogpt_platform/backend/backend/blocks/agentbroker.py` around lines 197 -
203, Validate that quantity is strictly positive by adding a check in the order
flow (e.g., in run()) that raises/returns an error if quantity <= 0 and mention
this validation alongside the SchemaField declaration for quantity; for limit
orders (when order_type == LIMIT) require price to be provided and greater than
0 (do not rely on the default 0.0), i.e., add a guard in run() that rejects
limit orders with price <= 0 and update any logic that omits the price field
(currently around the code building the order at lines creating the price
payload) to only omit price for non-limit orders.
| async def run(self, input_data: Input, **kwargs) -> BlockOutput: | ||
| try: | ||
| data = await self.place_order( | ||
| api_key=input_data.api_key, | ||
| pair=input_data.pair, | ||
| side=input_data.side.value, | ||
| order_type=input_data.order_type.value, | ||
| quantity=input_data.quantity, | ||
| price=input_data.price, | ||
| ) | ||
| yield "order_id", data.get("order_id", "") | ||
| yield "status", data.get("status", "") | ||
| yield "filled_quantity", float(data.get("filled_quantity", 0)) | ||
| yield "fees", float(data.get("fees", 0)) | ||
| yield "balance_usdc", float(data.get("balance_usdc", 0)) | ||
| except Exception as e: | ||
| yield "error", str(e) |
There was a problem hiding this comment.
🛠️ Refactor suggestion | 🟠 Major
Remove try/except wrapper; let the executor handle exceptions.
Same pattern issue as other blocks. Critical for order placement where partial success outputs before an error could be misleading.
♻️ Proposed fix
async def run(self, input_data: Input, **kwargs) -> BlockOutput:
- try:
- data = await self.place_order(
- api_key=input_data.api_key,
- pair=input_data.pair,
- side=input_data.side.value,
- order_type=input_data.order_type.value,
- quantity=input_data.quantity,
- price=input_data.price,
- )
- yield "order_id", data.get("order_id", "")
- yield "status", data.get("status", "")
- yield "filled_quantity", float(data.get("filled_quantity", 0))
- yield "fees", float(data.get("fees", 0))
- yield "balance_usdc", float(data.get("balance_usdc", 0))
- except Exception as e:
- yield "error", str(e)
+ data = await self.place_order(
+ api_key=input_data.api_key,
+ pair=input_data.pair,
+ side=input_data.side.value,
+ order_type=input_data.order_type.value,
+ quantity=input_data.quantity,
+ price=input_data.price,
+ )
+ yield "order_id", data.get("order_id", "")
+ yield "status", data.get("status", "")
+ yield "filled_quantity", float(data.get("filled_quantity", 0))
+ yield "fees", float(data.get("fees", 0))
+ yield "balance_usdc", float(data.get("balance_usdc", 0))🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@autogpt_platform/backend/backend/blocks/agentbroker.py` around lines 275 -
291, Remove the try/except wrapper in the async run method so exceptions
propagate to the executor: in the run function (the async def run(self,
input_data: Input, **kwargs) -> BlockOutput) delete the surrounding try/except
block that catches Exception and yields "error", and retain the await
self.place_order(...) call and subsequent yield statements for "order_id",
"status", "filled_quantity", "fees", and "balance_usdc"; this ensures
place_order errors are not swallowed and partial outputs are not emitted before
failure.
| async def run(self, input_data: Input, **kwargs) -> BlockOutput: | ||
| try: | ||
| data = await self.fetch_balance(input_data.api_key) | ||
| yield "balance_usdc", float(data.get("balance_usdc", 0)) | ||
| yield "total_portfolio_value", float(data.get("total_portfolio_value", 0)) | ||
| yield "trade_count", int(data.get("trade_count", 0)) | ||
| except Exception as e: | ||
| yield "error", str(e) |
There was a problem hiding this comment.
🛠️ Refactor suggestion | 🟠 Major
Remove try/except wrapper; let the executor handle exceptions.
Same pattern issue as other blocks in this file.
♻️ Proposed fix
async def run(self, input_data: Input, **kwargs) -> BlockOutput:
- try:
- data = await self.fetch_balance(input_data.api_key)
- yield "balance_usdc", float(data.get("balance_usdc", 0))
- yield "total_portfolio_value", float(data.get("total_portfolio_value", 0))
- yield "trade_count", int(data.get("trade_count", 0))
- except Exception as e:
- yield "error", str(e)
+ data = await self.fetch_balance(input_data.api_key)
+ yield "balance_usdc", float(data.get("balance_usdc", 0))
+ yield "total_portfolio_value", float(data.get("total_portfolio_value", 0))
+ yield "trade_count", int(data.get("trade_count", 0))📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| async def run(self, input_data: Input, **kwargs) -> BlockOutput: | |
| try: | |
| data = await self.fetch_balance(input_data.api_key) | |
| yield "balance_usdc", float(data.get("balance_usdc", 0)) | |
| yield "total_portfolio_value", float(data.get("total_portfolio_value", 0)) | |
| yield "trade_count", int(data.get("trade_count", 0)) | |
| except Exception as e: | |
| yield "error", str(e) | |
| async def run(self, input_data: Input, **kwargs) -> BlockOutput: | |
| data = await self.fetch_balance(input_data.api_key) | |
| yield "balance_usdc", float(data.get("balance_usdc", 0)) | |
| yield "total_portfolio_value", float(data.get("total_portfolio_value", 0)) | |
| yield "trade_count", int(data.get("trade_count", 0)) |
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@autogpt_platform/backend/backend/blocks/agentbroker.py` around lines 346 -
353, The run method currently wraps its logic in a try/except and yields an
"error" string on exception; remove that try/except so exceptions propagate to
the executor instead. Edit the async def run(self, input_data: Input, **kwargs)
-> BlockOutput implementation that calls await
self.fetch_balance(input_data.api_key) and yields "balance_usdc",
"total_portfolio_value", and "trade_count" to eliminate the surrounding
try/except/except block; do not change the yield keys or conversions, just let
exceptions from fetch_balance bubble up.
Review: PR #12502 (AgentBroker crypto trading blocks)New integration blocks for a crypto trading service. Concerns
Verdict: Needs changes -- item 1 (API key security) is blocking. |
|
closing for now due to unsigned cla :) feel free to reopen when signed :) |
Adds 4 blocks for trading crypto on AgentBroker (Jupiter DEX/Solana). No KYC required. Supports market/limit orders, price data, OHLCV candles. API: https://agentbroker.polsia.app
Changes
New file:
autogpt_platform/backend/backend/blocks/agentbroker.pyAdds 4 new blocks:
About AgentBroker
AgentBroker is a crypto exchange built specifically for AI agents:
Checklist
Blockbase class patternSchemaFieldapi_keyfield