Skip to content

feat: Adding the new Create Data component#9523

Closed
Empreiteiro wants to merge 10 commits into
langflow-ai:mainfrom
Empreiteiro:Empreiteiro-Create-Data
Closed

feat: Adding the new Create Data component#9523
Empreiteiro wants to merge 10 commits into
langflow-ai:mainfrom
Empreiteiro:Empreiteiro-Create-Data

Conversation

@Empreiteiro
Copy link
Copy Markdown
Collaborator

@Empreiteiro Empreiteiro commented Aug 25, 2025

Create Data Component - Dynamic Form Builder

Overview

A powerful dynamic form component that creates customizable input fields at runtime based on a table configuration. 
This component allows users to build flexible data collection forms that can receive input from other components 
or manual entry, making it ideal for dynamic API parameter collection, multi-source data aggregation, and 
flexible pipeline configuration.

Key Features

- **Dynamic Input Generation**: Creates input fields on-the-fly based on table configuration
- **Component Connectivity**: Inputs can connect to outputs from other components (Text, Data, Message, Number, Boolean)
- **Multiple Input Types**: Supports Text, Data, Number, Handle, and Boolean field types
- **Flexible Data Sources**: Accepts both manual input and component connections
- **Real-time Updates**: Form fields update immediately when table configuration changes
- **Dual Output Formats**: Provides both structured Data output and formatted Message output
- **Connection Tracking**: Monitors which fields are connected vs. manually filled

How It Works

1. **Configuration**: Users define form fields in a table with "Field Name" and "Field Type"
2. **Dynamic Generation**: The component automatically creates appropriate input fields based on the configuration
3. **Data Collection**: Fields can receive data from connected components or manual input
4. **Processing**: All field values are collected and returned as structured data or formatted messages

Field Type Mappings

- **Text** → MultilineInput (connects to Text, Message)
- **Data** → HandleInput (connects to Data)
- **Number** → IntInput (connects to Text, Message)
- **Handle** → HandleInput (connects to Text, Data, Message)
- **Boolean** → BoolInput (connects to any type)

Use Cases

- Dynamic API parameter collection from multiple sources
- Variable data aggregation from different components
- Flexible pipeline configuration
- Multi-source data processing
- Form-based data collection workflows

Outputs

- **Data Output**: Clean JSON structure with field name-value pairs
- **Message Output**: Formatted text display of all collected data

Summary by CodeRabbit

  • New Features

    • Conditional Router: added “is blank” and “is not blank” operators with UI that hides irrelevant options.
    • Data Operations: added JSON tools—Mapped JSON (path extraction) and jQuery (jq queries); new inputs for JSON mapping/querying; recursive remove/rename keys.
    • Create Data: new dynamic form component to build fields on the fly and output structured Data or Message.
  • Improvements

    • Router: refined case-sensitivity behavior.
    • Data Operations: normalized data handling, automatic key-path option population from JSON, and clearer error messages/logging.

Empreiteiro and others added 8 commits August 4, 2025 13:51
This PR enhances the DataOperationsComponent by introducing two new powerful operations:

JSON Path: Allows extracting values from nested JSON structures using path expressions, enabling more flexible data selection.

JSON Query: Integrates jq to support advanced JSON queries, including filters, projections, and transformations.

Additional improvements:

Input handling and validations for both new operations.

Enhanced error messages and logs for better debugging.

Extended UI field visibility logic in update_build_config to support dynamic path selection from JSON.

These updates significantly expand the component's capabilities for parsing, transforming, and querying structured JSON data.
feat: Adding new operations to the Data Operations component
This update extends the conditional_router.py logic by introducing two new operators:

is blank: Evaluates to true when the target value is None, an empty string, or whitespace only.

is not blank: Evaluates to true when the target value contains any non-whitespace characters.

These operators enhance conditional routing by enabling checks for empty or missing values, improving flow control in scenarios where data presence or absence must be validated.
@Empreiteiro Empreiteiro self-assigned this Aug 25, 2025
@Empreiteiro Empreiteiro added the feature New features and enhancements label Aug 25, 2025
@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented Aug 25, 2025

Important

Review skipped

Auto incremental reviews are disabled on this repository.

Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Walkthrough

Adds two operators (“is blank”, “is not blank”) to ConditionalRouterComponent with corresponding evaluation and build-config updates. Extends DataOperationsComponent with JSON path and jq query capabilities, recursive key ops, UI inputs, and build-time path extraction. Introduces a new dynamic form component (CrateData) that generates inputs from table-config and outputs collected Data/Message.

Changes

