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.

Files changed (126) hide show
  1. {pydantic_ai_slim-1.0.1 → pydantic_ai_slim-1.0.2}/PKG-INFO +6 -4
  2. {pydantic_ai_slim-1.0.1 → pydantic_ai_slim-1.0.2}/pydantic_ai/_agent_graph.py +50 -31
  3. {pydantic_ai_slim-1.0.1 → pydantic_ai_slim-1.0.2}/pydantic_ai/_tool_manager.py +4 -0
  4. {pydantic_ai_slim-1.0.1 → pydantic_ai_slim-1.0.2}/pydantic_ai/agent/__init__.py +3 -0
  5. pydantic_ai_slim-1.0.2/pydantic_ai/durable_exec/dbos/__init__.py +6 -0
  6. pydantic_ai_slim-1.0.2/pydantic_ai/durable_exec/dbos/_agent.py +718 -0
  7. pydantic_ai_slim-1.0.2/pydantic_ai/durable_exec/dbos/_mcp_server.py +89 -0
  8. pydantic_ai_slim-1.0.2/pydantic_ai/durable_exec/dbos/_model.py +137 -0
  9. pydantic_ai_slim-1.0.2/pydantic_ai/durable_exec/dbos/_utils.py +10 -0
  10. {pydantic_ai_slim-1.0.1 → pydantic_ai_slim-1.0.2}/pydantic_ai/mcp.py +1 -1
  11. {pydantic_ai_slim-1.0.1 → pydantic_ai_slim-1.0.2}/pydantic_ai/messages.py +12 -0
  12. {pydantic_ai_slim-1.0.1 → pydantic_ai_slim-1.0.2}/pydantic_ai/models/__init__.py +8 -0
  13. {pydantic_ai_slim-1.0.1 → pydantic_ai_slim-1.0.2}/pydantic_ai/models/anthropic.py +24 -0
  14. {pydantic_ai_slim-1.0.1 → pydantic_ai_slim-1.0.2}/pydantic_ai/models/google.py +43 -4
  15. {pydantic_ai_slim-1.0.1 → pydantic_ai_slim-1.0.2}/pydantic_ai/models/instrumented.py +27 -14
  16. {pydantic_ai_slim-1.0.1 → pydantic_ai_slim-1.0.2}/pydantic_ai/models/openai.py +67 -16
  17. {pydantic_ai_slim-1.0.1 → pydantic_ai_slim-1.0.2}/pydantic_ai/providers/bedrock.py +11 -3
  18. {pydantic_ai_slim-1.0.1 → pydantic_ai_slim-1.0.2}/pydantic_ai/tools.py +11 -0
  19. {pydantic_ai_slim-1.0.1 → pydantic_ai_slim-1.0.2}/pydantic_ai/toolsets/function.py +7 -0
  20. {pydantic_ai_slim-1.0.1 → pydantic_ai_slim-1.0.2}/pyproject.toml +3 -1
  21. {pydantic_ai_slim-1.0.1 → pydantic_ai_slim-1.0.2}/.gitignore +0 -0
  22. {pydantic_ai_slim-1.0.1 → pydantic_ai_slim-1.0.2}/LICENSE +0 -0
  23. {pydantic_ai_slim-1.0.1 → pydantic_ai_slim-1.0.2}/README.md +0 -0
  24. {pydantic_ai_slim-1.0.1 → pydantic_ai_slim-1.0.2}/pydantic_ai/__init__.py +0 -0
  25. {pydantic_ai_slim-1.0.1 → pydantic_ai_slim-1.0.2}/pydantic_ai/__main__.py +0 -0
  26. {pydantic_ai_slim-1.0.1 → pydantic_ai_slim-1.0.2}/pydantic_ai/_a2a.py +0 -0
  27. {pydantic_ai_slim-1.0.1 → pydantic_ai_slim-1.0.2}/pydantic_ai/_cli.py +0 -0
  28. {pydantic_ai_slim-1.0.1 → pydantic_ai_slim-1.0.2}/pydantic_ai/_function_schema.py +0 -0
  29. {pydantic_ai_slim-1.0.1 → pydantic_ai_slim-1.0.2}/pydantic_ai/_griffe.py +0 -0
  30. {pydantic_ai_slim-1.0.1 → pydantic_ai_slim-1.0.2}/pydantic_ai/_mcp.py +0 -0
  31. {pydantic_ai_slim-1.0.1 → pydantic_ai_slim-1.0.2}/pydantic_ai/_otel_messages.py +0 -0
  32. {pydantic_ai_slim-1.0.1 → pydantic_ai_slim-1.0.2}/pydantic_ai/_output.py +0 -0
  33. {pydantic_ai_slim-1.0.1 → pydantic_ai_slim-1.0.2}/pydantic_ai/_parts_manager.py +0 -0
  34. {pydantic_ai_slim-1.0.1 → pydantic_ai_slim-1.0.2}/pydantic_ai/_run_context.py +0 -0
  35. {pydantic_ai_slim-1.0.1 → pydantic_ai_slim-1.0.2}/pydantic_ai/_system_prompt.py +0 -0
  36. {pydantic_ai_slim-1.0.1 → pydantic_ai_slim-1.0.2}/pydantic_ai/_thinking_part.py +0 -0
  37. {pydantic_ai_slim-1.0.1 → pydantic_ai_slim-1.0.2}/pydantic_ai/_utils.py +0 -0
  38. {pydantic_ai_slim-1.0.1 → pydantic_ai_slim-1.0.2}/pydantic_ai/ag_ui.py +0 -0
  39. {pydantic_ai_slim-1.0.1 → pydantic_ai_slim-1.0.2}/pydantic_ai/agent/abstract.py +0 -0
  40. {pydantic_ai_slim-1.0.1 → pydantic_ai_slim-1.0.2}/pydantic_ai/agent/wrapper.py +0 -0
  41. {pydantic_ai_slim-1.0.1 → pydantic_ai_slim-1.0.2}/pydantic_ai/builtin_tools.py +0 -0
  42. {pydantic_ai_slim-1.0.1 → pydantic_ai_slim-1.0.2}/pydantic_ai/common_tools/__init__.py +0 -0
  43. {pydantic_ai_slim-1.0.1 → pydantic_ai_slim-1.0.2}/pydantic_ai/common_tools/duckduckgo.py +0 -0
  44. {pydantic_ai_slim-1.0.1 → pydantic_ai_slim-1.0.2}/pydantic_ai/common_tools/tavily.py +0 -0
  45. {pydantic_ai_slim-1.0.1 → pydantic_ai_slim-1.0.2}/pydantic_ai/direct.py +0 -0
  46. {pydantic_ai_slim-1.0.1 → pydantic_ai_slim-1.0.2}/pydantic_ai/durable_exec/__init__.py +0 -0
  47. {pydantic_ai_slim-1.0.1 → pydantic_ai_slim-1.0.2}/pydantic_ai/durable_exec/temporal/__init__.py +0 -0
  48. {pydantic_ai_slim-1.0.1 → pydantic_ai_slim-1.0.2}/pydantic_ai/durable_exec/temporal/_agent.py +0 -0
  49. {pydantic_ai_slim-1.0.1 → pydantic_ai_slim-1.0.2}/pydantic_ai/durable_exec/temporal/_function_toolset.py +0 -0
  50. {pydantic_ai_slim-1.0.1 → pydantic_ai_slim-1.0.2}/pydantic_ai/durable_exec/temporal/_logfire.py +0 -0
  51. {pydantic_ai_slim-1.0.1 → pydantic_ai_slim-1.0.2}/pydantic_ai/durable_exec/temporal/_mcp_server.py +0 -0
  52. {pydantic_ai_slim-1.0.1 → pydantic_ai_slim-1.0.2}/pydantic_ai/durable_exec/temporal/_model.py +0 -0
  53. {pydantic_ai_slim-1.0.1 → pydantic_ai_slim-1.0.2}/pydantic_ai/durable_exec/temporal/_run_context.py +0 -0
  54. {pydantic_ai_slim-1.0.1 → pydantic_ai_slim-1.0.2}/pydantic_ai/durable_exec/temporal/_toolset.py +0 -0
  55. {pydantic_ai_slim-1.0.1 → pydantic_ai_slim-1.0.2}/pydantic_ai/exceptions.py +0 -0
  56. {pydantic_ai_slim-1.0.1 → pydantic_ai_slim-1.0.2}/pydantic_ai/ext/__init__.py +0 -0
  57. {pydantic_ai_slim-1.0.1 → pydantic_ai_slim-1.0.2}/pydantic_ai/ext/aci.py +0 -0
  58. {pydantic_ai_slim-1.0.1 → pydantic_ai_slim-1.0.2}/pydantic_ai/ext/langchain.py +0 -0
  59. {pydantic_ai_slim-1.0.1 → pydantic_ai_slim-1.0.2}/pydantic_ai/format_prompt.py +0 -0
  60. {pydantic_ai_slim-1.0.1 → pydantic_ai_slim-1.0.2}/pydantic_ai/models/bedrock.py +0 -0
  61. {pydantic_ai_slim-1.0.1 → pydantic_ai_slim-1.0.2}/pydantic_ai/models/cohere.py +0 -0
  62. {pydantic_ai_slim-1.0.1 → pydantic_ai_slim-1.0.2}/pydantic_ai/models/fallback.py +0 -0
  63. {pydantic_ai_slim-1.0.1 → pydantic_ai_slim-1.0.2}/pydantic_ai/models/function.py +0 -0
  64. {pydantic_ai_slim-1.0.1 → pydantic_ai_slim-1.0.2}/pydantic_ai/models/gemini.py +0 -0
  65. {pydantic_ai_slim-1.0.1 → pydantic_ai_slim-1.0.2}/pydantic_ai/models/groq.py +0 -0
  66. {pydantic_ai_slim-1.0.1 → pydantic_ai_slim-1.0.2}/pydantic_ai/models/huggingface.py +0 -0
  67. {pydantic_ai_slim-1.0.1 → pydantic_ai_slim-1.0.2}/pydantic_ai/models/mcp_sampling.py +0 -0
  68. {pydantic_ai_slim-1.0.1 → pydantic_ai_slim-1.0.2}/pydantic_ai/models/mistral.py +0 -0
  69. {pydantic_ai_slim-1.0.1 → pydantic_ai_slim-1.0.2}/pydantic_ai/models/test.py +0 -0
  70. {pydantic_ai_slim-1.0.1 → pydantic_ai_slim-1.0.2}/pydantic_ai/models/wrapper.py +0 -0
  71. {pydantic_ai_slim-1.0.1 → pydantic_ai_slim-1.0.2}/pydantic_ai/output.py +0 -0
  72. {pydantic_ai_slim-1.0.1 → pydantic_ai_slim-1.0.2}/pydantic_ai/profiles/__init__.py +0 -0
  73. {pydantic_ai_slim-1.0.1 → pydantic_ai_slim-1.0.2}/pydantic_ai/profiles/_json_schema.py +0 -0
  74. {pydantic_ai_slim-1.0.1 → pydantic_ai_slim-1.0.2}/pydantic_ai/profiles/amazon.py +0 -0
  75. {pydantic_ai_slim-1.0.1 → pydantic_ai_slim-1.0.2}/pydantic_ai/profiles/anthropic.py +0 -0
  76. {pydantic_ai_slim-1.0.1 → pydantic_ai_slim-1.0.2}/pydantic_ai/profiles/cohere.py +0 -0
  77. {pydantic_ai_slim-1.0.1 → pydantic_ai_slim-1.0.2}/pydantic_ai/profiles/deepseek.py +0 -0
  78. {pydantic_ai_slim-1.0.1 → pydantic_ai_slim-1.0.2}/pydantic_ai/profiles/google.py +0 -0
  79. {pydantic_ai_slim-1.0.1 → pydantic_ai_slim-1.0.2}/pydantic_ai/profiles/grok.py +0 -0
  80. {pydantic_ai_slim-1.0.1 → pydantic_ai_slim-1.0.2}/pydantic_ai/profiles/groq.py +0 -0
  81. {pydantic_ai_slim-1.0.1 → pydantic_ai_slim-1.0.2}/pydantic_ai/profiles/harmony.py +0 -0
  82. {pydantic_ai_slim-1.0.1 → pydantic_ai_slim-1.0.2}/pydantic_ai/profiles/meta.py +0 -0
  83. {pydantic_ai_slim-1.0.1 → pydantic_ai_slim-1.0.2}/pydantic_ai/profiles/mistral.py +0 -0
  84. {pydantic_ai_slim-1.0.1 → pydantic_ai_slim-1.0.2}/pydantic_ai/profiles/moonshotai.py +0 -0
  85. {pydantic_ai_slim-1.0.1 → pydantic_ai_slim-1.0.2}/pydantic_ai/profiles/openai.py +0 -0
  86. {pydantic_ai_slim-1.0.1 → pydantic_ai_slim-1.0.2}/pydantic_ai/profiles/qwen.py +0 -0
  87. {pydantic_ai_slim-1.0.1 → pydantic_ai_slim-1.0.2}/pydantic_ai/providers/__init__.py +0 -0
  88. {pydantic_ai_slim-1.0.1 → pydantic_ai_slim-1.0.2}/pydantic_ai/providers/anthropic.py +0 -0
  89. {pydantic_ai_slim-1.0.1 → pydantic_ai_slim-1.0.2}/pydantic_ai/providers/azure.py +0 -0
  90. {pydantic_ai_slim-1.0.1 → pydantic_ai_slim-1.0.2}/pydantic_ai/providers/cerebras.py +0 -0
  91. {pydantic_ai_slim-1.0.1 → pydantic_ai_slim-1.0.2}/pydantic_ai/providers/cohere.py +0 -0
  92. {pydantic_ai_slim-1.0.1 → pydantic_ai_slim-1.0.2}/pydantic_ai/providers/deepseek.py +0 -0
  93. {pydantic_ai_slim-1.0.1 → pydantic_ai_slim-1.0.2}/pydantic_ai/providers/fireworks.py +0 -0
  94. {pydantic_ai_slim-1.0.1 → pydantic_ai_slim-1.0.2}/pydantic_ai/providers/github.py +0 -0
  95. {pydantic_ai_slim-1.0.1 → pydantic_ai_slim-1.0.2}/pydantic_ai/providers/google.py +0 -0
  96. {pydantic_ai_slim-1.0.1 → pydantic_ai_slim-1.0.2}/pydantic_ai/providers/google_gla.py +0 -0
  97. {pydantic_ai_slim-1.0.1 → pydantic_ai_slim-1.0.2}/pydantic_ai/providers/google_vertex.py +0 -0
  98. {pydantic_ai_slim-1.0.1 → pydantic_ai_slim-1.0.2}/pydantic_ai/providers/grok.py +0 -0
  99. {pydantic_ai_slim-1.0.1 → pydantic_ai_slim-1.0.2}/pydantic_ai/providers/groq.py +0 -0
  100. {pydantic_ai_slim-1.0.1 → pydantic_ai_slim-1.0.2}/pydantic_ai/providers/heroku.py +0 -0
  101. {pydantic_ai_slim-1.0.1 → pydantic_ai_slim-1.0.2}/pydantic_ai/providers/huggingface.py +0 -0
  102. {pydantic_ai_slim-1.0.1 → pydantic_ai_slim-1.0.2}/pydantic_ai/providers/litellm.py +0 -0
  103. {pydantic_ai_slim-1.0.1 → pydantic_ai_slim-1.0.2}/pydantic_ai/providers/mistral.py +0 -0
  104. {pydantic_ai_slim-1.0.1 → pydantic_ai_slim-1.0.2}/pydantic_ai/providers/moonshotai.py +0 -0
  105. {pydantic_ai_slim-1.0.1 → pydantic_ai_slim-1.0.2}/pydantic_ai/providers/ollama.py +0 -0
  106. {pydantic_ai_slim-1.0.1 → pydantic_ai_slim-1.0.2}/pydantic_ai/providers/openai.py +0 -0
  107. {pydantic_ai_slim-1.0.1 → pydantic_ai_slim-1.0.2}/pydantic_ai/providers/openrouter.py +0 -0
  108. {pydantic_ai_slim-1.0.1 → pydantic_ai_slim-1.0.2}/pydantic_ai/providers/together.py +0 -0
  109. {pydantic_ai_slim-1.0.1 → pydantic_ai_slim-1.0.2}/pydantic_ai/providers/vercel.py +0 -0
  110. {pydantic_ai_slim-1.0.1 → pydantic_ai_slim-1.0.2}/pydantic_ai/py.typed +0 -0
  111. {pydantic_ai_slim-1.0.1 → pydantic_ai_slim-1.0.2}/pydantic_ai/result.py +0 -0
  112. {pydantic_ai_slim-1.0.1 → pydantic_ai_slim-1.0.2}/pydantic_ai/retries.py +0 -0
  113. {pydantic_ai_slim-1.0.1 → pydantic_ai_slim-1.0.2}/pydantic_ai/run.py +0 -0
  114. {pydantic_ai_slim-1.0.1 → pydantic_ai_slim-1.0.2}/pydantic_ai/settings.py +0 -0
  115. {pydantic_ai_slim-1.0.1 → pydantic_ai_slim-1.0.2}/pydantic_ai/toolsets/__init__.py +0 -0
  116. {pydantic_ai_slim-1.0.1 → pydantic_ai_slim-1.0.2}/pydantic_ai/toolsets/_dynamic.py +0 -0
  117. {pydantic_ai_slim-1.0.1 → pydantic_ai_slim-1.0.2}/pydantic_ai/toolsets/abstract.py +0 -0
  118. {pydantic_ai_slim-1.0.1 → pydantic_ai_slim-1.0.2}/pydantic_ai/toolsets/approval_required.py +0 -0
  119. {pydantic_ai_slim-1.0.1 → pydantic_ai_slim-1.0.2}/pydantic_ai/toolsets/combined.py +0 -0
  120. {pydantic_ai_slim-1.0.1 → pydantic_ai_slim-1.0.2}/pydantic_ai/toolsets/external.py +0 -0
  121. {pydantic_ai_slim-1.0.1 → pydantic_ai_slim-1.0.2}/pydantic_ai/toolsets/filtered.py +0 -0
  122. {pydantic_ai_slim-1.0.1 → pydantic_ai_slim-1.0.2}/pydantic_ai/toolsets/prefixed.py +0 -0
  123. {pydantic_ai_slim-1.0.1 → pydantic_ai_slim-1.0.2}/pydantic_ai/toolsets/prepared.py +0 -0
  124. {pydantic_ai_slim-1.0.1 → pydantic_ai_slim-1.0.2}/pydantic_ai/toolsets/renamed.py +0 -0
  125. {pydantic_ai_slim-1.0.1 → pydantic_ai_slim-1.0.2}/pydantic_ai/toolsets/wrapper.py +0 -0
  126. {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.1
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.22
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.1
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.1; extra == 'evals'
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
- tool_parts_by_index[index] = tool_part
853
- if tool_user_part:
854
- user_parts_by_index[index] = tool_user_part
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
- output_parts.append(tool_parts_by_index[k])
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_
@@ -0,0 +1,6 @@
1
+ from ._agent import DBOSAgent
2
+ from ._mcp_server import DBOSMCPServer
3
+ from ._model import DBOSModel
4
+ from ._utils import StepConfig
5
+
6
+ __all__ = ['DBOSAgent', 'DBOSModel', 'DBOSMCPServer', 'StepConfig']