pydantic-ai-slim 1.0.0b1__tar.gz → 1.0.1__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.0.0b1 → pydantic_ai_slim-1.0.1}/PKG-INFO +6 -7
- {pydantic_ai_slim-1.0.0b1 → pydantic_ai_slim-1.0.1}/pydantic_ai/_a2a.py +1 -1
- {pydantic_ai_slim-1.0.0b1 → pydantic_ai_slim-1.0.1}/pydantic_ai/_agent_graph.py +16 -19
- {pydantic_ai_slim-1.0.0b1 → pydantic_ai_slim-1.0.1}/pydantic_ai/_parts_manager.py +3 -1
- {pydantic_ai_slim-1.0.0b1 → pydantic_ai_slim-1.0.1}/pydantic_ai/_tool_manager.py +29 -6
- {pydantic_ai_slim-1.0.0b1 → pydantic_ai_slim-1.0.1}/pydantic_ai/ag_ui.py +75 -43
- {pydantic_ai_slim-1.0.0b1 → pydantic_ai_slim-1.0.1}/pydantic_ai/agent/__init__.py +7 -7
- {pydantic_ai_slim-1.0.0b1 → pydantic_ai_slim-1.0.1}/pydantic_ai/durable_exec/temporal/_agent.py +71 -10
- {pydantic_ai_slim-1.0.0b1 → pydantic_ai_slim-1.0.1}/pydantic_ai/exceptions.py +2 -2
- {pydantic_ai_slim-1.0.0b1 → pydantic_ai_slim-1.0.1}/pydantic_ai/mcp.py +13 -25
- {pydantic_ai_slim-1.0.0b1 → pydantic_ai_slim-1.0.1}/pydantic_ai/messages.py +78 -19
- {pydantic_ai_slim-1.0.0b1 → pydantic_ai_slim-1.0.1}/pydantic_ai/models/__init__.py +1 -0
- {pydantic_ai_slim-1.0.0b1 → pydantic_ai_slim-1.0.1}/pydantic_ai/models/anthropic.py +4 -11
- {pydantic_ai_slim-1.0.0b1 → pydantic_ai_slim-1.0.1}/pydantic_ai/models/bedrock.py +6 -14
- {pydantic_ai_slim-1.0.0b1 → pydantic_ai_slim-1.0.1}/pydantic_ai/models/gemini.py +3 -1
- {pydantic_ai_slim-1.0.0b1 → pydantic_ai_slim-1.0.1}/pydantic_ai/models/google.py +15 -1
- {pydantic_ai_slim-1.0.0b1 → pydantic_ai_slim-1.0.1}/pydantic_ai/models/groq.py +122 -34
- {pydantic_ai_slim-1.0.0b1 → pydantic_ai_slim-1.0.1}/pydantic_ai/models/instrumented.py +5 -0
- {pydantic_ai_slim-1.0.0b1 → pydantic_ai_slim-1.0.1}/pydantic_ai/models/openai.py +17 -13
- {pydantic_ai_slim-1.0.0b1 → pydantic_ai_slim-1.0.1}/pydantic_ai/providers/__init__.py +4 -0
- {pydantic_ai_slim-1.0.0b1 → pydantic_ai_slim-1.0.1}/pydantic_ai/providers/google_vertex.py +2 -1
- {pydantic_ai_slim-1.0.0b1 → pydantic_ai_slim-1.0.1}/pydantic_ai/providers/groq.py +21 -2
- pydantic_ai_slim-1.0.1/pydantic_ai/providers/litellm.py +134 -0
- {pydantic_ai_slim-1.0.0b1 → pydantic_ai_slim-1.0.1}/pydantic_ai/retries.py +42 -2
- {pydantic_ai_slim-1.0.0b1 → pydantic_ai_slim-1.0.1}/pydantic_ai/tools.py +7 -7
- {pydantic_ai_slim-1.0.0b1 → pydantic_ai_slim-1.0.1}/pydantic_ai/toolsets/combined.py +2 -2
- {pydantic_ai_slim-1.0.0b1 → pydantic_ai_slim-1.0.1}/pydantic_ai/toolsets/function.py +47 -19
- {pydantic_ai_slim-1.0.0b1 → pydantic_ai_slim-1.0.1}/pydantic_ai/usage.py +37 -3
- {pydantic_ai_slim-1.0.0b1 → pydantic_ai_slim-1.0.1}/pyproject.toml +9 -5
- {pydantic_ai_slim-1.0.0b1 → pydantic_ai_slim-1.0.1}/.gitignore +0 -0
- {pydantic_ai_slim-1.0.0b1 → pydantic_ai_slim-1.0.1}/LICENSE +0 -0
- {pydantic_ai_slim-1.0.0b1 → pydantic_ai_slim-1.0.1}/README.md +0 -0
- {pydantic_ai_slim-1.0.0b1 → pydantic_ai_slim-1.0.1}/pydantic_ai/__init__.py +0 -0
- {pydantic_ai_slim-1.0.0b1 → pydantic_ai_slim-1.0.1}/pydantic_ai/__main__.py +0 -0
- {pydantic_ai_slim-1.0.0b1 → pydantic_ai_slim-1.0.1}/pydantic_ai/_cli.py +0 -0
- {pydantic_ai_slim-1.0.0b1 → pydantic_ai_slim-1.0.1}/pydantic_ai/_function_schema.py +0 -0
- {pydantic_ai_slim-1.0.0b1 → pydantic_ai_slim-1.0.1}/pydantic_ai/_griffe.py +0 -0
- {pydantic_ai_slim-1.0.0b1 → pydantic_ai_slim-1.0.1}/pydantic_ai/_mcp.py +0 -0
- {pydantic_ai_slim-1.0.0b1 → pydantic_ai_slim-1.0.1}/pydantic_ai/_otel_messages.py +0 -0
- {pydantic_ai_slim-1.0.0b1 → pydantic_ai_slim-1.0.1}/pydantic_ai/_output.py +0 -0
- {pydantic_ai_slim-1.0.0b1 → pydantic_ai_slim-1.0.1}/pydantic_ai/_run_context.py +0 -0
- {pydantic_ai_slim-1.0.0b1 → pydantic_ai_slim-1.0.1}/pydantic_ai/_system_prompt.py +0 -0
- {pydantic_ai_slim-1.0.0b1 → pydantic_ai_slim-1.0.1}/pydantic_ai/_thinking_part.py +0 -0
- {pydantic_ai_slim-1.0.0b1 → pydantic_ai_slim-1.0.1}/pydantic_ai/_utils.py +0 -0
- {pydantic_ai_slim-1.0.0b1 → pydantic_ai_slim-1.0.1}/pydantic_ai/agent/abstract.py +0 -0
- {pydantic_ai_slim-1.0.0b1 → pydantic_ai_slim-1.0.1}/pydantic_ai/agent/wrapper.py +0 -0
- {pydantic_ai_slim-1.0.0b1 → pydantic_ai_slim-1.0.1}/pydantic_ai/builtin_tools.py +0 -0
- {pydantic_ai_slim-1.0.0b1 → pydantic_ai_slim-1.0.1}/pydantic_ai/common_tools/__init__.py +0 -0
- {pydantic_ai_slim-1.0.0b1 → pydantic_ai_slim-1.0.1}/pydantic_ai/common_tools/duckduckgo.py +0 -0
- {pydantic_ai_slim-1.0.0b1 → pydantic_ai_slim-1.0.1}/pydantic_ai/common_tools/tavily.py +0 -0
- {pydantic_ai_slim-1.0.0b1 → pydantic_ai_slim-1.0.1}/pydantic_ai/direct.py +0 -0
- {pydantic_ai_slim-1.0.0b1 → pydantic_ai_slim-1.0.1}/pydantic_ai/durable_exec/__init__.py +0 -0
- {pydantic_ai_slim-1.0.0b1 → pydantic_ai_slim-1.0.1}/pydantic_ai/durable_exec/temporal/__init__.py +0 -0
- {pydantic_ai_slim-1.0.0b1 → pydantic_ai_slim-1.0.1}/pydantic_ai/durable_exec/temporal/_function_toolset.py +0 -0
- {pydantic_ai_slim-1.0.0b1 → pydantic_ai_slim-1.0.1}/pydantic_ai/durable_exec/temporal/_logfire.py +0 -0
- {pydantic_ai_slim-1.0.0b1 → pydantic_ai_slim-1.0.1}/pydantic_ai/durable_exec/temporal/_mcp_server.py +0 -0
- {pydantic_ai_slim-1.0.0b1 → pydantic_ai_slim-1.0.1}/pydantic_ai/durable_exec/temporal/_model.py +0 -0
- {pydantic_ai_slim-1.0.0b1 → pydantic_ai_slim-1.0.1}/pydantic_ai/durable_exec/temporal/_run_context.py +0 -0
- {pydantic_ai_slim-1.0.0b1 → pydantic_ai_slim-1.0.1}/pydantic_ai/durable_exec/temporal/_toolset.py +0 -0
- {pydantic_ai_slim-1.0.0b1 → pydantic_ai_slim-1.0.1}/pydantic_ai/ext/__init__.py +0 -0
- {pydantic_ai_slim-1.0.0b1 → pydantic_ai_slim-1.0.1}/pydantic_ai/ext/aci.py +0 -0
- {pydantic_ai_slim-1.0.0b1 → pydantic_ai_slim-1.0.1}/pydantic_ai/ext/langchain.py +0 -0
- {pydantic_ai_slim-1.0.0b1 → pydantic_ai_slim-1.0.1}/pydantic_ai/format_prompt.py +0 -0
- {pydantic_ai_slim-1.0.0b1 → pydantic_ai_slim-1.0.1}/pydantic_ai/models/cohere.py +0 -0
- {pydantic_ai_slim-1.0.0b1 → pydantic_ai_slim-1.0.1}/pydantic_ai/models/fallback.py +0 -0
- {pydantic_ai_slim-1.0.0b1 → pydantic_ai_slim-1.0.1}/pydantic_ai/models/function.py +0 -0
- {pydantic_ai_slim-1.0.0b1 → pydantic_ai_slim-1.0.1}/pydantic_ai/models/huggingface.py +0 -0
- {pydantic_ai_slim-1.0.0b1 → pydantic_ai_slim-1.0.1}/pydantic_ai/models/mcp_sampling.py +0 -0
- {pydantic_ai_slim-1.0.0b1 → pydantic_ai_slim-1.0.1}/pydantic_ai/models/mistral.py +0 -0
- {pydantic_ai_slim-1.0.0b1 → pydantic_ai_slim-1.0.1}/pydantic_ai/models/test.py +0 -0
- {pydantic_ai_slim-1.0.0b1 → pydantic_ai_slim-1.0.1}/pydantic_ai/models/wrapper.py +0 -0
- {pydantic_ai_slim-1.0.0b1 → pydantic_ai_slim-1.0.1}/pydantic_ai/output.py +0 -0
- {pydantic_ai_slim-1.0.0b1 → pydantic_ai_slim-1.0.1}/pydantic_ai/profiles/__init__.py +0 -0
- {pydantic_ai_slim-1.0.0b1 → pydantic_ai_slim-1.0.1}/pydantic_ai/profiles/_json_schema.py +0 -0
- {pydantic_ai_slim-1.0.0b1 → pydantic_ai_slim-1.0.1}/pydantic_ai/profiles/amazon.py +0 -0
- {pydantic_ai_slim-1.0.0b1 → pydantic_ai_slim-1.0.1}/pydantic_ai/profiles/anthropic.py +0 -0
- {pydantic_ai_slim-1.0.0b1 → pydantic_ai_slim-1.0.1}/pydantic_ai/profiles/cohere.py +0 -0
- {pydantic_ai_slim-1.0.0b1 → pydantic_ai_slim-1.0.1}/pydantic_ai/profiles/deepseek.py +0 -0
- {pydantic_ai_slim-1.0.0b1 → pydantic_ai_slim-1.0.1}/pydantic_ai/profiles/google.py +0 -0
- {pydantic_ai_slim-1.0.0b1 → pydantic_ai_slim-1.0.1}/pydantic_ai/profiles/grok.py +0 -0
- {pydantic_ai_slim-1.0.0b1 → pydantic_ai_slim-1.0.1}/pydantic_ai/profiles/groq.py +0 -0
- {pydantic_ai_slim-1.0.0b1 → pydantic_ai_slim-1.0.1}/pydantic_ai/profiles/harmony.py +0 -0
- {pydantic_ai_slim-1.0.0b1 → pydantic_ai_slim-1.0.1}/pydantic_ai/profiles/meta.py +0 -0
- {pydantic_ai_slim-1.0.0b1 → pydantic_ai_slim-1.0.1}/pydantic_ai/profiles/mistral.py +0 -0
- {pydantic_ai_slim-1.0.0b1 → pydantic_ai_slim-1.0.1}/pydantic_ai/profiles/moonshotai.py +0 -0
- {pydantic_ai_slim-1.0.0b1 → pydantic_ai_slim-1.0.1}/pydantic_ai/profiles/openai.py +0 -0
- {pydantic_ai_slim-1.0.0b1 → pydantic_ai_slim-1.0.1}/pydantic_ai/profiles/qwen.py +0 -0
- {pydantic_ai_slim-1.0.0b1 → pydantic_ai_slim-1.0.1}/pydantic_ai/providers/anthropic.py +0 -0
- {pydantic_ai_slim-1.0.0b1 → pydantic_ai_slim-1.0.1}/pydantic_ai/providers/azure.py +0 -0
- {pydantic_ai_slim-1.0.0b1 → pydantic_ai_slim-1.0.1}/pydantic_ai/providers/bedrock.py +0 -0
- {pydantic_ai_slim-1.0.0b1 → pydantic_ai_slim-1.0.1}/pydantic_ai/providers/cerebras.py +0 -0
- {pydantic_ai_slim-1.0.0b1 → pydantic_ai_slim-1.0.1}/pydantic_ai/providers/cohere.py +0 -0
- {pydantic_ai_slim-1.0.0b1 → pydantic_ai_slim-1.0.1}/pydantic_ai/providers/deepseek.py +0 -0
- {pydantic_ai_slim-1.0.0b1 → pydantic_ai_slim-1.0.1}/pydantic_ai/providers/fireworks.py +0 -0
- {pydantic_ai_slim-1.0.0b1 → pydantic_ai_slim-1.0.1}/pydantic_ai/providers/github.py +0 -0
- {pydantic_ai_slim-1.0.0b1 → pydantic_ai_slim-1.0.1}/pydantic_ai/providers/google.py +0 -0
- {pydantic_ai_slim-1.0.0b1 → pydantic_ai_slim-1.0.1}/pydantic_ai/providers/google_gla.py +0 -0
- {pydantic_ai_slim-1.0.0b1 → pydantic_ai_slim-1.0.1}/pydantic_ai/providers/grok.py +0 -0
- {pydantic_ai_slim-1.0.0b1 → pydantic_ai_slim-1.0.1}/pydantic_ai/providers/heroku.py +0 -0
- {pydantic_ai_slim-1.0.0b1 → pydantic_ai_slim-1.0.1}/pydantic_ai/providers/huggingface.py +0 -0
- {pydantic_ai_slim-1.0.0b1 → pydantic_ai_slim-1.0.1}/pydantic_ai/providers/mistral.py +0 -0
- {pydantic_ai_slim-1.0.0b1 → pydantic_ai_slim-1.0.1}/pydantic_ai/providers/moonshotai.py +0 -0
- {pydantic_ai_slim-1.0.0b1 → pydantic_ai_slim-1.0.1}/pydantic_ai/providers/ollama.py +0 -0
- {pydantic_ai_slim-1.0.0b1 → pydantic_ai_slim-1.0.1}/pydantic_ai/providers/openai.py +0 -0
- {pydantic_ai_slim-1.0.0b1 → pydantic_ai_slim-1.0.1}/pydantic_ai/providers/openrouter.py +0 -0
- {pydantic_ai_slim-1.0.0b1 → pydantic_ai_slim-1.0.1}/pydantic_ai/providers/together.py +0 -0
- {pydantic_ai_slim-1.0.0b1 → pydantic_ai_slim-1.0.1}/pydantic_ai/providers/vercel.py +0 -0
- {pydantic_ai_slim-1.0.0b1 → pydantic_ai_slim-1.0.1}/pydantic_ai/py.typed +0 -0
- {pydantic_ai_slim-1.0.0b1 → pydantic_ai_slim-1.0.1}/pydantic_ai/result.py +0 -0
- {pydantic_ai_slim-1.0.0b1 → pydantic_ai_slim-1.0.1}/pydantic_ai/run.py +0 -0
- {pydantic_ai_slim-1.0.0b1 → pydantic_ai_slim-1.0.1}/pydantic_ai/settings.py +0 -0
- {pydantic_ai_slim-1.0.0b1 → pydantic_ai_slim-1.0.1}/pydantic_ai/toolsets/__init__.py +0 -0
- {pydantic_ai_slim-1.0.0b1 → pydantic_ai_slim-1.0.1}/pydantic_ai/toolsets/_dynamic.py +0 -0
- {pydantic_ai_slim-1.0.0b1 → pydantic_ai_slim-1.0.1}/pydantic_ai/toolsets/abstract.py +0 -0
- {pydantic_ai_slim-1.0.0b1 → pydantic_ai_slim-1.0.1}/pydantic_ai/toolsets/approval_required.py +0 -0
- {pydantic_ai_slim-1.0.0b1 → pydantic_ai_slim-1.0.1}/pydantic_ai/toolsets/external.py +0 -0
- {pydantic_ai_slim-1.0.0b1 → pydantic_ai_slim-1.0.1}/pydantic_ai/toolsets/filtered.py +0 -0
- {pydantic_ai_slim-1.0.0b1 → pydantic_ai_slim-1.0.1}/pydantic_ai/toolsets/prefixed.py +0 -0
- {pydantic_ai_slim-1.0.0b1 → pydantic_ai_slim-1.0.1}/pydantic_ai/toolsets/prepared.py +0 -0
- {pydantic_ai_slim-1.0.0b1 → pydantic_ai_slim-1.0.1}/pydantic_ai/toolsets/renamed.py +0 -0
- {pydantic_ai_slim-1.0.0b1 → pydantic_ai_slim-1.0.1}/pydantic_ai/toolsets/wrapper.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: pydantic-ai-slim
|
|
3
|
-
Version: 1.0.
|
|
3
|
+
Version: 1.0.1
|
|
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
|
|
@@ -9,7 +9,7 @@ Project-URL: Changelog, https://github.com/pydantic/pydantic-ai/releases
|
|
|
9
9
|
Author-email: Samuel Colvin <samuel@pydantic.dev>, Marcelo Trylesinski <marcelotryle@gmail.com>, David Montague <david@pydantic.dev>, Alex Hall <alex@pydantic.dev>, Douwe Maan <douwe@pydantic.dev>
|
|
10
10
|
License-Expression: MIT
|
|
11
11
|
License-File: LICENSE
|
|
12
|
-
Classifier: Development Status ::
|
|
12
|
+
Classifier: Development Status :: 5 - Production/Stable
|
|
13
13
|
Classifier: Environment :: Console
|
|
14
14
|
Classifier: Environment :: MacOS X
|
|
15
15
|
Classifier: Intended Audience :: Developers
|
|
@@ -28,13 +28,12 @@ Classifier: Programming Language :: Python :: 3.13
|
|
|
28
28
|
Classifier: Topic :: Internet
|
|
29
29
|
Classifier: Topic :: Software Development :: Libraries :: Python Modules
|
|
30
30
|
Requires-Python: >=3.10
|
|
31
|
-
Requires-Dist: eval-type-backport>=0.2.0
|
|
32
31
|
Requires-Dist: exceptiongroup; python_version < '3.11'
|
|
33
32
|
Requires-Dist: genai-prices>=0.0.22
|
|
34
33
|
Requires-Dist: griffe>=1.3.2
|
|
35
34
|
Requires-Dist: httpx>=0.27
|
|
36
35
|
Requires-Dist: opentelemetry-api>=1.28.0
|
|
37
|
-
Requires-Dist: pydantic-graph==1.0.
|
|
36
|
+
Requires-Dist: pydantic-graph==1.0.1
|
|
38
37
|
Requires-Dist: pydantic>=2.10
|
|
39
38
|
Requires-Dist: typing-inspection>=0.4.0
|
|
40
39
|
Provides-Extra: a2a
|
|
@@ -56,7 +55,7 @@ Requires-Dist: cohere>=5.16.0; (platform_system != 'Emscripten') and extra == 'c
|
|
|
56
55
|
Provides-Extra: duckduckgo
|
|
57
56
|
Requires-Dist: ddgs>=9.0.0; extra == 'duckduckgo'
|
|
58
57
|
Provides-Extra: evals
|
|
59
|
-
Requires-Dist: pydantic-evals==1.0.
|
|
58
|
+
Requires-Dist: pydantic-evals==1.0.1; extra == 'evals'
|
|
60
59
|
Provides-Extra: google
|
|
61
60
|
Requires-Dist: google-genai>=1.31.0; extra == 'google'
|
|
62
61
|
Provides-Extra: groq
|
|
@@ -66,7 +65,7 @@ Requires-Dist: huggingface-hub[inference]>=0.33.5; extra == 'huggingface'
|
|
|
66
65
|
Provides-Extra: logfire
|
|
67
66
|
Requires-Dist: logfire[httpx]>=3.14.1; extra == 'logfire'
|
|
68
67
|
Provides-Extra: mcp
|
|
69
|
-
Requires-Dist: mcp>=1.12.3;
|
|
68
|
+
Requires-Dist: mcp>=1.12.3; extra == 'mcp'
|
|
70
69
|
Provides-Extra: mistral
|
|
71
70
|
Requires-Dist: mistralai>=1.9.2; extra == 'mistral'
|
|
72
71
|
Provides-Extra: openai
|
|
@@ -76,7 +75,7 @@ Requires-Dist: tenacity>=8.2.3; extra == 'retries'
|
|
|
76
75
|
Provides-Extra: tavily
|
|
77
76
|
Requires-Dist: tavily-python>=0.5.0; extra == 'tavily'
|
|
78
77
|
Provides-Extra: temporal
|
|
79
|
-
Requires-Dist: temporalio==1.
|
|
78
|
+
Requires-Dist: temporalio==1.17.0; extra == 'temporal'
|
|
80
79
|
Provides-Extra: vertexai
|
|
81
80
|
Requires-Dist: google-auth>=2.36.0; extra == 'vertexai'
|
|
82
81
|
Requires-Dist: requests>=2.32.2; extra == 'vertexai'
|
|
@@ -272,7 +272,7 @@ class AgentWorker(Worker[list[ModelMessage]], Generic[WorkerOutputT, AgentDepsT]
|
|
|
272
272
|
assert_never(part)
|
|
273
273
|
return model_parts
|
|
274
274
|
|
|
275
|
-
def _response_parts_to_a2a(self, parts:
|
|
275
|
+
def _response_parts_to_a2a(self, parts: Sequence[ModelResponsePart]) -> list[Part]:
|
|
276
276
|
"""Convert pydantic-ai ModelResponsePart objects to A2A Part objects.
|
|
277
277
|
|
|
278
278
|
This handles the conversion from pydantic-ai's internal response parts to
|
|
@@ -2,7 +2,6 @@ from __future__ import annotations as _annotations
|
|
|
2
2
|
|
|
3
3
|
import asyncio
|
|
4
4
|
import dataclasses
|
|
5
|
-
import hashlib
|
|
6
5
|
from collections import defaultdict, deque
|
|
7
6
|
from collections.abc import AsyncIterator, Awaitable, Callable, Iterator, Sequence
|
|
8
7
|
from contextlib import asynccontextmanager, contextmanager
|
|
@@ -302,16 +301,21 @@ class UserPromptNode(AgentNode[DepsT, NodeRunEndT]):
|
|
|
302
301
|
if self.system_prompt_dynamic_functions:
|
|
303
302
|
for msg in messages:
|
|
304
303
|
if isinstance(msg, _messages.ModelRequest):
|
|
305
|
-
|
|
304
|
+
reevaluated_message_parts: list[_messages.ModelRequestPart] = []
|
|
305
|
+
for part in msg.parts:
|
|
306
306
|
if isinstance(part, _messages.SystemPromptPart) and part.dynamic_ref:
|
|
307
307
|
# Look up the runner by its ref
|
|
308
308
|
if runner := self.system_prompt_dynamic_functions.get( # pragma: lax no cover
|
|
309
309
|
part.dynamic_ref
|
|
310
310
|
):
|
|
311
311
|
updated_part_content = await runner.run(run_context)
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
312
|
+
part = _messages.SystemPromptPart(updated_part_content, dynamic_ref=part.dynamic_ref)
|
|
313
|
+
|
|
314
|
+
reevaluated_message_parts.append(part)
|
|
315
|
+
|
|
316
|
+
# Replace message parts with reevaluated ones to prevent mutating parts list
|
|
317
|
+
if reevaluated_message_parts != msg.parts:
|
|
318
|
+
msg.parts = reevaluated_message_parts
|
|
315
319
|
|
|
316
320
|
async def _sys_parts(self, run_context: RunContext[DepsT]) -> list[_messages.ModelRequestPart]:
|
|
317
321
|
"""Build the initial messages for the conversation."""
|
|
@@ -650,13 +654,6 @@ def build_run_context(ctx: GraphRunContext[GraphAgentState, GraphAgentDeps[DepsT
|
|
|
650
654
|
)
|
|
651
655
|
|
|
652
656
|
|
|
653
|
-
def multi_modal_content_identifier(identifier: str | bytes) -> str:
|
|
654
|
-
"""Generate stable identifier for multi-modal content to help LLM in finding a specific file in tool call responses."""
|
|
655
|
-
if isinstance(identifier, str):
|
|
656
|
-
identifier = identifier.encode('utf-8')
|
|
657
|
-
return hashlib.sha1(identifier).hexdigest()[:6]
|
|
658
|
-
|
|
659
|
-
|
|
660
657
|
async def process_function_tools( # noqa: C901
|
|
661
658
|
tool_manager: ToolManager[DepsT],
|
|
662
659
|
tool_calls: list[_messages.ToolCallPart],
|
|
@@ -764,6 +761,7 @@ async def process_function_tools( # noqa: C901
|
|
|
764
761
|
calls_to_run,
|
|
765
762
|
deferred_tool_results,
|
|
766
763
|
ctx.deps.tracer,
|
|
764
|
+
ctx.deps.usage_limits,
|
|
767
765
|
output_parts,
|
|
768
766
|
deferred_calls,
|
|
769
767
|
):
|
|
@@ -810,6 +808,7 @@ async def _call_tools(
|
|
|
810
808
|
tool_calls: list[_messages.ToolCallPart],
|
|
811
809
|
deferred_tool_results: dict[str, DeferredToolResult],
|
|
812
810
|
tracer: Tracer,
|
|
811
|
+
usage_limits: _usage.UsageLimits | None,
|
|
813
812
|
output_parts: list[_messages.ModelRequestPart],
|
|
814
813
|
output_deferred_calls: dict[Literal['external', 'unapproved'], list[_messages.ToolCallPart]],
|
|
815
814
|
) -> AsyncIterator[_messages.HandleResponseEvent]:
|
|
@@ -830,7 +829,7 @@ async def _call_tools(
|
|
|
830
829
|
):
|
|
831
830
|
tasks = [
|
|
832
831
|
asyncio.create_task(
|
|
833
|
-
_call_tool(tool_manager, call, deferred_tool_results.get(call.tool_call_id)),
|
|
832
|
+
_call_tool(tool_manager, call, deferred_tool_results.get(call.tool_call_id), usage_limits),
|
|
834
833
|
name=call.tool_name,
|
|
835
834
|
)
|
|
836
835
|
for call in tool_calls
|
|
@@ -870,14 +869,15 @@ async def _call_tool(
|
|
|
870
869
|
tool_manager: ToolManager[DepsT],
|
|
871
870
|
tool_call: _messages.ToolCallPart,
|
|
872
871
|
tool_call_result: DeferredToolResult | None,
|
|
872
|
+
usage_limits: _usage.UsageLimits | None,
|
|
873
873
|
) -> tuple[_messages.ToolReturnPart | _messages.RetryPromptPart, _messages.UserPromptPart | None]:
|
|
874
874
|
try:
|
|
875
875
|
if tool_call_result is None:
|
|
876
|
-
tool_result = await tool_manager.handle_call(tool_call)
|
|
876
|
+
tool_result = await tool_manager.handle_call(tool_call, usage_limits=usage_limits)
|
|
877
877
|
elif isinstance(tool_call_result, ToolApproved):
|
|
878
878
|
if tool_call_result.override_args is not None:
|
|
879
879
|
tool_call = dataclasses.replace(tool_call, args=tool_call_result.override_args)
|
|
880
|
-
tool_result = await tool_manager.handle_call(tool_call)
|
|
880
|
+
tool_result = await tool_manager.handle_call(tool_call, usage_limits=usage_limits)
|
|
881
881
|
elif isinstance(tool_call_result, ToolDenied):
|
|
882
882
|
return _messages.ToolReturnPart(
|
|
883
883
|
tool_name=tool_call.tool_name,
|
|
@@ -915,10 +915,7 @@ async def _call_tool(
|
|
|
915
915
|
f'`ToolReturn` should be used directly.'
|
|
916
916
|
)
|
|
917
917
|
elif isinstance(content, _messages.MultiModalContent):
|
|
918
|
-
|
|
919
|
-
identifier = content.identifier or multi_modal_content_identifier(content.data)
|
|
920
|
-
else:
|
|
921
|
-
identifier = multi_modal_content_identifier(content.url)
|
|
918
|
+
identifier = content.identifier
|
|
922
919
|
|
|
923
920
|
return_values.append(f'See file {identifier}')
|
|
924
921
|
user_contents.extend([f'This is file {identifier}:', content])
|
|
@@ -154,6 +154,7 @@ class ModelResponsePartsManager:
|
|
|
154
154
|
*,
|
|
155
155
|
vendor_part_id: Hashable | None,
|
|
156
156
|
content: str | None = None,
|
|
157
|
+
id: str | None = None,
|
|
157
158
|
signature: str | None = None,
|
|
158
159
|
) -> ModelResponseStreamEvent:
|
|
159
160
|
"""Handle incoming thinking content, creating or updating a ThinkingPart in the manager as appropriate.
|
|
@@ -167,6 +168,7 @@ class ModelResponsePartsManager:
|
|
|
167
168
|
of thinking. If None, a new part will be created unless the latest part is already
|
|
168
169
|
a ThinkingPart.
|
|
169
170
|
content: The thinking content to append to the appropriate ThinkingPart.
|
|
171
|
+
id: An optional id for the thinking part.
|
|
170
172
|
signature: An optional signature for the thinking content.
|
|
171
173
|
|
|
172
174
|
Returns:
|
|
@@ -197,7 +199,7 @@ class ModelResponsePartsManager:
|
|
|
197
199
|
if content is not None:
|
|
198
200
|
# There is no existing thinking part that should be updated, so create a new one
|
|
199
201
|
new_part_index = len(self._parts)
|
|
200
|
-
part = ThinkingPart(content=content, signature=signature)
|
|
202
|
+
part = ThinkingPart(content=content, id=id, signature=signature)
|
|
201
203
|
if vendor_part_id is not None: # pragma: no branch
|
|
202
204
|
self._vendor_id_to_part_index[vendor_part_id] = new_part_index
|
|
203
205
|
self._parts.append(part)
|
|
@@ -14,6 +14,7 @@ from .exceptions import ModelRetry, ToolRetryError, UnexpectedModelBehavior
|
|
|
14
14
|
from .messages import ToolCallPart
|
|
15
15
|
from .tools import ToolDefinition
|
|
16
16
|
from .toolsets.abstract import AbstractToolset, ToolsetTool
|
|
17
|
+
from .usage import UsageLimits
|
|
17
18
|
|
|
18
19
|
|
|
19
20
|
@dataclass
|
|
@@ -66,7 +67,11 @@ class ToolManager(Generic[AgentDepsT]):
|
|
|
66
67
|
return None
|
|
67
68
|
|
|
68
69
|
async def handle_call(
|
|
69
|
-
self,
|
|
70
|
+
self,
|
|
71
|
+
call: ToolCallPart,
|
|
72
|
+
allow_partial: bool = False,
|
|
73
|
+
wrap_validation_errors: bool = True,
|
|
74
|
+
usage_limits: UsageLimits | None = None,
|
|
70
75
|
) -> Any:
|
|
71
76
|
"""Handle a tool call by validating the arguments, calling the tool, and handling retries.
|
|
72
77
|
|
|
@@ -74,13 +79,14 @@ class ToolManager(Generic[AgentDepsT]):
|
|
|
74
79
|
call: The tool call part to handle.
|
|
75
80
|
allow_partial: Whether to allow partial validation of the tool arguments.
|
|
76
81
|
wrap_validation_errors: Whether to wrap validation errors in a retry prompt part.
|
|
82
|
+
usage_limits: Optional usage limits to check before executing tools.
|
|
77
83
|
"""
|
|
78
84
|
if self.tools is None or self.ctx is None:
|
|
79
85
|
raise ValueError('ToolManager has not been prepared for a run step yet') # pragma: no cover
|
|
80
86
|
|
|
81
87
|
if (tool := self.tools.get(call.tool_name)) and tool.tool_def.kind == 'output':
|
|
82
|
-
# Output tool calls are not traced
|
|
83
|
-
return await self._call_tool(call, allow_partial, wrap_validation_errors)
|
|
88
|
+
# Output tool calls are not traced and not counted
|
|
89
|
+
return await self._call_tool(call, allow_partial, wrap_validation_errors, count_tool_usage=False)
|
|
84
90
|
else:
|
|
85
91
|
return await self._call_tool_traced(
|
|
86
92
|
call,
|
|
@@ -88,9 +94,17 @@ class ToolManager(Generic[AgentDepsT]):
|
|
|
88
94
|
wrap_validation_errors,
|
|
89
95
|
self.ctx.tracer,
|
|
90
96
|
self.ctx.trace_include_content,
|
|
97
|
+
usage_limits,
|
|
91
98
|
)
|
|
92
99
|
|
|
93
|
-
async def _call_tool(
|
|
100
|
+
async def _call_tool(
|
|
101
|
+
self,
|
|
102
|
+
call: ToolCallPart,
|
|
103
|
+
allow_partial: bool,
|
|
104
|
+
wrap_validation_errors: bool,
|
|
105
|
+
usage_limits: UsageLimits | None = None,
|
|
106
|
+
count_tool_usage: bool = True,
|
|
107
|
+
) -> Any:
|
|
94
108
|
if self.tools is None or self.ctx is None:
|
|
95
109
|
raise ValueError('ToolManager has not been prepared for a run step yet') # pragma: no cover
|
|
96
110
|
|
|
@@ -121,7 +135,15 @@ class ToolManager(Generic[AgentDepsT]):
|
|
|
121
135
|
else:
|
|
122
136
|
args_dict = validator.validate_python(call.args or {}, allow_partial=pyd_allow_partial)
|
|
123
137
|
|
|
124
|
-
|
|
138
|
+
if usage_limits is not None and count_tool_usage:
|
|
139
|
+
usage_limits.check_before_tool_call(self.ctx.usage)
|
|
140
|
+
|
|
141
|
+
result = await self.toolset.call_tool(name, args_dict, ctx, tool)
|
|
142
|
+
|
|
143
|
+
if count_tool_usage:
|
|
144
|
+
self.ctx.usage.tool_calls += 1
|
|
145
|
+
|
|
146
|
+
return result
|
|
125
147
|
except (ValidationError, ModelRetry) as e:
|
|
126
148
|
max_retries = tool.max_retries if tool is not None else 1
|
|
127
149
|
current_retry = self.ctx.retries.get(name, 0)
|
|
@@ -160,6 +182,7 @@ class ToolManager(Generic[AgentDepsT]):
|
|
|
160
182
|
wrap_validation_errors: bool,
|
|
161
183
|
tracer: Tracer,
|
|
162
184
|
include_content: bool = False,
|
|
185
|
+
usage_limits: UsageLimits | None = None,
|
|
163
186
|
) -> Any:
|
|
164
187
|
"""See <https://opentelemetry.io/docs/specs/semconv/gen-ai/gen-ai-spans/#execute-tool-span>."""
|
|
165
188
|
span_attributes = {
|
|
@@ -189,7 +212,7 @@ class ToolManager(Generic[AgentDepsT]):
|
|
|
189
212
|
}
|
|
190
213
|
with tracer.start_as_current_span('running tool', attributes=span_attributes) as span:
|
|
191
214
|
try:
|
|
192
|
-
tool_result = await self._call_tool(call, allow_partial, wrap_validation_errors)
|
|
215
|
+
tool_result = await self._call_tool(call, allow_partial, wrap_validation_errors, usage_limits)
|
|
193
216
|
except ToolRetryError as e:
|
|
194
217
|
part = e.tool_retry
|
|
195
218
|
if include_content and span.is_recording():
|
|
@@ -68,6 +68,9 @@ try:
|
|
|
68
68
|
TextMessageContentEvent,
|
|
69
69
|
TextMessageEndEvent,
|
|
70
70
|
TextMessageStartEvent,
|
|
71
|
+
# TODO: Enable once https://github.com/ag-ui-protocol/ag-ui/issues/289 is resolved.
|
|
72
|
+
# ThinkingEndEvent,
|
|
73
|
+
# ThinkingStartEvent,
|
|
71
74
|
ThinkingTextMessageContentEvent,
|
|
72
75
|
ThinkingTextMessageEndEvent,
|
|
73
76
|
ThinkingTextMessageStartEvent,
|
|
@@ -392,6 +395,12 @@ async def _agent_stream(run: AgentRun[AgentDepsT, Any]) -> AsyncIterator[BaseEve
|
|
|
392
395
|
if stream_ctx.part_end: # pragma: no branch
|
|
393
396
|
yield stream_ctx.part_end
|
|
394
397
|
stream_ctx.part_end = None
|
|
398
|
+
if stream_ctx.thinking:
|
|
399
|
+
# TODO: Enable once https://github.com/ag-ui-protocol/ag-ui/issues/289 is resolved.
|
|
400
|
+
# yield ThinkingEndEvent(
|
|
401
|
+
# type=EventType.THINKING_END,
|
|
402
|
+
# )
|
|
403
|
+
stream_ctx.thinking = False
|
|
395
404
|
elif isinstance(node, CallToolsNode):
|
|
396
405
|
async with node.stream(run.ctx) as handle_stream:
|
|
397
406
|
async for event in handle_stream:
|
|
@@ -400,7 +409,7 @@ async def _agent_stream(run: AgentRun[AgentDepsT, Any]) -> AsyncIterator[BaseEve
|
|
|
400
409
|
yield msg
|
|
401
410
|
|
|
402
411
|
|
|
403
|
-
async def _handle_model_request_event(
|
|
412
|
+
async def _handle_model_request_event( # noqa: C901
|
|
404
413
|
stream_ctx: _RequestStreamContext,
|
|
405
414
|
agent_event: ModelResponseStreamEvent,
|
|
406
415
|
) -> AsyncIterator[BaseEvent]:
|
|
@@ -420,56 +429,70 @@ async def _handle_model_request_event(
|
|
|
420
429
|
stream_ctx.part_end = None
|
|
421
430
|
|
|
422
431
|
part = agent_event.part
|
|
423
|
-
if isinstance(part,
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
432
|
+
if isinstance(part, ThinkingPart): # pragma: no branch
|
|
433
|
+
if not stream_ctx.thinking:
|
|
434
|
+
# TODO: Enable once https://github.com/ag-ui-protocol/ag-ui/issues/289 is resolved.
|
|
435
|
+
# yield ThinkingStartEvent(
|
|
436
|
+
# type=EventType.THINKING_START,
|
|
437
|
+
# )
|
|
438
|
+
stream_ctx.thinking = True
|
|
439
|
+
|
|
440
|
+
if part.content:
|
|
441
|
+
yield ThinkingTextMessageStartEvent(
|
|
442
|
+
type=EventType.THINKING_TEXT_MESSAGE_START,
|
|
443
|
+
)
|
|
444
|
+
yield ThinkingTextMessageContentEvent(
|
|
445
|
+
type=EventType.THINKING_TEXT_MESSAGE_CONTENT,
|
|
431
446
|
delta=part.content,
|
|
432
447
|
)
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
448
|
+
stream_ctx.part_end = ThinkingTextMessageEndEvent(
|
|
449
|
+
type=EventType.THINKING_TEXT_MESSAGE_END,
|
|
450
|
+
)
|
|
451
|
+
else:
|
|
452
|
+
if stream_ctx.thinking:
|
|
453
|
+
# TODO: Enable once https://github.com/ag-ui-protocol/ag-ui/issues/289 is resolved.
|
|
454
|
+
# yield ThinkingEndEvent(
|
|
455
|
+
# type=EventType.THINKING_END,
|
|
456
|
+
# )
|
|
457
|
+
stream_ctx.thinking = False
|
|
458
|
+
|
|
459
|
+
if isinstance(part, TextPart):
|
|
460
|
+
message_id = stream_ctx.new_message_id()
|
|
461
|
+
yield TextMessageStartEvent(
|
|
462
|
+
message_id=message_id,
|
|
463
|
+
)
|
|
464
|
+
if part.content: # pragma: no branch
|
|
465
|
+
yield TextMessageContentEvent(
|
|
466
|
+
message_id=message_id,
|
|
467
|
+
delta=part.content,
|
|
468
|
+
)
|
|
469
|
+
stream_ctx.part_end = TextMessageEndEvent(
|
|
470
|
+
message_id=message_id,
|
|
471
|
+
)
|
|
472
|
+
elif isinstance(part, ToolCallPart): # pragma: no branch
|
|
473
|
+
message_id = stream_ctx.message_id or stream_ctx.new_message_id()
|
|
474
|
+
yield ToolCallStartEvent(
|
|
475
|
+
tool_call_id=part.tool_call_id,
|
|
476
|
+
tool_call_name=part.tool_name,
|
|
477
|
+
parent_message_id=message_id,
|
|
478
|
+
)
|
|
479
|
+
if part.args:
|
|
480
|
+
yield ToolCallArgsEvent(
|
|
481
|
+
tool_call_id=part.tool_call_id,
|
|
482
|
+
delta=part.args if isinstance(part.args, str) else json.dumps(part.args),
|
|
483
|
+
)
|
|
484
|
+
stream_ctx.part_end = ToolCallEndEvent(
|
|
445
485
|
tool_call_id=part.tool_call_id,
|
|
446
|
-
delta=part.args if isinstance(part.args, str) else json.dumps(part.args),
|
|
447
486
|
)
|
|
448
|
-
stream_ctx.part_end = ToolCallEndEvent(
|
|
449
|
-
tool_call_id=part.tool_call_id,
|
|
450
|
-
)
|
|
451
|
-
|
|
452
|
-
elif isinstance(part, ThinkingPart): # pragma: no branch
|
|
453
|
-
yield ThinkingTextMessageStartEvent(
|
|
454
|
-
type=EventType.THINKING_TEXT_MESSAGE_START,
|
|
455
|
-
)
|
|
456
|
-
# Always send the content even if it's empty, as it may be
|
|
457
|
-
# used to indicate the start of thinking.
|
|
458
|
-
yield ThinkingTextMessageContentEvent(
|
|
459
|
-
type=EventType.THINKING_TEXT_MESSAGE_CONTENT,
|
|
460
|
-
delta=part.content,
|
|
461
|
-
)
|
|
462
|
-
stream_ctx.part_end = ThinkingTextMessageEndEvent(
|
|
463
|
-
type=EventType.THINKING_TEXT_MESSAGE_END,
|
|
464
|
-
)
|
|
465
487
|
|
|
466
488
|
elif isinstance(agent_event, PartDeltaEvent):
|
|
467
489
|
delta = agent_event.delta
|
|
468
490
|
if isinstance(delta, TextPartDelta):
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
491
|
+
if delta.content_delta: # pragma: no branch
|
|
492
|
+
yield TextMessageContentEvent(
|
|
493
|
+
message_id=stream_ctx.message_id,
|
|
494
|
+
delta=delta.content_delta,
|
|
495
|
+
)
|
|
473
496
|
elif isinstance(delta, ToolCallPartDelta): # pragma: no branch
|
|
474
497
|
assert delta.tool_call_id, '`ToolCallPartDelta.tool_call_id` must be set'
|
|
475
498
|
yield ToolCallArgsEvent(
|
|
@@ -478,6 +501,14 @@ async def _handle_model_request_event(
|
|
|
478
501
|
)
|
|
479
502
|
elif isinstance(delta, ThinkingPartDelta): # pragma: no branch
|
|
480
503
|
if delta.content_delta: # pragma: no branch
|
|
504
|
+
if not isinstance(stream_ctx.part_end, ThinkingTextMessageEndEvent):
|
|
505
|
+
yield ThinkingTextMessageStartEvent(
|
|
506
|
+
type=EventType.THINKING_TEXT_MESSAGE_START,
|
|
507
|
+
)
|
|
508
|
+
stream_ctx.part_end = ThinkingTextMessageEndEvent(
|
|
509
|
+
type=EventType.THINKING_TEXT_MESSAGE_END,
|
|
510
|
+
)
|
|
511
|
+
|
|
481
512
|
yield ThinkingTextMessageContentEvent(
|
|
482
513
|
type=EventType.THINKING_TEXT_MESSAGE_CONTENT,
|
|
483
514
|
delta=delta.content_delta,
|
|
@@ -629,6 +660,7 @@ class _RequestStreamContext:
|
|
|
629
660
|
|
|
630
661
|
message_id: str = ''
|
|
631
662
|
part_end: BaseEvent | None = None
|
|
663
|
+
thinking: bool = False
|
|
632
664
|
|
|
633
665
|
def new_message_id(self) -> str:
|
|
634
666
|
"""Generate a new message ID for the request stream.
|
|
@@ -4,15 +4,15 @@ import dataclasses
|
|
|
4
4
|
import inspect
|
|
5
5
|
import json
|
|
6
6
|
import warnings
|
|
7
|
+
from asyncio import Lock
|
|
7
8
|
from collections.abc import AsyncIterator, Awaitable, Callable, Iterator, Sequence
|
|
8
9
|
from contextlib import AbstractAsyncContextManager, AsyncExitStack, asynccontextmanager, contextmanager
|
|
9
10
|
from contextvars import ContextVar
|
|
10
11
|
from typing import TYPE_CHECKING, Any, ClassVar, cast, overload
|
|
11
12
|
|
|
12
|
-
import anyio
|
|
13
13
|
from opentelemetry.trace import NoOpTracer, use_span
|
|
14
14
|
from pydantic.json_schema import GenerateJsonSchema
|
|
15
|
-
from typing_extensions import TypeVar, deprecated
|
|
15
|
+
from typing_extensions import Self, TypeVar, deprecated
|
|
16
16
|
|
|
17
17
|
from pydantic_graph import Graph
|
|
18
18
|
|
|
@@ -157,7 +157,7 @@ class Agent(AbstractAgent[AgentDepsT, OutputDataT]):
|
|
|
157
157
|
|
|
158
158
|
_event_stream_handler: EventStreamHandler[AgentDepsT] | None = dataclasses.field(repr=False)
|
|
159
159
|
|
|
160
|
-
_enter_lock:
|
|
160
|
+
_enter_lock: Lock = dataclasses.field(repr=False)
|
|
161
161
|
_entered_count: int = dataclasses.field(repr=False)
|
|
162
162
|
_exit_stack: AsyncExitStack | None = dataclasses.field(repr=False)
|
|
163
163
|
|
|
@@ -374,7 +374,7 @@ class Agent(AbstractAgent[AgentDepsT, OutputDataT]):
|
|
|
374
374
|
_utils.Option[Sequence[Tool[AgentDepsT] | ToolFuncEither[AgentDepsT, ...]]]
|
|
375
375
|
] = ContextVar('_override_tools', default=None)
|
|
376
376
|
|
|
377
|
-
self._enter_lock =
|
|
377
|
+
self._enter_lock = Lock()
|
|
378
378
|
self._entered_count = 0
|
|
379
379
|
self._exit_stack = None
|
|
380
380
|
|
|
@@ -1066,7 +1066,7 @@ class Agent(AbstractAgent[AgentDepsT, OutputDataT]):
|
|
|
1066
1066
|
strict: Whether to enforce JSON schema compliance (only affects OpenAI).
|
|
1067
1067
|
See [`ToolDefinition`][pydantic_ai.tools.ToolDefinition] for more info.
|
|
1068
1068
|
requires_approval: Whether this tool requires human-in-the-loop approval. Defaults to False.
|
|
1069
|
-
See the [tools documentation](../tools.md#human-in-the-loop-tool-approval) for more info.
|
|
1069
|
+
See the [tools documentation](../deferred-tools.md#human-in-the-loop-tool-approval) for more info.
|
|
1070
1070
|
"""
|
|
1071
1071
|
|
|
1072
1072
|
def tool_decorator(
|
|
@@ -1165,7 +1165,7 @@ class Agent(AbstractAgent[AgentDepsT, OutputDataT]):
|
|
|
1165
1165
|
strict: Whether to enforce JSON schema compliance (only affects OpenAI).
|
|
1166
1166
|
See [`ToolDefinition`][pydantic_ai.tools.ToolDefinition] for more info.
|
|
1167
1167
|
requires_approval: Whether this tool requires human-in-the-loop approval. Defaults to False.
|
|
1168
|
-
See the [tools documentation](../tools.md#human-in-the-loop-tool-approval) for more info.
|
|
1168
|
+
See the [tools documentation](../deferred-tools.md#human-in-the-loop-tool-approval) for more info.
|
|
1169
1169
|
"""
|
|
1170
1170
|
|
|
1171
1171
|
def tool_decorator(func_: ToolFuncPlain[ToolParams]) -> ToolFuncPlain[ToolParams]:
|
|
@@ -1355,7 +1355,7 @@ class Agent(AbstractAgent[AgentDepsT, OutputDataT]):
|
|
|
1355
1355
|
|
|
1356
1356
|
return schema # pyright: ignore[reportReturnType]
|
|
1357
1357
|
|
|
1358
|
-
async def __aenter__(self) ->
|
|
1358
|
+
async def __aenter__(self) -> Self:
|
|
1359
1359
|
"""Enter the agent context.
|
|
1360
1360
|
|
|
1361
1361
|
This will start all [`MCPServerStdio`s][pydantic_ai.mcp.MCPServerStdio] registered as `toolsets` so they are ready to be used.
|