mirror of
https://github.com/BerriAI/litellm.git
synced 2026-10-09 03:18:44 +00:00
refactor(anthropic): drop the recursion the workload identity paths did not need
The repo's recursion guard rejects unignored recursive functions, and this branch had added three. Two were plain iteration written as recursion: the model list walked its pages recursively, and the base URL stripped chat suffixes by calling itself. The third mattered more: a token exchange follower whose leader published nothing called get_token again, so a contended entry grew the stack one frame per failed leader All three are loops now. The suffix strip re-strips trailing slashes on each pass, which the recursion got for free by re-entering a function that begins by stripping them, and which a doubled suffix needs to keep matching The passthrough header tests also pin SERVER_ROOT_PATH. They drive the real relay, and a sibling test leaving that variable set re-prefixes the route, so the request 404s before any header is built and the assertion never runs
This commit is contained in:
parent
0a88371a3a
commit
0a69790bb9
3 changed files with 25 additions and 14 deletions
|
|
@ -186,13 +186,15 @@ def _fetch_anthropic_models_page(
|
|||
def _fetch_anthropic_model_ids(
|
||||
api_base: str, headers: Mapping[str, str], after_id: str | None, pages_left: int
|
||||
) -> tuple[str, ...]:
|
||||
if pages_left <= 0:
|
||||
raise Exception(f"Anthropic /v1/models did not terminate within {_MODEL_LIST_PAGE_CAP} pages.")
|
||||
page: Final = _fetch_anthropic_models_page(api_base, headers, after_id)
|
||||
page_ids: Final = tuple(entry.id for entry in page.data)
|
||||
if not page.has_more or page.last_id is None:
|
||||
return page_ids
|
||||
return page_ids + _fetch_anthropic_model_ids(api_base, headers, page.last_id, pages_left - 1)
|
||||
collected: tuple[str, ...] = () # rebind-ok: accumulates one page of ids per iteration
|
||||
cursor: str | None = after_id # rebind-ok: advances to each page's last_id
|
||||
for _ in range(max(pages_left, 0)):
|
||||
page: Final = _fetch_anthropic_models_page(api_base, headers, cursor)
|
||||
collected += tuple(entry.id for entry in page.data)
|
||||
if not page.has_more or page.last_id is None:
|
||||
return collected
|
||||
cursor = page.last_id
|
||||
raise Exception(f"Anthropic /v1/models did not terminate within {_MODEL_LIST_PAGE_CAP} pages.")
|
||||
|
||||
|
||||
class AnthropicModelInfo(BaseLLMModelInfo):
|
||||
|
|
|
|||
|
|
@ -275,13 +275,17 @@ def _strip_chat_suffix(base: str) -> str:
|
|||
|
||||
def _strip_path_suffixes(path: str) -> str:
|
||||
"""Drop the chat-surface suffixes a deployment base may carry, so every tier derives the same
|
||||
token URL. Recursion depth is bounded by the path's own segment count."""
|
||||
trimmed: Final = path.rstrip("/")
|
||||
shortened: Final = next(
|
||||
(trimmed.removesuffix(suffix) for suffix in _CHAT_BASE_SUFFIXES if trimmed.endswith(suffix)),
|
||||
trimmed,
|
||||
)
|
||||
return trimmed if shortened == trimmed else _strip_path_suffixes(shortened)
|
||||
token URL. Each pass removes at most one suffix, so the loop is bounded by the segment count."""
|
||||
trimmed = path.rstrip("/") # rebind-ok: fixed-point strip, one suffix per pass
|
||||
while True:
|
||||
shortened: Final = next(
|
||||
(trimmed.removesuffix(suffix) for suffix in _CHAT_BASE_SUFFIXES if trimmed.endswith(suffix)),
|
||||
trimmed,
|
||||
)
|
||||
if shortened == trimmed:
|
||||
return trimmed
|
||||
# Re-strip: a doubled suffix leaves a trailing slash that would stop the next match.
|
||||
trimmed = shortened.rstrip("/")
|
||||
|
||||
|
||||
def _config_value(litellm_params: Mapping[str, object] | None, param_key: str, env_name: str) -> str | None:
|
||||
|
|
|
|||
|
|
@ -3967,6 +3967,11 @@ class TestAnthropicProxyRouteCallerAuthHeaders:
|
|||
):
|
||||
monkeypatch.delenv(name, raising=False)
|
||||
|
||||
# A sibling test leaving SERVER_ROOT_PATH set re-prefixes the passthrough route, so
|
||||
# /anthropic/... stops resolving and the request 404s before any header is built.
|
||||
# Pin it so this class asserts on headers rather than on ambient state.
|
||||
monkeypatch.delenv("SERVER_ROOT_PATH", raising=False)
|
||||
|
||||
def _enable_wif(self, monkeypatch) -> None:
|
||||
from litellm.llms.anthropic import common_utils as anthropic_common_utils
|
||||
from litellm.llms.anthropic.wif import aget_anthropic_wif_token
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue