pydantic-ai-slim 0.4.11__tar.gz → 0.5.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.4.11 → pydantic_ai_slim-0.5.0}/PKG-INFO +3 -3
- {pydantic_ai_slim-0.4.11 → pydantic_ai_slim-0.5.0}/pydantic_ai/_function_schema.py +7 -4
- {pydantic_ai_slim-0.4.11 → pydantic_ai_slim-0.5.0}/pydantic_ai/messages.py +37 -10
- {pydantic_ai_slim-0.4.11 → pydantic_ai_slim-0.5.0}/pydantic_ai/profiles/openai.py +22 -12
- {pydantic_ai_slim-0.4.11 → pydantic_ai_slim-0.5.0}/pydantic_ai/tools.py +13 -5
- {pydantic_ai_slim-0.4.11 → pydantic_ai_slim-0.5.0}/.gitignore +0 -0
- {pydantic_ai_slim-0.4.11 → pydantic_ai_slim-0.5.0}/LICENSE +0 -0
- {pydantic_ai_slim-0.4.11 → pydantic_ai_slim-0.5.0}/README.md +0 -0
- {pydantic_ai_slim-0.4.11 → pydantic_ai_slim-0.5.0}/pydantic_ai/__init__.py +0 -0
- {pydantic_ai_slim-0.4.11 → pydantic_ai_slim-0.5.0}/pydantic_ai/__main__.py +0 -0
- {pydantic_ai_slim-0.4.11 → pydantic_ai_slim-0.5.0}/pydantic_ai/_a2a.py +0 -0
- {pydantic_ai_slim-0.4.11 → pydantic_ai_slim-0.5.0}/pydantic_ai/_agent_graph.py +0 -0
- {pydantic_ai_slim-0.4.11 → pydantic_ai_slim-0.5.0}/pydantic_ai/_cli.py +0 -0
- {pydantic_ai_slim-0.4.11 → pydantic_ai_slim-0.5.0}/pydantic_ai/_griffe.py +0 -0
- {pydantic_ai_slim-0.4.11 → pydantic_ai_slim-0.5.0}/pydantic_ai/_mcp.py +0 -0
- {pydantic_ai_slim-0.4.11 → pydantic_ai_slim-0.5.0}/pydantic_ai/_output.py +0 -0
- {pydantic_ai_slim-0.4.11 → pydantic_ai_slim-0.5.0}/pydantic_ai/_parts_manager.py +0 -0
- {pydantic_ai_slim-0.4.11 → pydantic_ai_slim-0.5.0}/pydantic_ai/_run_context.py +0 -0
- {pydantic_ai_slim-0.4.11 → pydantic_ai_slim-0.5.0}/pydantic_ai/_system_prompt.py +0 -0
- {pydantic_ai_slim-0.4.11 → pydantic_ai_slim-0.5.0}/pydantic_ai/_thinking_part.py +0 -0
- {pydantic_ai_slim-0.4.11 → pydantic_ai_slim-0.5.0}/pydantic_ai/_tool_manager.py +0 -0
- {pydantic_ai_slim-0.4.11 → pydantic_ai_slim-0.5.0}/pydantic_ai/_utils.py +0 -0
- {pydantic_ai_slim-0.4.11 → pydantic_ai_slim-0.5.0}/pydantic_ai/ag_ui.py +0 -0
- {pydantic_ai_slim-0.4.11 → pydantic_ai_slim-0.5.0}/pydantic_ai/agent.py +0 -0
- {pydantic_ai_slim-0.4.11 → pydantic_ai_slim-0.5.0}/pydantic_ai/common_tools/__init__.py +0 -0
- {pydantic_ai_slim-0.4.11 → pydantic_ai_slim-0.5.0}/pydantic_ai/common_tools/duckduckgo.py +0 -0
- {pydantic_ai_slim-0.4.11 → pydantic_ai_slim-0.5.0}/pydantic_ai/common_tools/tavily.py +0 -0
- {pydantic_ai_slim-0.4.11 → pydantic_ai_slim-0.5.0}/pydantic_ai/direct.py +0 -0
- {pydantic_ai_slim-0.4.11 → pydantic_ai_slim-0.5.0}/pydantic_ai/exceptions.py +0 -0
- {pydantic_ai_slim-0.4.11 → pydantic_ai_slim-0.5.0}/pydantic_ai/ext/__init__.py +0 -0
- {pydantic_ai_slim-0.4.11 → pydantic_ai_slim-0.5.0}/pydantic_ai/ext/aci.py +0 -0
- {pydantic_ai_slim-0.4.11 → pydantic_ai_slim-0.5.0}/pydantic_ai/ext/langchain.py +0 -0
- {pydantic_ai_slim-0.4.11 → pydantic_ai_slim-0.5.0}/pydantic_ai/format_as_xml.py +0 -0
- {pydantic_ai_slim-0.4.11 → pydantic_ai_slim-0.5.0}/pydantic_ai/format_prompt.py +0 -0
- {pydantic_ai_slim-0.4.11 → pydantic_ai_slim-0.5.0}/pydantic_ai/mcp.py +0 -0
- {pydantic_ai_slim-0.4.11 → pydantic_ai_slim-0.5.0}/pydantic_ai/models/__init__.py +0 -0
- {pydantic_ai_slim-0.4.11 → pydantic_ai_slim-0.5.0}/pydantic_ai/models/anthropic.py +0 -0
- {pydantic_ai_slim-0.4.11 → pydantic_ai_slim-0.5.0}/pydantic_ai/models/bedrock.py +0 -0
- {pydantic_ai_slim-0.4.11 → pydantic_ai_slim-0.5.0}/pydantic_ai/models/cohere.py +0 -0
- {pydantic_ai_slim-0.4.11 → pydantic_ai_slim-0.5.0}/pydantic_ai/models/fallback.py +0 -0
- {pydantic_ai_slim-0.4.11 → pydantic_ai_slim-0.5.0}/pydantic_ai/models/function.py +0 -0
- {pydantic_ai_slim-0.4.11 → pydantic_ai_slim-0.5.0}/pydantic_ai/models/gemini.py +0 -0
- {pydantic_ai_slim-0.4.11 → pydantic_ai_slim-0.5.0}/pydantic_ai/models/google.py +0 -0
- {pydantic_ai_slim-0.4.11 → pydantic_ai_slim-0.5.0}/pydantic_ai/models/groq.py +0 -0
- {pydantic_ai_slim-0.4.11 → pydantic_ai_slim-0.5.0}/pydantic_ai/models/huggingface.py +0 -0
- {pydantic_ai_slim-0.4.11 → pydantic_ai_slim-0.5.0}/pydantic_ai/models/instrumented.py +0 -0
- {pydantic_ai_slim-0.4.11 → pydantic_ai_slim-0.5.0}/pydantic_ai/models/mcp_sampling.py +0 -0
- {pydantic_ai_slim-0.4.11 → pydantic_ai_slim-0.5.0}/pydantic_ai/models/mistral.py +0 -0
- {pydantic_ai_slim-0.4.11 → pydantic_ai_slim-0.5.0}/pydantic_ai/models/openai.py +0 -0
- {pydantic_ai_slim-0.4.11 → pydantic_ai_slim-0.5.0}/pydantic_ai/models/test.py +0 -0
- {pydantic_ai_slim-0.4.11 → pydantic_ai_slim-0.5.0}/pydantic_ai/models/wrapper.py +0 -0
- {pydantic_ai_slim-0.4.11 → pydantic_ai_slim-0.5.0}/pydantic_ai/output.py +0 -0
- {pydantic_ai_slim-0.4.11 → pydantic_ai_slim-0.5.0}/pydantic_ai/profiles/__init__.py +0 -0
- {pydantic_ai_slim-0.4.11 → pydantic_ai_slim-0.5.0}/pydantic_ai/profiles/_json_schema.py +0 -0
- {pydantic_ai_slim-0.4.11 → pydantic_ai_slim-0.5.0}/pydantic_ai/profiles/amazon.py +0 -0
- {pydantic_ai_slim-0.4.11 → pydantic_ai_slim-0.5.0}/pydantic_ai/profiles/anthropic.py +0 -0
- {pydantic_ai_slim-0.4.11 → pydantic_ai_slim-0.5.0}/pydantic_ai/profiles/cohere.py +0 -0
- {pydantic_ai_slim-0.4.11 → pydantic_ai_slim-0.5.0}/pydantic_ai/profiles/deepseek.py +0 -0
- {pydantic_ai_slim-0.4.11 → pydantic_ai_slim-0.5.0}/pydantic_ai/profiles/google.py +0 -0
- {pydantic_ai_slim-0.4.11 → pydantic_ai_slim-0.5.0}/pydantic_ai/profiles/grok.py +0 -0
- {pydantic_ai_slim-0.4.11 → pydantic_ai_slim-0.5.0}/pydantic_ai/profiles/meta.py +0 -0
- {pydantic_ai_slim-0.4.11 → pydantic_ai_slim-0.5.0}/pydantic_ai/profiles/mistral.py +0 -0
- {pydantic_ai_slim-0.4.11 → pydantic_ai_slim-0.5.0}/pydantic_ai/profiles/moonshotai.py +0 -0
- {pydantic_ai_slim-0.4.11 → pydantic_ai_slim-0.5.0}/pydantic_ai/profiles/qwen.py +0 -0
- {pydantic_ai_slim-0.4.11 → pydantic_ai_slim-0.5.0}/pydantic_ai/providers/__init__.py +0 -0
- {pydantic_ai_slim-0.4.11 → pydantic_ai_slim-0.5.0}/pydantic_ai/providers/anthropic.py +0 -0
- {pydantic_ai_slim-0.4.11 → pydantic_ai_slim-0.5.0}/pydantic_ai/providers/azure.py +0 -0
- {pydantic_ai_slim-0.4.11 → pydantic_ai_slim-0.5.0}/pydantic_ai/providers/bedrock.py +0 -0
- {pydantic_ai_slim-0.4.11 → pydantic_ai_slim-0.5.0}/pydantic_ai/providers/cohere.py +0 -0
- {pydantic_ai_slim-0.4.11 → pydantic_ai_slim-0.5.0}/pydantic_ai/providers/deepseek.py +0 -0
- {pydantic_ai_slim-0.4.11 → pydantic_ai_slim-0.5.0}/pydantic_ai/providers/fireworks.py +0 -0
- {pydantic_ai_slim-0.4.11 → pydantic_ai_slim-0.5.0}/pydantic_ai/providers/github.py +0 -0
- {pydantic_ai_slim-0.4.11 → pydantic_ai_slim-0.5.0}/pydantic_ai/providers/google.py +0 -0
- {pydantic_ai_slim-0.4.11 → pydantic_ai_slim-0.5.0}/pydantic_ai/providers/google_gla.py +0 -0
- {pydantic_ai_slim-0.4.11 → pydantic_ai_slim-0.5.0}/pydantic_ai/providers/google_vertex.py +0 -0
- {pydantic_ai_slim-0.4.11 → pydantic_ai_slim-0.5.0}/pydantic_ai/providers/grok.py +0 -0
- {pydantic_ai_slim-0.4.11 → pydantic_ai_slim-0.5.0}/pydantic_ai/providers/groq.py +0 -0
- {pydantic_ai_slim-0.4.11 → pydantic_ai_slim-0.5.0}/pydantic_ai/providers/heroku.py +0 -0
- {pydantic_ai_slim-0.4.11 → pydantic_ai_slim-0.5.0}/pydantic_ai/providers/huggingface.py +0 -0
- {pydantic_ai_slim-0.4.11 → pydantic_ai_slim-0.5.0}/pydantic_ai/providers/mistral.py +0 -0
- {pydantic_ai_slim-0.4.11 → pydantic_ai_slim-0.5.0}/pydantic_ai/providers/moonshotai.py +0 -0
- {pydantic_ai_slim-0.4.11 → pydantic_ai_slim-0.5.0}/pydantic_ai/providers/openai.py +0 -0
- {pydantic_ai_slim-0.4.11 → pydantic_ai_slim-0.5.0}/pydantic_ai/providers/openrouter.py +0 -0
- {pydantic_ai_slim-0.4.11 → pydantic_ai_slim-0.5.0}/pydantic_ai/providers/together.py +0 -0
- {pydantic_ai_slim-0.4.11 → pydantic_ai_slim-0.5.0}/pydantic_ai/providers/vercel.py +0 -0
- {pydantic_ai_slim-0.4.11 → pydantic_ai_slim-0.5.0}/pydantic_ai/py.typed +0 -0
- {pydantic_ai_slim-0.4.11 → pydantic_ai_slim-0.5.0}/pydantic_ai/result.py +0 -0
- {pydantic_ai_slim-0.4.11 → pydantic_ai_slim-0.5.0}/pydantic_ai/retries.py +0 -0
- {pydantic_ai_slim-0.4.11 → pydantic_ai_slim-0.5.0}/pydantic_ai/settings.py +0 -0
- {pydantic_ai_slim-0.4.11 → pydantic_ai_slim-0.5.0}/pydantic_ai/toolsets/__init__.py +0 -0
- {pydantic_ai_slim-0.4.11 → pydantic_ai_slim-0.5.0}/pydantic_ai/toolsets/abstract.py +0 -0
- {pydantic_ai_slim-0.4.11 → pydantic_ai_slim-0.5.0}/pydantic_ai/toolsets/combined.py +0 -0
- {pydantic_ai_slim-0.4.11 → pydantic_ai_slim-0.5.0}/pydantic_ai/toolsets/deferred.py +0 -0
- {pydantic_ai_slim-0.4.11 → pydantic_ai_slim-0.5.0}/pydantic_ai/toolsets/filtered.py +0 -0
- {pydantic_ai_slim-0.4.11 → pydantic_ai_slim-0.5.0}/pydantic_ai/toolsets/function.py +0 -0
- {pydantic_ai_slim-0.4.11 → pydantic_ai_slim-0.5.0}/pydantic_ai/toolsets/prefixed.py +0 -0
- {pydantic_ai_slim-0.4.11 → pydantic_ai_slim-0.5.0}/pydantic_ai/toolsets/prepared.py +0 -0
- {pydantic_ai_slim-0.4.11 → pydantic_ai_slim-0.5.0}/pydantic_ai/toolsets/renamed.py +0 -0
- {pydantic_ai_slim-0.4.11 → pydantic_ai_slim-0.5.0}/pydantic_ai/toolsets/wrapper.py +0 -0
- {pydantic_ai_slim-0.4.11 → pydantic_ai_slim-0.5.0}/pydantic_ai/usage.py +0 -0
- {pydantic_ai_slim-0.4.11 → pydantic_ai_slim-0.5.0}/pyproject.toml +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: pydantic-ai-slim
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.5.0
|
|
4
4
|
Summary: Agent Framework / shim to use Pydantic with LLMs, slim package
|
|
5
5
|
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>
|
|
6
6
|
License-Expression: MIT
|
|
@@ -30,7 +30,7 @@ Requires-Dist: exceptiongroup; python_version < '3.11'
|
|
|
30
30
|
Requires-Dist: griffe>=1.3.2
|
|
31
31
|
Requires-Dist: httpx>=0.27
|
|
32
32
|
Requires-Dist: opentelemetry-api>=1.28.0
|
|
33
|
-
Requires-Dist: pydantic-graph==0.
|
|
33
|
+
Requires-Dist: pydantic-graph==0.5.0
|
|
34
34
|
Requires-Dist: pydantic>=2.10
|
|
35
35
|
Requires-Dist: typing-inspection>=0.4.0
|
|
36
36
|
Provides-Extra: a2a
|
|
@@ -51,7 +51,7 @@ Requires-Dist: cohere>=5.16.0; (platform_system != 'Emscripten') and extra == 'c
|
|
|
51
51
|
Provides-Extra: duckduckgo
|
|
52
52
|
Requires-Dist: ddgs>=9.0.0; extra == 'duckduckgo'
|
|
53
53
|
Provides-Extra: evals
|
|
54
|
-
Requires-Dist: pydantic-evals==0.
|
|
54
|
+
Requires-Dist: pydantic-evals==0.5.0; extra == 'evals'
|
|
55
55
|
Provides-Extra: google
|
|
56
56
|
Requires-Dist: google-genai>=1.24.0; extra == 'google'
|
|
57
57
|
Provides-Extra: groq
|
|
@@ -154,9 +154,13 @@ def function_schema( # noqa: C901
|
|
|
154
154
|
if p.kind == Parameter.VAR_POSITIONAL:
|
|
155
155
|
annotation = list[annotation]
|
|
156
156
|
|
|
157
|
-
|
|
157
|
+
required = p.default is Parameter.empty
|
|
158
|
+
# FieldInfo.from_annotated_attribute expects a type, `annotation` is Any
|
|
158
159
|
annotation = cast(type[Any], annotation)
|
|
159
|
-
|
|
160
|
+
if required:
|
|
161
|
+
field_info = FieldInfo.from_annotation(annotation)
|
|
162
|
+
else:
|
|
163
|
+
field_info = FieldInfo.from_annotated_attribute(annotation, p.default)
|
|
160
164
|
if field_info.description is None:
|
|
161
165
|
field_info.description = field_descriptions.get(field_name)
|
|
162
166
|
|
|
@@ -164,7 +168,7 @@ def function_schema( # noqa: C901
|
|
|
164
168
|
field_name,
|
|
165
169
|
field_info,
|
|
166
170
|
decorators,
|
|
167
|
-
required=
|
|
171
|
+
required=required,
|
|
168
172
|
)
|
|
169
173
|
# noinspection PyTypeChecker
|
|
170
174
|
td_schema.setdefault('metadata', {})['is_model_like'] = is_model_like(annotation)
|
|
@@ -281,7 +285,6 @@ def _build_schema(
|
|
|
281
285
|
td_schema = core_schema.typed_dict_schema(
|
|
282
286
|
fields,
|
|
283
287
|
config=core_config,
|
|
284
|
-
total=var_kwargs_schema is None,
|
|
285
288
|
extras_schema=gen_schema.generate_schema(var_kwargs_schema) if var_kwargs_schema else None,
|
|
286
289
|
)
|
|
287
290
|
return td_schema, None
|
|
@@ -106,7 +106,7 @@ class FileUrl(ABC):
|
|
|
106
106
|
- `GoogleModel`: `VideoUrl.vendor_metadata` is used as `video_metadata`: https://ai.google.dev/gemini-api/docs/video-understanding#customize-video-processing
|
|
107
107
|
"""
|
|
108
108
|
|
|
109
|
-
_media_type: str | None = field(init=False, repr=False)
|
|
109
|
+
_media_type: str | None = field(init=False, repr=False, compare=False)
|
|
110
110
|
|
|
111
111
|
def __init__(
|
|
112
112
|
self,
|
|
@@ -120,19 +120,21 @@ class FileUrl(ABC):
|
|
|
120
120
|
self.force_download = force_download
|
|
121
121
|
self._media_type = media_type
|
|
122
122
|
|
|
123
|
-
@abstractmethod
|
|
124
|
-
def _infer_media_type(self) -> str:
|
|
125
|
-
"""Return the media type of the file, based on the url."""
|
|
126
|
-
|
|
127
123
|
@property
|
|
128
124
|
def media_type(self) -> str:
|
|
129
|
-
"""Return the media type of the file, based on the
|
|
125
|
+
"""Return the media type of the file, based on the URL or the provided `media_type`."""
|
|
130
126
|
return self._media_type or self._infer_media_type()
|
|
131
127
|
|
|
128
|
+
@abstractmethod
|
|
129
|
+
def _infer_media_type(self) -> str:
|
|
130
|
+
"""Infer the media type of the file based on the URL."""
|
|
131
|
+
raise NotImplementedError
|
|
132
|
+
|
|
132
133
|
@property
|
|
133
134
|
@abstractmethod
|
|
134
135
|
def format(self) -> str:
|
|
135
136
|
"""The file format."""
|
|
137
|
+
raise NotImplementedError
|
|
136
138
|
|
|
137
139
|
__repr__ = _utils.dataclasses_no_defaults_repr
|
|
138
140
|
|
|
@@ -182,7 +184,9 @@ class VideoUrl(FileUrl):
|
|
|
182
184
|
elif self.is_youtube:
|
|
183
185
|
return 'video/mp4'
|
|
184
186
|
else:
|
|
185
|
-
raise ValueError(
|
|
187
|
+
raise ValueError(
|
|
188
|
+
f'Could not infer media type from video URL: {self.url}. Explicitly provide a `media_type` instead.'
|
|
189
|
+
)
|
|
186
190
|
|
|
187
191
|
@property
|
|
188
192
|
def is_youtube(self) -> bool:
|
|
@@ -238,7 +242,9 @@ class AudioUrl(FileUrl):
|
|
|
238
242
|
if self.url.endswith('.aac'):
|
|
239
243
|
return 'audio/aac'
|
|
240
244
|
|
|
241
|
-
raise ValueError(
|
|
245
|
+
raise ValueError(
|
|
246
|
+
f'Could not infer media type from audio URL: {self.url}. Explicitly provide a `media_type` instead.'
|
|
247
|
+
)
|
|
242
248
|
|
|
243
249
|
@property
|
|
244
250
|
def format(self) -> AudioFormat:
|
|
@@ -278,7 +284,9 @@ class ImageUrl(FileUrl):
|
|
|
278
284
|
elif self.url.endswith('.webp'):
|
|
279
285
|
return 'image/webp'
|
|
280
286
|
else:
|
|
281
|
-
raise ValueError(
|
|
287
|
+
raise ValueError(
|
|
288
|
+
f'Could not infer media type from image URL: {self.url}. Explicitly provide a `media_type` instead.'
|
|
289
|
+
)
|
|
282
290
|
|
|
283
291
|
@property
|
|
284
292
|
def format(self) -> ImageFormat:
|
|
@@ -312,9 +320,28 @@ class DocumentUrl(FileUrl):
|
|
|
312
320
|
|
|
313
321
|
def _infer_media_type(self) -> str:
|
|
314
322
|
"""Return the media type of the document, based on the url."""
|
|
323
|
+
# Common document types are hardcoded here as mime-type support for these
|
|
324
|
+
# extensions varies across operating systems.
|
|
325
|
+
if self.url.endswith(('.md', '.mdx', '.markdown')):
|
|
326
|
+
return 'text/markdown'
|
|
327
|
+
elif self.url.endswith('.asciidoc'):
|
|
328
|
+
return 'text/x-asciidoc'
|
|
329
|
+
elif self.url.endswith('.txt'):
|
|
330
|
+
return 'text/plain'
|
|
331
|
+
elif self.url.endswith('.pdf'):
|
|
332
|
+
return 'application/pdf'
|
|
333
|
+
elif self.url.endswith('.rtf'):
|
|
334
|
+
return 'application/rtf'
|
|
335
|
+
elif self.url.endswith('.docx'):
|
|
336
|
+
return 'application/vnd.openxmlformats-officedocument.wordprocessingml.document'
|
|
337
|
+
elif self.url.endswith('.xlsx'):
|
|
338
|
+
return 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet'
|
|
339
|
+
|
|
315
340
|
type_, _ = guess_type(self.url)
|
|
316
341
|
if type_ is None:
|
|
317
|
-
raise ValueError(
|
|
342
|
+
raise ValueError(
|
|
343
|
+
f'Could not infer media type from document URL: {self.url}. Explicitly provide a `media_type` instead.'
|
|
344
|
+
)
|
|
318
345
|
return type_
|
|
319
346
|
|
|
320
347
|
@property
|
|
@@ -47,11 +47,6 @@ def openai_model_profile(model_name: str) -> ModelProfile:
|
|
|
47
47
|
_STRICT_INCOMPATIBLE_KEYS = [
|
|
48
48
|
'minLength',
|
|
49
49
|
'maxLength',
|
|
50
|
-
'pattern',
|
|
51
|
-
'format',
|
|
52
|
-
'minimum',
|
|
53
|
-
'maximum',
|
|
54
|
-
'multipleOf',
|
|
55
50
|
'patternProperties',
|
|
56
51
|
'unevaluatedProperties',
|
|
57
52
|
'propertyNames',
|
|
@@ -61,11 +56,21 @@ _STRICT_INCOMPATIBLE_KEYS = [
|
|
|
61
56
|
'contains',
|
|
62
57
|
'minContains',
|
|
63
58
|
'maxContains',
|
|
64
|
-
'minItems',
|
|
65
|
-
'maxItems',
|
|
66
59
|
'uniqueItems',
|
|
67
60
|
]
|
|
68
61
|
|
|
62
|
+
_STRICT_COMPATIBLE_STRING_FORMATS = [
|
|
63
|
+
'date-time',
|
|
64
|
+
'time',
|
|
65
|
+
'date',
|
|
66
|
+
'duration',
|
|
67
|
+
'email',
|
|
68
|
+
'hostname',
|
|
69
|
+
'ipv4',
|
|
70
|
+
'ipv6',
|
|
71
|
+
'uuid',
|
|
72
|
+
]
|
|
73
|
+
|
|
69
74
|
_sentinel = object()
|
|
70
75
|
|
|
71
76
|
|
|
@@ -127,6 +132,9 @@ class OpenAIJsonSchemaTransformer(JsonSchemaTransformer):
|
|
|
127
132
|
value = schema.get(key, _sentinel)
|
|
128
133
|
if value is not _sentinel:
|
|
129
134
|
incompatible_values[key] = value
|
|
135
|
+
if format := schema.get('format'):
|
|
136
|
+
if format not in _STRICT_COMPATIBLE_STRING_FORMATS:
|
|
137
|
+
incompatible_values['format'] = format
|
|
130
138
|
description = schema.get('description')
|
|
131
139
|
if incompatible_values:
|
|
132
140
|
if self.strict is True:
|
|
@@ -158,11 +166,13 @@ class OpenAIJsonSchemaTransformer(JsonSchemaTransformer):
|
|
|
158
166
|
schema['required'] = list(schema['properties'].keys())
|
|
159
167
|
|
|
160
168
|
elif self.strict is None:
|
|
161
|
-
if (
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
169
|
+
if schema.get('additionalProperties', None) not in (None, False):
|
|
170
|
+
self.is_strict_compatible = False
|
|
171
|
+
else:
|
|
172
|
+
# additional properties are disallowed by default
|
|
173
|
+
schema['additionalProperties'] = False
|
|
174
|
+
|
|
175
|
+
if 'properties' not in schema or 'required' not in schema:
|
|
166
176
|
self.is_strict_compatible = False
|
|
167
177
|
else:
|
|
168
178
|
required = schema['required']
|
|
@@ -133,11 +133,19 @@ A = TypeVar('A')
|
|
|
133
133
|
|
|
134
134
|
class GenerateToolJsonSchema(GenerateJsonSchema):
|
|
135
135
|
def typed_dict_schema(self, schema: core_schema.TypedDictSchema) -> JsonSchemaValue:
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
if 'additionalProperties' not in
|
|
139
|
-
|
|
140
|
-
|
|
136
|
+
json_schema = super().typed_dict_schema(schema)
|
|
137
|
+
# Workaround for https://github.com/pydantic/pydantic/issues/12123
|
|
138
|
+
if 'additionalProperties' not in json_schema: # pragma: no branch
|
|
139
|
+
extra = schema.get('extra_behavior') or schema.get('config', {}).get('extra_fields_behavior')
|
|
140
|
+
if extra == 'allow':
|
|
141
|
+
extras_schema = schema.get('extras_schema', None)
|
|
142
|
+
if extras_schema is not None:
|
|
143
|
+
json_schema['additionalProperties'] = self.generate_inner(extras_schema) or True
|
|
144
|
+
else:
|
|
145
|
+
json_schema['additionalProperties'] = True # pragma: no cover
|
|
146
|
+
elif extra == 'forbid':
|
|
147
|
+
json_schema['additionalProperties'] = False
|
|
148
|
+
return json_schema
|
|
141
149
|
|
|
142
150
|
def _named_required_fields_schema(self, named_required_fields: Sequence[tuple[str, bool, Any]]) -> JsonSchemaValue:
|
|
143
151
|
# Remove largely-useless property titles
|
|
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
|
|
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
|