Description
In Microsoft.Extensions.AI.ChatResponseExtensions.ToChatResponse(), a ChatMessage is built from a series of ChatResponseUpdate items. Each ChatResponseUpdate may have a CreatedAt timestamp and the last non-null timestamp of the updates becomes the timestamp for the resulting ChatMessage.
However, it appears that some LLM calls stream updates with timestamps set to the Unix epoch (i.e. 1/1/1970 12AM) as an equivalent for a "null" value. In those cases, because the deserialized value is a real DateTimeOffset, the resulting ChatMessage will end up with CreatedAt timestamp set to that "null" value.
It may be better to update the ChatMessage timestamp upon the next update only if that update's timestamp is later than the current timestamp. (Or, alternatively, treat a timestamp set to the UNIX epoch as equivalent to null.)
Reproduction Steps
Adding this test to the ChatResponseUpdateExtensionsTests.cs in the Microsoft.Extensions.AI.Abstractions.Tests exposes the issue.
[Theory]
[InlineData(false)]
[InlineData(true)]
public async Task ToChatResponse_AlternativeTimestamps(bool useAsync)
{
DateTimeOffset now = DateTimeOffset.UtcNow;
ChatResponseUpdate[] updates =
[
new(ChatRole.Tool, "f") { MessageId = "4", CreatedAt = now },
new(null, "g") { CreatedAt = DateTimeOffset.UnixEpoch },
];
ChatResponse response = useAsync ?
updates.ToChatResponse() :
await YieldAsync(updates).ToChatResponseAsync();
Assert.Single(response.Messages);
Assert.Equal("fg", response.Messages[0].Text);
Assert.Equal(ChatRole.Tool, response.Messages[0].Role);
Assert.Equal(now, response.Messages[0].CreatedAt);
}
Expected behavior
The first update's timestamp becomes the timestamp (i.e. CreatedAt) for the ChatMessage.
Actual behavior
The CreatedAt property of the ChatMessage is set to DateTimeOffset.UnixEpoc.
Regression?
Unknown.
Known Workarounds
None.
Configuration
.NET 9 with Microsoft.Extensions.AI.Abstractions version 9.9.0
Other information
No response
Description
In
Microsoft.Extensions.AI.ChatResponseExtensions.ToChatResponse(), aChatMessageis built from a series ofChatResponseUpdateitems. EachChatResponseUpdatemay have aCreatedAttimestamp and the last non-null timestamp of the updates becomes the timestamp for the resultingChatMessage.However, it appears that some LLM calls stream updates with timestamps set to the Unix epoch (i.e. 1/1/1970 12AM) as an equivalent for a "null" value. In those cases, because the deserialized value is a real
DateTimeOffset, the resultingChatMessagewill end up withCreatedAttimestamp set to that "null" value.It may be better to update the
ChatMessagetimestamp upon the next update only if that update's timestamp is later than the current timestamp. (Or, alternatively, treat a timestamp set to the UNIX epoch as equivalent tonull.)Reproduction Steps
Adding this test to the
ChatResponseUpdateExtensionsTests.csin theMicrosoft.Extensions.AI.Abstractions.Testsexposes the issue.Expected behavior
The first update's timestamp becomes the timestamp (i.e.
CreatedAt) for theChatMessage.Actual behavior
The
CreatedAtproperty of theChatMessageis set toDateTimeOffset.UnixEpoc.Regression?
Unknown.
Known Workarounds
None.
Configuration
.NET 9 with
Microsoft.Extensions.AI.Abstractionsversion9.9.0Other information
No response