Skip to content

Commit de0a4a2

Browse files
committed
Extract usage for unknown models
1 parent 3eaa11e commit de0a4a2

File tree

3 files changed

+14
-11
lines changed

3 files changed

+14
-11
lines changed

pydantic_ai_slim/pydantic_ai/models/anthropic.py

Lines changed: 1 addition & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,6 @@
77
from datetime import datetime
88
from typing import Any, Literal, cast, overload
99

10-
from genai_prices import extract_usage
1110
from pydantic import TypeAdapter
1211
from typing_extensions import assert_never
1312

@@ -638,12 +637,7 @@ def _map_usage(
638637
key: value for key, value in response_usage.model_dump().items() if isinstance(value, int)
639638
}
640639

641-
extracted_usage = extract_usage(dict(model=model, usage=details), provider_id=provider)
642-
643-
return usage.RequestUsage(
644-
**{key: value for key, value in extracted_usage.usage.__dict__.items() if isinstance(value, int)},
645-
details=details,
646-
)
640+
return usage.RequestUsage.extract(dict(model=model, usage=details), provider_id=provider, details=details)
647641

648642

649643
@dataclass

pydantic_ai_slim/pydantic_ai/usage.py

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,9 @@
33
import dataclasses
44
from copy import copy
55
from dataclasses import dataclass, fields
6-
from typing import Annotated
6+
from typing import Annotated, Any
77

8+
from genai_prices.data_snapshot import get_snapshot
89
from pydantic import AliasChoices, BeforeValidator, Field
910
from typing_extensions import deprecated, overload
1011

@@ -120,6 +121,14 @@ def __add__(self, other: RequestUsage) -> RequestUsage:
120121
new_usage.incr(other)
121122
return new_usage
122123

124+
@classmethod
125+
def extract(
126+
cls, data: Any, *, provider_id: str, api_flavor: str | None = None, details: dict[str, Any] | None = None
127+
) -> RequestUsage:
128+
provider = get_snapshot().find_provider(None, provider_id, None)
129+
_model_ref, extracted_usage = provider.extract_usage(data, api_flavor=api_flavor)
130+
return cls(**{k: v for k, v in extracted_usage.__dict__.items() if v is not None}, details=details or {})
131+
123132

124133
@dataclass(repr=False, kw_only=True)
125134
class RunUsage(UsageBase):

tests/models/test_anthropic.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1730,14 +1730,14 @@ def anth_msg(usage: BetaUsage) -> BetaMessage:
17301730
def test_usage(
17311731
message_callback: Callable[[], BetaMessage | BetaRawMessageStartEvent | BetaRawMessageDeltaEvent], usage: RunUsage
17321732
):
1733-
assert _map_usage(message_callback(), 'anthropic', 'claude-sonnet-4-5') == usage
1733+
assert _map_usage(message_callback(), 'anthropic', 'unknown') == usage
17341734

17351735

17361736
def test_streaming_usage():
17371737
start = BetaRawMessageStartEvent(message=anth_msg(BetaUsage(input_tokens=1, output_tokens=1)), type='message_start')
1738-
initial_usage = _map_usage(start, 'anthropic', 'claude-sonnet-4-5')
1738+
initial_usage = _map_usage(start, 'anthropic', 'unknown')
17391739
delta = BetaRawMessageDeltaEvent(delta=Delta(), usage=BetaMessageDeltaUsage(output_tokens=5), type='message_delta')
1740-
final_usage = _map_usage(delta, 'anthropic', 'claude-sonnet-4-5', existing_usage=initial_usage)
1740+
final_usage = _map_usage(delta, 'anthropic', 'unknown', existing_usage=initial_usage)
17411741
assert final_usage == snapshot(
17421742
RequestUsage(input_tokens=1, output_tokens=5, details={'input_tokens': 1, 'output_tokens': 5})
17431743
)

0 commit comments

Comments
 (0)