From 6f1a183b17c37b9139421af01a5693f1b1a126c0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mehmet=20Can=20=C5=9Eakiro=C4=9Flu?= <53798389+cansakiroglu@users.noreply.github.com> Date: Tue, 23 Jun 2026 16:45:46 +0300 Subject: [PATCH] fix: forward all perplexity search params instead of a hardcoded subset (#30752) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Forward all Perplexity search params instead of a hardcoded subset PerplexitySearchConfig.transform_search_request only copied four keys (max_results, search_domain_filter, max_tokens_per_page, country) into the outgoing request body and silently dropped everything else, so documented Search API parameters like search_after_date_filter, search_before_date_filter, last_updated_after_filter, last_updated_before_filter, search_recency_filter, search_language_filter, search_context_size and max_tokens never reached Perplexity even though callers could set them. Perplexity's native parameter names already match LiteLLM's unified search spec, so there is nothing to remap; the transformation now passes every set optional parameter through as-is, the same approach the Exa AI search transformation already takes. None-valued params are still omitted. * fix: update litellm/llms/perplexity/search/transformation.py add key != "query" Co-authored-by: greptile-apps[bot] <165735046+greptile-apps[bot]@users.noreply.github.com> * Add search transformation tests and extend PerplexitySearchRequest Adds unit tests asserting the Perplexity Search request body forwards the full documented parameter set (search_after_date_filter, search_before_date_filter, last_updated_after_filter, last_updated_before_filter, search_recency_filter, search_language_filter, search_context_size, max_tokens and the original four), omits None/unset params, passes through arbitrary params, and never lets an optional_params "query" key override the query argument. Extends the PerplexitySearchRequest TypedDict with those documented fields so it no longer advertises only the original four. * Use builtin list[str] for new search_language_filter field The UP006 strict-budget gate is over its ceiling on the base branch, so any net-new typing.List usage fails CI. Type the newly added search_language_filter field with the builtin list[str] generic instead of List[str] so the change adds no new UP006 violations. --------- Co-authored-by: Mehmet Can Şakiroğlu Co-authored-by: greptile-apps[bot] <165735046+greptile-apps[bot]@users.noreply.github.com> --- .../llms/perplexity/search/transformation.py | 54 +++++++-------- .../llms/perplexity/search/__init__.py | 0 .../test_perplexity_search_transformation.py | 67 +++++++++++++++++++ 3 files changed, 92 insertions(+), 29 deletions(-) create mode 100644 tests/test_litellm/llms/perplexity/search/__init__.py create mode 100644 tests/test_litellm/llms/perplexity/search/test_perplexity_search_transformation.py diff --git a/litellm/llms/perplexity/search/transformation.py b/litellm/llms/perplexity/search/transformation.py index 8ed165de742..1b82ed48805 100644 --- a/litellm/llms/perplexity/search/transformation.py +++ b/litellm/llms/perplexity/search/transformation.py @@ -29,6 +29,14 @@ class PerplexitySearchRequest(_PerplexitySearchRequestRequired, total=False): max_results: int # Optional - maximum number of results (1-20), default 10 search_domain_filter: List[str] # Optional - list of domains to filter (max 20) + search_recency_filter: str # Optional - hour | day | week | month | year + search_after_date_filter: str # Optional - publish date >= MM/DD/YYYY + search_before_date_filter: str # Optional - publish date <= MM/DD/YYYY + last_updated_after_filter: str # Optional - last-updated date >= MM/DD/YYYY + last_updated_before_filter: str # Optional - last-updated date <= MM/DD/YYYY + search_language_filter: list[str] # Optional - ISO 639-1 codes (max 20) + search_context_size: str # Optional - low | medium | high + max_tokens: int # Optional - max tokens across results max_tokens_per_page: int # Optional - max tokens per page, default 1024 country: str # Optional - country code filter (e.g., 'US', 'GB', 'DE') @@ -90,45 +98,33 @@ class PerplexitySearchConfig(BaseSearchConfig): """ Transform Search request to Perplexity API format. - Note: LiteLLM's native spec is the perplexity search spec. - - There's no transformation needed for the request data. + Perplexity's native parameter names match LiteLLM's unified search spec, + so every set optional parameter is passed through as-is rather than an + arbitrary subset. None-valued params are omitted. https://docs.perplexity.ai/api-reference/search-post Args: query: Search query (string or list of strings) - optional_params: Optional parameters for the request - - max_results: Maximum number of search results (1-20) - - search_domain_filter: List of domains to filter (max 20) - - max_tokens_per_page: Max tokens per page (default 1024) - - country: Country code filter (e.g., 'US', 'GB', 'DE') + optional_params: Optional Perplexity Search API parameters, forwarded + as-is (e.g. max_results, search_domain_filter, country, + max_tokens_per_page, search_recency_filter, search_after_date_filter, + search_before_date_filter, last_updated_after_filter, + last_updated_before_filter, search_language_filter, + search_context_size, max_tokens) Returns: - Dict with typed request data following PerplexitySearchRequest spec + Dict with the Perplexity Search request body """ - request_data: PerplexitySearchRequest = { - "query": query, + request_data: PerplexitySearchRequest = {"query": query} + + forwarded = { + key: value + for key, value in optional_params.items() + if value is not None and key != "query" } - # Add optional parameters following Perplexity API spec (only if not None) - max_results = optional_params.get("max_results") - if max_results is not None: - request_data["max_results"] = max_results - - search_domain_filter = optional_params.get("search_domain_filter") - if search_domain_filter is not None: - request_data["search_domain_filter"] = search_domain_filter - - max_tokens_per_page = optional_params.get("max_tokens_per_page") - if max_tokens_per_page is not None: - request_data["max_tokens_per_page"] = max_tokens_per_page - - country = optional_params.get("country") - if country is not None: - request_data["country"] = country - - return dict(request_data) + return dict(request_data, **forwarded) def transform_search_response( self, diff --git a/tests/test_litellm/llms/perplexity/search/__init__.py b/tests/test_litellm/llms/perplexity/search/__init__.py new file mode 100644 index 00000000000..e69de29bb2d diff --git a/tests/test_litellm/llms/perplexity/search/test_perplexity_search_transformation.py b/tests/test_litellm/llms/perplexity/search/test_perplexity_search_transformation.py new file mode 100644 index 00000000000..ef7cfc0f06d --- /dev/null +++ b/tests/test_litellm/llms/perplexity/search/test_perplexity_search_transformation.py @@ -0,0 +1,67 @@ +from litellm.llms.perplexity.search.transformation import PerplexitySearchConfig + + +class TestPerplexitySearchRequestTransformation: + def test_forwards_full_documented_param_set(self): + config = PerplexitySearchConfig() + optional_params = { + "search_after_date_filter": "01/01/2026", + "search_before_date_filter": "06/15/2026", + "last_updated_after_filter": "03/01/2026", + "last_updated_before_filter": "03/31/2026", + "search_recency_filter": "month", + "search_language_filter": ["en"], + "search_context_size": "high", + "max_tokens": 2048, + "max_results": 5, + "search_domain_filter": ["europa.eu"], + "max_tokens_per_page": 1024, + "country": "US", + } + + body = config.transform_search_request( + query="EU AI Act", optional_params=optional_params + ) + + assert body == {"query": "EU AI Act", **optional_params} + + def test_omits_unset_and_none_optional_params(self): + config = PerplexitySearchConfig() + + body = config.transform_search_request( + query="hello", + optional_params={"search_recency_filter": None, "max_results": 5}, + ) + + assert body == {"query": "hello", "max_results": 5} + + def test_passes_through_arbitrary_params(self): + config = PerplexitySearchConfig() + + body = config.transform_search_request( + query="hello", + optional_params={"some_new_perplexity_param": "x", "country": "GB"}, + ) + + assert body == { + "query": "hello", + "some_new_perplexity_param": "x", + "country": "GB", + } + + def test_query_argument_is_not_overridden_by_optional_params(self): + config = PerplexitySearchConfig() + + body = config.transform_search_request( + query="real query", + optional_params={"query": "injected", "search_recency_filter": "week"}, + ) + + assert body == {"query": "real query", "search_recency_filter": "week"} + + def test_query_only_request(self): + config = PerplexitySearchConfig() + + body = config.transform_search_request(query=["a", "b"], optional_params={}) + + assert body == {"query": ["a", "b"]}