vellum-ai 0.14.73__py3-none-any.whl → 0.14.74__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/client/core/serialization.py +0 -1
- vellum/client/types/secret_type_enum.py +3 -1
- vellum/workflows/nodes/displayable/bases/inline_prompt_node/node.py +2 -2
- vellum/workflows/nodes/displayable/bases/utils.py +2 -0
- vellum/workflows/nodes/experimental/tool_calling_node/node.py +5 -1
- vellum/workflows/nodes/experimental/tool_calling_node/tests/test_node.py +13 -0
- vellum/workflows/nodes/experimental/tool_calling_node/utils.py +14 -4
- vellum/workflows/state/encoder.py +2 -0
- vellum/workflows/types/definition.py +1 -1
- vellum/workflows/utils/functions.py +3 -3
- vellum/workflows/utils/tests/test_functions.py +7 -7
- {vellum_ai-0.14.73.dist-info → vellum_ai-0.14.74.dist-info}/METADATA +1 -1
- {vellum_ai-0.14.73.dist-info → vellum_ai-0.14.74.dist-info}/RECORD +27 -26
- vellum_ee/workflows/display/nodes/vellum/inline_prompt_node.py +36 -7
- vellum_ee/workflows/display/nodes/vellum/tests/test_prompt_node.py +102 -0
- vellum_ee/workflows/display/tests/workflow_serialization/generic_nodes/test_attributes_serialization.py +90 -0
- vellum_ee/workflows/display/tests/workflow_serialization/test_basic_inline_prompt_node_serialization.py +117 -0
- vellum_ee/workflows/display/tests/workflow_serialization/test_basic_tool_calling_node_inline_workflow_serialization.py +7 -0
- vellum_ee/workflows/display/tests/workflow_serialization/test_basic_tool_calling_node_serialization.py +7 -0
- vellum_ee/workflows/display/tests/workflow_serialization/test_basic_tool_calling_node_workflow_deployment_serialization.py +62 -0
- vellum_ee/workflows/display/utils/expressions.py +33 -2
- vellum_ee/workflows/display/workflows/base_workflow_display.py +20 -6
- vellum_ee/workflows/tests/test_display_meta.py +41 -0
- {vellum_ai-0.14.73.dist-info → vellum_ai-0.14.74.dist-info}/LICENSE +0 -0
- {vellum_ai-0.14.73.dist-info → vellum_ai-0.14.74.dist-info}/WHEEL +0 -0
- {vellum_ai-0.14.73.dist-info → vellum_ai-0.14.74.dist-info}/entry_points.txt +0 -0
@@ -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.74",
|
22
22
|
}
|
23
23
|
headers["X-API-KEY"] = self.api_key
|
24
24
|
return headers
|
@@ -33,9 +33,9 @@ from vellum.workflows.types import MergeBehavior
|
|
33
33
|
from vellum.workflows.types.definition import DeploymentDefinition
|
34
34
|
from vellum.workflows.types.generics import StateType, is_workflow_class
|
35
35
|
from vellum.workflows.utils.functions import (
|
36
|
-
compile_deployment_workflow_function_definition,
|
37
36
|
compile_function_definition,
|
38
37
|
compile_inline_workflow_function_definition,
|
38
|
+
compile_workflow_deployment_function_definition,
|
39
39
|
)
|
40
40
|
from vellum.workflows.utils.pydantic_schema import normalize_json
|
41
41
|
|
@@ -115,7 +115,7 @@ class BaseInlinePromptNode(BasePromptNode[StateType], Generic[StateType]):
|
|
115
115
|
normalized_functions.append(function)
|
116
116
|
elif isinstance(function, DeploymentDefinition):
|
117
117
|
normalized_functions.append(
|
118
|
-
|
118
|
+
compile_workflow_deployment_function_definition(
|
119
119
|
function.model_dump(),
|
120
120
|
vellum_client=self._context.vellum_client,
|
121
121
|
)
|
@@ -52,6 +52,8 @@ def primitive_to_vellum_value(value: Any) -> VellumValue:
|
|
52
52
|
return StringVellumValue(value=value)
|
53
53
|
elif isinstance(value, enum.Enum):
|
54
54
|
return StringVellumValue(value=value.value)
|
55
|
+
elif isinstance(value, bool):
|
56
|
+
return JsonVellumValue(value=value)
|
55
57
|
elif isinstance(value, (int, float)):
|
56
58
|
return NumberVellumValue(value=value)
|
57
59
|
elif isinstance(value, list) and (
|
@@ -32,6 +32,7 @@ class ToolCallingNode(BaseNode):
|
|
32
32
|
functions: List[Tool] - The functions that can be called
|
33
33
|
prompt_inputs: Optional[EntityInputsInterface] - Mapping of input variable names to values
|
34
34
|
function_configs: Optional[Dict[str, Dict[str, Any]]] - Mapping of function names to their configuration
|
35
|
+
max_prompt_iterations: Optional[int] - Maximum number of prompt iterations before stopping
|
35
36
|
"""
|
36
37
|
|
37
38
|
ml_model: ClassVar[str] = "gpt-4o-mini"
|
@@ -39,6 +40,7 @@ class ToolCallingNode(BaseNode):
|
|
39
40
|
functions: ClassVar[List[Tool]] = []
|
40
41
|
prompt_inputs: ClassVar[Optional[EntityInputsInterface]] = None
|
41
42
|
function_configs: ClassVar[Optional[Dict[str, Dict[str, Any]]]] = None
|
43
|
+
max_prompt_iterations: ClassVar[Optional[int]] = 5
|
42
44
|
|
43
45
|
class Outputs(BaseOutputs):
|
44
46
|
"""
|
@@ -65,6 +67,7 @@ class ToolCallingNode(BaseNode):
|
|
65
67
|
|
66
68
|
class ToolCallingState(BaseState):
|
67
69
|
chat_history: List[ChatMessage] = []
|
70
|
+
prompt_iterations: int = 0
|
68
71
|
|
69
72
|
class ToolCallingWorkflow(BaseWorkflow[BaseInputs, ToolCallingState]):
|
70
73
|
graph = self._graph
|
@@ -93,7 +96,7 @@ class ToolCallingNode(BaseNode):
|
|
93
96
|
|
94
97
|
return node_outputs
|
95
98
|
elif terminal_event.name == "workflow.execution.rejected":
|
96
|
-
raise
|
99
|
+
raise NodeException(message=terminal_event.error.message, code=terminal_event.error.code)
|
97
100
|
|
98
101
|
raise Exception(f"Unexpected workflow event: {terminal_event.name}")
|
99
102
|
|
@@ -103,6 +106,7 @@ class ToolCallingNode(BaseNode):
|
|
103
106
|
blocks=self.blocks,
|
104
107
|
functions=self.functions,
|
105
108
|
prompt_inputs=self.prompt_inputs,
|
109
|
+
max_prompt_iterations=self.max_prompt_iterations,
|
106
110
|
)
|
107
111
|
|
108
112
|
self._function_nodes = {}
|
@@ -12,6 +12,7 @@ from vellum.workflows.nodes.experimental.tool_calling_node.utils import create_f
|
|
12
12
|
from vellum.workflows.outputs.base import BaseOutputs
|
13
13
|
from vellum.workflows.state.base import BaseState, StateMeta
|
14
14
|
from vellum.workflows.state.context import WorkflowContext
|
15
|
+
from vellum.workflows.types.definition import DeploymentDefinition
|
15
16
|
|
16
17
|
|
17
18
|
def first_function() -> str:
|
@@ -127,3 +128,15 @@ def test_tool_calling_node_inline_workflow_context():
|
|
127
128
|
assert isinstance(function_response.content, StringChatMessageContent)
|
128
129
|
data = json.loads(function_response.content.value)
|
129
130
|
assert data["generated_files"] == {"script.py": "print('hello world')"}
|
131
|
+
|
132
|
+
|
133
|
+
def test_deployment_definition_release_tag_defaults_to_latest():
|
134
|
+
"""
|
135
|
+
Test that when creating a DeploymentDefinition without specifying release_tag,
|
136
|
+
it defaults to "LATEST".
|
137
|
+
"""
|
138
|
+
# WHEN we create a deployment definition without specifying release_tag
|
139
|
+
deployment_config = DeploymentDefinition(deployment="test-deployment")
|
140
|
+
|
141
|
+
# THEN the release_tag should default to "LATEST"
|
142
|
+
assert deployment_config.release_tag == "LATEST"
|
@@ -37,10 +37,16 @@ class FunctionNode(BaseNode):
|
|
37
37
|
|
38
38
|
|
39
39
|
class ToolRouterNode(InlinePromptNode):
|
40
|
+
max_prompt_iterations: Optional[int] = 5
|
41
|
+
|
40
42
|
class Trigger(InlinePromptNode.Trigger):
|
41
43
|
merge_behavior = MergeBehavior.AWAIT_ATTRIBUTES
|
42
44
|
|
43
45
|
def run(self) -> Iterator[BaseOutput]:
|
46
|
+
if self.state.prompt_iterations >= self.max_prompt_iterations:
|
47
|
+
max_iterations_message = f"Maximum number of prompt iterations `{self.max_prompt_iterations}` reached."
|
48
|
+
raise NodeException(message=max_iterations_message, code=WorkflowErrorCode.NODE_EXECUTION)
|
49
|
+
|
44
50
|
self.prompt_inputs = {**self.prompt_inputs, "chat_history": self.state.chat_history} # type: ignore
|
45
51
|
generator = super().run()
|
46
52
|
for output in generator:
|
@@ -50,6 +56,8 @@ class ToolRouterNode(InlinePromptNode):
|
|
50
56
|
if values[0].type == "STRING":
|
51
57
|
self.state.chat_history.append(ChatMessage(role="ASSISTANT", text=values[0].value))
|
52
58
|
elif values[0].type == "FUNCTION_CALL":
|
59
|
+
self.state.prompt_iterations += 1
|
60
|
+
|
53
61
|
function_call = values[0].value
|
54
62
|
if function_call is not None:
|
55
63
|
self.state.chat_history.append(
|
@@ -72,6 +80,7 @@ def create_tool_router_node(
|
|
72
80
|
blocks: List[PromptBlock],
|
73
81
|
functions: List[Tool],
|
74
82
|
prompt_inputs: Optional[EntityInputsInterface],
|
83
|
+
max_prompt_iterations: Optional[int] = None,
|
75
84
|
) -> Type[ToolRouterNode]:
|
76
85
|
if functions and len(functions) > 0:
|
77
86
|
# If we have functions, create dynamic ports for each function
|
@@ -120,6 +129,7 @@ def create_tool_router_node(
|
|
120
129
|
"blocks": blocks,
|
121
130
|
"functions": functions,
|
122
131
|
"prompt_inputs": prompt_inputs,
|
132
|
+
"max_prompt_iterations": max_prompt_iterations,
|
123
133
|
"Ports": Ports,
|
124
134
|
"__module__": __name__,
|
125
135
|
},
|
@@ -149,7 +159,7 @@ def create_function_node(
|
|
149
159
|
deployment = function.deployment
|
150
160
|
release_tag = function.release_tag
|
151
161
|
|
152
|
-
def
|
162
|
+
def execute_workflow_deployment_function(self) -> BaseNode.Outputs:
|
153
163
|
function_call_output = self.state.meta.node_outputs.get(tool_router_node.Outputs.results)
|
154
164
|
if function_call_output and len(function_call_output) > 0:
|
155
165
|
function_call = function_call_output[0]
|
@@ -187,10 +197,10 @@ def create_function_node(
|
|
187
197
|
return self.Outputs()
|
188
198
|
|
189
199
|
node = type(
|
190
|
-
f"
|
200
|
+
f"WorkflowDeploymentNode_{deployment}",
|
191
201
|
(FunctionNode,),
|
192
202
|
{
|
193
|
-
"run":
|
203
|
+
"run": execute_workflow_deployment_function,
|
194
204
|
"__module__": __name__,
|
195
205
|
},
|
196
206
|
)
|
@@ -219,7 +229,7 @@ def create_function_node(
|
|
219
229
|
elif terminal_event.name == "workflow.execution.fulfilled":
|
220
230
|
result = terminal_event.outputs
|
221
231
|
elif terminal_event.name == "workflow.execution.rejected":
|
222
|
-
raise
|
232
|
+
raise NodeException(message=terminal_event.error.message, code=terminal_event.error.code)
|
223
233
|
|
224
234
|
self.state.chat_history.append(
|
225
235
|
ChatMessage(
|
@@ -88,7 +88,7 @@ def _compile_default_value(default: Any) -> Any:
|
|
88
88
|
return default
|
89
89
|
|
90
90
|
|
91
|
-
def
|
91
|
+
def _compile_workflow_deployment_input(input_var: Any) -> dict[str, Any]:
|
92
92
|
"""
|
93
93
|
Converts a deployment workflow input variable to a JSON schema type definition.
|
94
94
|
"""
|
@@ -168,7 +168,7 @@ def compile_inline_workflow_function_definition(workflow_class: Type["BaseWorkfl
|
|
168
168
|
)
|
169
169
|
|
170
170
|
|
171
|
-
def
|
171
|
+
def compile_workflow_deployment_function_definition(
|
172
172
|
deployment_config: Dict[str, str],
|
173
173
|
vellum_client: Vellum,
|
174
174
|
) -> FunctionDefinition:
|
@@ -193,7 +193,7 @@ def compile_deployment_workflow_function_definition(
|
|
193
193
|
required = []
|
194
194
|
|
195
195
|
for input_var in input_variables:
|
196
|
-
properties[input_var.key] =
|
196
|
+
properties[input_var.key] = _compile_workflow_deployment_input(input_var)
|
197
197
|
|
198
198
|
if input_var.required and input_var.default is None:
|
199
199
|
required.append(input_var.key)
|
@@ -12,9 +12,9 @@ from vellum.workflows.inputs.base import BaseInputs
|
|
12
12
|
from vellum.workflows.nodes.bases.base import BaseNode
|
13
13
|
from vellum.workflows.state.base import BaseState
|
14
14
|
from vellum.workflows.utils.functions import (
|
15
|
-
compile_deployment_workflow_function_definition,
|
16
15
|
compile_function_definition,
|
17
16
|
compile_inline_workflow_function_definition,
|
17
|
+
compile_workflow_deployment_function_definition,
|
18
18
|
)
|
19
19
|
|
20
20
|
|
@@ -440,7 +440,7 @@ def test_compile_inline_workflow_function_definition__optionals():
|
|
440
440
|
)
|
441
441
|
|
442
442
|
|
443
|
-
def
|
443
|
+
def test_compile_workflow_deployment_function_definition__just_name():
|
444
444
|
# GIVEN a mock Vellum client and deployment
|
445
445
|
mock_client = Mock()
|
446
446
|
mock_release = Mock()
|
@@ -451,7 +451,7 @@ def test_compile_deployment_workflow_function_definition__just_name():
|
|
451
451
|
deployment_config = {"deployment": "my_deployment", "release_tag": "latest"}
|
452
452
|
|
453
453
|
# WHEN compiling the deployment workflow function
|
454
|
-
compiled_function =
|
454
|
+
compiled_function = compile_workflow_deployment_function_definition(deployment_config, mock_client)
|
455
455
|
|
456
456
|
# THEN it should return the compiled function definition (same structure as function test)
|
457
457
|
assert compiled_function == FunctionDefinition(
|
@@ -461,7 +461,7 @@ def test_compile_deployment_workflow_function_definition__just_name():
|
|
461
461
|
)
|
462
462
|
|
463
463
|
|
464
|
-
def
|
464
|
+
def test_compile_workflow_deployment_function_definition__all_args():
|
465
465
|
# GIVEN a mock Vellum client and deployment
|
466
466
|
mock_client = Mock()
|
467
467
|
mock_release = Mock()
|
@@ -497,7 +497,7 @@ def test_compile_deployment_workflow_function_definition__all_args():
|
|
497
497
|
deployment_config = {"deployment": "my_deployment", "release_tag": "latest"}
|
498
498
|
|
499
499
|
# WHEN compiling the deployment workflow function
|
500
|
-
compiled_function =
|
500
|
+
compiled_function = compile_workflow_deployment_function_definition(deployment_config, mock_client)
|
501
501
|
|
502
502
|
# THEN it should return the compiled function definition
|
503
503
|
assert compiled_function == FunctionDefinition(
|
@@ -524,7 +524,7 @@ def test_compile_deployment_workflow_function_definition__all_args():
|
|
524
524
|
)
|
525
525
|
|
526
526
|
|
527
|
-
def
|
527
|
+
def test_compile_workflow_deployment_function_definition__defaults():
|
528
528
|
# GIVEN a mock Vellum client and deployment
|
529
529
|
mock_client = Mock()
|
530
530
|
mock_release = Mock()
|
@@ -565,7 +565,7 @@ def test_compile_deployment_workflow_function_definition__defaults():
|
|
565
565
|
deployment_config = {"deployment": "my_deployment", "release_tag": "latest"}
|
566
566
|
|
567
567
|
# WHEN compiling the deployment workflow function
|
568
|
-
compiled_function =
|
568
|
+
compiled_function = compile_workflow_deployment_function_definition(deployment_config, mock_client)
|
569
569
|
|
570
570
|
# THEN it should return the compiled function definition with proper default handling
|
571
571
|
assert compiled_function == FunctionDefinition(
|
@@ -41,7 +41,7 @@ vellum_ee/workflows/display/nodes/vellum/conditional_node.py,sha256=9GtbvSJUNF62
|
|
41
41
|
vellum_ee/workflows/display/nodes/vellum/error_node.py,sha256=YhMsi2TG1zSR8E7IpxzzSncOyVLcvqTuGa3mr4RqHd8,2364
|
42
42
|
vellum_ee/workflows/display/nodes/vellum/final_output_node.py,sha256=zo-nalsuayMqeb2GwR2OB9SFK3y2U5aG-rtwrsjdasQ,3089
|
43
43
|
vellum_ee/workflows/display/nodes/vellum/guardrail_node.py,sha256=IniO5KvO0Rw9zghFg3RFvbXBTv6Zi1iuQhaA1DLazqU,2331
|
44
|
-
vellum_ee/workflows/display/nodes/vellum/inline_prompt_node.py,sha256=
|
44
|
+
vellum_ee/workflows/display/nodes/vellum/inline_prompt_node.py,sha256=O4crEYQYJ6XGiN7pEQKxJCGGUQCQKf3rSjKYE4D-iCY,12079
|
45
45
|
vellum_ee/workflows/display/nodes/vellum/inline_subworkflow_node.py,sha256=f7MeoxgKrdyb1dSJsvdDtZPlp1J2Pa4njPvN3qHVktA,6028
|
46
46
|
vellum_ee/workflows/display/nodes/vellum/map_node.py,sha256=uaZ2wcZR1J9C9iI0QWAsgNK9IlcuCz1808oxXmiYsLY,3908
|
47
47
|
vellum_ee/workflows/display/nodes/vellum/merge_node.py,sha256=RTP_raQWL8ZKoRKLpxLfpyXzw61TZeTCkTuM1uRLIkI,3274
|
@@ -57,7 +57,7 @@ vellum_ee/workflows/display/nodes/vellum/tests/test_error_node.py,sha256=540FoWM
|
|
57
57
|
vellum_ee/workflows/display/nodes/vellum/tests/test_inline_subworkflow_node.py,sha256=SKOYan-dxY4gsO0R4JyQUyWrABHBN8XImKw9Eeo4wGo,3535
|
58
58
|
vellum_ee/workflows/display/nodes/vellum/tests/test_note_node.py,sha256=uiMB0cOxKZzos7YKnj4ef4DFa2bOvZJWIv-hfbUV6Go,1218
|
59
59
|
vellum_ee/workflows/display/nodes/vellum/tests/test_prompt_deployment_node.py,sha256=G-qJyTNJkpqJiEZ3kCJl86CXJINLeFyf2lM0bQHCCOs,3822
|
60
|
-
vellum_ee/workflows/display/nodes/vellum/tests/test_prompt_node.py,sha256=
|
60
|
+
vellum_ee/workflows/display/nodes/vellum/tests/test_prompt_node.py,sha256=h3rXIfB349w11cMgNpqEWCI3ucTsTb30cWskXN8FoV0,14053
|
61
61
|
vellum_ee/workflows/display/nodes/vellum/tests/test_retry_node.py,sha256=h93ysolmbo2viisyhRnXKHPxiDK0I_dSAbYoHFYIoO4,1953
|
62
62
|
vellum_ee/workflows/display/nodes/vellum/tests/test_search_node.py,sha256=KvByxgbUkVyfPIVxTUBUk6a92JiJMi8eReZWxzfPExU,3864
|
63
63
|
vellum_ee/workflows/display/nodes/vellum/tests/test_subworkflow_deployment_node.py,sha256=BUzHJgjdWnPeZxjFjHfDBKnbFjYjnbXPjc-1hne1B2Y,3965
|
@@ -73,7 +73,7 @@ vellum_ee/workflows/display/tests/workflow_serialization/__init__.py,sha256=47DE
|
|
73
73
|
vellum_ee/workflows/display/tests/workflow_serialization/generic_nodes/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
74
74
|
vellum_ee/workflows/display/tests/workflow_serialization/generic_nodes/conftest.py,sha256=XOQDDRiG46etxTC7-_RUEutoNumXc02fo7oho4GYM0c,1900
|
75
75
|
vellum_ee/workflows/display/tests/workflow_serialization/generic_nodes/test_adornments_serialization.py,sha256=IuoR3QrsnshZSb1ggLBvQJnTw244lHBo70KmKLd0fwk,12852
|
76
|
-
vellum_ee/workflows/display/tests/workflow_serialization/generic_nodes/test_attributes_serialization.py,sha256
|
76
|
+
vellum_ee/workflows/display/tests/workflow_serialization/generic_nodes/test_attributes_serialization.py,sha256=DFNp_iUxlyE-zCJBH9ab3e1jQEK-NSE9M2CQd4NCjY8,24853
|
77
77
|
vellum_ee/workflows/display/tests/workflow_serialization/generic_nodes/test_outputs_serialization.py,sha256=s6_mnk0pkztU59wYpSfOFpMhAJaRjmyfxM6WJGtnD4Y,6456
|
78
78
|
vellum_ee/workflows/display/tests/workflow_serialization/generic_nodes/test_ports_serialization.py,sha256=PkSgghJDz0fpDB72HHPjLjo8LkZk-HpUkCQzRLX-iVw,40611
|
79
79
|
vellum_ee/workflows/display/tests/workflow_serialization/generic_nodes/test_trigger_serialization.py,sha256=dsJr8I9AdPwMOGszirfNDzZP2Ychd94aAKuPXAzknMk,4632
|
@@ -84,7 +84,7 @@ vellum_ee/workflows/display/tests/workflow_serialization/test_basic_default_stat
|
|
84
84
|
vellum_ee/workflows/display/tests/workflow_serialization/test_basic_error_node_serialization.py,sha256=w1BYEZXIMjWmcKGQXzhelHnKFlEAXmsgjkI9fcgqKXA,5850
|
85
85
|
vellum_ee/workflows/display/tests/workflow_serialization/test_basic_generic_node_serialization.py,sha256=-T0cd2jx1bC0ZNtAESF78fnYD_0nOqo8zMMLwRHUTRM,6227
|
86
86
|
vellum_ee/workflows/display/tests/workflow_serialization/test_basic_guardrail_node_serialization.py,sha256=PZ9Yec8D6e9wM2kh5eWtNvK5BghTf1RdvoSW5_pw3FM,7384
|
87
|
-
vellum_ee/workflows/display/tests/workflow_serialization/test_basic_inline_prompt_node_serialization.py,sha256=
|
87
|
+
vellum_ee/workflows/display/tests/workflow_serialization/test_basic_inline_prompt_node_serialization.py,sha256=tljn-ueIMEW3j2q6Ni9O852sdQMjut05ox4paBeJjm8,23714
|
88
88
|
vellum_ee/workflows/display/tests/workflow_serialization/test_basic_inline_subworkflow_serialization.py,sha256=3Djct7lIr2TPW-wDd_t6eoNdsE0hBOj9OwKWRroXMUo,21659
|
89
89
|
vellum_ee/workflows/display/tests/workflow_serialization/test_basic_map_node_serialization.py,sha256=91u9FWLErrNGfUkZ22ifk6IazGtaYoDFbZYjhxEESgI,16579
|
90
90
|
vellum_ee/workflows/display/tests/workflow_serialization/test_basic_merge_node_serialization.py,sha256=rtkAQw5awOFX3pWh0qz3f766-tTnPhToGsXVSHO4M4U,8352
|
@@ -93,8 +93,9 @@ vellum_ee/workflows/display/tests/workflow_serialization/test_basic_search_node_
|
|
93
93
|
vellum_ee/workflows/display/tests/workflow_serialization/test_basic_subworkflow_deployment_serialization.py,sha256=XWrhHg_acLsRHwjstBAii9Pmes9oXFtAUWSAVF1oSBc,11225
|
94
94
|
vellum_ee/workflows/display/tests/workflow_serialization/test_basic_templating_node_serialization.py,sha256=V8b6gKghLlO7PJI8xeNdnfn8aII0W_IFQvSQBQM62UQ,7721
|
95
95
|
vellum_ee/workflows/display/tests/workflow_serialization/test_basic_terminal_node_serialization.py,sha256=hDWtKXmGI1CKhTwTNqpu_d5RkE5n7SolMLtgd87KqTI,3856
|
96
|
-
vellum_ee/workflows/display/tests/workflow_serialization/test_basic_tool_calling_node_inline_workflow_serialization.py,sha256=
|
97
|
-
vellum_ee/workflows/display/tests/workflow_serialization/test_basic_tool_calling_node_serialization.py,sha256=
|
96
|
+
vellum_ee/workflows/display/tests/workflow_serialization/test_basic_tool_calling_node_inline_workflow_serialization.py,sha256=6q-lTGMp5HbQba3NsHUFSit8_zEBxIVPGE8yCw4SVx0,25720
|
97
|
+
vellum_ee/workflows/display/tests/workflow_serialization/test_basic_tool_calling_node_serialization.py,sha256=36-fpwj53JcRmo7RuHrsS6ZjJ3q4j8BC1wuKruBjIt8,9137
|
98
|
+
vellum_ee/workflows/display/tests/workflow_serialization/test_basic_tool_calling_node_workflow_deployment_serialization.py,sha256=zlb0Kfg1zqJsz1tD_1O-hkSKhV4-gfYI6AkK4-Yjk7U,2315
|
98
99
|
vellum_ee/workflows/display/tests/workflow_serialization/test_basic_try_node_serialization.py,sha256=pLCyMScV88DTBXRH7jXaXOEA1GBq8NIipCUFwIAWnwI,2771
|
99
100
|
vellum_ee/workflows/display/tests/workflow_serialization/test_complex_terminal_node_serialization.py,sha256=J4ouI8KxbMfxQP2Zq_9cWMGYgbjCWmKzjCJEtnSJb0I,5829
|
100
101
|
vellum_ee/workflows/display/tests/workflow_serialization/test_workflow_input_parameterization_error.py,sha256=vAdmn3YTBDpo55znbydQxsgg9ASqHcvsUPwiBR_7wfo,1461
|
@@ -102,14 +103,14 @@ vellum_ee/workflows/display/types.py,sha256=i4T7ElU5b5h-nA1i3scmEhO1BqmNDc4eJDHa
|
|
102
103
|
vellum_ee/workflows/display/utils/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
103
104
|
vellum_ee/workflows/display/utils/auto_layout.py,sha256=f4GiLn_LazweupfqTpubcdtdfE_vrOcmZudSsnYIY9E,3906
|
104
105
|
vellum_ee/workflows/display/utils/exceptions.py,sha256=LSwwxCYNxFkf5XMUcFkaZKpQ13OSrI7y_bpEUwbKVk0,169
|
105
|
-
vellum_ee/workflows/display/utils/expressions.py,sha256=
|
106
|
+
vellum_ee/workflows/display/utils/expressions.py,sha256=KxEl8yNx0yPvy0y84qABef5DwxRYGm0jgDd89i6PhSE,15534
|
106
107
|
vellum_ee/workflows/display/utils/registry.py,sha256=fWIm5Jj-10gNFjgn34iBu4RWv3Vd15ijtSN0V97bpW8,1513
|
107
108
|
vellum_ee/workflows/display/utils/tests/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
108
109
|
vellum_ee/workflows/display/utils/tests/test_auto_layout.py,sha256=vfXI769418s9vda5Gb5NFBH747WMOwSgHRXeLCTLVm8,2356
|
109
110
|
vellum_ee/workflows/display/utils/vellum.py,sha256=mtoXmSYwR7rvrq-d6CzCW_auaJXTct0Mi1F0xpRCiNQ,5627
|
110
111
|
vellum_ee/workflows/display/vellum.py,sha256=o7mq_vk2Yapu9DDKRz5l76h8EmCAypWGQYe6pryrbB8,3576
|
111
112
|
vellum_ee/workflows/display/workflows/__init__.py,sha256=kapXsC67VJcgSuiBMa86FdePG5A9kMB5Pi4Uy1O2ob4,207
|
112
|
-
vellum_ee/workflows/display/workflows/base_workflow_display.py,sha256=
|
113
|
+
vellum_ee/workflows/display/workflows/base_workflow_display.py,sha256=ZFZ8E2mIA-2aWnP9eRT_Z1s4efh7mTcdS8TQMlsICMY,40890
|
113
114
|
vellum_ee/workflows/display/workflows/get_vellum_workflow_display_class.py,sha256=gxz76AeCqgAZ9D2lZeTiZzxY9eMgn3qOSfVgiqYcOh8,2028
|
114
115
|
vellum_ee/workflows/display/workflows/tests/test_workflow_display.py,sha256=L7SKWJ26Ex-XXTNfHYXux7KP6I-dxE1EMQylap4Mhjs,31762
|
115
116
|
vellum_ee/workflows/display/workflows/vellum_workflow_display.py,sha256=aaKdmWrgEe5YyV4zuDY_4E3y-l59rIHQnNGiPj2OWxQ,359
|
@@ -134,7 +135,7 @@ vellum_ee/workflows/tests/local_workflow/nodes/__init__.py,sha256=1F6jxUpSKfPXPj
|
|
134
135
|
vellum_ee/workflows/tests/local_workflow/nodes/final_output.py,sha256=ZX7zBv87zirg0w9VKUW3QVDSdBLDqcqAMZjCL_oWbpU,297
|
135
136
|
vellum_ee/workflows/tests/local_workflow/nodes/templating_node.py,sha256=NQwFN61QkHfI3Vssz-B0NKGfupK8PU0FDSAIAhYBLi0,325
|
136
137
|
vellum_ee/workflows/tests/local_workflow/workflow.py,sha256=A4qOzOPNwePYxWbcAgIPLsmrVS_aVEZEc-wULSv787Q,393
|
137
|
-
vellum_ee/workflows/tests/test_display_meta.py,sha256=
|
138
|
+
vellum_ee/workflows/tests/test_display_meta.py,sha256=PkXJVnMZs9GNooDkd59n4YTBAX3XGPQWeSSVbhehVFM,5112
|
138
139
|
vellum_ee/workflows/tests/test_serialize_module.py,sha256=qcHbl6YaKtJebQJvw0OXCVlJXLkj6sjkbSMu05zXI0U,1874
|
139
140
|
vellum_ee/workflows/tests/test_server.py,sha256=SsOkS6sGO7uGC4mxvk4iv8AtcXs058P9hgFHzTWmpII,14519
|
140
141
|
vellum_ee/workflows/tests/test_virtual_files.py,sha256=TJEcMR0v2S8CkloXNmCHA0QW0K6pYNGaIjraJz7sFvY,2762
|
@@ -143,7 +144,7 @@ vellum/client/README.md,sha256=CuGUYnaE0Imt0KqQ4sIPaUghCjLHkF3DdEvZWu14-8s,4807
|
|
143
144
|
vellum/client/__init__.py,sha256=AYopGv2ZRVn3zsU8_km6KOvEHDbXiTPCVuYVI7bWvdA,120166
|
144
145
|
vellum/client/core/__init__.py,sha256=SQ85PF84B9MuKnBwHNHWemSGuy-g_515gFYNFhvEE0I,1438
|
145
146
|
vellum/client/core/api_error.py,sha256=RE8LELok2QCjABadECTvtDp7qejA1VmINCh6TbqPwSE,426
|
146
|
-
vellum/client/core/client_wrapper.py,sha256=
|
147
|
+
vellum/client/core/client_wrapper.py,sha256=KPv6Bi7gbvtP_1ZhF5Do4HCJqNkUHW0nNYBEtS1ZDeY,1869
|
147
148
|
vellum/client/core/datetime_utils.py,sha256=nBys2IsYrhPdszxGKCNRPSOCwa-5DWOHG95FB8G9PKo,1047
|
148
149
|
vellum/client/core/file.py,sha256=d4NNbX8XvXP32z8KpK2Xovv33nFfruIrpz0QWxlgpZk,2663
|
149
150
|
vellum/client/core/http_client.py,sha256=Z77OIxIbL4OAB2IDqjRq_sYa5yNYAWfmdhdCSSvh6Y4,19552
|
@@ -152,7 +153,7 @@ vellum/client/core/pydantic_utilities.py,sha256=lnpQ0SFnoVDtFp7vSHt5lmBXWeqgg03V
|
|
152
153
|
vellum/client/core/query_encoder.py,sha256=ekulqNd0j8TgD7ox-Qbz7liqX8-KP9blvT9DsRCenYM,2144
|
153
154
|
vellum/client/core/remove_none_from_dict.py,sha256=EU9SGgYidWq7SexuJbNs4-PZ-5Bl3Vppd864mS6vQZw,342
|
154
155
|
vellum/client/core/request_options.py,sha256=h0QUNCFVdCW_7GclVySCAY2w4NhtXVBUCmHgmzaxpcg,1681
|
155
|
-
vellum/client/core/serialization.py,sha256=
|
156
|
+
vellum/client/core/serialization.py,sha256=D9h_t-RQON3-CHWs1C4ESY9B-Yd5d-l5lnTLb_X896g,9601
|
156
157
|
vellum/client/environment.py,sha256=bcAFjoE9XXd7tiysYS90Os669IJmUMZS2JZ_ZQn0Dpg,498
|
157
158
|
vellum/client/errors/__init__.py,sha256=HZB8vVqzDNx0M2uFJ05S5RcGTH95iVDl4v3rQ4xRqSw,343
|
158
159
|
vellum/client/errors/bad_request_error.py,sha256=_EbO8mWqN9kFZPvIap8qa1lL_EWkRcsZe1HKV9GDWJY,264
|
@@ -574,7 +575,7 @@ vellum/client/types/search_results_input.py,sha256=kUfXw_NttVClGdEu9qGiZWXggFBKa
|
|
574
575
|
vellum/client/types/search_results_vellum_value.py,sha256=i_7d5cANsjuFSRwI3qUgzNdz6ZyrhakuxP4lMQeUFu4,774
|
575
576
|
vellum/client/types/search_results_vellum_value_request.py,sha256=Y36g5iLmweV4k_UiTDI9gSXf9Pn_aCwho0Z7dUNiVZU,803
|
576
577
|
vellum/client/types/search_weights_request.py,sha256=7YdTanQ82sDztyOwZGh6Iu9HJaTiAX3QnfxDQZJUzyE,828
|
577
|
-
vellum/client/types/secret_type_enum.py,sha256=
|
578
|
+
vellum/client/types/secret_type_enum.py,sha256=riVAwmIZxW39waRAr8at9RATpqPkBdEMTQqifHDyMOs,214
|
578
579
|
vellum/client/types/sentence_chunker_config.py,sha256=is3t8niS19gjRtqewSkLYpskJCbRloCZ78Kfe7zs3vE,709
|
579
580
|
vellum/client/types/sentence_chunker_config_request.py,sha256=EpGTP4z3YttiThYmdjwIBOI5YfsOlNP17dI9yiYqi3I,716
|
580
581
|
vellum/client/types/sentence_chunking.py,sha256=guqU3072X4h8Laf6LhTWQ5lpjBpTgoXRxKp5iXJby2U,783
|
@@ -1610,7 +1611,7 @@ vellum/workflows/nodes/displayable/bases/base_prompt_node/__init__.py,sha256=Org
|
|
1610
1611
|
vellum/workflows/nodes/displayable/bases/base_prompt_node/node.py,sha256=lGAWxTf02rRBgyxAFJNGldRX6sCRAZUDiUllg6zogHY,4459
|
1611
1612
|
vellum/workflows/nodes/displayable/bases/inline_prompt_node/__init__.py,sha256=Hl35IAoepRpE-j4cALaXVJIYTYOF3qszyVbxTj4kS1s,82
|
1612
1613
|
vellum/workflows/nodes/displayable/bases/inline_prompt_node/constants.py,sha256=fnjiRWLoRlC4Puo5oQcpZD5Hd-EesxsAo9l5tGAkpZQ,270
|
1613
|
-
vellum/workflows/nodes/displayable/bases/inline_prompt_node/node.py,sha256=
|
1614
|
+
vellum/workflows/nodes/displayable/bases/inline_prompt_node/node.py,sha256=6zzgeBTUwCiYTLRhrZAqmi-nU2r4q0gX-ytnatY5kwY,12896
|
1614
1615
|
vellum/workflows/nodes/displayable/bases/inline_prompt_node/tests/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
1615
1616
|
vellum/workflows/nodes/displayable/bases/inline_prompt_node/tests/test_inline_prompt_node.py,sha256=H1xEaL3vgEPAGQaF_rt8kLl46qmVJEEhcORXT7oRdPk,22626
|
1616
1617
|
vellum/workflows/nodes/displayable/bases/prompt_deployment_node.py,sha256=0a40fkkZkFMmZN0CsWf6EP_y1H6x36EGa3WcfVNyOsM,9797
|
@@ -1618,7 +1619,7 @@ vellum/workflows/nodes/displayable/bases/search_node.py,sha256=-BxQtuPgq8NZfUf5X
|
|
1618
1619
|
vellum/workflows/nodes/displayable/bases/tests/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
1619
1620
|
vellum/workflows/nodes/displayable/bases/tests/test_utils.py,sha256=eqdqbKNRWVMDPevgwLg1i6YK0g4L4bCy-7xCBN5yYZI,3156
|
1620
1621
|
vellum/workflows/nodes/displayable/bases/types.py,sha256=C37B2Qh2YP7s7pUjd-EYKc2Zl1TbnCgI_mENuUSb8bo,1706
|
1621
|
-
vellum/workflows/nodes/displayable/bases/utils.py,sha256=
|
1622
|
+
vellum/workflows/nodes/displayable/bases/utils.py,sha256=7L5wdQVm0ZMLpTJ7IBbTOzPhany7wSYPLYuY-0FBhvg,5490
|
1622
1623
|
vellum/workflows/nodes/displayable/code_execution_node/__init__.py,sha256=0FLWMMktpzSnmBMizQglBpcPrP80fzVsoJwJgf822Cg,76
|
1623
1624
|
vellum/workflows/nodes/displayable/code_execution_node/node.py,sha256=Qh4SPafzdRKbVKQH3h9SgH4vKeQQjvHAfP8ttUxLA2M,10304
|
1624
1625
|
vellum/workflows/nodes/displayable/code_execution_node/tests/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
@@ -1668,11 +1669,11 @@ vellum/workflows/nodes/experimental/__init__.py,sha256=_tpZGWAZLydcKxfrj1-plrZeT
|
|
1668
1669
|
vellum/workflows/nodes/experimental/openai_chat_completion_node/__init__.py,sha256=lsyD9laR9p7kx5-BXGH2gUTM242UhKy8SMV0SR6S2iE,90
|
1669
1670
|
vellum/workflows/nodes/experimental/openai_chat_completion_node/node.py,sha256=cKI2Ls25L-JVt4z4a2ozQa-YBeVy21Z7BQ32Sj7iBPE,10460
|
1670
1671
|
vellum/workflows/nodes/experimental/tool_calling_node/__init__.py,sha256=S7OzT3I4cyOU5Beoz87nPwCejCMP2FsHBFL8OcVmxJ4,118
|
1671
|
-
vellum/workflows/nodes/experimental/tool_calling_node/node.py,sha256=
|
1672
|
+
vellum/workflows/nodes/experimental/tool_calling_node/node.py,sha256=jwL1sbitmm1CpTOAEI0IIuc6VRr8d7yxUpS4Y5s9Bk8,5966
|
1672
1673
|
vellum/workflows/nodes/experimental/tool_calling_node/tests/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
1673
|
-
vellum/workflows/nodes/experimental/tool_calling_node/tests/test_node.py,sha256=
|
1674
|
+
vellum/workflows/nodes/experimental/tool_calling_node/tests/test_node.py,sha256=XK1H_QAT_nVFmFP442RYyPvpTfSgtU6kSGu3-OQPBNU,5072
|
1674
1675
|
vellum/workflows/nodes/experimental/tool_calling_node/tests/test_utils.py,sha256=sF4ZfGK2uQNBVXC9yrnbFVzKIM-HWvXO1wak160MUTE,1386
|
1675
|
-
vellum/workflows/nodes/experimental/tool_calling_node/utils.py,sha256=
|
1676
|
+
vellum/workflows/nodes/experimental/tool_calling_node/utils.py,sha256=ut3cdC7ezbxSvjMqHP0Km9yAVqOYoRztZVHShiq6zhk,12579
|
1676
1677
|
vellum/workflows/nodes/mocks.py,sha256=a1FjWEIocseMfjzM-i8DNozpUsaW0IONRpZmXBoWlyc,10455
|
1677
1678
|
vellum/workflows/nodes/tests/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
1678
1679
|
vellum/workflows/nodes/tests/test_mocks.py,sha256=mfPvrs75PKcsNsbJLQAN6PDFoVqs9TmQxpdyFKDdO60,7837
|
@@ -1705,7 +1706,7 @@ vellum/workflows/sandbox.py,sha256=GVJzVjMuYzOBnSrboB0_6MMRZWBluAyQ2o7syeaeBd0,2
|
|
1705
1706
|
vellum/workflows/state/__init__.py,sha256=yUUdR-_Vl7UiixNDYQZ-GEM_kJI9dnOia75TtuNEsnE,60
|
1706
1707
|
vellum/workflows/state/base.py,sha256=WIMJYyuHUrP4zt0Nudk66HAK1L6GgGmsU_GQp7BGE2U,22189
|
1707
1708
|
vellum/workflows/state/context.py,sha256=KOAI1wEGn8dGmhmAemJaf4SZbitP3jpIBcwKfznQaRE,3076
|
1708
|
-
vellum/workflows/state/encoder.py,sha256=
|
1709
|
+
vellum/workflows/state/encoder.py,sha256=I21qwYW3edIqlp78jdbjQgtou0hXYKvmofF-5_BCIlU,2552
|
1709
1710
|
vellum/workflows/state/store.py,sha256=uVe-oN73KwGV6M6YLhwZMMUQhzTQomsVfVnb8V91gVo,1147
|
1710
1711
|
vellum/workflows/state/tests/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
1711
1712
|
vellum/workflows/state/tests/test_state.py,sha256=YOiC9qZAzkdiqb7nRarNWeDwxo7xHv3y3czlHl81ezg,6741
|
@@ -1715,18 +1716,18 @@ vellum/workflows/tests/test_undefined.py,sha256=zMCVliCXVNLrlC6hEGyOWDnQADJ2g83y
|
|
1715
1716
|
vellum/workflows/types/__init__.py,sha256=KxUTMBGzuRCfiMqzzsykOeVvrrkaZmTTo1a7SLu8gRM,68
|
1716
1717
|
vellum/workflows/types/code_execution_node_wrappers.py,sha256=3MNIoFZKzVzNS5qFLVuDwMV17QJw72zo7NRf52yMq5A,3074
|
1717
1718
|
vellum/workflows/types/core.py,sha256=iLJkMKf417kjwRncWdT_qsfJ-qBv5x58um7SfrydJbs,1266
|
1718
|
-
vellum/workflows/types/definition.py,sha256=
|
1719
|
+
vellum/workflows/types/definition.py,sha256=guuCHZkto8bkknoMcjfXRhSaDuiNjx3SNkutPf1makc,2506
|
1719
1720
|
vellum/workflows/types/generics.py,sha256=tKXz0LwWJGKw1YGudyl9_yFDrRgU6yYV1yJV1Zv-LTw,1430
|
1720
1721
|
vellum/workflows/types/stack.py,sha256=h7NE0vXR7l9DevFBIzIAk1Zh59K-kECQtDTKOUunwMY,1314
|
1721
1722
|
vellum/workflows/types/tests/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
1722
1723
|
vellum/workflows/types/tests/test_utils.py,sha256=UnZog59tR577mVwqZRqqWn2fScoOU1H6up0EzS8zYhw,2536
|
1723
1724
|
vellum/workflows/types/utils.py,sha256=axxHbPLsnjhEOnMZrc5YarFd-P2bnsacBDQGNCvY8OY,6367
|
1724
1725
|
vellum/workflows/utils/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
1725
|
-
vellum/workflows/utils/functions.py,sha256=
|
1726
|
+
vellum/workflows/utils/functions.py,sha256=W4t-IXvCoIn_oVY_wEkph1xjpd_xpGzBwExWqgJXeho,7168
|
1726
1727
|
vellum/workflows/utils/names.py,sha256=QLUqfJ1tmSEeUwBKTTiv_Qk3QGbInC2RSmlXfGXc8Wo,380
|
1727
1728
|
vellum/workflows/utils/pydantic_schema.py,sha256=eR_bBtY-T0pttJP-ARwagSdCOnwPUtiT3cegm2lzDTQ,1310
|
1728
1729
|
vellum/workflows/utils/tests/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
1729
|
-
vellum/workflows/utils/tests/test_functions.py,sha256=
|
1730
|
+
vellum/workflows/utils/tests/test_functions.py,sha256=6AQt2Wu2Uj6UAxYzwi1Zd0YL4-ZOL47Yc_X3iE8ol9U,18445
|
1730
1731
|
vellum/workflows/utils/tests/test_names.py,sha256=aOqpyvMsOEK_9mg_-yaNxQDW7QQfwqsYs37PseyLhxw,402
|
1731
1732
|
vellum/workflows/utils/tests/test_uuids.py,sha256=i77ABQ0M3S-aFLzDXHJq_yr5FPkJEWCMBn1HJ3DObrE,437
|
1732
1733
|
vellum/workflows/utils/tests/test_vellum_variables.py,sha256=vbnKgm41aB5OXlO-ZIPbhQ6xDiZkT8KMxCLqz4zocWY,1791
|
@@ -1739,8 +1740,8 @@ vellum/workflows/workflows/event_filters.py,sha256=GSxIgwrX26a1Smfd-6yss2abGCnad
|
|
1739
1740
|
vellum/workflows/workflows/tests/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
1740
1741
|
vellum/workflows/workflows/tests/test_base_workflow.py,sha256=fROqff6AZpCIzaSwOKSdtYy4XR0UZQ6ejxL3RJOSJVs,20447
|
1741
1742
|
vellum/workflows/workflows/tests/test_context.py,sha256=VJBUcyWVtMa_lE5KxdhgMu0WYNYnUQUDvTF7qm89hJ0,2333
|
1742
|
-
vellum_ai-0.14.
|
1743
|
-
vellum_ai-0.14.
|
1744
|
-
vellum_ai-0.14.
|
1745
|
-
vellum_ai-0.14.
|
1746
|
-
vellum_ai-0.14.
|
1743
|
+
vellum_ai-0.14.74.dist-info/LICENSE,sha256=hOypcdt481qGNISA784bnAGWAE6tyIf9gc2E78mYC3E,1574
|
1744
|
+
vellum_ai-0.14.74.dist-info/METADATA,sha256=iFE4Twp7A5973aqOr498hlOQZ6LSnVAszYURwtB9VkI,5556
|
1745
|
+
vellum_ai-0.14.74.dist-info/WHEEL,sha256=sP946D7jFCHeNz5Iq4fL4Lu-PrWrFsgfLXbbkciIZwg,88
|
1746
|
+
vellum_ai-0.14.74.dist-info/entry_points.txt,sha256=HCH4yc_V3J_nDv3qJzZ_nYS8llCHZViCDP1ejgCc5Ak,42
|
1747
|
+
vellum_ai-0.14.74.dist-info/RECORD,,
|
@@ -15,6 +15,20 @@ from vellum_ee.workflows.display.utils.expressions import serialize_value
|
|
15
15
|
from vellum_ee.workflows.display.utils.vellum import infer_vellum_variable_type
|
16
16
|
from vellum_ee.workflows.display.vellum import NodeInput
|
17
17
|
|
18
|
+
|
19
|
+
def _contains_descriptors(obj):
|
20
|
+
"""Check if an object contains any descriptors or references that need special handling."""
|
21
|
+
if isinstance(obj, BaseDescriptor):
|
22
|
+
return True
|
23
|
+
elif isinstance(obj, dict):
|
24
|
+
return any(_contains_descriptors(v) for v in obj.values())
|
25
|
+
elif isinstance(obj, (list, tuple)):
|
26
|
+
return any(_contains_descriptors(item) for item in obj)
|
27
|
+
elif hasattr(obj, "__dict__"):
|
28
|
+
return any(_contains_descriptors(getattr(obj, field)) for field in obj.__dict__)
|
29
|
+
return False
|
30
|
+
|
31
|
+
|
18
32
|
_InlinePromptNodeType = TypeVar("_InlinePromptNodeType", bound=InlinePromptNode)
|
19
33
|
|
20
34
|
|
@@ -23,7 +37,6 @@ class BaseInlinePromptNodeDisplay(BaseNodeDisplay[_InlinePromptNodeType], Generi
|
|
23
37
|
InlinePromptNode.prompt_inputs,
|
24
38
|
}
|
25
39
|
__unserializable_attributes__ = {
|
26
|
-
InlinePromptNode.parameters,
|
27
40
|
InlinePromptNode.settings,
|
28
41
|
InlinePromptNode.expand_meta,
|
29
42
|
InlinePromptNode.request_options,
|
@@ -46,11 +59,15 @@ class BaseInlinePromptNodeDisplay(BaseNodeDisplay[_InlinePromptNodeType], Generi
|
|
46
59
|
|
47
60
|
ml_model = str(raise_if_descriptor(node.ml_model))
|
48
61
|
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
62
|
+
has_descriptors = _contains_descriptors(node_blocks)
|
63
|
+
|
64
|
+
blocks: list = []
|
65
|
+
if not has_descriptors:
|
66
|
+
blocks = [
|
67
|
+
self._generate_prompt_block(block, input_variable_id_by_name, [i])
|
68
|
+
for i, block in enumerate(node_blocks)
|
69
|
+
if not isinstance(block, BaseDescriptor)
|
70
|
+
]
|
54
71
|
|
55
72
|
functions = (
|
56
73
|
[self._generate_function_tools(function, i) for i, function in enumerate(function_definitions)]
|
@@ -72,7 +89,7 @@ class BaseInlinePromptNodeDisplay(BaseNodeDisplay[_InlinePromptNodeType], Generi
|
|
72
89
|
"target_handle_id": str(self.get_target_handle_id()),
|
73
90
|
"variant": "INLINE",
|
74
91
|
"exec_config": {
|
75
|
-
"parameters":
|
92
|
+
"parameters": self._serialize_parameters(node.parameters, display_context),
|
76
93
|
"input_variables": [prompt_input.dict() for prompt_input in prompt_inputs],
|
77
94
|
"prompt_template_block_data": {
|
78
95
|
"version": 1,
|
@@ -156,6 +173,7 @@ class BaseInlinePromptNodeDisplay(BaseNodeDisplay[_InlinePromptNodeType], Generi
|
|
156
173
|
}
|
157
174
|
|
158
175
|
elif prompt_block.block_type == "CHAT_MESSAGE":
|
176
|
+
|
159
177
|
chat_properties: JsonObject = {
|
160
178
|
"chat_role": prompt_block.chat_role,
|
161
179
|
"chat_source": prompt_block.chat_source,
|
@@ -253,3 +271,14 @@ class BaseInlinePromptNodeDisplay(BaseNodeDisplay[_InlinePromptNodeType], Generi
|
|
253
271
|
raise ValueError(f"Failed to serialize attribute '{attribute.name}': {e}")
|
254
272
|
|
255
273
|
return attributes
|
274
|
+
|
275
|
+
def _serialize_parameters(self, parameters, display_context: "WorkflowDisplayContext") -> JsonObject:
|
276
|
+
"""Serialize parameters, returning empty object when nested descriptors are detected."""
|
277
|
+
params = raise_if_descriptor(parameters)
|
278
|
+
if not params:
|
279
|
+
return {}
|
280
|
+
|
281
|
+
if _contains_descriptors(params):
|
282
|
+
return {}
|
283
|
+
|
284
|
+
return params.dict()
|
@@ -2,6 +2,7 @@ import pytest
|
|
2
2
|
from uuid import UUID
|
3
3
|
from typing import Type
|
4
4
|
|
5
|
+
from vellum.client.types.prompt_parameters import PromptParameters
|
5
6
|
from vellum.client.types.variable_prompt_block import VariablePromptBlock
|
6
7
|
from vellum.workflows import BaseWorkflow
|
7
8
|
from vellum.workflows.inputs import BaseInputs
|
@@ -280,3 +281,104 @@ def test_serialize_node__port_groups():
|
|
280
281
|
|
281
282
|
# AND the legacy source_handle_id should be the default port
|
282
283
|
assert my_prompt_node["data"]["source_handle_id"] == "149d97a4-3da3-44a9-95f7-ea7b8d38b877"
|
284
|
+
|
285
|
+
|
286
|
+
def test_serialize_node__prompt_parameters__dynamic_references():
|
287
|
+
# GIVEN input definition
|
288
|
+
class MyInputs(BaseInputs):
|
289
|
+
input_value: str
|
290
|
+
|
291
|
+
# AND a prompt node with PromptParameters containing dynamic references
|
292
|
+
class DynamicPromptNode(InlinePromptNode):
|
293
|
+
blocks = []
|
294
|
+
ml_model = "gpt-4o"
|
295
|
+
parameters = PromptParameters(custom_parameters={"json_schema": MyInputs.input_value})
|
296
|
+
|
297
|
+
# AND a workflow with the prompt node
|
298
|
+
class Workflow(BaseWorkflow[MyInputs, BaseState]):
|
299
|
+
graph = DynamicPromptNode
|
300
|
+
|
301
|
+
# WHEN the workflow is serialized
|
302
|
+
workflow_display = get_workflow_display(workflow_class=Workflow)
|
303
|
+
serialized_workflow: dict = workflow_display.serialize()
|
304
|
+
|
305
|
+
# THEN the node should properly serialize the PromptParameters
|
306
|
+
dynamic_prompt_node = next(
|
307
|
+
node
|
308
|
+
for node in serialized_workflow["workflow_raw_data"]["nodes"]
|
309
|
+
if node["id"] == str(DynamicPromptNode.__id__)
|
310
|
+
)
|
311
|
+
|
312
|
+
# AND the parameters should be properly serialized in exec_config
|
313
|
+
exec_config = dynamic_prompt_node["data"]["exec_config"]
|
314
|
+
assert "parameters" in exec_config
|
315
|
+
|
316
|
+
parameters = exec_config["parameters"]
|
317
|
+
assert parameters == {}
|
318
|
+
|
319
|
+
# AND the parameters should also be serialized in the attributes array
|
320
|
+
parameters_attribute = next(
|
321
|
+
(attr for attr in dynamic_prompt_node.get("attributes", []) if attr["name"] == "parameters"), None
|
322
|
+
)
|
323
|
+
assert parameters_attribute is not None
|
324
|
+
assert parameters_attribute["name"] == "parameters"
|
325
|
+
assert parameters_attribute["value"]["type"] == "DICTIONARY_REFERENCE"
|
326
|
+
assert parameters_attribute["value"]["entries"] == [
|
327
|
+
{
|
328
|
+
"id": "6b63ff96-a2eb-4c6e-bad1-bde01605fa86",
|
329
|
+
"key": "stop",
|
330
|
+
"value": {"type": "CONSTANT_VALUE", "value": {"type": "JSON", "value": None}},
|
331
|
+
},
|
332
|
+
{
|
333
|
+
"id": "265a1c17-2089-4ac1-b2ce-361b6b9a3335",
|
334
|
+
"key": "temperature",
|
335
|
+
"value": {"type": "CONSTANT_VALUE", "value": {"type": "JSON", "value": None}},
|
336
|
+
},
|
337
|
+
{
|
338
|
+
"id": "699976ec-8ec2-476a-a011-7cf810a8a307",
|
339
|
+
"key": "max_tokens",
|
340
|
+
"value": {"type": "CONSTANT_VALUE", "value": {"type": "JSON", "value": None}},
|
341
|
+
},
|
342
|
+
{
|
343
|
+
"id": "a87e23da-9794-41ff-ba80-c3a77e976e75",
|
344
|
+
"key": "top_p",
|
345
|
+
"value": {"type": "CONSTANT_VALUE", "value": {"type": "JSON", "value": None}},
|
346
|
+
},
|
347
|
+
{
|
348
|
+
"id": "18eb53c2-ec1a-4115-9f21-083af430df67",
|
349
|
+
"key": "top_k",
|
350
|
+
"value": {"type": "CONSTANT_VALUE", "value": {"type": "JSON", "value": None}},
|
351
|
+
},
|
352
|
+
{
|
353
|
+
"id": "295509a2-5837-452c-893d-f47b67c63c8a",
|
354
|
+
"key": "frequency_penalty",
|
355
|
+
"value": {"type": "CONSTANT_VALUE", "value": {"type": "JSON", "value": None}},
|
356
|
+
},
|
357
|
+
{
|
358
|
+
"id": "5fc64379-5566-426a-a909-dd56c3305aa5",
|
359
|
+
"key": "presence_penalty",
|
360
|
+
"value": {"type": "CONSTANT_VALUE", "value": {"type": "JSON", "value": None}},
|
361
|
+
},
|
362
|
+
{
|
363
|
+
"id": "5d326da0-c096-4425-8bf1-3a18764e96e3",
|
364
|
+
"key": "logit_bias",
|
365
|
+
"value": {"type": "CONSTANT_VALUE", "value": {"type": "JSON", "value": None}},
|
366
|
+
},
|
367
|
+
{
|
368
|
+
"id": "cd1a0e1b-6667-48a0-9964-257e1ec8851d",
|
369
|
+
"key": "custom_parameters",
|
370
|
+
"value": {
|
371
|
+
"entries": [
|
372
|
+
{
|
373
|
+
"id": "a9a3092e-dd18-4533-b6b5-24588ebd8f7f",
|
374
|
+
"key": "json_schema",
|
375
|
+
"value": {
|
376
|
+
"input_variable_id": "c02d1201-86d1-4364-b3b3-4fc6824db8a4",
|
377
|
+
"type": "WORKFLOW_INPUT",
|
378
|
+
},
|
379
|
+
}
|
380
|
+
],
|
381
|
+
"type": "DICTIONARY_REFERENCE",
|
382
|
+
},
|
383
|
+
},
|
384
|
+
]
|
@@ -1,7 +1,10 @@
|
|
1
|
+
import pytest
|
2
|
+
from dataclasses import dataclass
|
1
3
|
from uuid import uuid4
|
2
4
|
from typing import List
|
3
5
|
|
4
6
|
from deepdiff import DeepDiff
|
7
|
+
from pydantic import BaseModel
|
5
8
|
|
6
9
|
from vellum.client.types.chat_message import ChatMessage
|
7
10
|
from vellum.workflows.inputs.base import BaseInputs
|
@@ -70,6 +73,28 @@ def test_serialize_node__constant_value(serialize_node):
|
|
70
73
|
)
|
71
74
|
|
72
75
|
|
76
|
+
@pytest.mark.parametrize(
|
77
|
+
"boolean_value, expected_value",
|
78
|
+
[
|
79
|
+
(True, True),
|
80
|
+
(False, False),
|
81
|
+
],
|
82
|
+
)
|
83
|
+
def test_serialize_node__constant_boolean_value(serialize_node, boolean_value, expected_value):
|
84
|
+
class BooleanValueGenericNode(BaseNode):
|
85
|
+
attr: bool = boolean_value
|
86
|
+
|
87
|
+
serialized_node = serialize_node(BooleanValueGenericNode)
|
88
|
+
|
89
|
+
assert serialized_node["attributes"][0]["value"] == {
|
90
|
+
"type": "CONSTANT_VALUE",
|
91
|
+
"value": {
|
92
|
+
"type": "JSON",
|
93
|
+
"value": expected_value,
|
94
|
+
},
|
95
|
+
}
|
96
|
+
|
97
|
+
|
73
98
|
def test_serialize_node__constant_value_reference(serialize_node):
|
74
99
|
class ConstantValueReferenceGenericNode(BaseNode):
|
75
100
|
attr: str = ConstantValueReference("hello")
|
@@ -580,3 +605,68 @@ def test_serialize_node__coalesce(serialize_node):
|
|
580
605
|
serialized_node,
|
581
606
|
ignore_order=True,
|
582
607
|
)
|
608
|
+
|
609
|
+
|
610
|
+
def test_serialize_node__dataclass_with_node_output_reference(serialize_node):
|
611
|
+
@dataclass
|
612
|
+
class MyDataClass:
|
613
|
+
name: str
|
614
|
+
node_ref: str
|
615
|
+
|
616
|
+
class NodeWithOutput(BaseNode):
|
617
|
+
class Outputs(BaseNode.Outputs):
|
618
|
+
result: str
|
619
|
+
|
620
|
+
class NodeWithOutputDisplay(BaseNodeDisplay[NodeWithOutput]):
|
621
|
+
pass
|
622
|
+
|
623
|
+
class GenericNodeWithDataclass(BaseNode):
|
624
|
+
attr = MyDataClass(name="test", node_ref=NodeWithOutput.Outputs.result)
|
625
|
+
|
626
|
+
node_output_id = uuid4()
|
627
|
+
serialized_node = serialize_node(
|
628
|
+
node_class=GenericNodeWithDataclass,
|
629
|
+
global_node_displays={NodeWithOutput: NodeWithOutputDisplay()},
|
630
|
+
global_node_output_displays={
|
631
|
+
NodeWithOutput.Outputs.result: (NodeWithOutput, NodeOutputDisplay(id=node_output_id, name="result"))
|
632
|
+
},
|
633
|
+
)
|
634
|
+
|
635
|
+
attr_value = serialized_node["attributes"][0]["value"]
|
636
|
+
assert attr_value["type"] == "DICTIONARY_REFERENCE"
|
637
|
+
|
638
|
+
assert any(
|
639
|
+
entry["key"] == "node_ref" and entry["value"]["type"] == "NODE_OUTPUT" for entry in attr_value["entries"]
|
640
|
+
)
|
641
|
+
|
642
|
+
|
643
|
+
def test_serialize_node__pydantic_with_node_output_reference(serialize_node):
|
644
|
+
class MyPydanticModel(BaseModel):
|
645
|
+
name: str
|
646
|
+
node_ref: str
|
647
|
+
|
648
|
+
class NodeWithOutput(BaseNode):
|
649
|
+
class Outputs(BaseNode.Outputs):
|
650
|
+
result: str
|
651
|
+
|
652
|
+
class NodeWithOutputDisplay(BaseNodeDisplay[NodeWithOutput]):
|
653
|
+
pass
|
654
|
+
|
655
|
+
class GenericNodeWithPydantic(BaseNode):
|
656
|
+
attr = MyPydanticModel(name="test", node_ref=NodeWithOutput.Outputs.result)
|
657
|
+
|
658
|
+
node_output_id = uuid4()
|
659
|
+
serialized_node = serialize_node(
|
660
|
+
node_class=GenericNodeWithPydantic,
|
661
|
+
global_node_displays={NodeWithOutput: NodeWithOutputDisplay()},
|
662
|
+
global_node_output_displays={
|
663
|
+
NodeWithOutput.Outputs.result: (NodeWithOutput, NodeOutputDisplay(id=node_output_id, name="result"))
|
664
|
+
},
|
665
|
+
)
|
666
|
+
|
667
|
+
attr_value = serialized_node["attributes"][0]["value"]
|
668
|
+
assert attr_value["type"] == "DICTIONARY_REFERENCE"
|
669
|
+
|
670
|
+
assert any(
|
671
|
+
entry["key"] == "node_ref" and entry["value"]["type"] == "NODE_OUTPUT" for entry in attr_value["entries"]
|
672
|
+
)
|
@@ -240,6 +240,27 @@ def test_serialize_workflow():
|
|
240
240
|
},
|
241
241
|
},
|
242
242
|
},
|
243
|
+
{
|
244
|
+
"id": "2b98319f-f43d-42d9-a8b0-b148d5de0a2c",
|
245
|
+
"name": "parameters",
|
246
|
+
"value": {
|
247
|
+
"type": "CONSTANT_VALUE",
|
248
|
+
"value": {
|
249
|
+
"type": "JSON",
|
250
|
+
"value": {
|
251
|
+
"stop": [],
|
252
|
+
"temperature": 0.0,
|
253
|
+
"max_tokens": 4096,
|
254
|
+
"top_p": 1.0,
|
255
|
+
"top_k": 0,
|
256
|
+
"frequency_penalty": 0.0,
|
257
|
+
"presence_penalty": 0.0,
|
258
|
+
"logit_bias": None,
|
259
|
+
"custom_parameters": None,
|
260
|
+
},
|
261
|
+
},
|
262
|
+
},
|
263
|
+
},
|
243
264
|
],
|
244
265
|
},
|
245
266
|
prompt_node,
|
@@ -437,3 +458,99 @@ def test_serialize_workflow_with_descriptor_blocks():
|
|
437
458
|
},
|
438
459
|
}
|
439
460
|
]
|
461
|
+
|
462
|
+
|
463
|
+
def test_serialize_workflow_with_nested_descriptor_blocks():
|
464
|
+
"""Test that serialization handles BaseDescriptor instances nested in ChatMessageBlock.blocks."""
|
465
|
+
|
466
|
+
class TestInputs(BaseInputs):
|
467
|
+
noun: str
|
468
|
+
|
469
|
+
class UpstreamNode(BaseNode):
|
470
|
+
class Outputs(BaseNode.Outputs):
|
471
|
+
results: list
|
472
|
+
|
473
|
+
def run(self) -> Outputs:
|
474
|
+
return self.Outputs(results=["test"])
|
475
|
+
|
476
|
+
chat_block = ChatMessagePromptBlock(chat_role="SYSTEM", blocks=[JinjaPromptBlock(template="Hello")])
|
477
|
+
|
478
|
+
class TestInlinePromptNodeWithNestedDescriptorBlocks(InlinePromptNode):
|
479
|
+
ml_model = "gpt-4o"
|
480
|
+
blocks = [chat_block]
|
481
|
+
prompt_inputs = {"noun": TestInputs.noun}
|
482
|
+
|
483
|
+
object.__setattr__(chat_block, "blocks", [UpstreamNode.Outputs.results[0]])
|
484
|
+
|
485
|
+
class TestWorkflow(BaseWorkflow[TestInputs, BaseState]):
|
486
|
+
graph = UpstreamNode >> TestInlinePromptNodeWithNestedDescriptorBlocks
|
487
|
+
|
488
|
+
workflow_display = get_workflow_display(workflow_class=TestWorkflow)
|
489
|
+
serialized: dict = workflow_display.serialize()
|
490
|
+
|
491
|
+
prompt_nodes = [node for node in serialized["workflow_raw_data"]["nodes"] if node["type"] == "PROMPT"]
|
492
|
+
prompt_node = prompt_nodes[0]
|
493
|
+
|
494
|
+
blocks = prompt_node["data"]["exec_config"]["prompt_template_block_data"]["blocks"]
|
495
|
+
descriptor_blocks = [block for block in blocks if not isinstance(block, dict) or not block.get("block_type")]
|
496
|
+
assert len(descriptor_blocks) == 0, "BaseDescriptor blocks should not appear in serialized blocks"
|
497
|
+
|
498
|
+
blocks_attr = next((attr for attr in prompt_node["attributes"] if attr["name"] == "blocks"), None)
|
499
|
+
assert blocks_attr is not None, "blocks attribute should be present when blocks contain nested BaseDescriptor"
|
500
|
+
assert blocks_attr["value"]["type"] == "ARRAY_REFERENCE", "blocks attribute should be serialized as ARRAY_REFERENCE"
|
501
|
+
assert blocks_attr["value"]["items"] == [
|
502
|
+
{
|
503
|
+
"entries": [
|
504
|
+
{
|
505
|
+
"id": "24a203be-3cba-4b20-bc84-9993a476c120",
|
506
|
+
"key": "block_type",
|
507
|
+
"value": {"type": "CONSTANT_VALUE", "value": {"type": "STRING", "value": "CHAT_MESSAGE"}},
|
508
|
+
},
|
509
|
+
{
|
510
|
+
"id": "c06269e6-f74c-4860-8fa5-22dcbdc89399",
|
511
|
+
"key": "state",
|
512
|
+
"value": {"type": "CONSTANT_VALUE", "value": {"type": "JSON", "value": None}},
|
513
|
+
},
|
514
|
+
{
|
515
|
+
"id": "dd9c0d43-b931-4dc8-8b3a-a7507ddff0c1",
|
516
|
+
"key": "cache_config",
|
517
|
+
"value": {"type": "CONSTANT_VALUE", "value": {"type": "JSON", "value": None}},
|
518
|
+
},
|
519
|
+
{
|
520
|
+
"id": "bef22f2b-0b6e-4910-88cc-6df736d2e20e",
|
521
|
+
"key": "chat_role",
|
522
|
+
"value": {"type": "CONSTANT_VALUE", "value": {"type": "STRING", "value": "SYSTEM"}},
|
523
|
+
},
|
524
|
+
{
|
525
|
+
"id": "c0beec30-f85e-4a78-a3fb-baee54a692f8",
|
526
|
+
"key": "chat_source",
|
527
|
+
"value": {"type": "CONSTANT_VALUE", "value": {"type": "JSON", "value": None}},
|
528
|
+
},
|
529
|
+
{
|
530
|
+
"id": "f601f4f2-62fe-4697-9fe0-99ca8aa64500",
|
531
|
+
"key": "chat_message_unterminated",
|
532
|
+
"value": {"type": "CONSTANT_VALUE", "value": {"type": "JSON", "value": None}},
|
533
|
+
},
|
534
|
+
{
|
535
|
+
"id": "ad550008-64e3-44a3-a32a-84ec226db31c",
|
536
|
+
"key": "blocks",
|
537
|
+
"value": {
|
538
|
+
"items": [
|
539
|
+
{
|
540
|
+
"lhs": {
|
541
|
+
"node_id": "9fe5d3a3-7d26-4692-aa2d-e67c673b0c2b",
|
542
|
+
"node_output_id": "92f9a1b7-d33b-4f00-b4c2-e6f58150e166",
|
543
|
+
"type": "NODE_OUTPUT",
|
544
|
+
},
|
545
|
+
"operator": "accessField",
|
546
|
+
"rhs": {"type": "CONSTANT_VALUE", "value": {"type": "NUMBER", "value": 0.0}},
|
547
|
+
"type": "BINARY_EXPRESSION",
|
548
|
+
}
|
549
|
+
],
|
550
|
+
"type": "ARRAY_REFERENCE",
|
551
|
+
},
|
552
|
+
},
|
553
|
+
],
|
554
|
+
"type": "DICTIONARY_REFERENCE",
|
555
|
+
}
|
556
|
+
]
|
@@ -131,6 +131,8 @@ def test_serialize_workflow():
|
|
131
131
|
"value": [
|
132
132
|
{
|
133
133
|
"type": "INLINE_WORKFLOW",
|
134
|
+
"name": "BasicInlineSubworkflowWorkflow",
|
135
|
+
"description": "\n A workflow that gets the weather for a given city and date.\n ", # noqa: E501
|
134
136
|
"exec_config": {
|
135
137
|
"workflow_raw_data": {
|
136
138
|
"nodes": [
|
@@ -410,6 +412,11 @@ def test_serialize_workflow():
|
|
410
412
|
"name": "function_configs",
|
411
413
|
"value": {"type": "CONSTANT_VALUE", "value": {"type": "JSON", "value": None}},
|
412
414
|
},
|
415
|
+
{
|
416
|
+
"id": "1668419e-a193-43a5-8a97-3394e89bf278",
|
417
|
+
"name": "max_prompt_iterations",
|
418
|
+
"value": {"type": "CONSTANT_VALUE", "value": {"type": "NUMBER", "value": 5.0}},
|
419
|
+
},
|
413
420
|
],
|
414
421
|
"outputs": [
|
415
422
|
{"id": "e62bc785-a914-4066-b79e-8c89a5d0ec6c", "name": "text", "type": "STRING", "value": None},
|
@@ -131,6 +131,8 @@ def test_serialize_workflow():
|
|
131
131
|
"value": [
|
132
132
|
{
|
133
133
|
"type": "CODE_EXECUTION",
|
134
|
+
"name": "get_current_weather",
|
135
|
+
"description": "\n Get the current weather in a given location.\n ",
|
134
136
|
"definition": {
|
135
137
|
"state": None,
|
136
138
|
"cache_config": None,
|
@@ -183,6 +185,11 @@ def test_serialize_workflow():
|
|
183
185
|
],
|
184
186
|
},
|
185
187
|
},
|
188
|
+
{
|
189
|
+
"id": "1668419e-a193-43a5-8a97-3394e89bf278",
|
190
|
+
"name": "max_prompt_iterations",
|
191
|
+
"value": {"type": "CONSTANT_VALUE", "value": {"type": "NUMBER", "value": 5.0}},
|
192
|
+
},
|
186
193
|
],
|
187
194
|
"outputs": [
|
188
195
|
{"id": "e62bc785-a914-4066-b79e-8c89a5d0ec6c", "name": "text", "type": "STRING", "value": None},
|
@@ -0,0 +1,62 @@
|
|
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_deployment.workflow import (
|
6
|
+
BasicToolCallingNodeWorkflowDeploymentWorkflow,
|
7
|
+
)
|
8
|
+
|
9
|
+
|
10
|
+
def test_serialize_workflow():
|
11
|
+
# GIVEN a Workflow that uses a generic node
|
12
|
+
# WHEN we serialize it
|
13
|
+
workflow_display = get_workflow_display(workflow_class=BasicToolCallingNodeWorkflowDeploymentWorkflow)
|
14
|
+
|
15
|
+
serialized_workflow: dict = workflow_display.serialize()
|
16
|
+
# THEN we should get a serialized representation of the Workflow
|
17
|
+
assert serialized_workflow.keys() == {
|
18
|
+
"workflow_raw_data",
|
19
|
+
"input_variables",
|
20
|
+
"state_variables",
|
21
|
+
"output_variables",
|
22
|
+
}
|
23
|
+
|
24
|
+
# AND its input variables should be what we expect
|
25
|
+
input_variables = serialized_workflow["input_variables"]
|
26
|
+
assert len(input_variables) == 1
|
27
|
+
|
28
|
+
# AND its output variables should be what we expect
|
29
|
+
output_variables = serialized_workflow["output_variables"]
|
30
|
+
assert len(output_variables) == 2
|
31
|
+
assert not DeepDiff(
|
32
|
+
[
|
33
|
+
{"id": "3626cfa6-76f8-465e-b156-c809e3a2cee9", "key": "text", "type": "STRING"},
|
34
|
+
{"id": "cb82117a-d649-4c3e-9342-c552028fa2ad", "key": "chat_history", "type": "CHAT_HISTORY"},
|
35
|
+
],
|
36
|
+
output_variables,
|
37
|
+
ignore_order=True,
|
38
|
+
)
|
39
|
+
|
40
|
+
# AND its raw data should be what we expect
|
41
|
+
workflow_raw_data = serialized_workflow["workflow_raw_data"]
|
42
|
+
tool_calling_node = workflow_raw_data["nodes"][1]
|
43
|
+
function_attributes = next(attr for attr in tool_calling_node["attributes"] if attr["name"] == "functions")
|
44
|
+
assert function_attributes == {
|
45
|
+
"id": "73a94e3c-1935-4308-a68a-ecd5441804b7",
|
46
|
+
"name": "functions",
|
47
|
+
"value": {
|
48
|
+
"type": "CONSTANT_VALUE",
|
49
|
+
"value": {
|
50
|
+
"type": "JSON",
|
51
|
+
"value": [
|
52
|
+
{
|
53
|
+
"type": "WORKFLOW_DEPLOYMENT",
|
54
|
+
"name": "deployment_1",
|
55
|
+
"description": "Workflow deployment for deployment_1",
|
56
|
+
"deployment": "deployment_1",
|
57
|
+
"release_tag": "LATEST",
|
58
|
+
}
|
59
|
+
],
|
60
|
+
},
|
61
|
+
},
|
62
|
+
}
|
@@ -1,5 +1,8 @@
|
|
1
|
+
from dataclasses import asdict, is_dataclass
|
1
2
|
from typing import TYPE_CHECKING, Any, Dict, List, cast
|
2
3
|
|
4
|
+
from pydantic import BaseModel
|
5
|
+
|
3
6
|
from vellum.client.types.logical_operator import LogicalOperator
|
4
7
|
from vellum.workflows.descriptors.base import BaseDescriptor
|
5
8
|
from vellum.workflows.expressions.accessor import AccessorExpression
|
@@ -39,6 +42,7 @@ from vellum.workflows.references.state_value import StateValueReference
|
|
39
42
|
from vellum.workflows.references.vellum_secret import VellumSecretReference
|
40
43
|
from vellum.workflows.references.workflow_input import WorkflowInputReference
|
41
44
|
from vellum.workflows.types.core import JsonArray, JsonObject
|
45
|
+
from vellum.workflows.types.definition import DeploymentDefinition
|
42
46
|
from vellum.workflows.types.generics import is_workflow_class
|
43
47
|
from vellum.workflows.utils.uuids import uuid4_from_hash
|
44
48
|
from vellum_ee.workflows.display.utils.exceptions import UnsupportedSerializationException
|
@@ -290,6 +294,10 @@ def serialize_value(display_context: "WorkflowDisplayContext", value: Any) -> Js
|
|
290
294
|
"items": cast(JsonArray, serialized_items), # list[JsonObject] -> JsonArray
|
291
295
|
}
|
292
296
|
|
297
|
+
if is_dataclass(value) and not isinstance(value, type):
|
298
|
+
dict_value = asdict(value)
|
299
|
+
return serialize_value(display_context, dict_value)
|
300
|
+
|
293
301
|
if isinstance(value, dict):
|
294
302
|
serialized_entries: List[Dict[str, Any]] = [
|
295
303
|
{
|
@@ -321,18 +329,41 @@ def serialize_value(display_context: "WorkflowDisplayContext", value: Any) -> Js
|
|
321
329
|
from vellum_ee.workflows.display.workflows.get_vellum_workflow_display_class import get_workflow_display
|
322
330
|
|
323
331
|
workflow_display = get_workflow_display(workflow_class=value)
|
324
|
-
|
332
|
+
serialized_value: dict = workflow_display.serialize()
|
333
|
+
name = serialized_value["workflow_raw_data"]["definition"]["name"]
|
334
|
+
description = value.__doc__ or ""
|
325
335
|
return {
|
326
336
|
"type": "CONSTANT_VALUE",
|
327
337
|
"value": {
|
328
338
|
"type": "JSON",
|
329
339
|
"value": {
|
330
340
|
"type": "INLINE_WORKFLOW",
|
331
|
-
"
|
341
|
+
"name": name,
|
342
|
+
"description": description,
|
343
|
+
"exec_config": serialized_value,
|
344
|
+
},
|
345
|
+
},
|
346
|
+
}
|
347
|
+
|
348
|
+
if isinstance(value, DeploymentDefinition):
|
349
|
+
return {
|
350
|
+
"type": "CONSTANT_VALUE",
|
351
|
+
"value": {
|
352
|
+
"type": "JSON",
|
353
|
+
"value": {
|
354
|
+
"type": "WORKFLOW_DEPLOYMENT",
|
355
|
+
"name": value.deployment,
|
356
|
+
"description": f"Workflow deployment for {value.deployment}",
|
357
|
+
"deployment": value.deployment,
|
358
|
+
"release_tag": value.release_tag,
|
332
359
|
},
|
333
360
|
},
|
334
361
|
}
|
335
362
|
|
363
|
+
if isinstance(value, BaseModel):
|
364
|
+
dict_value = value.model_dump()
|
365
|
+
return serialize_value(display_context, dict_value)
|
366
|
+
|
336
367
|
if not isinstance(value, BaseDescriptor):
|
337
368
|
vellum_value = primitive_to_vellum_value(value)
|
338
369
|
return {
|
@@ -690,8 +690,7 @@ class BaseWorkflowDisplay(Generic[WorkflowType]):
|
|
690
690
|
try:
|
691
691
|
display_module = importlib.import_module(full_workflow_display_module_path)
|
692
692
|
except ModuleNotFoundError:
|
693
|
-
|
694
|
-
return None
|
693
|
+
return BaseWorkflowDisplay._gather_event_display_context_from_workflow_crawling(module_path, workflow_class)
|
695
694
|
|
696
695
|
WorkflowDisplayClass: Optional[Type[BaseWorkflowDisplay]] = None
|
697
696
|
for name, definition in display_module.__dict__.items():
|
@@ -708,11 +707,26 @@ class BaseWorkflowDisplay(Generic[WorkflowType]):
|
|
708
707
|
WorkflowDisplayClass = definition
|
709
708
|
break
|
710
709
|
|
711
|
-
if
|
712
|
-
|
713
|
-
|
710
|
+
if WorkflowDisplayClass:
|
711
|
+
return WorkflowDisplayClass().get_event_display_context()
|
712
|
+
|
713
|
+
return BaseWorkflowDisplay._gather_event_display_context_from_workflow_crawling(module_path, workflow_class)
|
714
|
+
|
715
|
+
@staticmethod
|
716
|
+
def _gather_event_display_context_from_workflow_crawling(
|
717
|
+
module_path: str,
|
718
|
+
workflow_class: Optional[Type[BaseWorkflow]] = None,
|
719
|
+
) -> Union[WorkflowEventDisplayContext, None]:
|
720
|
+
try:
|
721
|
+
if workflow_class is None:
|
722
|
+
workflow_class = BaseWorkflow.load_from_module(module_path)
|
714
723
|
|
715
|
-
|
724
|
+
workflow_display = get_workflow_display(workflow_class=workflow_class)
|
725
|
+
return workflow_display.get_event_display_context()
|
726
|
+
|
727
|
+
except ModuleNotFoundError:
|
728
|
+
logger.exception("Failed to load workflow from module %s", module_path)
|
729
|
+
return None
|
716
730
|
|
717
731
|
def get_event_display_context(self):
|
718
732
|
display_context = self.display_context
|
@@ -4,6 +4,7 @@ import sys
|
|
4
4
|
from uuid import uuid4
|
5
5
|
|
6
6
|
from vellum.workflows import BaseWorkflow
|
7
|
+
from vellum.workflows.events.workflow import WorkflowEventDisplayContext
|
7
8
|
from vellum_ee.workflows.display.workflows import BaseWorkflowDisplay
|
8
9
|
from vellum_ee.workflows.server.virtual_file_loader import VirtualFileFinder
|
9
10
|
|
@@ -102,3 +103,43 @@ class MyCustomWorkflowDisplay(BaseWorkflowDisplay[MyCustomWorkflow]):
|
|
102
103
|
assert display_meta.workflow_outputs == {
|
103
104
|
"answer": workflow_output_id,
|
104
105
|
}
|
106
|
+
|
107
|
+
|
108
|
+
def test_gather_event_display_context__workflow_crawling_without_display_module():
|
109
|
+
# GIVEN a workflow module without a display module
|
110
|
+
files = {
|
111
|
+
"__init__.py": "",
|
112
|
+
"workflow.py": """\
|
113
|
+
from vellum.workflows import BaseWorkflow
|
114
|
+
from vellum.workflows.nodes import BaseNode
|
115
|
+
|
116
|
+
class TestNode(BaseNode):
|
117
|
+
class Outputs(BaseNode.Outputs):
|
118
|
+
result: str
|
119
|
+
|
120
|
+
class TestWorkflow(BaseWorkflow):
|
121
|
+
graph = TestNode
|
122
|
+
|
123
|
+
class Outputs(BaseWorkflow.Outputs):
|
124
|
+
final_result = TestNode.Outputs.result
|
125
|
+
""",
|
126
|
+
}
|
127
|
+
|
128
|
+
namespace = str(uuid4())
|
129
|
+
|
130
|
+
# AND the virtual file loader is registered
|
131
|
+
sys.meta_path.append(VirtualFileFinder(files, namespace))
|
132
|
+
|
133
|
+
# WHEN the workflow display context is gathered
|
134
|
+
display_meta = BaseWorkflowDisplay.gather_event_display_context(namespace)
|
135
|
+
|
136
|
+
# THEN the workflow display context should be successfully created via workflow crawling
|
137
|
+
assert display_meta is not None
|
138
|
+
assert isinstance(display_meta, WorkflowEventDisplayContext)
|
139
|
+
|
140
|
+
# AND the node displays should be populated with the correct node structure
|
141
|
+
assert len(display_meta.node_displays) == 1
|
142
|
+
node_display = list(display_meta.node_displays.values())[0]
|
143
|
+
assert "result" in node_display.output_display
|
144
|
+
|
145
|
+
assert "final_result" in display_meta.workflow_outputs
|
File without changes
|
File without changes
|
File without changes
|