Further fixes for compatibility with Microsoft.Extensions repo. (#555)

This commit is contained in:
westey
2025-08-29 16:43:16 +01:00
committed by GitHub
Unverified
parent 0acc18805a
commit 1ed46e41a7
14 changed files with 127 additions and 135 deletions
@@ -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; }
@@ -12,7 +12,7 @@ namespace Microsoft.Extensions.AI.Agents;
/// <summary>
/// Represents an in-memory store for chat messages associated with a specific thread.
/// </summary>
internal class InMemoryChatMessageStore : IList<ChatMessage>, IChatMessageStore
internal sealed class InMemoryChatMessageStore : IList<ChatMessage>, IChatMessageStore
{
private readonly List<ChatMessage> _messages = new();
@@ -114,7 +114,7 @@ internal class InMemoryChatMessageStore : IList<ChatMessage>, IChatMessageStore
IEnumerator IEnumerable.GetEnumerator()
=> this.GetEnumerator();
internal class StoreState
internal sealed class StoreState
{
public IList<ChatMessage> Messages { get; set; } = new List<ChatMessage>();
}
@@ -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.
@@ -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);
}
/// <summary>
@@ -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);
}
/// <summary>
@@ -53,6 +53,7 @@ public class ChatClientAgentOptions
/// Gets or sets the agent id.
/// </summary>
public string? Id { get; set; }
/// <summary>
/// Gets or sets the agent name.
/// </summary>
@@ -77,7 +78,7 @@ public class ChatClientAgentOptions
/// Gets or sets a factory function to create an instance of <see cref="IChatMessageStore"/>
/// which will be used to store chat messages for this agent.
/// </summary>
public Func<IChatMessageStore>? ChatMessageStoreFactory { get; set; } = null;
public Func<IChatMessageStore>? ChatMessageStoreFactory { get; set; }
/// <summary>
/// Gets or sets a value indicating whether to use the provided <see cref="IChatClient"/> instance as is,
@@ -91,7 +92,7 @@ public class ChatClientAgentOptions
/// than the default ones. The provided <see cref="IChatClient"/> instance should then already be decorated
/// with the desired decorators.
/// </remarks>
public bool UseProvidedChatClientAsIs { get; set; } = false;
public bool UseProvidedChatClientAsIs { get; set; }
/// <summary>
/// Creates a new instance of <see cref="ChatClientAgentOptions"/> with the same values as this instance.
@@ -12,16 +12,6 @@ public sealed class ChatClientAgentRunOptions : AgentRunOptions
/// </summary>
/// <param name="chatOptions">Optional chat options to pass to the agent's invocation.</param>
public ChatClientAgentRunOptions(ChatOptions? chatOptions = null)
: this(null, chatOptions)
{
}
/// <summary>
/// Initializes a new instance of the <see cref="ChatClientAgentRunOptions"/> class.
/// </summary>
/// <param name="source">Optional source <see cref="AgentRunOptions"/> to clone.</param>
/// <param name="chatOptions">Optional chat options to pass to the agent's invocation.</param>
internal ChatClientAgentRunOptions(AgentRunOptions? source, ChatOptions? chatOptions = null)
{
this.ChatOptions = chatOptions;
}
@@ -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<AgentRunOptions?>(),
It.IsAny<CancellationToken>()))
.Returns(this._invokeStreamingResponses.ToAsyncEnumerable());
.Returns(ToAsyncEnumerableAsync(this._invokeStreamingResponses));
}
/// <summary>
@@ -370,7 +372,7 @@ public class AIAgentTests
AgentRunOptions? options = null,
CancellationToken cancellationToken = default)
{
throw new System.NotImplementedException();
throw new NotImplementedException();
}
public override IAsyncEnumerable<AgentRunResponseUpdate> 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<T> ToAsyncEnumerableAsync<T>(IEnumerable<T> values)
{
await Task.Yield();
foreach (var update in values)
{
yield return update;
}
}
}
@@ -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<Animal>(TestJsonSerializerContext.Default.Options);
response.TryDeserialize<Animal>(TestJsonSerializerContext.Default.Options, out Animal? animal);
// Assert.
Assert.NotNull(animal);
@@ -10,6 +10,26 @@ namespace Microsoft.Extensions.AI.Agents.Abstractions.UnitTests;
public class AgentRunResponseUpdateExtensionsTests
{
public static IEnumerable<object[]> ToAgentRunResponseCoalescesVariousSequenceAndGapLengthsMemberData()
{
foreach (bool useAsync in new[] { false, true })
{
for (int numSequences = 1; numSequences <= 3; numSequences++)
{
for (int sequenceLength = 1; sequenceLength <= 3; sequenceLength++)
{
for (int gapLength = 1; gapLength <= 3; gapLength++)
{
foreach (bool gapBeginningEnd in new[] { false, true })
{
yield return new object[] { useAsync, numSequences, sequenceLength, gapLength, false };
}
}
}
}
}
}
[Fact]
public void ToAgentRunResponseWithInvalidArgsThrows()
{
@@ -59,26 +79,6 @@ public class AgentRunResponseUpdateExtensionsTests
Assert.Equal("Hello, world!", response.Text);
}
public static IEnumerable<object[]> ToAgentRunResponseCoalescesVariousSequenceAndGapLengthsMemberData()
{
foreach (bool useAsync in new[] { false, true })
{
for (int numSequences = 1; numSequences <= 3; numSequences++)
{
for (int sequenceLength = 1; sequenceLength <= 3; sequenceLength++)
{
for (int gapLength = 1; gapLength <= 3; gapLength++)
{
foreach (bool gapBeginningEnd in new[] { false, true })
{
yield return new object[] { useAsync, numSequences, sequenceLength, gapLength, false };
}
}
}
}
}
}
[Theory]
[MemberData(nameof(ToAgentRunResponseCoalescesVariousSequenceAndGapLengthsMemberData))]
public async Task ToAgentRunResponseCoalescesVariousSequenceAndGapLengthsAsync(bool useAsync, int numSequences, int sequenceLength, int gapLength, bool gapBeginningEnd)
@@ -97,7 +97,7 @@ public class AgentThreadTests
var thread = new AgentThread();
// Act
var messages = await thread.GetMessagesAsync(CancellationToken.None).ToListAsync();
var messages = await ToListAsync(thread.GetMessagesAsync(CancellationToken.None));
// Assert
Assert.Empty(messages);
@@ -107,10 +107,10 @@ public class AgentThreadTests
public async Task GetMessagesAsyncReturnsEmptyListWhenAgentServiceIdAsync()
{
// Arrange
var thread = new AgentThread() { ConversationId = "thread-123" };
var thread = new AgentThread { ConversationId = "thread-123" };
// Act
var messages = await thread.GetMessagesAsync(CancellationToken.None).ToListAsync();
var messages = await ToListAsync(thread.GetMessagesAsync(CancellationToken.None));
// Assert
Assert.Empty(messages);
@@ -125,10 +125,10 @@ public class AgentThreadTests
new ChatMessage(ChatRole.User, "Hello"),
new ChatMessage(ChatRole.Assistant, "Hi there!")
};
var thread = new AgentThread() { MessageStore = store };
var thread = new AgentThread { MessageStore = store };
// Act
var messages = await thread.GetMessagesAsync(CancellationToken.None).ToListAsync();
var messages = await ToListAsync(thread.GetMessagesAsync(CancellationToken.None));
// Assert
Assert.Equal(2, messages.Count);
@@ -144,7 +144,7 @@ public class AgentThreadTests
public async Task OnNewMessagesAsyncDoesNothingWhenAgentServiceIdAsync()
{
// Arrange
var thread = new AgentThread() { ConversationId = "thread-123" };
var thread = new AgentThread { ConversationId = "thread-123" };
var messages = new List<ChatMessage>
{
new(ChatRole.User, "Hello"),
@@ -162,7 +162,7 @@ public class AgentThreadTests
{
// Arrange
var store = new InMemoryChatMessageStore();
var thread = new AgentThread() { MessageStore = store };
var thread = new AgentThread { MessageStore = store };
var messages = new List<ChatMessage>
{
new(ChatRole.User, "Hello"),
@@ -187,12 +187,12 @@ public class AgentThreadTests
{
// Arrange
var chatMessageStore = new InMemoryChatMessageStore();
var json = JsonSerializer.Deserialize<JsonElement>("""
var json = JsonSerializer.Deserialize("""
{
"storeState": { "messages": [{"authorName": "testAuthor"}] }
}
""");
var thread = new AgentThread() { MessageStore = chatMessageStore };
""", TestJsonSerializerContext.Default.JsonElement);
var thread = new AgentThread { MessageStore = chatMessageStore };
// Act.
await thread.DeserializeAsync(json);
@@ -208,11 +208,11 @@ public class AgentThreadTests
public async Task VerifyDeserializeWithIdAsync()
{
// Arrange
var json = JsonSerializer.Deserialize<JsonElement>("""
var json = JsonSerializer.Deserialize("""
{
"conversationId": "TestConvId"
}
""");
""", TestJsonSerializerContext.Default.JsonElement);
var thread = new AgentThread();
// Act
@@ -227,7 +227,7 @@ public class AgentThreadTests
public async Task DeserializeWithInvalidJsonThrowsAsync()
{
// Arrange
var invalidJson = JsonSerializer.Deserialize<JsonElement>("[42]");
var invalidJson = JsonSerializer.Deserialize("[42]", TestJsonSerializerContext.Default.JsonElement);
var thread = new AgentThread();
// Act & Assert
@@ -245,7 +245,7 @@ public class AgentThreadTests
public async Task VerifyThreadSerializationWithIdAsync()
{
// Arrange
var thread = new AgentThread() { ConversationId = "TestConvId" };
var thread = new AgentThread { ConversationId = "TestConvId" };
// Act
var json = await thread.SerializeAsync();
@@ -268,7 +268,7 @@ public class AgentThreadTests
// Arrange
var store = new InMemoryChatMessageStore();
store.Add(new ChatMessage(ChatRole.User, "TestContent") { AuthorName = "TestAuthor" });
var thread = new AgentThread() { MessageStore = store };
var thread = new AgentThread { MessageStore = store };
// Act
var json = await thread.SerializeAsync();
@@ -306,7 +306,9 @@ public class AgentThreadTests
JsonSerializerOptions options = new() { PropertyNamingPolicy = JsonNamingPolicy.SnakeCaseLower };
options.TypeInfoResolverChain.Add(AgentAbstractionsJsonUtilities.DefaultOptions.TypeInfoResolver!);
var storeStateElement = JsonSerializer.SerializeToElement(new { Key = "TestValue" });
var storeStateElement = JsonSerializer.SerializeToElement(
new Dictionary<string, object> { ["Key"] = "TestValue" },
TestJsonSerializerContext.Default.DictionaryStringObject);
var messageStoreMock = new Mock<IChatMessageStore>();
messageStoreMock
@@ -332,4 +334,15 @@ public class AgentThreadTests
}
#endregion Serialize Tests
private static async Task<List<T>> ToListAsync<T>(IAsyncEnumerable<T> values)
{
var result = new List<T>();
await foreach (var v in values)
{
result.Add(v);
}
return result;
}
}
@@ -62,7 +62,7 @@ public class InMemoryChatMessageStoreTests
{
var newStore = new InMemoryChatMessageStore();
var emptyObject = JsonSerializer.Deserialize<JsonElement>("{}");
var emptyObject = JsonSerializer.Deserialize<JsonElement>("{}", TestJsonSerializerContext.Default.JsonElement);
await newStore.DeserializeStateAsync(emptyObject);
@@ -129,7 +129,9 @@ public class InMemoryChatMessageStoreTests
{
// Arrange
var store = new InMemoryChatMessageStore();
var stateWithEmptyMessages = JsonSerializer.SerializeToElement(new { Messages = new List<ChatMessage>() });
var stateWithEmptyMessages = JsonSerializer.SerializeToElement(
new Dictionary<string, object> { ["Messages"] = new List<ChatMessage>() },
TestJsonSerializerContext.Default.IDictionaryStringObject);
// Act
await store.DeserializeStateAsync(stateWithEmptyMessages);
@@ -143,7 +145,9 @@ public class InMemoryChatMessageStoreTests
{
// Arrange
var store = new InMemoryChatMessageStore();
var stateWithNullMessages = JsonSerializer.SerializeToElement(new { Messages = (List<ChatMessage>?)null });
var stateWithNullMessages = JsonSerializer.SerializeToElement(
new Dictionary<string, object> { ["Messages"] = null! },
TestJsonSerializerContext.Default.DictionaryStringObject);
// Act
await store.DeserializeStateAsync(stateWithNullMessages);
@@ -162,8 +166,10 @@ public class InMemoryChatMessageStoreTests
new(ChatRole.User, "User message"),
new(ChatRole.Assistant, "Assistant message")
};
var state = new { Messages = messages };
var serializedState = JsonSerializer.SerializeToElement(state);
var state = new Dictionary<string, object> { ["Messages"] = messages };
var serializedState = JsonSerializer.SerializeToElement(
state,
TestJsonSerializerContext.Default.DictionaryStringObject);
// Act
await store.DeserializeStateAsync(serializedState);
@@ -1,5 +1,7 @@
// Copyright (c) Microsoft. All rights reserved.
using System.Collections.Generic;
using System.Text.Json;
using System.Text.Json.Serialization;
using Microsoft.Extensions.AI.Agents.Abstractions.UnitTests.Models;
@@ -13,4 +15,6 @@ namespace Microsoft.Extensions.AI.Agents.Abstractions.UnitTests;
[JsonSerializable(typeof(AgentRunResponseUpdate))]
[JsonSerializable(typeof(AgentRunOptions))]
[JsonSerializable(typeof(Animal))]
[JsonSerializable(typeof(JsonElement))]
[JsonSerializable(typeof(Dictionary<string, object?>))]
internal sealed partial class TestJsonSerializerContext : JsonSerializerContext;
@@ -5,10 +5,10 @@ namespace Microsoft.Extensions.AI.Agents.UnitTests.ChatCompletion;
public class ChatClientAgentRunOptionsTests
{
/// <summary>
/// Verify that ChatClientAgentRunOptions constructor works with null source and null chatOptions.
/// Verify that ChatClientAgentRunOptions constructor works with null chatOptions.
/// </summary>
[Fact]
public void ConstructorWorksWithNullSourceAndNullChatOptions()
public void ConstructorWorksWithNullChatOptions()
{
// Act
var runOptions = new ChatClientAgentRunOptions();
@@ -17,55 +17,6 @@ public class ChatClientAgentRunOptionsTests
Assert.Null(runOptions.ChatOptions);
}
/// <summary>
/// Verify that ChatClientAgentRunOptions constructor works with null source and provided chatOptions.
/// </summary>
[Fact]
public void ConstructorWorksWithNullSourceAndProvidedChatOptions()
{
// Arrange
var chatOptions = new ChatOptions { MaxOutputTokens = 100 };
// Act
var runOptions = new ChatClientAgentRunOptions(null, chatOptions);
// Assert
Assert.Same(chatOptions, runOptions.ChatOptions);
}
/// <summary>
/// Verify that ChatClientAgentRunOptions constructor copies properties from source AgentRunOptions.
/// </summary>
[Fact]
public void ConstructorCopiesPropertiesFromSourceAgentRunOptions()
{
// Arrange
var sourceRunOptions = new AgentRunOptions();
var chatOptions = new ChatOptions { MaxOutputTokens = 200 };
// Act
var runOptions = new ChatClientAgentRunOptions(sourceRunOptions, chatOptions);
// Assert
Assert.Same(chatOptions, runOptions.ChatOptions);
}
/// <summary>
/// Verify that ChatClientAgentRunOptions constructor works with source but null chatOptions.
/// </summary>
[Fact]
public void ConstructorWorksWithSourceButNullChatOptions()
{
// Arrange
var sourceRunOptions = new AgentRunOptions();
// Act
var runOptions = new ChatClientAgentRunOptions(sourceRunOptions, null);
// Assert
Assert.Null(runOptions.ChatOptions);
}
/// <summary>
/// Verify that ChatClientAgentRunOptions ChatOptions property is set and mutable.
/// </summary>
@@ -74,7 +25,7 @@ public class ChatClientAgentRunOptionsTests
{
// Arrange
var chatOptions = new ChatOptions { MaxOutputTokens = 100 };
var runOptions = new ChatClientAgentRunOptions(null, chatOptions);
var runOptions = new ChatClientAgentRunOptions(chatOptions);
chatOptions.MaxOutputTokens = 200; // Change the property to verify mutability
// Act & Assert
@@ -2,7 +2,6 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using Moq;
@@ -114,7 +113,7 @@ public class ChatClientAgentTests
ChatClientAgent agent = new(mockService.Object, options: new() { Instructions = "test instructions" });
// Act
await agent.RunAsync([new(ChatRole.User, "test")], chatOptions: chatOptions);
await agent.RunAsync([new(ChatRole.User, "test")], options: new ChatClientAgentRunOptions(chatOptions));
// Assert
mockService.Verify(
@@ -320,7 +319,7 @@ public class ChatClientAgentTests
AgentThread thread = new() { ConversationId = "ConvId" };
// Act & Assert
var response = await agent.RunAsync([new(ChatRole.User, "test")], thread, chatOptions: chatOptions);
var response = await agent.RunAsync([new(ChatRole.User, "test")], thread, options: new ChatClientAgentRunOptions(chatOptions));
Assert.NotNull(response);
}
@@ -340,7 +339,7 @@ public class ChatClientAgentTests
AgentThread thread = new() { ConversationId = "ThreadId" };
// Act & Assert
await Assert.ThrowsAsync<InvalidOperationException>(() => agent.RunAsync([new(ChatRole.User, "test")], thread, chatOptions: chatOptions));
await Assert.ThrowsAsync<InvalidOperationException>(() => agent.RunAsync([new(ChatRole.User, "test")], thread, options: new ChatClientAgentRunOptions(chatOptions)));
}
/// <summary>
@@ -363,7 +362,7 @@ public class ChatClientAgentTests
AgentThread thread = new() { ConversationId = "ConvId" };
// Act
await agent.RunAsync([new(ChatRole.User, "test")], thread, chatOptions: chatOptions);
await agent.RunAsync([new(ChatRole.User, "test")], thread, options: new ChatClientAgentRunOptions(chatOptions));
// Assert
Assert.Null(chatOptions.ConversationId);
@@ -757,7 +756,7 @@ public class ChatClientAgentTests
var messages = new List<ChatMessage> { new(ChatRole.User, "test") };
// Act
await agent.RunAsync(messages, chatOptions: requestChatOptions);
await agent.RunAsync(messages, options: new ChatClientAgentRunOptions(requestChatOptions));
// Assert
Assert.NotNull(capturedChatOptions);
@@ -780,21 +779,21 @@ public class ChatClientAgentTests
Temperature = 0.7f,
TopP = 0.9f,
ModelId = "agent-model",
AdditionalProperties = new AdditionalPropertiesDictionary() { ["key"] = "agent-value" }
AdditionalProperties = new AdditionalPropertiesDictionary { ["key"] = "agent-value" }
};
var requestChatOptions = new ChatOptions
{
// TopP and ModelId not set, should use agent values
MaxOutputTokens = 200,
Temperature = 0.3f,
AdditionalProperties = new AdditionalPropertiesDictionary() { ["key"] = "request-value" },
AdditionalProperties = new AdditionalPropertiesDictionary { ["key"] = "request-value" },
Instructions = "request instructions"
// TopP and ModelId not set, should use agent values
};
var expectedChatOptionsMerge = new ChatOptions
{
MaxOutputTokens = 200, // Request value takes priority
Temperature = 0.3f, // Request value takes priority
AdditionalProperties = new AdditionalPropertiesDictionary() { ["key"] = "request-value" }, // Request value takes priority
AdditionalProperties = new AdditionalPropertiesDictionary { ["key"] = "request-value" }, // Request value takes priority
TopP = 0.9f, // Agent value used when request doesn't specify
ModelId = "agent-model", // Agent value used when request doesn't specify
Instructions = "test instructions\nrequest instructions" // Request is in addition to agent instructions
@@ -819,7 +818,7 @@ public class ChatClientAgentTests
var messages = new List<ChatMessage> { new(ChatRole.User, "test") };
// Act
await agent.RunAsync(messages, chatOptions: requestChatOptions);
await agent.RunAsync(messages, options: new ChatClientAgentRunOptions(requestChatOptions));
// Assert
Assert.NotNull(capturedChatOptions);
@@ -898,12 +897,13 @@ public class ChatClientAgentTests
var messages = new List<ChatMessage> { new(ChatRole.User, "test") };
// Act
await agent.RunAsync(messages, chatOptions: requestChatOptions);
await agent.RunAsync(messages, options: new ChatClientAgentRunOptions(requestChatOptions));
// Assert
Assert.NotNull(capturedChatOptions);
Assert.NotNull(capturedChatOptions.Tools);
Assert.Equal(2, capturedChatOptions.Tools.Count);
// Request tools should come first, then agent tools
Assert.Contains(requestTool, capturedChatOptions.Tools);
Assert.Contains(agentTool, capturedChatOptions.Tools);
@@ -924,8 +924,8 @@ public class ChatClientAgentTests
};
var requestChatOptions = new ChatOptions
{
MaxOutputTokens = 100
// No Tools specified
MaxOutputTokens = 100
};
Mock<IChatClient> mockService = new();
@@ -947,7 +947,7 @@ public class ChatClientAgentTests
var messages = new List<ChatMessage> { new(ChatRole.User, "test") };
// Act
await agent.RunAsync(messages, chatOptions: requestChatOptions);
await agent.RunAsync(messages, options: new ChatClientAgentRunOptions(requestChatOptions));
// Assert
Assert.NotNull(capturedChatOptions);
@@ -994,7 +994,7 @@ public class ChatClientAgentTests
var messages = new List<ChatMessage> { new(ChatRole.User, "test") };
// Act
await agent.RunAsync(messages, chatOptions: requestChatOptions);
await agent.RunAsync(messages, options: new ChatClientAgentRunOptions(requestChatOptions));
// Assert
Assert.NotNull(capturedChatOptions);
@@ -1029,6 +1029,7 @@ public class ChatClientAgentTests
MaxOutputTokens = 200,
Temperature = 0.3f,
Instructions = "request instructions",
// Other properties not set, should use agent values
StopSequences = ["request-stop"]
};
@@ -1072,7 +1073,7 @@ public class ChatClientAgentTests
var messages = new List<ChatMessage> { new(ChatRole.User, "test") };
// Act
await agent.RunAsync(messages, chatOptions: requestChatOptions);
await agent.RunAsync(messages, options: new ChatClientAgentRunOptions(requestChatOptions));
// Assert
Assert.NotNull(capturedChatOptions);
@@ -1148,6 +1149,7 @@ public class ChatClientAgentTests
// Assert
Assert.NotNull(result);
Assert.IsAssignableFrom<IChatClient>(result);
// Note: The result will be the AgentInvokedChatClient wrapper, not the original mock
Assert.Equal("AgentInvokedChatClient", result.GetType().Name);
}
@@ -1490,7 +1492,7 @@ public class ChatClientAgentTests
s => s.GetStreamingResponseAsync(
It.IsAny<IEnumerable<ChatMessage>>(),
It.IsAny<ChatOptions>(),
It.IsAny<CancellationToken>())).Returns(returnUpdates.ToAsyncEnumerable());
It.IsAny<CancellationToken>())).Returns(ToAsyncEnumerableAsync(returnUpdates));
ChatClientAgent agent =
new(mockService.Object, options: new()
@@ -1499,10 +1501,15 @@ public class ChatClientAgentTests
});
// Act
var result = await agent.RunStreamingAsync([new ChatMessage(ChatRole.User, "Hello")]).ToArrayAsync();
var updates = agent.RunStreamingAsync([new ChatMessage(ChatRole.User, "Hello")]);
List<AgentRunResponseUpdate> result = [];
await foreach (var update in updates)
{
result.Add(update);
}
// Assert
Assert.Equal(2, result.Length);
Assert.Equal(2, result.Count);
Assert.Equal("wh", result[0].Text);
Assert.Equal("at?", result[1].Text);
@@ -1516,4 +1523,13 @@ public class ChatClientAgentTests
}
#endregion
private static async IAsyncEnumerable<T> ToAsyncEnumerableAsync<T>(IEnumerable<T> values)
{
await Task.Yield();
foreach (var update in values)
{
yield return update;
}
}
}