vellum-ai 0.10.6__py3-none-any.whl → 0.10.8__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 (49) hide show
  1. vellum/__init__.py +2 -0
  2. vellum/client/README.md +7 -52
  3. vellum/client/__init__.py +16 -136
  4. vellum/client/core/client_wrapper.py +1 -1
  5. vellum/client/resources/ad_hoc/client.py +14 -104
  6. vellum/client/resources/metric_definitions/client.py +113 -0
  7. vellum/client/resources/test_suites/client.py +8 -16
  8. vellum/client/resources/workflows/client.py +0 -32
  9. vellum/client/types/__init__.py +2 -0
  10. vellum/client/types/metric_definition_history_item.py +39 -0
  11. vellum/types/metric_definition_history_item.py +3 -0
  12. vellum/workflows/events/node.py +36 -3
  13. vellum/workflows/events/tests/test_event.py +89 -9
  14. vellum/workflows/events/types.py +1 -1
  15. vellum/workflows/nodes/core/inline_subworkflow_node/node.py +1 -0
  16. vellum/workflows/nodes/core/templating_node/node.py +5 -0
  17. vellum/workflows/nodes/displayable/api_node/node.py +1 -1
  18. vellum/workflows/nodes/displayable/bases/prompt_deployment_node.py +1 -2
  19. vellum/workflows/nodes/displayable/code_execution_node/node.py +1 -2
  20. vellum/workflows/nodes/displayable/code_execution_node/utils.py +13 -2
  21. vellum/workflows/nodes/displayable/conditional_node/node.py +2 -2
  22. vellum/workflows/nodes/displayable/inline_prompt_node/node.py +10 -3
  23. vellum/workflows/nodes/displayable/prompt_deployment_node/node.py +6 -1
  24. vellum/workflows/nodes/displayable/subworkflow_deployment_node/node.py +1 -2
  25. vellum/workflows/nodes/displayable/tests/test_text_prompt_deployment_node.py +1 -2
  26. vellum/workflows/ports/node_ports.py +2 -2
  27. vellum/workflows/ports/port.py +14 -0
  28. vellum/workflows/references/__init__.py +2 -0
  29. vellum/workflows/runner/runner.py +49 -8
  30. vellum/workflows/runner/types.py +1 -3
  31. vellum/workflows/state/encoder.py +2 -1
  32. vellum/workflows/types/__init__.py +5 -0
  33. vellum/workflows/types/tests/test_utils.py +6 -3
  34. vellum/workflows/types/utils.py +3 -0
  35. {vellum_ai-0.10.6.dist-info → vellum_ai-0.10.8.dist-info}/METADATA +1 -1
  36. {vellum_ai-0.10.6.dist-info → vellum_ai-0.10.8.dist-info}/RECORD +49 -47
  37. vellum_cli/__init__.py +23 -4
  38. vellum_cli/pull.py +28 -13
  39. vellum_cli/tests/test_pull.py +45 -2
  40. vellum_ee/workflows/display/nodes/base_node_display.py +1 -1
  41. vellum_ee/workflows/display/nodes/vellum/code_execution_node.py +17 -2
  42. vellum_ee/workflows/display/nodes/vellum/final_output_node.py +4 -2
  43. vellum_ee/workflows/display/nodes/vellum/map_node.py +20 -48
  44. vellum_ee/workflows/display/tests/workflow_serialization/test_basic_conditional_node_serialization.py +5 -16
  45. vellum_ee/workflows/display/tests/workflow_serialization/test_basic_map_node_serialization.py +11 -8
  46. vellum_ee/workflows/display/utils/vellum.py +3 -2
  47. {vellum_ai-0.10.6.dist-info → vellum_ai-0.10.8.dist-info}/LICENSE +0 -0
  48. {vellum_ai-0.10.6.dist-info → vellum_ai-0.10.8.dist-info}/WHEEL +0 -0
  49. {vellum_ai-0.10.6.dist-info → vellum_ai-0.10.8.dist-info}/entry_points.txt +0 -0
