Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -88,9 +88,9 @@ def _compile_subworkflow_inputs(self) -> List[WorkflowRequestInputRequest]:
def _add_compiled_input(
self, compiled_inputs: List[WorkflowRequestInputRequest], input_name: str, input_value: Any
) -> None:
# Exclude inputs that resolved to be null. This ensure that we don't pass input values
# Exclude inputs that resolved to be null or undefined. This ensures that we don't pass input values
# to optional subworkflow inputs whose values were unresolved.
if input_value is None:
if input_value is None or input_value is undefined:
return
if isinstance(input_value, str):
compiled_inputs.append(
Expand Down Expand Up @@ -155,12 +155,12 @@ def _compile_subworkflow_inputs_for_direct_invocation(self, workflow: "BaseWorkf
if isinstance(self.subworkflow_inputs, BaseInputs):
inputs_dict = {}
for input_descriptor, input_value in self.subworkflow_inputs:
if input_value is not None:
if input_value is not None and input_value is not undefined:
inputs_dict[input_descriptor.name] = input_value
return inputs_class(**inputs_dict)
else:
# Filter out None values for direct invocation
filtered_inputs = {k: v for k, v in self.subworkflow_inputs.items() if v is not None}
# Filter out None and undefined values for direct invocation
filtered_inputs = {k: v for k, v in self.subworkflow_inputs.items() if v is not None and v is not undefined}
return inputs_class(**filtered_inputs)

def _run_resolved_workflow(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
from vellum.workflows.context import execution_context
from vellum.workflows.errors import WorkflowErrorCode
from vellum.workflows.exceptions import NodeException
from vellum.workflows.nodes.bases.base import BaseNode
from vellum.workflows.nodes.displayable.subworkflow_deployment_node.node import SubworkflowDeploymentNode


Expand Down Expand Up @@ -493,3 +494,29 @@ class ExampleSubworkflowDeploymentNode(SubworkflowDeploymentNode):
# AND the error should indicate the missing required input
assert exc_info.value.code == WorkflowErrorCode.INVALID_INPUTS
assert exc_info.value.message == "Missing required input for 'my_var_1'"


def test_compile_subworkflow_inputs__undefined_input_filtered():
"""Confirm that undefined values in subworkflow_inputs are filtered out when compiling inputs for API calls."""

# GIVEN an upstream node with an output that is declared but never set (resolves to undefined)
class UpstreamNode(BaseNode):
class Outputs(BaseNode.Outputs):
unset_output: str

# AND a Subworkflow Deployment Node that references the unset output for an optional input
class ExampleSubworkflowDeploymentNode(SubworkflowDeploymentNode):
deployment = "example_subworkflow_deployment"
subworkflow_inputs = {
"required_input": "hello",
"optional_input": UpstreamNode.Outputs.unset_output,
}

# WHEN we compile the subworkflow inputs
node = ExampleSubworkflowDeploymentNode()
compiled_inputs = node._compile_subworkflow_inputs()

# THEN only the required_input should be included (undefined values should be filtered out)
assert len(compiled_inputs) == 1
assert compiled_inputs[0].name == "required_input"
assert compiled_inputs[0].value == "hello"