pydantic-ai-slim 0.8.0__py3-none-any.whl → 1.0.0b1__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.
Potentially problematic release.
This version of pydantic-ai-slim might be problematic. Click here for more details.
- pydantic_ai/__init__.py +28 -2
- pydantic_ai/_agent_graph.py +310 -140
- pydantic_ai/_function_schema.py +5 -5
- pydantic_ai/_griffe.py +2 -1
- pydantic_ai/_otel_messages.py +2 -2
- pydantic_ai/_output.py +31 -35
- pydantic_ai/_parts_manager.py +4 -4
- pydantic_ai/_run_context.py +3 -1
- pydantic_ai/_system_prompt.py +2 -2
- pydantic_ai/_tool_manager.py +3 -22
- pydantic_ai/_utils.py +14 -26
- pydantic_ai/ag_ui.py +7 -8
- pydantic_ai/agent/__init__.py +84 -17
- pydantic_ai/agent/abstract.py +35 -4
- pydantic_ai/agent/wrapper.py +6 -0
- pydantic_ai/builtin_tools.py +2 -2
- pydantic_ai/common_tools/duckduckgo.py +4 -2
- pydantic_ai/durable_exec/temporal/__init__.py +70 -17
- pydantic_ai/durable_exec/temporal/_agent.py +23 -2
- pydantic_ai/durable_exec/temporal/_function_toolset.py +53 -6
- pydantic_ai/durable_exec/temporal/_logfire.py +6 -3
- pydantic_ai/durable_exec/temporal/_mcp_server.py +2 -1
- pydantic_ai/durable_exec/temporal/_model.py +2 -2
- pydantic_ai/durable_exec/temporal/_run_context.py +2 -1
- pydantic_ai/durable_exec/temporal/_toolset.py +2 -1
- pydantic_ai/exceptions.py +45 -2
- pydantic_ai/format_prompt.py +2 -2
- pydantic_ai/mcp.py +2 -2
- pydantic_ai/messages.py +81 -28
- pydantic_ai/models/__init__.py +19 -7
- pydantic_ai/models/anthropic.py +6 -6
- pydantic_ai/models/bedrock.py +63 -57
- pydantic_ai/models/cohere.py +3 -3
- pydantic_ai/models/fallback.py +2 -2
- pydantic_ai/models/function.py +25 -23
- pydantic_ai/models/gemini.py +10 -13
- pydantic_ai/models/google.py +4 -4
- pydantic_ai/models/groq.py +5 -5
- pydantic_ai/models/huggingface.py +5 -5
- pydantic_ai/models/instrumented.py +44 -21
- pydantic_ai/models/mcp_sampling.py +3 -1
- pydantic_ai/models/mistral.py +8 -8
- pydantic_ai/models/openai.py +20 -29
- pydantic_ai/models/test.py +24 -4
- pydantic_ai/output.py +27 -32
- pydantic_ai/profiles/__init__.py +3 -3
- pydantic_ai/profiles/groq.py +1 -1
- pydantic_ai/profiles/openai.py +25 -4
- pydantic_ai/providers/anthropic.py +2 -3
- pydantic_ai/providers/bedrock.py +3 -2
- pydantic_ai/result.py +173 -52
- pydantic_ai/retries.py +10 -29
- pydantic_ai/run.py +12 -5
- pydantic_ai/tools.py +126 -22
- pydantic_ai/toolsets/__init__.py +4 -1
- pydantic_ai/toolsets/_dynamic.py +4 -4
- pydantic_ai/toolsets/abstract.py +18 -2
- pydantic_ai/toolsets/approval_required.py +32 -0
- pydantic_ai/toolsets/combined.py +7 -12
- pydantic_ai/toolsets/{deferred.py → external.py} +11 -5
- pydantic_ai/toolsets/filtered.py +1 -1
- pydantic_ai/toolsets/function.py +13 -4
- pydantic_ai/toolsets/wrapper.py +2 -1
- pydantic_ai/usage.py +7 -5
- {pydantic_ai_slim-0.8.0.dist-info → pydantic_ai_slim-1.0.0b1.dist-info}/METADATA +6 -7
- pydantic_ai_slim-1.0.0b1.dist-info/RECORD +120 -0
- pydantic_ai_slim-0.8.0.dist-info/RECORD +0 -119
- {pydantic_ai_slim-0.8.0.dist-info → pydantic_ai_slim-1.0.0b1.dist-info}/WHEEL +0 -0
- {pydantic_ai_slim-0.8.0.dist-info → pydantic_ai_slim-1.0.0b1.dist-info}/entry_points.txt +0 -0
- {pydantic_ai_slim-0.8.0.dist-info → pydantic_ai_slim-1.0.0b1.dist-info}/licenses/LICENSE +0 -0
pydantic_ai/messages.py
CHANGED
|
@@ -3,22 +3,19 @@ from __future__ import annotations as _annotations
|
|
|
3
3
|
import base64
|
|
4
4
|
from abc import ABC, abstractmethod
|
|
5
5
|
from collections.abc import Sequence
|
|
6
|
-
from dataclasses import dataclass, field, replace
|
|
6
|
+
from dataclasses import KW_ONLY, dataclass, field, replace
|
|
7
7
|
from datetime import datetime
|
|
8
8
|
from mimetypes import guess_type
|
|
9
|
-
from typing import TYPE_CHECKING, Annotated, Any, Literal,
|
|
9
|
+
from typing import TYPE_CHECKING, Annotated, Any, Literal, TypeAlias, cast, overload
|
|
10
10
|
|
|
11
11
|
import pydantic
|
|
12
12
|
import pydantic_core
|
|
13
13
|
from genai_prices import calc_price, types as genai_types
|
|
14
14
|
from opentelemetry._events import Event # pyright: ignore[reportPrivateImportUsage]
|
|
15
|
-
from typing_extensions import
|
|
15
|
+
from typing_extensions import deprecated
|
|
16
16
|
|
|
17
17
|
from . import _otel_messages, _utils
|
|
18
|
-
from ._utils import
|
|
19
|
-
generate_tool_call_id as _generate_tool_call_id,
|
|
20
|
-
now_utc as _now_utc,
|
|
21
|
-
)
|
|
18
|
+
from ._utils import generate_tool_call_id as _generate_tool_call_id, now_utc as _now_utc
|
|
22
19
|
from .exceptions import UnexpectedModelBehavior
|
|
23
20
|
from .usage import RequestUsage
|
|
24
21
|
|
|
@@ -65,6 +62,8 @@ class SystemPromptPart:
|
|
|
65
62
|
content: str
|
|
66
63
|
"""The content of the prompt."""
|
|
67
64
|
|
|
65
|
+
_: KW_ONLY
|
|
66
|
+
|
|
68
67
|
timestamp: datetime = field(default_factory=_now_utc)
|
|
69
68
|
"""The timestamp of the prompt."""
|
|
70
69
|
|
|
@@ -96,6 +95,8 @@ class FileUrl(ABC):
|
|
|
96
95
|
url: str
|
|
97
96
|
"""The URL of the file."""
|
|
98
97
|
|
|
98
|
+
_: KW_ONLY
|
|
99
|
+
|
|
99
100
|
force_download: bool = False
|
|
100
101
|
"""If the model supports it:
|
|
101
102
|
|
|
@@ -153,6 +154,8 @@ class VideoUrl(FileUrl):
|
|
|
153
154
|
url: str
|
|
154
155
|
"""The URL of the video."""
|
|
155
156
|
|
|
157
|
+
_: KW_ONLY
|
|
158
|
+
|
|
156
159
|
kind: Literal['video-url'] = 'video-url'
|
|
157
160
|
"""Type identifier, this is available on all parts as a discriminator."""
|
|
158
161
|
|
|
@@ -224,6 +227,8 @@ class AudioUrl(FileUrl):
|
|
|
224
227
|
url: str
|
|
225
228
|
"""The URL of the audio file."""
|
|
226
229
|
|
|
230
|
+
_: KW_ONLY
|
|
231
|
+
|
|
227
232
|
kind: Literal['audio-url'] = 'audio-url'
|
|
228
233
|
"""Type identifier, this is available on all parts as a discriminator."""
|
|
229
234
|
|
|
@@ -282,6 +287,8 @@ class ImageUrl(FileUrl):
|
|
|
282
287
|
url: str
|
|
283
288
|
"""The URL of the image."""
|
|
284
289
|
|
|
290
|
+
_: KW_ONLY
|
|
291
|
+
|
|
285
292
|
kind: Literal['image-url'] = 'image-url'
|
|
286
293
|
"""Type identifier, this is available on all parts as a discriminator."""
|
|
287
294
|
|
|
@@ -335,6 +342,8 @@ class DocumentUrl(FileUrl):
|
|
|
335
342
|
url: str
|
|
336
343
|
"""The URL of the document."""
|
|
337
344
|
|
|
345
|
+
_: KW_ONLY
|
|
346
|
+
|
|
338
347
|
kind: Literal['document-url'] = 'document-url'
|
|
339
348
|
"""Type identifier, this is available on all parts as a discriminator."""
|
|
340
349
|
|
|
@@ -406,6 +415,8 @@ class BinaryContent:
|
|
|
406
415
|
media_type: AudioMediaType | ImageMediaType | DocumentMediaType | str
|
|
407
416
|
"""The media type of the binary data."""
|
|
408
417
|
|
|
418
|
+
_: KW_ONLY
|
|
419
|
+
|
|
409
420
|
identifier: str | None = None
|
|
410
421
|
"""Identifier for the binary content, such as a URL or unique ID.
|
|
411
422
|
|
|
@@ -462,7 +473,8 @@ class BinaryContent:
|
|
|
462
473
|
__repr__ = _utils.dataclasses_no_defaults_repr
|
|
463
474
|
|
|
464
475
|
|
|
465
|
-
|
|
476
|
+
MultiModalContent = ImageUrl | AudioUrl | DocumentUrl | VideoUrl | BinaryContent
|
|
477
|
+
UserContent: TypeAlias = str | MultiModalContent
|
|
466
478
|
|
|
467
479
|
|
|
468
480
|
@dataclass(repr=False)
|
|
@@ -478,17 +490,19 @@ class ToolReturn:
|
|
|
478
490
|
return_value: Any
|
|
479
491
|
"""The return value to be used in the tool response."""
|
|
480
492
|
|
|
493
|
+
_: KW_ONLY
|
|
494
|
+
|
|
481
495
|
content: str | Sequence[UserContent] | None = None
|
|
482
496
|
"""The content to be sent to the model as a UserPromptPart."""
|
|
483
497
|
|
|
484
498
|
metadata: Any = None
|
|
485
499
|
"""Additional data that can be accessed programmatically by the application but is not sent to the LLM."""
|
|
486
500
|
|
|
501
|
+
kind: Literal['tool-return'] = 'tool-return'
|
|
502
|
+
|
|
487
503
|
__repr__ = _utils.dataclasses_no_defaults_repr
|
|
488
504
|
|
|
489
505
|
|
|
490
|
-
# Ideally this would be a Union of types, but Python 3.9 requires it to be a string, and strings don't work with `isinstance``.
|
|
491
|
-
MultiModalContentTypes = (ImageUrl, AudioUrl, DocumentUrl, VideoUrl, BinaryContent)
|
|
492
506
|
_document_format_lookup: dict[str, DocumentFormat] = {
|
|
493
507
|
'application/pdf': 'pdf',
|
|
494
508
|
'text/plain': 'txt',
|
|
@@ -536,6 +550,8 @@ class UserPromptPart:
|
|
|
536
550
|
content: str | Sequence[UserContent]
|
|
537
551
|
"""The content of the prompt."""
|
|
538
552
|
|
|
553
|
+
_: KW_ONLY
|
|
554
|
+
|
|
539
555
|
timestamp: datetime = field(default_factory=_now_utc)
|
|
540
556
|
"""The timestamp of the prompt."""
|
|
541
557
|
|
|
@@ -562,7 +578,7 @@ class UserPromptPart:
|
|
|
562
578
|
parts.append(
|
|
563
579
|
_otel_messages.TextPart(type='text', **({'content': part} if settings.include_content else {}))
|
|
564
580
|
)
|
|
565
|
-
elif isinstance(part,
|
|
581
|
+
elif isinstance(part, ImageUrl | AudioUrl | DocumentUrl | VideoUrl):
|
|
566
582
|
parts.append(
|
|
567
583
|
_otel_messages.MediaUrlPart(
|
|
568
584
|
type=part.kind,
|
|
@@ -599,6 +615,8 @@ class BaseToolReturnPart:
|
|
|
599
615
|
tool_call_id: str
|
|
600
616
|
"""The tool call identifier, this is used by some models including OpenAI."""
|
|
601
617
|
|
|
618
|
+
_: KW_ONLY
|
|
619
|
+
|
|
602
620
|
metadata: Any = None
|
|
603
621
|
"""Additional data that can be accessed programmatically by the application but is not sent to the LLM."""
|
|
604
622
|
|
|
@@ -654,6 +672,8 @@ class BaseToolReturnPart:
|
|
|
654
672
|
class ToolReturnPart(BaseToolReturnPart):
|
|
655
673
|
"""A tool return message, this encodes the result of running a tool."""
|
|
656
674
|
|
|
675
|
+
_: KW_ONLY
|
|
676
|
+
|
|
657
677
|
part_kind: Literal['tool-return'] = 'tool-return'
|
|
658
678
|
"""Part type identifier, this is available on all parts as a discriminator."""
|
|
659
679
|
|
|
@@ -662,6 +682,8 @@ class ToolReturnPart(BaseToolReturnPart):
|
|
|
662
682
|
class BuiltinToolReturnPart(BaseToolReturnPart):
|
|
663
683
|
"""A tool return message from a built-in tool."""
|
|
664
684
|
|
|
685
|
+
_: KW_ONLY
|
|
686
|
+
|
|
665
687
|
provider_name: str | None = None
|
|
666
688
|
"""The name of the provider that generated the response."""
|
|
667
689
|
|
|
@@ -695,6 +717,8 @@ class RetryPromptPart:
|
|
|
695
717
|
error details.
|
|
696
718
|
"""
|
|
697
719
|
|
|
720
|
+
_: KW_ONLY
|
|
721
|
+
|
|
698
722
|
tool_name: str | None = None
|
|
699
723
|
"""The name of the tool that was called, if any."""
|
|
700
724
|
|
|
@@ -753,7 +777,7 @@ class RetryPromptPart:
|
|
|
753
777
|
|
|
754
778
|
|
|
755
779
|
ModelRequestPart = Annotated[
|
|
756
|
-
|
|
780
|
+
SystemPromptPart | UserPromptPart | ToolReturnPart | RetryPromptPart, pydantic.Discriminator('part_kind')
|
|
757
781
|
]
|
|
758
782
|
"""A message part sent by Pydantic AI to a model."""
|
|
759
783
|
|
|
@@ -765,6 +789,8 @@ class ModelRequest:
|
|
|
765
789
|
parts: list[ModelRequestPart]
|
|
766
790
|
"""The parts of the user message."""
|
|
767
791
|
|
|
792
|
+
_: KW_ONLY
|
|
793
|
+
|
|
768
794
|
instructions: str | None = None
|
|
769
795
|
"""The instructions for the model."""
|
|
770
796
|
|
|
@@ -786,6 +812,8 @@ class TextPart:
|
|
|
786
812
|
content: str
|
|
787
813
|
"""The text content of the response."""
|
|
788
814
|
|
|
815
|
+
_: KW_ONLY
|
|
816
|
+
|
|
789
817
|
part_kind: Literal['text'] = 'text'
|
|
790
818
|
"""Part type identifier, this is available on all parts as a discriminator."""
|
|
791
819
|
|
|
@@ -803,6 +831,8 @@ class ThinkingPart:
|
|
|
803
831
|
content: str
|
|
804
832
|
"""The thinking content of the response."""
|
|
805
833
|
|
|
834
|
+
_: KW_ONLY
|
|
835
|
+
|
|
806
836
|
id: str | None = None
|
|
807
837
|
"""The identifier of the thinking part."""
|
|
808
838
|
|
|
@@ -881,6 +911,8 @@ class BaseToolCallPart:
|
|
|
881
911
|
class ToolCallPart(BaseToolCallPart):
|
|
882
912
|
"""A tool call from a model."""
|
|
883
913
|
|
|
914
|
+
_: KW_ONLY
|
|
915
|
+
|
|
884
916
|
part_kind: Literal['tool-call'] = 'tool-call'
|
|
885
917
|
"""Part type identifier, this is available on all parts as a discriminator."""
|
|
886
918
|
|
|
@@ -889,6 +921,8 @@ class ToolCallPart(BaseToolCallPart):
|
|
|
889
921
|
class BuiltinToolCallPart(BaseToolCallPart):
|
|
890
922
|
"""A tool call to a built-in tool."""
|
|
891
923
|
|
|
924
|
+
_: KW_ONLY
|
|
925
|
+
|
|
892
926
|
provider_name: str | None = None
|
|
893
927
|
"""The name of the provider that generated the response."""
|
|
894
928
|
|
|
@@ -897,7 +931,7 @@ class BuiltinToolCallPart(BaseToolCallPart):
|
|
|
897
931
|
|
|
898
932
|
|
|
899
933
|
ModelResponsePart = Annotated[
|
|
900
|
-
|
|
934
|
+
TextPart | ToolCallPart | BuiltinToolCallPart | BuiltinToolReturnPart | ThinkingPart,
|
|
901
935
|
pydantic.Discriminator('part_kind'),
|
|
902
936
|
]
|
|
903
937
|
"""A message part returned by a model."""
|
|
@@ -910,6 +944,8 @@ class ModelResponse:
|
|
|
910
944
|
parts: list[ModelResponsePart]
|
|
911
945
|
"""The parts of the model message."""
|
|
912
946
|
|
|
947
|
+
_: KW_ONLY
|
|
948
|
+
|
|
913
949
|
usage: RequestUsage = field(default_factory=RequestUsage)
|
|
914
950
|
"""Usage information for the request.
|
|
915
951
|
|
|
@@ -938,7 +974,7 @@ class ModelResponse:
|
|
|
938
974
|
For OpenAI models, this may include 'logprobs', 'finish_reason', etc.
|
|
939
975
|
"""
|
|
940
976
|
|
|
941
|
-
|
|
977
|
+
provider_response_id: str | None = None
|
|
942
978
|
"""request ID as specified by the model provider. This can be used to track the specific request to the model."""
|
|
943
979
|
|
|
944
980
|
def price(self) -> genai_types.PriceCalculation:
|
|
@@ -970,14 +1006,14 @@ class ModelResponse:
|
|
|
970
1006
|
body.setdefault('tool_calls', []).append(
|
|
971
1007
|
{
|
|
972
1008
|
'id': part.tool_call_id,
|
|
973
|
-
'type': 'function',
|
|
1009
|
+
'type': 'function',
|
|
974
1010
|
'function': {
|
|
975
1011
|
'name': part.tool_name,
|
|
976
1012
|
**({'arguments': part.args} if settings.include_content else {}),
|
|
977
1013
|
},
|
|
978
1014
|
}
|
|
979
1015
|
)
|
|
980
|
-
elif isinstance(part,
|
|
1016
|
+
elif isinstance(part, TextPart | ThinkingPart):
|
|
981
1017
|
kind = part.part_kind
|
|
982
1018
|
body.setdefault('content', []).append(
|
|
983
1019
|
{'kind': kind, **({'text': part.content} if settings.include_content else {})}
|
|
@@ -1026,14 +1062,19 @@ class ModelResponse:
|
|
|
1026
1062
|
return self.provider_details
|
|
1027
1063
|
|
|
1028
1064
|
@property
|
|
1029
|
-
@deprecated('`vendor_id` is deprecated, use `
|
|
1065
|
+
@deprecated('`vendor_id` is deprecated, use `provider_response_id` instead')
|
|
1030
1066
|
def vendor_id(self) -> str | None:
|
|
1031
|
-
return self.
|
|
1067
|
+
return self.provider_response_id
|
|
1068
|
+
|
|
1069
|
+
@property
|
|
1070
|
+
@deprecated('`provider_request_id` is deprecated, use `provider_response_id` instead')
|
|
1071
|
+
def provider_request_id(self) -> str | None:
|
|
1072
|
+
return self.provider_response_id
|
|
1032
1073
|
|
|
1033
1074
|
__repr__ = _utils.dataclasses_no_defaults_repr
|
|
1034
1075
|
|
|
1035
1076
|
|
|
1036
|
-
ModelMessage = Annotated[
|
|
1077
|
+
ModelMessage = Annotated[ModelRequest | ModelResponse, pydantic.Discriminator('kind')]
|
|
1037
1078
|
"""Any message sent to or returned by a model."""
|
|
1038
1079
|
|
|
1039
1080
|
ModelMessagesTypeAdapter = pydantic.TypeAdapter(
|
|
@@ -1049,6 +1090,8 @@ class TextPartDelta:
|
|
|
1049
1090
|
content_delta: str
|
|
1050
1091
|
"""The incremental text content to add to the existing `TextPart` content."""
|
|
1051
1092
|
|
|
1093
|
+
_: KW_ONLY
|
|
1094
|
+
|
|
1052
1095
|
part_delta_kind: Literal['text'] = 'text'
|
|
1053
1096
|
"""Part delta type identifier, used as a discriminator."""
|
|
1054
1097
|
|
|
@@ -1071,7 +1114,7 @@ class TextPartDelta:
|
|
|
1071
1114
|
__repr__ = _utils.dataclasses_no_defaults_repr
|
|
1072
1115
|
|
|
1073
1116
|
|
|
1074
|
-
@dataclass(repr=False)
|
|
1117
|
+
@dataclass(repr=False, kw_only=True)
|
|
1075
1118
|
class ThinkingPartDelta:
|
|
1076
1119
|
"""A partial update (delta) for a `ThinkingPart` to append new thinking content."""
|
|
1077
1120
|
|
|
@@ -1123,7 +1166,7 @@ class ThinkingPartDelta:
|
|
|
1123
1166
|
__repr__ = _utils.dataclasses_no_defaults_repr
|
|
1124
1167
|
|
|
1125
1168
|
|
|
1126
|
-
@dataclass(repr=False)
|
|
1169
|
+
@dataclass(repr=False, kw_only=True)
|
|
1127
1170
|
class ToolCallPartDelta:
|
|
1128
1171
|
"""A partial update (delta) for a `ToolCallPart` to modify tool name, arguments, or tool call ID."""
|
|
1129
1172
|
|
|
@@ -1243,12 +1286,12 @@ class ToolCallPartDelta:
|
|
|
1243
1286
|
|
|
1244
1287
|
|
|
1245
1288
|
ModelResponsePartDelta = Annotated[
|
|
1246
|
-
|
|
1289
|
+
TextPartDelta | ThinkingPartDelta | ToolCallPartDelta, pydantic.Discriminator('part_delta_kind')
|
|
1247
1290
|
]
|
|
1248
1291
|
"""A partial update (delta) for any model response part."""
|
|
1249
1292
|
|
|
1250
1293
|
|
|
1251
|
-
@dataclass(repr=False)
|
|
1294
|
+
@dataclass(repr=False, kw_only=True)
|
|
1252
1295
|
class PartStartEvent:
|
|
1253
1296
|
"""An event indicating that a new part has started.
|
|
1254
1297
|
|
|
@@ -1268,7 +1311,7 @@ class PartStartEvent:
|
|
|
1268
1311
|
__repr__ = _utils.dataclasses_no_defaults_repr
|
|
1269
1312
|
|
|
1270
1313
|
|
|
1271
|
-
@dataclass(repr=False)
|
|
1314
|
+
@dataclass(repr=False, kw_only=True)
|
|
1272
1315
|
class PartDeltaEvent:
|
|
1273
1316
|
"""An event indicating a delta update for an existing part."""
|
|
1274
1317
|
|
|
@@ -1284,7 +1327,7 @@ class PartDeltaEvent:
|
|
|
1284
1327
|
__repr__ = _utils.dataclasses_no_defaults_repr
|
|
1285
1328
|
|
|
1286
1329
|
|
|
1287
|
-
@dataclass(repr=False)
|
|
1330
|
+
@dataclass(repr=False, kw_only=True)
|
|
1288
1331
|
class FinalResultEvent:
|
|
1289
1332
|
"""An event indicating the response to the current model request matches the output schema and will produce a result."""
|
|
1290
1333
|
|
|
@@ -1299,7 +1342,7 @@ class FinalResultEvent:
|
|
|
1299
1342
|
|
|
1300
1343
|
|
|
1301
1344
|
ModelResponseStreamEvent = Annotated[
|
|
1302
|
-
|
|
1345
|
+
PartStartEvent | PartDeltaEvent | FinalResultEvent, pydantic.Discriminator('event_kind')
|
|
1303
1346
|
]
|
|
1304
1347
|
"""An event in the model response stream, starting a new part, applying a delta to an existing one, or indicating the final result."""
|
|
1305
1348
|
|
|
@@ -1310,6 +1353,9 @@ class FunctionToolCallEvent:
|
|
|
1310
1353
|
|
|
1311
1354
|
part: ToolCallPart
|
|
1312
1355
|
"""The (function) tool call to make."""
|
|
1356
|
+
|
|
1357
|
+
_: KW_ONLY
|
|
1358
|
+
|
|
1313
1359
|
event_kind: Literal['function_tool_call'] = 'function_tool_call'
|
|
1314
1360
|
"""Event type identifier, used as a discriminator."""
|
|
1315
1361
|
|
|
@@ -1333,6 +1379,9 @@ class FunctionToolResultEvent:
|
|
|
1333
1379
|
|
|
1334
1380
|
result: ToolReturnPart | RetryPromptPart
|
|
1335
1381
|
"""The result of the call to the function tool."""
|
|
1382
|
+
|
|
1383
|
+
_: KW_ONLY
|
|
1384
|
+
|
|
1336
1385
|
event_kind: Literal['function_tool_result'] = 'function_tool_result'
|
|
1337
1386
|
"""Event type identifier, used as a discriminator."""
|
|
1338
1387
|
|
|
@@ -1351,6 +1400,8 @@ class BuiltinToolCallEvent:
|
|
|
1351
1400
|
part: BuiltinToolCallPart
|
|
1352
1401
|
"""The built-in tool call to make."""
|
|
1353
1402
|
|
|
1403
|
+
_: KW_ONLY
|
|
1404
|
+
|
|
1354
1405
|
event_kind: Literal['builtin_tool_call'] = 'builtin_tool_call'
|
|
1355
1406
|
"""Event type identifier, used as a discriminator."""
|
|
1356
1407
|
|
|
@@ -1362,15 +1413,17 @@ class BuiltinToolResultEvent:
|
|
|
1362
1413
|
result: BuiltinToolReturnPart
|
|
1363
1414
|
"""The result of the call to the built-in tool."""
|
|
1364
1415
|
|
|
1416
|
+
_: KW_ONLY
|
|
1417
|
+
|
|
1365
1418
|
event_kind: Literal['builtin_tool_result'] = 'builtin_tool_result'
|
|
1366
1419
|
"""Event type identifier, used as a discriminator."""
|
|
1367
1420
|
|
|
1368
1421
|
|
|
1369
1422
|
HandleResponseEvent = Annotated[
|
|
1370
|
-
|
|
1423
|
+
FunctionToolCallEvent | FunctionToolResultEvent | BuiltinToolCallEvent | BuiltinToolResultEvent,
|
|
1371
1424
|
pydantic.Discriminator('event_kind'),
|
|
1372
1425
|
]
|
|
1373
1426
|
"""An event yielded when handling a model response, indicating tool calls and results."""
|
|
1374
1427
|
|
|
1375
|
-
AgentStreamEvent = Annotated[
|
|
1428
|
+
AgentStreamEvent = Annotated[ModelResponseStreamEvent | HandleResponseEvent, pydantic.Discriminator('event_kind')]
|
|
1376
1429
|
"""An event in the agent stream: model response stream events and response-handling events."""
|
pydantic_ai/models/__init__.py
CHANGED
|
@@ -7,16 +7,17 @@ specific LLM being used.
|
|
|
7
7
|
from __future__ import annotations as _annotations
|
|
8
8
|
|
|
9
9
|
import base64
|
|
10
|
+
import warnings
|
|
10
11
|
from abc import ABC, abstractmethod
|
|
11
12
|
from collections.abc import AsyncIterator, Iterator
|
|
12
13
|
from contextlib import asynccontextmanager, contextmanager
|
|
13
14
|
from dataclasses import dataclass, field, replace
|
|
14
15
|
from datetime import datetime
|
|
15
16
|
from functools import cache, cached_property
|
|
16
|
-
from typing import Any, Generic, TypeVar, overload
|
|
17
|
+
from typing import Any, Generic, Literal, TypeVar, overload
|
|
17
18
|
|
|
18
19
|
import httpx
|
|
19
|
-
from typing_extensions import
|
|
20
|
+
from typing_extensions import TypeAliasType, TypedDict
|
|
20
21
|
|
|
21
22
|
from .. import _utils
|
|
22
23
|
from .._output import OutputObjectDefinition
|
|
@@ -366,7 +367,7 @@ KnownModelName = TypeAliasType(
|
|
|
366
367
|
"""
|
|
367
368
|
|
|
368
369
|
|
|
369
|
-
@dataclass(repr=False)
|
|
370
|
+
@dataclass(repr=False, kw_only=True)
|
|
370
371
|
class ModelRequestParameters:
|
|
371
372
|
"""Configuration for an agent's request to a model, specifically related to tools and output handling."""
|
|
372
373
|
|
|
@@ -551,6 +552,7 @@ class StreamedResponse(ABC):
|
|
|
551
552
|
"""Streamed response from an LLM when calling a tool."""
|
|
552
553
|
|
|
553
554
|
model_request_parameters: ModelRequestParameters
|
|
555
|
+
|
|
554
556
|
final_result_event: FinalResultEvent | None = field(default=None, init=False)
|
|
555
557
|
|
|
556
558
|
_parts_manager: ModelResponsePartsManager = field(default_factory=ModelResponsePartsManager, init=False)
|
|
@@ -684,19 +686,29 @@ def infer_model(model: Model | KnownModelName | str) -> Model: # noqa: C901
|
|
|
684
686
|
try:
|
|
685
687
|
provider, model_name = model.split(':', maxsplit=1)
|
|
686
688
|
except ValueError:
|
|
689
|
+
provider = None
|
|
687
690
|
model_name = model
|
|
688
|
-
# TODO(Marcelo): We should deprecate this way.
|
|
689
691
|
if model_name.startswith(('gpt', 'o1', 'o3')):
|
|
690
692
|
provider = 'openai'
|
|
691
693
|
elif model_name.startswith('claude'):
|
|
692
694
|
provider = 'anthropic'
|
|
693
695
|
elif model_name.startswith('gemini'):
|
|
694
696
|
provider = 'google-gla'
|
|
697
|
+
|
|
698
|
+
if provider is not None:
|
|
699
|
+
warnings.warn(
|
|
700
|
+
f"Specifying a model name without a provider prefix is deprecated. Instead of {model_name!r}, use '{provider}:{model_name}'.",
|
|
701
|
+
DeprecationWarning,
|
|
702
|
+
)
|
|
695
703
|
else:
|
|
696
704
|
raise UserError(f'Unknown model: {model}')
|
|
697
705
|
|
|
698
|
-
if provider == 'vertexai':
|
|
699
|
-
|
|
706
|
+
if provider == 'vertexai': # pragma: no cover
|
|
707
|
+
warnings.warn(
|
|
708
|
+
"The 'vertexai' provider name is deprecated. Use 'google-vertex' instead.",
|
|
709
|
+
DeprecationWarning,
|
|
710
|
+
)
|
|
711
|
+
provider = 'google-vertex'
|
|
700
712
|
|
|
701
713
|
if provider == 'cohere':
|
|
702
714
|
from .cohere import CohereModel
|
|
@@ -909,5 +921,5 @@ def _get_final_result_event(e: ModelResponseStreamEvent, params: ModelRequestPar
|
|
|
909
921
|
elif isinstance(new_part, ToolCallPart) and (tool_def := params.tool_defs.get(new_part.tool_name)):
|
|
910
922
|
if tool_def.kind == 'output':
|
|
911
923
|
return FinalResultEvent(tool_name=new_part.tool_name, tool_call_id=new_part.tool_call_id)
|
|
912
|
-
elif tool_def.
|
|
924
|
+
elif tool_def.defer:
|
|
913
925
|
return FinalResultEvent(tool_name=None, tool_call_id=None)
|
pydantic_ai/models/anthropic.py
CHANGED
|
@@ -6,7 +6,7 @@ from collections.abc import AsyncGenerator, AsyncIterable, AsyncIterator
|
|
|
6
6
|
from contextlib import asynccontextmanager
|
|
7
7
|
from dataclasses import dataclass, field
|
|
8
8
|
from datetime import datetime, timezone
|
|
9
|
-
from typing import Any, Literal,
|
|
9
|
+
from typing import Any, Literal, cast, overload
|
|
10
10
|
|
|
11
11
|
from typing_extensions import assert_never
|
|
12
12
|
|
|
@@ -99,7 +99,7 @@ except ImportError as _import_error:
|
|
|
99
99
|
LatestAnthropicModelNames = ModelParam
|
|
100
100
|
"""Latest Anthropic models."""
|
|
101
101
|
|
|
102
|
-
AnthropicModelName =
|
|
102
|
+
AnthropicModelName = str | LatestAnthropicModelNames
|
|
103
103
|
"""Possible Anthropic model names.
|
|
104
104
|
|
|
105
105
|
Since Anthropic supports a variety of date-stamped models, we explicitly list the latest models but
|
|
@@ -290,7 +290,7 @@ class AnthropicModel(Model):
|
|
|
290
290
|
for item in response.content:
|
|
291
291
|
if isinstance(item, BetaTextBlock):
|
|
292
292
|
items.append(TextPart(content=item.text))
|
|
293
|
-
elif isinstance(item,
|
|
293
|
+
elif isinstance(item, BetaWebSearchToolResultBlock | BetaCodeExecutionToolResultBlock):
|
|
294
294
|
items.append(
|
|
295
295
|
BuiltinToolReturnPart(
|
|
296
296
|
provider_name='anthropic',
|
|
@@ -327,10 +327,10 @@ class AnthropicModel(Model):
|
|
|
327
327
|
)
|
|
328
328
|
|
|
329
329
|
return ModelResponse(
|
|
330
|
-
items,
|
|
330
|
+
parts=items,
|
|
331
331
|
usage=_map_usage(response),
|
|
332
332
|
model_name=response.model,
|
|
333
|
-
|
|
333
|
+
provider_response_id=response.id,
|
|
334
334
|
provider_name=self._provider.name,
|
|
335
335
|
)
|
|
336
336
|
|
|
@@ -654,7 +654,7 @@ class AnthropicStreamedResponse(StreamedResponse):
|
|
|
654
654
|
elif isinstance(event, BetaRawMessageDeltaEvent):
|
|
655
655
|
pass
|
|
656
656
|
|
|
657
|
-
elif isinstance(event,
|
|
657
|
+
elif isinstance(event, BetaRawContentBlockStopEvent | BetaRawMessageStopEvent): # pragma: no branch
|
|
658
658
|
current_block = None
|
|
659
659
|
|
|
660
660
|
@property
|