vellum-ai 0.14.8__py3-none-any.whl → 0.14.10__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.
Files changed (35) hide show
  1. vellum/client/core/client_wrapper.py +1 -1
  2. vellum/utils/templating/render.py +4 -1
  3. vellum/workflows/descriptors/base.py +6 -0
  4. vellum/workflows/descriptors/tests/test_utils.py +14 -0
  5. vellum/workflows/events/tests/test_event.py +40 -0
  6. vellum/workflows/events/workflow.py +21 -1
  7. vellum/workflows/expressions/greater_than.py +15 -8
  8. vellum/workflows/expressions/greater_than_or_equal_to.py +14 -8
  9. vellum/workflows/expressions/less_than.py +14 -8
  10. vellum/workflows/expressions/less_than_or_equal_to.py +14 -8
  11. vellum/workflows/expressions/parse_json.py +30 -0
  12. vellum/workflows/expressions/tests/__init__.py +0 -0
  13. vellum/workflows/expressions/tests/test_expressions.py +310 -0
  14. vellum/workflows/expressions/tests/test_parse_json.py +31 -0
  15. vellum/workflows/nodes/bases/base.py +5 -2
  16. vellum/workflows/nodes/core/templating_node/node.py +0 -1
  17. vellum/workflows/nodes/core/templating_node/tests/test_templating_node.py +49 -0
  18. vellum/workflows/nodes/displayable/api_node/tests/test_api_node.py +6 -7
  19. vellum/workflows/nodes/displayable/code_execution_node/node.py +18 -8
  20. vellum/workflows/nodes/displayable/code_execution_node/tests/test_code_execution_node.py +53 -0
  21. vellum/workflows/nodes/utils.py +14 -3
  22. vellum/workflows/runner/runner.py +34 -9
  23. vellum/workflows/state/encoder.py +2 -1
  24. {vellum_ai-0.14.8.dist-info → vellum_ai-0.14.10.dist-info}/METADATA +1 -1
  25. {vellum_ai-0.14.8.dist-info → vellum_ai-0.14.10.dist-info}/RECORD +35 -31
  26. vellum_ee/workflows/display/nodes/base_node_display.py +4 -0
  27. vellum_ee/workflows/display/tests/test_vellum_workflow_display.py +31 -0
  28. vellum_ee/workflows/display/types.py +1 -14
  29. vellum_ee/workflows/display/workflows/base_workflow_display.py +38 -18
  30. vellum_ee/workflows/display/workflows/tests/test_workflow_display.py +27 -0
  31. vellum_ee/workflows/tests/test_display_meta.py +2 -0
  32. vellum_ee/workflows/tests/test_server.py +1 -0
  33. {vellum_ai-0.14.8.dist-info → vellum_ai-0.14.10.dist-info}/LICENSE +0 -0
  34. {vellum_ai-0.14.8.dist-info → vellum_ai-0.14.10.dist-info}/WHEEL +0 -0
  35. {vellum_ai-0.14.8.dist-info → vellum_ai-0.14.10.dist-info}/entry_points.txt +0 -0
@@ -1,5 +1,6 @@
1
1
  from collections import defaultdict
2
2
  from copy import deepcopy
3
+ from dataclasses import dataclass
3
4
  import logging
4
5
  from queue import Empty, Queue
5
6
  from threading import Event as ThreadingEvent, Thread
@@ -63,6 +64,12 @@ ExternalInputsArg = Dict[ExternalInputReference, Any]
63
64
  BackgroundThreadItem = Union[BaseState, WorkflowEvent, None]
64
65
 
65
66
 
67
+ @dataclass
68
+ class ActiveNode(Generic[StateType]):
69
+ node: BaseNode[StateType]
70
+ was_outputs_streamed: bool = False
71
+
72
+
66
73
  class WorkflowRunner(Generic[StateType]):
67
74
  _entrypoints: Iterable[Type[BaseNode]]
68
75
 
@@ -136,7 +143,7 @@ class WorkflowRunner(Generic[StateType]):
136
143
  self._dependencies: Dict[Type[BaseNode], Set[Type[BaseNode]]] = defaultdict(set)
137
144
  self._state_forks: Set[StateType] = {self._initial_state}
138
145
 
139
- self._active_nodes_by_execution_id: Dict[UUID, BaseNode[StateType]] = {}
146
+ self._active_nodes_by_execution_id: Dict[UUID, ActiveNode[StateType]] = {}
140
147
  self._cancel_signal = cancel_signal
141
148
  self._execution_context = init_execution_context or get_execution_context()
142
149
  self._parent_context = self._execution_context.parent_context
@@ -321,11 +328,7 @@ class WorkflowRunner(Generic[StateType]):
321
328
  node_definition=node.__class__,
322
329
  error=e.error,
323
330
  ),
324
- parent=WorkflowParentContext(
325
- span_id=span_id,
326
- workflow_definition=self.workflow.__class__,
327
- parent=self._parent_context,
328
- ),
331
+ parent=parent_context,
329
332
  )
330
333
  )
331
334
  except Exception as e:
@@ -404,7 +407,7 @@ class WorkflowRunner(Generic[StateType]):
404
407
  current_parent = get_parent_context()
405
408
  node = node_class(state=state, context=self.workflow.context)
406
409
  state.meta.node_execution_cache.initiate_node_execution(node_class, node_span_id)
407
- self._active_nodes_by_execution_id[node_span_id] = node
410
+ self._active_nodes_by_execution_id[node_span_id] = ActiveNode(node=node)
408
411
 
