From 1ed46e41a721128ee5bc677a5d08402f2241f51d Mon Sep 17 00:00:00 2001
From: westey <164392973+westey-m@users.noreply.github.com>
Date: Fri, 29 Aug 2025 16:43:16 +0100
Subject: [PATCH] Further fixes for compatibility with Microsoft.Extensions
repo. (#555)
---
.../AgentThread.cs | 4 +-
.../InMemoryChatMessageStore.cs | 4 +-
.../ChatCompletion/ChatClientAgent.cs | 2 +-
.../ChatClientAgentExtensions.cs | 4 +-
.../ChatCompletion/ChatClientAgentOptions.cs | 5 +-
.../ChatClientAgentRunOptions.cs | 10 ----
.../AIAgentTests.cs | 17 +++++-
.../AgentRunResponseTests.cs | 2 +-
.../AgentRunResponseUpdateExtensionsTests.cs | 40 +++++++-------
.../AgentThreadTests.cs | 45 +++++++++------
.../InMemoryChatMessageStoreTests.cs | 16 ++++--
.../TestJsonSerializerContext.cs | 4 ++
.../ChatClientAgentRunOptionsTests.cs | 55 +------------------
.../ChatCompletion/ChatClientAgentTests.cs | 54 +++++++++++-------
14 files changed, 127 insertions(+), 135 deletions(-)
diff --git a/dotnet/src/Microsoft.Extensions.AI.Agents.Abstractions/AgentThread.cs b/dotnet/src/Microsoft.Extensions.AI.Agents.Abstractions/AgentThread.cs
index a705ba6530..63b8f07f69 100644
--- a/dotnet/src/Microsoft.Extensions.AI.Agents.Abstractions/AgentThread.cs
+++ b/dotnet/src/Microsoft.Extensions.AI.Agents.Abstractions/AgentThread.cs
@@ -205,7 +205,7 @@ public class AgentThread
}
// If we don't have any IChatMessageStore state return here.
- if (state?.StoreState is null || state?.StoreState?.ValueKind is JsonValueKind.Undefined or JsonValueKind.Null)
+ if (state?.StoreState is null || state?.StoreState.Value.ValueKind is JsonValueKind.Undefined or JsonValueKind.Null)
{
return;
}
@@ -219,7 +219,7 @@ public class AgentThread
await this._messageStore.DeserializeStateAsync(state!.StoreState.Value, jsonSerializerOptions, cancellationToken).ConfigureAwait(false);
}
- internal class ThreadState
+ internal sealed class ThreadState
{
public string? ConversationId { get; set; }
diff --git a/dotnet/src/Microsoft.Extensions.AI.Agents.Abstractions/InMemoryChatMessageStore.cs b/dotnet/src/Microsoft.Extensions.AI.Agents.Abstractions/InMemoryChatMessageStore.cs
index b535f10081..086a94b9c8 100644
--- a/dotnet/src/Microsoft.Extensions.AI.Agents.Abstractions/InMemoryChatMessageStore.cs
+++ b/dotnet/src/Microsoft.Extensions.AI.Agents.Abstractions/InMemoryChatMessageStore.cs
@@ -12,7 +12,7 @@ namespace Microsoft.Extensions.AI.Agents;
///
/// Represents an in-memory store for chat messages associated with a specific thread.
///
-internal class InMemoryChatMessageStore : IList, IChatMessageStore
+internal sealed class InMemoryChatMessageStore : IList, IChatMessageStore
{
private readonly List _messages = new();
@@ -114,7 +114,7 @@ internal class InMemoryChatMessageStore : IList, IChatMessageStore
IEnumerator IEnumerable.GetEnumerator()
=> this.GetEnumerator();
- internal class StoreState
+ internal sealed class StoreState
{
public IList Messages { get; set; } = new List();
}
diff --git a/dotnet/src/Microsoft.Extensions.AI.Agents/ChatCompletion/ChatClientAgent.cs b/dotnet/src/Microsoft.Extensions.AI.Agents/ChatCompletion/ChatClientAgent.cs
index 472ed7730d..76bb906a8d 100644
--- a/dotnet/src/Microsoft.Extensions.AI.Agents/ChatCompletion/ChatClientAgent.cs
+++ b/dotnet/src/Microsoft.Extensions.AI.Agents/ChatCompletion/ChatClientAgent.cs
@@ -231,7 +231,7 @@ public sealed class ChatClientAgent : AIAgent
// If no request chat options were provided, use the agent's chat options clone.
if (requestChatOptions is null)
{
- return this._agentOptions?.ChatOptions?.Clone();
+ return this._agentOptions?.ChatOptions.Clone();
}
// If both are present, we need to merge them.
diff --git a/dotnet/src/Microsoft.Extensions.AI.Agents/ChatCompletion/ChatClientAgentExtensions.cs b/dotnet/src/Microsoft.Extensions.AI.Agents/ChatCompletion/ChatClientAgentExtensions.cs
index d66a34f546..8dd36477a1 100644
--- a/dotnet/src/Microsoft.Extensions.AI.Agents/ChatCompletion/ChatClientAgentExtensions.cs
+++ b/dotnet/src/Microsoft.Extensions.AI.Agents/ChatCompletion/ChatClientAgentExtensions.cs
@@ -33,7 +33,7 @@ public static class ChatClientAgentExtensions
Throw.IfNull(agent);
Throw.IfNull(messages);
- return agent.RunAsync(messages, thread, new ChatClientAgentRunOptions(agentRunOptions, chatOptions), cancellationToken);
+ return agent.RunAsync(messages, thread, new ChatClientAgentRunOptions(chatOptions), cancellationToken);
}
///
@@ -80,7 +80,7 @@ public static class ChatClientAgentExtensions
Throw.IfNull(agent);
Throw.IfNull(messages);
- return agent.RunStreamingAsync(messages, thread, new ChatClientAgentRunOptions(agentRunOptions, chatOptions), cancellationToken);
+ return agent.RunStreamingAsync(messages, thread, new ChatClientAgentRunOptions(chatOptions), cancellationToken);
}
///
diff --git a/dotnet/src/Microsoft.Extensions.AI.Agents/ChatCompletion/ChatClientAgentOptions.cs b/dotnet/src/Microsoft.Extensions.AI.Agents/ChatCompletion/ChatClientAgentOptions.cs
index 2690539db1..2759523cc2 100644
--- a/dotnet/src/Microsoft.Extensions.AI.Agents/ChatCompletion/ChatClientAgentOptions.cs
+++ b/dotnet/src/Microsoft.Extensions.AI.Agents/ChatCompletion/ChatClientAgentOptions.cs
@@ -53,6 +53,7 @@ public class ChatClientAgentOptions
/// Gets or sets the agent id.
///
public string? Id { get; set; }
+
///
/// Gets or sets the agent name.
///
@@ -77,7 +78,7 @@ public class ChatClientAgentOptions
/// Gets or sets a factory function to create an instance of
/// which will be used to store chat messages for this agent.
///
- public Func? ChatMessageStoreFactory { get; set; } = null;
+ public Func? ChatMessageStoreFactory { get; set; }
///
/// Gets or sets a value indicating whether to use the provided instance as is,
@@ -91,7 +92,7 @@ public class ChatClientAgentOptions
/// than the default ones. The provided instance should then already be decorated
/// with the desired decorators.
///
- public bool UseProvidedChatClientAsIs { get; set; } = false;
+ public bool UseProvidedChatClientAsIs { get; set; }
///
/// Creates a new instance of with the same values as this instance.
diff --git a/dotnet/src/Microsoft.Extensions.AI.Agents/ChatCompletion/ChatClientAgentRunOptions.cs b/dotnet/src/Microsoft.Extensions.AI.Agents/ChatCompletion/ChatClientAgentRunOptions.cs
index e7d13e9b70..7148ea8199 100644
--- a/dotnet/src/Microsoft.Extensions.AI.Agents/ChatCompletion/ChatClientAgentRunOptions.cs
+++ b/dotnet/src/Microsoft.Extensions.AI.Agents/ChatCompletion/ChatClientAgentRunOptions.cs
@@ -12,16 +12,6 @@ public sealed class ChatClientAgentRunOptions : AgentRunOptions
///
/// Optional chat options to pass to the agent's invocation.
public ChatClientAgentRunOptions(ChatOptions? chatOptions = null)
- : this(null, chatOptions)
- {
- }
-
- ///
- /// Initializes a new instance of the class.
- ///
- /// Optional source to clone.
- /// Optional chat options to pass to the agent's invocation.
- internal ChatClientAgentRunOptions(AgentRunOptions? source, ChatOptions? chatOptions = null)
{
this.ChatOptions = chatOptions;
}
diff --git a/dotnet/tests/Microsoft.Extensions.AI.Agents.Abstractions.UnitTests/AIAgentTests.cs b/dotnet/tests/Microsoft.Extensions.AI.Agents.Abstractions.UnitTests/AIAgentTests.cs
index 5456c1b548..411e0bfb7e 100644
--- a/dotnet/tests/Microsoft.Extensions.AI.Agents.Abstractions.UnitTests/AIAgentTests.cs
+++ b/dotnet/tests/Microsoft.Extensions.AI.Agents.Abstractions.UnitTests/AIAgentTests.cs
@@ -1,5 +1,7 @@
// Copyright (c) Microsoft. All rights reserved.
+#pragma warning disable S3717 // Track use of "NotImplementedException"
+
using System;
using System.Collections.Generic;
using System.Linq;
@@ -44,7 +46,7 @@ public class AIAgentTests
this._agentThreadMock.Object,
It.IsAny(),
It.IsAny()))
- .Returns(this._invokeStreamingResponses.ToAsyncEnumerable());
+ .Returns(ToAsyncEnumerableAsync(this._invokeStreamingResponses));
}
///
@@ -370,7 +372,7 @@ public class AIAgentTests
AgentRunOptions? options = null,
CancellationToken cancellationToken = default)
{
- throw new System.NotImplementedException();
+ throw new NotImplementedException();
}
public override IAsyncEnumerable RunStreamingAsync(
@@ -379,7 +381,16 @@ public class AIAgentTests
AgentRunOptions? options = null,
CancellationToken cancellationToken = default)
{
- throw new System.NotImplementedException();
+ throw new NotImplementedException();
+ }
+ }
+
+ private static async IAsyncEnumerable ToAsyncEnumerableAsync(IEnumerable values)
+ {
+ await Task.Yield();
+ foreach (var update in values)
+ {
+ yield return update;
}
}
}
diff --git a/dotnet/tests/Microsoft.Extensions.AI.Agents.Abstractions.UnitTests/AgentRunResponseTests.cs b/dotnet/tests/Microsoft.Extensions.AI.Agents.Abstractions.UnitTests/AgentRunResponseTests.cs
index 46610d7138..b83050b620 100644
--- a/dotnet/tests/Microsoft.Extensions.AI.Agents.Abstractions.UnitTests/AgentRunResponseTests.cs
+++ b/dotnet/tests/Microsoft.Extensions.AI.Agents.Abstractions.UnitTests/AgentRunResponseTests.cs
@@ -259,7 +259,7 @@ public class AgentRunResponseTests
var response = new AgentRunResponse(new ChatMessage(ChatRole.Assistant, JsonSerializer.Serialize(expectedResult, TestJsonSerializerContext.Default.Animal)));
// Act.
- var animal = response.Deserialize(TestJsonSerializerContext.Default.Options);
+ response.TryDeserialize(TestJsonSerializerContext.Default.Options, out Animal? animal);
// Assert.
Assert.NotNull(animal);
diff --git a/dotnet/tests/Microsoft.Extensions.AI.Agents.Abstractions.UnitTests/AgentRunResponseUpdateExtensionsTests.cs b/dotnet/tests/Microsoft.Extensions.AI.Agents.Abstractions.UnitTests/AgentRunResponseUpdateExtensionsTests.cs
index 041bc201b2..a5e5cb097e 100644
--- a/dotnet/tests/Microsoft.Extensions.AI.Agents.Abstractions.UnitTests/AgentRunResponseUpdateExtensionsTests.cs
+++ b/dotnet/tests/Microsoft.Extensions.AI.Agents.Abstractions.UnitTests/AgentRunResponseUpdateExtensionsTests.cs
@@ -10,6 +10,26 @@ namespace Microsoft.Extensions.AI.Agents.Abstractions.UnitTests;
public class AgentRunResponseUpdateExtensionsTests
{
+ public static IEnumerable