vellum-ai 0.14.70__py3-none-any.whl → 0.14.72__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 (34) hide show
  1. vellum/client/core/client_wrapper.py +1 -1
  2. vellum/plugins/vellum_mypy.py +1 -1
  3. vellum/workflows/environment/environment.py +5 -2
  4. vellum/workflows/events/__init__.py +2 -0
  5. vellum/workflows/events/stream.py +28 -0
  6. vellum/workflows/events/workflow.py +3 -2
  7. vellum/workflows/nodes/displayable/code_execution_node/node.py +8 -1
  8. vellum/workflows/nodes/displayable/code_execution_node/tests/test_node.py +53 -0
  9. vellum/workflows/nodes/experimental/tool_calling_node/node.py +1 -1
  10. vellum/workflows/nodes/experimental/tool_calling_node/utils.py +2 -2
  11. vellum/workflows/references/environment_variable.py +11 -8
  12. vellum/workflows/runner/runner.py +21 -3
  13. vellum/workflows/utils/functions.py +55 -1
  14. vellum/workflows/utils/tests/test_functions.py +151 -1
  15. vellum/workflows/utils/tests/test_vellum_variables.py +25 -1
  16. vellum/workflows/utils/vellum_variables.py +30 -0
  17. vellum/workflows/workflows/base.py +11 -5
  18. {vellum_ai-0.14.70.dist-info → vellum_ai-0.14.72.dist-info}/METADATA +1 -1
  19. {vellum_ai-0.14.70.dist-info → vellum_ai-0.14.72.dist-info}/RECORD +34 -31
  20. vellum_cli/image_push.py +1 -5
  21. vellum_cli/push.py +7 -0
  22. vellum_cli/tests/test_image_push.py +1 -2
  23. vellum_cli/tests/test_push.py +33 -2
  24. vellum_ee/workflows/display/nodes/utils.py +2 -2
  25. vellum_ee/workflows/display/nodes/vellum/inline_prompt_node.py +7 -3
  26. vellum_ee/workflows/display/nodes/vellum/search_node.py +69 -6
  27. vellum_ee/workflows/display/nodes/vellum/tests/test_search_node.py +104 -0
  28. vellum_ee/workflows/display/tests/workflow_serialization/test_basic_inline_prompt_node_serialization.py +82 -0
  29. vellum_ee/workflows/display/tests/workflow_serialization/test_basic_search_node_serialization.py +4 -4
  30. vellum_ee/workflows/display/tests/workflow_serialization/test_workflow_input_parameterization_error.py +37 -0
  31. vellum_ee/workflows/display/utils/expressions.py +10 -1
  32. {vellum_ai-0.14.70.dist-info → vellum_ai-0.14.72.dist-info}/LICENSE +0 -0
  33. {vellum_ai-0.14.70.dist-info → vellum_ai-0.14.72.dist-info}/WHEEL +0 -0
  34. {vellum_ai-0.14.70.dist-info → vellum_ai-0.14.72.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.70",
21
+ "X-Fern-SDK-Version": "0.14.72",
22
22
  }
23
23
  headers["X-API-KEY"] = self.api_key
24
24
  return headers
@@ -573,7 +573,7 @@ class VellumMypyPlugin(Plugin):
573
573
  alias_target = alias.target
574
574
  if (
575
575
  not isinstance(alias_target, Instance)
576
- or not _is_subclass(alias_target.type, "typing.Iterator")
576
+ or not _is_subclass(alias_target.type, "vellum.workflows.events.stream.WorkflowEventGenerator")
577
577
  or not alias_target.args
578
578
  ):
579
579
  return ctx.default_return_type
@@ -5,8 +5,11 @@ from vellum.workflows.references import EnvironmentVariableReference
5
5
 
6
6
  class EnvironmentVariables:
7
7
  @staticmethod
