Repository navigation
Conversation
Serply is a Google SERP API. This wires it into the unified search seam
alongside the other Google-backed providers.
The config maps the Perplexity-unified params onto Serply's query string:
max_results -> num, country -> gl, and search_domain_filter -> site: and
-site: clauses appended to q. max_tokens_per_page has no equivalent and is
dropped. Everything else is forwarded untouched, so Serply's own surface
(tbs for time ranges, hl, start) stays reachable without LiteLLM tracking it.
Serply is a GET API, so transform_search_request hands its params to
get_complete_url through the request body under a private key, matching
google_pse and searchapi.
A response body that does not match the documented schema raises an
attributed error rather than degrading to a successful empty search, and
Serply's {"detail": ...} error envelope is unwrapped so the raw JSON does
not reach the user.
Price rows use Serply's published prepaid pricing: $2.00/1k queries at the
$5 entry pack, down to $0.75/1k at volume.
|
Codecov Report❌ Patch coverage is
📢 Thoughts on this report? Let us know! |
|
I checked the fix locally by symlinking that branch into $ python ./tests/documentation_tests/test_env_keys.py
Every environment variable read under ./litellm is documentedThe other three documentation tests pass too. Every other check on this PR is green, and Merging the docs PR and re-running should turn both green here. Let me know if you would rather I drop the |
Addresses the Greptile review on BerriAI#42150: removes the comments that narrate adjacent code and gives every test helper real parameter and return types instead of a bare `dict`
TLDR
Problem this solves:
google_pseis the only Google-backed option and Custom Search is sunsettingHow it solves it:
serplyto the search provider seam, same shape asserperUser Flow
Before: an admin who wants Serply behind the gateway cannot configure it, so every call to that tool 500s
search_provider: "serply"to the proxy config and restart{"query": "litellm unified search api", "max_results": 3, "country": "US"}litellm.APIConnectionError: 'serply' is not a valid SearchProvidersgoogle_pse, and Google Custom Search is closed to new customersAfter: the same config works and the same request returns normalized results
resultsarray oftitle,url,snippetanddate, the same shape every other search provider returnssearch_domain_filternarrows a query to a site, and Serply's owntbsreaches the provider untouched for time-ranged searchesRelevant issues
Affected release
Linear ticket
Pre-Submission checklist
Please complete all items before asking a LiteLLM maintainer to review your PR
uv run pytest tests/test_litellm/<your_test_file>.py -v. Leave the suites (make test-unit-*,make test-unit) to CI: it finishes in ~15 minutes where a laptop takes an hour or more@greptileaito re-request a review after pushing changes)Screenshots / Proof of Fix
Shared setup, identical on both sides.
SERPLY_API_KEYis a real key and every call below bills real Serply creditsexport SERPLY_API_KEY=... python litellm/proxy/proxy_cli.py --config serply_proxy_config.yaml --port 4000Before (0f7d4dc)
Case 1: basic search
{"error":{"message":"litellm.APIConnectionError: 'serply' is not a valid SearchProviders","type":"internal_server_error","param":null,"code":"500"}} http_status=500Case 2: restrict to a domain
{"error":{"message":"litellm.APIConnectionError: 'serply' is not a valid SearchProviders","type":"internal_server_error","param":null,"code":"500"}} http_status=500Case 3: time-ranged search
{"error":{"message":"litellm.APIConnectionError: 'serply' is not a valid SearchProviders","type":"internal_server_error","param":null,"code":"500"}} http_status=500After (755aff8)
Case 1: basic search
{ "results": [ { "title": "LiteLLM - Getting Started | liteLLM", "url": "https://docs.litellm.ai/", "snippet": "You can use LiteLLM through either the Proxy Server or Python SDK. Both gives you a unified interface to access multiple LLMs (100+ LLMs).", "date": null, "last_updated": null, "metadata": {"display_url": "docs.litellm.ai"} }, { "title": "Getting Started - LiteLLM", "url": "https://docs.litellm.ai/docs/", "snippet": "LiteLLM is a unified gateway for LLMs, agents, and MCP, so you don't need a separate agent or MCP gateway. One endpoint for 100+ models, A2A agents, and MCP ...", "date": null, "last_updated": null, "metadata": {"display_url": "docs.litellm.ai"} }, { "title": "Providers - LiteLLM", "url": "https://docs.litellm.ai/docs/providers", "snippet": "LiteLLM supports all AI models from CometAPI. CometAPI provides access to 500+ AI models through a unified API interface, including cutting-edge models like GPT ...", "date": null, "last_updated": null, "metadata": {"display_url": "docs.litellm.ai"} } ], "object": "search" } http_status=200Case 2: restrict to a domain
Case 3: time-ranged search
tbsreached Serply and every hit is inside the weekCase 4: bad key surfaces an attributed error
serply-bad-keytool from the shared config above{"detail": ...}envelope unwrapped instead of leaking raw JSONType
🆕 New Feature
Caveats (if any)
max_resultsis sent as Serply'snumwithout clamping. Serply serves one page of Google results, so a larger value returns about ten rather than failing, and clamping in the adapter would only hide that from the callermax_tokens_per_pagehas no Serply equivalent and is dropped. Everything the unified params do not cover is forwarded as-is, sotbs,hlandstartstay reachable, which is what Case 3 above exercisesDocs live in
BerriAI/litellm-docs, so they are a companion PR: BerriAI/litellm-docs#1592 adds the provider page, the sidebar entry and theSERPLY_API_BASEandSERPLY_API_KEYreference rows.code-qualityanddocumentationare red here until that one merges, both from the sametest_env_keys.pyfailure onSERPLY_API_BASE, and I verified locally that merging it turns them greenI did not add an Admin UI logo entry. Serper has none either, and I would rather not add an image asset to a PR that does not need one. Happy to add both in a follow-up if you want them
Disclosure: I work on Serply, so this adds my own company's API. Same shape as the Nimble and Serper providers that landed before it, and I am glad to make whatever changes you want