vellum-ai 0.14.41__py3-none-any.whl → 0.14.43__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (69) hide show
  1. vellum/__init__.py +4 -4
  2. vellum/client/core/client_wrapper.py +2 -2
  3. vellum/client/reference.md +110 -3
  4. vellum/client/resources/documents/client.py +0 -6
  5. vellum/client/resources/prompts/client.py +228 -1
  6. vellum/client/types/__init__.py +4 -4
  7. vellum/client/types/deployment_read.py +2 -2
  8. vellum/client/types/execute_api_response.py +3 -4
  9. vellum/client/types/execute_api_response_json.py +7 -0
  10. vellum/client/types/{workflow_event_display_context.py → prompt_push_response.py} +4 -12
  11. vellum/client/types/prompt_settings.py +1 -0
  12. vellum/client/types/workflow_event_execution_read.py +0 -4
  13. vellum/client/types/workflow_execution_initiated_body.py +0 -9
  14. vellum/client/types/workflow_execution_initiated_event.py +0 -4
  15. vellum/client/types/workflow_execution_span.py +0 -4
  16. vellum/types/{node_event_display_context.py → execute_api_response_json.py} +1 -1
  17. vellum/types/{workflow_event_display_context.py → prompt_push_response.py} +1 -1
  18. vellum/workflows/inputs/base.py +26 -3
  19. vellum/workflows/inputs/tests/test_inputs.py +15 -0
  20. vellum/workflows/nodes/bases/base.py +0 -3
  21. vellum/workflows/nodes/bases/base_adornment_node.py +9 -0
  22. vellum/workflows/nodes/bases/tests/test_base_adornment_node.py +31 -0
  23. vellum/workflows/nodes/core/map_node/node.py +3 -2
  24. vellum/workflows/nodes/core/map_node/tests/test_node.py +56 -0
  25. vellum/workflows/nodes/core/retry_node/node.py +2 -1
  26. vellum/workflows/nodes/displayable/bases/inline_prompt_node/node.py +62 -13
  27. vellum/workflows/nodes/displayable/bases/inline_prompt_node/tests/test_inline_prompt_node.py +177 -0
  28. vellum/workflows/nodes/experimental/tool_calling_node/node.py +3 -6
  29. vellum/workflows/nodes/experimental/tool_calling_node/utils.py +18 -15
  30. vellum/workflows/nodes/utils.py +14 -1
  31. vellum/workflows/references/output.py +1 -1
  32. vellum/workflows/references/workflow_input.py +5 -1
  33. vellum/workflows/runner/runner.py +2 -0
  34. vellum/workflows/workflows/base.py +5 -0
  35. {vellum_ai-0.14.41.dist-info → vellum_ai-0.14.43.dist-info}/METADATA +1 -1
  36. {vellum_ai-0.14.41.dist-info → vellum_ai-0.14.43.dist-info}/RECORD +68 -67
  37. vellum_cli/pull.py +7 -0
  38. vellum_cli/tests/test_pull.py +23 -0
  39. vellum_ee/workflows/display/nodes/base_node_display.py +32 -23
  40. vellum_ee/workflows/display/nodes/vellum/api_node.py +1 -0
  41. vellum_ee/workflows/display/nodes/vellum/code_execution_node.py +1 -0
  42. vellum_ee/workflows/display/nodes/vellum/conditional_node.py +1 -0
  43. vellum_ee/workflows/display/nodes/vellum/final_output_node.py +6 -6
  44. vellum_ee/workflows/display/nodes/vellum/guardrail_node.py +1 -0
  45. vellum_ee/workflows/display/nodes/vellum/inline_prompt_node.py +1 -0
  46. vellum_ee/workflows/display/nodes/vellum/inline_subworkflow_node.py +1 -0
  47. vellum_ee/workflows/display/nodes/vellum/map_node.py +15 -12
  48. vellum_ee/workflows/display/nodes/vellum/merge_node.py +1 -0
  49. vellum_ee/workflows/display/nodes/vellum/prompt_deployment_node.py +1 -0
  50. vellum_ee/workflows/display/nodes/vellum/search_node.py +1 -0
  51. vellum_ee/workflows/display/nodes/vellum/subworkflow_deployment_node.py +1 -0
  52. vellum_ee/workflows/display/nodes/vellum/templating_node.py +1 -0
  53. vellum_ee/workflows/display/tests/workflow_serialization/test_basic_api_node_serialization.py +1 -0
  54. vellum_ee/workflows/display/tests/workflow_serialization/test_basic_code_execution_node_serialization.py +3 -0
  55. vellum_ee/workflows/display/tests/workflow_serialization/test_basic_conditional_node_serialization.py +138 -0
  56. vellum_ee/workflows/display/tests/workflow_serialization/test_basic_guardrail_node_serialization.py +1 -0
  57. vellum_ee/workflows/display/tests/workflow_serialization/test_basic_inline_subworkflow_serialization.py +1 -0
  58. vellum_ee/workflows/display/tests/workflow_serialization/test_basic_map_node_serialization.py +3 -2
  59. vellum_ee/workflows/display/tests/workflow_serialization/test_basic_merge_node_serialization.py +1 -0
  60. vellum_ee/workflows/display/tests/workflow_serialization/test_basic_prompt_deployment_serialization.py +1 -0
  61. vellum_ee/workflows/display/tests/workflow_serialization/test_basic_search_node_serialization.py +1 -0
  62. vellum_ee/workflows/display/tests/workflow_serialization/test_basic_subworkflow_deployment_serialization.py +1 -0
  63. vellum_ee/workflows/display/tests/workflow_serialization/test_basic_templating_node_serialization.py +1 -0
  64. vellum_ee/workflows/display/tests/workflow_serialization/test_basic_terminal_node_serialization.py +2 -2
  65. vellum_ee/workflows/display/tests/workflow_serialization/test_complex_terminal_node_serialization.py +2 -2
  66. vellum/client/types/node_event_display_context.py +0 -30
  67. {vellum_ai-0.14.41.dist-info → vellum_ai-0.14.43.dist-info}/LICENSE +0 -0
  68. {vellum_ai-0.14.41.dist-info → vellum_ai-0.14.43.dist-info}/WHEEL +0 -0
  69. {vellum_ai-0.14.41.dist-info → vellum_ai-0.14.43.dist-info}/entry_points.txt +0 -0
