vellum-ai 1.1.5__py3-none-any.whl → 1.2.1__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 +18 -1
- vellum/client/__init__.py +3 -0
- vellum/client/core/client_wrapper.py +2 -2
- vellum/client/errors/__init__.py +10 -1
- vellum/client/errors/too_many_requests_error.py +11 -0
- vellum/client/errors/unauthorized_error.py +11 -0
- vellum/client/reference.md +94 -0
- vellum/client/resources/__init__.py +2 -0
- vellum/client/resources/events/__init__.py +4 -0
- vellum/client/resources/events/client.py +165 -0
- vellum/client/resources/events/raw_client.py +207 -0
- vellum/client/types/__init__.py +6 -0
- vellum/client/types/error_detail_response.py +22 -0
- vellum/client/types/event_create_response.py +26 -0
- vellum/client/types/execution_thinking_vellum_value.py +1 -1
- vellum/client/types/thinking_vellum_value.py +1 -1
- vellum/client/types/thinking_vellum_value_request.py +1 -1
- vellum/client/types/workflow_event.py +33 -0
- vellum/errors/too_many_requests_error.py +3 -0
- vellum/errors/unauthorized_error.py +3 -0
- vellum/resources/events/__init__.py +3 -0
- vellum/resources/events/client.py +3 -0
- vellum/resources/events/raw_client.py +3 -0
- vellum/types/error_detail_response.py +3 -0
- vellum/types/event_create_response.py +3 -0
- vellum/types/workflow_event.py +3 -0
- vellum/workflows/nodes/displayable/bases/api_node/node.py +4 -0
- vellum/workflows/nodes/displayable/bases/api_node/tests/test_node.py +26 -0
- vellum/workflows/nodes/displayable/bases/inline_prompt_node/node.py +6 -1
- vellum/workflows/nodes/displayable/bases/inline_prompt_node/tests/test_inline_prompt_node.py +22 -0
- vellum/workflows/sandbox.py +28 -8
- vellum/workflows/state/encoder.py +19 -1
- vellum/workflows/utils/hmac.py +44 -0
- {vellum_ai-1.1.5.dist-info → vellum_ai-1.2.1.dist-info}/METADATA +1 -1
- {vellum_ai-1.1.5.dist-info → vellum_ai-1.2.1.dist-info}/RECORD +61 -43
- vellum_ee/workflows/display/nodes/base_node_display.py +2 -2
- vellum_ee/workflows/display/nodes/vellum/inline_prompt_node.py +37 -7
- vellum_ee/workflows/display/nodes/vellum/retry_node.py +1 -1
- vellum_ee/workflows/display/nodes/vellum/tests/test_retry_node.py +1 -1
- vellum_ee/workflows/display/nodes/vellum/tests/test_tool_calling_node.py +314 -2
- vellum_ee/workflows/display/nodes/vellum/try_node.py +1 -1
- vellum_ee/workflows/display/tests/test_base_workflow_display.py +53 -1
- vellum_ee/workflows/display/tests/workflow_serialization/generic_nodes/test_adornments_serialization.py +9 -9
- vellum_ee/workflows/display/tests/workflow_serialization/generic_nodes/test_attributes_serialization.py +9 -9
- 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 -15
- vellum_ee/workflows/display/tests/workflow_serialization/generic_nodes/test_trigger_serialization.py +58 -3
- vellum_ee/workflows/display/tests/workflow_serialization/test_basic_code_execution_node_serialization.py +1 -1
- vellum_ee/workflows/display/tests/workflow_serialization/test_basic_inline_prompt_node_serialization.py +4 -0
- vellum_ee/workflows/display/tests/workflow_serialization/test_basic_inline_subworkflow_serialization.py +1 -1
- vellum_ee/workflows/display/tests/workflow_serialization/test_basic_tool_calling_node_inline_workflow_serialization.py +2 -2
- vellum_ee/workflows/display/tests/workflow_serialization/test_basic_tool_calling_node_serialization.py +1 -1
- vellum_ee/workflows/display/utils/expressions.py +9 -1
- vellum_ee/workflows/display/utils/registry.py +46 -0
- vellum_ee/workflows/display/workflows/base_workflow_display.py +21 -1
- vellum_ee/workflows/tests/test_registry.py +169 -0
- vellum_ee/workflows/tests/test_serialize_module.py +31 -0
- vellum_ee/workflows/tests/test_server.py +72 -0
- {vellum_ai-1.1.5.dist-info → vellum_ai-1.2.1.dist-info}/LICENSE +0 -0
- {vellum_ai-1.1.5.dist-info → vellum_ai-1.2.1.dist-info}/WHEEL +0 -0
- {vellum_ai-1.1.5.dist-info → vellum_ai-1.2.1.dist-info}/entry_points.txt +0 -0
@@ -1,12 +1,31 @@
|
|
1
|
+
from datetime import datetime
|
2
|
+
|
1
3
|
from vellum.client.types.prompt_parameters import PromptParameters
|
4
|
+
from vellum.client.types.release_review_reviewer import ReleaseReviewReviewer
|
5
|
+
from vellum.client.types.workflow_deployment_release import (
|
6
|
+
ReleaseEnvironment,
|
7
|
+
ReleaseReleaseTag,
|
8
|
+
SlimReleaseReview,
|
9
|
+
WorkflowDeploymentRelease,
|
10
|
+
WorkflowDeploymentReleaseWorkflowDeployment,
|
11
|
+
WorkflowDeploymentReleaseWorkflowVersion,
|
12
|
+
)
|
2
13
|
from vellum.workflows import BaseWorkflow
|
3
14
|
from vellum.workflows.inputs import BaseInputs
|
15
|
+
from vellum.workflows.nodes.bases import BaseNode
|
16
|
+
from vellum.workflows.nodes.displayable.code_execution_node.node import CodeExecutionNode
|
4
17
|
from vellum.workflows.nodes.displayable.inline_prompt_node.node import InlinePromptNode
|
5
18
|
from vellum.workflows.nodes.displayable.tool_calling_node.node import ToolCallingNode
|
6
19
|
from vellum.workflows.nodes.displayable.tool_calling_node.state import ToolCallingState
|
7
20
|
from vellum.workflows.nodes.displayable.tool_calling_node.utils import create_router_node, create_tool_prompt_node
|
21
|
+
from vellum.workflows.outputs.base import BaseOutputs
|
8
22
|
from vellum.workflows.state.base import BaseState
|
9
|
-
from vellum.workflows.types.definition import
|
23
|
+
from vellum.workflows.types.definition import (
|
24
|
+
AuthorizationType,
|
25
|
+
DeploymentDefinition,
|
26
|
+
EnvironmentVariableReference,
|
27
|
+
MCPServer,
|
28
|
+
)
|
10
29
|
from vellum_ee.workflows.display.nodes.get_node_display_class import get_node_display_class
|
11
30
|
from vellum_ee.workflows.display.workflows.get_vellum_workflow_display_class import get_workflow_display
|
12
31
|
|
@@ -184,6 +203,58 @@ def test_serialize_node__tool_calling_node__mcp_server_api_key():
|
|
184
203
|
}
|
185
204
|
|
186
205
|
|
206
|
+
def test_serialize_node__tool_calling_node__mcp_server_no_authorization():
|
207
|
+
# GIVEN a tool calling node with an mcp server
|
208
|
+
class MyToolCallingNode(ToolCallingNode):
|
209
|
+
functions = [
|
210
|
+
MCPServer(
|
211
|
+
name="my-mcp-server",
|
212
|
+
url="https://my-mcp-server.com",
|
213
|
+
)
|
214
|
+
]
|
215
|
+
|
216
|
+
# AND a workflow with the tool calling node
|
217
|
+
class Workflow(BaseWorkflow):
|
218
|
+
graph = MyToolCallingNode
|
219
|
+
|
220
|
+
# WHEN the workflow is serialized
|
221
|
+
workflow_display = get_workflow_display(workflow_class=Workflow)
|
222
|
+
serialized_workflow: dict = workflow_display.serialize()
|
223
|
+
|
224
|
+
# THEN the node should properly serialize the mcp server
|
225
|
+
my_tool_calling_node = next(
|
226
|
+
node
|
227
|
+
for node in serialized_workflow["workflow_raw_data"]["nodes"]
|
228
|
+
if node["id"] == str(MyToolCallingNode.__id__)
|
229
|
+
)
|
230
|
+
|
231
|
+
functions_attribute = next(
|
232
|
+
attribute for attribute in my_tool_calling_node["attributes"] if attribute["name"] == "functions"
|
233
|
+
)
|
234
|
+
|
235
|
+
assert functions_attribute == {
|
236
|
+
"id": "c8957551-cb3d-49af-8053-acd256c1d852",
|
237
|
+
"name": "functions",
|
238
|
+
"value": {
|
239
|
+
"type": "CONSTANT_VALUE",
|
240
|
+
"value": {
|
241
|
+
"type": "JSON",
|
242
|
+
"value": [
|
243
|
+
{
|
244
|
+
"type": "MCP_SERVER",
|
245
|
+
"name": "my-mcp-server",
|
246
|
+
"url": "https://my-mcp-server.com",
|
247
|
+
"authorization_type": None,
|
248
|
+
"bearer_token_value": None,
|
249
|
+
"api_key_header_key": None,
|
250
|
+
"api_key_header_value": None,
|
251
|
+
}
|
252
|
+
],
|
253
|
+
},
|
254
|
+
},
|
255
|
+
}
|
256
|
+
|
257
|
+
|
187
258
|
def test_serialize_tool_router_node():
|
188
259
|
"""
|
189
260
|
Test that the tool router node created by create_router_node serializes successfully.
|
@@ -243,7 +314,7 @@ def test_serialize_tool_router_node():
|
|
243
314
|
},
|
244
315
|
"display_data": {"position": {"x": 0.0, "y": 0.0}},
|
245
316
|
"id": "690c66e1-1e18-4984-b695-84beb0157541",
|
246
|
-
"label": "
|
317
|
+
"label": "Router Node",
|
247
318
|
"outputs": [],
|
248
319
|
"ports": [
|
249
320
|
{
|
@@ -332,3 +403,244 @@ def test_serialize_tool_router_node():
|
|
332
403
|
"trigger": {"id": "73a96f44-c2dd-40cc-96f6-49b9f914b166", "merge_behavior": "AWAIT_ATTRIBUTES"},
|
333
404
|
"type": "GENERIC",
|
334
405
|
}
|
406
|
+
|
407
|
+
|
408
|
+
def test_serialize_node__tool_calling_node__subworkflow_with_parent_input_reference():
|
409
|
+
"""
|
410
|
+
Test that a tool calling node with a subworkflow that references parent inputs serializes correctly
|
411
|
+
"""
|
412
|
+
|
413
|
+
# GIVEN a workflow inputs class
|
414
|
+
class MyInputs(BaseInputs):
|
415
|
+
text: str
|
416
|
+
greeting: str
|
417
|
+
|
418
|
+
# AND a code execution node that references parent inputs
|
419
|
+
class CodeExecution(CodeExecutionNode[BaseState, str]):
|
420
|
+
code = ""
|
421
|
+
code_inputs = {
|
422
|
+
"text": MyInputs.text,
|
423
|
+
}
|
424
|
+
runtime = "PYTHON_3_11_6"
|
425
|
+
packages = []
|
426
|
+
|
427
|
+
# AND a subworkflow that uses the code execution node
|
428
|
+
class FunctionSubworkflow(BaseWorkflow):
|
429
|
+
graph = CodeExecution
|
430
|
+
|
431
|
+
class Outputs(BaseWorkflow.Outputs):
|
432
|
+
output = CodeExecution.Outputs.result
|
433
|
+
|
434
|
+
# AND a tool calling node that uses the subworkflow
|
435
|
+
class MyToolCallingNode(ToolCallingNode):
|
436
|
+
ml_model = "gpt-4.1"
|
437
|
+
prompt_inputs = {
|
438
|
+
"text": MyInputs.text,
|
439
|
+
}
|
440
|
+
blocks = []
|
441
|
+
parameters = PromptParameters()
|
442
|
+
functions = [FunctionSubworkflow]
|
443
|
+
|
444
|
+
# AND a workflow with the tool calling node
|
445
|
+
class Workflow(BaseWorkflow[MyInputs, BaseState]):
|
446
|
+
graph = MyToolCallingNode
|
447
|
+
|
448
|
+
# WHEN the workflow is serialized
|
449
|
+
workflow_display = get_workflow_display(workflow_class=Workflow)
|
450
|
+
serialized_workflow: dict = workflow_display.serialize()
|
451
|
+
|
452
|
+
# THEN the node should properly serialize the functions with parent input references
|
453
|
+
my_tool_calling_node = next(
|
454
|
+
node
|
455
|
+
for node in serialized_workflow["workflow_raw_data"]["nodes"]
|
456
|
+
if node["id"] == str(MyToolCallingNode.__id__)
|
457
|
+
)
|
458
|
+
|
459
|
+
functions_attribute = next(
|
460
|
+
attribute for attribute in my_tool_calling_node["attributes"] if attribute["name"] == "functions"
|
461
|
+
)
|
462
|
+
|
463
|
+
data = functions_attribute["value"]["value"]["value"][0]
|
464
|
+
nodes = data["exec_config"]["workflow_raw_data"]["nodes"]
|
465
|
+
code_exec_node = next((node for node in nodes if node["type"] == "CODE_EXECUTION"), None)
|
466
|
+
|
467
|
+
assert code_exec_node is not None
|
468
|
+
text_input = next((input for input in code_exec_node["inputs"] if input["key"] == "text"), None)
|
469
|
+
assert text_input == {
|
470
|
+
"id": "da92a1c4-d37c-4008-a1ab-c0bcc0cd20d0",
|
471
|
+
"key": "text",
|
472
|
+
"value": {
|
473
|
+
"rules": [
|
474
|
+
{"type": "INPUT_VARIABLE", "data": {"input_variable_id": "6f0c1889-3f08-4c5c-bb24-f7b94169105c"}}
|
475
|
+
],
|
476
|
+
"combinator": "OR",
|
477
|
+
},
|
478
|
+
}
|
479
|
+
|
480
|
+
|
481
|
+
def test_serialize_tool_prompt_node_with_inline_workflow():
|
482
|
+
"""
|
483
|
+
Test that the tool prompt node created by create_tool_prompt_node serializes successfully with inline workflow.
|
484
|
+
"""
|
485
|
+
|
486
|
+
# GIVEN a simple inline workflow for tool calling
|
487
|
+
class SimpleWorkflowInputs(BaseInputs):
|
488
|
+
message: str
|
489
|
+
|
490
|
+
class SimpleNode(BaseNode):
|
491
|
+
message = SimpleWorkflowInputs.message
|
492
|
+
|
493
|
+
class Outputs(BaseOutputs):
|
494
|
+
result: str
|
495
|
+
|
496
|
+
def run(self) -> Outputs:
|
497
|
+
return self.Outputs(result=f"Processed: {self.message}")
|
498
|
+
|
499
|
+
class SimpleInlineWorkflow(BaseWorkflow[SimpleWorkflowInputs, BaseState]):
|
500
|
+
"""A simple workflow for testing inline tool serialization."""
|
501
|
+
|
502
|
+
graph = SimpleNode
|
503
|
+
|
504
|
+
class Outputs(BaseOutputs):
|
505
|
+
result = SimpleNode.Outputs.result
|
506
|
+
|
507
|
+
# WHEN we create a tool prompt node using create_tool_prompt_node with inline workflow
|
508
|
+
tool_prompt_node = create_tool_prompt_node(
|
509
|
+
ml_model="gpt-4o-mini",
|
510
|
+
blocks=[],
|
511
|
+
functions=[SimpleInlineWorkflow],
|
512
|
+
prompt_inputs=None,
|
513
|
+
parameters=PromptParameters(),
|
514
|
+
)
|
515
|
+
|
516
|
+
tool_prompt_node_display_class = get_node_display_class(tool_prompt_node)
|
517
|
+
tool_prompt_node_display = tool_prompt_node_display_class()
|
518
|
+
|
519
|
+
# AND we create a workflow that uses this tool prompt node
|
520
|
+
class TestWorkflow(BaseWorkflow[BaseInputs, ToolCallingState]):
|
521
|
+
graph = tool_prompt_node
|
522
|
+
|
523
|
+
# WHEN we serialize the entire workflow
|
524
|
+
workflow_display = get_workflow_display(workflow_class=TestWorkflow)
|
525
|
+
display_context = workflow_display.display_context
|
526
|
+
serialized_tool_prompt_node = tool_prompt_node_display.serialize(display_context)
|
527
|
+
|
528
|
+
# THEN prompt inputs should be serialized correctly
|
529
|
+
attributes = serialized_tool_prompt_node["attributes"]
|
530
|
+
assert isinstance(attributes, list)
|
531
|
+
prompt_inputs_attr = next(
|
532
|
+
(attr for attr in attributes if isinstance(attr, dict) and attr["name"] == "prompt_inputs"), None
|
533
|
+
)
|
534
|
+
assert prompt_inputs_attr == {
|
535
|
+
"id": "bc1320a2-23e4-4238-8b00-efbf88e91856",
|
536
|
+
"name": "prompt_inputs",
|
537
|
+
"value": {
|
538
|
+
"type": "DICTIONARY_REFERENCE",
|
539
|
+
"entries": [
|
540
|
+
{
|
541
|
+
"id": "76ceec7b-ec37-474f-ba38-2bfd27cecc5d",
|
542
|
+
"key": "chat_history",
|
543
|
+
"value": {
|
544
|
+
"type": "BINARY_EXPRESSION",
|
545
|
+
"lhs": {"type": "CONSTANT_VALUE", "value": {"type": "JSON", "value": []}},
|
546
|
+
"operator": "concat",
|
547
|
+
"rhs": {
|
548
|
+
"type": "WORKFLOW_STATE",
|
549
|
+
"state_variable_id": "7a1caaf5-99df-487a-8b2d-6512df2d871a",
|
550
|
+
},
|
551
|
+
},
|
552
|
+
}
|
553
|
+
],
|
554
|
+
},
|
555
|
+
}
|
556
|
+
|
557
|
+
|
558
|
+
def test_serialize_tool_prompt_node_with_workflow_deployment(vellum_client):
|
559
|
+
"""
|
560
|
+
Test that the tool prompt node serializes successfully with a workflow deployment.
|
561
|
+
"""
|
562
|
+
vellum_client.workflow_deployments.retrieve_workflow_deployment_release.return_value = WorkflowDeploymentRelease(
|
563
|
+
id="test-id",
|
564
|
+
created=datetime.now(),
|
565
|
+
environment=ReleaseEnvironment(
|
566
|
+
id="test-id",
|
567
|
+
name="test-name",
|
568
|
+
label="test-label",
|
569
|
+
),
|
570
|
+
created_by=None,
|
571
|
+
workflow_version=WorkflowDeploymentReleaseWorkflowVersion(
|
572
|
+
id="test-id",
|
573
|
+
input_variables=[],
|
574
|
+
output_variables=[],
|
575
|
+
),
|
576
|
+
deployment=WorkflowDeploymentReleaseWorkflowDeployment(name="test-name"),
|
577
|
+
description="test-description",
|
578
|
+
release_tags=[
|
579
|
+
ReleaseReleaseTag(
|
580
|
+
name="test-name",
|
581
|
+
source="USER",
|
582
|
+
)
|
583
|
+
],
|
584
|
+
reviews=[
|
585
|
+
SlimReleaseReview(
|
586
|
+
id="test-id",
|
587
|
+
created=datetime.now(),
|
588
|
+
reviewer=ReleaseReviewReviewer(
|
589
|
+
id="test-id",
|
590
|
+
full_name="test-name",
|
591
|
+
),
|
592
|
+
state="APPROVED",
|
593
|
+
)
|
594
|
+
],
|
595
|
+
)
|
596
|
+
|
597
|
+
# GIVEN a workflow deployment
|
598
|
+
workflow_deployment = DeploymentDefinition(
|
599
|
+
deployment="test-deployment",
|
600
|
+
release_tag="test-release-tag",
|
601
|
+
)
|
602
|
+
|
603
|
+
# WHEN we create a tool prompt node using create_tool_prompt_node with a workflow deployment
|
604
|
+
tool_prompt_node = create_tool_prompt_node(
|
605
|
+
ml_model="gpt-4o-mini",
|
606
|
+
blocks=[],
|
607
|
+
functions=[workflow_deployment],
|
608
|
+
prompt_inputs=None,
|
609
|
+
parameters=PromptParameters(),
|
610
|
+
)
|
611
|
+
|
612
|
+
tool_prompt_node_display_class = get_node_display_class(tool_prompt_node)
|
613
|
+
tool_prompt_node_display = tool_prompt_node_display_class()
|
614
|
+
|
615
|
+
# AND we create a workflow that uses this tool prompt node
|
616
|
+
class TestWorkflow(BaseWorkflow[BaseInputs, ToolCallingState]):
|
617
|
+
graph = tool_prompt_node
|
618
|
+
|
619
|
+
# WHEN we serialize the entire workflow
|
620
|
+
workflow_display = get_workflow_display(workflow_class=TestWorkflow)
|
621
|
+
display_context = workflow_display.display_context
|
622
|
+
serialized_tool_prompt_node = tool_prompt_node_display.serialize(display_context)
|
623
|
+
|
624
|
+
# THEN functions attribute should be serialized correctly
|
625
|
+
attributes = serialized_tool_prompt_node["attributes"]
|
626
|
+
assert isinstance(attributes, list)
|
627
|
+
functions_attr = next((attr for attr in attributes if isinstance(attr, dict) and attr["name"] == "functions"), None)
|
628
|
+
assert functions_attr == {
|
629
|
+
"id": "6326ccc4-7cf6-4235-ba3c-a6e860b0c48b",
|
630
|
+
"name": "functions",
|
631
|
+
"value": {
|
632
|
+
"type": "CONSTANT_VALUE",
|
633
|
+
"value": {
|
634
|
+
"type": "JSON",
|
635
|
+
"value": [
|
636
|
+
{
|
637
|
+
"type": "WORKFLOW_DEPLOYMENT",
|
638
|
+
"name": "test-name",
|
639
|
+
"description": "test-description",
|
640
|
+
"deployment": "test-deployment",
|
641
|
+
"release_tag": "test-release-tag",
|
642
|
+
}
|
643
|
+
],
|
644
|
+
},
|
645
|
+
},
|
646
|
+
}
|
@@ -2,7 +2,8 @@ from uuid import UUID
|
|
2
2
|
from typing import Dict
|
3
3
|
|
4
4
|
from vellum.workflows.inputs import BaseInputs
|
5
|
-
from vellum.workflows.nodes import BaseNode
|
5
|
+
from vellum.workflows.nodes import BaseNode, InlineSubworkflowNode
|
6
|
+
from vellum.workflows.outputs.base import BaseOutputs
|
6
7
|
from vellum.workflows.ports.port import Port
|
7
8
|
from vellum.workflows.references.lazy import LazyReference
|
8
9
|
from vellum.workflows.state import BaseState
|
@@ -327,3 +328,54 @@ def test_serialize__port_with_lazy_reference():
|
|
327
328
|
},
|
328
329
|
}
|
329
330
|
]
|
331
|
+
|
332
|
+
|
333
|
+
def test_global_propagation_deep_nested_subworkflows():
|
334
|
+
# GIVEN the root workflow, a middle workflow, and an inner workflow
|
335
|
+
|
336
|
+
class RootInputs(BaseInputs):
|
337
|
+
root_param: str
|
338
|
+
|
339
|
+
class MiddleInputs(BaseInputs):
|
340
|
+
middle_param: str
|
341
|
+
|
342
|
+
class InnerInputs(BaseInputs):
|
343
|
+
inner_param: str
|
344
|
+
|
345
|
+
class InnerNode(BaseNode):
|
346
|
+
class Outputs(BaseOutputs):
|
347
|
+
done: bool
|
348
|
+
|
349
|
+
def run(self) -> Outputs:
|
350
|
+
return self.Outputs(done=True)
|
351
|
+
|
352
|
+
class InnerWorkflow(BaseWorkflow[InnerInputs, BaseState]):
|
353
|
+
graph = InnerNode
|
354
|
+
|
355
|
+
class MiddleInlineSubworkflowNode(InlineSubworkflowNode):
|
356
|
+
subworkflow_inputs = {"inner_param": "x"}
|
357
|
+
subworkflow = InnerWorkflow
|
358
|
+
|
359
|
+
class MiddleWorkflow(BaseWorkflow[MiddleInputs, BaseState]):
|
360
|
+
graph = MiddleInlineSubworkflowNode
|
361
|
+
|
362
|
+
class OuterInlineSubworkflowNode(InlineSubworkflowNode):
|
363
|
+
subworkflow_inputs = {"middle_param": "y"}
|
364
|
+
subworkflow = MiddleWorkflow
|
365
|
+
|
366
|
+
class RootWorkflow(BaseWorkflow[RootInputs, BaseState]):
|
367
|
+
graph = OuterInlineSubworkflowNode
|
368
|
+
|
369
|
+
# WHEN we build the displays
|
370
|
+
root_display = get_workflow_display(workflow_class=RootWorkflow)
|
371
|
+
middle_display = get_workflow_display(
|
372
|
+
workflow_class=MiddleWorkflow, parent_display_context=root_display.display_context
|
373
|
+
)
|
374
|
+
inner_display = get_workflow_display(
|
375
|
+
workflow_class=InnerWorkflow, parent_display_context=middle_display.display_context
|
376
|
+
)
|
377
|
+
|
378
|
+
# THEN the deepest display must include root + middle + inner inputs in its GLOBAL view
|
379
|
+
inner_global_names = {ref.name for ref in inner_display.display_context.global_workflow_input_displays.keys()}
|
380
|
+
|
381
|
+
assert inner_global_names == {"middle_param", "inner_param", "root_param"}
|
@@ -47,7 +47,7 @@ def test_serialize_node__retry(serialize_node):
|
|
47
47
|
assert not DeepDiff(
|
48
48
|
{
|
49
49
|
"id": "188b50aa-e518-4b7b-a5e0-e2585fb1d7b5",
|
50
|
-
"label": "
|
50
|
+
"label": "Inner Retry Generic Node",
|
51
51
|
"type": "GENERIC",
|
52
52
|
"display_data": {"position": {"x": 0.0, "y": 0.0}},
|
53
53
|
"base": {"name": "BaseNode", "module": ["vellum", "workflows", "nodes", "bases", "base"]},
|
@@ -68,7 +68,7 @@ def test_serialize_node__retry(serialize_node):
|
|
68
68
|
"adornments": [
|
69
69
|
{
|
70
70
|
"id": "5be7d260-74f7-4734-b31b-a46a94539586",
|
71
|
-
"label": "
|
71
|
+
"label": "Retry Node",
|
72
72
|
"base": {
|
73
73
|
"name": "RetryNode",
|
74
74
|
"module": ["vellum", "workflows", "nodes", "core", "retry_node", "node"],
|
@@ -154,7 +154,7 @@ def test_serialize_node__try(serialize_node):
|
|
154
154
|
assert not DeepDiff(
|
155
155
|
{
|
156
156
|
"id": str(InnerTryGenericNode.__wrapped_node__.__id__),
|
157
|
-
"label": "
|
157
|
+
"label": "Inner Try Generic Node",
|
158
158
|
"type": "GENERIC",
|
159
159
|
"display_data": {"position": {"x": 0.0, "y": 0.0}},
|
160
160
|
"base": {"name": "BaseNode", "module": ["vellum", "workflows", "nodes", "bases", "base"]},
|
@@ -175,7 +175,7 @@ def test_serialize_node__try(serialize_node):
|
|
175
175
|
"adornments": [
|
176
176
|
{
|
177
177
|
"id": "3344083c-a32c-4a32-920b-0fb5093448fa",
|
178
|
-
"label": "
|
178
|
+
"label": "Try Node",
|
179
179
|
"base": {
|
180
180
|
"name": "TryNode",
|
181
181
|
"module": ["vellum", "workflows", "nodes", "core", "try_node", "node"],
|
@@ -248,7 +248,7 @@ def test_serialize_node__stacked():
|
|
248
248
|
assert not DeepDiff(
|
249
249
|
{
|
250
250
|
"id": "074833b0-e142-4bbc-8dec-209a35e178a3",
|
251
|
-
"label": "
|
251
|
+
"label": "Inner Stacked Generic Node",
|
252
252
|
"type": "GENERIC",
|
253
253
|
"display_data": {"position": {"x": 200.0, "y": -50.0}},
|
254
254
|
"base": {"name": "BaseNode", "module": ["vellum", "workflows", "nodes", "bases", "base"]},
|
@@ -272,7 +272,7 @@ def test_serialize_node__stacked():
|
|
272
272
|
"adornments": [
|
273
273
|
{
|
274
274
|
"id": "3344083c-a32c-4a32-920b-0fb5093448fa",
|
275
|
-
"label": "
|
275
|
+
"label": "Try Node",
|
276
276
|
"base": {
|
277
277
|
"name": "TryNode",
|
278
278
|
"module": ["vellum", "workflows", "nodes", "core", "try_node", "node"],
|
@@ -287,7 +287,7 @@ def test_serialize_node__stacked():
|
|
287
287
|
},
|
288
288
|
{
|
289
289
|
"id": "5be7d260-74f7-4734-b31b-a46a94539586",
|
290
|
-
"label": "
|
290
|
+
"label": "Retry Node",
|
291
291
|
"base": {
|
292
292
|
"name": "RetryNode",
|
293
293
|
"module": ["vellum", "workflows", "nodes", "core", "retry_node", "node"],
|
@@ -351,5 +351,5 @@ def test_serialize_node__adornment_order_matches_decorator_order():
|
|
351
351
|
|
352
352
|
adornments = cast(List[Dict[str, Any]], my_node["adornments"])
|
353
353
|
assert len(adornments) == 2
|
354
|
-
assert adornments[0]["label"] == "
|
355
|
-
assert adornments[1]["label"] == "
|
354
|
+
assert adornments[0]["label"] == "Try Node"
|
355
|
+
assert adornments[1]["label"] == "Retry Node"
|
@@ -34,7 +34,7 @@ def test_serialize_node__constant_value(serialize_node):
|
|
34
34
|
assert not DeepDiff(
|
35
35
|
{
|
36
36
|
"id": "67e07859-7f67-4287-9854-06ab4199e576",
|
37
|
-
"label": "
|
37
|
+
"label": "Constant Value Generic Node",
|
38
38
|
"type": "GENERIC",
|
39
39
|
"display_data": {"position": {"x": 0.0, "y": 0.0}},
|
40
40
|
"base": {"name": "BaseNode", "module": ["vellum", "workflows", "nodes", "bases", "base"]},
|
@@ -104,7 +104,7 @@ def test_serialize_node__constant_value_reference(serialize_node):
|
|
104
104
|
assert not DeepDiff(
|
105
105
|
{
|
106
106
|
"id": "73643f17-e49e-47d2-bd01-bb9c3eab6ae9",
|
107
|
-
"label": "
|
107
|
+
"label": "Constant Value Reference Generic Node",
|
108
108
|
"type": "GENERIC",
|
109
109
|
"display_data": {"position": {"x": 0.0, "y": 0.0}},
|
110
110
|
"base": {"name": "BaseNode", "module": ["vellum", "workflows", "nodes", "bases", "base"]},
|
@@ -146,7 +146,7 @@ def test_serialize_node__lazy_reference(serialize_node):
|
|
146
146
|
assert not DeepDiff(
|
147
147
|
{
|
148
148
|
"id": "3d6bfe3b-263a-40a6-8a05-98288e9559a4",
|
149
|
-
"label": "
|
149
|
+
"label": "Lazy Reference Generic Node",
|
150
150
|
"type": "GENERIC",
|
151
151
|
"display_data": {"position": {"x": 0.0, "y": 0.0}},
|
152
152
|
"base": {"name": "BaseNode", "module": ["vellum", "workflows", "nodes", "bases", "base"]},
|
@@ -229,7 +229,7 @@ def test_serialize_node__workflow_input(serialize_node):
|
|
229
229
|
assert not DeepDiff(
|
230
230
|
{
|
231
231
|
"id": "30116483-6f38-40e0-baf2-32de0e14e9a3",
|
232
|
-
"label": "
|
232
|
+
"label": "Workflow Input Generic Node",
|
233
233
|
"type": "GENERIC",
|
234
234
|
"display_data": {"position": {"x": 0.0, "y": 0.0}},
|
235
235
|
"base": {"name": "BaseNode", "module": ["vellum", "workflows", "nodes", "bases", "base"]},
|
@@ -292,7 +292,7 @@ def test_serialize_node__workflow_input_as_nested_chat_history():
|
|
292
292
|
assert not DeepDiff(
|
293
293
|
{
|
294
294
|
"id": "11be9d37-0069-4695-a317-14a3b6519d4e",
|
295
|
-
"label": "
|
295
|
+
"label": "Generic Node",
|
296
296
|
"type": "GENERIC",
|
297
297
|
"display_data": {"position": {"x": 200.0, "y": -50.0}},
|
298
298
|
"base": {"name": "BaseNode", "module": ["vellum", "workflows", "nodes", "bases", "base"]},
|
@@ -362,7 +362,7 @@ def test_serialize_node__node_output(serialize_node):
|
|
362
362
|
assert not DeepDiff(
|
363
363
|
{
|
364
364
|
"id": "7210742f-8c3e-4379-9800-8b4b7f5dd7ed",
|
365
|
-
"label": "
|
365
|
+
"label": "Generic Node Referencing Output",
|
366
366
|
"type": "GENERIC",
|
367
367
|
"display_data": {"position": {"x": 0.0, "y": 0.0}},
|
368
368
|
"base": {"name": "BaseNode", "module": ["vellum", "workflows", "nodes", "bases", "base"]},
|
@@ -412,7 +412,7 @@ def test_serialize_node__vellum_secret(serialize_node):
|
|
412
412
|
assert not DeepDiff(
|
413
413
|
{
|
414
414
|
"id": "0e75bd8f-882e-4ab7-8348-061319b574f7",
|
415
|
-
"label": "
|
415
|
+
"label": "Vellum Secret Generic Node",
|
416
416
|
"type": "GENERIC",
|
417
417
|
"display_data": {"position": {"x": 0.0, "y": 0.0}},
|
418
418
|
"base": {"name": "BaseNode", "module": ["vellum", "workflows", "nodes", "bases", "base"]},
|
@@ -465,7 +465,7 @@ def test_serialize_node__node_execution(serialize_node):
|
|
465
465
|
assert not DeepDiff(
|
466
466
|
{
|
467
467
|
"id": "f42dda6b-e856-49bd-b203-46c9dd66c08b",
|
468
|
-
"label": "
|
468
|
+
"label": "Generic Node Referencing Executions",
|
469
469
|
"type": "GENERIC",
|
470
470
|
"display_data": {"position": {"x": 0.0, "y": 0.0}},
|
471
471
|
"base": {"name": "BaseNode", "module": ["vellum", "workflows", "nodes", "bases", "base"]},
|
@@ -561,7 +561,7 @@ def test_serialize_node__coalesce(serialize_node):
|
|
561
561
|
assert not DeepDiff(
|
562
562
|
{
|
563
563
|
"id": "bb99f326-7d2a-4b5e-95f3-6039114798da",
|
564
|
-
"label": "
|
564
|
+
"label": "Coalesce Node Final",
|
565
565
|
"type": "GENERIC",
|
566
566
|
"display_data": {"position": {"x": 0.0, "y": 0.0}},
|
567
567
|
"base": {"name": "BaseNode", "module": ["vellum", "workflows", "nodes", "bases", "base"]},
|
vellum_ee/workflows/display/tests/workflow_serialization/generic_nodes/test_outputs_serialization.py
CHANGED
@@ -23,7 +23,7 @@ def test_serialize_node__annotated_output(serialize_node):
|
|
23
23
|
assert not DeepDiff(
|
24
24
|
{
|
25
25
|
"id": "e33ddf79-f48c-4057-ba17-d41a3a60ac98",
|
26
|
-
"label": "
|
26
|
+
"label": "Annotated Output Generic Node",
|
27
27
|
"type": "GENERIC",
|
28
28
|
"display_data": {"position": {"x": 0.0, "y": 0.0}},
|
29
29
|
"base": {"name": "BaseNode", "module": ["vellum", "workflows", "nodes", "bases", "base"]},
|
@@ -71,7 +71,7 @@ def test_serialize_node__workflow_input(serialize_node):
|
|
71
71
|
assert not DeepDiff(
|
72
72
|
{
|
73
73
|
"id": "30116483-6f38-40e0-baf2-32de0e14e9a3",
|
74
|
-
"label": "
|
74
|
+
"label": "Workflow Input Generic Node",
|
75
75
|
"type": "GENERIC",
|
76
76
|
"display_data": {"position": {"x": 0.0, "y": 0.0}},
|
77
77
|
"base": {"name": "BaseNode", "module": ["vellum", "workflows", "nodes", "bases", "base"]},
|
@@ -134,7 +134,7 @@ def test_serialize_node__node_output_reference(serialize_node):
|
|
134
134
|
assert not DeepDiff(
|
135
135
|
{
|
136
136
|
"id": "ac067acc-6a6f-44b1-ae84-428e965ce691",
|
137
|
-
"label": "
|
137
|
+
"label": "Generic Node Referencing Output",
|
138
138
|
"type": "GENERIC",
|
139
139
|
"display_data": {"position": {"x": 0.0, "y": 0.0}},
|
140
140
|
"base": {"name": "BaseNode", "module": ["vellum", "workflows", "nodes", "bases", "base"]},
|