feat(search): add TinyFish as search provider#30158
Conversation
…riAI#28598) Squash-merged by litellm-agent from Terrajlz's PR.
Squash-merged by litellm-agent from devauxbr's PR.
…erriAI#28505) (BerriAI#28575) * Forward custom_llm_provider through the Responses API bridge (Fixes BerriAI#28505) When a Chat Completions request to a GPT-5.4+ model contains both `tools` and `reasoning_effort`, `completion()` auto-routes through `responses_api_bridge`. The bridge handler called `litellm.responses()` / `litellm.aresponses()` without forwarding the already-resolved `custom_llm_provider`, so the downstream call re-invoked `get_llm_provider()` with `custom_llm_provider=None` and stripped a second provider prefix from a `provider/provider/model` deployment string. For a deployment configured as `openai/openai/openai/gpt-5.5`, the bridge flow sent `openai/gpt-5.5` to the upstream API instead of the correct `openai/openai/gpt-5.5`. Upstream APIs that enforce model-name allow-lists rejected this as `key_model_access_denied`. Fix: pass the locally-resolved `custom_llm_provider` into both the sync `responses()` and async `aresponses()` calls so the downstream `_resolve_model_provider_for_responses` sees an explicit provider and skips the second prefix-strip. New regression test `tests/test_litellm/completion_extras/test_responses_bridge_provider_propagation.py` pins both call sites: each must forward `custom_llm_provider`. * fix(28505): set custom_llm_provider on request_data instead of as duplicate kwarg Greptile flagged that the previous patch passed custom_llm_provider as an explicit kwarg to responses()/aresponses() while request_data already carried it via the spread of sanitized_litellm_params, which would raise TypeError: got multiple values for keyword argument on every real bridge call. Switches to assigning request_data['custom_llm_provider'] before the call so the resolved provider wins over whatever sanitized_litellm_params spread in, without duplicating the kwarg. Updates the regression test to seed request_data with a sentinel custom_llm_provider so it actually exercises the overwrite path (the previous test mocked transform_request with a minimal dict and never hit the conflict). * chore: trigger shin-agent re-eval on retargeted staging base * chore: trigger shin-agent re-eval against updated Greptile state
Add TinyFish (https://tinyfish.ai) as a new search provider for the LiteLLM Search API. TinyFish provides web search results via GET https://api.search.tinyfish.ai with X-API-Key authentication. Supports unified params (query, country, search_domain_filter) and TinyFish-specific passthrough params (language, page, include_thumbnail). Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
…thumbnail type Address Greptile review feedback: - Map max_results to query param and truncate results client-side (TinyFish API has no count param) - Fix include_thumbnail type annotation from str to bool - Add test for max_results truncation Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Greptile SummaryAdds TinyFish as the 14th search provider in LiteLLM, following the established GET-based pattern used by Brave and Serper. The implementation is self-contained in
Confidence Score: 5/5Additive provider integration with no changes to existing code paths; safe to merge. The change is purely additive: new files under litellm/llms/tinyfish/, a single enum entry, and one line in the provider config map. It follows the same GET-based provider pattern as Brave and Serper exactly. No existing behaviour is modified. No files require special attention.
|
| Filename | Overview |
|---|---|
| litellm/llms/tinyfish/search/transformation.py | Core TinyfishSearchConfig implementation following the Brave/GET-based provider pattern; max_results clamping is consistent between request and response. |
| litellm/llms/tinyfish/search/init.py | Minimal module export following the same convention as other search providers. |
| litellm/types/utils.py | Adds TINYFISH to the SearchProviders enum; minimal additive change. |
| litellm/utils.py | Registers TinyfishSearchConfig in get_provider_search_config(); follows the established provider registration pattern. |
| tests/search_tests/test_tinyfish_search.py | 7 mock-only unit tests; no real network calls. |
| model_prices_and_context_window.json | Adds tinyfish/search pricing entry with input_cost_per_query=0.0. |
| provider_endpoints_support.json | Adds tinyfish endpoint metadata. |
| tests/code_coverage_tests/enforce_llms_folder_style.py | Registers tinyfish in SEARCH_PROVIDERS list. |
Reviews (2): Last reviewed commit: "fix(search/tinyfish): clamp max_results ..." | Re-trigger Greptile
…ch_request Address Greptile P2 feedback: apply max(1, ...) in transform_search_request so the API receives the same clamped value that transform_search_response uses. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
|
Thanks for adding TinyFish as a search provider! Two small things to get this review-ready:
Once that's in we'll take another look! |
|
Thanks @Sameerlite! Here's the live integration test output against the real TinyFish API: All features working end-to-end: basic search, domain filtering ( |
|
@simantak-dabhade Can you fix these merge conflicts? Thanks! |
Drop explicit AND from domain filter query to match the approved implementation. Set pricing to zero. Rename test to match behavior.
Drop explicit AND from domain filter query to match the approved implementation. Set pricing to zero. Rename test to match behavior.
Summary
Adds TinyFish as the 14th search provider in LiteLLM, following the same GET-based pattern as Brave/Serper.
TinyfishSearchConfig(BaseSearchConfig)with full request/response transformationcountry→location,search_domain_filter→site:operators,max_results→ client-side truncation)X-API-Keyheader (fromapi_keyparam orTINYFISH_API_KEYenv var)Files changed (8)
litellm/llms/tinyfish/search/__init__.pylitellm/llms/tinyfish/search/transformation.pyTinyfishSearchConfigimplementationlitellm/types/utils.pyTINYFISHtoSearchProvidersenumlitellm/utils.pyget_provider_search_config()model_prices_and_context_window.jsontinyfish/searchpricing entryprovider_endpoints_support.jsontests/code_coverage_tests/enforce_llms_folder_style.pySEARCH_PROVIDERStests/search_tests/test_tinyfish_search.pyProof of testing
Live integration test against real TinyFish API also confirmed working (basic search, country, domain filter, max_results all return correct results).
Test plan
🤖 Generated with Claude Code