vellum-ai 1.7.0__py3-none-any.whl → 1.7.1__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.
@@ -27,10 +27,10 @@ class BaseClientWrapper:
27
27
 
28
28
  def get_headers(self) -> typing.Dict[str, str]:
29
29
  headers: typing.Dict[str, str] = {
30
- "User-Agent": "vellum-ai/1.7.0",
30
+ "User-Agent": "vellum-ai/1.7.1",
31
31
  "X-Fern-Language": "Python",
32
32
  "X-Fern-SDK-Name": "vellum-ai",
33
- "X-Fern-SDK-Version": "1.7.0",
33
+ "X-Fern-SDK-Version": "1.7.1",
34
34
  **(self.get_custom_headers() or {}),
35
35
  }
36
36
  if self._api_version is not None:
@@ -1,9 +1,7 @@
1
1
  import logging
2
2
  from uuid import UUID
3
- from typing import Iterator, List, Optional, Tuple, Type, Union
3
+ from typing import Iterator, Optional, Type, Union
4
4
 
5
- from vellum.client.types.vellum_span import VellumSpan
6
- from vellum.client.types.workflow_execution_initiated_event import WorkflowExecutionInitiatedEvent
7
5
  from vellum.workflows.events.workflow import WorkflowEvent
8
6
  from vellum.workflows.nodes.utils import cast_to_output_type
9
7
  from vellum.workflows.resolvers.base import BaseWorkflowResolver
@@ -20,38 +18,6 @@ class VellumResolver(BaseWorkflowResolver):
20
18
  def get_state_snapshot_history(self) -> Iterator[BaseState]:
21
19
  return iter([])
22
20
 
23
- def _find_previous_and_root_span(
24
- self, execution_id: str, spans: List[VellumSpan]
25
- ) -> Tuple[Optional[str], Optional[str], Optional[str], Optional[str]]:
26
- previous_trace_id: Optional[str] = None
27
- root_trace_id: Optional[str] = None
28
- previous_span_id: Optional[str] = None
29
- root_span_id: Optional[str] = None
30
-
31
- for span in spans:
32
- # Look for workflow execution spans with matching ID first
33
- if span.name == "workflow.execution" and span.span_id == execution_id:
34
- # Find the WorkflowExecutionInitiatedEvent in the span's events
35
- initiated_event = next(
36
- (event for event in span.events if isinstance(event, WorkflowExecutionInitiatedEvent)), None
37
- )
38
- if initiated_event:
39
- previous_trace_id = initiated_event.trace_id
40
- previous_span_id = initiated_event.span_id
41
- links = initiated_event.links
42
- if links:
43
- root_span = next((link for link in links if link.type == "ROOT_SPAN"), None)
44
- if root_span:
45
- root_trace_id = root_span.trace_id
46
- root_span_id = root_span.span_context.span_id
47
- else:
48
- # no links means this is the first execution
49
- root_trace_id = initiated_event.trace_id
50
- root_span_id = initiated_event.span_id
51
- break
52
-
53
- return previous_trace_id, root_trace_id, previous_span_id, root_span_id
54
-
55
21
  def _deserialize_state(self, state_data: dict, state_class: Type[BaseState]) -> BaseState:
56
22
  """Deserialize state data with proper type conversion for complex types like List[ChatMessage]."""
57
23
  converted_data = {}
@@ -79,18 +45,19 @@ class VellumResolver(BaseWorkflowResolver):
79
45
  return None
80
46
 
81
47
  client = self._context.vellum_client