vellum_cli/pull.py CHANGED
@@ -7,28 +7,38 @@ from typing import Optional
7
7
  from dotenv import load_dotenv
8
8
 
9
9
  from vellum.workflows.vellum_client import create_vellum_client
10
- from vellum_cli.config import load_vellum_cli_config
10
+ from vellum_cli.config import WorkflowConfig, load_vellum_cli_config
11
11
  from vellum_cli.logger import load_cli_logger
12
12
 
13
13
 
14
14
  def pull_command(
15
- module: Optional[str], legacy_module: Optional[bool] = None, include_json: Optional[bool] = None
15
+ module: Optional[str] = None,
16
+ workflow_sandbox_id: Optional[str] = None,
17
+ include_json: Optional[bool] = None,
18
+ exclude_code: Optional[bool] = None,
16
19
  ) -> None:
17
20
  load_dotenv()
18
21
  logger = load_cli_logger()
19
22
  config = load_vellum_cli_config()
20
23
 
21
- if not config.workflows:
22
- raise ValueError("No Workflows found in project to pull.")
23
-
24
- if len(config.workflows) > 1 and not module:
25
- raise ValueError("Multiple workflows found in project to pull. Pulling only a single workflow is supported.")
26
-
27
24
  workflow_config = (
28
- next((w for w in config.workflows if w.module == module), None) if module else config.workflows[0]
25
+ next((w for w in config.workflows if w.module == module), None)
26
+ if module
27
+ else (config.workflows[0] if config.workflows else None)
29
28
  )
29
+ save_lock_file = False
30
30
  if workflow_config is None:
31
- raise ValueError(f"No workflow config for '{module}' found in project to push.")
31
+ if module:
32
+ raise ValueError(f"No workflow config for '{module}' found in project to pull.")
33
+ elif workflow_sandbox_id:
34
+ workflow_config = WorkflowConfig(
35
+ workflow_sandbox_id=workflow_sandbox_id,
36
+ module=f"workflow_{workflow_sandbox_id.split('-')[0]}",
37
+ )
38
+ config.workflows.append(workflow_config)
39
+ save_lock_file = True
40
+ else:
41
+ raise ValueError("No workflow config found in project to pull from.")
32
42
 
33
43
  if not workflow_config.workflow_sandbox_id:
34
44
  raise ValueError("No workflow sandbox ID found in project to pull from.")
