pydantic-ai-slim 1.0.1__tar.gz → 1.0.2__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of pydantic-ai-slim might be problematic. Click here for more details.
- {pydantic_ai_slim-1.0.1 → pydantic_ai_slim-1.0.2}/PKG-INFO +6 -4
- {pydantic_ai_slim-1.0.1 → pydantic_ai_slim-1.0.2}/pydantic_ai/_agent_graph.py +50 -31
- {pydantic_ai_slim-1.0.1 → pydantic_ai_slim-1.0.2}/pydantic_ai/_tool_manager.py +4 -0
- {pydantic_ai_slim-1.0.1 → pydantic_ai_slim-1.0.2}/pydantic_ai/agent/__init__.py +3 -0
- pydantic_ai_slim-1.0.2/pydantic_ai/durable_exec/dbos/__init__.py +6 -0
- pydantic_ai_slim-1.0.2/pydantic_ai/durable_exec/dbos/_agent.py +718 -0
- pydantic_ai_slim-1.0.2/pydantic_ai/durable_exec/dbos/_mcp_server.py +89 -0
- pydantic_ai_slim-1.0.2/pydantic_ai/durable_exec/dbos/_model.py +137 -0
- pydantic_ai_slim-1.0.2/pydantic_ai/durable_exec/dbos/_utils.py +10 -0
- {pydantic_ai_slim-1.0.1 → pydantic_ai_slim-1.0.2}/pydantic_ai/mcp.py +1 -1
- {pydantic_ai_slim-1.0.1 → pydantic_ai_slim-1.0.2}/pydantic_ai/messages.py +12 -0
- {pydantic_ai_slim-1.0.1 → pydantic_ai_slim-1.0.2}/pydantic_ai/models/__init__.py +8 -0
- {pydantic_ai_slim-1.0.1 → pydantic_ai_slim-1.0.2}/pydantic_ai/models/anthropic.py +24 -0
- {pydantic_ai_slim-1.0.1 → pydantic_ai_slim-1.0.2}/pydantic_ai/models/google.py +43 -4
- {pydantic_ai_slim-1.0.1 → pydantic_ai_slim-1.0.2}/pydantic_ai/models/instrumented.py +27 -14
- {pydantic_ai_slim-1.0.1 → pydantic_ai_slim-1.0.2}/pydantic_ai/models/openai.py +67 -16
- {pydantic_ai_slim-1.0.1 → pydantic_ai_slim-1.0.2}/pydantic_ai/providers/bedrock.py +11 -3
- {pydantic_ai_slim-1.0.1 → pydantic_ai_slim-1.0.2}/pydantic_ai/tools.py +11 -0
- {pydantic_ai_slim-1.0.1 → pydantic_ai_slim-1.0.2}/pydantic_ai/toolsets/function.py +7 -0
- {pydantic_ai_slim-1.0.1 → pydantic_ai_slim-1.0.2}/pyproject.toml +3 -1
- {pydantic_ai_slim-1.0.1 → pydantic_ai_slim-1.0.2}/.gitignore +0 -0
- {pydantic_ai_slim-1.0.1 → pydantic_ai_slim-1.0.2}/LICENSE +0 -0
- {pydantic_ai_slim-1.0.1 → pydantic_ai_slim-1.0.2}/README.md +0 -0
- {pydantic_ai_slim-1.0.1 → pydantic_ai_slim-1.0.2}/pydantic_ai/__init__.py +0 -0
- {pydantic_ai_slim-1.0.1 → pydantic_ai_slim-1.0.2}/pydantic_ai/__main__.py +0 -0
- {pydantic_ai_slim-1.0.1 → pydantic_ai_slim-1.0.2}/pydantic_ai/_a2a.py +0 -0
- {pydantic_ai_slim-1.0.1 → pydantic_ai_slim-1.0.2}/pydantic_ai/_cli.py +0 -0
- {pydantic_ai_slim-1.0.1 → pydantic_ai_slim-1.0.2}/pydantic_ai/_function_schema.py +0 -0
- {pydantic_ai_slim-1.0.1 → pydantic_ai_slim-1.0.2}/pydantic_ai/_griffe.py +0 -0
- {pydantic_ai_slim-1.0.1 → pydantic_ai_slim-1.0.2}/pydantic_ai/_mcp.py +0 -0
- {pydantic_ai_slim-1.0.1 → pydantic_ai_slim-1.0.2}/pydantic_ai/_otel_messages.py +0 -0
- {pydantic_ai_slim-1.0.1 → pydantic_ai_slim-1.0.2}/pydantic_ai/_output.py +0 -0
- {pydantic_ai_slim-1.0.1 → pydantic_ai_slim-1.0.2}/pydantic_ai/_parts_manager.py +0 -0
- {pydantic_ai_slim-1.0.1 → pydantic_ai_slim-1.0.2}/pydantic_ai/_run_context.py +0 -0
- {pydantic_ai_slim-1.0.1 → pydantic_ai_slim-1.0.2}/pydantic_ai/_system_prompt.py +0 -0
- {pydantic_ai_slim-1.0.1 → pydantic_ai_slim-1.0.2}/pydantic_ai/_thinking_part.py +0 -0
- {pydantic_ai_slim-1.0.1 → pydantic_ai_slim-1.0.2}/pydantic_ai/_utils.py +0 -0
- {pydantic_ai_slim-1.0.1 → pydantic_ai_slim-1.0.2}/pydantic_ai/ag_ui.py +0 -0
- {pydantic_ai_slim-1.0.1 → pydantic_ai_slim-1.0.2}/pydantic_ai/agent/abstract.py +0 -0
- {pydantic_ai_slim-1.0.1 → pydantic_ai_slim-1.0.2}/pydantic_ai/agent/wrapper.py +0 -0
- {pydantic_ai_slim-1.0.1 → pydantic_ai_slim-1.0.2}/pydantic_ai/builtin_tools.py +0 -0
- {pydantic_ai_slim-1.0.1 → pydantic_ai_slim-1.0.2}/pydantic_ai/common_tools/__init__.py +0 -0
- {pydantic_ai_slim-1.0.1 → pydantic_ai_slim-1.0.2}/pydantic_ai/common_tools/duckduckgo.py +0 -0
- {pydantic_ai_slim-1.0.1 → pydantic_ai_slim-1.0.2}/pydantic_ai/common_tools/tavily.py +0 -0
- {pydantic_ai_slim-1.0.1 → pydantic_ai_slim-1.0.2}/pydantic_ai/direct.py +0 -0
- {pydantic_ai_slim-1.0.1 → pydantic_ai_slim-1.0.2}/pydantic_ai/durable_exec/__init__.py +0 -0
- {pydantic_ai_slim-1.0.1 → pydantic_ai_slim-1.0.2}/pydantic_ai/durable_exec/temporal/__init__.py +0 -0
- {pydantic_ai_slim-1.0.1 → pydantic_ai_slim-1.0.2}/pydantic_ai/durable_exec/temporal/_agent.py +0 -0
- {pydantic_ai_slim-1.0.1 → pydantic_ai_slim-1.0.2}/pydantic_ai/durable_exec/temporal/_function_toolset.py +0 -0
- {pydantic_ai_slim-1.0.1 → pydantic_ai_slim-1.0.2}/pydantic_ai/durable_exec/temporal/_logfire.py +0 -0
- {pydantic_ai_slim-1.0.1 → pydantic_ai_slim-1.0.2}/pydantic_ai/durable_exec/temporal/_mcp_server.py +0 -0
- {pydantic_ai_slim-1.0.1 → pydantic_ai_slim-1.0.2}/pydantic_ai/durable_exec/temporal/_model.py +0 -0
- {pydantic_ai_slim-1.0.1 → pydantic_ai_slim-1.0.2}/pydantic_ai/durable_exec/temporal/_run_context.py +0 -0
- {pydantic_ai_slim-1.0.1 → pydantic_ai_slim-1.0.2}/pydantic_ai/durable_exec/temporal/_toolset.py +0 -0
- {pydantic_ai_slim-1.0.1 → pydantic_ai_slim-1.0.2}/pydantic_ai/exceptions.py +0 -0
- {pydantic_ai_slim-1.0.1 → pydantic_ai_slim-1.0.2}/pydantic_ai/ext/__init__.py +0 -0
- {pydantic_ai_slim-1.0.1 → pydantic_ai_slim-1.0.2}/pydantic_ai/ext/aci.py +0 -0
- {pydantic_ai_slim-1.0.1 → pydantic_ai_slim-1.0.2}/pydantic_ai/ext/langchain.py +0 -0
- {pydantic_ai_slim-1.0.1 → pydantic_ai_slim-1.0.2}/pydantic_ai/format_prompt.py +0 -0
- {pydantic_ai_slim-1.0.1 → pydantic_ai_slim-1.0.2}/pydantic_ai/models/bedrock.py +0 -0
- {pydantic_ai_slim-1.0.1 → pydantic_ai_slim-1.0.2}/pydantic_ai/models/cohere.py +0 -0
- {pydantic_ai_slim-1.0.1 → pydantic_ai_slim-1.0.2}/pydantic_ai/models/fallback.py +0 -0
- {pydantic_ai_slim-1.0.1 → pydantic_ai_slim-1.0.2}/pydantic_ai/models/function.py +0 -0
- {pydantic_ai_slim-1.0.1 → pydantic_ai_slim-1.0.2}/pydantic_ai/models/gemini.py +0 -0
- {pydantic_ai_slim-1.0.1 → pydantic_ai_slim-1.0.2}/pydantic_ai/models/groq.py +0 -0
- {pydantic_ai_slim-1.0.1 → pydantic_ai_slim-1.0.2}/pydantic_ai/models/huggingface.py +0 -0
- {pydantic_ai_slim-1.0.1 → pydantic_ai_slim-1.0.2}/pydantic_ai/models/mcp_sampling.py +0 -0
- {pydantic_ai_slim-1.0.1 → pydantic_ai_slim-1.0.2}/pydantic_ai/models/mistral.py +0 -0
- {pydantic_ai_slim-1.0.1 → pydantic_ai_slim-1.0.2}/pydantic_ai/models/test.py +0 -0
- {pydantic_ai_slim-1.0.1 → pydantic_ai_slim-1.0.2}/pydantic_ai/models/wrapper.py +0 -0
- {pydantic_ai_slim-1.0.1 → pydantic_ai_slim-1.0.2}/pydantic_ai/output.py +0 -0
- {pydantic_ai_slim-1.0.1 → pydantic_ai_slim-1.0.2}/pydantic_ai/profiles/__init__.py +0 -0
- {pydantic_ai_slim-1.0.1 → pydantic_ai_slim-1.0.2}/pydantic_ai/profiles/_json_schema.py +0 -0
- {pydantic_ai_slim-1.0.1 → pydantic_ai_slim-1.0.2}/pydantic_ai/profiles/amazon.py +0 -0
- {pydantic_ai_slim-1.0.1 → pydantic_ai_slim-1.0.2}/pydantic_ai/profiles/anthropic.py +0 -0
- {pydantic_ai_slim-1.0.1 → pydantic_ai_slim-1.0.2}/pydantic_ai/profiles/cohere.py +0 -0
- {pydantic_ai_slim-1.0.1 → pydantic_ai_slim-1.0.2}/pydantic_ai/profiles/deepseek.py +0 -0
- {pydantic_ai_slim-1.0.1 → pydantic_ai_slim-1.0.2}/pydantic_ai/profiles/google.py +0 -0
- {pydantic_ai_slim-1.0.1 → pydantic_ai_slim-1.0.2}/pydantic_ai/profiles/grok.py +0 -0
- {pydantic_ai_slim-1.0.1 → pydantic_ai_slim-1.0.2}/pydantic_ai/profiles/groq.py +0 -0
- {pydantic_ai_slim-1.0.1 → pydantic_ai_slim-1.0.2}/pydantic_ai/profiles/harmony.py +0 -0
- {pydantic_ai_slim-1.0.1 → pydantic_ai_slim-1.0.2}/pydantic_ai/profiles/meta.py +0 -0
- {pydantic_ai_slim-1.0.1 → pydantic_ai_slim-1.0.2}/pydantic_ai/profiles/mistral.py +0 -0
- {pydantic_ai_slim-1.0.1 → pydantic_ai_slim-1.0.2}/pydantic_ai/profiles/moonshotai.py +0 -0
- {pydantic_ai_slim-1.0.1 → pydantic_ai_slim-1.0.2}/pydantic_ai/profiles/openai.py +0 -0
- {pydantic_ai_slim-1.0.1 → pydantic_ai_slim-1.0.2}/pydantic_ai/profiles/qwen.py +0 -0
- {pydantic_ai_slim-1.0.1 → pydantic_ai_slim-1.0.2}/pydantic_ai/providers/__init__.py +0 -0
- {pydantic_ai_slim-1.0.1 → pydantic_ai_slim-1.0.2}/pydantic_ai/providers/anthropic.py +0 -0
- {pydantic_ai_slim-1.0.1 → pydantic_ai_slim-1.0.2}/pydantic_ai/providers/azure.py +0 -0
- {pydantic_ai_slim-1.0.1 → pydantic_ai_slim-1.0.2}/pydantic_ai/providers/cerebras.py +0 -0
- {pydantic_ai_slim-1.0.1 → pydantic_ai_slim-1.0.2}/pydantic_ai/providers/cohere.py +0 -0
- {pydantic_ai_slim-1.0.1 → pydantic_ai_slim-1.0.2}/pydantic_ai/providers/deepseek.py +0 -0
- {pydantic_ai_slim-1.0.1 → pydantic_ai_slim-1.0.2}/pydantic_ai/providers/fireworks.py +0 -0
- {pydantic_ai_slim-1.0.1 → pydantic_ai_slim-1.0.2}/pydantic_ai/providers/github.py +0 -0
- {pydantic_ai_slim-1.0.1 → pydantic_ai_slim-1.0.2}/pydantic_ai/providers/google.py +0 -0
- {pydantic_ai_slim-1.0.1 → pydantic_ai_slim-1.0.2}/pydantic_ai/providers/google_gla.py +0 -0
- {pydantic_ai_slim-1.0.1 → pydantic_ai_slim-1.0.2}/pydantic_ai/providers/google_vertex.py +0 -0
- {pydantic_ai_slim-1.0.1 → pydantic_ai_slim-1.0.2}/pydantic_ai/providers/grok.py +0 -0
- {pydantic_ai_slim-1.0.1 → pydantic_ai_slim-1.0.2}/pydantic_ai/providers/groq.py +0 -0
- {pydantic_ai_slim-1.0.1 → pydantic_ai_slim-1.0.2}/pydantic_ai/providers/heroku.py +0 -0
- {pydantic_ai_slim-1.0.1 → pydantic_ai_slim-1.0.2}/pydantic_ai/providers/huggingface.py +0 -0
- {pydantic_ai_slim-1.0.1 → pydantic_ai_slim-1.0.2}/pydantic_ai/providers/litellm.py +0 -0
- {pydantic_ai_slim-1.0.1 → pydantic_ai_slim-1.0.2}/pydantic_ai/providers/mistral.py +0 -0
- {pydantic_ai_slim-1.0.1 → pydantic_ai_slim-1.0.2}/pydantic_ai/providers/moonshotai.py +0 -0
- {pydantic_ai_slim-1.0.1 → pydantic_ai_slim-1.0.2}/pydantic_ai/providers/ollama.py +0 -0
- {pydantic_ai_slim-1.0.1 → pydantic_ai_slim-1.0.2}/pydantic_ai/providers/openai.py +0 -0
- {pydantic_ai_slim-1.0.1 → pydantic_ai_slim-1.0.2}/pydantic_ai/providers/openrouter.py +0 -0
- {pydantic_ai_slim-1.0.1 → pydantic_ai_slim-1.0.2}/pydantic_ai/providers/together.py +0 -0
- {pydantic_ai_slim-1.0.1 → pydantic_ai_slim-1.0.2}/pydantic_ai/providers/vercel.py +0 -0
- {pydantic_ai_slim-1.0.1 → pydantic_ai_slim-1.0.2}/pydantic_ai/py.typed +0 -0
- {pydantic_ai_slim-1.0.1 → pydantic_ai_slim-1.0.2}/pydantic_ai/result.py +0 -0
- {pydantic_ai_slim-1.0.1 → pydantic_ai_slim-1.0.2}/pydantic_ai/retries.py +0 -0
- {pydantic_ai_slim-1.0.1 → pydantic_ai_slim-1.0.2}/pydantic_ai/run.py +0 -0
- {pydantic_ai_slim-1.0.1 → pydantic_ai_slim-1.0.2}/pydantic_ai/settings.py +0 -0
- {pydantic_ai_slim-1.0.1 → pydantic_ai_slim-1.0.2}/pydantic_ai/toolsets/__init__.py +0 -0
- {pydantic_ai_slim-1.0.1 → pydantic_ai_slim-1.0.2}/pydantic_ai/toolsets/_dynamic.py +0 -0
- {pydantic_ai_slim-1.0.1 → pydantic_ai_slim-1.0.2}/pydantic_ai/toolsets/abstract.py +0 -0
- {pydantic_ai_slim-1.0.1 → pydantic_ai_slim-1.0.2}/pydantic_ai/toolsets/approval_required.py +0 -0
- {pydantic_ai_slim-1.0.1 → pydantic_ai_slim-1.0.2}/pydantic_ai/toolsets/combined.py +0 -0
- {pydantic_ai_slim-1.0.1 → pydantic_ai_slim-1.0.2}/pydantic_ai/toolsets/external.py +0 -0
- {pydantic_ai_slim-1.0.1 → pydantic_ai_slim-1.0.2}/pydantic_ai/toolsets/filtered.py +0 -0
- {pydantic_ai_slim-1.0.1 → pydantic_ai_slim-1.0.2}/pydantic_ai/toolsets/prefixed.py +0 -0
- {pydantic_ai_slim-1.0.1 → pydantic_ai_slim-1.0.2}/pydantic_ai/toolsets/prepared.py +0 -0
- {pydantic_ai_slim-1.0.1 → pydantic_ai_slim-1.0.2}/pydantic_ai/toolsets/renamed.py +0 -0
- {pydantic_ai_slim-1.0.1 → pydantic_ai_slim-1.0.2}/pydantic_ai/toolsets/wrapper.py +0 -0
- {pydantic_ai_slim-1.0.1 → pydantic_ai_slim-1.0.2}/pydantic_ai/usage.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: pydantic-ai-slim
|
|
3
|
-
Version: 1.0.
|
|
3
|
+
Version: 1.0.2
|
|
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
|
|
@@ -29,11 +29,11 @@ Classifier: Topic :: Internet
|
|
|
29
29
|
Classifier: Topic :: Software Development :: Libraries :: Python Modules
|
|
30
30
|
Requires-Python: >=3.10
|
|
31
31
|
Requires-Dist: exceptiongroup; python_version < '3.11'
|
|
32
|
-
Requires-Dist: genai-prices>=0.0.
|
|
32
|
+
Requires-Dist: genai-prices>=0.0.23
|
|
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.0.
|
|
36
|
+
Requires-Dist: pydantic-graph==1.0.2
|
|
37
37
|
Requires-Dist: pydantic>=2.10
|
|
38
38
|
Requires-Dist: typing-inspection>=0.4.0
|
|
39
39
|
Provides-Extra: a2a
|
|
@@ -52,10 +52,12 @@ Requires-Dist: pyperclip>=1.9.0; extra == 'cli'
|
|
|
52
52
|
Requires-Dist: rich>=13; extra == 'cli'
|
|
53
53
|
Provides-Extra: cohere
|
|
54
54
|
Requires-Dist: cohere>=5.16.0; (platform_system != 'Emscripten') and extra == 'cohere'
|
|
55
|
+
Provides-Extra: dbos
|
|
56
|
+
Requires-Dist: dbos>=1.13.0; extra == 'dbos'
|
|
55
57
|
Provides-Extra: duckduckgo
|
|
56
58
|
Requires-Dist: ddgs>=9.0.0; extra == 'duckduckgo'
|
|
57
59
|
Provides-Extra: evals
|
|
58
|
-
Requires-Dist: pydantic-evals==1.0.
|
|
60
|
+
Requires-Dist: pydantic-evals==1.0.2; extra == 'evals'
|
|
59
61
|
Provides-Extra: google
|
|
60
62
|
Requires-Dist: google-genai>=1.31.0; extra == 'google'
|
|
61
63
|
Provides-Extra: groq
|
|
@@ -2,6 +2,8 @@ from __future__ import annotations as _annotations
|
|
|
2
2
|
|
|
3
3
|
import asyncio
|
|
4
4
|
import dataclasses
|
|
5
|
+
import inspect
|
|
6
|
+
from asyncio import Task
|
|
5
7
|
from collections import defaultdict, deque
|
|
6
8
|
from collections.abc import AsyncIterator, Awaitable, Callable, Iterator, Sequence
|
|
7
9
|
from contextlib import asynccontextmanager, contextmanager
|
|
@@ -740,7 +742,6 @@ async def process_function_tools( # noqa: C901
|
|
|
740
742
|
deferred_tool_results: dict[str, DeferredToolResult] = {}
|
|
741
743
|
if build_run_context(ctx).tool_call_approved and ctx.deps.tool_call_results is not None:
|
|
742
744
|
deferred_tool_results = ctx.deps.tool_call_results
|
|
743
|
-
|
|
744
745
|
# Deferred tool calls are "run" as well, by reading their value from the tool call results
|
|
745
746
|
calls_to_run.extend(tool_calls_by_kind['external'])
|
|
746
747
|
calls_to_run.extend(tool_calls_by_kind['unapproved'])
|
|
@@ -819,7 +820,6 @@ async def _call_tools(
|
|
|
819
820
|
for call in tool_calls:
|
|
820
821
|
yield _messages.FunctionToolCallEvent(call)
|
|
821
822
|
|
|
822
|
-
# Run all tool tasks in parallel
|
|
823
823
|
with tracer.start_as_current_span(
|
|
824
824
|
'running tools',
|
|
825
825
|
attributes={
|
|
@@ -827,39 +827,58 @@ async def _call_tools(
|
|
|
827
827
|
'logfire.msg': f'running {len(tool_calls)} tool{"" if len(tool_calls) == 1 else "s"}',
|
|
828
828
|
},
|
|
829
829
|
):
|
|
830
|
-
tasks = [
|
|
831
|
-
asyncio.create_task(
|
|
832
|
-
_call_tool(tool_manager, call, deferred_tool_results.get(call.tool_call_id), usage_limits),
|
|
833
|
-
name=call.tool_name,
|
|
834
|
-
)
|
|
835
|
-
for call in tool_calls
|
|
836
|
-
]
|
|
837
|
-
|
|
838
|
-
pending = tasks
|
|
839
|
-
while pending:
|
|
840
|
-
done, pending = await asyncio.wait(pending, return_when=asyncio.FIRST_COMPLETED)
|
|
841
|
-
for task in done:
|
|
842
|
-
index = tasks.index(task)
|
|
843
|
-
try:
|
|
844
|
-
tool_part, tool_user_part = task.result()
|
|
845
|
-
except exceptions.CallDeferred:
|
|
846
|
-
deferred_calls_by_index[index] = 'external'
|
|
847
|
-
except exceptions.ApprovalRequired:
|
|
848
|
-
deferred_calls_by_index[index] = 'unapproved'
|
|
849
|
-
else:
|
|
850
|
-
yield _messages.FunctionToolResultEvent(tool_part)
|
|
851
830
|
|
|
852
|
-
|
|
853
|
-
|
|
854
|
-
|
|
831
|
+
async def handle_call_or_result(
|
|
832
|
+
coro_or_task: Awaitable[
|
|
833
|
+
tuple[_messages.ToolReturnPart | _messages.RetryPromptPart, _messages.UserPromptPart | None]
|
|
834
|
+
]
|
|
835
|
+
| Task[tuple[_messages.ToolReturnPart | _messages.RetryPromptPart, _messages.UserPromptPart | None]],
|
|
836
|
+
index: int,
|
|
837
|
+
) -> _messages.HandleResponseEvent | None:
|
|
838
|
+
try:
|
|
839
|
+
tool_part, tool_user_part = (
|
|
840
|
+
(await coro_or_task) if inspect.isawaitable(coro_or_task) else coro_or_task.result()
|
|
841
|
+
)
|
|
842
|
+
except exceptions.CallDeferred:
|
|
843
|
+
deferred_calls_by_index[index] = 'external'
|
|
844
|
+
except exceptions.ApprovalRequired:
|
|
845
|
+
deferred_calls_by_index[index] = 'unapproved'
|
|
846
|
+
else:
|
|
847
|
+
tool_parts_by_index[index] = tool_part
|
|
848
|
+
if tool_user_part:
|
|
849
|
+
user_parts_by_index[index] = tool_user_part
|
|
850
|
+
|
|
851
|
+
return _messages.FunctionToolResultEvent(tool_part)
|
|
852
|
+
|
|
853
|
+
if tool_manager.should_call_sequentially(tool_calls):
|
|
854
|
+
for index, call in enumerate(tool_calls):
|
|
855
|
+
if event := await handle_call_or_result(
|
|
856
|
+
_call_tool(tool_manager, call, deferred_tool_results.get(call.tool_call_id), usage_limits),
|
|
857
|
+
index,
|
|
858
|
+
):
|
|
859
|
+
yield event
|
|
860
|
+
|
|
861
|
+
else:
|
|
862
|
+
tasks = [
|
|
863
|
+
asyncio.create_task(
|
|
864
|
+
_call_tool(tool_manager, call, deferred_tool_results.get(call.tool_call_id), usage_limits),
|
|
865
|
+
name=call.tool_name,
|
|
866
|
+
)
|
|
867
|
+
for call in tool_calls
|
|
868
|
+
]
|
|
869
|
+
|
|
870
|
+
pending = tasks
|
|
871
|
+
while pending:
|
|
872
|
+
done, pending = await asyncio.wait(pending, return_when=asyncio.FIRST_COMPLETED)
|
|
873
|
+
for task in done:
|
|
874
|
+
index = tasks.index(task)
|
|
875
|
+
if event := await handle_call_or_result(coro_or_task=task, index=index):
|
|
876
|
+
yield event
|
|
855
877
|
|
|
856
878
|
# We append the results at the end, rather than as they are received, to retain a consistent ordering
|
|
857
879
|
# This is mostly just to simplify testing
|
|
858
|
-
for k in sorted(tool_parts_by_index)
|
|
859
|
-
|
|
860
|
-
|
|
861
|
-
for k in sorted(user_parts_by_index):
|
|
862
|
-
output_parts.append(user_parts_by_index[k])
|
|
880
|
+
output_parts.extend([tool_parts_by_index[k] for k in sorted(tool_parts_by_index)])
|
|
881
|
+
output_parts.extend([user_parts_by_index[k] for k in sorted(user_parts_by_index)])
|
|
863
882
|
|
|
864
883
|
for k in sorted(deferred_calls_by_index):
|
|
865
884
|
output_deferred_calls[deferred_calls_by_index[k]].append(tool_calls[k])
|
|
@@ -56,6 +56,10 @@ class ToolManager(Generic[AgentDepsT]):
|
|
|
56
56
|
|
|
57
57
|
return [tool.tool_def for tool in self.tools.values()]
|
|
58
58
|
|
|
59
|
+
def should_call_sequentially(self, calls: list[ToolCallPart]) -> bool:
|
|
60
|
+
"""Whether to require sequential tool calls for a list of tool calls."""
|
|
61
|
+
return any(tool_def.sequential for call in calls if (tool_def := self.get_tool_def(call.tool_name)))
|
|
62
|
+
|
|
59
63
|
def get_tool_def(self, name: str) -> ToolDefinition | None:
|
|
60
64
|
"""Get the tool definition for a given tool name, or `None` if the tool is unknown."""
|
|
61
65
|
if self.tools is None:
|
|
@@ -1119,6 +1119,7 @@ class Agent(AbstractAgent[AgentDepsT, OutputDataT]):
|
|
|
1119
1119
|
require_parameter_descriptions: bool = False,
|
|
1120
1120
|
schema_generator: type[GenerateJsonSchema] = GenerateToolJsonSchema,
|
|
1121
1121
|
strict: bool | None = None,
|
|
1122
|
+
sequential: bool = False,
|
|
1122
1123
|
requires_approval: bool = False,
|
|
1123
1124
|
) -> Any:
|
|
1124
1125
|
"""Decorator to register a tool function which DOES NOT take `RunContext` as an argument.
|
|
@@ -1164,6 +1165,7 @@ class Agent(AbstractAgent[AgentDepsT, OutputDataT]):
|
|
|
1164
1165
|
schema_generator: The JSON schema generator class to use for this tool. Defaults to `GenerateToolJsonSchema`.
|
|
1165
1166
|
strict: Whether to enforce JSON schema compliance (only affects OpenAI).
|
|
1166
1167
|
See [`ToolDefinition`][pydantic_ai.tools.ToolDefinition] for more info.
|
|
1168
|
+
sequential: Whether the function requires a sequential/serial execution environment. Defaults to False.
|
|
1167
1169
|
requires_approval: Whether this tool requires human-in-the-loop approval. Defaults to False.
|
|
1168
1170
|
See the [tools documentation](../deferred-tools.md#human-in-the-loop-tool-approval) for more info.
|
|
1169
1171
|
"""
|
|
@@ -1180,6 +1182,7 @@ class Agent(AbstractAgent[AgentDepsT, OutputDataT]):
|
|
|
1180
1182
|
require_parameter_descriptions,
|
|
1181
1183
|
schema_generator,
|
|
1182
1184
|
strict,
|
|
1185
|
+
sequential,
|
|
1183
1186
|
requires_approval,
|
|
1184
1187
|
)
|
|
1185
1188
|
return func_
|