82
- response = client.workflow_executions.retrieve_workflow_execution_detail(
83
- execution_id=previous_execution_id,
48
+ response = client.workflows.retrieve_state(
49
+ span_id=previous_execution_id,
84
50
  )
85
51
 
86
52
  if response.state is None:
87
53
  return None
88
54
 
89
- previous_trace_id, root_trace_id, previous_span_id, root_span_id = self._find_previous_and_root_span(
90
- previous_execution_id, response.spans
91
- )
92
-
93
- if previous_trace_id is None or root_trace_id is None or previous_span_id is None or root_span_id is None:
55
+ if (
56
+ response.previous_trace_id is None
57
+ or response.root_trace_id is None
58
+ or response.previous_span_id is None
59
+ or response.root_span_id is None
60
+ ):
94
61
  logger.warning("Could not find required execution events for state loading")
95
62
  return None
96
63
 
@@ -106,8 +73,8 @@ class VellumResolver(BaseWorkflowResolver):
106
73
 
107
74
  return LoadStateResult(
108
75
  state=state,
109
- previous_trace_id=previous_trace_id,
110
- previous_span_id=previous_span_id,
111
- root_trace_id=root_trace_id,
112
- root_span_id=root_span_id,
76
+ previous_trace_id=response.previous_trace_id,
77
+ previous_span_id=response.previous_span_id,
78
+ root_trace_id=response.root_trace_id,
79
+ root_span_id=response.root_span_id,
113
80
  )
@@ -4,14 +4,7 @@ from uuid import uuid4
4
4
  from typing import List
5
5
 
6
6
  from vellum import ChatMessage
7
- from vellum.client.types.span_link import SpanLink
8
- from vellum.client.types.vellum_code_resource_definition import VellumCodeResourceDefinition
9
- from vellum.client.types.workflow_execution_detail import WorkflowExecutionDetail
10
- from vellum.client.types.workflow_execution_initiated_body import WorkflowExecutionInitiatedBody
11
- from vellum.client.types.workflow_execution_initiated_event import WorkflowExecutionInitiatedEvent
12
- from vellum.client.types.workflow_execution_span import WorkflowExecutionSpan
13
- from vellum.client.types.workflow_execution_span_attributes import WorkflowExecutionSpanAttributes
14
- from vellum.client.types.workflow_parent_context import WorkflowParentContext
7
+ from vellum.client.types.workflow_resolved_state import WorkflowResolvedState
15
8
  from vellum.workflows import BaseWorkflow
16
9
  from vellum.workflows.inputs.base import BaseInputs
17
10
  from vellum.workflows.resolvers.resolver import VellumResolver
@@ -24,7 +17,6 @@ def test_load_state_with_context_success():
24
17
  """Test load_state successfully loads state when context and client are available."""
25
18
  resolver = VellumResolver()
26
19
  execution_id = uuid4()
27
- root_execution_id = uuid4()
28
20
 
29
21
  class TestState(BaseState):
30
22
  test_key: str = "test_value"
@@ -50,60 +42,24 @@ def test_load_state_with_context_success():
50
42
  },
51
43
  }
52
44
 
53
- mock_workflow_definition = VellumCodeResourceDefinition(
54
- name="TestWorkflow", module=["test", "module"], id=str(uuid4())
55
- )
56
-
57
- mock_body = WorkflowExecutionInitiatedBody(workflow_definition=mock_workflow_definition, inputs={})
58
-
59
45
  previous_trace_id = str(uuid4())
46
+ previous_span_id = str(uuid4())
60
47
  root_trace_id = str(uuid4())
48
+ root_span_id = str(uuid4())
61
49
 