8
- def get(name: str, default: Optional[str] = None) -> EnvironmentVariableReference:
9
- return EnvironmentVariableReference(name=name, default=default)
8
+ def get(name: str, default: Optional[str] = None):
9
+ env_ref = EnvironmentVariableReference(name=name)
10
+ if default is not None:
11
+ return env_ref.coalesce(default)
12
+ return env_ref
10
13
 
11
14
 
12
15
  # Deprecated: Use EnvironmentVariables instead. Will be removed in v0.15.0
@@ -5,6 +5,7 @@ from .node import (
5
5
  NodeExecutionRejectedEvent,
6
6
  NodeExecutionStreamingEvent,
7
7
  )
8
+ from .stream import WorkflowEventGenerator
8
9
  from .workflow import (
9
10
  WorkflowEvent,
10
11
  WorkflowEventStream,
@@ -26,4 +27,5 @@ __all__ = [
26
27
  "WorkflowExecutionStreamingEvent",
27
28
  "WorkflowEvent",
28
29
  "WorkflowEventStream",
30
+ "WorkflowEventGenerator",
29
31
  ]
@@ -0,0 +1,28 @@
1
+ from uuid import UUID
2
+ from typing import Generator, Generic, Iterator, TypeVar
3
+
4
+ EventType = TypeVar("EventType")
5
+
6
+
7
+ class WorkflowEventGenerator(Generic[EventType]):
8
+ """
9
+ Generic wrapper for event streams that exposes span_id as a top-level property
10
+ while maintaining iterator compatibility.
11
+ """
12
+
13
+ def __init__(self, event_generator: Generator[EventType, None, None], span_id: UUID):
14
+ self._event_generator = event_generator
15
+ self._span_id = span_id
16
+
17
+ @property
18
+ def span_id(self) -> UUID:
19
+ """The span_id associated with this workflow stream."""
20
+ return self._span_id
21
+
22
+ def __iter__(self) -> Iterator[EventType]:
23
+ """Return self to make this object iterable."""
24
+ return self
25
+
26
+ def __next__(self) -> EventType:
27
+ """Get the next event from the underlying generator."""
28
+ return next(self._event_generator)
@@ -1,5 +1,5 @@
1
1
  from uuid import UUID
2
- from typing import TYPE_CHECKING, Any, Dict, Generator, Generic, Iterable, Literal, Optional, Type, Union
2
+ from typing import TYPE_CHECKING, Any, Dict, Generic, Iterable, Literal, Optional, Type, Union
3
3
  from typing_extensions import TypeGuard
4
4
 
5
5
  from pydantic import field_serializer
@@ -19,6 +19,7 @@ from .node import (
19
19
  NodeExecutionResumedEvent,
20
20
  NodeExecutionStreamingEvent,
21
21
  )
22
+ from .stream import WorkflowEventGenerator
22
23
  from .types import BaseEvent, default_serializer
23
24
 
24
25
  if TYPE_CHECKING:
@@ -193,7 +194,7 @@ WorkflowEvent = Union[
193
194
  WorkflowExecutionSnapshottedEvent,
194
195
  ]
195
196
 
196
- WorkflowEventStream = Generator[WorkflowEvent, None, None]
197
+ WorkflowEventStream = WorkflowEventGenerator[WorkflowEvent]
197
198
 
198
199
  WorkflowExecutionEvent = Union[
199
200
  WorkflowExecutionInitiatedEvent,
@@ -98,7 +98,7 @@ class CodeExecutionNode(BaseNode[StateType], Generic[StateType, _OutputType], me
98
98
  def run(self) -> Outputs:
99
99
  output_type = self.__class__.get_output_type()
100
100
  code, filepath = self._resolve_code()
101
- if not self.packages and self.runtime == "PYTHON_3_11_6":
101
+ if not self.packages and self.runtime == "PYTHON_3_11_6" and not self._has_secrets_in_code_inputs():
102
102
  logs, result = run_code_inline(code, self.code_inputs, output_type, filepath)
103
103
  return self.Outputs(result=result, log=logs)
104
104
 
@@ -133,6 +133,13 @@ class CodeExecutionNode(BaseNode[StateType], Generic[StateType, _OutputType], me
133
133
 
134
134
  return self.Outputs(result=code_execution_result.output.value, log=code_execution_result.log)
135
135
 
136
+ def _has_secrets_in_code_inputs(self) -> bool:
137
+ """Check if any code_inputs contain VellumSecret instances that require API execution."""
138
+ for input_value in self.code_inputs.values():
139
+ if isinstance(input_value, VellumSecret):
140
+ return True
141
+ return False
142
+
136
143
  def _compile_code_inputs(self) -> List[CodeExecutorInput]:
137
144
  # TODO: We may want to consolidate with prompt deployment input compilation
138
145
  # https://app.shortcut.com/vellum/story/4117
@@ -1233,3 +1233,56 @@ def main(numbers: List[str]) -> str:
1233
1233
  ],
1234
1234
  request_options=None,
1235
1235
  )
1236
+
1237
+
1238
+ def test_run_node__vellum_secret_forces_api_execution(vellum_client):
1239
+ """Test that CodeExecutionNode with VellumSecretReference forces API execution instead of inline execution."""
1240
+
1241
+ # GIVEN a node that subclasses CodeExecutionNode with VellumSecretReference but no packages
1242
+ # This should normally run inline, but the presence of secrets should force API execution
1243
+ class State(BaseState):
1244
+ pass
1245
+
1246
+ class ExampleCodeExecutionNode(CodeExecutionNode[State, str]):
1247
+ code = """
1248
+ def main(secret: str) -> str:
1249
+ return f"Secret value: {secret}"
1250
+ """
1251
+ runtime = "PYTHON_3_11_6"
1252
+ # Note: No packages specified, which would normally trigger inline execution
1253
+
1254
+ code_inputs = {
1255
+ "secret": VellumSecretReference("MY_SECRET"),
1256
+ }
1257
+
1258
+ # AND we know what the Code Execution Node will respond with
1259
+ mock_code_execution = CodeExecutorResponse(
1260
+ log="",
1261
+ output=StringVellumValue(value="Secret value: my_secret_value"),
1262
+ )
1263
+ vellum_client.execute_code.return_value = mock_code_execution
1264
+
1265
+ # WHEN we run the node
1266
+ node = ExampleCodeExecutionNode(state=State())
1267
+ outputs = node.run()
1268
+
1269
+ # THEN the node should have produced the outputs we expect
1270
+ assert outputs == {"result": "Secret value: my_secret_value", "log": ""}
1271
+
1272
+ # AND we should have invoked the Code via API (not inline) due to the secret
1273
+ vellum_client.execute_code.assert_called_once_with(
1274
+ input_values=[
1275
+ CodeExecutorSecretInput(
1276
+ name="secret",
1277
+ value="MY_SECRET",
1278
+ )
1279
+ ],
1280
+ code="""
1281
+ def main(secret: str) -> str:
1282
+ return f"Secret value: {secret}"
1283
+ """,
1284
+ runtime="PYTHON_3_11_6",
1285
+ output_type="STRING",
1286
+ packages=[],
1287
+ request_options=None,
1288
+ )
@@ -110,7 +110,7 @@ class ToolCallingNode(BaseNode):
110
110
 
111
111
  # Get configuration for this function
112
112
  config = {}
113
- if self.function_configs and function.__name__ in self.function_configs:
113
+ if callable(function) and self.function_configs and function.__name__ in self.function_configs:
114
114
  config = self.function_configs[function.__name__]
115
115
 
116
116
  packages = config.get("packages", None)
@@ -145,7 +145,7 @@ def create_function_node(
145
145
  """
146
146
  if is_workflow_class(function):
147
147
  # Create a class-level wrapper that calls the original function
148
- def execute_function(self) -> BaseNode.Outputs:
148
+ def execute_inline_workflow_function(self) -> BaseNode.Outputs:
149
149
  outputs = self.state.meta.node_outputs.get(tool_router_node.Outputs.text)
150
150
 
151
151
  outputs = json.loads(outputs)
@@ -181,7 +181,7 @@ def create_function_node(
181
181
  f"InlineWorkflowNode_{function.__name__}",
182
182
  (FunctionNode,),
183
183
  {
184
- "run": execute_function,
184
+ "run": execute_inline_workflow_function,
185
185
  "__module__": __name__,
186
186
  },
187
187
  )
@@ -1,6 +1,7 @@
1
1
  import os
2
- from typing import TYPE_CHECKING, Optional
2
+ from typing import TYPE_CHECKING, Any, Optional
3
3
 
4
+ from vellum.workflows.constants import undefined
4
5
  from vellum.workflows.descriptors.base import BaseDescriptor
5
6
 
6
7
  if TYPE_CHECKING:
@@ -8,16 +9,18 @@ if TYPE_CHECKING:
8
9
 
9
10
 
10
11
  class EnvironmentVariableReference(BaseDescriptor[str]):
11
- def __init__(self, *, name: str, default: Optional[str] = None):
12
+ def __init__(
13
+ self,
14
+ *,
15
+ name: str,
16
+ # DEPRECATED - to be removed in 0.15.0 release
17
+ default: Optional[str] = None,
18
+ ):
12
19
  super().__init__(name=name, types=(str,))
13
- self._default = default
14
20
 
15
- def resolve(self, state: "BaseState") -> str:
21
+ def resolve(self, state: "BaseState") -> Any:
16
22
  env_value = os.environ.get(self.name)
17
23
  if env_value is not None:
18
24
  return env_value
19
25
 
20
- if self._default is not None:
21
- return self._default
22
-
23
- return ""
26
+ return undefined
@@ -5,7 +5,21 @@ import logging
5
5
  from queue import Empty, Queue
6
6
  from threading import Event as ThreadingEvent, Thread
7
7
  from uuid import UUID, uuid4
8
- from typing import TYPE_CHECKING, Any, Dict, Generic, Iterable, Iterator, Optional, Sequence, Set, Tuple, Type, Union
8
+ from typing import (
9
+ TYPE_CHECKING,
10
+ Any,
11
+ Dict,
12
+ Generator,
13
+ Generic,
14
+ Iterable,
15
+ Iterator,
16
+ Optional,
17
+ Sequence,
18
+ Set,
19
+ Tuple,
20
+ Type,
21
+ Union,
22
+ )
9
23
 
10
24
  from vellum.workflows.constants import undefined
11
25
  from vellum.workflows.context import ExecutionContext, execution_context, get_execution_context
@@ -17,7 +31,7 @@ from vellum.workflows.events import (
17
31
  NodeExecutionRejectedEvent,
18
32
  NodeExecutionStreamingEvent,
19
33
  WorkflowEvent,
20
- WorkflowEventStream,
34
+ WorkflowEventGenerator,
21
35
  WorkflowExecutionFulfilledEvent,
22
36
  WorkflowExecutionInitiatedEvent,
23
37
  WorkflowExecutionRejectedEvent,
@@ -31,6 +45,7 @@ from vellum.workflows.events.node import (
31
45
  )
32
46
  from vellum.workflows.events.types import BaseEvent, NodeParentContext, ParentContext, WorkflowParentContext
33
47
  from vellum.workflows.events.workflow import (
48
+ WorkflowEventStream,
34
49
  WorkflowExecutionFulfilledBody,
35
50
  WorkflowExecutionInitiatedBody,
36
51
  WorkflowExecutionPausedBody,
@@ -730,7 +745,7 @@ class WorkflowRunner(Generic[StateType]):
730
745
  return event.workflow_definition == self.workflow.__class__
731
746
  return False
732
747
 
733
- def stream(self) -> WorkflowEventStream:
748
+ def _generate_events(self) -> Generator[WorkflowEvent, None, None]:
734
749
  background_thread = Thread(
735
750
  target=self._run_background_thread,
736
751
  name=f"{self.workflow.__class__.__name__}.background_thread",
@@ -788,3 +803,6 @@ class WorkflowRunner(Generic[StateType]):
788
803
 
789
804
  self._background_thread_queue.put(None)
790
805
  cancel_thread_kill_switch.set()
806
+
807
+ def stream(self) -> WorkflowEventStream:
808
+ return WorkflowEventGenerator(self._generate_events(), self._initial_state.meta.span_id)
@@ -1,12 +1,14 @@
1
1
  import dataclasses
2
2
  import inspect
3
- from typing import TYPE_CHECKING, Any, Callable, Optional, Type, Union, get_args, get_origin
3
+ from typing import TYPE_CHECKING, Any, Callable, Dict, Optional, Type, Union, get_args, get_origin
4
4
 
5
5
  from pydantic import BaseModel
6
6
  from pydantic_core import PydanticUndefined
7
7
  from pydash import snake_case
8
8
 
9
+ from vellum import Vellum
9
10
  from vellum.client.types.function_definition import FunctionDefinition
11
+ from vellum.workflows.utils.vellum_variables import vellum_variable_type_to_openapi_type
10
12
 
11
13
  if TYPE_CHECKING:
12
14
  from vellum.workflows.workflows.base import BaseWorkflow
@@ -86,6 +88,19 @@ def _compile_default_value(default: Any) -> Any:
86
88
  return default
87
89
 
88
90
 
91
+ def _compile_deployment_workflow_input(input_var: Any) -> dict[str, Any]:
92
+ """
93
+ Converts a deployment workflow input variable to a JSON schema type definition.
94
+ """
95
+ primitive_type = vellum_variable_type_to_openapi_type(input_var.type)
96
+ input_schema = {"type": primitive_type}
97
+
98
+ if input_var.default is not None:
99
+ input_schema["default"] = input_var.default.value
100
+
101
+ return input_schema
102
+
103
+
89
104
  def compile_function_definition(function: Callable) -> FunctionDefinition:
90
105
  """
91
106
  Converts a Python function into our Vellum-native FunctionDefinition type.
@@ -151,3 +166,42 @@ def compile_workflow_function_definition(workflow_class: Type["BaseWorkflow"]) -
151
166
  description=workflow_class.__doc__,
152
167
  parameters=parameters,
153
168
  )
169
+
170
+
171
+ def compile_deployment_workflow_function_definition(
172
+ deployment_config: Dict[str, str],
173
+ vellum_client: Vellum,
174
+ ) -> FunctionDefinition:
175
+ """
176
+ Converts a deployment workflow config into our Vellum-native FunctionDefinition type.
177
+
178
+ Args:
179
+ deployment_config: Dict with 'deployment' and 'release_tag' keys
180
+ vellum_client: Vellum client instance
181
+ """
182
+ deployment = deployment_config["deployment"]
183
+ release_tag = deployment_config["release_tag"]
184
+
185
+ workflow_deployment_release = vellum_client.release_reviews.retrieve_workflow_deployment_release(
186
+ deployment, release_tag
187
+ )
188
+
189
+ input_variables = workflow_deployment_release.workflow_version.input_variables
190
+ description = workflow_deployment_release.description
191
+
192
+ properties = {}
193
+ required = []
194
+
195
+ for input_var in input_variables:
196
+ properties[input_var.key] = _compile_deployment_workflow_input(input_var)
197
+
198
+ if input_var.required and input_var.default is None:
199
+ required.append(input_var.key)
200
+
201
+ parameters = {"type": "object", "properties": properties, "required": required}
202
+
203
+ return FunctionDefinition(
204
+ name=deployment,
205
+ description=description,
206
+ parameters=parameters,
207
+ )
@@ -1,14 +1,21 @@
1
1
  from dataclasses import dataclass
2
+ from unittest.mock import Mock
2
3
  from typing import Dict, List, Optional, Union
3
4
 
4
5
  from pydantic import BaseModel
5
6
 
6
7
  from vellum.client.types.function_definition import FunctionDefinition
8
+ from vellum.client.types.string_vellum_value import StringVellumValue
9
+ from vellum.client.types.vellum_variable import VellumVariable
7
10
  from vellum.workflows import BaseWorkflow
8
11
  from vellum.workflows.inputs.base import BaseInputs
9
12
  from vellum.workflows.nodes.bases.base import BaseNode
10
13
  from vellum.workflows.state.base import BaseState
11
- from vellum.workflows.utils.functions import compile_function_definition, compile_workflow_function_definition
14
+ from vellum.workflows.utils.functions import (
15
+ compile_deployment_workflow_function_definition,
16
+ compile_function_definition,
17
+ compile_workflow_function_definition,
18
+ )
12
19
 
13
20
 
14
21
  def test_compile_function_definition__just_name():
@@ -431,3 +438,146 @@ def test_compile_workflow_function_definition__optionals():
431
438
  "required": ["a", "b", "c"],
432
439
  },
433
440
  )
