diff --git a/agent/error_classifier.py b/agent/error_classifier.py index 2d43806bc07..a64683ba41e 100644 --- a/agent/error_classifier.py +++ b/agent/error_classifier.py @@ -355,6 +355,14 @@ _CONTENT_POLICY_BLOCKED_PATTERNS = [ # echo back; the underscore form is provider-specific enough. "content_filter", "responsibleaipolicyviolation", + # MiniMax output-layer safety filter. The error string is surfaced + # verbatim by MiniMax SDK / OpenAI-compatible endpoints, usually in the + # form "output new_sensitive (1027)" when the model's *output* (often a + # large tool-call argument block) trips the upstream safety filter and + # the SSE stream is truncated mid-flight. ``new_sensitive`` is the + # filter name and is narrow enough that billing / format / auth error + # strings will not collide. See #32421. + "new_sensitive", ] # Auth patterns (non-status-code signals) diff --git a/tests/run_agent/test_18028_content_policy_blocked.py b/tests/run_agent/test_18028_content_policy_blocked.py index 1edf16b87ca..5b0ca093494 100644 --- a/tests/run_agent/test_18028_content_policy_blocked.py +++ b/tests/run_agent/test_18028_content_policy_blocked.py @@ -41,6 +41,27 @@ class TestContentPolicyBlockedClassification: assert result.should_compress is False assert result.should_rotate_credential is False + def test_minimax_output_safety_filter(self): + """#32421 — MiniMax output-layer safety filter (e.g. ``output + new_sensitive (1027)``) trips mid-stream when the model emits a + large tool-call argument block. Must classify as + ``content_policy_blocked`` so the loop aborts the 3x retry burn and + routes to a configured fallback model. + """ + from agent.error_classifier import classify_api_error, FailoverReason + + e = Exception( + "Stream stalled mid tool-call: output new_sensitive (1027) " + "[MiniMax-M2.7] — request was rejected by upstream safety " + "filter, see provider response for details." + ) + result = classify_api_error(e, provider="MiniMax", model="MiniMax-M2.7") + assert result.reason == FailoverReason.content_policy_blocked + assert result.retryable is False + assert result.should_fallback is True + assert result.should_compress is False + assert result.should_rotate_credential is False + class TestContentPolicyTriggersClientErrorAbort: """Mirror the ``is_client_error`` predicate in