pydantic-ai-slim 1.2.0__tar.gz → 1.3.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.2.0 → pydantic_ai_slim-1.3.0}/PKG-INFO +5 -5
  2. {pydantic_ai_slim-1.2.0 → pydantic_ai_slim-1.3.0}/pydantic_ai/__init__.py +2 -0
  3. {pydantic_ai_slim-1.2.0 → pydantic_ai_slim-1.3.0}/pydantic_ai/_agent_graph.py +31 -6
  4. {pydantic_ai_slim-1.2.0 → pydantic_ai_slim-1.3.0}/pydantic_ai/agent/__init__.py +8 -8
  5. {pydantic_ai_slim-1.2.0 → pydantic_ai_slim-1.3.0}/pydantic_ai/builtin_tools.py +35 -4
  6. {pydantic_ai_slim-1.2.0 → pydantic_ai_slim-1.3.0}/pydantic_ai/exceptions.py +5 -0
  7. {pydantic_ai_slim-1.2.0 → pydantic_ai_slim-1.3.0}/pydantic_ai/mcp.py +1 -22
  8. {pydantic_ai_slim-1.2.0 → pydantic_ai_slim-1.3.0}/pydantic_ai/models/__init__.py +34 -34
  9. {pydantic_ai_slim-1.2.0 → pydantic_ai_slim-1.3.0}/pydantic_ai/models/anthropic.py +2 -2
  10. {pydantic_ai_slim-1.2.0 → pydantic_ai_slim-1.3.0}/pydantic_ai/models/bedrock.py +4 -4
  11. {pydantic_ai_slim-1.2.0 → pydantic_ai_slim-1.3.0}/pydantic_ai/models/cohere.py +0 -7
  12. {pydantic_ai_slim-1.2.0 → pydantic_ai_slim-1.3.0}/pydantic_ai/models/gemini.py +9 -2
  13. {pydantic_ai_slim-1.2.0 → pydantic_ai_slim-1.3.0}/pydantic_ai/models/google.py +5 -7
  14. {pydantic_ai_slim-1.2.0 → pydantic_ai_slim-1.3.0}/pydantic_ai/models/groq.py +4 -4
  15. {pydantic_ai_slim-1.2.0 → pydantic_ai_slim-1.3.0}/pydantic_ai/models/huggingface.py +2 -2
  16. {pydantic_ai_slim-1.2.0 → pydantic_ai_slim-1.3.0}/pydantic_ai/models/openai.py +53 -36
  17. {pydantic_ai_slim-1.2.0 → pydantic_ai_slim-1.3.0}/pydantic_ai/providers/__init__.py +21 -12
  18. {pydantic_ai_slim-1.2.0 → pydantic_ai_slim-1.3.0}/pydantic_ai/providers/bedrock.py +60 -16
  19. {pydantic_ai_slim-1.2.0 → pydantic_ai_slim-1.3.0}/pydantic_ai/providers/gateway.py +60 -72
  20. {pydantic_ai_slim-1.2.0 → pydantic_ai_slim-1.3.0}/pydantic_ai/providers/google.py +61 -23
  21. pydantic_ai_slim-1.3.0/pydantic_ai/providers/ovhcloud.py +95 -0
  22. {pydantic_ai_slim-1.2.0 → pydantic_ai_slim-1.3.0}/pydantic_ai/usage.py +13 -2
  23. {pydantic_ai_slim-1.2.0 → pydantic_ai_slim-1.3.0}/pyproject.toml +2 -2
  24. {pydantic_ai_slim-1.2.0 → pydantic_ai_slim-1.3.0}/.gitignore +0 -0
  25. {pydantic_ai_slim-1.2.0 → pydantic_ai_slim-1.3.0}/LICENSE +0 -0
  26. {pydantic_ai_slim-1.2.0 → pydantic_ai_slim-1.3.0}/README.md +0 -0
  27. {pydantic_ai_slim-1.2.0 → pydantic_ai_slim-1.3.0}/pydantic_ai/__main__.py +0 -0
  28. {pydantic_ai_slim-1.2.0 → pydantic_ai_slim-1.3.0}/pydantic_ai/_a2a.py +0 -0
  29. {pydantic_ai_slim-1.2.0 → pydantic_ai_slim-1.3.0}/pydantic_ai/_cli.py +0 -0
  30. {pydantic_ai_slim-1.2.0 → pydantic_ai_slim-1.3.0}/pydantic_ai/_function_schema.py +0 -0
  31. {pydantic_ai_slim-1.2.0 → pydantic_ai_slim-1.3.0}/pydantic_ai/_griffe.py +0 -0
  32. {pydantic_ai_slim-1.2.0 → pydantic_ai_slim-1.3.0}/pydantic_ai/_instrumentation.py +0 -0
  33. {pydantic_ai_slim-1.2.0 → pydantic_ai_slim-1.3.0}/pydantic_ai/_json_schema.py +0 -0
  34. {pydantic_ai_slim-1.2.0 → pydantic_ai_slim-1.3.0}/pydantic_ai/_mcp.py +0 -0
  35. {pydantic_ai_slim-1.2.0 → pydantic_ai_slim-1.3.0}/pydantic_ai/_otel_messages.py +0 -0
  36. {pydantic_ai_slim-1.2.0 → pydantic_ai_slim-1.3.0}/pydantic_ai/_output.py +0 -0
  37. {pydantic_ai_slim-1.2.0 → pydantic_ai_slim-1.3.0}/pydantic_ai/_parts_manager.py +0 -0
  38. {pydantic_ai_slim-1.2.0 → pydantic_ai_slim-1.3.0}/pydantic_ai/_run_context.py +0 -0
  39. {pydantic_ai_slim-1.2.0 → pydantic_ai_slim-1.3.0}/pydantic_ai/_system_prompt.py +0 -0
  40. {pydantic_ai_slim-1.2.0 → pydantic_ai_slim-1.3.0}/pydantic_ai/_thinking_part.py +0 -0
  41. {pydantic_ai_slim-1.2.0 → pydantic_ai_slim-1.3.0}/pydantic_ai/_tool_manager.py +0 -0
  42. {pydantic_ai_slim-1.2.0 → pydantic_ai_slim-1.3.0}/pydantic_ai/_utils.py +0 -0
  43. {pydantic_ai_slim-1.2.0 → pydantic_ai_slim-1.3.0}/pydantic_ai/ag_ui.py +0 -0
  44. {pydantic_ai_slim-1.2.0 → pydantic_ai_slim-1.3.0}/pydantic_ai/agent/abstract.py +0 -0
  45. {pydantic_ai_slim-1.2.0 → pydantic_ai_slim-1.3.0}/pydantic_ai/agent/wrapper.py +0 -0
  46. {pydantic_ai_slim-1.2.0 → pydantic_ai_slim-1.3.0}/pydantic_ai/common_tools/__init__.py +0 -0
  47. {pydantic_ai_slim-1.2.0 → pydantic_ai_slim-1.3.0}/pydantic_ai/common_tools/duckduckgo.py +0 -0
  48. {pydantic_ai_slim-1.2.0 → pydantic_ai_slim-1.3.0}/pydantic_ai/common_tools/tavily.py +0 -0
  49. {pydantic_ai_slim-1.2.0 → pydantic_ai_slim-1.3.0}/pydantic_ai/direct.py +0 -0
  50. {pydantic_ai_slim-1.2.0 → pydantic_ai_slim-1.3.0}/pydantic_ai/durable_exec/__init__.py +0 -0
  51. {pydantic_ai_slim-1.2.0 → pydantic_ai_slim-1.3.0}/pydantic_ai/durable_exec/dbos/__init__.py +0 -0
  52. {pydantic_ai_slim-1.2.0 → pydantic_ai_slim-1.3.0}/pydantic_ai/durable_exec/dbos/_agent.py +0 -0
  53. {pydantic_ai_slim-1.2.0 → pydantic_ai_slim-1.3.0}/pydantic_ai/durable_exec/dbos/_mcp_server.py +0 -0
  54. {pydantic_ai_slim-1.2.0 → pydantic_ai_slim-1.3.0}/pydantic_ai/durable_exec/dbos/_model.py +0 -0
  55. {pydantic_ai_slim-1.2.0 → pydantic_ai_slim-1.3.0}/pydantic_ai/durable_exec/dbos/_utils.py +0 -0
  56. {pydantic_ai_slim-1.2.0 → pydantic_ai_slim-1.3.0}/pydantic_ai/durable_exec/prefect/__init__.py +0 -0
  57. {pydantic_ai_slim-1.2.0 → pydantic_ai_slim-1.3.0}/pydantic_ai/durable_exec/prefect/_agent.py +0 -0
  58. {pydantic_ai_slim-1.2.0 → pydantic_ai_slim-1.3.0}/pydantic_ai/durable_exec/prefect/_cache_policies.py +0 -0
  59. {pydantic_ai_slim-1.2.0 → pydantic_ai_slim-1.3.0}/pydantic_ai/durable_exec/prefect/_function_toolset.py +0 -0
  60. {pydantic_ai_slim-1.2.0 → pydantic_ai_slim-1.3.0}/pydantic_ai/durable_exec/prefect/_mcp_server.py +0 -0
  61. {pydantic_ai_slim-1.2.0 → pydantic_ai_slim-1.3.0}/pydantic_ai/durable_exec/prefect/_model.py +0 -0
  62. {pydantic_ai_slim-1.2.0 → pydantic_ai_slim-1.3.0}/pydantic_ai/durable_exec/prefect/_toolset.py +0 -0
  63. {pydantic_ai_slim-1.2.0 → pydantic_ai_slim-1.3.0}/pydantic_ai/durable_exec/prefect/_types.py +0 -0
  64. {pydantic_ai_slim-1.2.0 → pydantic_ai_slim-1.3.0}/pydantic_ai/durable_exec/temporal/__init__.py +0 -0
  65. {pydantic_ai_slim-1.2.0 → pydantic_ai_slim-1.3.0}/pydantic_ai/durable_exec/temporal/_agent.py +0 -0
  66. {pydantic_ai_slim-1.2.0 → pydantic_ai_slim-1.3.0}/pydantic_ai/durable_exec/temporal/_function_toolset.py +0 -0
  67. {pydantic_ai_slim-1.2.0 → pydantic_ai_slim-1.3.0}/pydantic_ai/durable_exec/temporal/_logfire.py +0 -0
  68. {pydantic_ai_slim-1.2.0 → pydantic_ai_slim-1.3.0}/pydantic_ai/durable_exec/temporal/_mcp_server.py +0 -0
  69. {pydantic_ai_slim-1.2.0 → pydantic_ai_slim-1.3.0}/pydantic_ai/durable_exec/temporal/_model.py +0 -0
  70. {pydantic_ai_slim-1.2.0 → pydantic_ai_slim-1.3.0}/pydantic_ai/durable_exec/temporal/_run_context.py +0 -0
  71. {pydantic_ai_slim-1.2.0 → pydantic_ai_slim-1.3.0}/pydantic_ai/durable_exec/temporal/_toolset.py +0 -0
  72. {pydantic_ai_slim-1.2.0 → pydantic_ai_slim-1.3.0}/pydantic_ai/ext/__init__.py +0 -0
  73. {pydantic_ai_slim-1.2.0 → pydantic_ai_slim-1.3.0}/pydantic_ai/ext/aci.py +0 -0
  74. {pydantic_ai_slim-1.2.0 → pydantic_ai_slim-1.3.0}/pydantic_ai/ext/langchain.py +0 -0
  75. {pydantic_ai_slim-1.2.0 → pydantic_ai_slim-1.3.0}/pydantic_ai/format_prompt.py +0 -0
  76. {pydantic_ai_slim-1.2.0 → pydantic_ai_slim-1.3.0}/pydantic_ai/messages.py +0 -0
  77. {pydantic_ai_slim-1.2.0 → pydantic_ai_slim-1.3.0}/pydantic_ai/models/fallback.py +0 -0
  78. {pydantic_ai_slim-1.2.0 → pydantic_ai_slim-1.3.0}/pydantic_ai/models/function.py +0 -0
  79. {pydantic_ai_slim-1.2.0 → pydantic_ai_slim-1.3.0}/pydantic_ai/models/instrumented.py +0 -0
  80. {pydantic_ai_slim-1.2.0 → pydantic_ai_slim-1.3.0}/pydantic_ai/models/mcp_sampling.py +0 -0
  81. {pydantic_ai_slim-1.2.0 → pydantic_ai_slim-1.3.0}/pydantic_ai/models/mistral.py +0 -0
  82. {pydantic_ai_slim-1.2.0 → pydantic_ai_slim-1.3.0}/pydantic_ai/models/test.py +0 -0
  83. {pydantic_ai_slim-1.2.0 → pydantic_ai_slim-1.3.0}/pydantic_ai/models/wrapper.py +0 -0
  84. {pydantic_ai_slim-1.2.0 → pydantic_ai_slim-1.3.0}/pydantic_ai/output.py +0 -0
  85. {pydantic_ai_slim-1.2.0 → pydantic_ai_slim-1.3.0}/pydantic_ai/profiles/__init__.py +0 -0
  86. {pydantic_ai_slim-1.2.0 → pydantic_ai_slim-1.3.0}/pydantic_ai/profiles/amazon.py +0 -0
  87. {pydantic_ai_slim-1.2.0 → pydantic_ai_slim-1.3.0}/pydantic_ai/profiles/anthropic.py +0 -0
  88. {pydantic_ai_slim-1.2.0 → pydantic_ai_slim-1.3.0}/pydantic_ai/profiles/cohere.py +0 -0
  89. {pydantic_ai_slim-1.2.0 → pydantic_ai_slim-1.3.0}/pydantic_ai/profiles/deepseek.py +0 -0
  90. {pydantic_ai_slim-1.2.0 → pydantic_ai_slim-1.3.0}/pydantic_ai/profiles/google.py +0 -0
  91. {pydantic_ai_slim-1.2.0 → pydantic_ai_slim-1.3.0}/pydantic_ai/profiles/grok.py +0 -0
  92. {pydantic_ai_slim-1.2.0 → pydantic_ai_slim-1.3.0}/pydantic_ai/profiles/groq.py +0 -0
  93. {pydantic_ai_slim-1.2.0 → pydantic_ai_slim-1.3.0}/pydantic_ai/profiles/harmony.py +0 -0
  94. {pydantic_ai_slim-1.2.0 → pydantic_ai_slim-1.3.0}/pydantic_ai/profiles/meta.py +0 -0
  95. {pydantic_ai_slim-1.2.0 → pydantic_ai_slim-1.3.0}/pydantic_ai/profiles/mistral.py +0 -0
  96. {pydantic_ai_slim-1.2.0 → pydantic_ai_slim-1.3.0}/pydantic_ai/profiles/moonshotai.py +0 -0
  97. {pydantic_ai_slim-1.2.0 → pydantic_ai_slim-1.3.0}/pydantic_ai/profiles/openai.py +0 -0
  98. {pydantic_ai_slim-1.2.0 → pydantic_ai_slim-1.3.0}/pydantic_ai/profiles/qwen.py +0 -0
  99. {pydantic_ai_slim-1.2.0 → pydantic_ai_slim-1.3.0}/pydantic_ai/providers/anthropic.py +0 -0
  100. {pydantic_ai_slim-1.2.0 → pydantic_ai_slim-1.3.0}/pydantic_ai/providers/azure.py +0 -0
  101. {pydantic_ai_slim-1.2.0 → pydantic_ai_slim-1.3.0}/pydantic_ai/providers/cerebras.py +0 -0
  102. {pydantic_ai_slim-1.2.0 → pydantic_ai_slim-1.3.0}/pydantic_ai/providers/cohere.py +0 -0
  103. {pydantic_ai_slim-1.2.0 → pydantic_ai_slim-1.3.0}/pydantic_ai/providers/deepseek.py +0 -0
  104. {pydantic_ai_slim-1.2.0 → pydantic_ai_slim-1.3.0}/pydantic_ai/providers/fireworks.py +0 -0
  105. {pydantic_ai_slim-1.2.0 → pydantic_ai_slim-1.3.0}/pydantic_ai/providers/github.py +0 -0
  106. {pydantic_ai_slim-1.2.0 → pydantic_ai_slim-1.3.0}/pydantic_ai/providers/google_gla.py +0 -0
  107. {pydantic_ai_slim-1.2.0 → pydantic_ai_slim-1.3.0}/pydantic_ai/providers/google_vertex.py +0 -0
  108. {pydantic_ai_slim-1.2.0 → pydantic_ai_slim-1.3.0}/pydantic_ai/providers/grok.py +0 -0
  109. {pydantic_ai_slim-1.2.0 → pydantic_ai_slim-1.3.0}/pydantic_ai/providers/groq.py +0 -0
  110. {pydantic_ai_slim-1.2.0 → pydantic_ai_slim-1.3.0}/pydantic_ai/providers/heroku.py +0 -0
  111. {pydantic_ai_slim-1.2.0 → pydantic_ai_slim-1.3.0}/pydantic_ai/providers/huggingface.py +0 -0
  112. {pydantic_ai_slim-1.2.0 → pydantic_ai_slim-1.3.0}/pydantic_ai/providers/litellm.py +0 -0
  113. {pydantic_ai_slim-1.2.0 → pydantic_ai_slim-1.3.0}/pydantic_ai/providers/mistral.py +0 -0
  114. {pydantic_ai_slim-1.2.0 → pydantic_ai_slim-1.3.0}/pydantic_ai/providers/moonshotai.py +0 -0
  115. {pydantic_ai_slim-1.2.0 → pydantic_ai_slim-1.3.0}/pydantic_ai/providers/nebius.py +0 -0
  116. {pydantic_ai_slim-1.2.0 → pydantic_ai_slim-1.3.0}/pydantic_ai/providers/ollama.py +0 -0
  117. {pydantic_ai_slim-1.2.0 → pydantic_ai_slim-1.3.0}/pydantic_ai/providers/openai.py +0 -0
  118. {pydantic_ai_slim-1.2.0 → pydantic_ai_slim-1.3.0}/pydantic_ai/providers/openrouter.py +0 -0
  119. {pydantic_ai_slim-1.2.0 → pydantic_ai_slim-1.3.0}/pydantic_ai/providers/together.py +0 -0
  120. {pydantic_ai_slim-1.2.0 → pydantic_ai_slim-1.3.0}/pydantic_ai/providers/vercel.py +0 -0
  121. {pydantic_ai_slim-1.2.0 → pydantic_ai_slim-1.3.0}/pydantic_ai/py.typed +0 -0
  122. {pydantic_ai_slim-1.2.0 → pydantic_ai_slim-1.3.0}/pydantic_ai/result.py +0 -0
  123. {pydantic_ai_slim-1.2.0 → pydantic_ai_slim-1.3.0}/pydantic_ai/retries.py +0 -0
  124. {pydantic_ai_slim-1.2.0 → pydantic_ai_slim-1.3.0}/pydantic_ai/run.py +0 -0
  125. {pydantic_ai_slim-1.2.0 → pydantic_ai_slim-1.3.0}/pydantic_ai/settings.py +0 -0
  126. {pydantic_ai_slim-1.2.0 → pydantic_ai_slim-1.3.0}/pydantic_ai/tools.py +0 -0
  127. {pydantic_ai_slim-1.2.0 → pydantic_ai_slim-1.3.0}/pydantic_ai/toolsets/__init__.py +0 -0
  128. {pydantic_ai_slim-1.2.0 → pydantic_ai_slim-1.3.0}/pydantic_ai/toolsets/_dynamic.py +0 -0
  129. {pydantic_ai_slim-1.2.0 → pydantic_ai_slim-1.3.0}/pydantic_ai/toolsets/abstract.py +0 -0
  130. {pydantic_ai_slim-1.2.0 → pydantic_ai_slim-1.3.0}/pydantic_ai/toolsets/approval_required.py +0 -0
  131. {pydantic_ai_slim-1.2.0 → pydantic_ai_slim-1.3.0}/pydantic_ai/toolsets/combined.py +0 -0
  132. {pydantic_ai_slim-1.2.0 → pydantic_ai_slim-1.3.0}/pydantic_ai/toolsets/external.py +0 -0
  133. {pydantic_ai_slim-1.2.0 → pydantic_ai_slim-1.3.0}/pydantic_ai/toolsets/filtered.py +0 -0
  134. {pydantic_ai_slim-1.2.0 → pydantic_ai_slim-1.3.0}/pydantic_ai/toolsets/function.py +0 -0
  135. {pydantic_ai_slim-1.2.0 → pydantic_ai_slim-1.3.0}/pydantic_ai/toolsets/prefixed.py +0 -0
  136. {pydantic_ai_slim-1.2.0 → pydantic_ai_slim-1.3.0}/pydantic_ai/toolsets/prepared.py +0 -0
  137. {pydantic_ai_slim-1.2.0 → pydantic_ai_slim-1.3.0}/pydantic_ai/toolsets/renamed.py +0 -0
  138. {pydantic_ai_slim-1.2.0 → pydantic_ai_slim-1.3.0}/pydantic_ai/toolsets/wrapper.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: pydantic-ai-slim