Cohort / File(s) Summary of Changes
Conditional Router Operators
src/backend/base/langflow/components/logic/conditional_router.py
Added “is blank”/“is not blank” operators; adjusted case handling; evaluation for blank/non-blank; build-config hides case_sensitive/match_text where applicable; operator list updated.
Data Operations JSON & Recursion
src/backend/base/langflow/components/processing/data_operations.py
Added actions “Mapped JSON” and “jQuery”; new inputs (mapped_json_display, selected_key, query); jq-based json_query/json_path with repair_json; recursive helpers (extract_all_paths, remove_keys_recursive, rename_keys_recursive); normalized data handling; build-config populates JSON paths; updated dispatch and metadata.
Dynamic Form Component
src/backend/base/langflow/components/processing/new_create_data.py
New CrateData component; dynamically generates inputs from form_fields; collects/normalizes values; exposes Data (process_form) and Message (get_message); tracks connection info; build-config creates dynamic_* inputs per field.

Sequence Diagram(s)

sequenceDiagram
  autonumber
  actor User
  participant Router as ConditionalRouterComponent
  participant Downstream as Targets

  User->>Router: input_text, operator, match_text, case_sensitive
  alt operator == "is blank"
    Router->>Router: check empty/whitespace
  else operator == "is not blank"
    Router->>Router: check any non-whitespace
  else other operators
    Router->>Router: evaluate per existing logic
  end
  Router-->>Downstream: route based on evaluation result
  note over Router: Build-config hides case_sensitive/match_text for\nregex/blank operators where applicable
Loading
sequenceDiagram
  autonumber
  actor User
  participant Comp as DataOperationsComponent
  participant jq as jq/repair_json

  User->>Comp: action="Mapped JSON", mapped_json_display, selected_key
  Comp->>Comp: update_build_config: parse JSON, extract_all_paths
  Comp->>jq: json_path via jq on normalized data
  jq-->>Comp: path result
  Comp-->>User: Data(result)

  User->>Comp: action="jQuery", query
  Comp->>jq: repair_json + jq(query)
  jq-->>Comp: query result/error
  Comp-->>User: Data(result) or error
Loading
sequenceDiagram
  autonumber
  actor User
  participant Crate as CrateData
  participant UI as Builder

  User->>Crate: form_fields (table)
  Crate->>Crate: update_build_config: create dynamic_* inputs
  UI-->>User: Renders dynamic inputs
  User->>Crate: provide values / connect handles
  Crate->>Crate: get_dynamic_values (normalize, track connections)
  User->>Crate: run process_form
  Crate-->>User: Data(form_data)
  User->>Crate: run get_message
  Crate-->>User: Message(summary)
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60 minutes

Possibly related PRs

Suggested labels

enhancement, size:L, lgtm

Suggested reviewers

  • ogabrielluiz
  • edwinjosechittilappilly
✨ Finishing Touches
🧪 Generate unit tests
  • Create PR with unit tests
  • Post copyable unit tests in a comment

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

❤️ Share
🪧 Tips

Chat

There are 3 ways to chat with CodeRabbit:

  • Review comments: Directly reply to a review comment made by CodeRabbit. Example:
    • I pushed a fix in commit <commit_id>, please review it.
    • Open a follow-up GitHub issue for this discussion.
  • Files and specific lines of code (under the "Files changed" tab): Tag @coderabbitai in a new review comment at the desired location with your query.
  • PR comments: Tag @coderabbitai in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
    • @coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.

Support

Need help? Create a ticket on our support page for assistance with any issues or questions.

CodeRabbit Commands (Invoked using PR/Issue comments)

Type @coderabbitai help to get the list of available commands.

Other keywords and placeholders

  • Add @coderabbitai ignore anywhere in the PR description to prevent this PR from being reviewed.
  • Add @coderabbitai summary to generate the high-level summary at a specific location in the PR description.
  • Add @coderabbitai anywhere in the PR title to generate the title automatically.

Status, Documentation and Community

  • Visit our Status Page to check the current availability of CodeRabbit.
  • Visit our Documentation for detailed information on how to use CodeRabbit.
  • Join our Discord Community to get help, request features, and share feedback.
  • Follow us on X/Twitter for updates and announcements.

@github-actions github-actions Bot added the enhancement New feature or request label Aug 25, 2025
@github-actions github-actions Bot added enhancement New feature or request and removed enhancement New feature or request labels Aug 25, 2025
@Empreiteiro Empreiteiro deleted the Empreiteiro-Create-Data branch August 25, 2025 18:55
@github-actions github-actions Bot added enhancement New feature or request and removed enhancement New feature or request labels Aug 25, 2025
@sonarqubecloud
Copy link
Copy Markdown

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 5

🧹 Nitpick comments (11)
src/backend/base/langflow/components/logic/conditional_router.py (3)

98-101: Case-folding exemption is reasonable, but reconsider regex behavior

