Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
22 changes: 15 additions & 7 deletions pydantic_ai_slim/pydantic_ai/profiles/openai.py
Original file line number Diff line number Diff line change
Expand Up @@ -47,11 +47,6 @@ def openai_model_profile(model_name: str) -> ModelProfile:
_STRICT_INCOMPATIBLE_KEYS = [
'minLength',
'maxLength',
'pattern',
'format',
'minimum',
'maximum',
'multipleOf',
'patternProperties',
'unevaluatedProperties',
'propertyNames',
Expand All @@ -61,11 +56,21 @@ def openai_model_profile(model_name: str) -> ModelProfile:
'contains',
'minContains',
'maxContains',
'minItems',
'maxItems',
'uniqueItems',
]

_STRICT_COMPATIBLE_STRING_FORMATS = [
'date-time',
'time',
'date',
'duration',
'email',
'hostname',
'ipv4',
'ipv6',
'uuid',
]

_sentinel = object()


Expand Down Expand Up @@ -127,6 +132,9 @@ def transform(self, schema: JsonSchema) -> JsonSchema: # noqa C901
value = schema.get(key, _sentinel)
if value is not _sentinel:
incompatible_values[key] = value
if format := schema.get('format'):
if format not in _STRICT_COMPATIBLE_STRING_FORMATS:
incompatible_values['format'] = format
description = schema.get('description')
if incompatible_values:
if self.strict is True:
Expand Down
70 changes: 53 additions & 17 deletions tests/models/test_openai.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
import pytest
from dirty_equals import IsListOrTuple
from inline_snapshot import snapshot
from pydantic import BaseModel, Discriminator, Field, Tag
from pydantic import AnyUrl, BaseModel, Discriminator, Field, Tag
from typing_extensions import TypedDict

from pydantic_ai import Agent, ModelHTTPError, ModelRetry, UnexpectedModelBehavior
Expand Down Expand Up @@ -1094,6 +1094,14 @@ def tool_with_default(x: int = 1) -> str:
return f'{x}' # pragma: no cover


def tool_with_datetime(x: datetime) -> str:
return f'{x}' # pragma: no cover


def tool_with_url(x: AnyUrl) -> str:
return f'{x}' # pragma: no cover


def tool_with_recursion(x: MyRecursiveDc, y: MyDefaultRecursiveDc):
return f'{x} {y}' # pragma: no cover

Expand Down Expand Up @@ -1156,6 +1164,45 @@ def tool_with_tuples(x: tuple[int], y: tuple[str] = ('abc',)) -> str:
),
snapshot(True),
),
(
tool_with_datetime,
None,
snapshot(
{
'additionalProperties': False,
'properties': {'x': {'format': 'date-time', 'type': 'string'}},
'required': ['x'],
'type': 'object',
}
),
snapshot(True),
),
(
tool_with_url,
None,
snapshot(
{
'additionalProperties': False,
'properties': {'x': {'format': 'uri', 'minLength': 1, 'type': 'string'}},
'required': ['x'],
'type': 'object',
}
),
snapshot(None),
),
(
tool_with_url,
True,
snapshot(
{
'additionalProperties': False,
'properties': {'x': {'type': 'string', 'description': 'minLength=1, format=uri'}},
'required': ['x'],
'type': 'object',
}
),
snapshot(True),
),
(
tool_with_recursion,
None,
Expand Down Expand Up @@ -1432,16 +1479,8 @@ def tool_with_tuples(x: tuple[int], y: tuple[str] = ('abc',)) -> str:
{
'additionalProperties': False,
'properties': {
'x': {
'prefixItems': [{'type': 'integer'}],
'type': 'array',
'description': 'minItems=1, maxItems=1',
},
'y': {
'prefixItems': [{'type': 'string'}],
'type': 'array',
'description': 'minItems=1, maxItems=1',
},
'x': {'maxItems': 1, 'minItems': 1, 'prefixItems': [{'type': 'integer'}], 'type': 'array'},
'y': {'maxItems': 1, 'minItems': 1, 'prefixItems': [{'type': 'string'}], 'type': 'array'},
},
'required': ['x', 'y'],
'type': 'object',
Expand Down Expand Up @@ -1537,9 +1576,10 @@ class MyModel(BaseModel):
},
'my_recursive': {'anyOf': [{'$ref': '#'}, {'type': 'null'}]},
'my_tuple': {
'maxItems': 1,
'minItems': 1,
'prefixItems': [{'type': 'integer'}],
'type': 'array',
'description': 'minItems=1, maxItems=1',
},
},
'required': ['my_recursive', 'my_patterns', 'my_tuple', 'my_list', 'my_discriminated_union'],
Expand All @@ -1555,11 +1595,7 @@ class MyModel(BaseModel):
'properties': {},
'required': [],
},
'my_tuple': {
'prefixItems': [{'type': 'integer'}],
'type': 'array',
'description': 'minItems=1, maxItems=1',
},
'my_tuple': {'maxItems': 1, 'minItems': 1, 'prefixItems': [{'type': 'integer'}], 'type': 'array'},
'my_list': {'items': {'type': 'number'}, 'type': 'array'},
'my_discriminated_union': {'anyOf': [{'$ref': '#/$defs/Apple'}, {'$ref': '#/$defs/Banana'}]},
},
Expand Down