@@ -1905,3 +1905,116 @@ async def test_streaming_redacted_thinking_block_preserved_in_final():
19051905
19061906 text_part = final .content .parts [1 ]
19071907 assert text_part .text == "Done."
1908+
1909+
1910+ # --- Tests for Anthropic API error handling ---
1911+
1912+
1913+ def _make_non_streaming_request ():
1914+ return LlmRequest (
1915+ model = "claude-sonnet-4-20250514" ,
1916+ contents = [Content (role = "user" , parts = [Part .from_text (text = "Hi" )])],
1917+ config = types .GenerateContentConfig (system_instruction = "Test" ),
1918+ )
1919+
1920+
1921+ def _make_rate_limit_error ():
1922+ import anthropic
1923+
1924+ mock_response = MagicMock ()
1925+ mock_response .status_code = 429
1926+ mock_response .headers = {}
1927+ return anthropic .RateLimitError (
1928+ message = "rate limit exceeded" ,
1929+ response = mock_response ,
1930+ body = {"error" : {"message" : "rate limit exceeded" }},
1931+ )
1932+
1933+
1934+ def _make_auth_error ():
1935+ import anthropic
1936+
1937+ mock_response = MagicMock ()
1938+ mock_response .status_code = 401
1939+ mock_response .headers = {}
1940+ return anthropic .AuthenticationError (
1941+ message = "invalid api key" ,
1942+ response = mock_response ,
1943+ body = {"error" : {"message" : "invalid api key" }},
1944+ )
1945+
1946+
1947+ @pytest .mark .asyncio
1948+ async def test_non_streaming_rate_limit_raises_anthropic_rate_limit_error ():
1949+ """RateLimitError is re-raised as AnthropicRateLimitError with helpful message."""
1950+ from google .adk .models .anthropic_llm import AnthropicRateLimitError
1951+
1952+ llm = AnthropicLlm (model = "claude-sonnet-4-20250514" )
1953+ mock_client = MagicMock ()
1954+ mock_client .messages .create = AsyncMock (side_effect = _make_rate_limit_error ())
1955+
1956+ with mock .patch .object (llm , "_anthropic_client" , mock_client ):
1957+ with pytest .raises (AnthropicRateLimitError ):
1958+ _ = [
1959+ r
1960+ async for r in llm .generate_content_async (
1961+ _make_non_streaming_request (), stream = False
1962+ )
1963+ ]
1964+
1965+
1966+ @pytest .mark .asyncio
1967+ async def test_streaming_rate_limit_raises_anthropic_rate_limit_error ():
1968+ """RateLimitError is re-raised as AnthropicRateLimitError in streaming path."""
1969+ from google .adk .models .anthropic_llm import AnthropicRateLimitError
1970+
1971+ llm = AnthropicLlm (model = "claude-sonnet-4-20250514" )
1972+ mock_client = MagicMock ()
1973+ mock_client .messages .create = AsyncMock (side_effect = _make_rate_limit_error ())
1974+
1975+ with mock .patch .object (llm , "_anthropic_client" , mock_client ):
1976+ with pytest .raises (AnthropicRateLimitError ):
1977+ _ = [
1978+ r
1979+ async for r in llm .generate_content_async (
1980+ _make_non_streaming_request (), stream = True
1981+ )
1982+ ]
1983+
1984+
1985+ @pytest .mark .asyncio
1986+ async def test_non_streaming_other_errors_propagate ():
1987+ """Non-rate-limit errors propagate unchanged."""
1988+ import anthropic
1989+
1990+ llm = AnthropicLlm (model = "claude-sonnet-4-20250514" )
1991+ mock_client = MagicMock ()
1992+ mock_client .messages .create = AsyncMock (side_effect = _make_auth_error ())
1993+
1994+ with mock .patch .object (llm , "_anthropic_client" , mock_client ):
1995+ with pytest .raises (anthropic .AuthenticationError ):
1996+ _ = [
1997+ r
1998+ async for r in llm .generate_content_async (
1999+ _make_non_streaming_request (), stream = False
2000+ )
2001+ ]
2002+
2003+
2004+ @pytest .mark .asyncio
2005+ async def test_streaming_other_errors_propagate ():
2006+ """Non-rate-limit errors propagate unchanged in streaming path."""
2007+ import anthropic
2008+
2009+ llm = AnthropicLlm (model = "claude-sonnet-4-20250514" )
2010+ mock_client = MagicMock ()
2011+ mock_client .messages .create = AsyncMock (side_effect = _make_auth_error ())
2012+
2013+ with mock .patch .object (llm , "_anthropic_client" , mock_client ):
2014+ with pytest .raises (anthropic .AuthenticationError ):
2015+ _ = [
2016+ r
2017+ async for r in llm .generate_content_async (
2018+ _make_non_streaming_request (), stream = True
2019+ )
2020+ ]
0 commit comments