fix(responses): treat an empty guardrail texts answer as no rewrite like chat completions
Some checks failed
LiteLLM Rust / rust-lint (push) Has been cancelled
LiteLLM Rust / rust-test (push) Has been cancelled
LiteLLM Rust / rust-wheel (push) Has been cancelled

Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
This commit is contained in:
yucheng 2026-09-30 01:32:35 +00:00
parent fdcc1494be
commit 263a1d43bb
2 changed files with 5 additions and 23 deletions

View file

@ -568,7 +568,7 @@ class OpenAIResponsesHandler(BaseTranslation):
guardrailed_inputs: GenericGuardrailAPIInputs,
) -> None:
returned_texts: Final = guardrailed_inputs.get("texts")
if returned_texts is None:
if not returned_texts:
return
rewritten_texts: Final = tuple(returned_texts)
offset: Final = 0 if extracted.instructions is None else 1

View file

@ -356,31 +356,13 @@ class TestOpenAIResponsesHandlerInputProcessing:
assert data["input"] == original["input"]
@pytest.mark.asyncio
@pytest.mark.parametrize("answered_texts", [None, ()], ids=["no_texts_key", "empty_texts"])
@pytest.mark.parametrize("data_input", ["Hello", [{"role": "user", "content": "Hello"}]])
async def test_empty_texts_answer_is_rejected_instead_of_forwarding_the_raw_request(
self, data_input: str | list[dict[str, str]]
) -> None:
from litellm.llms.base_llm.guardrail_translation.utils import UnappliableRequestRewrite
handler = OpenAIResponsesHandler()
guardrail = TextsReplacingGuardrail(guardrail_name="emptier", texts=())
data = {"model": "gpt-4", "instructions": "Be terse", "input": data_input}
original = copy.deepcopy(data)
with pytest.raises(UnappliableRequestRewrite) as excinfo:
await handler.process_input_messages(data, guardrail)
assert excinfo.value.guardrail_name == "emptier"
assert data["instructions"] == original["instructions"]
assert data["input"] == original["input"]
@pytest.mark.asyncio
@pytest.mark.parametrize("data_input", ["Hello", [{"role": "user", "content": "Hello"}]])
async def test_answer_without_texts_key_leaves_instructions_and_input_untouched(
self, data_input: str | list[dict[str, str]]
async def test_answer_without_texts_leaves_instructions_and_input_untouched_like_chat_completions(
self, answered_texts: tuple[str, ...] | None, data_input: str | list[dict[str, str]]
) -> None:
handler = OpenAIResponsesHandler()
guardrail = TextsReplacingGuardrail(guardrail_name="silent", texts=None)
guardrail = TextsReplacingGuardrail(guardrail_name="silent", texts=answered_texts)
data = {"model": "gpt-4", "instructions": "Be terse", "input": data_input}
original = copy.deepcopy(data)