62
- previous_invocation = WorkflowExecutionInitiatedEvent(
63
- id=str(uuid4()),
50
+ mock_response = WorkflowResolvedState(
51
+ trace_id=str(uuid4()),
64
52
  timestamp=datetime.now(),
65
- trace_id=previous_trace_id,
66
53
  span_id=str(execution_id),
67
- body=mock_body,
68
- links=[
69
- SpanLink(
70
- trace_id=previous_trace_id,
71
- type="PREVIOUS_SPAN",
72
- span_context=WorkflowParentContext(workflow_definition=mock_workflow_definition, span_id=str(uuid4())),
73
- ),
74
- SpanLink(
75
- trace_id=root_trace_id,
76
- type="ROOT_SPAN",
77
- span_context=WorkflowParentContext(
78
- workflow_definition=mock_workflow_definition, span_id=str(root_execution_id)
79
- ),
80
- ),
81
- ],
82
- )
83
-
84
- root_invocation = WorkflowExecutionInitiatedEvent(
85
- id=str(uuid4()),
86
- timestamp=datetime.now(),
87
- trace_id=root_trace_id,
88
- span_id=str(root_execution_id),
89
- body=mock_body,
90
- links=None, # Root invocation has no links
91
- )
92
-
93
- mock_span = WorkflowExecutionSpan(
94
- span_id=str(execution_id), # Use the actual execution_id
95
- start_ts=datetime.now(),
96
- end_ts=datetime.now(),
97
- attributes=WorkflowExecutionSpanAttributes(label="Test Workflow", workflow_id=str(uuid4())),
98
- events=[previous_invocation, root_invocation],
99
- )
100
-
101
- mock_response = WorkflowExecutionDetail(
102
- span_id="test-span-id", start=datetime.now(), inputs=[], outputs=[], spans=[mock_span], state=state_dict
54
+ state=state_dict,
55
+ previous_trace_id=previous_trace_id,
56
+ previous_span_id=previous_span_id,
57
+ root_trace_id=root_trace_id,
58
+ root_span_id=root_span_id,
103
59
  )
104
60
 
105
61
  mock_client = Mock()
106
- mock_client.workflow_executions.retrieve_workflow_execution_detail.return_value = mock_response
62
+ mock_client.workflows.retrieve_state.return_value = mock_response
107
63
 
108
64
  # AND context with the test workflow class is set up
109
65
  context = WorkflowContext(vellum_client=mock_client)
@@ -123,21 +79,18 @@ def test_load_state_with_context_success():
123
79
  assert str(result.state.meta.span_id) != prev_span_id
124
80
 
125
81
  # AND should have span link info
126
- assert result.previous_trace_id == previous_invocation.trace_id
127
- assert result.previous_span_id == previous_invocation.span_id
128
- assert result.root_trace_id == root_invocation.trace_id
129
- assert result.root_span_id == root_invocation.span_id
82
+ assert result.previous_trace_id == previous_trace_id
83
+ assert result.previous_span_id == previous_span_id
84
+ assert result.root_trace_id == root_trace_id
85
+ assert result.root_span_id == root_span_id
130
86
 
131
- mock_client.workflow_executions.retrieve_workflow_execution_detail.assert_called_once_with(
132
- execution_id=str(execution_id)
133
- )
87
+ mock_client.workflows.retrieve_state.assert_called_once_with(span_id=str(execution_id))
134
88
 
135
89
 
136
90
  def test_load_state_with_chat_message_list():
137
91
  """Test load_state successfully loads state with chat_history containing ChatMessage list."""
138
92
  resolver = VellumResolver()
139
93
  execution_id = uuid4()
140
- root_execution_id = uuid4()
141
94
 
142
95
  class TestStateWithChatHistory(BaseState):
143
96
  test_key: str = "test_value"
@@ -169,60 +122,24 @@ def test_load_state_with_chat_message_list():
169
122
  },
170
123
  }
171
124
 
172
- mock_workflow_definition = VellumCodeResourceDefinition(
173
- name="TestWorkflow", module=["test", "module"], id=str(uuid4())
174
- )
175
-
176
- mock_body = WorkflowExecutionInitiatedBody(workflow_definition=mock_workflow_definition, inputs={})
177
-
178
125
  previous_trace_id = str(uuid4())
126
+ previous_span_id = str(uuid4())
179
127
  root_trace_id = str(uuid4())
128
+ root_span_id = str(uuid4())
180
129
 
