fix(anthropic): propagate api_base to count_tokens endpoint

When a deployment configures a custom api_base, /v1/messages/count_tokens
was silently routing to api.anthropic.com instead. The token counter read
api_base from litellm_params but never passed it to the handler; the handler
had the parameter but used it as a raw URL without appending the path.

Fixes: propagate api_base (and ANTHROPIC_API_BASE env fallback) from
AnthropicTokenCounter.count_tokens into the handler, and add
_build_count_tokens_url to AnthropicCountTokensConfig to correctly append
/v1/messages/count_tokens to any base variant.
This commit is contained in:
Lodri Péter 2026-06-24 22:34:32 +02:00
parent 6003187165
commit f8eaf7f8bd
4 changed files with 69 additions and 9 deletions

View file

@ -68,8 +68,8 @@ class AnthropicCountTokensHandler(AnthropicCountTokensConfig):
verbose_logger.debug(f"Transformed request: {request_body}")
# Get endpoint URL
endpoint_url = api_base or self.get_anthropic_count_tokens_endpoint()
# Get endpoint URL; append the count_tokens path when a custom base is given
endpoint_url = self._build_count_tokens_url(api_base)
verbose_logger.debug(f"Making request to: {endpoint_url}")

View file

@ -63,11 +63,16 @@ class AnthropicTokenCounter(BaseTokenCounter):
verbose_logger.warning("No Anthropic API key found for token counting")
return None
api_base: Optional[str] = litellm_params.get("api_base") or os.getenv(
"ANTHROPIC_API_BASE"
)
try:
result = await anthropic_count_tokens_handler.handle_count_tokens_request(
model=model_to_use,
messages=messages,
api_key=api_key,
api_base=api_base,
tools=tools,
system=system,
)

View file

@ -19,14 +19,22 @@ class AnthropicCountTokensConfig:
- Response: {"input_tokens": <number>}
"""
def get_anthropic_count_tokens_endpoint(self) -> str:
"""
Get the Anthropic CountTokens API endpoint.
_COUNT_TOKENS_PATH: str = "/v1/messages/count_tokens"
_DEFAULT_ENDPOINT: str = f"https://api.anthropic.com{_COUNT_TOKENS_PATH}"
Returns:
The endpoint URL for the CountTokens API
"""
return "https://api.anthropic.com/v1/messages/count_tokens"
def get_anthropic_count_tokens_endpoint(self) -> str:
return self._DEFAULT_ENDPOINT
def _build_count_tokens_url(self, api_base: Optional[str]) -> str:
"""Return the full count_tokens URL, appending the path when a custom base is provided."""
if not api_base:
return self._DEFAULT_ENDPOINT
base = api_base.rstrip("/")
if base.endswith(self._COUNT_TOKENS_PATH):
return base
if base.endswith("/v1/messages"):
return f"{base}/count_tokens"
return f"{base}{self._COUNT_TOKENS_PATH}"
def transform_request_to_count_tokens(
self,

View file

@ -93,3 +93,50 @@ def test_transform_no_system_no_tools():
assert "system" not in result
assert "tools" not in result
def test_build_count_tokens_url_no_base():
"""No custom base -> default Anthropic endpoint."""
config = AnthropicCountTokensConfig()
assert (
config._build_count_tokens_url(None)
== "https://api.anthropic.com/v1/messages/count_tokens"
)
def test_build_count_tokens_url_bare_base():
"""Plain domain base gets full path appended."""
config = AnthropicCountTokensConfig()
assert (
config._build_count_tokens_url("https://my-proxy.example.com")
== "https://my-proxy.example.com/v1/messages/count_tokens"
)
def test_build_count_tokens_url_base_with_v1_messages():
"""Base already ending in /v1/messages gets only /count_tokens."""
config = AnthropicCountTokensConfig()
assert (
config._build_count_tokens_url("https://my-proxy.example.com/v1/messages")
== "https://my-proxy.example.com/v1/messages/count_tokens"
)
def test_build_count_tokens_url_already_full():
"""Base already containing the full path is returned as-is."""
config = AnthropicCountTokensConfig()
assert (
config._build_count_tokens_url(
"https://my-proxy.example.com/v1/messages/count_tokens"
)
== "https://my-proxy.example.com/v1/messages/count_tokens"
)
def test_build_count_tokens_url_trailing_slash_stripped():
"""Trailing slash on the base is ignored."""
config = AnthropicCountTokensConfig()
assert (
config._build_count_tokens_url("https://my-proxy.example.com/")
== "https://my-proxy.example.com/v1/messages/count_tokens"
)