mirror of
https://github.com/BerriAI/litellm.git
synced 2026-08-28 05:25:59 +00:00
fix(utils): make prompt_token_calculator count claude models again
The claude branch called the anthropic SDK's `Anthropic().count_tokens`, which the
SDK removed, so every claude call raised AttributeError. Counting now goes through
litellm's own token_counter, which handles anthropic models offline and drops the
SDK dependency entirely.
Hiding that was a swallowed error: `except Exception: Exception("Anthropic import
failed please run `pip install anthropic`")` built the exception without raising
it, so an environment missing the SDK fell through to the unguarded
`from anthropic import ...` on the next line and got a bare ModuleNotFoundError
instead of the install hint.
That was the codebase's last PLW0133, so the rule graduates from the ratcheted
budget into ruff.toml where it hard-fails, and editors get the diagnostic inline.
This commit is contained in:
parent
f818a48ae5
commit
6975b8ea4b
4 changed files with 25 additions and 21 deletions
|
|
@ -6526,21 +6526,10 @@ def acreate(*args, **kwargs): ## Thin client to handle the acreate langchain ca
|
|||
|
||||
|
||||
def prompt_token_calculator(model, messages):
|
||||
# use tiktoken or anthropic's tokenizer depending on the model
|
||||
text: Final = " ".join(message["content"] for message in messages)
|
||||
num_tokens = 0
|
||||
if "claude" in model:
|
||||
try:
|
||||
import anthropic
|
||||
except Exception:
|
||||
Exception("Anthropic import failed please run `pip install anthropic`")
|
||||
from anthropic import AI_PROMPT, HUMAN_PROMPT, Anthropic
|
||||
|
||||
anthropic_obj: Final = Anthropic()
|
||||
num_tokens = anthropic_obj.count_tokens(text)
|
||||
else:
|
||||
num_tokens = len(_get_default_encoding().encode(text))
|
||||
return num_tokens
|
||||
return token_counter(model=model, text=text)
|
||||
return len(_get_default_encoding().encode(text))
|
||||
|
||||
|
||||
def valid_model(model):
|
||||
|
|
|
|||
|
|
@ -57,7 +57,7 @@
|
|||
"limit": 3
|
||||
},
|
||||
"BLE001": {
|
||||
"limit": 2920
|
||||
"limit": 2919
|
||||
},
|
||||
"C401": {
|
||||
"limit": 8
|
||||
|
|
@ -108,7 +108,7 @@
|
|||
"limit": 3
|
||||
},
|
||||
"F401": {
|
||||
"limit": 17
|
||||
"limit": 14
|
||||
},
|
||||
"LOG015": {
|
||||
"limit": 5
|
||||
|
|
@ -152,9 +152,6 @@
|
|||
"PLW0127": {
|
||||
"limit": 57
|
||||
},
|
||||
"PLW0133": {
|
||||
"limit": 1
|
||||
},
|
||||
"PLW0602": {
|
||||
"limit": 215
|
||||
},
|
||||
|
|
|
|||
|
|
@ -5,9 +5,9 @@ lint.ignore = ["F405", "E402", "F403"]
|
|||
lint.extend-select = [
|
||||
"T20", "PGH004", "RUF008", "RUF009", "RUF100",
|
||||
"B033", "FURB136", "FURB168", "FURB188", "I001", "PERF402", "PIE790", "PIE800", "PLC0208",
|
||||
"PLR0402", "PLR1711", "PLR1730", "PLR2044", "PYI030", "PYI041", "PYI064", "RET501", "RUF010",
|
||||
"RUF022", "RUF023", "RUF051", "SIM114", "SIM118", "TC005", "UP006", "UP007", "UP008", "UP012",
|
||||
"UP018", "UP024", "UP032", "UP034", "UP035", "UP037", "UP045",
|
||||
"PLR0402", "PLR1711", "PLR1730", "PLR2044", "PLW0133", "PYI030", "PYI041", "PYI064", "RET501",
|
||||
"RUF010", "RUF022", "RUF023", "RUF051", "SIM114", "SIM118", "TC005", "UP006", "UP007", "UP008",
|
||||
"UP012", "UP018", "UP024", "UP032", "UP034", "UP035", "UP037", "UP045",
|
||||
]
|
||||
# RUF100 (unused-noqa) only knows the rules enabled in THIS config, so it would strip
|
||||
# `# noqa` directives that protect rules enforced elsewhere. List those codes as external
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
import json
|
||||
import logging
|
||||
import os
|
||||
import sys
|
||||
from typing import Final
|
||||
from unittest.mock import AsyncMock, MagicMock, patch
|
||||
|
||||
|
|
@ -41,6 +42,7 @@ from litellm.utils import (
|
|||
get_prompt_cache_min_tokens,
|
||||
is_cached_message,
|
||||
is_prompt_caching_valid_prompt,
|
||||
prompt_token_calculator,
|
||||
)
|
||||
|
||||
# Adds the parent directory to the system path
|
||||
|
|
@ -4973,3 +4975,19 @@ def test_completion_does_not_leak_rust_flag_into_provider_request_body():
|
|||
create_kwargs = mock_client.chat.completions.with_raw_response.create.call_args.kwargs
|
||||
assert "rust" not in create_kwargs
|
||||
assert "rust" not in (create_kwargs.get("extra_body") or {})
|
||||
|
||||
|
||||
def test_prompt_token_calculator_counts_claude_without_the_anthropic_sdk():
|
||||
"""
|
||||
The claude branch used to call the anthropic SDK's `count_tokens`, which the SDK
|
||||
removed, so every claude call raised AttributeError. Counting must work with
|
||||
`anthropic` unimportable.
|
||||
"""
|
||||
messages: Final = [{"role": "user", "content": "the quick brown fox jumps over the lazy dog"}]
|
||||
|
||||
with patch.dict(sys.modules, {"anthropic": None}):
|
||||
claude_tokens = prompt_token_calculator("claude-sonnet-4-5", messages)
|
||||
gpt_tokens = prompt_token_calculator("gpt-4o", messages)
|
||||
|
||||
assert claude_tokens == 9
|
||||
assert gpt_tokens == 9
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue