pydantic-ai-slim 1.0.15__py3-none-any.whl → 1.0.17__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.
@@ -25,6 +25,7 @@ from pydantic_ai import (
25
25
  )
26
26
  from pydantic_ai.agent import AbstractAgent, AgentRun, AgentRunResult, EventStreamHandler, WrapperAgent
27
27
  from pydantic_ai.agent.abstract import Instructions, RunOutputDataT
28
+ from pydantic_ai.builtin_tools import AbstractBuiltinTool
28
29
  from pydantic_ai.exceptions import UserError
29
30
  from pydantic_ai.models import Model
30
31
  from pydantic_ai.output import OutputDataT, OutputSpec
@@ -259,7 +260,7 @@ class TemporalAgent(WrapperAgent[AgentDepsT, OutputDataT]):
259
260
  user_prompt: str | Sequence[_messages.UserContent] | None = None,
260
261
  *,
261
262
  output_type: None = None,
262
- message_history: list[_messages.ModelMessage] | None = None,
263
+ message_history: Sequence[_messages.ModelMessage] | None = None,
263
264
  deferred_tool_results: DeferredToolResults | None = None,
264
265
  model: models.Model | models.KnownModelName | str | None = None,
265
266
  deps: AgentDepsT = None,
@@ -268,6 +269,7 @@ class TemporalAgent(WrapperAgent[AgentDepsT, OutputDataT]):
268
269
  usage: _usage.RunUsage | None = None,
269
270
  infer_name: bool = True,
270
271
  toolsets: Sequence[AbstractToolset[AgentDepsT]] | None = None,
272
+ builtin_tools: Sequence[AbstractBuiltinTool] | None = None,
271
273
  event_stream_handler: EventStreamHandler[AgentDepsT] | None = None,
272
274
  ) -> AgentRunResult[OutputDataT]: ...
273
275
 
@@ -277,7 +279,7 @@ class TemporalAgent(WrapperAgent[AgentDepsT, OutputDataT]):
277
279
  user_prompt: str | Sequence[_messages.UserContent] | None = None,
278
280
  *,
279
281
  output_type: OutputSpec[RunOutputDataT],
280
- message_history: list[_messages.ModelMessage] | None = None,
282
+ message_history: Sequence[_messages.ModelMessage] | None = None,
281
283
  deferred_tool_results: DeferredToolResults | None = None,
282
284
  model: models.Model | models.KnownModelName | str | None = None,
283
285
  deps: AgentDepsT = None,
@@ -286,6 +288,7 @@ class TemporalAgent(WrapperAgent[AgentDepsT, OutputDataT]):
286
288
  usage: _usage.RunUsage | None = None,
287
289
  infer_name: bool = True,
288
290
  toolsets: Sequence[AbstractToolset[AgentDepsT]] | None = None,
291
+ builtin_tools: Sequence[AbstractBuiltinTool] | None = None,
289
292
  event_stream_handler: EventStreamHandler[AgentDepsT] | None = None,
290
293
  ) -> AgentRunResult[RunOutputDataT]: ...
291
294
 
@@ -294,7 +297,7 @@ class TemporalAgent(WrapperAgent[AgentDepsT, OutputDataT]):
294
297
  user_prompt: str | Sequence[_messages.UserContent] | None = None,
295
298
  *,
296
299
  output_type: OutputSpec[RunOutputDataT] | None = None,
297
- message_history: list[_messages.ModelMessage] | None = None,
300
+ message_history: Sequence[_messages.ModelMessage] | None = None,
298
301
  deferred_tool_results: DeferredToolResults | None = None,
299
302
  model: models.Model | models.KnownModelName | str | None = None,
300
303
  deps: AgentDepsT = None,
@@ -303,6 +306,7 @@ class TemporalAgent(WrapperAgent[AgentDepsT, OutputDataT]):
303
306
  usage: _usage.RunUsage | None = None,
304
307
  infer_name: bool = True,
305
308
  toolsets: Sequence[AbstractToolset[AgentDepsT]] | None = None,
309
+ builtin_tools: Sequence[AbstractBuiltinTool] | None = None,
306
310
  event_stream_handler: EventStreamHandler[AgentDepsT] | None = None,
307
311
  **_deprecated_kwargs: Never,
308
312
  ) -> AgentRunResult[Any]:
@@ -337,6 +341,7 @@ class TemporalAgent(WrapperAgent[AgentDepsT, OutputDataT]):
337
341
  infer_name: Whether to try to infer the agent name from the call frame if it's not set.
338
342
  toolsets: Optional additional toolsets for this run.
339
343
  event_stream_handler: Optional event stream handler to use for this run.
344
+ builtin_tools: Optional additional builtin tools for this run.
340
345
 
341
346
  Returns:
342
347
  The result of the run.
@@ -359,6 +364,7 @@ class TemporalAgent(WrapperAgent[AgentDepsT, OutputDataT]):
359
364
  usage=usage,
360
365
  infer_name=infer_name,
361
366
  toolsets=toolsets,
367
+ builtin_tools=builtin_tools,
362
368
  event_stream_handler=event_stream_handler or self.event_stream_handler,
363
369
  **_deprecated_kwargs,
364
370
  )
@@ -369,7 +375,7 @@ class TemporalAgent(WrapperAgent[AgentDepsT, OutputDataT]):
369
375
  user_prompt: str | Sequence[_messages.UserContent] | None = None,
370
376
  *,
371
377
  output_type: None = None,
372
- message_history: list[_messages.ModelMessage] | None = None,
378
+ message_history: Sequence[_messages.ModelMessage] | None = None,
373
379
  deferred_tool_results: DeferredToolResults | None = None,
374
380
  model: models.Model | models.KnownModelName | str | None = None,
375
381
  deps: AgentDepsT = None,
@@ -378,6 +384,7 @@ class TemporalAgent(WrapperAgent[AgentDepsT, OutputDataT]):
378
384
  usage: _usage.RunUsage | None = None,
379
385
  infer_name: bool = True,
380
386
  toolsets: Sequence[AbstractToolset[AgentDepsT]] | None = None,
387
+ builtin_tools: Sequence[AbstractBuiltinTool] | None = None,
381
388
  event_stream_handler: EventStreamHandler[AgentDepsT] | None = None,
382
389
  ) -> AgentRunResult[OutputDataT]: ...
383
390
 
@@ -387,7 +394,7 @@ class TemporalAgent(WrapperAgent[AgentDepsT, OutputDataT]):
387
394
  user_prompt: str | Sequence[_messages.UserContent] | None = None,
388
395
  *,
389
396
  output_type: OutputSpec[RunOutputDataT],
390
- message_history: list[_messages.ModelMessage] | None = None,
397
+ message_history: Sequence[_messages.ModelMessage] | None = None,
391
398
  deferred_tool_results: DeferredToolResults | None = None,
392
399
  model: models.Model | models.KnownModelName | str | None = None,
393
400
  deps: AgentDepsT = None,
@@ -396,6 +403,7 @@ class TemporalAgent(WrapperAgent[AgentDepsT, OutputDataT]):
396
403
  usage: _usage.RunUsage | None = None,
397
404
  infer_name: bool = True,
398
405
  toolsets: Sequence[AbstractToolset[AgentDepsT]] | None = None,
406
+ builtin_tools: Sequence[AbstractBuiltinTool] | None = None,
399
407
  event_stream_handler: EventStreamHandler[AgentDepsT] | None = None,
400
408
  ) -> AgentRunResult[RunOutputDataT]: ...
401
409
 
@@ -404,7 +412,7 @@ class TemporalAgent(WrapperAgent[AgentDepsT, OutputDataT]):
404
412
  user_prompt: str | Sequence[_messages.UserContent] | None = None,
405
413
  *,
406
414
  output_type: OutputSpec[RunOutputDataT] | None = None,
407
- message_history: list[_messages.ModelMessage] | None = None,
415
+ message_history: Sequence[_messages.ModelMessage] | None = None,
408
416
  deferred_tool_results: DeferredToolResults | None = None,
409
417
  model: models.Model | models.KnownModelName | str | None = None,
410
418
  deps: AgentDepsT = None,
@@ -413,6 +421,7 @@ class TemporalAgent(WrapperAgent[AgentDepsT, OutputDataT]):
413
421
  usage: _usage.RunUsage | None = None,
414
422
  infer_name: bool = True,
415
423
  toolsets: Sequence[AbstractToolset[AgentDepsT]] | None = None,
424
+ builtin_tools: Sequence[AbstractBuiltinTool] | None = None,
416
425
  event_stream_handler: EventStreamHandler[AgentDepsT] | None = None,
417
426
  **_deprecated_kwargs: Never,
418
427
  ) -> AgentRunResult[Any]:
@@ -446,6 +455,7 @@ class TemporalAgent(WrapperAgent[AgentDepsT, OutputDataT]):
446
455
  infer_name: Whether to try to infer the agent name from the call frame if it's not set.
447
456
  toolsets: Optional additional toolsets for this run.
448
457
  event_stream_handler: Optional event stream handler to use for this run.
458
+ builtin_tools: Optional additional builtin tools for this run.
449
459
 
450
460
  Returns:
451
461
  The result of the run.
@@ -467,6 +477,7 @@ class TemporalAgent(WrapperAgent[AgentDepsT, OutputDataT]):
467
477
  usage=usage,
468
478
  infer_name=infer_name,
469
479
  toolsets=toolsets,
480
+ builtin_tools=builtin_tools,
470
481
  event_stream_handler=event_stream_handler,
471
482
  **_deprecated_kwargs,
472
483
  )
@@ -477,7 +488,7 @@ class TemporalAgent(WrapperAgent[AgentDepsT, OutputDataT]):
477
488
  user_prompt: str | Sequence[_messages.UserContent] | None = None,
478
489
  *,
479
490
  output_type: None = None,
480
- message_history: list[_messages.ModelMessage] | None = None,
491
+ message_history: Sequence[_messages.ModelMessage] | None = None,
481
492
  deferred_tool_results: DeferredToolResults | None = None,
482
493
  model: models.Model | models.KnownModelName | str | None = None,
483
494
  deps: AgentDepsT = None,
@@ -486,6 +497,7 @@ class TemporalAgent(WrapperAgent[AgentDepsT, OutputDataT]):
486
497
  usage: _usage.RunUsage | None = None,
487
498
  infer_name: bool = True,
488
499
  toolsets: Sequence[AbstractToolset[AgentDepsT]] | None = None,
500
+ builtin_tools: Sequence[AbstractBuiltinTool] | None = None,
489
501
  event_stream_handler: EventStreamHandler[AgentDepsT] | None = None,
490
502
  ) -> AbstractAsyncContextManager[StreamedRunResult[AgentDepsT, OutputDataT]]: ...
491
503
 
@@ -495,7 +507,7 @@ class TemporalAgent(WrapperAgent[AgentDepsT, OutputDataT]):
495
507
  user_prompt: str | Sequence[_messages.UserContent] | None = None,
496
508
  *,
497
509
  output_type: OutputSpec[RunOutputDataT],
498
- message_history: list[_messages.ModelMessage] | None = None,
510
+ message_history: Sequence[_messages.ModelMessage] | None = None,
499
511
  deferred_tool_results: DeferredToolResults | None = None,
500
512
  model: models.Model | models.KnownModelName | str | None = None,
501
513
  deps: AgentDepsT = None,
@@ -504,6 +516,7 @@ class TemporalAgent(WrapperAgent[AgentDepsT, OutputDataT]):
504
516
  usage: _usage.RunUsage | None = None,
505
517
  infer_name: bool = True,
506
518
  toolsets: Sequence[AbstractToolset[AgentDepsT]] | None = None,
519
+ builtin_tools: Sequence[AbstractBuiltinTool] | None = None,
507
520
  event_stream_handler: EventStreamHandler[AgentDepsT] | None = None,
508
521
  ) -> AbstractAsyncContextManager[StreamedRunResult[AgentDepsT, RunOutputDataT]]: ...
509
522
 
@@ -513,7 +526,7 @@ class TemporalAgent(WrapperAgent[AgentDepsT, OutputDataT]):
513
526
  user_prompt: str | Sequence[_messages.UserContent] | None = None,
514
527
  *,
515
528
  output_type: OutputSpec[RunOutputDataT] | None = None,
516
- message_history: list[_messages.ModelMessage] | None = None,
529
+ message_history: Sequence[_messages.ModelMessage] | None = None,
517
530
  deferred_tool_results: DeferredToolResults | None = None,
518
531
  model: models.Model | models.KnownModelName | str | None = None,
519
532
  deps: AgentDepsT = None,
@@ -522,6 +535,7 @@ class TemporalAgent(WrapperAgent[AgentDepsT, OutputDataT]):
522
535
  usage: _usage.RunUsage | None = None,
523
536
  infer_name: bool = True,
524
537
  toolsets: Sequence[AbstractToolset[AgentDepsT]] | None = None,
538
+ builtin_tools: Sequence[AbstractBuiltinTool] | None = None,
525
539
  event_stream_handler: EventStreamHandler[AgentDepsT] | None = None,
526
540
  **_deprecated_kwargs: Never,
527
541
  ) -> AsyncIterator[StreamedRunResult[AgentDepsT, Any]]:
@@ -552,6 +566,7 @@ class TemporalAgent(WrapperAgent[AgentDepsT, OutputDataT]):
552
566
  usage: Optional usage to start with, useful for resuming a conversation or agents used in tools.
553
567
  infer_name: Whether to try to infer the agent name from the call frame if it's not set.
554
568
  toolsets: Optional additional toolsets for this run.
569
+ builtin_tools: Optional additional builtin tools for this run.
555
570
  event_stream_handler: Optional event stream handler to use for this run. It will receive all the events up until the final result is found, which you can then read or stream from inside the context manager.
556
571
 
557
572
  Returns:
@@ -576,6 +591,7 @@ class TemporalAgent(WrapperAgent[AgentDepsT, OutputDataT]):
576
591
  infer_name=infer_name,
577
592
  toolsets=toolsets,
578
593
  event_stream_handler=event_stream_handler,
594
+ builtin_tools=builtin_tools,
579
595
  **_deprecated_kwargs,
580
596
  ) as result:
581
597
  yield result
@@ -586,7 +602,7 @@ class TemporalAgent(WrapperAgent[AgentDepsT, OutputDataT]):
586
602
  user_prompt: str | Sequence[_messages.UserContent] | None = None,
587
603
  *,
588
604
  output_type: None = None,
589
- message_history: list[_messages.ModelMessage] | None = None,
605
+ message_history: Sequence[_messages.ModelMessage] | None = None,
590
606
  deferred_tool_results: DeferredToolResults | None = None,
591
607
  model: models.Model | models.KnownModelName | str | None = None,
592
608
  deps: AgentDepsT = None,
@@ -595,6 +611,7 @@ class TemporalAgent(WrapperAgent[AgentDepsT, OutputDataT]):
595
611
  usage: _usage.RunUsage | None = None,
596
612
  infer_name: bool = True,
597
613
  toolsets: Sequence[AbstractToolset[AgentDepsT]] | None = None,
614
+ builtin_tools: Sequence[AbstractBuiltinTool] | None = None,
598
615
  ) -> AsyncIterator[_messages.AgentStreamEvent | AgentRunResultEvent[OutputDataT]]: ...
599
616
 
600
617
  @overload
@@ -603,7 +620,7 @@ class TemporalAgent(WrapperAgent[AgentDepsT, OutputDataT]):
603
620
  user_prompt: str | Sequence[_messages.UserContent] | None = None,
604
621
  *,
605
622
  output_type: OutputSpec[RunOutputDataT],
606
- message_history: list[_messages.ModelMessage] | None = None,
623
+ message_history: Sequence[_messages.ModelMessage] | None = None,
607
624
  deferred_tool_results: DeferredToolResults | None = None,
608
625
  model: models.Model | models.KnownModelName | str | None = None,
609
626
  deps: AgentDepsT = None,
@@ -612,6 +629,7 @@ class TemporalAgent(WrapperAgent[AgentDepsT, OutputDataT]):
612
629
  usage: _usage.RunUsage | None = None,
613
630
  infer_name: bool = True,
614
631
  toolsets: Sequence[AbstractToolset[AgentDepsT]] | None = None,
632
+ builtin_tools: Sequence[AbstractBuiltinTool] | None = None,
615
633
  ) -> AsyncIterator[_messages.AgentStreamEvent | AgentRunResultEvent[RunOutputDataT]]: ...
616
634
 
617
635
  def run_stream_events(
@@ -619,7 +637,7 @@ class TemporalAgent(WrapperAgent[AgentDepsT, OutputDataT]):
619
637
  user_prompt: str | Sequence[_messages.UserContent] | None = None,
620
638
  *,
621
639
  output_type: OutputSpec[RunOutputDataT] | None = None,
622
- message_history: list[_messages.ModelMessage] | None = None,
640
+ message_history: Sequence[_messages.ModelMessage] | None = None,
623
641
  deferred_tool_results: DeferredToolResults | None = None,
624
642
  model: models.Model | models.KnownModelName | str | None = None,
625
643
  deps: AgentDepsT = None,
@@ -628,6 +646,7 @@ class TemporalAgent(WrapperAgent[AgentDepsT, OutputDataT]):
628
646
  usage: _usage.RunUsage | None = None,
629
647
  infer_name: bool = True,
630
648
  toolsets: Sequence[AbstractToolset[AgentDepsT]] | None = None,
649
+ builtin_tools: Sequence[AbstractBuiltinTool] | None = None,
631
650
  ) -> AsyncIterator[_messages.AgentStreamEvent | AgentRunResultEvent[Any]]:
632
651
  """Run the agent with a user prompt in async mode and stream events from the run.
633
652
 
@@ -673,6 +692,7 @@ class TemporalAgent(WrapperAgent[AgentDepsT, OutputDataT]):
673
692
  usage: Optional usage to start with, useful for resuming a conversation or agents used in tools.
674
693
  infer_name: Whether to try to infer the agent name from the call frame if it's not set.
675
694
  toolsets: Optional additional toolsets for this run.
695
+ builtin_tools: Optional additional builtin tools for this run.
676
696
 
677
697
  Returns:
678
698
  An async iterable of stream events `AgentStreamEvent` and finally a `AgentRunResultEvent` with the final
@@ -696,6 +716,7 @@ class TemporalAgent(WrapperAgent[AgentDepsT, OutputDataT]):
696
716
  usage=usage,
697
717
  infer_name=infer_name,
698
718
  toolsets=toolsets,
719
+ builtin_tools=builtin_tools,
699
720
  )
700
721
 
701
722
  @overload
@@ -704,7 +725,7 @@ class TemporalAgent(WrapperAgent[AgentDepsT, OutputDataT]):
704
725
  user_prompt: str | Sequence[_messages.UserContent] | None = None,
705
726
  *,
706
727
  output_type: None = None,
707
- message_history: list[_messages.ModelMessage] | None = None,
728
+ message_history: Sequence[_messages.ModelMessage] | None = None,
708
729
  deferred_tool_results: DeferredToolResults | None = None,
709
730
  model: models.Model | models.KnownModelName | str | None = None,
710
731
  deps: AgentDepsT = None,
@@ -712,6 +733,7 @@ class TemporalAgent(WrapperAgent[AgentDepsT, OutputDataT]):
712
733
  usage_limits: _usage.UsageLimits | None = None,
713
734
  usage: _usage.RunUsage | None = None,
714
735
  infer_name: bool = True,
736
+ builtin_tools: Sequence[AbstractBuiltinTool] | None = None,
715
737
  toolsets: Sequence[AbstractToolset[AgentDepsT]] | None = None,
716
738
  **_deprecated_kwargs: Never,
717
739
  ) -> AbstractAsyncContextManager[AgentRun[AgentDepsT, OutputDataT]]: ...
@@ -722,7 +744,7 @@ class TemporalAgent(WrapperAgent[AgentDepsT, OutputDataT]):
722
744
  user_prompt: str | Sequence[_messages.UserContent] | None = None,
723
745
  *,
724
746
  output_type: OutputSpec[RunOutputDataT],
725
- message_history: list[_messages.ModelMessage] | None = None,
747
+ message_history: Sequence[_messages.ModelMessage] | None = None,
726
748
  deferred_tool_results: DeferredToolResults | None = None,
727
749
  model: models.Model | models.KnownModelName | str | None = None,
728
750
  deps: AgentDepsT = None,
@@ -731,6 +753,7 @@ class TemporalAgent(WrapperAgent[AgentDepsT, OutputDataT]):
731
753
  usage: _usage.RunUsage | None = None,
732
754
  infer_name: bool = True,
733
755
  toolsets: Sequence[AbstractToolset[AgentDepsT]] | None = None,
756
+ builtin_tools: Sequence[AbstractBuiltinTool] | None = None,
734
757
  **_deprecated_kwargs: Never,
735
758
  ) -> AbstractAsyncContextManager[AgentRun[AgentDepsT, RunOutputDataT]]: ...
736
759
 
@@ -740,7 +763,7 @@ class TemporalAgent(WrapperAgent[AgentDepsT, OutputDataT]):
740
763
  user_prompt: str | Sequence[_messages.UserContent] | None = None,
741
764
  *,
742
765
  output_type: OutputSpec[RunOutputDataT] | None = None,
743
- message_history: list[_messages.ModelMessage] | None = None,
766
+ message_history: Sequence[_messages.ModelMessage] | None = None,
744
767
  deferred_tool_results: DeferredToolResults | None = None,
745
768
  model: models.Model | models.KnownModelName | str | None = None,
746
769
  deps: AgentDepsT = None,
@@ -749,6 +772,7 @@ class TemporalAgent(WrapperAgent[AgentDepsT, OutputDataT]):
749
772
  usage: _usage.RunUsage | None = None,
750
773
  infer_name: bool = True,
751
774
  toolsets: Sequence[AbstractToolset[AgentDepsT]] | None = None,
775
+ builtin_tools: Sequence[AbstractBuiltinTool] | None = None,
752
776
  **_deprecated_kwargs: Never,
753
777
  ) -> AsyncIterator[AgentRun[AgentDepsT, Any]]:
754
778
  """A contextmanager which can be used to iterate over the agent graph's nodes as they are executed.
@@ -822,6 +846,7 @@ class TemporalAgent(WrapperAgent[AgentDepsT, OutputDataT]):
822
846
  usage: Optional usage to start with, useful for resuming a conversation or agents used in tools.
823
847
  infer_name: Whether to try to infer the agent name from the call frame if it's not set.
824
848
  toolsets: Optional additional toolsets for this run.
849
+ builtin_tools: Optional additional builtin tools for this run.
825
850
 
826
851
  Returns:
827
852
  The result of the run.
@@ -854,6 +879,7 @@ class TemporalAgent(WrapperAgent[AgentDepsT, OutputDataT]):
854
879
  usage=usage,
855
880
  infer_name=infer_name,
856
881
  toolsets=toolsets,
882
+ builtin_tools=builtin_tools,
857
883
  **_deprecated_kwargs,
858
884
  ) as run:
859
885
  yield run
@@ -862,18 +888,20 @@ class TemporalAgent(WrapperAgent[AgentDepsT, OutputDataT]):
862
888
  def override(
863
889
  self,
864
890
  *,
891
+ name: str | _utils.Unset = _utils.UNSET,
865
892
  deps: AgentDepsT | _utils.Unset = _utils.UNSET,
866
893
  model: models.Model | models.KnownModelName | str | _utils.Unset = _utils.UNSET,
867
894
  toolsets: Sequence[AbstractToolset[AgentDepsT]] | _utils.Unset = _utils.UNSET,
868
895
  tools: Sequence[Tool[AgentDepsT] | ToolFuncEither[AgentDepsT, ...]] | _utils.Unset = _utils.UNSET,
869
896
  instructions: Instructions[AgentDepsT] | _utils.Unset = _utils.UNSET,
870
897
  ) -> Iterator[None]:
871
- """Context manager to temporarily override agent dependencies, model, toolsets, tools, or instructions.
898
+ """Context manager to temporarily override agent name, dependencies, model, toolsets, tools, or instructions.
872
899
 
873
900
  This is particularly useful when testing.
874
901
  You can find an example of this [here](../testing.md#overriding-model-via-pytest-fixtures).
875
902
 
876
903
  Args:
904
+ name: The name to use instead of the name passed to the agent constructor and agent run.
877
905
  deps: The dependencies to use instead of the dependencies passed to the agent run.
878
906
  model: The model to use instead of the model passed to the agent run.
879
907
  toolsets: The toolsets to use instead of the toolsets passed to the agent constructor and agent run.
@@ -895,6 +923,7 @@ class TemporalAgent(WrapperAgent[AgentDepsT, OutputDataT]):
895
923
  )
896
924
 
897
925
  with super().override(
926
+ name=name,
898
927
  deps=deps,
899
928
  model=model,
900
929
  toolsets=toolsets,
@@ -2,7 +2,7 @@ from __future__ import annotations as _annotations
2
2
 
3
3
  from collections.abc import Iterable, Iterator, Mapping
4
4
  from dataclasses import asdict, dataclass, field, fields, is_dataclass
5
- from datetime import date
5
+ from datetime import date, time, timedelta
6
6
  from enum import Enum
7
7
  from typing import Any, Literal
8
8
  from xml.etree import ElementTree
@@ -27,7 +27,7 @@ def format_as_xml(
27
27
  This is useful since LLMs often find it easier to read semi-structured data (e.g. examples) as XML,
28
28
  rather than JSON etc.
29
29
 
30
- Supports: `str`, `bytes`, `bytearray`, `bool`, `int`, `float`, `date`, `datetime`, `Enum`,
30
+ Supports: `str`, `bytes`, `bytearray`, `bool`, `int`, `float`, `date`, `datetime`, `time`, `timedelta`, `Enum`,
31
31
  `Mapping`, `Iterable`, `dataclass`, and `BaseModel`.
32
32
 
33
33
  Args:
@@ -104,8 +104,10 @@ class _ToXml:
104
104
  element.text = value.decode(errors='ignore')
105
105
  elif isinstance(value, bool | int | float | Enum):
106
106
  element.text = str(value)
107
- elif isinstance(value, date):
107
+ elif isinstance(value, date | time):
108
108
  element.text = value.isoformat()
109
+ elif isinstance(value, timedelta):
110
+ element.text = str(value)
109
111
  elif isinstance(value, Mapping):
110
112
  if tag is None and path in self._element_names:
111
113
  element.tag = self._element_names[path]
@@ -165,7 +167,7 @@ class _ToXml:
165
167
  path: str = '',
166
168
  ):
167
169
  """Parse data structures as dataclasses or Pydantic models to extract element names and attributes."""
168
- if value is None or isinstance(value, (str | int | float | date | bytearray | bytes | bool)):
170
+ if value is None or isinstance(value, (str | int | float | date | time | timedelta | bytearray | bytes | bool)):
169
171
  return
170
172
  elif isinstance(value, Mapping):
171
173
  for k, v in value.items(): # pyright: ignore[reportUnknownVariableType]
pydantic_ai/messages.py CHANGED
@@ -114,22 +114,8 @@ class FileUrl(ABC):
114
114
 
115
115
  _: KW_ONLY
116
116
 
117
- identifier: str
118
- """The identifier of the file, such as a unique ID. generating one from the url if not explicitly set.
119
-
120
- This identifier can be provided to the model in a message to allow it to refer to this file in a tool call argument,
121
- and the tool can look up the file in question by iterating over the message history and finding the matching `FileUrl`.
122
-
123
- This identifier is only automatically passed to the model when the `FileUrl` is returned by a tool.
124
- If you're passing the `FileUrl` as a user message, it's up to you to include a separate text part with the identifier,
125
- e.g. "This is file <identifier>:" preceding the `FileUrl`.
126
-
127
- It's also included in inline-text delimiters for providers that require inlining text documents, so the model can
128
- distinguish multiple files.
129
- """
130
-
131
117
  force_download: bool = False
132
- """If the model supports it:
118
+ """For OpenAI and Google APIs it:
133
119
 
134
120
  * If True, the file is downloaded and the data is sent to the model as bytes.
135
121
  * If False, the URL is sent directly to the model and no download is performed.
@@ -147,20 +133,24 @@ class FileUrl(ABC):
147
133
  compare=False, default=None
148
134
  )
149
135
 
136
+ _identifier: Annotated[str | None, pydantic.Field(alias='identifier', default=None, exclude=True)] = field(
137
+ compare=False, default=None
138
+ )
139
+
150
140
  def __init__(
151
141
  self,
152
142
  url: str,
153
143
  *,
154
- force_download: bool = False,
155
- vendor_metadata: dict[str, Any] | None = None,
156
144
  media_type: str | None = None,
157
145
  identifier: str | None = None,
146
+ force_download: bool = False,
147
+ vendor_metadata: dict[str, Any] | None = None,
158
148
  ) -> None:
159
149
  self.url = url
150
+ self._media_type = media_type
151
+ self._identifier = identifier
160
152
  self.force_download = force_download
161
153
  self.vendor_metadata = vendor_metadata
162
- self._media_type = media_type
163
- self.identifier = identifier or _multi_modal_content_identifier(url)
164
154
 
165
155
  @pydantic.computed_field
166
156
  @property
@@ -168,6 +158,23 @@ class FileUrl(ABC):
168
158
  """Return the media type of the file, based on the URL or the provided `media_type`."""
169
159
  return self._media_type or self._infer_media_type()
170
160
 
161
+ @pydantic.computed_field
162
+ @property
163
+ def identifier(self) -> str:
164
+ """The identifier of the file, such as a unique ID.
165
+
166
+ This identifier can be provided to the model in a message to allow it to refer to this file in a tool call argument,
167
+ and the tool can look up the file in question by iterating over the message history and finding the matching `FileUrl`.
168
+
169
+ This identifier is only automatically passed to the model when the `FileUrl` is returned by a tool.
170
+ If you're passing the `FileUrl` as a user message, it's up to you to include a separate text part with the identifier,
171
+ e.g. "This is file <identifier>:" preceding the `FileUrl`.
172
+
173
+ It's also included in inline-text delimiters for providers that require inlining text documents, so the model can
174
+ distinguish multiple files.
175
+ """
176
+ return self._identifier or _multi_modal_content_identifier(self.url)
177
+
171
178
  @abstractmethod
172
179
  def _infer_media_type(self) -> str:
173
180
  """Infer the media type of the file based on the URL."""
@@ -198,20 +205,21 @@ class VideoUrl(FileUrl):
198
205
  self,
199
206
  url: str,
200
207
  *,
208
+ media_type: str | None = None,
209
+ identifier: str | None = None,
201
210
  force_download: bool = False,
202
211
  vendor_metadata: dict[str, Any] | None = None,
203
- media_type: str | None = None,
204
212
  kind: Literal['video-url'] = 'video-url',
205
- identifier: str | None = None,
206
213
  # Required for inline-snapshot which expects all dataclass `__init__` methods to take all field names as kwargs.
207
214
  _media_type: str | None = None,
215
+ _identifier: str | None = None,
208
216
  ) -> None:
209
217
  super().__init__(
210
218
  url=url,
211
219
  force_download=force_download,
212
220
  vendor_metadata=vendor_metadata,
213
221
  media_type=media_type or _media_type,
214
- identifier=identifier,
222
+ identifier=identifier or _identifier,
215
223
  )
216
224
  self.kind = kind
217
225
 
@@ -273,20 +281,21 @@ class AudioUrl(FileUrl):
273
281
  self,
274
282
  url: str,
275
283
  *,
284
+ media_type: str | None = None,
285
+ identifier: str | None = None,
276
286
  force_download: bool = False,
277
287
  vendor_metadata: dict[str, Any] | None = None,
278
- media_type: str | None = None,
279
288
  kind: Literal['audio-url'] = 'audio-url',
280
- identifier: str | None = None,
281
289
  # Required for inline-snapshot which expects all dataclass `__init__` methods to take all field names as kwargs.
282
290
  _media_type: str | None = None,
291
+ _identifier: str | None = None,
283
292
  ) -> None:
284
293
  super().__init__(
285
294
  url=url,
286
295
  force_download=force_download,
287
296
  vendor_metadata=vendor_metadata,
288
297
  media_type=media_type or _media_type,
289
- identifier=identifier,
298
+ identifier=identifier or _identifier,
290
299
  )
291
300
  self.kind = kind
292
301
 
@@ -335,20 +344,21 @@ class ImageUrl(FileUrl):
335
344
  self,
336
345
  url: str,
337
346
  *,
347
+ media_type: str | None = None,
348
+ identifier: str | None = None,
338
349
  force_download: bool = False,
339
350
  vendor_metadata: dict[str, Any] | None = None,
340
- media_type: str | None = None,
341
351
  kind: Literal['image-url'] = 'image-url',
342
- identifier: str | None = None,
343
352
  # Required for inline-snapshot which expects all dataclass `__init__` methods to take all field names as kwargs.
344
353
  _media_type: str | None = None,
354
+ _identifier: str | None = None,
345
355
  ) -> None:
346
356
  super().__init__(
347
357
  url=url,
348
358
  force_download=force_download,
349
359
  vendor_metadata=vendor_metadata,
350
360
  media_type=media_type or _media_type,
351
- identifier=identifier,
361
+ identifier=identifier or _identifier,
352
362
  )
353
363
  self.kind = kind
354
364
 
@@ -392,20 +402,21 @@ class DocumentUrl(FileUrl):
392
402
  self,
393
403
  url: str,
394
404
  *,
405
+ media_type: str | None = None,
406
+ identifier: str | None = None,
395
407
  force_download: bool = False,
396
408
  vendor_metadata: dict[str, Any] | None = None,
397
- media_type: str | None = None,
398
409
  kind: Literal['document-url'] = 'document-url',
399
- identifier: str | None = None,
400
410
  # Required for inline-snapshot which expects all dataclass `__init__` methods to take all field names as kwargs.
401
411
  _media_type: str | None = None,
412
+ _identifier: str | None = None,
402
413
  ) -> None:
403
414
  super().__init__(
404
415
  url=url,
405
416
  force_download=force_download,
406
417
  vendor_metadata=vendor_metadata,
407
418
  media_type=media_type or _media_type,
408
- identifier=identifier,
419
+ identifier=identifier or _identifier,
409
420
  )
410
421
  self.kind = kind
411
422
 
@@ -460,16 +471,6 @@ class BinaryContent:
460
471
  media_type: AudioMediaType | ImageMediaType | DocumentMediaType | str
461
472
  """The media type of the binary data."""
462
473
 
463
- identifier: str
464
- """Identifier for the binary content, such as a unique ID.
465
- This identifier can be provided to the model in a message to allow it to refer to this file in a tool call argument,
466
- and the tool can look up the file in question by iterating over the message history and finding the matching `BinaryContent`.
467
-
468
- This identifier is only automatically passed to the model when the `BinaryContent` is returned by a tool.
469
- If you're passing the `BinaryContent` as a user message, it's up to you to include a separate text part with the identifier,
470
- e.g. "This is file <identifier>:" preceding the `BinaryContent`.
471
- """
472
-
473
474
  vendor_metadata: dict[str, Any] | None = None
474
475
  """Vendor-specific metadata for the file.
475
476
 
@@ -478,6 +479,10 @@ class BinaryContent:
478
479
  - `OpenAIChatModel`, `OpenAIResponsesModel`: `BinaryContent.vendor_metadata['detail']` is used as `detail` setting for images
479
480
  """
480
481
 
482
+ _identifier: Annotated[str | None, pydantic.Field(alias='identifier', default=None, exclude=True)] = field(
483
+ compare=False, default=None
484
+ )
485
+
481
486
  kind: Literal['binary'] = 'binary'
482
487
  """Type identifier, this is available on all parts as a discriminator."""
483
488
 
@@ -489,10 +494,12 @@ class BinaryContent:
489
494
  identifier: str | None = None,
490
495
  vendor_metadata: dict[str, Any] | None = None,
491
496
  kind: Literal['binary'] = 'binary',
497
+ # Required for inline-snapshot which expects all dataclass `__init__` methods to take all field names as kwargs.
498
+ _identifier: str | None = None,
492
499
  ) -> None:
493
500
  self.data = data
494
501
  self.media_type = media_type
495
- self.identifier = identifier or _multi_modal_content_identifier(data)
502
+ self._identifier = identifier or _identifier
496
503
  self.vendor_metadata = vendor_metadata
497
504
  self.kind = kind
498
505
 
@@ -518,6 +525,23 @@ class BinaryContent:
518
525
  media_type, data = data_uri[len(prefix) :].split(';base64,', 1)
519
526
  return cls(data=base64.b64decode(data), media_type=media_type)
520
527
 
528
+ @pydantic.computed_field
529
+ @property
530
+ def identifier(self) -> str:
531
+ """Identifier for the binary content, such as a unique ID.
532
+
533
+ This identifier can be provided to the model in a message to allow it to refer to this file in a tool call argument,
534
+ and the tool can look up the file in question by iterating over the message history and finding the matching `BinaryContent`.
535
+
536
+ This identifier is only automatically passed to the model when the `BinaryContent` is returned by a tool.
537
+ If you're passing the `BinaryContent` as a user message, it's up to you to include a separate text part with the identifier,
538
+ e.g. "This is file <identifier>:" preceding the `BinaryContent`.
539
+
540
+ It's also included in inline-text delimiters for providers that require inlining text documents, so the model can
541
+ distinguish multiple files.
542
+ """
543
+ return self._identifier or _multi_modal_content_identifier(self.data)
544
+
521
545
  @property
522
546
  def data_uri(self) -> str:
523
547
  """Convert the `BinaryContent` to a data URI."""
@@ -571,9 +595,13 @@ class BinaryImage(BinaryContent):
571
595
  media_type: str,
572
596
  identifier: str | None = None,
573
597
  vendor_metadata: dict[str, Any] | None = None,
598
+ # Required for inline-snapshot which expects all dataclass `__init__` methods to take all field names as kwargs.
574
599
  kind: Literal['binary'] = 'binary',
600
+ _identifier: str | None = None,
575
601
  ):
576
- super().__init__(data=data, media_type=media_type, identifier=identifier, vendor_metadata=vendor_metadata)
602
+ super().__init__(
603
+ data=data, media_type=media_type, identifier=identifier or _identifier, vendor_metadata=vendor_metadata
604
+ )
577
605
 
578
606
  if not self.is_image:
579
607
  raise ValueError('`BinaryImage` must be have a media type that starts with "image/"') # pragma: no cover