Excluding "regex", "is blank", and "is not blank" from automatic lowercasing is correct. However, hiding case sensitivity for regex (see Lines 169-171) removes the ability to run case-insensitive patterns. If case-insensitive regex is desired, consider honoring case_sensitive for regex by applying re.IGNORECASE.

Apply both changes below together if you want to support case-insensitive regex:

-        if not case_sensitive and operator not in ["regex", "is blank", "is not blank"]:
+        if not case_sensitive and operator not in ["regex", "is blank", "is not blank"]:
             input_text = input_text.lower()
             match_text = match_text.lower()
 ...
-        if operator == "regex":
+        if operator == "regex":
             try:
-                return bool(re.match(match_text, input_text))
+                flags = 0 if case_sensitive else re.IGNORECASE
+                return bool(re.compile(match_text, flags).search(input_text))
             except re.error:
                 return False  # Return False if the regex is invalid

And in update_build_config:

-            # Hide case_sensitive for regex and blank operators
-            if field_value in ["regex", "is blank", "is not blank"]:
+            # Hide case_sensitive for blank operators
+            if field_value in ["is blank", "is not blank"]:
                 build_config.pop("case_sensitive", None)

117-121: Blank checks are correct; can be simplified

The semantics are right and handle None safely. Minor nit: you can simplify with not input_text or not input_text.strip() and bool(input_text and input_text.strip()).

-        if operator == "is blank":
-            return not input_text or input_text.strip() == ""
-        if operator == "is not blank":
-            return bool(input_text and input_text.strip() != "")
+        if operator == "is blank":
+            return not input_text or not input_text.strip()
+        if operator == "is not blank":
+            return bool(input_text and input_text.strip())

169-188: Prefer toggling visibility over popping inputs from build_config

Popping inputs removes configuration and can lead to jittery UI or loss of state. Toggle show=False/True instead to preserve previous values and metadata, mirroring patterns used elsewhere.

-            # Hide case_sensitive for regex and blank operators
-            if field_value in ["regex", "is blank", "is not blank"]:
-                build_config.pop("case_sensitive", None)
+            # Hide case_sensitive for blank operators
+            if field_value in ["is blank", "is not blank"]:
+                if "case_sensitive" in build_config:
+                    build_config["case_sensitive"]["show"] = False
             elif "case_sensitive" not in build_config:
                 case_sensitive_input = next(
                     (input_field for input_field in self.inputs if input_field.name == "case_sensitive"), None
                 )
                 if case_sensitive_input:
-                    build_config["case_sensitive"] = case_sensitive_input.to_dict()
+                    build_config["case_sensitive"] = case_sensitive_input.to_dict()
+                    build_config["case_sensitive"]["show"] = True
@@
-            # Hide match_text for blank operators
-            if field_value in ["is blank", "is not blank"]:
-                build_config.pop("match_text", None)
+            # Hide match_text for blank operators
+            if field_value in ["is blank", "is not blank"]:
+                if "match_text" in build_config:
+                    build_config["match_text"]["show"] = False
             elif "match_text" not in build_config:
                 match_text_input = next(
                     (input_field for input_field in self.inputs if input_field.name == "match_text"), None
                 )
                 if match_text_input:
-                    build_config["match_text"] = match_text_input.to_dict()
+                    build_config["match_text"] = match_text_input.to_dict()
+                    build_config["match_text"]["show"] = True
src/backend/base/langflow/components/processing/new_create_data.py (3)

136-147: Boolean connectivity and Number connectivity may not behave as described

  • PR objective states Boolean connects to any type; here BoolInput is created with input_types=[] (and a comment to avoid errors), effectively disabling connections.
  • Mapping “Number” to IntInput with input_types=["Text","Message"] might not validate at runtime, since IntInput’s validator expects numeric types.

Proposed changes:

  • Omit input_types for BoolInput to allow default behavior.
  • Consider using Str/Message input for numeric, then cast in process_form, or ensure the framework coerces Message/Text-to-number before IntInput validation.
