pydantic-ai-slim 1.4.0__tar.gz → 1.5.0__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 (138) hide show
  1. {pydantic_ai_slim-1.4.0 → pydantic_ai_slim-1.5.0}/PKG-INFO +3 -3
  2. {pydantic_ai_slim-1.4.0 → pydantic_ai_slim-1.5.0}/pydantic_ai/_agent_graph.py +23 -12
  3. {pydantic_ai_slim-1.4.0 → pydantic_ai_slim-1.5.0}/pydantic_ai/_utils.py +8 -8
  4. {pydantic_ai_slim-1.4.0 → pydantic_ai_slim-1.5.0}/pydantic_ai/agent/__init__.py +3 -7
  5. {pydantic_ai_slim-1.4.0 → pydantic_ai_slim-1.5.0}/pydantic_ai/durable_exec/temporal/__init__.py +11 -0
  6. {pydantic_ai_slim-1.4.0 → pydantic_ai_slim-1.5.0}/pydantic_ai/durable_exec/temporal/_function_toolset.py +2 -1
  7. {pydantic_ai_slim-1.4.0 → pydantic_ai_slim-1.5.0}/pydantic_ai/exceptions.py +1 -1
  8. {pydantic_ai_slim-1.4.0 → pydantic_ai_slim-1.5.0}/pydantic_ai/messages.py +1 -1
  9. {pydantic_ai_slim-1.4.0 → pydantic_ai_slim-1.5.0}/pydantic_ai/providers/google.py +31 -2
  10. {pydantic_ai_slim-1.4.0 → pydantic_ai_slim-1.5.0}/pydantic_ai/run.py +40 -24
  11. {pydantic_ai_slim-1.4.0 → pydantic_ai_slim-1.5.0}/.gitignore +0 -0
  12. {pydantic_ai_slim-1.4.0 → pydantic_ai_slim-1.5.0}/LICENSE +0 -0
  13. {pydantic_ai_slim-1.4.0 → pydantic_ai_slim-1.5.0}/README.md +0 -0
  14. {pydantic_ai_slim-1.4.0 → pydantic_ai_slim-1.5.0}/pydantic_ai/__init__.py +0 -0
  15. {pydantic_ai_slim-1.4.0 → pydantic_ai_slim-1.5.0}/pydantic_ai/__main__.py +0 -0
  16. {pydantic_ai_slim-1.4.0 → pydantic_ai_slim-1.5.0}/pydantic_ai/_a2a.py +0 -0
  17. {pydantic_ai_slim-1.4.0 → pydantic_ai_slim-1.5.0}/pydantic_ai/_cli.py +0 -0
  18. {pydantic_ai_slim-1.4.0 → pydantic_ai_slim-1.5.0}/pydantic_ai/_function_schema.py +0 -0
  19. {pydantic_ai_slim-1.4.0 → pydantic_ai_slim-1.5.0}/pydantic_ai/_griffe.py +0 -0
  20. {pydantic_ai_slim-1.4.0 → pydantic_ai_slim-1.5.0}/pydantic_ai/_instrumentation.py +0 -0
  21. {pydantic_ai_slim-1.4.0 → pydantic_ai_slim-1.5.0}/pydantic_ai/_json_schema.py +0 -0
  22. {pydantic_ai_slim-1.4.0 → pydantic_ai_slim-1.5.0}/pydantic_ai/_mcp.py +0 -0
  23. {pydantic_ai_slim-1.4.0 → pydantic_ai_slim-1.5.0}/pydantic_ai/_otel_messages.py +0 -0
  24. {pydantic_ai_slim-1.4.0 → pydantic_ai_slim-1.5.0}/pydantic_ai/_output.py +0 -0
  25. {pydantic_ai_slim-1.4.0 → pydantic_ai_slim-1.5.0}/pydantic_ai/_parts_manager.py +0 -0
  26. {pydantic_ai_slim-1.4.0 → pydantic_ai_slim-1.5.0}/pydantic_ai/_run_context.py +0 -0
  27. {pydantic_ai_slim-1.4.0 → pydantic_ai_slim-1.5.0}/pydantic_ai/_system_prompt.py +0 -0
  28. {pydantic_ai_slim-1.4.0 → pydantic_ai_slim-1.5.0}/pydantic_ai/_thinking_part.py +0 -0
  29. {pydantic_ai_slim-1.4.0 → pydantic_ai_slim-1.5.0}/pydantic_ai/_tool_manager.py +0 -0
  30. {pydantic_ai_slim-1.4.0 → pydantic_ai_slim-1.5.0}/pydantic_ai/ag_ui.py +0 -0
  31. {pydantic_ai_slim-1.4.0 → pydantic_ai_slim-1.5.0}/pydantic_ai/agent/abstract.py +0 -0
  32. {pydantic_ai_slim-1.4.0 → pydantic_ai_slim-1.5.0}/pydantic_ai/agent/wrapper.py +0 -0
  33. {pydantic_ai_slim-1.4.0 → pydantic_ai_slim-1.5.0}/pydantic_ai/builtin_tools.py +0 -0
  34. {pydantic_ai_slim-1.4.0 → pydantic_ai_slim-1.5.0}/pydantic_ai/common_tools/__init__.py +0 -0
  35. {pydantic_ai_slim-1.4.0 → pydantic_ai_slim-1.5.0}/pydantic_ai/common_tools/duckduckgo.py +0 -0
  36. {pydantic_ai_slim-1.4.0 → pydantic_ai_slim-1.5.0}/pydantic_ai/common_tools/tavily.py +0 -0
  37. {pydantic_ai_slim-1.4.0 → pydantic_ai_slim-1.5.0}/pydantic_ai/direct.py +0 -0
  38. {pydantic_ai_slim-1.4.0 → pydantic_ai_slim-1.5.0}/pydantic_ai/durable_exec/__init__.py +0 -0
  39. {pydantic_ai_slim-1.4.0 → pydantic_ai_slim-1.5.0}/pydantic_ai/durable_exec/dbos/__init__.py +0 -0
  40. {pydantic_ai_slim-1.4.0 → pydantic_ai_slim-1.5.0}/pydantic_ai/durable_exec/dbos/_agent.py +0 -0
  41. {pydantic_ai_slim-1.4.0 → pydantic_ai_slim-1.5.0}/pydantic_ai/durable_exec/dbos/_mcp_server.py +0 -0
  42. {pydantic_ai_slim-1.4.0 → pydantic_ai_slim-1.5.0}/pydantic_ai/durable_exec/dbos/_model.py +0 -0
  43. {pydantic_ai_slim-1.4.0 → pydantic_ai_slim-1.5.0}/pydantic_ai/durable_exec/dbos/_utils.py +0 -0
  44. {pydantic_ai_slim-1.4.0 → pydantic_ai_slim-1.5.0}/pydantic_ai/durable_exec/prefect/__init__.py +0 -0
  45. {pydantic_ai_slim-1.4.0 → pydantic_ai_slim-1.5.0}/pydantic_ai/durable_exec/prefect/_agent.py +0 -0
  46. {pydantic_ai_slim-1.4.0 → pydantic_ai_slim-1.5.0}/pydantic_ai/durable_exec/prefect/_cache_policies.py +0 -0
  47. {pydantic_ai_slim-1.4.0 → pydantic_ai_slim-1.5.0}/pydantic_ai/durable_exec/prefect/_function_toolset.py +0 -0
  48. {pydantic_ai_slim-1.4.0 → pydantic_ai_slim-1.5.0}/pydantic_ai/durable_exec/prefect/_mcp_server.py +0 -0
  49. {pydantic_ai_slim-1.4.0 → pydantic_ai_slim-1.5.0}/pydantic_ai/durable_exec/prefect/_model.py +0 -0
  50. {pydantic_ai_slim-1.4.0 → pydantic_ai_slim-1.5.0}/pydantic_ai/durable_exec/prefect/_toolset.py +0 -0
  51. {pydantic_ai_slim-1.4.0 → pydantic_ai_slim-1.5.0}/pydantic_ai/durable_exec/prefect/_types.py +0 -0
  52. {pydantic_ai_slim-1.4.0 → pydantic_ai_slim-1.5.0}/pydantic_ai/durable_exec/temporal/_agent.py +0 -0
  53. {pydantic_ai_slim-1.4.0 → pydantic_ai_slim-1.5.0}/pydantic_ai/durable_exec/temporal/_logfire.py +0 -0
  54. {pydantic_ai_slim-1.4.0 → pydantic_ai_slim-1.5.0}/pydantic_ai/durable_exec/temporal/_mcp_server.py +0 -0
  55. {pydantic_ai_slim-1.4.0 → pydantic_ai_slim-1.5.0}/pydantic_ai/durable_exec/temporal/_model.py +0 -0
  56. {pydantic_ai_slim-1.4.0 → pydantic_ai_slim-1.5.0}/pydantic_ai/durable_exec/temporal/_run_context.py +0 -0
  57. {pydantic_ai_slim-1.4.0 → pydantic_ai_slim-1.5.0}/pydantic_ai/durable_exec/temporal/_toolset.py +0 -0
  58. {pydantic_ai_slim-1.4.0 → pydantic_ai_slim-1.5.0}/pydantic_ai/ext/__init__.py +0 -0
  59. {pydantic_ai_slim-1.4.0 → pydantic_ai_slim-1.5.0}/pydantic_ai/ext/aci.py +0 -0
  60. {pydantic_ai_slim-1.4.0 → pydantic_ai_slim-1.5.0}/pydantic_ai/ext/langchain.py +0 -0
  61. {pydantic_ai_slim-1.4.0 → pydantic_ai_slim-1.5.0}/pydantic_ai/format_prompt.py +0 -0
  62. {pydantic_ai_slim-1.4.0 → pydantic_ai_slim-1.5.0}/pydantic_ai/mcp.py +0 -0
  63. {pydantic_ai_slim-1.4.0 → pydantic_ai_slim-1.5.0}/pydantic_ai/models/__init__.py +0 -0
  64. {pydantic_ai_slim-1.4.0 → pydantic_ai_slim-1.5.0}/pydantic_ai/models/anthropic.py +0 -0
  65. {pydantic_ai_slim-1.4.0 → pydantic_ai_slim-1.5.0}/pydantic_ai/models/bedrock.py +0 -0
  66. {pydantic_ai_slim-1.4.0 → pydantic_ai_slim-1.5.0}/pydantic_ai/models/cohere.py +0 -0
  67. {pydantic_ai_slim-1.4.0 → pydantic_ai_slim-1.5.0}/pydantic_ai/models/fallback.py +0 -0
  68. {pydantic_ai_slim-1.4.0 → pydantic_ai_slim-1.5.0}/pydantic_ai/models/function.py +0 -0
  69. {pydantic_ai_slim-1.4.0 → pydantic_ai_slim-1.5.0}/pydantic_ai/models/gemini.py +0 -0
  70. {pydantic_ai_slim-1.4.0 → pydantic_ai_slim-1.5.0}/pydantic_ai/models/google.py +0 -0
  71. {pydantic_ai_slim-1.4.0 → pydantic_ai_slim-1.5.0}/pydantic_ai/models/groq.py +0 -0
  72. {pydantic_ai_slim-1.4.0 → pydantic_ai_slim-1.5.0}/pydantic_ai/models/huggingface.py +0 -0
  73. {pydantic_ai_slim-1.4.0 → pydantic_ai_slim-1.5.0}/pydantic_ai/models/instrumented.py +0 -0
  74. {pydantic_ai_slim-1.4.0 → pydantic_ai_slim-1.5.0}/pydantic_ai/models/mcp_sampling.py +0 -0
  75. {pydantic_ai_slim-1.4.0 → pydantic_ai_slim-1.5.0}/pydantic_ai/models/mistral.py +0 -0
  76. {pydantic_ai_slim-1.4.0 → pydantic_ai_slim-1.5.0}/pydantic_ai/models/openai.py +0 -0
  77. {pydantic_ai_slim-1.4.0 → pydantic_ai_slim-1.5.0}/pydantic_ai/models/test.py +0 -0
  78. {pydantic_ai_slim-1.4.0 → pydantic_ai_slim-1.5.0}/pydantic_ai/models/wrapper.py +0 -0
  79. {pydantic_ai_slim-1.4.0 → pydantic_ai_slim-1.5.0}/pydantic_ai/output.py +0 -0
  80. {pydantic_ai_slim-1.4.0 → pydantic_ai_slim-1.5.0}/pydantic_ai/profiles/__init__.py +0 -0
  81. {pydantic_ai_slim-1.4.0 → pydantic_ai_slim-1.5.0}/pydantic_ai/profiles/amazon.py +0 -0
  82. {pydantic_ai_slim-1.4.0 → pydantic_ai_slim-1.5.0}/pydantic_ai/profiles/anthropic.py +0 -0
  83. {pydantic_ai_slim-1.4.0 → pydantic_ai_slim-1.5.0}/pydantic_ai/profiles/cohere.py +0 -0
  84. {pydantic_ai_slim-1.4.0 → pydantic_ai_slim-1.5.0}/pydantic_ai/profiles/deepseek.py +0 -0
  85. {pydantic_ai_slim-1.4.0 → pydantic_ai_slim-1.5.0}/pydantic_ai/profiles/google.py +0 -0
  86. {pydantic_ai_slim-1.4.0 → pydantic_ai_slim-1.5.0}/pydantic_ai/profiles/grok.py +0 -0
  87. {pydantic_ai_slim-1.4.0 → pydantic_ai_slim-1.5.0}/pydantic_ai/profiles/groq.py +0 -0
  88. {pydantic_ai_slim-1.4.0 → pydantic_ai_slim-1.5.0}/pydantic_ai/profiles/harmony.py +0 -0
  89. {pydantic_ai_slim-1.4.0 → pydantic_ai_slim-1.5.0}/pydantic_ai/profiles/meta.py +0 -0
  90. {pydantic_ai_slim-1.4.0 → pydantic_ai_slim-1.5.0}/pydantic_ai/profiles/mistral.py +0 -0
  91. {pydantic_ai_slim-1.4.0 → pydantic_ai_slim-1.5.0}/pydantic_ai/profiles/moonshotai.py +0 -0
  92. {pydantic_ai_slim-1.4.0 → pydantic_ai_slim-1.5.0}/pydantic_ai/profiles/openai.py +0 -0
  93. {pydantic_ai_slim-1.4.0 → pydantic_ai_slim-1.5.0}/pydantic_ai/profiles/qwen.py +0 -0
  94. {pydantic_ai_slim-1.4.0 → pydantic_ai_slim-1.5.0}/pydantic_ai/providers/__init__.py +0 -0
  95. {pydantic_ai_slim-1.4.0 → pydantic_ai_slim-1.5.0}/pydantic_ai/providers/anthropic.py +0 -0
  96. {pydantic_ai_slim-1.4.0 → pydantic_ai_slim-1.5.0}/pydantic_ai/providers/azure.py +0 -0
  97. {pydantic_ai_slim-1.4.0 → pydantic_ai_slim-1.5.0}/pydantic_ai/providers/bedrock.py +0 -0
  98. {pydantic_ai_slim-1.4.0 → pydantic_ai_slim-1.5.0}/pydantic_ai/providers/cerebras.py +0 -0
  99. {pydantic_ai_slim-1.4.0 → pydantic_ai_slim-1.5.0}/pydantic_ai/providers/cohere.py +0 -0
  100. {pydantic_ai_slim-1.4.0 → pydantic_ai_slim-1.5.0}/pydantic_ai/providers/deepseek.py +0 -0
  101. {pydantic_ai_slim-1.4.0 → pydantic_ai_slim-1.5.0}/pydantic_ai/providers/fireworks.py +0 -0
  102. {pydantic_ai_slim-1.4.0 → pydantic_ai_slim-1.5.0}/pydantic_ai/providers/gateway.py +0 -0
  103. {pydantic_ai_slim-1.4.0 → pydantic_ai_slim-1.5.0}/pydantic_ai/providers/github.py +0 -0
  104. {pydantic_ai_slim-1.4.0 → pydantic_ai_slim-1.5.0}/pydantic_ai/providers/google_gla.py +0 -0
  105. {pydantic_ai_slim-1.4.0 → pydantic_ai_slim-1.5.0}/pydantic_ai/providers/google_vertex.py +0 -0
  106. {pydantic_ai_slim-1.4.0 → pydantic_ai_slim-1.5.0}/pydantic_ai/providers/grok.py +0 -0
  107. {pydantic_ai_slim-1.4.0 → pydantic_ai_slim-1.5.0}/pydantic_ai/providers/groq.py +0 -0
  108. {pydantic_ai_slim-1.4.0 → pydantic_ai_slim-1.5.0}/pydantic_ai/providers/heroku.py +0 -0
  109. {pydantic_ai_slim-1.4.0 → pydantic_ai_slim-1.5.0}/pydantic_ai/providers/huggingface.py +0 -0
  110. {pydantic_ai_slim-1.4.0 → pydantic_ai_slim-1.5.0}/pydantic_ai/providers/litellm.py +0 -0
  111. {pydantic_ai_slim-1.4.0 → pydantic_ai_slim-1.5.0}/pydantic_ai/providers/mistral.py +0 -0
  112. {pydantic_ai_slim-1.4.0 → pydantic_ai_slim-1.5.0}/pydantic_ai/providers/moonshotai.py +0 -0
  113. {pydantic_ai_slim-1.4.0 → pydantic_ai_slim-1.5.0}/pydantic_ai/providers/nebius.py +0 -0
  114. {pydantic_ai_slim-1.4.0 → pydantic_ai_slim-1.5.0}/pydantic_ai/providers/ollama.py +0 -0
  115. {pydantic_ai_slim-1.4.0 → pydantic_ai_slim-1.5.0}/pydantic_ai/providers/openai.py +0 -0
  116. {pydantic_ai_slim-1.4.0 → pydantic_ai_slim-1.5.0}/pydantic_ai/providers/openrouter.py +0 -0
  117. {pydantic_ai_slim-1.4.0 → pydantic_ai_slim-1.5.0}/pydantic_ai/providers/ovhcloud.py +0 -0
  118. {pydantic_ai_slim-1.4.0 → pydantic_ai_slim-1.5.0}/pydantic_ai/providers/together.py +0 -0
  119. {pydantic_ai_slim-1.4.0 → pydantic_ai_slim-1.5.0}/pydantic_ai/providers/vercel.py +0 -0
  120. {pydantic_ai_slim-1.4.0 → pydantic_ai_slim-1.5.0}/pydantic_ai/py.typed +0 -0
  121. {pydantic_ai_slim-1.4.0 → pydantic_ai_slim-1.5.0}/pydantic_ai/result.py +0 -0
  122. {pydantic_ai_slim-1.4.0 → pydantic_ai_slim-1.5.0}/pydantic_ai/retries.py +0 -0
  123. {pydantic_ai_slim-1.4.0 → pydantic_ai_slim-1.5.0}/pydantic_ai/settings.py +0 -0
  124. {pydantic_ai_slim-1.4.0 → pydantic_ai_slim-1.5.0}/pydantic_ai/tools.py +0 -0
  125. {pydantic_ai_slim-1.4.0 → pydantic_ai_slim-1.5.0}/pydantic_ai/toolsets/__init__.py +0 -0
  126. {pydantic_ai_slim-1.4.0 → pydantic_ai_slim-1.5.0}/pydantic_ai/toolsets/_dynamic.py +0 -0
  127. {pydantic_ai_slim-1.4.0 → pydantic_ai_slim-1.5.0}/pydantic_ai/toolsets/abstract.py +0 -0
  128. {pydantic_ai_slim-1.4.0 → pydantic_ai_slim-1.5.0}/pydantic_ai/toolsets/approval_required.py +0 -0
  129. {pydantic_ai_slim-1.4.0 → pydantic_ai_slim-1.5.0}/pydantic_ai/toolsets/combined.py +0 -0
  130. {pydantic_ai_slim-1.4.0 → pydantic_ai_slim-1.5.0}/pydantic_ai/toolsets/external.py +0 -0
  131. {pydantic_ai_slim-1.4.0 → pydantic_ai_slim-1.5.0}/pydantic_ai/toolsets/filtered.py +0 -0
  132. {pydantic_ai_slim-1.4.0 → pydantic_ai_slim-1.5.0}/pydantic_ai/toolsets/function.py +0 -0
  133. {pydantic_ai_slim-1.4.0 → pydantic_ai_slim-1.5.0}/pydantic_ai/toolsets/prefixed.py +0 -0
  134. {pydantic_ai_slim-1.4.0 → pydantic_ai_slim-1.5.0}/pydantic_ai/toolsets/prepared.py +0 -0
  135. {pydantic_ai_slim-1.4.0 → pydantic_ai_slim-1.5.0}/pydantic_ai/toolsets/renamed.py +0 -0
  136. {pydantic_ai_slim-1.4.0 → pydantic_ai_slim-1.5.0}/pydantic_ai/toolsets/wrapper.py +0 -0
  137. {pydantic_ai_slim-1.4.0 → pydantic_ai_slim-1.5.0}/pydantic_ai/usage.py +0 -0
  138. {pydantic_ai_slim-1.4.0 → pydantic_ai_slim-1.5.0}/pyproject.toml +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: pydantic-ai-slim
3
- Version: 1.4.0
3
+ Version: 1.5.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.4.0
36
+ Requires-Dist: pydantic-graph==1.5.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.4.0; extra == 'evals'
60
+ Requires-Dist: pydantic-evals==1.5.0; extra == 'evals'
61
61
  Provides-Extra: google
62
62
  Requires-Dist: google-genai>=1.46.0; extra == 'google'
63
63
  Provides-Extra: groq
@@ -20,7 +20,8 @@ from pydantic_ai._instrumentation import DEFAULT_INSTRUMENTATION_VERSION
20
20
  from pydantic_ai._tool_manager import ToolManager
21
21
  from pydantic_ai._utils import dataclasses_no_defaults_repr, get_union_args, is_async_callable, run_in_executor
22
22
  from pydantic_ai.builtin_tools import AbstractBuiltinTool
23
- from pydantic_graph import BaseNode, Graph, GraphRunContext
23
+ from pydantic_graph import BaseNode, GraphRunContext
24
+ from pydantic_graph.beta import Graph, GraphBuilder
24
25
  from pydantic_graph.nodes import End, NodeRunEndT
25
26
 
26
27
  from . import _output, _system_prompt, exceptions, messages as _messages, models, result, usage as _usage
@@ -1162,22 +1163,32 @@ def build_agent_graph(
1162
1163
  name: str | None,
1163
1164
  deps_type: type[DepsT],
1164
1165
  output_type: OutputSpec[OutputT],
1165
- ) -> Graph[GraphAgentState, GraphAgentDeps[DepsT, result.FinalResult[OutputT]], result.FinalResult[OutputT]]:
1166
+ ) -> Graph[
1167
+ GraphAgentState,
1168
+ GraphAgentDeps[DepsT, OutputT],
1169
+ UserPromptNode[DepsT, OutputT],
1170
+ result.FinalResult[OutputT],
1171
+ ]:
1166
1172
  """Build the execution [Graph][pydantic_graph.Graph] for a given agent."""
1167
- nodes = (
1168
- UserPromptNode[DepsT],
1169
- ModelRequestNode[DepsT],
1170
- CallToolsNode[DepsT],
1171
- SetFinalResult[DepsT],
1172
- )
1173
- graph = Graph[GraphAgentState, GraphAgentDeps[DepsT, Any], result.FinalResult[OutputT]](
1174
- nodes=nodes,
1173
+ g = GraphBuilder(
1175
1174
  name=name or 'Agent',
1176
1175
  state_type=GraphAgentState,
1177
- run_end_type=result.FinalResult[OutputT],
1176
+ deps_type=GraphAgentDeps[DepsT, OutputT],
1177
+ input_type=UserPromptNode[DepsT, OutputT],
1178
+ output_type=result.FinalResult[OutputT],
1178
1179
  auto_instrument=False,
1179
1180
  )
1180
- return graph
1181
+
1182
+ g.add(
1183
+ g.edge_from(g.start_node).to(UserPromptNode[DepsT, OutputT]),
1184
+ g.node(UserPromptNode[DepsT, OutputT]),
1185
+ g.node(ModelRequestNode[DepsT, OutputT]),
1186
+ g.node(CallToolsNode[DepsT, OutputT]),
1187
+ g.node(
1188
+ SetFinalResult[DepsT, OutputT],
1189
+ ),
1190
+ )
1191
+ return g.build(validate_graph_structure=False)
1181
1192
 
1182
1193
 
1183
1194
  async def _process_message_history(
@@ -147,7 +147,7 @@ async def group_by_temporal(
147
147
  aiterable: The async iterable to group.
148
148
  soft_max_interval: Maximum interval over which to group items, this should avoid a trickle of items causing
149
149
  a group to never be yielded. It's a soft max in the sense that once we're over this time, we yield items
150
- as soon as `aiter.__anext__()` returns. If `None`, no grouping/debouncing is performed
150
+ as soon as `anext(aiter)` returns. If `None`, no grouping/debouncing is performed
151
151
 
152
152
  Returns:
153
153
  A context manager usable as an async iterable of lists of items produced by the input async iterable.
@@ -171,7 +171,7 @@ async def group_by_temporal(
171
171
  buffer: list[T] = []
172
172
  group_start_time = time.monotonic()
173
173
 
174
- aiterator = aiterable.__aiter__()
174
+ aiterator = aiter(aiterable)
175
175
  while True:
176
176
  if group_start_time is None:
177
177
  # group hasn't started, we just wait for the maximum interval
@@ -182,9 +182,9 @@ async def group_by_temporal(
182
182
 
183
183
  # if there's no current task, we get the next one
184
184
  if task is None:
185
- # aiter.__anext__() returns an Awaitable[T], not a Coroutine which asyncio.create_task expects
185
+ # anext(aiter) returns an Awaitable[T], not a Coroutine which asyncio.create_task expects
186
186
  # so far, this doesn't seem to be a problem
187
- task = asyncio.create_task(aiterator.__anext__()) # pyright: ignore[reportArgumentType]
187
+ task = asyncio.create_task(anext(aiterator)) # pyright: ignore[reportArgumentType]
188
188
 
189
189
  # we use asyncio.wait to avoid cancelling the coroutine if it's not done
190
190
  done, _ = await asyncio.wait((task,), timeout=wait_time)
@@ -284,10 +284,10 @@ class PeekableAsyncStream(Generic[T]):
284
284
 
285
285
  # Otherwise, we need to fetch the next item from the underlying iterator.
286
286
  if self._source_iter is None:
287
- self._source_iter = self._source.__aiter__()
287
+ self._source_iter = aiter(self._source)
288
288
 
289
289
  try:
290
- self._buffer = await self._source_iter.__anext__()
290
+ self._buffer = await anext(self._source_iter)
291
291
  except StopAsyncIteration:
292
292
  self._exhausted = True
293
293
  return UNSET
@@ -318,10 +318,10 @@ class PeekableAsyncStream(Generic[T]):
318
318
 
319
319
  # Otherwise, fetch the next item from the source.
320
320
  if self._source_iter is None:
321
- self._source_iter = self._source.__aiter__()
321
+ self._source_iter = aiter(self._source)
322
322
 
323
323
  try:
324
- return await self._source_iter.__anext__()
324
+ return await anext(self._source_iter)
325
325
  except StopAsyncIteration:
326
326
  self._exhausted = True
327
327
  raise
@@ -15,7 +15,6 @@ from pydantic.json_schema import GenerateJsonSchema
15
15
  from typing_extensions import Self, TypeVar, deprecated
16
16
 
17
17
  from pydantic_ai._instrumentation import DEFAULT_INSTRUMENTATION_VERSION, InstrumentationNames
18
- from pydantic_graph import Graph
19
18
 
20
19
  from .. import (
21
20
  _agent_graph,
@@ -41,7 +40,6 @@ from ..builtin_tools import AbstractBuiltinTool
41
40
  from ..models.instrumented import InstrumentationSettings, InstrumentedModel, instrument_model
42
41
  from ..output import OutputDataT, OutputSpec
43
42
  from ..profiles import ModelProfile
44
- from ..result import FinalResult
45
43
  from ..run import AgentRun, AgentRunResult
46
44
  from ..settings import ModelSettings, merge_model_settings
47
45
  from ..tools import (
@@ -566,9 +564,7 @@ class Agent(AbstractAgent[AgentDepsT, OutputDataT]):
566
564
  tool_manager = ToolManager[AgentDepsT](toolset)
567
565
 
568
566
  # Build the graph
569
- graph: Graph[_agent_graph.GraphAgentState, _agent_graph.GraphAgentDeps[AgentDepsT, Any], FinalResult[Any]] = (
570
- _agent_graph.build_agent_graph(self.name, self._deps_type, output_type_)
571
- )
567
+ graph = _agent_graph.build_agent_graph(self.name, self._deps_type, output_type_)
572
568
 
573
569
  # Build the initial state
574
570
  usage = usage or _usage.RunUsage()
@@ -628,7 +624,7 @@ class Agent(AbstractAgent[AgentDepsT, OutputDataT]):
628
624
  instrumentation_settings=instrumentation_settings,
629
625
  )
630
626
 
631
- start_node = _agent_graph.UserPromptNode[AgentDepsT](
627
+ user_prompt_node = _agent_graph.UserPromptNode[AgentDepsT](
632
628
  user_prompt=user_prompt,
633
629
  deferred_tool_results=deferred_tool_results,
634
630
  instructions=instructions_literal,
@@ -655,7 +651,7 @@ class Agent(AbstractAgent[AgentDepsT, OutputDataT]):
655
651
 
656
652
  try:
657
653
  async with graph.iter(
658
- start_node,
654
+ inputs=user_prompt_node,
659
655
  state=state,
660
656
  deps=graph_deps,
661
657
  span=use_span(run_span) if run_span.is_recording() else None,
@@ -36,6 +36,17 @@ __all__ = [
36
36
  'TemporalWrapperToolset',
37
37
  ]
38
38
 
39
+ # We need eagerly import the anyio backends or it will happens inside workflow code and temporal has issues
40
+ # Note: It's difficult to add a test that covers this because pytest presumably does these imports itself
41
+ # when you have a @pytest.mark.anyio somewhere.
42
+ # I suppose we could add a test that runs a python script in a separate process, but I have not done that...
43
+ import anyio._backends._asyncio # pyright: ignore[reportUnusedImport]
44
+
45
+ try:
46
+ import anyio._backends._trio # noqa F401 # pyright: ignore[reportUnusedImport]
47
+ except ImportError:
48
+ pass
49
+
39
50
 
40
51
  class PydanticAIPlugin(ClientPlugin, WorkerPlugin):
41
52
  """Temporal client and worker plugin for Pydantic AI."""
@@ -2,11 +2,12 @@ from __future__ import annotations
2
2
 
3
3
  from collections.abc import Callable
4
4
  from dataclasses import dataclass
5
- from typing import Annotated, Any, Literal, assert_never
5
+ from typing import Annotated, Any, Literal
6
6
 
7
7
  from pydantic import ConfigDict, Discriminator, with_config
8
8
  from temporalio import activity, workflow
9
9
  from temporalio.workflow import ActivityConfig
10
+ from typing_extensions import assert_never
10
11
 
11
12
  from pydantic_ai import FunctionToolset, ToolsetTool
12
13
  from pydantic_ai.exceptions import ApprovalRequired, CallDeferred, ModelRetry, UserError
@@ -159,7 +159,7 @@ class ModelHTTPError(AgentRunError):
159
159
  super().__init__(message)
160
160
 
161
161
 
162
- class FallbackExceptionGroup(ExceptionGroup):
162
+ class FallbackExceptionGroup(ExceptionGroup[Any]):
163
163
  """A group of exceptions that can be raised when all fallback models fail."""
164
164
 
165
165
 
@@ -480,7 +480,7 @@ class BinaryContent:
480
480
  """
481
481
 
482
482
  _identifier: Annotated[str | None, pydantic.Field(alias='identifier', default=None, exclude=True)] = field(
483
- compare=False, default=None
483
+ compare=False, default=None, repr=False
484
484
  )
485
485
 
486
486
  kind: Literal['binary'] = 'binary'
@@ -13,7 +13,8 @@ from pydantic_ai.providers import Provider
13
13
 
14
14
  try:
15
15
  from google.auth.credentials import Credentials
16
- from google.genai import Client
16
+ from google.genai._api_client import BaseApiClient
17
+ from google.genai.client import Client, DebugConfig
17
18
  from google.genai.types import HttpOptions
18
19
  except ImportError as _import_error:
19
20
  raise ImportError(
@@ -114,7 +115,7 @@ class GoogleProvider(Provider[Client]):
114
115
  base_url=base_url,
115
116
  headers={'User-Agent': get_user_agent()},
116
117
  httpx_async_client=http_client,
117
- # TODO: Remove once https://github.com/googleapis/python-genai/pull/1509#issuecomment-3430028790 is solved.
118
+ # TODO: Remove once https://github.com/googleapis/python-genai/issues/1565 is solved.
118
119
  async_client_args={'transport': httpx.AsyncHTTPTransport()},
119
120
  )
120
121
  if not vertexai:
@@ -186,9 +187,37 @@ More details [here](https://cloud.google.com/vertex-ai/generative-ai/docs/learn/
186
187
 
187
188
 
188
189
  class _SafelyClosingClient(Client):
190
+ @staticmethod
191
+ def _get_api_client(
192
+ vertexai: bool | None = None,
193
+ api_key: str | None = None,
194
+ credentials: Credentials | None = None,
195
+ project: str | None = None,
196
+ location: str | None = None,
197
+ debug_config: DebugConfig | None = None,
198
+ http_options: HttpOptions | None = None,
199
+ ) -> BaseApiClient:
200
+ return _NonClosingApiClient(
201
+ vertexai=vertexai,
202
+ api_key=api_key,
203
+ credentials=credentials,
204
+ project=project,
205
+ location=location,
206
+ http_options=http_options,
207
+ )
208
+
189
209
  def close(self) -> None:
190
210
  # This is called from `Client.__del__`, even if `Client.__init__` raised an error before `self._api_client` is set, which would raise an `AttributeError` here.
211
+ # TODO: Remove once https://github.com/googleapis/python-genai/issues/1567 is solved.
191
212
  try:
192
213
  super().close()
193
214
  except AttributeError:
194
215
  pass
216
+
217
+
218
+ class _NonClosingApiClient(BaseApiClient):
219
+ async def aclose(self) -> None:
220
+ # The original implementation also calls `await self._async_httpx_client.aclose()`, but we don't want to close our `cached_async_http_client` or the one the user passed in.
221
+ # TODO: Remove once https://github.com/googleapis/python-genai/issues/1566 is solved.
222
+ if self._aiohttp_session:
223
+ await self._aiohttp_session.close() # pragma: no cover
@@ -1,12 +1,14 @@
1
1
  from __future__ import annotations as _annotations
2
2
 
3
3
  import dataclasses
4
- from collections.abc import AsyncIterator
4
+ from collections.abc import AsyncIterator, Sequence
5
5
  from copy import deepcopy
6
6
  from datetime import datetime
7
7
  from typing import TYPE_CHECKING, Any, Generic, Literal, overload
8
8
 
9
- from pydantic_graph import End, GraphRun, GraphRunContext
9
+ from pydantic_graph import BaseNode, End, GraphRunContext
10
+ from pydantic_graph.beta.graph import EndMarker, GraphRun, GraphTask, JoinItem
11
+ from pydantic_graph.beta.step import NodeStep
10
12
 
11
13
  from . import (
12
14
  _agent_graph,
@@ -112,12 +114,8 @@ class AgentRun(Generic[AgentDepsT, OutputDataT]):
112
114
 
113
115
  This is the next node that will be used during async iteration, or if a node is not passed to `self.next(...)`.
114
116
  """
115
- next_node = self._graph_run.next_node
116
- if isinstance(next_node, End):
117
- return next_node
118
- if _agent_graph.is_agent_node(next_node):
119
- return next_node
120
- raise exceptions.AgentRunError(f'Unexpected node type: {type(next_node)}') # pragma: no cover
117
+ task = self._graph_run.next_task
118
+ return self._task_to_node(task)
121
119
 
122
120
  @property
123
121
  def result(self) -> AgentRunResult[OutputDataT] | None:
@@ -126,13 +124,13 @@ class AgentRun(Generic[AgentDepsT, OutputDataT]):
126
124
  Once the run returns an [`End`][pydantic_graph.nodes.End] node, `result` is populated
127
125
  with an [`AgentRunResult`][pydantic_ai.agent.AgentRunResult].
128
126
  """
129
- graph_run_result = self._graph_run.result
130
- if graph_run_result is None:
127
+ graph_run_output = self._graph_run.output
128
+ if graph_run_output is None:
131
129
  return None
132
130
  return AgentRunResult(
133
- graph_run_result.output.output,
134
- graph_run_result.output.tool_name,
135
- graph_run_result.state,
131
+ graph_run_output.output,
132
+ graph_run_output.tool_name,
133
+ self._graph_run.state,
136
134
  self._graph_run.deps.new_message_index,
137
135
  self._traceparent(required=False),
138
136
  )
@@ -147,11 +145,28 @@ class AgentRun(Generic[AgentDepsT, OutputDataT]):
147
145
  self,
148
146
  ) -> _agent_graph.AgentNode[AgentDepsT, OutputDataT] | End[FinalResult[OutputDataT]]:
149
147
  """Advance to the next node automatically based on the last returned node."""
150
- next_node = await self._graph_run.__anext__()
151
- if _agent_graph.is_agent_node(node=next_node):
152
- return next_node
153
- assert isinstance(next_node, End), f'Unexpected node type: {type(next_node)}'
154
- return next_node
148
+ task = await anext(self._graph_run)
149
+ return self._task_to_node(task)
150
+
151
+ def _task_to_node(
152
+ self, task: EndMarker[FinalResult[OutputDataT]] | JoinItem | Sequence[GraphTask]
153
+ ) -> _agent_graph.AgentNode[AgentDepsT, OutputDataT] | End[FinalResult[OutputDataT]]:
154
+ if isinstance(task, Sequence) and len(task) == 1:
155
+ first_task = task[0]
156
+ if isinstance(first_task.inputs, BaseNode): # pragma: no branch
157
+ base_node: BaseNode[
158
+ _agent_graph.GraphAgentState,
159
+ _agent_graph.GraphAgentDeps[AgentDepsT, OutputDataT],
160
+ FinalResult[OutputDataT],
161
+ ] = first_task.inputs # type: ignore[reportUnknownMemberType]
162
+ if _agent_graph.is_agent_node(node=base_node): # pragma: no branch
163
+ return base_node
164
+ if isinstance(task, EndMarker):
165
+ return End(task.value)
166
+ raise exceptions.AgentRunError(f'Unexpected node: {task}') # pragma: no cover
167
+
168
+ def _node_to_task(self, node: _agent_graph.AgentNode[AgentDepsT, OutputDataT]) -> GraphTask:
169
+ return GraphTask(NodeStep(type(node)).id, inputs=node, fork_stack=())
155
170
 
156
171
  async def next(
157
172
  self,
@@ -222,11 +237,12 @@ class AgentRun(Generic[AgentDepsT, OutputDataT]):
222
237
  """
223
238
  # Note: It might be nice to expose a synchronous interface for iteration, but we shouldn't do it
224
239
  # on this class, or else IDEs won't warn you if you accidentally use `for` instead of `async for` to iterate.
225
- next_node = await self._graph_run.next(node)
226
- if _agent_graph.is_agent_node(next_node):
227
- return next_node
228
- assert isinstance(next_node, End), f'Unexpected node type: {type(next_node)}'
229
- return next_node
240
+ task = [self._node_to_task(node)]
241
+ try:
242
+ task = await self._graph_run.next(task)
243
+ except StopAsyncIteration:
244
+ pass
245
+ return self._task_to_node(task)
230
246
 
231
247
  # TODO (v2): Make this a property
232
248
  def usage(self) -> _usage.RunUsage:
@@ -234,7 +250,7 @@ class AgentRun(Generic[AgentDepsT, OutputDataT]):
234
250
  return self._graph_run.state.usage
235
251
 
236
252
  def __repr__(self) -> str: # pragma: no cover
237
- result = self._graph_run.result
253
+ result = self._graph_run.output
238
254
  result_repr = '<run not finished>' if result is None else repr(result.output)
239
255
  return f'<{type(self).__name__} result={result_repr} usage={self.usage()}>'
240
256