Skip to content

Commit 9c5c529

Browse files
R0bojiDouweM
authored andcommitted
Handle None created timestamp coming from OpenRouter API (pydantic#2247)
Co-authored-by: Douwe Maan <[email protected]>
1 parent 9889b6f commit 9c5c529

File tree

2 files changed

+25
-3
lines changed

2 files changed

+25
-3
lines changed

pydantic_ai_slim/pydantic_ai/models/openai.py

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@
1717

1818
from .. import ModelHTTPError, UnexpectedModelBehavior, _utils, usage
1919
from .._output import DEFAULT_OUTPUT_TOOL_NAME, OutputObjectDefinition
20-
from .._utils import guard_tool_call_id as _guard_tool_call_id, number_to_datetime
20+
from .._utils import guard_tool_call_id as _guard_tool_call_id, now_utc as _now_utc, number_to_datetime
2121
from ..messages import (
2222
AudioUrl,
2323
BinaryContent,
@@ -357,11 +357,17 @@ def _process_response(self, response: chat.ChatCompletion | str) -> ModelRespons
357357
if not isinstance(response, chat.ChatCompletion):
358358
raise UnexpectedModelBehavior('Invalid response from OpenAI chat completions endpoint, expected JSON data')
359359

360+
if response.created:
361+
timestamp = number_to_datetime(response.created)
362+
else:
363+
timestamp = _now_utc()
364+
response.created = int(timestamp.timestamp())
365+
360366
try:
361367
response = chat.ChatCompletion.model_validate(response.model_dump())
362368
except ValidationError as e:
363369
raise UnexpectedModelBehavior(f'Invalid response from OpenAI chat completions endpoint: {e}') from e
364-
timestamp = number_to_datetime(response.created)
370+
365371
choice = response.choices[0]
366372
items: list[ModelResponsePart] = []
367373
# The `reasoning_content` is only present in DeepSeek models.

tests/models/test_openai.py

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2599,7 +2599,7 @@ async def test_invalid_response(allow_model_requests: None):
25992599
with pytest.raises(UnexpectedModelBehavior) as exc_info:
26002600
await agent.run('What is the capital of France?')
26012601
assert exc_info.value.message.startswith(
2602-
'Invalid response from OpenAI chat completions endpoint: 5 validation errors for ChatCompletion'
2602+
'Invalid response from OpenAI chat completions endpoint: 4 validation errors for ChatCompletion'
26032603
)
26042604

26052605

@@ -2615,3 +2615,19 @@ async def test_text_response(allow_model_requests: None):
26152615
assert exc_info.value.message == snapshot(
26162616
'Invalid response from OpenAI chat completions endpoint, expected JSON data'
26172617
)
2618+
2619+
2620+
async def test_process_response_no_created_timestamp(allow_model_requests: None):
2621+
c = completion_message(
2622+
ChatCompletionMessage(content='world', role='assistant'),
2623+
)
2624+
c.created = None # type: ignore
2625+
2626+
mock_client = MockOpenAI.create_mock(c)
2627+
m = OpenAIModel('gpt-4o', provider=OpenAIProvider(openai_client=mock_client))
2628+
agent = Agent(m)
2629+
result = await agent.run('Hello')
2630+
messages = result.all_messages()
2631+
response_message = messages[1]
2632+
assert isinstance(response_message, ModelResponse)
2633+
assert response_message.timestamp == IsNow(tz=timezone.utc)

0 commit comments

Comments
 (0)