vellum-ai 0.14.27__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/client/core/client_wrapper.py +1 -1
- vellum/client/core/jsonable_encoder.py +1 -1
- vellum/client/resources/documents/client.py +0 -14
- 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/inline_prompt_node/tests/test_node.py +13 -2
- {vellum_ai-0.14.27.dist-info → vellum_ai-0.14.28.dist-info}/METADATA +1 -1
- {vellum_ai-0.14.27.dist-info → vellum_ai-0.14.28.dist-info}/RECORD +16 -16
- 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 +36 -11
- {vellum_ai-0.14.27.dist-info → vellum_ai-0.14.28.dist-info}/LICENSE +0 -0
- {vellum_ai-0.14.27.dist-info → vellum_ai-0.14.28.dist-info}/WHEEL +0 -0
- {vellum_ai-0.14.27.dist-info → vellum_ai-0.14.28.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.
|
21
|
+
"X-Fern-SDK-Version": "0.14.28",
|
22
22
|
}
|
23
23
|
headers["X_API_KEY"] = self.api_key
|
24
24
|
return headers
|
@@ -45,7 +45,7 @@ def jsonable_encoder(obj: Any, custom_encoder: Optional[Dict[Any, Callable[[Any]
|
|
45
45
|
encoder = getattr(obj.__config__, "json_encoders", {}) # type: ignore # Pydantic v1
|
46
46
|
if custom_encoder:
|
47
47
|
encoder.update(custom_encoder)
|
48
|
-
obj_dict = obj.
|
48
|
+
obj_dict = obj.dict(by_alias=True)
|
49
49
|
if "__root__" in obj_dict:
|
50
50
|
obj_dict = obj_dict["__root__"]
|
51
51
|
if "root" in obj_dict:
|
@@ -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
|
@@ -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):
|
@@ -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
|
+
]
|
@@ -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,18 +121,18 @@ 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
126
|
vellum/__init__.py,sha256=88-79I29hBTQvR1uH_BOCGMWuj2a4Nx82R_8KIESg28,40470
|
127
127
|
vellum/client/README.md,sha256=JkCJjmMZl4jrPj46pkmL9dpK4gSzQQmP5I7z4aME4LY,4749
|
128
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
|
135
|
-
vellum/client/core/jsonable_encoder.py,sha256=
|
135
|
+
vellum/client/core/jsonable_encoder.py,sha256=qaF1gtgH-kQZb4kJskETwcCsOPUof-NnYVdszHkb-dM,3656
|
136
136
|
vellum/client/core/pydantic_utilities.py,sha256=6ev3gtER-hjlq7PcPL9XT_YSCdgyCE8ZKHJ9Uc-gHIg,12071
|
137
137
|
vellum/client/core/query_encoder.py,sha256=ekulqNd0j8TgD7ox-Qbz7liqX8-KP9blvT9DsRCenYM,2144
|
138
138
|
vellum/client/core/remove_none_from_dict.py,sha256=EU9SGgYidWq7SexuJbNs4-PZ-5Bl3Vppd864mS6vQZw,342
|
@@ -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
|
@@ -1447,8 +1447,8 @@ vellum/workflows/errors/types.py,sha256=tVW7Il9zalnwWzdoDLqYPIvRTOhXIv6FPORZAbU7
|
|
1447
1447
|
vellum/workflows/events/__init__.py,sha256=6pxxceJo2dcaRkWtkDAYlUQZ-PHBQSZytIoyuUK48Qw,759
|
1448
1448
|
vellum/workflows/events/node.py,sha256=jbmNHjdp331Q1IRK-AWtAxwF6Lidb9R7__N5rQuilE8,5401
|
1449
1449
|
vellum/workflows/events/tests/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
1450
|
-
vellum/workflows/events/tests/test_event.py,sha256=
|
1451
|
-
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
|
1452
1452
|
vellum/workflows/events/workflow.py,sha256=xdqU6WOexaAqzJbU2Zw42o2LJhK7SDPtTFO5REGv17I,7293
|
1453
1453
|
vellum/workflows/exceptions.py,sha256=NiBiR3ggfmPxBVqD-H1SqmjI-7mIn0EStSN1BqApvCM,1213
|
1454
1454
|
vellum/workflows/expressions/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
@@ -1548,7 +1548,7 @@ vellum/workflows/nodes/displayable/code_execution_node/tests/__init__.py,sha256=
|
|
1548
1548
|
vellum/workflows/nodes/displayable/code_execution_node/tests/fixtures/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
1549
1549
|
vellum/workflows/nodes/displayable/code_execution_node/tests/fixtures/main.py,sha256=5QsbmkzSlSbcbWTG_JmIqcP-JNJzOPTKxGzdHos19W4,79
|
1550
1550
|
vellum/workflows/nodes/displayable/code_execution_node/tests/test_code_execution_node.py,sha256=xAaoOfQHQUlp0iKlig87t0aT2cJM-8PxiTb1QDg8VmY,24641
|
1551
|
-
vellum/workflows/nodes/displayable/code_execution_node/utils.py,sha256=
|
1551
|
+
vellum/workflows/nodes/displayable/code_execution_node/utils.py,sha256=PI0IQysC3uASv4nof23O4gIWpoNl3tRleb1q417bfTw,3896
|
1552
1552
|
vellum/workflows/nodes/displayable/conditional_node/__init__.py,sha256=AS_EIqFdU1F9t8aLmbZU-rLh9ry6LCJ0uj0D8F0L5Uw,72
|
1553
1553
|
vellum/workflows/nodes/displayable/conditional_node/node.py,sha256=Qjfl33gZ3JEgxBA1EgzSUebboGvsARthIxxcQyvx5Gg,1152
|
1554
1554
|
vellum/workflows/nodes/displayable/conftest.py,sha256=tD_WIiw5WjFqnzgnGLtEZDaMj2XhQ1DptnBTKYeBbI0,5705
|
@@ -1562,7 +1562,7 @@ vellum/workflows/nodes/displayable/guardrail_node/test_node.py,sha256=1yPIAt4_GW
|
|
1562
1562
|
vellum/workflows/nodes/displayable/inline_prompt_node/__init__.py,sha256=gSUOoEZLlrx35-tQhSAd3An8WDwBqyiQh-sIebLU9wU,74
|
1563
1563
|
vellum/workflows/nodes/displayable/inline_prompt_node/node.py,sha256=8RXZqWMzViUjFfbpmcy1gkSsKnEpci8BGwsuPYv4xMQ,3380
|
1564
1564
|
vellum/workflows/nodes/displayable/inline_prompt_node/tests/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
1565
|
-
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
|
1566
1566
|
vellum/workflows/nodes/displayable/merge_node/__init__.py,sha256=J8IC08dSH7P76wKlNuxe1sn7toNGtSQdFirUbtPDEs0,60
|
1567
1567
|
vellum/workflows/nodes/displayable/merge_node/node.py,sha256=nZtGGVAvY4fvGg8vwV6sTQ8_QLRnigeXt0vf2FL272A,450
|
1568
1568
|
vellum/workflows/nodes/displayable/note_node/__init__.py,sha256=KWA3P4fyYJ-fOTky8qNGlcOotQ-HeHJ9AjZt6mRQmCE,58
|
@@ -1650,8 +1650,8 @@ vellum/workflows/workflows/event_filters.py,sha256=GSxIgwrX26a1Smfd-6yss2abGCnad
|
|
1650
1650
|
vellum/workflows/workflows/tests/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
1651
1651
|
vellum/workflows/workflows/tests/test_base_workflow.py,sha256=tCxrV3QBHL8wfdEO3bvKteDdw32xBlUl1_WxkAwaONw,8344
|
1652
1652
|
vellum/workflows/workflows/tests/test_context.py,sha256=VJBUcyWVtMa_lE5KxdhgMu0WYNYnUQUDvTF7qm89hJ0,2333
|
1653
|
-
vellum_ai-0.14.
|
1654
|
-
vellum_ai-0.14.
|
1655
|
-
vellum_ai-0.14.
|
1656
|
-
vellum_ai-0.14.
|
1657
|
-
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
|
@@ -4,11 +4,18 @@ from uuid import uuid4
|
|
4
4
|
from typing import Type, cast
|
5
5
|
|
6
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
|
7
9
|
from vellum.workflows import BaseWorkflow
|
8
10
|
from vellum.workflows.nodes import BaseNode
|
9
11
|
from vellum_ee.workflows.server.virtual_file_loader import VirtualFileFinder
|
10
12
|
|
11
13
|
|
14
|
+
@pytest.fixture
|
15
|
+
def mock_open(mocker):
|
16
|
+
return mocker.patch("vellum.workflows.nodes.displayable.code_execution_node.utils.open")
|
17
|
+
|
18
|
+
|
12
19
|
def test_load_workflow_event_display_context():
|
13
20
|
# DEPRECATED: Use `vellum.workflows.events.workflow.WorkflowEventDisplayContext` instead. Will be removed in 0.15.0
|
14
21
|
from vellum_ee.workflows.display.types import WorkflowEventDisplayContext
|
@@ -72,9 +79,16 @@ class StartNode(BaseNode):
|
|
72
79
|
assert start_node.foo.instance.name == "StartNode.Outputs.bar"
|
73
80
|
|
74
81
|
|
75
|
-
|
76
|
-
|
77
|
-
|
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
|
78
92
|
files = {
|
79
93
|
"__init__.py": "",
|
80
94
|
"workflow.py": """\
|
@@ -95,18 +109,13 @@ from typing import Any
|
|
95
109
|
from vellum.workflows.nodes.displayable import CodeExecutionNode as BaseCodeExecutionNode
|
96
110
|
from vellum.workflows.state import BaseState
|
97
111
|
|
98
|
-
class CodeExecutionNode(BaseCodeExecutionNode[BaseState,
|
112
|
+
class CodeExecutionNode(BaseCodeExecutionNode[BaseState, int]):
|
99
113
|
filepath = "./script.ts"
|
100
114
|
code_inputs = {}
|
101
115
|
runtime = "TYPESCRIPT_5_3_3"
|
102
116
|
packages = []
|
103
117
|
""",
|
104
|
-
"nodes/code_execution_node/script.ts":
|
105
|
-
text: string,
|
106
|
-
}): any {
|
107
|
-
const matches = inputs.text.match(/\\((.+?)\\)/gs);
|
108
|
-
return matches;
|
109
|
-
}""",
|
118
|
+
"nodes/code_execution_node/script.ts": ts_code,
|
110
119
|
}
|
111
120
|
|
112
121
|
namespace = str(uuid4())
|
@@ -114,6 +123,16 @@ class CodeExecutionNode(BaseCodeExecutionNode[BaseState, Any]):
|
|
114
123
|
# AND the virtual file loader is registered
|
115
124
|
sys.meta_path.append(VirtualFileFinder(files, namespace))
|
116
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
|
+
|
117
136
|
# WHEN the workflow is loaded
|
118
137
|
Workflow = BaseWorkflow.load_from_module(namespace)
|
119
138
|
workflow = Workflow()
|
@@ -122,4 +141,10 @@ class CodeExecutionNode(BaseCodeExecutionNode[BaseState, Any]):
|
|
122
141
|
assert workflow
|
123
142
|
|
124
143
|
event = workflow.run()
|
125
|
-
assert event.name == "workflow.execution.fulfilled"
|
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
|