From e701f41e668f0490b0aad26d416b9ea4d369160a Mon Sep 17 00:00:00 2001 From: Zamil Majdy Date: Fri, 20 Jun 2025 13:56:53 -0700 Subject: [PATCH] feat(blocks): Enabling auto type conversion on block input schema mismatch for nested input (#10203) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Since auto conversion is applied before merging nested input in the block, it breaks the auto conversion break. ### Changes 🏗️ * Enabling auto-type conversion on block input schema mismatch for nested input * Add batching feature for `CreateListBlock` * Increase default max_token size for LLM call ### 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: - [x] Run `AIStructuredResponseGeneratorBlock` with non-string prompt value (should be auto-converted). --- autogpt_platform/backend/backend/blocks/basic.py | 10 ++++++++-- autogpt_platform/backend/backend/blocks/llm.py | 4 ++-- autogpt_platform/backend/backend/executor/utils.py | 12 ++++++------ 3 files changed, 16 insertions(+), 10 deletions(-) diff --git a/autogpt_platform/backend/backend/blocks/basic.py b/autogpt_platform/backend/backend/blocks/basic.py index 63906a13d9..7e52e70f12 100644 --- a/autogpt_platform/backend/backend/blocks/basic.py +++ b/autogpt_platform/backend/backend/blocks/basic.py @@ -456,6 +456,11 @@ class CreateListBlock(Block): description="A list of values to be combined into a new list.", placeholder="e.g., ['Alice', 25, True]", ) + max_size: int | None = SchemaField( + default=None, + description="Maximum size of the list. If provided, the list will be yielded in chunks of this size.", + advanced=True, + ) class Output(BlockSchema): list: List[Any] = SchemaField( @@ -492,8 +497,9 @@ class CreateListBlock(Block): async def run(self, input_data: Input, **kwargs) -> BlockOutput: try: - # The values are already validated by Pydantic schema - yield "list", input_data.values + max_size = input_data.max_size or len(input_data.values) + for i in range(0, len(input_data.values), max_size): + yield "list", input_data.values[i : i + max_size] except Exception as e: yield "error", f"Failed to create list: {str(e)}" diff --git a/autogpt_platform/backend/backend/blocks/llm.py b/autogpt_platform/backend/backend/blocks/llm.py index 20a4626678..5230cb4428 100644 --- a/autogpt_platform/backend/backend/blocks/llm.py +++ b/autogpt_platform/backend/backend/blocks/llm.py @@ -348,10 +348,10 @@ async def llm_call( # Calculate available tokens based on context window and input length estimated_input_tokens = estimate_token_count(prompt) context_window = llm_model.context_window - model_max_output = llm_model.max_output_tokens or 4096 + model_max_output = llm_model.max_output_tokens or int(2**15) user_max = max_tokens or model_max_output available_tokens = max(context_window - estimated_input_tokens, 0) - max_tokens = max(min(available_tokens, model_max_output, user_max), 0) + max_tokens = max(min(available_tokens, model_max_output, user_max), 1) if provider == "openai": tools_param = tools if tools else openai.NOT_GIVEN diff --git a/autogpt_platform/backend/backend/executor/utils.py b/autogpt_platform/backend/backend/executor/utils.py index 82f1659169..4ef18d509f 100644 --- a/autogpt_platform/backend/backend/executor/utils.py +++ b/autogpt_platform/backend/backend/executor/utils.py @@ -402,12 +402,6 @@ def validate_exec( return None, f"Block for {node.block_id} not found." schema = node_block.input_schema - # Convert non-matching data types to the expected input schema. - for name, data_type in schema.__annotations__.items(): - value = data.get(name) - if (value is not None) and (type(value) is not data_type): - data[name] = convert(value, data_type) - # Input data (without default values) should contain all required fields. error_prefix = f"Input data missing or mismatch for `{node_block.name}`:" if missing_links := schema.get_missing_links(data, node.input_links): @@ -419,6 +413,12 @@ def validate_exec( if resolve_input: data = merge_execution_input(data) + # Convert non-matching data types to the expected input schema. + for name, data_type in schema.__annotations__.items(): + value = data.get(name) + if (value is not None) and (type(value) is not data_type): + data[name] = convert(value, data_type) + # Input data post-merge should contain all required fields from the schema. if missing_input := schema.get_missing_input(data): return None, f"{error_prefix} missing input {missing_input}"