Python: Fix: AgentRunResponse.created_at returns local datetime labeled as UTC (#2590)

* Initial plan

* Fix created_at to use UTC datetime and add unit tests

Co-authored-by: moonbox3 <35585003+moonbox3@users.noreply.github.com>

* Address code review feedback: move datetime imports to top of test files

Co-authored-by: moonbox3 <35585003+moonbox3@users.noreply.github.com>

* Add UTC timestamp test for OpenAIResponsesClient._create_response_content

Co-authored-by: moonbox3 <35585003+moonbox3@users.noreply.github.com>

* Fix lint issue

---------

Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
Co-authored-by: moonbox3 <35585003+moonbox3@users.noreply.github.com>
Co-authored-by: Evan Mattson <evan.mattson@microsoft.com>
This commit is contained in:
Copilot
2025-12-04 05:09:52 +00:00
committed by GitHub
co-authored by moonbox3 copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com> Evan Mattson
parent ae06c9e4bb
commit 292a2078fa
6 changed files with 175 additions and 7 deletions
@@ -1,6 +1,7 @@
# Copyright (c) Microsoft. All rights reserved.
from copy import deepcopy
from datetime import datetime, timezone
from unittest.mock import AsyncMock, MagicMock, patch
import pytest
@@ -370,3 +371,75 @@ async def test_get_streaming_no_stream(
messages=chat_history,
)
]
# region UTC Timestamp Tests
def test_chat_response_created_at_uses_utc(openai_unit_test_env: dict[str, str]):
"""Test that ChatResponse.created_at uses UTC timestamp, not local time.
This is a regression test for the issue where created_at was using local time
but labeling it as UTC (with 'Z' suffix).
"""
from agent_framework import ChatOptions
# Use a specific Unix timestamp: 1733011890 = 2024-12-01T00:31:30Z (UTC)
# This ensures we test that the timestamp is actually converted to UTC
utc_timestamp = 1733011890
mock_response = ChatCompletion(
id="test_id",
choices=[
Choice(index=0, message=ChatCompletionMessage(content="test", role="assistant"), finish_reason="stop")
],
created=utc_timestamp,
model="test",
object="chat.completion",
)
client = OpenAIChatClient()
response = client._create_chat_response(mock_response, ChatOptions())
# Verify that created_at is correctly formatted as UTC
assert response.created_at is not None
assert response.created_at.endswith("Z"), "Timestamp should end with 'Z' for UTC"
# Parse the timestamp and verify it matches UTC time
expected_utc_time = datetime.fromtimestamp(utc_timestamp, tz=timezone.utc)
expected_formatted = expected_utc_time.strftime("%Y-%m-%dT%H:%M:%S.%fZ")
assert response.created_at == expected_formatted, (
f"Expected UTC timestamp {expected_formatted}, got {response.created_at}"
)
def test_chat_response_update_created_at_uses_utc(openai_unit_test_env: dict[str, str]):
"""Test that ChatResponseUpdate.created_at uses UTC timestamp, not local time.
This is a regression test for the issue where created_at was using local time
but labeling it as UTC (with 'Z' suffix).
"""
# Use a specific Unix timestamp: 1733011890 = 2024-12-01T00:31:30Z (UTC)
utc_timestamp = 1733011890
mock_chunk = ChatCompletionChunk(
id="test_id",
choices=[ChunkChoice(index=0, delta=ChunkChoiceDelta(content="test", role="assistant"), finish_reason="stop")],
created=utc_timestamp,
model="test",
object="chat.completion.chunk",
)
client = OpenAIChatClient()
response_update = client._create_chat_response_update(mock_chunk)
# Verify that created_at is correctly formatted as UTC
assert response_update.created_at is not None
assert response_update.created_at.endswith("Z"), "Timestamp should end with 'Z' for UTC"
# Parse the timestamp and verify it matches UTC time
expected_utc_time = datetime.fromtimestamp(utc_timestamp, tz=timezone.utc)
expected_formatted = expected_utc_time.strftime("%Y-%m-%dT%H:%M:%S.%fZ")
assert response_update.created_at == expected_formatted, (
f"Expected UTC timestamp {expected_formatted}, got {response_update.created_at}"
)
@@ -3,6 +3,7 @@
import asyncio
import base64
import os
from datetime import datetime, timezone
from typing import Annotated
from unittest.mock import MagicMock, patch
@@ -684,6 +685,51 @@ def test_create_response_content_with_mcp_approval_request() -> None:
assert req.function_call.additional_properties["server_label"] == "My_MCP"
def test_responses_client_created_at_uses_utc(openai_unit_test_env: dict[str, str]) -> None:
"""Test that ChatResponse from responses client uses UTC timestamp.
This is a regression test for the issue where created_at was using local time
but labeling it as UTC (with 'Z' suffix).
"""
client = OpenAIResponsesClient()
# Use a specific Unix timestamp: 1733011890 = 2024-12-01T00:31:30Z (UTC)
utc_timestamp = 1733011890
mock_response = MagicMock()
mock_response.output_parsed = None
mock_response.metadata = {}
mock_response.usage = None
mock_response.id = "test-id"
mock_response.model = "test-model"
mock_response.created_at = utc_timestamp
mock_message_content = MagicMock()
mock_message_content.type = "output_text"
mock_message_content.text = "Test response"
mock_message_content.annotations = None
mock_message_item = MagicMock()
mock_message_item.type = "message"
mock_message_item.content = [mock_message_content]
mock_response.output = [mock_message_item]
with patch.object(client, "_get_metadata_from_response", return_value={}):
response = client._create_response_content(mock_response, chat_options=ChatOptions()) # type: ignore
# Verify that created_at is correctly formatted as UTC
assert response.created_at is not None
assert response.created_at.endswith("Z"), "Timestamp should end with 'Z' for UTC"
# Parse the timestamp and verify it matches UTC time
expected_utc_time = datetime.fromtimestamp(utc_timestamp, tz=timezone.utc)
expected_formatted = expected_utc_time.strftime("%Y-%m-%dT%H:%M:%S.%fZ")
assert response.created_at == expected_formatted, (
f"Expected UTC timestamp {expected_formatted}, got {response.created_at}"
)
def test_tools_to_response_tools_with_raw_image_generation() -> None:
"""Test that raw image_generation tool dict is handled correctly with parameter mapping."""
client = OpenAIResponsesClient(model_id="test-model", api_key="test-key")