vellum-ai 0.14.37__py3-none-any.whl → 0.14.39__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 +10 -0
- vellum/client/core/client_wrapper.py +1 -1
- vellum/client/reference.md +6272 -0
- vellum/client/types/__init__.py +10 -0
- vellum/client/types/ad_hoc_fulfilled_prompt_execution_meta.py +2 -0
- vellum/client/types/fulfilled_prompt_execution_meta.py +2 -0
- vellum/client/types/test_suite_run_exec_config_request.py +4 -0
- vellum/client/types/test_suite_run_progress.py +20 -0
- vellum/client/types/test_suite_run_prompt_sandbox_exec_config_data_request.py +27 -0
- vellum/client/types/test_suite_run_prompt_sandbox_exec_config_request.py +29 -0
- vellum/client/types/test_suite_run_read.py +3 -0
- vellum/client/types/test_suite_run_workflow_sandbox_exec_config_data_request.py +22 -0
- vellum/client/types/test_suite_run_workflow_sandbox_exec_config_request.py +29 -0
- vellum/client/types/vellum_sdk_error_code_enum.py +1 -0
- vellum/client/types/workflow_execution_event_error_code.py +1 -0
- vellum/plugins/pydantic.py +1 -1
- vellum/types/test_suite_run_progress.py +3 -0
- vellum/types/test_suite_run_prompt_sandbox_exec_config_data_request.py +3 -0
- vellum/types/test_suite_run_prompt_sandbox_exec_config_request.py +3 -0
- vellum/types/test_suite_run_workflow_sandbox_exec_config_data_request.py +3 -0
- vellum/types/test_suite_run_workflow_sandbox_exec_config_request.py +3 -0
- vellum/workflows/errors/types.py +1 -0
- vellum/workflows/events/node.py +2 -1
- vellum/workflows/events/tests/test_event.py +1 -0
- vellum/workflows/events/types.py +3 -40
- vellum/workflows/events/workflow.py +15 -4
- vellum/workflows/nodes/displayable/bases/base_prompt_node/node.py +7 -1
- vellum/workflows/nodes/displayable/bases/prompt_deployment_node.py +94 -3
- vellum/workflows/nodes/displayable/conftest.py +2 -6
- vellum/workflows/nodes/displayable/guardrail_node/node.py +1 -1
- vellum/workflows/nodes/displayable/guardrail_node/tests/__init__.py +0 -0
- vellum/workflows/nodes/displayable/guardrail_node/tests/test_node.py +50 -0
- vellum/workflows/nodes/displayable/inline_prompt_node/tests/test_node.py +6 -1
- vellum/workflows/nodes/displayable/prompt_deployment_node/tests/test_node.py +323 -0
- vellum/workflows/runner/runner.py +78 -57
- vellum/workflows/state/base.py +177 -50
- vellum/workflows/state/tests/test_state.py +26 -20
- vellum/workflows/types/definition.py +71 -0
- vellum/workflows/types/generics.py +34 -1
- vellum/workflows/workflows/base.py +26 -19
- vellum/workflows/workflows/tests/test_base_workflow.py +232 -1
- {vellum_ai-0.14.37.dist-info → vellum_ai-0.14.39.dist-info}/METADATA +1 -1
- {vellum_ai-0.14.37.dist-info → vellum_ai-0.14.39.dist-info}/RECORD +49 -35
- vellum_cli/push.py +2 -3
- vellum_cli/tests/test_push.py +52 -0
- vellum_ee/workflows/display/vellum.py +0 -5
- {vellum_ai-0.14.37.dist-info → vellum_ai-0.14.39.dist-info}/LICENSE +0 -0
- {vellum_ai-0.14.37.dist-info → vellum_ai-0.14.39.dist-info}/WHEEL +0 -0
- {vellum_ai-0.14.37.dist-info → vellum_ai-0.14.39.dist-info}/entry_points.txt +0 -0
@@ -0,0 +1,50 @@
|
|
1
|
+
from vellum import TestSuiteRunMetricNumberOutput
|
2
|
+
from vellum.client.types.chat_history_input import ChatHistoryInput
|
3
|
+
from vellum.client.types.chat_message import ChatMessage
|
4
|
+
from vellum.client.types.json_input import JsonInput
|
5
|
+
from vellum.client.types.metric_definition_execution import MetricDefinitionExecution
|
6
|
+
from vellum.client.types.number_input import NumberInput
|
7
|
+
from vellum.client.types.string_input import StringInput
|
8
|
+
from vellum.workflows.nodes.displayable.guardrail_node.node import GuardrailNode
|
9
|
+
|
10
|
+
|
11
|
+
def test_guardrail_node__inputs(vellum_client):
|
12
|
+
"""Test that GuardrailNode correctly handles inputs."""
|
13
|
+
|
14
|
+
# GIVEN a Guardrail Node with inputs
|
15
|
+
class MyGuard(GuardrailNode):
|
16
|
+
metric_definition = "example_metric_definition"
|
17
|
+
metric_inputs = {
|
18
|
+
"a_string": "hello",
|
19
|
+
"a_chat_history": [ChatMessage(role="USER", text="Hello, how are you?")],
|
20
|
+
"a_dict": {"foo": "bar"},
|
21
|
+
"a_int": 42,
|
22
|
+
"a_float": 3.14,
|
23
|
+
}
|
24
|
+
|
25
|
+
vellum_client.metric_definitions.execute_metric_definition.return_value = MetricDefinitionExecution(
|
26
|
+
outputs=[
|
27
|
+
TestSuiteRunMetricNumberOutput(
|
28
|
+
name="score",
|
29
|
+
value=1.0,
|
30
|
+
),
|
31
|
+
],
|
32
|
+
)
|
33
|
+
|
34
|
+
# WHEN the node is run
|
35
|
+
MyGuard().run()
|
36
|
+
|
37
|
+
# THEN the metric_definitions.execute_metric_definition method should be called with the correct inputs
|
38
|
+
mock_api = vellum_client.metric_definitions.execute_metric_definition
|
39
|
+
assert mock_api.call_count == 1
|
40
|
+
|
41
|
+
assert mock_api.call_args.kwargs["inputs"] == [
|
42
|
+
StringInput(name="a_string", type="STRING", value="hello"),
|
43
|
+
ChatHistoryInput(
|
44
|
+
name="a_chat_history", type="CHAT_HISTORY", value=[ChatMessage(role="USER", text="Hello, how are you?")]
|
45
|
+
),
|
46
|
+
JsonInput(name="a_dict", type="JSON", value={"foo": "bar"}),
|
47
|
+
NumberInput(name="a_int", type="NUMBER", value=42.0),
|
48
|
+
NumberInput(name="a_float", type="NUMBER", value=3.14),
|
49
|
+
]
|
50
|
+
assert len(mock_api.call_args.kwargs["inputs"]) == 5
|
@@ -170,8 +170,13 @@ def test_inline_prompt_node__function_definitions(vellum_adhoc_prompt_client):
|
|
170
170
|
WorkflowErrorCode.INTERNAL_ERROR,
|
171
171
|
"Failed to execute Prompt",
|
172
172
|
),
|
173
|
+
(
|
174
|
+
ApiError(status_code=403, body={"detail": "Provider credentials is missing or unavailable"}),
|
175
|
+
WorkflowErrorCode.PROVIDER_CREDENTIALS_UNAVAILABLE,
|
176
|
+
"Provider credentials is missing or unavailable",
|
177
|
+
),
|
173
178
|
],
|
174
|
-
ids=["404", "invalid_dict", "invalid_body", "no_status_code", "500"],
|
179
|
+
ids=["404", "invalid_dict", "invalid_body", "no_status_code", "500", "403"],
|
175
180
|
)
|
176
181
|
def test_inline_prompt_node__api_error__invalid_inputs_node_exception(
|
177
182
|
vellum_adhoc_prompt_client, exception, expected_code, expected_message
|
@@ -5,6 +5,8 @@ from typing import Any, Iterator, List
|
|
5
5
|
|
6
6
|
from httpx import Response
|
7
7
|
|
8
|
+
from vellum import RejectedExecutePromptEvent
|
9
|
+
from vellum.client import ApiError
|
8
10
|
from vellum.client.types.chat_history_input_request import ChatHistoryInputRequest
|
9
11
|
from vellum.client.types.chat_message import ChatMessage
|
10
12
|
from vellum.client.types.chat_message_request import ChatMessageRequest
|
@@ -15,6 +17,8 @@ from vellum.client.types.json_input_request import JsonInputRequest
|
|
15
17
|
from vellum.client.types.prompt_output import PromptOutput
|
16
18
|
from vellum.client.types.string_vellum_value import StringVellumValue
|
17
19
|
from vellum.workflows.context import execution_context
|
20
|
+
from vellum.workflows.errors import WorkflowErrorCode
|
21
|
+
from vellum.workflows.exceptions import NodeException
|
18
22
|
from vellum.workflows.nodes.displayable.prompt_deployment_node.node import PromptDeploymentNode
|
19
23
|
|
20
24
|
|
@@ -194,3 +198,322 @@ def test_prompt_deployment_node__json_output(vellum_client):
|
|
194
198
|
json_output = outputs[2]
|
195
199
|
assert json_output.name == "json"
|
196
200
|
assert json_output.value == expected_json
|
201
|
+
|
202
|
+
|
203
|
+
def test_prompt_deployment_node__all_fallbacks_fail(vellum_client):
|
204
|
+
# GIVEN a Prompt Deployment Node with fallback models
|
205
|
+
class TestPromptDeploymentNode(PromptDeploymentNode):
|
206
|
+
deployment = "test_deployment"
|
207
|
+
prompt_inputs = {"query": "test query"}
|
208
|
+
ml_model_fallbacks = ["fallback_model_1", "fallback_model_2"]
|
209
|
+
|
210
|
+
# AND all models fail with 404 errors
|
211
|
+
primary_error = ApiError(
|
212
|
+
body={"detail": "Failed to find model 'primary_model'"},
|
213
|
+
status_code=404,
|
214
|
+
)
|
215
|
+
fallback1_error = ApiError(
|
216
|
+
body={"detail": "Failed to find model 'fallback_model_1'"},
|
217
|
+
status_code=404,
|
218
|
+
)
|
219
|
+
fallback2_error = ApiError(
|
220
|
+
body={"detail": "Failed to find model 'fallback_model_2'"},
|
221
|
+
status_code=404,
|
222
|
+
)
|
223
|
+
|
224
|
+
vellum_client.execute_prompt_stream.side_effect = [primary_error, fallback1_error, fallback2_error]
|
225
|
+
|
226
|
+
# WHEN we run the node
|
227
|
+
node = TestPromptDeploymentNode()
|
228
|
+
|
229
|
+
# THEN an exception should be raised
|
230
|
+
with pytest.raises(NodeException) as exc_info:
|
231
|
+
list(node.run())
|
232
|
+
|
233
|
+
# AND the client should have been called three times
|
234
|
+
assert vellum_client.execute_prompt_stream.call_count == 3
|
235
|
+
|
236
|
+
# AND we get the expected error message
|
237
|
+
assert (
|
238
|
+
exc_info.value.message
|
239
|
+
== "Failed to execute prompts with these fallbacks: ['fallback_model_1', 'fallback_model_2']"
|
240
|
+
)
|
241
|
+
|
242
|
+
|
243
|
+
def test_prompt_deployment_node__fallback_success(vellum_client):
|
244
|
+
# GIVEN a Prompt Deployment Node with fallback models
|
245
|
+
class TestPromptDeploymentNode(PromptDeploymentNode):
|
246
|
+
deployment = "test_deployment"
|
247
|
+
prompt_inputs = {"query": "test query"}
|
248
|
+
ml_model_fallbacks = ["fallback_model_1", "fallback_model_2"]
|
249
|
+
|
250
|
+
# AND the primary model fails with a 404 error
|
251
|
+
primary_error = ApiError(
|
252
|
+
body={"detail": "Failed to find model 'primary_model'"},
|
253
|
+
status_code=404,
|
254
|
+
)
|
255
|
+
|
256
|
+
# AND the first fallback model succeeds
|
257
|
+
def generate_successful_stream():
|
258
|
+
execution_id = str(uuid4())
|
259
|
+
events = [
|
260
|
+
InitiatedExecutePromptEvent(execution_id=execution_id),
|
261
|
+
FulfilledExecutePromptEvent(
|
262
|
+
execution_id=execution_id, outputs=[StringVellumValue(value="Fallback response")]
|
263
|
+
),
|
264
|
+
]
|
265
|
+
return iter(events)
|
266
|
+
|
267
|
+
# Set up the mock to fail on primary but succeed on first fallback
|
268
|
+
vellum_client.execute_prompt_stream.side_effect = [primary_error, generate_successful_stream()]
|
269
|
+
|
270
|
+
# WHEN we run the node
|
271
|
+
node = TestPromptDeploymentNode()
|
272
|
+
outputs = list(node.run())
|
273
|
+
|
274
|
+
# THEN the node should complete successfully using the fallback model
|
275
|
+
assert len(outputs) > 0
|
276
|
+
assert outputs[-1].value == "Fallback response"
|
277
|
+
|
278
|
+
# AND the client should have been called twice (once for primary, once for fallback)
|
279
|
+
assert vellum_client.execute_prompt_stream.call_count == 2
|
280
|
+
|
281
|
+
# AND the second call should include the fallback model override
|
282
|
+
second_call_kwargs = vellum_client.execute_prompt_stream.call_args_list[1][1]
|
283
|
+
body_params = second_call_kwargs["request_options"]["additional_body_parameters"]
|
284
|
+
assert body_params["overrides"]["ml_model_fallback"] == "fallback_model_1"
|
285
|
+
|
286
|
+
|
287
|
+
def test_prompt_deployment_node__provider_error_with_fallbacks(vellum_client):
|
288
|
+
# GIVEN a Prompt Deployment Node with fallback models
|
289
|
+
class TestPromptDeploymentNode(PromptDeploymentNode):
|
290
|
+
deployment = "test_deployment"
|
291
|
+
prompt_inputs = {}
|
292
|
+
ml_model_fallbacks = ["gpt-4o", "gemini-1.5-flash-latest"]
|
293
|
+
|
294
|
+
# AND the primary model starts but then fails with a provider error
|
295
|
+
def generate_primary_events():
|
296
|
+
execution_id = str(uuid4())
|
297
|
+
events = [
|
298
|
+
InitiatedExecutePromptEvent(execution_id=execution_id),
|
299
|
+
RejectedExecutePromptEvent(
|
300
|
+
execution_id=execution_id,
|
301
|
+
error={
|
302
|
+
"code": "PROVIDER_ERROR",
|
303
|
+
"message": "The model provider encountered an error",
|
304
|
+
},
|
305
|
+
),
|
306
|
+
]
|
307
|
+
return iter(events)
|
308
|
+
|
309
|
+
# AND the fallback model succeeds
|
310
|
+
def generate_fallback_events():
|
311
|
+
execution_id = str(uuid4())
|
312
|
+
expected_outputs: List[PromptOutput] = [StringVellumValue(value="Fallback response")]
|
313
|
+
events = [
|
314
|
+
InitiatedExecutePromptEvent(execution_id=execution_id),
|
315
|
+
FulfilledExecutePromptEvent(execution_id=execution_id, outputs=expected_outputs),
|
316
|
+
]
|
317
|
+
return iter(events)
|
318
|
+
|
319
|
+
vellum_client.execute_prompt_stream.side_effect = [generate_primary_events(), generate_fallback_events()]
|
320
|
+
|
321
|
+
# WHEN we run the node
|
322
|
+
node = TestPromptDeploymentNode()
|
323
|
+
outputs = list(node.run())
|
324
|
+
|
325
|
+
# THEN the node should complete successfully using the fallback model
|
326
|
+
assert len(outputs) > 0
|
327
|
+
assert outputs[-1].value == "Fallback response"
|
328
|
+
|
329
|
+
# AND the client should have been called twice
|
330
|
+
assert vellum_client.execute_prompt_stream.call_count == 2
|
331
|
+
|
332
|
+
# AND the second call should include the fallback model override
|
333
|
+
second_call_kwargs = vellum_client.execute_prompt_stream.call_args_list[1][1]
|
334
|
+
body_params = second_call_kwargs["request_options"]["additional_body_parameters"]
|
335
|
+
assert body_params["overrides"]["ml_model_fallback"] == "gpt-4o"
|
336
|
+
|
337
|
+
|
338
|
+
def test_prompt_deployment_node__multiple_fallbacks_mixed_errors(vellum_client):
|
339
|
+
"""
|
340
|
+
This test case is when the primary model fails with an api error and
|
341
|
+
the first fallback fails with a provider error
|
342
|
+
"""
|
343
|
+
|
344
|
+
# GIVEN a Prompt Deployment Node with multiple fallback models
|
345
|
+
class TestPromptDeploymentNode(PromptDeploymentNode):
|
346
|
+
deployment = "test_deployment"
|
347
|
+
prompt_inputs = {}
|
348
|
+
ml_model_fallbacks = ["gpt-4o", "gemini-1.5-flash-latest"]
|
349
|
+
|
350
|
+
# AND the primary model fails with an API error
|
351
|
+
primary_error = ApiError(
|
352
|
+
body={"detail": "Failed to find model 'primary_model'"},
|
353
|
+
status_code=404,
|
354
|
+
)
|
355
|
+
|
356
|
+
# AND the first fallback model fails with a provider error
|
357
|
+
def generate_fallback1_events():
|
358
|
+
execution_id = str(uuid4())
|
359
|
+
events = [
|
360
|
+
InitiatedExecutePromptEvent(execution_id=execution_id),
|
361
|
+
RejectedExecutePromptEvent(
|
362
|
+
execution_id=execution_id,
|
363
|
+
error={
|
364
|
+
"code": "PROVIDER_ERROR",
|
365
|
+
"message": "The first fallback provider encountered an error",
|
366
|
+
},
|
367
|
+
),
|
368
|
+
]
|
369
|
+
return iter(events)
|
370
|
+
|
371
|
+
# AND the second fallback model succeeds
|
372
|
+
def generate_fallback2_events():
|
373
|
+
execution_id = str(uuid4())
|
374
|
+
expected_outputs: List[PromptOutput] = [StringVellumValue(value="Second fallback response")]
|
375
|
+
events = [
|
376
|
+
InitiatedExecutePromptEvent(execution_id=execution_id),
|
377
|
+
FulfilledExecutePromptEvent(execution_id=execution_id, outputs=expected_outputs),
|
378
|
+
]
|
379
|
+
return iter(events)
|
380
|
+
|
381
|
+
vellum_client.execute_prompt_stream.side_effect = [
|
382
|
+
primary_error,
|
383
|
+
generate_fallback1_events(),
|
384
|
+
generate_fallback2_events(),
|
385
|
+
]
|
386
|
+
|
387
|
+
# WHEN we run the node
|
388
|
+
node = TestPromptDeploymentNode()
|
389
|
+
outputs = list(node.run())
|
390
|
+
|
391
|
+
# THEN the node should complete successfully using the second fallback model
|
392
|
+
assert len(outputs) > 0
|
393
|
+
assert outputs[-1].value == "Second fallback response"
|
394
|
+
|
395
|
+
# AND the client should have been called three times
|
396
|
+
assert vellum_client.execute_prompt_stream.call_count == 3
|
397
|
+
|
398
|
+
# AND the calls should include the correct model overrides
|
399
|
+
first_fallback_call = vellum_client.execute_prompt_stream.call_args_list[1][1]
|
400
|
+
first_fallback_params = first_fallback_call["request_options"]["additional_body_parameters"]
|
401
|
+
assert first_fallback_params["overrides"]["ml_model_fallback"] == "gpt-4o"
|
402
|
+
|
403
|
+
second_fallback_call = vellum_client.execute_prompt_stream.call_args_list[2][1]
|
404
|
+
second_fallback_params = second_fallback_call["request_options"]["additional_body_parameters"]
|
405
|
+
assert second_fallback_params["overrides"]["ml_model_fallback"] == "gemini-1.5-flash-latest"
|
406
|
+
|
407
|
+
|
408
|
+
def test_prompt_deployment_node_multiple_provider_errors(vellum_client):
|
409
|
+
# GIVEN a Prompt Deployment Node with a single fallback model
|
410
|
+
class TestPromptDeploymentNode(PromptDeploymentNode):
|
411
|
+
deployment = "test_deployment"
|
412
|
+
prompt_inputs = {}
|
413
|
+
ml_model_fallbacks = ["gpt-4o"]
|
414
|
+
|
415
|
+
# AND the primary model fails with a provider error
|
416
|
+
def generate_primary_events():
|
417
|
+
execution_id = str(uuid4())
|
418
|
+
events = [
|
419
|
+
InitiatedExecutePromptEvent(execution_id=execution_id),
|
420
|
+
RejectedExecutePromptEvent(
|
421
|
+
execution_id=execution_id,
|
422
|
+
error={
|
423
|
+
"code": "PROVIDER_ERROR",
|
424
|
+
"message": "The primary provider encountered an error",
|
425
|
+
},
|
426
|
+
),
|
427
|
+
]
|
428
|
+
return iter(events)
|
429
|
+
|
430
|
+
# AND the fallback model also fails with a provider error
|
431
|
+
def generate_fallback1_events():
|
432
|
+
execution_id = str(uuid4())
|
433
|
+
events = [
|
434
|
+
InitiatedExecutePromptEvent(execution_id=execution_id),
|
435
|
+
RejectedExecutePromptEvent(
|
436
|
+
execution_id=execution_id,
|
437
|
+
error={
|
438
|
+
"code": "PROVIDER_ERROR",
|
439
|
+
"message": "The first fallback provider encountered an error",
|
440
|
+
},
|
441
|
+
),
|
442
|
+
]
|
443
|
+
return iter(events)
|
444
|
+
|
445
|
+
vellum_client.execute_prompt_stream.side_effect = [
|
446
|
+
generate_primary_events(),
|
447
|
+
generate_fallback1_events(),
|
448
|
+
]
|
449
|
+
|
450
|
+
# WHEN we run the node
|
451
|
+
with pytest.raises(NodeException) as exc_info:
|
452
|
+
node = TestPromptDeploymentNode()
|
453
|
+
list(node.run())
|
454
|
+
|
455
|
+
# THEN we should get an exception
|
456
|
+
assert exc_info.value.message == "Failed to execute prompts with these fallbacks: ['gpt-4o']"
|
457
|
+
|
458
|
+
# AND the client should have been called two times
|
459
|
+
assert vellum_client.execute_prompt_stream.call_count == 2
|
460
|
+
|
461
|
+
# AND the calls should include the correct model overrides
|
462
|
+
first_fallback_call = vellum_client.execute_prompt_stream.call_args_list[1][1]
|
463
|
+
first_fallback_params = first_fallback_call["request_options"]["additional_body_parameters"]
|
464
|
+
assert first_fallback_params["overrides"]["ml_model_fallback"] == "gpt-4o"
|
465
|
+
|
466
|
+
|
467
|
+
def test_prompt_deployment_node__no_fallbacks(vellum_client):
|
468
|
+
# GIVEN a Prompt Deployment Node with no fallback models
|
469
|
+
class TestPromptDeploymentNode(PromptDeploymentNode):
|
470
|
+
deployment = "test_deployment"
|
471
|
+
prompt_inputs = {}
|
472
|
+
|
473
|
+
# AND the primary model fails with an API error
|
474
|
+
primary_error = ApiError(
|
475
|
+
body={"detail": "Failed to find model 'primary_model'"},
|
476
|
+
status_code=404,
|
477
|
+
)
|
478
|
+
|
479
|
+
vellum_client.execute_prompt_stream.side_effect = primary_error
|
480
|
+
|
481
|
+
# WHEN we run the node
|
482
|
+
node = TestPromptDeploymentNode()
|
483
|
+
|
484
|
+
# THEN the node should raise an exception
|
485
|
+
with pytest.raises(NodeException) as exc_info:
|
486
|
+
list(node.run())
|
487
|
+
|
488
|
+
# AND the exception should contain the original error message
|
489
|
+
assert exc_info.value.message == "Failed to find model 'primary_model'"
|
490
|
+
assert exc_info.value.code == WorkflowErrorCode.INVALID_INPUTS
|
491
|
+
|
492
|
+
# AND the client should have been called only once (for the primary model)
|
493
|
+
assert vellum_client.execute_prompt_stream.call_count == 1
|
494
|
+
|
495
|
+
|
496
|
+
def test_prompt_deployment_node__provider_credentials_missing(vellum_client):
|
497
|
+
# GIVEN a Prompt Deployment Node
|
498
|
+
class TestPromptDeploymentNode(PromptDeploymentNode):
|
499
|
+
deployment = "test_deployment"
|
500
|
+
prompt_inputs = {}
|
501
|
+
|
502
|
+
# AND the client responds with a 403 error of provider credentials missing
|
503
|
+
primary_error = ApiError(
|
504
|
+
body={"detail": "Provider credentials is missing or unavailable"},
|
505
|
+
status_code=403,
|
506
|
+
)
|
507
|
+
|
508
|
+
vellum_client.execute_prompt_stream.side_effect = primary_error
|
509
|
+
|
510
|
+
# WHEN we run the node
|
511
|
+
node = TestPromptDeploymentNode()
|
512
|
+
|
513
|
+
# THEN the node should raise an exception
|
514
|
+
with pytest.raises(NodeException) as exc_info:
|
515
|
+
list(node.run())
|
516
|
+
|
517
|
+
# AND the exception should contain the original error message
|
518
|
+
assert exc_info.value.message == "Provider credentials is missing or unavailable"
|
519
|
+
assert exc_info.value.code == WorkflowErrorCode.PROVIDER_CREDENTIALS_UNAVAILABLE
|