fix(skills): surface proxy 429s from search embeddings instead of a 503

ProxyRateLimitError is also an OpenAIError, so the search engine was folding
a key rate limit into skill_search_unavailable. Proxy HTTPExceptions now
propagate so the caller gets the same 429 the /embeddings route returns

Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
This commit is contained in:
yassin 2026-09-05 19:47:56 +00:00
parent 9ae68a6d18
commit ef6ec53599
2 changed files with 6 additions and 2 deletions

View file

@ -9,6 +9,7 @@ from itertools import chain, islice
from types import MappingProxyType
from typing import TYPE_CHECKING, Final, Protocol, TypeAlias
from fastapi import HTTPException
from openai import OpenAIError
from pydantic import BaseModel, ConfigDict
@ -87,6 +88,8 @@ _CacheKey: TypeAlias = tuple[str, str]
async def _embed_all(embed: Embedder, texts: Sequence[str]) -> tuple[Vector, ...] | EmbeddingFailed:
try:
vectors: Final = tuple(await embed(texts))
except HTTPException:
raise
except (OpenAIError, ValueError, BudgetExceededError) as exc:
return EmbeddingFailed(reason=f"embedding the search query failed: {exc}")
if len(vectors) != len(texts):

View file

@ -23,6 +23,7 @@ from litellm.llms.litellm_proxy.skills.skill_search import (
from litellm.proxy._types import LiteLLM_SkillsTable, LitellmUserRoles, UserAPIKeyAuth
from litellm.proxy.anthropic_endpoints.skills_endpoints import router
from litellm.proxy.auth.user_api_key_auth import user_api_key_auth
from litellm.proxy.common_utils.proxy_rate_limit_error import ProxyRateLimitError
from litellm.proxy.common_utils.semantic_text_index import Vector, cosine_similarity
CALLER: Final = UserAPIKeyAuth(api_key="hashed-caller-key", team_id="team-1", user_id="user-1")
@ -332,7 +333,7 @@ class TestSearchSkills:
async def test_a_key_over_its_limit_never_reaches_the_embedding_model(self) -> None:
router = _embedding_router()
key_limits = MagicMock()
key_limits.pre_call_hook = AsyncMock(side_effect=HTTPException(status_code=429, detail="rpm exceeded"))
key_limits.pre_call_hook = AsyncMock(side_effect=ProxyRateLimitError(detail="rpm exceeded"))
with pytest.raises(HTTPException) as raised:
await search_skills(
"language translation",
@ -456,7 +457,7 @@ class TestGetSkillsQuery:
def test_a_key_over_its_rate_limit_gets_a_429_without_embedding(
self, accessible_skills: AsyncMock, embedding_router: MagicMock, key_limits: MagicMock
) -> None:
key_limits.pre_call_hook = AsyncMock(side_effect=HTTPException(status_code=429, detail="rpm exceeded"))
key_limits.pre_call_hook = AsyncMock(side_effect=ProxyRateLimitError(detail="rpm exceeded"))
response = _client(LitellmUserRoles.PROXY_ADMIN).get(
"/v1/skills",
params={"custom_llm_provider": "litellm_proxy", "query": "language translation"},