pydantic-ai-slim 0.7.6__tar.gz → 0.8.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.
- {pydantic_ai_slim-0.7.6 → pydantic_ai_slim-0.8.0}/PKG-INFO +4 -4
- {pydantic_ai_slim-0.7.6 → pydantic_ai_slim-0.8.0}/pydantic_ai/_cli.py +2 -1
- {pydantic_ai_slim-0.7.6 → pydantic_ai_slim-0.8.0}/pydantic_ai/ag_ui.py +2 -2
- {pydantic_ai_slim-0.7.6 → pydantic_ai_slim-0.8.0}/pydantic_ai/agent/__init__.py +8 -8
- {pydantic_ai_slim-0.7.6 → pydantic_ai_slim-0.8.0}/pydantic_ai/agent/abstract.py +31 -18
- {pydantic_ai_slim-0.7.6 → pydantic_ai_slim-0.8.0}/pydantic_ai/direct.py +5 -3
- {pydantic_ai_slim-0.7.6 → pydantic_ai_slim-0.8.0}/pydantic_ai/durable_exec/temporal/_function_toolset.py +9 -2
- {pydantic_ai_slim-0.7.6 → pydantic_ai_slim-0.8.0}/pydantic_ai/mcp.py +48 -71
- {pydantic_ai_slim-0.7.6 → pydantic_ai_slim-0.8.0}/pydantic_ai/messages.py +46 -10
- {pydantic_ai_slim-0.7.6 → pydantic_ai_slim-0.8.0}/pydantic_ai/models/__init__.py +4 -5
- {pydantic_ai_slim-0.7.6 → pydantic_ai_slim-0.8.0}/pydantic_ai/models/openai.py +12 -2
- {pydantic_ai_slim-0.7.6 → pydantic_ai_slim-0.8.0}/pydantic_ai/result.py +5 -5
- {pydantic_ai_slim-0.7.6 → pydantic_ai_slim-0.8.0}/pyproject.toml +1 -1
- {pydantic_ai_slim-0.7.6 → pydantic_ai_slim-0.8.0}/.gitignore +0 -0
- {pydantic_ai_slim-0.7.6 → pydantic_ai_slim-0.8.0}/LICENSE +0 -0
- {pydantic_ai_slim-0.7.6 → pydantic_ai_slim-0.8.0}/README.md +0 -0
- {pydantic_ai_slim-0.7.6 → pydantic_ai_slim-0.8.0}/pydantic_ai/__init__.py +0 -0
- {pydantic_ai_slim-0.7.6 → pydantic_ai_slim-0.8.0}/pydantic_ai/__main__.py +0 -0
- {pydantic_ai_slim-0.7.6 → pydantic_ai_slim-0.8.0}/pydantic_ai/_a2a.py +0 -0
- {pydantic_ai_slim-0.7.6 → pydantic_ai_slim-0.8.0}/pydantic_ai/_agent_graph.py +0 -0
- {pydantic_ai_slim-0.7.6 → pydantic_ai_slim-0.8.0}/pydantic_ai/_function_schema.py +0 -0
- {pydantic_ai_slim-0.7.6 → pydantic_ai_slim-0.8.0}/pydantic_ai/_griffe.py +0 -0
- {pydantic_ai_slim-0.7.6 → pydantic_ai_slim-0.8.0}/pydantic_ai/_mcp.py +0 -0
- {pydantic_ai_slim-0.7.6 → pydantic_ai_slim-0.8.0}/pydantic_ai/_otel_messages.py +0 -0
- {pydantic_ai_slim-0.7.6 → pydantic_ai_slim-0.8.0}/pydantic_ai/_output.py +0 -0
- {pydantic_ai_slim-0.7.6 → pydantic_ai_slim-0.8.0}/pydantic_ai/_parts_manager.py +0 -0
- {pydantic_ai_slim-0.7.6 → pydantic_ai_slim-0.8.0}/pydantic_ai/_run_context.py +0 -0
- {pydantic_ai_slim-0.7.6 → pydantic_ai_slim-0.8.0}/pydantic_ai/_system_prompt.py +0 -0
- {pydantic_ai_slim-0.7.6 → pydantic_ai_slim-0.8.0}/pydantic_ai/_thinking_part.py +0 -0
- {pydantic_ai_slim-0.7.6 → pydantic_ai_slim-0.8.0}/pydantic_ai/_tool_manager.py +0 -0
- {pydantic_ai_slim-0.7.6 → pydantic_ai_slim-0.8.0}/pydantic_ai/_utils.py +0 -0
- {pydantic_ai_slim-0.7.6 → pydantic_ai_slim-0.8.0}/pydantic_ai/agent/wrapper.py +0 -0
- {pydantic_ai_slim-0.7.6 → pydantic_ai_slim-0.8.0}/pydantic_ai/builtin_tools.py +0 -0
- {pydantic_ai_slim-0.7.6 → pydantic_ai_slim-0.8.0}/pydantic_ai/common_tools/__init__.py +0 -0
- {pydantic_ai_slim-0.7.6 → pydantic_ai_slim-0.8.0}/pydantic_ai/common_tools/duckduckgo.py +0 -0
- {pydantic_ai_slim-0.7.6 → pydantic_ai_slim-0.8.0}/pydantic_ai/common_tools/tavily.py +0 -0
- {pydantic_ai_slim-0.7.6 → pydantic_ai_slim-0.8.0}/pydantic_ai/durable_exec/__init__.py +0 -0
- {pydantic_ai_slim-0.7.6 → pydantic_ai_slim-0.8.0}/pydantic_ai/durable_exec/temporal/__init__.py +0 -0
- {pydantic_ai_slim-0.7.6 → pydantic_ai_slim-0.8.0}/pydantic_ai/durable_exec/temporal/_agent.py +0 -0
- {pydantic_ai_slim-0.7.6 → pydantic_ai_slim-0.8.0}/pydantic_ai/durable_exec/temporal/_logfire.py +0 -0
- {pydantic_ai_slim-0.7.6 → pydantic_ai_slim-0.8.0}/pydantic_ai/durable_exec/temporal/_mcp_server.py +0 -0
- {pydantic_ai_slim-0.7.6 → pydantic_ai_slim-0.8.0}/pydantic_ai/durable_exec/temporal/_model.py +0 -0
- {pydantic_ai_slim-0.7.6 → pydantic_ai_slim-0.8.0}/pydantic_ai/durable_exec/temporal/_run_context.py +0 -0
- {pydantic_ai_slim-0.7.6 → pydantic_ai_slim-0.8.0}/pydantic_ai/durable_exec/temporal/_toolset.py +0 -0
- {pydantic_ai_slim-0.7.6 → pydantic_ai_slim-0.8.0}/pydantic_ai/exceptions.py +0 -0
- {pydantic_ai_slim-0.7.6 → pydantic_ai_slim-0.8.0}/pydantic_ai/ext/__init__.py +0 -0
- {pydantic_ai_slim-0.7.6 → pydantic_ai_slim-0.8.0}/pydantic_ai/ext/aci.py +0 -0
- {pydantic_ai_slim-0.7.6 → pydantic_ai_slim-0.8.0}/pydantic_ai/ext/langchain.py +0 -0
- {pydantic_ai_slim-0.7.6 → pydantic_ai_slim-0.8.0}/pydantic_ai/format_prompt.py +0 -0
- {pydantic_ai_slim-0.7.6 → pydantic_ai_slim-0.8.0}/pydantic_ai/models/anthropic.py +0 -0
- {pydantic_ai_slim-0.7.6 → pydantic_ai_slim-0.8.0}/pydantic_ai/models/bedrock.py +0 -0
- {pydantic_ai_slim-0.7.6 → pydantic_ai_slim-0.8.0}/pydantic_ai/models/cohere.py +0 -0
- {pydantic_ai_slim-0.7.6 → pydantic_ai_slim-0.8.0}/pydantic_ai/models/fallback.py +0 -0
- {pydantic_ai_slim-0.7.6 → pydantic_ai_slim-0.8.0}/pydantic_ai/models/function.py +0 -0
- {pydantic_ai_slim-0.7.6 → pydantic_ai_slim-0.8.0}/pydantic_ai/models/gemini.py +0 -0
- {pydantic_ai_slim-0.7.6 → pydantic_ai_slim-0.8.0}/pydantic_ai/models/google.py +0 -0
- {pydantic_ai_slim-0.7.6 → pydantic_ai_slim-0.8.0}/pydantic_ai/models/groq.py +0 -0
- {pydantic_ai_slim-0.7.6 → pydantic_ai_slim-0.8.0}/pydantic_ai/models/huggingface.py +0 -0
- {pydantic_ai_slim-0.7.6 → pydantic_ai_slim-0.8.0}/pydantic_ai/models/instrumented.py +0 -0
- {pydantic_ai_slim-0.7.6 → pydantic_ai_slim-0.8.0}/pydantic_ai/models/mcp_sampling.py +0 -0
- {pydantic_ai_slim-0.7.6 → pydantic_ai_slim-0.8.0}/pydantic_ai/models/mistral.py +0 -0
- {pydantic_ai_slim-0.7.6 → pydantic_ai_slim-0.8.0}/pydantic_ai/models/test.py +0 -0
- {pydantic_ai_slim-0.7.6 → pydantic_ai_slim-0.8.0}/pydantic_ai/models/wrapper.py +0 -0
- {pydantic_ai_slim-0.7.6 → pydantic_ai_slim-0.8.0}/pydantic_ai/output.py +0 -0
- {pydantic_ai_slim-0.7.6 → pydantic_ai_slim-0.8.0}/pydantic_ai/profiles/__init__.py +0 -0
- {pydantic_ai_slim-0.7.6 → pydantic_ai_slim-0.8.0}/pydantic_ai/profiles/_json_schema.py +0 -0
- {pydantic_ai_slim-0.7.6 → pydantic_ai_slim-0.8.0}/pydantic_ai/profiles/amazon.py +0 -0
- {pydantic_ai_slim-0.7.6 → pydantic_ai_slim-0.8.0}/pydantic_ai/profiles/anthropic.py +0 -0
- {pydantic_ai_slim-0.7.6 → pydantic_ai_slim-0.8.0}/pydantic_ai/profiles/cohere.py +0 -0
- {pydantic_ai_slim-0.7.6 → pydantic_ai_slim-0.8.0}/pydantic_ai/profiles/deepseek.py +0 -0
- {pydantic_ai_slim-0.7.6 → pydantic_ai_slim-0.8.0}/pydantic_ai/profiles/google.py +0 -0
- {pydantic_ai_slim-0.7.6 → pydantic_ai_slim-0.8.0}/pydantic_ai/profiles/grok.py +0 -0
- {pydantic_ai_slim-0.7.6 → pydantic_ai_slim-0.8.0}/pydantic_ai/profiles/groq.py +0 -0
- {pydantic_ai_slim-0.7.6 → pydantic_ai_slim-0.8.0}/pydantic_ai/profiles/harmony.py +0 -0
- {pydantic_ai_slim-0.7.6 → pydantic_ai_slim-0.8.0}/pydantic_ai/profiles/meta.py +0 -0
- {pydantic_ai_slim-0.7.6 → pydantic_ai_slim-0.8.0}/pydantic_ai/profiles/mistral.py +0 -0
- {pydantic_ai_slim-0.7.6 → pydantic_ai_slim-0.8.0}/pydantic_ai/profiles/moonshotai.py +0 -0
- {pydantic_ai_slim-0.7.6 → pydantic_ai_slim-0.8.0}/pydantic_ai/profiles/openai.py +0 -0
- {pydantic_ai_slim-0.7.6 → pydantic_ai_slim-0.8.0}/pydantic_ai/profiles/qwen.py +0 -0
- {pydantic_ai_slim-0.7.6 → pydantic_ai_slim-0.8.0}/pydantic_ai/providers/__init__.py +0 -0
- {pydantic_ai_slim-0.7.6 → pydantic_ai_slim-0.8.0}/pydantic_ai/providers/anthropic.py +0 -0
- {pydantic_ai_slim-0.7.6 → pydantic_ai_slim-0.8.0}/pydantic_ai/providers/azure.py +0 -0
- {pydantic_ai_slim-0.7.6 → pydantic_ai_slim-0.8.0}/pydantic_ai/providers/bedrock.py +0 -0
- {pydantic_ai_slim-0.7.6 → pydantic_ai_slim-0.8.0}/pydantic_ai/providers/cerebras.py +0 -0
- {pydantic_ai_slim-0.7.6 → pydantic_ai_slim-0.8.0}/pydantic_ai/providers/cohere.py +0 -0
- {pydantic_ai_slim-0.7.6 → pydantic_ai_slim-0.8.0}/pydantic_ai/providers/deepseek.py +0 -0
- {pydantic_ai_slim-0.7.6 → pydantic_ai_slim-0.8.0}/pydantic_ai/providers/fireworks.py +0 -0
- {pydantic_ai_slim-0.7.6 → pydantic_ai_slim-0.8.0}/pydantic_ai/providers/github.py +0 -0
- {pydantic_ai_slim-0.7.6 → pydantic_ai_slim-0.8.0}/pydantic_ai/providers/google.py +0 -0
- {pydantic_ai_slim-0.7.6 → pydantic_ai_slim-0.8.0}/pydantic_ai/providers/google_gla.py +0 -0
- {pydantic_ai_slim-0.7.6 → pydantic_ai_slim-0.8.0}/pydantic_ai/providers/google_vertex.py +0 -0
- {pydantic_ai_slim-0.7.6 → pydantic_ai_slim-0.8.0}/pydantic_ai/providers/grok.py +0 -0
- {pydantic_ai_slim-0.7.6 → pydantic_ai_slim-0.8.0}/pydantic_ai/providers/groq.py +0 -0
- {pydantic_ai_slim-0.7.6 → pydantic_ai_slim-0.8.0}/pydantic_ai/providers/heroku.py +0 -0
- {pydantic_ai_slim-0.7.6 → pydantic_ai_slim-0.8.0}/pydantic_ai/providers/huggingface.py +0 -0
- {pydantic_ai_slim-0.7.6 → pydantic_ai_slim-0.8.0}/pydantic_ai/providers/mistral.py +0 -0
- {pydantic_ai_slim-0.7.6 → pydantic_ai_slim-0.8.0}/pydantic_ai/providers/moonshotai.py +0 -0
- {pydantic_ai_slim-0.7.6 → pydantic_ai_slim-0.8.0}/pydantic_ai/providers/ollama.py +0 -0
- {pydantic_ai_slim-0.7.6 → pydantic_ai_slim-0.8.0}/pydantic_ai/providers/openai.py +0 -0
- {pydantic_ai_slim-0.7.6 → pydantic_ai_slim-0.8.0}/pydantic_ai/providers/openrouter.py +0 -0
- {pydantic_ai_slim-0.7.6 → pydantic_ai_slim-0.8.0}/pydantic_ai/providers/together.py +0 -0
- {pydantic_ai_slim-0.7.6 → pydantic_ai_slim-0.8.0}/pydantic_ai/providers/vercel.py +0 -0
- {pydantic_ai_slim-0.7.6 → pydantic_ai_slim-0.8.0}/pydantic_ai/py.typed +0 -0
- {pydantic_ai_slim-0.7.6 → pydantic_ai_slim-0.8.0}/pydantic_ai/retries.py +0 -0
- {pydantic_ai_slim-0.7.6 → pydantic_ai_slim-0.8.0}/pydantic_ai/run.py +0 -0
- {pydantic_ai_slim-0.7.6 → pydantic_ai_slim-0.8.0}/pydantic_ai/settings.py +0 -0
- {pydantic_ai_slim-0.7.6 → pydantic_ai_slim-0.8.0}/pydantic_ai/tools.py +0 -0
- {pydantic_ai_slim-0.7.6 → pydantic_ai_slim-0.8.0}/pydantic_ai/toolsets/__init__.py +0 -0
- {pydantic_ai_slim-0.7.6 → pydantic_ai_slim-0.8.0}/pydantic_ai/toolsets/_dynamic.py +0 -0
- {pydantic_ai_slim-0.7.6 → pydantic_ai_slim-0.8.0}/pydantic_ai/toolsets/abstract.py +0 -0
- {pydantic_ai_slim-0.7.6 → pydantic_ai_slim-0.8.0}/pydantic_ai/toolsets/combined.py +0 -0
- {pydantic_ai_slim-0.7.6 → pydantic_ai_slim-0.8.0}/pydantic_ai/toolsets/deferred.py +0 -0
- {pydantic_ai_slim-0.7.6 → pydantic_ai_slim-0.8.0}/pydantic_ai/toolsets/filtered.py +0 -0
- {pydantic_ai_slim-0.7.6 → pydantic_ai_slim-0.8.0}/pydantic_ai/toolsets/function.py +0 -0
- {pydantic_ai_slim-0.7.6 → pydantic_ai_slim-0.8.0}/pydantic_ai/toolsets/prefixed.py +0 -0
- {pydantic_ai_slim-0.7.6 → pydantic_ai_slim-0.8.0}/pydantic_ai/toolsets/prepared.py +0 -0
- {pydantic_ai_slim-0.7.6 → pydantic_ai_slim-0.8.0}/pydantic_ai/toolsets/renamed.py +0 -0
- {pydantic_ai_slim-0.7.6 → pydantic_ai_slim-0.8.0}/pydantic_ai/toolsets/wrapper.py +0 -0
- {pydantic_ai_slim-0.7.6 → pydantic_ai_slim-0.8.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: 0.
|
|
3
|
+
Version: 0.8.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
|
|
@@ -35,7 +35,7 @@ Requires-Dist: genai-prices>=0.0.22
|
|
|
35
35
|
Requires-Dist: griffe>=1.3.2
|
|
36
36
|
Requires-Dist: httpx>=0.27
|
|
37
37
|
Requires-Dist: opentelemetry-api>=1.28.0
|
|
38
|
-
Requires-Dist: pydantic-graph==0.
|
|
38
|
+
Requires-Dist: pydantic-graph==0.8.0
|
|
39
39
|
Requires-Dist: pydantic>=2.10
|
|
40
40
|
Requires-Dist: typing-inspection>=0.4.0
|
|
41
41
|
Provides-Extra: a2a
|
|
@@ -57,7 +57,7 @@ Requires-Dist: cohere>=5.16.0; (platform_system != 'Emscripten') and extra == 'c
|
|
|
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==0.
|
|
60
|
+
Requires-Dist: pydantic-evals==0.8.0; extra == 'evals'
|
|
61
61
|
Provides-Extra: google
|
|
62
62
|
Requires-Dist: google-genai>=1.31.0; extra == 'google'
|
|
63
63
|
Provides-Extra: groq
|
|
@@ -67,7 +67,7 @@ Requires-Dist: huggingface-hub[inference]>=0.33.5; extra == 'huggingface'
|
|
|
67
67
|
Provides-Extra: logfire
|
|
68
68
|
Requires-Dist: logfire>=3.14.1; extra == 'logfire'
|
|
69
69
|
Provides-Extra: mcp
|
|
70
|
-
Requires-Dist: mcp>=1.
|
|
70
|
+
Requires-Dist: mcp>=1.12.3; (python_version >= '3.10') and extra == 'mcp'
|
|
71
71
|
Provides-Extra: mistral
|
|
72
72
|
Requires-Dist: mistralai>=1.9.2; extra == 'mistral'
|
|
73
73
|
Provides-Extra: openai
|
|
@@ -228,6 +228,7 @@ async def run_chat(
|
|
|
228
228
|
prog_name: str,
|
|
229
229
|
config_dir: Path | None = None,
|
|
230
230
|
deps: AgentDepsT = None,
|
|
231
|
+
message_history: list[ModelMessage] | None = None,
|
|
231
232
|
) -> int:
|
|
232
233
|
prompt_history_path = (config_dir or PYDANTIC_AI_HOME) / PROMPT_HISTORY_FILENAME
|
|
233
234
|
prompt_history_path.parent.mkdir(parents=True, exist_ok=True)
|
|
@@ -235,7 +236,7 @@ async def run_chat(
|
|
|
235
236
|
session: PromptSession[Any] = PromptSession(history=FileHistory(str(prompt_history_path)))
|
|
236
237
|
|
|
237
238
|
multiline = False
|
|
238
|
-
messages: list[ModelMessage] = []
|
|
239
|
+
messages: list[ModelMessage] = message_history[:] if message_history else []
|
|
239
240
|
|
|
240
241
|
while True:
|
|
241
242
|
try:
|
|
@@ -28,11 +28,11 @@ from ._agent_graph import CallToolsNode, ModelRequestNode
|
|
|
28
28
|
from .agent import AbstractAgent, AgentRun
|
|
29
29
|
from .exceptions import UserError
|
|
30
30
|
from .messages import (
|
|
31
|
-
AgentStreamEvent,
|
|
32
31
|
FunctionToolResultEvent,
|
|
33
32
|
ModelMessage,
|
|
34
33
|
ModelRequest,
|
|
35
34
|
ModelResponse,
|
|
35
|
+
ModelResponseStreamEvent,
|
|
36
36
|
PartDeltaEvent,
|
|
37
37
|
PartStartEvent,
|
|
38
38
|
SystemPromptPart,
|
|
@@ -403,7 +403,7 @@ async def _agent_stream(run: AgentRun[AgentDepsT, Any]) -> AsyncIterator[BaseEve
|
|
|
403
403
|
|
|
404
404
|
async def _handle_model_request_event(
|
|
405
405
|
stream_ctx: _RequestStreamContext,
|
|
406
|
-
agent_event:
|
|
406
|
+
agent_event: ModelResponseStreamEvent,
|
|
407
407
|
) -> AsyncIterator[BaseEvent]:
|
|
408
408
|
"""Handle an agent event and yield AG-UI protocol events.
|
|
409
409
|
|
|
@@ -26,7 +26,14 @@ from .. import (
|
|
|
26
26
|
models,
|
|
27
27
|
usage as _usage,
|
|
28
28
|
)
|
|
29
|
-
from .._agent_graph import
|
|
29
|
+
from .._agent_graph import (
|
|
30
|
+
CallToolsNode,
|
|
31
|
+
EndStrategy,
|
|
32
|
+
HistoryProcessor,
|
|
33
|
+
ModelRequestNode,
|
|
34
|
+
UserPromptNode,
|
|
35
|
+
capture_run_messages,
|
|
36
|
+
)
|
|
30
37
|
from .._output import OutputToolset
|
|
31
38
|
from .._tool_manager import ToolManager
|
|
32
39
|
from ..builtin_tools import AbstractBuiltinTool
|
|
@@ -60,13 +67,6 @@ from ..toolsets.prepared import PreparedToolset
|
|
|
60
67
|
from .abstract import AbstractAgent, EventStreamHandler, RunOutputDataT
|
|
61
68
|
from .wrapper import WrapperAgent
|
|
62
69
|
|
|
63
|
-
# Re-exporting like this improves auto-import behavior in PyCharm
|
|
64
|
-
capture_run_messages = _agent_graph.capture_run_messages
|
|
65
|
-
EndStrategy = _agent_graph.EndStrategy
|
|
66
|
-
CallToolsNode = _agent_graph.CallToolsNode
|
|
67
|
-
ModelRequestNode = _agent_graph.ModelRequestNode
|
|
68
|
-
UserPromptNode = _agent_graph.UserPromptNode
|
|
69
|
-
|
|
70
70
|
if TYPE_CHECKING:
|
|
71
71
|
from ..mcp import MCPServer
|
|
72
72
|
|
|
@@ -5,7 +5,7 @@ from abc import ABC, abstractmethod
|
|
|
5
5
|
from collections.abc import AsyncIterable, AsyncIterator, Awaitable, Iterator, Mapping, Sequence
|
|
6
6
|
from contextlib import AbstractAsyncContextManager, asynccontextmanager, contextmanager
|
|
7
7
|
from types import FrameType
|
|
8
|
-
from typing import TYPE_CHECKING, Any, Callable, Generic,
|
|
8
|
+
from typing import TYPE_CHECKING, Any, Callable, Generic, cast, overload
|
|
9
9
|
|
|
10
10
|
from typing_extensions import Self, TypeAlias, TypeIs, TypeVar
|
|
11
11
|
|
|
@@ -34,13 +34,6 @@ from ..tools import (
|
|
|
34
34
|
from ..toolsets import AbstractToolset
|
|
35
35
|
from ..usage import RunUsage, UsageLimits
|
|
36
36
|
|
|
37
|
-
# Re-exporting like this improves auto-import behavior in PyCharm
|
|
38
|
-
capture_run_messages = _agent_graph.capture_run_messages
|
|
39
|
-
EndStrategy = _agent_graph.EndStrategy
|
|
40
|
-
CallToolsNode = _agent_graph.CallToolsNode
|
|
41
|
-
ModelRequestNode = _agent_graph.ModelRequestNode
|
|
42
|
-
UserPromptNode = _agent_graph.UserPromptNode
|
|
43
|
-
|
|
44
37
|
if TYPE_CHECKING:
|
|
45
38
|
from fasta2a.applications import FastA2A
|
|
46
39
|
from fasta2a.broker import Broker
|
|
@@ -60,11 +53,7 @@ RunOutputDataT = TypeVar('RunOutputDataT')
|
|
|
60
53
|
"""Type variable for the result data of a run where `output_type` was customized on the run call."""
|
|
61
54
|
|
|
62
55
|
EventStreamHandler: TypeAlias = Callable[
|
|
63
|
-
[
|
|
64
|
-
RunContext[AgentDepsT],
|
|
65
|
-
AsyncIterable[Union[_messages.AgentStreamEvent, _messages.HandleResponseEvent]],
|
|
66
|
-
],
|
|
67
|
-
Awaitable[None],
|
|
56
|
+
[RunContext[AgentDepsT], AsyncIterable[_messages.AgentStreamEvent]], Awaitable[None]
|
|
68
57
|
]
|
|
69
58
|
"""A function that receives agent [`RunContext`][pydantic_ai.tools.RunContext] and an async iterable of events from the model's streaming response and the agent's execution of tools."""
|
|
70
59
|
|
|
@@ -452,7 +441,9 @@ class AbstractAgent(Generic[AgentDepsT, OutputDataT], ABC):
|
|
|
452
441
|
async with node.stream(graph_ctx) as stream:
|
|
453
442
|
final_result_event = None
|
|
454
443
|
|
|
455
|
-
async def stream_to_final(
|
|
444
|
+
async def stream_to_final(
|
|
445
|
+
stream: AgentStream,
|
|
446
|
+
) -> AsyncIterator[_messages.ModelResponseStreamEvent]:
|
|
456
447
|
nonlocal final_result_event
|
|
457
448
|
async for event in stream:
|
|
458
449
|
yield event
|
|
@@ -899,12 +890,18 @@ class AbstractAgent(Generic[AgentDepsT, OutputDataT], ABC):
|
|
|
899
890
|
lifespan=lifespan,
|
|
900
891
|
)
|
|
901
892
|
|
|
902
|
-
async def to_cli(
|
|
893
|
+
async def to_cli(
|
|
894
|
+
self: Self,
|
|
895
|
+
deps: AgentDepsT = None,
|
|
896
|
+
prog_name: str = 'pydantic-ai',
|
|
897
|
+
message_history: list[_messages.ModelMessage] | None = None,
|
|
898
|
+
) -> None:
|
|
903
899
|
"""Run the agent in a CLI chat interface.
|
|
904
900
|
|
|
905
901
|
Args:
|
|
906
902
|
deps: The dependencies to pass to the agent.
|
|
907
903
|
prog_name: The name of the program to use for the CLI. Defaults to 'pydantic-ai'.
|
|
904
|
+
message_history: History of the conversation so far.
|
|
908
905
|
|
|
909
906
|
Example:
|
|
910
907
|
```python {title="agent_to_cli.py" test="skip"}
|
|
@@ -920,14 +917,28 @@ class AbstractAgent(Generic[AgentDepsT, OutputDataT], ABC):
|
|
|
920
917
|
|
|
921
918
|
from pydantic_ai._cli import run_chat
|
|
922
919
|
|
|
923
|
-
await run_chat(
|
|
920
|
+
await run_chat(
|
|
921
|
+
stream=True,
|
|
922
|
+
agent=self,
|
|
923
|
+
deps=deps,
|
|
924
|
+
console=Console(),
|
|
925
|
+
code_theme='monokai',
|
|
926
|
+
prog_name=prog_name,
|
|
927
|
+
message_history=message_history,
|
|
928
|
+
)
|
|
924
929
|
|
|
925
|
-
def to_cli_sync(
|
|
930
|
+
def to_cli_sync(
|
|
931
|
+
self: Self,
|
|
932
|
+
deps: AgentDepsT = None,
|
|
933
|
+
prog_name: str = 'pydantic-ai',
|
|
934
|
+
message_history: list[_messages.ModelMessage] | None = None,
|
|
935
|
+
) -> None:
|
|
926
936
|
"""Run the agent in a CLI chat interface with the non-async interface.
|
|
927
937
|
|
|
928
938
|
Args:
|
|
929
939
|
deps: The dependencies to pass to the agent.
|
|
930
940
|
prog_name: The name of the program to use for the CLI. Defaults to 'pydantic-ai'.
|
|
941
|
+
message_history: History of the conversation so far.
|
|
931
942
|
|
|
932
943
|
```python {title="agent_to_cli_sync.py" test="skip"}
|
|
933
944
|
from pydantic_ai import Agent
|
|
@@ -937,4 +948,6 @@ class AbstractAgent(Generic[AgentDepsT, OutputDataT], ABC):
|
|
|
937
948
|
agent.to_cli_sync(prog_name='assistant')
|
|
938
949
|
```
|
|
939
950
|
"""
|
|
940
|
-
return get_event_loop().run_until_complete(
|
|
951
|
+
return get_event_loop().run_until_complete(
|
|
952
|
+
self.to_cli(deps=deps, prog_name=prog_name, message_history=message_history)
|
|
953
|
+
)
|
|
@@ -275,7 +275,9 @@ class StreamedResponseSync:
|
|
|
275
275
|
"""
|
|
276
276
|
|
|
277
277
|
_async_stream_cm: AbstractAsyncContextManager[StreamedResponse]
|
|
278
|
-
_queue: queue.Queue[messages.
|
|
278
|
+
_queue: queue.Queue[messages.ModelResponseStreamEvent | Exception | None] = field(
|
|
279
|
+
default_factory=queue.Queue, init=False
|
|
280
|
+
)
|
|
279
281
|
_thread: threading.Thread | None = field(default=None, init=False)
|
|
280
282
|
_stream_response: StreamedResponse | None = field(default=None, init=False)
|
|
281
283
|
_exception: Exception | None = field(default=None, init=False)
|
|
@@ -295,8 +297,8 @@ class StreamedResponseSync:
|
|
|
295
297
|
) -> None:
|
|
296
298
|
self._cleanup()
|
|
297
299
|
|
|
298
|
-
def __iter__(self) -> Iterator[messages.
|
|
299
|
-
"""Stream the response as an iterable of [`
|
|
300
|
+
def __iter__(self) -> Iterator[messages.ModelResponseStreamEvent]:
|
|
301
|
+
"""Stream the response as an iterable of [`ModelResponseStreamEvent`][pydantic_ai.messages.ModelResponseStreamEvent]s."""
|
|
300
302
|
self._check_context_manager_usage()
|
|
301
303
|
|
|
302
304
|
while True:
|
|
@@ -51,7 +51,10 @@ class TemporalFunctionToolset(TemporalWrapperToolset[AgentDepsT]):
|
|
|
51
51
|
'Removing or renaming tools during an agent run is not supported with Temporal.'
|
|
52
52
|
) from e
|
|
53
53
|
|
|
54
|
-
|
|
54
|
+
# The tool args will already have been validated into their proper types in the `ToolManager`,
|
|
55
|
+
# but `execute_activity` would have turned them into simple Python types again, so we need to re-validate them.
|
|
56
|
+
args_dict = tool.args_validator.validate_python(params.tool_args)
|
|
57
|
+
return await self.wrapped.call_tool(name, args_dict, ctx, tool)
|
|
55
58
|
|
|
56
59
|
# Set type hint explicitly so that Temporal can take care of serialization and deserialization
|
|
57
60
|
call_tool_activity.__annotations__['deps'] = deps_type
|
|
@@ -85,7 +88,11 @@ class TemporalFunctionToolset(TemporalWrapperToolset[AgentDepsT]):
|
|
|
85
88
|
return await workflow.execute_activity( # pyright: ignore[reportUnknownMemberType]
|
|
86
89
|
activity=self.call_tool_activity,
|
|
87
90
|
args=[
|
|
88
|
-
_CallToolParams(
|
|
91
|
+
_CallToolParams(
|
|
92
|
+
name=name,
|
|
93
|
+
tool_args=tool_args,
|
|
94
|
+
serialized_run_context=serialized_run_context,
|
|
95
|
+
),
|
|
89
96
|
ctx.deps,
|
|
90
97
|
],
|
|
91
98
|
**tool_activity_config,
|
|
@@ -18,14 +18,13 @@ import pydantic_core
|
|
|
18
18
|
from anyio.streams.memory import MemoryObjectReceiveStream, MemoryObjectSendStream
|
|
19
19
|
from typing_extensions import Self, assert_never, deprecated
|
|
20
20
|
|
|
21
|
-
from pydantic_ai.
|
|
22
|
-
from pydantic_ai.tools import ToolDefinition
|
|
21
|
+
from pydantic_ai.tools import RunContext, ToolDefinition
|
|
23
22
|
|
|
24
23
|
from .toolsets.abstract import AbstractToolset, ToolsetTool
|
|
25
24
|
|
|
26
25
|
try:
|
|
27
26
|
from mcp import types as mcp_types
|
|
28
|
-
from mcp.client.session import ClientSession, LoggingFnT
|
|
27
|
+
from mcp.client.session import ClientSession, ElicitationFnT, LoggingFnT
|
|
29
28
|
from mcp.client.sse import sse_client
|
|
30
29
|
from mcp.client.stdio import StdioServerParameters, stdio_client
|
|
31
30
|
from mcp.client.streamable_http import GetSessionIdCallback, streamablehttp_client
|
|
@@ -57,14 +56,49 @@ class MCPServer(AbstractToolset[Any], ABC):
|
|
|
57
56
|
"""
|
|
58
57
|
|
|
59
58
|
tool_prefix: str | None
|
|
59
|
+
"""A prefix to add to all tools that are registered with the server.
|
|
60
|
+
|
|
61
|
+
If not empty, will include a trailing underscore(`_`).
|
|
62
|
+
|
|
63
|
+
e.g. if `tool_prefix='foo'`, then a tool named `bar` will be registered as `foo_bar`
|
|
64
|
+
"""
|
|
65
|
+
|
|
60
66
|
log_level: mcp_types.LoggingLevel | None
|
|
67
|
+
"""The log level to set when connecting to the server, if any.
|
|
68
|
+
|
|
69
|
+
See <https://modelcontextprotocol.io/specification/2025-03-26/server/utilities/logging#logging> for more details.
|
|
70
|
+
|
|
71
|
+
If `None`, no log level will be set.
|
|
72
|
+
"""
|
|
73
|
+
|
|
61
74
|
log_handler: LoggingFnT | None
|
|
75
|
+
"""A handler for logging messages from the server."""
|
|
76
|
+
|
|
62
77
|
timeout: float
|
|
78
|
+
"""The timeout in seconds to wait for the client to initialize."""
|
|
79
|
+
|
|
63
80
|
read_timeout: float
|
|
81
|
+
"""Maximum time in seconds to wait for new messages before timing out.
|
|
82
|
+
|
|
83
|
+
This timeout applies to the long-lived connection after it's established.
|
|
84
|
+
If no new messages are received within this time, the connection will be considered stale
|
|
85
|
+
and may be closed. Defaults to 5 minutes (300 seconds).
|
|
86
|
+
"""
|
|
87
|
+
|
|
64
88
|
process_tool_call: ProcessToolCallback | None
|
|
89
|
+
"""Hook to customize tool calling and optionally pass extra metadata."""
|
|
90
|
+
|
|
65
91
|
allow_sampling: bool
|
|
92
|
+
"""Whether to allow MCP sampling through this client."""
|
|
93
|
+
|
|
66
94
|
sampling_model: models.Model | None
|
|
95
|
+
"""The model to use for sampling."""
|
|
96
|
+
|
|
67
97
|
max_retries: int
|
|
98
|
+
"""The maximum number of times to retry a tool call."""
|
|
99
|
+
|
|
100
|
+
elicitation_callback: ElicitationFnT | None = None
|
|
101
|
+
"""Callback function to handle elicitation requests from the server."""
|
|
68
102
|
|
|
69
103
|
_id: str | None
|
|
70
104
|
|
|
@@ -87,6 +121,7 @@ class MCPServer(AbstractToolset[Any], ABC):
|
|
|
87
121
|
allow_sampling: bool = True,
|
|
88
122
|
sampling_model: models.Model | None = None,
|
|
89
123
|
max_retries: int = 1,
|
|
124
|
+
elicitation_callback: ElicitationFnT | None = None,
|
|
90
125
|
*,
|
|
91
126
|
id: str | None = None,
|
|
92
127
|
):
|
|
@@ -99,6 +134,7 @@ class MCPServer(AbstractToolset[Any], ABC):
|
|
|
99
134
|
self.allow_sampling = allow_sampling
|
|
100
135
|
self.sampling_model = sampling_model
|
|
101
136
|
self.max_retries = max_retries
|
|
137
|
+
self.elicitation_callback = elicitation_callback
|
|
102
138
|
|
|
103
139
|
self._id = id or tool_prefix
|
|
104
140
|
|
|
@@ -247,6 +283,7 @@ class MCPServer(AbstractToolset[Any], ABC):
|
|
|
247
283
|
read_stream=self._read_stream,
|
|
248
284
|
write_stream=self._write_stream,
|
|
249
285
|
sampling_callback=self._sampling_callback if self.allow_sampling else None,
|
|
286
|
+
elicitation_callback=self.elicitation_callback,
|
|
250
287
|
logging_callback=self.log_handler,
|
|
251
288
|
read_timeout_seconds=timedelta(seconds=self.read_timeout),
|
|
252
289
|
)
|
|
@@ -404,46 +441,15 @@ class MCPServerStdio(MCPServer):
|
|
|
404
441
|
|
|
405
442
|
# last fields are re-defined from the parent class so they appear as fields
|
|
406
443
|
tool_prefix: str | None
|
|
407
|
-
"""A prefix to add to all tools that are registered with the server.
|
|
408
|
-
|
|
409
|
-
If not empty, will include a trailing underscore(`_`).
|
|
410
|
-
|
|
411
|
-
e.g. if `tool_prefix='foo'`, then a tool named `bar` will be registered as `foo_bar`
|
|
412
|
-
"""
|
|
413
|
-
|
|
414
444
|
log_level: mcp_types.LoggingLevel | None
|
|
415
|
-
"""The log level to set when connecting to the server, if any.
|
|
416
|
-
|
|
417
|
-
See <https://modelcontextprotocol.io/specification/2025-03-26/server/utilities/logging#logging> for more details.
|
|
418
|
-
|
|
419
|
-
If `None`, no log level will be set.
|
|
420
|
-
"""
|
|
421
|
-
|
|
422
445
|
log_handler: LoggingFnT | None
|
|
423
|
-
"""A handler for logging messages from the server."""
|
|
424
|
-
|
|
425
446
|
timeout: float
|
|
426
|
-
"""The timeout in seconds to wait for the client to initialize."""
|
|
427
|
-
|
|
428
447
|
read_timeout: float
|
|
429
|
-
"""Maximum time in seconds to wait for new messages before timing out.
|
|
430
|
-
|
|
431
|
-
This timeout applies to the long-lived connection after it's established.
|
|
432
|
-
If no new messages are received within this time, the connection will be considered stale
|
|
433
|
-
and may be closed. Defaults to 5 minutes (300 seconds).
|
|
434
|
-
"""
|
|
435
|
-
|
|
436
448
|
process_tool_call: ProcessToolCallback | None
|
|
437
|
-
"""Hook to customize tool calling and optionally pass extra metadata."""
|
|
438
|
-
|
|
439
449
|
allow_sampling: bool
|
|
440
|
-
"""Whether to allow MCP sampling through this client."""
|
|
441
|
-
|
|
442
450
|
sampling_model: models.Model | None
|
|
443
|
-
"""The model to use for sampling."""
|
|
444
|
-
|
|
445
451
|
max_retries: int
|
|
446
|
-
|
|
452
|
+
elicitation_callback: ElicitationFnT | None = None
|
|
447
453
|
|
|
448
454
|
def __init__(
|
|
449
455
|
self,
|
|
@@ -460,6 +466,7 @@ class MCPServerStdio(MCPServer):
|
|
|
460
466
|
allow_sampling: bool = True,
|
|
461
467
|
sampling_model: models.Model | None = None,
|
|
462
468
|
max_retries: int = 1,
|
|
469
|
+
elicitation_callback: ElicitationFnT | None = None,
|
|
463
470
|
*,
|
|
464
471
|
id: str | None = None,
|
|
465
472
|
):
|
|
@@ -479,6 +486,7 @@ class MCPServerStdio(MCPServer):
|
|
|
479
486
|
allow_sampling: Whether to allow MCP sampling through this client.
|
|
480
487
|
sampling_model: The model to use for sampling.
|
|
481
488
|
max_retries: The maximum number of times to retry a tool call.
|
|
489
|
+
elicitation_callback: Callback function to handle elicitation requests from the server.
|
|
482
490
|
id: An optional unique ID for the MCP server. An MCP server needs to have an ID in order to be used in a durable execution environment like Temporal, in which case the ID will be used to identify the server's activities within the workflow.
|
|
483
491
|
"""
|
|
484
492
|
self.command = command
|
|
@@ -496,6 +504,7 @@ class MCPServerStdio(MCPServer):
|
|
|
496
504
|
allow_sampling,
|
|
497
505
|
sampling_model,
|
|
498
506
|
max_retries,
|
|
507
|
+
elicitation_callback,
|
|
499
508
|
id=id,
|
|
500
509
|
)
|
|
501
510
|
|
|
@@ -560,50 +569,15 @@ class _MCPServerHTTP(MCPServer):
|
|
|
560
569
|
|
|
561
570
|
# last fields are re-defined from the parent class so they appear as fields
|
|
562
571
|
tool_prefix: str | None
|
|
563
|
-
"""A prefix to add to all tools that are registered with the server.
|
|
564
|
-
|
|
565
|
-
If not empty, will include a trailing underscore (`_`).
|
|
566
|
-
|
|
567
|
-
For example, if `tool_prefix='foo'`, then a tool named `bar` will be registered as `foo_bar`
|
|
568
|
-
"""
|
|
569
|
-
|
|
570
572
|
log_level: mcp_types.LoggingLevel | None
|
|
571
|
-
"""The log level to set when connecting to the server, if any.
|
|
572
|
-
|
|
573
|
-
See <https://modelcontextprotocol.io/introduction#logging> for more details.
|
|
574
|
-
|
|
575
|
-
If `None`, no log level will be set.
|
|
576
|
-
"""
|
|
577
|
-
|
|
578
573
|
log_handler: LoggingFnT | None
|
|
579
|
-
"""A handler for logging messages from the server."""
|
|
580
|
-
|
|
581
574
|
timeout: float
|
|
582
|
-
"""Initial connection timeout in seconds for establishing the connection.
|
|
583
|
-
|
|
584
|
-
This timeout applies to the initial connection setup and handshake.
|
|
585
|
-
If the connection cannot be established within this time, the operation will fail.
|
|
586
|
-
"""
|
|
587
|
-
|
|
588
575
|
read_timeout: float
|
|
589
|
-
"""Maximum time in seconds to wait for new messages before timing out.
|
|
590
|
-
|
|
591
|
-
This timeout applies to the long-lived connection after it's established.
|
|
592
|
-
If no new messages are received within this time, the connection will be considered stale
|
|
593
|
-
and may be closed. Defaults to 5 minutes (300 seconds).
|
|
594
|
-
"""
|
|
595
|
-
|
|
596
576
|
process_tool_call: ProcessToolCallback | None
|
|
597
|
-
"""Hook to customize tool calling and optionally pass extra metadata."""
|
|
598
|
-
|
|
599
577
|
allow_sampling: bool
|
|
600
|
-
"""Whether to allow MCP sampling through this client."""
|
|
601
|
-
|
|
602
578
|
sampling_model: models.Model | None
|
|
603
|
-
"""The model to use for sampling."""
|
|
604
|
-
|
|
605
579
|
max_retries: int
|
|
606
|
-
|
|
580
|
+
elicitation_callback: ElicitationFnT | None = None
|
|
607
581
|
|
|
608
582
|
def __init__(
|
|
609
583
|
self,
|
|
@@ -621,6 +595,7 @@ class _MCPServerHTTP(MCPServer):
|
|
|
621
595
|
allow_sampling: bool = True,
|
|
622
596
|
sampling_model: models.Model | None = None,
|
|
623
597
|
max_retries: int = 1,
|
|
598
|
+
elicitation_callback: ElicitationFnT | None = None,
|
|
624
599
|
**_deprecated_kwargs: Any,
|
|
625
600
|
):
|
|
626
601
|
"""Build a new MCP server.
|
|
@@ -639,6 +614,7 @@ class _MCPServerHTTP(MCPServer):
|
|
|
639
614
|
allow_sampling: Whether to allow MCP sampling through this client.
|
|
640
615
|
sampling_model: The model to use for sampling.
|
|
641
616
|
max_retries: The maximum number of times to retry a tool call.
|
|
617
|
+
elicitation_callback: Callback function to handle elicitation requests from the server.
|
|
642
618
|
"""
|
|
643
619
|
if 'sse_read_timeout' in _deprecated_kwargs:
|
|
644
620
|
if read_timeout is not None:
|
|
@@ -668,6 +644,7 @@ class _MCPServerHTTP(MCPServer):
|
|
|
668
644
|
allow_sampling,
|
|
669
645
|
sampling_model,
|
|
670
646
|
max_retries,
|
|
647
|
+
elicitation_callback,
|
|
671
648
|
id=id,
|
|
672
649
|
)
|
|
673
650
|
|
|
@@ -110,7 +110,9 @@ class FileUrl(ABC):
|
|
|
110
110
|
- `GoogleModel`: `VideoUrl.vendor_metadata` is used as `video_metadata`: https://ai.google.dev/gemini-api/docs/video-understanding#customize-video-processing
|
|
111
111
|
"""
|
|
112
112
|
|
|
113
|
-
_media_type: str | None
|
|
113
|
+
_media_type: Annotated[str | None, pydantic.Field(alias='media_type', default=None, exclude=True)] = field(
|
|
114
|
+
compare=False, default=None
|
|
115
|
+
)
|
|
114
116
|
|
|
115
117
|
def __init__(
|
|
116
118
|
self,
|
|
@@ -124,6 +126,7 @@ class FileUrl(ABC):
|
|
|
124
126
|
self.force_download = force_download
|
|
125
127
|
self._media_type = media_type
|
|
126
128
|
|
|
129
|
+
@pydantic.computed_field
|
|
127
130
|
@property
|
|
128
131
|
def media_type(self) -> str:
|
|
129
132
|
"""Return the media type of the file, based on the URL or the provided `media_type`."""
|
|
@@ -160,8 +163,16 @@ class VideoUrl(FileUrl):
|
|
|
160
163
|
vendor_metadata: dict[str, Any] | None = None,
|
|
161
164
|
media_type: str | None = None,
|
|
162
165
|
kind: Literal['video-url'] = 'video-url',
|
|
166
|
+
*,
|
|
167
|
+
# Required for inline-snapshot which expects all dataclass `__init__` methods to take all field names as kwargs.
|
|
168
|
+
_media_type: str | None = None,
|
|
163
169
|
) -> None:
|
|
164
|
-
super().__init__(
|
|
170
|
+
super().__init__(
|
|
171
|
+
url=url,
|
|
172
|
+
force_download=force_download,
|
|
173
|
+
vendor_metadata=vendor_metadata,
|
|
174
|
+
media_type=media_type or _media_type,
|
|
175
|
+
)
|
|
165
176
|
self.kind = kind
|
|
166
177
|
|
|
167
178
|
def _infer_media_type(self) -> VideoMediaType:
|
|
@@ -223,8 +234,16 @@ class AudioUrl(FileUrl):
|
|
|
223
234
|
vendor_metadata: dict[str, Any] | None = None,
|
|
224
235
|
media_type: str | None = None,
|
|
225
236
|
kind: Literal['audio-url'] = 'audio-url',
|
|
237
|
+
*,
|
|
238
|
+
# Required for inline-snapshot which expects all dataclass `__init__` methods to take all field names as kwargs.
|
|
239
|
+
_media_type: str | None = None,
|
|
226
240
|
) -> None:
|
|
227
|
-
super().__init__(
|
|
241
|
+
super().__init__(
|
|
242
|
+
url=url,
|
|
243
|
+
force_download=force_download,
|
|
244
|
+
vendor_metadata=vendor_metadata,
|
|
245
|
+
media_type=media_type or _media_type,
|
|
246
|
+
)
|
|
228
247
|
self.kind = kind
|
|
229
248
|
|
|
230
249
|
def _infer_media_type(self) -> AudioMediaType:
|
|
@@ -273,8 +292,16 @@ class ImageUrl(FileUrl):
|
|
|
273
292
|
vendor_metadata: dict[str, Any] | None = None,
|
|
274
293
|
media_type: str | None = None,
|
|
275
294
|
kind: Literal['image-url'] = 'image-url',
|
|
295
|
+
*,
|
|
296
|
+
# Required for inline-snapshot which expects all dataclass `__init__` methods to take all field names as kwargs.
|
|
297
|
+
_media_type: str | None = None,
|
|
276
298
|
) -> None:
|
|
277
|
-
super().__init__(
|
|
299
|
+
super().__init__(
|
|
300
|
+
url=url,
|
|
301
|
+
force_download=force_download,
|
|
302
|
+
vendor_metadata=vendor_metadata,
|
|
303
|
+
media_type=media_type or _media_type,
|
|
304
|
+
)
|
|
278
305
|
self.kind = kind
|
|
279
306
|
|
|
280
307
|
def _infer_media_type(self) -> ImageMediaType:
|
|
@@ -318,8 +345,16 @@ class DocumentUrl(FileUrl):
|
|
|
318
345
|
vendor_metadata: dict[str, Any] | None = None,
|
|
319
346
|
media_type: str | None = None,
|
|
320
347
|
kind: Literal['document-url'] = 'document-url',
|
|
348
|
+
*,
|
|
349
|
+
# Required for inline-snapshot which expects all dataclass `__init__` methods to take all field names as kwargs.
|
|
350
|
+
_media_type: str | None = None,
|
|
321
351
|
) -> None:
|
|
322
|
-
super().__init__(
|
|
352
|
+
super().__init__(
|
|
353
|
+
url=url,
|
|
354
|
+
force_download=force_download,
|
|
355
|
+
vendor_metadata=vendor_metadata,
|
|
356
|
+
media_type=media_type or _media_type,
|
|
357
|
+
)
|
|
323
358
|
self.kind = kind
|
|
324
359
|
|
|
325
360
|
def _infer_media_type(self) -> str:
|
|
@@ -1263,13 +1298,10 @@ class FinalResultEvent:
|
|
|
1263
1298
|
__repr__ = _utils.dataclasses_no_defaults_repr
|
|
1264
1299
|
|
|
1265
1300
|
|
|
1266
|
-
ModelResponseStreamEvent = Annotated[
|
|
1267
|
-
"""An event in the model response stream, either starting a new part or applying a delta to an existing one."""
|
|
1268
|
-
|
|
1269
|
-
AgentStreamEvent = Annotated[
|
|
1301
|
+
ModelResponseStreamEvent = Annotated[
|
|
1270
1302
|
Union[PartStartEvent, PartDeltaEvent, FinalResultEvent], pydantic.Discriminator('event_kind')
|
|
1271
1303
|
]
|
|
1272
|
-
"""An event in the
|
|
1304
|
+
"""An event in the model response stream, starting a new part, applying a delta to an existing one, or indicating the final result."""
|
|
1273
1305
|
|
|
1274
1306
|
|
|
1275
1307
|
@dataclass(repr=False)
|
|
@@ -1338,3 +1370,7 @@ HandleResponseEvent = Annotated[
|
|
|
1338
1370
|
Union[FunctionToolCallEvent, FunctionToolResultEvent, BuiltinToolCallEvent, BuiltinToolResultEvent],
|
|
1339
1371
|
pydantic.Discriminator('event_kind'),
|
|
1340
1372
|
]
|
|
1373
|
+
"""An event yielded when handling a model response, indicating tool calls and results."""
|
|
1374
|
+
|
|
1375
|
+
AgentStreamEvent = Annotated[Union[ModelResponseStreamEvent, HandleResponseEvent], pydantic.Discriminator('event_kind')]
|
|
1376
|
+
"""An event in the agent stream: model response stream events and response-handling events."""
|
|
@@ -25,7 +25,6 @@ from .._run_context import RunContext
|
|
|
25
25
|
from ..builtin_tools import AbstractBuiltinTool
|
|
26
26
|
from ..exceptions import UserError
|
|
27
27
|
from ..messages import (
|
|
28
|
-
AgentStreamEvent,
|
|
29
28
|
FileUrl,
|
|
30
29
|
FinalResultEvent,
|
|
31
30
|
ModelMessage,
|
|
@@ -555,11 +554,11 @@ class StreamedResponse(ABC):
|
|
|
555
554
|
final_result_event: FinalResultEvent | None = field(default=None, init=False)
|
|
556
555
|
|
|
557
556
|
_parts_manager: ModelResponsePartsManager = field(default_factory=ModelResponsePartsManager, init=False)
|
|
558
|
-
_event_iterator: AsyncIterator[
|
|
557
|
+
_event_iterator: AsyncIterator[ModelResponseStreamEvent] | None = field(default=None, init=False)
|
|
559
558
|
_usage: RequestUsage = field(default_factory=RequestUsage, init=False)
|
|
560
559
|
|
|
561
|
-
def __aiter__(self) -> AsyncIterator[
|
|
562
|
-
"""Stream the response as an async iterable of [`
|
|
560
|
+
def __aiter__(self) -> AsyncIterator[ModelResponseStreamEvent]:
|
|
561
|
+
"""Stream the response as an async iterable of [`ModelResponseStreamEvent`][pydantic_ai.messages.ModelResponseStreamEvent]s.
|
|
563
562
|
|
|
564
563
|
This proxies the `_event_iterator()` and emits all events, while also checking for matches
|
|
565
564
|
on the result schema and emitting a [`FinalResultEvent`][pydantic_ai.messages.FinalResultEvent] if/when the
|
|
@@ -569,7 +568,7 @@ class StreamedResponse(ABC):
|
|
|
569
568
|
|
|
570
569
|
async def iterator_with_final_event(
|
|
571
570
|
iterator: AsyncIterator[ModelResponseStreamEvent],
|
|
572
|
-
) -> AsyncIterator[
|
|
571
|
+
) -> AsyncIterator[ModelResponseStreamEvent]:
|
|
573
572
|
async for event in iterator:
|
|
574
573
|
yield event
|
|
575
574
|
if (
|
|
@@ -1375,11 +1375,21 @@ def _map_usage(response: chat.ChatCompletion | ChatCompletionChunk | responses.R
|
|
|
1375
1375
|
).items()
|
|
1376
1376
|
if isinstance(value, int)
|
|
1377
1377
|
}
|
|
1378
|
-
|
|
1378
|
+
# Handle vLLM compatibility - some providers don't include token details
|
|
1379
|
+
if getattr(response_usage, 'input_tokens_details', None) is not None:
|
|
1380
|
+
cache_read_tokens = response_usage.input_tokens_details.cached_tokens
|
|
1381
|
+
else:
|
|
1382
|
+
cache_read_tokens = 0
|
|
1383
|
+
|
|
1384
|
+
if getattr(response_usage, 'output_tokens_details', None) is not None:
|
|
1385
|
+
details['reasoning_tokens'] = response_usage.output_tokens_details.reasoning_tokens
|
|
1386
|
+
else:
|
|
1387
|
+
details['reasoning_tokens'] = 0
|
|
1388
|
+
|
|
1379
1389
|
return usage.RequestUsage(
|
|
1380
1390
|
input_tokens=response_usage.input_tokens,
|
|
1381
1391
|
output_tokens=response_usage.output_tokens,
|
|
1382
|
-
cache_read_tokens=
|
|
1392
|
+
cache_read_tokens=cache_read_tokens,
|
|
1383
1393
|
details=details,
|
|
1384
1394
|
)
|
|
1385
1395
|
else:
|
|
@@ -22,7 +22,7 @@ from ._output import (
|
|
|
22
22
|
ToolOutputSchema,
|
|
23
23
|
)
|
|
24
24
|
from ._run_context import AgentDepsT, RunContext
|
|
25
|
-
from .messages import
|
|
25
|
+
from .messages import ModelResponseStreamEvent
|
|
26
26
|
from .output import (
|
|
27
27
|
OutputDataT,
|
|
28
28
|
ToolOutput,
|
|
@@ -51,7 +51,7 @@ class AgentStream(Generic[AgentDepsT, OutputDataT]):
|
|
|
51
51
|
_usage_limits: UsageLimits | None
|
|
52
52
|
_tool_manager: ToolManager[AgentDepsT]
|
|
53
53
|
|
|
54
|
-
_agent_stream_iterator: AsyncIterator[
|
|
54
|
+
_agent_stream_iterator: AsyncIterator[ModelResponseStreamEvent] | None = field(default=None, init=False)
|
|
55
55
|
_initial_run_ctx_usage: RunUsage = field(init=False)
|
|
56
56
|
|
|
57
57
|
def __post_init__(self):
|
|
@@ -221,8 +221,8 @@ class AgentStream(Generic[AgentDepsT, OutputDataT]):
|
|
|
221
221
|
deltas.append(text)
|
|
222
222
|
yield ''.join(deltas)
|
|
223
223
|
|
|
224
|
-
def __aiter__(self) -> AsyncIterator[
|
|
225
|
-
"""Stream [`
|
|
224
|
+
def __aiter__(self) -> AsyncIterator[ModelResponseStreamEvent]:
|
|
225
|
+
"""Stream [`ModelResponseStreamEvent`][pydantic_ai.messages.ModelResponseStreamEvent]s."""
|
|
226
226
|
if self._agent_stream_iterator is None:
|
|
227
227
|
self._agent_stream_iterator = _get_usage_checking_stream_response(
|
|
228
228
|
self._raw_stream_response, self._usage_limits, self.usage
|
|
@@ -426,7 +426,7 @@ def _get_usage_checking_stream_response(
|
|
|
426
426
|
stream_response: models.StreamedResponse,
|
|
427
427
|
limits: UsageLimits | None,
|
|
428
428
|
get_usage: Callable[[], RunUsage],
|
|
429
|
-
) -> AsyncIterator[
|
|
429
|
+
) -> AsyncIterator[ModelResponseStreamEvent]:
|
|
430
430
|
if limits is not None and limits.has_token_limits():
|
|
431
431
|
|
|
432
432
|
async def _usage_checking_iterator():
|
|
@@ -84,7 +84,7 @@ tavily = ["tavily-python>=0.5.0"]
|
|
|
84
84
|
# CLI
|
|
85
85
|
cli = ["rich>=13", "prompt-toolkit>=3", "argcomplete>=3.5.0", "pyperclip>=1.9.0"]
|
|
86
86
|
# MCP
|
|
87
|
-
mcp = ["mcp>=1.
|
|
87
|
+
mcp = ["mcp>=1.12.3; python_version >= '3.10'"]
|
|
88
88
|
# Evals
|
|
89
89
|
evals = ["pydantic-evals=={{ version }}"]
|
|
90
90
|
# A2A
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{pydantic_ai_slim-0.7.6 → pydantic_ai_slim-0.8.0}/pydantic_ai/durable_exec/temporal/__init__.py
RENAMED
|
File without changes
|
{pydantic_ai_slim-0.7.6 → pydantic_ai_slim-0.8.0}/pydantic_ai/durable_exec/temporal/_agent.py
RENAMED
|
File without changes
|
{pydantic_ai_slim-0.7.6 → pydantic_ai_slim-0.8.0}/pydantic_ai/durable_exec/temporal/_logfire.py
RENAMED
|
File without changes
|
{pydantic_ai_slim-0.7.6 → pydantic_ai_slim-0.8.0}/pydantic_ai/durable_exec/temporal/_mcp_server.py
RENAMED
|
File without changes
|
{pydantic_ai_slim-0.7.6 → pydantic_ai_slim-0.8.0}/pydantic_ai/durable_exec/temporal/_model.py
RENAMED
|
File without changes
|
{pydantic_ai_slim-0.7.6 → pydantic_ai_slim-0.8.0}/pydantic_ai/durable_exec/temporal/_run_context.py
RENAMED
|
File without changes
|
{pydantic_ai_slim-0.7.6 → pydantic_ai_slim-0.8.0}/pydantic_ai/durable_exec/temporal/_toolset.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|