409
412
  worker_thread = Thread(
410
413
  target=self._context_run_work_item,
@@ -413,10 +416,11 @@ class WorkflowRunner(Generic[StateType]):
413
416
  worker_thread.start()
414
417
 
415
418
  def _handle_work_item_event(self, event: WorkflowEvent) -> Optional[WorkflowError]:
416
- node = self._active_nodes_by_execution_id.get(event.span_id)
417
- if not node:
419
+ active_node = self._active_nodes_by_execution_id.get(event.span_id)
420
+ if not active_node:
418
421
  return None
419
422
 
423
+ node = active_node.node
420
424
  if event.name == "node.execution.rejected":
421
425
  self._active_nodes_by_execution_id.pop(event.span_id)
422
426
  return event.error
@@ -431,6 +435,7 @@ class WorkflowRunner(Generic[StateType]):
431
435
  if node_output_descriptor.name != event.output.name:
432
436
  continue
433
437
 
438
+ active_node.was_outputs_streamed = True
434
439
  self._workflow_event_outer_queue.put(
435
440
  self._stream_workflow_event(
436
441
  BaseOutput(
@@ -447,6 +452,26 @@ class WorkflowRunner(Generic[StateType]):
447
452
 
448
453
  if event.name == "node.execution.fulfilled":
449
454
  self._active_nodes_by_execution_id.pop(event.span_id)
455
+ if not active_node.was_outputs_streamed:
456
+ for event_node_output_descriptor, node_output_value in event.outputs:
457
+ for workflow_output_descriptor in self.workflow.Outputs:
458
+ node_output_descriptor = workflow_output_descriptor.instance
459
+ if not isinstance(node_output_descriptor, OutputReference):
460
+ continue
461
+ if node_output_descriptor.outputs_class != event.node_definition.Outputs:
462
+ continue
463
+ if node_output_descriptor.name != event_node_output_descriptor.name:
464
+ continue
465
+
466
+ self._workflow_event_outer_queue.put(
467
+ self._stream_workflow_event(
468
+ BaseOutput(
469
+ name=workflow_output_descriptor.name,
470
+ value=node_output_value,
471
+ )
472
+ )
473
+ )
474
+
450
475
  self._handle_invoked_ports(node.state, event.invoked_ports)
451
476
 
452
477
  return None
@@ -8,6 +8,7 @@ from typing import Any, Callable, Dict, Type
8
8
 
9
9
  from pydantic import BaseModel
10
10
 
11
+ from vellum.workflows.constants import undefined
11
12
  from vellum.workflows.inputs.base import BaseInputs
12
13
  from vellum.workflows.outputs.base import BaseOutput, BaseOutputs
13
14
  from vellum.workflows.ports.port import Port
@@ -22,7 +23,7 @@ class DefaultStateEncoder(JSONEncoder):
22
23
  return dict(obj)
23
24
 
24
25
  if isinstance(obj, (BaseInputs, BaseOutputs)):
25
- return {descriptor.name: value for descriptor, value in obj}
26
+ return {descriptor.name: value for descriptor, value in obj if value is not undefined}
26
27
 
27
28
  if isinstance(obj, (BaseOutput, Port)):
28
29
  return obj.serialize()
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: vellum-ai
3
- Version: 0.14.8
3
+ Version: 0.14.10
4
4
  Summary:
5
5
  License: MIT
6
6
  Requires-Python: >=3.9,<4.0
@@ -23,7 +23,7 @@ vellum_ee/workflows/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSu
23
23
  vellum_ee/workflows/display/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
24
24
  vellum_ee/workflows/display/base.py,sha256=ak29FIsawhaFa9_paZUHThlZRFJ1xB486JWKuSt1PYY,1965
25
25
  vellum_ee/workflows/display/nodes/__init__.py,sha256=436iSAh_Ex5tC68oEYvNgPu05ZVIAVXnS4PKGrQeZ0Y,321
26
- vellum_ee/workflows/display/nodes/base_node_display.py,sha256=H0sOYd8H7bz9ggSPEs5fwqyp27NAIu4YPNuNB9g0dQA,16289
26
+ vellum_ee/workflows/display/nodes/base_node_display.py,sha256=h4_JqwH_AsT92OK14S3kqssZDjL-uyXnJfo0XcLijK0,16492
27
27
  vellum_ee/workflows/display/nodes/base_node_vellum_display.py,sha256=pLO0dORfRu--Ne9NgoyFT_CNjfpr5fGCsgbsMkUF5GM,2845
28
28
  vellum_ee/workflows/display/nodes/get_node_display_class.py,sha256=0S6ksPp53WXWh1RQVH71nj2bkCWBj4ZaFYhTxW3N2F4,1230
29
29
  vellum_ee/workflows/display/nodes/tests/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
@@ -56,7 +56,7 @@ vellum_ee/workflows/display/nodes/vellum/tests/test_utils.py,sha256=4YUaTeD_OWF-
56
56
  vellum_ee/workflows/display/nodes/vellum/try_node.py,sha256=HBfGz4yt9GlmMW9JxzaCacPnHBDNIeXE8Jhqr9DqLLw,6191
57
57
  vellum_ee/workflows/display/nodes/vellum/utils.py,sha256=F_0BrlSszllK_BhryPbojIleLq2dGXOfQD1rVp3fNFg,4733
58
58
  vellum_ee/workflows/display/tests/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
59
- vellum_ee/workflows/display/tests/test_vellum_workflow_display.py,sha256=yfTwpPgOzxJBrUz4cb-T8QQf8lF3TYm-Of40usUNOnc,7494
59
+ vellum_ee/workflows/display/tests/test_vellum_workflow_display.py,sha256=cdpUoDNli8ULlNTrU6rnT4TZAIR8mzsG9ZbLrikPybU,8518
60
60
  vellum_ee/workflows/display/tests/workflow_serialization/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
61
61
  vellum_ee/workflows/display/tests/workflow_serialization/generic_nodes/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
62
62
  vellum_ee/workflows/display/tests/workflow_serialization/generic_nodes/conftest.py,sha256=A1-tIpC5KIKG9JA_rkd1nLS8zUG3Kb4QiVdvb3boFxE,2509
@@ -83,15 +83,15 @@ vellum_ee/workflows/display/tests/workflow_serialization/test_basic_templating_n
83
83
  vellum_ee/workflows/display/tests/workflow_serialization/test_basic_terminal_node_serialization.py,sha256=NdhE3lm7RMQ8DqkraPSq24IbOxNla9unbs4tsMWRzm4,3781
84
84
  vellum_ee/workflows/display/tests/workflow_serialization/test_basic_try_node_serialization.py,sha256=eD5686C9nWC5s6t08vbAnm9qf9t53gYQM-E1FwAa75c,3035
85
85
  vellum_ee/workflows/display/tests/workflow_serialization/test_complex_terminal_node_serialization.py,sha256=huKAOeMJ2MKmp6XtbvMJTUadqynoV40Ypoz9jsBEBEQ,7431
86
- vellum_ee/workflows/display/types.py,sha256=xDC1zy4rWKNqDtSr-h6MQfWnJ6scZ_Sadxp4t8Q3PY4,2897
86
+ vellum_ee/workflows/display/types.py,sha256=ixfmcQn51Rhsm4_0hWfG0_WpzLE89ZrDZpeYBklsP1Q,2592
87
87
  vellum_ee/workflows/display/utils/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
88
88
  vellum_ee/workflows/display/utils/expressions.py,sha256=9FpOslDI-RCR5m4TgAu9KCHh4aTVnh7CHR2ykyMUDw0,1151
89
89
  vellum_ee/workflows/display/utils/vellum.py,sha256=UjK_RxnSEmlIu9klGCPWU5RAQBmgZ7cRbRdgxaTbubE,8081
90
90
  vellum_ee/workflows/display/vellum.py,sha256=7mqQaKZPPrLMcXSAQkPIxCy5x8HkKs5PbCu3GRaC2o8,8507
91
91
  vellum_ee/workflows/display/workflows/__init__.py,sha256=kapXsC67VJcgSuiBMa86FdePG5A9kMB5Pi4Uy1O2ob4,207
92
- vellum_ee/workflows/display/workflows/base_workflow_display.py,sha256=hTX1PQGSpuEiuAjlonyxE9V48UzTy4ReczX-dn8oPeY,18655
92
+ vellum_ee/workflows/display/workflows/base_workflow_display.py,sha256=Z9s_rtqAH5IfBtXOw40gbiT0GZeN6JRdFwGgPT-DIYM,20143
93
93
  vellum_ee/workflows/display/workflows/get_vellum_workflow_display_class.py,sha256=kp0u8LN_2IwshLrhMImhpZx1hRyAcD5gXY-kDuuaGMQ,1269
94
- vellum_ee/workflows/display/workflows/tests/test_workflow_display.py,sha256=_yB3-u7_bWdD4lUBWpRdWztJmJL-DXkkZaw9Vy9HH6g,3245
94
+ vellum_ee/workflows/display/workflows/tests/test_workflow_display.py,sha256=STVSG0eL97mdnwBA5nOOgW8AuK8k-b8kWDyHKatNXIA,4259
95
95
  vellum_ee/workflows/display/workflows/vellum_workflow_display.py,sha256=mbAzCpswOek34ITeTkesbVreCXpulj4NFjIg3RcdVZ8,18243
96
96
  vellum_ee/workflows/server/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
97
97
  vellum_ee/workflows/server/virtual_file_loader.py,sha256=X_DdNK7MfyOjKWekk6YQpOSCT6klKcdjT6nVJcBH1sM,1481
@@ -114,15 +114,15 @@ vellum_ee/workflows/tests/local_workflow/nodes/__init__.py,sha256=1F6jxUpSKfPXPj
114
114
  vellum_ee/workflows/tests/local_workflow/nodes/final_output.py,sha256=ZX7zBv87zirg0w9VKUW3QVDSdBLDqcqAMZjCL_oWbpU,297
115
115
  vellum_ee/workflows/tests/local_workflow/nodes/templating_node.py,sha256=NQwFN61QkHfI3Vssz-B0NKGfupK8PU0FDSAIAhYBLi0,325
116
116
  vellum_ee/workflows/tests/local_workflow/workflow.py,sha256=A4qOzOPNwePYxWbcAgIPLsmrVS_aVEZEc-wULSv787Q,393
117
- vellum_ee/workflows/tests/test_display_meta.py,sha256=pzdqND4KLWs7EUIbpXuqgso7BIRpoUsO3T_bgeENs0Q,2205
118
- vellum_ee/workflows/tests/test_server.py,sha256=SvKUrUPmOf3sIInXcFjETekql60npb4cAn1GPbF0bPs,391
117
+ vellum_ee/workflows/tests/test_display_meta.py,sha256=xLQ7QtIXIiIm61pm2lyl588Ohzc3pjyq1nDp-qVu2Fs,2295
118
+ vellum_ee/workflows/tests/test_server.py,sha256=M6vvQ2hjIpDWtQdDM9EPbMvUrZ93niAuYnxMNJWOjPA,511
119
119
  vellum_ee/workflows/tests/test_virtual_files.py,sha256=TJEcMR0v2S8CkloXNmCHA0QW0K6pYNGaIjraJz7sFvY,2762
120
120
  vellum/__init__.py,sha256=a_aM1_A04XGma4MAIDNeBF9BKzWbiQaVVMRzImHuxjA,36438
121
121
  vellum/client/README.md,sha256=JkCJjmMZl4jrPj46pkmL9dpK4gSzQQmP5I7z4aME4LY,4749
122
122
  vellum/client/__init__.py,sha256=tKtdM1_GqmGq1gpi9ydWD_T-MM7fPn8QdHh8ww19cNI,117564
123
123
  vellum/client/core/__init__.py,sha256=SQ85PF84B9MuKnBwHNHWemSGuy-g_515gFYNFhvEE0I,1438
124
124
  vellum/client/core/api_error.py,sha256=RE8LELok2QCjABadECTvtDp7qejA1VmINCh6TbqPwSE,426
125
- vellum/client/core/client_wrapper.py,sha256=NOBkPB9txdePCb8-MgjYVJwNHQWPG9yrRX2B7sxaT-o,1868
125
+ vellum/client/core/client_wrapper.py,sha256=6EXwOd5Ka1mFWVlZmNuffO99dtW8DTAiRFes4vDlQFY,1869
126
126
  vellum/client/core/datetime_utils.py,sha256=nBys2IsYrhPdszxGKCNRPSOCwa-5DWOHG95FB8G9PKo,1047
127
127
  vellum/client/core/file.py,sha256=X9IbmkZmB2bB_DpmZAO3crWdXagOakAyn6UCOCImCPg,2322
128
128
  vellum/client/core/http_client.py,sha256=R0pQpCppnEtxccGvXl4uJ76s7ro_65Fo_erlNNLp_AI,19228
@@ -1287,7 +1287,7 @@ vellum/utils/templating/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG
1287
1287
  vellum/utils/templating/constants.py,sha256=8OHMO6WFAEimbIaiHc5gy6s91D7_KvW-vTlEMWwvl_M,711
1288
1288
  vellum/utils/templating/custom_filters.py,sha256=XVHriwazejRZmxB_eg4xHgCxl7AiQQ2sx-hRLMmylfU,885
1289
1289
  vellum/utils/templating/exceptions.py,sha256=cDp140PP4OnInW4qAvg3KqiSiF70C71UyEAKRBR1Abo,46
1290
- vellum/utils/templating/render.py,sha256=5OsD1e9fks1aysYTyPKjYGaloYUbIKWpajcxtjtiFuU,2037
1290
+ vellum/utils/templating/render.py,sha256=P2t9qU4w_WdXAVLM5Nj3bc1-XlIKOkwK-czQ80pHBag,2172
1291
1291
  vellum/utils/templating/tests/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
1292
1292
  vellum/utils/templating/tests/test_custom_filters.py,sha256=mkJwc7t1gE13SKgPxhF-lN_m2XGCkphCB9Te81dGekI,532
1293
1293
  vellum/utils/typing.py,sha256=wx_daFqD69cYkuJTVnvNrpjhqC3uuhbnyJ9_bIwC9OU,327
@@ -1298,9 +1298,9 @@ vellum/workflows/__init__.py,sha256=CssPsbNvN6rDhoLuqpEv7MMKGa51vE6dvAh6U31Pcio,
1298
1298
  vellum/workflows/constants.py,sha256=2yg4_uo5gpqViy3ZLSwfC8qTybleYCtOnhA4Rj6bacM,1310
1299
1299
  vellum/workflows/context.py,sha256=DwSf8lO9NHABiqOoD3exgrjUoRuNsKtutaL5TgRbD-A,1441
1300
1300
  vellum/workflows/descriptors/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
1301
- vellum/workflows/descriptors/base.py,sha256=gSib3vJpcI_UC8y8jhdp-hOK3_TGTF-SuwdhxF6x5iQ,14332
1301
+ vellum/workflows/descriptors/base.py,sha256=jtT11I5oB-CPWlJBZmc1RcVe4_xOKjimBthiHQHQuT0,14597
1302
1302
  vellum/workflows/descriptors/exceptions.py,sha256=gUy4UD9JFUKSeQnQpeuDSLiRqWjWiIsxLahB7p_q3JY,54
1303
- vellum/workflows/descriptors/tests/test_utils.py,sha256=yrXgu6J6pwqCxJKY3w-i-9t9KKzAkMR7SIICzdcII4k,5266
1303
+ vellum/workflows/descriptors/tests/test_utils.py,sha256=xoojJMyG5WLG9xGtmUjirz3lDFCcDsAcxjrtbdG8dNE,6060
1304
1304
  vellum/workflows/descriptors/utils.py,sha256=gmVXJjf2yWmvlYey41J2FZHeSou0JuCHKb3826K_Jok,3838
1305
1305
  vellum/workflows/edges/__init__.py,sha256=wSkmAnz9xyi4vZwtDbKxwlplt2skD7n3NsxkvR_pUus,50
1306
1306
  vellum/workflows/edges/edge.py,sha256=N0SnY3gKVuxImPAdCbPMPlHJIXbkQ3fwq_LbJRvVMFc,677
@@ -1313,9 +1313,9 @@ vellum/workflows/errors/types.py,sha256=tVW7Il9zalnwWzdoDLqYPIvRTOhXIv6FPORZAbU7
1313
1313
  vellum/workflows/events/__init__.py,sha256=6pxxceJo2dcaRkWtkDAYlUQZ-PHBQSZytIoyuUK48Qw,759
1314
1314
  vellum/workflows/events/node.py,sha256=uHT6If0esgZ3nLjrjmUPTKf3qbjGhoV_x5YKpjDBDcU,5280
1315
1315
  vellum/workflows/events/tests/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
1316
- vellum/workflows/events/tests/test_event.py,sha256=9rbp92dQXpGFad-LjE2nYU17neKkiHxQz9X8RsoCWs4,13718
1316
+ vellum/workflows/events/tests/test_event.py,sha256=uRfMwSOqU-ROeZKCEngGvvJYlOZuxBhnC3qH5AGi3fM,15399
1317
1317
  vellum/workflows/events/types.py,sha256=cjRE8WL8tYCFradd9NOGl_H0mN3LiWWnA1uHmyT2Q0Q,3412
1318
- vellum/workflows/events/workflow.py,sha256=lveoWXtVRLjdO_nu0z6VlKeTqlGimogamiFR-jYihlE,5184
1318
+ vellum/workflows/events/workflow.py,sha256=sLO29djAeHGVd4hLhaNtOQ48uwUjfl-DotZQt06PxQA,6033
1319
1319
  vellum/workflows/exceptions.py,sha256=NiBiR3ggfmPxBVqD-H1SqmjI-7mIn0EStSN1BqApvCM,1213
1320
1320
  vellum/workflows/expressions/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
1321
1321
  vellum/workflows/expressions/accessor.py,sha256=ItZF7fMLzVTqsdAiaXb5SiDupXmX0X9xbIus1W6hRds,1870
@@ -1330,8 +1330,8 @@ vellum/workflows/expressions/does_not_end_with.py,sha256=idw2OSuIk02XwBM5CXYOESf
1330
1330
  vellum/workflows/expressions/does_not_equal.py,sha256=LNiCibRZZIxaIrwotjW3SIsKYHWR7BpOItFI-x5KuKU,764
1331
1331
  vellum/workflows/expressions/ends_with.py,sha256=FkWZjAudc_DFM-fK-A3_tr6WXavfs_Qi7F6JtVgMglw,1117
1332
1332
  vellum/workflows/expressions/equals.py,sha256=gbI6BKQR7cLQih226-ge_BFSLprgEjqbdiIxo7WFg_E,758
1333
- vellum/workflows/expressions/greater_than.py,sha256=fTM2YF3FY_eOkRtGpgVWcv8qNt4K3lazONUIqcD8oe8,1263
1334
- vellum/workflows/expressions/greater_than_or_equal_to.py,sha256=sazL_-Jsgjo4jcQeE-6EC0BFHZACriaYMQH4rn0dqEo,1275
1333
+ vellum/workflows/expressions/greater_than.py,sha256=1sbUH6Obf-VoBgs7ilIncwYBHYfXliKmShppTuLMtCI,1247
1334
+ vellum/workflows/expressions/greater_than_or_equal_to.py,sha256=tsD5ZalB4SlryvEsvVtDkSr5Z13B2pABmHB8oHD8ojs,1276
1335
1335
  vellum/workflows/expressions/in_.py,sha256=RgiAIFntXGN4eWoOVBj1gqLymnBxSiw5hYD3TngF3dk,1123
1336
1336
  vellum/workflows/expressions/is_blank.py,sha256=vOOmK5poXmiNRVH7MR0feIFnL4rwKn7vmmTkJ9TcfVU,904
1337
1337
  vellum/workflows/expressions/is_nil.py,sha256=xCHwhKlm2UnfC-bVedmGgENCrzNtcn4ZeCYwNflVWbU,748
@@ -1341,11 +1341,15 @@ vellum/workflows/expressions/is_not_null.py,sha256=EoHXFgZScKP_BM2a5Z7YFQN6l7RME
1341
1341
  vellum/workflows/expressions/is_not_undefined.py,sha256=9s-RUQBqM17-_nIRvwsHuarLdHVtrxVuwnqBNJEtmh0,735
1342
1342
  vellum/workflows/expressions/is_null.py,sha256=C75ALGlG_sTGcxI46tm9HtgPVfJ7DwTIyKzX8qtEiDU,660
1343
1343
  vellum/workflows/expressions/is_undefined.py,sha256=uUBK3rxYbwoeRq36AGFc7d61hXzTp8UacQAi-1JbaW0,724
1344
- vellum/workflows/expressions/less_than.py,sha256=BcfkUH6Bb2inwR8jILn1hebUiyC74foVijBA-JymwT0,1260
1345
- vellum/workflows/expressions/less_than_or_equal_to.py,sha256=4i1FR6FzlKam29cZPPnXUqACslO242Ww-wZZY4CEK6A,1272
1344
+ vellum/workflows/expressions/less_than.py,sha256=chY9puJ6jDB2EinjfyGNrSplJ1NJC-BB-GGSSB33bqI,1237
1345
+ vellum/workflows/expressions/less_than_or_equal_to.py,sha256=JtTDBa8yFKy3fGaCOA1tb_5s1JkY8FFnH6kpoeXGnT4,1267
1346
1346
  vellum/workflows/expressions/not_between.py,sha256=ZtRJeJDSSlOvajL8YoBoh5o_khjIn9xSSeQCnXYbHFE,1506
1347
1347
  vellum/workflows/expressions/not_in.py,sha256=pFvwkFPsn3WJw61ssFgM2U1dqWEeglfz4FVT4xwm5Mc,1144
1348
1348
  vellum/workflows/expressions/or_.py,sha256=s-8YdMSSCDS2yijR38kguwok3iqmDMMgDYKV93b4O4s,914
1349
+ vellum/workflows/expressions/parse_json.py,sha256=xsk6j3HF7bU1yF6fwt5P9Ugcyd5D9ZXrdng11FRilUI,1088
1350
+ vellum/workflows/expressions/tests/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
1351
+ vellum/workflows/expressions/tests/test_expressions.py,sha256=3b6k8xs-CItBBw95NygFLUNoNPKxI4VA1GyWbkMtqyI,11623
1352
+ vellum/workflows/expressions/tests/test_parse_json.py,sha256=zpB_qE5_EwWQL7ULQUJm0o1PRSfWZdAqZNW6Ah13oJE,1059
1349
1353
  vellum/workflows/graph/__init__.py,sha256=3sHlay5d_-uD7j3QJXiGl0WHFZZ_QScRvgyDhN2GhHY,74
1350
1354
  vellum/workflows/graph/graph.py,sha256=GGR8cGpSuNWPIiTWNWsj6l70upb5nIxAyFcn7VdaJIs,5506
1351
1355
  vellum/workflows/graph/tests/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
@@ -1357,7 +1361,7 @@ vellum/workflows/inputs/tests/test_inputs.py,sha256=Haa0Px0obef7rgIddO6wwHF_bzmv
1357
1361
  vellum/workflows/logging.py,sha256=_a217XogktV4Ncz6xKFz7WfYmZAzkfVRVuC0rWob8ls,437
1358
1362
  vellum/workflows/nodes/__init__.py,sha256=aVdQVv7Y3Ro3JlqXGpxwaU2zrI06plDHD2aumH5WUIs,1157
1359
1363
  vellum/workflows/nodes/bases/__init__.py,sha256=cniHuz_RXdJ4TQgD8CBzoiKDiPxg62ErdVpCbWICX64,58
1360
- vellum/workflows/nodes/bases/base.py,sha256=O_O4pVZy0_H-4t2umBMumh_a9TCpmQsBGLcLjlS0vtE,14928
1364
+ vellum/workflows/nodes/bases/base.py,sha256=lVHODc1mjUFCorhZfK01zHohOWz9CYz7dnUzA-KENJ4,15036
1361
1365
  vellum/workflows/nodes/bases/base_adornment_node.py,sha256=eFTgsPCYb3eyGS0-kw7C6crFnwFx437R5wh9-8bWYts,2905
1362
1366
  vellum/workflows/nodes/bases/tests/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
1363
1367
  vellum/workflows/nodes/bases/tests/test_base_node.py,sha256=4SOdZzvugVtN8CIuo5RrapAxSYGXnxUwQ77dXJ64oTU,6295
@@ -1377,8 +1381,8 @@ vellum/workflows/nodes/core/retry_node/node.py,sha256=Vt3fx4G-DRIb9a-IHIUfaAclgf
1377
1381
  vellum/workflows/nodes/core/retry_node/tests/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
1378
1382
  vellum/workflows/nodes/core/retry_node/tests/test_node.py,sha256=RM_OHwxrHwyxvlQQBJPqVBxpedFuWQ9h2-Xa3kP75sc,4399
1379
1383
  vellum/workflows/nodes/core/templating_node/__init__.py,sha256=GmyuYo81_A1_Bz6id69ozVFS6FKiuDsZTiA3I6MaL2U,70
1380
- vellum/workflows/nodes/core/templating_node/node.py,sha256=Vqlg4L-5XNuIdbZKQe-GEYqTIV7iXNjLO7QIRgz4ujc,3722
1381
- vellum/workflows/nodes/core/templating_node/tests/test_templating_node.py,sha256=nY2P6r7cW85k7NEKXUFNeDTMWlz8ZEZyMY2Sg-0qO_E,7327
1384
+ vellum/workflows/nodes/core/templating_node/node.py,sha256=-JIqLUv6Xpx_LTVZt7whQ2X2VatgHDdTxjMrz64luEs,3721
1385
+ vellum/workflows/nodes/core/templating_node/tests/test_templating_node.py,sha256=ldnmSASx0TfAnT3ZvU0AXtN0diZGrfySiXipuJIIzWU,9055
1382
1386
  vellum/workflows/nodes/core/try_node/__init__.py,sha256=JVD4DrldTIqFQQFrubs9KtWCCc0YCAc7Fzol5ZWIWeM,56
1383
1387
  vellum/workflows/nodes/core/try_node/node.py,sha256=_0df2_6kim8pW4hB7IXUJOYS4fLduaeGDH4rRhYYvcg,4212
1384
1388
  vellum/workflows/nodes/core/try_node/tests/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
@@ -1387,7 +1391,7 @@ vellum/workflows/nodes/displayable/__init__.py,sha256=6F_4DlSwvHuilWnIalp8iDjjDX
1387
1391
  vellum/workflows/nodes/displayable/api_node/__init__.py,sha256=MoxdQSnidIj1Nf_d-hTxlOxcZXaZnsWFDbE-PkTK24o,56
1388
1392
  vellum/workflows/nodes/displayable/api_node/node.py,sha256=QdpsyGVxo5PcN8nwGZpcpW_YMKHr3_VvmbK1BlrdOFk,2547
1389
1393
  vellum/workflows/nodes/displayable/api_node/tests/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
1390
- vellum/workflows/nodes/displayable/api_node/tests/test_api_node.py,sha256=Ta-ZkZvllPHpLamiDRdEtVlwBJUFcvBHpyKLY6q06_A,2309
1394
+ vellum/workflows/nodes/displayable/api_node/tests/test_api_node.py,sha256=RtQWnFfq0HNqY2A6c5SdwHl8A91K4Vq8un5UJwwnkSw,2180
1391
1395
  vellum/workflows/nodes/displayable/bases/__init__.py,sha256=0mWIx3qUrzllV7jqt7wN03vWGMuI1WrrLZeMLT2Cl2c,304
1392
1396
  vellum/workflows/nodes/displayable/bases/api_node/__init__.py,sha256=1jwx4WC358CLA1jgzl_UD-rZmdMm2v9Mps39ndwCD7U,64
1393
1397
  vellum/workflows/nodes/displayable/bases/api_node/node.py,sha256=-LOKjU_rY1UWgD0DS5LJwAClBI8N7zrdmwigE3y5rhc,4000
@@ -1403,11 +1407,11 @@ vellum/workflows/nodes/displayable/bases/tests/test_utils.py,sha256=eqdqbKNRWVMD
1403
1407
  vellum/workflows/nodes/displayable/bases/types.py,sha256=C37B2Qh2YP7s7pUjd-EYKc2Zl1TbnCgI_mENuUSb8bo,1706
1404
1408
  vellum/workflows/nodes/displayable/bases/utils.py,sha256=ckMUenSsNkiYmSw6FmjSMHYaCk8Y8_sUjL6lkFFEqts,5412
1405
1409
  vellum/workflows/nodes/displayable/code_execution_node/__init__.py,sha256=0FLWMMktpzSnmBMizQglBpcPrP80fzVsoJwJgf822Cg,76
1406
- vellum/workflows/nodes/displayable/code_execution_node/node.py,sha256=_yrQn_uLwy8zVW1RjFMoeomDEsbpbbKK7ifMGEBfNlk,9120
1410
+ vellum/workflows/nodes/displayable/code_execution_node/node.py,sha256=pdDrjI8wdqMyf52kK6TlSjSU-MRxV2SKDwKcK2LCgkU,9547
1407
1411
  vellum/workflows/nodes/displayable/code_execution_node/tests/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
1408
1412
  vellum/workflows/nodes/displayable/code_execution_node/tests/fixtures/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
1409
1413
  vellum/workflows/nodes/displayable/code_execution_node/tests/fixtures/main.py,sha256=5QsbmkzSlSbcbWTG_JmIqcP-JNJzOPTKxGzdHos19W4,79
1410
- vellum/workflows/nodes/displayable/code_execution_node/tests/test_code_execution_node.py,sha256=4ADDKsObtUs0PhcWyAjWyQcAF7PGUYE0CxjYp8d-1NM,20637
1414
+ vellum/workflows/nodes/displayable/code_execution_node/tests/test_code_execution_node.py,sha256=OTnw5jgX90xWVB3vKryL5QSIr2YnGBz-W0q9C9LpNoc,22471
1411
1415
  vellum/workflows/nodes/displayable/code_execution_node/utils.py,sha256=BQraIN4I3DCzXLEuBlRYCyp7ote7hQmnnKHu4jFHCCA,5174
1412
1416
  vellum/workflows/nodes/displayable/conditional_node/__init__.py,sha256=AS_EIqFdU1F9t8aLmbZU-rLh9ry6LCJ0uj0D8F0L5Uw,72
1413
1417
  vellum/workflows/nodes/displayable/conditional_node/node.py,sha256=Qjfl33gZ3JEgxBA1EgzSUebboGvsARthIxxcQyvx5Gg,1152
@@ -1444,7 +1448,7 @@ vellum/workflows/nodes/experimental/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQ
1444
1448
  vellum/workflows/nodes/experimental/openai_chat_completion_node/__init__.py,sha256=lsyD9laR9p7kx5-BXGH2gUTM242UhKy8SMV0SR6S2iE,90
1445
1449
  vellum/workflows/nodes/experimental/openai_chat_completion_node/node.py,sha256=1EGeiaT-Zoo6pttQFKKBcdf3dmhAbjKGaErYD5FFwlc,10185
1446
1450
  vellum/workflows/nodes/mocks.py,sha256=gvM2tyoe-V84jFbFdhQsyGAPyQBzmjn_CkhT_yxccgY,499
1447
- vellum/workflows/nodes/utils.py,sha256=YRj3qIz6--N6CuDiKalsWpBmUR6z7WcRhqtLxoenDZE,4354
1451
+ vellum/workflows/nodes/utils.py,sha256=fq49n624n_nBMIFcc0JiNkHy3qna-bsA1HZRPa5AOJE,4918
1448
1452
  vellum/workflows/outputs/__init__.py,sha256=AyZ4pRh_ACQIGvkf0byJO46EDnSix1ZCAXfvh-ms1QE,94
1449
1453
  vellum/workflows/outputs/base.py,sha256=2MtTlyzePopMZDpBWQIV8HRV-km1-z0vI8Gm012q9OQ,8665
1450
1454
  vellum/workflows/ports/__init__.py,sha256=bZuMt-R7z5bKwpu4uPW7LlJeePOQWmCcDSXe5frUY5g,101
@@ -1466,12 +1470,12 @@ vellum/workflows/references/workflow_input.py,sha256=86IuhlBz-9cGxeUzizyjdp482aj
1466
1470
  vellum/workflows/resolvers/__init__.py,sha256=eH6hTvZO4IciDaf_cf7aM2vs-DkBDyJPycOQevJxQnI,82
1467
1471
  vellum/workflows/resolvers/base.py,sha256=WHra9LRtlTuB1jmuNqkfVE2JUgB61Cyntn8f0b0WZg4,411
1468
1472
  vellum/workflows/runner/__init__.py,sha256=i1iG5sAhtpdsrlvwgH6B-m49JsINkiWyPWs8vyT-bqM,72
1469
- vellum/workflows/runner/runner.py,sha256=XUaAdkG0AEkfPc0ri1j0KXUUqrUfTKmUfQXllgE1yq8,29854
1473
+ vellum/workflows/runner/runner.py,sha256=_p19T1woplSxZGabZuSUFBKSYBrXADrM7b_1YnWVN3g,31013
1470
1474
  vellum/workflows/sandbox.py,sha256=GVJzVjMuYzOBnSrboB0_6MMRZWBluAyQ2o7syeaeBd0,2235
1471
1475
  vellum/workflows/state/__init__.py,sha256=yUUdR-_Vl7UiixNDYQZ-GEM_kJI9dnOia75TtuNEsnE,60
1472
1476
  vellum/workflows/state/base.py,sha256=Vkhneko3VlQrPsMLU1PYSzXU_W1u7_AraJsghiv5O-4,15512
1473
1477
  vellum/workflows/state/context.py,sha256=yePVr4CCTQn5bjo1697JOO24fKFQpVNzooL07xL4gL0,2702
1474
- vellum/workflows/state/encoder.py,sha256=WdUidpOaBDx5lilJl8V8McFDHQYiCLCJR9dmktdzdZY,1836
1478
+ vellum/workflows/state/encoder.py,sha256=TnOQojc5lTQ83g9QbpA4UCqShJvutmTMxbpKt-9gNe4,1911
1475
1479
  vellum/workflows/state/store.py,sha256=VYGBQgN1bpd1as5eGiouV_7scg8QsRs4_1aqZAGIsRQ,793
1476
1480
  vellum/workflows/state/tests/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
1477
1481
  vellum/workflows/state/tests/test_state.py,sha256=jBynFR4m74Vn51DdmKBLkxb1loTy1CnJPtzPmdAFQUo,5159
@@ -1502,8 +1506,8 @@ vellum/workflows/workflows/event_filters.py,sha256=GSxIgwrX26a1Smfd-6yss2abGCnad
1502
1506
  vellum/workflows/workflows/tests/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
1503
1507
  vellum/workflows/workflows/tests/test_base_workflow.py,sha256=NRteiICyJvDM5zrtUfq2fZoXcGQVaWC9xmNlLLVW0cU,7979
1504
1508
  vellum/workflows/workflows/tests/test_context.py,sha256=VJBUcyWVtMa_lE5KxdhgMu0WYNYnUQUDvTF7qm89hJ0,2333
1505
- vellum_ai-0.14.8.dist-info/LICENSE,sha256=hOypcdt481qGNISA784bnAGWAE6tyIf9gc2E78mYC3E,1574
1506
- vellum_ai-0.14.8.dist-info/METADATA,sha256=rjXn1UMzW7AdriljPfHof7rjjp7GseRXLTfRswDoSBc,5407
1507
- vellum_ai-0.14.8.dist-info/WHEEL,sha256=sP946D7jFCHeNz5Iq4fL4Lu-PrWrFsgfLXbbkciIZwg,88
1508
- vellum_ai-0.14.8.dist-info/entry_points.txt,sha256=HCH4yc_V3J_nDv3qJzZ_nYS8llCHZViCDP1ejgCc5Ak,42
1509
- vellum_ai-0.14.8.dist-info/RECORD,,
1509
+ vellum_ai-0.14.10.dist-info/LICENSE,sha256=hOypcdt481qGNISA784bnAGWAE6tyIf9gc2E78mYC3E,1574
1510
+ vellum_ai-0.14.10.dist-info/METADATA,sha256=XNLaqqk85P8uRcr65-_IDfNPVi1dpNP9YvZgm43wAGs,5408
1511
+ vellum_ai-0.14.10.dist-info/WHEEL,sha256=sP946D7jFCHeNz5Iq4fL4Lu-PrWrFsgfLXbbkciIZwg,88
1512
+ vellum_ai-0.14.10.dist-info/entry_points.txt,sha256=HCH4yc_V3J_nDv3qJzZ_nYS8llCHZViCDP1ejgCc5Ak,42
1513
+ vellum_ai-0.14.10.dist-info/RECORD,,
@@ -27,6 +27,7 @@ from vellum.workflows.expressions.is_not_undefined import IsNotUndefinedExpressi
27
27
  from vellum.workflows.expressions.is_null import IsNullExpression
28
28
  from vellum.workflows.expressions.is_undefined import IsUndefinedExpression
29
29
  from vellum.workflows.expressions.not_between import NotBetweenExpression
30
+ from vellum.workflows.expressions.parse_json import ParseJsonExpression
30
31
  from vellum.workflows.nodes.bases.base import BaseNode
31
32
  from vellum.workflows.nodes.utils import get_wrapped_node
32
33
  from vellum.workflows.ports import Port
@@ -386,6 +387,9 @@ class BaseNodeDisplay(Generic[NodeType], metaclass=BaseNodeDisplayMeta):
386
387
  "node_id": str(node_class_display.node_id),
387
388
  }
388
389
 
390
+ if isinstance(value, ParseJsonExpression):
391
+ raise ValueError("ParseJsonExpression is not supported in the UI")
392
+
389
393
  if not isinstance(value, BaseDescriptor):
390
394
  vellum_value = primitive_to_vellum_value(value)
391
395
  return {
@@ -1,3 +1,4 @@
1
+ import pytest
1
2
  from uuid import UUID
2
3
  from typing import Dict
3
4
 
@@ -228,3 +229,33 @@ def test_vellum_workflow_display__serialize_with_unused_nodes_and_edges():
228
229
  break
229
230
 
230
231
  assert edge_found, "Edge between unused nodes NodeB and NodeC not found in serialized output"
232
+
233
+
234
+ def test_parse_json_not_supported_in_ui():
235
+ """
236
+ Test that verifies ParseJsonExpression is not yet supported in the UI.
237
+ This test should fail once UI support is added, at which point it should be updated.
238
+ """
239
+ # GIVEN a workflow that uses the parse_json function
240
+ from vellum.workflows.references.constant import ConstantValueReference
241
+
242
+ class JsonNode(BaseNode):
243
+ class Outputs(BaseNode.Outputs):
244
+ json_result = ConstantValueReference('{"key": "value"}').parse_json()
245
+
246
+ class Workflow(BaseWorkflow):
247
+ graph = JsonNode
248
+
249
+ class Outputs(BaseWorkflow.Outputs):
250
+ final = JsonNode.Outputs.json_result
251
+
252
+ # WHEN we attempt to serialize it
253
+ workflow_display = get_workflow_display(
254
+ base_display_class=VellumWorkflowDisplay,
255
+ workflow_class=Workflow,
256
+ )
257
+
258
+ with pytest.raises(ValueError) as exc_info:
259
+ workflow_display.serialize()
260
+
261
+ assert "ParseJsonExpression is not supported in the UI" == str(exc_info.value)
@@ -1,9 +1,8 @@
1
1
  from dataclasses import dataclass, field
2
- from uuid import UUID
3
2
  from typing import TYPE_CHECKING, Dict, Generic, Tuple, Type, TypeVar
4
3
 
5
- from vellum.client.core import UniversalBaseModel
6
4
  from vellum.workflows.descriptors.base import BaseDescriptor
5
+ from vellum.workflows.events.workflow import WorkflowEventDisplayContext # noqa: F401
7
6
  from vellum.workflows.nodes import BaseNode
8
7
  from vellum.workflows.ports import Port
9
8
  from vellum.workflows.references import OutputReference, StateValueReference, WorkflowInputReference
@@ -25,18 +24,6 @@ NodeDisplayType = TypeVar("NodeDisplayType", bound="BaseNodeDisplay")
25
24
  WorkflowDisplayType = TypeVar("WorkflowDisplayType", bound="BaseWorkflowDisplay")
26
25
 
27
26
 
28
- class NodeDisplay(UniversalBaseModel):
29
- input_display: Dict[str, UUID]
30
- output_display: Dict[str, UUID]
31
- port_display: Dict[str, UUID]
32
-
33
-
34
- class WorkflowEventDisplayContext(UniversalBaseModel):
35
- node_displays: Dict[str, NodeDisplay]
36
- workflow_inputs: Dict[str, UUID]
37
- workflow_outputs: Dict[str, UUID]
38
-
39
-
40
27
  @dataclass
41
28
  class WorkflowDisplayContext(
42
29
  Generic[
@@ -9,6 +9,7 @@ from typing import Any, Dict, Generic, Iterator, List, Optional, Tuple, Type, Un
9
9
  from vellum.workflows import BaseWorkflow
10
10
  from vellum.workflows.descriptors.base import BaseDescriptor
11
11
  from vellum.workflows.edges import Edge
12
+ from vellum.workflows.events.workflow import NodeEventDisplayContext, WorkflowEventDisplayContext
12
13
  from vellum.workflows.expressions.coalesce_expression import CoalesceExpression
13
14
  from vellum.workflows.nodes.bases import BaseNode
14
15
  from vellum.workflows.nodes.utils import get_wrapped_node
@@ -33,12 +34,9 @@ from vellum_ee.workflows.display.base import (
33
34
  from vellum_ee.workflows.display.nodes.base_node_vellum_display import BaseNodeVellumDisplay
34
35
  from vellum_ee.workflows.display.nodes.get_node_display_class import get_node_display_class
35
36
  from vellum_ee.workflows.display.nodes.types import NodeOutputDisplay, PortDisplay, PortDisplayOverrides
36
- from vellum_ee.workflows.display.types import (
37
- NodeDisplay,
38
- NodeDisplayType,
39
- WorkflowDisplayContext,
40
- WorkflowEventDisplayContext,
41
- )
37
+ from vellum_ee.workflows.display.nodes.utils import raise_if_descriptor
38
+ from vellum_ee.workflows.display.types import NodeDisplayType, WorkflowDisplayContext
39
+ from vellum_ee.workflows.display.workflows.get_vellum_workflow_display_class import get_workflow_display
42
40
 
43
41
  logger = logging.getLogger(__name__)
44
42
 
@@ -387,10 +385,15 @@ class BaseWorkflowDisplay(
387
385
  except ModuleNotFoundError:
388
386
  return None
389
387
 
390
- display_context = display_class.WorkflowDisplay(workflow_class).display_context
391
- if not isinstance(display_context, WorkflowDisplayContext):
388
+ workflow_display = display_class.WorkflowDisplay(workflow_class)
389
+ if not isinstance(workflow_display, BaseWorkflowDisplay):
392
390
  return None
393
391
 
392
+ return workflow_display.get_event_display_context()
393
+
394
+ def get_event_display_context(self):
395
+ display_context = self.display_context
396
+
394
397
  workflow_outputs = {
395
398
  output.name: display_context.workflow_output_displays[output].id
396
399
  for output in display_context.workflow_output_displays
@@ -402,27 +405,44 @@ class BaseWorkflowDisplay(
402
405
  node_displays = {
403
406
  str(node.__id__): display_context.node_displays[node] for node in display_context.node_displays
404
407
  }
405
- temp_node_displays = {}
406
- for node in node_displays:
407
- current_node = node_displays[node]
408
+ node_event_displays = {}
409
+ for node_id in node_displays:
410
+ current_node_display = node_displays[node_id]
408
411
  input_display = {}
409
- if isinstance(current_node, BaseNodeVellumDisplay):
410
- input_display = current_node.node_input_ids_by_name
412
+ if isinstance(current_node_display, BaseNodeVellumDisplay):
413
+ input_display = current_node_display.node_input_ids_by_name
411
414
  node_display_meta = {
412
- output.name: current_node.output_display[output].id for output in current_node.output_display
415
+ output.name: current_node_display.output_display[output].id
416
+ for output in current_node_display.output_display
413
417
  }
414
- port_display_meta = {port.name: current_node.port_displays[port].id for port in current_node.port_displays}
415
-
416
- temp_node_displays[node] = NodeDisplay(
418
+ port_display_meta = {
419
+ port.name: current_node_display.port_displays[port].id for port in current_node_display.port_displays
420
+ }
421
+ node = current_node_display._node
422
+ subworkflow_display_context: Optional[WorkflowEventDisplayContext] = None
423
+ if hasattr(node, "subworkflow"):
424
+ # All nodes that have a subworkflow attribute are currently expected to call them `subworkflow`
425
+ # This will change if in the future we decide to support multiple subworkflows on a single node
426
+ subworkflow_attribute = raise_if_descriptor(getattr(node, "subworkflow"))
427
+ if issubclass(subworkflow_attribute, BaseWorkflow):
428
+ subworkflow_display = get_workflow_display(
429
+ base_display_class=display_context.workflow_display_class,
430
+ workflow_class=subworkflow_attribute,
431
+ parent_display_context=display_context,
432
+ )
433
+ subworkflow_display_context = subworkflow_display.get_event_display_context()
434
+
435
+ node_event_displays[node_id] = NodeEventDisplayContext(
417
436
  input_display=input_display,
418
437
  output_display=node_display_meta,
419
438
  port_display=port_display_meta,
439
+ subworkflow_display=subworkflow_display_context,
420
440
  )
421
441
 
422
442
  display_meta = WorkflowEventDisplayContext(
423
443
  workflow_outputs=workflow_outputs,
424
444
  workflow_inputs=workflow_inputs,
425
- node_displays=temp_node_displays,
445
+ node_displays=node_event_displays,
426
446
  )
427
447
  return display_meta
428
448
 
@@ -1,6 +1,7 @@
1
1
  import pytest
2
2
 
3
3
  from vellum.workflows.nodes.bases.base import BaseNode
4
+ from vellum.workflows.nodes.core.inline_subworkflow_node.node import InlineSubworkflowNode
4
5
  from vellum.workflows.workflows.base import BaseWorkflow
5
6
  from vellum_ee.workflows.display.nodes import BaseNodeDisplay
6
7
  from vellum_ee.workflows.display.vellum import NodeDisplayData, NodeDisplayPosition
@@ -92,3 +93,29 @@ def test_serialize_workflow__node_display_class_not_registered():
92
93
 
93
94
  # THEN it should should succeed
94
95
  assert data is not None
96
+
97
+
98
+ def test_get_event_display_context__node_display_to_include_subworkflow_display():
99
+ # GIVEN a simple workflow
100
+ class InnerNode(BaseNode):
101
+ pass
102
+
103
+ class Subworkflow(BaseWorkflow):
104
+ graph = InnerNode
105
+
106
+ # AND a workflow that includes the subworkflow
107
+ class SubworkflowNode(InlineSubworkflowNode):
108
+ subworkflow = Subworkflow
109
+
110
+ class MyWorkflow(BaseWorkflow):
111
+ graph = SubworkflowNode
112
+
113
+ # WHEN we gather the event display context
114
+ display_context = VellumWorkflowDisplay(MyWorkflow).get_event_display_context()
115
+
116
+ # THEN the subworkflow display should be included
117
+ assert str(SubworkflowNode.__id__) in display_context.node_displays
118
+ node_event_display = display_context.node_displays[str(SubworkflowNode.__id__)]
119
+
120
+ assert node_event_display.subworkflow_display is not None
121
+ assert str(InnerNode.__id__) in node_event_display.subworkflow_display.node_displays
@@ -40,11 +40,13 @@ def test_base_class_dynamic_import(files):
40
40
  },
41
41
  "output_display": {"result": UUID("423bc529-1a1a-4f72-af4d-cbdb5f0a5929")},
42
42
  "port_display": {"default": UUID("afda9a19-0618-42e1-9b63-5d0db2a88f62")},
43
+ "subworkflow_display": None,
43
44
  },
44
45
  "f3ef4b2b-fec9-4026-9cc6-e5eac295307f": {
45
46
  "input_display": {"node_input": UUID("fe6cba85-2423-4b5e-8f85-06311a8be5fb")},
46
47
  "output_display": {"value": UUID("5469b810-6ea6-4362-9e79-e360d44a1405")},
47
48
  "port_display": {},
49
+ "subworkflow_display": None,
48
50
  },
49
51
  },
50
52
  "workflow_inputs": {"input_value": UUID("2268a996-bd17-4832-b3ff-f5662d54b306")},
@@ -2,6 +2,7 @@ from vellum.client.core.pydantic_utilities import UniversalBaseModel
2
2
 
3
3
 
4
4
  def test_load_workflow_event_display_context():
5
+ # DEPRECATED: Use `vellum.workflows.events.workflow.WorkflowEventDisplayContext` instead. Will be removed in 0.15.0
5
6
  from vellum_ee.workflows.display.types import WorkflowEventDisplayContext
6
7
 
7
8
  # We are actually just ensuring there are no circular dependencies when