@@ -30,6 +30,7 @@ from vellum.workflows.expressions.contains import ContainsExpression
30
30
  from vellum.workflows.expressions.does_not_begin_with import DoesNotBeginWithExpression
31
31
  from vellum.workflows.expressions.does_not_contain import DoesNotContainExpression
32
32
  from vellum.workflows.expressions.does_not_end_with import DoesNotEndWithExpression
33
+ from vellum.workflows.expressions.does_not_equal import DoesNotEqualExpression
33
34
  from vellum.workflows.expressions.ends_with import EndsWithExpression
34
35
  from vellum.workflows.expressions.equals import EqualsExpression
35
36
  from vellum.workflows.expressions.greater_than import GreaterThanExpression
@@ -177,29 +178,7 @@ class BaseNodeDisplay(Generic[NodeType], metaclass=BaseNodeDisplayMeta):
177
178
  existing_adornments = adornments if adornments is not None else []
178
179
  return display_class().serialize(display_context, adornments=existing_adornments + [adornment])
179
180
 
180
- ports: JsonArray = []
181
- for port in node.Ports:
182
- id = str(self.get_node_port_display(port).id)
183
-
184
- if port._condition_type:
185
- ports.append(
186
- {
187
- "id": id,
188
- "name": port.name,
189
- "type": port._condition_type.value,
190
- "expression": (
191
- self.serialize_condition(display_context, port._condition) if port._condition else None
192
- ),
193
- }
194
- )
195
- else:
196
- ports.append(
197
- {
198
- "id": id,
199
- "name": port.name,
200
- "type": "DEFAULT",
201
- }
202
- )
181
+ ports = self.serialize_ports(display_context)
203
182
 
204
183
  outputs: JsonArray = []
205
184
  for output in node.Outputs:
@@ -236,6 +215,35 @@ class BaseNodeDisplay(Generic[NodeType], metaclass=BaseNodeDisplayMeta):
236
215
  "outputs": outputs,
237
216
  }
238
217
 
218
+ def serialize_ports(self, display_context: "WorkflowDisplayContext") -> JsonArray:
219
+ """Serialize the ports of the node."""
220
+ node = self._node
221
+ ports: JsonArray = []
222
+
223
+ for port in node.Ports:
224
+ id = str(self.get_node_port_display(port).id)
225
+ if port._condition_type:
226
+ ports.append(
227
+ {
228
+ "id": id,
229
+ "name": port.name,
230
+ "type": port._condition_type.value,
231
+ "expression": (
232
+ self.serialize_condition(display_context, port._condition) if port._condition else None
233
+ ),
234
+ }
235
+ )
236
+ else:
237
+ ports.append(
238
+ {
239
+ "id": id,
240
+ "name": port.name,
241
+ "type": "DEFAULT",
242
+ }
243
+ )
244
+
245
+ return ports
246
+
239
247
  def get_base(self) -> CodeResourceDefinition:
240
248
  node = self._node
241
249
 
@@ -438,6 +446,7 @@ class BaseNodeDisplay(Generic[NodeType], metaclass=BaseNodeDisplayMeta):
438
446
  DoesNotBeginWithExpression,
439
447
  DoesNotContainExpression,
440
448
  DoesNotEndWithExpression,
