From ab26541b9a1feaab728c86685ef89b06885f16de Mon Sep 17 00:00:00 2001 From: SHL0MS Date: Tue, 9 Jun 2026 17:54:23 -0400 Subject: [PATCH] test(transports): lock in content_filter passthrough for OpenRouter OpenRouter (and every other OpenAI-compatible provider) uses the default chat_completions transport, so it is already covered by the refusal fix: an upstream Claude / moderation refusal arrives as finish_reason="content_filter" (often empty content, no message.refusal). Add a regression test asserting the transport passes that finish reason straight through to the loop's content_filter handler. (cherry picked from commit 60168a513bc9edc508aa8968d0163bd5feb87055) --- .../agent/transports/test_chat_completions.py | 22 +++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/tests/agent/transports/test_chat_completions.py b/tests/agent/transports/test_chat_completions.py index 8dbc5b885fa..588b019d7b2 100644 --- a/tests/agent/transports/test_chat_completions.py +++ b/tests/agent/transports/test_chat_completions.py @@ -900,6 +900,28 @@ class TestChatCompletionsNormalize: assert nr.content == "declined" assert nr.provider_data == {"refusal": "declined"} + def test_explicit_content_filter_finish_reason_passes_through(self, transport): + """OpenRouter (and other OpenAI-compatible providers) surface an + upstream Claude / moderation refusal as ``finish_reason="content_filter"`` + — often with empty content and no ``message.refusal`` field. The + transport must pass that finish reason straight through so the loop's + content_filter refusal handler fires; no ``message.refusal`` required. + This is the OpenRouter coverage path (OpenRouter uses the default + chat_completions transport).""" + r = SimpleNamespace( + choices=[SimpleNamespace( + message=SimpleNamespace( + content=None, tool_calls=None, reasoning_content=None, + refusal=None, + ), + finish_reason="content_filter", + )], + usage=None, + ) + nr = transport.normalize_response(r) + assert nr.finish_reason == "content_filter" + assert nr.content is None + def test_refusal_does_not_clobber_existing_content(self, transport): """If the model emitted partial text *and* a refusal, keep the visible text as content but still flag the refusal via content_filter."""