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.
- pydantic_ai/_run_context.py +6 -2
- pydantic_ai/_utils.py +18 -0
- pydantic_ai/agent/abstract.py +129 -3
- pydantic_ai/durable_exec/temporal/_function_toolset.py +23 -73
- pydantic_ai/durable_exec/temporal/_mcp_server.py +30 -30
- pydantic_ai/durable_exec/temporal/_run_context.py +7 -2
- pydantic_ai/durable_exec/temporal/_toolset.py +67 -3
- pydantic_ai/messages.py +6 -0
- pydantic_ai/models/google.py +5 -12
- pydantic_ai/models/openai.py +4 -0
- pydantic_ai/providers/anthropic.py +2 -2
- pydantic_ai/providers/openrouter.py +3 -0
- pydantic_ai/result.py +154 -1
- pydantic_ai/tools.py +10 -6
- pydantic_ai/ui/_adapter.py +2 -2
- pydantic_ai/ui/_event_stream.py +4 -4
- pydantic_ai/ui/ag_ui/_event_stream.py +11 -2
- pydantic_ai/ui/ag_ui/app.py +8 -1
- {pydantic_ai_slim-1.9.0.dist-info → pydantic_ai_slim-1.10.0.dist-info}/METADATA +3 -3
- {pydantic_ai_slim-1.9.0.dist-info → pydantic_ai_slim-1.10.0.dist-info}/RECORD +23 -23
- {pydantic_ai_slim-1.9.0.dist-info → pydantic_ai_slim-1.10.0.dist-info}/WHEEL +0 -0
- {pydantic_ai_slim-1.9.0.dist-info → pydantic_ai_slim-1.10.0.dist-info}/entry_points.txt +0 -0
- {pydantic_ai_slim-1.9.0.dist-info → pydantic_ai_slim-1.10.0.dist-info}/licenses/LICENSE +0 -0
pydantic_ai/_run_context.py
CHANGED
|
@@ -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[
|
|
28
|
+
class RunContext(Generic[RunContextAgentDepsT]):
|
|
25
29
|
"""Information about the current call."""
|
|
26
30
|
|
|
27
|
-
deps:
|
|
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
|
pydantic_ai/agent/abstract.py
CHANGED
|
@@ -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
|
|
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
|
|
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
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
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:
|
|
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
|
-
|
|
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
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
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
|
|
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
|
|
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:
|
|
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
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
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
|
-
) ->
|
|
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
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
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
|
|
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:
|
|
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
|
|
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.
|
|
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] = {
|
pydantic_ai/models/google.py
CHANGED
|
@@ -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
|
-
|
|
475
|
-
|
|
476
|
-
|
|
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 == '
|
|
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
|
-
|
|
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:
|
pydantic_ai/models/openai.py
CHANGED
|
@@ -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[
|
|
248
|
+
class Tool(Generic[ToolAgentDepsT]):
|
|
245
249
|
"""A tool function for an agent."""
|
|
246
250
|
|
|
247
|
-
function: ToolFuncEither[
|
|
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[
|
|
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[
|
|
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[
|
|
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[
|
|
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`
|
pydantic_ai/ui/_adapter.py
CHANGED
|
@@ -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
|
|
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 =
|
|
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.'
|
pydantic_ai/ui/_event_stream.py
CHANGED
|
@@ -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
|
-
|
|
177
|
+
parent_message_id = self.message_id
|
|
171
178
|
|
|
172
|
-
yield ToolCallStartEvent(
|
|
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
|
|
pydantic_ai/ui/ag_ui/app.py
CHANGED
|
@@ -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.
|
|
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.
|
|
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.
|
|
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
|
|
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=
|
|
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=
|
|
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=
|
|
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=
|
|
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=
|
|
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=
|
|
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=
|
|
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=
|
|
61
|
-
pydantic_ai/durable_exec/temporal/_toolset.py,sha256=
|
|
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=
|
|
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=
|
|
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=
|
|
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=
|
|
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=
|
|
139
|
-
pydantic_ai/ui/_event_stream.py,sha256=
|
|
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=
|
|
144
|
-
pydantic_ai/ui/ag_ui/app.py,sha256=
|
|
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.
|
|
152
|
-
pydantic_ai_slim-1.
|
|
153
|
-
pydantic_ai_slim-1.
|
|
154
|
-
pydantic_ai_slim-1.
|
|
155
|
-
pydantic_ai_slim-1.
|
|
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,,
|
|
File without changes
|
|
File without changes
|
|
File without changes
|