diff --git a/examples/experimental/litellm/src/switchyard_litellm/client.py b/examples/experimental/litellm/src/switchyard_litellm/client.py index dc0286c1f..04cc9a9a3 100644 --- a/examples/experimental/litellm/src/switchyard_litellm/client.py +++ b/examples/experimental/litellm/src/switchyard_litellm/client.py @@ -290,7 +290,7 @@ def _response(response: ModelResponse) -> dict[str, object]: "name": tool_call.function.name, "arguments": arguments, }) - if not content: + if not content and choice.finish_reason != "content_filter": raise ValueError("LiteLLM returned no text content") return { "id": response.id, diff --git a/examples/experimental/litellm/tests/test_client.py b/examples/experimental/litellm/tests/test_client.py index 5e3654816..3fd821b7e 100644 --- a/examples/experimental/litellm/tests/test_client.py +++ b/examples/experimental/litellm/tests/test_client.py @@ -552,3 +552,25 @@ async def test_cached_token_count_preserves_explicit_zero() -> None: await client.aclose() assert response["usage"]["cached_input_tokens"] == 0 + + +def test_response_content_filter_empty_content() -> None: + """Empty content with a content_filter finish reason must be normalized.""" + from types import SimpleNamespace + + from switchyard_litellm.client import _response + + response = SimpleNamespace( + id="chatcmpl-test", + model="openai/strong", + choices=[ + SimpleNamespace( + message=SimpleNamespace(content=None, tool_calls=None), + finish_reason="content_filter", + ) + ], + usage=None, + ) + result = _response(response) + assert result["outputs"][0]["content"] == [] + assert result["outputs"][0]["stop_reason"] == "content_filter"