fix(api): fix human input form substitution

Fix the issues that output fields are not properly replaced for
humaninput form.
This commit is contained in:
QuantumGhost 2026-01-04 16:50:24 +08:00
parent 3ab1ad6530
commit e6eb879c61
5 changed files with 14 additions and 23 deletions

View File

@ -16,7 +16,7 @@ from core.workflow.nodes.base.variable_template_parser import VariableTemplatePa
from .enums import ButtonStyle, DeliveryMethodType, EmailRecipientType, FormInputType, PlaceholderType, TimeoutUnit
_OUTPUT_VARIABLE_PATTERN = re.compile(r"\{\{#\$outputs\.(?P<field_name>[a-zA-Z_][a-zA-Z0-9_]{0,29})#\}\}")
_OUTPUT_VARIABLE_PATTERN = re.compile(r"\{\{#\$output\.(?P<field_name>[a-zA-Z_][a-zA-Z0-9_]{0,29})#\}\}")
class _WebAppDeliveryConfig(BaseModel):

View File

@ -264,7 +264,7 @@ class HumanInputNode(Node[HumanInputNodeData]):
This method should:
1. Parse the form_content markdown
2. Substitute {{#node_name.var_name#}} with actual values
3. Keep {{#$outputs.field_name#}} placeholders for form inputs
3. Keep {{#$output.field_name#}} placeholders for form inputs
"""
rendered_form_content = self.graph_runtime_state.variable_pool.convert_template(
self._node_data.form_content,
@ -278,11 +278,11 @@ class HumanInputNode(Node[HumanInputNodeData]):
field_names: Sequence[str],
) -> str:
"""
Replace {{#$outputs.xxx#}} placeholders with submitted values.
Replace {{#$output.xxx#}} placeholders with submitted values.
"""
rendered_content = form_content
for field_name in field_names:
placeholder = "{{#$outputs." + field_name + "#}}"
placeholder = "{{#$output." + field_name + "#}}"
value = outputs.get(field_name)
if value is None:
replacement = ""

View File

@ -778,7 +778,7 @@ class WorkflowService:
variable_pool=variable_pool,
)
rendered_content = node._render_form_content()
rendered_content = node._render_form_content_before_submission()
resolved_placeholder_values = node._resolve_inputs()
node_data = cast(HumanInputNodeData, node.get_base_node_data())
human_input_required = HumanInputRequired(
@ -823,7 +823,7 @@ class WorkflowService:
node_config=node_config,
variable_pool=variable_pool,
)
node_data = cast(HumanInputNodeData, node.get_base_node_data())
node_data = node.node_data
available_actions = {user_action.id for user_action in node_data.user_actions}
if action not in available_actions:
@ -835,21 +835,12 @@ class WorkflowService:
missing_list = ", ".join(sorted(missing_inputs))
raise ValueError(f"Missing inputs: {missing_list}")
rendered_content = node._render_form_content()
rendered_content = node._render_form_content_before_submission()
outputs: dict[str, Any] = dict(form_inputs)
outputs["__action_id"] = action
rendered_content_with_outputs = rendered_content
for field_name in node_data.outputs_field_names():
placeholder = f"{{{{#$outputs.{field_name}#}}}}"
value = outputs.get(field_name)
if value is None:
replacement = ""
elif isinstance(value, (dict, list)):
replacement = json.dumps(value, ensure_ascii=False)
else:
replacement = str(value)
rendered_content_with_outputs = rendered_content_with_outputs.replace(placeholder, replacement)
outputs["__rendered_content"] = rendered_content_with_outputs
outputs["__rendered_content"] = node._render_form_content_with_outputs(
node_data.form_content, outputs, node_data.outputs_field_names()
)
enclosing_node_type_and_id = draft_workflow.get_enclosing_node_type_and_id(node_config)
enclosing_node_id = enclosing_node_type_and_id[1] if enclosing_node_type_and_id else None

View File

@ -221,11 +221,11 @@ class TestHumanInputNodeData:
A content is required:
{{#$outputs.content#}}
{{#$output.content#}}
A ending is required:
{{#$outputs.ending#}}
{{#$output.ending#}}
"""
node_data = HumanInputNodeData(title="Human Input", form_content=content)
@ -407,7 +407,7 @@ class TestHumanInputNodeRenderedContent:
node_data = HumanInputNodeData(
title="Human Input",
form_content="Name: {{#$outputs.name#}}",
form_content="Name: {{#$output.name#}}",
inputs=[
FormInput(
type=FormInputType.TEXT_INPUT,

View File

@ -22,7 +22,7 @@ class _FakeFormRepository:
return self._form
def _build_node(form_content: str = "Please enter your name:\n\n{{#$outputs.name#}}") -> HumanInputNode:
def _build_node(form_content: str = "Please enter your name:\n\n{{#$output.name#}}") -> HumanInputNode:
system_variables = SystemVariable.empty()
system_variables.workflow_execution_id = str(uuid.uuid4())
graph_runtime_state = GraphRuntimeState(