pydantic-ai-slim 1.7.0__tar.gz → 1.9.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.
- {pydantic_ai_slim-1.7.0 → pydantic_ai_slim-1.9.0}/.gitignore +1 -1
- {pydantic_ai_slim-1.7.0 → pydantic_ai_slim-1.9.0}/PKG-INFO +5 -3
- {pydantic_ai_slim-1.7.0 → pydantic_ai_slim-1.9.0}/pydantic_ai/__init__.py +2 -0
- {pydantic_ai_slim-1.7.0 → pydantic_ai_slim-1.9.0}/pydantic_ai/_agent_graph.py +3 -0
- {pydantic_ai_slim-1.7.0 → pydantic_ai_slim-1.9.0}/pydantic_ai/_cli.py +2 -2
- pydantic_ai_slim-1.9.0/pydantic_ai/ag_ui.py +163 -0
- {pydantic_ai_slim-1.7.0 → pydantic_ai_slim-1.9.0}/pydantic_ai/agent/abstract.py +17 -6
- {pydantic_ai_slim-1.7.0 → pydantic_ai_slim-1.9.0}/pydantic_ai/direct.py +16 -4
- {pydantic_ai_slim-1.7.0 → pydantic_ai_slim-1.9.0}/pydantic_ai/durable_exec/dbos/_agent.py +3 -0
- {pydantic_ai_slim-1.7.0 → pydantic_ai_slim-1.9.0}/pydantic_ai/durable_exec/prefect/_agent.py +3 -0
- {pydantic_ai_slim-1.7.0 → pydantic_ai_slim-1.9.0}/pydantic_ai/durable_exec/temporal/_agent.py +3 -0
- {pydantic_ai_slim-1.7.0 → pydantic_ai_slim-1.9.0}/pydantic_ai/messages.py +39 -7
- {pydantic_ai_slim-1.7.0 → pydantic_ai_slim-1.9.0}/pydantic_ai/models/__init__.py +42 -1
- {pydantic_ai_slim-1.7.0 → pydantic_ai_slim-1.9.0}/pydantic_ai/models/groq.py +9 -1
- {pydantic_ai_slim-1.7.0 → pydantic_ai_slim-1.9.0}/pydantic_ai/models/openai.py +2 -3
- {pydantic_ai_slim-1.7.0 → pydantic_ai_slim-1.9.0}/pydantic_ai/result.py +19 -7
- pydantic_ai_slim-1.9.0/pydantic_ai/ui/__init__.py +16 -0
- pydantic_ai_slim-1.9.0/pydantic_ai/ui/_adapter.py +386 -0
- pydantic_ai_slim-1.9.0/pydantic_ai/ui/_event_stream.py +591 -0
- pydantic_ai_slim-1.9.0/pydantic_ai/ui/_messages_builder.py +28 -0
- pydantic_ai_slim-1.9.0/pydantic_ai/ui/ag_ui/__init__.py +9 -0
- pydantic_ai_slim-1.9.0/pydantic_ai/ui/ag_ui/_adapter.py +187 -0
- pydantic_ai_slim-1.9.0/pydantic_ai/ui/ag_ui/_event_stream.py +227 -0
- pydantic_ai_slim-1.9.0/pydantic_ai/ui/ag_ui/app.py +141 -0
- pydantic_ai_slim-1.9.0/pydantic_ai/ui/vercel_ai/__init__.py +16 -0
- pydantic_ai_slim-1.9.0/pydantic_ai/ui/vercel_ai/_adapter.py +199 -0
- pydantic_ai_slim-1.9.0/pydantic_ai/ui/vercel_ai/_event_stream.py +187 -0
- pydantic_ai_slim-1.9.0/pydantic_ai/ui/vercel_ai/_utils.py +16 -0
- pydantic_ai_slim-1.9.0/pydantic_ai/ui/vercel_ai/request_types.py +275 -0
- pydantic_ai_slim-1.9.0/pydantic_ai/ui/vercel_ai/response_types.py +230 -0
- {pydantic_ai_slim-1.7.0 → pydantic_ai_slim-1.9.0}/pyproject.toml +2 -0
- pydantic_ai_slim-1.7.0/pydantic_ai/ag_ui.py +0 -809
- {pydantic_ai_slim-1.7.0 → pydantic_ai_slim-1.9.0}/LICENSE +0 -0
- {pydantic_ai_slim-1.7.0 → pydantic_ai_slim-1.9.0}/README.md +0 -0
- {pydantic_ai_slim-1.7.0 → pydantic_ai_slim-1.9.0}/pydantic_ai/__main__.py +0 -0
- {pydantic_ai_slim-1.7.0 → pydantic_ai_slim-1.9.0}/pydantic_ai/_a2a.py +0 -0
- {pydantic_ai_slim-1.7.0 → pydantic_ai_slim-1.9.0}/pydantic_ai/_function_schema.py +0 -0
- {pydantic_ai_slim-1.7.0 → pydantic_ai_slim-1.9.0}/pydantic_ai/_griffe.py +0 -0
- {pydantic_ai_slim-1.7.0 → pydantic_ai_slim-1.9.0}/pydantic_ai/_instrumentation.py +0 -0
- {pydantic_ai_slim-1.7.0 → pydantic_ai_slim-1.9.0}/pydantic_ai/_json_schema.py +0 -0
- {pydantic_ai_slim-1.7.0 → pydantic_ai_slim-1.9.0}/pydantic_ai/_mcp.py +0 -0
- {pydantic_ai_slim-1.7.0 → pydantic_ai_slim-1.9.0}/pydantic_ai/_otel_messages.py +0 -0
- {pydantic_ai_slim-1.7.0 → pydantic_ai_slim-1.9.0}/pydantic_ai/_output.py +0 -0
- {pydantic_ai_slim-1.7.0 → pydantic_ai_slim-1.9.0}/pydantic_ai/_parts_manager.py +0 -0
- {pydantic_ai_slim-1.7.0 → pydantic_ai_slim-1.9.0}/pydantic_ai/_run_context.py +0 -0
- {pydantic_ai_slim-1.7.0 → pydantic_ai_slim-1.9.0}/pydantic_ai/_system_prompt.py +0 -0
- {pydantic_ai_slim-1.7.0 → pydantic_ai_slim-1.9.0}/pydantic_ai/_thinking_part.py +0 -0
- {pydantic_ai_slim-1.7.0 → pydantic_ai_slim-1.9.0}/pydantic_ai/_tool_manager.py +0 -0
- {pydantic_ai_slim-1.7.0 → pydantic_ai_slim-1.9.0}/pydantic_ai/_utils.py +0 -0
- {pydantic_ai_slim-1.7.0 → pydantic_ai_slim-1.9.0}/pydantic_ai/agent/__init__.py +0 -0
- {pydantic_ai_slim-1.7.0 → pydantic_ai_slim-1.9.0}/pydantic_ai/agent/wrapper.py +0 -0
- {pydantic_ai_slim-1.7.0 → pydantic_ai_slim-1.9.0}/pydantic_ai/builtin_tools.py +0 -0
- {pydantic_ai_slim-1.7.0 → pydantic_ai_slim-1.9.0}/pydantic_ai/common_tools/__init__.py +0 -0
- {pydantic_ai_slim-1.7.0 → pydantic_ai_slim-1.9.0}/pydantic_ai/common_tools/duckduckgo.py +0 -0
- {pydantic_ai_slim-1.7.0 → pydantic_ai_slim-1.9.0}/pydantic_ai/common_tools/tavily.py +0 -0
- {pydantic_ai_slim-1.7.0 → pydantic_ai_slim-1.9.0}/pydantic_ai/durable_exec/__init__.py +0 -0
- {pydantic_ai_slim-1.7.0 → pydantic_ai_slim-1.9.0}/pydantic_ai/durable_exec/dbos/__init__.py +0 -0
- {pydantic_ai_slim-1.7.0 → pydantic_ai_slim-1.9.0}/pydantic_ai/durable_exec/dbos/_mcp_server.py +0 -0
- {pydantic_ai_slim-1.7.0 → pydantic_ai_slim-1.9.0}/pydantic_ai/durable_exec/dbos/_model.py +0 -0
- {pydantic_ai_slim-1.7.0 → pydantic_ai_slim-1.9.0}/pydantic_ai/durable_exec/dbos/_utils.py +0 -0
- {pydantic_ai_slim-1.7.0 → pydantic_ai_slim-1.9.0}/pydantic_ai/durable_exec/prefect/__init__.py +0 -0
- {pydantic_ai_slim-1.7.0 → pydantic_ai_slim-1.9.0}/pydantic_ai/durable_exec/prefect/_cache_policies.py +0 -0
- {pydantic_ai_slim-1.7.0 → pydantic_ai_slim-1.9.0}/pydantic_ai/durable_exec/prefect/_function_toolset.py +0 -0
- {pydantic_ai_slim-1.7.0 → pydantic_ai_slim-1.9.0}/pydantic_ai/durable_exec/prefect/_mcp_server.py +0 -0
- {pydantic_ai_slim-1.7.0 → pydantic_ai_slim-1.9.0}/pydantic_ai/durable_exec/prefect/_model.py +0 -0
- {pydantic_ai_slim-1.7.0 → pydantic_ai_slim-1.9.0}/pydantic_ai/durable_exec/prefect/_toolset.py +0 -0
- {pydantic_ai_slim-1.7.0 → pydantic_ai_slim-1.9.0}/pydantic_ai/durable_exec/prefect/_types.py +0 -0
- {pydantic_ai_slim-1.7.0 → pydantic_ai_slim-1.9.0}/pydantic_ai/durable_exec/temporal/__init__.py +0 -0
- {pydantic_ai_slim-1.7.0 → pydantic_ai_slim-1.9.0}/pydantic_ai/durable_exec/temporal/_function_toolset.py +0 -0
- {pydantic_ai_slim-1.7.0 → pydantic_ai_slim-1.9.0}/pydantic_ai/durable_exec/temporal/_logfire.py +0 -0
- {pydantic_ai_slim-1.7.0 → pydantic_ai_slim-1.9.0}/pydantic_ai/durable_exec/temporal/_mcp_server.py +0 -0
- {pydantic_ai_slim-1.7.0 → pydantic_ai_slim-1.9.0}/pydantic_ai/durable_exec/temporal/_model.py +0 -0
- {pydantic_ai_slim-1.7.0 → pydantic_ai_slim-1.9.0}/pydantic_ai/durable_exec/temporal/_run_context.py +0 -0
- {pydantic_ai_slim-1.7.0 → pydantic_ai_slim-1.9.0}/pydantic_ai/durable_exec/temporal/_toolset.py +0 -0
- {pydantic_ai_slim-1.7.0 → pydantic_ai_slim-1.9.0}/pydantic_ai/exceptions.py +0 -0
- {pydantic_ai_slim-1.7.0 → pydantic_ai_slim-1.9.0}/pydantic_ai/ext/__init__.py +0 -0
- {pydantic_ai_slim-1.7.0 → pydantic_ai_slim-1.9.0}/pydantic_ai/ext/aci.py +0 -0
- {pydantic_ai_slim-1.7.0 → pydantic_ai_slim-1.9.0}/pydantic_ai/ext/langchain.py +0 -0
- {pydantic_ai_slim-1.7.0 → pydantic_ai_slim-1.9.0}/pydantic_ai/format_prompt.py +0 -0
- {pydantic_ai_slim-1.7.0 → pydantic_ai_slim-1.9.0}/pydantic_ai/mcp.py +0 -0
- {pydantic_ai_slim-1.7.0 → pydantic_ai_slim-1.9.0}/pydantic_ai/models/anthropic.py +0 -0
- {pydantic_ai_slim-1.7.0 → pydantic_ai_slim-1.9.0}/pydantic_ai/models/bedrock.py +0 -0
- {pydantic_ai_slim-1.7.0 → pydantic_ai_slim-1.9.0}/pydantic_ai/models/cohere.py +0 -0
- {pydantic_ai_slim-1.7.0 → pydantic_ai_slim-1.9.0}/pydantic_ai/models/fallback.py +0 -0
- {pydantic_ai_slim-1.7.0 → pydantic_ai_slim-1.9.0}/pydantic_ai/models/function.py +0 -0
- {pydantic_ai_slim-1.7.0 → pydantic_ai_slim-1.9.0}/pydantic_ai/models/gemini.py +0 -0
- {pydantic_ai_slim-1.7.0 → pydantic_ai_slim-1.9.0}/pydantic_ai/models/google.py +0 -0
- {pydantic_ai_slim-1.7.0 → pydantic_ai_slim-1.9.0}/pydantic_ai/models/huggingface.py +0 -0
- {pydantic_ai_slim-1.7.0 → pydantic_ai_slim-1.9.0}/pydantic_ai/models/instrumented.py +0 -0
- {pydantic_ai_slim-1.7.0 → pydantic_ai_slim-1.9.0}/pydantic_ai/models/mcp_sampling.py +0 -0
- {pydantic_ai_slim-1.7.0 → pydantic_ai_slim-1.9.0}/pydantic_ai/models/mistral.py +0 -0
- {pydantic_ai_slim-1.7.0 → pydantic_ai_slim-1.9.0}/pydantic_ai/models/outlines.py +0 -0
- {pydantic_ai_slim-1.7.0 → pydantic_ai_slim-1.9.0}/pydantic_ai/models/test.py +0 -0
- {pydantic_ai_slim-1.7.0 → pydantic_ai_slim-1.9.0}/pydantic_ai/models/wrapper.py +0 -0
- {pydantic_ai_slim-1.7.0 → pydantic_ai_slim-1.9.0}/pydantic_ai/output.py +0 -0
- {pydantic_ai_slim-1.7.0 → pydantic_ai_slim-1.9.0}/pydantic_ai/profiles/__init__.py +0 -0
- {pydantic_ai_slim-1.7.0 → pydantic_ai_slim-1.9.0}/pydantic_ai/profiles/amazon.py +0 -0
- {pydantic_ai_slim-1.7.0 → pydantic_ai_slim-1.9.0}/pydantic_ai/profiles/anthropic.py +0 -0
- {pydantic_ai_slim-1.7.0 → pydantic_ai_slim-1.9.0}/pydantic_ai/profiles/cohere.py +0 -0
- {pydantic_ai_slim-1.7.0 → pydantic_ai_slim-1.9.0}/pydantic_ai/profiles/deepseek.py +0 -0
- {pydantic_ai_slim-1.7.0 → pydantic_ai_slim-1.9.0}/pydantic_ai/profiles/google.py +0 -0
- {pydantic_ai_slim-1.7.0 → pydantic_ai_slim-1.9.0}/pydantic_ai/profiles/grok.py +0 -0
- {pydantic_ai_slim-1.7.0 → pydantic_ai_slim-1.9.0}/pydantic_ai/profiles/groq.py +0 -0
- {pydantic_ai_slim-1.7.0 → pydantic_ai_slim-1.9.0}/pydantic_ai/profiles/harmony.py +0 -0
- {pydantic_ai_slim-1.7.0 → pydantic_ai_slim-1.9.0}/pydantic_ai/profiles/meta.py +0 -0
- {pydantic_ai_slim-1.7.0 → pydantic_ai_slim-1.9.0}/pydantic_ai/profiles/mistral.py +0 -0
- {pydantic_ai_slim-1.7.0 → pydantic_ai_slim-1.9.0}/pydantic_ai/profiles/moonshotai.py +0 -0
- {pydantic_ai_slim-1.7.0 → pydantic_ai_slim-1.9.0}/pydantic_ai/profiles/openai.py +0 -0
- {pydantic_ai_slim-1.7.0 → pydantic_ai_slim-1.9.0}/pydantic_ai/profiles/qwen.py +0 -0
- {pydantic_ai_slim-1.7.0 → pydantic_ai_slim-1.9.0}/pydantic_ai/providers/__init__.py +0 -0
- {pydantic_ai_slim-1.7.0 → pydantic_ai_slim-1.9.0}/pydantic_ai/providers/anthropic.py +0 -0
- {pydantic_ai_slim-1.7.0 → pydantic_ai_slim-1.9.0}/pydantic_ai/providers/azure.py +0 -0
- {pydantic_ai_slim-1.7.0 → pydantic_ai_slim-1.9.0}/pydantic_ai/providers/bedrock.py +0 -0
- {pydantic_ai_slim-1.7.0 → pydantic_ai_slim-1.9.0}/pydantic_ai/providers/cerebras.py +0 -0
- {pydantic_ai_slim-1.7.0 → pydantic_ai_slim-1.9.0}/pydantic_ai/providers/cohere.py +0 -0
- {pydantic_ai_slim-1.7.0 → pydantic_ai_slim-1.9.0}/pydantic_ai/providers/deepseek.py +0 -0
- {pydantic_ai_slim-1.7.0 → pydantic_ai_slim-1.9.0}/pydantic_ai/providers/fireworks.py +0 -0
- {pydantic_ai_slim-1.7.0 → pydantic_ai_slim-1.9.0}/pydantic_ai/providers/gateway.py +0 -0
- {pydantic_ai_slim-1.7.0 → pydantic_ai_slim-1.9.0}/pydantic_ai/providers/github.py +0 -0
- {pydantic_ai_slim-1.7.0 → pydantic_ai_slim-1.9.0}/pydantic_ai/providers/google.py +0 -0
- {pydantic_ai_slim-1.7.0 → pydantic_ai_slim-1.9.0}/pydantic_ai/providers/google_gla.py +0 -0
- {pydantic_ai_slim-1.7.0 → pydantic_ai_slim-1.9.0}/pydantic_ai/providers/google_vertex.py +0 -0
- {pydantic_ai_slim-1.7.0 → pydantic_ai_slim-1.9.0}/pydantic_ai/providers/grok.py +0 -0
- {pydantic_ai_slim-1.7.0 → pydantic_ai_slim-1.9.0}/pydantic_ai/providers/groq.py +0 -0
- {pydantic_ai_slim-1.7.0 → pydantic_ai_slim-1.9.0}/pydantic_ai/providers/heroku.py +0 -0
- {pydantic_ai_slim-1.7.0 → pydantic_ai_slim-1.9.0}/pydantic_ai/providers/huggingface.py +0 -0
- {pydantic_ai_slim-1.7.0 → pydantic_ai_slim-1.9.0}/pydantic_ai/providers/litellm.py +0 -0
- {pydantic_ai_slim-1.7.0 → pydantic_ai_slim-1.9.0}/pydantic_ai/providers/mistral.py +0 -0
- {pydantic_ai_slim-1.7.0 → pydantic_ai_slim-1.9.0}/pydantic_ai/providers/moonshotai.py +0 -0
- {pydantic_ai_slim-1.7.0 → pydantic_ai_slim-1.9.0}/pydantic_ai/providers/nebius.py +0 -0
- {pydantic_ai_slim-1.7.0 → pydantic_ai_slim-1.9.0}/pydantic_ai/providers/ollama.py +0 -0
- {pydantic_ai_slim-1.7.0 → pydantic_ai_slim-1.9.0}/pydantic_ai/providers/openai.py +0 -0
- {pydantic_ai_slim-1.7.0 → pydantic_ai_slim-1.9.0}/pydantic_ai/providers/openrouter.py +0 -0
- {pydantic_ai_slim-1.7.0 → pydantic_ai_slim-1.9.0}/pydantic_ai/providers/outlines.py +0 -0
- {pydantic_ai_slim-1.7.0 → pydantic_ai_slim-1.9.0}/pydantic_ai/providers/ovhcloud.py +0 -0
- {pydantic_ai_slim-1.7.0 → pydantic_ai_slim-1.9.0}/pydantic_ai/providers/together.py +0 -0
- {pydantic_ai_slim-1.7.0 → pydantic_ai_slim-1.9.0}/pydantic_ai/providers/vercel.py +0 -0
- {pydantic_ai_slim-1.7.0 → pydantic_ai_slim-1.9.0}/pydantic_ai/py.typed +0 -0
- {pydantic_ai_slim-1.7.0 → pydantic_ai_slim-1.9.0}/pydantic_ai/retries.py +0 -0
- {pydantic_ai_slim-1.7.0 → pydantic_ai_slim-1.9.0}/pydantic_ai/run.py +0 -0
- {pydantic_ai_slim-1.7.0 → pydantic_ai_slim-1.9.0}/pydantic_ai/settings.py +0 -0
- {pydantic_ai_slim-1.7.0 → pydantic_ai_slim-1.9.0}/pydantic_ai/tools.py +0 -0
- {pydantic_ai_slim-1.7.0 → pydantic_ai_slim-1.9.0}/pydantic_ai/toolsets/__init__.py +0 -0
- {pydantic_ai_slim-1.7.0 → pydantic_ai_slim-1.9.0}/pydantic_ai/toolsets/_dynamic.py +0 -0
- {pydantic_ai_slim-1.7.0 → pydantic_ai_slim-1.9.0}/pydantic_ai/toolsets/abstract.py +0 -0
- {pydantic_ai_slim-1.7.0 → pydantic_ai_slim-1.9.0}/pydantic_ai/toolsets/approval_required.py +0 -0
- {pydantic_ai_slim-1.7.0 → pydantic_ai_slim-1.9.0}/pydantic_ai/toolsets/combined.py +0 -0
- {pydantic_ai_slim-1.7.0 → pydantic_ai_slim-1.9.0}/pydantic_ai/toolsets/external.py +0 -0
- {pydantic_ai_slim-1.7.0 → pydantic_ai_slim-1.9.0}/pydantic_ai/toolsets/fastmcp.py +0 -0
- {pydantic_ai_slim-1.7.0 → pydantic_ai_slim-1.9.0}/pydantic_ai/toolsets/filtered.py +0 -0
- {pydantic_ai_slim-1.7.0 → pydantic_ai_slim-1.9.0}/pydantic_ai/toolsets/function.py +0 -0
- {pydantic_ai_slim-1.7.0 → pydantic_ai_slim-1.9.0}/pydantic_ai/toolsets/prefixed.py +0 -0
- {pydantic_ai_slim-1.7.0 → pydantic_ai_slim-1.9.0}/pydantic_ai/toolsets/prepared.py +0 -0
- {pydantic_ai_slim-1.7.0 → pydantic_ai_slim-1.9.0}/pydantic_ai/toolsets/renamed.py +0 -0
- {pydantic_ai_slim-1.7.0 → pydantic_ai_slim-1.9.0}/pydantic_ai/toolsets/wrapper.py +0 -0
- {pydantic_ai_slim-1.7.0 → pydantic_ai_slim-1.9.0}/pydantic_ai/usage.py +0 -0
- {pydantic_ai_slim-1.7.0 → pydantic_ai_slim-1.9.0}/venv +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: pydantic-ai-slim
|
|
3
|
-
Version: 1.
|
|
3
|
+
Version: 1.9.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.
|
|
36
|
+
Requires-Dist: pydantic-graph==1.9.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.
|
|
60
|
+
Requires-Dist: pydantic-evals==1.9.0; extra == 'evals'
|
|
61
61
|
Provides-Extra: fastmcp
|
|
62
62
|
Requires-Dist: fastmcp>=2.12.0; extra == 'fastmcp'
|
|
63
63
|
Provides-Extra: google
|
|
@@ -96,6 +96,8 @@ Provides-Extra: tavily
|
|
|
96
96
|
Requires-Dist: tavily-python>=0.5.0; extra == 'tavily'
|
|
97
97
|
Provides-Extra: temporal
|
|
98
98
|
Requires-Dist: temporalio==1.18.0; extra == 'temporal'
|
|
99
|
+
Provides-Extra: ui
|
|
100
|
+
Requires-Dist: starlette>=0.45.3; extra == 'ui'
|
|
99
101
|
Provides-Extra: vertexai
|
|
100
102
|
Requires-Dist: google-auth>=2.36.0; extra == 'vertexai'
|
|
101
103
|
Requires-Dist: requests>=2.32.2; extra == 'vertexai'
|
|
@@ -65,6 +65,7 @@ from .messages import (
|
|
|
65
65
|
ModelResponseStreamEvent,
|
|
66
66
|
MultiModalContent,
|
|
67
67
|
PartDeltaEvent,
|
|
68
|
+
PartEndEvent,
|
|
68
69
|
PartStartEvent,
|
|
69
70
|
RetryPromptPart,
|
|
70
71
|
SystemPromptPart,
|
|
@@ -164,6 +165,7 @@ __all__ = (
|
|
|
164
165
|
'ModelResponseStreamEvent',
|
|
165
166
|
'MultiModalContent',
|
|
166
167
|
'PartDeltaEvent',
|
|
168
|
+
'PartEndEvent',
|
|
167
169
|
'PartStartEvent',
|
|
168
170
|
'RetryPromptPart',
|
|
169
171
|
'SystemPromptPart',
|
|
@@ -267,6 +267,9 @@ class UserPromptNode(AgentNode[DepsT, NodeRunEndT]):
|
|
|
267
267
|
|
|
268
268
|
next_message.instructions = await ctx.deps.get_instructions(run_context)
|
|
269
269
|
|
|
270
|
+
if not messages and not next_message.parts and not next_message.instructions:
|
|
271
|
+
raise exceptions.UserError('No message history, user prompt, or instructions provided')
|
|
272
|
+
|
|
270
273
|
return ModelRequestNode[DepsT, NodeRunEndT](request=next_message)
|
|
271
274
|
|
|
272
275
|
async def _handle_deferred_tool_results( # noqa: C901
|
|
@@ -103,7 +103,7 @@ def cli_exit(prog_name: str = 'pai'): # pragma: no cover
|
|
|
103
103
|
|
|
104
104
|
|
|
105
105
|
def cli( # noqa: C901
|
|
106
|
-
args_list: Sequence[str] | None = None, *, prog_name: str = 'pai', default_model: str = 'openai:gpt-
|
|
106
|
+
args_list: Sequence[str] | None = None, *, prog_name: str = 'pai', default_model: str = 'openai:gpt-5'
|
|
107
107
|
) -> int:
|
|
108
108
|
"""Run the CLI and return the exit code for the process."""
|
|
109
109
|
parser = argparse.ArgumentParser(
|
|
@@ -124,7 +124,7 @@ Special prompts:
|
|
|
124
124
|
'-m',
|
|
125
125
|
'--model',
|
|
126
126
|
nargs='?',
|
|
127
|
-
help=f'Model to use, in format "<provider>:<model>" e.g. "openai:gpt-
|
|
127
|
+
help=f'Model to use, in format "<provider>:<model>" e.g. "openai:gpt-5" or "anthropic:claude-sonnet-4-5". Defaults to "{default_model}".',
|
|
128
128
|
)
|
|
129
129
|
# we don't want to autocomplete or list models that don't include the provider,
|
|
130
130
|
# e.g. we want to show `openai:gpt-4o` but not `gpt-4o`
|
|
@@ -0,0 +1,163 @@
|
|
|
1
|
+
"""Provides an AG-UI protocol adapter for the Pydantic AI agent.
|
|
2
|
+
|
|
3
|
+
This package provides seamless integration between pydantic-ai agents and ag-ui
|
|
4
|
+
for building interactive AI applications with streaming event-based communication.
|
|
5
|
+
"""
|
|
6
|
+
|
|
7
|
+
# TODO (v2): Remove this module in favor of `pydantic_ai.ui.ag_ui`
|
|
8
|
+
|
|
9
|
+
from __future__ import annotations
|
|
10
|
+
|
|
11
|
+
from collections.abc import AsyncIterator, Sequence
|
|
12
|
+
from typing import Any
|
|
13
|
+
|
|
14
|
+
from . import DeferredToolResults
|
|
15
|
+
from .agent import AbstractAgent
|
|
16
|
+
from .messages import ModelMessage
|
|
17
|
+
from .models import KnownModelName, Model
|
|
18
|
+
from .output import OutputSpec
|
|
19
|
+
from .settings import ModelSettings
|
|
20
|
+
from .tools import AgentDepsT
|
|
21
|
+
from .toolsets import AbstractToolset
|
|
22
|
+
from .usage import RunUsage, UsageLimits
|
|
23
|
+
|
|
24
|
+
try:
|
|
25
|
+
from ag_ui.core import BaseEvent
|
|
26
|
+
from ag_ui.core.types import RunAgentInput
|
|
27
|
+
from starlette.requests import Request
|
|
28
|
+
from starlette.responses import Response
|
|
29
|
+
|
|
30
|
+
from .ui import SSE_CONTENT_TYPE, OnCompleteFunc, StateDeps, StateHandler
|
|
31
|
+
from .ui.ag_ui import AGUIAdapter
|
|
32
|
+
from .ui.ag_ui.app import AGUIApp
|
|
33
|
+
except ImportError as e: # pragma: no cover
|
|
34
|
+
raise ImportError(
|
|
35
|
+
'Please install the `ag-ui-protocol` and `starlette` packages to use `AGUIAdapter`, '
|
|
36
|
+
'you can use the `ag-ui` optional group — `pip install "pydantic-ai-slim[ag-ui]"`'
|
|
37
|
+
) from e
|
|
38
|
+
|
|
39
|
+
|
|
40
|
+
__all__ = [
|
|
41
|
+
'SSE_CONTENT_TYPE',
|
|
42
|
+
'StateDeps',
|
|
43
|
+
'StateHandler',
|
|
44
|
+
'AGUIApp',
|
|
45
|
+
'OnCompleteFunc',
|
|
46
|
+
'handle_ag_ui_request',
|
|
47
|
+
'run_ag_ui',
|
|
48
|
+
]
|
|
49
|
+
|
|
50
|
+
|
|
51
|
+
async def handle_ag_ui_request(
|
|
52
|
+
agent: AbstractAgent[AgentDepsT, Any],
|
|
53
|
+
request: Request,
|
|
54
|
+
*,
|
|
55
|
+
output_type: OutputSpec[Any] | None = None,
|
|
56
|
+
message_history: Sequence[ModelMessage] | None = None,
|
|
57
|
+
deferred_tool_results: DeferredToolResults | None = None,
|
|
58
|
+
model: Model | KnownModelName | str | None = None,
|
|
59
|
+
deps: AgentDepsT = None,
|
|
60
|
+
model_settings: ModelSettings | None = None,
|
|
61
|
+
usage_limits: UsageLimits | None = None,
|
|
62
|
+
usage: RunUsage | None = None,
|
|
63
|
+
infer_name: bool = True,
|
|
64
|
+
toolsets: Sequence[AbstractToolset[AgentDepsT]] | None = None,
|
|
65
|
+
on_complete: OnCompleteFunc[BaseEvent] | None = None,
|
|
66
|
+
) -> Response:
|
|
67
|
+
"""Handle an AG-UI request by running the agent and returning a streaming response.
|
|
68
|
+
|
|
69
|
+
Args:
|
|
70
|
+
agent: The agent to run.
|
|
71
|
+
request: The Starlette request (e.g. from FastAPI) containing the AG-UI run input.
|
|
72
|
+
|
|
73
|
+
output_type: Custom output type to use for this run, `output_type` may only be used if the agent has no
|
|
74
|
+
output validators since output validators would expect an argument that matches the agent's output type.
|
|
75
|
+
message_history: History of the conversation so far.
|
|
76
|
+
deferred_tool_results: Optional results for deferred tool calls in the message history.
|
|
77
|
+
model: Optional model to use for this run, required if `model` was not set when creating the agent.
|
|
78
|
+
deps: Optional dependencies to use for this run.
|
|
79
|
+
model_settings: Optional settings to use for this model's request.
|
|
80
|
+
usage_limits: Optional limits on model request count or token usage.
|
|
81
|
+
usage: Optional usage to start with, useful for resuming a conversation or agents used in tools.
|
|
82
|
+
infer_name: Whether to try to infer the agent name from the call frame if it's not set.
|
|
83
|
+
toolsets: Optional additional toolsets for this run.
|
|
84
|
+
on_complete: Optional callback function called when the agent run completes successfully.
|
|
85
|
+
The callback receives the completed [`AgentRunResult`][pydantic_ai.agent.AgentRunResult] and can access `all_messages()` and other result data.
|
|
86
|
+
|
|
87
|
+
Returns:
|
|
88
|
+
A streaming Starlette response with AG-UI protocol events.
|
|
89
|
+
"""
|
|
90
|
+
return await AGUIAdapter[AgentDepsT].dispatch_request(
|
|
91
|
+
request,
|
|
92
|
+
agent=agent,
|
|
93
|
+
deps=deps,
|
|
94
|
+
output_type=output_type,
|
|
95
|
+
message_history=message_history,
|
|
96
|
+
deferred_tool_results=deferred_tool_results,
|
|
97
|
+
model=model,
|
|
98
|
+
model_settings=model_settings,
|
|
99
|
+
usage_limits=usage_limits,
|
|
100
|
+
usage=usage,
|
|
101
|
+
infer_name=infer_name,
|
|
102
|
+
toolsets=toolsets,
|
|
103
|
+
on_complete=on_complete,
|
|
104
|
+
)
|
|
105
|
+
|
|
106
|
+
|
|
107
|
+
def run_ag_ui(
|
|
108
|
+
agent: AbstractAgent[AgentDepsT, Any],
|
|
109
|
+
run_input: RunAgentInput,
|
|
110
|
+
accept: str = SSE_CONTENT_TYPE,
|
|
111
|
+
*,
|
|
112
|
+
output_type: OutputSpec[Any] | None = None,
|
|
113
|
+
message_history: Sequence[ModelMessage] | None = None,
|
|
114
|
+
deferred_tool_results: DeferredToolResults | None = None,
|
|
115
|
+
model: Model | KnownModelName | str | None = None,
|
|
116
|
+
deps: AgentDepsT = None,
|
|
117
|
+
model_settings: ModelSettings | None = None,
|
|
118
|
+
usage_limits: UsageLimits | None = None,
|
|
119
|
+
usage: RunUsage | None = None,
|
|
120
|
+
infer_name: bool = True,
|
|
121
|
+
toolsets: Sequence[AbstractToolset[AgentDepsT]] | None = None,
|
|
122
|
+
on_complete: OnCompleteFunc[BaseEvent] | None = None,
|
|
123
|
+
) -> AsyncIterator[str]:
|
|
124
|
+
"""Run the agent with the AG-UI run input and stream AG-UI protocol events.
|
|
125
|
+
|
|
126
|
+
Args:
|
|
127
|
+
agent: The agent to run.
|
|
128
|
+
run_input: The AG-UI run input containing thread_id, run_id, messages, etc.
|
|
129
|
+
accept: The accept header value for the run.
|
|
130
|
+
|
|
131
|
+
output_type: Custom output type to use for this run, `output_type` may only be used if the agent has no
|
|
132
|
+
output validators since output validators would expect an argument that matches the agent's output type.
|
|
133
|
+
message_history: History of the conversation so far.
|
|
134
|
+
deferred_tool_results: Optional results for deferred tool calls in the message history.
|
|
135
|
+
model: Optional model to use for this run, required if `model` was not set when creating the agent.
|
|
136
|
+
deps: Optional dependencies to use for this run.
|
|
137
|
+
model_settings: Optional settings to use for this model's request.
|
|
138
|
+
usage_limits: Optional limits on model request count or token usage.
|
|
139
|
+
usage: Optional usage to start with, useful for resuming a conversation or agents used in tools.
|
|
140
|
+
infer_name: Whether to try to infer the agent name from the call frame if it's not set.
|
|
141
|
+
toolsets: Optional additional toolsets for this run.
|
|
142
|
+
on_complete: Optional callback function called when the agent run completes successfully.
|
|
143
|
+
The callback receives the completed [`AgentRunResult`][pydantic_ai.agent.AgentRunResult] and can access `all_messages()` and other result data.
|
|
144
|
+
|
|
145
|
+
Yields:
|
|
146
|
+
Streaming event chunks encoded as strings according to the accept header value.
|
|
147
|
+
"""
|
|
148
|
+
adapter = AGUIAdapter(agent=agent, run_input=run_input, accept=accept)
|
|
149
|
+
return adapter.encode_stream(
|
|
150
|
+
adapter.run_stream(
|
|
151
|
+
output_type=output_type,
|
|
152
|
+
message_history=message_history,
|
|
153
|
+
deferred_tool_results=deferred_tool_results,
|
|
154
|
+
model=model,
|
|
155
|
+
deps=deps,
|
|
156
|
+
model_settings=model_settings,
|
|
157
|
+
usage_limits=usage_limits,
|
|
158
|
+
usage=usage,
|
|
159
|
+
infer_name=infer_name,
|
|
160
|
+
toolsets=toolsets,
|
|
161
|
+
on_complete=on_complete,
|
|
162
|
+
),
|
|
163
|
+
)
|
|
@@ -49,7 +49,7 @@ if TYPE_CHECKING:
|
|
|
49
49
|
from starlette.routing import BaseRoute, Route
|
|
50
50
|
from starlette.types import ExceptionHandler, Lifespan
|
|
51
51
|
|
|
52
|
-
from
|
|
52
|
+
from pydantic_ai.ui.ag_ui.app import AGUIApp
|
|
53
53
|
|
|
54
54
|
|
|
55
55
|
T = TypeVar('T')
|
|
@@ -654,6 +654,9 @@ class AbstractAgent(Generic[AgentDepsT, OutputDataT], ABC):
|
|
|
654
654
|
PartStartEvent(index=0, part=TextPart(content='The capital of ')),
|
|
655
655
|
FinalResultEvent(tool_name=None, tool_call_id=None),
|
|
656
656
|
PartDeltaEvent(index=0, delta=TextPartDelta(content_delta='France is Paris. ')),
|
|
657
|
+
PartEndEvent(
|
|
658
|
+
index=0, part=TextPart(content='The capital of France is Paris. ')
|
|
659
|
+
),
|
|
657
660
|
AgentRunResultEvent(
|
|
658
661
|
result=AgentRunResult(output='The capital of France is Paris. ')
|
|
659
662
|
),
|
|
@@ -683,6 +686,9 @@ class AbstractAgent(Generic[AgentDepsT, OutputDataT], ABC):
|
|
|
683
686
|
An async iterable of stream events `AgentStreamEvent` and finally a `AgentRunResultEvent` with the final
|
|
684
687
|
run result.
|
|
685
688
|
"""
|
|
689
|
+
if infer_name and self.name is None:
|
|
690
|
+
self._infer_name(inspect.currentframe())
|
|
691
|
+
|
|
686
692
|
# unfortunately this hack of returning a generator rather than defining it right here is
|
|
687
693
|
# required to allow overloads of this method to work in python's typing system, or at least with pyright
|
|
688
694
|
# or at least I couldn't make it work without
|
|
@@ -696,7 +702,6 @@ class AbstractAgent(Generic[AgentDepsT, OutputDataT], ABC):
|
|
|
696
702
|
model_settings=model_settings,
|
|
697
703
|
usage_limits=usage_limits,
|
|
698
704
|
usage=usage,
|
|
699
|
-
infer_name=infer_name,
|
|
700
705
|
toolsets=toolsets,
|
|
701
706
|
builtin_tools=builtin_tools,
|
|
702
707
|
)
|
|
@@ -713,7 +718,6 @@ class AbstractAgent(Generic[AgentDepsT, OutputDataT], ABC):
|
|
|
713
718
|
model_settings: ModelSettings | None = None,
|
|
714
719
|
usage_limits: _usage.UsageLimits | None = None,
|
|
715
720
|
usage: _usage.RunUsage | None = None,
|
|
716
|
-
infer_name: bool = True,
|
|
717
721
|
toolsets: Sequence[AbstractToolset[AgentDepsT]] | None = None,
|
|
718
722
|
builtin_tools: Sequence[AbstractBuiltinTool] | None = None,
|
|
719
723
|
) -> AsyncIterator[_messages.AgentStreamEvent | AgentRunResultEvent[Any]]:
|
|
@@ -739,7 +743,7 @@ class AbstractAgent(Generic[AgentDepsT, OutputDataT], ABC):
|
|
|
739
743
|
model_settings=model_settings,
|
|
740
744
|
usage_limits=usage_limits,
|
|
741
745
|
usage=usage,
|
|
742
|
-
infer_name=
|
|
746
|
+
infer_name=False,
|
|
743
747
|
toolsets=toolsets,
|
|
744
748
|
builtin_tools=builtin_tools,
|
|
745
749
|
event_stream_handler=event_stream_handler,
|
|
@@ -989,11 +993,14 @@ class AbstractAgent(Generic[AgentDepsT, OutputDataT], ABC):
|
|
|
989
993
|
async def __aexit__(self, *args: Any) -> bool | None:
|
|
990
994
|
raise NotImplementedError
|
|
991
995
|
|
|
996
|
+
# TODO (v2): Remove in favor of using `AGUIApp` directly -- we don't have `to_temporal()` or `to_vercel_ai()` either.
|
|
992
997
|
def to_ag_ui(
|
|
993
998
|
self,
|
|
994
999
|
*,
|
|
995
1000
|
# Agent.iter parameters
|
|
996
1001
|
output_type: OutputSpec[OutputDataT] | None = None,
|
|
1002
|
+
message_history: Sequence[_messages.ModelMessage] | None = None,
|
|
1003
|
+
deferred_tool_results: DeferredToolResults | None = None,
|
|
997
1004
|
model: models.Model | models.KnownModelName | str | None = None,
|
|
998
1005
|
deps: AgentDepsT = None,
|
|
999
1006
|
model_settings: ModelSettings | None = None,
|
|
@@ -1034,12 +1041,14 @@ class AbstractAgent(Generic[AgentDepsT, OutputDataT], ABC):
|
|
|
1034
1041
|
uvicorn app:app --host 0.0.0.0 --port 8000
|
|
1035
1042
|
```
|
|
1036
1043
|
|
|
1037
|
-
See [AG-UI docs](../ag-ui.md) for more information.
|
|
1044
|
+
See [AG-UI docs](../ui/ag-ui.md) for more information.
|
|
1038
1045
|
|
|
1039
1046
|
Args:
|
|
1040
1047
|
output_type: Custom output type to use for this run, `output_type` may only be used if the agent has
|
|
1041
1048
|
no output validators since output validators would expect an argument that matches the agent's
|
|
1042
1049
|
output type.
|
|
1050
|
+
message_history: History of the conversation so far.
|
|
1051
|
+
deferred_tool_results: Optional results for deferred tool calls in the message history.
|
|
1043
1052
|
model: Optional model to use for this run, required if `model` was not set when creating the agent.
|
|
1044
1053
|
deps: Optional dependencies to use for this run.
|
|
1045
1054
|
model_settings: Optional settings to use for this model's request.
|
|
@@ -1069,12 +1078,14 @@ class AbstractAgent(Generic[AgentDepsT, OutputDataT], ABC):
|
|
|
1069
1078
|
Returns:
|
|
1070
1079
|
An ASGI application for running Pydantic AI agents with AG-UI protocol support.
|
|
1071
1080
|
"""
|
|
1072
|
-
from
|
|
1081
|
+
from pydantic_ai.ui.ag_ui.app import AGUIApp
|
|
1073
1082
|
|
|
1074
1083
|
return AGUIApp(
|
|
1075
1084
|
agent=self,
|
|
1076
1085
|
# Agent.iter parameters
|
|
1077
1086
|
output_type=output_type,
|
|
1087
|
+
message_history=message_history,
|
|
1088
|
+
deferred_tool_results=deferred_tool_results,
|
|
1078
1089
|
model=model,
|
|
1079
1090
|
deps=deps,
|
|
1080
1091
|
model_settings=model_settings,
|
|
@@ -50,7 +50,7 @@ async def model_request(
|
|
|
50
50
|
|
|
51
51
|
async def main():
|
|
52
52
|
model_response = await model_request(
|
|
53
|
-
'anthropic:claude-
|
|
53
|
+
'anthropic:claude-haiku-4-5',
|
|
54
54
|
[ModelRequest.user_text_prompt('What is the capital of France?')] # (1)!
|
|
55
55
|
)
|
|
56
56
|
print(model_response)
|
|
@@ -58,7 +58,7 @@ async def model_request(
|
|
|
58
58
|
ModelResponse(
|
|
59
59
|
parts=[TextPart(content='The capital of France is Paris.')],
|
|
60
60
|
usage=RequestUsage(input_tokens=56, output_tokens=7),
|
|
61
|
-
model_name='claude-
|
|
61
|
+
model_name='claude-haiku-4-5',
|
|
62
62
|
timestamp=datetime.datetime(...),
|
|
63
63
|
)
|
|
64
64
|
'''
|
|
@@ -103,7 +103,7 @@ def model_request_sync(
|
|
|
103
103
|
from pydantic_ai.direct import model_request_sync
|
|
104
104
|
|
|
105
105
|
model_response = model_request_sync(
|
|
106
|
-
'anthropic:claude-
|
|
106
|
+
'anthropic:claude-haiku-4-5',
|
|
107
107
|
[ModelRequest.user_text_prompt('What is the capital of France?')] # (1)!
|
|
108
108
|
)
|
|
109
109
|
print(model_response)
|
|
@@ -111,7 +111,7 @@ def model_request_sync(
|
|
|
111
111
|
ModelResponse(
|
|
112
112
|
parts=[TextPart(content='The capital of France is Paris.')],
|
|
113
113
|
usage=RequestUsage(input_tokens=56, output_tokens=7),
|
|
114
|
-
model_name='claude-
|
|
114
|
+
model_name='claude-haiku-4-5',
|
|
115
115
|
timestamp=datetime.datetime(...),
|
|
116
116
|
)
|
|
117
117
|
'''
|
|
@@ -172,6 +172,12 @@ def model_request_stream(
|
|
|
172
172
|
index=0, delta=TextPartDelta(content_delta='a German-born theoretical ')
|
|
173
173
|
),
|
|
174
174
|
PartDeltaEvent(index=0, delta=TextPartDelta(content_delta='physicist.')),
|
|
175
|
+
PartEndEvent(
|
|
176
|
+
index=0,
|
|
177
|
+
part=TextPart(
|
|
178
|
+
content='Albert Einstein was a German-born theoretical physicist.'
|
|
179
|
+
),
|
|
180
|
+
),
|
|
175
181
|
]
|
|
176
182
|
'''
|
|
177
183
|
```
|
|
@@ -229,6 +235,12 @@ def model_request_stream_sync(
|
|
|
229
235
|
index=0, delta=TextPartDelta(content_delta='a German-born theoretical ')
|
|
230
236
|
),
|
|
231
237
|
PartDeltaEvent(index=0, delta=TextPartDelta(content_delta='physicist.')),
|
|
238
|
+
PartEndEvent(
|
|
239
|
+
index=0,
|
|
240
|
+
part=TextPart(
|
|
241
|
+
content='Albert Einstein was a German-born theoretical physicist.'
|
|
242
|
+
),
|
|
243
|
+
),
|
|
232
244
|
]
|
|
233
245
|
'''
|
|
234
246
|
```
|
|
@@ -640,6 +640,9 @@ class DBOSAgent(WrapperAgent[AgentDepsT, OutputDataT], DBOSConfiguredInstance):
|
|
|
640
640
|
PartStartEvent(index=0, part=TextPart(content='The capital of ')),
|
|
641
641
|
FinalResultEvent(tool_name=None, tool_call_id=None),
|
|
642
642
|
PartDeltaEvent(index=0, delta=TextPartDelta(content_delta='France is Paris. ')),
|
|
643
|
+
PartEndEvent(
|
|
644
|
+
index=0, part=TextPart(content='The capital of France is Paris. ')
|
|
645
|
+
),
|
|
643
646
|
AgentRunResultEvent(
|
|
644
647
|
result=AgentRunResult(output='The capital of France is Paris. ')
|
|
645
648
|
),
|
{pydantic_ai_slim-1.7.0 → pydantic_ai_slim-1.9.0}/pydantic_ai/durable_exec/prefect/_agent.py
RENAMED
|
@@ -598,6 +598,9 @@ class PrefectAgent(WrapperAgent[AgentDepsT, OutputDataT]):
|
|
|
598
598
|
PartStartEvent(index=0, part=TextPart(content='The capital of ')),
|
|
599
599
|
FinalResultEvent(tool_name=None, tool_call_id=None),
|
|
600
600
|
PartDeltaEvent(index=0, delta=TextPartDelta(content_delta='France is Paris. ')),
|
|
601
|
+
PartEndEvent(
|
|
602
|
+
index=0, part=TextPart(content='The capital of France is Paris. ')
|
|
603
|
+
),
|
|
601
604
|
AgentRunResultEvent(
|
|
602
605
|
result=AgentRunResult(output='The capital of France is Paris. ')
|
|
603
606
|
),
|
{pydantic_ai_slim-1.7.0 → pydantic_ai_slim-1.9.0}/pydantic_ai/durable_exec/temporal/_agent.py
RENAMED
|
@@ -669,6 +669,9 @@ class TemporalAgent(WrapperAgent[AgentDepsT, OutputDataT]):
|
|
|
669
669
|
PartStartEvent(index=0, part=TextPart(content='The capital of ')),
|
|
670
670
|
FinalResultEvent(tool_name=None, tool_call_id=None),
|
|
671
671
|
PartDeltaEvent(index=0, delta=TextPartDelta(content_delta='France is Paris. ')),
|
|
672
|
+
PartEndEvent(
|
|
673
|
+
index=0, part=TextPart(content='The capital of France is Paris. ')
|
|
674
|
+
),
|
|
672
675
|
AgentRunResultEvent(
|
|
673
676
|
result=AgentRunResult(output='The capital of France is Paris. ')
|
|
674
677
|
),
|
|
@@ -13,7 +13,7 @@ import pydantic
|
|
|
13
13
|
import pydantic_core
|
|
14
14
|
from genai_prices import calc_price, types as genai_types
|
|
15
15
|
from opentelemetry._events import Event # pyright: ignore[reportPrivateImportUsage]
|
|
16
|
-
from typing_extensions import
|
|
16
|
+
from typing_extensions import deprecated
|
|
17
17
|
|
|
18
18
|
from . import _otel_messages, _utils
|
|
19
19
|
from ._utils import generate_tool_call_id as _generate_tool_call_id, now_utc as _now_utc
|
|
@@ -514,16 +514,16 @@ class BinaryContent:
|
|
|
514
514
|
vendor_metadata=bc.vendor_metadata,
|
|
515
515
|
)
|
|
516
516
|
else:
|
|
517
|
-
return bc
|
|
517
|
+
return bc
|
|
518
518
|
|
|
519
519
|
@classmethod
|
|
520
|
-
def from_data_uri(cls, data_uri: str) ->
|
|
520
|
+
def from_data_uri(cls, data_uri: str) -> BinaryContent:
|
|
521
521
|
"""Create a `BinaryContent` from a data URI."""
|
|
522
522
|
prefix = 'data:'
|
|
523
523
|
if not data_uri.startswith(prefix):
|
|
524
|
-
raise ValueError('Data URI must start with "data:"')
|
|
524
|
+
raise ValueError('Data URI must start with "data:"')
|
|
525
525
|
media_type, data = data_uri[len(prefix) :].split(';base64,', 1)
|
|
526
|
-
return cls(data=base64.b64decode(data), media_type=media_type)
|
|
526
|
+
return cls.narrow_type(cls(data=base64.b64decode(data), media_type=media_type))
|
|
527
527
|
|
|
528
528
|
@pydantic.computed_field
|
|
529
529
|
@property
|
|
@@ -1612,6 +1612,14 @@ class PartStartEvent:
|
|
|
1612
1612
|
part: ModelResponsePart
|
|
1613
1613
|
"""The newly started `ModelResponsePart`."""
|
|
1614
1614
|
|
|
1615
|
+
previous_part_kind: (
|
|
1616
|
+
Literal['text', 'thinking', 'tool-call', 'builtin-tool-call', 'builtin-tool-return', 'file'] | None
|
|
1617
|
+
) = None
|
|
1618
|
+
"""The kind of the previous part, if any.
|
|
1619
|
+
|
|
1620
|
+
This is useful for UI event streams to know whether to group parts of the same kind together when emitting events.
|
|
1621
|
+
"""
|
|
1622
|
+
|
|
1615
1623
|
event_kind: Literal['part_start'] = 'part_start'
|
|
1616
1624
|
"""Event type identifier, used as a discriminator."""
|
|
1617
1625
|
|
|
@@ -1634,6 +1642,30 @@ class PartDeltaEvent:
|
|
|
1634
1642
|
__repr__ = _utils.dataclasses_no_defaults_repr
|
|
1635
1643
|
|
|
1636
1644
|
|
|
1645
|
+
@dataclass(repr=False, kw_only=True)
|
|
1646
|
+
class PartEndEvent:
|
|
1647
|
+
"""An event indicating that a part is complete."""
|
|
1648
|
+
|
|
1649
|
+
index: int
|
|
1650
|
+
"""The index of the part within the overall response parts list."""
|
|
1651
|
+
|
|
1652
|
+
part: ModelResponsePart
|
|
1653
|
+
"""The complete `ModelResponsePart`."""
|
|
1654
|
+
|
|
1655
|
+
next_part_kind: (
|
|
1656
|
+
Literal['text', 'thinking', 'tool-call', 'builtin-tool-call', 'builtin-tool-return', 'file'] | None
|
|
1657
|
+
) = None
|
|
1658
|
+
"""The kind of the next part, if any.
|
|
1659
|
+
|
|
1660
|
+
This is useful for UI event streams to know whether to group parts of the same kind together when emitting events.
|
|
1661
|
+
"""
|
|
1662
|
+
|
|
1663
|
+
event_kind: Literal['part_end'] = 'part_end'
|
|
1664
|
+
"""Event type identifier, used as a discriminator."""
|
|
1665
|
+
|
|
1666
|
+
__repr__ = _utils.dataclasses_no_defaults_repr
|
|
1667
|
+
|
|
1668
|
+
|
|
1637
1669
|
@dataclass(repr=False, kw_only=True)
|
|
1638
1670
|
class FinalResultEvent:
|
|
1639
1671
|
"""An event indicating the response to the current model request matches the output schema and will produce a result."""
|
|
@@ -1649,9 +1681,9 @@ class FinalResultEvent:
|
|
|
1649
1681
|
|
|
1650
1682
|
|
|
1651
1683
|
ModelResponseStreamEvent = Annotated[
|
|
1652
|
-
PartStartEvent | PartDeltaEvent | FinalResultEvent, pydantic.Discriminator('event_kind')
|
|
1684
|
+
PartStartEvent | PartDeltaEvent | PartEndEvent | FinalResultEvent, pydantic.Discriminator('event_kind')
|
|
1653
1685
|
]
|
|
1654
|
-
"""An event in the model response stream, starting a new part, applying a delta to an existing one, or indicating the final result."""
|
|
1686
|
+
"""An event in the model response stream, starting a new part, applying a delta to an existing one, indicating a part is complete, or indicating the final result."""
|
|
1655
1687
|
|
|
1656
1688
|
|
|
1657
1689
|
@dataclass(repr=False)
|
|
@@ -27,6 +27,7 @@ from .._run_context import RunContext
|
|
|
27
27
|
from ..builtin_tools import AbstractBuiltinTool
|
|
28
28
|
from ..exceptions import UserError
|
|
29
29
|
from ..messages import (
|
|
30
|
+
BaseToolCallPart,
|
|
30
31
|
BinaryImage,
|
|
31
32
|
FilePart,
|
|
32
33
|
FileUrl,
|
|
@@ -35,9 +36,12 @@ from ..messages import (
|
|
|
35
36
|
ModelMessage,
|
|
36
37
|
ModelRequest,
|
|
37
38
|
ModelResponse,
|
|
39
|
+
ModelResponsePart,
|
|
38
40
|
ModelResponseStreamEvent,
|
|
41
|
+
PartEndEvent,
|
|
39
42
|
PartStartEvent,
|
|
40
43
|
TextPart,
|
|
44
|
+
ThinkingPart,
|
|
41
45
|
ToolCallPart,
|
|
42
46
|
VideoUrl,
|
|
43
47
|
)
|
|
@@ -543,7 +547,44 @@ class StreamedResponse(ABC):
|
|
|
543
547
|
async for event in iterator:
|
|
544
548
|
yield event
|
|
545
549
|
|
|
546
|
-
|
|
550
|
+
async def iterator_with_part_end(
|
|
551
|
+
iterator: AsyncIterator[ModelResponseStreamEvent],
|
|
552
|
+
) -> AsyncIterator[ModelResponseStreamEvent]:
|
|
553
|
+
last_start_event: PartStartEvent | None = None
|
|
554
|
+
|
|
555
|
+
def part_end_event(next_part: ModelResponsePart | None = None) -> PartEndEvent | None:
|
|
556
|
+
if not last_start_event:
|
|
557
|
+
return None
|
|
558
|
+
|
|
559
|
+
index = last_start_event.index
|
|
560
|
+
part = self._parts_manager.get_parts()[index]
|
|
561
|
+
if not isinstance(part, TextPart | ThinkingPart | BaseToolCallPart):
|
|
562
|
+
# Parts other than these 3 don't have deltas, so don't need an end part.
|
|
563
|
+
return None
|
|
564
|
+
|
|
565
|
+
return PartEndEvent(
|
|
566
|
+
index=index,
|
|
567
|
+
part=part,
|
|
568
|
+
next_part_kind=next_part.part_kind if next_part else None,
|
|
569
|
+
)
|
|
570
|
+
|
|
571
|
+
async for event in iterator:
|
|
572
|
+
if isinstance(event, PartStartEvent):
|
|
573
|
+
if last_start_event:
|
|
574
|
+
end_event = part_end_event(event.part)
|
|
575
|
+
if end_event:
|
|
576
|
+
yield end_event
|
|
577
|
+
|
|
578
|
+
event.previous_part_kind = last_start_event.part.part_kind
|
|
579
|
+
last_start_event = event
|
|
580
|
+
|
|
581
|
+
yield event
|
|
582
|
+
|
|
583
|
+
end_event = part_end_event()
|
|
584
|
+
if end_event:
|
|
585
|
+
yield end_event
|
|
586
|
+
|
|
587
|
+
self._event_iterator = iterator_with_part_end(iterator_with_final_event(self._get_event_iterator()))
|
|
547
588
|
return self._event_iterator
|
|
548
589
|
|
|
549
590
|
@abstractmethod
|
|
@@ -524,6 +524,8 @@ class GroqStreamedResponse(StreamedResponse):
|
|
|
524
524
|
async def _get_event_iterator(self) -> AsyncIterator[ModelResponseStreamEvent]: # noqa: C901
|
|
525
525
|
try:
|
|
526
526
|
executed_tool_call_id: str | None = None
|
|
527
|
+
reasoning_index = 0
|
|
528
|
+
reasoning = False
|
|
527
529
|
async for chunk in self._response:
|
|
528
530
|
self._usage += _map_usage(chunk)
|
|
529
531
|
|
|
@@ -540,10 +542,16 @@ class GroqStreamedResponse(StreamedResponse):
|
|
|
540
542
|
self.finish_reason = _FINISH_REASON_MAP.get(raw_finish_reason)
|
|
541
543
|
|
|
542
544
|
if choice.delta.reasoning is not None:
|
|
545
|
+
if not reasoning:
|
|
546
|
+
reasoning_index += 1
|
|
547
|
+
reasoning = True
|
|
548
|
+
|
|
543
549
|
# NOTE: The `reasoning` field is only present if `groq_reasoning_format` is set to `parsed`.
|
|
544
550
|
yield self._parts_manager.handle_thinking_delta(
|
|
545
|
-
vendor_part_id='reasoning', content=choice.delta.reasoning
|
|
551
|
+
vendor_part_id=f'reasoning-{reasoning_index}', content=choice.delta.reasoning
|
|
546
552
|
)
|
|
553
|
+
else:
|
|
554
|
+
reasoning = False
|
|
547
555
|
|
|
548
556
|
if choice.delta.executed_tools:
|
|
549
557
|
for tool in choice.delta.executed_tools:
|
|
@@ -1148,10 +1148,10 @@ class OpenAIResponsesModel(Model):
|
|
|
1148
1148
|
+ list(model_settings.get('openai_builtin_tools', []))
|
|
1149
1149
|
+ self._get_tools(model_request_parameters)
|
|
1150
1150
|
)
|
|
1151
|
-
|
|
1151
|
+
profile = OpenAIModelProfile.from_profile(self.profile)
|
|
1152
1152
|
if not tools:
|
|
1153
1153
|
tool_choice: Literal['none', 'required', 'auto'] | None = None
|
|
1154
|
-
elif not model_request_parameters.allow_text_output:
|
|
1154
|
+
elif not model_request_parameters.allow_text_output and profile.openai_supports_tool_choice_required:
|
|
1155
1155
|
tool_choice = 'required'
|
|
1156
1156
|
else:
|
|
1157
1157
|
tool_choice = 'auto'
|
|
@@ -1184,7 +1184,6 @@ class OpenAIResponsesModel(Model):
|
|
|
1184
1184
|
text = text or {}
|
|
1185
1185
|
text['verbosity'] = verbosity
|
|
1186
1186
|
|
|
1187
|
-
profile = OpenAIModelProfile.from_profile(self.profile)
|
|
1188
1187
|
unsupported_model_settings = profile.openai_unsupported_model_settings
|
|
1189
1188
|
for setting in unsupported_model_settings:
|
|
1190
1189
|
model_settings.pop(setting, None)
|