3
- Version: 1.2.0
3
+ Version: 1.3.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.31
32
+ 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.2.0
36
+ Requires-Dist: pydantic-graph==1.3.0
37
37
  Requires-Dist: pydantic>=2.10
38
38
  Requires-Dist: typing-inspection>=0.4.0
39
39
  Provides-Extra: a2a
@@ -57,9 +57,9 @@ 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.2.0; extra == 'evals'
60
+ Requires-Dist: pydantic-evals==1.3.0; extra == 'evals'
61
61
  Provides-Extra: google
62
- Requires-Dist: google-genai>=1.31.0; extra == 'google'
62
+ Requires-Dist: google-genai>=1.46.0; extra == 'google'
63
63
  Provides-Extra: groq
64
64
  Requires-Dist: groq>=0.25.0; extra == 'groq'
65
65
  Provides-Extra: huggingface
@@ -22,6 +22,7 @@ from .exceptions import (
22
22
  ApprovalRequired,
23
23
  CallDeferred,
24
24
  FallbackExceptionGroup,
25
+ IncompleteToolCall,
25
26
  ModelHTTPError,
26
27
  ModelRetry,
27
28
  UnexpectedModelBehavior,
@@ -124,6 +125,7 @@ __all__ = (
124
125
  'ModelRetry',
125
126
  'ModelHTTPError',
126
127
  'FallbackExceptionGroup',
128
+ 'IncompleteToolCall',
127
129
  'UnexpectedModelBehavior',
128
130
  'UsageLimitExceeded',
129
131
  'UserError',
@@ -92,9 +92,28 @@ class GraphAgentState:
92
92
  retries: int = 0
93
93
  run_step: int = 0
94
94
 
95
- def increment_retries(self, max_result_retries: int, error: BaseException | None = None) -> None:
95
+ def increment_retries(
96
+ self,
97
+ max_result_retries: int,
98
+ error: BaseException | None = None,
99
+ model_settings: ModelSettings | None = None,
100
+ ) -> None:
96
101
  self.retries += 1
97
102
  if self.retries > max_result_retries:
103
+ if (
104
+ self.message_history
105
+ and isinstance(model_response := self.message_history[-1], _messages.ModelResponse)
106
+ and model_response.finish_reason == 'length'
107
+ and model_response.parts
108
+ and isinstance(tool_call := model_response.parts[-1], _messages.ToolCallPart)
109
+ ):
110
+ try:
111
+ tool_call.args_as_dict()
112
+ except Exception:
113
+ max_tokens = (model_settings or {}).get('max_tokens') if model_settings else None
114
+ raise exceptions.IncompleteToolCall(
115
+ f'Model token limit ({max_tokens if max_tokens is not None else "provider default"}) exceeded while emitting a tool call, resulting in incomplete arguments. Increase max tokens or simplify tool call arguments to fit within limit.'
116
+ )
98
117
  message = f'Exceeded maximum retries ({max_result_retries}) for output validation'
99
118
  if error:
100
119
  if isinstance(error, exceptions.UnexpectedModelBehavior) and error.__cause__ is not None:
@@ -568,7 +587,7 @@ class CallToolsNode(AgentNode[DepsT, NodeRunEndT]):
568
587
  # resubmit the most recent request that resulted in an empty response,
569
588
  # as the empty response and request will not create any items in the API payload,
570
589
  # in the hope the model will return a non-empty response this time.
571
- ctx.state.increment_retries(ctx.deps.max_result_retries)
590
+ ctx.state.increment_retries(ctx.deps.max_result_retries, model_settings=ctx.deps.model_settings)
572
591
  self._next_node = ModelRequestNode[DepsT, NodeRunEndT](_messages.ModelRequest(parts=[]))
573
592
  return
574
593
 
@@ -630,7 +649,9 @@ class CallToolsNode(AgentNode[DepsT, NodeRunEndT]):
630
649
  )
631
650
  raise ToolRetryError(m)
632
651
  except ToolRetryError as e:
633
- ctx.state.increment_retries(ctx.deps.max_result_retries, e)
652
+ ctx.state.increment_retries(
653
+ ctx.deps.max_result_retries, error=e, model_settings=ctx.deps.model_settings
654
+ )
634
655
  self._next_node = ModelRequestNode[DepsT, NodeRunEndT](_messages.ModelRequest(parts=[e.tool_retry]))
635
656
 
636
657
  self._events_iterator = _run_stream()
@@ -788,10 +809,14 @@ async def process_tool_calls( # noqa: C901
788
809
  try:
789
810
  result_data = await tool_manager.handle_call(call)
790
811
  except exceptions.UnexpectedModelBehavior as e:
791
- ctx.state.increment_retries(ctx.deps.max_result_retries, e)
812
+ ctx.state.increment_retries(
813
+ ctx.deps.max_result_retries, error=e, model_settings=ctx.deps.model_settings
814
+ )
792
815
  raise e # pragma: lax no cover
793
816
  except ToolRetryError as e:
794
- ctx.state.increment_retries(ctx.deps.max_result_retries, e)
817
+ ctx.state.increment_retries(
818
+ ctx.deps.max_result_retries, error=e, model_settings=ctx.deps.model_settings
819
+ )
795
820
  yield _messages.FunctionToolCallEvent(call)
796
821
  output_parts.append(e.tool_retry)
797
822
  yield _messages.FunctionToolResultEvent(e.tool_retry)
@@ -820,7 +845,7 @@ async def process_tool_calls( # noqa: C901
820
845
 
821
846
  # Then, we handle unknown tool calls
822
847
  if tool_calls_by_kind['unknown']:
823
- ctx.state.increment_retries(ctx.deps.max_result_retries)
848
+ ctx.state.increment_retries(ctx.deps.max_result_retries, model_settings=ctx.deps.model_settings)
824
849
  calls_to_run.extend(tool_calls_by_kind['unknown'])
825
850
 
826
851
  calls_to_run_results: dict[str, DeferredToolResult] = {}
@@ -662,14 +662,14 @@ class Agent(AbstractAgent[AgentDepsT, OutputDataT]):
662
662
  )
663
663
 
664
664
  try:
665
- async with toolset:
666
- async with graph.iter(
667
- start_node,
668
- state=state,
669
- deps=graph_deps,
670
- span=use_span(run_span) if run_span.is_recording() else None,
671
- infer_name=False,
672
- ) as graph_run:
665
+ async with graph.iter(
666
+ start_node,
667
+ state=state,
668
+ deps=graph_deps,
669
+ span=use_span(run_span) if run_span.is_recording() else None,
670
+ infer_name=False,
671
+ ) as graph_run:
672
+ async with toolset:
673
673
  agent_run = AgentRun(graph_run)
674
674
  yield agent_run
675
675
  if (final_result := agent_run.result) is not None and run_span.is_recording():
@@ -2,13 +2,12 @@ from __future__ import annotations as _annotations
2
2
 
3
3
  from abc import ABC
4
4
  from dataclasses import dataclass
5
- from typing import TYPE_CHECKING, Literal
5
+ from typing import Annotated, Any, Literal, Union
6
6
 
7
+ import pydantic
8
+ from pydantic_core import core_schema
7
9
  from typing_extensions import TypedDict
8
10
 
9
- if TYPE_CHECKING:
10
- from .builtin_tools import AbstractBuiltinTool
11
-
12
11
  __all__ = (
13
12
  'AbstractBuiltinTool',
14
13
  'WebSearchTool',
@@ -19,6 +18,8 @@ __all__ = (
19
18
  'MemoryTool',
20
19
  )
21
20
 
21
+ _BUILTIN_TOOL_TYPES: dict[str, type[AbstractBuiltinTool]] = {}
22
+
22
23
 
23
24
  @dataclass(kw_only=True)
24
25
  class AbstractBuiltinTool(ABC):
@@ -32,6 +33,26 @@ class AbstractBuiltinTool(ABC):
32
33
  kind: str = 'unknown_builtin_tool'
33
34
  """Built-in tool identifier, this should be available on all built-in tools as a discriminator."""
34
35
 
36
+ def __init_subclass__(cls, **kwargs: Any) -> None:
37
+ super().__init_subclass__(**kwargs)
38
+ _BUILTIN_TOOL_TYPES[cls.kind] = cls
39
+
40
+ @classmethod
41
+ def __get_pydantic_core_schema__(
42
+ cls, _source_type: Any, handler: pydantic.GetCoreSchemaHandler
43
+ ) -> core_schema.CoreSchema:
44
+ if cls is not AbstractBuiltinTool:
45
+ return handler(cls)
46
+
47
+ tools = _BUILTIN_TOOL_TYPES.values()
48
+ if len(tools) == 1: # pragma: no cover
49
+ tools_type = next(iter(tools))
50
+ else:
51
+ tools_annotated = [Annotated[tool, pydantic.Tag(tool.kind)] for tool in tools]
52
+ tools_type = Annotated[Union[tuple(tools_annotated)], pydantic.Discriminator(_tool_discriminator)] # noqa: UP007
53
+
54
+ return handler(tools_type)
55
+
35
56
 
36
57
  @dataclass(kw_only=True)
37
58
  class WebSearchTool(AbstractBuiltinTool):
@@ -120,6 +141,7 @@ class WebSearchUserLocation(TypedDict, total=False):
120
141
  """The timezone of the user's location."""
121
142
 
122
143
 
144
+ @dataclass(kw_only=True)
123
145
  class CodeExecutionTool(AbstractBuiltinTool):
124
146
  """A builtin tool that allows your agent to execute code.
125
147
 
@@ -134,6 +156,7 @@ class CodeExecutionTool(AbstractBuiltinTool):
134
156
  """The kind of tool."""
135
157
 
136
158
 
159
+ @dataclass(kw_only=True)
137
160
  class UrlContextTool(AbstractBuiltinTool):
138
161
  """Allows your agent to access contents from URLs.
139
162
 
@@ -227,6 +250,7 @@ class ImageGenerationTool(AbstractBuiltinTool):
227
250
  """The kind of tool."""
228
251
 
229
252
 
253
+ @dataclass(kw_only=True)
230
254
  class MemoryTool(AbstractBuiltinTool):
231
255
  """A builtin tool that allows your agent to use memory.
232
256
 
@@ -237,3 +261,10 @@ class MemoryTool(AbstractBuiltinTool):
237
261
 
238
262
  kind: str = 'memory'
239
263
  """The kind of tool."""
264
+
265
+
266
+ def _tool_discriminator(tool_data: dict[str, Any] | AbstractBuiltinTool) -> str:
267
+ if isinstance(tool_data, dict):
268
+ return tool_data.get('kind', AbstractBuiltinTool.kind)
269
+ else:
270
+ return tool_data.kind
@@ -23,6 +23,7 @@ __all__ = (
23
23
  'UnexpectedModelBehavior',
24
24
  'UsageLimitExceeded',
25
25
  'ModelHTTPError',
26
+ 'IncompleteToolCall',
26
27
  'FallbackExceptionGroup',
27
28
  )
28
29
 
@@ -168,3 +169,7 @@ class ToolRetryError(Exception):
168
169
  def __init__(self, tool_retry: RetryPromptPart):
169
170
  self.tool_retry = tool_retry
170
171
  super().__init__()
172
+
173
+
174
+ class IncompleteToolCall(UnexpectedModelBehavior):
175
+ """Error raised when a model stops due to token limit while emitting a tool call."""
@@ -441,14 +441,9 @@ class MCPServerStdio(MCPServer):
441
441
  'uv', args=['run', 'mcp-run-python', 'stdio'], timeout=10
442
442
  )
443
443
  agent = Agent('openai:gpt-4o', toolsets=[server])
444
-
445
- async def main():
446
- async with agent: # (2)!
447
- ...
448
444
  ```
449
445
 
450
446
  1. See [MCP Run Python](https://github.com/pydantic/mcp-run-python) for more information.
451
- 2. This will start the server as a subprocess and connect to it.
452
447
  """
453
448
 
454
449
  command: str
@@ -788,13 +783,7 @@ class MCPServerSSE(_MCPServerHTTP):
788
783
 
789
784
  server = MCPServerSSE('http://localhost:3001/sse')
790
785
  agent = Agent('openai:gpt-4o', toolsets=[server])
791
-
792
- async def main():
793
- async with agent: # (1)!
794
- ...
795
786
  ```
796
-
797
- 1. This will connect to a server running on `localhost:3001`.
798
787
  """
799
788
 
800
789
  @classmethod
@@ -837,13 +826,7 @@ class MCPServerHTTP(MCPServerSSE):
837
826
 
838
827
  server = MCPServerHTTP('http://localhost:3001/sse')
839
828
  agent = Agent('openai:gpt-4o', toolsets=[server])
840
-
841
- async def main():
842
- async with agent: # (2)!
843
- ...
844
829
  ```
845
-
846
- 1. This will connect to a server running on `localhost:3001`.
847
830
  """
848
831
 
849
832
 
@@ -862,12 +845,8 @@ class MCPServerStreamableHTTP(_MCPServerHTTP):
862
845
  from pydantic_ai import Agent
863
846
  from pydantic_ai.mcp import MCPServerStreamableHTTP
864
847
 
865
- server = MCPServerStreamableHTTP('http://localhost:8000/mcp') # (1)!
848
+ server = MCPServerStreamableHTTP('http://localhost:8000/mcp')
866
849
  agent = Agent('openai:gpt-4o', toolsets=[server])
867
-
868
- async def main():
869
- async with agent: # (2)!
870
- ...
871
850
  ```
872
851
  """
873
852
 
@@ -43,6 +43,7 @@ from ..messages import (
43
43
  )
44
44
  from ..output import OutputMode
45
45
  from ..profiles import DEFAULT_PROFILE, ModelProfile, ModelProfileSpec
46
+ from ..providers import infer_provider
46
47
  from ..settings import ModelSettings, merge_model_settings
47
48
  from ..tools import ToolDefinition
48
49
  from ..usage import RequestUsage
@@ -129,15 +130,8 @@ KnownModelName = TypeAliasType(
129
130
  'cerebras:qwen-3-235b-a22b-thinking-2507',
130
131
  'cohere:c4ai-aya-expanse-32b',
131
132
  'cohere:c4ai-aya-expanse-8b',
132
- 'cohere:command',
133
- 'cohere:command-light',
134
- 'cohere:command-light-nightly',
135
133
  'cohere:command-nightly',
136
- 'cohere:command-r',
137
- 'cohere:command-r-03-2024',
138
134
  'cohere:command-r-08-2024',
139
- 'cohere:command-r-plus',
140
- 'cohere:command-r-plus-04-2024',
141
135
  'cohere:command-r-plus-08-2024',
142
136
  'cohere:command-r7b-12-2024',
143
137
  'deepseek:deepseek-chat',
@@ -644,41 +638,39 @@ def infer_model(model: Model | KnownModelName | str) -> Model: # noqa: C901
644
638
  return TestModel()
645
639
 
646
640
  try:
647
- provider, model_name = model.split(':', maxsplit=1)
641
+ provider_name, model_name = model.split(':', maxsplit=1)
648
642
  except ValueError:
649
- provider = None
643
+ provider_name = None
650
644
  model_name = model
651
645
  if model_name.startswith(('gpt', 'o1', 'o3')):
652
- provider = 'openai'
646
+ provider_name = 'openai'
653
647
  elif model_name.startswith('claude'):
654
- provider = 'anthropic'
648
+ provider_name = 'anthropic'
655
649
  elif model_name.startswith('gemini'):
656
- provider = 'google-gla'
650
+ provider_name = 'google-gla'
657
651
 
658
- if provider is not None:
652
+ if provider_name is not None:
659
653
  warnings.warn(
660
- f"Specifying a model name without a provider prefix is deprecated. Instead of {model_name!r}, use '{provider}:{model_name}'.",
654
+ f"Specifying a model name without a provider prefix is deprecated. Instead of {model_name!r}, use '{provider_name}:{model_name}'.",
661
655
  DeprecationWarning,
662
656
  )
663
657
  else:
664
658
  raise UserError(f'Unknown model: {model}')
665
659
 
666
- if provider == 'vertexai': # pragma: no cover
660
+ if provider_name == 'vertexai': # pragma: no cover
667
661
  warnings.warn(
668
662
  "The 'vertexai' provider name is deprecated. Use 'google-vertex' instead.",
669
663
  DeprecationWarning,
670
664
  )
671
- provider = 'google-vertex'
665
+ provider_name = 'google-vertex'
672
666
 
673
- if provider == 'gateway':
674
- from ..providers.gateway import infer_model as infer_model_from_gateway
667
+ provider = infer_provider(provider_name)
675
668
 
676
- return infer_model_from_gateway(model_name)
677
- elif provider == 'cohere':
678
- from .cohere import CohereModel
679
-
680
- return CohereModel(model_name, provider=provider)
681
- elif provider in (
669
+ model_kind = provider_name
670
+ if model_kind.startswith('gateway/'):
671
+ model_kind = provider_name.removeprefix('gateway/')
672
+ if model_kind in (
673
+ 'openai',
682
674
  'azure',
683
675
  'deepseek',
684
676
  'cerebras',
@@ -688,42 +680,50 @@ def infer_model(model: Model | KnownModelName | str) -> Model: # noqa: C901
688
680
  'heroku',
689
681
  'moonshotai',
690
682
  'ollama',
691
- 'openai',
692
- 'openai-chat',
693
683
  'openrouter',
694
684
  'together',
695
685
  'vercel',
696
686
  'litellm',
697
687
  'nebius',
688
+ 'ovhcloud',
698
689
  ):
690
+ model_kind = 'openai-chat'
691
+ elif model_kind in ('google-gla', 'google-vertex'):
692
+ model_kind = 'google'
693
+
694
+ if model_kind == 'openai-chat':
699
695
  from .openai import OpenAIChatModel
700
696
 
701
697
  return OpenAIChatModel(model_name, provider=provider)
702
- elif provider == 'openai-responses':
698
+ elif model_kind == 'openai-responses':
703
699
  from .openai import OpenAIResponsesModel
704
700
 
705
- return OpenAIResponsesModel(model_name, provider='openai')
706
- elif provider in ('google-gla', 'google-vertex'):
701
+ return OpenAIResponsesModel(model_name, provider=provider)
702
+ elif model_kind == 'google':
707
703
  from .google import GoogleModel
708
704
 
709
705
  return GoogleModel(model_name, provider=provider)
710
- elif provider == 'groq':
706
+ elif model_kind == 'groq':
711
707
  from .groq import GroqModel
712
708
 
713
709
  return GroqModel(model_name, provider=provider)
714
- elif provider == 'mistral':
710
+ elif model_kind == 'cohere':
711
+ from .cohere import CohereModel
712
+
713
+ return CohereModel(model_name, provider=provider)
714
+ elif model_kind == 'mistral':
715
715
  from .mistral import MistralModel
716
716
 
717
717
  return MistralModel(model_name, provider=provider)
718
- elif provider == 'anthropic':
718
+ elif model_kind == 'anthropic':
719
719
  from .anthropic import AnthropicModel
720
720
 
721
721
  return AnthropicModel(model_name, provider=provider)
722
- elif provider == 'bedrock':
722
+ elif model_kind == 'bedrock':
723
723
  from .bedrock import BedrockConverseModel
724
724
 
725
725
  return BedrockConverseModel(model_name, provider=provider)
726
- elif provider == 'huggingface':
726
+ elif model_kind == 'huggingface':
727
727
  from .huggingface import HuggingFaceModel
728
728
 
729
729
  return HuggingFaceModel(model_name, provider=provider)
@@ -162,7 +162,7 @@ class AnthropicModel(Model):
162
162
  self,
163
163
  model_name: AnthropicModelName,
164
164
  *,
165
- provider: Literal['anthropic'] | Provider[AsyncAnthropicClient] = 'anthropic',
165
+ provider: Literal['anthropic', 'gateway'] | Provider[AsyncAnthropicClient] = 'anthropic',
166
166
  profile: ModelProfileSpec | None = None,
167
167
  settings: ModelSettings | None = None,
168
168
  ):
@@ -179,7 +179,7 @@ class AnthropicModel(Model):
179
179
  self._model_name = model_name
180
180
 
181
181
  if isinstance(provider, str):
182
- provider = infer_provider(provider)
182
+ provider = infer_provider('gateway/anthropic' if provider == 'gateway' else provider)
183
183
  self._provider = provider
184
184
  self.client = provider.client
185
185
 
@@ -207,7 +207,7 @@ class BedrockConverseModel(Model):
207
207
  self,
208
208
  model_name: BedrockModelName,
209
209
  *,
210
- provider: Literal['bedrock'] | Provider[BaseClient] = 'bedrock',
210
+ provider: Literal['bedrock', 'gateway'] | Provider[BaseClient] = 'bedrock',
211
211
  profile: ModelProfileSpec | None = None,
212
212
  settings: ModelSettings | None = None,
213
213
  ):
@@ -226,7 +226,7 @@ class BedrockConverseModel(Model):
226
226
  self._model_name = model_name
227
227
 
228
228
  if isinstance(provider, str):
229
- provider = infer_provider(provider)
229
+ provider = infer_provider('gateway/bedrock' if provider == 'gateway' else provider)
230
230
  self._provider = provider
231
231
  self.client = cast('BedrockRuntimeClient', provider.client)
232
232
 
@@ -701,8 +701,8 @@ class BedrockStreamedResponse(StreamedResponse):
701
701
  signature=signature,
702
702
  provider_name=self.provider_name if signature else None,
703
703
  )
704
- if 'text' in delta:
705
- maybe_event = self._parts_manager.handle_text_delta(vendor_part_id=index, content=delta['text'])
704
+ if text := delta.get('text'):
705
+ maybe_event = self._parts_manager.handle_text_delta(vendor_part_id=index, content=text)
706
706
  if maybe_event is not None: # pragma: no branch
707
707
  yield maybe_event
708
708
  if 'toolUse' in delta:
@@ -62,15 +62,8 @@ except ImportError as _import_error:
62
62
  LatestCohereModelNames = Literal[
63
63
  'c4ai-aya-expanse-32b',
64
64
  'c4ai-aya-expanse-8b',
65
- 'command',
66
- 'command-light',
67
- 'command-light-nightly',
68
65
  'command-nightly',
69
- 'command-r',
70
- 'command-r-03-2024',
71
66
  'command-r-08-2024',
72
- 'command-r-plus',
73
- 'command-r-plus-04-2024',
74
67
  'command-r-plus-08-2024',
75
68
  'command-r7b-12-2024',
76
69
  ]
@@ -38,7 +38,7 @@ from ..messages import (
38
38
  VideoUrl,
39
39
  )
40
40
  from ..profiles import ModelProfileSpec
41
- from ..providers import Provider, infer_provider
41
+ from ..providers import Provider
42
42
  from ..settings import ModelSettings
43
43
  from ..tools import ToolDefinition
44
44
  from . import Model, ModelRequestParameters, StreamedResponse, check_allow_model_requests, download_item, get_user_agent
@@ -131,7 +131,14 @@ class GeminiModel(Model):
131
131
  self._model_name = model_name
132
132
 
133
133
  if isinstance(provider, str):
134
- provider = infer_provider(provider)
134
+ if provider == 'google-gla':
135
+ from pydantic_ai.providers.google_gla import GoogleGLAProvider # type: ignore[reportDeprecated]
136
+
137
+ provider = GoogleGLAProvider() # type: ignore[reportDeprecated]
138
+ else:
139
+ from pydantic_ai.providers.google_vertex import GoogleVertexProvider # type: ignore[reportDeprecated]
140
+
141
+ provider = GoogleVertexProvider() # type: ignore[reportDeprecated]
135
142
  self._provider = provider
136
143
  self.client = provider.client
137
144
  self._url = str(self.client.base_url)
@@ -37,7 +37,7 @@ from ..messages import (
37
37
  VideoUrl,
38
38
  )
39
39
  from ..profiles import ModelProfileSpec
40
- from ..providers import Provider
40
+ from ..providers import Provider, infer_provider
41
41
  from ..settings import ModelSettings
42
42
  from ..tools import ToolDefinition
43
43
  from . import (
@@ -85,8 +85,6 @@ try:
85
85
  UrlContextDict,
86
86
  VideoMetadataDict,
87
87
  )
88
-
89
- from ..providers.google import GoogleProvider
90
88
  except ImportError as _import_error:
91
89
  raise ImportError(
92
90
  'Please install `google-genai` to use the Google model, '
@@ -187,7 +185,7 @@ class GoogleModel(Model):
187
185
  self,
188
186
  model_name: GoogleModelName,
189
187
  *,
190
- provider: Literal['google-gla', 'google-vertex'] | Provider[Client] = 'google-gla',
188
+ provider: Literal['google-gla', 'google-vertex', 'gateway'] | Provider[Client] = 'google-gla',
191
189
  profile: ModelProfileSpec | None = None,
192
190
  settings: ModelSettings | None = None,
193
191
  ):
@@ -196,15 +194,15 @@ class GoogleModel(Model):
196
194
  Args:
197
195
  model_name: The name of the model to use.
198
196
  provider: The provider to use for authentication and API access. Can be either the string
199
- 'google-gla' or 'google-vertex' or an instance of `Provider[httpx.AsyncClient]`.
200
- If not provided, a new provider will be created using the other parameters.
197
+ 'google-gla' or 'google-vertex' or an instance of `Provider[google.genai.AsyncClient]`.
198
+ Defaults to 'google-gla'.
201
199
  profile: The model profile to use. Defaults to a profile picked by the provider based on the model name.
202
200
  settings: The model settings to use. Defaults to None.
203
201
  """
204
202
  self._model_name = model_name
205
203
 
206
204
  if isinstance(provider, str):
207
- provider = GoogleProvider(vertexai=provider == 'google-vertex')
205
+ provider = infer_provider('gateway/google-vertex' if provider == 'gateway' else provider)
208
206
  self._provider = provider
209
207
  self.client = provider.client
210
208
 
@@ -141,7 +141,7 @@ class GroqModel(Model):
141
141
  self,
142
142
  model_name: GroqModelName,
143
143
  *,
144
- provider: Literal['groq'] | Provider[AsyncGroq] = 'groq',
144
+ provider: Literal['groq', 'gateway'] | Provider[AsyncGroq] = 'groq',
145
145
  profile: ModelProfileSpec | None = None,
146
146
  settings: ModelSettings | None = None,
147
147
  ):
@@ -159,7 +159,7 @@ class GroqModel(Model):
159
159
  self._model_name = model_name
160
160
 
161
161
  if isinstance(provider, str):
162
- provider = infer_provider(provider)
162
+ provider = infer_provider('gateway/groq' if provider == 'gateway' else provider)
163
163
  self._provider = provider
164
164
  self.client = provider.client
165
165
 
@@ -330,7 +330,7 @@ class GroqModel(Model):
330
330
  if call_part and return_part: # pragma: no branch
331
331
  items.append(call_part)
332
332
  items.append(return_part)
333
- if choice.message.content is not None:
333
+ if choice.message.content:
334
334
  # NOTE: The `<think>` tag is only present if `groq_reasoning_format` is set to `raw`.
335
335
  items.extend(split_content_into_text_and_thinking(choice.message.content, self.profile.thinking_tags))
336
336
  if choice.message.tool_calls is not None:
@@ -563,7 +563,7 @@ class GroqStreamedResponse(StreamedResponse):
563
563
 
564
564
  # Handle the text part of the response
565
565
  content = choice.delta.content
566
- if content is not None:
566
+ if content:
567
567
  maybe_event = self._parts_manager.handle_text_delta(
568
568
  vendor_part_id='content',
569
569
  content=content,
@@ -277,7 +277,7 @@ class HuggingFaceModel(Model):
277
277
 
278
278
  items: list[ModelResponsePart] = []
279
279
 
280
- if content is not None:
280
+ if content:
281
281
  items.extend(split_content_into_text_and_thinking(content, self.profile.thinking_tags))
282
282
  if tool_calls is not None:
283
283
  for c in tool_calls:
@@ -482,7 +482,7 @@ class HuggingFaceStreamedResponse(StreamedResponse):
482
482
 
483
483
  # Handle the text part of the response
484
484
  content = choice.delta.content
485
- if content is not None:
485
+ if content:
486
486
  maybe_event = self._parts_manager.handle_text_delta(
487
487
  vendor_part_id='content',
488
488
  content=content,