vellum-ai 1.6.4__py3-none-any.whl → 1.7.0__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 +2 -2
- vellum/client/reference.md +81 -0
- vellum/client/resources/container_images/client.py +8 -2
- vellum/client/resources/container_images/raw_client.py +8 -0
- vellum/client/resources/workflows/client.py +81 -0
- vellum/client/resources/workflows/raw_client.py +85 -0
- vellum/client/types/__init__.py +2 -0
- vellum/client/types/workflow_resolved_state.py +31 -0
- vellum/types/workflow_resolved_state.py +3 -0
- vellum/workflows/descriptors/base.py +3 -0
- vellum/workflows/errors/types.py +1 -0
- vellum/workflows/inputs/base.py +4 -1
- vellum/workflows/inputs/tests/test_inputs.py +21 -0
- vellum/workflows/runner/runner.py +16 -0
- vellum/workflows/workflows/base.py +2 -0
- {vellum_ai-1.6.4.dist-info → vellum_ai-1.7.0.dist-info}/METADATA +1 -1
- {vellum_ai-1.6.4.dist-info → vellum_ai-1.7.0.dist-info}/RECORD +35 -33
- vellum_ee/assets/node-definitions.json +157 -12
- vellum_ee/workflows/display/exceptions.py +2 -6
- vellum_ee/workflows/display/nodes/vellum/code_execution_node.py +1 -1
- vellum_ee/workflows/display/nodes/vellum/inline_subworkflow_node.py +1 -1
- vellum_ee/workflows/display/nodes/vellum/prompt_deployment_node.py +11 -4
- vellum_ee/workflows/display/nodes/vellum/search_node.py +4 -4
- vellum_ee/workflows/display/nodes/vellum/subworkflow_deployment_node.py +11 -4
- vellum_ee/workflows/display/nodes/vellum/tests/test_code_execution_node.py +1 -1
- vellum_ee/workflows/display/utils/exceptions.py +19 -0
- vellum_ee/workflows/display/utils/expressions.py +19 -11
- vellum_ee/workflows/display/utils/vellum.py +7 -1
- vellum_ee/workflows/display/workflows/base_workflow_display.py +2 -2
- vellum_ee/workflows/display/workflows/tests/test_workflow_display.py +54 -1
- vellum_ee/workflows/tests/test_server.py +41 -0
- {vellum_ai-1.6.4.dist-info → vellum_ai-1.7.0.dist-info}/LICENSE +0 -0
- {vellum_ai-1.6.4.dist-info → vellum_ai-1.7.0.dist-info}/WHEEL +0 -0
- {vellum_ai-1.6.4.dist-info → vellum_ai-1.7.0.dist-info}/entry_points.txt +0 -0
@@ -15,7 +15,7 @@ from vellum.workflows.references.lazy import LazyReference
|
|
15
15
|
from vellum.workflows.references.node import NodeReference
|
16
16
|
from vellum.workflows.references.vellum_secret import VellumSecretReference
|
17
17
|
from vellum.workflows.utils.vellum_variables import primitive_type_to_vellum_variable_type
|
18
|
-
from vellum_ee.workflows.display.utils.exceptions import UnsupportedSerializationException
|
18
|
+
from vellum_ee.workflows.display.utils.exceptions import InvalidInputReferenceError, UnsupportedSerializationException
|
19
19
|
from vellum_ee.workflows.display.utils.expressions import get_child_descriptor
|
20
20
|
|
21
21
|
if TYPE_CHECKING:
|
@@ -124,6 +124,12 @@ def create_node_input_value_pointer_rule(
|
|
124
124
|
child_descriptor = get_child_descriptor(value, display_context)
|
125
125
|
return create_node_input_value_pointer_rule(child_descriptor, display_context)
|
126
126
|
if isinstance(value, WorkflowInputReference):
|
127
|
+
if value not in display_context.global_workflow_input_displays:
|
128
|
+
raise InvalidInputReferenceError(
|
129
|
+
message=f"Inputs class '{value.inputs_class.__qualname__}' has no attribute '{value.name}'",
|
130
|
+
inputs_class_name=value.inputs_class.__qualname__,
|
131
|
+
attribute_name=value.name,
|
132
|
+
)
|
127
133
|
workflow_input_display = display_context.global_workflow_input_displays[value]
|
128
134
|
return InputVariablePointer(data=InputVariableData(input_variable_id=str(workflow_input_display.id)))
|
129
135
|
if isinstance(value, VellumSecretReference):
|
@@ -39,7 +39,6 @@ from vellum_ee.workflows.display.base import (
|
|
39
39
|
WorkflowOutputDisplay,
|
40
40
|
)
|
41
41
|
from vellum_ee.workflows.display.editor.types import NodeDisplayData, NodeDisplayPosition
|
42
|
-
from vellum_ee.workflows.display.exceptions import NodeValidationError
|
43
42
|
from vellum_ee.workflows.display.nodes.base_node_display import BaseNodeDisplay
|
44
43
|
from vellum_ee.workflows.display.nodes.get_node_display_class import get_node_display_class
|
45
44
|
from vellum_ee.workflows.display.nodes.types import NodeOutputDisplay, PortDisplay
|
@@ -57,6 +56,7 @@ from vellum_ee.workflows.display.types import (
|
|
57
56
|
WorkflowOutputDisplays,
|
58
57
|
)
|
59
58
|
from vellum_ee.workflows.display.utils.auto_layout import auto_layout_nodes
|
59
|
+
from vellum_ee.workflows.display.utils.exceptions import UserFacingException
|
60
60
|
from vellum_ee.workflows.display.utils.expressions import serialize_value
|
61
61
|
from vellum_ee.workflows.display.utils.registry import register_workflow_display_class
|
62
62
|
from vellum_ee.workflows.display.utils.vellum import infer_vellum_variable_type
|
@@ -203,7 +203,7 @@ class BaseWorkflowDisplay(Generic[WorkflowType]):
|
|
203
203
|
self.display_context.add_validation_error(validation_error)
|
204
204
|
|
205
205
|
serialized_node = node_display.serialize(self.display_context)
|
206
|
-
except (NotImplementedError,
|
206
|
+
except (NotImplementedError, UserFacingException) as e:
|
207
207
|
self.display_context.add_error(e)
|
208
208
|
self.display_context.add_invalid_node(node)
|
209
209
|
continue
|
@@ -14,7 +14,7 @@ from vellum.workflows.state.base import BaseState
|
|
14
14
|
from vellum.workflows.types.core import JsonObject
|
15
15
|
from vellum.workflows.workflows.base import BaseWorkflow
|
16
16
|
from vellum_ee.workflows.display.editor.types import NodeDisplayData, NodeDisplayPosition
|
17
|
-
from vellum_ee.workflows.display.nodes import BaseNodeDisplay
|
17
|
+
from vellum_ee.workflows.display.nodes.base_node_display import BaseNodeDisplay
|
18
18
|
from vellum_ee.workflows.display.nodes.vellum.retry_node import BaseRetryNodeDisplay
|
19
19
|
from vellum_ee.workflows.display.nodes.vellum.try_node import BaseTryNodeDisplay
|
20
20
|
from vellum_ee.workflows.display.types import WorkflowDisplayContext
|
@@ -997,3 +997,56 @@ def test_serialize_workflow__with_complete_node_failure_prunes_edges():
|
|
997
997
|
node_types = [node["type"] for node in data["workflow_raw_data"]["nodes"]]
|
998
998
|
assert "ENTRYPOINT" in node_types
|
999
999
|
assert "GENERIC" in node_types # This is the WorkingNode that should still be serialized
|
1000
|
+
|
1001
|
+
|
1002
|
+
def test_serialize_workflow__node_with_invalid_input_reference():
|
1003
|
+
"""Test that serialization captures errors when nodes reference a non-existent input attribute."""
|
1004
|
+
|
1005
|
+
# GIVEN a workflow with defined inputs
|
1006
|
+
class Inputs(BaseInputs):
|
1007
|
+
valid_input: str
|
1008
|
+
|
1009
|
+
# AND a templating node that references a non-existent input
|
1010
|
+
class MyTemplatingNode(TemplatingNode):
|
1011
|
+
class Outputs(TemplatingNode.Outputs):
|
1012
|
+
pass
|
1013
|
+
|
1014
|
+
template = "valid: {{ valid_input }}, invalid: {{ invalid_ref }}"
|
1015
|
+
inputs = {
|
1016
|
+
"valid_input": Inputs.valid_input,
|
1017
|
+
"invalid_ref": Inputs.invalid_ref,
|
1018
|
+
}
|
1019
|
+
|
1020
|
+
# AND a base node that also references the non-existent input
|
1021
|
+
class MyBaseNode(BaseNode):
|
1022
|
+
invalid_ref = Inputs.invalid_ref
|
1023
|
+
|
1024
|
+
class Outputs(BaseNode.Outputs):
|
1025
|
+
result: str
|
1026
|
+
|
1027
|
+
def run(self) -> BaseNode.Outputs:
|
1028
|
+
return self.Outputs(result="done")
|
1029
|
+
|
1030
|
+
class MyBaseNodeDisplay(BaseNodeDisplay[MyBaseNode]):
|
1031
|
+
__serializable_inputs__ = {MyBaseNode.invalid_ref}
|
1032
|
+
|
1033
|
+
# WHEN we create a workflow with both nodes and serialize with dry_run=True
|
1034
|
+
class MyWorkflow(BaseWorkflow[Inputs, BaseState]):
|
1035
|
+
graph = MyTemplatingNode >> MyBaseNode
|
1036
|
+
|
1037
|
+
workflow_display = get_workflow_display(workflow_class=MyWorkflow, dry_run=True)
|
1038
|
+
serialized = workflow_display.serialize()
|
1039
|
+
|
1040
|
+
# THEN the serialization should succeed without raising an exception
|
1041
|
+
assert serialized is not None
|
1042
|
+
assert "workflow_raw_data" in serialized
|
1043
|
+
|
1044
|
+
errors = list(workflow_display.display_context.errors)
|
1045
|
+
assert len(errors) > 0
|
1046
|
+
|
1047
|
+
# AND the error messages should reference the missing attribute
|
1048
|
+
error_messages = [str(e) for e in errors]
|
1049
|
+
assert any("invalid_ref" in msg for msg in error_messages)
|
1050
|
+
|
1051
|
+
invalid_nodes = list(workflow_display.display_context.invalid_nodes)
|
1052
|
+
assert len(invalid_nodes) >= 2
|
@@ -1,3 +1,4 @@
|
|
1
|
+
import pytest
|
1
2
|
import sys
|
2
3
|
from uuid import uuid4
|
3
4
|
from typing import Type, cast
|
@@ -6,6 +7,7 @@ from vellum.client.core.pydantic_utilities import UniversalBaseModel
|
|
6
7
|
from vellum.client.types.code_executor_response import CodeExecutorResponse
|
7
8
|
from vellum.client.types.number_vellum_value import NumberVellumValue
|
8
9
|
from vellum.workflows import BaseWorkflow
|
10
|
+
from vellum.workflows.exceptions import WorkflowInitializationException
|
9
11
|
from vellum.workflows.nodes import BaseNode
|
10
12
|
from vellum.workflows.state.context import WorkflowContext
|
11
13
|
from vellum.workflows.utils.uuids import generate_workflow_deployment_prefix
|
@@ -499,6 +501,45 @@ class MapNodeWorkflow(BaseWorkflow):
|
|
499
501
|
assert event.body.outputs == {"results": [1.0, 1.0, 1.0]}
|
500
502
|
|
501
503
|
|
504
|
+
def test_load_from_module__syntax_error_in_node_file():
|
505
|
+
"""
|
506
|
+
Tests that a syntax error in a node file raises WorkflowInitializationException with user-facing message.
|
507
|
+
"""
|
508
|
+
# GIVEN a workflow module with a node file containing a syntax error (missing colon)
|
509
|
+
files = {
|
510
|
+
"__init__.py": "",
|
511
|
+
"workflow.py": """\
|
512
|
+
from vellum.workflows import BaseWorkflow
|
513
|
+
from .nodes.broken_node import BrokenNode
|
514
|
+
|
515
|
+
class Workflow(BaseWorkflow):
|
516
|
+
graph = BrokenNode
|
517
|
+
""",
|
518
|
+
"nodes/__init__.py": "",
|
519
|
+
"nodes/broken_node.py": """\
|
520
|
+
from vellum.workflows.nodes import BaseNode
|
521
|
+
|
522
|
+
class BrokenNode(BaseNode) # Missing colon
|
523
|
+
\"\"\"This node has a syntax error.\"\"\"
|
524
|
+
""",
|
525
|
+
}
|
526
|
+
|
527
|
+
namespace = str(uuid4())
|
528
|
+
|
529
|
+
# AND the virtual file loader is registered
|
530
|
+
sys.meta_path.append(VirtualFileFinder(files, namespace))
|
531
|
+
|
532
|
+
# WHEN we attempt to load the workflow
|
533
|
+
# THEN it should raise WorkflowInitializationException
|
534
|
+
with pytest.raises(WorkflowInitializationException) as exc_info:
|
535
|
+
BaseWorkflow.load_from_module(namespace)
|
536
|
+
|
537
|
+
# AND the error message should be user-friendly
|
538
|
+
error_message = str(exc_info.value)
|
539
|
+
assert "Failed to load workflow module:" in error_message
|
540
|
+
assert "invalid syntax" in error_message or "expected ':'" in error_message
|
541
|
+
|
542
|
+
|
502
543
|
def test_serialize_module__tool_calling_node_with_single_tool():
|
503
544
|
"""Test that serialize_module works with a tool calling node that has a single tool."""
|
504
545
|
|
File without changes
|
File without changes
|
File without changes
|