vellum-ai 0.14.49__py3-none-any.whl → 0.14.50__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.
- vellum/__init__.py +6 -2
- vellum/client/core/client_wrapper.py +1 -1
- vellum/client/types/__init__.py +6 -2
- vellum/client/types/deployment_read.py +1 -1
- vellum/client/types/slim_workflow_execution_read.py +2 -2
- vellum/client/types/workflow_event_execution_read.py +2 -2
- vellum/client/types/{workflow_execution_usage_calculation_fulfilled_body.py → workflow_execution_usage_calculation_error.py} +5 -6
- vellum/client/types/workflow_execution_usage_calculation_error_code_enum.py +7 -0
- vellum/client/types/workflow_execution_usage_result.py +24 -0
- vellum/types/{workflow_execution_usage_calculation_fulfilled_body.py → workflow_execution_usage_calculation_error.py} +1 -1
- vellum/types/workflow_execution_usage_calculation_error_code_enum.py +3 -0
- vellum/types/workflow_execution_usage_result.py +3 -0
- vellum/workflows/nodes/core/map_node/node.py +74 -87
- vellum/workflows/nodes/core/map_node/tests/test_node.py +49 -0
- vellum/workflows/state/encoder.py +4 -0
- vellum/workflows/workflows/base.py +8 -0
- {vellum_ai-0.14.49.dist-info → vellum_ai-0.14.50.dist-info}/METADATA +1 -1
- {vellum_ai-0.14.49.dist-info → vellum_ai-0.14.50.dist-info}/RECORD +27 -22
- vellum_ee/workflows/display/nodes/base_node_display.py +23 -1
- vellum_ee/workflows/display/nodes/get_node_display_class.py +1 -24
- vellum_ee/workflows/display/tests/workflow_serialization/test_basic_tool_calling_node_serialization.py +177 -0
- vellum_ee/workflows/display/utils/expressions.py +1 -1
- vellum_ee/workflows/display/workflows/base_workflow_display.py +3 -24
- vellum_ee/workflows/display/workflows/tests/test_workflow_display.py +3 -3
- {vellum_ai-0.14.49.dist-info → vellum_ai-0.14.50.dist-info}/LICENSE +0 -0
- {vellum_ai-0.14.49.dist-info → vellum_ai-0.14.50.dist-info}/WHEEL +0 -0
- {vellum_ai-0.14.49.dist-info → vellum_ai-0.14.50.dist-info}/entry_points.txt +0 -0
vellum/__init__.py
CHANGED
@@ -544,7 +544,9 @@ from .types import (
|
|
544
544
|
WorkflowExecutionSpanAttributes,
|
545
545
|
WorkflowExecutionStreamingBody,
|
546
546
|
WorkflowExecutionStreamingEvent,
|
547
|
-
|
547
|
+
WorkflowExecutionUsageCalculationError,
|
548
|
+
WorkflowExecutionUsageCalculationErrorCodeEnum,
|
549
|
+
WorkflowExecutionUsageResult,
|
548
550
|
WorkflowExecutionViewOnlineEvalMetricResult,
|
549
551
|
WorkflowExecutionWorkflowResultEvent,
|
550
552
|
WorkflowExpandMetaRequest,
|
@@ -1177,7 +1179,9 @@ __all__ = [
|
|
1177
1179
|
"WorkflowExecutionSpanAttributes",
|
1178
1180
|
"WorkflowExecutionStreamingBody",
|
1179
1181
|
"WorkflowExecutionStreamingEvent",
|
1180
|
-
"
|
1182
|
+
"WorkflowExecutionUsageCalculationError",
|
1183
|
+
"WorkflowExecutionUsageCalculationErrorCodeEnum",
|
1184
|
+
"WorkflowExecutionUsageResult",
|
1181
1185
|
"WorkflowExecutionViewOnlineEvalMetricResult",
|
1182
1186
|
"WorkflowExecutionWorkflowResultEvent",
|
1183
1187
|
"WorkflowExpandMetaRequest",
|
@@ -18,7 +18,7 @@ class BaseClientWrapper:
|
|
18
18
|
headers: typing.Dict[str, str] = {
|
19
19
|
"X-Fern-Language": "Python",
|
20
20
|
"X-Fern-SDK-Name": "vellum-ai",
|
21
|
-
"X-Fern-SDK-Version": "0.14.
|
21
|
+
"X-Fern-SDK-Version": "0.14.50",
|
22
22
|
}
|
23
23
|
headers["X-API-KEY"] = self.api_key
|
24
24
|
return headers
|
vellum/client/types/__init__.py
CHANGED
@@ -568,7 +568,9 @@ from .workflow_execution_span import WorkflowExecutionSpan
|
|
568
568
|
from .workflow_execution_span_attributes import WorkflowExecutionSpanAttributes
|
569
569
|
from .workflow_execution_streaming_body import WorkflowExecutionStreamingBody
|
570
570
|
from .workflow_execution_streaming_event import WorkflowExecutionStreamingEvent
|
571
|
-
from .
|
571
|
+
from .workflow_execution_usage_calculation_error import WorkflowExecutionUsageCalculationError
|
572
|
+
from .workflow_execution_usage_calculation_error_code_enum import WorkflowExecutionUsageCalculationErrorCodeEnum
|
573
|
+
from .workflow_execution_usage_result import WorkflowExecutionUsageResult
|
572
574
|
from .workflow_execution_view_online_eval_metric_result import WorkflowExecutionViewOnlineEvalMetricResult
|
573
575
|
from .workflow_execution_workflow_result_event import WorkflowExecutionWorkflowResultEvent
|
574
576
|
from .workflow_expand_meta_request import WorkflowExpandMetaRequest
|
@@ -1154,7 +1156,9 @@ __all__ = [
|
|
1154
1156
|
"WorkflowExecutionSpanAttributes",
|
1155
1157
|
"WorkflowExecutionStreamingBody",
|
1156
1158
|
"WorkflowExecutionStreamingEvent",
|
1157
|
-
"
|
1159
|
+
"WorkflowExecutionUsageCalculationError",
|
1160
|
+
"WorkflowExecutionUsageCalculationErrorCodeEnum",
|
1161
|
+
"WorkflowExecutionUsageResult",
|
1158
1162
|
"WorkflowExecutionViewOnlineEvalMetricResult",
|
1159
1163
|
"WorkflowExecutionWorkflowResultEvent",
|
1160
1164
|
"WorkflowExpandMetaRequest",
|
@@ -50,7 +50,7 @@ class DeploymentRead(UniversalBaseModel):
|
|
50
50
|
|
51
51
|
active_model_version_ids: typing.Optional[typing.List[str]] = pydantic.Field(default=None)
|
52
52
|
"""
|
53
|
-
Deprecated. This now always returns
|
53
|
+
Deprecated. This now always returns an empty array.
|
54
54
|
"""
|
55
55
|
|
56
56
|
last_deployed_history_item_id: str = pydantic.Field()
|
@@ -15,7 +15,7 @@ from .execution_vellum_value import ExecutionVellumValue
|
|
15
15
|
from .workflow_error import WorkflowError
|
16
16
|
from .workflow_execution_actual import WorkflowExecutionActual
|
17
17
|
from .workflow_execution_view_online_eval_metric_result import WorkflowExecutionViewOnlineEvalMetricResult
|
18
|
-
from .
|
18
|
+
from .workflow_execution_usage_result import WorkflowExecutionUsageResult
|
19
19
|
from ..core.pydantic_utilities import IS_PYDANTIC_V2
|
20
20
|
import pydantic
|
21
21
|
|
@@ -30,7 +30,7 @@ class SlimWorkflowExecutionRead(UniversalBaseModel):
|
|
30
30
|
error: typing.Optional[WorkflowError] = None
|
31
31
|
latest_actual: typing.Optional[WorkflowExecutionActual] = None
|
32
32
|
metric_results: typing.List[WorkflowExecutionViewOnlineEvalMetricResult]
|
33
|
-
usage_results: typing.List[
|
33
|
+
usage_results: typing.Optional[typing.List[WorkflowExecutionUsageResult]] = None
|
34
34
|
|
35
35
|
if IS_PYDANTIC_V2:
|
36
36
|
model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict(extra="allow", frozen=True) # type: ignore # Pydantic v2
|
@@ -15,7 +15,7 @@ from .execution_vellum_value import ExecutionVellumValue
|
|
15
15
|
from .workflow_error import WorkflowError
|
16
16
|
from .workflow_execution_actual import WorkflowExecutionActual
|
17
17
|
from .workflow_execution_view_online_eval_metric_result import WorkflowExecutionViewOnlineEvalMetricResult
|
18
|
-
from .
|
18
|
+
from .workflow_execution_usage_result import WorkflowExecutionUsageResult
|
19
19
|
from .vellum_span import VellumSpan
|
20
20
|
from ..core.pydantic_utilities import IS_PYDANTIC_V2
|
21
21
|
import pydantic
|
@@ -31,7 +31,7 @@ class WorkflowEventExecutionRead(UniversalBaseModel):
|
|
31
31
|
error: typing.Optional[WorkflowError] = None
|
32
32
|
latest_actual: typing.Optional[WorkflowExecutionActual] = None
|
33
33
|
metric_results: typing.List[WorkflowExecutionViewOnlineEvalMetricResult]
|
34
|
-
usage_results: typing.List[
|
34
|
+
usage_results: typing.Optional[typing.List[WorkflowExecutionUsageResult]] = None
|
35
35
|
spans: typing.List[VellumSpan]
|
36
36
|
|
37
37
|
if IS_PYDANTIC_V2:
|
@@ -1,16 +1,15 @@
|
|
1
1
|
# This file was auto-generated by Fern from our API Definition.
|
2
2
|
|
3
3
|
from ..core.pydantic_utilities import UniversalBaseModel
|
4
|
-
import
|
5
|
-
from .ml_model_usage_wrapper import MlModelUsageWrapper
|
6
|
-
from .price import Price
|
4
|
+
from .workflow_execution_usage_calculation_error_code_enum import WorkflowExecutionUsageCalculationErrorCodeEnum
|
7
5
|
from ..core.pydantic_utilities import IS_PYDANTIC_V2
|
6
|
+
import typing
|
8
7
|
import pydantic
|
9
8
|
|
10
9
|
|
11
|
-
class
|
12
|
-
|
13
|
-
|
10
|
+
class WorkflowExecutionUsageCalculationError(UniversalBaseModel):
|
11
|
+
code: WorkflowExecutionUsageCalculationErrorCodeEnum
|
12
|
+
message: str
|
14
13
|
|
15
14
|
if IS_PYDANTIC_V2:
|
16
15
|
model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict(extra="allow", frozen=True) # type: ignore # Pydantic v2
|
@@ -0,0 +1,24 @@
|
|
1
|
+
# This file was auto-generated by Fern from our API Definition.
|
2
|
+
|
3
|
+
from ..core.pydantic_utilities import UniversalBaseModel
|
4
|
+
import typing
|
5
|
+
from .ml_model_usage_wrapper import MlModelUsageWrapper
|
6
|
+
from .price import Price
|
7
|
+
from .workflow_execution_usage_calculation_error import WorkflowExecutionUsageCalculationError
|
8
|
+
from ..core.pydantic_utilities import IS_PYDANTIC_V2
|
9
|
+
import pydantic
|
10
|
+
|
11
|
+
|
12
|
+
class WorkflowExecutionUsageResult(UniversalBaseModel):
|
13
|
+
usage: typing.Optional[typing.List[MlModelUsageWrapper]] = None
|
14
|
+
cost: typing.Optional[typing.List[Price]] = None
|
15
|
+
error: typing.Optional[WorkflowExecutionUsageCalculationError] = 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
|
@@ -1,7 +1,7 @@
|
|
1
1
|
from collections import defaultdict
|
2
|
+
import concurrent.futures
|
2
3
|
import logging
|
3
4
|
from queue import Empty, Queue
|
4
|
-
from threading import Thread
|
5
5
|
from typing import (
|
6
6
|
TYPE_CHECKING,
|
7
7
|
Callable,
|
@@ -75,95 +75,90 @@ class MapNode(BaseAdornmentNode[StateType], Generic[StateType, MapNodeItemType])
|
|
75
75
|
return
|
76
76
|
|
77
77
|
self._event_queue: Queue[Tuple[int, WorkflowEvent]] = Queue()
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
78
|
+
fulfilled_iterations: List[bool] = [False] * len(self.items)
|
79
|
+
|
80
|
+
max_workers = self.max_concurrency if self.max_concurrency is not None else len(self.items)
|
81
|
+
|
82
|
+
with concurrent.futures.ThreadPoolExecutor(max_workers=max_workers) as executor:
|
83
|
+
futures = []
|
82
84
|
current_execution_context = get_execution_context()
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
|
118
|
-
|
119
|
-
|
120
|
-
|
121
|
-
|
122
|
-
|
123
|
-
|
124
|
-
|
125
|
-
|
126
|
-
|
85
|
+
for index, item in enumerate(self.items):
|
86
|
+
future = executor.submit(
|
87
|
+
self._context_run_subworkflow,
|
88
|
+
item=item,
|
89
|
+
index=index,
|
90
|
+
current_execution_context=current_execution_context,
|
91
|
+
)
|
92
|
+
futures.append(future)
|
93
|
+
|
94
|
+
while not all(fulfilled_iterations):
|
95
|
+
try:
|
96
|
+
map_node_event = self._event_queue.get(block=False)
|
97
|
+
index = map_node_event[0]
|
98
|
+
subworkflow_event = map_node_event[1]
|
99
|
+
self._context._emit_subworkflow_event(subworkflow_event)
|
100
|
+
|
101
|
+
if not is_workflow_event(subworkflow_event):
|
102
|
+
continue
|
103
|
+
|
104
|
+
if subworkflow_event.workflow_definition != self.subworkflow:
|
105
|
+
continue
|
106
|
+
|
107
|
+
if subworkflow_event.name == "workflow.execution.initiated":
|
108
|
+
for output_name in mapped_items.keys():
|
109
|
+
yield BaseOutput(name=output_name, delta=(None, index, "INITIATED"))
|
110
|
+
|
111
|
+
elif subworkflow_event.name == "workflow.execution.fulfilled":
|
112
|
+
for output_reference, output_value in subworkflow_event.outputs:
|
113
|
+
if not isinstance(output_reference, OutputReference):
|
114
|
+
logger.error(
|
115
|
+
"Invalid key to map node's subworkflow event outputs",
|
116
|
+
extra={"output_reference_type": type(output_reference)},
|
117
|
+
)
|
118
|
+
continue
|
119
|
+
|
120
|
+
output_mapped_items = mapped_items[output_reference.name]
|
121
|
+
if index < 0 or index >= len(output_mapped_items):
|
122
|
+
logger.error(
|
123
|
+
"Invalid map node index",
|
124
|
+
extra={"index": index, "output_name": output_reference.name},
|
125
|
+
)
|
126
|
+
continue
|
127
|
+
|
128
|
+
output_mapped_items[index] = output_value
|
129
|
+
yield BaseOutput(
|
130
|
+
name=output_reference.name,
|
131
|
+
delta=(output_value, index, "FULFILLED"),
|
127
132
|
)
|
128
|
-
continue
|
129
133
|
|
130
|
-
|
131
|
-
if index < 0 or index >= len(output_mapped_items):
|
132
|
-
logger.error(
|
133
|
-
"Invalid map node index", extra={"index": index, "output_name": output_reference.name}
|
134
|
-
)
|
135
|
-
continue
|
134
|
+
fulfilled_iterations[index] = True
|
136
135
|
|
137
|
-
|
138
|
-
|
139
|
-
|
140
|
-
|
136
|
+
elif subworkflow_event.name == "workflow.execution.paused":
|
137
|
+
raise NodeException(
|
138
|
+
code=WorkflowErrorCode.INVALID_OUTPUTS,
|
139
|
+
message=f"Subworkflow unexpectedly paused on iteration {index}",
|
141
140
|
)
|
141
|
+
elif subworkflow_event.name == "workflow.execution.rejected":
|
142
|
+
raise NodeException(
|
143
|
+
f"Subworkflow failed on iteration {index} with error: {subworkflow_event.error.message}",
|
144
|
+
code=subworkflow_event.error.code,
|
145
|
+
)
|
146
|
+
except Empty:
|
147
|
+
all_futures_done = all(future.done() for future in futures)
|
142
148
|
|
143
|
-
|
144
|
-
|
145
|
-
|
146
|
-
|
147
|
-
|
148
|
-
|
149
|
-
|
150
|
-
raise NodeException(
|
151
|
-
code=WorkflowErrorCode.INVALID_OUTPUTS,
|
152
|
-
message=f"Subworkflow unexpectedly paused on iteration {index}",
|
153
|
-
)
|
154
|
-
elif subworkflow_event.name == "workflow.execution.rejected":
|
155
|
-
raise NodeException(
|
156
|
-
f"Subworkflow failed on iteration {index} with error: {subworkflow_event.error.message}",
|
157
|
-
code=subworkflow_event.error.code,
|
158
|
-
)
|
159
|
-
except Empty:
|
160
|
-
pass
|
149
|
+
if all_futures_done:
|
150
|
+
if not all(fulfilled_iterations):
|
151
|
+
if self._event_queue.empty():
|
152
|
+
logger.warning("All threads completed but not all iterations fulfilled")
|
153
|
+
break
|
154
|
+
else:
|
155
|
+
break
|
161
156
|
|
162
157
|
for output_name, output_list in mapped_items.items():
|
163
158
|
yield BaseOutput(name=output_name, value=output_list)
|
164
159
|
|
165
160
|
def _context_run_subworkflow(
|
166
|
-
self,
|
161
|
+
self, item: MapNodeItemType, index: int, current_execution_context: ExecutionContext
|
167
162
|
) -> None:
|
168
163
|
parent_context = current_execution_context.parent_context
|
169
164
|
trace_id = current_execution_context.trace_id
|
@@ -186,14 +181,6 @@ class MapNode(BaseAdornmentNode[StateType], Generic[StateType, MapNodeItemType])
|
|
186
181
|
for event in events:
|
187
182
|
self._event_queue.put((index, event))
|
188
183
|
|
189
|
-
def _start_thread(self) -> bool:
|
190
|
-
if self._concurrency_queue.empty():
|
191
|
-
return False
|
192
|
-
|
193
|
-
thread = self._concurrency_queue.get()
|
194
|
-
thread.start()
|
195
|
-
return True
|
196
|
-
|
197
184
|
@overload
|
198
185
|
@classmethod
|
199
186
|
def wrap(
|
@@ -1,3 +1,5 @@
|
|
1
|
+
import datetime
|
2
|
+
import threading
|
1
3
|
import time
|
2
4
|
|
3
5
|
from vellum.workflows.inputs.base import BaseInputs
|
@@ -172,3 +174,50 @@ def test_map_node__nested_map_node():
|
|
172
174
|
["apple carrot", "apple potato"],
|
173
175
|
["banana carrot", "banana potato"],
|
174
176
|
]
|
177
|
+
|
178
|
+
|
179
|
+
def test_map_node_parallel_execution_with_workflow():
|
180
|
+
# TODO: Find a better way to test this such that it represents what a user would see.
|
181
|
+
# https://linear.app/vellum/issue/APO-482/find-a-better-way-to-test-concurrency-with-map-nodes
|
182
|
+
thread_ids = {}
|
183
|
+
|
184
|
+
# GIVEN a series of nodes that simulate work
|
185
|
+
class BaseNode1(BaseNode):
|
186
|
+
item = MapNode.SubworkflowInputs.item
|
187
|
+
|
188
|
+
class Outputs(BaseOutputs):
|
189
|
+
output: str
|
190
|
+
thread_id: int
|
191
|
+
|
192
|
+
def run(self) -> Outputs:
|
193
|
+
current_thread_id = threading.get_ident()
|
194
|
+
thread_ids[self.item] = current_thread_id
|
195
|
+
|
196
|
+
# Simulate work
|
197
|
+
time.sleep(0.01)
|
198
|
+
|
199
|
+
end = time.time()
|
200
|
+
end_str = datetime.datetime.fromtimestamp(end).strftime("%Y-%m-%d %H:%M:%S.%f")
|
201
|
+
|
202
|
+
return self.Outputs(output=end_str, thread_id=current_thread_id)
|
203
|
+
|
204
|
+
# AND a workflow that connects these nodes
|
205
|
+
class TestWorkflow(BaseWorkflow[MapNode.SubworkflowInputs, BaseState]):
|
206
|
+
graph = BaseNode1
|
207
|
+
|
208
|
+
class Outputs(BaseWorkflow.Outputs):
|
209
|
+
final_output = BaseNode1.Outputs.output
|
210
|
+
thread_id = BaseNode1.Outputs.thread_id
|
211
|
+
|
212
|
+
# AND a map node that uses this workflow
|
213
|
+
class TestMapNode(MapNode):
|
214
|
+
items = [1, 2, 3]
|
215
|
+
subworkflow = TestWorkflow
|
216
|
+
|
217
|
+
# WHEN we run the map node
|
218
|
+
node = TestMapNode()
|
219
|
+
list(node.run())
|
220
|
+
|
221
|
+
# AND each item should have run on a different thread
|
222
|
+
thread_ids_list = list(thread_ids.values())
|
223
|
+
assert len(set(thread_ids_list)) == 3
|
@@ -13,6 +13,7 @@ from vellum.workflows.inputs.base import BaseInputs
|
|
13
13
|
from vellum.workflows.outputs.base import BaseOutput, BaseOutputs
|
14
14
|
from vellum.workflows.ports.port import Port
|
15
15
|
from vellum.workflows.state.base import BaseState, NodeExecutionCache
|
16
|
+
from vellum.workflows.utils.functions import compile_function_definition
|
16
17
|
|
17
18
|
|
18
19
|
class DefaultStateEncoder(JSONEncoder):
|
@@ -57,6 +58,9 @@ class DefaultStateEncoder(JSONEncoder):
|
|
57
58
|
if isinstance(obj, type):
|
58
59
|
return str(obj)
|
59
60
|
|
61
|
+
if callable(obj):
|
62
|
+
return compile_function_definition(obj)
|
63
|
+
|
60
64
|
if obj.__class__ in self.encoders:
|
61
65
|
return self.encoders[obj.__class__](obj)
|
62
66
|
|
@@ -276,6 +276,14 @@ class BaseWorkflow(Generic[InputsType, StateType], metaclass=_BaseWorkflowMeta):
|
|
276
276
|
"""
|
277
277
|
return cls._get_edges_from_subgraphs(cls.get_unused_subgraphs())
|
278
278
|
|
279
|
+
@classmethod
|
280
|
+
def get_all_nodes(cls) -> Iterator[Type[BaseNode]]:
|
281
|
+
"""
|
282
|
+
Returns an iterator over all nodes in the Workflow, used or unused.
|
283
|
+
"""
|
284
|
+
yield from cls.get_nodes()
|
285
|
+
yield from cls.get_unused_nodes()
|
286
|
+
|
279
287
|
@classmethod
|
280
288
|
def get_entrypoints(cls) -> Iterable[Type[BaseNode]]:
|
281
289
|
return iter({e for g in cls.get_subgraphs() for e in g.entrypoints})
|
@@ -26,8 +26,8 @@ vellum_ee/workflows/display/base.py,sha256=EqlQFD56kpqMY02ZBJBQajzJKh33Dwi60Wo77
|
|
26
26
|
vellum_ee/workflows/display/editor/__init__.py,sha256=MSAgY91xCEg2neH5d8jXx5wRdR962ftZVa6vO9BGq9k,167
|
27
27
|
vellum_ee/workflows/display/editor/types.py,sha256=x-tOOCJ6CF4HmiKDfCmcc3bOVfc1EBlP5o6u5WEfLoY,567
|
28
28
|
vellum_ee/workflows/display/nodes/__init__.py,sha256=jI1aPBQf8DkmrYoZ4O-wR1duqZByOf5mDFmo_wFJPE4,307
|
29
|
-
vellum_ee/workflows/display/nodes/base_node_display.py,sha256=
|
30
|
-
vellum_ee/workflows/display/nodes/get_node_display_class.py,sha256=
|
29
|
+
vellum_ee/workflows/display/nodes/base_node_display.py,sha256=mzODbbNfrjOi7rVQb6FFCEjQHZkTs76nAc8L-Q5yCnQ,16491
|
30
|
+
vellum_ee/workflows/display/nodes/get_node_display_class.py,sha256=jI_kUi9LnNLDpY63QtlC4TfN8P571VN4LpzH0I1ZtLk,1149
|
31
31
|
vellum_ee/workflows/display/nodes/tests/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
32
32
|
vellum_ee/workflows/display/nodes/tests/test_base_node_display.py,sha256=Z4Mf7xLCNiblSbpKI0BrV5modQr-ZcFzhfir_OSyTTs,2997
|
33
33
|
vellum_ee/workflows/display/nodes/types.py,sha256=St1BB6no528OyELGiyRabWao0GGw6mLhstQAvEACbGk,247
|
@@ -89,19 +89,20 @@ vellum_ee/workflows/display/tests/workflow_serialization/test_basic_search_node_
|
|
89
89
|
vellum_ee/workflows/display/tests/workflow_serialization/test_basic_subworkflow_deployment_serialization.py,sha256=KkYZc_bZuq1lmDcvUz3QxIqJLpQPCZioD1FHUNsMJY8,11211
|
90
90
|
vellum_ee/workflows/display/tests/workflow_serialization/test_basic_templating_node_serialization.py,sha256=aZaqRDrkO3ytcmdM2eKJqHSt60MF070NMj6M2vgzOKc,7711
|
91
91
|
vellum_ee/workflows/display/tests/workflow_serialization/test_basic_terminal_node_serialization.py,sha256=r748dpS13HtwY7t_KQFExFssxRy0xI2d-wxmhiUHRe0,3850
|
92
|
+
vellum_ee/workflows/display/tests/workflow_serialization/test_basic_tool_calling_node_serialization.py,sha256=rp9suYcwVZPpIQ3ChlWWvahMlaUd7u-31VmesR0Mn8w,7683
|
92
93
|
vellum_ee/workflows/display/tests/workflow_serialization/test_basic_try_node_serialization.py,sha256=EL5kfakuoEcwD85dGjhMta-J-PpCHRSDoc80SdbBrQk,2769
|
93
94
|
vellum_ee/workflows/display/tests/workflow_serialization/test_complex_terminal_node_serialization.py,sha256=RmFUDx8dYdfsOE2CGLvdXqNNRtLLpVzXDN8dqZyMcZ8,5822
|
94
95
|
vellum_ee/workflows/display/types.py,sha256=i4T7ElU5b5h-nA1i3scmEhO1BqmNDc4eJDHavATD88w,2821
|
95
96
|
vellum_ee/workflows/display/utils/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
96
97
|
vellum_ee/workflows/display/utils/exceptions.py,sha256=LSwwxCYNxFkf5XMUcFkaZKpQ13OSrI7y_bpEUwbKVk0,169
|
97
|
-
vellum_ee/workflows/display/utils/expressions.py,sha256=
|
98
|
+
vellum_ee/workflows/display/utils/expressions.py,sha256=qsKRgxm9zKFgAgjc9LqKEWP1rtdzXA1NDsXu9kyhf60,12416
|
98
99
|
vellum_ee/workflows/display/utils/registry.py,sha256=fWIm5Jj-10gNFjgn34iBu4RWv3Vd15ijtSN0V97bpW8,1513
|
99
100
|
vellum_ee/workflows/display/utils/vellum.py,sha256=mtoXmSYwR7rvrq-d6CzCW_auaJXTct0Mi1F0xpRCiNQ,5627
|
100
101
|
vellum_ee/workflows/display/vellum.py,sha256=o7mq_vk2Yapu9DDKRz5l76h8EmCAypWGQYe6pryrbB8,3576
|
101
102
|
vellum_ee/workflows/display/workflows/__init__.py,sha256=kapXsC67VJcgSuiBMa86FdePG5A9kMB5Pi4Uy1O2ob4,207
|
102
|
-
vellum_ee/workflows/display/workflows/base_workflow_display.py,sha256=
|
103
|
+
vellum_ee/workflows/display/workflows/base_workflow_display.py,sha256=DbjLChDtlNAs86sWL5-ojYYzwFsOjACAGfquxM3VYcw,32563
|
103
104
|
vellum_ee/workflows/display/workflows/get_vellum_workflow_display_class.py,sha256=gxz76AeCqgAZ9D2lZeTiZzxY9eMgn3qOSfVgiqYcOh8,2028
|
104
|
-
vellum_ee/workflows/display/workflows/tests/test_workflow_display.py,sha256=
|
105
|
+
vellum_ee/workflows/display/workflows/tests/test_workflow_display.py,sha256=rRwXLgsXqiaSn3jzP7lc--pytRW3Jmnj2-zNq5l-FQ4,29472
|
105
106
|
vellum_ee/workflows/display/workflows/vellum_workflow_display.py,sha256=aaKdmWrgEe5YyV4zuDY_4E3y-l59rIHQnNGiPj2OWxQ,359
|
106
107
|
vellum_ee/workflows/server/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
107
108
|
vellum_ee/workflows/server/virtual_file_loader.py,sha256=7JphJcSO3H85qiC2DpFfBWjC3JjrbRmoynBC6KKHVsA,2710
|
@@ -127,12 +128,12 @@ vellum_ee/workflows/tests/local_workflow/workflow.py,sha256=A4qOzOPNwePYxWbcAgIP
|
|
127
128
|
vellum_ee/workflows/tests/test_display_meta.py,sha256=C25dErwghPNXio49pvSRxyOuc96srH6eYEwTAWdE2zY,2258
|
128
129
|
vellum_ee/workflows/tests/test_server.py,sha256=SsOkS6sGO7uGC4mxvk4iv8AtcXs058P9hgFHzTWmpII,14519
|
129
130
|
vellum_ee/workflows/tests/test_virtual_files.py,sha256=TJEcMR0v2S8CkloXNmCHA0QW0K6pYNGaIjraJz7sFvY,2762
|
130
|
-
vellum/__init__.py,sha256=
|
131
|
+
vellum/__init__.py,sha256=Hqfl49WZJzzqOKzVsTGi-j9twIqFOoRmACJsrEsjL44,41918
|
131
132
|
vellum/client/README.md,sha256=qmaVIP42MnxAu8jV7u-CsgVFfs3-pHQODrXdZdFxtaw,4749
|
132
133
|
vellum/client/__init__.py,sha256=PEnFl7LbXQcvAi3bVN2qyt5xm2FtVtq7xWKkcWM3Tg4,120166
|
133
134
|
vellum/client/core/__init__.py,sha256=SQ85PF84B9MuKnBwHNHWemSGuy-g_515gFYNFhvEE0I,1438
|
134
135
|
vellum/client/core/api_error.py,sha256=RE8LELok2QCjABadECTvtDp7qejA1VmINCh6TbqPwSE,426
|
135
|
-
vellum/client/core/client_wrapper.py,sha256=
|
136
|
+
vellum/client/core/client_wrapper.py,sha256=0Uo8ifbV1rC2jIjuU95Td5DeLVDs0xqQP3DETAbhbEU,1869
|
136
137
|
vellum/client/core/datetime_utils.py,sha256=nBys2IsYrhPdszxGKCNRPSOCwa-5DWOHG95FB8G9PKo,1047
|
137
138
|
vellum/client/core/file.py,sha256=d4NNbX8XvXP32z8KpK2Xovv33nFfruIrpz0QWxlgpZk,2663
|
138
139
|
vellum/client/core/http_client.py,sha256=Z77OIxIbL4OAB2IDqjRq_sYa5yNYAWfmdhdCSSvh6Y4,19552
|
@@ -200,7 +201,7 @@ vellum/client/resources/workspace_secrets/__init__.py,sha256=FTtvy8EDg9nNNg9WCat
|
|
200
201
|
vellum/client/resources/workspace_secrets/client.py,sha256=zlBdbeTP6sqvtyl_DlrpfG-W5hSP7tJ1NYLSygi4CLU,8205
|
201
202
|
vellum/client/resources/workspaces/__init__.py,sha256=FTtvy8EDg9nNNg9WCatVgKTRYV8-_v1roeGPAKoa_pw,65
|
202
203
|
vellum/client/resources/workspaces/client.py,sha256=RthwzN1o-Jxwg5yyNNodavFyNUSxfLoTv26w3mRR5g8,3595
|
203
|
-
vellum/client/types/__init__.py,sha256=
|
204
|
+
vellum/client/types/__init__.py,sha256=wFQ3c_Pu8mGQFHIUy5dORq6Afmp5jdl9pnfUizIXjtI,63474
|
204
205
|
vellum/client/types/ad_hoc_execute_prompt_event.py,sha256=bCjujA2XsOgyF3bRZbcEqV2rOIymRgsLoIRtZpB14xg,607
|
205
206
|
vellum/client/types/ad_hoc_expand_meta.py,sha256=1gv-NCsy_6xBYupLvZH979yf2VMdxAU-l0y0ynMKZaw,1331
|
206
207
|
vellum/client/types/ad_hoc_fulfilled_prompt_execution_meta.py,sha256=oDG60TpwK1YNSKhRsBbiP2O3ZF9PKR-M9chGIfKw4R4,1004
|
@@ -271,7 +272,7 @@ vellum/client/types/create_test_suite_test_case_request.py,sha256=3LmAy6U8tUJ75d
|
|
271
272
|
vellum/client/types/deployment_history_item.py,sha256=-u7UYEFpVOlFijErPLGO99WYQxAnctZK52W-GM4KJJU,1132
|
272
273
|
vellum/client/types/deployment_provider_payload_response.py,sha256=b0lkt0rK88ARQaMWn9MAHeWtMBsZKofDMlOAUsQvv7g,818
|
273
274
|
vellum/client/types/deployment_provider_payload_response_payload.py,sha256=xHLQnWFN0AZRZdrOiKawwpoKK7BTmnZfp0P7FCc2ZqE,188
|
274
|
-
vellum/client/types/deployment_read.py,sha256=
|
275
|
+
vellum/client/types/deployment_read.py,sha256=l6cy00p4y7JncJ-BwVl_NdCVWPNRjZqFz6DdL2vTTqY,1977
|
275
276
|
vellum/client/types/deployment_release_tag_deployment_history_item.py,sha256=df4qKHT1f-z0jnRS4UmP8MQe6u3PwYej_d8KDF7EL88,631
|
276
277
|
vellum/client/types/deployment_release_tag_read.py,sha256=dUrTOz9LH1gAvC_ktMB_7NztkeBnlNSX_9x15Ld3D3I,1278
|
277
278
|
vellum/client/types/docker_service_token.py,sha256=T0icNHBKsIs6TrEiDRjckM_f37hcF1DMwEE8161tTvY,614
|
@@ -565,7 +566,7 @@ vellum/client/types/slim_document.py,sha256=HJiymYPvRxfxhBUkD8epW0hQ2Vt9PQtv398Q
|
|
565
566
|
vellum/client/types/slim_document_document_to_document_index.py,sha256=vo7WbRRzbApQxT0MZu_NkjQmsFD8LoezmyeKBeGZpI8,1346
|
566
567
|
vellum/client/types/slim_release_review.py,sha256=7DXmD1AVa_Wj7e0qiR7GUN9cSqwkk1JloYmp_3oluQQ,783
|
567
568
|
vellum/client/types/slim_workflow_deployment.py,sha256=Js-ycMFZ8-kNFPsd4bZew9nI_eN2M_58LzDHeCjkfTg,2009
|
568
|
-
vellum/client/types/slim_workflow_execution_read.py,sha256=
|
569
|
+
vellum/client/types/slim_workflow_execution_read.py,sha256=Opm1HTYVMz_D2USQCB-5ZoJ4EjKKfrDhoXc0hETldVM,1936
|
569
570
|
vellum/client/types/span_link.py,sha256=2NISI8V94W0MeIdos7aSKFmpVJgEEunuSEnKlWTUH5c,1353
|
570
571
|
vellum/client/types/span_link_type_enum.py,sha256=NaBXnHnOKMZvgHfjhwJJNqM4wuTOxtGkMIXjN2hU-6A,130
|
571
572
|
vellum/client/types/streaming_ad_hoc_execute_prompt_event.py,sha256=NdgmJ3AZMp6io-whZIGnGb49aiqz6__KafsrzjEF_9o,1183
|
@@ -717,7 +718,7 @@ vellum/client/types/workflow_deployment_release_workflow_deployment.py,sha256=ir
|
|
717
718
|
vellum/client/types/workflow_deployment_release_workflow_version.py,sha256=V1Eb3goBX2lle851LkhR1tbCFa0z_O-yhMuQWCN6c-g,773
|
718
719
|
vellum/client/types/workflow_error.py,sha256=EQajkEmLS64T0wYm0goHQl0rT7Lguurk8pLwkhjsgAI,282
|
719
720
|
vellum/client/types/workflow_event_error.py,sha256=HIewu_kh3KNPpWegAQArvAGHCp-cBIXqlUAAc_dBZhc,687
|
720
|
-
vellum/client/types/workflow_event_execution_read.py,sha256=
|
721
|
+
vellum/client/types/workflow_event_execution_read.py,sha256=TQaBs2ZkOOJOjCkdmgI9ZX7c4XgIaNIBozCmZlOoZp8,2008
|
721
722
|
vellum/client/types/workflow_execution_actual.py,sha256=YL5WL4O4CyaZWSrxqpE4chJ28EJlyScj5JeaLttegEg,843
|
722
723
|
vellum/client/types/workflow_execution_actual_chat_history_request.py,sha256=L6U8tgM7SiU4qGJMZChFzj6HfHgO-YAlTXfbT7ZIaE4,1993
|
723
724
|
vellum/client/types/workflow_execution_actual_json_request.py,sha256=5QYaPCSOwFnjH_kTrB2bTznTMFExSZdBhTkmelf1h4Q,1931
|
@@ -741,7 +742,9 @@ vellum/client/types/workflow_execution_span.py,sha256=3vHEx3k31fLacQaV2iMT-vibjw
|
|
741
742
|
vellum/client/types/workflow_execution_span_attributes.py,sha256=SRW7mD-6uS8eA57EU6q2thBqSFfJSH4tXI9H3szZwYQ,575
|
742
743
|
vellum/client/types/workflow_execution_streaming_body.py,sha256=phni9pJKkFGsQ5IcS4ogtG1EjBzpdBiYpN9CPbkjxH8,746
|
743
744
|
vellum/client/types/workflow_execution_streaming_event.py,sha256=_xazehYJ5ZwTDc5cC7rpX7nDir_4glPOnx9c9ZPod1g,1551
|
744
|
-
vellum/client/types/
|
745
|
+
vellum/client/types/workflow_execution_usage_calculation_error.py,sha256=O44pAaA3pOpn6dqxfsAFx4QnXeVfIggGWbgmTzQV4Ms,754
|
746
|
+
vellum/client/types/workflow_execution_usage_calculation_error_code_enum.py,sha256=O8CGCaWKuhnRjmQXTsw4gQn5hfDFiKED8bJYzP8R0LM,258
|
747
|
+
vellum/client/types/workflow_execution_usage_result.py,sha256=wZdRqzG_Lwi8gqDHGEU6ayx3pvO9oe8hIPzDDePELz8,928
|
745
748
|
vellum/client/types/workflow_execution_view_online_eval_metric_result.py,sha256=1qxIHqBRhEMfbOhBpztOPhcH3mqe7bfezO7PUHUfDg4,759
|
746
749
|
vellum/client/types/workflow_execution_workflow_result_event.py,sha256=gjyXmojwtAOtAzpILpFkJB9tM02okSXqYRw9-3rTVDA,939
|
747
750
|
vellum/client/types/workflow_expand_meta_request.py,sha256=-6I1Zveo3wFJEWbmSsN9OiOI7ekCJxF4xEL_ApB6XE8,1151
|
@@ -1415,7 +1418,9 @@ vellum/types/workflow_execution_span.py,sha256=qnyiKgPrKKl0lvVtmpm09zOMTWKDBZ9nD
|
|
1415
1418
|
vellum/types/workflow_execution_span_attributes.py,sha256=LCyfr-e1lwrTpMge9agbjtVDxt1l1FTZK8koMqxy6VM,172
|
1416
1419
|
vellum/types/workflow_execution_streaming_body.py,sha256=MjkV8RLMtFj1r0yGPIuhf4Dz_EFeVU2tN8Oz6-cPssQ,171
|
1417
1420
|
vellum/types/workflow_execution_streaming_event.py,sha256=XDEyaGRMfR9cpaRJ-WCb0O-o4LAdoMPCbjRLdYI1r-0,172
|
1418
|
-
vellum/types/
|
1421
|
+
vellum/types/workflow_execution_usage_calculation_error.py,sha256=tMF1PYRRKjC0N-GL_Az2A8Mv-1H8tS3oln_NPh6k3zo,180
|
1422
|
+
vellum/types/workflow_execution_usage_calculation_error_code_enum.py,sha256=HMqRue9gC5NRgbqt_FhANKGeNz8Vgu9fjZpEvRTek9o,190
|
1423
|
+
vellum/types/workflow_execution_usage_result.py,sha256=SrVrcv5xngwbS-6eCWU4XJ9QyyUwGJ1mPfgHPOhNqbs,169
|
1419
1424
|
vellum/types/workflow_execution_view_online_eval_metric_result.py,sha256=dLnk3CfQOAeYIO5kiR0U8SY4JcqFWvVYwkDL-LkA5Co,187
|
1420
1425
|
vellum/types/workflow_execution_workflow_result_event.py,sha256=3bNxtChEfqny5eEazFcGmqQpmC8283Q0J2hxLje-uks,178
|
1421
1426
|
vellum/types/workflow_expand_meta_request.py,sha256=Ahb7gjZekJ5qI0HGHLCbn3hCpkX08EnzeXEH_3ivB4E,166
|
@@ -1551,9 +1556,9 @@ vellum/workflows/nodes/core/inline_subworkflow_node/node.py,sha256=rgcjc3gaCEX9u
|
|
1551
1556
|
vellum/workflows/nodes/core/inline_subworkflow_node/tests/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
1552
1557
|
vellum/workflows/nodes/core/inline_subworkflow_node/tests/test_node.py,sha256=kUqwcRMMxjTHALbwGUXCJT_aJBrHS1bkg49oL8R0JO8,4337
|
1553
1558
|
vellum/workflows/nodes/core/map_node/__init__.py,sha256=MXpZYmGfhsMJHqqlpd64WiJRtbAtAMQz-_3fCU_cLV0,56
|
1554
|
-
vellum/workflows/nodes/core/map_node/node.py,sha256=
|
1559
|
+
vellum/workflows/nodes/core/map_node/node.py,sha256=rbF7fLAU0vUDEpgtWqeQTZFlhWOhJw38tgxWJ6exud8,9313
|
1555
1560
|
vellum/workflows/nodes/core/map_node/tests/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
1556
|
-
vellum/workflows/nodes/core/map_node/tests/test_node.py,sha256=
|
1561
|
+
vellum/workflows/nodes/core/map_node/tests/test_node.py,sha256=f3lSPYAU1vJUCLCujNOo0EAeBbOM9hnY5A1Wy58korc,6905
|
1557
1562
|
vellum/workflows/nodes/core/retry_node/__init__.py,sha256=lN2bIy5a3Uzhs_FYCrooADyYU6ZGShtvLKFWpelwPvo,60
|
1558
1563
|
vellum/workflows/nodes/core/retry_node/node.py,sha256=abtGvinLfi1tKqYIsWQKZtBUisF2Qw2yT1YoPw9cVk4,5297
|
1559
1564
|
vellum/workflows/nodes/core/retry_node/tests/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
@@ -1668,7 +1673,7 @@ vellum/workflows/sandbox.py,sha256=GVJzVjMuYzOBnSrboB0_6MMRZWBluAyQ2o7syeaeBd0,2
|
|
1668
1673
|
vellum/workflows/state/__init__.py,sha256=yUUdR-_Vl7UiixNDYQZ-GEM_kJI9dnOia75TtuNEsnE,60
|
1669
1674
|
vellum/workflows/state/base.py,sha256=ZXDmVafs6sExcbx1azrZjEGQsmuY68mSRWfI7t2PT4c,22330
|
1670
1675
|
vellum/workflows/state/context.py,sha256=KOAI1wEGn8dGmhmAemJaf4SZbitP3jpIBcwKfznQaRE,3076
|
1671
|
-
vellum/workflows/state/encoder.py,sha256=
|
1676
|
+
vellum/workflows/state/encoder.py,sha256=z7Mk6jQC-92wCj6XTK7VEnJ8px_lU8qy0BINqwGDN4I,2063
|
1672
1677
|
vellum/workflows/state/store.py,sha256=uVe-oN73KwGV6M6YLhwZMMUQhzTQomsVfVnb8V91gVo,1147
|
1673
1678
|
vellum/workflows/state/tests/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
1674
1679
|
vellum/workflows/state/tests/test_state.py,sha256=YOiC9qZAzkdiqb7nRarNWeDwxo7xHv3y3czlHl81ezg,6741
|
@@ -1696,13 +1701,13 @@ vellum/workflows/utils/uuids.py,sha256=DFzPv9RCvsKhvdTEIQyfSek2A31D6S_QcmeLPbgrg
|
|
1696
1701
|
vellum/workflows/utils/vellum_variables.py,sha256=UiGlUh0a8vel2FbW3w-xbHxSv_jNutkDdqMVtP_b42A,3385
|
1697
1702
|
vellum/workflows/vellum_client.py,sha256=xkfoucodxNK5JR2-lbRqZx3xzDgExWkP6kySrpi_Ubc,1079
|
1698
1703
|
vellum/workflows/workflows/__init__.py,sha256=KY45TqvavCCvXIkyCFMEc0dc6jTMOUci93U2DUrlZYc,66
|
1699
|
-
vellum/workflows/workflows/base.py,sha256=
|
1704
|
+
vellum/workflows/workflows/base.py,sha256=V60RZat8mG0XmMuIjprkHnacD_MpUdxGcN9t4TaP_Pg,24044
|
1700
1705
|
vellum/workflows/workflows/event_filters.py,sha256=GSxIgwrX26a1Smfd-6yss2abGCnadGsrSZGa7t7LpJA,2008
|
1701
1706
|
vellum/workflows/workflows/tests/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
1702
1707
|
vellum/workflows/workflows/tests/test_base_workflow.py,sha256=8P5YIsNMO78_CR1NNK6wkEdkMB4b3Q_Ni1qxh78OnHo,20481
|
1703
1708
|
vellum/workflows/workflows/tests/test_context.py,sha256=VJBUcyWVtMa_lE5KxdhgMu0WYNYnUQUDvTF7qm89hJ0,2333
|
1704
|
-
vellum_ai-0.14.
|
1705
|
-
vellum_ai-0.14.
|
1706
|
-
vellum_ai-0.14.
|
1707
|
-
vellum_ai-0.14.
|
1708
|
-
vellum_ai-0.14.
|
1709
|
+
vellum_ai-0.14.50.dist-info/LICENSE,sha256=hOypcdt481qGNISA784bnAGWAE6tyIf9gc2E78mYC3E,1574
|
1710
|
+
vellum_ai-0.14.50.dist-info/METADATA,sha256=E3j3kzjmM-9HAa1xAKCgCf5JsoBVzbm7vadnxywpahY,5484
|
1711
|
+
vellum_ai-0.14.50.dist-info/WHEEL,sha256=sP946D7jFCHeNz5Iq4fL4Lu-PrWrFsgfLXbbkciIZwg,88
|
1712
|
+
vellum_ai-0.14.50.dist-info/entry_points.txt,sha256=HCH4yc_V3J_nDv3qJzZ_nYS8llCHZViCDP1ejgCc5Ak,42
|
1713
|
+
vellum_ai-0.14.50.dist-info/RECORD,,
|
@@ -44,18 +44,40 @@ if TYPE_CHECKING:
|
|
44
44
|
_NodeDisplayAttrType = TypeVar("_NodeDisplayAttrType")
|
45
45
|
|
46
46
|
|
47
|
+
def _get_node_input_ids_by_ref(node_class: Type[BaseNode], path: str, inst: Any):
|
48
|
+
if isinstance(inst, dict):
|
49
|
+
node_input_ids_by_name: Dict[str, UUID] = {}
|
50
|
+
for key, value in inst.items():
|
51
|
+
node_input_ids_by_name.update(_get_node_input_ids_by_ref(node_class, f"{path}.{key}", value))
|
52
|
+
return node_input_ids_by_name
|
53
|
+
|
54
|
+
return {path: uuid4_from_hash(f"{node_class.__id__}|{path}")}
|
55
|
+
|
56
|
+
|
47
57
|
class BaseNodeDisplayMeta(type):
|
48
58
|
def __new__(mcs, name: str, bases: Tuple[Type, ...], dct: Dict[str, Any]) -> Any:
|
49
59
|
cls = cast(Type["BaseNodeDisplay"], super().__new__(mcs, name, bases, dct))
|
60
|
+
# This cast shouldn't be necessary, but it's a workaround for a mypy bug
|
61
|
+
node_class = cast(Type[BaseNode], cls.infer_node_class() if name != "BaseNodeDisplay" else BaseNode)
|
50
62
|
|
51
63
|
if not dct.get("output_display"):
|
52
|
-
node_class = cls.infer_node_class()
|
53
64
|
cls.output_display = {
|
54
65
|
ref: NodeOutputDisplay(id=node_class.__output_ids__[ref.name], name=ref.name)
|
55
66
|
for ref in node_class.Outputs
|
56
67
|
if ref.name in node_class.__output_ids__
|
57
68
|
}
|
58
69
|
|
70
|
+
if not dct.get("node_input_ids_by_name"):
|
71
|
+
node_input_ids_by_name: Dict[str, UUID] = {}
|
72
|
+
for ref in node_class:
|
73
|
+
if ref not in cls.__serializable_inputs__:
|
74
|
+
continue
|
75
|
+
|
76
|
+
node_input_ids_by_name.update(_get_node_input_ids_by_ref(node_class, ref.name, ref.instance))
|
77
|
+
|
78
|
+
if node_input_ids_by_name:
|
79
|
+
cls.node_input_ids_by_name = node_input_ids_by_name
|
80
|
+
|
59
81
|
return cls.__annotate_node__()
|
60
82
|
|
61
83
|
def __annotate_node__(cls):
|
@@ -1,9 +1,7 @@
|
|
1
1
|
import types
|
2
|
-
from
|
3
|
-
from typing import TYPE_CHECKING, Any, Dict, Generic, Type, TypeVar
|
2
|
+
from typing import TYPE_CHECKING, Generic, Type, TypeVar
|
4
3
|
|
5
4
|
from vellum.workflows.types.generics import NodeType
|
6
|
-
from vellum.workflows.utils.uuids import uuid4_from_hash
|
7
5
|
from vellum_ee.workflows.display.utils.registry import get_from_node_display_registry
|
8
6
|
|
9
7
|
if TYPE_CHECKING:
|
@@ -22,30 +20,9 @@ def get_node_display_class(node_class: Type[NodeType]) -> Type["BaseNodeDisplay"
|
|
22
20
|
# `base_node_display_class` is always a Generic class, so it's safe to index into it
|
23
21
|
NodeDisplayBaseClass = base_node_display_class[_NodeClassType] # type: ignore[index]
|
24
22
|
|
25
|
-
def _get_node_input_ids_by_ref(path: str, inst: Any):
|
26
|
-
if isinstance(inst, dict):
|
27
|
-
node_input_ids_by_name: Dict[str, UUID] = {}
|
28
|
-
for key, value in inst.items():
|
29
|
-
node_input_ids_by_name.update(_get_node_input_ids_by_ref(f"{path}.{key}", value))
|
30
|
-
return node_input_ids_by_name
|
31
|
-
|
32
|
-
return {path: uuid4_from_hash(f"{node_class.__id__}|{path}")}
|
33
|
-
|
34
|
-
def exec_body(ns: Dict):
|
35
|
-
node_input_ids_by_name: Dict[str, UUID] = {}
|
36
|
-
for ref in node_class:
|
37
|
-
if ref not in base_node_display_class.__serializable_inputs__:
|
38
|
-
continue
|
39
|
-
|
40
|
-
node_input_ids_by_name.update(_get_node_input_ids_by_ref(ref.name, ref.instance))
|
41
|
-
|
42
|
-
if node_input_ids_by_name:
|
43
|
-
ns["node_input_ids_by_name"] = node_input_ids_by_name
|
44
|
-
|
45
23
|
NodeDisplayClass = types.new_class(
|
46
24
|
f"{node_class.__name__}Display",
|
47
25
|
bases=(NodeDisplayBaseClass, Generic[_NodeClassType]),
|
48
|
-
exec_body=exec_body,
|
49
26
|
)
|
50
27
|
|
51
28
|
return NodeDisplayClass
|
@@ -0,0 +1,177 @@
|
|
1
|
+
from deepdiff import DeepDiff
|
2
|
+
|
3
|
+
from vellum_ee.workflows.display.workflows.get_vellum_workflow_display_class import get_workflow_display
|
4
|
+
|
5
|
+
from tests.workflows.basic_tool_calling_node.workflow import BasicToolCallingNodeWorkflow
|
6
|
+
|
7
|
+
|
8
|
+
def test_serialize_workflow():
|
9
|
+
# GIVEN a Workflow that uses a generic node
|
10
|
+
# WHEN we serialize it
|
11
|
+
workflow_display = get_workflow_display(workflow_class=BasicToolCallingNodeWorkflow)
|
12
|
+
|
13
|
+
serialized_workflow: dict = workflow_display.serialize()
|
14
|
+
# THEN we should get a serialized representation of the Workflow
|
15
|
+
assert serialized_workflow.keys() == {
|
16
|
+
"workflow_raw_data",
|
17
|
+
"input_variables",
|
18
|
+
"state_variables",
|
19
|
+
"output_variables",
|
20
|
+
}
|
21
|
+
|
22
|
+
# AND its input variables should be what we expect
|
23
|
+
input_variables = serialized_workflow["input_variables"]
|
24
|
+
assert len(input_variables) == 0
|
25
|
+
|
26
|
+
# AND its output variables should be what we expect
|
27
|
+
output_variables = serialized_workflow["output_variables"]
|
28
|
+
assert len(output_variables) == 2
|
29
|
+
assert not DeepDiff(
|
30
|
+
[
|
31
|
+
{"id": "8e7c0147-930d-4b7f-b6b1-6d79641cd3eb", "key": "text", "type": "STRING"},
|
32
|
+
{"id": "01a07e6d-7269-4f45-8b44-ef0227a2e88d", "key": "chat_history", "type": "CHAT_HISTORY"},
|
33
|
+
],
|
34
|
+
output_variables,
|
35
|
+
ignore_order=True,
|
36
|
+
)
|
37
|
+
|
38
|
+
# AND its raw data should be what we expect
|
39
|
+
workflow_raw_data = serialized_workflow["workflow_raw_data"]
|
40
|
+
tool_calling_node = workflow_raw_data["nodes"][1]
|
41
|
+
assert tool_calling_node == {
|
42
|
+
"id": "21f29cac-da87-495f-bba1-093d423f4e46",
|
43
|
+
"label": "GetCurrentWeatherNode",
|
44
|
+
"type": "GENERIC",
|
45
|
+
"display_data": {
|
46
|
+
"position": {"x": 0.0, "y": 0.0},
|
47
|
+
"comment": {"value": "\n A tool calling node that calls the get_current_weather function.\n "},
|
48
|
+
},
|
49
|
+
"base": {
|
50
|
+
"name": "ToolCallingNode",
|
51
|
+
"module": ["vellum", "workflows", "nodes", "experimental", "tool_calling_node", "node"],
|
52
|
+
},
|
53
|
+
"definition": {
|
54
|
+
"name": "GetCurrentWeatherNode",
|
55
|
+
"module": ["tests", "workflows", "basic_tool_calling_node", "workflow"],
|
56
|
+
},
|
57
|
+
"trigger": {"id": "2414743b-b1dd-4552-8abf-9b7481df9762", "merge_behavior": "AWAIT_ATTRIBUTES"},
|
58
|
+
"ports": [{"id": "3cd6d78c-9dad-42aa-ad38-31f67057c379", "name": "default", "type": "DEFAULT"}],
|
59
|
+
"adornments": None,
|
60
|
+
"attributes": [
|
61
|
+
{
|
62
|
+
"id": "44420e39-966f-4c59-bdf8-6365a61c5d2a",
|
63
|
+
"name": "ml_model",
|
64
|
+
"value": {"type": "CONSTANT_VALUE", "value": {"type": "STRING", "value": "gpt-4o-mini"}},
|
65
|
+
},
|
66
|
+
{
|
67
|
+
"id": "669cfb4b-8c25-460e-8952-b63d91302cbc",
|
68
|
+
"name": "blocks",
|
69
|
+
"value": {
|
70
|
+
"type": "CONSTANT_VALUE",
|
71
|
+
"value": {
|
72
|
+
"type": "JSON",
|
73
|
+
"value": [
|
74
|
+
{
|
75
|
+
"block_type": "CHAT_MESSAGE",
|
76
|
+
"state": None,
|
77
|
+
"cache_config": None,
|
78
|
+
"chat_role": "SYSTEM",
|
79
|
+
"chat_source": None,
|
80
|
+
"chat_message_unterminated": None,
|
81
|
+
"blocks": [
|
82
|
+
{
|
83
|
+
"block_type": "RICH_TEXT",
|
84
|
+
"state": None,
|
85
|
+
"cache_config": None,
|
86
|
+
"blocks": [
|
87
|
+
{
|
88
|
+
"block_type": "PLAIN_TEXT",
|
89
|
+
"state": None,
|
90
|
+
"cache_config": None,
|
91
|
+
"text": "You are a weather expert",
|
92
|
+
}
|
93
|
+
],
|
94
|
+
}
|
95
|
+
],
|
96
|
+
},
|
97
|
+
{
|
98
|
+
"block_type": "CHAT_MESSAGE",
|
99
|
+
"state": None,
|
100
|
+
"cache_config": None,
|
101
|
+
"chat_role": "USER",
|
102
|
+
"chat_source": None,
|
103
|
+
"chat_message_unterminated": None,
|
104
|
+
"blocks": [
|
105
|
+
{
|
106
|
+
"block_type": "RICH_TEXT",
|
107
|
+
"state": None,
|
108
|
+
"cache_config": None,
|
109
|
+
"blocks": [
|
110
|
+
{
|
111
|
+
"block_type": "VARIABLE",
|
112
|
+
"state": None,
|
113
|
+
"cache_config": None,
|
114
|
+
"input_variable": "question",
|
115
|
+
}
|
116
|
+
],
|
117
|
+
}
|
118
|
+
],
|
119
|
+
},
|
120
|
+
],
|
121
|
+
},
|
122
|
+
},
|
123
|
+
},
|
124
|
+
{
|
125
|
+
"id": "78324739-ff89-47a5-902b-10da0cb95c6d",
|
126
|
+
"name": "functions",
|
127
|
+
"value": {
|
128
|
+
"type": "CONSTANT_VALUE",
|
129
|
+
"value": {
|
130
|
+
"type": "JSON",
|
131
|
+
"value": [
|
132
|
+
{
|
133
|
+
"state": None,
|
134
|
+
"cache_config": None,
|
135
|
+
"name": "get_current_weather",
|
136
|
+
"description": None,
|
137
|
+
"parameters": {
|
138
|
+
"type": "object",
|
139
|
+
"properties": {"location": {"type": "string"}, "unit": {"type": "string"}},
|
140
|
+
"required": ["location", "unit"],
|
141
|
+
},
|
142
|
+
"forced": None,
|
143
|
+
"strict": None,
|
144
|
+
}
|
145
|
+
],
|
146
|
+
},
|
147
|
+
},
|
148
|
+
},
|
149
|
+
{
|
150
|
+
"id": "0f6dc102-3460-4963-91fa-7ba85d65ef7a",
|
151
|
+
"name": "prompt_inputs",
|
152
|
+
"value": {
|
153
|
+
"type": "CONSTANT_VALUE",
|
154
|
+
"value": {"type": "JSON", "value": {"question": "What's the weather like in San Francisco?"}},
|
155
|
+
},
|
156
|
+
},
|
157
|
+
{
|
158
|
+
"id": "5c041b7d-732c-4773-a93a-32211f2af0b3",
|
159
|
+
"name": "max_tool_calls",
|
160
|
+
"value": {"type": "CONSTANT_VALUE", "value": {"type": "NUMBER", "value": 1.0}},
|
161
|
+
},
|
162
|
+
],
|
163
|
+
"outputs": [
|
164
|
+
{
|
165
|
+
"id": "e62bc785-a914-4066-b79e-8c89a5d0ec6c",
|
166
|
+
"name": "text",
|
167
|
+
"type": "STRING",
|
168
|
+
"value": {"type": "CONSTANT_VALUE", "value": {"type": "STRING", "value": ""}},
|
169
|
+
},
|
170
|
+
{
|
171
|
+
"id": "4674f1d9-e3af-411f-8a55-40a3a3ab5394",
|
172
|
+
"name": "chat_history",
|
173
|
+
"type": "CHAT_HISTORY",
|
174
|
+
"value": {"type": "CONSTANT_VALUE", "value": {"type": "JSON", "value": []}},
|
175
|
+
},
|
176
|
+
],
|
177
|
+
}
|
@@ -153,20 +153,8 @@ class BaseWorkflowDisplay(Generic[WorkflowType]):
|
|
153
153
|
"definition": None,
|
154
154
|
}
|
155
155
|
|
156
|
-
# Add all the nodes in the
|
157
|
-
for node in self._workflow.
|
158
|
-
node_display = self.display_context.node_displays[node]
|
159
|
-
|
160
|
-
try:
|
161
|
-
serialized_node = node_display.serialize(self.display_context)
|
162
|
-
except NotImplementedError as e:
|
163
|
-
self.add_error(e)
|
164
|
-
continue
|
165
|
-
|
166
|
-
serialized_nodes[node_display.node_id] = serialized_node
|
167
|
-
|
168
|
-
# Add all unused nodes in the workflow
|
169
|
-
for node in self._workflow.get_unused_nodes():
|
156
|
+
# Add all the nodes in the workflows
|
157
|
+
for node in self._workflow.get_all_nodes():
|
170
158
|
node_display = self.display_context.node_displays[node]
|
171
159
|
|
172
160
|
try:
|
@@ -417,16 +405,7 @@ class BaseWorkflowDisplay(Generic[WorkflowType]):
|
|
417
405
|
|
418
406
|
port_displays: PortDisplays = {}
|
419
407
|
|
420
|
-
for node in self._workflow.
|
421
|
-
self._enrich_node_displays(
|
422
|
-
node=node,
|
423
|
-
node_displays=node_displays,
|
424
|
-
global_node_displays=global_node_displays,
|
425
|
-
global_node_output_displays=global_node_output_displays,
|
426
|
-
port_displays=port_displays,
|
427
|
-
)
|
428
|
-
|
429
|
-
for node in self._workflow.get_unused_nodes():
|
408
|
+
for node in self._workflow.get_all_nodes():
|
430
409
|
self._enrich_node_displays(
|
431
410
|
node=node,
|
432
411
|
node_displays=node_displays,
|
@@ -466,7 +466,7 @@ def test_serialize_workflow__array_values():
|
|
466
466
|
assert "value" in array_output
|
467
467
|
assert array_output["value"] == {
|
468
468
|
"type": "CONSTANT_VALUE",
|
469
|
-
"value": {"type": "JSON", "
|
469
|
+
"value": {"type": "JSON", "value": ["item1", "item2", "item3"]},
|
470
470
|
}
|
471
471
|
|
472
472
|
nested_array_outputs = [val for val in outputs if isinstance(val, dict) and val["name"] == "nested_array_value"]
|
@@ -477,7 +477,7 @@ def test_serialize_workflow__array_values():
|
|
477
477
|
assert "value" in nested_array_output
|
478
478
|
assert nested_array_output["value"] == {
|
479
479
|
"type": "CONSTANT_VALUE",
|
480
|
-
"value": {"type": "JSON", "
|
480
|
+
"value": {"type": "JSON", "value": [["item1", "item2", "item3"], ["item4", "item5", "item6"]]},
|
481
481
|
}
|
482
482
|
|
483
483
|
mixed_array_outputs = [val for val in outputs if isinstance(val, dict) and val["name"] == "mixed_array_value"]
|
@@ -488,7 +488,7 @@ def test_serialize_workflow__array_values():
|
|
488
488
|
assert "value" in mixed_array_output
|
489
489
|
assert mixed_array_output["value"] == {
|
490
490
|
"type": "CONSTANT_VALUE",
|
491
|
-
"value": {"type": "JSON", "
|
491
|
+
"value": {"type": "JSON", "value": [["item1"], "item2", "item3"]},
|
492
492
|
}
|
493
493
|
|
494
494
|
|
File without changes
|
File without changes
|
File without changes
|