vellum-ai 0.14.45__py3-none-any.whl → 0.14.47__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/README.md +2 -2
- vellum/client/__init__.py +72 -6
- vellum/client/core/client_wrapper.py +1 -1
- vellum/client/core/file.py +13 -8
- vellum/client/core/http_client.py +26 -14
- vellum/client/core/pydantic_utilities.py +2 -2
- vellum/client/core/request_options.py +3 -0
- vellum/client/resources/ad_hoc/client.py +14 -2
- vellum/client/resources/container_images/client.py +6 -0
- vellum/client/resources/deployments/client.py +12 -0
- vellum/client/resources/document_indexes/client.py +18 -0
- vellum/client/resources/documents/client.py +6 -0
- vellum/client/resources/folder_entities/client.py +6 -0
- vellum/client/resources/metric_definitions/client.py +6 -0
- vellum/client/resources/prompts/client.py +6 -0
- vellum/client/resources/sandboxes/client.py +12 -0
- vellum/client/resources/test_suite_runs/client.py +6 -0
- vellum/client/resources/test_suites/client.py +2 -2
- vellum/client/resources/workflow_deployments/client.py +6 -0
- vellum/client/resources/workflow_sandboxes/client.py +6 -0
- vellum/client/resources/workflows/client.py +6 -4
- vellum/client/resources/workspace_secrets/client.py +6 -0
- vellum/client/types/api_request_parent_context.py +0 -6
- vellum/client/types/array_input.py +0 -5
- vellum/client/types/code_execution_node_array_result.py +0 -5
- vellum/client/types/code_execution_node_result.py +0 -5
- vellum/client/types/code_execution_node_result_data.py +0 -5
- vellum/client/types/code_executor_response.py +0 -5
- vellum/client/types/create_test_suite_test_case_request.py +0 -5
- vellum/client/types/deployment_history_item.py +0 -5
- vellum/client/types/deployment_read.py +0 -5
- vellum/client/types/execute_workflow_response.py +0 -5
- vellum/client/types/execution_array_vellum_value.py +0 -5
- vellum/client/types/external_test_case_execution.py +0 -5
- vellum/client/types/external_test_case_execution_request.py +0 -5
- vellum/client/types/fulfilled_execute_workflow_workflow_result_event.py +0 -7
- vellum/client/types/fulfilled_workflow_node_result_event.py +0 -5
- vellum/client/types/initiated_workflow_node_result_event.py +0 -5
- vellum/client/types/metadata_filter_config_request.py +0 -5
- vellum/client/types/metric_definition_execution.py +0 -5
- vellum/client/types/metric_definition_history_item.py +0 -5
- vellum/client/types/named_test_case_array_variable_value.py +0 -5
- vellum/client/types/named_test_case_array_variable_value_request.py +0 -7
- vellum/client/types/node_execution_fulfilled_event.py +0 -11
- vellum/client/types/node_execution_initiated_event.py +0 -11
- vellum/client/types/node_execution_paused_event.py +0 -11
- vellum/client/types/node_execution_rejected_event.py +0 -11
- vellum/client/types/node_execution_resumed_event.py +0 -11
- vellum/client/types/node_execution_span.py +0 -11
- vellum/client/types/node_execution_streaming_event.py +0 -11
- vellum/client/types/node_input_compiled_array_value.py +0 -5
- vellum/client/types/node_output_compiled_array_value.py +0 -5
- vellum/client/types/node_parent_context.py +0 -6
- vellum/client/types/paginated_slim_deployment_read_list.py +0 -5
- vellum/client/types/paginated_slim_workflow_deployment_list.py +0 -5
- vellum/client/types/paginated_test_suite_run_execution_list.py +0 -5
- vellum/client/types/paginated_test_suite_test_case_list.py +0 -5
- vellum/client/types/prompt_deployment_parent_context.py +0 -6
- vellum/client/types/prompt_exec_config.py +0 -6
- vellum/client/types/rejected_workflow_node_result_event.py +0 -5
- vellum/client/types/replace_test_suite_test_case_request.py +0 -5
- vellum/client/types/search_filters_request.py +0 -7
- vellum/client/types/search_request_options_request.py +0 -7
- vellum/client/types/slim_deployment_read.py +0 -5
- vellum/client/types/slim_workflow_deployment.py +0 -5
- vellum/client/types/slim_workflow_execution_read.py +0 -12
- vellum/client/types/span_link.py +0 -6
- vellum/client/types/streaming_workflow_node_result_event.py +0 -5
- vellum/client/types/templating_node_array_result.py +0 -5
- vellum/client/types/templating_node_result.py +0 -5
- vellum/client/types/templating_node_result_data.py +0 -5
- vellum/client/types/terminal_node_array_result.py +0 -5
- vellum/client/types/terminal_node_result.py +0 -5
- vellum/client/types/terminal_node_result_data.py +0 -5
- vellum/client/types/test_case_array_variable_value.py +0 -5
- vellum/client/types/test_suite_run_execution.py +0 -5
- vellum/client/types/test_suite_run_execution_array_output.py +0 -5
- vellum/client/types/test_suite_run_execution_metric_result.py +0 -5
- vellum/client/types/test_suite_run_external_exec_config.py +0 -5
- vellum/client/types/test_suite_run_external_exec_config_data.py +0 -5
- vellum/client/types/test_suite_run_external_exec_config_data_request.py +0 -7
- vellum/client/types/test_suite_run_external_exec_config_request.py +0 -7
- vellum/client/types/test_suite_run_metric_array_output.py +0 -5
- vellum/client/types/test_suite_run_read.py +0 -5
- vellum/client/types/test_suite_test_case.py +0 -5
- vellum/client/types/test_suite_test_case_create_bulk_operation_request.py +0 -7
- vellum/client/types/test_suite_test_case_replace_bulk_operation_request.py +0 -7
- vellum/client/types/test_suite_test_case_upsert_bulk_operation_request.py +0 -7
- vellum/client/types/upsert_test_suite_test_case_request.py +0 -5
- vellum/client/types/vellum_value_logical_condition_group_request.py +0 -3
- vellum/client/types/vellum_value_logical_condition_request.py +0 -5
- vellum/client/types/vellum_variable.py +0 -5
- vellum/client/types/workflow_deployment_event_executions_response.py +0 -26
- vellum/client/types/workflow_deployment_history_item.py +0 -5
- vellum/client/types/workflow_deployment_parent_context.py +0 -6
- vellum/client/types/workflow_deployment_read.py +0 -5
- vellum/client/types/workflow_deployment_release.py +0 -5
- vellum/client/types/workflow_deployment_release_workflow_version.py +0 -5
- vellum/client/types/workflow_event_execution_read.py +0 -12
- vellum/client/types/workflow_execution_actual.py +0 -5
- vellum/client/types/workflow_execution_fulfilled_event.py +0 -11
- vellum/client/types/workflow_execution_initiated_event.py +0 -11
- vellum/client/types/workflow_execution_node_result_event.py +0 -5
- vellum/client/types/workflow_execution_paused_event.py +0 -11
- vellum/client/types/workflow_execution_rejected_event.py +0 -11
- vellum/client/types/workflow_execution_resumed_event.py +0 -11
- vellum/client/types/workflow_execution_snapshotted_event.py +0 -13
- vellum/client/types/workflow_execution_span.py +0 -11
- vellum/client/types/workflow_execution_streaming_event.py +0 -11
- vellum/client/types/workflow_execution_view_online_eval_metric_result.py +0 -7
- vellum/client/types/workflow_execution_workflow_result_event.py +0 -5
- vellum/client/types/workflow_output_array.py +0 -5
- vellum/client/types/workflow_parent_context.py +0 -6
- vellum/client/types/workflow_result_event.py +0 -5
- vellum/client/types/workflow_result_event_output_data_array.py +0 -5
- vellum/client/types/workflow_sandbox_parent_context.py +0 -6
- vellum/workflows/nodes/bases/base.py +26 -6
- vellum/workflows/nodes/bases/tests/test_base_node.py +30 -0
- vellum/workflows/nodes/core/try_node/node.py +3 -6
- vellum/workflows/nodes/core/try_node/tests/test_node.py +0 -24
- vellum/workflows/nodes/displayable/bases/prompt_deployment_node.py +8 -14
- vellum/workflows/nodes/displayable/code_execution_node/tests/test_code_execution_node.py +112 -0
- vellum/workflows/nodes/displayable/code_execution_node/utils.py +3 -54
- vellum/workflows/nodes/displayable/tests/test_text_prompt_deployment_node.py +5 -6
- vellum/workflows/nodes/utils.py +8 -0
- vellum/workflows/types/code_execution_node_wrappers.py +69 -0
- vellum/workflows/vellum_client.py +19 -7
- {vellum_ai-0.14.45.dist-info → vellum_ai-0.14.47.dist-info}/METADATA +1 -1
- {vellum_ai-0.14.45.dist-info → vellum_ai-0.14.47.dist-info}/RECORD +162 -161
- vellum_cli/config.py +7 -2
- vellum_cli/push.py +5 -1
- vellum_cli/tests/test_push.py +192 -8
- vellum_ee/workflows/display/nodes/base_node_display.py +17 -6
- vellum_ee/workflows/display/nodes/get_node_display_class.py +4 -5
- vellum_ee/workflows/display/nodes/vellum/api_node.py +11 -0
- vellum_ee/workflows/display/nodes/vellum/code_execution_node.py +5 -0
- vellum_ee/workflows/display/nodes/vellum/error_node.py +22 -16
- vellum_ee/workflows/display/nodes/vellum/guardrail_node.py +2 -0
- vellum_ee/workflows/display/nodes/vellum/inline_prompt_node.py +46 -12
- vellum_ee/workflows/display/nodes/vellum/inline_subworkflow_node.py +2 -0
- vellum_ee/workflows/display/nodes/vellum/map_node.py +2 -0
- vellum_ee/workflows/display/nodes/vellum/prompt_deployment_node.py +3 -5
- vellum_ee/workflows/display/nodes/vellum/search_node.py +8 -0
- vellum_ee/workflows/display/nodes/vellum/subworkflow_deployment_node.py +2 -5
- vellum_ee/workflows/display/nodes/vellum/templating_node.py +2 -0
- vellum_ee/workflows/display/nodes/vellum/tests/test_code_execution_node.py +1 -1
- vellum_ee/workflows/display/nodes/vellum/tests/test_error_node.py +4 -0
- vellum_ee/workflows/display/nodes/vellum/tests/test_prompt_deployment_node.py +4 -3
- vellum_ee/workflows/display/nodes/vellum/tests/test_prompt_node.py +36 -2
- vellum_ee/workflows/display/nodes/vellum/tests/test_subworkflow_deployment_node.py +5 -4
- vellum_ee/workflows/display/nodes/vellum/tests/test_templating_node.py +1 -1
- vellum_ee/workflows/display/tests/test_base_workflow_display.py +44 -0
- vellum_ee/workflows/display/tests/workflow_serialization/test_basic_error_node_serialization.py +2 -4
- vellum_ee/workflows/display/types.py +3 -0
- vellum_ee/workflows/display/utils/expressions.py +3 -3
- vellum_ee/workflows/display/utils/vellum.py +1 -3
- vellum_ee/workflows/display/workflows/base_workflow_display.py +10 -0
- vellum_ee/workflows/display/workflows/get_vellum_workflow_display_class.py +3 -0
- vellum_ee/workflows/display/workflows/tests/test_workflow_display.py +53 -0
- {vellum_ai-0.14.45.dist-info → vellum_ai-0.14.47.dist-info}/LICENSE +0 -0
- {vellum_ai-0.14.45.dist-info → vellum_ai-0.14.47.dist-info}/WHEEL +0 -0
- {vellum_ai-0.14.45.dist-info → vellum_ai-0.14.47.dist-info}/entry_points.txt +0 -0
@@ -409,6 +409,56 @@ def main(word: str) -> int:
|
|
409
409
|
assert exc_info.value.message == "Expected an output of type 'int', but received 'str'"
|
410
410
|
|
411
411
|
|
412
|
+
def test_run_node__run_inline__incorrect_output_type_list():
|
413
|
+
"""Confirm that CodeExecutionNodes raise an error if the output type is incorrect during inline execution."""
|
414
|
+
|
415
|
+
# GIVEN a node that subclasses CodeExecutionNode that returns a list but is defined to return an int
|
416
|
+
class ExampleCodeExecutionNode(CodeExecutionNode[BaseState, int]):
|
417
|
+
code = """\
|
418
|
+
def main(output: list[str]) -> int:
|
419
|
+
return output.value
|
420
|
+
"""
|
421
|
+
runtime = "PYTHON_3_11_6"
|
422
|
+
|
423
|
+
code_inputs = {
|
424
|
+
"output": ["hello", "world"],
|
425
|
+
}
|
426
|
+
|
427
|
+
# WHEN we run the node
|
428
|
+
node = ExampleCodeExecutionNode()
|
429
|
+
with pytest.raises(NodeException) as exc_info:
|
430
|
+
node.run()
|
431
|
+
|
432
|
+
# THEN the node should have produced the exception we expected
|
433
|
+
assert exc_info.value.message == "Expected an output of type 'int', but received 'list'"
|
434
|
+
|
435
|
+
|
436
|
+
def test_run_node__run_inline__incorrect_output_type_dict():
|
437
|
+
"""Confirm that CodeExecutionNodes raise an error if the output type is incorrect during inline execution."""
|
438
|
+
|
439
|
+
# GIVEN a node that subclasses CodeExecutionNode that returns a dict but is defined to return an int
|
440
|
+
class ExampleCodeExecutionNode(CodeExecutionNode[BaseState, int]):
|
441
|
+
code = """\
|
442
|
+
def main(output: dict[str, str]) -> int:
|
443
|
+
return output.value
|
444
|
+
"""
|
445
|
+
runtime = "PYTHON_3_11_6"
|
446
|
+
|
447
|
+
code_inputs = {
|
448
|
+
"output": {
|
449
|
+
"foo": "bar",
|
450
|
+
}
|
451
|
+
}
|
452
|
+
|
453
|
+
# WHEN we run the node
|
454
|
+
node = ExampleCodeExecutionNode()
|
455
|
+
with pytest.raises(NodeException) as exc_info:
|
456
|
+
node.run()
|
457
|
+
|
458
|
+
# THEN the node should have produced the exception we expected
|
459
|
+
assert exc_info.value.message == "Expected an output of type 'int', but received 'dict'"
|
460
|
+
|
461
|
+
|
412
462
|
def test_run_node__run_inline__valid_dict_to_pydantic():
|
413
463
|
"""Confirm that CodeExecutionNodes can convert a dict to a Pydantic model during inline execution."""
|
414
464
|
|
@@ -821,3 +871,65 @@ def main(arg1: list) -> str:
|
|
821
871
|
|
822
872
|
# AND the result should be the correct output
|
823
873
|
assert outputs == {"result": "bar", "log": ""}
|
874
|
+
|
875
|
+
|
876
|
+
def test_run_node__string_value_wrapper__get_attr():
|
877
|
+
# GIVEN a node that accesses the 'value' property of a string input
|
878
|
+
class ExampleCodeExecutionNode(CodeExecutionNode[BaseState, str]):
|
879
|
+
code = """\
|
880
|
+
def main(text: str) -> str:
|
881
|
+
return text.value
|
882
|
+
"""
|
883
|
+
code_inputs = {
|
884
|
+
"text": "hello",
|
885
|
+
}
|
886
|
+
runtime = "PYTHON_3_11_6"
|
887
|
+
|
888
|
+
# WHEN we run the node
|
889
|
+
node = ExampleCodeExecutionNode()
|
890
|
+
outputs = node.run()
|
891
|
+
|
892
|
+
# THEN the node should successfully access the string value through the .value property
|
893
|
+
assert outputs == {"result": "hello", "log": ""}
|
894
|
+
|
895
|
+
|
896
|
+
def test_run_node__string_value_wrapper__get_item():
|
897
|
+
# GIVEN a node that accesses the 'value' property of a string input
|
898
|
+
class ExampleCodeExecutionNode(CodeExecutionNode[BaseState, str]):
|
899
|
+
code = """\
|
900
|
+
def main(text: str) -> str:
|
901
|
+
return text["value"]
|
902
|
+
"""
|
903
|
+
code_inputs = {
|
904
|
+
"text": "hello",
|
905
|
+
}
|
906
|
+
runtime = "PYTHON_3_11_6"
|
907
|
+
|
908
|
+
# WHEN we run the node
|
909
|
+
node = ExampleCodeExecutionNode()
|
910
|
+
outputs = node.run()
|
911
|
+
|
912
|
+
# THEN the node should successfully access the string value through the .value property
|
913
|
+
assert outputs == {"result": "hello", "log": ""}
|
914
|
+
|
915
|
+
|
916
|
+
def test_run_node__string_value_wrapper__list_of_dicts():
|
917
|
+
# GIVEN a node that accesses the 'value' property of a string input
|
918
|
+
class ExampleCodeExecutionNode(CodeExecutionNode[BaseState, Any]):
|
919
|
+
code = """\
|
920
|
+
def main(output: list[str]) -> list[str]:
|
921
|
+
results = []
|
922
|
+
for item in output:
|
923
|
+
results.append(item['value'])
|
924
|
+
|
925
|
+
return results
|
926
|
+
"""
|
927
|
+
code_inputs = {"output": ['{"foo": "bar"}', '{"foo2": "bar2"}']}
|
928
|
+
runtime = "PYTHON_3_11_6"
|
929
|
+
|
930
|
+
# WHEN we run the node
|
931
|
+
node = ExampleCodeExecutionNode()
|
932
|
+
outputs = node.run()
|
933
|
+
|
934
|
+
# THEN the node should successfully access the string value
|
935
|
+
assert outputs == {"result": ['{"foo": "bar"}', '{"foo2": "bar2"}'], "log": ""}
|
@@ -8,6 +8,7 @@ from vellum.workflows.errors.types import WorkflowErrorCode
|
|
8
8
|
from vellum.workflows.exceptions import NodeException
|
9
9
|
from vellum.workflows.nodes.utils import cast_to_output_type
|
10
10
|
from vellum.workflows.state.context import WorkflowContext
|
11
|
+
from vellum.workflows.types.code_execution_node_wrappers import ListWrapper, clean_for_dict_wrapper
|
11
12
|
from vellum.workflows.types.core import EntityInputsInterface
|
12
13
|
|
13
14
|
|
@@ -35,58 +36,6 @@ def read_file_from_path(
|
|
35
36
|
return None
|
36
37
|
|
37
38
|
|
38
|
-
class ListWrapper(list):
|
39
|
-
def __getitem__(self, key):
|
40
|
-
item = super().__getitem__(key)
|
41
|
-
if not isinstance(item, DictWrapper) and not isinstance(item, ListWrapper):
|
42
|
-
self.__setitem__(key, _clean_for_dict_wrapper(item))
|
43
|
-
|
44
|
-
return super().__getitem__(key)
|
45
|
-
|
46
|
-
|
47
|
-
class DictWrapper(dict):
|
48
|
-
"""
|
49
|
-
This wraps a dict object to make it behave basically the same as a standard javascript object
|
50
|
-
and enables us to use vellum types here without a shared library since we don't actually
|
51
|
-
typecheck things here.
|
52
|
-
"""
|
53
|
-
|
54
|
-
def __getitem__(self, key):
|
55
|
-
return self.__getattr__(key)
|
56
|
-
|
57
|
-
def __getattr__(self, attr):
|
58
|
-
if attr not in self:
|
59
|
-
if attr == "value":
|
60
|
-
# In order to be backwards compatible with legacy Workflows, which wrapped
|
61
|
-
# several values as VellumValue objects, we use the "value" key to return itself
|
62
|
-
return self
|
63
|
-
|
64
|
-
raise AttributeError(f"dict has no key: '{attr}'")
|
65
|
-
|
66
|
-
item = super().__getitem__(attr)
|
67
|
-
if not isinstance(item, DictWrapper) and not isinstance(item, ListWrapper):
|
68
|
-
self.__setattr__(attr, _clean_for_dict_wrapper(item))
|
69
|
-
|
70
|
-
return super().__getitem__(attr)
|
71
|
-
|
72
|
-
def __setattr__(self, name, value):
|
73
|
-
self[name] = value
|
74
|
-
|
75
|
-
|
76
|
-
def _clean_for_dict_wrapper(obj):
|
77
|
-
if isinstance(obj, dict):
|
78
|
-
wrapped = DictWrapper(obj)
|
79
|
-
for key in wrapped:
|
80
|
-
wrapped[key] = _clean_for_dict_wrapper(wrapped[key])
|
81
|
-
|
82
|
-
return wrapped
|
83
|
-
|
84
|
-
elif isinstance(obj, list):
|
85
|
-
return ListWrapper(map(lambda item: _clean_for_dict_wrapper(item), obj))
|
86
|
-
|
87
|
-
return obj
|
88
|
-
|
89
|
-
|
90
39
|
def run_code_inline(
|
91
40
|
code: str,
|
92
41
|
inputs: EntityInputsInterface,
|
@@ -107,12 +56,12 @@ def run_code_inline(
|
|
107
56
|
(
|
108
57
|
item.model_dump()
|
109
58
|
if isinstance(item, BaseModel)
|
110
|
-
else
|
59
|
+
else clean_for_dict_wrapper(item) if isinstance(item, (dict, list, str)) else item
|
111
60
|
)
|
112
61
|
for item in value
|
113
62
|
]
|
114
63
|
)
|
115
|
-
return
|
64
|
+
return clean_for_dict_wrapper(value)
|
116
65
|
|
117
66
|
exec_globals = {
|
118
67
|
"__arg__inputs": {name: wrap_value(value) for name, value in inputs.items()},
|
@@ -9,7 +9,6 @@ from vellum import (
|
|
9
9
|
PromptOutput,
|
10
10
|
StringVellumValue,
|
11
11
|
)
|
12
|
-
from vellum.workflows.constants import OMIT
|
13
12
|
from vellum.workflows.inputs import BaseInputs
|
14
13
|
from vellum.workflows.nodes import PromptDeploymentNode
|
15
14
|
from vellum.workflows.state import BaseState
|
@@ -66,14 +65,14 @@ def test_text_prompt_deployment_node__basic(vellum_client):
|
|
66
65
|
|
67
66
|
# AND we should have made the expected call to stream the prompt execution
|
68
67
|
vellum_client.execute_prompt_stream.assert_called_once_with(
|
69
|
-
expand_meta=
|
70
|
-
expand_raw=
|
71
|
-
external_id=
|
68
|
+
expand_meta=None,
|
69
|
+
expand_raw=None,
|
70
|
+
external_id=None,
|
72
71
|
inputs=[],
|
73
|
-
metadata=
|
72
|
+
metadata=None,
|
74
73
|
prompt_deployment_id=None,
|
75
74
|
prompt_deployment_name="my-deployment",
|
76
|
-
raw_overrides=
|
75
|
+
raw_overrides=None,
|
77
76
|
release_tag="LATEST",
|
78
77
|
request_options={
|
79
78
|
"additional_body_parameters": {"execution_context": {"parent_context": None, "trace_id": mock.ANY}}
|
vellum/workflows/nodes/utils.py
CHANGED
@@ -1,4 +1,5 @@
|
|
1
1
|
from functools import cache
|
2
|
+
import inspect
|
2
3
|
import json
|
3
4
|
import sys
|
4
5
|
from types import ModuleType
|
@@ -14,6 +15,7 @@ from vellum.workflows.nodes import BaseNode
|
|
14
15
|
from vellum.workflows.nodes.bases.base_adornment_node import BaseAdornmentNode
|
15
16
|
from vellum.workflows.ports.port import Port
|
16
17
|
from vellum.workflows.state.base import BaseState
|
18
|
+
from vellum.workflows.types.code_execution_node_wrappers import DictWrapper, ListWrapper, StringValueWrapper
|
17
19
|
from vellum.workflows.types.core import Json
|
18
20
|
from vellum.workflows.types.generics import NodeType
|
19
21
|
|
@@ -176,6 +178,12 @@ def parse_type_from_str(result_as_str: str, output_type: Any) -> Any:
|
|
176
178
|
|
177
179
|
|
178
180
|
def _get_type_name(obj: Any) -> str:
|
181
|
+
if inspect.isclass(obj) and issubclass(obj, StringValueWrapper):
|
182
|
+
return "str"
|
183
|
+
if inspect.isclass(obj) and issubclass(obj, ListWrapper):
|
184
|
+
return "list"
|
185
|
+
if inspect.isclass(obj) and issubclass(obj, DictWrapper):
|
186
|
+
return "dict"
|
179
187
|
if isinstance(obj, type):
|
180
188
|
return obj.__name__
|
181
189
|
|
@@ -0,0 +1,69 @@
|
|
1
|
+
class StringValueWrapper(str):
|
2
|
+
def __getitem__(self, key):
|
3
|
+
if key == "value":
|
4
|
+
return self
|
5
|
+
raise KeyError(key)
|
6
|
+
|
7
|
+
def __getattr__(self, attr):
|
8
|
+
if attr == "value":
|
9
|
+
return self
|
10
|
+
raise AttributeError(f"'str' object has no attribute '{attr}'")
|
11
|
+
|
12
|
+
|
13
|
+
class ListWrapper(list):
|
14
|
+
def __getitem__(self, key):
|
15
|
+
item = super().__getitem__(key)
|
16
|
+
if not isinstance(item, DictWrapper) and not isinstance(item, ListWrapper):
|
17
|
+
self.__setitem__(key, clean_for_dict_wrapper(item))
|
18
|
+
|
19
|
+
return super().__getitem__(key)
|
20
|
+
|
21
|
+
def __getattr__(self, attr):
|
22
|
+
if attr == "value":
|
23
|
+
return self
|
24
|
+
raise AttributeError(f"'list' object has no attribute '{attr}'")
|
25
|
+
|
26
|
+
|
27
|
+
class DictWrapper(dict):
|
28
|
+
"""
|
29
|
+
This wraps a dict object to make it behave basically the same as a standard javascript object
|
30
|
+
and enables us to use vellum types here without a shared library since we don't actually
|
31
|
+
typecheck things here.
|
32
|
+
"""
|
33
|
+
|
34
|
+
def __getitem__(self, key):
|
35
|
+
return self.__getattr__(key)
|
36
|
+
|
37
|
+
def __getattr__(self, attr):
|
38
|
+
if attr not in self:
|
39
|
+
if attr == "value":
|
40
|
+
# In order to be backwards compatible with legacy Workflows, which wrapped
|
41
|
+
# several values as VellumValue objects, we use the "value" key to return itself
|
42
|
+
return self
|
43
|
+
|
44
|
+
raise AttributeError(f"dict has no key: '{attr}'")
|
45
|
+
|
46
|
+
item = super().__getitem__(attr)
|
47
|
+
if not isinstance(item, DictWrapper) and not isinstance(item, ListWrapper):
|
48
|
+
self.__setattr__(attr, clean_for_dict_wrapper(item))
|
49
|
+
|
50
|
+
return super().__getitem__(attr)
|
51
|
+
|
52
|
+
def __setattr__(self, name, value):
|
53
|
+
self[name] = value
|
54
|
+
|
55
|
+
|
56
|
+
def clean_for_dict_wrapper(obj):
|
57
|
+
if isinstance(obj, dict):
|
58
|
+
wrapped = DictWrapper(obj)
|
59
|
+
for key in wrapped:
|
60
|
+
wrapped[key] = clean_for_dict_wrapper(wrapped[key])
|
61
|
+
|
62
|
+
return wrapped
|
63
|
+
|
64
|
+
elif isinstance(obj, list):
|
65
|
+
return ListWrapper(map(lambda item: clean_for_dict_wrapper(item), obj))
|
66
|
+
elif isinstance(obj, str):
|
67
|
+
return StringValueWrapper(obj)
|
68
|
+
|
69
|
+
return obj
|
@@ -1,22 +1,34 @@
|
|
1
1
|
import os
|
2
|
-
from typing import Optional
|
2
|
+
from typing import List, Optional
|
3
3
|
|
4
4
|
from vellum import Vellum, VellumEnvironment
|
5
5
|
|
6
6
|
|
7
|
-
def create_vellum_client(api_key: Optional[str] = None) -> Vellum:
|
7
|
+
def create_vellum_client(api_key: Optional[str] = None, api_url: Optional[str] = None) -> Vellum:
|
8
8
|
if api_key is None:
|
9
9
|
api_key = os.getenv("VELLUM_API_KEY", default="")
|
10
10
|
|
11
11
|
return Vellum(
|
12
12
|
api_key=api_key,
|
13
|
-
environment=create_vellum_environment(),
|
13
|
+
environment=create_vellum_environment(api_url),
|
14
14
|
)
|
15
15
|
|
16
16
|
|
17
|
-
def create_vellum_environment() -> VellumEnvironment:
|
17
|
+
def create_vellum_environment(api_url: Optional[str] = None) -> VellumEnvironment:
|
18
18
|
return VellumEnvironment(
|
19
|
-
default=
|
20
|
-
documents=
|
21
|
-
predict=
|
19
|
+
default=_resolve_env([api_url, "VELLUM_DEFAULT_API_URL", "VELLUM_API_URL"], "https://api.vellum.ai"),
|
20
|
+
documents=_resolve_env([api_url, "VELLUM_DOCUMENTS_API_URL", "VELLUM_API_URL"], "https://documents.vellum.ai"),
|
21
|
+
predict=_resolve_env([api_url, "VELLUM_PREDICT_API_URL", "VELLUM_API_URL"], "https://predict.vellum.ai"),
|
22
22
|
)
|
23
|
+
|
24
|
+
|
25
|
+
def _resolve_env(names: List[Optional[str]], default: str = "") -> str:
|
26
|
+
for name in names:
|
27
|
+
if not name:
|
28
|
+
continue
|
29
|
+
|
30
|
+
value = os.getenv(name)
|
31
|
+
if value:
|
32
|
+
return value
|
33
|
+
|
34
|
+
return default
|