pydantic-ai-slim 1.0.18__tar.gz → 1.2.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 (137) hide show
  1. {pydantic_ai_slim-1.0.18 → pydantic_ai_slim-1.2.0}/PKG-INFO +7 -5
  2. {pydantic_ai_slim-1.0.18 → pydantic_ai_slim-1.2.0}/pydantic_ai/_agent_graph.py +13 -0
  3. {pydantic_ai_slim-1.0.18 → pydantic_ai_slim-1.2.0}/pydantic_ai/agent/__init__.py +43 -12
  4. {pydantic_ai_slim-1.0.18 → pydantic_ai_slim-1.2.0}/pydantic_ai/agent/abstract.py +12 -0
  5. pydantic_ai_slim-1.2.0/pydantic_ai/durable_exec/prefect/__init__.py +15 -0
  6. pydantic_ai_slim-1.2.0/pydantic_ai/durable_exec/prefect/_agent.py +833 -0
  7. pydantic_ai_slim-1.2.0/pydantic_ai/durable_exec/prefect/_cache_policies.py +102 -0
  8. pydantic_ai_slim-1.2.0/pydantic_ai/durable_exec/prefect/_function_toolset.py +58 -0
  9. pydantic_ai_slim-1.2.0/pydantic_ai/durable_exec/prefect/_mcp_server.py +60 -0
  10. pydantic_ai_slim-1.2.0/pydantic_ai/durable_exec/prefect/_model.py +152 -0
  11. pydantic_ai_slim-1.2.0/pydantic_ai/durable_exec/prefect/_toolset.py +67 -0
  12. pydantic_ai_slim-1.2.0/pydantic_ai/durable_exec/prefect/_types.py +44 -0
  13. {pydantic_ai_slim-1.0.18 → pydantic_ai_slim-1.2.0}/pydantic_ai/models/__init__.py +3 -0
  14. {pydantic_ai_slim-1.0.18 → pydantic_ai_slim-1.2.0}/pydantic_ai/models/google.py +6 -0
  15. {pydantic_ai_slim-1.0.18 → pydantic_ai_slim-1.2.0}/pydantic_ai/models/openai.py +42 -45
  16. {pydantic_ai_slim-1.0.18 → pydantic_ai_slim-1.2.0}/pydantic_ai/providers/gateway.py +16 -7
  17. {pydantic_ai_slim-1.0.18 → pydantic_ai_slim-1.2.0}/pydantic_ai/toolsets/function.py +19 -12
  18. {pydantic_ai_slim-1.0.18 → pydantic_ai_slim-1.2.0}/pyproject.toml +4 -2
  19. {pydantic_ai_slim-1.0.18 → pydantic_ai_slim-1.2.0}/.gitignore +0 -0
  20. {pydantic_ai_slim-1.0.18 → pydantic_ai_slim-1.2.0}/LICENSE +0 -0
  21. {pydantic_ai_slim-1.0.18 → pydantic_ai_slim-1.2.0}/README.md +0 -0
  22. {pydantic_ai_slim-1.0.18 → pydantic_ai_slim-1.2.0}/pydantic_ai/__init__.py +0 -0
  23. {pydantic_ai_slim-1.0.18 → pydantic_ai_slim-1.2.0}/pydantic_ai/__main__.py +0 -0
  24. {pydantic_ai_slim-1.0.18 → pydantic_ai_slim-1.2.0}/pydantic_ai/_a2a.py +0 -0
  25. {pydantic_ai_slim-1.0.18 → pydantic_ai_slim-1.2.0}/pydantic_ai/_cli.py +0 -0
  26. {pydantic_ai_slim-1.0.18 → pydantic_ai_slim-1.2.0}/pydantic_ai/_function_schema.py +0 -0
  27. {pydantic_ai_slim-1.0.18 → pydantic_ai_slim-1.2.0}/pydantic_ai/_griffe.py +0 -0
  28. {pydantic_ai_slim-1.0.18 → pydantic_ai_slim-1.2.0}/pydantic_ai/_instrumentation.py +0 -0
  29. {pydantic_ai_slim-1.0.18 → pydantic_ai_slim-1.2.0}/pydantic_ai/_json_schema.py +0 -0
  30. {pydantic_ai_slim-1.0.18 → pydantic_ai_slim-1.2.0}/pydantic_ai/_mcp.py +0 -0
  31. {pydantic_ai_slim-1.0.18 → pydantic_ai_slim-1.2.0}/pydantic_ai/_otel_messages.py +0 -0
  32. {pydantic_ai_slim-1.0.18 → pydantic_ai_slim-1.2.0}/pydantic_ai/_output.py +0 -0
  33. {pydantic_ai_slim-1.0.18 → pydantic_ai_slim-1.2.0}/pydantic_ai/_parts_manager.py +0 -0
  34. {pydantic_ai_slim-1.0.18 → pydantic_ai_slim-1.2.0}/pydantic_ai/_run_context.py +0 -0
  35. {pydantic_ai_slim-1.0.18 → pydantic_ai_slim-1.2.0}/pydantic_ai/_system_prompt.py +0 -0
  36. {pydantic_ai_slim-1.0.18 → pydantic_ai_slim-1.2.0}/pydantic_ai/_thinking_part.py +0 -0
  37. {pydantic_ai_slim-1.0.18 → pydantic_ai_slim-1.2.0}/pydantic_ai/_tool_manager.py +0 -0
  38. {pydantic_ai_slim-1.0.18 → pydantic_ai_slim-1.2.0}/pydantic_ai/_utils.py +0 -0
  39. {pydantic_ai_slim-1.0.18 → pydantic_ai_slim-1.2.0}/pydantic_ai/ag_ui.py +0 -0
  40. {pydantic_ai_slim-1.0.18 → pydantic_ai_slim-1.2.0}/pydantic_ai/agent/wrapper.py +0 -0
  41. {pydantic_ai_slim-1.0.18 → pydantic_ai_slim-1.2.0}/pydantic_ai/builtin_tools.py +0 -0
  42. {pydantic_ai_slim-1.0.18 → pydantic_ai_slim-1.2.0}/pydantic_ai/common_tools/__init__.py +0 -0
  43. {pydantic_ai_slim-1.0.18 → pydantic_ai_slim-1.2.0}/pydantic_ai/common_tools/duckduckgo.py +0 -0
  44. {pydantic_ai_slim-1.0.18 → pydantic_ai_slim-1.2.0}/pydantic_ai/common_tools/tavily.py +0 -0
  45. {pydantic_ai_slim-1.0.18 → pydantic_ai_slim-1.2.0}/pydantic_ai/direct.py +0 -0
  46. {pydantic_ai_slim-1.0.18 → pydantic_ai_slim-1.2.0}/pydantic_ai/durable_exec/__init__.py +0 -0
  47. {pydantic_ai_slim-1.0.18 → pydantic_ai_slim-1.2.0}/pydantic_ai/durable_exec/dbos/__init__.py +0 -0
  48. {pydantic_ai_slim-1.0.18 → pydantic_ai_slim-1.2.0}/pydantic_ai/durable_exec/dbos/_agent.py +0 -0
  49. {pydantic_ai_slim-1.0.18 → pydantic_ai_slim-1.2.0}/pydantic_ai/durable_exec/dbos/_mcp_server.py +0 -0
  50. {pydantic_ai_slim-1.0.18 → pydantic_ai_slim-1.2.0}/pydantic_ai/durable_exec/dbos/_model.py +0 -0
  51. {pydantic_ai_slim-1.0.18 → pydantic_ai_slim-1.2.0}/pydantic_ai/durable_exec/dbos/_utils.py +0 -0
  52. {pydantic_ai_slim-1.0.18 → pydantic_ai_slim-1.2.0}/pydantic_ai/durable_exec/temporal/__init__.py +0 -0
  53. {pydantic_ai_slim-1.0.18 → pydantic_ai_slim-1.2.0}/pydantic_ai/durable_exec/temporal/_agent.py +0 -0
  54. {pydantic_ai_slim-1.0.18 → pydantic_ai_slim-1.2.0}/pydantic_ai/durable_exec/temporal/_function_toolset.py +0 -0
  55. {pydantic_ai_slim-1.0.18 → pydantic_ai_slim-1.2.0}/pydantic_ai/durable_exec/temporal/_logfire.py +0 -0
  56. {pydantic_ai_slim-1.0.18 → pydantic_ai_slim-1.2.0}/pydantic_ai/durable_exec/temporal/_mcp_server.py +0 -0
  57. {pydantic_ai_slim-1.0.18 → pydantic_ai_slim-1.2.0}/pydantic_ai/durable_exec/temporal/_model.py +0 -0
  58. {pydantic_ai_slim-1.0.18 → pydantic_ai_slim-1.2.0}/pydantic_ai/durable_exec/temporal/_run_context.py +0 -0
  59. {pydantic_ai_slim-1.0.18 → pydantic_ai_slim-1.2.0}/pydantic_ai/durable_exec/temporal/_toolset.py +0 -0
  60. {pydantic_ai_slim-1.0.18 → pydantic_ai_slim-1.2.0}/pydantic_ai/exceptions.py +0 -0
  61. {pydantic_ai_slim-1.0.18 → pydantic_ai_slim-1.2.0}/pydantic_ai/ext/__init__.py +0 -0
  62. {pydantic_ai_slim-1.0.18 → pydantic_ai_slim-1.2.0}/pydantic_ai/ext/aci.py +0 -0
  63. {pydantic_ai_slim-1.0.18 → pydantic_ai_slim-1.2.0}/pydantic_ai/ext/langchain.py +0 -0
  64. {pydantic_ai_slim-1.0.18 → pydantic_ai_slim-1.2.0}/pydantic_ai/format_prompt.py +0 -0
  65. {pydantic_ai_slim-1.0.18 → pydantic_ai_slim-1.2.0}/pydantic_ai/mcp.py +0 -0
  66. {pydantic_ai_slim-1.0.18 → pydantic_ai_slim-1.2.0}/pydantic_ai/messages.py +0 -0
  67. {pydantic_ai_slim-1.0.18 → pydantic_ai_slim-1.2.0}/pydantic_ai/models/anthropic.py +0 -0
  68. {pydantic_ai_slim-1.0.18 → pydantic_ai_slim-1.2.0}/pydantic_ai/models/bedrock.py +0 -0
  69. {pydantic_ai_slim-1.0.18 → pydantic_ai_slim-1.2.0}/pydantic_ai/models/cohere.py +0 -0
  70. {pydantic_ai_slim-1.0.18 → pydantic_ai_slim-1.2.0}/pydantic_ai/models/fallback.py +0 -0
  71. {pydantic_ai_slim-1.0.18 → pydantic_ai_slim-1.2.0}/pydantic_ai/models/function.py +0 -0
  72. {pydantic_ai_slim-1.0.18 → pydantic_ai_slim-1.2.0}/pydantic_ai/models/gemini.py +0 -0
  73. {pydantic_ai_slim-1.0.18 → pydantic_ai_slim-1.2.0}/pydantic_ai/models/groq.py +0 -0
  74. {pydantic_ai_slim-1.0.18 → pydantic_ai_slim-1.2.0}/pydantic_ai/models/huggingface.py +0 -0
  75. {pydantic_ai_slim-1.0.18 → pydantic_ai_slim-1.2.0}/pydantic_ai/models/instrumented.py +0 -0
  76. {pydantic_ai_slim-1.0.18 → pydantic_ai_slim-1.2.0}/pydantic_ai/models/mcp_sampling.py +0 -0
  77. {pydantic_ai_slim-1.0.18 → pydantic_ai_slim-1.2.0}/pydantic_ai/models/mistral.py +0 -0
  78. {pydantic_ai_slim-1.0.18 → pydantic_ai_slim-1.2.0}/pydantic_ai/models/test.py +0 -0
  79. {pydantic_ai_slim-1.0.18 → pydantic_ai_slim-1.2.0}/pydantic_ai/models/wrapper.py +0 -0
  80. {pydantic_ai_slim-1.0.18 → pydantic_ai_slim-1.2.0}/pydantic_ai/output.py +0 -0
  81. {pydantic_ai_slim-1.0.18 → pydantic_ai_slim-1.2.0}/pydantic_ai/profiles/__init__.py +0 -0
  82. {pydantic_ai_slim-1.0.18 → pydantic_ai_slim-1.2.0}/pydantic_ai/profiles/amazon.py +0 -0
  83. {pydantic_ai_slim-1.0.18 → pydantic_ai_slim-1.2.0}/pydantic_ai/profiles/anthropic.py +0 -0
  84. {pydantic_ai_slim-1.0.18 → pydantic_ai_slim-1.2.0}/pydantic_ai/profiles/cohere.py +0 -0
  85. {pydantic_ai_slim-1.0.18 → pydantic_ai_slim-1.2.0}/pydantic_ai/profiles/deepseek.py +0 -0
  86. {pydantic_ai_slim-1.0.18 → pydantic_ai_slim-1.2.0}/pydantic_ai/profiles/google.py +0 -0
  87. {pydantic_ai_slim-1.0.18 → pydantic_ai_slim-1.2.0}/pydantic_ai/profiles/grok.py +0 -0
  88. {pydantic_ai_slim-1.0.18 → pydantic_ai_slim-1.2.0}/pydantic_ai/profiles/groq.py +0 -0
  89. {pydantic_ai_slim-1.0.18 → pydantic_ai_slim-1.2.0}/pydantic_ai/profiles/harmony.py +0 -0
  90. {pydantic_ai_slim-1.0.18 → pydantic_ai_slim-1.2.0}/pydantic_ai/profiles/meta.py +0 -0
  91. {pydantic_ai_slim-1.0.18 → pydantic_ai_slim-1.2.0}/pydantic_ai/profiles/mistral.py +0 -0
  92. {pydantic_ai_slim-1.0.18 → pydantic_ai_slim-1.2.0}/pydantic_ai/profiles/moonshotai.py +0 -0
  93. {pydantic_ai_slim-1.0.18 → pydantic_ai_slim-1.2.0}/pydantic_ai/profiles/openai.py +0 -0
  94. {pydantic_ai_slim-1.0.18 → pydantic_ai_slim-1.2.0}/pydantic_ai/profiles/qwen.py +0 -0
  95. {pydantic_ai_slim-1.0.18 → pydantic_ai_slim-1.2.0}/pydantic_ai/providers/__init__.py +0 -0
  96. {pydantic_ai_slim-1.0.18 → pydantic_ai_slim-1.2.0}/pydantic_ai/providers/anthropic.py +0 -0
  97. {pydantic_ai_slim-1.0.18 → pydantic_ai_slim-1.2.0}/pydantic_ai/providers/azure.py +0 -0
  98. {pydantic_ai_slim-1.0.18 → pydantic_ai_slim-1.2.0}/pydantic_ai/providers/bedrock.py +0 -0
  99. {pydantic_ai_slim-1.0.18 → pydantic_ai_slim-1.2.0}/pydantic_ai/providers/cerebras.py +0 -0
  100. {pydantic_ai_slim-1.0.18 → pydantic_ai_slim-1.2.0}/pydantic_ai/providers/cohere.py +0 -0
  101. {pydantic_ai_slim-1.0.18 → pydantic_ai_slim-1.2.0}/pydantic_ai/providers/deepseek.py +0 -0
  102. {pydantic_ai_slim-1.0.18 → pydantic_ai_slim-1.2.0}/pydantic_ai/providers/fireworks.py +0 -0
  103. {pydantic_ai_slim-1.0.18 → pydantic_ai_slim-1.2.0}/pydantic_ai/providers/github.py +0 -0
  104. {pydantic_ai_slim-1.0.18 → pydantic_ai_slim-1.2.0}/pydantic_ai/providers/google.py +0 -0
  105. {pydantic_ai_slim-1.0.18 → pydantic_ai_slim-1.2.0}/pydantic_ai/providers/google_gla.py +0 -0
  106. {pydantic_ai_slim-1.0.18 → pydantic_ai_slim-1.2.0}/pydantic_ai/providers/google_vertex.py +0 -0
  107. {pydantic_ai_slim-1.0.18 → pydantic_ai_slim-1.2.0}/pydantic_ai/providers/grok.py +0 -0
  108. {pydantic_ai_slim-1.0.18 → pydantic_ai_slim-1.2.0}/pydantic_ai/providers/groq.py +0 -0
  109. {pydantic_ai_slim-1.0.18 → pydantic_ai_slim-1.2.0}/pydantic_ai/providers/heroku.py +0 -0
  110. {pydantic_ai_slim-1.0.18 → pydantic_ai_slim-1.2.0}/pydantic_ai/providers/huggingface.py +0 -0
  111. {pydantic_ai_slim-1.0.18 → pydantic_ai_slim-1.2.0}/pydantic_ai/providers/litellm.py +0 -0
  112. {pydantic_ai_slim-1.0.18 → pydantic_ai_slim-1.2.0}/pydantic_ai/providers/mistral.py +0 -0
  113. {pydantic_ai_slim-1.0.18 → pydantic_ai_slim-1.2.0}/pydantic_ai/providers/moonshotai.py +0 -0
  114. {pydantic_ai_slim-1.0.18 → pydantic_ai_slim-1.2.0}/pydantic_ai/providers/nebius.py +0 -0
  115. {pydantic_ai_slim-1.0.18 → pydantic_ai_slim-1.2.0}/pydantic_ai/providers/ollama.py +0 -0
  116. {pydantic_ai_slim-1.0.18 → pydantic_ai_slim-1.2.0}/pydantic_ai/providers/openai.py +0 -0
  117. {pydantic_ai_slim-1.0.18 → pydantic_ai_slim-1.2.0}/pydantic_ai/providers/openrouter.py +0 -0
  118. {pydantic_ai_slim-1.0.18 → pydantic_ai_slim-1.2.0}/pydantic_ai/providers/together.py +0 -0
  119. {pydantic_ai_slim-1.0.18 → pydantic_ai_slim-1.2.0}/pydantic_ai/providers/vercel.py +0 -0
  120. {pydantic_ai_slim-1.0.18 → pydantic_ai_slim-1.2.0}/pydantic_ai/py.typed +0 -0
  121. {pydantic_ai_slim-1.0.18 → pydantic_ai_slim-1.2.0}/pydantic_ai/result.py +0 -0
  122. {pydantic_ai_slim-1.0.18 → pydantic_ai_slim-1.2.0}/pydantic_ai/retries.py +0 -0
  123. {pydantic_ai_slim-1.0.18 → pydantic_ai_slim-1.2.0}/pydantic_ai/run.py +0 -0
  124. {pydantic_ai_slim-1.0.18 → pydantic_ai_slim-1.2.0}/pydantic_ai/settings.py +0 -0
  125. {pydantic_ai_slim-1.0.18 → pydantic_ai_slim-1.2.0}/pydantic_ai/tools.py +0 -0
  126. {pydantic_ai_slim-1.0.18 → pydantic_ai_slim-1.2.0}/pydantic_ai/toolsets/__init__.py +0 -0
  127. {pydantic_ai_slim-1.0.18 → pydantic_ai_slim-1.2.0}/pydantic_ai/toolsets/_dynamic.py +0 -0
  128. {pydantic_ai_slim-1.0.18 → pydantic_ai_slim-1.2.0}/pydantic_ai/toolsets/abstract.py +0 -0
  129. {pydantic_ai_slim-1.0.18 → pydantic_ai_slim-1.2.0}/pydantic_ai/toolsets/approval_required.py +0 -0
  130. {pydantic_ai_slim-1.0.18 → pydantic_ai_slim-1.2.0}/pydantic_ai/toolsets/combined.py +0 -0
  131. {pydantic_ai_slim-1.0.18 → pydantic_ai_slim-1.2.0}/pydantic_ai/toolsets/external.py +0 -0
  132. {pydantic_ai_slim-1.0.18 → pydantic_ai_slim-1.2.0}/pydantic_ai/toolsets/filtered.py +0 -0
  133. {pydantic_ai_slim-1.0.18 → pydantic_ai_slim-1.2.0}/pydantic_ai/toolsets/prefixed.py +0 -0
  134. {pydantic_ai_slim-1.0.18 → pydantic_ai_slim-1.2.0}/pydantic_ai/toolsets/prepared.py +0 -0
  135. {pydantic_ai_slim-1.0.18 → pydantic_ai_slim-1.2.0}/pydantic_ai/toolsets/renamed.py +0 -0
  136. {pydantic_ai_slim-1.0.18 → pydantic_ai_slim-1.2.0}/pydantic_ai/toolsets/wrapper.py +0 -0
  137. {pydantic_ai_slim-1.0.18 → pydantic_ai_slim-1.2.0}/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.18
3
+ Version: 1.2.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
@@ -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.30
32
+ Requires-Dist: genai-prices>=0.0.31
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.18
36
+ Requires-Dist: pydantic-graph==1.2.0
37
37
  Requires-Dist: pydantic>=2.10
38
38
  Requires-Dist: typing-inspection>=0.4.0
39
39
  Provides-Extra: a2a
@@ -42,7 +42,7 @@ Provides-Extra: ag-ui
42
42
  Requires-Dist: ag-ui-protocol>=0.1.8; extra == 'ag-ui'
43
43
  Requires-Dist: starlette>=0.45.3; extra == 'ag-ui'
44
44
  Provides-Extra: anthropic
45
- Requires-Dist: anthropic>=0.69.0; extra == 'anthropic'
45
+ Requires-Dist: anthropic>=0.70.0; extra == 'anthropic'
46
46
  Provides-Extra: bedrock
47
47
  Requires-Dist: boto3>=1.39.0; extra == 'bedrock'
48
48
  Provides-Extra: cli
@@ -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.0.18; extra == 'evals'
60
+ Requires-Dist: pydantic-evals==1.2.0; extra == 'evals'
61
61
  Provides-Extra: google
62
62
  Requires-Dist: google-genai>=1.31.0; extra == 'google'
63
63
  Provides-Extra: groq