441
+
442
+
443
+ def test_compile_deployment_workflow_function_definition__just_name():
444
+ # GIVEN a mock Vellum client and deployment
445
+ mock_client = Mock()
446
+ mock_release = Mock()
447
+ mock_release.workflow_version.input_variables = []
448
+ mock_release.description = "This is a test deployment"
449
+ mock_client.release_reviews.retrieve_workflow_deployment_release.return_value = mock_release
450
+
451
+ deployment_config = {"deployment": "my_deployment", "release_tag": "latest"}
452
+
453
+ # WHEN compiling the deployment workflow function
454
+ compiled_function = compile_deployment_workflow_function_definition(deployment_config, mock_client)
455
+
456
+ # THEN it should return the compiled function definition (same structure as function test)
457
+ assert compiled_function == FunctionDefinition(
458
+ name="my_deployment",
459
+ description="This is a test deployment",
460
+ parameters={"type": "object", "properties": {}, "required": []},
461
+ )
462
+
463
+
464
+ def test_compile_deployment_workflow_function_definition__all_args():
465
+ # GIVEN a mock Vellum client and deployment
466
+ mock_client = Mock()
467
+ mock_release = Mock()
468
+
469
+ mock_inputs = []
470
+ for key, vellum_type in [
471
+ ("a", "STRING"),
472
+ ("b", "NUMBER"),
473
+ ("c", "JSON"),
474
+ ("d", "CHAT_HISTORY"),
475
+ ("e", "SEARCH_RESULTS"),
476
+ ("f", "ERROR"),
477
+ ("g", "ARRAY"),
478
+ ("h", "FUNCTION_CALL"),
479
+ ("i", "IMAGE"),
480
+ ("j", "AUDIO"),
481
+ ("k", "DOCUMENT"),
482
+ ("l", "NULL"),
483
+ ]:
484
+ mock_input = VellumVariable(
485
+ id=f"input_{key}",
486
+ key=key,
487
+ type=vellum_type,
488
+ required=True,
489
+ default=None,
490
+ )
491
+ mock_inputs.append(mock_input)
492
+
493
+ mock_release.workflow_version.input_variables = mock_inputs
494
+ mock_release.description = "This is a test deployment"
495
+ mock_client.release_reviews.retrieve_workflow_deployment_release.return_value = mock_release
496
+
497
+ deployment_config = {"deployment": "my_deployment", "release_tag": "latest"}
498
+
499
+ # WHEN compiling the deployment workflow function
500
+ compiled_function = compile_deployment_workflow_function_definition(deployment_config, mock_client)
501
+
502
+ # THEN it should return the compiled function definition
503
+ assert compiled_function == FunctionDefinition(
504
+ name="my_deployment",
505
+ description="This is a test deployment",
506
+ parameters={
507
+ "type": "object",
508
+ "properties": {
509
+ "a": {"type": "string"},
510
+ "b": {"type": "number"},
511
+ "c": {"type": "object"},
512
+ "d": {"type": "array"},
513
+ "e": {"type": "array"},
514
+ "f": {"type": "object"},
515
+ "g": {"type": "array"},
516
+ "h": {"type": "object"},
517
+ "i": {"type": "object"},
518
+ "j": {"type": "object"},
519
+ "k": {"type": "object"},
520
+ "l": {"type": "null"},
521
+ },
522
+ "required": ["a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k", "l"],
523
+ },
524
+ )
525
+
526
+
527
+ def test_compile_deployment_workflow_function_definition__defaults():
528
+ # GIVEN a mock Vellum client and deployment
529
+ mock_client = Mock()
530
+ mock_release = Mock()
531
+
532
+ mock_inputs = []
533
+
534
+ mock_input_no_default = VellumVariable(
535
+ id="no_default",
536
+ key="no_default",
537
+ type="STRING",
538
+ required=True,
539
+ default=None,
540
+ )
541
+ mock_inputs.append(mock_input_no_default)
542
+
543
+ mock_input_null_default = VellumVariable(
544
+ id="null_default",
545
+ key="null_default",
546
+ type="STRING",
547
+ required=False,
548
+ default=StringVellumValue(value=None),
549
+ )
550
+ mock_inputs.append(mock_input_null_default)
551
+
552
+ mock_input_actual_default = VellumVariable(
553
+ id="actual_default",
554
+ key="actual_default",
555
+ type="STRING",
556
+ required=False,
557
+ default=StringVellumValue(value="hello world"),
558
+ )
559
+ mock_inputs.append(mock_input_actual_default)
560
+
561
+ mock_release.workflow_version.input_variables = mock_inputs
562
+ mock_release.description = "This is a test deployment"
563
+ mock_client.release_reviews.retrieve_workflow_deployment_release.return_value = mock_release
564
+
565
+ deployment_config = {"deployment": "my_deployment", "release_tag": "latest"}
566
+
567
+ # WHEN compiling the deployment workflow function
568
+ compiled_function = compile_deployment_workflow_function_definition(deployment_config, mock_client)
569
+
570
+ # THEN it should return the compiled function definition with proper default handling
571
+ assert compiled_function == FunctionDefinition(
572
+ name="my_deployment",
573
+ description="This is a test deployment",
574
+ parameters={
575
+ "type": "object",
576
+ "properties": {
577
+ "no_default": {"type": "string"},
578
+ "null_default": {"type": "string", "default": None},
579
+ "actual_default": {"type": "string", "default": "hello world"},
580
+ },
581
+ "required": ["no_default"],
582
+ },
583
+ )
@@ -3,7 +3,10 @@ from typing import List, Optional
3
3
 
4
4
  from vellum import ChatMessage, SearchResult, VellumAudio, VellumDocument, VellumImage
5
5
  from vellum.workflows.types.core import Json
6
- from vellum.workflows.utils.vellum_variables import primitive_type_to_vellum_variable_type
6
+ from vellum.workflows.utils.vellum_variables import (
7
+ primitive_type_to_vellum_variable_type,
8
+ vellum_variable_type_to_openapi_type,
9
+ )
7
10
 
8
11
 
9
12
  @pytest.mark.parametrize(
@@ -31,3 +34,24 @@ from vellum.workflows.utils.vellum_variables import primitive_type_to_vellum_var
31
34
  )
32
35
  def test_primitive_type_to_vellum_variable_type(type_, expected):
33
36
  assert primitive_type_to_vellum_variable_type(type_) == expected
37
+
38
+
39
+ @pytest.mark.parametrize(
40
+ "vellum_type, expected",
41
+ [
42
+ ("STRING", "string"),
43
+ ("NUMBER", "number"),
44
+ ("JSON", "object"),
45
+ ("CHAT_HISTORY", "array"),
46
+ ("SEARCH_RESULTS", "array"),
47
+ ("ERROR", "object"),
48
+ ("ARRAY", "array"),
49
+ ("FUNCTION_CALL", "object"),
50
+ ("IMAGE", "object"),
51
+ ("AUDIO", "object"),
52
+ ("DOCUMENT", "object"),
53
+ ("NULL", "null"),
54
+ ],
55
+ )
56
+ def test_vellum_variable_type_to_openapi_type(vellum_type, expected):
57
+ assert vellum_variable_type_to_openapi_type(vellum_type) == expected
@@ -78,6 +78,36 @@ def primitive_type_to_vellum_variable_type(type_: Union[Type, BaseDescriptor]) -
78
78
  return "JSON"