-                    build_config[dynamic_input_name] = BoolInput(
+                    build_config[dynamic_input_name] = BoolInput(
                         name=dynamic_input_name,
                         display_name=display_name,
                         info=help_text,
                         value=default_bool,
-                        input_types=[],
                         required=required,
                     )

If you confirm IntInput accepts Message/Text inputs in this project (via automatic extraction from connected components), no action needed for “Number.” Otherwise, switch Number to MultilineInput with input_types=["Text","Message"] and parse to int in process_form.

Also applies to: 237-248


357-371: Honor include_metadata in output

You expose include_metadata but don’t use it. Include connection info when requested.

-        # Return clean Data object with just the field values
-        return Data(data=dynamic_values)
+        # Return Data; optionally include metadata
+        if self.include_metadata:
+            return Data(data={"values": dynamic_values, "connections": getattr(self, "_connection_info", {})})
+        return Data(data=dynamic_values)

1-9: Minor: unused imports / tighten typing

SecretStrInput, json, and List are unused.

-from langflow.io import StrInput, IntInput, BoolInput, MultilineInput, TableInput, Output, SecretStrInput, FloatInput, HandleInput
+from langflow.io import StrInput, IntInput, BoolInput, MultilineInput, TableInput, Output, FloatInput, HandleInput
@@
-from typing import Any, Dict, List
-import json
+from typing import Any, Dict
src/backend/base/langflow/components/processing/data_operations.py (5)

81-93: Path extraction utility — LGTM with a tiny style nit

Logic is correct and jq-friendly (“.a.b[0]”). The over-indentation under the list branch is harmless but will be auto-fixed by formatting.


282-285: Duplicate method definition: remove the first operation_exception

operation_exception is defined twice; keep a single definition to avoid confusion.

-    def operation_exception(self, operations: list[str]) -> None:
-        msg = f"{operations} operations are not supported in combination with each other."
-        raise ValueError(msg)
-

427-432: Duplicate method definition: remove the second compare_values

compare_values also appears earlier (Lines 398-404). Remove the duplicated one.

-    def compare_values(self, item_value: Any, filter_value: str, operator: str) -> bool:
-        comparison_func = OPERATORS.get(operator)
-        if comparison_func:
-            return comparison_func(item_value, filter_value)
-        return False

201-227: Clarify UI copy: “jQuery” input description

The info says “Used by Parse JSON operation,” but the action is called “jQuery” and you use jq. Update the text to match.

         MessageTextInput(
             name="query",
             display_name="jQuery",
-            info="JSON Query to filter the data. Used by Parse JSON operation.",
+            info="JQ query to filter the data (powered by jq). Used by the jQuery operation.",
             placeholder=".properties.hs_object_id",
             show=False,
         ),

493-508: json_path robustness: prefer normalized data and ensure jq import

Given jq is now imported, consider using get_normalized_data() so users can pass either Data with nested data or a flat dict. Current approach uses .data only.

-            input_payload = self.data[0].data if isinstance(self.data, list) else self.data.data
+            input_payload = self.get_normalized_data()
📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

💡 Knowledge Base configuration:

  • MCP integration is disabled by default for public repositories
  • Jira integration is disabled by default for public repositories
  • Linear integration is disabled by default for public repositories

You can enable these sources in your CodeRabbit configuration.

📥 Commits

Reviewing files that changed from the base of the PR and between ae274a3 and 9573da9.

📒 Files selected for processing (3)
  • src/backend/base/langflow/components/logic/conditional_router.py (4 hunks)
  • src/backend/base/langflow/components/processing/data_operations.py (14 hunks)
  • src/backend/base/langflow/components/processing/new_create_data.py (1 hunks)
🧰 Additional context used
📓 Path-based instructions (3)
src/backend/base/langflow/components/**/*.py

📄 CodeRabbit inference engine (.cursor/rules/backend_development.mdc)

src/backend/base/langflow/components/**/*.py: Add new backend components to the appropriate subdirectory under src/backend/base/langflow/components/
Implement async component methods using async def and await for asynchronous operations
Use asyncio.create_task for background work in async components and ensure proper cleanup on cancellation
Use asyncio.Queue for non-blocking queue operations in async components and handle timeouts appropriately

Files:

  • src/backend/base/langflow/components/processing/new_create_data.py
  • src/backend/base/langflow/components/logic/conditional_router.py
  • src/backend/base/langflow/components/processing/data_operations.py
{src/backend/**/*.py,tests/**/*.py,Makefile}

📄 CodeRabbit inference engine (.cursor/rules/backend_development.mdc)

{src/backend/**/*.py,tests/**/*.py,Makefile}: Run make format_backend to format Python code before linting or committing changes
Run make lint to perform linting checks on backend Python code

Files:

  • src/backend/base/langflow/components/processing/new_create_data.py
  • src/backend/base/langflow/components/logic/conditional_router.py
  • src/backend/base/langflow/components/processing/data_operations.py
src/backend/**/components/**/*.py

📄 CodeRabbit inference engine (.cursor/rules/icons.mdc)

In your Python component class, set the icon attribute to a string matching the frontend icon mapping exactly (case-sensitive).

Files:

  • src/backend/base/langflow/components/processing/new_create_data.py
  • src/backend/base/langflow/components/logic/conditional_router.py
  • src/backend/base/langflow/components/processing/data_operations.py
🧬 Code graph analysis (2)
src/backend/base/langflow/components/processing/new_create_data.py (3)
src/backend/base/langflow/inputs/inputs.py (7)
  • StrInput (128-184)
  • IntInput (343-375)
  • MultilineInput (259-269)
  • TableInput (38-73)
  • SecretStrInput (285-340)
  • FloatInput (378-410)
  • HandleInput (76-87)
src/backend/base/langflow/schema/message.py (2)
  • Message (39-288)
  • json (299-301)
src/backend/base/langflow/schema/data.py (1)
  • Data (23-285)
src/backend/base/langflow/components/processing/data_operations.py (3)
src/backend/base/langflow/inputs/inputs.py (5)
  • DictInput (449-464)
  • DropdownInput (467-491)
  • MessageTextInput (205-256)
  • SortableListInput (535-545)
  • MultilineInput (259-269)
src/backend/base/langflow/schema/data.py (1)
  • Data (23-285)
src/backend/base/langflow/utils/component_utils.py (2)
  • set_current_fields (119-147)
  • set_field_display (56-60)
⏰ 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). (3)
  • GitHub Check: Update Starter Projects
  • GitHub Check: Run Ruff Check and Format
  • GitHub Check: Ruff Style Check (3.13)