181
- previous_invocation = WorkflowExecutionInitiatedEvent(
182
- id=str(uuid4()),
183
- timestamp=datetime.now(),
184
- trace_id=previous_trace_id,
185
- span_id=str(execution_id),
186
- body=mock_body,
187
- links=[
188
- SpanLink(
189
- trace_id=previous_trace_id,
190
- type="PREVIOUS_SPAN",
191
- span_context=WorkflowParentContext(workflow_definition=mock_workflow_definition, span_id=str(uuid4())),
192
- ),
193
- SpanLink(
194
- trace_id=root_trace_id,
195
- type="ROOT_SPAN",
196
- span_context=WorkflowParentContext(
197
- workflow_definition=mock_workflow_definition, span_id=str(root_execution_id)
198
- ),
199
- ),
200
- ],
201
- )
202
-
203
- root_invocation = WorkflowExecutionInitiatedEvent(
204
- id=str(uuid4()),
130
+ mock_response = WorkflowResolvedState(
131
+ trace_id=str(uuid4()),
205
132
  timestamp=datetime.now(),
206
- trace_id=root_trace_id,
207
- span_id=str(root_execution_id),
208
- body=mock_body,
209
- links=None,
210
- )
211
-
212
- mock_span = WorkflowExecutionSpan(
213
133
  span_id=str(execution_id),
214
- start_ts=datetime.now(),
215
- end_ts=datetime.now(),
216
- attributes=WorkflowExecutionSpanAttributes(label="Test Workflow", workflow_id=str(uuid4())),
217
- events=[previous_invocation, root_invocation],
218
- )
219
-
220
- mock_response = WorkflowExecutionDetail(
221
- span_id="test-span-id", start=datetime.now(), inputs=[], outputs=[], spans=[mock_span], state=state_dict
134
+ state=state_dict,
135
+ previous_trace_id=previous_trace_id,
136
+ previous_span_id=previous_span_id,
137
+ root_trace_id=root_trace_id,
138
+ root_span_id=root_span_id,
222
139
  )
223
140
 
224
141
  mock_client = Mock()
225
- mock_client.workflow_executions.retrieve_workflow_execution_detail.return_value = mock_response
142
+ mock_client.workflows.retrieve_state.return_value = mock_response
226
143
 
227
144
  # AND context with the test workflow class is set up
228
145
  context = WorkflowContext(vellum_client=mock_client)
@@ -247,6 +164,4 @@ def test_load_state_with_chat_message_list():
247
164
  assert result.state.chat_history[2].role == "USER"
248
165
  assert result.state.chat_history[2].text == "What can you help me with?"
249
166
 
250
- mock_client.workflow_executions.retrieve_workflow_execution_detail.assert_called_once_with(
251
- execution_id=str(execution_id)
252
- )
167
+ mock_client.workflows.retrieve_state.assert_called_once_with(span_id=str(execution_id))
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: vellum-ai
3
- Version: 1.7.0
3
+ Version: 1.7.1
4
4
  Summary:
5
5
  License: MIT
6
6
  Requires-Python: >=3.9,<4.0
@@ -22,7 +22,7 @@ vellum_cli/tests/test_ping.py,sha256=b3aQLd-N59_8w2rRiWqwpB1rlHaKEYVbAj1Y3hi7A-g
22
22
  vellum_cli/tests/test_pull.py,sha256=e2XHzcHIx9k-FyuNAl7wMSNsSSebPGyP6U05JGcddFs,49447
23
23
  vellum_cli/tests/test_push.py,sha256=2MjkNKr_9Guv5Exjsm3L1BeVXmPkKUcCSiKnp90HgW4,41996
24
24
  vellum_ee/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
25
- vellum_ee/assets/node-definitions.json,sha256=tinXep1k-FicJWSPQb5mlWRkdKul1WJtG4o94SqD4ds,29800
25
+ vellum_ee/assets/node-definitions.json,sha256=UkHixt8WAnHmupooOrtpxYCaNG-5pRon1c8QUlc0Vhk,30754
26
26
  vellum_ee/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
27
27
  vellum_ee/scripts/generate_node_definitions.py,sha256=FOYQsXIqU45I0OAcsyZUGODF9JK44yunf58rR6YaAdA,3303
28
28
  vellum_ee/workflows/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
@@ -55,7 +55,7 @@ vellum_ee/workflows/display/nodes/vellum/prompt_deployment_node.py,sha256=Ue727X
55
55
  vellum_ee/workflows/display/nodes/vellum/retry_node.py,sha256=5xv5OR4xRuI1R5yqJDZTNdCFYY-z8PkTdpWM4ziGjw0,3192
56
56
  vellum_ee/workflows/display/nodes/vellum/search_node.py,sha256=ZHqkwzCRsM0TkZmh3ePHreZAoQXeT-SFS7zbUrSjMsw,12037
57
57
  vellum_ee/workflows/display/nodes/vellum/subworkflow_deployment_node.py,sha256=hC5hTSRf1f9ppiZ_wXzpcp-jl0fwNAUB9PY8s0AykHs,3131
58
- vellum_ee/workflows/display/nodes/vellum/templating_node.py,sha256=QExp4l2KMNBdqMVDL4CG_iFMpFf3RYiTP2q5P2DmEFk,3178
58
+ vellum_ee/workflows/display/nodes/vellum/templating_node.py,sha256=sWupmR7Ri2ZeCLx8713JbuawabR_kpWp_-HwT1tCrtU,3163
59
59
  vellum_ee/workflows/display/nodes/vellum/tests/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
60
60
  vellum_ee/workflows/display/nodes/vellum/tests/test_api_node.py,sha256=DQAtsabvn6BE6xWwKNHzMOppzoy1-1dssNnrwbHUdRU,1490
61
61
  vellum_ee/workflows/display/nodes/vellum/tests/test_code_execution_node.py,sha256=6_1yVYftVnqXJn3hLUGHlcHvbgKbQgBfS6vYQ6R79oc,10891
@@ -79,7 +79,7 @@ vellum_ee/workflows/display/tests/test_base_workflow_display.py,sha256=-LYQw5nWq
79
79
  vellum_ee/workflows/display/tests/workflow_serialization/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
80
80
  vellum_ee/workflows/display/tests/workflow_serialization/generic_nodes/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
81
81
  vellum_ee/workflows/display/tests/workflow_serialization/generic_nodes/conftest.py,sha256=Y-ajeT65b5varmrZCw6L3hir4hJCFq-eO0jZfRcrs7g,1886
82
- vellum_ee/workflows/display/tests/workflow_serialization/generic_nodes/test_adornments_serialization.py,sha256=bD9AtBo7Pz1Drbh420NR0VSiHBfExw_UtNRPCiAqki0,13967
82
+ vellum_ee/workflows/display/tests/workflow_serialization/generic_nodes/test_adornments_serialization.py,sha256=wdVaFvxicj48Kj-6VUlu61KR0oSArLTjownRi2p0NWQ,14941
83
83
  vellum_ee/workflows/display/tests/workflow_serialization/generic_nodes/test_attributes_serialization.py,sha256=bPTwkLpB7trFLpAaDvXMfMP0c9H1u_c1cdnj7K-gtnw,24962
84
84
  vellum_ee/workflows/display/tests/workflow_serialization/generic_nodes/test_outputs_serialization.py,sha256=SwXRzjdoEZLvkzaRMvRV8_UqbBm0EB_UtAHD_zXKZBY,6303
85
85
  vellum_ee/workflows/display/tests/workflow_serialization/generic_nodes/test_ports_serialization.py,sha256=jubGYgLJImOqILd5LjnYJ4B1UMIrToDrQbPZOvaQCX4,40035
@@ -126,7 +126,7 @@ vellum_ee/workflows/display/utils/tests/test_events.py,sha256=42IEBnMbaQrH8gigw5
126
126
  vellum_ee/workflows/display/utils/vellum.py,sha256=Bt7kdLdXoBsHn5dVEY2uKcF542VL09jwu8J_30rl2vk,6413
127
127
  vellum_ee/workflows/display/vellum.py,sha256=J2mdJZ1sdLW535DDUkq_Vm8Z572vhuxHxVZF9deKSdk,391
128
128
  vellum_ee/workflows/display/workflows/__init__.py,sha256=JTB9ObEV3l4gGGdtfBHwVJtTTKC22uj-a-XjTVwXCyA,148
129
- vellum_ee/workflows/display/workflows/base_workflow_display.py,sha256=FAsEeqkQu4xGvdZ4Ri5H7LDEISQYziidPc2QHzbOVWs,44311
129
+ vellum_ee/workflows/display/workflows/base_workflow_display.py,sha256=uP3pqSloGjmUYBvVfKP0skZXJnqZxm7TEVxSLdrzU5c,44682
130
130
  vellum_ee/workflows/display/workflows/get_vellum_workflow_display_class.py,sha256=gxz76AeCqgAZ9D2lZeTiZzxY9eMgn3qOSfVgiqYcOh8,2028
131
131
  vellum_ee/workflows/display/workflows/tests/test_workflow_display.py,sha256=lg-c_3P3ldtqWq2VFsk_2Mkn3pVdXWuT59QpH7QwXVs,39764
132
132
  vellum_ee/workflows/server/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
@@ -160,7 +160,7 @@ vellum/client/README.md,sha256=flqu57ubZNTfpq60CdLtJC9gp4WEkyjb_n_eZ4OYf9w,6497
160
160
  vellum/client/__init__.py,sha256=rMnKRqL5-356SBc-rfm56MkO87PuAi2mtcfBszcJU1M,74316
161
161
  vellum/client/core/__init__.py,sha256=lTcqUPXcx4112yLDd70RAPeqq6tu3eFMe1pKOqkW9JQ,1562
162
162
  vellum/client/core/api_error.py,sha256=44vPoTyWN59gonCIZMdzw7M1uspygiLnr3GNFOoVL2Q,614
163
- vellum/client/core/client_wrapper.py,sha256=7jdvkc9bp52v55uLBImLe_fMXRZUgS2HqLAzuk-JDRg,2840
163
+ vellum/client/core/client_wrapper.py,sha256=9h4pM282vdjaHkk3Un2KTjxOCDbg7xu7r__5qwxzPZ8,2840
164
164
  vellum/client/core/datetime_utils.py,sha256=nBys2IsYrhPdszxGKCNRPSOCwa-5DWOHG95FB8G9PKo,1047
165
165
  vellum/client/core/file.py,sha256=d4NNbX8XvXP32z8KpK2Xovv33nFfruIrpz0QWxlgpZk,2663
166
166
  vellum/client/core/force_multipart.py,sha256=awxh5MtcRYe74ehY8U76jzv6fYM_w_D3Rur7KQQzSDk,429
@@ -2017,8 +2017,8 @@ vellum/workflows/references/vellum_secret.py,sha256=Od4d19a5yletWMqNfJR5d_mZQUkV
2017
2017
  vellum/workflows/references/workflow_input.py,sha256=W3rOK1EPd2gYHb04WJwmNm1CUSdvZ9LKrs8RMKxACBs,1751
2018
2018
  vellum/workflows/resolvers/__init__.py,sha256=eH6hTvZO4IciDaf_cf7aM2vs-DkBDyJPycOQevJxQnI,82
2019
2019
  vellum/workflows/resolvers/base.py,sha256=wrQiSC02Bw4-dBwgFjJIHsjpe-4xz4rUJs_1RdErKA0,1164
2020
- vellum/workflows/resolvers/resolver.py,sha256=yK-oY0HDsFJcjlNKAm3vpsPKRIFerIh59FcTwuEN5RY,4839
2021
- vellum/workflows/resolvers/tests/test_resolver.py,sha256=jXkJBb9SwtoH__bBN-ECohpyD0aTIB9ErEvtFhuTMQM,9750
2020
+ vellum/workflows/resolvers/resolver.py,sha256=EIIiA2OlaVUPiKiSh6egQZxPA6ny1GDMdPq1AuN-mV8,2961
2021
+ vellum/workflows/resolvers/tests/test_resolver.py,sha256=PnUGzsulo1It_LjjhHsRNiILvvl5G_IaK8ZX56zKC28,6204
2022
2022
  vellum/workflows/resolvers/types.py,sha256=Hndhlk69g6EKLh_LYg5ILepW5U_h_BYNllfzhS9k8p4,237
2023
2023
  vellum/workflows/runner/__init__.py,sha256=i1iG5sAhtpdsrlvwgH6B-m49JsINkiWyPWs8vyT-bqM,72
2024
2024
  vellum/workflows/runner/runner.py,sha256=rwMZlQBkzK-EfewC6OysNCeuDeTCfpNuzaUlgYoFJMw,43329
@@ -2065,8 +2065,8 @@ vellum/workflows/workflows/event_filters.py,sha256=GSxIgwrX26a1Smfd-6yss2abGCnad
2065
2065
  vellum/workflows/workflows/tests/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
2066
2066
  vellum/workflows/workflows/tests/test_base_workflow.py,sha256=Boa-_m9ii2Qsa1RvVM-VYniF7zCpzGgEGy-OnPZkrHg,23941
2067
2067
  vellum/workflows/workflows/tests/test_context.py,sha256=VJBUcyWVtMa_lE5KxdhgMu0WYNYnUQUDvTF7qm89hJ0,2333
2068
- vellum_ai-1.7.0.dist-info/LICENSE,sha256=hOypcdt481qGNISA784bnAGWAE6tyIf9gc2E78mYC3E,1574
2069
- vellum_ai-1.7.0.dist-info/METADATA,sha256=SMmQ-iMX4Dymys9Y_j7Jz4xq_QJGNUf8U9xYOgYKSw0,5547
2070
- vellum_ai-1.7.0.dist-info/WHEEL,sha256=sP946D7jFCHeNz5Iq4fL4Lu-PrWrFsgfLXbbkciIZwg,88
2071
- vellum_ai-1.7.0.dist-info/entry_points.txt,sha256=xVavzAKN4iF_NbmhWOlOkHluka0YLkbN_pFQ9pW3gLI,117
2072
- vellum_ai-1.7.0.dist-info/RECORD,,
2068
+ vellum_ai-1.7.1.dist-info/LICENSE,sha256=hOypcdt481qGNISA784bnAGWAE6tyIf9gc2E78mYC3E,1574
2069
+ vellum_ai-1.7.1.dist-info/METADATA,sha256=M80DXrz0TQVVr0BUKSFDyCqBpCHtXk3_c4M6vTqK-eQ,5547
2070
+ vellum_ai-1.7.1.dist-info/WHEEL,sha256=sP946D7jFCHeNz5Iq4fL4Lu-PrWrFsgfLXbbkciIZwg,88
2071
+ vellum_ai-1.7.1.dist-info/entry_points.txt,sha256=xVavzAKN4iF_NbmhWOlOkHluka0YLkbN_pFQ9pW3gLI,117
2072
+ vellum_ai-1.7.1.dist-info/RECORD,,
@@ -699,6 +699,51 @@
699
699
  }
