|
2 | 2 |
|
3 | 3 | import datetime |
4 | 4 | from typing import Any |
| 5 | +from unittest.mock import Mock |
5 | 6 |
|
6 | 7 | import pytest |
| 8 | +from botocore.exceptions import ClientError |
7 | 9 | from inline_snapshot import snapshot |
8 | 10 | from typing_extensions import TypedDict |
9 | 11 |
|
|
14 | 16 | FunctionToolCallEvent, |
15 | 17 | FunctionToolResultEvent, |
16 | 18 | ImageUrl, |
| 19 | + ModelHTTPError, |
17 | 20 | ModelRequest, |
18 | 21 | ModelResponse, |
19 | 22 | PartDeltaEvent, |
@@ -1376,3 +1379,87 @@ async def test_bedrock_model_stream_empty_text_delta(allow_model_requests: None, |
1376 | 1379 | PartEndEvent(index=1, part=TextPart(content='Hello! How can I help you today?')), |
1377 | 1380 | ] |
1378 | 1381 | ) |
| 1382 | + |
| 1383 | + |
| 1384 | +def test_bedrock_throttling_error(bedrock_provider: BedrockProvider): |
| 1385 | + """Test that ThrottlingException converts to ModelHTTPError with 429 status.""" |
| 1386 | + expected_error = {'Code': 'ThrottlingException', 'Message': 'Rate exceeded'} |
| 1387 | + expected_status = 429 |
| 1388 | + model_id = 'us.amazon.nova.micro-v1:0' |
| 1389 | + |
| 1390 | + # Mock the client to raise throttling exception |
| 1391 | + error_response = {'Error': expected_error, 'ResponseMetadata': {'HTTPStatusCode': expected_status}} |
| 1392 | + mock_client = Mock() |
| 1393 | + mock_client.converse.side_effect = ClientError(error_response, 'Converse') # type: ignore[reportArgumentType] |
| 1394 | + mock_client.meta.endpoint_url = 'https://bedrock-runtime.us-east-1.amazonaws.com' |
| 1395 | + |
| 1396 | + # Create provider with mocked client |
| 1397 | + from pydantic_ai.providers.bedrock import BedrockProvider |
| 1398 | + |
| 1399 | + provider = BedrockProvider(bedrock_client=mock_client) |
| 1400 | + model = BedrockConverseModel(model_id, provider=provider) |
| 1401 | + agent = Agent(model) |
| 1402 | + |
| 1403 | + with pytest.raises(ModelHTTPError) as exc_info: |
| 1404 | + agent.run_sync('hello') |
| 1405 | + |
| 1406 | + assert exc_info.value.status_code == expected_status |
| 1407 | + assert exc_info.value.model_name == model_id |
| 1408 | + assert exc_info.value.body == expected_error |
| 1409 | + |
| 1410 | + |
| 1411 | +def test_bedrock_server_error(): |
| 1412 | + """Test that 5xx errors convert to ModelHTTPError.""" |
| 1413 | + expected_error = {'Code': 'InternalServerError', 'Message': 'Internal error'} |
| 1414 | + expected_status = 500 |
| 1415 | + model_id = 'us.amazon.nova.micro-v1:0' |
| 1416 | + |
| 1417 | + # Mock the client to raise throttling exception |
| 1418 | + error_response = {'Error': expected_error, 'ResponseMetadata': {'HTTPStatusCode': expected_status}} |
| 1419 | + mock_client = Mock() |
| 1420 | + mock_client.converse.side_effect = ClientError(error_response, 'Converse') # type: ignore[reportArgumentType] |
| 1421 | + |
| 1422 | + mock_client.meta.endpoint_url = 'https://bedrock-runtime.us-east-1.amazonaws.com' |
| 1423 | + |
| 1424 | + # Create provider with mocked client |
| 1425 | + from pydantic_ai.providers.bedrock import BedrockProvider |
| 1426 | + |
| 1427 | + provider = BedrockProvider(bedrock_client=mock_client) |
| 1428 | + model = BedrockConverseModel(model_id, provider=provider) |
| 1429 | + agent = Agent(model) |
| 1430 | + |
| 1431 | + with pytest.raises(ModelHTTPError) as exc_info: |
| 1432 | + agent.run_sync('hello') |
| 1433 | + |
| 1434 | + assert exc_info.value.status_code == expected_status |
| 1435 | + assert exc_info.value.model_name == model_id |
| 1436 | + assert exc_info.value.body == expected_error |
| 1437 | + |
| 1438 | + |
| 1439 | +async def test_bedrock_streaming_error(): |
| 1440 | + """Test that errors during streaming convert to ModelHTTPError.""" |
| 1441 | + expected_error = {'Code': 'ThrottlingException', 'Message': 'Rate exceeded'} |
| 1442 | + expected_status = 429 |
| 1443 | + model_id = 'us.amazon.nova.micro-v1:0' |
| 1444 | + |
| 1445 | + # Mock the client to raise throttling exception |
| 1446 | + error_response = {'Error': expected_error, 'ResponseMetadata': {'HTTPStatusCode': expected_status}} |
| 1447 | + mock_client = Mock() |
| 1448 | + mock_client.converse_stream.side_effect = ClientError(error_response, 'ConverseStream') # type: ignore[reportArgumentType] |
| 1449 | + |
| 1450 | + mock_client.meta.endpoint_url = 'https://bedrock-runtime.us-east-1.amazonaws.com' |
| 1451 | + |
| 1452 | + # Create provider with mocked client |
| 1453 | + from pydantic_ai.providers.bedrock import BedrockProvider |
| 1454 | + |
| 1455 | + provider = BedrockProvider(bedrock_client=mock_client) |
| 1456 | + model = BedrockConverseModel(model_id, provider=provider) |
| 1457 | + agent = Agent(model) |
| 1458 | + |
| 1459 | + with pytest.raises(ModelHTTPError) as exc_info: |
| 1460 | + async with agent.run_stream('hello'): |
| 1461 | + pass |
| 1462 | + |
| 1463 | + assert exc_info.value.status_code == expected_status |
| 1464 | + assert exc_info.value.model_name == model_id |
| 1465 | + assert exc_info.value.body == expected_error |
0 commit comments