🔇 Additional comments (3)
src/backend/base/langflow/components/logic/conditional_router.py (1)

40-42: New operators added — LGTM

Adding "is blank" and "is not blank" to the operator list is consistent with the component’s purpose and improves UX. No concerns.

src/backend/base/langflow/components/processing/data_operations.py (2)

239-266: JSON Query path — solid, with good error messaging

The repair, unwrap, jq compile, and result handling are sensible. Nice logging. No change requested.


471-481: Operations update and mapped JSON parsing — LGTM after missing imports fix

The field toggling and dynamic options population look good. With the added import json, this path should work as intended.

Also applies to: 481-490

Comment on lines 1 to 7
import ast
from typing import TYPE_CHECKING, Any
from json_repair import repair_json

from langflow.custom import Component
from langflow.inputs import DictInput, DropdownInput, MessageTextInput, SortableListInput
from langflow.inputs import DictInput, DropdownInput, MessageTextInput, SortableListInput, MultilineInput
from langflow.io import DataInput, Output
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue

Missing imports used later

update_build_config uses json, and json_path uses jq, but they are not imported at module level, causing NameError at runtime.

 import ast
-from typing import TYPE_CHECKING, Any
-from json_repair import repair_json
+from typing import TYPE_CHECKING, Any
+import json
+import jq
+from json_repair import repair_json
📝 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.

Suggested change
import ast
from typing import TYPE_CHECKING, Any
from json_repair import repair_json
from langflow.custom import Component
from langflow.inputs import DictInput, DropdownInput, MessageTextInput, SortableListInput
from langflow.inputs import DictInput, DropdownInput, MessageTextInput, SortableListInput, MultilineInput
from langflow.io import DataInput, Output
import ast
from typing import TYPE_CHECKING, Any
import json
import jq
from json_repair import repair_json
from langflow.custom import Component
from langflow.inputs import DictInput, DropdownInput, MessageTextInput, SortableListInput, MultilineInput
from langflow.io import DataInput, Output
🤖 Prompt for AI Agents
In src/backend/base/langflow/components/processing/data_operations.py around
lines 1 to 7, the functions update_build_config and json_path reference json and
jq but those modules are not imported, causing NameError; add module-level
imports for json and jq at the top of the file (alongside existing imports) so
json and jq are available to the functions when called.