700
700
  ]
701
701
  },
702
+ {
703
+ "id": "ee9b5234-247b-49d1-bed4-490312f18838",
704
+ "display_data": {
705
+ "position": {
706
+ "x": 0.0,
707
+ "y": 0.0
708
+ },
709
+ "comment": {
710
+ "value": "Used to render a Jinja template.\n\n Useful for lightweight data transformations and complex string templating.\n ",
711
+ "expanded": true
712
+ }
713
+ },
714
+ "base": {
715
+ "name": "BaseNode",
716
+ "module": [
717
+ "vellum",
718
+ "workflows",
719
+ "nodes",
720
+ "bases",
721
+ "base"
722
+ ]
723
+ },
724
+ "definition": {
725
+ "name": "TemplatingNode",
726
+ "module": [
727
+ "vellum",
728
+ "workflows",
729
+ "nodes",
730
+ "core",
731
+ "templating_node",
732
+ "node"
733
+ ]
734
+ },
735
+ "trigger": {
736
+ "id": "005e1cd2-5452-4e1f-be6a-ac9fe3c02b9b",
737
+ "merge_behavior": "AWAIT_ATTRIBUTES"
738
+ },
739
+ "ports": [
740
+ {
741
+ "id": "8f4460f0-717b-4972-a6f4-ac164e5e204e",
742
+ "name": "default",
743
+ "type": "DEFAULT"
744
+ }
745
+ ]
746
+ },
702
747
  {
703
748
  "id": "035842e0-34ed-43af-97de-a706e40912ae",
704
749
  "label": "Tool Calling Node",
@@ -1010,10 +1055,5 @@
1010
1055
  ]
1011
1056
  }
1012
1057
  ],
1013
- "errors": [
1014
- {
1015
- "node": "TemplatingNode",
1016
- "error": "KeyError: TemplatingNode.Outputs.result"
1017
- }
1018
- ]
1058
+ "errors": []
1019
1059
  }
@@ -50,7 +50,7 @@ class BaseTemplatingNodeDisplay(BaseNodeDisplay[_TemplatingNodeType], Generic[_T
50
50
  # Misc type ignore is due to `node.Outputs` being generic
51
51
  # https://app.shortcut.com/vellum/story/4784
52
52
  output_descriptor = node.Outputs.result # type: ignore [misc]
53
- output_display = display_context.global_node_output_displays[output_descriptor]
53
+ output_display = self.get_node_output_display(output_descriptor)
54
54
  inferred_output_type = primitive_type_to_vellum_variable_type(output_descriptor)
55
55
 
56
56
  return {
@@ -353,3 +353,33 @@ def test_serialize_node__adornment_order_matches_decorator_order():
353
353
  assert len(adornments) == 2
354
354
  assert adornments[0]["label"] == "Try Node"
355
355
  assert adornments[1]["label"] == "Retry Node"
356
+
357
+
358
+ def test_serialize_workflow__retry_node_edges():
359
+ """
360
+ Tests that both retry-adorned nodes are correctly serialized in the nodes array.
361
+ """
362
+
363
+ @RetryNode.wrap(max_attempts=3, delay=60)
364
+ class FirstNode(BaseNode):
365
+ class Outputs(BaseOutputs):
366
+ value: str
367
+
368
+ @RetryNode.wrap(max_attempts=5, delay=120)
369
+ class SecondNode(BaseNode):
370
+ class Outputs(BaseOutputs):
371
+ result: str
372
+
373
+ class MyWorkflow(BaseWorkflow):
374
+ graph = FirstNode >> SecondNode
375
+
376
+ workflow_display = get_workflow_display(workflow_class=MyWorkflow)
377
+ exec_config = cast(Dict[str, Any], workflow_display.serialize())
378
+
379
+ assert isinstance(exec_config["workflow_raw_data"], dict)
380
+ assert isinstance(exec_config["workflow_raw_data"]["nodes"], list)
381
+
382
+ nodes = cast(List[Dict[str, Any]], exec_config["workflow_raw_data"]["nodes"])
383
+
384
+ generic_nodes = [node for node in nodes if node["type"] == "GENERIC"]
385
+ assert len(generic_nodes) == 2
@@ -208,7 +208,15 @@ class BaseWorkflowDisplay(Generic[WorkflowType]):
208
208
  self.display_context.add_invalid_node(node)
209
209
  continue
210
210
 
211
- serialized_nodes[node_display.node_id] = serialized_node
211
+ # Use wrapped node's ID as dict key for adornment wrappers to prevent overwrites
212
+ wrapped_node = get_wrapped_node(node)
213
+ if wrapped_node:
214
+ wrapped_node_display = self.display_context.node_displays[wrapped_node]
215
+ dict_key = wrapped_node_display.node_id
216
+ else:
217
+ dict_key = node_display.node_id
218
+
219
+ serialized_nodes[dict_key] = serialized_node
212
220
 
213
221
  synthetic_output_edges: JsonArray = []
214
222
  output_variables: JsonArray = []