@@ -36,10 +46,10 @@ def pull_command(
36
46
  logger.info(f"Pulling workflow into {workflow_config.module}")
37
47
  client = create_vellum_client()
38
48
  query_parameters = {}
39
- if legacy_module:
40
- query_parameters["legacyModule"] = legacy_module
41
49
  if include_json:
42
50
  query_parameters["include_json"] = include_json
51
+ if exclude_code:
52
+ query_parameters["exclude_code"] = exclude_code
43
53
 
44
54
  response = client.workflows.pull(
45
55
  workflow_config.workflow_sandbox_id,
@@ -81,6 +91,11 @@ def pull_command(
81
91
  target.write(source.read().decode("utf-8"))
82
92
 
83
93
  if include_json:
84
- logger.warning("The pulled JSON representation of the Workflow should be used for debugging purposely only. Its schema should be considered unstable and subject to change at any time.")
94
+ logger.warning(
95
+ "The pulled JSON representation of the Workflow should be used for debugging purposely only. Its schema should be considered unstable and subject to change at any time."
96
+ )
97
+
98
+ if save_lock_file:
99
+ config.save()
85
100
 
86
101
  logger.info(f"Successfully pulled Workflow into {workflow_config.module}")
@@ -69,8 +69,33 @@ def test_pull(vellum_client, mock_module):
69
69
  pull_command(module)
70
70
 
71
71
  # THEN the workflow.py file is written to the module directory
72
- assert os.path.exists(os.path.join(temp_dir, *module.split("."), "workflow.py"))
73
- with open(os.path.join(temp_dir, *module.split("."), "workflow.py")) as f:
72
+ workflow_py = os.path.join(temp_dir, *module.split("."), "workflow.py")
73
+ assert os.path.exists(workflow_py)
74
+ with open(workflow_py) as f:
75
+ assert f.read() == "print('hello')"
76
+
77
+
78
+ def test_pull__sandbox_id_with_no_config(vellum_client):
79
+ # GIVEN a workflow sandbox id
80
+ workflow_sandbox_id = "87654321-0000-0000-0000-000000000000"
81
+
82
+ # AND the workflow pull API call returns a zip file
83
+ vellum_client.workflows.pull.return_value = iter([zip_file_map({"workflow.py": "print('hello')"})])
84
+
85
+ # AND we are currently in a new directory
86
+ current_dir = os.getcwd()
87
+ temp_dir = tempfile.mkdtemp()
88
+ os.chdir(temp_dir)
89
+
90
+ # WHEN the user runs the pull command with the workflow sandbox id and no module
91
+ pull_command(workflow_sandbox_id=workflow_sandbox_id)
92
+ os.chdir(current_dir)
93
+
94
+ # THEN the pull api is called with exclude_code=True
95
+ vellum_client.workflows.pull.assert_called_once()
96
+ workflow_py = os.path.join(temp_dir, "workflow_87654321", "workflow.py")
97
+ assert os.path.exists(workflow_py)
98
+ with open(workflow_py) as f:
74
99
  assert f.read() == "print('hello')"
75
100
 
76
101
 
@@ -168,3 +193,21 @@ def test_pull__include_json(vellum_client, mock_module):
168
193
  vellum_client.workflows.pull.assert_called_once()
169
194
  call_args = vellum_client.workflows.pull.call_args.kwargs
170
195
  assert call_args["request_options"]["additional_query_parameters"] == {"include_json": True}
196
+
197
+
198
+ def test_pull__exclude_code(vellum_client, mock_module):
199
+ # GIVEN a module on the user's filesystem
200
+ _, module = mock_module
201
+
202
+ # AND the workflow pull API call returns a zip file
203
+ vellum_client.workflows.pull.return_value = iter(
204
+ [zip_file_map({"workflow.py": "print('hello')", "workflow.json": "{}"})]
205
+ )
206
+
207
+ # WHEN the user runs the pull command
208
+ pull_command(module, exclude_code=True)
209
+
210
+ # THEN the pull api is called with exclude_code=True
211
+ vellum_client.workflows.pull.assert_called_once()
212
+ call_args = vellum_client.workflows.pull.call_args.kwargs
213
+ assert call_args["request_options"]["additional_query_parameters"] == {"exclude_code": True}
@@ -1,7 +1,7 @@
1
1
  from functools import cached_property
2
2
  import inspect
3
3
  from uuid import UUID
4
- from typing import TYPE_CHECKING, Any, Dict, Generic, Optional, Type, TypeVar, get_args, get_origin, cast
4
+ from typing import TYPE_CHECKING, Any, Dict, Generic, Optional, Type, TypeVar, cast, get_args, get_origin
5
5
 
6
6
  from vellum.workflows.nodes.bases.base import BaseNode
7
7
  from vellum.workflows.nodes.utils import get_wrapped_node, has_wrapped_node
@@ -1,5 +1,5 @@
1
1
  from uuid import UUID
2
- from typing import ClassVar, Generic, Optional, TypeVar
2
+ from typing import ClassVar, Dict, Generic, Optional, TypeVar
3
3
 
4
4
  from vellum.workflows.nodes.displayable.code_execution_node import CodeExecutionNode
5
5
  from vellum.workflows.nodes.displayable.code_execution_node.utils import read_file_from_path
@@ -20,6 +20,8 @@ class BaseCodeExecutionNodeDisplay(BaseNodeVellumDisplay[_CodeExecutionNodeType]
20
20
  output_id: ClassVar[Optional[UUID]] = None
21
21
  log_output_id: ClassVar[Optional[UUID]] = None
22
22
 
23
+ node_input_ids_by_name: ClassVar[Dict[str, UUID]] = {}
24
+
23
25
  def serialize(
24
26
  self, display_context: WorkflowDisplayContext, error_output_id: Optional[UUID] = None, **kwargs
25
27
  ) -> JsonObject:
@@ -27,6 +29,19 @@ class BaseCodeExecutionNodeDisplay(BaseNodeVellumDisplay[_CodeExecutionNodeType]
27
29
  node_id = self.node_id
28
30
 
29
31
  code = read_file_from_path(raise_if_descriptor(node.filepath))
32
+ code_inputs = raise_if_descriptor(node.code_inputs)
33
+
34
+ inputs = [
35
+ create_node_input(
36
+ node_id=node_id,
37
+ input_name=variable_name,
38
+ value=variable_value,
39
+ display_context=display_context,
40
+ input_id=self.node_input_ids_by_name.get(variable_name),
41
+ )
42
+ for variable_name, variable_value in code_inputs.items()
43
+ ]
44
+
30
45
  code_node_input = create_node_input(
31
46
  node_id=node_id,
32
47
  input_name="code",
@@ -41,7 +56,7 @@ class BaseCodeExecutionNodeDisplay(BaseNodeVellumDisplay[_CodeExecutionNodeType]
41
56
  display_context=display_context,
42
57
  input_id=self.runtime_input_id,
43
58
  )
44
- inputs = [code_node_input, runtime_node_input]
59
+ inputs.extend([code_node_input, runtime_node_input])
45
60
 
46
61
  packages = raise_if_descriptor(node.packages)
47
62
 
@@ -1,14 +1,16 @@
1
1
  from uuid import UUID
2
2
  from typing import Any, ClassVar, Generic, Optional, TypeVar
3
3
 
4
+ from vellum.workflows.nodes.core.map_node.node import MapNode
5
+ from vellum.workflows.nodes.displayable.final_output_node import FinalOutputNode
6
+ from vellum.workflows.references.output import OutputReference
7
+ from vellum.workflows.types.core import JsonObject
4
8
  from vellum_ee.workflows.display.nodes.base_node_vellum_display import BaseNodeVellumDisplay
5
9
  from vellum_ee.workflows.display.nodes.utils import to_kebab_case
6
10
  from vellum_ee.workflows.display.nodes.vellum.utils import create_node_input
7
11
  from vellum_ee.workflows.display.types import WorkflowDisplayContext
8
12
  from vellum_ee.workflows.display.utils.uuids import uuid4_from_hash
9
13
  from vellum_ee.workflows.display.utils.vellum import infer_vellum_variable_type
10
- from vellum.workflows.nodes.displayable.final_output_node import FinalOutputNode
11
- from vellum.workflows.types.core import JsonObject
12
14
 
13
15
  _FinalOutputNodeType = TypeVar("_FinalOutputNodeType", bound=FinalOutputNode)
14
16
 
@@ -1,59 +1,32 @@
1
1
  from uuid import UUID
2
- from typing import Any, ClassVar, Dict, Generic, List, Optional, Type, TypeVar
2
+ from typing import Collection, Dict, Generic, List, Optional, TypeVar, cast
3
3
 
4
- from vellum import VellumVariable
5
4
  from vellum.workflows.nodes import MapNode
6
5
  from vellum.workflows.types.core import JsonObject
7
6
  from vellum_ee.workflows.display.nodes.base_node_vellum_display import BaseNodeVellumDisplay
8
7
  from vellum_ee.workflows.display.nodes.utils import raise_if_descriptor
9
8
  from vellum_ee.workflows.display.nodes.vellum.utils import create_node_input
10
9
  from vellum_ee.workflows.display.types import WorkflowDisplayContext
11
- from vellum_ee.workflows.display.utils.uuids import uuid4_from_hash
12
- from vellum_ee.workflows.display.utils.vellum import infer_vellum_variable_type
13
10
  from vellum_ee.workflows.display.workflows.get_vellum_workflow_display_class import get_workflow_display
14
11
 
15
12
  _MapNodeType = TypeVar("_MapNodeType", bound=MapNode)
16
13
 
17
14
 
18
15
  class BaseMapNodeDisplay(BaseNodeVellumDisplay[_MapNodeType], Generic[_MapNodeType]):
19
- workflow_input_ids_by_name: ClassVar[Dict[str, UUID]] = {}
20
-
21
16
  def serialize(
22
17
  self, display_context: WorkflowDisplayContext, error_output_id: Optional[UUID] = None, **kwargs
23
18
  ) -> JsonObject:
24
19
  node = self._node
25
20
  node_id = self.node_id
26
21
 
27
- workflow_inputs: List[VellumVariable] = []
28
22
  subworkflow = raise_if_descriptor(node.subworkflow)
29
- for descriptor in subworkflow.get_inputs_class():
30
- # In WaC it's always 'all_items'
31
- # In Vellum it's always 'items'
32
- variable_name = descriptor.name if descriptor.name != "all_items" else "items"
33
- variable_id = str(
34
- self.workflow_input_ids_by_name.get(variable_name)
35
- or uuid4_from_hash(f"{self.node_id}|{variable_name}")
36
- )
37
- workflow_inputs.append(
38
- VellumVariable(
39
- id=variable_id,
40
- key=variable_name,
41
- type=infer_vellum_variable_type(descriptor),
42
- )
43
- )
44
-
45
- items_workflow_input = next(input for input in workflow_inputs if input.key == "items")
46
- item_workflow_input = next(input for input in workflow_inputs if input.key == "item")
47
- index_workflow_input = next(input for input in workflow_inputs if input.key == "index")
48
-
49
- workflow_outputs = self._generate_workflow_outputs(node)
50
23
 
51
24
  items_node_input = create_node_input(
52
25
  node_id=node_id,
53
26
  input_name="items",
54
27
  value=node.items,
55
28
  display_context=display_context,
56
- input_id=UUID(items_workflow_input.id),
29
+ input_id=self.node_input_ids_by_name.get("items"),
57
30
  )
58
31
  node_inputs = [items_node_input]
59
32
 
@@ -63,6 +36,19 @@ class BaseMapNodeDisplay(BaseNodeVellumDisplay[_MapNodeType], Generic[_MapNodeTy
63
36
  )
64
37
  serialized_subworkflow = subworkflow_display.serialize()
65
38
 
39
+ renamed_input_variables = []
40
+ for input_variable in cast(List[Dict[str, str]], serialized_subworkflow["input_variables"]):
41
+ if input_variable["key"] == "all_items":
42
+ renamed_item = { **input_variable, "key": "items" }
43
+ renamed_input_variables.append(renamed_item)
44
+ else:
45
+ renamed_input_variables.append(input_variable)
46
+
47
+ # Note: This must match the items input ID for the map node's node input
48
+ items_workflow_input_id = next(input_variable["id"] for input_variable in renamed_input_variables if input_variable["key"] == "items")
49
+ item_workflow_input_id = next(input_variable["id"] for input_variable in renamed_input_variables if input_variable["key"] == "item")
50
+ index_workflow_input_id = next(input_variable["id"] for input_variable in renamed_input_variables if input_variable["key"] == "index")
51
+
66
52
  return {
67
53
  "id": str(node_id),
68
54
  "type": "MAP",
@@ -74,27 +60,13 @@ class BaseMapNodeDisplay(BaseNodeVellumDisplay[_MapNodeType], Generic[_MapNodeTy
74
60
  "target_handle_id": str(self.get_target_handle_id()),
75
61
  "variant": "INLINE",
76
62
  "workflow_raw_data": serialized_subworkflow["workflow_raw_data"],
77
- "input_variables": [workflow_input.dict() for workflow_input in workflow_inputs],
78
- "output_variables": [workflow_output.dict() for workflow_output in workflow_outputs],
63
+ "input_variables": cast(JsonObject, renamed_input_variables),
64
+ "output_variables": serialized_subworkflow["output_variables"],
79
65
  "concurrency": raise_if_descriptor(node.concurrency),
80
- "items_input_id": str(items_workflow_input.id),
81
- "item_input_id": str(item_workflow_input.id),
82
- "index_input_id": str(index_workflow_input.id),
66
+ "items_input_id": items_workflow_input_id,
67
+ "item_input_id": item_workflow_input_id,
68
+ "index_input_id": index_workflow_input_id,
83
69
  },
84
70
  "display_data": self.get_display_data().dict(),
85
71
  "definition": self.get_definition().dict(),
86
72
  }
87
-
88
- def _generate_workflow_outputs(
89
- self,
90
- node: Type[MapNode],
91
- ) -> List[VellumVariable]:
92
- workflow_outputs: List[VellumVariable] = []
93
- for output_descriptor in raise_if_descriptor(node.subworkflow).Outputs: # type: ignore[union-attr]
94
- node_output_display = self.get_node_output_display(output_descriptor)
95
- output_type = infer_vellum_variable_type(output_descriptor)
96
- workflow_outputs.append(
97
- VellumVariable(id=str(node_output_display.id), key=node_output_display.name, type=output_type)
98
- )
99
-
100
- return workflow_outputs
@@ -13,30 +13,20 @@ from vellum.workflows.expressions.does_not_equal import DoesNotEqualExpression
13
13
  from vellum.workflows.expressions.ends_with import EndsWithExpression
14
14
  from vellum.workflows.expressions.equals import EqualsExpression
15
15
  from vellum.workflows.expressions.greater_than import GreaterThanExpression
16
- from vellum.workflows.expressions.greater_than_or_equal_to import (
17
- GreaterThanOrEqualToExpression,
18
- )
16
+ from vellum.workflows.expressions.greater_than_or_equal_to import GreaterThanOrEqualToExpression
19
17
  from vellum.workflows.expressions.in_ import InExpression
20
18
  from vellum.workflows.expressions.is_not_null import IsNotNullExpression
21
19
  from vellum.workflows.expressions.is_null import IsNullExpression
22
20
  from vellum.workflows.expressions.less_than import LessThanExpression
23
- from vellum.workflows.expressions.less_than_or_equal_to import (
24
- LessThanOrEqualToExpression,
25
- )
21
+ from vellum.workflows.expressions.less_than_or_equal_to import LessThanOrEqualToExpression
26
22
  from vellum.workflows.expressions.not_between import NotBetweenExpression
27
23
  from vellum.workflows.expressions.not_in import NotInExpression
28
- from vellum_ee.workflows.display.nodes.base_node_vellum_display import (
29
- BaseNodeVellumDisplay,
30
- )
24
+ from vellum_ee.workflows.display.nodes.base_node_vellum_display import BaseNodeVellumDisplay
31
25
  from vellum_ee.workflows.display.workflows import VellumWorkflowDisplay
32
- from vellum_ee.workflows.display.workflows.get_vellum_workflow_display_class import (
33
- get_workflow_display,
34
- )
26
+ from vellum_ee.workflows.display.workflows.get_vellum_workflow_display_class import get_workflow_display
35
27
 
36
28
  from tests.workflows.basic_conditional_node.workflow import CategoryWorkflow
37
- from tests.workflows.basic_conditional_node.workflow_with_only_one_conditional_node import (
38
- create_simple_workflow,
39
- )
29
+ from tests.workflows.basic_conditional_node.workflow_with_only_one_conditional_node import create_simple_workflow
40
30
 
41
31
 
42
32
  def test_serialize_workflow():
@@ -965,7 +955,6 @@ def test_conditional_node_serialize_all_operators_with_lhs_and_rhs(
965
955
 
966
956
  # AND the conditional node should be what we expect
967
957
  conditional_node = workflow_raw_data["nodes"][1]
968
- print(conditional_node)
969
958
  assert not DeepDiff(
970
959
  {
971
960
  "id": "a9143814-6bb0-4cb3-a817-4fc076417121",
@@ -228,15 +228,15 @@ def test_serialize_workflow():
228
228
  },
229
229
  },
230
230
  "input_variables": [
231
- {"id": "0fe9dff5-7595-4ff3-a420-416f3fc6f809", "key": "item", "type": "JSON"},
232
- {"id": "27dfe8ba-8be7-4de9-a930-2ec3e375b149", "key": "index", "type": "NUMBER"},
233
- {"id": "4c0a109f-599e-4d04-a396-a51474fc2996", "key": "items", "type": "JSON"},
231
+ {"id": "b29bb546-9bc8-4136-857d-8c7a464ba9d4", "key": "item", "type": "JSON", "required": True, "default": None, "extensions": {"color": None}},
232
+ {"id": "17e7ca49-668f-450d-a792-e1f97d13db67", "key": "index", "type": "NUMBER", "required": True, "default": None, "extensions": {"color": None}},
233
+ {"id": "d6fc6c7a-235f-4b98-86f3-e258d1198f93", "key": "items", "type": "JSON", "required": True, "default": None, "extensions": {"color": None}},
234
234
  ],
235
- "output_variables": [{"id": "56b34d4a-d3a6-4bdb-80a4-dbf644791274", "key": "count", "type": "NUMBER"}],
235
+ "output_variables": [{"id": "2a957315-fae0-4366-8a35-f0b315c5eade", "key": "count", "type": "NUMBER"}],
236
236
  "concurrency": None,
237
- "items_input_id": "4c0a109f-599e-4d04-a396-a51474fc2996",
238
- "item_input_id": "0fe9dff5-7595-4ff3-a420-416f3fc6f809",
239
- "index_input_id": "27dfe8ba-8be7-4de9-a930-2ec3e375b149",
237
+ "items_input_id": "d6fc6c7a-235f-4b98-86f3-e258d1198f93",
238
+ "item_input_id": "b29bb546-9bc8-4136-857d-8c7a464ba9d4",
239
+ "index_input_id": "17e7ca49-668f-450d-a792-e1f97d13db67",
240
240
  },
241
241
  "display_data": {"position": {"x": 0.0, "y": 0.0}},
242
242
  "definition": {
@@ -288,7 +288,7 @@ def test_serialize_workflow():
288
288
  "type": "NODE_OUTPUT",
289
289
  "data": {
290
290
  "node_id": "bf83099a-40df-4445-b90d-1f6f1067ebe3",
291
- "output_id": "56b34d4a-d3a6-4bdb-80a4-dbf644791274",
291
+ "output_id": "2a957315-fae0-4366-8a35-f0b315c5eade",
292
292
  },
293
293
  }
294
294
  ],
@@ -323,6 +323,9 @@ def test_serialize_workflow():
323
323
  },
324
324
  },
325
325
  workflow_raw_data["nodes"][2],
326
+ # TODO: Fix output ID not referencing map node workflow output
327
+ # https://app.shortcut.com/vellum/story/5667/fix-output-display-reference-on-map-nodes
328
+ exclude_regex_paths=r"root\['inputs'\]\[0\]\['value'\]\['rules'\]\[0\]\['data'\]\['output_id'\]",
326
329
  )
327
330
 
328
331
  # AND each edge should be serialized correctly
@@ -4,7 +4,9 @@ import typing
4
4
  from typing import Any, List, Union, cast
5
5
 
6
6
  from vellum import ChatMessage, SearchResult, SearchResultRequest, VellumVariableType
7
+ from vellum.client.types.array_vellum_value import ArrayVellumValue
7
8
  from vellum.workflows.descriptors.base import BaseDescriptor
9
+ from vellum.workflows.nodes.core.map_node.node import MapNodeItemType
8
10
  from vellum.workflows.references import OutputReference, WorkflowInputReference
9
11
  from vellum.workflows.references.execution_count import ExecutionCountReference
10
12
  from vellum.workflows.references.node import NodeReference
@@ -45,9 +47,8 @@ def infer_vellum_variable_type(value: Any) -> VellumVariableType:
45
47
  raise ValueError(
46
48
  f"Expected NodeReference {descriptor.name} to have an instance pointing to a descriptor"
47
49
  )
48
-
49
50
  descriptor = descriptor.instance
50
-
51
+
51
52
  inferred_type = primitive_type_to_vellum_variable_type(descriptor)
52
53
  else:
53
54
  vellum_variable_value = primitive_to_vellum_value(value)