@@ -72,6 +72,8 @@ Provides-Extra: mistral
72
72
  Requires-Dist: mistralai>=1.9.10; extra == 'mistral'
73
73
  Provides-Extra: openai
74
74
  Requires-Dist: openai>=1.107.2; extra == 'openai'
75
+ Provides-Extra: prefect
76
+ Requires-Dist: prefect>=3.4.21; extra == 'prefect'
75
77
  Provides-Extra: retries
76
78
  Requires-Dist: tenacity>=8.2.3; extra == 'retries'
77
79
  Provides-Extra: tavily
@@ -710,6 +710,18 @@ class CallToolsNode(AgentNode[DepsT, NodeRunEndT]):
710
710
  __repr__ = dataclasses_no_defaults_repr
711
711
 
712
712
 
713
+ @dataclasses.dataclass
714
+ class SetFinalResult(AgentNode[DepsT, NodeRunEndT]):
715
+ """A node that immediately ends the graph run after a streaming response produced a final result."""
716
+
717
+ final_result: result.FinalResult[NodeRunEndT]
718
+
719
+ async def run(
720
+ self, ctx: GraphRunContext[GraphAgentState, GraphAgentDeps[DepsT, NodeRunEndT]]
721
+ ) -> End[result.FinalResult[NodeRunEndT]]:
722
+ return End(self.final_result)
723
+
724
+
713
725
  def build_run_context(ctx: GraphRunContext[GraphAgentState, GraphAgentDeps[DepsT, Any]]) -> RunContext[DepsT]:
714
726
  """Build a `RunContext` object from the current agent graph run context."""
715
727
  return RunContext[DepsT](
@@ -1123,6 +1135,7 @@ def build_agent_graph(
1123
1135
  UserPromptNode[DepsT],
1124
1136
  ModelRequestNode[DepsT],
1125
1137
  CallToolsNode[DepsT],
1138
+ SetFinalResult[DepsT],
1126
1139
  )
1127
1140
  graph = Graph[GraphAgentState, GraphAgentDeps[DepsT, Any], result.FinalResult[OutputT]](
1128
1141
  nodes=nodes,
@@ -685,30 +685,53 @@ class Agent(AbstractAgent[AgentDepsT, OutputDataT]):
685
685
  finally:
686
686
  try:
687
687
  if instrumentation_settings and run_span.is_recording():
688
- run_span.set_attributes(self._run_span_end_attributes(state, usage, instrumentation_settings))
688
+ run_span.set_attributes(
689
+ self._run_span_end_attributes(
690
+ instrumentation_settings, usage, state.message_history, graph_deps.new_message_index
691
+ )
692
+ )
689
693
  finally:
690
694
  run_span.end()
691
695
 
692
696
  def _run_span_end_attributes(
693
- self, state: _agent_graph.GraphAgentState, usage: _usage.RunUsage, settings: InstrumentationSettings
697
+ self,
698
+ settings: InstrumentationSettings,
699
+ usage: _usage.RunUsage,
700
+ message_history: list[_messages.ModelMessage],
701
+ new_message_index: int,
694
702
  ):
695
- literal_instructions, _ = self._get_instructions()
696
-
697
703
  if settings.version == 1:
698
704
  attrs = {
699
705
  'all_messages_events': json.dumps(
700
- [
701
- InstrumentedModel.event_to_dict(e)
702
- for e in settings.messages_to_otel_events(state.message_history)
703
- ]
706
+ [InstrumentedModel.event_to_dict(e) for e in settings.messages_to_otel_events(message_history)]
704
707
  )
705
708
  }
706
709
  else:
707
- attrs = {
708
- 'pydantic_ai.all_messages': json.dumps(settings.messages_to_otel_messages(list(state.message_history))),
709
- **settings.system_instructions_attributes(literal_instructions),
710
+ # Store the last instructions here for convenience
711
+ last_instructions = InstrumentedModel._get_instructions(message_history) # pyright: ignore[reportPrivateUsage]
712
+ attrs: dict[str, Any] = {
713
+ 'pydantic_ai.all_messages': json.dumps(settings.messages_to_otel_messages(list(message_history))),
714
+ **settings.system_instructions_attributes(last_instructions),
710
715
  }
711
716
 
717
+ # If this agent run was provided with existing history, store an attribute indicating the point at which the
718
+ # new messages begin.
719
+ if new_message_index > 0:
720
+ attrs['pydantic_ai.new_message_index'] = new_message_index
721
+
722
+ # If the instructions for this agent run were not always the same, store an attribute that indicates that.
723
+ # This can signal to an observability UI that different steps in the agent run had different instructions.
724
+ # Note: We purposely only look at "new" messages because they are the only ones produced by this agent run.
725
+ if any(
726
+ (
727
+ isinstance(m, _messages.ModelRequest)
728
+ and m.instructions is not None
729
+ and m.instructions != last_instructions
730
+ )
731
+ for m in message_history[new_message_index:]
732
+ ):
733
+ attrs['pydantic_ai.variable_instructions'] = True
734
+
712
735
  return {
713
736
  **usage.opentelemetry_attributes(),
714
737
  **attrs,
@@ -716,7 +739,7 @@ class Agent(AbstractAgent[AgentDepsT, OutputDataT]):
716
739
  {
717
740
  'type': 'object',
718
741
  'properties': {
719
- **{attr: {'type': 'array'} for attr in attrs.keys()},
742
+ **{k: {'type': 'array'} if isinstance(v, str) else {} for k, v in attrs.items()},
720
743
  'final_result': {'type': 'object'},
721
744
  },
722
745
  }
@@ -1006,6 +1029,7 @@ class Agent(AbstractAgent[AgentDepsT, OutputDataT]):
1006
1029
  /,
1007
1030
  *,
1008
1031
  name: str | None = None,
1032
+ description: str | None = None,
1009
1033
  retries: int | None = None,
1010
1034
  prepare: ToolPrepareFunc[AgentDepsT] | None = None,
1011
1035
  docstring_format: DocstringFormat = 'auto',
@@ -1023,6 +1047,7 @@ class Agent(AbstractAgent[AgentDepsT, OutputDataT]):
1023
1047
  /,
1024
1048
  *,
1025
1049
  name: str | None = None,
1050
+ description: str | None = None,
1026
1051
  retries: int | None = None,
1027
1052
  prepare: ToolPrepareFunc[AgentDepsT] | None = None,
1028
1053
  docstring_format: DocstringFormat = 'auto',
@@ -1065,6 +1090,7 @@ class Agent(AbstractAgent[AgentDepsT, OutputDataT]):
1065
1090
  Args:
1066
1091
  func: The tool function to register.
1067
1092
  name: The name of the tool, defaults to the function name.
1093
+ description: The description of the tool, defaults to the function docstring.
1068
1094
  retries: The number of retries to allow for this tool, defaults to the agent's default retries,
1069
1095
  which defaults to 1.
1070
1096
  prepare: custom method to prepare the tool definition for each step, return `None` to omit this
@@ -1090,6 +1116,7 @@ class Agent(AbstractAgent[AgentDepsT, OutputDataT]):
1090
1116
  func_,
1091
1117
  takes_ctx=True,
1092
1118
  name=name,
1119
+ description=description,
1093
1120
  retries=retries,
1094
1121
  prepare=prepare,
1095
1122
  docstring_format=docstring_format,
@@ -1113,6 +1140,7 @@ class Agent(AbstractAgent[AgentDepsT, OutputDataT]):
1113
1140
  /,
1114
1141
  *,
1115
1142
  name: str | None = None,
1143
+ description: str | None = None,
1116
1144
  retries: int | None = None,
1117
1145
  prepare: ToolPrepareFunc[AgentDepsT] | None = None,
1118
1146
  docstring_format: DocstringFormat = 'auto',
@@ -1130,6 +1158,7 @@ class Agent(AbstractAgent[AgentDepsT, OutputDataT]):
1130
1158
  /,
1131
1159
  *,
1132
1160
  name: str | None = None,
1161
+ description: str | None = None,
1133
1162
  retries: int | None = None,
1134
1163
  prepare: ToolPrepareFunc[AgentDepsT] | None = None,
1135
1164
  docstring_format: DocstringFormat = 'auto',
@@ -1172,6 +1201,7 @@ class Agent(AbstractAgent[AgentDepsT, OutputDataT]):
1172
1201
  Args:
1173
1202
  func: The tool function to register.
1174
1203
  name: The name of the tool, defaults to the function name.
1204
+ description: The description of the tool, defaults to the function docstring.
1175
1205
  retries: The number of retries to allow for this tool, defaults to the agent's default retries,
1176
1206
  which defaults to 1.
1177
1207
  prepare: custom method to prepare the tool definition for each step, return `None` to omit this
@@ -1195,6 +1225,7 @@ class Agent(AbstractAgent[AgentDepsT, OutputDataT]):
1195
1225
  func_,
1196
1226
  takes_ctx=False,
1197
1227
  name=name,
1228
+ description=description,
1198
1229
  retries=retries,
1199
1230
  prepare=prepare,
1200
1231
  docstring_format=docstring_format,
@@ -524,6 +524,14 @@ class AbstractAgent(Generic[AgentDepsT, OutputDataT], ABC):
524
524
  await stream.get_output(), final_result.tool_name, final_result.tool_call_id
525
525
  )
526
526
 
527
+ # When we get here, the `ModelRequestNode` has completed streaming after the final result was found.
528
+ # When running an agent with `agent.run`, we'd then move to `CallToolsNode` to execute the tool calls and
529
+ # find the final result.
530
+ # We also want to execute tool calls (in case `agent.end_strategy == 'exhaustive'`) here, but
531
+ # we don't want to use run the `CallToolsNode` logic to determine the final output, as it would be
532
+ # wasteful and could produce a different result (e.g. when text output is followed by tool calls).
533
+ # So we call `process_tool_calls` directly and then end the run with the found final result.
534
+
527
535
  parts: list[_messages.ModelRequestPart] = []
528
536
  async for _event in _agent_graph.process_tool_calls(
529
537
  tool_manager=graph_ctx.deps.tool_manager,
@@ -534,9 +542,13 @@ class AbstractAgent(Generic[AgentDepsT, OutputDataT], ABC):
534
542
  output_parts=parts,
535
543
  ):
536
544
  pass
545
+
546
+ # For backwards compatibility, append a new ModelRequest using the tool returns and retries
537
547
  if parts:
538
548
  messages.append(_messages.ModelRequest(parts))
539
549
 
550
+ await agent_run.next(_agent_graph.SetFinalResult(final_result))
551
+
540
552
  yield StreamedRunResult(
541
553
  messages,
542
554
  graph_ctx.deps.new_message_index,
@@ -0,0 +1,15 @@
1
+ from ._agent import PrefectAgent
2
+ from ._cache_policies import DEFAULT_PYDANTIC_AI_CACHE_POLICY
3
+ from ._function_toolset import PrefectFunctionToolset
4
+ from ._mcp_server import PrefectMCPServer
5
+ from ._model import PrefectModel
6
+ from ._types import TaskConfig
7
+
8
+ __all__ = [
9
+ 'PrefectAgent',
10
+ 'PrefectModel',
11
+ 'PrefectMCPServer',
12
+ 'PrefectFunctionToolset',
13
+ 'TaskConfig',
14
+ 'DEFAULT_PYDANTIC_AI_CACHE_POLICY',
15
+ ]