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"]}