mirror of
https://github.com/Significant-Gravitas/AutoGPT.git
synced 2026-04-08 03:00:28 -04:00
I'm getting circular import issues because there is a lot of cross-importing between `backend.data`, `backend.blocks`, and other modules. This change reduces block-related cross-imports and thus risk of breaking circular imports. ### Changes 🏗️ - Strip down `backend.data.block` - Move `Block` base class and related class/enum defs to `backend.blocks._base` - Move `is_block_auth_configured` to `backend.blocks._utils` - Move `get_blocks()`, `get_io_block_ids()` etc. to `backend.blocks` (`__init__.py`) - Update imports everywhere - Remove unused and poorly typed `Block.create()` - Change usages from `block_cls.create()` to `block_cls()` - Improve typing of `load_all_blocks` and `get_blocks` - Move cross-import of `backend.api.features.library.model` from `backend/data/__init__.py` to `backend/data/integrations.py` - Remove deprecated attribute `NodeModel.webhook` - Re-generate OpenAPI spec and fix frontend usage - Eliminate module-level `backend.blocks` import from `blocks/agent.py` - Eliminate module-level `backend.data.execution` and `backend.executor.manager` imports from `blocks/helpers/review.py` - Replace `BlockInput` with `GraphInput` for graph inputs ### Checklist 📋 #### For code changes: - [x] I have clearly listed my changes in the PR description - [x] I have made a test plan - [x] I have tested my changes according to the test plan: - CI static type-checking + tests should be sufficient for this
103 lines
3.7 KiB
Python
103 lines
3.7 KiB
Python
from typing import Any
|
|
|
|
from backend.blocks._base import (
|
|
Block,
|
|
BlockCategory,
|
|
BlockOutput,
|
|
BlockSchemaInput,
|
|
BlockSchemaOutput,
|
|
)
|
|
from backend.data.model import SchemaField
|
|
from backend.util.json import loads
|
|
|
|
|
|
class StepThroughItemsBlock(Block):
|
|
class Input(BlockSchemaInput):
|
|
items: list = SchemaField(
|
|
advanced=False,
|
|
description="The list or dictionary of items to iterate over",
|
|
placeholder="[1, 2, 3, 4, 5] or {'key1': 'value1', 'key2': 'value2'}",
|
|
default_factory=list,
|
|
)
|
|
items_object: dict = SchemaField(
|
|
advanced=False,
|
|
description="The list or dictionary of items to iterate over",
|
|
placeholder="[1, 2, 3, 4, 5] or {'key1': 'value1', 'key2': 'value2'}",
|
|
default_factory=dict,
|
|
)
|
|
items_str: str = SchemaField(
|
|
advanced=False,
|
|
description="The list or dictionary of items to iterate over",
|
|
placeholder="[1, 2, 3, 4, 5] or {'key1': 'value1', 'key2': 'value2'}",
|
|
default="",
|
|
)
|
|
|
|
class Output(BlockSchemaOutput):
|
|
item: Any = SchemaField(description="The current item in the iteration")
|
|
key: Any = SchemaField(
|
|
description="The key or index of the current item in the iteration",
|
|
)
|
|
|
|
def __init__(self):
|
|
super().__init__(
|
|
id="f66a3543-28d3-4ab5-8945-9b336371e2ce",
|
|
input_schema=StepThroughItemsBlock.Input,
|
|
output_schema=StepThroughItemsBlock.Output,
|
|
categories={BlockCategory.LOGIC},
|
|
description="Iterates over a list or dictionary and outputs each item.",
|
|
test_input={"items": [1, 2, 3, {"key1": "value1", "key2": "value2"}]},
|
|
test_output=[
|
|
("item", 1),
|
|
("key", 0),
|
|
("item", 2),
|
|
("key", 1),
|
|
("item", 3),
|
|
("key", 2),
|
|
("item", {"key1": "value1", "key2": "value2"}),
|
|
("key", 3),
|
|
],
|
|
test_mock={},
|
|
)
|
|
|
|
async def run(self, input_data: Input, **kwargs) -> BlockOutput:
|
|
# Security fix: Add limits to prevent DoS from large iterations
|
|
MAX_ITEMS = 10000 # Maximum items to iterate
|
|
MAX_ITEM_SIZE = 1024 * 1024 # 1MB per item
|
|
|
|
for data in [input_data.items, input_data.items_object, input_data.items_str]:
|
|
if not data:
|
|
continue
|
|
|
|
# Limit string size before parsing
|
|
if isinstance(data, str):
|
|
if len(data) > MAX_ITEM_SIZE:
|
|
raise ValueError(
|
|
f"Input too large: {len(data)} bytes > {MAX_ITEM_SIZE} bytes"
|
|
)
|
|
items = loads(data)
|
|
else:
|
|
items = data
|
|
|
|
# Check total item count
|
|
if isinstance(items, (list, dict)):
|
|
if len(items) > MAX_ITEMS:
|
|
raise ValueError(f"Too many items: {len(items)} > {MAX_ITEMS}")
|
|
|
|
iteration_count = 0
|
|
if isinstance(items, dict):
|
|
# If items is a dictionary, iterate over its values
|
|
for key, value in items.items():
|
|
if iteration_count >= MAX_ITEMS:
|
|
break
|
|
yield "item", value
|
|
yield "key", key # Fixed: should yield key, not item
|
|
iteration_count += 1
|
|
else:
|
|
# If items is a list, iterate over the list
|
|
for index, item in enumerate(items):
|
|
if iteration_count >= MAX_ITEMS:
|
|
break
|
|
yield "item", item
|
|
yield "key", index
|
|
iteration_count += 1
|