pydantic-ai-slim 0.7.2__py3-none-any.whl → 0.7.3__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- pydantic_ai/_agent_graph.py +2 -2
- pydantic_ai/_cli.py +18 -3
- pydantic_ai/_run_context.py +2 -2
- pydantic_ai/ag_ui.py +4 -4
- pydantic_ai/agent/__init__.py +7 -9
- pydantic_ai/agent/abstract.py +16 -18
- pydantic_ai/agent/wrapper.py +4 -6
- pydantic_ai/direct.py +4 -4
- pydantic_ai/durable_exec/temporal/_agent.py +13 -15
- pydantic_ai/durable_exec/temporal/_model.py +2 -2
- pydantic_ai/messages.py +16 -6
- pydantic_ai/models/__init__.py +5 -5
- pydantic_ai/models/anthropic.py +27 -26
- pydantic_ai/models/bedrock.py +24 -26
- pydantic_ai/models/cohere.py +20 -25
- pydantic_ai/models/fallback.py +15 -15
- pydantic_ai/models/function.py +7 -9
- pydantic_ai/models/gemini.py +43 -39
- pydantic_ai/models/google.py +59 -40
- pydantic_ai/models/groq.py +22 -19
- pydantic_ai/models/huggingface.py +18 -21
- pydantic_ai/models/instrumented.py +4 -4
- pydantic_ai/models/mcp_sampling.py +1 -2
- pydantic_ai/models/mistral.py +24 -22
- pydantic_ai/models/openai.py +98 -44
- pydantic_ai/models/test.py +4 -5
- pydantic_ai/profiles/openai.py +13 -3
- pydantic_ai/providers/openai.py +1 -1
- pydantic_ai/result.py +5 -5
- pydantic_ai/run.py +4 -11
- pydantic_ai/usage.py +229 -67
- {pydantic_ai_slim-0.7.2.dist-info → pydantic_ai_slim-0.7.3.dist-info}/METADATA +10 -4
- {pydantic_ai_slim-0.7.2.dist-info → pydantic_ai_slim-0.7.3.dist-info}/RECORD +36 -36
- {pydantic_ai_slim-0.7.2.dist-info → pydantic_ai_slim-0.7.3.dist-info}/WHEEL +0 -0
- {pydantic_ai_slim-0.7.2.dist-info → pydantic_ai_slim-0.7.3.dist-info}/entry_points.txt +0 -0
- {pydantic_ai_slim-0.7.2.dist-info → pydantic_ai_slim-0.7.3.dist-info}/licenses/LICENSE +0 -0
pydantic_ai/models/openai.py
CHANGED
|
@@ -9,7 +9,7 @@ from datetime import datetime
|
|
|
9
9
|
from typing import Any, Literal, Union, cast, overload
|
|
10
10
|
|
|
11
11
|
from pydantic import ValidationError
|
|
12
|
-
from typing_extensions import assert_never
|
|
12
|
+
from typing_extensions import assert_never, deprecated
|
|
13
13
|
|
|
14
14
|
from .. import ModelHTTPError, UnexpectedModelBehavior, _utils, usage
|
|
15
15
|
from .._output import DEFAULT_OUTPUT_TOOL_NAME, OutputObjectDefinition
|
|
@@ -40,7 +40,7 @@ from ..messages import (
|
|
|
40
40
|
VideoUrl,
|
|
41
41
|
)
|
|
42
42
|
from ..profiles import ModelProfile, ModelProfileSpec
|
|
43
|
-
from ..profiles.openai import OpenAIModelProfile
|
|
43
|
+
from ..profiles.openai import OpenAIModelProfile, OpenAISystemPromptRole
|
|
44
44
|
from ..providers import Provider, infer_provider
|
|
45
45
|
from ..settings import ModelSettings
|
|
46
46
|
from ..tools import ToolDefinition
|
|
@@ -100,8 +100,6 @@ Using this more broad type for the model name instead of the ChatModel definitio
|
|
|
100
100
|
allows this model to be used more easily with other model types (ie, Ollama, Deepseek).
|
|
101
101
|
"""
|
|
102
102
|
|
|
103
|
-
OpenAISystemPromptRole = Literal['system', 'developer', 'user']
|
|
104
|
-
|
|
105
103
|
|
|
106
104
|
class OpenAIModelSettings(ModelSettings, total=False):
|
|
107
105
|
"""Settings used for an OpenAI model request."""
|
|
@@ -196,10 +194,59 @@ class OpenAIModel(Model):
|
|
|
196
194
|
"""
|
|
197
195
|
|
|
198
196
|
client: AsyncOpenAI = field(repr=False)
|
|
199
|
-
system_prompt_role: OpenAISystemPromptRole | None = field(default=None, repr=False)
|
|
200
197
|
|
|
201
198
|
_model_name: OpenAIModelName = field(repr=False)
|
|
202
|
-
|
|
199
|
+
_provider: Provider[AsyncOpenAI] = field(repr=False)
|
|
200
|
+
|
|
201
|
+
@overload
|
|
202
|
+
def __init__(
|
|
203
|
+
self,
|
|
204
|
+
model_name: OpenAIModelName,
|
|
205
|
+
*,
|
|
206
|
+
provider: Literal[
|
|
207
|
+
'openai',
|
|
208
|
+
'deepseek',
|
|
209
|
+
'azure',
|
|
210
|
+
'openrouter',
|
|
211
|
+
'moonshotai',
|
|
212
|
+
'vercel',
|
|
213
|
+
'grok',
|
|
214
|
+
'fireworks',
|
|
215
|
+
'together',
|
|
216
|
+
'heroku',
|
|
217
|
+
'github',
|
|
218
|
+
'ollama',
|
|
219
|
+
]
|
|
220
|
+
| Provider[AsyncOpenAI] = 'openai',
|
|
221
|
+
profile: ModelProfileSpec | None = None,
|
|
222
|
+
settings: ModelSettings | None = None,
|
|
223
|
+
) -> None: ...
|
|
224
|
+
|
|
225
|
+
@deprecated('Set the `system_prompt_role` in the `OpenAIModelProfile` instead.')
|
|
226
|
+
@overload
|
|
227
|
+
def __init__(
|
|
228
|
+
self,
|
|
229
|
+
model_name: OpenAIModelName,
|
|
230
|
+
*,
|
|
231
|
+
provider: Literal[
|
|
232
|
+
'openai',
|
|
233
|
+
'deepseek',
|
|
234
|
+
'azure',
|
|
235
|
+
'openrouter',
|
|
236
|
+
'moonshotai',
|
|
237
|
+
'vercel',
|
|
238
|
+
'grok',
|
|
239
|
+
'fireworks',
|
|
240
|
+
'together',
|
|
241
|
+
'heroku',
|
|
242
|
+
'github',
|
|
243
|
+
'ollama',
|
|
244
|
+
]
|
|
245
|
+
| Provider[AsyncOpenAI] = 'openai',
|
|
246
|
+
profile: ModelProfileSpec | None = None,
|
|
247
|
+
system_prompt_role: OpenAISystemPromptRole | None = None,
|
|
248
|
+
settings: ModelSettings | None = None,
|
|
249
|
+
) -> None: ...
|
|
203
250
|
|
|
204
251
|
def __init__(
|
|
205
252
|
self,
|
|
@@ -240,16 +287,33 @@ class OpenAIModel(Model):
|
|
|
240
287
|
|
|
241
288
|
if isinstance(provider, str):
|
|
242
289
|
provider = infer_provider(provider)
|
|
290
|
+
self._provider = provider
|
|
243
291
|
self.client = provider.client
|
|
244
292
|
|
|
245
|
-
self.system_prompt_role = system_prompt_role
|
|
246
|
-
|
|
247
293
|
super().__init__(settings=settings, profile=profile or provider.model_profile)
|
|
248
294
|
|
|
295
|
+
if system_prompt_role is not None:
|
|
296
|
+
self.profile = OpenAIModelProfile(openai_system_prompt_role=system_prompt_role).update(self.profile)
|
|
297
|
+
|
|
249
298
|
@property
|
|
250
299
|
def base_url(self) -> str:
|
|
251
300
|
return str(self.client.base_url)
|
|
252
301
|
|
|
302
|
+
@property
|
|
303
|
+
def model_name(self) -> OpenAIModelName:
|
|
304
|
+
"""The model name."""
|
|
305
|
+
return self._model_name
|
|
306
|
+
|
|
307
|
+
@property
|
|
308
|
+
def system(self) -> str:
|
|
309
|
+
"""The model provider."""
|
|
310
|
+
return self._provider.name
|
|
311
|
+
|
|
312
|
+
@property
|
|
313
|
+
@deprecated('Set the `system_prompt_role` in the `OpenAIModelProfile` instead.')
|
|
314
|
+
def system_prompt_role(self) -> OpenAISystemPromptRole | None:
|
|
315
|
+
return OpenAIModelProfile.from_profile(self.profile).openai_system_prompt_role
|
|
316
|
+
|
|
253
317
|
async def request(
|
|
254
318
|
self,
|
|
255
319
|
messages: list[ModelMessage],
|
|
@@ -261,7 +325,6 @@ class OpenAIModel(Model):
|
|
|
261
325
|
messages, False, cast(OpenAIModelSettings, model_settings or {}), model_request_parameters
|
|
262
326
|
)
|
|
263
327
|
model_response = self._process_response(response)
|
|
264
|
-
model_response.usage.requests = 1
|
|
265
328
|
return model_response
|
|
266
329
|
|
|
267
330
|
@asynccontextmanager
|
|
@@ -279,16 +342,6 @@ class OpenAIModel(Model):
|
|
|
279
342
|
async with response:
|
|
280
343
|
yield await self._process_streamed_response(response, model_request_parameters)
|
|
281
344
|
|
|
282
|
-
@property
|
|
283
|
-
def model_name(self) -> OpenAIModelName:
|
|
284
|
-
"""The model name."""
|
|
285
|
-
return self._model_name
|
|
286
|
-
|
|
287
|
-
@property
|
|
288
|
-
def system(self) -> str:
|
|
289
|
-
"""The system / model provider."""
|
|
290
|
-
return self._system
|
|
291
|
-
|
|
292
345
|
@overload
|
|
293
346
|
async def _completions_create(
|
|
294
347
|
self,
|
|
@@ -445,8 +498,8 @@ class OpenAIModel(Model):
|
|
|
445
498
|
usage=_map_usage(response),
|
|
446
499
|
model_name=response.model,
|
|
447
500
|
timestamp=timestamp,
|
|
448
|
-
|
|
449
|
-
|
|
501
|
+
provider_details=vendor_details,
|
|
502
|
+
provider_request_id=response.id,
|
|
450
503
|
)
|
|
451
504
|
|
|
452
505
|
async def _process_streamed_response(
|
|
@@ -562,9 +615,10 @@ class OpenAIModel(Model):
|
|
|
562
615
|
async def _map_user_message(self, message: ModelRequest) -> AsyncIterable[chat.ChatCompletionMessageParam]:
|
|
563
616
|
for part in message.parts:
|
|
564
617
|
if isinstance(part, SystemPromptPart):
|
|
565
|
-
|
|
618
|
+
system_prompt_role = OpenAIModelProfile.from_profile(self.profile).openai_system_prompt_role
|
|
619
|
+
if system_prompt_role == 'developer':
|
|
566
620
|
yield chat.ChatCompletionDeveloperMessageParam(role='developer', content=part.content)
|
|
567
|
-
elif
|
|
621
|
+
elif system_prompt_role == 'user':
|
|
568
622
|
yield chat.ChatCompletionUserMessageParam(role='user', content=part.content)
|
|
569
623
|
else:
|
|
570
624
|
yield chat.ChatCompletionSystemMessageParam(role='system', content=part.content)
|
|
@@ -660,10 +714,9 @@ class OpenAIResponsesModel(Model):
|
|
|
660
714
|
"""
|
|
661
715
|
|
|
662
716
|
client: AsyncOpenAI = field(repr=False)
|
|
663
|
-
system_prompt_role: OpenAISystemPromptRole | None = field(default=None)
|
|
664
717
|
|
|
665
718
|
_model_name: OpenAIModelName = field(repr=False)
|
|
666
|
-
|
|
719
|
+
_provider: Provider[AsyncOpenAI] = field(repr=False)
|
|
667
720
|
|
|
668
721
|
def __init__(
|
|
669
722
|
self,
|
|
@@ -686,6 +739,7 @@ class OpenAIResponsesModel(Model):
|
|
|
686
739
|
|
|
687
740
|
if isinstance(provider, str):
|
|
688
741
|
provider = infer_provider(provider)
|
|
742
|
+
self._provider = provider
|
|
689
743
|
self.client = provider.client
|
|
690
744
|
|
|
691
745
|
super().__init__(settings=settings, profile=profile or provider.model_profile)
|
|
@@ -697,8 +751,8 @@ class OpenAIResponsesModel(Model):
|
|
|
697
751
|
|
|
698
752
|
@property
|
|
699
753
|
def system(self) -> str:
|
|
700
|
-
"""The
|
|
701
|
-
return self.
|
|
754
|
+
"""The model provider."""
|
|
755
|
+
return self._provider.name
|
|
702
756
|
|
|
703
757
|
async def request(
|
|
704
758
|
self,
|
|
@@ -747,7 +801,7 @@ class OpenAIResponsesModel(Model):
|
|
|
747
801
|
items,
|
|
748
802
|
usage=_map_usage(response),
|
|
749
803
|
model_name=response.model,
|
|
750
|
-
|
|
804
|
+
provider_request_id=response.id,
|
|
751
805
|
timestamp=timestamp,
|
|
752
806
|
)
|
|
753
807
|
|
|
@@ -1265,10 +1319,10 @@ class OpenAIResponsesStreamedResponse(StreamedResponse):
|
|
|
1265
1319
|
return self._timestamp
|
|
1266
1320
|
|
|
1267
1321
|
|
|
1268
|
-
def _map_usage(response: chat.ChatCompletion | ChatCompletionChunk | responses.Response) -> usage.
|
|
1322
|
+
def _map_usage(response: chat.ChatCompletion | ChatCompletionChunk | responses.Response) -> usage.RequestUsage:
|
|
1269
1323
|
response_usage = response.usage
|
|
1270
1324
|
if response_usage is None:
|
|
1271
|
-
return usage.
|
|
1325
|
+
return usage.RequestUsage()
|
|
1272
1326
|
elif isinstance(response_usage, responses.ResponseUsage):
|
|
1273
1327
|
details: dict[str, int] = {
|
|
1274
1328
|
key: value
|
|
@@ -1278,29 +1332,29 @@ def _map_usage(response: chat.ChatCompletion | ChatCompletionChunk | responses.R
|
|
|
1278
1332
|
if isinstance(value, int)
|
|
1279
1333
|
}
|
|
1280
1334
|
details['reasoning_tokens'] = response_usage.output_tokens_details.reasoning_tokens
|
|
1281
|
-
|
|
1282
|
-
|
|
1283
|
-
|
|
1284
|
-
|
|
1285
|
-
total_tokens=response_usage.total_tokens,
|
|
1335
|
+
return usage.RequestUsage(
|
|
1336
|
+
input_tokens=response_usage.input_tokens,
|
|
1337
|
+
output_tokens=response_usage.output_tokens,
|
|
1338
|
+
cache_read_tokens=response_usage.input_tokens_details.cached_tokens,
|
|
1286
1339
|
details=details,
|
|
1287
1340
|
)
|
|
1288
1341
|
else:
|
|
1289
1342
|
details = {
|
|
1290
1343
|
key: value
|
|
1291
1344
|
for key, value in response_usage.model_dump(
|
|
1292
|
-
exclude={'prompt_tokens', 'completion_tokens', 'total_tokens'}
|
|
1345
|
+
exclude_none=True, exclude={'prompt_tokens', 'completion_tokens', 'total_tokens'}
|
|
1293
1346
|
).items()
|
|
1294
1347
|
if isinstance(value, int)
|
|
1295
1348
|
}
|
|
1349
|
+
u = usage.RequestUsage(
|
|
1350
|
+
input_tokens=response_usage.prompt_tokens,
|
|
1351
|
+
output_tokens=response_usage.completion_tokens,
|
|
1352
|
+
details=details,
|
|
1353
|
+
)
|
|
1296
1354
|
if response_usage.completion_tokens_details is not None:
|
|
1297
1355
|
details.update(response_usage.completion_tokens_details.model_dump(exclude_none=True))
|
|
1356
|
+
u.output_audio_tokens = response_usage.completion_tokens_details.audio_tokens or 0
|
|
1298
1357
|
if response_usage.prompt_tokens_details is not None:
|
|
1299
|
-
|
|
1300
|
-
|
|
1301
|
-
|
|
1302
|
-
request_tokens=response_usage.prompt_tokens,
|
|
1303
|
-
response_tokens=response_usage.completion_tokens,
|
|
1304
|
-
total_tokens=response_usage.total_tokens,
|
|
1305
|
-
details=details,
|
|
1306
|
-
)
|
|
1358
|
+
u.input_audio_tokens = response_usage.prompt_tokens_details.audio_tokens or 0
|
|
1359
|
+
u.cache_read_tokens = response_usage.prompt_tokens_details.cached_tokens or 0
|
|
1360
|
+
return u
|
pydantic_ai/models/test.py
CHANGED
|
@@ -31,7 +31,7 @@ from ..messages import (
|
|
|
31
31
|
from ..profiles import ModelProfileSpec
|
|
32
32
|
from ..settings import ModelSettings
|
|
33
33
|
from ..tools import ToolDefinition
|
|
34
|
-
from ..usage import
|
|
34
|
+
from ..usage import RequestUsage
|
|
35
35
|
from . import Model, ModelRequestParameters, StreamedResponse
|
|
36
36
|
from .function import _estimate_string_tokens, _estimate_usage # pyright: ignore[reportPrivateUsage]
|
|
37
37
|
|
|
@@ -113,7 +113,6 @@ class TestModel(Model):
|
|
|
113
113
|
self.last_model_request_parameters = model_request_parameters
|
|
114
114
|
model_response = self._request(messages, model_settings, model_request_parameters)
|
|
115
115
|
model_response.usage = _estimate_usage([*messages, model_response])
|
|
116
|
-
model_response.usage.requests = 1
|
|
117
116
|
return model_response
|
|
118
117
|
|
|
119
118
|
@asynccontextmanager
|
|
@@ -141,7 +140,7 @@ class TestModel(Model):
|
|
|
141
140
|
|
|
142
141
|
@property
|
|
143
142
|
def system(self) -> str:
|
|
144
|
-
"""The
|
|
143
|
+
"""The model provider."""
|
|
145
144
|
return self._system
|
|
146
145
|
|
|
147
146
|
def gen_tool_args(self, tool_def: ToolDefinition) -> Any:
|
|
@@ -468,6 +467,6 @@ class _JsonSchemaTestData:
|
|
|
468
467
|
return s
|
|
469
468
|
|
|
470
469
|
|
|
471
|
-
def _get_string_usage(text: str) ->
|
|
470
|
+
def _get_string_usage(text: str) -> RequestUsage:
|
|
472
471
|
response_tokens = _estimate_string_tokens(text)
|
|
473
|
-
return
|
|
472
|
+
return RequestUsage(output_tokens=response_tokens)
|
pydantic_ai/profiles/openai.py
CHANGED
|
@@ -2,11 +2,13 @@ from __future__ import annotations as _annotations
|
|
|
2
2
|
|
|
3
3
|
import re
|
|
4
4
|
from dataclasses import dataclass
|
|
5
|
-
from typing import Any
|
|
5
|
+
from typing import Any, Literal
|
|
6
6
|
|
|
7
7
|
from . import ModelProfile
|
|
8
8
|
from ._json_schema import JsonSchema, JsonSchemaTransformer
|
|
9
9
|
|
|
10
|
+
OpenAISystemPromptRole = Literal['system', 'developer', 'user']
|
|
11
|
+
|
|
10
12
|
|
|
11
13
|
@dataclass
|
|
12
14
|
class OpenAIModelProfile(ModelProfile):
|
|
@@ -26,8 +28,10 @@ class OpenAIModelProfile(ModelProfile):
|
|
|
26
28
|
# safe to pass that value along. Default is `True` to preserve existing
|
|
27
29
|
# behaviour for OpenAI itself and most providers.
|
|
28
30
|
openai_supports_tool_choice_required: bool = True
|
|
29
|
-
"""Whether the provider accepts the value ``tool_choice='required'`` in the
|
|
30
|
-
|
|
31
|
+
"""Whether the provider accepts the value ``tool_choice='required'`` in the request payload."""
|
|
32
|
+
|
|
33
|
+
openai_system_prompt_role: OpenAISystemPromptRole | None = None
|
|
34
|
+
"""The role to use for the system prompt message. If not provided, defaults to `'system'`."""
|
|
31
35
|
|
|
32
36
|
|
|
33
37
|
def openai_model_profile(model_name: str) -> ModelProfile:
|
|
@@ -36,11 +40,17 @@ def openai_model_profile(model_name: str) -> ModelProfile:
|
|
|
36
40
|
# Structured Outputs (output mode 'native') is only supported with the gpt-4o-mini, gpt-4o-mini-2024-07-18, and gpt-4o-2024-08-06 model snapshots and later.
|
|
37
41
|
# We leave it in here for all models because the `default_structured_output_mode` is `'tool'`, so `native` is only used
|
|
38
42
|
# when the user specifically uses the `NativeOutput` marker, so an error from the API is acceptable.
|
|
43
|
+
|
|
44
|
+
# The o1-mini model doesn't support the `system` role, so we default to `user`.
|
|
45
|
+
# See https://github.com/pydantic/pydantic-ai/issues/974 for more details.
|
|
46
|
+
openai_system_prompt_role = 'user' if model_name.startswith('o1-mini') else None
|
|
47
|
+
|
|
39
48
|
return OpenAIModelProfile(
|
|
40
49
|
json_schema_transformer=OpenAIJsonSchemaTransformer,
|
|
41
50
|
supports_json_schema_output=True,
|
|
42
51
|
supports_json_object_output=True,
|
|
43
52
|
openai_supports_sampling_settings=not is_reasoning_model,
|
|
53
|
+
openai_system_prompt_role=openai_system_prompt_role,
|
|
44
54
|
)
|
|
45
55
|
|
|
46
56
|
|
pydantic_ai/providers/openai.py
CHANGED
pydantic_ai/result.py
CHANGED
|
@@ -27,7 +27,7 @@ from .output import (
|
|
|
27
27
|
OutputDataT,
|
|
28
28
|
ToolOutput,
|
|
29
29
|
)
|
|
30
|
-
from .usage import
|
|
30
|
+
from .usage import RunUsage, UsageLimits
|
|
31
31
|
|
|
32
32
|
__all__ = (
|
|
33
33
|
'OutputDataT',
|
|
@@ -52,7 +52,7 @@ class AgentStream(Generic[AgentDepsT, OutputDataT]):
|
|
|
52
52
|
_tool_manager: ToolManager[AgentDepsT]
|
|
53
53
|
|
|
54
54
|
_agent_stream_iterator: AsyncIterator[AgentStreamEvent] | None = field(default=None, init=False)
|
|
55
|
-
_initial_run_ctx_usage:
|
|
55
|
+
_initial_run_ctx_usage: RunUsage = field(init=False)
|
|
56
56
|
|
|
57
57
|
def __post_init__(self):
|
|
58
58
|
self._initial_run_ctx_usage = copy(self._run_ctx.usage)
|
|
@@ -110,7 +110,7 @@ class AgentStream(Generic[AgentDepsT, OutputDataT]):
|
|
|
110
110
|
"""Get the current state of the response."""
|
|
111
111
|
return self._raw_stream_response.get()
|
|
112
112
|
|
|
113
|
-
def usage(self) ->
|
|
113
|
+
def usage(self) -> RunUsage:
|
|
114
114
|
"""Return the usage of the whole run.
|
|
115
115
|
|
|
116
116
|
!!! note
|
|
@@ -382,7 +382,7 @@ class StreamedRunResult(Generic[AgentDepsT, OutputDataT]):
|
|
|
382
382
|
await self._marked_completed(self._stream_response.get())
|
|
383
383
|
return output
|
|
384
384
|
|
|
385
|
-
def usage(self) ->
|
|
385
|
+
def usage(self) -> RunUsage:
|
|
386
386
|
"""Return the usage of the whole run.
|
|
387
387
|
|
|
388
388
|
!!! note
|
|
@@ -425,7 +425,7 @@ class FinalResult(Generic[OutputDataT]):
|
|
|
425
425
|
def _get_usage_checking_stream_response(
|
|
426
426
|
stream_response: models.StreamedResponse,
|
|
427
427
|
limits: UsageLimits | None,
|
|
428
|
-
get_usage: Callable[[],
|
|
428
|
+
get_usage: Callable[[], RunUsage],
|
|
429
429
|
) -> AsyncIterator[AgentStreamEvent]:
|
|
430
430
|
if limits is not None and limits.has_token_limits():
|
|
431
431
|
|
pydantic_ai/run.py
CHANGED
|
@@ -66,9 +66,7 @@ class AgentRun(Generic[AgentDepsT, OutputDataT]):
|
|
|
66
66
|
CallToolsNode(
|
|
67
67
|
model_response=ModelResponse(
|
|
68
68
|
parts=[TextPart(content='The capital of France is Paris.')],
|
|
69
|
-
usage=
|
|
70
|
-
requests=1, request_tokens=56, response_tokens=7, total_tokens=63
|
|
71
|
-
),
|
|
69
|
+
usage=RequestUsage(input_tokens=56, output_tokens=7),
|
|
72
70
|
model_name='gpt-4o',
|
|
73
71
|
timestamp=datetime.datetime(...),
|
|
74
72
|
)
|
|
@@ -203,12 +201,7 @@ class AgentRun(Generic[AgentDepsT, OutputDataT]):
|
|
|
203
201
|
CallToolsNode(
|
|
204
202
|
model_response=ModelResponse(
|
|
205
203
|
parts=[TextPart(content='The capital of France is Paris.')],
|
|
206
|
-
usage=
|
|
207
|
-
requests=1,
|
|
208
|
-
request_tokens=56,
|
|
209
|
-
response_tokens=7,
|
|
210
|
-
total_tokens=63,
|
|
211
|
-
),
|
|
204
|
+
usage=RequestUsage(input_tokens=56, output_tokens=7),
|
|
212
205
|
model_name='gpt-4o',
|
|
213
206
|
timestamp=datetime.datetime(...),
|
|
214
207
|
)
|
|
@@ -235,7 +228,7 @@ class AgentRun(Generic[AgentDepsT, OutputDataT]):
|
|
|
235
228
|
assert isinstance(next_node, End), f'Unexpected node type: {type(next_node)}'
|
|
236
229
|
return next_node
|
|
237
230
|
|
|
238
|
-
def usage(self) -> _usage.
|
|
231
|
+
def usage(self) -> _usage.RunUsage:
|
|
239
232
|
"""Get usage statistics for the run so far, including token usage, model requests, and so on."""
|
|
240
233
|
return self._graph_run.state.usage
|
|
241
234
|
|
|
@@ -352,6 +345,6 @@ class AgentRunResult(Generic[OutputDataT]):
|
|
|
352
345
|
self.new_messages(output_tool_return_content=output_tool_return_content)
|
|
353
346
|
)
|
|
354
347
|
|
|
355
|
-
def usage(self) -> _usage.
|
|
348
|
+
def usage(self) -> _usage.RunUsage:
|
|
356
349
|
"""Return the usage of the whole run."""
|
|
357
350
|
return self._state.usage
|