79
79
 
80
80
 
81
+ def vellum_variable_type_to_openapi_type(vellum_type: VellumVariableType) -> str:
82
+ """Converts a VellumVariableType to a JSON schema primitive type string"""
83
+ if vellum_type == "STRING":
84
+ return "string"
85
+ elif vellum_type == "NUMBER":
86
+ return "number"
87
+ elif vellum_type == "JSON":
88
+ return "object"
89
+ elif vellum_type == "CHAT_HISTORY":
90
+ return "array"
91
+ elif vellum_type == "SEARCH_RESULTS":
92
+ return "array"
93
+ elif vellum_type == "ERROR":
94
+ return "object"
95
+ elif vellum_type == "ARRAY":
96
+ return "array"
97
+ elif vellum_type == "FUNCTION_CALL":
98
+ return "object"
99
+ elif vellum_type == "IMAGE":
100
+ return "object"
101
+ elif vellum_type == "AUDIO":
102
+ return "object"
103
+ elif vellum_type == "DOCUMENT":
104
+ return "object"
105
+ elif vellum_type == "NULL":
106
+ return "null"
107
+ else:
108
+ return "object"
109
+
110
+
81
111
  def _is_type_optionally_equal(type_: Type, target_type: Type) -> bool:
82
112
  if type_ == target_type:
