vellum-ai 1.0.2__py3-none-any.whl → 1.0.4__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 +6 -0
- vellum/client/__init__.py +4 -0
- vellum/client/core/client_wrapper.py +2 -2
- vellum/client/reference.md +58 -0
- vellum/client/resources/__init__.py +2 -0
- vellum/client/resources/workflow_executions/__init__.py +2 -0
- vellum/client/resources/workflow_executions/client.py +125 -0
- vellum/client/types/__init__.py +4 -0
- vellum/client/types/node_output_compiled_thinking_value.py +28 -0
- vellum/client/types/node_output_compiled_value.py +2 -0
- vellum/client/types/organization_limit_config.py +1 -0
- vellum/client/types/workflow_execution_detail.py +42 -0
- vellum/prompts/blocks/compilation.py +5 -1
- vellum/prompts/blocks/tests/test_compilation.py +64 -0
- vellum/resources/workflow_executions/__init__.py +3 -0
- vellum/resources/workflow_executions/client.py +3 -0
- vellum/types/node_output_compiled_thinking_value.py +3 -0
- vellum/types/workflow_execution_detail.py +3 -0
- vellum/workflows/descriptors/base.py +12 -0
- vellum/workflows/expressions/concat.py +32 -0
- vellum/workflows/expressions/tests/test_concat.py +53 -0
- vellum/workflows/nodes/displayable/inline_prompt_node/node.py +1 -2
- vellum/workflows/nodes/displayable/prompt_deployment_node/node.py +1 -2
- vellum/workflows/nodes/displayable/tool_calling_node/composio_service.py +83 -0
- vellum/workflows/nodes/displayable/tool_calling_node/tests/test_composio_service.py +122 -0
- vellum/workflows/nodes/displayable/tool_calling_node/utils.py +28 -6
- vellum/workflows/types/core.py +2 -2
- vellum/workflows/types/definition.py +20 -1
- vellum/workflows/types/tests/test_definition.py +14 -1
- {vellum_ai-1.0.2.dist-info → vellum_ai-1.0.4.dist-info}/METADATA +3 -1
- {vellum_ai-1.0.2.dist-info → vellum_ai-1.0.4.dist-info}/RECORD +34 -22
- {vellum_ai-1.0.2.dist-info → vellum_ai-1.0.4.dist-info}/LICENSE +0 -0
- {vellum_ai-1.0.2.dist-info → vellum_ai-1.0.4.dist-info}/WHEEL +0 -0
- {vellum_ai-1.0.2.dist-info → vellum_ai-1.0.4.dist-info}/entry_points.txt +0 -0
vellum/__init__.py
CHANGED
@@ -272,6 +272,7 @@ from .client.types import (
|
|
272
272
|
NodeOutputCompiledNumberValue,
|
273
273
|
NodeOutputCompiledSearchResultsValue,
|
274
274
|
NodeOutputCompiledStringValue,
|
275
|
+
NodeOutputCompiledThinkingValue,
|
275
276
|
NodeOutputCompiledValue,
|
276
277
|
NodeParentContext,
|
277
278
|
NormalizedLogProbs,
|
@@ -541,6 +542,7 @@ from .client.types import (
|
|
541
542
|
WorkflowExecutionActualChatHistoryRequest,
|
542
543
|
WorkflowExecutionActualJsonRequest,
|
543
544
|
WorkflowExecutionActualStringRequest,
|
545
|
+
WorkflowExecutionDetail,
|
544
546
|
WorkflowExecutionEventErrorCode,
|
545
547
|
WorkflowExecutionEventType,
|
546
548
|
WorkflowExecutionFulfilledBody,
|
@@ -631,6 +633,7 @@ from .resources import (
|
|
631
633
|
test_suite_runs,
|
632
634
|
test_suites,
|
633
635
|
workflow_deployments,
|
636
|
+
workflow_executions,
|
634
637
|
workflow_sandboxes,
|
635
638
|
workflows,
|
636
639
|
workspace_secrets,
|
@@ -919,6 +922,7 @@ __all__ = [
|
|
919
922
|
"NodeOutputCompiledNumberValue",
|
920
923
|
"NodeOutputCompiledSearchResultsValue",
|
921
924
|
"NodeOutputCompiledStringValue",
|
925
|
+
"NodeOutputCompiledThinkingValue",
|
922
926
|
"NodeOutputCompiledValue",
|
923
927
|
"NodeParentContext",
|
924
928
|
"NormalizedLogProbs",
|
@@ -1192,6 +1196,7 @@ __all__ = [
|
|
1192
1196
|
"WorkflowExecutionActualChatHistoryRequest",
|
1193
1197
|
"WorkflowExecutionActualJsonRequest",
|
1194
1198
|
"WorkflowExecutionActualStringRequest",
|
1199
|
+
"WorkflowExecutionDetail",
|
1195
1200
|
"WorkflowExecutionEventErrorCode",
|
1196
1201
|
"WorkflowExecutionEventType",
|
1197
1202
|
"WorkflowExecutionFulfilledBody",
|
@@ -1273,6 +1278,7 @@ __all__ = [
|
|
1273
1278
|
"test_suite_runs",
|
1274
1279
|
"test_suites",
|
1275
1280
|
"workflow_deployments",
|
1281
|
+
"workflow_executions",
|
1276
1282
|
"workflow_sandboxes",
|
1277
1283
|
"workflows",
|
1278
1284
|
"workspace_secrets",
|
vellum/client/__init__.py
CHANGED
@@ -21,6 +21,7 @@ from .resources.test_suite_runs.client import TestSuiteRunsClient
|
|
21
21
|
from .resources.test_suites.client import TestSuitesClient
|
22
22
|
from .resources.workflow_deployments.client import WorkflowDeploymentsClient
|
23
23
|
from .resources.release_reviews.client import ReleaseReviewsClient
|
24
|
+
from .resources.workflow_executions.client import WorkflowExecutionsClient
|
24
25
|
from .resources.workflow_sandboxes.client import WorkflowSandboxesClient
|
25
26
|
from .resources.workflows.client import WorkflowsClient
|
26
27
|
from .resources.workspace_secrets.client import WorkspaceSecretsClient
|
@@ -79,6 +80,7 @@ from .resources.test_suite_runs.client import AsyncTestSuiteRunsClient
|
|
79
80
|
from .resources.test_suites.client import AsyncTestSuitesClient
|
80
81
|
from .resources.workflow_deployments.client import AsyncWorkflowDeploymentsClient
|
81
82
|
from .resources.release_reviews.client import AsyncReleaseReviewsClient
|
83
|
+
from .resources.workflow_executions.client import AsyncWorkflowExecutionsClient
|
82
84
|
from .resources.workflow_sandboxes.client import AsyncWorkflowSandboxesClient
|
83
85
|
from .resources.workflows.client import AsyncWorkflowsClient
|
84
86
|
from .resources.workspace_secrets.client import AsyncWorkspaceSecretsClient
|
@@ -163,6 +165,7 @@ class Vellum:
|
|
163
165
|
self.test_suites = TestSuitesClient(client_wrapper=self._client_wrapper)
|
164
166
|
self.workflow_deployments = WorkflowDeploymentsClient(client_wrapper=self._client_wrapper)
|
165
167
|
self.release_reviews = ReleaseReviewsClient(client_wrapper=self._client_wrapper)
|
168
|
+
self.workflow_executions = WorkflowExecutionsClient(client_wrapper=self._client_wrapper)
|
166
169
|
self.workflow_sandboxes = WorkflowSandboxesClient(client_wrapper=self._client_wrapper)
|
167
170
|
self.workflows = WorkflowsClient(client_wrapper=self._client_wrapper)
|
168
171
|
self.workspace_secrets = WorkspaceSecretsClient(client_wrapper=self._client_wrapper)
|
@@ -1597,6 +1600,7 @@ class AsyncVellum:
|
|
1597
1600
|
self.test_suites = AsyncTestSuitesClient(client_wrapper=self._client_wrapper)
|
1598
1601
|
self.workflow_deployments = AsyncWorkflowDeploymentsClient(client_wrapper=self._client_wrapper)
|
1599
1602
|
self.release_reviews = AsyncReleaseReviewsClient(client_wrapper=self._client_wrapper)
|
1603
|
+
self.workflow_executions = AsyncWorkflowExecutionsClient(client_wrapper=self._client_wrapper)
|
1600
1604
|
self.workflow_sandboxes = AsyncWorkflowSandboxesClient(client_wrapper=self._client_wrapper)
|
1601
1605
|
self.workflows = AsyncWorkflowsClient(client_wrapper=self._client_wrapper)
|
1602
1606
|
self.workspace_secrets = AsyncWorkspaceSecretsClient(client_wrapper=self._client_wrapper)
|
@@ -25,10 +25,10 @@ class BaseClientWrapper:
|
|
25
25
|
|
26
26
|
def get_headers(self) -> typing.Dict[str, str]:
|
27
27
|
headers: typing.Dict[str, str] = {
|
28
|
-
"User-Agent": "vellum-ai/1.0.
|
28
|
+
"User-Agent": "vellum-ai/1.0.4",
|
29
29
|
"X-Fern-Language": "Python",
|
30
30
|
"X-Fern-SDK-Name": "vellum-ai",
|
31
|
-
"X-Fern-SDK-Version": "1.0.
|
31
|
+
"X-Fern-SDK-Version": "1.0.4",
|
32
32
|
}
|
33
33
|
if self._api_version is not None:
|
34
34
|
headers["X-API-Version"] = self._api_version
|
vellum/client/reference.md
CHANGED
@@ -6029,6 +6029,64 @@ client.release_reviews.retrieve_workflow_deployment_release(
|
|
6029
6029
|
</dl>
|
6030
6030
|
|
6031
6031
|
|
6032
|
+
</dd>
|
6033
|
+
</dl>
|
6034
|
+
</details>
|
6035
|
+
|
6036
|
+
## WorkflowExecutions
|
6037
|
+
<details><summary><code>client.workflow_executions.<a href="src/vellum/resources/workflow_executions/client.py">retrieve_workflow_execution_detail</a>(...)</code></summary>
|
6038
|
+
<dl>
|
6039
|
+
<dd>
|
6040
|
+
|
6041
|
+
#### 🔌 Usage
|
6042
|
+
|
6043
|
+
<dl>
|
6044
|
+
<dd>
|
6045
|
+
|
6046
|
+
<dl>
|
6047
|
+
<dd>
|
6048
|
+
|
6049
|
+
```python
|
6050
|
+
from vellum import Vellum
|
6051
|
+
|
6052
|
+
client = Vellum(
|
6053
|
+
api_version="YOUR_API_VERSION",
|
6054
|
+
api_key="YOUR_API_KEY",
|
6055
|
+
)
|
6056
|
+
client.workflow_executions.retrieve_workflow_execution_detail(
|
6057
|
+
execution_id="execution_id",
|
6058
|
+
)
|
6059
|
+
|
6060
|
+
```
|
6061
|
+
</dd>
|
6062
|
+
</dl>
|
6063
|
+
</dd>
|
6064
|
+
</dl>
|
6065
|
+
|
6066
|
+
#### ⚙️ Parameters
|
6067
|
+
|
6068
|
+
<dl>
|
6069
|
+
<dd>
|
6070
|
+
|
6071
|
+
<dl>
|
6072
|
+
<dd>
|
6073
|
+
|
6074
|
+
**execution_id:** `str`
|
6075
|
+
|
6076
|
+
</dd>
|
6077
|
+
</dl>
|
6078
|
+
|
6079
|
+
<dl>
|
6080
|
+
<dd>
|
6081
|
+
|
6082
|
+
**request_options:** `typing.Optional[RequestOptions]` — Request-specific configuration.
|
6083
|
+
|
6084
|
+
</dd>
|
6085
|
+
</dl>
|
6086
|
+
</dd>
|
6087
|
+
</dl>
|
6088
|
+
|
6089
|
+
|
6032
6090
|
</dd>
|
6033
6091
|
</dl>
|
6034
6092
|
</details>
|
@@ -16,6 +16,7 @@ from . import (
|
|
16
16
|
test_suite_runs,
|
17
17
|
test_suites,
|
18
18
|
workflow_deployments,
|
19
|
+
workflow_executions,
|
19
20
|
workflow_sandboxes,
|
20
21
|
workflows,
|
21
22
|
workspace_secrets,
|
@@ -50,6 +51,7 @@ __all__ = [
|
|
50
51
|
"test_suite_runs",
|
51
52
|
"test_suites",
|
52
53
|
"workflow_deployments",
|
54
|
+
"workflow_executions",
|
53
55
|
"workflow_sandboxes",
|
54
56
|
"workflows",
|
55
57
|
"workspace_secrets",
|
@@ -0,0 +1,125 @@
|
|
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.workflow_execution_detail import WorkflowExecutionDetail
|
7
|
+
from ...core.jsonable_encoder import jsonable_encoder
|
8
|
+
from ...core.pydantic_utilities import parse_obj_as
|
9
|
+
from json.decoder import JSONDecodeError
|
10
|
+
from ...core.api_error import ApiError
|
11
|
+
from ...core.client_wrapper import AsyncClientWrapper
|
12
|
+
|
13
|
+
|
14
|
+
class WorkflowExecutionsClient:
|
15
|
+
def __init__(self, *, client_wrapper: SyncClientWrapper):
|
16
|
+
self._client_wrapper = client_wrapper
|
17
|
+
|
18
|
+
def retrieve_workflow_execution_detail(
|
19
|
+
self, execution_id: str, *, request_options: typing.Optional[RequestOptions] = None
|
20
|
+
) -> WorkflowExecutionDetail:
|
21
|
+
"""
|
22
|
+
Parameters
|
23
|
+
----------
|
24
|
+
execution_id : str
|
25
|
+
|
26
|
+
request_options : typing.Optional[RequestOptions]
|
27
|
+
Request-specific configuration.
|
28
|
+
|
29
|
+
Returns
|
30
|
+
-------
|
31
|
+
WorkflowExecutionDetail
|
32
|
+
|
33
|
+
|
34
|
+
Examples
|
35
|
+
--------
|
36
|
+
from vellum import Vellum
|
37
|
+
|
38
|
+
client = Vellum(
|
39
|
+
api_version="YOUR_API_VERSION",
|
40
|
+
api_key="YOUR_API_KEY",
|
41
|
+
)
|
42
|
+
client.workflow_executions.retrieve_workflow_execution_detail(
|
43
|
+
execution_id="execution_id",
|
44
|
+
)
|
45
|
+
"""
|
46
|
+
_response = self._client_wrapper.httpx_client.request(
|
47
|
+
f"v1/workflow-executions/{jsonable_encoder(execution_id)}/detail",
|
48
|
+
base_url=self._client_wrapper.get_environment().default,
|
49
|
+
method="GET",
|
50
|
+
request_options=request_options,
|
51
|
+
)
|
52
|
+
try:
|
53
|
+
if 200 <= _response.status_code < 300:
|
54
|
+
return typing.cast(
|
55
|
+
WorkflowExecutionDetail,
|
56
|
+
parse_obj_as(
|
57
|
+
type_=WorkflowExecutionDetail, # type: ignore
|
58
|
+
object_=_response.json(),
|
59
|
+
),
|
60
|
+
)
|
61
|
+
_response_json = _response.json()
|
62
|
+
except JSONDecodeError:
|
63
|
+
raise ApiError(status_code=_response.status_code, body=_response.text)
|
64
|
+
raise ApiError(status_code=_response.status_code, body=_response_json)
|
65
|
+
|
66
|
+
|
67
|
+
class AsyncWorkflowExecutionsClient:
|
68
|
+
def __init__(self, *, client_wrapper: AsyncClientWrapper):
|
69
|
+
self._client_wrapper = client_wrapper
|
70
|
+
|
71
|
+
async def retrieve_workflow_execution_detail(
|
72
|
+
self, execution_id: str, *, request_options: typing.Optional[RequestOptions] = None
|
73
|
+
) -> WorkflowExecutionDetail:
|
74
|
+
"""
|
75
|
+
Parameters
|
76
|
+
----------
|
77
|
+
execution_id : str
|
78
|
+
|
79
|
+
request_options : typing.Optional[RequestOptions]
|
80
|
+
Request-specific configuration.
|
81
|
+
|
82
|
+
Returns
|
83
|
+
-------
|
84
|
+
WorkflowExecutionDetail
|
85
|
+
|
86
|
+
|
87
|
+
Examples
|
88
|
+
--------
|
89
|
+
import asyncio
|
90
|
+
|
91
|
+
from vellum import AsyncVellum
|
92
|
+
|
93
|
+
client = AsyncVellum(
|
94
|
+
api_version="YOUR_API_VERSION",
|
95
|
+
api_key="YOUR_API_KEY",
|
96
|
+
)
|
97
|
+
|
98
|
+
|
99
|
+
async def main() -> None:
|
100
|
+
await client.workflow_executions.retrieve_workflow_execution_detail(
|
101
|
+
execution_id="execution_id",
|
102
|
+
)
|
103
|
+
|
104
|
+
|
105
|
+
asyncio.run(main())
|
106
|
+
"""
|
107
|
+
_response = await self._client_wrapper.httpx_client.request(
|
108
|
+
f"v1/workflow-executions/{jsonable_encoder(execution_id)}/detail",
|
109
|
+
base_url=self._client_wrapper.get_environment().default,
|
110
|
+
method="GET",
|
111
|
+
request_options=request_options,
|
112
|
+
)
|
113
|
+
try:
|
114
|
+
if 200 <= _response.status_code < 300:
|
115
|
+
return typing.cast(
|
116
|
+
WorkflowExecutionDetail,
|
117
|
+
parse_obj_as(
|
118
|
+
type_=WorkflowExecutionDetail, # type: ignore
|
119
|
+
object_=_response.json(),
|
120
|
+
),
|
121
|
+
)
|
122
|
+
_response_json = _response.json()
|
123
|
+
except JSONDecodeError:
|
124
|
+
raise ApiError(status_code=_response.status_code, body=_response.text)
|
125
|
+
raise ApiError(status_code=_response.status_code, body=_response_json)
|
vellum/client/types/__init__.py
CHANGED
@@ -280,6 +280,7 @@ from .node_output_compiled_json_value import NodeOutputCompiledJsonValue
|
|
280
280
|
from .node_output_compiled_number_value import NodeOutputCompiledNumberValue
|
281
281
|
from .node_output_compiled_search_results_value import NodeOutputCompiledSearchResultsValue
|
282
282
|
from .node_output_compiled_string_value import NodeOutputCompiledStringValue
|
283
|
+
from .node_output_compiled_thinking_value import NodeOutputCompiledThinkingValue
|
283
284
|
from .node_output_compiled_value import NodeOutputCompiledValue
|
284
285
|
from .node_parent_context import NodeParentContext
|
285
286
|
from .normalized_log_probs import NormalizedLogProbs
|
@@ -565,6 +566,7 @@ from .workflow_execution_actual import WorkflowExecutionActual
|
|
565
566
|
from .workflow_execution_actual_chat_history_request import WorkflowExecutionActualChatHistoryRequest
|
566
567
|
from .workflow_execution_actual_json_request import WorkflowExecutionActualJsonRequest
|
567
568
|
from .workflow_execution_actual_string_request import WorkflowExecutionActualStringRequest
|
569
|
+
from .workflow_execution_detail import WorkflowExecutionDetail
|
568
570
|
from .workflow_execution_event_error_code import WorkflowExecutionEventErrorCode
|
569
571
|
from .workflow_execution_event_type import WorkflowExecutionEventType
|
570
572
|
from .workflow_execution_fulfilled_body import WorkflowExecutionFulfilledBody
|
@@ -900,6 +902,7 @@ __all__ = [
|
|
900
902
|
"NodeOutputCompiledNumberValue",
|
901
903
|
"NodeOutputCompiledSearchResultsValue",
|
902
904
|
"NodeOutputCompiledStringValue",
|
905
|
+
"NodeOutputCompiledThinkingValue",
|
903
906
|
"NodeOutputCompiledValue",
|
904
907
|
"NodeParentContext",
|
905
908
|
"NormalizedLogProbs",
|
@@ -1169,6 +1172,7 @@ __all__ = [
|
|
1169
1172
|
"WorkflowExecutionActualChatHistoryRequest",
|
1170
1173
|
"WorkflowExecutionActualJsonRequest",
|
1171
1174
|
"WorkflowExecutionActualStringRequest",
|
1175
|
+
"WorkflowExecutionDetail",
|
1172
1176
|
"WorkflowExecutionEventErrorCode",
|
1173
1177
|
"WorkflowExecutionEventType",
|
1174
1178
|
"WorkflowExecutionFulfilledBody",
|
@@ -0,0 +1,28 @@
|
|
1
|
+
# This file was auto-generated by Fern from our API Definition.
|
2
|
+
|
3
|
+
from ..core.pydantic_utilities import UniversalBaseModel
|
4
|
+
import typing
|
5
|
+
from .string_vellum_value import StringVellumValue
|
6
|
+
from .workflow_node_result_event_state import WorkflowNodeResultEventState
|
7
|
+
from ..core.pydantic_utilities import IS_PYDANTIC_V2
|
8
|
+
import pydantic
|
9
|
+
|
10
|
+
|
11
|
+
class NodeOutputCompiledThinkingValue(UniversalBaseModel):
|
12
|
+
"""
|
13
|
+
An output returned by a node that is of type THINKING.
|
14
|
+
"""
|
15
|
+
|
16
|
+
type: typing.Literal["THINKING"] = "THINKING"
|
17
|
+
value: typing.Optional[StringVellumValue] = None
|
18
|
+
node_output_id: str
|
19
|
+
state: typing.Optional[WorkflowNodeResultEventState] = None
|
20
|
+
|
21
|
+
if IS_PYDANTIC_V2:
|
22
|
+
model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict(extra="allow", frozen=True) # type: ignore # Pydantic v2
|
23
|
+
else:
|
24
|
+
|
25
|
+
class Config:
|
26
|
+
frozen = True
|
27
|
+
smart_union = True
|
28
|
+
extra = pydantic.Extra.allow
|
@@ -9,6 +9,7 @@ from .node_output_compiled_search_results_value import NodeOutputCompiledSearchR
|
|
9
9
|
from .node_output_compiled_error_value import NodeOutputCompiledErrorValue
|
10
10
|
from .node_output_compiled_array_value import NodeOutputCompiledArrayValue
|
11
11
|
from .node_output_compiled_function_call_value import NodeOutputCompiledFunctionCallValue
|
12
|
+
from .node_output_compiled_thinking_value import NodeOutputCompiledThinkingValue
|
12
13
|
|
13
14
|
NodeOutputCompiledValue = typing.Union[
|
14
15
|
NodeOutputCompiledStringValue,
|
@@ -19,4 +20,5 @@ NodeOutputCompiledValue = typing.Union[
|
|
19
20
|
NodeOutputCompiledErrorValue,
|
20
21
|
NodeOutputCompiledArrayValue,
|
21
22
|
NodeOutputCompiledFunctionCallValue,
|
23
|
+
NodeOutputCompiledThinkingValue,
|
22
24
|
]
|
@@ -13,6 +13,7 @@ class OrganizationLimitConfig(UniversalBaseModel):
|
|
13
13
|
prompt_executions_quota: typing.Optional[Quota] = None
|
14
14
|
workflow_executions_quota: typing.Optional[Quota] = None
|
15
15
|
workflow_runtime_seconds_quota: typing.Optional[Quota] = None
|
16
|
+
max_workflow_runtime_seconds: typing.Optional[int] = None
|
16
17
|
|
17
18
|
if IS_PYDANTIC_V2:
|
18
19
|
model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict(extra="allow", frozen=True) # type: ignore # Pydantic v2
|
@@ -0,0 +1,42 @@
|
|
1
|
+
# This file was auto-generated by Fern from our API Definition.
|
2
|
+
|
3
|
+
from ..core.pydantic_utilities import UniversalBaseModel
|
4
|
+
from .api_request_parent_context import ApiRequestParentContext
|
5
|
+
from .node_parent_context import NodeParentContext
|
6
|
+
from .prompt_deployment_parent_context import PromptDeploymentParentContext
|
7
|
+
from .span_link import SpanLink
|
8
|
+
from .workflow_deployment_parent_context import WorkflowDeploymentParentContext
|
9
|
+
from .workflow_parent_context import WorkflowParentContext
|
10
|
+
from .workflow_sandbox_parent_context import WorkflowSandboxParentContext
|
11
|
+
from .array_vellum_value import ArrayVellumValue
|
12
|
+
import typing
|
13
|
+
from .parent_context import ParentContext
|
14
|
+
import datetime as dt
|
15
|
+
from .execution_vellum_value import ExecutionVellumValue
|
16
|
+
from .workflow_error import WorkflowError
|
17
|
+
from .workflow_execution_usage_result import WorkflowExecutionUsageResult
|
18
|
+
from .vellum_span import VellumSpan
|
19
|
+
from ..core.pydantic_utilities import IS_PYDANTIC_V2
|
20
|
+
import pydantic
|
21
|
+
|
22
|
+
|
23
|
+
class WorkflowExecutionDetail(UniversalBaseModel):
|
24
|
+
span_id: str
|
25
|
+
parent_context: typing.Optional[ParentContext] = None
|
26
|
+
start: dt.datetime
|
27
|
+
end: typing.Optional[dt.datetime] = None
|
28
|
+
inputs: typing.List[ExecutionVellumValue]
|
29
|
+
outputs: typing.List[ExecutionVellumValue]
|
30
|
+
error: typing.Optional[WorkflowError] = None
|
31
|
+
usage_results: typing.Optional[typing.List[WorkflowExecutionUsageResult]] = None
|
32
|
+
spans: typing.List[VellumSpan]
|
33
|
+
state: typing.Optional[typing.Dict[str, typing.Optional[typing.Any]]] = None
|
34
|
+
|
35
|
+
if IS_PYDANTIC_V2:
|
36
|
+
model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict(extra="allow", frozen=True) # type: ignore # Pydantic v2
|
37
|
+
else:
|
38
|
+
|
39
|
+
class Config:
|
40
|
+
frozen = True
|
41
|
+
smart_union = True
|
42
|
+
extra = pydantic.Extra.allow
|
@@ -105,7 +105,11 @@ def compile_prompt_blocks(
|
|
105
105
|
cache_config=block.cache_config,
|
106
106
|
)
|
107
107
|
)
|
108
|
-
elif compiled_input == "JSON":
|
108
|
+
elif compiled_input.type == "JSON":
|
109
|
+
# Skip empty JSON arrays when there are chat message blocks present
|
110
|
+
if compiled_input.value == [] and any(block.block_type == "CHAT_MESSAGE" for block in compiled_blocks):
|
111
|
+
continue
|
112
|
+
|
109
113
|
compiled_blocks.append(
|
110
114
|
CompiledValuePromptBlock(
|
111
115
|
content=JsonVellumValue(value=compiled_input.value),
|
@@ -10,7 +10,10 @@ from vellum import (
|
|
10
10
|
VariablePromptBlock,
|
11
11
|
VellumVariable,
|
12
12
|
)
|
13
|
+
from vellum.client.types.json_vellum_value import JsonVellumValue
|
13
14
|
from vellum.client.types.number_input import NumberInput
|
15
|
+
from vellum.client.types.prompt_block import PromptBlock
|
16
|
+
from vellum.client.types.prompt_request_json_input import PromptRequestJsonInput
|
14
17
|
from vellum.prompts.blocks.compilation import compile_prompt_blocks
|
15
18
|
from vellum.prompts.blocks.types import CompiledChatMessagePromptBlock, CompiledValuePromptBlock
|
16
19
|
|
@@ -146,3 +149,64 @@ def test_compile_prompt_blocks__happy(blocks, inputs, input_variables, expected)
|
|
146
149
|
actual = compile_prompt_blocks(blocks=blocks, inputs=inputs, input_variables=input_variables)
|
147
150
|
|
148
151
|
assert actual == expected
|
152
|
+
|
153
|
+
|
154
|
+
def test_compile_prompt_blocks__empty_json_variable_with_chat_message_blocks():
|
155
|
+
"""Test JSON variable handling logic, specifically the empty array skipping behavior."""
|
156
|
+
|
157
|
+
# GIVEN empty array with chat message blocks
|
158
|
+
blocks_with_chat: list[PromptBlock] = [
|
159
|
+
ChatMessagePromptBlock(
|
160
|
+
chat_role="USER",
|
161
|
+
blocks=[RichTextPromptBlock(blocks=[PlainTextPromptBlock(text="User message")])],
|
162
|
+
),
|
163
|
+
VariablePromptBlock(input_variable="json_data"),
|
164
|
+
]
|
165
|
+
|
166
|
+
inputs_with_empty_json = [PromptRequestJsonInput(key="json_data", value=[], type="JSON")]
|
167
|
+
|
168
|
+
input_variables = [VellumVariable(id="901ec2d6-430c-4341-b963-ca689006f5cc", type="JSON", key="json_data")]
|
169
|
+
|
170
|
+
# THEN the empty JSON array should be skipped when there are chat message blocks
|
171
|
+
expected_with_chat = [
|
172
|
+
CompiledChatMessagePromptBlock(
|
173
|
+
role="USER",
|
174
|
+
blocks=[CompiledValuePromptBlock(content=StringVellumValue(value="User message"))],
|
175
|
+
),
|
176
|
+
]
|
177
|
+
|
178
|
+
actual = compile_prompt_blocks(
|
179
|
+
blocks=blocks_with_chat, inputs=inputs_with_empty_json, input_variables=input_variables
|
180
|
+
)
|
181
|
+
assert actual == expected_with_chat
|
182
|
+
|
183
|
+
|
184
|
+
def test_compile_prompt_blocks__non_empty_json_variable_with_chat_message_blocks():
|
185
|
+
"""Test that non-empty JSON variables are included even when there are chat message blocks."""
|
186
|
+
|
187
|
+
# GIVEN non-empty JSON with chat message blocks
|
188
|
+
blocks_with_chat: list[PromptBlock] = [
|
189
|
+
ChatMessagePromptBlock(
|
190
|
+
chat_role="USER",
|
191
|
+
blocks=[RichTextPromptBlock(blocks=[PlainTextPromptBlock(text="User message")])],
|
192
|
+
),
|
193
|
+
VariablePromptBlock(input_variable="json_data"),
|
194
|
+
]
|
195
|
+
|
196
|
+
inputs_with_non_empty_json = [PromptRequestJsonInput(key="json_data", value={"key": "value"}, type="JSON")]
|
197
|
+
|
198
|
+
input_variables = [VellumVariable(id="901ec2d6-430c-4341-b963-ca689006f5cc", type="JSON", key="json_data")]
|
199
|
+
|
200
|
+
# THEN the non-empty JSON should be included
|
201
|
+
expected_with_non_empty = [
|
202
|
+
CompiledChatMessagePromptBlock(
|
203
|
+
role="USER",
|
204
|
+
blocks=[CompiledValuePromptBlock(content=StringVellumValue(value="User message"))],
|
205
|
+
),
|
206
|
+
CompiledValuePromptBlock(content=JsonVellumValue(value={"key": "value"})),
|
207
|
+
]
|
208
|
+
|
209
|
+
actual = compile_prompt_blocks(
|
210
|
+
blocks=blocks_with_chat, inputs=inputs_with_non_empty_json, input_variables=input_variables
|
211
|
+
)
|
212
|
+
assert actual == expected_with_non_empty
|
@@ -6,6 +6,7 @@ if TYPE_CHECKING:
|
|
6
6
|
from vellum.workflows.expressions.begins_with import BeginsWithExpression
|
7
7
|
from vellum.workflows.expressions.between import BetweenExpression
|
8
8
|
from vellum.workflows.expressions.coalesce_expression import CoalesceExpression
|
9
|
+
from vellum.workflows.expressions.concat import ConcatExpression
|
9
10
|
from vellum.workflows.expressions.contains import ContainsExpression
|
10
11
|
from vellum.workflows.expressions.does_not_begin_with import DoesNotBeginWithExpression
|
11
12
|
from vellum.workflows.expressions.does_not_contain import DoesNotContainExpression
|
@@ -364,3 +365,14 @@ class BaseDescriptor(Generic[_T]):
|
|
364
365
|
from vellum.workflows.expressions.is_error import IsErrorExpression
|
365
366
|
|
366
367
|
return IsErrorExpression(expression=self)
|
368
|
+
|
369
|
+
@overload
|
370
|
+
def concat(self, other: "BaseDescriptor[_O]") -> "ConcatExpression[_T, _O]": ...
|
371
|
+
|
372
|
+
@overload
|
373
|
+
def concat(self, other: _O) -> "ConcatExpression[_T, _O]": ...
|
374
|
+
|
375
|
+
def concat(self, other: "Union[BaseDescriptor[_O], _O]") -> "ConcatExpression[_T, _O]":
|
376
|
+
from vellum.workflows.expressions.concat import ConcatExpression
|
377
|
+
|
378
|
+
return ConcatExpression(lhs=self, rhs=other)
|
@@ -0,0 +1,32 @@
|
|
1
|
+
from typing import Generic, TypeVar, Union
|
2
|
+
|
3
|
+
from vellum.workflows.descriptors.base import BaseDescriptor
|
4
|
+
from vellum.workflows.descriptors.exceptions import InvalidExpressionException
|
5
|
+
from vellum.workflows.descriptors.utils import resolve_value
|
6
|
+
from vellum.workflows.state.base import BaseState
|
7
|
+
|
8
|
+
LHS = TypeVar("LHS")
|
9
|
+
RHS = TypeVar("RHS")
|
10
|
+
|
11
|
+
|
12
|
+
class ConcatExpression(BaseDescriptor[list], Generic[LHS, RHS]):
|
13
|
+
def __init__(
|
14
|
+
self,
|
15
|
+
*,
|
16
|
+
lhs: Union[BaseDescriptor[LHS], LHS],
|
17
|
+
rhs: Union[BaseDescriptor[RHS], RHS],
|
18
|
+
) -> None:
|
19
|
+
super().__init__(name=f"{lhs} + {rhs}", types=(list,))
|
20
|
+
self._lhs = lhs
|
21
|
+
self._rhs = rhs
|
22
|
+
|
23
|
+
def resolve(self, state: "BaseState") -> list:
|
24
|
+
lval = resolve_value(self._lhs, state)
|
25
|
+
rval = resolve_value(self._rhs, state)
|
26
|
+
|
27
|
+
if not isinstance(lval, list):
|
28
|
+
raise InvalidExpressionException(f"Expected LHS to be a list, got {type(lval)}")
|
29
|
+
if not isinstance(rval, list):
|
30
|
+
raise InvalidExpressionException(f"Expected RHS to be a list, got {type(rval)}")
|
31
|
+
|
32
|
+
return lval + rval
|
@@ -0,0 +1,53 @@
|
|
1
|
+
import pytest
|
2
|
+
|
3
|
+
from vellum.workflows.descriptors.exceptions import InvalidExpressionException
|
4
|
+
from vellum.workflows.references.constant import ConstantValueReference
|
5
|
+
from vellum.workflows.state.base import BaseState
|
6
|
+
|
7
|
+
|
8
|
+
class TestState(BaseState):
|
9
|
+
pass
|
10
|
+
|
11
|
+
|
12
|
+
def test_concat_expression_happy_path():
|
13
|
+
# GIVEN two lists
|
14
|
+
state = TestState()
|
15
|
+
lhs_ref = ConstantValueReference([1, 2, 3])
|
16
|
+
rhs_ref = ConstantValueReference([4, 5, 6])
|
17
|
+
concat_expr = lhs_ref.concat(rhs_ref)
|
18
|
+
|
19
|
+
# WHEN we resolve the expression
|
20
|
+
result = concat_expr.resolve(state)
|
21
|
+
|
22
|
+
# THEN the lists should be concatenated
|
23
|
+
assert result == [1, 2, 3, 4, 5, 6]
|
24
|
+
|
25
|
+
|
26
|
+
def test_concat_expression_lhs_fail():
|
27
|
+
# GIVEN a non-list lhs and a list rhs
|
28
|
+
state = TestState()
|
29
|
+
lhs_ref = ConstantValueReference(0)
|
30
|
+
rhs_ref = ConstantValueReference([4, 5, 6])
|
31
|
+
concat_expr = lhs_ref.concat(rhs_ref)
|
32
|
+
|
33
|
+
# WHEN we attempt to resolve the expression
|
34
|
+
with pytest.raises(InvalidExpressionException) as exc_info:
|
35
|
+
concat_expr.resolve(state)
|
36
|
+
|
37
|
+
# THEN an exception should be raised
|
38
|
+
assert "Expected LHS to be a list, got <class 'int'>" in str(exc_info.value)
|
39
|
+
|
40
|
+
|
41
|
+
def test_concat_expression_rhs_fail():
|
42
|
+
# GIVEN a list lhs and a non-list rhs
|
43
|
+
state = TestState()
|
44
|
+
lhs_ref = ConstantValueReference([1, 2, 3])
|
45
|
+
rhs_ref = ConstantValueReference(False)
|
46
|
+
concat_expr = lhs_ref.concat(rhs_ref)
|
47
|
+
|
48
|
+
# WHEN we attempt to resolve the expression
|
49
|
+
with pytest.raises(InvalidExpressionException) as exc_info:
|
50
|
+
concat_expr.resolve(state)
|
51
|
+
|
52
|
+
# THEN an exception should be raised
|
53
|
+
assert "Expected RHS to be a list, got <class 'bool'>" in str(exc_info.value)
|
@@ -64,8 +64,7 @@ class InlinePromptNode(BaseInlinePromptNode[StateType]):
|
|
64
64
|
elif output.type == "FUNCTION_CALL":
|
65
65
|
string_outputs.append(output.value.model_dump_json(indent=4))
|
66
66
|
elif output.type == "THINKING":
|
67
|
-
|
68
|
-
string_outputs.append(output.value.value)
|
67
|
+
continue
|
69
68
|
else:
|
70
69
|
string_outputs.append(output.value.message)
|
71
70
|
|