Skip to content

feat: support multi-select input in start node - #41137

Draft
ddddajie wants to merge 7 commits into
langgenius:mainfrom
ddddajie:feat/40575-multi-select-start-input
Draft

feat: support multi-select input in start node#41137
ddddajie wants to merge 7 commits into
langgenius:mainfrom
ddddajie:feat/40575-multi-select-start-input

Conversation

@ddddajie

Copy link
Copy Markdown
Contributor

Important

This is a Draft PR while the Graphon prerequisite is pending. It depends on langgenius/graphon#259, which adds VariableEntityType.MULTI_SELECT.

Summary

Fixes #40575

Adds a dedicated multi-select user input type for Start Nodes.

The implementation keeps selected values as a native string[] / array[string] throughout the workflow path instead of serializing them into a scalar string.

What is included

  • Add the multi-select Start Node input type and map it to array[string] downstream.
  • Reuse the existing options editor for configuring predefined choices.
  • Support optional and required multi-select inputs; an empty array is rejected only when the field is required.
  • Validate submitted values on the backend: values must be strings, must belong to the configured options, and duplicates are rejected while preserving selection order.
  • Keep optional empty selections as a typed empty string array.
  • Add Start Node configuration UI support without introducing a multi-select default value in v1.
  • Add runtime support for before-run forms, embedded chat, chat history, and public run-once flows.
  • Preserve multi-select payloads as native arrays across frontend submission paths.
  • Add focused backend and frontend regression tests.

Dependency / current Draft status

This PR depends on langgenius/graphon#259.

That Graphon PR introduces VariableEntityType.MULTI_SELECT while reusing the existing ARRAY_STRING runtime type, so no new Graphon segment/runtime type is required.

The Dify-side feature implementation is complete on this branch. I am intentionally not bumping the Graphon dependency to an unreleased commit. Once Graphon #259 is merged and released, the remaining work for this PR is:

  1. bump Dify's Graphon dependency to the released version containing MULTI_SELECT;
  2. update api/uv.lock;
  3. run final backend/frontend integration and regression verification;
  4. mark this PR ready for review.

Until that release exists, CI may fail where the currently pinned Graphon version does not yet expose VariableEntityType.MULTI_SELECT.

Verification performed on the implementation branch

  • Graphon targeted tests: 14 passed.
  • Dify backend targeted tests: approximately 82 focused tests passed.
  • Frontend runtime/config regression suite: 14 spec files, 333 tests passed.
  • TSS lint: 5982 passed.
  • vp lint: exited successfully (existing warnings only).
  • vp check --no-fmt: 0 errors (existing warnings only).
  • git diff --check: passed.

Screenshots

Not added yet because this PR is still a Draft waiting on the Graphon prerequisite. UI screenshots can be added before marking it ready for review if requested.

