From de138f347991b96cec669f753b0efc97d73e0520 Mon Sep 17 00:00:00 2001 From: Zachary Juang Date: Fri, 30 Jan 2026 21:07:24 -0500 Subject: [PATCH 1/2] fix --- posthog/ai/gemini/gemini_converter.py | 2 +- posthog/test/ai/gemini/test_gemini.py | 39 +++++++++++++++++++++++++++ 2 files changed, 40 insertions(+), 1 deletion(-) diff --git a/posthog/ai/gemini/gemini_converter.py b/posthog/ai/gemini/gemini_converter.py index 1d521105..36613b6f 100644 --- a/posthog/ai/gemini/gemini_converter.py +++ b/posthog/ai/gemini/gemini_converter.py @@ -420,7 +420,7 @@ def extract_gemini_web_search_count(response: Any) -> int: """ # Check for grounding_metadata in candidates - if hasattr(response, "candidates"): + if hasattr(response, "candidates") and response.candidates: for candidate in response.candidates: if ( hasattr(candidate, "grounding_metadata") diff --git a/posthog/test/ai/gemini/test_gemini.py b/posthog/test/ai/gemini/test_gemini.py index 0adaa151..b63cec8f 100644 --- a/posthog/test/ai/gemini/test_gemini.py +++ b/posthog/test/ai/gemini/test_gemini.py @@ -1161,3 +1161,42 @@ def test_empty_array_grounding_metadata_no_web_search( assert "$ai_web_search_count" not in props assert props["$ai_input_tokens"] == 15 assert props["$ai_output_tokens"] == 12 + + +def test_none_candidates_no_web_search(mock_client, mock_google_genai_client): + """Test that response with candidates=None does not crash web search extraction.""" + + mock_response = MagicMock() + + # Mock usage metadata + mock_usage = MagicMock() + mock_usage.prompt_token_count = 5 + mock_usage.candidates_token_count = 8 + mock_usage.cached_content_token_count = 0 + mock_usage.thoughts_token_count = 0 + mock_response.usage_metadata = mock_usage + + # candidates attribute exists but is None + mock_response.candidates = None + mock_response.text = "Hello!" + + mock_google_genai_client.models.generate_content.return_value = mock_response + + client = Client(api_key="test-key", posthog_client=mock_client) + + response = client.models.generate_content( + model="gemini-2.5-flash", + contents="Hi", + posthog_distinct_id="test-id", + ) + + assert response == mock_response + assert mock_client.capture.call_count == 1 + + call_args = mock_client.capture.call_args[1] + props = call_args["properties"] + + # Should not crash and web search count should not be present + assert "$ai_web_search_count" not in props + assert props["$ai_input_tokens"] == 5 + assert props["$ai_output_tokens"] == 8 From a790900e0d463c44ef1458c241f87f507a3b33b4 Mon Sep 17 00:00:00 2001 From: Zachary Juang Date: Thu, 19 Feb 2026 13:53:41 +0800 Subject: [PATCH 2/2] add sampo --- .sampo/changesets/forthright-lord-loviatar.md | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 .sampo/changesets/forthright-lord-loviatar.md diff --git a/.sampo/changesets/forthright-lord-loviatar.md b/.sampo/changesets/forthright-lord-loviatar.md new file mode 100644 index 00000000..111757b5 --- /dev/null +++ b/.sampo/changesets/forthright-lord-loviatar.md @@ -0,0 +1,5 @@ +--- +pypi/posthog: patch +--- + +fix: extract_gemini_web_search_count