mirror of
https://github.com/crewAIInc/crewAI.git
synced 2026-08-10 16:32:28 +00:00
Fix Anthropic native provider to include cache tokens in input totals.
Anthropic reports cache read and cache creation separately from input_tokens; fold them into input_tokens and total_tokens so billed usage is not underreported on cached workloads.
This commit is contained in:
@@ -12,6 +12,7 @@ from crewai.llms.base_llm import BaseLLM, JsonResponseFormat, llm_call_context
|
|||||||
from crewai.llms.hooks.base import BaseInterceptor
|
from crewai.llms.hooks.base import BaseInterceptor
|
||||||
from crewai.llms.hooks.transport import AsyncHTTPTransport, HTTPTransport
|
from crewai.llms.hooks.transport import AsyncHTTPTransport, HTTPTransport
|
||||||
from crewai.llms.providers.utils.common import safe_tool_conversion
|
from crewai.llms.providers.utils.common import safe_tool_conversion
|
||||||
|
from crewai.types.usage_metrics import _coerce_int
|
||||||
from crewai.utilities.agent_utils import is_context_length_exceeded
|
from crewai.utilities.agent_utils import is_context_length_exceeded
|
||||||
from crewai.utilities.exceptions.context_window_exceeding_exception import (
|
from crewai.utilities.exceptions.context_window_exceeding_exception import (
|
||||||
LLMContextLengthExceededError,
|
LLMContextLengthExceededError,
|
||||||
@@ -1965,12 +1966,15 @@ class AnthropicCompletion(BaseLLM):
|
|||||||
"""Extract token usage and response metadata from Anthropic response."""
|
"""Extract token usage and response metadata from Anthropic response."""
|
||||||
if hasattr(response, "usage") and response.usage:
|
if hasattr(response, "usage") and response.usage:
|
||||||
usage = response.usage
|
usage = response.usage
|
||||||
input_tokens = getattr(usage, "input_tokens", 0)
|
input_tokens = _coerce_int(getattr(usage, "input_tokens", 0))
|
||||||
output_tokens = getattr(usage, "output_tokens", 0)
|
output_tokens = _coerce_int(getattr(usage, "output_tokens", 0))
|
||||||
cache_read_tokens = getattr(usage, "cache_read_input_tokens", 0) or 0
|
cache_read_tokens = _coerce_int(
|
||||||
cache_creation_tokens = (
|
getattr(usage, "cache_read_input_tokens", 0)
|
||||||
getattr(usage, "cache_creation_input_tokens", 0) or 0
|
|
||||||
)
|
)
|
||||||
|
cache_creation_tokens = _coerce_int(
|
||||||
|
getattr(usage, "cache_creation_input_tokens", 0)
|
||||||
|
)
|
||||||
|
input_tokens = input_tokens + cache_read_tokens + cache_creation_tokens
|
||||||
result: dict[str, Any] = {
|
result: dict[str, Any] = {
|
||||||
"input_tokens": input_tokens,
|
"input_tokens": input_tokens,
|
||||||
"output_tokens": output_tokens,
|
"output_tokens": output_tokens,
|
||||||
|
|||||||
@@ -549,7 +549,12 @@ def test_anthropic_token_usage_tracking():
|
|||||||
with patch.object(llm._client.messages, 'create') as mock_create:
|
with patch.object(llm._client.messages, 'create') as mock_create:
|
||||||
mock_response = MagicMock()
|
mock_response = MagicMock()
|
||||||
mock_response.content = [MagicMock(text="test response")]
|
mock_response.content = [MagicMock(text="test response")]
|
||||||
mock_response.usage = MagicMock(input_tokens=50, output_tokens=25)
|
mock_response.usage = MagicMock(
|
||||||
|
input_tokens=50,
|
||||||
|
output_tokens=25,
|
||||||
|
cache_read_input_tokens=0,
|
||||||
|
cache_creation_input_tokens=0,
|
||||||
|
)
|
||||||
mock_create.return_value = mock_response
|
mock_create.return_value = mock_response
|
||||||
|
|
||||||
result = llm.call("Hello")
|
result = llm.call("Hello")
|
||||||
@@ -1653,9 +1658,9 @@ def test_anthropic_cache_creation_tokens_extraction():
|
|||||||
mock_response.model = None
|
mock_response.model = None
|
||||||
|
|
||||||
usage = llm._extract_anthropic_token_usage(mock_response)
|
usage = llm._extract_anthropic_token_usage(mock_response)
|
||||||
assert usage["input_tokens"] == 100
|
assert usage["input_tokens"] == 150
|
||||||
assert usage["output_tokens"] == 50
|
assert usage["output_tokens"] == 50
|
||||||
assert usage["total_tokens"] == 150
|
assert usage["total_tokens"] == 200
|
||||||
assert usage["cached_prompt_tokens"] == 30
|
assert usage["cached_prompt_tokens"] == 30
|
||||||
assert usage["cache_creation_tokens"] == 20
|
assert usage["cache_creation_tokens"] == 20
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user