From 89712b2dcb6b74fbd2b207096dcedcf9ee4810fb Mon Sep 17 00:00:00 2001 From: Gowtham Date: Fri, 9 Oct 2026 16:39:10 +0530 Subject: [PATCH] fix(search): handle engine-specific SerpApi result keys Expands SerpApi result parsing to dynamically check for 'shopping_results', 'news_results', 'local_results', and 'jobs_results' when 'organic_results' is absent, matching official SerpApi engine behavior. --- litellm/llms/serpapi/search/transformation.py | 19 +++++++++++---- .../test_serpapi_search_transformation.py | 23 +++++++++++++++++++ 2 files changed, 37 insertions(+), 5 deletions(-) diff --git a/litellm/llms/serpapi/search/transformation.py b/litellm/llms/serpapi/search/transformation.py index 6611acc5ee9..ed40caba956 100644 --- a/litellm/llms/serpapi/search/transformation.py +++ b/litellm/llms/serpapi/search/transformation.py @@ -157,15 +157,24 @@ class SerpApiSearchConfig(BaseSearchConfig): """ response_json: Final = raw_response.json() + results_list: Final = ( # pyright: ignore[reportUnknownVariableType] # standard response shape + response_json.get("organic_results") + or response_json.get("news_results") + or response_json.get("shopping_results") + or response_json.get("local_results") + or response_json.get("jobs_results") + or [] + ) + results: Final = [ SearchResult( - title=result.get("title", ""), - url=result.get("link", ""), - snippet=result.get("snippet", ""), - date=result.get("date"), + title=result.get("title", ""), # pyright: ignore[reportUnknownArgumentType, reportUnknownMemberType] # parsing generic json dict + url=result.get("link", ""), # pyright: ignore[reportUnknownArgumentType, reportUnknownMemberType] # parsing generic json dict + snippet=result.get("snippet", ""), # pyright: ignore[reportUnknownArgumentType, reportUnknownMemberType] # parsing generic json dict + date=result.get("date"), # pyright: ignore[reportUnknownArgumentType, reportUnknownMemberType] # parsing generic json dict last_updated=None, ) - for result in response_json.get("organic_results", []) + for result in results_list # pyright: ignore[reportUnknownVariableType] # iterating generic json array ] return SearchResponse( diff --git a/tests/unit/llms/serpapi/search/test_serpapi_search_transformation.py b/tests/unit/llms/serpapi/search/test_serpapi_search_transformation.py index 5df92d906c8..ba387935111 100644 --- a/tests/unit/llms/serpapi/search/test_serpapi_search_transformation.py +++ b/tests/unit/llms/serpapi/search/test_serpapi_search_transformation.py @@ -236,6 +236,29 @@ class TestSerpApiSearchConfig: assert result.results[1].url == "https://example.com/2" assert result.results[1].date is None + def test_transform_search_response_shopping_results(self): + config = SerpApiSearchConfig() + + mock_response = Mock(spec=httpx.Response) + mock_response.json.return_value = { + "shopping_results": [ + { + "title": "Shopping Result 1", + "link": "https://example.com/shop", + "snippet": "Buy this thing", + } + ] + } + + result = config.transform_search_response( + raw_response=mock_response, + logging_obj=MagicMock(), + ) + + assert isinstance(result, SearchResponse) + assert len(result.results) == 1 + assert result.results[0].title == "Shopping Result 1" + def test_transform_search_response_empty_results(self): config = SerpApiSearchConfig()