vellum-ai 0.14.50__py3-none-any.whl → 0.14.51__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.
@@ -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.50",
21
+ "X-Fern-SDK-Version": "0.14.51",
22
22
  }
23
23
  headers["X-API-KEY"] = self.api_key
24
24
  return headers
@@ -20,7 +20,6 @@ from vellum.client import ApiError, RequestOptions
20
20
  from vellum.client.types.chat_message_request import ChatMessageRequest
21
21
  from vellum.client.types.prompt_settings import PromptSettings
22
22
  from vellum.client.types.rich_text_child_block import RichTextChildBlock
23
- from vellum.workflows.constants import OMIT
24
23
  from vellum.workflows.context import get_execution_context
25
24
  from vellum.workflows.errors import WorkflowErrorCode
26
25
  from vellum.workflows.errors.types import vellum_error_to_workflow_error
@@ -56,7 +55,7 @@ class BaseInlinePromptNode(BasePromptNode[StateType], Generic[StateType]):
56
55
  functions: Optional[List[Union[FunctionDefinition, Callable]]] = None
57
56
 
58
57
  parameters: PromptParameters = DEFAULT_PROMPT_PARAMETERS
59
- expand_meta: Optional[AdHocExpandMeta] = OMIT
58
+ expand_meta: Optional[AdHocExpandMeta] = None
60
59
 
61
60
  settings: Optional[PromptSettings] = None
62
61
 
@@ -270,7 +270,7 @@ def test_inline_prompt_node__json_output(vellum_adhoc_prompt_client):
270
270
  # AND we should have made the expected call to Vellum search
271
271
  vellum_adhoc_prompt_client.adhoc_execute_prompt_stream.assert_called_once_with(
272
272
  blocks=[],
273
- expand_meta=Ellipsis,
273
+ expand_meta=None,
274
274
  functions=None,
275
275
  input_values=[],
276
276
  input_variables=[],
@@ -350,7 +350,7 @@ def test_inline_prompt_node__streaming_disabled(vellum_adhoc_prompt_client):
350
350
  # AND we should have made the expected call to Vellum search
351
351
  vellum_adhoc_prompt_client.adhoc_execute_prompt.assert_called_once_with(
352
352
  blocks=[],
353
- expand_meta=Ellipsis,
353
+ expand_meta=None,
354
354
  functions=None,
355
355
  input_values=[],
356
356
  input_variables=[],
@@ -444,7 +444,7 @@ def test_inline_prompt_node__json_output_with_streaming_disabled(vellum_adhoc_pr
444
444
  # AND we should have made the expected call to Vellum search
445
445
  vellum_adhoc_prompt_client.adhoc_execute_prompt.assert_called_once_with(
446
446
  blocks=[],
447
- expand_meta=Ellipsis,
447
+ expand_meta=None,
448
448
  functions=None,
449
449
  input_values=[],
450
450
  input_variables=[],
@@ -74,7 +74,7 @@ def test_inline_text_prompt_node__basic(vellum_adhoc_prompt_client):
74
74
  # AND we should have made the expected call to Vellum search
75
75
  vellum_adhoc_prompt_client.adhoc_execute_prompt_stream.assert_called_once_with(
76
76
  blocks=[],
77
- expand_meta=Ellipsis,
77
+ expand_meta=None,
78
78
  functions=None,
79
79
  input_values=[],
80
80
  input_variables=[],
@@ -0,0 +1,3 @@
1
+ from .tool_calling_node import ToolCallingNode
2
+
3
+ __all__ = ["ToolCallingNode"]
@@ -0,0 +1,53 @@
1
+ from vellum.client.types.function_call import FunctionCall
2
+ from vellum.client.types.function_call_vellum_value import FunctionCallVellumValue
3
+ from vellum.workflows.nodes.experimental.tool_calling_node.utils import create_tool_router_node
4
+ from vellum.workflows.state.base import BaseState, StateMeta
5
+
6
+
7
+ def first_function() -> str:
8
+ return "first_function"
9
+
10
+
11
+ def second_function() -> str:
12
+ return "second_function"
13
+
14
+
15
+ def test_port_condition_match_function_name():
16
+ """
17
+ Test that the port condition correctly matches the function name.
18
+ """
19
+ # GIVEN a tool router node
20
+ router_node = create_tool_router_node(
21
+ ml_model="test-model",
22
+ blocks=[],
23
+ functions=[first_function, second_function],
24
+ prompt_inputs=None,
25
+ )
26
+
27
+ # AND a state with a function call to the first function
28
+ state = BaseState(
29
+ meta=StateMeta(
30
+ node_outputs={
31
+ router_node.Outputs.results: [
32
+ FunctionCallVellumValue(
33
+ value=FunctionCall(
34
+ arguments={}, id="call_zp7pBQjGAOBCr7lo0AbR1HXT", name="first_function", state="FULFILLED"
35
+ ),
36
+ )
37
+ ],
38
+ },
39
+ )
40
+ )
41
+
42
+ # WHEN the port condition is resolved
43
+ # THEN the first function port should be true
44
+ first_function_port = getattr(router_node.Ports, "first_function")
45
+ assert first_function_port.resolve_condition(state) is True
46
+
47
+ # AND the second function port should be false
48
+ second_function_port = getattr(router_node.Ports, "second_function")
49
+ assert second_function_port.resolve_condition(state) is False
50
+
51
+ # AND the default port should be false
52
+ default_port = getattr(router_node.Ports, "default")
53
+ assert default_port.resolve_condition(state) is False
@@ -57,12 +57,19 @@ def create_tool_router_node(
57
57
  Ports = type("Ports", (), {})
58
58
  for function in functions:
59
59
  function_name = function.__name__
60
- port_condition = LazyReference(
61
- lambda: (
62
- node.Outputs.results[0]["type"].equals("FUNCTION_CALL")
63
- & node.Outputs.results[0]["value"]["name"].equals(function_name)
60
+
61
+ # Avoid using lambda to capture function_name
62
+ # lambda will capture the function_name by reference,
63
+ # and if the function_name is changed, the port_condition will also change.
64
+ def create_port_condition(fn_name):
65
+ return LazyReference(
66
+ lambda: (
67
+ node.Outputs.results[0]["type"].equals("FUNCTION_CALL")
68
+ & node.Outputs.results[0]["value"]["name"].equals(fn_name)
69
+ )
64
70
  )
65
- )
71
+
72
+ port_condition = create_port_condition(function_name)
66
73
  port = Port.on_if(port_condition)
67
74
  setattr(Ports, function_name, port)
68
75
 
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: vellum-ai
3
- Version: 0.14.50
3
+ Version: 0.14.51
4
4
  Summary:
5
5
  License: MIT
6
6
  Requires-Python: >=3.9,<4.0
@@ -26,7 +26,7 @@ vellum_ee/workflows/display/base.py,sha256=EqlQFD56kpqMY02ZBJBQajzJKh33Dwi60Wo77
26
26
  vellum_ee/workflows/display/editor/__init__.py,sha256=MSAgY91xCEg2neH5d8jXx5wRdR962ftZVa6vO9BGq9k,167
27
27
  vellum_ee/workflows/display/editor/types.py,sha256=x-tOOCJ6CF4HmiKDfCmcc3bOVfc1EBlP5o6u5WEfLoY,567
28
28
  vellum_ee/workflows/display/nodes/__init__.py,sha256=jI1aPBQf8DkmrYoZ4O-wR1duqZByOf5mDFmo_wFJPE4,307
29
- vellum_ee/workflows/display/nodes/base_node_display.py,sha256=mzODbbNfrjOi7rVQb6FFCEjQHZkTs76nAc8L-Q5yCnQ,16491
29
+ vellum_ee/workflows/display/nodes/base_node_display.py,sha256=2VyAk9SjBpt_b2fp81KlFxS5ddk2JhcldEI1S4crPj0,16921
30
30
  vellum_ee/workflows/display/nodes/get_node_display_class.py,sha256=jI_kUi9LnNLDpY63QtlC4TfN8P571VN4LpzH0I1ZtLk,1149
31
31
  vellum_ee/workflows/display/nodes/tests/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
32
32
  vellum_ee/workflows/display/nodes/tests/test_base_node_display.py,sha256=Z4Mf7xLCNiblSbpKI0BrV5modQr-ZcFzhfir_OSyTTs,2997
@@ -40,7 +40,7 @@ vellum_ee/workflows/display/nodes/vellum/conditional_node.py,sha256=MrvyiYD0qgQf
40
40
  vellum_ee/workflows/display/nodes/vellum/error_node.py,sha256=m2DmOXm9-jiiIl6zwkXHNfsYp5PTpBHEdt5xaIsabWo,2363
41
41
  vellum_ee/workflows/display/nodes/vellum/final_output_node.py,sha256=jUDI2FwVaw0Or4zJL58J_g0S--i59Hzik60s_Es_M-8,3098
42
42
  vellum_ee/workflows/display/nodes/vellum/guardrail_node.py,sha256=5_5D5PMzBOeUdVtRlANbfEsu7Gv3r37dLvpfjGAqYac,2330
43
- vellum_ee/workflows/display/nodes/vellum/inline_prompt_node.py,sha256=gVwQwycEPNtCs8tWbFyIMLpCA7zXnqcmuuhFqRWNxZM,10368
43
+ vellum_ee/workflows/display/nodes/vellum/inline_prompt_node.py,sha256=-6Ru9W_vfNdLKLStB40qicMx6WvdejPM3PE54Onqk5w,10943
44
44
  vellum_ee/workflows/display/nodes/vellum/inline_subworkflow_node.py,sha256=fQV5o83BPTwGX6o-ThN4r7BcIhySyqwpW1JGYWpvSJI,5625
45
45
  vellum_ee/workflows/display/nodes/vellum/map_node.py,sha256=CiklGf5_tDbqE1XQm2mnbtoL01_2JYjcnB4FDTpMImQ,3824
46
46
  vellum_ee/workflows/display/nodes/vellum/merge_node.py,sha256=yBWeN4T_lOsDVnNOKWRiT7JYKu0IR5Fx2z99iq6QKSA,3273
@@ -55,7 +55,7 @@ vellum_ee/workflows/display/nodes/vellum/tests/test_code_execution_node.py,sha25
55
55
  vellum_ee/workflows/display/nodes/vellum/tests/test_error_node.py,sha256=540FoWMpJ3EN_DPjHsr9ODJWCRVcUa5hZBn-5T2GiHU,1665
56
56
  vellum_ee/workflows/display/nodes/vellum/tests/test_note_node.py,sha256=uiMB0cOxKZzos7YKnj4ef4DFa2bOvZJWIv-hfbUV6Go,1218
57
57
  vellum_ee/workflows/display/nodes/vellum/tests/test_prompt_deployment_node.py,sha256=G-qJyTNJkpqJiEZ3kCJl86CXJINLeFyf2lM0bQHCCOs,3822
58
- vellum_ee/workflows/display/nodes/vellum/tests/test_prompt_node.py,sha256=RPpromm0y9y-MukL8cmxpl9hYaw-JuNo8vFDOcLI4V4,8801
58
+ vellum_ee/workflows/display/nodes/vellum/tests/test_prompt_node.py,sha256=9bNpdCBUSLTUmCh04Z-kgXxJ5dKWFJ53V6xrQMEVxyU,9942
59
59
  vellum_ee/workflows/display/nodes/vellum/tests/test_retry_node.py,sha256=h93ysolmbo2viisyhRnXKHPxiDK0I_dSAbYoHFYIoO4,1953
60
60
  vellum_ee/workflows/display/nodes/vellum/tests/test_subworkflow_deployment_node.py,sha256=BUzHJgjdWnPeZxjFjHfDBKnbFjYjnbXPjc-1hne1B2Y,3965
61
61
  vellum_ee/workflows/display/nodes/vellum/tests/test_templating_node.py,sha256=LSk2gx9TpGXbAqKe8dggQW8yJZqj-Cf0EGJFeGGlEcw,3321
@@ -133,7 +133,7 @@ vellum/client/README.md,sha256=qmaVIP42MnxAu8jV7u-CsgVFfs3-pHQODrXdZdFxtaw,4749
133
133
  vellum/client/__init__.py,sha256=PEnFl7LbXQcvAi3bVN2qyt5xm2FtVtq7xWKkcWM3Tg4,120166
134
134
  vellum/client/core/__init__.py,sha256=SQ85PF84B9MuKnBwHNHWemSGuy-g_515gFYNFhvEE0I,1438
135
135
  vellum/client/core/api_error.py,sha256=RE8LELok2QCjABadECTvtDp7qejA1VmINCh6TbqPwSE,426
136
- vellum/client/core/client_wrapper.py,sha256=0Uo8ifbV1rC2jIjuU95Td5DeLVDs0xqQP3DETAbhbEU,1869
136
+ vellum/client/core/client_wrapper.py,sha256=0O1XpnpyuPVD86JFBVwkbpWYMkAmrvehoYpQg2THQRM,1869
137
137
  vellum/client/core/datetime_utils.py,sha256=nBys2IsYrhPdszxGKCNRPSOCwa-5DWOHG95FB8G9PKo,1047
138
138
  vellum/client/core/file.py,sha256=d4NNbX8XvXP32z8KpK2Xovv33nFfruIrpz0QWxlgpZk,2663
139
139
  vellum/client/core/http_client.py,sha256=Z77OIxIbL4OAB2IDqjRq_sYa5yNYAWfmdhdCSSvh6Y4,19552
@@ -1582,9 +1582,9 @@ vellum/workflows/nodes/displayable/bases/base_prompt_node/__init__.py,sha256=Org
1582
1582
  vellum/workflows/nodes/displayable/bases/base_prompt_node/node.py,sha256=amBXi7Tv50AbGLhfWbwX83PlOdV1XyYRyQmpa6_afE4,3511
1583
1583
  vellum/workflows/nodes/displayable/bases/inline_prompt_node/__init__.py,sha256=Hl35IAoepRpE-j4cALaXVJIYTYOF3qszyVbxTj4kS1s,82
1584
1584
  vellum/workflows/nodes/displayable/bases/inline_prompt_node/constants.py,sha256=fnjiRWLoRlC4Puo5oQcpZD5Hd-EesxsAo9l5tGAkpZQ,270
1585
- vellum/workflows/nodes/displayable/bases/inline_prompt_node/node.py,sha256=wqN1EjyjTL6McUmlkHWu3GXVzcNaqDjavvmKUHDaVqg,10623
1585
+ vellum/workflows/nodes/displayable/bases/inline_prompt_node/node.py,sha256=eG_buxb4DlgvBzewseQDiUu7Vc2uaoOariVVsWt1068,10579
1586
1586
  vellum/workflows/nodes/displayable/bases/inline_prompt_node/tests/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
1587
- vellum/workflows/nodes/displayable/bases/inline_prompt_node/tests/test_inline_prompt_node.py,sha256=YPOFoaEBENfOzE_qWo3WdQ_E1dQk78aLCWk8gOMvTjg,16042
1587
+ vellum/workflows/nodes/displayable/bases/inline_prompt_node/tests/test_inline_prompt_node.py,sha256=inTS8OyGe_62rV4S77HwhqhlTAeJgZlqieeGhdK_ecs,16030
1588
1588
  vellum/workflows/nodes/displayable/bases/prompt_deployment_node.py,sha256=T99UWACTD9ytVDVHa6W2go00V7HNwDxOyBFyMM2GnhQ,9567
1589
1589
  vellum/workflows/nodes/displayable/bases/search_node.py,sha256=3UtbqY3QO4kzfJHbmUNZGnEEfJmaoiF892u8H6TGjp8,5381
1590
1590
  vellum/workflows/nodes/displayable/bases/tests/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
@@ -1631,16 +1631,17 @@ vellum/workflows/nodes/displayable/subworkflow_deployment_node/node.py,sha256=bi
1631
1631
  vellum/workflows/nodes/displayable/subworkflow_deployment_node/tests/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
1632
1632
  vellum/workflows/nodes/displayable/subworkflow_deployment_node/tests/test_node.py,sha256=2KdPh1TeIeW_3xJq4QzAwfcuqL6PmMTLNPz4nSaDLmY,18030
1633
1633
  vellum/workflows/nodes/displayable/tests/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
1634
- vellum/workflows/nodes/displayable/tests/test_inline_text_prompt_node.py,sha256=LaxohBcKfSW2PSiBBlx67FdW_q4YC2BM2ouH-vuGPAA,4700
1634
+ vellum/workflows/nodes/displayable/tests/test_inline_text_prompt_node.py,sha256=MHuIolSsrY9ziwoXWsye3XOODncL9DLZOkNYzQMLhRw,4696
1635
1635
  vellum/workflows/nodes/displayable/tests/test_search_node_wth_text_output.py,sha256=VepO5z1277c1y5N6LLIC31nnWD1aak2m5oPFplfJHHs,6935
1636
1636
  vellum/workflows/nodes/displayable/tests/test_text_prompt_deployment_node.py,sha256=dc3EEn1sOICpr3GdS8eyeFtExaGwWWcw9eHSdkRhQJU,2584
1637
1637
  vellum/workflows/nodes/experimental/README.md,sha256=eF6DfIL8t-HbF9-mcofOMymKrraiBHDLKTlnBa51ZiE,284
1638
- vellum/workflows/nodes/experimental/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
1638
+ vellum/workflows/nodes/experimental/__init__.py,sha256=_tpZGWAZLydcKxfrj1-plrZeTajskVhUr1A6mHoSaWM,78
1639
1639
  vellum/workflows/nodes/experimental/openai_chat_completion_node/__init__.py,sha256=lsyD9laR9p7kx5-BXGH2gUTM242UhKy8SMV0SR6S2iE,90
1640
1640
  vellum/workflows/nodes/experimental/openai_chat_completion_node/node.py,sha256=cKI2Ls25L-JVt4z4a2ozQa-YBeVy21Z7BQ32Sj7iBPE,10460
1641
1641
  vellum/workflows/nodes/experimental/tool_calling_node/__init__.py,sha256=S7OzT3I4cyOU5Beoz87nPwCejCMP2FsHBFL8OcVmxJ4,118
1642
1642
  vellum/workflows/nodes/experimental/tool_calling_node/node.py,sha256=NUC7VZj2D86IDQzjCq_a3-Xeqj_b3BE8T1kOMIfN7V8,4878
1643
- vellum/workflows/nodes/experimental/tool_calling_node/utils.py,sha256=_b4xqs2jEQY9aWCCJsFvZZrvXo74NeYiIkD7uJ9RHeU,4781
1643
+ vellum/workflows/nodes/experimental/tool_calling_node/tests/test_tool_calling_node.py,sha256=sxG26mOwt4N36RLoPJ-ngginPqC5qFzD_kGj9izdCFI,1833
1644
+ vellum/workflows/nodes/experimental/tool_calling_node/utils.py,sha256=cdFR0yeb0mDl5CmH27cYQWIb4STg-ZfqtuI6rW66AHo,5097
1644
1645
  vellum/workflows/nodes/mocks.py,sha256=a1FjWEIocseMfjzM-i8DNozpUsaW0IONRpZmXBoWlyc,10455
1645
1646
  vellum/workflows/nodes/tests/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
1646
1647
  vellum/workflows/nodes/tests/test_mocks.py,sha256=mfPvrs75PKcsNsbJLQAN6PDFoVqs9TmQxpdyFKDdO60,7837
@@ -1706,8 +1707,8 @@ vellum/workflows/workflows/event_filters.py,sha256=GSxIgwrX26a1Smfd-6yss2abGCnad
1706
1707
  vellum/workflows/workflows/tests/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
1707
1708
  vellum/workflows/workflows/tests/test_base_workflow.py,sha256=8P5YIsNMO78_CR1NNK6wkEdkMB4b3Q_Ni1qxh78OnHo,20481
1708
1709
  vellum/workflows/workflows/tests/test_context.py,sha256=VJBUcyWVtMa_lE5KxdhgMu0WYNYnUQUDvTF7qm89hJ0,2333
1709
- vellum_ai-0.14.50.dist-info/LICENSE,sha256=hOypcdt481qGNISA784bnAGWAE6tyIf9gc2E78mYC3E,1574
1710
- vellum_ai-0.14.50.dist-info/METADATA,sha256=E3j3kzjmM-9HAa1xAKCgCf5JsoBVzbm7vadnxywpahY,5484
1711
- vellum_ai-0.14.50.dist-info/WHEEL,sha256=sP946D7jFCHeNz5Iq4fL4Lu-PrWrFsgfLXbbkciIZwg,88
1712
- vellum_ai-0.14.50.dist-info/entry_points.txt,sha256=HCH4yc_V3J_nDv3qJzZ_nYS8llCHZViCDP1ejgCc5Ak,42
1713
- vellum_ai-0.14.50.dist-info/RECORD,,
1710
+ vellum_ai-0.14.51.dist-info/LICENSE,sha256=hOypcdt481qGNISA784bnAGWAE6tyIf9gc2E78mYC3E,1574
1711
+ vellum_ai-0.14.51.dist-info/METADATA,sha256=ngfPkauTzHEOvea_irMQiqBgZSWEPIppPpKxA3VmlA0,5484
1712
+ vellum_ai-0.14.51.dist-info/WHEEL,sha256=sP946D7jFCHeNz5Iq4fL4Lu-PrWrFsgfLXbbkciIZwg,88
1713
+ vellum_ai-0.14.51.dist-info/entry_points.txt,sha256=HCH4yc_V3J_nDv3qJzZ_nYS8llCHZViCDP1ejgCc5Ak,42
1714
+ vellum_ai-0.14.51.dist-info/RECORD,,
@@ -133,6 +133,10 @@ class BaseNodeDisplay(Generic[NodeType], metaclass=BaseNodeDisplayMeta):
133
133
  # Used by each class extending BaseNodeDisplay to specify which attributes are meant to be serialized
134
134
  # as the former `"inputs"` field
135
135
  __serializable_inputs__: Set[NodeReference] = set()
136
+ # Used by each class extending BaseNodeDisplay to specify which attributes are meant to be opted out
137
+ # of serialization. It's possible that we keep this one as a user facing api in the future, but
138
+ # don't want to commit to that decision just yet
139
+ __unserializable_attributes__: Set[NodeReference] = set()
136
140
  # END: Attributes for backwards compatible serialization
137
141
 
138
142
  def serialize(self, display_context: "WorkflowDisplayContext", **kwargs: Any) -> JsonObject:
@@ -145,9 +149,12 @@ class BaseNodeDisplay(Generic[NodeType], metaclass=BaseNodeDisplayMeta):
145
149
  # We don't need to serialize generic node attributes containing a subworkflow
146
150
  continue
147
151
 
152
+ if attribute in self.__unserializable_attributes__:
153
+ continue
154
+
148
155
  id = (
149
156
  str(self.attribute_ids_by_name[attribute.name])
150
- if self.attribute_ids_by_name
157
+ if self.attribute_ids_by_name.get(attribute.name)
151
158
  else str(uuid4_from_hash(f"{node_id}|{attribute.name}"))
152
159
  )
153
160
  try:
@@ -19,6 +19,14 @@ _InlinePromptNodeType = TypeVar("_InlinePromptNodeType", bound=InlinePromptNode)
19
19
 
20
20
  class BaseInlinePromptNodeDisplay(BaseNodeDisplay[_InlinePromptNodeType], Generic[_InlinePromptNodeType]):
21
21
  __serializable_inputs__ = {InlinePromptNode.prompt_inputs}
22
+ __unserializable_attributes__ = {
23
+ InlinePromptNode.blocks,
24
+ InlinePromptNode.functions,
25
+ InlinePromptNode.parameters,
26
+ InlinePromptNode.settings,
27
+ InlinePromptNode.expand_meta,
28
+ InlinePromptNode.request_options,
29
+ }
22
30
 
23
31
  def serialize(
24
32
  self, display_context: WorkflowDisplayContext, error_output_id: Optional[UUID] = None, **kwargs
@@ -219,16 +227,25 @@ class BaseInlinePromptNodeDisplay(BaseNodeDisplay[_InlinePromptNodeType], Generi
219
227
  return block
220
228
 
221
229
  def _serialize_attributes(self, display_context: "WorkflowDisplayContext"):
222
- attribute_instances_by_name = {}
230
+ attributes = []
223
231
  for attribute in self._node:
224
- if attribute.name in self.attribute_ids_by_name:
225
- attribute_instances_by_name[attribute.name] = attribute.instance
226
-
227
- return [
228
- {
229
- "id": str(attr_id),
230
- "name": attr_name,
231
- "value": serialize_value(display_context, attribute_instances_by_name[attr_name]),
232
- }
233
- for attr_name, attr_id in self.attribute_ids_by_name.items()
234
- ]
232
+ if attribute in self.__unserializable_attributes__:
233
+ continue
234
+
235
+ id = (
236
+ str(self.attribute_ids_by_name[attribute.name])
237
+ if self.attribute_ids_by_name.get(attribute.name)
238
+ else str(uuid4_from_hash(f"{self.node_id}|{attribute.name}"))
239
+ )
240
+ try:
241
+ attributes.append(
242
+ {
243
+ "id": id,
244
+ "name": attribute.name,
245
+ "value": serialize_value(display_context, attribute.instance),
246
+ }
247
+ )
248
+ except ValueError as e:
249
+ raise ValueError(f"Failed to serialize attribute '{attribute.name}': {e}")
250
+
251
+ return attributes
@@ -4,6 +4,7 @@ from typing import Type
4
4
 
5
5
  from vellum.client.types.variable_prompt_block import VariablePromptBlock
6
6
  from vellum.workflows import BaseWorkflow
7
+ from vellum.workflows.inputs import BaseInputs
7
8
  from vellum.workflows.nodes import BaseNode
8
9
  from vellum.workflows.nodes.displayable.inline_prompt_node.node import InlinePromptNode
9
10
  from vellum.workflows.ports.port import Port
@@ -145,7 +146,7 @@ def test_serialize_node__prompt_inputs__state_reference():
145
146
  ml_model = "gpt-4o"
146
147
 
147
148
  # AND a workflow with the prompt node
148
- class Workflow(BaseWorkflow):
149
+ class Workflow(BaseWorkflow[BaseInputs, MyState]):
149
150
  graph = MyPromptNode
150
151
 
151
152
  # WHEN the workflow is serialized
@@ -184,6 +185,37 @@ def test_serialize_node__prompt_inputs__state_reference():
184
185
  },
185
186
  ]
186
187
 
188
+ # AND the prompt attributes should include a dictionary reference with the state reference
189
+ prompt_inputs_attribute = next(
190
+ attribute for attribute in my_prompt_node["attributes"] if attribute["name"] == "prompt_inputs"
191
+ )
192
+ assert prompt_inputs_attribute == {
193
+ "id": "3b6e1363-e41b-458e-ad28-95a61fdedac1",
194
+ "name": "prompt_inputs",
195
+ "value": {
196
+ "type": "DICTIONARY_REFERENCE",
197
+ "entries": [
198
+ {
199
+ "key": "foo",
200
+ "value": {
201
+ "type": "STATE_VALUE",
202
+ "state_variable_id": "45649791-c642-4405-aff9-a1fafd780ea1",
203
+ },
204
+ },
205
+ {
206
+ "key": "bar",
207
+ "value": {
208
+ "type": "CONSTANT_VALUE",
209
+ "value": {
210
+ "type": "STRING",
211
+ "value": "baz",
212
+ },
213
+ },
214
+ },
215
+ ],
216
+ },
217
+ }
218
+
187
219
 
188
220
  def test_serialize_node__unreferenced_variable_block__still_serializes():
189
221
  # GIVEN a prompt node with an unreferenced variable block