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 14:09:52 +09:00
committed by GitHub
Unverified
parent ae06c9e4bb
commit 292a2078fa
6 changed files with 175 additions and 7 deletions
@@ -2,6 +2,7 @@
import base64
from collections.abc import AsyncIterable
from datetime import datetime, timezone
from typing import Any
import pytest
@@ -936,6 +937,52 @@ def test_agent_run_response_update_str_method(text_content: TextContent) -> None
assert str(update) == "Test content"
def test_agent_run_response_update_created_at() -> None:
"""Test that AgentRunResponseUpdate properly handles created_at timestamps."""
# Test with a properly formatted UTC timestamp
utc_timestamp = "2024-12-01T00:31:30.000000Z"
update = AgentRunResponseUpdate(
contents=[TextContent(text="test")],
role=Role.ASSISTANT,
created_at=utc_timestamp,
)
assert update.created_at == utc_timestamp
assert update.created_at.endswith("Z"), "Timestamp should end with 'Z' for UTC"
# Verify that we can generate a proper UTC timestamp
now_utc = datetime.now(tz=timezone.utc)
formatted_utc = now_utc.strftime("%Y-%m-%dT%H:%M:%S.%fZ")
update_with_now = AgentRunResponseUpdate(
contents=[TextContent(text="test")],
role=Role.ASSISTANT,
created_at=formatted_utc,
)
assert update_with_now.created_at == formatted_utc
assert update_with_now.created_at.endswith("Z")
def test_agent_run_response_created_at() -> None:
"""Test that AgentRunResponse properly handles created_at timestamps."""
# Test with a properly formatted UTC timestamp
utc_timestamp = "2024-12-01T00:31:30.000000Z"
response = AgentRunResponse(
messages=[ChatMessage(role=Role.ASSISTANT, text="Hello")],
created_at=utc_timestamp,
)
assert response.created_at == utc_timestamp
assert response.created_at.endswith("Z"), "Timestamp should end with 'Z' for UTC"
# Verify that we can generate a proper UTC timestamp
now_utc = datetime.now(tz=timezone.utc)
formatted_utc = now_utc.strftime("%Y-%m-%dT%H:%M:%S.%fZ")
response_with_now = AgentRunResponse(
messages=[ChatMessage(role=Role.ASSISTANT, text="Hello")],
created_at=formatted_utc,
)
assert response_with_now.created_at == formatted_utc
assert response_with_now.created_at.endswith("Z")
# region ErrorContent
@@ -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")