mirror of
https://github.com/BerriAI/litellm.git
synced 2026-10-25 05:54:53 +00:00
feat(you_com): prefer YDC_API_KEY env var (keep YOUCOM_API_KEY fallback)
YDC_API_KEY is You.com's canonical API key env var (used by its own docs,
SDK, and the LangChain/CrewAI/DSPy integrations). The you_com search provider
previously only read YOUCOM_API_KEY. This makes YDC_API_KEY the preferred
name while keeping YOUCOM_API_KEY as a backward-compatible fallback, so
existing configs keep working.
- resolve_server_api_key now reads ("YDC_API_KEY", "YOUCOM_API_KEY") in order
- get_complete_url checks YDC_API_KEY before YOUCOM_API_KEY
- example config comment updated to YDC_API_KEY
- tests: YDC takes precedence over legacy key; legacy key still works
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
fa307fe9e5
commit
df1bd1729b
3 changed files with 82 additions and 10 deletions
|
|
@ -43,7 +43,7 @@ class YouComSearchConfig(BaseSearchConfig):
|
|||
# Keyed tier (higher rate limits): authenticate with X-API-Key.
|
||||
YOU_COM_API_BASE = "https://ydc-index.io"
|
||||
# Keyless free tier: IP-throttled (100 queries/day) and requires no auth.
|
||||
# Used automatically when YOUCOM_API_KEY is not set.
|
||||
# Used automatically when no API key (YDC_API_KEY / YOUCOM_API_KEY) is set.
|
||||
YOU_COM_FREE_API_BASE = "https://api.you.com/v1/agents/search"
|
||||
|
||||
@staticmethod
|
||||
|
|
@ -60,14 +60,15 @@ class YouComSearchConfig(BaseSearchConfig):
|
|||
"""
|
||||
Set headers for the You.com Search API.
|
||||
|
||||
If YOUCOM_API_KEY (or an explicit api_key) is present, use the keyed
|
||||
endpoint with the `X-API-Key` header. Otherwise fall through to the
|
||||
keyless free tier; no auth header is required.
|
||||
If an API key is present (YDC_API_KEY, the legacy YOUCOM_API_KEY, or an
|
||||
explicit api_key), use the keyed endpoint with the `X-API-Key` header.
|
||||
Otherwise fall through to the keyless free tier; no auth header is
|
||||
required.
|
||||
"""
|
||||
api_key = self.resolve_server_api_key(
|
||||
caller_api_key=api_key,
|
||||
caller_api_base=api_base,
|
||||
key_env_vars=("YOUCOM_API_KEY",),
|
||||
key_env_vars=("YDC_API_KEY", "YOUCOM_API_KEY"),
|
||||
base_env_var="YOUCOM_API_BASE",
|
||||
default_api_base=self.YOU_COM_API_BASE,
|
||||
)
|
||||
|
|
@ -92,14 +93,18 @@ class YouComSearchConfig(BaseSearchConfig):
|
|||
Pick the endpoint based on whether an API key is configured.
|
||||
|
||||
- api_base explicit override -> use it as-is (normalized)
|
||||
- YOUCOM_API_KEY set -> keyed endpoint (ydc-index.io/v1/search)
|
||||
- YDC_API_KEY / YOUCOM_API_KEY -> keyed endpoint (ydc-index.io/v1/search)
|
||||
- no key -> keyless free tier (api.you.com/v1/agents/search)
|
||||
"""
|
||||
if api_base is None:
|
||||
api_base = get_secret_str("YOUCOM_API_BASE")
|
||||
|
||||
if api_base is None:
|
||||
api_key = kwargs.get("api_key") or get_secret_str("YOUCOM_API_KEY")
|
||||
api_key = (
|
||||
kwargs.get("api_key")
|
||||
or get_secret_str("YDC_API_KEY")
|
||||
or get_secret_str("YOUCOM_API_KEY")
|
||||
)
|
||||
if api_key:
|
||||
api_base = self.YOU_COM_API_BASE
|
||||
else:
|
||||
|
|
|
|||
|
|
@ -8,7 +8,7 @@ search_tools:
|
|||
- search_tool_name: "my-perplexity-search"
|
||||
litellm_params:
|
||||
search_provider: "perplexity"
|
||||
# Alternative provider example (requires YOUCOM_API_KEY):
|
||||
# Alternative provider example (requires YDC_API_KEY):
|
||||
# - search_tool_name: "my-you-com-search"
|
||||
# litellm_params:
|
||||
# search_provider: "you_com"
|
||||
|
|
|
|||
|
|
@ -20,9 +20,11 @@ class TestYouComSearch:
|
|||
@pytest.fixture(autouse=True)
|
||||
def _set_api_key(self, monkeypatch):
|
||||
"""
|
||||
Default fixture: YOUCOM_API_KEY is set, scoped to this test.
|
||||
Tests that need the key absent should call `monkeypatch.delenv` themselves.
|
||||
Default fixture: the canonical YDC_API_KEY is cleared and the legacy
|
||||
YOUCOM_API_KEY is set, scoped to this test. Tests that need the key
|
||||
absent should call `monkeypatch.delenv` themselves.
|
||||
"""
|
||||
monkeypatch.delenv("YDC_API_KEY", raising=False)
|
||||
monkeypatch.setenv("YOUCOM_API_KEY", "test-api-key")
|
||||
|
||||
@pytest.mark.asyncio
|
||||
|
|
@ -328,6 +330,71 @@ class TestYouComSearch:
|
|||
headers = call_args.kwargs.get("headers", {})
|
||||
assert headers["X-API-Key"] == "my-programmatic-key"
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_you_com_search_prefers_ydc_api_key_over_legacy(self, monkeypatch):
|
||||
"""
|
||||
YDC_API_KEY is the canonical env var and must take precedence over the
|
||||
legacy YOUCOM_API_KEY when both are set: the keyed endpoint is selected
|
||||
and X-API-Key carries the YDC_API_KEY value.
|
||||
"""
|
||||
monkeypatch.setenv("YDC_API_KEY", "ydc-key")
|
||||
monkeypatch.setenv("YOUCOM_API_KEY", "legacy-key")
|
||||
|
||||
mock_response = MagicMock()
|
||||
mock_response.status_code = 200
|
||||
mock_response.json.return_value = {
|
||||
"results": {"web": [], "news": []},
|
||||
"metadata": {},
|
||||
}
|
||||
|
||||
with patch(
|
||||
"litellm.llms.custom_httpx.http_handler.AsyncHTTPHandler.post",
|
||||
new_callable=AsyncMock,
|
||||
) as mock_post:
|
||||
mock_post.return_value = mock_response
|
||||
|
||||
await litellm.asearch(
|
||||
query="anything",
|
||||
search_provider="you_com",
|
||||
)
|
||||
|
||||
call_args = mock_post.call_args
|
||||
assert call_args.kwargs["url"] == "https://ydc-index.io/v1/search"
|
||||
headers = call_args.kwargs.get("headers", {})
|
||||
assert headers["X-API-Key"] == "ydc-key"
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_you_com_search_legacy_youcom_api_key_still_works(self, monkeypatch):
|
||||
"""
|
||||
Backwards compatibility: with only the legacy YOUCOM_API_KEY set (and
|
||||
YDC_API_KEY absent), the keyed endpoint is still selected.
|
||||
"""
|
||||
monkeypatch.delenv("YDC_API_KEY", raising=False)
|
||||
monkeypatch.setenv("YOUCOM_API_KEY", "legacy-key")
|
||||
|
||||
mock_response = MagicMock()
|
||||
mock_response.status_code = 200
|
||||
mock_response.json.return_value = {
|
||||
"results": {"web": [], "news": []},
|
||||
"metadata": {},
|
||||
}
|
||||
|
||||
with patch(
|
||||
"litellm.llms.custom_httpx.http_handler.AsyncHTTPHandler.post",
|
||||
new_callable=AsyncMock,
|
||||
) as mock_post:
|
||||
mock_post.return_value = mock_response
|
||||
|
||||
await litellm.asearch(
|
||||
query="anything",
|
||||
search_provider="you_com",
|
||||
)
|
||||
|
||||
call_args = mock_post.call_args
|
||||
assert call_args.kwargs["url"] == "https://ydc-index.io/v1/search"
|
||||
headers = call_args.kwargs.get("headers", {})
|
||||
assert headers["X-API-Key"] == "legacy-key"
|
||||
|
||||
def test_you_com_search_complete_url_uses_programmatic_api_key(self, monkeypatch):
|
||||
"""
|
||||
get_complete_url selects the keyed endpoint from a forwarded api_key even
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue