diff --git a/src/agentos/provider/failures.py b/src/agentos/provider/failures.py index 0d447c288..4c050182a 100644 --- a/src/agentos/provider/failures.py +++ b/src/agentos/provider/failures.py @@ -87,10 +87,15 @@ def _is_context_overflow(text: str) -> bool: "input exceeds", "provider_request_budget_exhausted", "too many tokens", + # Gemini's canonical input-token-limit error, e.g. "The input token + # count (5911388) exceeds the maximum number of tokens allowed + # (1048576)." — does not contain "input exceeds" or "maximum + # context" since the token counts sit between the fixed phrases. + "input token count", + "exceeds the maximum number of tokens allowed", ) ) - def _is_policy_refusal(text: str) -> bool: return any( marker in text diff --git a/tests/test_provider_failures.py b/tests/test_provider_failures.py index ca4cbf856..c15fb7a2e 100644 --- a/tests/test_provider_failures.py +++ b/tests/test_provider_failures.py @@ -13,3 +13,43 @@ def test_provider_request_budget_exhausted_is_context_overflow() -> None: ) is ProviderFailureKind.CONTEXT_OVERFLOW ) + +def test_gemini_input_token_count_message_is_context_overflow() -> None: + # Gemini's real, canonical context-overflow error. Numbers vary per + # request but the surrounding phrasing is fixed. Before the fix this + # matched none of the context-overflow markers and fell through to + # BAD_REQUEST, so the runtime never triggered COMPACT_AND_RETRY. + message = ( + "The input token count (5911388) exceeds the maximum number of " + "tokens allowed (1048576)." + ) + + assert ( + classify_provider_error( + provider_name="gemini", + status_code=400, + raw_code="400", + message=message, + ) + is ProviderFailureKind.CONTEXT_OVERFLOW + ) + + +def test_gemini_input_token_count_message_is_context_overflow_regardless_of_token_counts() -> ( + None +): + # Same shape, different digit counts — guards against a marker that + # accidentally depends on a specific number of digits. + message = ( + "The input token count (132478) exceeds the maximum number of " + "tokens allowed (131072)." + ) + + assert ( + classify_provider_error( + provider_name="gemini", + status_code=400, + message=message, + ) + is ProviderFailureKind.CONTEXT_OVERFLOW + )