vellum-ai 0.14.26__py3-none-any.whl → 0.14.28__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 +4 -0
- vellum/client/__init__.py +4 -0
- vellum/client/core/client_wrapper.py +1 -1
- vellum/client/resources/__init__.py +2 -0
- vellum/client/resources/documents/client.py +0 -14
- vellum/client/resources/prompts/__init__.py +2 -0
- vellum/client/resources/prompts/client.py +197 -0
- vellum/client/types/__init__.py +2 -0
- vellum/client/types/prompt_exec_config.py +37 -0
- vellum/resources/prompts/__init__.py +3 -0
- vellum/resources/prompts/client.py +3 -0
- vellum/types/prompt_exec_config.py +3 -0
- vellum/workflows/events/tests/test_event.py +29 -1
- vellum/workflows/events/types.py +62 -3
- vellum/workflows/nodes/displayable/code_execution_node/utils.py +3 -2
- vellum/workflows/nodes/displayable/guardrail_node/node.py +10 -11
- vellum/workflows/nodes/displayable/guardrail_node/test_node.py +38 -0
- vellum/workflows/nodes/displayable/inline_prompt_node/tests/test_node.py +13 -2
- vellum/workflows/runner/runner.py +2 -0
- {vellum_ai-0.14.26.dist-info → vellum_ai-0.14.28.dist-info}/METADATA +1 -1
- {vellum_ai-0.14.26.dist-info → vellum_ai-0.14.28.dist-info}/RECORD +28 -21
- vellum_ee/workflows/display/nodes/vellum/inline_prompt_node.py +2 -1
- vellum_ee/workflows/display/nodes/vellum/tests/test_prompt_node.py +80 -1
- vellum_ee/workflows/server/virtual_file_loader.py +16 -4
- vellum_ee/workflows/tests/test_server.py +79 -0
- {vellum_ai-0.14.26.dist-info → vellum_ai-0.14.28.dist-info}/LICENSE +0 -0
- {vellum_ai-0.14.26.dist-info → vellum_ai-0.14.28.dist-info}/WHEEL +0 -0
- {vellum_ai-0.14.26.dist-info → vellum_ai-0.14.28.dist-info}/entry_points.txt +0 -0
vellum/__init__.py
CHANGED
@@ -300,6 +300,7 @@ from .types import (
|
|
300
300
|
PromptDeploymentExpandMetaRequest,
|
301
301
|
PromptDeploymentInputRequest,
|
302
302
|
PromptDeploymentParentContext,
|
303
|
+
PromptExecConfig,
|
303
304
|
PromptExecutionMeta,
|
304
305
|
PromptNodeExecutionMeta,
|
305
306
|
PromptNodeResult,
|
@@ -589,6 +590,7 @@ from .resources import (
|
|
589
590
|
metric_definitions,
|
590
591
|
ml_models,
|
591
592
|
organizations,
|
593
|
+
prompts,
|
592
594
|
sandboxes,
|
593
595
|
test_suite_runs,
|
594
596
|
test_suites,
|
@@ -910,6 +912,7 @@ __all__ = [
|
|
910
912
|
"PromptDeploymentExpandMetaRequest",
|
911
913
|
"PromptDeploymentInputRequest",
|
912
914
|
"PromptDeploymentParentContext",
|
915
|
+
"PromptExecConfig",
|
913
916
|
"PromptExecutionMeta",
|
914
917
|
"PromptNodeExecutionMeta",
|
915
918
|
"PromptNodeResult",
|
@@ -1193,6 +1196,7 @@ __all__ = [
|
|
1193
1196
|
"metric_definitions",
|
1194
1197
|
"ml_models",
|
1195
1198
|
"organizations",
|
1199
|
+
"prompts",
|
1196
1200
|
"sandboxes",
|
1197
1201
|
"test_suite_runs",
|
1198
1202
|
"test_suites",
|
vellum/client/__init__.py
CHANGED
@@ -13,6 +13,7 @@ from .resources.folder_entities.client import FolderEntitiesClient
|
|
13
13
|
from .resources.metric_definitions.client import MetricDefinitionsClient
|
14
14
|
from .resources.ml_models.client import MlModelsClient
|
15
15
|
from .resources.organizations.client import OrganizationsClient
|
16
|
+
from .resources.prompts.client import PromptsClient
|
16
17
|
from .resources.sandboxes.client import SandboxesClient
|
17
18
|
from .resources.test_suite_runs.client import TestSuiteRunsClient
|
18
19
|
from .resources.test_suites.client import TestSuitesClient
|
@@ -69,6 +70,7 @@ from .resources.folder_entities.client import AsyncFolderEntitiesClient
|
|
69
70
|
from .resources.metric_definitions.client import AsyncMetricDefinitionsClient
|
70
71
|
from .resources.ml_models.client import AsyncMlModelsClient
|
71
72
|
from .resources.organizations.client import AsyncOrganizationsClient
|
73
|
+
from .resources.prompts.client import AsyncPromptsClient
|
72
74
|
from .resources.sandboxes.client import AsyncSandboxesClient
|
73
75
|
from .resources.test_suite_runs.client import AsyncTestSuiteRunsClient
|
74
76
|
from .resources.test_suites.client import AsyncTestSuitesClient
|
@@ -145,6 +147,7 @@ class Vellum:
|
|
145
147
|
self.metric_definitions = MetricDefinitionsClient(client_wrapper=self._client_wrapper)
|
146
148
|
self.ml_models = MlModelsClient(client_wrapper=self._client_wrapper)
|
147
149
|
self.organizations = OrganizationsClient(client_wrapper=self._client_wrapper)
|
150
|
+
self.prompts = PromptsClient(client_wrapper=self._client_wrapper)
|
148
151
|
self.sandboxes = SandboxesClient(client_wrapper=self._client_wrapper)
|
149
152
|
self.test_suite_runs = TestSuiteRunsClient(client_wrapper=self._client_wrapper)
|
150
153
|
self.test_suites = TestSuitesClient(client_wrapper=self._client_wrapper)
|
@@ -1486,6 +1489,7 @@ class AsyncVellum:
|
|
1486
1489
|
self.metric_definitions = AsyncMetricDefinitionsClient(client_wrapper=self._client_wrapper)
|
1487
1490
|
self.ml_models = AsyncMlModelsClient(client_wrapper=self._client_wrapper)
|
1488
1491
|
self.organizations = AsyncOrganizationsClient(client_wrapper=self._client_wrapper)
|
1492
|
+
self.prompts = AsyncPromptsClient(client_wrapper=self._client_wrapper)
|
1489
1493
|
self.sandboxes = AsyncSandboxesClient(client_wrapper=self._client_wrapper)
|
1490
1494
|
self.test_suite_runs = AsyncTestSuiteRunsClient(client_wrapper=self._client_wrapper)
|
1491
1495
|
self.test_suites = AsyncTestSuitesClient(client_wrapper=self._client_wrapper)
|
@@ -18,7 +18,7 @@ class BaseClientWrapper:
|
|
18
18
|
headers: typing.Dict[str, str] = {
|
19
19
|
"X-Fern-Language": "Python",
|
20
20
|
"X-Fern-SDK-Name": "vellum-ai",
|
21
|
-
"X-Fern-SDK-Version": "0.14.
|
21
|
+
"X-Fern-SDK-Version": "0.14.28",
|
22
22
|
}
|
23
23
|
headers["X_API_KEY"] = self.api_key
|
24
24
|
return headers
|
@@ -10,6 +10,7 @@ from . import (
|
|
10
10
|
metric_definitions,
|
11
11
|
ml_models,
|
12
12
|
organizations,
|
13
|
+
prompts,
|
13
14
|
sandboxes,
|
14
15
|
test_suite_runs,
|
15
16
|
test_suites,
|
@@ -42,6 +43,7 @@ __all__ = [
|
|
42
43
|
"metric_definitions",
|
43
44
|
"ml_models",
|
44
45
|
"organizations",
|
46
|
+
"prompts",
|
45
47
|
"sandboxes",
|
46
48
|
"test_suite_runs",
|
47
49
|
"test_suites",
|
@@ -277,13 +277,6 @@ class DocumentsClient:
|
|
277
277
|
|
278
278
|
**Note:** Uses a base url of `https://documents.vellum.ai`.
|
279
279
|
|
280
|
-
This is a multipart/form-data request. The `contents` field should be a file upload. It also expects a JSON body with the following fields:
|
281
|
-
- `add_to_index_names: list[str]` - Optionally include the names of all indexes that you'd like this document to be included in
|
282
|
-
- `external_id: str | None` - Optionally include an external ID for this document. This is useful if you want to re-upload the same document later when its contents change and would like it to be re-indexed.
|
283
|
-
- `label: str` - A human-friendly name for this document. Typically the filename.
|
284
|
-
- `keywords: list[str] | None` - Optionally include a list of keywords that'll be associated with this document. Used when performing keyword searches.
|
285
|
-
- `metadata: dict[str, Any]` - A stringified JSON object containing any metadata associated with the document that you'd like to filter upon later.
|
286
|
-
|
287
280
|
Parameters
|
288
281
|
----------
|
289
282
|
label : str
|
@@ -673,13 +666,6 @@ class AsyncDocumentsClient:
|
|
673
666
|
|
674
667
|
**Note:** Uses a base url of `https://documents.vellum.ai`.
|
675
668
|
|
676
|
-
This is a multipart/form-data request. The `contents` field should be a file upload. It also expects a JSON body with the following fields:
|
677
|
-
- `add_to_index_names: list[str]` - Optionally include the names of all indexes that you'd like this document to be included in
|
678
|
-
- `external_id: str | None` - Optionally include an external ID for this document. This is useful if you want to re-upload the same document later when its contents change and would like it to be re-indexed.
|
679
|
-
- `label: str` - A human-friendly name for this document. Typically the filename.
|
680
|
-
- `keywords: list[str] | None` - Optionally include a list of keywords that'll be associated with this document. Used when performing keyword searches.
|
681
|
-
- `metadata: dict[str, Any]` - A stringified JSON object containing any metadata associated with the document that you'd like to filter upon later.
|
682
|
-
|
683
669
|
Parameters
|
684
670
|
----------
|
685
671
|
label : str
|
@@ -0,0 +1,197 @@
|
|
1
|
+
# This file was auto-generated by Fern from our API Definition.
|
2
|
+
|
3
|
+
from ...core.client_wrapper import SyncClientWrapper
|
4
|
+
import typing
|
5
|
+
from ...core.request_options import RequestOptions
|
6
|
+
from ...types.prompt_exec_config import PromptExecConfig
|
7
|
+
from ...core.jsonable_encoder import jsonable_encoder
|
8
|
+
from ...core.pydantic_utilities import parse_obj_as
|
9
|
+
from ...errors.bad_request_error import BadRequestError
|
10
|
+
from ...errors.not_found_error import NotFoundError
|
11
|
+
from json.decoder import JSONDecodeError
|
12
|
+
from ...core.api_error import ApiError
|
13
|
+
from ...core.client_wrapper import AsyncClientWrapper
|
14
|
+
|
15
|
+
|
16
|
+
class PromptsClient:
|
17
|
+
def __init__(self, *, client_wrapper: SyncClientWrapper):
|
18
|
+
self._client_wrapper = client_wrapper
|
19
|
+
|
20
|
+
def pull(
|
21
|
+
self,
|
22
|
+
id: str,
|
23
|
+
*,
|
24
|
+
prompt_variant_id: typing.Optional[str] = None,
|
25
|
+
request_options: typing.Optional[RequestOptions] = None,
|
26
|
+
) -> PromptExecConfig:
|
27
|
+
"""
|
28
|
+
Used to pull the definition of a Prompt from Vellum.
|
29
|
+
|
30
|
+
Parameters
|
31
|
+
----------
|
32
|
+
id : str
|
33
|
+
The ID of the Prompt to pull from. Prompt Sandbox IDs are currently supported.
|
34
|
+
|
35
|
+
prompt_variant_id : typing.Optional[str]
|
36
|
+
The ID of the Prompt Variant within a Prompt Sandbox to pull. Must be included if providing the ID of a Prompt Sandbox.
|
37
|
+
|
38
|
+
request_options : typing.Optional[RequestOptions]
|
39
|
+
Request-specific configuration.
|
40
|
+
|
41
|
+
Returns
|
42
|
+
-------
|
43
|
+
PromptExecConfig
|
44
|
+
|
45
|
+
|
46
|
+
Examples
|
47
|
+
--------
|
48
|
+
from vellum import Vellum
|
49
|
+
|
50
|
+
client = Vellum(
|
51
|
+
api_key="YOUR_API_KEY",
|
52
|
+
)
|
53
|
+
client.prompts.pull(
|
54
|
+
id="id",
|
55
|
+
)
|
56
|
+
"""
|
57
|
+
_response = self._client_wrapper.httpx_client.request(
|
58
|
+
f"v1/prompts/{jsonable_encoder(id)}/pull",
|
59
|
+
base_url=self._client_wrapper.get_environment().default,
|
60
|
+
method="GET",
|
61
|
+
params={
|
62
|
+
"prompt_variant_id": prompt_variant_id,
|
63
|
+
},
|
64
|
+
headers={
|
65
|
+
"Accept": "application/json",
|
66
|
+
},
|
67
|
+
request_options=request_options,
|
68
|
+
)
|
69
|
+
try:
|
70
|
+
if 200 <= _response.status_code < 300:
|
71
|
+
return typing.cast(
|
72
|
+
PromptExecConfig,
|
73
|
+
parse_obj_as(
|
74
|
+
type_=PromptExecConfig, # type: ignore
|
75
|
+
object_=_response.json(),
|
76
|
+
),
|
77
|
+
)
|
78
|
+
if _response.status_code == 400:
|
79
|
+
raise BadRequestError(
|
80
|
+
typing.cast(
|
81
|
+
typing.Optional[typing.Any],
|
82
|
+
parse_obj_as(
|
83
|
+
type_=typing.Optional[typing.Any], # type: ignore
|
84
|
+
object_=_response.json(),
|
85
|
+
),
|
86
|
+
)
|
87
|
+
)
|
88
|
+
if _response.status_code == 404:
|
89
|
+
raise NotFoundError(
|
90
|
+
typing.cast(
|
91
|
+
typing.Optional[typing.Any],
|
92
|
+
parse_obj_as(
|
93
|
+
type_=typing.Optional[typing.Any], # type: ignore
|
94
|
+
object_=_response.json(),
|
95
|
+
),
|
96
|
+
)
|
97
|
+
)
|
98
|
+
_response_json = _response.json()
|
99
|
+
except JSONDecodeError:
|
100
|
+
raise ApiError(status_code=_response.status_code, body=_response.text)
|
101
|
+
raise ApiError(status_code=_response.status_code, body=_response_json)
|
102
|
+
|
103
|
+
|
104
|
+
class AsyncPromptsClient:
|
105
|
+
def __init__(self, *, client_wrapper: AsyncClientWrapper):
|
106
|
+
self._client_wrapper = client_wrapper
|
107
|
+
|
108
|
+
async def pull(
|
109
|
+
self,
|
110
|
+
id: str,
|
111
|
+
*,
|
112
|
+
prompt_variant_id: typing.Optional[str] = None,
|
113
|
+
request_options: typing.Optional[RequestOptions] = None,
|
114
|
+
) -> PromptExecConfig:
|
115
|
+
"""
|
116
|
+
Used to pull the definition of a Prompt from Vellum.
|
117
|
+
|
118
|
+
Parameters
|
119
|
+
----------
|
120
|
+
id : str
|
121
|
+
The ID of the Prompt to pull from. Prompt Sandbox IDs are currently supported.
|
122
|
+
|
123
|
+
prompt_variant_id : typing.Optional[str]
|
124
|
+
The ID of the Prompt Variant within a Prompt Sandbox to pull. Must be included if providing the ID of a Prompt Sandbox.
|
125
|
+
|
126
|
+
request_options : typing.Optional[RequestOptions]
|
127
|
+
Request-specific configuration.
|
128
|
+
|
129
|
+
Returns
|
130
|
+
-------
|
131
|
+
PromptExecConfig
|
132
|
+
|
133
|
+
|
134
|
+
Examples
|
135
|
+
--------
|
136
|
+
import asyncio
|
137
|
+
|
138
|
+
from vellum import AsyncVellum
|
139
|
+
|
140
|
+
client = AsyncVellum(
|
141
|
+
api_key="YOUR_API_KEY",
|
142
|
+
)
|
143
|
+
|
144
|
+
|
145
|
+
async def main() -> None:
|
146
|
+
await client.prompts.pull(
|
147
|
+
id="id",
|
148
|
+
)
|
149
|
+
|
150
|
+
|
151
|
+
asyncio.run(main())
|
152
|
+
"""
|
153
|
+
_response = await self._client_wrapper.httpx_client.request(
|
154
|
+
f"v1/prompts/{jsonable_encoder(id)}/pull",
|
155
|
+
base_url=self._client_wrapper.get_environment().default,
|
156
|
+
method="GET",
|
157
|
+
params={
|
158
|
+
"prompt_variant_id": prompt_variant_id,
|
159
|
+
},
|
160
|
+
headers={
|
161
|
+
"Accept": "application/json",
|
162
|
+
},
|
163
|
+
request_options=request_options,
|
164
|
+
)
|
165
|
+
try:
|
166
|
+
if 200 <= _response.status_code < 300:
|
167
|
+
return typing.cast(
|
168
|
+
PromptExecConfig,
|
169
|
+
parse_obj_as(
|
170
|
+
type_=PromptExecConfig, # type: ignore
|
171
|
+
object_=_response.json(),
|
172
|
+
),
|
173
|
+
)
|
174
|
+
if _response.status_code == 400:
|
175
|
+
raise BadRequestError(
|
176
|
+
typing.cast(
|
177
|
+
typing.Optional[typing.Any],
|
178
|
+
parse_obj_as(
|
179
|
+
type_=typing.Optional[typing.Any], # type: ignore
|
180
|
+
object_=_response.json(),
|
181
|
+
),
|
182
|
+
)
|
183
|
+
)
|
184
|
+
if _response.status_code == 404:
|
185
|
+
raise NotFoundError(
|
186
|
+
typing.cast(
|
187
|
+
typing.Optional[typing.Any],
|
188
|
+
parse_obj_as(
|
189
|
+
type_=typing.Optional[typing.Any], # type: ignore
|
190
|
+
object_=_response.json(),
|
191
|
+
),
|
192
|
+
)
|
193
|
+
)
|
194
|
+
_response_json = _response.json()
|
195
|
+
except JSONDecodeError:
|
196
|
+
raise ApiError(status_code=_response.status_code, body=_response.text)
|
197
|
+
raise ApiError(status_code=_response.status_code, body=_response_json)
|
vellum/client/types/__init__.py
CHANGED
@@ -308,6 +308,7 @@ from .prompt_block_state import PromptBlockState
|
|
308
308
|
from .prompt_deployment_expand_meta_request import PromptDeploymentExpandMetaRequest
|
309
309
|
from .prompt_deployment_input_request import PromptDeploymentInputRequest
|
310
310
|
from .prompt_deployment_parent_context import PromptDeploymentParentContext
|
311
|
+
from .prompt_exec_config import PromptExecConfig
|
311
312
|
from .prompt_execution_meta import PromptExecutionMeta
|
312
313
|
from .prompt_node_execution_meta import PromptNodeExecutionMeta
|
313
314
|
from .prompt_node_result import PromptNodeResult
|
@@ -892,6 +893,7 @@ __all__ = [
|
|
892
893
|
"PromptDeploymentExpandMetaRequest",
|
893
894
|
"PromptDeploymentInputRequest",
|
894
895
|
"PromptDeploymentParentContext",
|
896
|
+
"PromptExecConfig",
|
895
897
|
"PromptExecutionMeta",
|
896
898
|
"PromptNodeExecutionMeta",
|
897
899
|
"PromptNodeResult",
|
@@ -0,0 +1,37 @@
|
|
1
|
+
# This file was auto-generated by Fern from our API Definition.
|
2
|
+
|
3
|
+
from __future__ import annotations
|
4
|
+
from ..core.pydantic_utilities import UniversalBaseModel
|
5
|
+
from .array_vellum_value import ArrayVellumValue
|
6
|
+
from .chat_message_prompt_block import ChatMessagePromptBlock
|
7
|
+
import typing
|
8
|
+
from .vellum_variable import VellumVariable
|
9
|
+
from .prompt_parameters import PromptParameters
|
10
|
+
from .prompt_settings import PromptSettings
|
11
|
+
from .prompt_block import PromptBlock
|
12
|
+
from .function_definition import FunctionDefinition
|
13
|
+
from ..core.pydantic_utilities import IS_PYDANTIC_V2
|
14
|
+
import pydantic
|
15
|
+
from ..core.pydantic_utilities import update_forward_refs
|
16
|
+
|
17
|
+
|
18
|
+
class PromptExecConfig(UniversalBaseModel):
|
19
|
+
ml_model: str
|
20
|
+
input_variables: typing.List[VellumVariable]
|
21
|
+
parameters: PromptParameters
|
22
|
+
settings: typing.Optional[PromptSettings] = None
|
23
|
+
blocks: typing.List[PromptBlock]
|
24
|
+
functions: typing.Optional[typing.List[FunctionDefinition]] = None
|
25
|
+
|
26
|
+
if IS_PYDANTIC_V2:
|
27
|
+
model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict(extra="allow", frozen=True) # type: ignore # Pydantic v2
|
28
|
+
else:
|
29
|
+
|
30
|
+
class Config:
|
31
|
+
frozen = True
|
32
|
+
smart_union = True
|
33
|
+
extra = pydantic.Extra.allow
|
34
|
+
|
35
|
+
|
36
|
+
update_forward_refs(ArrayVellumValue, PromptExecConfig=PromptExecConfig)
|
37
|
+
update_forward_refs(ChatMessagePromptBlock, PromptExecConfig=PromptExecConfig)
|
@@ -4,6 +4,7 @@ from uuid import UUID
|
|
4
4
|
|
5
5
|
from deepdiff import DeepDiff
|
6
6
|
|
7
|
+
from vellum.client.core.pydantic_utilities import UniversalBaseModel
|
7
8
|
from vellum.workflows.constants import undefined
|
8
9
|
from vellum.workflows.errors.types import WorkflowError, WorkflowErrorCode
|
9
10
|
from vellum.workflows.events.node import (
|
@@ -14,7 +15,7 @@ from vellum.workflows.events.node import (
|
|
14
15
|
NodeExecutionStreamingBody,
|
15
16
|
NodeExecutionStreamingEvent,
|
16
17
|
)
|
17
|
-
from vellum.workflows.events.types import NodeParentContext, WorkflowParentContext
|
18
|
+
from vellum.workflows.events.types import NodeParentContext, ParentContext, WorkflowParentContext
|
18
19
|
from vellum.workflows.events.workflow import (
|
19
20
|
WorkflowExecutionFulfilledBody,
|
20
21
|
WorkflowExecutionFulfilledEvent,
|
@@ -419,3 +420,30 @@ mock_node_uuid = str(uuid4_from_hash(MockNode.__qualname__))
|
|
419
420
|
)
|
420
421
|
def test_event_serialization(event, expected_json):
|
421
422
|
assert not DeepDiff(event.model_dump(mode="json"), expected_json)
|
423
|
+
|
424
|
+
|
425
|
+
def test_parent_context__deserialize_from_json__invalid_parent_context():
|
426
|
+
# GIVEN an event with a parent context that Vellum is introducing in the future
|
427
|
+
data = {
|
428
|
+
"foo": "bar",
|
429
|
+
"parent": {
|
430
|
+
"type": "SOME_FUTURE_ENTITY",
|
431
|
+
"span_id": "123e4567-e89b-12d3-a456-426614174000",
|
432
|
+
"some_randome_field": "some_random_value",
|
433
|
+
"parent": None,
|
434
|
+
},
|
435
|
+
}
|
436
|
+
|
437
|
+
# AND a dataclass that references the parent context
|
438
|
+
class MyData(UniversalBaseModel):
|
439
|
+
foo: str
|
440
|
+
parent: ParentContext
|
441
|
+
|
442
|
+
# WHEN the data is deserialized
|
443
|
+
event = MyData.model_validate(data)
|
444
|
+
|
445
|
+
# THEN the event is deserialized correctly
|
446
|
+
assert event.parent
|
447
|
+
assert event.parent.type == "UNKNOWN"
|
448
|
+
assert event.parent.span_id == UUID("123e4567-e89b-12d3-a456-426614174000")
|
449
|
+
assert event.parent.parent is None
|
vellum/workflows/events/types.py
CHANGED
@@ -1,9 +1,10 @@
|
|
1
1
|
from datetime import datetime
|
2
2
|
import json
|
3
3
|
from uuid import UUID, uuid4
|
4
|
-
from typing import Annotated, Any, Dict, List, Literal, Optional, Union
|
4
|
+
from typing import Annotated, Any, Dict, List, Literal, Optional, Union, get_args
|
5
5
|
|
6
|
-
from pydantic import BeforeValidator, Field
|
6
|
+
from pydantic import BeforeValidator, Field, GetCoreSchemaHandler, Tag, ValidationInfo
|
7
|
+
from pydantic_core import CoreSchema, core_schema
|
7
8
|
|
8
9
|
from vellum.core.pydantic_utilities import UniversalBaseModel
|
9
10
|
from vellum.workflows.state.encoder import DefaultStateEncoder
|
@@ -112,6 +113,59 @@ class APIRequestParentContext(BaseParentContext):
|
|
112
113
|
type: Literal["API_REQUEST"] = "API_REQUEST"
|
113
114
|
|
114
115
|
|
116
|
+
class UnknownParentContext(BaseParentContext):
|
117
|
+
type: Literal["UNKNOWN"] = "UNKNOWN"
|
118
|
+
|
119
|
+
|
120
|
+
def _cast_parent_context_discriminator(v: Any) -> Any:
|
121
|
+
if v in PARENT_CONTEXT_TYPES:
|
122
|
+
return v
|
123
|
+
|
124
|
+
return "UNKNOWN"
|
125
|
+
|
126
|
+
|
127
|
+
def _get_parent_context_discriminator(v: Any) -> Any:
|
128
|
+
if isinstance(v, dict) and "type" in v:
|
129
|
+
return _cast_parent_context_discriminator(v["type"])
|
130
|
+
|
131
|
+
if isinstance(v, PARENT_CONTEXT_CHOICES):
|
132
|
+
return v.type
|
133
|
+
|
134
|
+
return _cast_parent_context_discriminator(v)
|
135
|
+
|
136
|
+
|
137
|
+
def _tag_parent_context_discriminator(v: Any) -> Any:
|
138
|
+
return Tag(_get_parent_context_discriminator(v))
|
139
|
+
|
140
|
+
|
141
|
+
def _validate_parent_context_discriminator(v: Any, info: ValidationInfo) -> Any:
|
142
|
+
if isinstance(v, str):
|
143
|
+
return _get_parent_context_discriminator(v)
|
144
|
+
|
145
|
+
if isinstance(v, dict) and "type" in v:
|
146
|
+
v["type"] = _get_parent_context_discriminator(v["type"])
|
147
|
+
|
148
|
+
return v
|
149
|
+
|
150
|
+
|
151
|
+
class ParentContextDiscriminator:
|
152
|
+
def __get_pydantic_core_schema__(self, source_type: Any, handler: GetCoreSchemaHandler) -> CoreSchema:
|
153
|
+
original_schema = handler(source_type)
|
154
|
+
tagged_union_choices = {}
|
155
|
+
for index, choice in enumerate(original_schema["choices"]):
|
156
|
+
tagged_union_choices[Tag(PARENT_CONTEXT_TYPES[index])] = choice
|
157
|
+
|
158
|
+
tagged_union_schema = core_schema.tagged_union_schema(
|
159
|
+
tagged_union_choices,
|
160
|
+
_tag_parent_context_discriminator,
|
161
|
+
)
|
162
|
+
return core_schema.with_info_before_validator_function(
|
163
|
+
function=_validate_parent_context_discriminator,
|
164
|
+
schema=tagged_union_schema,
|
165
|
+
field_name="type",
|
166
|
+
)
|
167
|
+
|
168
|
+
|
115
169
|
# Define the discriminated union
|
116
170
|
ParentContext = Annotated[
|
117
171
|
Union[
|
@@ -121,8 +175,13 @@ ParentContext = Annotated[
|
|
121
175
|
PromptDeploymentParentContext,
|
122
176
|
WorkflowSandboxParentContext,
|
123
177
|
APIRequestParentContext,
|
178
|
+
UnknownParentContext,
|
124
179
|
],
|
125
|
-
|
180
|
+
ParentContextDiscriminator(),
|
181
|
+
]
|
182
|
+
PARENT_CONTEXT_CHOICES = get_args(get_args(ParentContext)[0])
|
183
|
+
PARENT_CONTEXT_TYPES = [
|
184
|
+
pc.model_fields["type"].default for pc in PARENT_CONTEXT_CHOICES if issubclass(pc, UniversalBaseModel)
|
126
185
|
]
|
127
186
|
|
128
187
|
# Update the forward references
|
@@ -14,10 +14,11 @@ def read_file_from_path(node_filepath: str, script_filepath: str) -> Union[str,
|
|
14
14
|
node_filepath_dir = os.path.dirname(node_filepath)
|
15
15
|
full_filepath = os.path.join(node_filepath_dir, script_filepath)
|
16
16
|
|
17
|
-
|
17
|
+
try:
|
18
18
|
with open(full_filepath) as file:
|
19
19
|
return file.read()
|
20
|
-
|
20
|
+
except (FileNotFoundError, IsADirectoryError):
|
21
|
+
return None
|
21
22
|
|
22
23
|
|
23
24
|
class ListWrapper(list):
|
@@ -52,19 +52,18 @@ class GuardrailNode(BaseNode[StateType], Generic[StateType]):
|
|
52
52
|
message="Metric execution must have one output named 'score' with type 'float'",
|
53
53
|
code=WorkflowErrorCode.INVALID_OUTPUTS,
|
54
54
|
)
|
55
|
-
|
56
|
-
log = metric_outputs.get("log")
|
57
|
-
|
58
|
-
if log is not None and not isinstance(log, str):
|
59
|
-
raise NodeException(
|
60
|
-
message="Metric execution log output must be of type 'str'",
|
61
|
-
code=WorkflowErrorCode.INVALID_OUTPUTS,
|
62
|
-
)
|
63
|
-
if log:
|
64
|
-
metric_outputs.pop("log")
|
65
|
-
|
66
55
|
metric_outputs.pop("score")
|
67
56
|
|
57
|
+
if "log" in metric_outputs:
|
58
|
+
log = metric_outputs.pop("log") or ""
|
59
|
+
if not isinstance(log, str):
|
60
|
+
raise NodeException(
|
61
|
+
message="Metric execution log output must be of type 'str'",
|
62
|
+
code=WorkflowErrorCode.INVALID_OUTPUTS,
|
63
|
+
)
|
64
|
+
else:
|
65
|
+
log = None
|
66
|
+
|
68
67
|
return self.Outputs(score=score, log=log, **metric_outputs)
|
69
68
|
|
70
69
|
def _compile_metric_inputs(self) -> List[MetricDefinitionInput]:
|
@@ -0,0 +1,38 @@
|
|
1
|
+
import pytest
|
2
|
+
|
3
|
+
from vellum import TestSuiteRunMetricNumberOutput
|
4
|
+
from vellum.client.types.metric_definition_execution import MetricDefinitionExecution
|
5
|
+
from vellum.client.types.test_suite_run_metric_string_output import TestSuiteRunMetricStringOutput
|
6
|
+
from vellum.workflows.nodes.displayable.guardrail_node.node import GuardrailNode
|
7
|
+
|
8
|
+
|
9
|
+
@pytest.mark.parametrize("log_value", [None, ""], ids=["None", "Empty"])
|
10
|
+
def test_run_guardrail_node__empty_log(vellum_client, log_value):
|
11
|
+
"""Confirm that we can successfully invoke a Guardrail Node"""
|
12
|
+
|
13
|
+
# GIVEN a Guardrail Node
|
14
|
+
class MyGuard(GuardrailNode):
|
15
|
+
metric_definition = "example_metric_definition"
|
16
|
+
metric_inputs = {}
|
17
|
+
|
18
|
+
# AND we know that the guardrail node will return a blank log
|
19
|
+
mock_metric_execution = MetricDefinitionExecution(
|
20
|
+
outputs=[
|
21
|
+
TestSuiteRunMetricNumberOutput(
|
22
|
+
name="score",
|
23
|
+
value=0.6,
|
24
|
+
),
|
25
|
+
TestSuiteRunMetricStringOutput(
|
26
|
+
name="log",
|
27
|
+
value=log_value,
|
28
|
+
),
|
29
|
+
],
|
30
|
+
)
|
31
|
+
vellum_client.metric_definitions.execute_metric_definition.return_value = mock_metric_execution
|
32
|
+
|
33
|
+
# WHEN we run the Guardrail Node
|
34
|
+
outputs = MyGuard().run()
|
35
|
+
|
36
|
+
# THEN the workflow should have completed successfully
|
37
|
+
assert outputs.score == 0.6
|
38
|
+
assert outputs.log == ""
|
@@ -9,6 +9,7 @@ from httpx import Response
|
|
9
9
|
from vellum.client.core.api_error import ApiError
|
10
10
|
from vellum.client.core.pydantic_utilities import UniversalBaseModel
|
11
11
|
from vellum.client.types.chat_message import ChatMessage
|
12
|
+
from vellum.client.types.chat_message_prompt_block import ChatMessagePromptBlock
|
12
13
|
from vellum.client.types.chat_message_request import ChatMessageRequest
|
13
14
|
from vellum.client.types.execute_prompt_event import ExecutePromptEvent
|
14
15
|
from vellum.client.types.fulfilled_execute_prompt_event import FulfilledExecutePromptEvent
|
@@ -241,7 +242,7 @@ def test_inline_prompt_node__parent_context(mock_httpx_transport, mock_complex_p
|
|
241
242
|
# GIVEN a prompt node
|
242
243
|
class MyNode(InlinePromptNode):
|
243
244
|
ml_model = "gpt-4o"
|
244
|
-
blocks = []
|
245
|
+
blocks = [ChatMessagePromptBlock(chat_role="USER", blocks=[])]
|
245
246
|
prompt_inputs = {}
|
246
247
|
|
247
248
|
# AND a known response from the httpx client
|
@@ -276,6 +277,16 @@ def test_inline_prompt_node__parent_context(mock_httpx_transport, mock_complex_p
|
|
276
277
|
|
277
278
|
# AND the prompt is executed with the correct execution context
|
278
279
|
call_request_args = mock_httpx_transport.handle_request.call_args_list[0][0][0]
|
279
|
-
|
280
|
+
call_request = json.loads(call_request_args.read().decode("utf-8"))
|
281
|
+
request_execution_context = call_request["execution_context"]
|
280
282
|
assert request_execution_context["trace_id"] == str(trace_id)
|
281
283
|
assert request_execution_context["parent_context"]
|
284
|
+
|
285
|
+
# AND the blocks are serialized as expected
|
286
|
+
assert call_request["blocks"] == [
|
287
|
+
{
|
288
|
+
"block_type": "CHAT_MESSAGE",
|
289
|
+
"chat_role": "USER",
|
290
|
+
"blocks": [],
|
291
|
+
}
|
292
|
+
]
|
@@ -321,6 +321,7 @@ class WorkflowRunner(Generic[StateType]):
|
|
321
321
|
)
|
322
322
|
)
|
323
323
|
except NodeException as e:
|
324
|
+
logger.info(e)
|
324
325
|
self._workflow_event_inner_queue.put(
|
325
326
|
NodeExecutionRejectedEvent(
|
326
327
|
trace_id=node.state.meta.trace_id,
|
@@ -333,6 +334,7 @@ class WorkflowRunner(Generic[StateType]):
|
|
333
334
|
)
|
334
335
|
)
|
335
336
|
except WorkflowInitializationException as e:
|
337
|
+
logger.info(e)
|
336
338
|
self._workflow_event_inner_queue.put(
|
337
339
|
NodeExecutionRejectedEvent(
|
338
340
|
trace_id=node.state.meta.trace_id,
|
@@ -41,7 +41,7 @@ vellum_ee/workflows/display/nodes/vellum/conditional_node.py,sha256=ybLIa4uclqVI
|
|
41
41
|
vellum_ee/workflows/display/nodes/vellum/error_node.py,sha256=I1Jkp2htRINJATtv1e-zs9BrReFX842djpiVgBPHDYg,2186
|
42
42
|
vellum_ee/workflows/display/nodes/vellum/final_output_node.py,sha256=BJ--Y-LCbGFJve3OFEKHVxrw8TKvgb342opYLJibToc,3128
|
43
43
|
vellum_ee/workflows/display/nodes/vellum/guardrail_node.py,sha256=aYZSJTxknU4LMiQdWk9LcK6CkhdozeDEMiRxfAyUNEc,2202
|
44
|
-
vellum_ee/workflows/display/nodes/vellum/inline_prompt_node.py,sha256=
|
44
|
+
vellum_ee/workflows/display/nodes/vellum/inline_prompt_node.py,sha256=86hkneLIBS4Jel3GWsPVIIFqXGD3RHIpXw0iGa_Zues,8843
|
45
45
|
vellum_ee/workflows/display/nodes/vellum/inline_subworkflow_node.py,sha256=MU9I8CB1X1TgL1aa1eT6DHWwNJ-2v79t74xl0oy-fBo,5510
|
46
46
|
vellum_ee/workflows/display/nodes/vellum/map_node.py,sha256=8CPnn06HIBxBOiECevUffeVmQmCpec6WtPQnNl9gj9Y,3748
|
47
47
|
vellum_ee/workflows/display/nodes/vellum/merge_node.py,sha256=xtyecs9mJ_WEwVpP12jxYwvehLXynhqLrPJ-Ahdk2GA,3232
|
@@ -54,7 +54,7 @@ vellum_ee/workflows/display/nodes/vellum/templating_node.py,sha256=5EWzdA3TSUPlb
|
|
54
54
|
vellum_ee/workflows/display/nodes/vellum/tests/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
55
55
|
vellum_ee/workflows/display/nodes/vellum/tests/test_code_execution_node.py,sha256=p0fCvbKzpGvVrg67QmJd14m9E8_DG0u5s6SYIhzlkNA,4018
|
56
56
|
vellum_ee/workflows/display/nodes/vellum/tests/test_error_node.py,sha256=ulrpoYUW-5kIxfG4Lf5F2p0k_EoYKhmahEbF3P_eruM,1648
|
57
|
-
vellum_ee/workflows/display/nodes/vellum/tests/test_prompt_node.py,sha256=
|
57
|
+
vellum_ee/workflows/display/nodes/vellum/tests/test_prompt_node.py,sha256=fu9nxD4FInSfKbipJJ7UE617VkeUWs_uS6SeEz_8-Iw,4691
|
58
58
|
vellum_ee/workflows/display/nodes/vellum/tests/test_retry_node.py,sha256=NuIw8Yb42KUdoGi3Ur8_7VPg50IC4hNrwAkCociwqNk,2091
|
59
59
|
vellum_ee/workflows/display/nodes/vellum/tests/test_templating_node.py,sha256=Us32jf_FQnLuT4Bs2o5JyHxihCTAN8ozZghWIR0pl9k,3459
|
60
60
|
vellum_ee/workflows/display/nodes/vellum/tests/test_try_node.py,sha256=mtzB8LJlFCHVFM4H5AanLp29gQfaVmnN4A4iaRGJHoI,2427
|
@@ -100,7 +100,7 @@ vellum_ee/workflows/display/workflows/get_vellum_workflow_display_class.py,sha25
|
|
100
100
|
vellum_ee/workflows/display/workflows/tests/test_workflow_display.py,sha256=nD6_lZnNp56siVJwhlWzSEHdMaSKjvWlsJa31SqfQAE,10623
|
101
101
|
vellum_ee/workflows/display/workflows/vellum_workflow_display.py,sha256=AzGZ7ApiwXAHuymTJoXJketUegyC1dmB1blzoni5eh8,13423
|
102
102
|
vellum_ee/workflows/server/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
103
|
-
vellum_ee/workflows/server/virtual_file_loader.py,sha256=
|
103
|
+
vellum_ee/workflows/server/virtual_file_loader.py,sha256=7JphJcSO3H85qiC2DpFfBWjC3JjrbRmoynBC6KKHVsA,2710
|
104
104
|
vellum_ee/workflows/tests/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
105
105
|
vellum_ee/workflows/tests/local_files/__init__.py,sha256=UyP6kKkRqr9cTKHQF4MVLdLk5MM9GGcLuqxXsQGm22Y,51
|
106
106
|
vellum_ee/workflows/tests/local_files/base_class.py,sha256=UuiC7J68MVr6A4949QYiBpXOLdsvFG_Cw1muEPiHT6I,298
|
@@ -121,14 +121,14 @@ vellum_ee/workflows/tests/local_workflow/nodes/final_output.py,sha256=ZX7zBv87zi
|
|
121
121
|
vellum_ee/workflows/tests/local_workflow/nodes/templating_node.py,sha256=NQwFN61QkHfI3Vssz-B0NKGfupK8PU0FDSAIAhYBLi0,325
|
122
122
|
vellum_ee/workflows/tests/local_workflow/workflow.py,sha256=A4qOzOPNwePYxWbcAgIPLsmrVS_aVEZEc-wULSv787Q,393
|
123
123
|
vellum_ee/workflows/tests/test_display_meta.py,sha256=C25dErwghPNXio49pvSRxyOuc96srH6eYEwTAWdE2zY,2258
|
124
|
-
vellum_ee/workflows/tests/test_server.py,sha256=
|
124
|
+
vellum_ee/workflows/tests/test_server.py,sha256=Ll4o9gg0Q4r8uX6Kt8LWgIz0u2zLwPiZxl3TuqoZpxg,4707
|
125
125
|
vellum_ee/workflows/tests/test_virtual_files.py,sha256=TJEcMR0v2S8CkloXNmCHA0QW0K6pYNGaIjraJz7sFvY,2762
|
126
|
-
vellum/__init__.py,sha256=
|
126
|
+
vellum/__init__.py,sha256=88-79I29hBTQvR1uH_BOCGMWuj2a4Nx82R_8KIESg28,40470
|
127
127
|
vellum/client/README.md,sha256=JkCJjmMZl4jrPj46pkmL9dpK4gSzQQmP5I7z4aME4LY,4749
|
128
|
-
vellum/client/__init__.py,sha256=
|
128
|
+
vellum/client/__init__.py,sha256=Jv9sI5BNFo2OYA9px_aREFSIp655ryC3eaZSRI6yH1k,117826
|
129
129
|
vellum/client/core/__init__.py,sha256=SQ85PF84B9MuKnBwHNHWemSGuy-g_515gFYNFhvEE0I,1438
|
130
130
|
vellum/client/core/api_error.py,sha256=RE8LELok2QCjABadECTvtDp7qejA1VmINCh6TbqPwSE,426
|
131
|
-
vellum/client/core/client_wrapper.py,sha256=
|
131
|
+
vellum/client/core/client_wrapper.py,sha256=UH9Mq4cJvem6l6xfFj0IWt_RPwlM-wLXpcS5F1LSo2k,1869
|
132
132
|
vellum/client/core/datetime_utils.py,sha256=nBys2IsYrhPdszxGKCNRPSOCwa-5DWOHG95FB8G9PKo,1047
|
133
133
|
vellum/client/core/file.py,sha256=X9IbmkZmB2bB_DpmZAO3crWdXagOakAyn6UCOCImCPg,2322
|
134
134
|
vellum/client/core/http_client.py,sha256=R0pQpCppnEtxccGvXl4uJ76s7ro_65Fo_erlNNLp_AI,19228
|
@@ -144,7 +144,7 @@ vellum/client/errors/bad_request_error.py,sha256=_EbO8mWqN9kFZPvIap8qa1lL_EWkRcs
|
|
144
144
|
vellum/client/errors/forbidden_error.py,sha256=QO1kKlhClAPES6zsEK7g9pglWnxn3KWaOCAawWOg6Aw,263
|
145
145
|
vellum/client/errors/internal_server_error.py,sha256=8USCagXyJJ1MOm9snpcXIUt6eNXvrd_aq7Gfcu1vlOI,268
|
146
146
|
vellum/client/errors/not_found_error.py,sha256=tBVCeBC8n3C811WHRj_n-hs3h8MqwR5gp0vLiobk7W8,262
|
147
|
-
vellum/client/resources/__init__.py,sha256=
|
147
|
+
vellum/client/resources/__init__.py,sha256=UcVAa7Iwo6e5ijqrraBlDlUA5wnXYVfRMJwXGJkz8UM,1511
|
148
148
|
vellum/client/resources/ad_hoc/__init__.py,sha256=FTtvy8EDg9nNNg9WCatVgKTRYV8-_v1roeGPAKoa_pw,65
|
149
149
|
vellum/client/resources/ad_hoc/client.py,sha256=_liorv4AsoJ55kVu0a5oWB3Qeff0iUKXqoHEIyDWLxc,14173
|
150
150
|
vellum/client/resources/container_images/__init__.py,sha256=FTtvy8EDg9nNNg9WCatVgKTRYV8-_v1roeGPAKoa_pw,65
|
@@ -159,7 +159,7 @@ vellum/client/resources/document_indexes/client.py,sha256=UcznU0NyvdNBpV4UCsTqG3
|
|
159
159
|
vellum/client/resources/document_indexes/types/__init__.py,sha256=IoFqKHN_VBdEhC7VL8_6Jbatrn0e0zuYEJAJUahcUR0,196
|
160
160
|
vellum/client/resources/document_indexes/types/document_indexes_list_request_status.py,sha256=sfUEB0cvOSmlE2iITqnMVyHv05Zy2fWP4QjCIYqMg0M,178
|
161
161
|
vellum/client/resources/documents/__init__.py,sha256=FTtvy8EDg9nNNg9WCatVgKTRYV8-_v1roeGPAKoa_pw,65
|
162
|
-
vellum/client/resources/documents/client.py,sha256=
|
162
|
+
vellum/client/resources/documents/client.py,sha256=DOiZ0i0iuGxPWTxDZsd8kndZPMB4GslHvyj1gBkrTIc,26048
|
163
163
|
vellum/client/resources/folder_entities/__init__.py,sha256=QOp7UMMB3a32GrfVaud35ECn4fqPBKXxCyClsDgd6GE,175
|
164
164
|
vellum/client/resources/folder_entities/client.py,sha256=xkT6D1TwPxvf1eXgDhRpKg7_O2V78jwBsIGyJgnI5SY,11110
|
165
165
|
vellum/client/resources/folder_entities/types/__init__.py,sha256=cHabrupjC-HL3kj-UZ9WdVzqHoQHCu6QsLFB3wlOs7k,212
|
@@ -170,6 +170,8 @@ vellum/client/resources/ml_models/__init__.py,sha256=FTtvy8EDg9nNNg9WCatVgKTRYV8
|
|
170
170
|
vellum/client/resources/ml_models/client.py,sha256=XIYapTEY6GRNr7V0Kjy5bEeKmrhv9ul8qlQY2A5LFqQ,3872
|
171
171
|
vellum/client/resources/organizations/__init__.py,sha256=FTtvy8EDg9nNNg9WCatVgKTRYV8-_v1roeGPAKoa_pw,65
|
172
172
|
vellum/client/resources/organizations/client.py,sha256=Uye92moqjAcOCs4astmuFpT92QdC5SLMunA-C8_G-gA,3675
|
173
|
+
vellum/client/resources/prompts/__init__.py,sha256=FTtvy8EDg9nNNg9WCatVgKTRYV8-_v1roeGPAKoa_pw,65
|
174
|
+
vellum/client/resources/prompts/client.py,sha256=_rNTUjhl_ZF3vyQa_M1BSTrX4DlFXU_SXkwwCEYKD2s,6598
|
173
175
|
vellum/client/resources/sandboxes/__init__.py,sha256=FTtvy8EDg9nNNg9WCatVgKTRYV8-_v1roeGPAKoa_pw,65
|
174
176
|
vellum/client/resources/sandboxes/client.py,sha256=i-6DHap5k6gFcYS-kWI8ayJFVZxb-GENRft6BJwVam4,17158
|
175
177
|
vellum/client/resources/test_suite_runs/__init__.py,sha256=FTtvy8EDg9nNNg9WCatVgKTRYV8-_v1roeGPAKoa_pw,65
|
@@ -191,7 +193,7 @@ vellum/client/resources/workspace_secrets/__init__.py,sha256=FTtvy8EDg9nNNg9WCat
|
|
191
193
|
vellum/client/resources/workspace_secrets/client.py,sha256=h7UzXLyTttPq1t-JZGMg1BWxypxJvBGUdqg7KGT7MK4,8027
|
192
194
|
vellum/client/resources/workspaces/__init__.py,sha256=FTtvy8EDg9nNNg9WCatVgKTRYV8-_v1roeGPAKoa_pw,65
|
193
195
|
vellum/client/resources/workspaces/client.py,sha256=RthwzN1o-Jxwg5yyNNodavFyNUSxfLoTv26w3mRR5g8,3595
|
194
|
-
vellum/client/types/__init__.py,sha256=
|
196
|
+
vellum/client/types/__init__.py,sha256=MUfv33R5OwoLX1dHVETCtWFNM3Xz-jWPJ2Z8ZrXlLqM,61259
|
195
197
|
vellum/client/types/ad_hoc_execute_prompt_event.py,sha256=bCjujA2XsOgyF3bRZbcEqV2rOIymRgsLoIRtZpB14xg,607
|
196
198
|
vellum/client/types/ad_hoc_expand_meta.py,sha256=1gv-NCsy_6xBYupLvZH979yf2VMdxAU-l0y0ynMKZaw,1331
|
197
199
|
vellum/client/types/ad_hoc_fulfilled_prompt_execution_meta.py,sha256=Bfvf1d_dkmshxRACVM5vcxbH_7AQY23RmrrnPc0ytYY,939
|
@@ -488,6 +490,7 @@ vellum/client/types/prompt_block_state.py,sha256=BRAzTYARoSU36IVZGWMeeqhl5fgFMXC
|
|
488
490
|
vellum/client/types/prompt_deployment_expand_meta_request.py,sha256=agsiAaHB6lDoZPlnfJ2nmhB4Ud4EiJJTX05YmduyCPo,1910
|
489
491
|
vellum/client/types/prompt_deployment_input_request.py,sha256=KrT4-Ew2VvTWXEkYQz2oyHn5EDOgrMW7FzRFaPH3ARg,353
|
490
492
|
vellum/client/types/prompt_deployment_parent_context.py,sha256=eu8dYmRb789uZeFVzbRkJrErDYZXo35f2qaNBcY0wOQ,2319
|
493
|
+
vellum/client/types/prompt_exec_config.py,sha256=kthvyEe-IzfTpOBd1fYrczHuxD-v7k6cwjmuaY170RQ,1390
|
491
494
|
vellum/client/types/prompt_execution_meta.py,sha256=3hhMZgdAR5mKfnh2e_eVN3oKfT0E9w26khVPrpjn7jk,1141
|
492
495
|
vellum/client/types/prompt_node_execution_meta.py,sha256=IyWH__nCp5uwS0N32b2ZEsA-Fv7AZDB4nnlRZayU2Gc,888
|
493
496
|
vellum/client/types/prompt_node_result.py,sha256=3jewO-nPodoXTq_5RxgwhKfDZrvoPjRZ_vUXLeqiuHY,749
|
@@ -822,6 +825,8 @@ vellum/resources/ml_models/__init__.py,sha256=qIepoIEWDHz3u7i0bW3jnTpdTdfPGhA1LB
|
|
822
825
|
vellum/resources/ml_models/client.py,sha256=RSYFEe1BnFTDBMur2_eR3ZkLZbdWeTGe_OIuMwcsfdw,158
|
823
826
|
vellum/resources/organizations/__init__.py,sha256=FD1umjszsErkQIAI6aZ7Lv_T6iN5IafeCbgv25uIpYo,155
|
824
827
|
vellum/resources/organizations/client.py,sha256=68HAX4pswpJDH0-Yjc3teoloSJBUGRv8O1V8tCqFSuk,162
|
828
|
+
vellum/resources/prompts/__init__.py,sha256=CtN_jI0nc0C3yqxUPR1uWs5Mvxhlce5c-d8E96GVt4g,149
|
829
|
+
vellum/resources/prompts/client.py,sha256=9S00NNuuiz41m6-kOL6KCxu9bnYMORrXrXVWfFEeW5o,156
|
825
830
|
vellum/resources/sandboxes/__init__.py,sha256=sycp4Bgvj9GzBGjiXhtmKFjOdBsIoDfMFaQrvDK_lGo,151
|
826
831
|
vellum/resources/sandboxes/client.py,sha256=PBpYOg43HN-9B4YKtPqmE1aFag39ypLc5UWSxixUJjo,158
|
827
832
|
vellum/resources/test_suite_runs/__init__.py,sha256=PfRYjodfN_rYZlUTiBnVXxdwQNcdmI-qT6MCqubd3ug,157
|
@@ -1140,6 +1145,7 @@ vellum/types/prompt_block_state.py,sha256=tKqNrZnHWjvfGS_6oIUTpdCPGxvRJa31Le6qWL
|
|
1140
1145
|
vellum/types/prompt_deployment_expand_meta_request.py,sha256=5dBdvjjK9zCKxrPMdKQPj6iG8A06GAlb_zazde6qZsU,175
|
1141
1146
|
vellum/types/prompt_deployment_input_request.py,sha256=z8CxCZWnKW8BBZajQ6iDnz-2gaxU-FrnYrVe_MvC3FU,169
|
1142
1147
|
vellum/types/prompt_deployment_parent_context.py,sha256=U9X9PvXhG6ZUE8RxLrH13xfqKvs3DOwbxzWmujoXTbg,170
|
1148
|
+
vellum/types/prompt_exec_config.py,sha256=aNeOGDi6l2rVzvkFt8CJE6L3W2EmY8gZaSb5051w8as,156
|
1143
1149
|
vellum/types/prompt_execution_meta.py,sha256=_5izDjusf-TM69zKhvXr5EHH4Fx9jfWkg8F5_KNJV-w,159
|
1144
1150
|
vellum/types/prompt_node_execution_meta.py,sha256=cJoHlIn_lb_sLpQniB8eszRJvFI6mJij9QgUIiKtiCY,164
|
1145
1151
|
vellum/types/prompt_node_result.py,sha256=9ootTTh8lscQ-0WE0-bqdmn7XFvpP7uavO-g7mPkA3Q,156
|
@@ -1441,8 +1447,8 @@ vellum/workflows/errors/types.py,sha256=tVW7Il9zalnwWzdoDLqYPIvRTOhXIv6FPORZAbU7
|
|
1441
1447
|
vellum/workflows/events/__init__.py,sha256=6pxxceJo2dcaRkWtkDAYlUQZ-PHBQSZytIoyuUK48Qw,759
|
1442
1448
|
vellum/workflows/events/node.py,sha256=jbmNHjdp331Q1IRK-AWtAxwF6Lidb9R7__N5rQuilE8,5401
|
1443
1449
|
vellum/workflows/events/tests/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
1444
|
-
vellum/workflows/events/tests/test_event.py,sha256=
|
1445
|
-
vellum/workflows/events/types.py,sha256=
|
1450
|
+
vellum/workflows/events/tests/test_event.py,sha256=WRxjOO1470rFH40O56RWjhonIdupW782h_FRAhIQZCQ,17823
|
1451
|
+
vellum/workflows/events/types.py,sha256=cKXEZEZ4C_O38CH-qiu8nYSMy2DVJ66lQayJO5A-haU,5690
|
1446
1452
|
vellum/workflows/events/workflow.py,sha256=xdqU6WOexaAqzJbU2Zw42o2LJhK7SDPtTFO5REGv17I,7293
|
1447
1453
|
vellum/workflows/exceptions.py,sha256=NiBiR3ggfmPxBVqD-H1SqmjI-7mIn0EStSN1BqApvCM,1213
|
1448
1454
|
vellum/workflows/expressions/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
@@ -1542,7 +1548,7 @@ vellum/workflows/nodes/displayable/code_execution_node/tests/__init__.py,sha256=
|
|
1542
1548
|
vellum/workflows/nodes/displayable/code_execution_node/tests/fixtures/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
1543
1549
|
vellum/workflows/nodes/displayable/code_execution_node/tests/fixtures/main.py,sha256=5QsbmkzSlSbcbWTG_JmIqcP-JNJzOPTKxGzdHos19W4,79
|
1544
1550
|
vellum/workflows/nodes/displayable/code_execution_node/tests/test_code_execution_node.py,sha256=xAaoOfQHQUlp0iKlig87t0aT2cJM-8PxiTb1QDg8VmY,24641
|
1545
|
-
vellum/workflows/nodes/displayable/code_execution_node/utils.py,sha256=
|
1551
|
+
vellum/workflows/nodes/displayable/code_execution_node/utils.py,sha256=PI0IQysC3uASv4nof23O4gIWpoNl3tRleb1q417bfTw,3896
|
1546
1552
|
vellum/workflows/nodes/displayable/conditional_node/__init__.py,sha256=AS_EIqFdU1F9t8aLmbZU-rLh9ry6LCJ0uj0D8F0L5Uw,72
|
1547
1553
|
vellum/workflows/nodes/displayable/conditional_node/node.py,sha256=Qjfl33gZ3JEgxBA1EgzSUebboGvsARthIxxcQyvx5Gg,1152
|
1548
1554
|
vellum/workflows/nodes/displayable/conftest.py,sha256=tD_WIiw5WjFqnzgnGLtEZDaMj2XhQ1DptnBTKYeBbI0,5705
|
@@ -1551,11 +1557,12 @@ vellum/workflows/nodes/displayable/final_output_node/node.py,sha256=PuQ0RvtAmoSI
|
|
1551
1557
|
vellum/workflows/nodes/displayable/final_output_node/tests/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
1552
1558
|
vellum/workflows/nodes/displayable/final_output_node/tests/test_node.py,sha256=E6LQ74qZjY4Xi4avx2qdOCgGhF8pEcNLBh8cqYRkzMI,709
|
1553
1559
|
vellum/workflows/nodes/displayable/guardrail_node/__init__.py,sha256=Ab5eXmOoBhyV4dMWdzh32HLUmnPIBEK_zFCT38C4Fng,68
|
1554
|
-
vellum/workflows/nodes/displayable/guardrail_node/node.py,sha256=
|
1560
|
+
vellum/workflows/nodes/displayable/guardrail_node/node.py,sha256=YMXBLHB4_TYWGvbWMQP2WH0ckktK1uFDOEYkRJc-RfE,4422
|
1561
|
+
vellum/workflows/nodes/displayable/guardrail_node/test_node.py,sha256=1yPIAt4_GWiUKT6u3rTW2XKp62b8xG8Jj3JWeCm5ZDM,1368
|
1555
1562
|
vellum/workflows/nodes/displayable/inline_prompt_node/__init__.py,sha256=gSUOoEZLlrx35-tQhSAd3An8WDwBqyiQh-sIebLU9wU,74
|
1556
1563
|
vellum/workflows/nodes/displayable/inline_prompt_node/node.py,sha256=8RXZqWMzViUjFfbpmcy1gkSsKnEpci8BGwsuPYv4xMQ,3380
|
1557
1564
|
vellum/workflows/nodes/displayable/inline_prompt_node/tests/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
1558
|
-
vellum/workflows/nodes/displayable/inline_prompt_node/tests/test_node.py,sha256=
|
1565
|
+
vellum/workflows/nodes/displayable/inline_prompt_node/tests/test_node.py,sha256=D06GymJGoMt9StKpTzqYk8wvmRedkvcRdYUHPUznvK4,10554
|
1559
1566
|
vellum/workflows/nodes/displayable/merge_node/__init__.py,sha256=J8IC08dSH7P76wKlNuxe1sn7toNGtSQdFirUbtPDEs0,60
|
1560
1567
|
vellum/workflows/nodes/displayable/merge_node/node.py,sha256=nZtGGVAvY4fvGg8vwV6sTQ8_QLRnigeXt0vf2FL272A,450
|
1561
1568
|
vellum/workflows/nodes/displayable/note_node/__init__.py,sha256=KWA3P4fyYJ-fOTky8qNGlcOotQ-HeHJ9AjZt6mRQmCE,58
|
@@ -1607,7 +1614,7 @@ vellum/workflows/references/workflow_input.py,sha256=lq7BiiLBHQNP-vP2p1TN2QBq0_L
|
|
1607
1614
|
vellum/workflows/resolvers/__init__.py,sha256=eH6hTvZO4IciDaf_cf7aM2vs-DkBDyJPycOQevJxQnI,82
|
1608
1615
|
vellum/workflows/resolvers/base.py,sha256=WHra9LRtlTuB1jmuNqkfVE2JUgB61Cyntn8f0b0WZg4,411
|
1609
1616
|
vellum/workflows/runner/__init__.py,sha256=i1iG5sAhtpdsrlvwgH6B-m49JsINkiWyPWs8vyT-bqM,72
|
1610
|
-
vellum/workflows/runner/runner.py,sha256=
|
1617
|
+
vellum/workflows/runner/runner.py,sha256=ww4fjZJBENkB5HJxdj92kTz7k_EyifCeAreupy5qIxs,31813
|
1611
1618
|
vellum/workflows/sandbox.py,sha256=GVJzVjMuYzOBnSrboB0_6MMRZWBluAyQ2o7syeaeBd0,2235
|
1612
1619
|
vellum/workflows/state/__init__.py,sha256=yUUdR-_Vl7UiixNDYQZ-GEM_kJI9dnOia75TtuNEsnE,60
|
1613
1620
|
vellum/workflows/state/base.py,sha256=Vkhneko3VlQrPsMLU1PYSzXU_W1u7_AraJsghiv5O-4,15512
|
@@ -1643,8 +1650,8 @@ vellum/workflows/workflows/event_filters.py,sha256=GSxIgwrX26a1Smfd-6yss2abGCnad
|
|
1643
1650
|
vellum/workflows/workflows/tests/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
1644
1651
|
vellum/workflows/workflows/tests/test_base_workflow.py,sha256=tCxrV3QBHL8wfdEO3bvKteDdw32xBlUl1_WxkAwaONw,8344
|
1645
1652
|
vellum/workflows/workflows/tests/test_context.py,sha256=VJBUcyWVtMa_lE5KxdhgMu0WYNYnUQUDvTF7qm89hJ0,2333
|
1646
|
-
vellum_ai-0.14.
|
1647
|
-
vellum_ai-0.14.
|
1648
|
-
vellum_ai-0.14.
|
1649
|
-
vellum_ai-0.14.
|
1650
|
-
vellum_ai-0.14.
|
1653
|
+
vellum_ai-0.14.28.dist-info/LICENSE,sha256=hOypcdt481qGNISA784bnAGWAE6tyIf9gc2E78mYC3E,1574
|
1654
|
+
vellum_ai-0.14.28.dist-info/METADATA,sha256=N7nbaIH39gbgUyBqZttgkemMWEoUpoQUJLtpd6bxTl0,5484
|
1655
|
+
vellum_ai-0.14.28.dist-info/WHEEL,sha256=sP946D7jFCHeNz5Iq4fL4Lu-PrWrFsgfLXbbkciIZwg,88
|
1656
|
+
vellum_ai-0.14.28.dist-info/entry_points.txt,sha256=HCH4yc_V3J_nDv3qJzZ_nYS8llCHZViCDP1ejgCc5Ak,42
|
1657
|
+
vellum_ai-0.14.28.dist-info/RECORD,,
|
@@ -94,7 +94,8 @@ class BaseInlinePromptNodeDisplay(BaseNodeVellumDisplay[_InlinePromptNodeType],
|
|
94
94
|
input_name=variable_name,
|
95
95
|
value=variable_value,
|
96
96
|
display_context=display_context,
|
97
|
-
input_id=self.node_input_ids_by_name.get(variable_name)
|
97
|
+
input_id=self.node_input_ids_by_name.get(f"{InlinePromptNode.prompt_inputs.name}.{variable_name}")
|
98
|
+
or self.node_input_ids_by_name.get(variable_name),
|
98
99
|
)
|
99
100
|
vellum_variable_type = infer_vellum_variable_type(variable_value)
|
100
101
|
node_inputs.append(node_input)
|
@@ -1,7 +1,12 @@
|
|
1
|
+
import pytest
|
2
|
+
from uuid import UUID
|
3
|
+
from typing import Type
|
4
|
+
|
1
5
|
from vellum.workflows import BaseWorkflow
|
2
6
|
from vellum.workflows.nodes import BaseNode
|
3
7
|
from vellum.workflows.nodes.displayable.inline_prompt_node.node import InlinePromptNode
|
4
8
|
from vellum.workflows.references.lazy import LazyReference
|
9
|
+
from vellum_ee.workflows.display.nodes.vellum.inline_prompt_node import BaseInlinePromptNodeDisplay
|
5
10
|
from vellum_ee.workflows.display.workflows.get_vellum_workflow_display_class import get_workflow_display
|
6
11
|
from vellum_ee.workflows.display.workflows.vellum_workflow_display import VellumWorkflowDisplay
|
7
12
|
|
@@ -34,7 +39,7 @@ def test_serialize_node__lazy_reference_in_prompt_inputs():
|
|
34
39
|
|
35
40
|
assert lazy_reference_node["inputs"] == [
|
36
41
|
{
|
37
|
-
"id": "
|
42
|
+
"id": "aa81c1bc-d5d8-4ae8-8946-e9f4d0c1ab5f",
|
38
43
|
"key": "attr",
|
39
44
|
"value": {
|
40
45
|
"combinator": "OR",
|
@@ -50,3 +55,77 @@ def test_serialize_node__lazy_reference_in_prompt_inputs():
|
|
50
55
|
},
|
51
56
|
}
|
52
57
|
]
|
58
|
+
|
59
|
+
|
60
|
+
def _no_display_class(Node: Type[InlinePromptNode]):
|
61
|
+
return None
|
62
|
+
|
63
|
+
|
64
|
+
def _display_class_with_node_input_ids_by_name(Node: Type[InlinePromptNode]):
|
65
|
+
class PromptNodeDisplay(BaseInlinePromptNodeDisplay[Node]): # type: ignore[valid-type]
|
66
|
+
node_input_ids_by_name = {"foo": UUID("fba6a4d5-835a-4e99-afb7-f6a4aed15110")}
|
67
|
+
|
68
|
+
return PromptNodeDisplay
|
69
|
+
|
70
|
+
|
71
|
+
def _display_class_with_node_input_ids_by_name_with_inputs_prefix(Node: Type[InlinePromptNode]):
|
72
|
+
class PromptNodeDisplay(BaseInlinePromptNodeDisplay[Node]): # type: ignore[valid-type]
|
73
|
+
node_input_ids_by_name = {"prompt_inputs.foo": UUID("fba6a4d5-835a-4e99-afb7-f6a4aed15110")}
|
74
|
+
|
75
|
+
return PromptNodeDisplay
|
76
|
+
|
77
|
+
|
78
|
+
@pytest.mark.parametrize(
|
79
|
+
["GetDisplayClass", "expected_input_id"],
|
80
|
+
[
|
81
|
+
(_no_display_class, "8aa4ce7f-5eb8-41b7-abd0-ea2b40c8fb88"),
|
82
|
+
(_display_class_with_node_input_ids_by_name, "fba6a4d5-835a-4e99-afb7-f6a4aed15110"),
|
83
|
+
(_display_class_with_node_input_ids_by_name_with_inputs_prefix, "fba6a4d5-835a-4e99-afb7-f6a4aed15110"),
|
84
|
+
],
|
85
|
+
ids=[
|
86
|
+
"no_display_class",
|
87
|
+
"display_class_with_node_input_ids_by_name",
|
88
|
+
"display_class_with_node_input_ids_by_name_with_inputs_prefix",
|
89
|
+
],
|
90
|
+
)
|
91
|
+
def test_serialize_node__prompt_inputs(GetDisplayClass, expected_input_id):
|
92
|
+
# GIVEN a prompt node with inputs
|
93
|
+
class MyPromptNode(InlinePromptNode):
|
94
|
+
prompt_inputs = {"foo": "bar"}
|
95
|
+
blocks = []
|
96
|
+
ml_model = "gpt-4o"
|
97
|
+
|
98
|
+
# AND a workflow with the prompt node
|
99
|
+
class Workflow(BaseWorkflow):
|
100
|
+
graph = MyPromptNode
|
101
|
+
|
102
|
+
# AND a display class
|
103
|
+
GetDisplayClass(MyPromptNode)
|
104
|
+
|
105
|
+
# WHEN the workflow is serialized
|
106
|
+
workflow_display = get_workflow_display(base_display_class=VellumWorkflowDisplay, workflow_class=Workflow)
|
107
|
+
serialized_workflow: dict = workflow_display.serialize()
|
108
|
+
|
109
|
+
# THEN the node should properly serialize the inputs
|
110
|
+
my_prompt_node = next(
|
111
|
+
node for node in serialized_workflow["workflow_raw_data"]["nodes"] if node["id"] == str(MyPromptNode.__id__)
|
112
|
+
)
|
113
|
+
|
114
|
+
assert my_prompt_node["inputs"] == [
|
115
|
+
{
|
116
|
+
"id": expected_input_id,
|
117
|
+
"key": "foo",
|
118
|
+
"value": {
|
119
|
+
"rules": [
|
120
|
+
{
|
121
|
+
"type": "CONSTANT_VALUE",
|
122
|
+
"data": {
|
123
|
+
"type": "STRING",
|
124
|
+
"value": "bar",
|
125
|
+
},
|
126
|
+
}
|
127
|
+
],
|
128
|
+
"combinator": "OR",
|
129
|
+
},
|
130
|
+
}
|
131
|
+
]
|
@@ -1,5 +1,7 @@
|
|
1
1
|
import importlib
|
2
|
+
from importlib.machinery import ModuleSpec
|
2
3
|
import re
|
4
|
+
import sys
|
3
5
|
from typing import Optional
|
4
6
|
|
5
7
|
|
@@ -8,11 +10,20 @@ class VirtualFileLoader(importlib.abc.Loader):
|
|
8
10
|
self.files = files
|
9
11
|
self.namespace = namespace
|
10
12
|
|
11
|
-
def create_module(self, spec):
|
12
|
-
|
13
|
+
def create_module(self, spec: ModuleSpec):
|
14
|
+
"""
|
15
|
+
We started with cpython/Lib/importlib/_bootstrap.py::FrozenImporter::create_module here
|
16
|
+
|
17
|
+
https://github.com/python/cpython/blob/053c285f6b41f92fbdd1d4ff0c959cceefacd7cd/Lib/importlib/_bootstrap.py#L1160C1-L1169C22
|
18
|
+
|
19
|
+
and reduced our needs to just updating the __file__ attribute directly.
|
20
|
+
"""
|
21
|
+
module = type(sys)(spec.name)
|
22
|
+
module.__file__ = spec.origin
|
23
|
+
return module
|
13
24
|
|
14
25
|
def exec_module(self, module):
|
15
|
-
module_info = self._resolve_module(module.__spec__.
|
26
|
+
module_info = self._resolve_module(module.__spec__.name)
|
16
27
|
|
17
28
|
if module_info:
|
18
29
|
file_path, code = module_info
|
@@ -66,7 +77,8 @@ class VirtualFileFinder(importlib.abc.MetaPathFinder, importlib.abc.Loader):
|
|
66
77
|
return importlib.machinery.ModuleSpec(
|
67
78
|
fullname,
|
68
79
|
self.loader,
|
69
|
-
origin=
|
80
|
+
origin=file_path,
|
70
81
|
is_package=is_package,
|
71
82
|
)
|
83
|
+
|
72
84
|
return None
|
@@ -1,13 +1,21 @@
|
|
1
|
+
import pytest
|
1
2
|
import sys
|
2
3
|
from uuid import uuid4
|
3
4
|
from typing import Type, cast
|
4
5
|
|
5
6
|
from vellum.client.core.pydantic_utilities import UniversalBaseModel
|
7
|
+
from vellum.client.types.code_executor_response import CodeExecutorResponse
|
8
|
+
from vellum.client.types.number_vellum_value import NumberVellumValue
|
6
9
|
from vellum.workflows import BaseWorkflow
|
7
10
|
from vellum.workflows.nodes import BaseNode
|
8
11
|
from vellum_ee.workflows.server.virtual_file_loader import VirtualFileFinder
|
9
12
|
|
10
13
|
|
14
|
+
@pytest.fixture
|
15
|
+
def mock_open(mocker):
|
16
|
+
return mocker.patch("vellum.workflows.nodes.displayable.code_execution_node.utils.open")
|
17
|
+
|
18
|
+
|
11
19
|
def test_load_workflow_event_display_context():
|
12
20
|
# DEPRECATED: Use `vellum.workflows.events.workflow.WorkflowEventDisplayContext` instead. Will be removed in 0.15.0
|
13
21
|
from vellum_ee.workflows.display.types import WorkflowEventDisplayContext
|
@@ -69,3 +77,74 @@ class StartNode(BaseNode):
|
|
69
77
|
# AND the lazy reference has the correct name
|
70
78
|
assert start_node.foo.instance
|
71
79
|
assert start_node.foo.instance.name == "StartNode.Outputs.bar"
|
80
|
+
|
81
|
+
|
82
|
+
def test_load_from_module__ts_code_in_file_loader(
|
83
|
+
mock_open,
|
84
|
+
vellum_client,
|
85
|
+
):
|
86
|
+
# GIVEN typescript code
|
87
|
+
ts_code = """async function main(): any {
|
88
|
+
return 5;
|
89
|
+
}"""
|
90
|
+
|
91
|
+
# AND a workflow module with only a code execution node
|
92
|
+
files = {
|
93
|
+
"__init__.py": "",
|
94
|
+
"workflow.py": """\
|
95
|
+
from vellum.workflows import BaseWorkflow
|
96
|
+
from .nodes.code_execution_node import CodeExecutionNode
|
97
|
+
|
98
|
+
class Workflow(BaseWorkflow):
|
99
|
+
graph = CodeExecutionNode
|
100
|
+
""",
|
101
|
+
"nodes/__init__.py": """\
|
102
|
+
from .code_execution_node import CodeExecutionNode
|
103
|
+
|
104
|
+
__all__ = ["CodeExecutionNode"]
|
105
|
+
""",
|
106
|
+
"nodes/code_execution_node.py": """\
|
107
|
+
from typing import Any
|
108
|
+
|
109
|
+
from vellum.workflows.nodes.displayable import CodeExecutionNode as BaseCodeExecutionNode
|
110
|
+
from vellum.workflows.state import BaseState
|
111
|
+
|
112
|
+
class CodeExecutionNode(BaseCodeExecutionNode[BaseState, int]):
|
113
|
+
filepath = "./script.ts"
|
114
|
+
code_inputs = {}
|
115
|
+
runtime = "TYPESCRIPT_5_3_3"
|
116
|
+
packages = []
|
117
|
+
""",
|
118
|
+
"nodes/code_execution_node/script.ts": ts_code,
|
119
|
+
}
|
120
|
+
|
121
|
+
namespace = str(uuid4())
|
122
|
+
|
123
|
+
# AND the virtual file loader is registered
|
124
|
+
sys.meta_path.append(VirtualFileFinder(files, namespace))
|
125
|
+
|
126
|
+
# AND the open function returns our file content
|
127
|
+
mock_open.return_value.__enter__.return_value.read.return_value = ts_code
|
128
|
+
|
129
|
+
# AND we know what the Code Execution Node will respond with
|
130
|
+
mock_code_execution = CodeExecutorResponse(
|
131
|
+
log="hello",
|
132
|
+
output=NumberVellumValue(value=5),
|
133
|
+
)
|
134
|
+
vellum_client.execute_code.return_value = mock_code_execution
|
135
|
+
|
136
|
+
# WHEN the workflow is loaded
|
137
|
+
Workflow = BaseWorkflow.load_from_module(namespace)
|
138
|
+
workflow = Workflow()
|
139
|
+
|
140
|
+
# THEN the workflow is successfully initialized
|
141
|
+
assert workflow
|
142
|
+
|
143
|
+
event = workflow.run()
|
144
|
+
assert event.name == "workflow.execution.fulfilled", event.model_dump_json()
|
145
|
+
|
146
|
+
# AND we pass in the correct file path to the open function
|
147
|
+
assert mock_open.call_args[0][0] == f"{namespace}/nodes/./script.ts"
|
148
|
+
|
149
|
+
# AND we invoke the Code Execution Node with the correct code
|
150
|
+
assert vellum_client.execute_code.call_args.kwargs["code"] == ts_code
|
File without changes
|
File without changes
|
File without changes
|