449
+ DoesNotEqualExpression,
441
450
  EndsWithExpression,
442
451
  EqualsExpression,
443
452
  GreaterThanExpression,
@@ -192,4 +192,5 @@ class BaseAPINodeDisplay(BaseNodeDisplay[_APINodeType], Generic[_APINodeType]):
192
192
  "display_data": self.get_display_data().dict(),
193
193
  "base": self.get_base().dict(),
194
194
  "definition": self.get_definition().dict(),
195
+ "ports": self.serialize_ports(display_context),
195
196
  }
@@ -98,4 +98,5 @@ class BaseCodeExecutionNodeDisplay(BaseNodeDisplay[_CodeExecutionNodeType], Gene
98
98
  "display_data": self.get_display_data().dict(),
99
99
  "base": self.get_base().dict(),
100
100
  "definition": self.get_definition().dict(),
101
+ "ports": self.serialize_ports(display_context),
101
102
  }
@@ -217,6 +217,7 @@ but the defined conditions have length {len(condition_ids)}"""
217
217
  "display_data": self.get_display_data().dict(),
218
218
  "base": self.get_base().dict(),
219
219
  "definition": self.get_definition().dict(),
220
+ "ports": self.serialize_ports(display_context),
220
221
  }
221
222
 
222
223
  def get_nested_rule_details_by_path(
@@ -12,11 +12,11 @@ from vellum_ee.workflows.display.utils.vellum import infer_vellum_variable_type
12
12
 
13
13
  _FinalOutputNodeType = TypeVar("_FinalOutputNodeType", bound=FinalOutputNode)
14
14
 
15
+ NODE_INPUT_KEY = "node_input"
16
+
15
17
 
16
18
  class BaseFinalOutputNodeDisplay(BaseNodeDisplay[_FinalOutputNodeType], Generic[_FinalOutputNodeType]):
17
- output_id: ClassVar[Optional[UUID]] = None
18
19
  output_name: ClassVar[Optional[str]] = None
19
- node_input_id: ClassVar[Optional[UUID]] = None
20
20
 
21
21
  def serialize(self, display_context: WorkflowDisplayContext, **kwargs: Any) -> JsonObject:
22
22
  node = self._node
@@ -24,7 +24,7 @@ class BaseFinalOutputNodeDisplay(BaseNodeDisplay[_FinalOutputNodeType], Generic[
24
24
 
25
25
  node_input = create_node_input(
26
26
  node_id,
27
- "node_input",
27
+ NODE_INPUT_KEY,
28
28
  # Get the pointer that the Terminal Node's output is referencing
29
29
  node.Outputs.value.instance,
30
30
  display_context,
@@ -58,13 +58,13 @@ class BaseFinalOutputNodeDisplay(BaseNodeDisplay[_FinalOutputNodeType], Generic[
58
58
  }
59
59
 
60
60
  def _get_output_id(self) -> UUID:
61
- explicit_value = self._get_explicit_node_display_attr("output_id", UUID)
62
- return explicit_value if explicit_value else uuid4_from_hash(f"{self.node_id}|output_id")
61
+ explicit_value = self.output_display.get(self._node.Outputs.value)
62
+ return explicit_value.id if explicit_value else uuid4_from_hash(f"{self.node_id}|output_id")
63
63
 
64
64
  def _get_output_name(self) -> str:
65
65
  explicit_value = self._get_explicit_node_display_attr("output_name", str)
66
66
  return explicit_value if explicit_value else to_kebab_case(self._node.__name__)
67
67
 
68
68
  def _get_node_input_id(self) -> UUID:
69
- explicit_value = self._get_explicit_node_display_attr("node_input_id", UUID)
69
+ explicit_value = self.node_input_ids_by_name.get(NODE_INPUT_KEY)
70
70
  return explicit_value if explicit_value else uuid4_from_hash(f"{self.node_id}|node_input_id")
@@ -46,4 +46,5 @@ class BaseGuardrailNodeDisplay(BaseNodeDisplay[_GuardrailNodeType], Generic[_Gua
46
46
  "display_data": self.get_display_data().dict(),
47
47
  "base": self.get_base().dict(),
48
48
  "definition": self.get_definition().dict(),
49
+ "ports": self.serialize_ports(display_context),
49
50
  }
@@ -72,6 +72,7 @@ class BaseInlinePromptNodeDisplay(BaseNodeDisplay[_InlinePromptNodeType], Generi
72
72
  {"id": str(output_display.id), "name": "text", "type": "STRING", "value": None},
73
73
  {"id": str(array_display.id), "name": "results", "type": "ARRAY", "value": None},
74
74
  ],
75
+ "ports": self.serialize_ports(display_context),
75
76
  }
76
77
 
77
78
  def _generate_node_and_prompt_inputs(
@@ -54,6 +54,7 @@ class BaseInlineSubworkflowNodeDisplay(
54
54
  "display_data": self.get_display_data().dict(),
55
55
  "base": self.get_base().dict(),
56
56
  "definition": self.get_definition().dict(),
57
+ "ports": self.serialize_ports(display_context),
57
58
  }
58
59
 
59
60
  def _generate_node_and_workflow_inputs(
@@ -1,5 +1,5 @@
1
1
  from uuid import UUID
2
- from typing import Dict, Generic, List, Optional, TypeVar, cast
2
+ from typing import Generic, Optional, TypeVar, cast
3
3
 
4
4
  from vellum.workflows.nodes import MapNode
5
5
  from vellum.workflows.types.core import JsonObject
@@ -36,24 +36,26 @@ class BaseMapNodeDisplay(BaseAdornmentNodeDisplay[_MapNodeType], Generic[_MapNod
36
36
  parent_display_context=display_context,
37
37
  )
38
38
  serialized_subworkflow = subworkflow_display.serialize()
39
+ if not isinstance(serialized_subworkflow["input_variables"], list):
40
+ raise ValueError("input_variables must be a list")
39
41
 
40
- renamed_input_variables = []
41
- for input_variable in cast(List[Dict[str, str]], serialized_subworkflow["input_variables"]):
42
- if input_variable["key"] == "all_items":
43
- renamed_item = {**input_variable, "key": "items"}
44
- renamed_input_variables.append(renamed_item)
45
- else:
46
- renamed_input_variables.append(input_variable)
42
+ input_variables = serialized_subworkflow["input_variables"]
47
43
 
48
44
  # Note: This must match the items input ID for the map node's node input
49
45
  items_workflow_input_id = next(
50
- input_variable["id"] for input_variable in renamed_input_variables if input_variable["key"] == "items"
46
+ input_variable["id"]
47
+ for input_variable in input_variables
48
+ if isinstance(input_variable, dict) and input_variable["key"] == "items"
51
49
  )
52
50
  item_workflow_input_id = next(
53
- input_variable["id"] for input_variable in renamed_input_variables if input_variable["key"] == "item"
51
+ input_variable["id"]
52
+ for input_variable in input_variables
53
+ if isinstance(input_variable, dict) and input_variable["key"] == "item"
54
54
  )
55
55
  index_workflow_input_id = next(
56
- input_variable["id"] for input_variable in renamed_input_variables if input_variable["key"] == "index"
56
+ input_variable["id"]
57
+ for input_variable in input_variables
58
+ if isinstance(input_variable, dict) and input_variable["key"] == "index"
57
59
  )
58
60
 
59
61
  return {
@@ -67,7 +69,7 @@ class BaseMapNodeDisplay(BaseAdornmentNodeDisplay[_MapNodeType], Generic[_MapNod
67
69
  "target_handle_id": str(self.get_target_handle_id()),
68
70
  "variant": "INLINE",
69
71
  "workflow_raw_data": serialized_subworkflow["workflow_raw_data"],
70
- "input_variables": cast(JsonObject, renamed_input_variables),
72
+ "input_variables": cast(JsonObject, input_variables),
71
73
  "output_variables": serialized_subworkflow["output_variables"],
72
74
  "concurrency": raise_if_descriptor(node.max_concurrency),
73
75
  "items_input_id": items_workflow_input_id,
@@ -77,4 +79,5 @@ class BaseMapNodeDisplay(BaseAdornmentNodeDisplay[_MapNodeType], Generic[_MapNod
77
79
  "display_data": self.get_display_data().dict(),
78
80
  "base": self.get_base().dict(),
79
81
  "definition": self.get_definition().dict(),
82
+ "ports": self.serialize_ports(display_context),
80
83
  }
@@ -50,6 +50,7 @@ class BaseMergeNodeDisplay(BaseNodeDisplay[_MergeNodeType], Generic[_MergeNodeTy
50
50
  "display_data": self.get_display_data().dict(),
51
51
  "base": self.get_base().dict(),
52
52
  "definition": self.get_definition().dict(),
53
+ "ports": self.serialize_ports(display_context),
53
54
  }
54
55
 
55
56
  def get_target_handle_ids(self) -> Optional[List[UUID]]:
@@ -66,4 +66,5 @@ class BasePromptDeploymentNodeDisplay(BaseNodeDisplay[_PromptDeploymentNodeType]
66
66
  "display_data": self.get_display_data().dict(),
67
67
  "base": self.get_base().dict(),
68
68
  "definition": self.get_definition().dict(),
69
+ "ports": self.serialize_ports(display_context),
69
70
  }
@@ -68,6 +68,7 @@ class BaseSearchNodeDisplay(BaseNodeDisplay[_SearchNodeType], Generic[_SearchNod
68
68
  "display_data": self.get_display_data().dict(),
69
69
  "base": self.get_base().dict(),
70
70
  "definition": self.get_definition().dict(),
71
+ "ports": self.serialize_ports(display_context),
71
72
  }
72
73
 
73
74
  def _generate_search_node_inputs(
@@ -57,4 +57,5 @@ class BaseSubworkflowDeploymentNodeDisplay(
57
57
  "display_data": self.get_display_data().dict(),
58
58
  "base": self.get_base().dict(),
59
59
  "definition": self.get_definition().dict(),
60
+ "ports": self.serialize_ports(display_context),
60
61
  }
@@ -67,4 +67,5 @@ class BaseTemplatingNodeDisplay(BaseNodeDisplay[_TemplatingNodeType], Generic[_T
67
67
  "display_data": self.get_display_data().dict(),
68
68
  "base": self.get_base().dict(),
69
69
  "definition": self.get_definition().dict(),
70
+ "ports": self.serialize_ports(display_context),
70
71
  }
@@ -194,6 +194,7 @@ def test_serialize_workflow(vellum_client):
194
194
  "name": "SimpleAPINode",
195
195
  "module": ["tests", "workflows", "basic_api_node", "workflow"],
196
196
  },
197
+ "ports": [{"id": "7c33b4d3-9204-4bd5-9371-80ee34f83073", "name": "default", "type": "DEFAULT"}],
197
198
  },
198
199
  api_node,
199
200
  )
@@ -111,6 +111,7 @@ def test_serialize_workflow_with_filepath():
111
111
  "module": ["tests", "workflows", "basic_code_execution_node", "workflow"],
112
112
  "name": "SimpleCodeExecutionNode",
113
113
  },
114
+ "ports": [{"id": "832f81ec-427b-42a8-825c-e62c43c1f961", "name": "default", "type": "DEFAULT"}],
114
115
  }
115
116
  assert not DeepDiff(
116
117
  [
@@ -343,6 +344,7 @@ def test_serialize_workflow_with_code():
343
344
  "name": "SimpleCodeExecutionNode",
344
345
  "module": ["tests", "workflows", "basic_code_execution_node", "workflow_with_code"],
345
346
  },
347
+ "ports": [{"id": "832f81ec-427b-42a8-825c-e62c43c1f961", "name": "default", "type": "DEFAULT"}],
346
348
  }
347
349
  assert not DeepDiff(
348
350
  [
@@ -603,6 +605,7 @@ def test_serialize_workflow__try_wrapped():
603
605
  ],
604
606
  }
605
607
  ],
608
+ "ports": [{"id": "832f81ec-427b-42a8-825c-e62c43c1f961", "name": "default", "type": "DEFAULT"}],
606
609
  }
607
610
 
608
611
  final_output_nodes = workflow_raw_data["nodes"][2:]
@@ -425,6 +425,87 @@ def test_serialize_workflow():
425
425
  "name": "CategoryConditionalNode",
426
426
  "module": ["tests", "workflows", "basic_conditional_node", "workflow"],
427
427
  },
428
+ "ports": [
429
+ {
430
+ "id": "3a45b81f-95e4-4cbd-8997-bfdbe30251e8",
431
+ "name": "category_question",
432
+ "type": "IF",
433
+ "expression": {
434
+ "type": "BINARY_EXPRESSION",
435
+ "lhs": {"type": "WORKFLOW_INPUT", "input_variable_id": "eece050a-432e-4a2c-8c87-9480397e4cbf"},
436
+ "operator": "=",
437
+ "rhs": {"type": "CONSTANT_VALUE", "value": {"type": "STRING", "value": "question"}},
438
+ },
439
+ },
440
+ {
441
+ "id": "7202f702-1ebc-4067-ab1e-ec67e49158ee",
442
+ "name": "category_complaint",
443
+ "type": "ELIF",
444
+ "expression": {
445
+ "type": "BINARY_EXPRESSION",
446
+ "lhs": {"type": "WORKFLOW_INPUT", "input_variable_id": "eece050a-432e-4a2c-8c87-9480397e4cbf"},
447
+ "operator": "=",
448
+ "rhs": {"type": "CONSTANT_VALUE", "value": {"type": "STRING", "value": "complaint"}},
449
+ },
450
+ },
451
+ {
452
+ "id": "cf45705d-1a47-43a6-9d24-a7fdf78baae0",
453
+ "name": "category_compliment",
454
+ "type": "ELIF",
455
+ "expression": {
456
+ "type": "BINARY_EXPRESSION",
457
+ "lhs": {"type": "WORKFLOW_INPUT", "input_variable_id": "eece050a-432e-4a2c-8c87-9480397e4cbf"},
458
+ "operator": "=",
459
+ "rhs": {"type": "CONSTANT_VALUE", "value": {"type": "STRING", "value": "compliment"}},
460
+ },
461
+ },
462
+ {
463
+ "id": "f04610dd-61cf-41b0-b337-2235e101cdb0",
464
+ "name": "category_statement",
465
+ "type": "ELIF",
466
+ "expression": {
467
+ "type": "BINARY_EXPRESSION",
468
+ "lhs": {
469
+ "type": "BINARY_EXPRESSION",
470
+ "lhs": {
471
+ "type": "WORKFLOW_INPUT",
472
+ "input_variable_id": "eece050a-432e-4a2c-8c87-9480397e4cbf",
473
+ },
474
+ "operator": "=",
475
+ "rhs": {"type": "CONSTANT_VALUE", "value": {"type": "STRING", "value": "statement"}},
476
+ },
477
+ "operator": "and",
478
+ "rhs": {
479
+ "type": "BINARY_EXPRESSION",
480
+ "lhs": {
481
+ "type": "BINARY_EXPRESSION",
482
+ "lhs": {
483
+ "type": "WORKFLOW_INPUT",
484
+ "input_variable_id": "eece050a-432e-4a2c-8c87-9480397e4cbf",
485
+ },
486
+ "operator": "=",
487
+ "rhs": {"type": "CONSTANT_VALUE", "value": {"type": "STRING", "value": "statement"}},
488
+ },
489
+ "operator": "and",
490
+ "rhs": {
491
+ "type": "BINARY_EXPRESSION",
492
+ "lhs": {
493
+ "type": "WORKFLOW_INPUT",
494
+ "input_variable_id": "eece050a-432e-4a2c-8c87-9480397e4cbf",
495
+ },
496
+ "operator": "=",
497
+ "rhs": {"type": "CONSTANT_VALUE", "value": {"type": "STRING", "value": "statement"}},
498
+ },
499
+ },
500
+ },
501
+ },
502
+ {
503
+ "id": "f9dde637-ea90-465f-a871-caf8380ae377",
504
+ "name": "category_fallthrough",
505
+ "type": "ELSE",
506
+ "expression": None,
507
+ },
508
+ ],
428
509
  },
429
510
  conditional_node,
430
511
  ignore_order=True,
@@ -873,6 +954,25 @@ def test_conditional_node_serialize_all_operators_with_lhs_and_rhs(descriptor, o
873
954
  "name": "SimpleConditionalNode",
874
955
  "module": ["tests", "workflows", "basic_conditional_node", "workflow_with_only_one_conditional_node"],
875
956
  },
957
+ "ports": [
958
+ {
959
+ "id": "2ff87aa6-37cf-43dd-af9d-13b9198ab70a",
960
+ "name": "text_str",
961
+ "type": "IF",
962
+ "expression": {
963
+ "type": "BINARY_EXPRESSION",
964
+ "lhs": {"type": "CONSTANT_VALUE", "value": {"type": "STRING", "value": "123"}},
965
+ "operator": f"{operator}",
966
+ "rhs": {"type": "CONSTANT_VALUE", "value": {"type": "STRING", "value": "123"}},
967
+ },
968
+ },
969
+ {
970
+ "id": "9a7e8c2e-0228-4321-8f74-61cb5778f3df",
971
+ "name": "text_fallthrough",
972
+ "type": "ELSE",
973
+ "expression": None,
974
+ },
975
+ ],
876
976
  },
877
977
  conditional_node,
878
978
  ignore_order=True,
@@ -966,6 +1066,24 @@ def test_conditional_node_serialize_all_operators_with_expression(descriptor, op
966
1066
  "name": "SimpleConditionalNode",
967
1067
  "module": ["tests", "workflows", "basic_conditional_node", "workflow_with_only_one_conditional_node"],
968
1068
  },
1069
+ "ports": [
1070
+ {
1071
+ "id": "2ff87aa6-37cf-43dd-af9d-13b9198ab70a",
1072
+ "name": "text_str",
1073
+ "type": "IF",
1074
+ "expression": {
1075
+ "type": "UNARY_EXPRESSION",
1076
+ "lhs": {"type": "CONSTANT_VALUE", "value": {"type": "STRING", "value": "123"}},
1077
+ "operator": f"{operator}",
1078
+ },
1079
+ },
1080
+ {
1081
+ "id": "9a7e8c2e-0228-4321-8f74-61cb5778f3df",
1082
+ "name": "text_fallthrough",
1083
+ "type": "ELSE",
1084
+ "expression": None,
1085
+ },
1086
+ ],
969
1087
  },
970
1088
  conditional_node,
971
1089
  ignore_order=True,
@@ -1072,6 +1190,26 @@ def test_conditional_node_serialize_all_operators_with_value_and_start_and_end(d
1072
1190
  "name": "SimpleConditionalNode",
1073
1191
  "module": ["tests", "workflows", "basic_conditional_node", "workflow_with_only_one_conditional_node"],
1074
1192
  },
1193
+ "ports": [
1194
+ {
1195
+ "id": "2ff87aa6-37cf-43dd-af9d-13b9198ab70a",
1196
+ "name": "text_str",
1197
+ "type": "IF",
1198
+ "expression": {
1199
+ "type": "TERNARY_EXPRESSION",
1200
+ "base": {"type": "CONSTANT_VALUE", "value": {"type": "STRING", "value": "123"}},
1201
+ "operator": f"{operator}",
1202
+ "lhs": {"type": "CONSTANT_VALUE", "value": {"type": "STRING", "value": "123"}},
1203
+ "rhs": {"type": "CONSTANT_VALUE", "value": {"type": "STRING", "value": "123"}},
1204
+ },
1205
+ },
1206
+ {
1207
+ "id": "9a7e8c2e-0228-4321-8f74-61cb5778f3df",
1208
+ "name": "text_fallthrough",
1209
+ "type": "ELSE",
1210
+ "expression": None,
1211
+ },
1212
+ ],
1075
1213
  },
1076
1214
  conditional_node,
1077
1215
  ignore_order=True,
@@ -118,6 +118,7 @@ def test_serialize_workflow():
118
118
  "module": ["tests", "workflows", "basic_guardrail_node", "workflow"],
119
119
  "name": "ExampleGuardrailNode",
120
120
  },
121
+ "ports": [{"id": "0ed87407-697e-4ae9-ab9b-6c5cc2e57cf7", "name": "default", "type": "DEFAULT"}],
121
122
  }
122
123
 
123
124
  final_output_node = workflow_raw_data["nodes"][2]
@@ -299,6 +299,7 @@ def test_serialize_workflow():
299
299
  "name": "ExampleInlineSubworkflowNode",
300
300
  "module": ["tests", "workflows", "basic_inline_subworkflow", "workflow"],
301
301
  },
302
+ "ports": [{"id": "cfd831bc-ee7f-44d0-8d76-0ba0cd0277dc", "name": "default", "type": "DEFAULT"}],
302
303
  },
303
304
  subworkflow_node,
304
305
  ignore_order=True,
@@ -254,7 +254,7 @@ def test_serialize_workflow():
254
254
  "extensions": {"color": None},
255
255
  },
256
256
  {
257
- "id": "d6fc6c7a-235f-4b98-86f3-e258d1198f93",
257
+ "id": "0acef1e7-caa1-4d9f-bb69-6981729af18d",
258
258
  "key": "items",
259
259
  "type": "JSON",
260
260
  "required": True,
@@ -264,7 +264,7 @@ def test_serialize_workflow():
264
264
  ],
265
265
  "output_variables": [{"id": "2a957315-fae0-4366-8a35-f0b315c5eade", "key": "count", "type": "NUMBER"}],
266
266
  "concurrency": None,
267
- "items_input_id": "d6fc6c7a-235f-4b98-86f3-e258d1198f93",
267
+ "items_input_id": "0acef1e7-caa1-4d9f-bb69-6981729af18d",
268
268
  "item_input_id": "b29bb546-9bc8-4136-857d-8c7a464ba9d4",
269
269
  "index_input_id": "17e7ca49-668f-450d-a792-e1f97d13db67",
270
270
  },
@@ -277,6 +277,7 @@ def test_serialize_workflow():
277
277
  "name": "MapFruitsNode",
278
278
  "module": ["tests", "workflows", "basic_map_node", "workflow"],
279
279
  },
280
+ "ports": [{"id": "a2171a61-0657-43ad-b6d9-cf93ce3270d0", "name": "default", "type": "DEFAULT"}],
280
281
  },
281
282
  map_node,
282
283
  ignore_order=True,
@@ -84,6 +84,7 @@ def test_serialize_workflow__await_all():
84
84
  "module": ["tests", "workflows", "basic_merge_node", "await_all_workflow"],
85
85
  "name": "AwaitAllMergeNode",
86
86
  },
87
+ "ports": [{"id": "3bbc469f-0fb0-4b3d-a28b-746fefec2818", "name": "default", "type": "DEFAULT"}],
87
88
  },
88
89
  merge_node,
89
90
  ignore_order_func=lambda x: x.path() == "root['data']['target_handles']",
@@ -157,6 +157,7 @@ def test_serialize_workflow(vellum_client):
157
157
  "module": ["tests", "workflows", "basic_text_prompt_deployment", "workflow"],
158
158
  "name": "ExamplePromptDeploymentNode",
159
159
  },
160
+ "ports": [{"id": "2f26c7e0-283d-4f04-b639-adebb56bc679", "name": "default", "type": "DEFAULT"}],
160
161
  }
161
162
 
162
163
  final_output_node = workflow_raw_data["nodes"][2]
@@ -239,6 +239,7 @@ def test_serialize_workflow():
239
239
  "name": "SimpleSearchNode",
240
240
  "module": ["tests", "workflows", "basic_search_node", "workflow"],
241
241
  },
242
+ "ports": [{"id": "00ae06b3-f8d9-4ae6-9fbf-e4ff4d520e9b", "name": "default", "type": "DEFAULT"}],
242
243
  }
243
244
 
244
245
  final_output_node = workflow_raw_data["nodes"][2]
@@ -154,6 +154,7 @@ def test_serialize_workflow(vellum_client):
154
154
  "module": ["tests", "workflows", "basic_subworkflow_deployment", "workflow"],
155
155
  "name": "ExampleSubworkflowDeploymentNode",
156
156
  },
157
+ "ports": [{"id": "ab0db8a9-7b53-4d88-8667-273b31303273", "name": "default", "type": "DEFAULT"}],
157
158
  }
158
159
 
159
160
  assert not DeepDiff(
@@ -113,6 +113,7 @@ def test_serialize_workflow():
113
113
  "name": "ExampleTemplatingNode",
114
114
  "module": ["tests", "workflows", "basic_templating_node", "workflow_with_json_input"],
115
115
  },
116
+ "ports": [{"id": "39317827-df43-4f5a-bfbc-20bffc839748", "name": "default", "type": "DEFAULT"}],
116
117
  },
117
118
  templating_node,
118
119
  )
@@ -68,7 +68,7 @@ def test_serialize_workflow():
68
68
  "label": "Basic Final Output Node",
69
69
  "name": "basic-final-output-node",
70
70
  "target_handle_id": "0173d3c6-11d1-44b7-b070-ca9ff5119046",
71
- "output_id": "97349956-d228-4b51-a64b-1331f788373f",
71
+ "output_id": "aa63e3f6-fde3-4d19-84ef-29982d44d709",
72
72
  "output_type": "STRING",
73
73
  "node_input_id": "5322567a-f40c-400a-96b3-c3b054db543e",
74
74
  },
@@ -98,7 +98,7 @@ def test_serialize_workflow():
98
98
  },
99
99
  "outputs": [
100
100
  {
101
- "id": "97349956-d228-4b51-a64b-1331f788373f",
101
+ "id": "aa63e3f6-fde3-4d19-84ef-29982d44d709",
102
102
  "name": "value",
103
103
  "type": "STRING",
104
104
  "value": {"type": "WORKFLOW_INPUT", "input_variable_id": "e39a7b63-de15-490a-ae9b-8112c767aea0"},
@@ -92,7 +92,7 @@ def test_serialize_workflow__missing_final_output_node():
92
92
  "label": "First Final Output Node",
93
93
  "name": "first-final-output-node",
94
94
  "target_handle_id": "a0c2eb7a-398e-4f28-b63d-f3bae9b563ee",
95
- "output_id": "5517e50d-7f40-4f7c-acb2-e329d79a25bf",
95
+ "output_id": "0cd02933-c5b9-47c9-aede-e97c5870e8aa",
96
96
  "output_type": "STRING",
97
97
  "node_input_id": "16363762-c14a-4162-8fab-525079d3cffe",
98
98
  },
@@ -122,7 +122,7 @@ def test_serialize_workflow__missing_final_output_node():
122
122
  },
123
123
  "outputs": [
124
124
  {
125
- "id": "5517e50d-7f40-4f7c-acb2-e329d79a25bf",
125
+ "id": "0cd02933-c5b9-47c9-aede-e97c5870e8aa",
126
126
  "name": "value",
127
127
  "type": "STRING",
128
128
  "value": {
@@ -1,30 +0,0 @@
1
- # This file was auto-generated by Fern from our API Definition.
2
-
3
- from __future__ import annotations
4
- from ..core.pydantic_utilities import UniversalBaseModel
5
- import typing
6
- from ..core.pydantic_utilities import IS_PYDANTIC_V2
7
- import pydantic
8
- from ..core.pydantic_utilities import update_forward_refs
9
-
10
-
11
- class NodeEventDisplayContext(UniversalBaseModel):
12
- input_display: typing.Dict[str, str]
13
- output_display: typing.Dict[str, str]
14
- port_display: typing.Dict[str, str]
15
- subworkflow_display: typing.Optional["WorkflowEventDisplayContext"] = None
16
-
17
- if IS_PYDANTIC_V2:
18
- model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict(extra="allow", frozen=True) # type: ignore # Pydantic v2
19
- else:
20
-
21
- class Config:
22
- frozen = True
23
- smart_union = True
24
- extra = pydantic.Extra.allow
25
-
26
-
27
- from .workflow_event_display_context import WorkflowEventDisplayContext # noqa: E402
28
-
29
- update_forward_refs(WorkflowEventDisplayContext, NodeEventDisplayContext=NodeEventDisplayContext)
30
- update_forward_refs(NodeEventDisplayContext)