mirror of
https://github.com/BerriAI/litellm.git
synced 2026-09-14 23:21:35 +00:00
fix: extract human-readable message from dict detail in SSE error frame
This commit is contained in:
parent
46dd136103
commit
b99c44af93
2 changed files with 31 additions and 5 deletions
|
|
@ -1332,9 +1332,15 @@ class BedrockGuardrail(CustomGuardrail, BaseAWSLLM):
|
|||
# An async generator cannot propagate an exception as an HTTP error response
|
||||
# after the 200 header has been written. Convert hard-block exceptions to
|
||||
# in-band SSE error frames so the client receives a structured error.
|
||||
# _get_http_exception_for_blocked_guardrail raises with a dict detail;
|
||||
# extract the human-readable "error" key
|
||||
if isinstance(e.detail, dict):
|
||||
message = e.detail.get("error", str(e.detail))
|
||||
else:
|
||||
message = str(e.detail)
|
||||
error_data = {
|
||||
"error": {
|
||||
"message": str(e.detail),
|
||||
"message": message,
|
||||
"code": e.status_code,
|
||||
"type": "guardrail_violation",
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2218,7 +2218,16 @@ async def test_streaming_hook_converts_http_exception_to_sse_error_frame_paralle
|
|||
for c in chunks:
|
||||
yield c
|
||||
|
||||
hard_block = HTTPException(status_code=400, detail="Violated guardrail policy")
|
||||
# Use the production dict-detail shape from _get_http_exception_for_blocked_guardrail
|
||||
hard_block = HTTPException(
|
||||
status_code=400,
|
||||
detail={
|
||||
"error": "Violated guardrail policy",
|
||||
"bedrock_guardrail_response": "",
|
||||
"guardrailIdentifier": "test-id",
|
||||
"guardrailVersion": "DRAFT",
|
||||
},
|
||||
)
|
||||
|
||||
with patch.object(
|
||||
guardrail, "make_bedrock_api_request", AsyncMock(side_effect=hard_block)
|
||||
|
|
@ -2240,7 +2249,8 @@ async def test_streaming_hook_converts_http_exception_to_sse_error_frame_paralle
|
|||
payload = _json.loads(error_frame[len("data: "):].rstrip())
|
||||
assert payload["error"]["code"] == 400
|
||||
assert payload["error"]["type"] == "guardrail_violation"
|
||||
assert "Violated guardrail policy" in payload["error"]["message"]
|
||||
# Must be a clean string, not a Python dict repr
|
||||
assert payload["error"]["message"] == "Violated guardrail policy"
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
|
|
@ -2271,7 +2281,16 @@ async def test_streaming_hook_converts_http_exception_to_sse_error_frame_output_
|
|||
for c in chunks:
|
||||
yield c
|
||||
|
||||
hard_block = HTTPException(status_code=400, detail="Violated guardrail policy")
|
||||
# Use the production dict-detail shape from _get_http_exception_for_blocked_guardrail
|
||||
hard_block = HTTPException(
|
||||
status_code=400,
|
||||
detail={
|
||||
"error": "Violated guardrail policy",
|
||||
"bedrock_guardrail_response": "",
|
||||
"guardrailIdentifier": "test-id",
|
||||
"guardrailVersion": "DRAFT",
|
||||
},
|
||||
)
|
||||
|
||||
with patch.object(
|
||||
guardrail, "make_bedrock_api_request", AsyncMock(side_effect=hard_block)
|
||||
|
|
@ -2292,4 +2311,5 @@ async def test_streaming_hook_converts_http_exception_to_sse_error_frame_output_
|
|||
payload = _json.loads(error_frame[len("data: "):].rstrip())
|
||||
assert payload["error"]["code"] == 400
|
||||
assert payload["error"]["type"] == "guardrail_violation"
|
||||
assert "Violated guardrail policy" in payload["error"]["message"]
|
||||
# Must be a clean string, not a Python dict repr
|
||||
assert payload["error"]["message"] == "Violated guardrail policy"
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue