pydantic-ai-slim 1.9.0__py3-none-any.whl → 1.10.0__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.
@@ -16,15 +16,19 @@ if TYPE_CHECKING:
16
16
  from .models import Model
17
17
  from .result import RunUsage
18
18
 
19
+ # TODO (v2): Change the default for all typevars like this from `None` to `object`
19
20
  AgentDepsT = TypeVar('AgentDepsT', default=None, contravariant=True)
20
21
  """Type variable for agent dependencies."""
21
22
 
23
+ RunContextAgentDepsT = TypeVar('RunContextAgentDepsT', default=None, covariant=True)
24
+ """Type variable for the agent dependencies in `RunContext`."""
25
+
22
26
 
23
27
  @dataclasses.dataclass(repr=False, kw_only=True)
24
- class RunContext(Generic[AgentDepsT]):
28
+ class RunContext(Generic[RunContextAgentDepsT]):
25
29
  """Information about the current call."""
26
30
 
27
- deps: AgentDepsT
31
+ deps: RunContextAgentDepsT
28
32
  """Dependencies for the agent."""
29
33
  model: Model
30
34
  """The model used in this run."""
pydantic_ai/_utils.py CHANGED
@@ -234,6 +234,15 @@ def sync_anext(iterator: Iterator[T]) -> T:
234
234
  raise StopAsyncIteration() from e
235
235
 
236
236
 
237
+ def sync_async_iterator(async_iter: AsyncIterator[T]) -> Iterator[T]:
238
+ loop = get_event_loop()
239
+ while True:
240
+ try:
241
+ yield loop.run_until_complete(anext(async_iter))
242
+ except StopAsyncIteration:
243
+ break
244
+
245
+
237
246
  def now_utc() -> datetime:
238
247
  return datetime.now(tz=timezone.utc)
239
248
 
@@ -489,3 +498,12 @@ def get_union_args(tp: Any) -> tuple[Any, ...]:
489
498
  return tuple(_unwrap_annotated(arg) for arg in get_args(tp))
490
499
  else:
491
500
  return ()
501
+
502
+
503
+ def get_event_loop():
504
+ try:
505
+ event_loop = asyncio.get_event_loop()
506
+ except RuntimeError: # pragma: lax no cover
507
+ event_loop = asyncio.new_event_loop()
508
+ asyncio.set_event_loop(event_loop)
509
+ return event_loop
@@ -12,7 +12,6 @@ import anyio
12
12
  from typing_extensions import Self, TypeIs, TypeVar
13
13
 
14
14
  from pydantic_graph import End
15
- from pydantic_graph._utils import get_event_loop
16
15
 
17
16
  from .. import (
18
17
  _agent_graph,
@@ -335,7 +334,7 @@ class AbstractAgent(Generic[AgentDepsT, OutputDataT], ABC):
335
334
  if infer_name and self.name is None:
336
335
  self._infer_name(inspect.currentframe())
337
336
 
338
- return get_event_loop().run_until_complete(
337
+ return _utils.get_event_loop().run_until_complete(
339
338
  self.run(
340
339
  user_prompt,
341
340
  output_type=output_type,
@@ -581,6 +580,133 @@ class AbstractAgent(Generic[AgentDepsT, OutputDataT], ABC):
581
580
  if not yielded:
582
581
  raise exceptions.AgentRunError('Agent run finished without producing a final result') # pragma: no cover
583
582
 
583
+ @overload
584
+ def run_stream_sync(
585
+ self,
586
+ user_prompt: str | Sequence[_messages.UserContent] | None = None,
587
+ *,
588
+ output_type: None = None,
589
+ message_history: Sequence[_messages.ModelMessage] | None = None,
590
+ deferred_tool_results: DeferredToolResults | None = None,
591
+ model: models.Model | models.KnownModelName | str | None = None,
592
+ deps: AgentDepsT = None,
593
+ model_settings: ModelSettings | None = None,
594
+ usage_limits: _usage.UsageLimits | None = None,
595
+ usage: _usage.RunUsage | None = None,
596
+ infer_name: bool = True,
597
+ toolsets: Sequence[AbstractToolset[AgentDepsT]] | None = None,
598
+ builtin_tools: Sequence[AbstractBuiltinTool] | None = None,
599
+ event_stream_handler: EventStreamHandler[AgentDepsT] | None = None,
600
+ ) -> result.StreamedRunResultSync[AgentDepsT, OutputDataT]: ...
601
+
602
+ @overload
603
+ def run_stream_sync(
604
+ self,
605
+ user_prompt: str | Sequence[_messages.UserContent] | None = None,
606
+ *,
607
+ output_type: OutputSpec[RunOutputDataT],
608
+ message_history: Sequence[_messages.ModelMessage] | None = None,
609
+ deferred_tool_results: DeferredToolResults | None = None,
610
+ model: models.Model | models.KnownModelName | str | None = None,
611
+ deps: AgentDepsT = None,
612
+ model_settings: ModelSettings | None = None,
613
+ usage_limits: _usage.UsageLimits | None = None,
614
+ usage: _usage.RunUsage | None = None,
615
+ infer_name: bool = True,
616
+ toolsets: Sequence[AbstractToolset[AgentDepsT]] | None = None,
617
+ builtin_tools: Sequence[AbstractBuiltinTool] | None = None,
618
+ event_stream_handler: EventStreamHandler[AgentDepsT] | None = None,
619
+ ) -> result.StreamedRunResultSync[AgentDepsT, RunOutputDataT]: ...
620
+
621
+ def run_stream_sync(
622
+ self,
623
+ user_prompt: str | Sequence[_messages.UserContent] | None = None,
624
+ *,
625
+ output_type: OutputSpec[RunOutputDataT] | None = None,
626
+ message_history: Sequence[_messages.ModelMessage] | None = None,
627
+ deferred_tool_results: DeferredToolResults | None = None,
628
+ model: models.Model | models.KnownModelName | str | None = None,
629
+ deps: AgentDepsT = None,
630
+ model_settings: ModelSettings | None = None,
631
+ usage_limits: _usage.UsageLimits | None = None,
632
+ usage: _usage.RunUsage | None = None,
633
+ infer_name: bool = True,
634
+ toolsets: Sequence[AbstractToolset[AgentDepsT]] | None = None,
635
+ builtin_tools: Sequence[AbstractBuiltinTool] | None = None,
636
+ event_stream_handler: EventStreamHandler[AgentDepsT] | None = None,
637
+ ) -> result.StreamedRunResultSync[AgentDepsT, Any]:
638
+ """Run the agent with a user prompt in sync streaming mode.
639
+
640
+ This is a convenience method that wraps [`run_stream()`][pydantic_ai.agent.AbstractAgent.run_stream] with `loop.run_until_complete(...)`.
641
+ You therefore can't use this method inside async code or if there's an active event loop.
642
+
643
+ This method builds an internal agent graph (using system prompts, tools and output schemas) and then
644
+ runs the graph until the model produces output matching the `output_type`, for example text or structured data.
645
+ At this point, a streaming run result object is yielded from which you can stream the output as it comes in,
646
+ and -- once this output has completed streaming -- get the complete output, message history, and usage.
647
+
648
+ As this method will consider the first output matching the `output_type` to be the final output,
649
+ it will stop running the agent graph and will not execute any tool calls made by the model after this "final" output.
650
+ If you want to always run the agent graph to completion and stream events and output at the same time,
651
+ use [`agent.run()`][pydantic_ai.agent.AbstractAgent.run] with an `event_stream_handler` or [`agent.iter()`][pydantic_ai.agent.AbstractAgent.iter] instead.
652
+
653
+ Example:
654
+ ```python
655
+ from pydantic_ai import Agent
656
+
657
+ agent = Agent('openai:gpt-4o')
658
+
659
+ def main():
660
+ response = agent.run_stream_sync('What is the capital of the UK?')
661
+ print(response.get_output())
662
+ #> The capital of the UK is London.
663
+ ```
664
+
665
+ Args:
666
+ user_prompt: User input to start/continue the conversation.
667
+ output_type: Custom output type to use for this run, `output_type` may only be used if the agent has no
668
+ output validators since output validators would expect an argument that matches the agent's output type.
669
+ message_history: History of the conversation so far.
670
+ deferred_tool_results: Optional results for deferred tool calls in the message history.
671
+ model: Optional model to use for this run, required if `model` was not set when creating the agent.
672
+ deps: Optional dependencies to use for this run.
673
+ model_settings: Optional settings to use for this model's request.
674
+ usage_limits: Optional limits on model request count or token usage.
675
+ usage: Optional usage to start with, useful for resuming a conversation or agents used in tools.
676
+ infer_name: Whether to try to infer the agent name from the call frame if it's not set.
677
+ toolsets: Optional additional toolsets for this run.
678
+ builtin_tools: Optional additional builtin tools for this run.
679
+ event_stream_handler: Optional handler for events from the model's streaming response and the agent's execution of tools to use for this run.
680
+ 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.
681
+ Note that it does _not_ receive any events after the final result is found.
682
+
683
+ Returns:
684
+ The result of the run.
685
+ """
686
+ if infer_name and self.name is None:
687
+ self._infer_name(inspect.currentframe())
688
+
689
+ async def _consume_stream():
690
+ async with self.run_stream(
691
+ user_prompt,
692
+ output_type=output_type,
693
+ message_history=message_history,
694
+ deferred_tool_results=deferred_tool_results,
695
+ model=model,
696
+ deps=deps,
697
+ model_settings=model_settings,
698
+ usage_limits=usage_limits,
699
+ usage=usage,
700
+ infer_name=infer_name,
701
+ toolsets=toolsets,
702
+ builtin_tools=builtin_tools,
703
+ event_stream_handler=event_stream_handler,
704
+ ) as stream_result:
705
+ yield stream_result
706
+
707
+ async_result = _utils.get_event_loop().run_until_complete(anext(_consume_stream()))
708
+ return result.StreamedRunResultSync(async_result)
709
+
584
710
  @overload
585
711
  def run_stream_events(
586
712
  self,
@@ -1217,6 +1343,6 @@ class AbstractAgent(Generic[AgentDepsT, OutputDataT], ABC):
1217
1343
  agent.to_cli_sync(prog_name='assistant')
1218
1344
  ```
1219
1345
  """
1220
- return get_event_loop().run_until_complete(
1346
+ return _utils.get_event_loop().run_until_complete(
1221
1347
  self.to_cli(deps=deps, prog_name=prog_name, message_history=message_history)
1222
1348
  )
@@ -1,57 +1,22 @@
1
1
  from __future__ import annotations
2
2
 
3
3
  from collections.abc import Callable
4
- from dataclasses import dataclass
5
- from typing import Annotated, Any, Literal
4
+ from typing import Any, Literal
6
5
 
7
- from pydantic import ConfigDict, Discriminator, with_config
8
6
  from temporalio import activity, workflow
9
7
  from temporalio.workflow import ActivityConfig
10
- from typing_extensions import assert_never
11
8
 
12
9
  from pydantic_ai import FunctionToolset, ToolsetTool
13
- from pydantic_ai.exceptions import ApprovalRequired, CallDeferred, ModelRetry, UserError
10
+ from pydantic_ai.exceptions import UserError
14
11
  from pydantic_ai.tools import AgentDepsT, RunContext
15
12
  from pydantic_ai.toolsets.function import FunctionToolsetTool
16
13
 
17
14
  from ._run_context import TemporalRunContext
18
- from ._toolset import TemporalWrapperToolset
19
-
20
-
21
- @dataclass
22
- @with_config(ConfigDict(arbitrary_types_allowed=True))
23
- class _CallToolParams:
24
- name: str
25
- tool_args: dict[str, Any]
26
- serialized_run_context: Any
27
-
28
-
29
- @dataclass
30
- class _ApprovalRequired:
31
- kind: Literal['approval_required'] = 'approval_required'
32
-
33
-
34
- @dataclass
35
- class _CallDeferred:
36
- kind: Literal['call_deferred'] = 'call_deferred'
37
-
38
-
39
- @dataclass
40
- class _ModelRetry:
41
- message: str
42
- kind: Literal['model_retry'] = 'model_retry'
43
-
44
-
45
- @dataclass
46
- class _ToolReturn:
47
- result: Any
48
- kind: Literal['tool_return'] = 'tool_return'
49
-
50
-
51
- _CallToolResult = Annotated[
52
- _ApprovalRequired | _CallDeferred | _ModelRetry | _ToolReturn,
53
- Discriminator('kind'),
54
- ]
15
+ from ._toolset import (
16
+ CallToolParams,
17
+ CallToolResult,
18
+ TemporalWrapperToolset,
19
+ )
55
20
 
56
21
 
57
22
  class TemporalFunctionToolset(TemporalWrapperToolset[AgentDepsT]):
@@ -70,7 +35,7 @@ class TemporalFunctionToolset(TemporalWrapperToolset[AgentDepsT]):
70
35
  self.tool_activity_config = tool_activity_config
71
36
  self.run_context_type = run_context_type
72
37
 
73
- async def call_tool_activity(params: _CallToolParams, deps: AgentDepsT) -> _CallToolResult:
38
+ async def call_tool_activity(params: CallToolParams, deps: AgentDepsT) -> CallToolResult:
74
39
  name = params.name
75
40
  ctx = self.run_context_type.deserialize_run_context(params.serialized_run_context, deps=deps)
76
41
  try:
@@ -84,15 +49,7 @@ class TemporalFunctionToolset(TemporalWrapperToolset[AgentDepsT]):
84
49
  # The tool args will already have been validated into their proper types in the `ToolManager`,
85
50
  # but `execute_activity` would have turned them into simple Python types again, so we need to re-validate them.
86
51
  args_dict = tool.args_validator.validate_python(params.tool_args)
87
- try:
88
- result = await self.wrapped.call_tool(name, args_dict, ctx, tool)
89
- return _ToolReturn(result=result)
90
- except ApprovalRequired:
91
- return _ApprovalRequired()
92
- except CallDeferred:
93
- return _CallDeferred()
94
- except ModelRetry as e:
95
- return _ModelRetry(message=e.message)
52
+ return await self._wrap_call_tool_result(self.wrapped.call_tool(name, args_dict, ctx, tool))
96
53
 
97
54
  # Set type hint explicitly so that Temporal can take care of serialization and deserialization
98
55
  call_tool_activity.__annotations__['deps'] = deps_type
@@ -123,25 +80,18 @@ class TemporalFunctionToolset(TemporalWrapperToolset[AgentDepsT]):
123
80
 
124
81
  tool_activity_config = self.activity_config | tool_activity_config
125
82
  serialized_run_context = self.run_context_type.serialize_run_context(ctx)
126
- result = await workflow.execute_activity( # pyright: ignore[reportUnknownMemberType]
127
- activity=self.call_tool_activity,
128
- args=[
129
- _CallToolParams(
130
- name=name,
131
- tool_args=tool_args,
132
- serialized_run_context=serialized_run_context,
133
- ),
134
- ctx.deps,
135
- ],
136
- **tool_activity_config,
83
+ return self._unwrap_call_tool_result(
84
+ await workflow.execute_activity( # pyright: ignore[reportUnknownMemberType]
85
+ activity=self.call_tool_activity,
86
+ args=[
87
+ CallToolParams(
88
+ name=name,
89
+ tool_args=tool_args,
90
+ serialized_run_context=serialized_run_context,
91
+ tool_def=None,
92
+ ),
93
+ ctx.deps,
94
+ ],
95
+ **tool_activity_config,
96
+ )
137
97
  )
138
- if isinstance(result, _ApprovalRequired):
139
- raise ApprovalRequired()
140
- elif isinstance(result, _CallDeferred):
141
- raise CallDeferred()
142
- elif isinstance(result, _ModelRetry):
143
- raise ModelRetry(result.message)
144
- elif isinstance(result, _ToolReturn):
145
- return result.result
146
- else:
147
- assert_never(result)
@@ -11,11 +11,15 @@ from typing_extensions import Self
11
11
 
12
12
  from pydantic_ai import ToolsetTool
13
13
  from pydantic_ai.exceptions import UserError
14
- from pydantic_ai.mcp import MCPServer, ToolResult
14
+ from pydantic_ai.mcp import MCPServer
15
15
  from pydantic_ai.tools import AgentDepsT, RunContext, ToolDefinition
16
16
 
17
17
  from ._run_context import TemporalRunContext
18
- from ._toolset import TemporalWrapperToolset
18
+ from ._toolset import (
19
+ CallToolParams,
20
+ CallToolResult,
21
+ TemporalWrapperToolset,
22
+ )
19
23
 
20
24
 
21
25
  @dataclass
@@ -24,15 +28,6 @@ class _GetToolsParams:
24
28
  serialized_run_context: Any
25
29
 
26
30
 
27
- @dataclass
28
- @with_config(ConfigDict(arbitrary_types_allowed=True))
29
- class _CallToolParams:
30
- name: str
31
- tool_args: dict[str, Any]
32
- serialized_run_context: Any
33
- tool_def: ToolDefinition
34
-
35
-
36
31
  class TemporalMCPServer(TemporalWrapperToolset[AgentDepsT]):
37
32
  def __init__(
38
33
  self,
@@ -72,13 +67,16 @@ class TemporalMCPServer(TemporalWrapperToolset[AgentDepsT]):
72
67
  get_tools_activity
73
68
  )
74
69
 
75
- async def call_tool_activity(params: _CallToolParams, deps: AgentDepsT) -> ToolResult:
70
+ async def call_tool_activity(params: CallToolParams, deps: AgentDepsT) -> CallToolResult:
76
71
  run_context = self.run_context_type.deserialize_run_context(params.serialized_run_context, deps=deps)
77
- return await self.wrapped.call_tool(
78
- params.name,
79
- params.tool_args,
80
- run_context,
81
- self.tool_for_tool_def(params.tool_def),
72
+ assert isinstance(params.tool_def, ToolDefinition)
73
+ return await self._wrap_call_tool_result(
74
+ self.wrapped.call_tool(
75
+ params.name,
76
+ params.tool_args,
77
+ run_context,
78
+ self.tool_for_tool_def(params.tool_def),
79
+ )
82
80
  )
83
81
 
84
82
  # Set type hint explicitly so that Temporal can take care of serialization and deserialization
@@ -125,22 +123,24 @@ class TemporalMCPServer(TemporalWrapperToolset[AgentDepsT]):
125
123
  tool_args: dict[str, Any],
126
124
  ctx: RunContext[AgentDepsT],
127
125
  tool: ToolsetTool[AgentDepsT],
128
- ) -> ToolResult:
126
+ ) -> CallToolResult:
129
127
  if not workflow.in_workflow():
130
128
  return await super().call_tool(name, tool_args, ctx, tool)
131
129
 
132
130
  tool_activity_config = self.activity_config | self.tool_activity_config.get(name, {})
133
131
  serialized_run_context = self.run_context_type.serialize_run_context(ctx)
134
- return await workflow.execute_activity( # pyright: ignore[reportUnknownMemberType]
135
- activity=self.call_tool_activity,
136
- args=[
137
- _CallToolParams(
138
- name=name,
139
- tool_args=tool_args,
140
- serialized_run_context=serialized_run_context,
141
- tool_def=tool.tool_def,
142
- ),
143
- ctx.deps,
144
- ],
145
- **tool_activity_config,
132
+ return self._unwrap_call_tool_result(
133
+ await workflow.execute_activity( # pyright: ignore[reportUnknownMemberType]
134
+ activity=self.call_tool_activity,
135
+ args=[
136
+ CallToolParams(
137
+ name=name,
138
+ tool_args=tool_args,
139
+ serialized_run_context=serialized_run_context,
140
+ tool_def=tool.tool_def,
141
+ ),
142
+ ctx.deps,
143
+ ],
144
+ **tool_activity_config,
145
+ )
146
146
  )
@@ -2,8 +2,13 @@ from __future__ import annotations
2
2
 
3
3
  from typing import Any
4
4
 
5
+ from typing_extensions import TypeVar
6
+
5
7
  from pydantic_ai.exceptions import UserError
6
- from pydantic_ai.tools import AgentDepsT, RunContext
8
+ from pydantic_ai.tools import RunContext
9
+
10
+ AgentDepsT = TypeVar('AgentDepsT', default=None, covariant=True)
11
+ """Type variable for the agent dependencies in `RunContext`."""
7
12
 
8
13
 
9
14
  class TemporalRunContext(RunContext[AgentDepsT]):
@@ -47,6 +52,6 @@ class TemporalRunContext(RunContext[AgentDepsT]):
47
52
  }
48
53
 
49
54
  @classmethod
50
- def deserialize_run_context(cls, ctx: dict[str, Any], deps: AgentDepsT) -> TemporalRunContext[AgentDepsT]:
55
+ def deserialize_run_context(cls, ctx: dict[str, Any], deps: Any) -> TemporalRunContext[Any]:
51
56
  """Deserialize the run context from a `dict[str, Any]`."""
52
57
  return cls(**ctx, deps=deps)
@@ -1,17 +1,58 @@
1
1
  from __future__ import annotations
2
2
 
3
3
  from abc import ABC, abstractmethod
4
- from collections.abc import Callable
5
- from typing import Any, Literal
4
+ from collections.abc import Awaitable, Callable
5
+ from dataclasses import dataclass
6
+ from typing import Annotated, Any, Literal
6
7
 
8
+ from pydantic import ConfigDict, Discriminator, with_config
7
9
  from temporalio.workflow import ActivityConfig
10
+ from typing_extensions import assert_never
8
11
 
9
12
  from pydantic_ai import AbstractToolset, FunctionToolset, WrapperToolset
10
- from pydantic_ai.tools import AgentDepsT
13
+ from pydantic_ai.exceptions import ApprovalRequired, CallDeferred, ModelRetry
14
+ from pydantic_ai.tools import AgentDepsT, ToolDefinition
11
15
 
12
16
  from ._run_context import TemporalRunContext
13
17
 
14
18
 
19
+ @dataclass
20
+ @with_config(ConfigDict(arbitrary_types_allowed=True))
21
+ class CallToolParams:
22
+ name: str
23
+ tool_args: dict[str, Any]
24
+ serialized_run_context: Any
25
+ tool_def: ToolDefinition | None
26
+
27
+
28
+ @dataclass
29
+ class _ApprovalRequired:
30
+ kind: Literal['approval_required'] = 'approval_required'
31
+
32
+
33
+ @dataclass
34
+ class _CallDeferred:
35
+ kind: Literal['call_deferred'] = 'call_deferred'
36
+
37
+
38
+ @dataclass
39
+ class _ModelRetry:
40
+ message: str
41
+ kind: Literal['model_retry'] = 'model_retry'
42
+
43
+
44
+ @dataclass
45
+ class _ToolReturn:
46
+ result: Any
47
+ kind: Literal['tool_return'] = 'tool_return'
48
+
49
+
50
+ CallToolResult = Annotated[
51
+ _ApprovalRequired | _CallDeferred | _ModelRetry | _ToolReturn,
52
+ Discriminator('kind'),
53
+ ]
54
+
55
+
15
56
  class TemporalWrapperToolset(WrapperToolset[AgentDepsT], ABC):
16
57
  @property
17
58
  def id(self) -> str:
@@ -30,6 +71,29 @@ class TemporalWrapperToolset(WrapperToolset[AgentDepsT], ABC):
30
71
  # Temporalized toolsets cannot be swapped out after the fact.
31
72
  return self
32
73
 
74
+ async def _wrap_call_tool_result(self, coro: Awaitable[Any]) -> CallToolResult:
75
+ try:
76
+ result = await coro
77
+ return _ToolReturn(result=result)
78
+ except ApprovalRequired:
79
+ return _ApprovalRequired()
80
+ except CallDeferred:
81
+ return _CallDeferred()
82
+ except ModelRetry as e:
83
+ return _ModelRetry(message=e.message)
84
+
85
+ def _unwrap_call_tool_result(self, result: CallToolResult) -> Any:
86
+ if isinstance(result, _ToolReturn):
87
+ return result.result
88
+ elif isinstance(result, _ApprovalRequired):
89
+ raise ApprovalRequired()
90
+ elif isinstance(result, _CallDeferred):
91
+ raise CallDeferred()
92
+ elif isinstance(result, _ModelRetry):
93
+ raise ModelRetry(result.message)
94
+ else:
95
+ assert_never(result)
96
+
33
97
 
34
98
  def temporalize_toolset(
35
99
  toolset: AbstractToolset[AgentDepsT],
pydantic_ai/messages.py CHANGED
@@ -34,6 +34,7 @@ DocumentMediaType: TypeAlias = Literal[
34
34
  'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet',
35
35
  'text/html',
36
36
  'text/markdown',
37
+ 'application/msword',
37
38
  'application/vnd.ms-excel',
38
39
  ]
39
40
  VideoMediaType: TypeAlias = Literal[
@@ -434,8 +435,12 @@ class DocumentUrl(FileUrl):
434
435
  return 'application/pdf'
435
436
  elif self.url.endswith('.rtf'):
436
437
  return 'application/rtf'
438
+ elif self.url.endswith('.doc'):
439
+ return 'application/msword'
437
440
  elif self.url.endswith('.docx'):
438
441
  return 'application/vnd.openxmlformats-officedocument.wordprocessingml.document'
442
+ elif self.url.endswith('.xls'):
443
+ return 'application/vnd.ms-excel'
439
444
  elif self.url.endswith('.xlsx'):
440
445
  return 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet'
441
446
 
@@ -645,6 +650,7 @@ _document_format_lookup: dict[str, DocumentFormat] = {
645
650
  'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet': 'xlsx',
646
651
  'text/html': 'html',
647
652
  'text/markdown': 'md',
653
+ 'application/msword': 'doc',
648
654
  'application/vnd.ms-excel': 'xls',
649
655
  }
650
656
  _audio_format_lookup: dict[str, AudioFormat] = {
@@ -471,11 +471,9 @@ class GoogleModel(Model):
471
471
  raise UnexpectedModelBehavior(
472
472
  f'Content filter {raw_finish_reason.value!r} triggered', response.model_dump_json()
473
473
  )
474
- else:
475
- raise UnexpectedModelBehavior(
476
- 'Content field missing from Gemini response', response.model_dump_json()
477
- ) # pragma: no cover
478
- parts = candidate.content.parts or []
474
+ parts = [] # pragma: no cover
475
+ else:
476
+ parts = candidate.content.parts or []
479
477
 
480
478
  usage = _metadata_as_usage(response)
481
479
  return _process_response_from_parts(
@@ -649,17 +647,12 @@ class GeminiStreamedResponse(StreamedResponse):
649
647
  # )
650
648
 
651
649
  if candidate.content is None or candidate.content.parts is None:
652
- if self.finish_reason == 'stop': # pragma: no cover
653
- # Normal completion - skip this chunk
654
- continue
655
- elif self.finish_reason == 'content_filter' and raw_finish_reason: # pragma: no cover
650
+ if self.finish_reason == 'content_filter' and raw_finish_reason: # pragma: no cover
656
651
  raise UnexpectedModelBehavior(
657
652
  f'Content filter {raw_finish_reason.value!r} triggered', chunk.model_dump_json()
658
653
  )
659
654
  else: # pragma: no cover
660
- raise UnexpectedModelBehavior(
661
- 'Content field missing from streaming Gemini response', chunk.model_dump_json()
662
- )
655
+ continue
663
656
 
664
657
  parts = candidate.content.parts
665
658
  if not parts:
@@ -948,6 +948,10 @@ class OpenAIResponsesModel(Model):
948
948
 
949
949
  super().__init__(settings=settings, profile=profile or provider.model_profile)
950
950
 
951
+ @property
952
+ def base_url(self) -> str:
953
+ return str(self.client.base_url)
954
+
951
955
  @property
952
956
  def model_name(self) -> OpenAIModelName:
953
957
  """The model name."""
@@ -12,7 +12,7 @@ from pydantic_ai.profiles.anthropic import anthropic_model_profile
12
12
  from pydantic_ai.providers import Provider
13
13
 
14
14
  try:
15
- from anthropic import AsyncAnthropic, AsyncAnthropicBedrock
15
+ from anthropic import AsyncAnthropic, AsyncAnthropicBedrock, AsyncAnthropicVertex
16
16
  except ImportError as _import_error:
17
17
  raise ImportError(
18
18
  'Please install the `anthropic` package to use the Anthropic provider, '
@@ -20,7 +20,7 @@ except ImportError as _import_error:
20
20
  ) from _import_error
21
21
 
22
22
 
23
- AsyncAnthropicClient: TypeAlias = AsyncAnthropic | AsyncAnthropicBedrock
23
+ AsyncAnthropicClient: TypeAlias = AsyncAnthropic | AsyncAnthropicBedrock | AsyncAnthropicVertex
24
24
 
25
25
 
26
26
  class AnthropicProvider(Provider[AsyncAnthropicClient]):
@@ -81,6 +81,9 @@ class OpenRouterProvider(Provider[AsyncOpenAI]):
81
81
  @overload
82
82
  def __init__(self, *, api_key: str, http_client: httpx.AsyncClient) -> None: ...
83
83
 
84
+ @overload
85
+ def __init__(self, *, http_client: httpx.AsyncClient) -> None: ...
86
+
84
87
  @overload
85
88
  def __init__(self, *, openai_client: AsyncOpenAI | None = None) -> None: ...
86
89
 
pydantic_ai/result.py CHANGED
@@ -1,6 +1,6 @@
1
1
  from __future__ import annotations as _annotations
2
2
 
3
- from collections.abc import AsyncIterator, Awaitable, Callable, Iterable
3
+ from collections.abc import AsyncIterator, Awaitable, Callable, Iterable, Iterator
4
4
  from copy import deepcopy
5
5
  from dataclasses import dataclass, field
6
6
  from datetime import datetime
@@ -35,6 +35,7 @@ __all__ = (
35
35
  'OutputDataT_inv',
36
36
  'ToolOutput',
37
37
  'OutputValidatorFunc',
38
+ 'StreamedRunResultSync',
38
39
  )
39
40
 
40
41
 
@@ -555,6 +556,158 @@ class StreamedRunResult(Generic[AgentDepsT, OutputDataT]):
555
556
  await self._on_complete()
556
557
 
557
558
 
559
+ @dataclass(init=False)
560
+ class StreamedRunResultSync(Generic[AgentDepsT, OutputDataT]):
561
+ """Synchronous wrapper for [`StreamedRunResult`][pydantic_ai.result.StreamedRunResult] that only exposes sync methods."""
562
+
563
+ _streamed_run_result: StreamedRunResult[AgentDepsT, OutputDataT]
564
+
565
+ def __init__(self, streamed_run_result: StreamedRunResult[AgentDepsT, OutputDataT]) -> None:
566
+ self._streamed_run_result = streamed_run_result
567
+
568
+ def all_messages(self, *, output_tool_return_content: str | None = None) -> list[_messages.ModelMessage]:
569
+ """Return the history of messages.
570
+
571
+ Args:
572
+ output_tool_return_content: The return content of the tool call to set in the last message.
573
+ This provides a convenient way to modify the content of the output tool call if you want to continue
574
+ the conversation and want to set the response to the output tool call. If `None`, the last message will
575
+ not be modified.
576
+
577
+ Returns:
578
+ List of messages.
579
+ """
580
+ return self._streamed_run_result.all_messages(output_tool_return_content=output_tool_return_content)
581
+
582
+ def all_messages_json(self, *, output_tool_return_content: str | None = None) -> bytes: # pragma: no cover
583
+ """Return all messages from [`all_messages`][pydantic_ai.result.StreamedRunResultSync.all_messages] as JSON bytes.
584
+
585
+ Args:
586
+ output_tool_return_content: The return content of the tool call to set in the last message.
587
+ This provides a convenient way to modify the content of the output tool call if you want to continue
588
+ the conversation and want to set the response to the output tool call. If `None`, the last message will
589
+ not be modified.
590
+
591
+ Returns:
592
+ JSON bytes representing the messages.
593
+ """
594
+ return self._streamed_run_result.all_messages_json(output_tool_return_content=output_tool_return_content)
595
+
596
+ def new_messages(self, *, output_tool_return_content: str | None = None) -> list[_messages.ModelMessage]:
597
+ """Return new messages associated with this run.
598
+
599
+ Messages from older runs are excluded.
600
+
601
+ Args:
602
+ output_tool_return_content: The return content of the tool call to set in the last message.
603
+ This provides a convenient way to modify the content of the output tool call if you want to continue
604
+ the conversation and want to set the response to the output tool call. If `None`, the last message will
605
+ not be modified.
606
+
607
+ Returns:
608
+ List of new messages.
609
+ """
610
+ return self._streamed_run_result.new_messages(output_tool_return_content=output_tool_return_content)
611
+
612
+ def new_messages_json(self, *, output_tool_return_content: str | None = None) -> bytes: # pragma: no cover
613
+ """Return new messages from [`new_messages`][pydantic_ai.result.StreamedRunResultSync.new_messages] as JSON bytes.
614
+
615
+ Args:
616
+ output_tool_return_content: The return content of the tool call to set in the last message.
617
+ This provides a convenient way to modify the content of the output tool call if you want to continue
618
+ the conversation and want to set the response to the output tool call. If `None`, the last message will
619
+ not be modified.
620
+
621
+ Returns:
622
+ JSON bytes representing the new messages.
623
+ """
624
+ return self._streamed_run_result.new_messages_json(output_tool_return_content=output_tool_return_content)
625
+
626
+ def stream_output(self, *, debounce_by: float | None = 0.1) -> Iterator[OutputDataT]:
627
+ """Stream the output as an iterable.
628
+
629
+ The pydantic validator for structured data will be called in
630
+ [partial mode](https://docs.pydantic.dev/dev/concepts/experimental/#partial-validation)
631
+ on each iteration.
632
+
633
+ Args:
634
+ debounce_by: by how much (if at all) to debounce/group the output chunks by. `None` means no debouncing.
635
+ Debouncing is particularly important for long structured outputs to reduce the overhead of
636
+ performing validation as each token is received.
637
+
638
+ Returns:
639
+ An iterable of the response data.
640
+ """
641
+ return _utils.sync_async_iterator(self._streamed_run_result.stream_output(debounce_by=debounce_by))
642
+
643
+ def stream_text(self, *, delta: bool = False, debounce_by: float | None = 0.1) -> Iterator[str]:
644
+ """Stream the text result as an iterable.
645
+
646
+ !!! note
647
+ Result validators will NOT be called on the text result if `delta=True`.
648
+
649
+ Args:
650
+ delta: if `True`, yield each chunk of text as it is received, if `False` (default), yield the full text
651
+ up to the current point.
652
+ debounce_by: by how much (if at all) to debounce/group the response chunks by. `None` means no debouncing.
653
+ Debouncing is particularly important for long structured responses to reduce the overhead of
654
+ performing validation as each token is received.
655
+ """
656
+ return _utils.sync_async_iterator(self._streamed_run_result.stream_text(delta=delta, debounce_by=debounce_by))
657
+
658
+ def stream_responses(self, *, debounce_by: float | None = 0.1) -> Iterator[tuple[_messages.ModelResponse, bool]]:
659
+ """Stream the response as an iterable of Structured LLM Messages.
660
+
661
+ Args:
662
+ debounce_by: by how much (if at all) to debounce/group the response chunks by. `None` means no debouncing.
663
+ Debouncing is particularly important for long structured responses to reduce the overhead of
664
+ performing validation as each token is received.
665
+
666
+ Returns:
667
+ An iterable of the structured response message and whether that is the last message.
668
+ """
669
+ return _utils.sync_async_iterator(self._streamed_run_result.stream_responses(debounce_by=debounce_by))
670
+
671
+ def get_output(self) -> OutputDataT:
672
+ """Stream the whole response, validate and return it."""
673
+ return _utils.get_event_loop().run_until_complete(self._streamed_run_result.get_output())
674
+
675
+ @property
676
+ def response(self) -> _messages.ModelResponse:
677
+ """Return the current state of the response."""
678
+ return self._streamed_run_result.response
679
+
680
+ def usage(self) -> RunUsage:
681
+ """Return the usage of the whole run.
682
+
683
+ !!! note
684
+ This won't return the full usage until the stream is finished.
685
+ """
686
+ return self._streamed_run_result.usage()
687
+
688
+ def timestamp(self) -> datetime:
689
+ """Get the timestamp of the response."""
690
+ return self._streamed_run_result.timestamp()
691
+
692
+ def validate_response_output(self, message: _messages.ModelResponse, *, allow_partial: bool = False) -> OutputDataT:
693
+ """Validate a structured result message."""
694
+ return _utils.get_event_loop().run_until_complete(
695
+ self._streamed_run_result.validate_response_output(message, allow_partial=allow_partial)
696
+ )
697
+
698
+ @property
699
+ def is_complete(self) -> bool:
700
+ """Whether the stream has all been received.
701
+
702
+ This is set to `True` when one of
703
+ [`stream_output`][pydantic_ai.result.StreamedRunResultSync.stream_output],
704
+ [`stream_text`][pydantic_ai.result.StreamedRunResultSync.stream_text],
705
+ [`stream_responses`][pydantic_ai.result.StreamedRunResultSync.stream_responses] or
706
+ [`get_output`][pydantic_ai.result.StreamedRunResultSync.get_output] completes.
707
+ """
708
+ return self._streamed_run_result.is_complete
709
+
710
+
558
711
  @dataclass(repr=False)
559
712
  class FinalResult(Generic[OutputDataT]):
560
713
  """Marker class storing the final output of an agent run and associated metadata."""
pydantic_ai/tools.py CHANGED
@@ -240,16 +240,20 @@ class GenerateToolJsonSchema(GenerateJsonSchema):
240
240
  return s
241
241
 
242
242
 
243
+ ToolAgentDepsT = TypeVar('ToolAgentDepsT', default=object, contravariant=True)
244
+ """Type variable for agent dependencies for a tool."""
245
+
246
+
243
247
  @dataclass(init=False)
244
- class Tool(Generic[AgentDepsT]):
248
+ class Tool(Generic[ToolAgentDepsT]):
245
249
  """A tool function for an agent."""
246
250
 
247
- function: ToolFuncEither[AgentDepsT]
251
+ function: ToolFuncEither[ToolAgentDepsT]
248
252
  takes_ctx: bool
249
253
  max_retries: int | None
250
254
  name: str
251
255
  description: str | None
252
- prepare: ToolPrepareFunc[AgentDepsT] | None
256
+ prepare: ToolPrepareFunc[ToolAgentDepsT] | None
253
257
  docstring_format: DocstringFormat
254
258
  require_parameter_descriptions: bool
255
259
  strict: bool | None
@@ -265,13 +269,13 @@ class Tool(Generic[AgentDepsT]):
265
269
 
266
270
  def __init__(
267
271
  self,
268
- function: ToolFuncEither[AgentDepsT],
272
+ function: ToolFuncEither[ToolAgentDepsT],
269
273
  *,
270
274
  takes_ctx: bool | None = None,
271
275
  max_retries: int | None = None,
272
276
  name: str | None = None,
273
277
  description: str | None = None,
274
- prepare: ToolPrepareFunc[AgentDepsT] | None = None,
278
+ prepare: ToolPrepareFunc[ToolAgentDepsT] | None = None,
275
279
  docstring_format: DocstringFormat = 'auto',
276
280
  require_parameter_descriptions: bool = False,
277
281
  schema_generator: type[GenerateJsonSchema] = GenerateToolJsonSchema,
@@ -413,7 +417,7 @@ class Tool(Generic[AgentDepsT]):
413
417
  metadata=self.metadata,
414
418
  )
415
419
 
416
- async def prepare_tool_def(self, ctx: RunContext[AgentDepsT]) -> ToolDefinition | None:
420
+ async def prepare_tool_def(self, ctx: RunContext[ToolAgentDepsT]) -> ToolDefinition | None:
417
421
  """Get the tool definition.
418
422
 
419
423
  By default, this method creates a tool definition, then either returns it, or calls `self.prepare`
@@ -2,7 +2,7 @@ from __future__ import annotations
2
2
 
3
3
  from abc import ABC, abstractmethod
4
4
  from collections.abc import AsyncIterator, Sequence
5
- from dataclasses import KW_ONLY, Field, dataclass, replace
5
+ from dataclasses import KW_ONLY, Field, dataclass
6
6
  from functools import cached_property
7
7
  from http import HTTPStatus
8
8
  from typing import (
@@ -238,7 +238,7 @@ class UIAdapter(ABC, Generic[RunInputT, MessageT, EventT, AgentDepsT, OutputData
238
238
  else:
239
239
  state = raw_state
240
240
 
241
- deps = replace(deps, state=state)
241
+ deps.state = state
242
242
  elif self.state:
243
243
  raise UserError(
244
244
  f'State is provided but `deps` of type `{type(deps).__name__}` does not implement the `StateHandler` protocol: it needs to be a dataclass with a non-optional `state` field.'
@@ -404,7 +404,7 @@ class UIEventStream(ABC, Generic[RunInputT, EventT, AgentDepsT, OutputDataT]):
404
404
 
405
405
  Override this to inject custom events at the start of the request.
406
406
  """
407
- return
407
+ return # pragma: lax no cover
408
408
  yield # Make this an async generator
409
409
 
410
410
  async def after_request(self) -> AsyncIterator[EventT]:
@@ -412,7 +412,7 @@ class UIEventStream(ABC, Generic[RunInputT, EventT, AgentDepsT, OutputDataT]):
412
412
 
413
413
  Override this to inject custom events at the end of the request.
414
414
  """
415
- return
415
+ return # pragma: lax no cover
416
416
  yield # Make this an async generator
417
417
 
418
418
  async def before_response(self) -> AsyncIterator[EventT]:
@@ -420,7 +420,7 @@ class UIEventStream(ABC, Generic[RunInputT, EventT, AgentDepsT, OutputDataT]):
420
420
 
421
421
  Override this to inject custom events at the start of the response.
422
422
  """
423
- return
423
+ return # pragma: no cover
424
424
  yield # Make this an async generator
425
425
 
426
426
  async def after_response(self) -> AsyncIterator[EventT]:
@@ -428,7 +428,7 @@ class UIEventStream(ABC, Generic[RunInputT, EventT, AgentDepsT, OutputDataT]):
428
428
 
429
429
  Override this to inject custom events at the end of the response.
430
430
  """
431
- return
431
+ return # pragma: lax no cover
432
432
  yield # Make this an async generator
433
433
 
434
434
  async def handle_text_start(self, part: TextPart, follows_text: bool = False) -> AsyncIterator[EventT]:
@@ -92,6 +92,13 @@ class AGUIEventStream(UIEventStream[RunAgentInput, BaseEvent, AgentDepsT, Output
92
92
  run_id=self.run_input.run_id,
93
93
  )
94
94
 
95
+ async def before_response(self) -> AsyncIterator[BaseEvent]:
96
+ # Prevent parts from a subsequent response being tied to parts from an earlier response.
97
+ # See https://github.com/pydantic/pydantic-ai/issues/3316
98
+ self.new_message_id()
99
+ return
100
+ yield # Make this an async generator
101
+
95
102
  async def after_stream(self) -> AsyncIterator[BaseEvent]:
96
103
  if not self._error:
97
104
  yield RunFinishedEvent(
@@ -167,9 +174,11 @@ class AGUIEventStream(UIEventStream[RunAgentInput, BaseEvent, AgentDepsT, Output
167
174
  self, part: ToolCallPart | BuiltinToolCallPart, tool_call_id: str | None = None
168
175
  ) -> AsyncIterator[BaseEvent]:
169
176
  tool_call_id = tool_call_id or part.tool_call_id
170
- message_id = self.message_id or self.new_message_id()
177
+ parent_message_id = self.message_id
171
178
 
172
- yield ToolCallStartEvent(tool_call_id=tool_call_id, tool_call_name=part.tool_name, parent_message_id=message_id)
179
+ yield ToolCallStartEvent(
180
+ tool_call_id=tool_call_id, tool_call_name=part.tool_name, parent_message_id=parent_message_id
181
+ )
173
182
  if part.args:
174
183
  yield ToolCallArgsEvent(tool_call_id=tool_call_id, delta=part.args_as_json_str())
175
184
 
@@ -3,6 +3,7 @@
3
3
  from __future__ import annotations
4
4
 
5
5
  from collections.abc import Callable, Mapping, Sequence
6
+ from dataclasses import replace
6
7
  from typing import Any, Generic
7
8
 
8
9
  from typing_extensions import Self
@@ -18,7 +19,7 @@ from pydantic_ai.tools import AgentDepsT
18
19
  from pydantic_ai.toolsets import AbstractToolset
19
20
  from pydantic_ai.usage import RunUsage, UsageLimits
20
21
 
21
- from .. import OnCompleteFunc
22
+ from .. import OnCompleteFunc, StateHandler
22
23
  from ._adapter import AGUIAdapter
23
24
 
24
25
  try:
@@ -121,6 +122,12 @@ class AGUIApp(Generic[AgentDepsT, OutputDataT], Starlette):
121
122
 
122
123
  async def run_agent(request: Request) -> Response:
123
124
  """Endpoint to run the agent with the provided input data."""
125
+ # `dispatch_request` will store the frontend state from the request on `deps.state` (if it implements the `StateHandler` protocol),
126
+ # so we need to copy the deps to avoid different requests mutating the same deps object.
127
+ nonlocal deps
128
+ if isinstance(deps, StateHandler): # pragma: no branch
129
+ deps = replace(deps)
130
+
124
131
  return await AGUIAdapter[AgentDepsT, OutputDataT].dispatch_request(
125
132
  request,
126
133
  agent=agent,
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: pydantic-ai-slim
3
- Version: 1.9.0
3
+ Version: 1.10.0
4
4
  Summary: Agent Framework / shim to use Pydantic with LLMs, slim package
5
5
  Project-URL: Homepage, https://github.com/pydantic/pydantic-ai/tree/main/pydantic_ai_slim
6
6
  Project-URL: Source, https://github.com/pydantic/pydantic-ai/tree/main/pydantic_ai_slim
@@ -33,7 +33,7 @@ Requires-Dist: genai-prices>=0.0.35
33
33
  Requires-Dist: griffe>=1.3.2
34
34
  Requires-Dist: httpx>=0.27
35
35
  Requires-Dist: opentelemetry-api>=1.28.0
36
- Requires-Dist: pydantic-graph==1.9.0
36
+ Requires-Dist: pydantic-graph==1.10.0
37
37
  Requires-Dist: pydantic>=2.10
38
38
  Requires-Dist: typing-inspection>=0.4.0
39
39
  Provides-Extra: a2a
@@ -57,7 +57,7 @@ Requires-Dist: dbos>=1.14.0; extra == 'dbos'
57
57
  Provides-Extra: duckduckgo
58
58
  Requires-Dist: ddgs>=9.0.0; extra == 'duckduckgo'
59
59
  Provides-Extra: evals
60
- Requires-Dist: pydantic-evals==1.9.0; extra == 'evals'
60
+ Requires-Dist: pydantic-evals==1.10.0; extra == 'evals'
61
61
  Provides-Extra: fastmcp
62
62
  Requires-Dist: fastmcp>=2.12.0; extra == 'fastmcp'
63
63
  Provides-Extra: google
@@ -11,28 +11,28 @@ pydantic_ai/_mcp.py,sha256=PuvwnlLjv7YYOa9AZJCrklevBug99zGMhwJCBGG7BHQ,5626
11
11
  pydantic_ai/_otel_messages.py,sha256=SsMpbyI1fIISOck_wQcZJPIOei8lOmvwARkdPSCx8y8,1650
12
12
  pydantic_ai/_output.py,sha256=83Imvnwqwr-zveX_I95E24zt2Iqn-ofpd0HsbvOhS70,41274
13
13
  pydantic_ai/_parts_manager.py,sha256=05m8q2JZQk9Z8vNKOocxGDJQwYgbUGABGBRnXYJcsg8,19914
14
- pydantic_ai/_run_context.py,sha256=-ah9Ipf3mLTbvuYqmJSqBmBexaCcED7HGA1Llzs0dKU,2324
14
+ pydantic_ai/_run_context.py,sha256=fGNn9-RSAa7sEG_iqDTC-v-wKDuPsD3TRDvdVLXaXY0,2577
15
15
  pydantic_ai/_system_prompt.py,sha256=WdDW_DTGHujcFFaK-J7J6mA4ZDJZ0IOKpyizJA-1Y5Q,1142
16
16
  pydantic_ai/_thinking_part.py,sha256=_0DajGyWPa50WUTPWN1UPfZw0xD8_hHcuSt0T3fgRr0,1295
17
17
  pydantic_ai/_tool_manager.py,sha256=se5Fikg4HaiTOnxJ4LFrezktZ2Zfv9a2OH0V9PtFE54,10464
18
- pydantic_ai/_utils.py,sha256=65H0E1GVGO2OmXpSoSbWDEPUxqLFVOzDXs3UkN2fyik,16580
18
+ pydantic_ai/_utils.py,sha256=LCZCzZWAyS852bjqwYSL4fvkmvLJMTkCN09ruaICldY,17062
19
19
  pydantic_ai/ag_ui.py,sha256=kE7bk-yH7_GLkup0_EGqSiA5ZpxGqeeN0tb8tQ3QXe4,6974
20
20
  pydantic_ai/builtin_tools.py,sha256=EYSp9JVRethTLz-cL6HNrFRqnYaJMYBoDi-FTMcFf8c,8448
21
21
  pydantic_ai/direct.py,sha256=GnPFyHa2HkUEAKd2uVHMxZ90KM76lYGa9AQM84dEUXg,15513
22
22
  pydantic_ai/exceptions.py,sha256=gCmXLaic_PLD6_X6CNY0hcKRGr-bNUeKeV_ZR9Xyt7U,5141
23
23
  pydantic_ai/format_prompt.py,sha256=cLyWO8g77Y4JzqVSikqodXaAfTn6i-k206rNhYTiIsE,9710
24
24
  pydantic_ai/mcp.py,sha256=FHlD5pHH7Z6h76P6IjddQz0Pt6F0gAVlepmks4U1Cho,36190
25
- pydantic_ai/messages.py,sha256=th9AyBBrpyXZeHOVDJkWJZZkMGsL3vYJ7E5vDFYmItc,65957
25
+ pydantic_ai/messages.py,sha256=cTuaiM0NjcvwMn_x2U7NVdnlWuye_v6qz-1qMLfmO58,66182
26
26
  pydantic_ai/output.py,sha256=q91oqvJ-FqV9GbUUil7WVWbii66SVsVZ54AEm_NWSEo,13002
27
27
  pydantic_ai/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
28
- pydantic_ai/result.py,sha256=nOTTGUJUHqSbOQzWikzPJa3sJmztDzEeV-5DVHd_q0o,26998
28
+ pydantic_ai/result.py,sha256=57Bn1Jcxw_jEigGwPhVsVflokNJ2e-HEdjGddxp5cos,34660
29
29
  pydantic_ai/retries.py,sha256=QM4oDA9DG-Y2qP06fbCp8Dqq8ups40Rr4HYjAOlbNyM,14650
30
30
  pydantic_ai/run.py,sha256=5mOgh7UkLRtCjs1S85NM6OjcWvOy91VQhCkNMQQPhxs,17039
31
31
  pydantic_ai/settings.py,sha256=HlQxrw62YsXpIIhhddecYNTquDfhnpfaZU7y1p4CuVs,3935
32
- pydantic_ai/tools.py,sha256=dCecmJtRkF1ioqFYbfT00XGGqzGB4PPO9n6IrHCQtnc,20343
32
+ pydantic_ai/tools.py,sha256=ITisUdqf_vuTUhwifriMxinE9b5etAzcODPh6CRbOmk,20503
33
33
  pydantic_ai/usage.py,sha256=lhReoVNwqt7mfmWk40A1ddnKk4-MVFJ0qCl_oFdGzxo,16251
34
34
  pydantic_ai/agent/__init__.py,sha256=rvVo5Fw78yu5IOVE6ub6tmJTIuDGsIY15D3_KTFXtx4,66525
35
- pydantic_ai/agent/abstract.py,sha256=zXj7fZHG7Nj6WwVajWuNI0xHqWEX2Zyte_lGmyDZd6o,56378
35
+ pydantic_ai/agent/abstract.py,sha256=kv2ktxJcsB414VmnHeGnfH1UoGNcdo3mkC5QvG5KusY,63184
36
36
  pydantic_ai/agent/wrapper.py,sha256=ygwfMq24mGe3pGIK-TtPAy3cV7M8VZJW3ulEHvwNTck,10293
37
37
  pydantic_ai/common_tools/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
38
38
  pydantic_ai/common_tools/duckduckgo.py,sha256=1ae_o3zqMGrC6KFqAmuqPwJqQgNBTisuvU2jX9KU8PI,2273
@@ -53,12 +53,12 @@ pydantic_ai/durable_exec/prefect/_toolset.py,sha256=dBgIMsQikjJgGr7_QAs3UG7nycBB
53
53
  pydantic_ai/durable_exec/prefect/_types.py,sha256=cTtXnKokPSCDMBQJrLlEho0mJLvDIGNCZF-q6infkkU,1270
54
54
  pydantic_ai/durable_exec/temporal/__init__.py,sha256=KTbzwj9C-Xu6i5kwgMraUsKfmjfz6yxBc4FCJNEbFjs,6187
55
55
  pydantic_ai/durable_exec/temporal/_agent.py,sha256=I03CafhyyZ4KVN9DtnypMvRcNXYsfapDv9LUwCGZPzM,44594
56
- pydantic_ai/durable_exec/temporal/_function_toolset.py,sha256=blGpeMWDfqgGcGrPEnQ2LE0FGv_jQ6legY4o2PWd3Fo,5582
56
+ pydantic_ai/durable_exec/temporal/_function_toolset.py,sha256=lYE66Rv7ofh3_gzaMr1dkTU8sg-c7ntjVDFSUMEfq_w,4224
57
57
  pydantic_ai/durable_exec/temporal/_logfire.py,sha256=ASd7vb0cd61yESI0mgU2w9SCGxsOegz95HtQjKdlQkE,2472
58
- pydantic_ai/durable_exec/temporal/_mcp_server.py,sha256=vxfWeI7ZtYyXVgX621rPtG-WOZjlKWnqJhcvR9eBgIo,6014
58
+ pydantic_ai/durable_exec/temporal/_mcp_server.py,sha256=wBN8R1wFQ9SUiZvskqE-LuSLqm2K2naElnVwHLkdkDY,6104
59
59
  pydantic_ai/durable_exec/temporal/_model.py,sha256=sOrDgMjQmCizSXe041dNpd5EDFAXgE6r0LGZghWkaeg,7546
60
- pydantic_ai/durable_exec/temporal/_run_context.py,sha256=Y0RTm-P6q8Oziu2gml6hpAjhbVBeJuktEme84qwXE8A,2449
61
- pydantic_ai/durable_exec/temporal/_toolset.py,sha256=IlPQrumm2MpZrb518ru15s0jIl8-cGwvE6ZNWIZrFuE,2879
60
+ pydantic_ai/durable_exec/temporal/_run_context.py,sha256=fYWTAN4zswf7ugE7PDgD5qlauc5j9RKhIRxE7zupGkc,2592
61
+ pydantic_ai/durable_exec/temporal/_toolset.py,sha256=wO7wnk9cp4RWo_kCZ4iZhe_rTe6YfG3poHH9gg134hI,4692
62
62
  pydantic_ai/ext/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
63
63
  pydantic_ai/ext/aci.py,sha256=YWYLXzTQJ6hS7qfgNycA8cRl69gogGgThqEU6II7eMA,2527
64
64
  pydantic_ai/ext/langchain.py,sha256=kmbbV3Cx2BiNYEJCZMHVYQquUQD-zG2L_bwDangy0Ww,2317
@@ -69,13 +69,13 @@ pydantic_ai/models/cohere.py,sha256=wQ3UYiFMs5Oyeyz5sd6NyG3b94iCeYBptnJC8bEYOUA,
69
69
  pydantic_ai/models/fallback.py,sha256=fjQz7qRuxEwC6aFYkglBv-2Z39-6kZ931vs6o7PIti8,5016
70
70
  pydantic_ai/models/function.py,sha256=7-ej1m4f7c1TbvgB8sF02qlFD7Kf-EX-k_xN4RkbIEw,15880
71
71
  pydantic_ai/models/gemini.py,sha256=ZMO1mUX6GXPo0N2OHoi_nS9Lb-Rqf0YFsILoRcssaG4,40410
72
- pydantic_ai/models/google.py,sha256=rcYzRMELj98dgnw8YrBHM1R3HLVjCTkWgDXMSNQrxOA,42141
72
+ pydantic_ai/models/google.py,sha256=xaQkej5FYD4LRil4enwZHb5GmYmUqB_Wvj7-1oWdBnk,41700
73
73
  pydantic_ai/models/groq.py,sha256=HxJSquMfqOAS8gsQQQJyM8iReaPYp0VywK740thOYCU,29931
74
74
  pydantic_ai/models/huggingface.py,sha256=iADyoCKYrNyjixr55rEpXW02F-sah4rLmqrThEcNNDw,21464
75
75
  pydantic_ai/models/instrumented.py,sha256=J8eVTutr3UP1r_wd5sM5c0BIdzkRqT-EGgd2NiF0ssQ,22319
76
76
  pydantic_ai/models/mcp_sampling.py,sha256=qY4y4nXbRpNp2QbkfjzWLvF_8KLZGXypz4cc0lYRHXU,3553
77
77
  pydantic_ai/models/mistral.py,sha256=fi57hADjYxZw8wEpAcNI6mqY32VG9hHK9GGRQ-9vlZg,33905
78
- pydantic_ai/models/openai.py,sha256=JV47aeiHJ6GnFI6-gi9nuuWkGalqmqff2DtCaZ0Q6ZI,109208
78
+ pydantic_ai/models/openai.py,sha256=OO4O7HlEdHXx_sAv0y7Lf8NeVJac248JsrlRiNjagRk,109295
79
79
  pydantic_ai/models/outlines.py,sha256=Un4KERT-jW97georXrE3iNuThFiYaYxZjGYHm2-PpD8,24270
80
80
  pydantic_ai/models/test.py,sha256=cRiLD1uXKERUkBTyrVj3L5NQHoDrDqL5UU9EG_odkTg,20707
81
81
  pydantic_ai/models/wrapper.py,sha256=nwh8Gea59blbr1JDKlUnkYICuI9TUubC4qP7iZRRW28,2440
@@ -94,7 +94,7 @@ pydantic_ai/profiles/moonshotai.py,sha256=e1RJnbEvazE6aJAqfmYLYGNtwNwg52XQDRDkcL
94
94
  pydantic_ai/profiles/openai.py,sha256=kve8KnvsGguioNi1gQtO7dqF8vvxR8W21fERehb3GPo,10053
95
95
  pydantic_ai/profiles/qwen.py,sha256=9SnTpMKndxNQMFyumyaOczJa5JGWbYQdpVKKW4OzKjk,749
96
96
  pydantic_ai/providers/__init__.py,sha256=Fwpu0w2-NpkKYQkDS2__kaWOR3dMW2KiE9v0K1EKwP4,4985
97
- pydantic_ai/providers/anthropic.py,sha256=vwNjO2JJ0Ux_3PXI9_XvzNZ24PKessm8z2ja1uzbBwM,3327
97
+ pydantic_ai/providers/anthropic.py,sha256=gAxVAJYrhUhq3FEUaYy3rNxkB52EDISL4Zf5yzd5ups,3372
98
98
  pydantic_ai/providers/azure.py,sha256=PFRykTOfARMdANODnTLq__0ZynX7DlQ35GVf2Qs9VBY,5814
99
99
  pydantic_ai/providers/bedrock.py,sha256=bPbz-o3UhDzCRrg5xCrTfluLpDi2Yy9-JiCtC5mCIRk,8539
100
100
  pydantic_ai/providers/cerebras.py,sha256=3rIu092TYYuI5S4mlRjWxay5uomPbEDyHWIBMfrDBdA,3427
@@ -116,7 +116,7 @@ pydantic_ai/providers/moonshotai.py,sha256=iaQHZRYJb7hqeq-Di7Qb0LYJ8EEoE7a_wWtlt
116
116
  pydantic_ai/providers/nebius.py,sha256=nGpgbZnBZgNz4wHTi1vgvc-9tO2_zj5r3vRzEUbhPKM,3877
117
117
  pydantic_ai/providers/ollama.py,sha256=jg48g_3fYsvK8g-V3UOmR9HOsvnvb533BAB-rZZDxdA,4733
118
118
  pydantic_ai/providers/openai.py,sha256=cVVf99GgBnYBKYeWKBscvnkoRCu0ctWuKulG19lgWMo,3401
119
- pydantic_ai/providers/openrouter.py,sha256=o33Fk7kMyMhEM4NcSXU6IuG0cIUc45ySaenozrRypBI,4145
119
+ pydantic_ai/providers/openrouter.py,sha256=H5EgV0DGDFw-pgfYquy9uy8C8dXwl9mmfor991jlXL8,4231
120
120
  pydantic_ai/providers/outlines.py,sha256=9Y3bnRKooqeUIVquexf75oGWpj8XOpJ71tBMWp0mTMQ,1251
121
121
  pydantic_ai/providers/ovhcloud.py,sha256=qvPB7-hgeClBMeNSKOiTrF-pSp6RczRaqWg5iAeUwss,3428
122
122
  pydantic_ai/providers/together.py,sha256=QtIR1BVJjoEYLvsUFpvPe81akx0iQvjYptl87XVpCpo,3441
@@ -135,21 +135,21 @@ pydantic_ai/toolsets/prepared.py,sha256=Zjfz6S8In6PBVxoKFN9sKPN984zO6t0awB7Lnq5K
135
135
  pydantic_ai/toolsets/renamed.py,sha256=JuLHpi-hYPiSPlaTpN8WiXLiGsywYK0axi2lW2Qs75k,1637
136
136
  pydantic_ai/toolsets/wrapper.py,sha256=KRzF1p8dncHbva8CE6Ud-IC5E_aygIHlwH5atXK55k4,1673
137
137
  pydantic_ai/ui/__init__.py,sha256=J19J5ZWFWcg_SbnHxqwR_tK4A53NlpaTFk898n7tQww,406
138
- pydantic_ai/ui/_adapter.py,sha256=OUqD-MqdWBg69lbV7WCMqFgHiy5wXeCGZCzUSxC1YYE,16597
139
- pydantic_ai/ui/_event_stream.py,sha256=MsS4PZ88RkYjhqq1zOotBLoDvI5D5DS8Ed2sIGQXBss,24984
138
+ pydantic_ai/ui/_adapter.py,sha256=f73ChFKjAmg1Tios3-rvE70htpEGMKwx-bhWg7ZAMGI,16573
139
+ pydantic_ai/ui/_event_stream.py,sha256=icW6OEkC4y2tBP8PljzUSPqmE2rSQurNQ3F1xotI_-I,25076
140
140
  pydantic_ai/ui/_messages_builder.py,sha256=jQaKD8B8GtkDXCRb1134ufnRpv84mLgGzdZeCsFwikY,1215
141
141
  pydantic_ai/ui/ag_ui/__init__.py,sha256=CWtc_Xu-upchzJYoEgJy_0o2NnfUItT-gFbOVWDO8UE,192
142
142
  pydantic_ai/ui/ag_ui/_adapter.py,sha256=UbXbT3Iq0h-_UAIR7dcDPnomfSE2uM05O58e3PLt51I,6988
143
- pydantic_ai/ui/ag_ui/_event_stream.py,sha256=_NEZvOaVNSTBTD2hSoVUeUZ13mzzqaQQC9SrM1Tg48o,9017
144
- pydantic_ai/ui/ag_ui/app.py,sha256=YY8nnSNox4ngV7GcOZCJU6uG5FeKoObEtpkahG0cOnQ,7504
143
+ pydantic_ai/ui/ag_ui/_event_stream.py,sha256=eJEdi72207T1D4ftuG_EwHcvi2ZXXRk5bDbI0llzN4g,9348
144
+ pydantic_ai/ui/ag_ui/app.py,sha256=0reVNuSOF3vNuONjbFys8pUl0wikgJ4lIMffwzc_8so,7927
145
145
  pydantic_ai/ui/vercel_ai/__init__.py,sha256=RG6J_W7Hr89XP-GST8uRPMbxveA2EB4BmoYSuUko79s,488
146
146
  pydantic_ai/ui/vercel_ai/_adapter.py,sha256=8QWDzGuIb2paM1nivS7w8x9-a7TPM8DJ6lggKkm-nrM,8723
147
147
  pydantic_ai/ui/vercel_ai/_event_stream.py,sha256=78DXqziNDtdtxrgiilYQqCNXh3Ct62jWcCwtVsy__3U,6806
148
148
  pydantic_ai/ui/vercel_ai/_utils.py,sha256=F-2qOC8Ckp-xSwuKp4Y0_8achi8RIGWHOSs1y7diD48,441
149
149
  pydantic_ai/ui/vercel_ai/request_types.py,sha256=VQpYZJdJ2aCm2NtZPhHzBws6Qkm5aYdNcGyq-Q8IQV8,7387
150
150
  pydantic_ai/ui/vercel_ai/response_types.py,sha256=nuU41wFXOCdnlyQRPZZmV9HEOvCZVjdczlg5A8qADTY,5258
151
- pydantic_ai_slim-1.9.0.dist-info/METADATA,sha256=5_K5Te_aJ_LXYtWBp9rU3x0flq9BCvNgETslhc1x10c,5659
152
- pydantic_ai_slim-1.9.0.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
153
- pydantic_ai_slim-1.9.0.dist-info/entry_points.txt,sha256=kbKxe2VtDCYS06hsI7P3uZGxcVC08-FPt1rxeiMpIps,50
154
- pydantic_ai_slim-1.9.0.dist-info/licenses/LICENSE,sha256=vA6Jc482lEyBBuGUfD1pYx-cM7jxvLYOxPidZ30t_PQ,1100
155
- pydantic_ai_slim-1.9.0.dist-info/RECORD,,
151
+ pydantic_ai_slim-1.10.0.dist-info/METADATA,sha256=CKxuvI-j6tveJ-GufhUjENDFqZFZGx4aaS1jkc1TC5M,5662
152
+ pydantic_ai_slim-1.10.0.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
153
+ pydantic_ai_slim-1.10.0.dist-info/entry_points.txt,sha256=kbKxe2VtDCYS06hsI7P3uZGxcVC08-FPt1rxeiMpIps,50
154
+ pydantic_ai_slim-1.10.0.dist-info/licenses/LICENSE,sha256=vA6Jc482lEyBBuGUfD1pYx-cM7jxvLYOxPidZ30t_PQ,1100
155
+ pydantic_ai_slim-1.10.0.dist-info/RECORD,,