vellum-ai 0.14.19__py3-none-any.whl → 0.14.21__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/client/core/client_wrapper.py +1 -1
- vellum/workflows/nodes/displayable/api_node/node.py +1 -1
- vellum/workflows/nodes/displayable/bases/api_node/node.py +7 -2
- vellum/workflows/nodes/displayable/code_execution_node/node.py +1 -1
- vellum/workflows/nodes/displayable/code_execution_node/tests/test_code_execution_node.py +41 -0
- vellum/workflows/nodes/displayable/code_execution_node/utils.py +6 -1
- vellum/workflows/nodes/tests/test_utils.py +34 -2
- vellum/workflows/nodes/utils.py +26 -0
- vellum/workflows/references/lazy.py +9 -1
- vellum/workflows/references/tests/test_lazy.py +30 -0
- {vellum_ai-0.14.19.dist-info → vellum_ai-0.14.21.dist-info}/METADATA +1 -1
- {vellum_ai-0.14.19.dist-info → vellum_ai-0.14.21.dist-info}/RECORD +44 -42
- vellum_ee/workflows/display/base.py +6 -6
- vellum_ee/workflows/display/nodes/base_node_display.py +27 -2
- vellum_ee/workflows/display/nodes/base_node_vellum_display.py +0 -20
- vellum_ee/workflows/display/nodes/get_node_display_class.py +3 -3
- vellum_ee/workflows/display/nodes/vellum/api_node.py +9 -16
- vellum_ee/workflows/display/nodes/vellum/code_execution_node.py +7 -3
- vellum_ee/workflows/display/nodes/vellum/inline_prompt_node.py +2 -6
- vellum_ee/workflows/display/nodes/vellum/merge_node.py +8 -5
- vellum_ee/workflows/display/nodes/vellum/prompt_deployment_node.py +2 -6
- vellum_ee/workflows/display/nodes/vellum/tests/test_code_execution_node.py +113 -0
- vellum_ee/workflows/display/tests/workflow_serialization/generic_nodes/conftest.py +2 -2
- vellum_ee/workflows/display/tests/workflow_serialization/generic_nodes/test_adornments_serialization.py +4 -4
- vellum_ee/workflows/display/tests/workflow_serialization/generic_nodes/test_attributes_serialization.py +8 -8
- vellum_ee/workflows/display/tests/workflow_serialization/generic_nodes/test_outputs_serialization.py +3 -3
- vellum_ee/workflows/display/tests/workflow_serialization/generic_nodes/test_ports_serialization.py +14 -14
- vellum_ee/workflows/display/tests/workflow_serialization/generic_nodes/test_trigger_serialization.py +3 -3
- vellum_ee/workflows/display/tests/workflow_serialization/test_basic_conditional_node_serialization.py +5 -5
- vellum_ee/workflows/display/tests/workflow_serialization/test_basic_default_state_serialization.py +1 -1
- vellum_ee/workflows/display/tests/workflow_serialization/test_basic_generic_node_serialization.py +1 -1
- vellum_ee/workflows/display/tests/workflow_serialization/test_basic_inline_subworkflow_serialization.py +2 -2
- vellum_ee/workflows/display/tests/workflow_serialization/test_basic_map_node_serialization.py +2 -2
- vellum_ee/workflows/display/tests/workflow_serialization/test_basic_merge_node_serialization.py +3 -3
- vellum_ee/workflows/display/types.py +4 -7
- vellum_ee/workflows/display/vellum.py +11 -3
- vellum_ee/workflows/display/workflows/base_workflow_display.py +45 -34
- vellum_ee/workflows/display/workflows/vellum_workflow_display.py +33 -80
- vellum_ee/workflows/server/virtual_file_loader.py +52 -22
- vellum_ee/workflows/tests/local_workflow/display/workflow.py +3 -5
- vellum_ee/workflows/tests/test_server.py +61 -0
- {vellum_ai-0.14.19.dist-info → vellum_ai-0.14.21.dist-info}/LICENSE +0 -0
- {vellum_ai-0.14.19.dist-info → vellum_ai-0.14.21.dist-info}/WHEEL +0 -0
- {vellum_ai-0.14.19.dist-info → vellum_ai-0.14.21.dist-info}/entry_points.txt +0 -0
@@ -1,42 +1,72 @@
|
|
1
1
|
import importlib
|
2
|
+
import re
|
3
|
+
from typing import Optional
|
2
4
|
|
3
5
|
|
4
6
|
class VirtualFileLoader(importlib.abc.Loader):
|
5
|
-
def __init__(self,
|
6
|
-
self.
|
7
|
-
self.
|
7
|
+
def __init__(self, files: dict[str, str], namespace: str):
|
8
|
+
self.files = files
|
9
|
+
self.namespace = namespace
|
8
10
|
|
9
11
|
def create_module(self, spec):
|
10
12
|
return None # use default module creation
|
11
13
|
|
12
14
|
def exec_module(self, module):
|
13
|
-
|
14
|
-
exec(self.code, module.__dict__)
|
15
|
+
module_info = self._resolve_module(module.__spec__.origin)
|
15
16
|
|
17
|
+
if module_info:
|
18
|
+
file_path, code = module_info
|
19
|
+
compiled = compile(code, file_path, "exec")
|
20
|
+
exec(compiled, module.__dict__)
|
16
21
|
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
22
|
+
def get_source(self, fullname):
|
23
|
+
"""
|
24
|
+
`inspect` module uses this method to get the source code of a module.
|
25
|
+
"""
|
26
|
+
|
27
|
+
module_info = self._resolve_module(fullname)
|
28
|
+
if module_info:
|
29
|
+
return module_info[1]
|
30
|
+
|
31
|
+
return None
|
32
|
+
|
33
|
+
def _resolve_module(self, fullname: str) -> Optional[tuple[str, str]]:
|
34
|
+
file_path = self._get_file_path(fullname)
|
35
|
+
code = self._get_code(file_path)
|
36
|
+
|
37
|
+
if code is not None:
|
38
|
+
return file_path, code
|
21
39
|
|
22
|
-
|
23
|
-
|
24
|
-
|
40
|
+
if not file_path.endswith("__init__.py"):
|
41
|
+
file_path = re.sub(r"\.py$", "/__init__.py", file_path)
|
42
|
+
code = self._get_code(file_path)
|
25
43
|
|
26
|
-
|
44
|
+
if code is not None:
|
45
|
+
return file_path, code
|
46
|
+
|
47
|
+
return None
|
27
48
|
|
28
|
-
|
29
|
-
|
30
|
-
files_key = f"{key_name.replace('.', '/')}/__init__.py"
|
49
|
+
def _get_file_path(self, fullname):
|
50
|
+
return f"{fullname.replace('.', '/')}.py"
|
31
51
|
|
32
|
-
|
33
|
-
|
52
|
+
def _get_code(self, file_path):
|
53
|
+
file_key_name = re.sub(r"^" + re.escape(self.namespace) + r"/", "", file_path)
|
54
|
+
return self.files.get(file_key_name)
|
55
|
+
|
56
|
+
|
57
|
+
class VirtualFileFinder(importlib.abc.MetaPathFinder, importlib.abc.Loader):
|
58
|
+
def __init__(self, files: dict[str, str], namespace: str):
|
59
|
+
self.loader = VirtualFileLoader(files, namespace)
|
34
60
|
|
35
|
-
|
61
|
+
def find_spec(self, fullname: str, path, target=None):
|
62
|
+
module_info = self.loader._resolve_module(fullname)
|
63
|
+
if module_info:
|
64
|
+
file_path, _ = module_info
|
65
|
+
is_package = file_path.endswith("__init__.py")
|
36
66
|
return importlib.machinery.ModuleSpec(
|
37
|
-
|
38
|
-
|
39
|
-
origin=
|
67
|
+
fullname,
|
68
|
+
self.loader,
|
69
|
+
origin=fullname,
|
40
70
|
is_package=is_package,
|
41
71
|
)
|
42
72
|
return None
|
@@ -1,7 +1,7 @@
|
|
1
1
|
from uuid import UUID
|
2
2
|
|
3
|
+
from vellum_ee.workflows.display.base import EdgeDisplay
|
3
4
|
from vellum_ee.workflows.display.vellum import (
|
4
|
-
EdgeVellumDisplayOverrides,
|
5
5
|
EntrypointVellumDisplayOverrides,
|
6
6
|
NodeDisplayData,
|
7
7
|
NodeDisplayPosition,
|
@@ -36,13 +36,11 @@ class WorkflowDisplay(VellumWorkflowDisplay[Workflow]):
|
|
36
36
|
entrypoint_displays = {
|
37
37
|
TemplatingNode: EntrypointVellumDisplayOverrides(
|
38
38
|
id=UUID("0bf86989-13f2-438c-ab9c-d172e5771d31"),
|
39
|
-
edge_display=
|
39
|
+
edge_display=EdgeDisplay(id=UUID("38532a0e-9432-4ed2-8a34-48a29fd6984d")),
|
40
40
|
)
|
41
41
|
}
|
42
42
|
edge_displays = {
|
43
|
-
(TemplatingNode.Ports.default, FinalOutput):
|
44
|
-
id=UUID("417c56a4-cdc1-4f9d-a10c-b535163f51e8")
|
45
|
-
)
|
43
|
+
(TemplatingNode.Ports.default, FinalOutput): EdgeDisplay(id=UUID("417c56a4-cdc1-4f9d-a10c-b535163f51e8"))
|
46
44
|
}
|
47
45
|
output_displays = {
|
48
46
|
Workflow.Outputs.final_output: WorkflowOutputVellumDisplayOverrides(
|
@@ -1,4 +1,11 @@
|
|
1
|
+
import sys
|
2
|
+
from uuid import uuid4
|
3
|
+
from typing import Type, cast
|
4
|
+
|
1
5
|
from vellum.client.core.pydantic_utilities import UniversalBaseModel
|
6
|
+
from vellum.workflows import BaseWorkflow
|
7
|
+
from vellum.workflows.nodes import BaseNode
|
8
|
+
from vellum_ee.workflows.server.virtual_file_loader import VirtualFileFinder
|
2
9
|
|
3
10
|
|
4
11
|
def test_load_workflow_event_display_context():
|
@@ -8,3 +15,57 @@ def test_load_workflow_event_display_context():
|
|
8
15
|
# We are actually just ensuring there are no circular dependencies when
|
9
16
|
# our Workflow Server imports this class.
|
10
17
|
assert issubclass(WorkflowEventDisplayContext, UniversalBaseModel)
|
18
|
+
|
19
|
+
|
20
|
+
def test_load_from_module__lazy_reference_in_file_loader():
|
21
|
+
# GIVEN a workflow module with a node containing a lazy reference
|
22
|
+
files = {
|
23
|
+
"__init__.py": "",
|
24
|
+
"workflow.py": """\
|
25
|
+
from vellum.workflows import BaseWorkflow
|
26
|
+
from .nodes.start_node import StartNode
|
27
|
+
|
28
|
+
class Workflow(BaseWorkflow):
|
29
|
+
graph = StartNode
|
30
|
+
""",
|
31
|
+
"nodes/__init__.py": """\
|
32
|
+
from .start_node import StartNode
|
33
|
+
|
34
|
+
__all__ = [
|
35
|
+
"StartNode",
|
36
|
+
]
|
37
|
+
""",
|
38
|
+
"nodes/start_node.py": """\
|
39
|
+
from vellum.workflows.nodes import BaseNode
|
40
|
+
from vellum.workflows.references import LazyReference
|
41
|
+
|
42
|
+
class StartNode(BaseNode):
|
43
|
+
foo = LazyReference(lambda: StartNode.Outputs.bar)
|
44
|
+
|
45
|
+
class Outputs(BaseNode.Outputs):
|
46
|
+
bar = str
|
47
|
+
""",
|
48
|
+
}
|
49
|
+
|
50
|
+
namespace = str(uuid4())
|
51
|
+
|
52
|
+
# AND the virtual file loader is registered
|
53
|
+
sys.meta_path.append(VirtualFileFinder(files, namespace))
|
54
|
+
|
55
|
+
# WHEN the workflow is loaded
|
56
|
+
Workflow = BaseWorkflow.load_from_module(namespace)
|
57
|
+
workflow = Workflow()
|
58
|
+
|
59
|
+
# THEN the workflow is successfully initialized
|
60
|
+
assert workflow
|
61
|
+
|
62
|
+
# AND the graph is just a BaseNode
|
63
|
+
# ideally this would be true, but the loader uses a different BaseNode class definition than
|
64
|
+
# the one in this test module.
|
65
|
+
# assert isinstance(workflow.graph, BaseNode)
|
66
|
+
start_node = cast(Type[BaseNode], workflow.graph)
|
67
|
+
assert start_node.__bases__ == (BaseNode,)
|
68
|
+
|
69
|
+
# AND the lazy reference has the correct name
|
70
|
+
assert start_node.foo.instance
|
71
|
+
assert start_node.foo.instance.name == "StartNode.Outputs.bar"
|
File without changes
|
File without changes
|
File without changes
|