vellum-ai 0.14.7__py3-none-any.whl → 0.14.9__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 +2 -0
- vellum/client/core/client_wrapper.py +1 -1
- vellum/client/types/__init__.py +2 -0
- vellum/client/types/document_prompt_block.py +29 -0
- vellum/client/types/prompt_block.py +2 -0
- vellum/types/document_prompt_block.py +3 -0
- vellum/workflows/descriptors/base.py +6 -0
- vellum/workflows/descriptors/tests/test_utils.py +14 -0
- vellum/workflows/events/tests/test_event.py +40 -0
- vellum/workflows/events/workflow.py +20 -1
- vellum/workflows/expressions/greater_than.py +15 -8
- vellum/workflows/expressions/greater_than_or_equal_to.py +14 -8
- vellum/workflows/expressions/less_than.py +14 -8
- vellum/workflows/expressions/less_than_or_equal_to.py +14 -8
- vellum/workflows/expressions/parse_json.py +30 -0
- vellum/workflows/expressions/tests/__init__.py +0 -0
- vellum/workflows/expressions/tests/test_expressions.py +310 -0
- vellum/workflows/expressions/tests/test_parse_json.py +31 -0
- vellum/workflows/nodes/bases/base.py +5 -2
- vellum/workflows/nodes/displayable/api_node/tests/test_api_node.py +34 -2
- vellum/workflows/nodes/displayable/bases/api_node/node.py +1 -1
- vellum/workflows/nodes/displayable/code_execution_node/node.py +18 -8
- vellum/workflows/nodes/displayable/code_execution_node/tests/test_code_execution_node.py +53 -0
- vellum/workflows/runner/runner.py +33 -4
- vellum/workflows/state/encoder.py +2 -1
- {vellum_ai-0.14.7.dist-info → vellum_ai-0.14.9.dist-info}/METADATA +1 -1
- {vellum_ai-0.14.7.dist-info → vellum_ai-0.14.9.dist-info}/RECORD +44 -38
- vellum_cli/__init__.py +9 -2
- vellum_cli/config.py +1 -0
- vellum_cli/init.py +6 -2
- vellum_cli/pull.py +1 -0
- vellum_cli/tests/test_init.py +194 -76
- vellum_cli/tests/test_pull.py +8 -0
- vellum_cli/tests/test_push.py +1 -0
- vellum_ee/workflows/display/nodes/base_node_display.py +4 -0
- vellum_ee/workflows/display/tests/test_vellum_workflow_display.py +114 -0
- vellum_ee/workflows/display/tests/workflow_serialization/generic_nodes/test_adornments_serialization.py +118 -3
- vellum_ee/workflows/display/types.py +1 -14
- vellum_ee/workflows/display/workflows/base_workflow_display.py +48 -19
- vellum_ee/workflows/display/workflows/vellum_workflow_display.py +12 -0
- vellum_ee/workflows/tests/test_server.py +1 -0
- {vellum_ai-0.14.7.dist-info → vellum_ai-0.14.9.dist-info}/LICENSE +0 -0
- {vellum_ai-0.14.7.dist-info → vellum_ai-0.14.9.dist-info}/WHEEL +0 -0
- {vellum_ai-0.14.7.dist-info → vellum_ai-0.14.9.dist-info}/entry_points.txt +0 -0
@@ -1,4 +1,3 @@
|
|
1
|
-
import pytest
|
2
1
|
from uuid import uuid4
|
3
2
|
|
4
3
|
from deepdiff import DeepDiff
|
@@ -217,7 +216,6 @@ def test_serialize_node__try(serialize_node):
|
|
217
216
|
)
|
218
217
|
|
219
218
|
|
220
|
-
@pytest.mark.skip(reason="Not implemented")
|
221
219
|
def test_serialize_node__stacked():
|
222
220
|
@TryNode.wrap()
|
223
221
|
@RetryNode.wrap(max_attempts=5)
|
@@ -236,4 +234,121 @@ def test_serialize_node__stacked():
|
|
236
234
|
exec_config = workflow_display.serialize()
|
237
235
|
|
238
236
|
# THEN the workflow display is created successfully
|
239
|
-
assert
|
237
|
+
assert not DeepDiff(
|
238
|
+
{
|
239
|
+
"workflow_raw_data": {
|
240
|
+
"nodes": [
|
241
|
+
{
|
242
|
+
"id": "c14c1c9b-a7a4-4d2c-84fb-c940cfb09525",
|
243
|
+
"type": "ENTRYPOINT",
|
244
|
+
"inputs": [],
|
245
|
+
"data": {
|
246
|
+
"label": "Entrypoint Node",
|
247
|
+
"source_handle_id": "51a5eb25-af14-4bee-9ced-d2aa534ea8e9",
|
248
|
+
},
|
249
|
+
"display_data": {"position": {"x": 0.0, "y": 0.0}},
|
250
|
+
"base": None,
|
251
|
+
"definition": None,
|
252
|
+
},
|
253
|
+
{
|
254
|
+
"id": "074833b0-e142-4bbc-8dec-209a35e178a3",
|
255
|
+
"label": "test_serialize_node__stacked.<locals>.InnerStackedGenericNode",
|
256
|
+
"type": "GENERIC",
|
257
|
+
"display_data": {"position": {"x": 0.0, "y": 0.0}},
|
258
|
+
"base": {"name": "BaseNode", "module": ["vellum", "workflows", "nodes", "bases", "base"]},
|
259
|
+
"definition": {
|
260
|
+
"name": "InnerStackedGenericNode",
|
261
|
+
"module": [
|
262
|
+
"vellum_ee",
|
263
|
+
"workflows",
|
264
|
+
"display",
|
265
|
+
"tests",
|
266
|
+
"workflow_serialization",
|
267
|
+
"generic_nodes",
|
268
|
+
"test_adornments_serialization",
|
269
|
+
],
|
270
|
+
},
|
271
|
+
"trigger": {"id": "f206358d-04a5-41c9-beee-0871a074fa48", "merge_behavior": "AWAIT_ATTRIBUTES"},
|
272
|
+
"ports": [{"id": "408cd5fb-3a3e-4eb2-9889-61111bd6a129", "name": "default", "type": "DEFAULT"}],
|
273
|
+
"adornments": [
|
274
|
+
{
|
275
|
+
"id": "5be7d260-74f7-4734-b31b-a46a94539586",
|
276
|
+
"label": "RetryNode",
|
277
|
+
"base": {
|
278
|
+
"name": "RetryNode",
|
279
|
+
"module": ["vellum", "workflows", "nodes", "core", "retry_node", "node"],
|
280
|
+
},
|
281
|
+
"attributes": [
|
282
|
+
{
|
283
|
+
"id": "c91782e3-140f-4938-9c23-d2a7b85dcdd8",
|
284
|
+
"name": "retry_on_error_code",
|
285
|
+
"value": {"type": "CONSTANT_VALUE", "value": {"type": "JSON", "value": None}},
|
286
|
+
},
|
287
|
+
{
|
288
|
+
"id": "f388e93b-8c68-4f54-8577-bbd0c9091557",
|
289
|
+
"name": "max_attempts",
|
290
|
+
"value": {"type": "CONSTANT_VALUE", "value": {"type": "NUMBER", "value": 5}},
|
291
|
+
},
|
292
|
+
{
|
293
|
+
"id": "8a07dc58-3fed-41d4-8ca6-31ee0bb86c61",
|
294
|
+
"name": "delay",
|
295
|
+
"value": {"type": "CONSTANT_VALUE", "value": {"type": "JSON", "value": None}},
|
296
|
+
},
|
297
|
+
{
|
298
|
+
"id": "73a02e62-4535-4e1f-97b5-1264ca8b1d71",
|
299
|
+
"name": "retry_on_condition",
|
300
|
+
"value": {"type": "CONSTANT_VALUE", "value": {"type": "JSON", "value": None}},
|
301
|
+
},
|
302
|
+
],
|
303
|
+
},
|
304
|
+
{
|
305
|
+
"id": "3344083c-a32c-4a32-920b-0fb5093448fa",
|
306
|
+
"label": "TryNode",
|
307
|
+
"base": {
|
308
|
+
"name": "TryNode",
|
309
|
+
"module": ["vellum", "workflows", "nodes", "core", "try_node", "node"],
|
310
|
+
},
|
311
|
+
"attributes": [
|
312
|
+
{
|
313
|
+
"id": "ab2fbab0-e2a0-419b-b1ef-ce11ecf11e90",
|
314
|
+
"name": "on_error_code",
|
315
|
+
"value": {"type": "CONSTANT_VALUE", "value": {"type": "JSON", "value": None}},
|
316
|
+
}
|
317
|
+
],
|
318
|
+
},
|
319
|
+
],
|
320
|
+
"attributes": [],
|
321
|
+
"outputs": [],
|
322
|
+
},
|
323
|
+
],
|
324
|
+
"edges": [
|
325
|
+
{
|
326
|
+
"id": "e8bd50dd-37a0-49b0-8b7b-f1dd8eb478b9",
|
327
|
+
"source_node_id": "c14c1c9b-a7a4-4d2c-84fb-c940cfb09525",
|
328
|
+
"source_handle_id": "51a5eb25-af14-4bee-9ced-d2aa534ea8e9",
|
329
|
+
"target_node_id": "074833b0-e142-4bbc-8dec-209a35e178a3",
|
330
|
+
"target_handle_id": "f206358d-04a5-41c9-beee-0871a074fa48",
|
331
|
+
"type": "DEFAULT",
|
332
|
+
}
|
333
|
+
],
|
334
|
+
"display_data": {"viewport": {"x": 0.0, "y": 0.0, "zoom": 1.0}},
|
335
|
+
"definition": {
|
336
|
+
"name": "StackedWorkflow",
|
337
|
+
"module": [
|
338
|
+
"vellum_ee",
|
339
|
+
"workflows",
|
340
|
+
"display",
|
341
|
+
"tests",
|
342
|
+
"workflow_serialization",
|
343
|
+
"generic_nodes",
|
344
|
+
"test_adornments_serialization",
|
345
|
+
],
|
346
|
+
},
|
347
|
+
},
|
348
|
+
"input_variables": [],
|
349
|
+
"state_variables": [],
|
350
|
+
"output_variables": [],
|
351
|
+
},
|
352
|
+
exec_config,
|
353
|
+
ignore_order=True,
|
354
|
+
)
|
@@ -1,9 +1,8 @@
|
|
1
1
|
from dataclasses import dataclass, field
|
2
|
-
from uuid import UUID
|
3
2
|
from typing import TYPE_CHECKING, Dict, Generic, Tuple, Type, TypeVar
|
4
3
|
|
5
|
-
from vellum.client.core import UniversalBaseModel
|
6
4
|
from vellum.workflows.descriptors.base import BaseDescriptor
|
5
|
+
from vellum.workflows.events.workflow import WorkflowEventDisplayContext # noqa: F401
|
7
6
|
from vellum.workflows.nodes import BaseNode
|
8
7
|
from vellum.workflows.ports import Port
|
9
8
|
from vellum.workflows.references import OutputReference, StateValueReference, WorkflowInputReference
|
@@ -25,18 +24,6 @@ NodeDisplayType = TypeVar("NodeDisplayType", bound="BaseNodeDisplay")
|
|
25
24
|
WorkflowDisplayType = TypeVar("WorkflowDisplayType", bound="BaseWorkflowDisplay")
|
26
25
|
|
27
26
|
|
28
|
-
class NodeDisplay(UniversalBaseModel):
|
29
|
-
input_display: Dict[str, UUID]
|
30
|
-
output_display: Dict[str, UUID]
|
31
|
-
port_display: Dict[str, UUID]
|
32
|
-
|
33
|
-
|
34
|
-
class WorkflowEventDisplayContext(UniversalBaseModel):
|
35
|
-
node_displays: Dict[str, NodeDisplay]
|
36
|
-
workflow_inputs: Dict[str, UUID]
|
37
|
-
workflow_outputs: Dict[str, UUID]
|
38
|
-
|
39
|
-
|
40
27
|
@dataclass
|
41
28
|
class WorkflowDisplayContext(
|
42
29
|
Generic[
|
@@ -9,6 +9,7 @@ from typing import Any, Dict, Generic, Iterator, List, Optional, Tuple, Type, Un
|
|
9
9
|
from vellum.workflows import BaseWorkflow
|
10
10
|
from vellum.workflows.descriptors.base import BaseDescriptor
|
11
11
|
from vellum.workflows.edges import Edge
|
12
|
+
from vellum.workflows.events.workflow import NodeDisplay, WorkflowEventDisplayContext
|
12
13
|
from vellum.workflows.expressions.coalesce_expression import CoalesceExpression
|
13
14
|
from vellum.workflows.nodes.bases import BaseNode
|
14
15
|
from vellum.workflows.nodes.utils import get_wrapped_node
|
@@ -33,12 +34,7 @@ from vellum_ee.workflows.display.base import (
|
|
33
34
|
from vellum_ee.workflows.display.nodes.base_node_vellum_display import BaseNodeVellumDisplay
|
34
35
|
from vellum_ee.workflows.display.nodes.get_node_display_class import get_node_display_class
|
35
36
|
from vellum_ee.workflows.display.nodes.types import NodeOutputDisplay, PortDisplay, PortDisplayOverrides
|
36
|
-
from vellum_ee.workflows.display.types import
|
37
|
-
NodeDisplay,
|
38
|
-
NodeDisplayType,
|
39
|
-
WorkflowDisplayContext,
|
40
|
-
WorkflowEventDisplayContext,
|
41
|
-
)
|
37
|
+
from vellum_ee.workflows.display.types import NodeDisplayType, WorkflowDisplayContext
|
42
38
|
|
43
39
|
logger = logging.getLogger(__name__)
|
44
40
|
|
@@ -217,23 +213,30 @@ class BaseWorkflowDisplay(
|
|
217
213
|
# TODO: We should still serialize nodes that are in the workflow's directory but aren't used in the graph.
|
218
214
|
# https://app.shortcut.com/vellum/story/5394
|
219
215
|
for node in self._workflow.get_nodes():
|
220
|
-
|
216
|
+
extracted_node_displays = self._extract_node_displays(node)
|
217
|
+
|
218
|
+
for extracted_node, extracted_node_display in extracted_node_displays.items():
|
219
|
+
if extracted_node not in node_displays:
|
220
|
+
node_displays[extracted_node] = extracted_node_display
|
221
|
+
|
222
|
+
if extracted_node not in global_node_displays:
|
223
|
+
global_node_displays[extracted_node] = extracted_node_display
|
221
224
|
|
222
|
-
|
223
|
-
|
225
|
+
self._enrich_global_node_output_displays(node, extracted_node_displays[node], global_node_output_displays)
|
226
|
+
self._enrich_node_port_displays(node, extracted_node_displays[node], port_displays)
|
224
227
|
|
225
|
-
|
226
|
-
|
228
|
+
for node in self._workflow.get_unused_nodes():
|
229
|
+
extracted_node_displays = self._extract_node_displays(node)
|
227
230
|
|
228
|
-
|
229
|
-
|
230
|
-
|
231
|
-
inner_node_display = self._get_node_display(inner_node)
|
232
|
-
node_displays[inner_node] = inner_node_display
|
233
|
-
global_node_displays[inner_node] = inner_node_display
|
231
|
+
for extracted_node, extracted_node_display in extracted_node_displays.items():
|
232
|
+
if extracted_node not in node_displays:
|
233
|
+
node_displays[extracted_node] = extracted_node_display
|
234
234
|
|
235
|
-
|
236
|
-
|
235
|
+
if extracted_node not in global_node_displays:
|
236
|
+
global_node_displays[extracted_node] = extracted_node_display
|
237
|
+
|
238
|
+
self._enrich_global_node_output_displays(node, extracted_node_displays[node], global_node_output_displays)
|
239
|
+
self._enrich_node_port_displays(node, extracted_node_displays[node], port_displays)
|
237
240
|
|
238
241
|
workflow_input_displays: Dict[WorkflowInputReference, WorkflowInputsDisplayType] = {}
|
239
242
|
# If we're dealing with a nested workflow, then it should have access to the inputs of its parents.
|
@@ -280,6 +283,15 @@ class BaseWorkflowDisplay(
|
|
280
283
|
edge, node_displays, port_displays, overrides=edge_display_overrides
|
281
284
|
)
|
282
285
|
|
286
|
+
for edge in self._workflow.get_unused_edges():
|
287
|
+
if edge in edge_displays:
|
288
|
+
continue
|
289
|
+
|
290
|
+
edge_display_overrides = self.edge_displays.get((edge.from_port, edge.to_node))
|
291
|
+
edge_displays[(edge.from_port, edge.to_node)] = self._generate_edge_display(
|
292
|
+
edge, node_displays, port_displays, overrides=edge_display_overrides
|
293
|
+
)
|
294
|
+
|
283
295
|
workflow_output_displays: Dict[BaseDescriptor, WorkflowOutputDisplay] = {}
|
284
296
|
for workflow_output in self._workflow.Outputs:
|
285
297
|
if workflow_output in workflow_output_displays:
|
@@ -409,3 +421,20 @@ class BaseWorkflowDisplay(
|
|
409
421
|
node_displays=temp_node_displays,
|
410
422
|
)
|
411
423
|
return display_meta
|
424
|
+
|
425
|
+
def _extract_node_displays(self, node: Type[BaseNode]) -> Dict[Type[BaseNode], NodeDisplayType]:
|
426
|
+
node_display = self._get_node_display(node)
|
427
|
+
additional_node_displays: Dict[Type[BaseNode], NodeDisplayType] = {
|
428
|
+
node: node_display,
|
429
|
+
}
|
430
|
+
|
431
|
+
# Nodes wrapped in a decorator need to be in our node display dictionary for later retrieval
|
432
|
+
inner_node = get_wrapped_node(node)
|
433
|
+
if inner_node:
|
434
|
+
inner_node_displays = self._extract_node_displays(inner_node)
|
435
|
+
|
436
|
+
for node, display in inner_node_displays.items():
|
437
|
+
if node not in additional_node_displays:
|
438
|
+
additional_node_displays[node] = display
|
439
|
+
|
440
|
+
return additional_node_displays
|
@@ -126,6 +126,18 @@ class VellumWorkflowDisplay(
|
|
126
126
|
|
127
127
|
nodes.append(serialized_node)
|
128
128
|
|
129
|
+
# Add all unused nodes in the workflow
|
130
|
+
for node in self._workflow.get_unused_nodes():
|
131
|
+
node_display = self.display_context.node_displays[node]
|
132
|
+
|
133
|
+
try:
|
134
|
+
serialized_node = node_display.serialize(self.display_context)
|
135
|
+
except NotImplementedError as e:
|
136
|
+
self.add_error(e)
|
137
|
+
continue
|
138
|
+
|
139
|
+
nodes.append(serialized_node)
|
140
|
+
|
129
141
|
synthetic_output_edges: JsonArray = []
|
130
142
|
output_variables: JsonArray = []
|
131
143
|
final_output_nodes = [
|
@@ -2,6 +2,7 @@ from vellum.client.core.pydantic_utilities import UniversalBaseModel
|
|
2
2
|
|
3
3
|
|
4
4
|
def test_load_workflow_event_display_context():
|
5
|
+
# DEPRECATED: Use `vellum.workflows.events.workflow.WorkflowEventDisplayContext` instead. Will be removed in 0.15.0
|
5
6
|
from vellum_ee.workflows.display.types import WorkflowEventDisplayContext
|
6
7
|
|
7
8
|
# We are actually just ensuring there are no circular dependencies when
|
File without changes
|
File without changes
|
File without changes
|