83
113
  return True
@@ -42,6 +42,7 @@ from vellum.workflows.events.node import (
42
42
  NodeExecutionStreamingBody,
43
43
  NodeExecutionStreamingEvent,
44
44
  )
45
+ from vellum.workflows.events.stream import WorkflowEventGenerator
45
46
  from vellum.workflows.events.workflow import (
46
47
  GenericWorkflowEvent,
47
48
  WorkflowExecutionFulfilledBody,
@@ -167,7 +168,7 @@ class BaseWorkflow(Generic[InputsType, StateType], metaclass=_BaseWorkflowMeta):
167
168
  WorkflowExecutionPausedEvent,
168
169
  ]
169
170
 
170
- WorkflowEventStream = Generator[WorkflowEvent, None, None]
171
+ WorkflowEventStream = WorkflowEventGenerator[WorkflowEvent]
171
172
 
172
173
  def __init__(
173
174
  self,
@@ -444,7 +445,7 @@ class BaseWorkflow(Generic[InputsType, StateType], metaclass=_BaseWorkflowMeta):
444
445
  """
445
446
 
446
447
  should_yield = event_filter or workflow_event_filter
447
- for event in WorkflowRunner(
448
+ runner_stream = WorkflowRunner(
448
449
  self,
449
450
  inputs=inputs,
450
451
  state=state,
@@ -454,9 +455,14 @@ class BaseWorkflow(Generic[InputsType, StateType], metaclass=_BaseWorkflowMeta):
454
455
  node_output_mocks=node_output_mocks,
455
456
  max_concurrency=max_concurrency,
456
457
  init_execution_context=self._execution_context,
457
- ).stream():
458
- if should_yield(self.__class__, event):
459
- yield event
458
+ ).stream()
459
+
460
+ def _generate_filtered_events() -> Generator[BaseWorkflow.WorkflowEvent, None, None]:
461
+ for event in runner_stream:
462
+ if should_yield(self.__class__, event):
463
+ yield event
464
+
465
+ return WorkflowEventGenerator(_generate_filtered_events(), runner_stream.span_id)
460
466
 
461
467
  def validate(self) -> None:
462
468
  """
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: vellum-ai
3
- Version: 0.14.70
3
+ Version: 0.14.72
4
4
  Summary:
5
5
  License: MIT
6
6
  Requires-Python: >=3.9,<4.0