Checklist

  • This change requires a documentation update, included: Dify Document
  • I understand that this PR may be closed in case there was no previous discussion or issues. (This doesn't apply to typos!)
  • I've added a test for each change that was introduced, and I tried as much as possible to make a single atomic change.
  • I've updated the documentation accordingly.
  • I ran make lint && make type-check (backend) and vp staged (frontend) to appease the lint gods

From ChatGPT

@github-actions github-actions Bot added the web This relates to changes on the web. label Aug 24, 2026
@github-actions

github-actions Bot commented Aug 24, 2026

Copy link
Copy Markdown
Contributor

Pyrefly Diff

base → PR
--- /tmp/pyrefly_base.txt	2026-08-24 05:40:21.002850779 +0000
+++ /tmp/pyrefly_pr.txt	2026-08-24 05:40:07.489719983 +0000
@@ -460,6 +460,10 @@
    --> providers/vdb/vdb-weaviate/tests/unit_tests/test_weaviate_vector.py:891:42
 ERROR Argument `SimpleNamespace` is not assignable to parameter `dataset` with type `Dataset` in function `dify_vdb_weaviate.weaviate_vector.WeaviateVectorFactory.init_vector` [bad-argument-type]
    --> providers/vdb/vdb-weaviate/tests/unit_tests/test_weaviate_vector.py:920:42
+ERROR Class `VariableEntityType` has no class attribute `MULTI_SELECT` [missing-attribute]
+   --> core/app/apps/base_app_generator.py:265:18
+ERROR Class `VariableEntityType` has no class attribute `MULTI_SELECT` [missing-attribute]
+  --> core/workflow/variable_pool_initializer.py:21:29
 ERROR Object of class `FromClause` has no attribute `metadata` [missing-attribute]
   --> tests/helpers/legacy_model_type_migration.py:64:16
 ERROR Object of class `FromClause` has no attribute `metadata` [missing-attribute]
@@ -4333,17 +4337,19 @@
 ERROR Argument `Literal['CHAT']` is not assignable to parameter `app_mode` with type `AppMode` in function `core.app.app_config.base_app_config_manager.BaseAppConfigManager.convert_features` [bad-argument-type]
    --> tests/unit_tests/core/app/app_config/test_base_app_config_manager.py:178:71
 ERROR Cannot index into `VariableEntity` [bad-index]
-   --> tests/unit_tests/core/app/app_config/workflow_ui_based_app/test_workflow_ui_based_app_manager.py:119:16
+   --> tests/unit_tests/core/app/app_config/workflow_ui_based_app/test_workflow_ui_based_app_manager.py:120:16
 ERROR Cannot index into `VariableEntity` [bad-index]
-   --> tests/unit_tests/core/app/app_config/workflow_ui_based_app/test_workflow_ui_based_app_manager.py:140:16
+   --> tests/unit_tests/core/app/app_config/workflow_ui_based_app/test_workflow_ui_based_app_manager.py:141:16
 ERROR Cannot index into `VariableEntity` [bad-index]
-   --> tests/unit_tests/core/app/app_config/workflow_ui_based_app/test_workflow_ui_based_app_manager.py:159:16
+   --> tests/unit_tests/core/app/app_config/workflow_ui_based_app/test_workflow_ui_based_app_manager.py:160:16
 ERROR Cannot index into `VariableEntity` [bad-index]
-   --> tests/unit_tests/core/app/app_config/workflow_ui_based_app/test_workflow_ui_based_app_manager.py:178:16
+   --> tests/unit_tests/core/app/app_config/workflow_ui_based_app/test_workflow_ui_based_app_manager.py:179:16
+ERROR Class `VariableEntityType` has no class attribute `MULTI_SELECT` [missing-attribute]
+   --> tests/unit_tests/core/app/app_config/workflow_ui_based_app/test_workflow_ui_based_app_manager.py:194:34
 ERROR Cannot index into `RagPipelineVariableEntity` [bad-index]
-   --> tests/unit_tests/core/app/app_config/workflow_ui_based_app/test_workflow_ui_based_app_manager.py:246:16
+   --> tests/unit_tests/core/app/app_config/workflow_ui_based_app/test_workflow_ui_based_app_manager.py:264:16
 ERROR Cannot index into `RagPipelineVariableEntity` [bad-index]
-   --> tests/unit_tests/core/app/app_config/workflow_ui_based_app/test_workflow_ui_based_app_manager.py:273:16
+   --> tests/unit_tests/core/app/app_config/workflow_ui_based_app/test_workflow_ui_based_app_manager.py:291:16
 ERROR Expected a mapping, got Unknown | None [invalid-argument]
   --> tests/unit_tests/core/app/apps/advanced_chat/test_app_config_manager.py:50:29
 ERROR No matching overload found for function `core.app.apps.advanced_chat.app_generator.AdvancedChatAppGenerator.generate` called with arguments: (app_model=SimpleNamespace, workflow=SimpleNamespace, user=SimpleNamespace, args=dict[str, dict[@_, @_]], invoke_from=Literal[InvokeFrom.WEB_APP], workflow_run_id=Literal['run-id'], streaming=Literal[False], session=Session) [no-matching-overload]
@@ -4978,8 +4984,16 @@
   --> tests/unit_tests/core/app/apps/test_base_app_generate_response_converter.py:40:9
 ERROR Class member `_DummyConverter.convert_stream_simple_response` overrides a member in a parent class but is missing an `@override` decorator [missing-override-decorator]
   --> tests/unit_tests/core/app/apps/test_base_app_generate_response_converter.py:47:9
+ERROR Class `VariableEntityType` has no class attribute `MULTI_SELECT` [missing-attribute]
+   --> tests/unit_tests/core/app/apps/test_base_app_generator.py:346:14
+ERROR Class `VariableEntityType` has no class attribute `MULTI_SELECT` [missing-attribute]
+   --> tests/unit_tests/core/app/apps/test_base_app_generator.py:373:14
+ERROR Class `VariableEntityType` has no class attribute `MULTI_SELECT` [missing-attribute]
+   --> tests/unit_tests/core/app/apps/test_base_app_generator.py:388:14
+ERROR Class `VariableEntityType` has no class attribute `MULTI_SELECT` [missing-attribute]
+   --> tests/unit_tests/core/app/apps/test_base_app_generator.py:648:22
 ERROR Object of class `Account` has no attribute `tenant_id` [missing-attribute]
-   --> tests/unit_tests/core/app/apps/test_base_app_generator.py:599:9
+   --> tests/unit_tests/core/app/apps/test_base_app_generator.py:684:9
 ERROR Class member `DummyQueueManager._publish` overrides a member in a parent class but is missing an `@override` decorator [missing-override-decorator]
   --> tests/unit_tests/core/app/apps/test_base_app_queue_manager.py:18:9
 ERROR Argument `SimpleNamespace` is not assignable to parameter `graph_runtime_state` with type `GraphRuntimeState | None` in function `core.app.apps.base_app_queue_manager.AppQueueManager.graph_runtime_state` [bad-argument-type]
@@ -5152,6 +5166,8 @@
   --> tests/unit_tests/core/app/apps/test_workflow_app_runner_notifications.py:36:51
 ERROR Argument `_DummyWorkflowEntry` is not assignable to parameter `workflow_entry` with type `WorkflowEntry` in function `core.app.apps.workflow_app_runner.WorkflowBasedAppRunner._handle_event` [bad-argument-type]
   --> tests/unit_tests/core/app/apps/test_workflow_app_runner_notifications.py:57:26
+ERROR Class `VariableEntityType` has no class attribute `MULTI_SELECT` [missing-attribute]
+   --> tests/unit_tests/core/app/apps/test_workflow_app_runner_single_node.py:187:18
 ERROR Class member `_RecordingWorkflowAppRunner._publish_event` overrides a member in a parent class but is missing an `@override` decorator [missing-override-decorator]
   --> tests/unit_tests/core/app/apps/test_workflow_pause_events.py:38:9
 ERROR Argument `SimpleNamespace` is not assignable to parameter `workflow_entry` with type `WorkflowEntry` in function `core.app.apps.workflow_app_runner.WorkflowBasedAppRunner._handle_event` [bad-argument-type]
@@ -7938,20 +7954,24 @@
    --> tests/unit_tests/core/workflow/test_node_runtime.py:883:23
 ERROR Object of class `object` has no attribute `tool` [missing-attribute]
    --> tests/unit_tests/core/workflow/test_node_runtime.py:886:12
+ERROR Class `VariableEntityType` has no class attribute `MULTI_SELECT` [missing-attribute]
+   --> tests/unit_tests/core/workflow/test_variable_pool.py:111:68
 ERROR Argument `SimpleNamespace` is not assignable to parameter `graph_runtime_state` with type `GraphRuntimeState` in function `core.workflow.workflow_entry.WorkflowEntry.__init__` [bad-argument-type]
-  --> tests/unit_tests/core/workflow/test_workflow_entry_helpers.py:69:29
+  --> tests/unit_tests/core/workflow/test_workflow_entry_helpers.py:70:29
 ERROR Argument `SimpleNamespace` is not assignable to parameter `graph_runtime_state` with type `GraphRuntimeState` in function `core.workflow.workflow_entry.WorkflowEntry.__init__` [bad-argument-type]
-   --> tests/unit_tests/core/workflow/test_workflow_entry_helpers.py:127:37
+   --> tests/unit_tests/core/workflow/test_workflow_entry_helpers.py:128:37
+ERROR Argument `SimpleNamespace` is not assignable to parameter `workflow` with type `Workflow` in function `core.workflow.workflow_entry.WorkflowEntry.single_step_run` [bad-argument-type]
+   --> tests/unit_tests/core/workflow/test_workflow_entry_helpers.py:447:26
 ERROR Class member `EmptySplitKey.split` overrides parent class `UserString` in an inconsistent manner [bad-override]
-   --> tests/unit_tests/core/workflow/test_workflow_entry_helpers.py:710:17
+   --> tests/unit_tests/core/workflow/test_workflow_entry_helpers.py:782:17
 ERROR Class member `EmptySplitKey.split` overrides a member in a parent class but is missing an `@override` decorator [missing-override-decorator]
-   --> tests/unit_tests/core/workflow/test_workflow_entry_helpers.py:710:17
+   --> tests/unit_tests/core/workflow/test_workflow_entry_helpers.py:782:17
 ERROR `TestMappingUserInputsBranches.test_rejects_invalid_node_variable_key.EmptySplitKey` is not assignable to dict key type `str` [bad-assignment]
-   --> tests/unit_tests/core/workflow/test_workflow_entry_helpers.py:715:35
+   --> tests/unit_tests/core/workflow/test_workflow_entry_helpers.py:787:35
 ERROR Argument `TestWorkflowEntryNodeLayers.test_run_node_with_layers_reports_success.FakeNode` is not assignable to parameter `node` with type `Node[Unknown]` in function `core.workflow.workflow_entry.WorkflowEntry._run_node_with_layers` [bad-argument-type]
-   --> tests/unit_tests/core/workflow/test_workflow_entry_helpers.py:784:78
+   --> tests/unit_tests/core/workflow/test_workflow_entry_helpers.py:856:78
 ERROR Argument `TestWorkflowEntryNodeLayers.test_run_node_with_layers_reports_errors.FakeNode` is not assignable to parameter `node` with type `Node[Unknown]` in function `core.workflow.workflow_entry.WorkflowEntry._run_node_with_layers` [bad-argument-type]
-   --> tests/unit_tests/core/workflow/test_workflow_entry_helpers.py:818:73
+   --> tests/unit_tests/core/workflow/test_workflow_entry_helpers.py:890:73
 ERROR Missing argument `case` in function `enterprise.telemetry.contracts.TelemetryEnvelope.__init__` [missing-argument]
    --> tests/unit_tests/enterprise/telemetry/test_contracts.py:110:30
 ERROR Missing argument `tenant_id` in function `enterprise.telemetry.contracts.TelemetryEnvelope.__init__` [missing-argument]

@github-actions

github-actions Bot commented Aug 24, 2026

Copy link
Copy Markdown
Contributor

Pyrefly Type Coverage

Metric Base PR Delta
Type coverage 60.73% 60.72% -0.01%
Strict coverage 60.32% 60.31% -0.01%
Typed symbols 41,226 41,228 +2
Untyped symbols 26,835 26,852 +17
Modules 3242 3242 0

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

Labels

web This relates to changes on the web.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Add Multi-select / Checkbox Group Input to Start Node User Input

1 participant