Comment on lines +10 to +16
class CrateData(Component):
"""
Dynamic Form Component

This component creates dynamic inputs that can receive data from other components
or be filled manually. It demonstrates advanced dynamic input functionality with
component connectivity.
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue

Typo: class name should match “Create Data”; internal name should be consistent

Public surface and PR title say “Create Data,” but the class is CrateData and name is AdvancedDynamicFormBuilder. This will confuse users and break search/discovery.

-class CrateData(Component):
+class CreateData(Component):
@@
-    name = "AdvancedDynamicFormBuilder"
+    name = "CreateData"

Also applies to: 52-56

🤖 Prompt for AI Agents
In src/backend/base/langflow/components/processing/new_create_data.py around
lines 10-16 (and also fix lines 52-56), the class is misspelled as CrateData and
its internal name is AdvancedDynamicFormBuilder which contradicts the PR title
"Create Data"; rename the class to CreateData and update the internal
name/display name to "Create Data" (or a consistent identifier like CreateData)
at lines 52-56, and search/replace any local references in this file to preserve
behavior and imports so consumers and discovery match the public surface.

Comment on lines +66 to +81
table_schema=[
{
"name": "field_name",
"display_name": "Field Name",
"type": "str",
"description": "Name for the field (used as both internal name and display label)"
},
{
"name": "field_type",
"display_name": "Field Type",
"type": "str",
"description": "Type of input field to create",
"options": ["Text", "Data", "Number", "Handle", "Boolean"],
"value": "Text"
}
],
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Expose Float in the table options (docstring and mapping already support it)

UI schema omits “Float”, making the float branch unreachable despite support in code and docs.

-                    "options": ["Text", "Data", "Number", "Handle", "Boolean"],
+                    "options": ["Text", "Data", "Number", "Float", "Handle", "Boolean"],
📝 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.

Suggested change
table_schema=[
{
"name": "field_name",
"display_name": "Field Name",
"type": "str",
"description": "Name for the field (used as both internal name and display label)"
},
{
"name": "field_type",
"display_name": "Field Type",
"type": "str",
"description": "Type of input field to create",
"options": ["Text", "Data", "Number", "Handle", "Boolean"],
"value": "Text"
}
],
table_schema=[
{
"name": "field_name",
"display_name": "Field Name",
"type": "str",
"description": "Name for the field (used as both internal name and display label)"
},
{
"name": "field_type",
"display_name": "Field Type",
"type": "str",
"description": "Type of input field to create",
"options": ["Text", "Data", "Number", "Float", "Handle", "Boolean"],
"value": "Text"
}
],
🤖 Prompt for AI Agents
In src/backend/base/langflow/components/processing/new_create_data.py around
lines 66 to 81, the UI schema's field_type options omit "Float" which prevents
the float branch from being reachable; add "Float" to the options array (e.g.,
["Text", "Data", "Number", "Float", "Handle", "Boolean"]) and keep the default
value as "Text" so the float option is selectable from the UI.

Comment on lines +123 to +151
for i, field_config in enumerate(field_value):
# Safety check to ensure field_config is not None
if field_config is None:
continue

field_name = field_config.get("field_name", f"field_{i}")
display_name = field_name # Use field_name as display_name
field_type_option = field_config.get("field_type", "Text")
default_value = "" # All fields have empty default value
required = False # All fields are optional by default
help_text = "" # All fields have empty help text

# Map field type options to actual field types and input types
field_type_mapping = {
"Text": {"field_type": "multiline", "input_types": ["Text", "Message"]},
"Data": {"field_type": "data", "input_types": ["Data"]},
"Number": {"field_type": "number", "input_types": ["Text", "Message"]},
"Handle": {"field_type": "handle", "input_types": ["Text", "Data", "Message"]},
"Boolean": {"field_type": "boolean", "input_types": None}
}

field_config_mapped = field_type_mapping.get(field_type_option, {"field_type": "text", "input_types": []})
field_type = field_config_mapped["field_type"]
input_types_list = field_config_mapped["input_types"]

# Create the appropriate input type based on field_type
dynamic_input_name = f"dynamic_{field_name}"

if field_type == "text":
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Sanitize dynamic field names to safe identifiers and avoid collisions

Using raw field_name in dynamic_{field_name} risks spaces/special chars and duplicates. Normalize and de-duplicate for robust attribute access.

-                field_name = field_config.get("field_name", f"field_{i}")
+                raw_field_name = field_config.get("field_name", f"field_{i}")
+                # allow [a-zA-Z0-9_], collapse whitespace, ensure uniqueness
+                import re
+                safe = re.sub(r"\W+", "_", str(raw_field_name)).strip("_") or f"field_{i}"
+                field_name = f"{safe}_{i}" if safe in (name.split("dynamic_")[-1] for name in build_config.keys()) else safe
📝 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.

Suggested change
for i, field_config in enumerate(field_value):
# Safety check to ensure field_config is not None
if field_config is None:
continue
field_name = field_config.get("field_name", f"field_{i}")
display_name = field_name # Use field_name as display_name
field_type_option = field_config.get("field_type", "Text")
default_value = "" # All fields have empty default value
required = False # All fields are optional by default
help_text = "" # All fields have empty help text
# Map field type options to actual field types and input types
field_type_mapping = {
"Text": {"field_type": "multiline", "input_types": ["Text", "Message"]},
"Data": {"field_type": "data", "input_types": ["Data"]},
"Number": {"field_type": "number", "input_types": ["Text", "Message"]},
"Handle": {"field_type": "handle", "input_types": ["Text", "Data", "Message"]},
"Boolean": {"field_type": "boolean", "input_types": None}
}
field_config_mapped = field_type_mapping.get(field_type_option, {"field_type": "text", "input_types": []})
field_type = field_config_mapped["field_type"]
input_types_list = field_config_mapped["input_types"]
# Create the appropriate input type based on field_type
dynamic_input_name = f"dynamic_{field_name}"
if field_type == "text":
for i, field_config in enumerate(field_value):
# Safety check to ensure field_config is not None
if field_config is None:
continue
raw_field_name = field_config.get("field_name", f"field_{i}")
# allow [a-zA-Z0-9_], collapse whitespace, ensure uniqueness
import re
safe = re.sub(r"\W+", "_", str(raw_field_name)).strip("_") or f"field_{i}"
field_name = (
f"{safe}_{i}"
if safe in (name.split("dynamic_")[-1] for name in build_config.keys())
else safe
)
display_name = field_name # Use field_name as display_name
field_type_option = field_config.get("field_type", "Text")
default_value = "" # All fields have empty default value
required = False # All fields are optional by default
help_text = "" # All fields have empty help text
# Map field type options to actual field types and input types
field_type_mapping = {
"Text": {"field_type": "multiline", "input_types": ["Text", "Message"]},
"Data": {"field_type": "data", "input_types": ["Data"]},
"Number": {"field_type": "number", "input_types": ["Text", "Message"]},
"Handle": {"field_type": "handle", "input_types": ["Text", "Data", "Message"]},
"Boolean": {"field_type": "boolean", "input_types": None}
}
field_config_mapped = field_type_mapping.get(
field_type_option,
{"field_type": "text", "input_types": []},
)
field_type = field_config_mapped["field_type"]
input_types_list = field_config_mapped["input_types"]
# Create the appropriate input type based on field_type
dynamic_input_name = f"dynamic_{field_name}"
if field_type == "text":
🤖 Prompt for AI Agents
In src/backend/base/langflow/components/processing/new_create_data.py around
lines 123 to 151, dynamic field names are generated as f"dynamic_{field_name}"
which can include spaces/special characters and can collide; sanitize and
de-duplicate names by: normalize field_name to a safe identifier (trim, lower,
replace non-alphanumeric characters with underscores, ensure it starts with a
letter or underscore), maintain a set/dict of used identifiers and if a
collision occurs append an incrementing suffix (e.g., _1, _2), and then use that
sanitized unique identifier to build dynamic_input_name; apply this logic before
creating inputs so all downstream attribute access uses the safe, unique name.

Comment on lines +151 to +279
if field_type == "text":
if input_types_list:
build_config[dynamic_input_name] = StrInput(
name=dynamic_input_name,
display_name=display_name,
info=f"{help_text} (Can connect to: {', '.join(input_types_list)})",
value=default_value,
required=required,
input_types=input_types_list,
)
else:
build_config[dynamic_input_name] = StrInput(
name=dynamic_input_name,
display_name=display_name,
info=help_text,
value=default_value,
required=required,
)

elif field_type == "multiline":
if input_types_list:
build_config[dynamic_input_name] = MultilineInput(
name=dynamic_input_name,
display_name=display_name,
info=f"{help_text} (Can connect to: {', '.join(input_types_list)})",
value=default_value,
required=required,
input_types=input_types_list,
)
else:
build_config[dynamic_input_name] = MultilineInput(
name=dynamic_input_name,
display_name=display_name,
info=help_text,
value=default_value,
required=required,
)

elif field_type == "number":
try:
default_int = int(default_value) if default_value else 0
except ValueError:
default_int = 0

if input_types_list:
build_config[dynamic_input_name] = IntInput(
name=dynamic_input_name,
display_name=display_name,
info=f"{help_text} (Can connect to: {', '.join(input_types_list)})",
value=default_int,
required=required,
input_types=input_types_list,
)
else:
build_config[dynamic_input_name] = IntInput(
name=dynamic_input_name,
display_name=display_name,
info=help_text,
value=default_int,
required=required,
)

elif field_type == "float":
try:
default_float = float(default_value) if default_value else 0.0
except ValueError:
default_float = 0.0

if input_types_list:
build_config[dynamic_input_name] = FloatInput(
name=dynamic_input_name,
display_name=display_name,
info=f"{help_text} (Can connect to: {', '.join(input_types_list)})",
value=default_float,
required=required,
input_types=input_types_list,
)
else:
build_config[dynamic_input_name] = FloatInput(
name=dynamic_input_name,
display_name=display_name,
info=help_text,
value=default_float,
required=required,
)

elif field_type == "boolean":
default_bool = default_value.lower() in ["true", "1", "yes"] if default_value else False

# Boolean fields don't use input_types parameter to avoid errors
build_config[dynamic_input_name] = BoolInput(
name=dynamic_input_name,
display_name=display_name,
info=help_text,
value=default_bool,
input_types=[],
required=required,
)

elif field_type == "handle":
# HandleInput for generic data connections
build_config[dynamic_input_name] = HandleInput(
name=dynamic_input_name,
display_name=display_name,
info=f"{help_text} (Accepts: {', '.join(input_types_list) if input_types_list else 'Any'})",
input_types=input_types_list if input_types_list else ["Data", "Text", "Message"],
required=required,
)

elif field_type == "data":
# Specialized for Data type connections
build_config[dynamic_input_name] = HandleInput(
name=dynamic_input_name,
display_name=display_name,
info=f"{help_text} (Data input)",
input_types=["Data"] if not input_types_list else input_types_list,
required=required,
)

else:
# Default to text input for unknown types
build_config[dynamic_input_name] = StrInput(
name=dynamic_input_name,
display_name=display_name,
info=f"{help_text} (Unknown type '{field_type}', defaulting to text)",
value=default_value,
required=required,
)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue

Critical: build_config must receive serializable dicts, not Input objects

All dynamic assignments store Input instances directly in build_config. Other components call .to_dict() when mutating build_config. Keeping objects here will break serialization/UI.

Apply .to_dict() to all dynamic input assignments (pattern shown below; repeat for each branch):

-                        build_config[dynamic_input_name] = StrInput(
+                        build_config[dynamic_input_name] = StrInput(
                             name=dynamic_input_name,
                             display_name=display_name,
                             info=f"{help_text} (Can connect to: {', '.join(input_types_list)})",
                             value=default_value,
                             required=required,
                             input_types=input_types_list,
-                        )
+                        ).to_dict()
@@
-                        build_config[dynamic_input_name] = MultilineInput(
+                        build_config[dynamic_input_name] = MultilineInput(
                             name=dynamic_input_name,
                             display_name=display_name,
                             info=help_text,
                             value=default_value,
                             required=required,
-                        )
+                        ).to_dict()
@@
-                        build_config[dynamic_input_name] = IntInput(
+                        build_config[dynamic_input_name] = IntInput(
                             name=dynamic_input_name,
                             display_name=display_name,
                             info=f"{help_text} (Can connect to: {', '.join(input_types_list)})",
                             value=default_int,
                             required=required,
                             input_types=input_types_list,
-                        )
+                        ).to_dict()
@@
-                        build_config[dynamic_input_name] = FloatInput(
+                        build_config[dynamic_input_name] = FloatInput(
                             name=dynamic_input_name,
                             display_name=display_name,
                             info=help_text,
                             value=default_float,
                             required=required,
-                        )
+                        ).to_dict()
@@
-                    build_config[dynamic_input_name] = BoolInput(
+                    build_config[dynamic_input_name] = BoolInput(
                         name=dynamic_input_name,
                         display_name=display_name,
                         info=help_text,
                         value=default_bool,
                         required=required,
-                    )
+                    ).to_dict()
@@
-                    build_config[dynamic_input_name] = HandleInput(
+                    build_config[dynamic_input_name] = HandleInput(
                         name=dynamic_input_name,
                         display_name=display_name,
                         info=f"{help_text} (Accepts: {', '.join(input_types_list) if input_types_list else 'Any'})",
                         input_types=input_types_list if input_types_list else ["Data", "Text", "Message"],
                         required=required,
-                    )
+                    ).to_dict()
@@
-                    build_config[dynamic_input_name] = HandleInput(
+                    build_config[dynamic_input_name] = HandleInput(
                         name=dynamic_input_name,
                         display_name=display_name,
                         info=f"{help_text} (Data input)",
                         input_types=["Data"] if not input_types_list else input_types_list,
                         required=required,
-                    )
+                    ).to_dict()
@@
-                    build_config[dynamic_input_name] = StrInput(
+                    build_config[dynamic_input_name] = StrInput(
                         name=dynamic_input_name,
                         display_name=display_name,
                         info=f"{help_text} (Unknown type '{field_type}', defaulting to text)",
                         value=default_value,
                         required=required,
-                    )
+                    ).to_dict()

Committable suggestion skipped: line range outside the PR's diff.

🤖 Prompt for AI Agents
In src/backend/base/langflow/components/processing/new_create_data.py around
lines 151 to 279, build_config is being assigned Input class instances
(StrInput, MultilineInput, IntInput, FloatInput, BoolInput, HandleInput) which
are not JSON-serializable and will break downstream code; update every branch so
the value stored in build_config is the result of calling .to_dict() on the
Input instance (i.e., create the Input(...) as currently written, then call
.to_dict() and assign that dict to build_config[dynamic_input_name]); apply this
change to all branches including text, multiline, number, float, boolean,
handle, data and the default case, and preserve any input_types overrides and
default value conversions before calling .to_dict().

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

enhancement New feature or request feature New features and enhancements

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant