pydantic-ai-slim 0.2.6__py3-none-any.whl → 0.2.7__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/_agent_graph.py +18 -5
- pydantic_ai/_output.py +6 -2
- pydantic_ai/_parts_manager.py +5 -5
- pydantic_ai/_pydantic.py +8 -1
- pydantic_ai/_utils.py +9 -1
- pydantic_ai/agent.py +24 -49
- pydantic_ai/direct.py +7 -31
- pydantic_ai/mcp.py +59 -7
- pydantic_ai/messages.py +72 -29
- pydantic_ai/models/anthropic.py +80 -87
- pydantic_ai/models/bedrock.py +2 -2
- pydantic_ai/models/google.py +1 -1
- pydantic_ai/models/mistral.py +1 -1
- pydantic_ai/models/openai.py +0 -1
- pydantic_ai/result.py +5 -3
- pydantic_ai/tools.py +7 -3
- pydantic_ai/usage.py +7 -2
- {pydantic_ai_slim-0.2.6.dist-info → pydantic_ai_slim-0.2.7.dist-info}/METADATA +4 -4
- {pydantic_ai_slim-0.2.6.dist-info → pydantic_ai_slim-0.2.7.dist-info}/RECORD +22 -22
- {pydantic_ai_slim-0.2.6.dist-info → pydantic_ai_slim-0.2.7.dist-info}/WHEEL +0 -0
- {pydantic_ai_slim-0.2.6.dist-info → pydantic_ai_slim-0.2.7.dist-info}/entry_points.txt +0 -0
- {pydantic_ai_slim-0.2.6.dist-info → pydantic_ai_slim-0.2.7.dist-info}/licenses/LICENSE +0 -0
pydantic_ai/messages.py
CHANGED
|
@@ -13,6 +13,7 @@ import pydantic_core
|
|
|
13
13
|
from opentelemetry._events import Event # pyright: ignore[reportPrivateImportUsage]
|
|
14
14
|
from typing_extensions import TypeAlias
|
|
15
15
|
|
|
16
|
+
from . import _utils
|
|
16
17
|
from ._utils import generate_tool_call_id as _generate_tool_call_id, now_utc as _now_utc
|
|
17
18
|
from .exceptions import UnexpectedModelBehavior
|
|
18
19
|
from .usage import Usage
|
|
@@ -50,7 +51,7 @@ DocumentFormat: TypeAlias = Literal['csv', 'doc', 'docx', 'html', 'md', 'pdf', '
|
|
|
50
51
|
VideoFormat: TypeAlias = Literal['mkv', 'mov', 'mp4', 'webm', 'flv', 'mpeg', 'mpg', 'wmv', 'three_gp']
|
|
51
52
|
|
|
52
53
|
|
|
53
|
-
@dataclass
|
|
54
|
+
@dataclass(repr=False)
|
|
54
55
|
class SystemPromptPart:
|
|
55
56
|
"""A system prompt, generally written by the application developer.
|
|
56
57
|
|
|
@@ -75,8 +76,10 @@ class SystemPromptPart:
|
|
|
75
76
|
def otel_event(self, _settings: InstrumentationSettings) -> Event:
|
|
76
77
|
return Event('gen_ai.system.message', body={'content': self.content, 'role': 'system'})
|
|
77
78
|
|
|
79
|
+
__repr__ = _utils.dataclasses_no_defaults_repr
|
|
78
80
|
|
|
79
|
-
|
|
81
|
+
|
|
82
|
+
@dataclass(repr=False)
|
|
80
83
|
class VideoUrl:
|
|
81
84
|
"""A URL to an video."""
|
|
82
85
|
|
|
@@ -116,8 +119,10 @@ class VideoUrl:
|
|
|
116
119
|
"""
|
|
117
120
|
return _video_format_lookup[self.media_type]
|
|
118
121
|
|
|
122
|
+
__repr__ = _utils.dataclasses_no_defaults_repr
|
|
123
|
+
|
|
119
124
|
|
|
120
|
-
@dataclass
|
|
125
|
+
@dataclass(repr=False)
|
|
121
126
|
class AudioUrl:
|
|
122
127
|
"""A URL to an audio file."""
|
|
123
128
|
|
|
@@ -142,8 +147,10 @@ class AudioUrl:
|
|
|
142
147
|
"""The file format of the audio file."""
|
|
143
148
|
return _audio_format_lookup[self.media_type]
|
|
144
149
|
|
|
150
|
+
__repr__ = _utils.dataclasses_no_defaults_repr
|
|
151
|
+
|
|
145
152
|
|
|
146
|
-
@dataclass
|
|
153
|
+
@dataclass(repr=False)
|
|
147
154
|
class ImageUrl:
|
|
148
155
|
"""A URL to an image."""
|
|
149
156
|
|
|
@@ -175,8 +182,10 @@ class ImageUrl:
|
|
|
175
182
|
"""
|
|
176
183
|
return _image_format_lookup[self.media_type]
|
|
177
184
|
|
|
185
|
+
__repr__ = _utils.dataclasses_no_defaults_repr
|
|
178
186
|
|
|
179
|
-
|
|
187
|
+
|
|
188
|
+
@dataclass(repr=False)
|
|
180
189
|
class DocumentUrl:
|
|
181
190
|
"""The URL of the document."""
|
|
182
191
|
|
|
@@ -206,8 +215,10 @@ class DocumentUrl:
|
|
|
206
215
|
except KeyError as e:
|
|
207
216
|
raise ValueError(f'Unknown document media type: {media_type}') from e
|
|
208
217
|
|
|
218
|
+
__repr__ = _utils.dataclasses_no_defaults_repr
|
|
219
|
+
|
|
209
220
|
|
|
210
|
-
@dataclass
|
|
221
|
+
@dataclass(repr=False)
|
|
211
222
|
class BinaryContent:
|
|
212
223
|
"""Binary content, e.g. an audio or image file."""
|
|
213
224
|
|
|
@@ -255,6 +266,8 @@ class BinaryContent:
|
|
|
255
266
|
except KeyError as e:
|
|
256
267
|
raise ValueError(f'Unknown media type: {self.media_type}') from e
|
|
257
268
|
|
|
269
|
+
__repr__ = _utils.dataclasses_no_defaults_repr
|
|
270
|
+
|
|
258
271
|
|
|
259
272
|
UserContent: TypeAlias = 'str | ImageUrl | AudioUrl | DocumentUrl | VideoUrl | BinaryContent'
|
|
260
273
|
|
|
@@ -292,7 +305,7 @@ _video_format_lookup: dict[str, VideoFormat] = {
|
|
|
292
305
|
}
|
|
293
306
|
|
|
294
307
|
|
|
295
|
-
@dataclass
|
|
308
|
+
@dataclass(repr=False)
|
|
296
309
|
class UserPromptPart:
|
|
297
310
|
"""A user prompt, generally written by the end user.
|
|
298
311
|
|
|
@@ -329,11 +342,13 @@ class UserPromptPart:
|
|
|
329
342
|
content.append({'kind': part.kind}) # pragma: no cover
|
|
330
343
|
return Event('gen_ai.user.message', body={'content': content, 'role': 'user'})
|
|
331
344
|
|
|
345
|
+
__repr__ = _utils.dataclasses_no_defaults_repr
|
|
346
|
+
|
|
332
347
|
|
|
333
348
|
tool_return_ta: pydantic.TypeAdapter[Any] = pydantic.TypeAdapter(Any, config=pydantic.ConfigDict(defer_build=True))
|
|
334
349
|
|
|
335
350
|
|
|
336
|
-
@dataclass
|
|
351
|
+
@dataclass(repr=False)
|
|
337
352
|
class ToolReturnPart:
|
|
338
353
|
"""A tool return message, this encodes the result of running a tool."""
|
|
339
354
|
|
|
@@ -373,11 +388,13 @@ class ToolReturnPart:
|
|
|
373
388
|
body={'content': self.content, 'role': 'tool', 'id': self.tool_call_id, 'name': self.tool_name},
|
|
374
389
|
)
|
|
375
390
|
|
|
391
|
+
__repr__ = _utils.dataclasses_no_defaults_repr
|
|
392
|
+
|
|
376
393
|
|
|
377
394
|
error_details_ta = pydantic.TypeAdapter(list[pydantic_core.ErrorDetails], config=pydantic.ConfigDict(defer_build=True))
|
|
378
395
|
|
|
379
396
|
|
|
380
|
-
@dataclass
|
|
397
|
+
@dataclass(repr=False)
|
|
381
398
|
class RetryPromptPart:
|
|
382
399
|
"""A message back to a model asking it to try again.
|
|
383
400
|
|
|
@@ -438,6 +455,8 @@ class RetryPromptPart:
|
|
|
438
455
|
},
|
|
439
456
|
)
|
|
440
457
|
|
|
458
|
+
__repr__ = _utils.dataclasses_no_defaults_repr
|
|
459
|
+
|
|
441
460
|
|
|
442
461
|
ModelRequestPart = Annotated[
|
|
443
462
|
Union[SystemPromptPart, UserPromptPart, ToolReturnPart, RetryPromptPart], pydantic.Discriminator('part_kind')
|
|
@@ -445,7 +464,7 @@ ModelRequestPart = Annotated[
|
|
|
445
464
|
"""A message part sent by PydanticAI to a model."""
|
|
446
465
|
|
|
447
466
|
|
|
448
|
-
@dataclass
|
|
467
|
+
@dataclass(repr=False)
|
|
449
468
|
class ModelRequest:
|
|
450
469
|
"""A request generated by PydanticAI and sent to a model, e.g. a message from the PydanticAI app to the model."""
|
|
451
470
|
|
|
@@ -463,8 +482,10 @@ class ModelRequest:
|
|
|
463
482
|
"""Create a `ModelRequest` with a single user prompt as text."""
|
|
464
483
|
return cls(parts=[UserPromptPart(user_prompt)], instructions=instructions)
|
|
465
484
|
|
|
485
|
+
__repr__ = _utils.dataclasses_no_defaults_repr
|
|
466
486
|
|
|
467
|
-
|
|
487
|
+
|
|
488
|
+
@dataclass(repr=False)
|
|
468
489
|
class TextPart:
|
|
469
490
|
"""A plain text response from a model."""
|
|
470
491
|
|
|
@@ -478,15 +499,17 @@ class TextPart:
|
|
|
478
499
|
"""Return `True` if the text content is non-empty."""
|
|
479
500
|
return bool(self.content)
|
|
480
501
|
|
|
502
|
+
__repr__ = _utils.dataclasses_no_defaults_repr
|
|
503
|
+
|
|
481
504
|
|
|
482
|
-
@dataclass
|
|
505
|
+
@dataclass(repr=False)
|
|
483
506
|
class ToolCallPart:
|
|
484
507
|
"""A tool call from a model."""
|
|
485
508
|
|
|
486
509
|
tool_name: str
|
|
487
510
|
"""The name of the tool to call."""
|
|
488
511
|
|
|
489
|
-
args: str | dict[str, Any]
|
|
512
|
+
args: str | dict[str, Any] | None = None
|
|
490
513
|
"""The arguments to pass to the tool.
|
|
491
514
|
|
|
492
515
|
This is stored either as a JSON string or a Python dictionary depending on how data was received.
|
|
@@ -506,10 +529,10 @@ class ToolCallPart:
|
|
|
506
529
|
|
|
507
530
|
This is just for convenience with models that require dicts as input.
|
|
508
531
|
"""
|
|
532
|
+
if not self.args:
|
|
533
|
+
return {}
|
|
509
534
|
if isinstance(self.args, dict):
|
|
510
535
|
return self.args
|
|
511
|
-
if isinstance(self.args, str) and not self.args:
|
|
512
|
-
return {}
|
|
513
536
|
args = pydantic_core.from_json(self.args)
|
|
514
537
|
assert isinstance(args, dict), 'args should be a dict'
|
|
515
538
|
return cast(dict[str, Any], args)
|
|
@@ -519,6 +542,8 @@ class ToolCallPart:
|
|
|
519
542
|
|
|
520
543
|
This is just for convenience with models that require JSON strings as input.
|
|
521
544
|
"""
|
|
545
|
+
if not self.args:
|
|
546
|
+
return '{}'
|
|
522
547
|
if isinstance(self.args, str):
|
|
523
548
|
return self.args
|
|
524
549
|
return pydantic_core.to_json(self.args).decode()
|
|
@@ -532,12 +557,14 @@ class ToolCallPart:
|
|
|
532
557
|
else:
|
|
533
558
|
return bool(self.args)
|
|
534
559
|
|
|
560
|
+
__repr__ = _utils.dataclasses_no_defaults_repr
|
|
561
|
+
|
|
535
562
|
|
|
536
563
|
ModelResponsePart = Annotated[Union[TextPart, ToolCallPart], pydantic.Discriminator('part_kind')]
|
|
537
564
|
"""A message part returned by a model."""
|
|
538
565
|
|
|
539
566
|
|
|
540
|
-
@dataclass
|
|
567
|
+
@dataclass(repr=False)
|
|
541
568
|
class ModelResponse:
|
|
542
569
|
"""A response from a model, e.g. a message from the model to the PydanticAI app."""
|
|
543
570
|
|
|
@@ -602,6 +629,8 @@ class ModelResponse:
|
|
|
602
629
|
|
|
603
630
|
return result
|
|
604
631
|
|
|
632
|
+
__repr__ = _utils.dataclasses_no_defaults_repr
|
|
633
|
+
|
|
605
634
|
|
|
606
635
|
ModelMessage = Annotated[Union[ModelRequest, ModelResponse], pydantic.Discriminator('kind')]
|
|
607
636
|
"""Any message sent to or returned by a model."""
|
|
@@ -612,7 +641,7 @@ ModelMessagesTypeAdapter = pydantic.TypeAdapter(
|
|
|
612
641
|
"""Pydantic [`TypeAdapter`][pydantic.type_adapter.TypeAdapter] for (de)serializing messages."""
|
|
613
642
|
|
|
614
643
|
|
|
615
|
-
@dataclass
|
|
644
|
+
@dataclass(repr=False)
|
|
616
645
|
class TextPartDelta:
|
|
617
646
|
"""A partial update (delta) for a `TextPart` to append new text content."""
|
|
618
647
|
|
|
@@ -638,8 +667,10 @@ class TextPartDelta:
|
|
|
638
667
|
raise ValueError('Cannot apply TextPartDeltas to non-TextParts') # pragma: no cover
|
|
639
668
|
return replace(part, content=part.content + self.content_delta)
|
|
640
669
|
|
|
670
|
+
__repr__ = _utils.dataclasses_no_defaults_repr
|
|
671
|
+
|
|
641
672
|
|
|
642
|
-
@dataclass
|
|
673
|
+
@dataclass(repr=False)
|
|
643
674
|
class ToolCallPartDelta:
|
|
644
675
|
"""A partial update (delta) for a `ToolCallPart` to modify tool name, arguments, or tool call ID."""
|
|
645
676
|
|
|
@@ -666,9 +697,9 @@ class ToolCallPartDelta:
|
|
|
666
697
|
"""Convert this delta to a fully formed `ToolCallPart` if possible, otherwise return `None`.
|
|
667
698
|
|
|
668
699
|
Returns:
|
|
669
|
-
A `ToolCallPart` if
|
|
700
|
+
A `ToolCallPart` if `tool_name_delta` is set, otherwise `None`.
|
|
670
701
|
"""
|
|
671
|
-
if self.tool_name_delta is None
|
|
702
|
+
if self.tool_name_delta is None:
|
|
672
703
|
return None
|
|
673
704
|
|
|
674
705
|
return ToolCallPart(self.tool_name_delta, self.args_delta, self.tool_call_id or _generate_tool_call_id())
|
|
@@ -728,7 +759,7 @@ class ToolCallPartDelta:
|
|
|
728
759
|
delta = replace(delta, tool_call_id=self.tool_call_id)
|
|
729
760
|
|
|
730
761
|
# If we now have enough data to create a full ToolCallPart, do so
|
|
731
|
-
if delta.tool_name_delta is not None
|
|
762
|
+
if delta.tool_name_delta is not None:
|
|
732
763
|
return ToolCallPart(delta.tool_name_delta, delta.args_delta, delta.tool_call_id or _generate_tool_call_id())
|
|
733
764
|
|
|
734
765
|
return delta
|
|
@@ -741,12 +772,12 @@ class ToolCallPartDelta:
|
|
|
741
772
|
part = replace(part, tool_name=tool_name)
|
|
742
773
|
|
|
743
774
|
if isinstance(self.args_delta, str):
|
|
744
|
-
if
|
|
775
|
+
if isinstance(part.args, dict):
|
|
745
776
|
raise UnexpectedModelBehavior(f'Cannot apply JSON deltas to non-JSON tool arguments ({part=}, {self=})')
|
|
746
|
-
updated_json = part.args + self.args_delta
|
|
777
|
+
updated_json = (part.args or '') + self.args_delta
|
|
747
778
|
part = replace(part, args=updated_json)
|
|
748
779
|
elif isinstance(self.args_delta, dict):
|
|
749
|
-
if
|
|
780
|
+
if isinstance(part.args, str):
|
|
750
781
|
raise UnexpectedModelBehavior(f'Cannot apply dict deltas to non-dict tool arguments ({part=}, {self=})')
|
|
751
782
|
updated_dict = {**(part.args or {}), **self.args_delta}
|
|
752
783
|
part = replace(part, args=updated_dict)
|
|
@@ -755,12 +786,14 @@ class ToolCallPartDelta:
|
|
|
755
786
|
part = replace(part, tool_call_id=self.tool_call_id)
|
|
756
787
|
return part
|
|
757
788
|
|
|
789
|
+
__repr__ = _utils.dataclasses_no_defaults_repr
|
|
790
|
+
|
|
758
791
|
|
|
759
792
|
ModelResponsePartDelta = Annotated[Union[TextPartDelta, ToolCallPartDelta], pydantic.Discriminator('part_delta_kind')]
|
|
760
793
|
"""A partial update (delta) for any model response part."""
|
|
761
794
|
|
|
762
795
|
|
|
763
|
-
@dataclass
|
|
796
|
+
@dataclass(repr=False)
|
|
764
797
|
class PartStartEvent:
|
|
765
798
|
"""An event indicating that a new part has started.
|
|
766
799
|
|
|
@@ -777,8 +810,10 @@ class PartStartEvent:
|
|
|
777
810
|
event_kind: Literal['part_start'] = 'part_start'
|
|
778
811
|
"""Event type identifier, used as a discriminator."""
|
|
779
812
|
|
|
813
|
+
__repr__ = _utils.dataclasses_no_defaults_repr
|
|
780
814
|
|
|
781
|
-
|
|
815
|
+
|
|
816
|
+
@dataclass(repr=False)
|
|
782
817
|
class PartDeltaEvent:
|
|
783
818
|
"""An event indicating a delta update for an existing part."""
|
|
784
819
|
|
|
@@ -791,8 +826,10 @@ class PartDeltaEvent:
|
|
|
791
826
|
event_kind: Literal['part_delta'] = 'part_delta'
|
|
792
827
|
"""Event type identifier, used as a discriminator."""
|
|
793
828
|
|
|
829
|
+
__repr__ = _utils.dataclasses_no_defaults_repr
|
|
830
|
+
|
|
794
831
|
|
|
795
|
-
@dataclass
|
|
832
|
+
@dataclass(repr=False)
|
|
796
833
|
class FinalResultEvent:
|
|
797
834
|
"""An event indicating the response to the current model request matches the output schema and will produce a result."""
|
|
798
835
|
|
|
@@ -803,6 +840,8 @@ class FinalResultEvent:
|
|
|
803
840
|
event_kind: Literal['final_result'] = 'final_result'
|
|
804
841
|
"""Event type identifier, used as a discriminator."""
|
|
805
842
|
|
|
843
|
+
__repr__ = _utils.dataclasses_no_defaults_repr
|
|
844
|
+
|
|
806
845
|
|
|
807
846
|
ModelResponseStreamEvent = Annotated[Union[PartStartEvent, PartDeltaEvent], pydantic.Discriminator('event_kind')]
|
|
808
847
|
"""An event in the model response stream, either starting a new part or applying a delta to an existing one."""
|
|
@@ -813,7 +852,7 @@ AgentStreamEvent = Annotated[
|
|
|
813
852
|
"""An event in the agent stream."""
|
|
814
853
|
|
|
815
854
|
|
|
816
|
-
@dataclass
|
|
855
|
+
@dataclass(repr=False)
|
|
817
856
|
class FunctionToolCallEvent:
|
|
818
857
|
"""An event indicating the start to a call to a function tool."""
|
|
819
858
|
|
|
@@ -827,8 +866,10 @@ class FunctionToolCallEvent:
|
|
|
827
866
|
def __post_init__(self):
|
|
828
867
|
self.call_id = self.part.tool_call_id or str(uuid.uuid4())
|
|
829
868
|
|
|
869
|
+
__repr__ = _utils.dataclasses_no_defaults_repr
|
|
830
870
|
|
|
831
|
-
|
|
871
|
+
|
|
872
|
+
@dataclass(repr=False)
|
|
832
873
|
class FunctionToolResultEvent:
|
|
833
874
|
"""An event indicating the result of a function tool call."""
|
|
834
875
|
|
|
@@ -839,6 +880,8 @@ class FunctionToolResultEvent:
|
|
|
839
880
|
event_kind: Literal['function_tool_result'] = 'function_tool_result'
|
|
840
881
|
"""Event type identifier, used as a discriminator."""
|
|
841
882
|
|
|
883
|
+
__repr__ = _utils.dataclasses_no_defaults_repr
|
|
884
|
+
|
|
842
885
|
|
|
843
886
|
HandleResponseEvent = Annotated[
|
|
844
887
|
Union[FunctionToolCallEvent, FunctionToolResultEvent], pydantic.Discriminator('event_kind')
|