Skip to content

Conversation

Copy link
Contributor

Copilot AI commented Jan 5, 2026

  • Understand the issue: ToChatResponse{Async} should use the first update's CreatedAt instead of the last
  • Identify the code to change: ChatResponseExtensions.cs lines 521-524 (message) and 566-569 (response)
  • Implement the fix: Change CreatedAt logic to prefer first non-null, non-epoch value
  • Update tests: Modify tests that expect "last wins" behavior to expect "first wins"
  • Build and test: All 108 ChatResponseUpdateExtensionsTests pass on net8.0 and net9.0
  • Address PR review feedback:
    • Updated comments to clarify CreatedAt uses first valid value
    • Used DateTimeOffset.UnixEpoch under #if NET instead of custom field
    • Simplified IsValidCreatedAt to use direct nullable comparison
    • Added tests for datetime values less than Unix epoch

Summary

Changed the ToChatResponse{Async} implementation so that the CreatedAt property reflects the first appropriate update's CreatedAt property rather than the last. Values that are less than or equal to the Unix epoch are treated as null (invalid). This ensures that when streaming responses from providers like Mistral, the CreatedAt accurately reflects when the message content was generated, not when the usage update was received.

Original prompt

This section details on the original issue you should resolve

<issue_title>Inaccurate CreatedAt returned by ToChatResponse</issue_title>
<issue_description>```csharp
ChatResponseUpdate[] updates =
[
new()
{
Role = ChatRole.Assistant,
Contents = [new TextContent("Hi")],
CreatedAt = DateTimeOffset.UtcNow,
},
new()
{
Role = ChatRole.Assistant,
Contents = [new UsageContent { Details = new UsageDetails { TotalTokenCount = 1 } }],
CreatedAt = DateTimeOffset.UtcNow + TimeSpan.FromMinutes(11),
},
];
Console.WriteLine(updates.ToChatResponse().Messages[0].CreatedAt);


In this example `Messages[0].CreatedAt` will get the value of the second update. I think it would make more sense to get the value of the first update as the second update is not really part of the message.

In the mistral API, I noticed significant delay between the usage update and the last text update so I would like it to be reflected in the ChatResponse.</issue_description>

<agent_instructions>Please update the ToChatResponse{Async} implementation so that the CreatedAt property reflects the first appropriate update's CreatedAt property rather than the last (it should treat any value that's less than or equal to the Unix epoch as being the same as null). Update existing tests accordingly.</agent_instructions>

## Comments on the Issue (you are @copilot in this section)

<comments>
<comment_new><author>@stephentoub</author><body>
If you do non-streaming with a really large response, is the creation date you get back closer to the time of the request or the time of completion? </body></comment_new>
<comment_new><author>@stephentoub</author><body>
Ok. I played around with some other providers, and it does look like CreatedAt should reflect the first rather than last update.</body></comment_new>
</comments>


✨ Let Copilot coding agent set things up for you — coding agent works faster and does higher quality work when set up for your repo.

Microsoft Reviewers: Open in CodeFlow

Copilot AI and others added 3 commits January 5, 2026 15:03
…f last

Changed the logic in ProcessUpdate to prefer the first valid CreatedAt value
(non-null and after Unix epoch) rather than the latest one. This fixes the
issue where UsageContent updates with later timestamps were incorrectly
overwriting the message CreatedAt with a value that doesn't reflect when
the actual message content was generated.

Co-authored-by: stephentoub <[email protected]>
Copilot AI changed the title [WIP] Fix inaccurate CreatedAt returned by ToChatResponse Fix ToChatResponse to use first appropriate CreatedAt instead of last Jan 5, 2026
Copilot AI requested a review from stephentoub January 5, 2026 15:09
@stephentoub stephentoub marked this pull request as ready for review January 5, 2026 15:11
@stephentoub stephentoub requested a review from a team as a code owner January 5, 2026 15:11
Copilot AI review requested due to automatic review settings January 5, 2026 15:11
…ixEpoch under #if NET

- Updated comments in ProcessUpdate to clarify that CreatedAt prefers first valid value
- Used DateTimeOffset.UnixEpoch under #if NET instead of custom _unixEpoch field

Co-authored-by: stephentoub <[email protected]>
Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR fixes a bug where ToChatResponse{Async} was incorrectly using the timestamp from the last update rather than the first update when constructing a ChatResponse. This caused inaccurate CreatedAt values when usage updates arrive significantly after content updates (e.g., in the Mistral API where usage updates can be delayed by several minutes).

Key Changes:

  • Modified timestamp handling to use "first valid value wins" behavior instead of "last value wins"
  • Added IsValidCreatedAt helper that treats values ≤ Unix epoch (1970-01-01) as null/invalid
  • Updated all affected tests to reflect the new first-wins behavior and use valid timestamps (years ≥ 1970)

Reviewed changes

Copilot reviewed 2 out of 2 changed files in this pull request and generated 1 comment.

File Description
src/Libraries/Microsoft.Extensions.AI.Abstractions/ChatCompletion/ChatResponseExtensions.cs Changed ProcessUpdate to set CreatedAt only when null (first-wins), added IsValidCreatedAt helper and Unix epoch constant
test/Libraries/Microsoft.Extensions.AI.Abstractions.Tests/ChatCompletion/ChatResponseUpdateExtensionsTests.cs Updated test timestamps from invalid years (1, 2) to valid ones (2024, 2025), updated expected values to match first-wins behavior, and corrected comments to reflect new semantics

Simplified the IsValidCreatedAt helper to use direct comparison (createdAt > UnixEpoch) instead of pattern matching first. The comparison returns false when the nullable value is null.

Co-authored-by: stephentoub <[email protected]>
Added test cases to validate that datetime values less than Unix epoch
(not just equal to it) are treated the same as null:
- Added test cases to ToChatResponse_TimestampFolding_MemberData for 1969 and 1960 dates
- Updated ToChatResponse_AlternativeTimestamps to include a before-epoch timestamp

Co-authored-by: stephentoub <[email protected]>
This was referenced Jan 15, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area-ai Microsoft.Extensions.AI libraries

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Inaccurate CreatedAt returned by ToChatResponse

3 participants