Skip to content

.Net: Add conformance tests for checking messages passed to thread. #11332

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Draft
wants to merge 2 commits into
base: main
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion dotnet/src/Agents/AzureAI/AzureAIAgentThread.cs
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ namespace Microsoft.SemanticKernel.Agents.AzureAI;
/// <summary>
/// Represents a conversation thread for an Azure AI agent.
/// </summary>
public sealed class AzureAIAgentThread : AgentThread
public class AzureAIAgentThread : AgentThread
{
private readonly AgentsClient _client;
private readonly IEnumerable<ThreadMessageOptions>? _messages;
Expand Down
2 changes: 1 addition & 1 deletion dotnet/src/Agents/Bedrock/BedrockAgentThread.cs
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ namespace Microsoft.SemanticKernel.Agents.Bedrock;
/// <summary>
/// Represents a conversation thread for a Bedrock agent.
/// </summary>
public sealed class BedrockAgentThread : AgentThread
public class BedrockAgentThread : AgentThread
{
private readonly AmazonBedrockAgentRuntimeClient _runtimeClient;

Expand Down
2 changes: 1 addition & 1 deletion dotnet/src/Agents/Core/ChatHistoryAgentThread.cs
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ namespace Microsoft.SemanticKernel.Agents;
/// <summary>
/// Represents a conversation thread based on an instance of <see cref="ChatHistory"/> that is maanged inside this class.
/// </summary>
public sealed class ChatHistoryAgentThread : AgentThread
public class ChatHistoryAgentThread : AgentThread
{
private readonly ChatHistory _chatHistory = new();

Expand Down
2 changes: 1 addition & 1 deletion dotnet/src/Agents/OpenAI/OpenAIAssistantAgentThread.cs
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ namespace Microsoft.SemanticKernel.Agents.OpenAI;
/// <summary>
/// Represents a conversation thread for an Open AI Assistant agent.
/// </summary>
public sealed class OpenAIAssistantAgentThread : AgentThread
public class OpenAIAssistantAgentThread : AgentThread
{
private readonly bool _useThreadConstructorExtension = false;
private readonly AssistantClient _client;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@
using System.Threading.Tasks;
using Microsoft.SemanticKernel.Agents;
using Microsoft.SemanticKernel.ChatCompletion;
using Moq;
using SemanticKernel.IntegrationTests.Agents.CommonInterfaceConformance.AgentThreadMocks;
using Xunit;

namespace SemanticKernel.IntegrationTests.Agents.CommonInterfaceConformance;
Expand All @@ -19,6 +21,10 @@ public abstract class AgentFixture : IAsyncLifetime

public abstract AgentThread CreatedAgentThread { get; }

public abstract AgentThread MockCreatedAgentThread { get; }

public abstract Mock<IMessageMockableAgentThread> MockableMessageCreatedAgentThread { get; }

public abstract AgentThread ServiceFailingAgentThread { get; }

public abstract AgentThread CreatedServiceFailingAgentThread { get; }
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
// Copyright (c) Microsoft. All rights reserved.

using System.Threading;
using Microsoft.SemanticKernel;
using Microsoft.SemanticKernel.Agents;

namespace SemanticKernel.IntegrationTests.Agents.CommonInterfaceConformance.AgentThreadMocks;

/// <summary>
/// Interface for mocking <see cref="AgentThread"/> objects in a way that we can check messages sent to the thread.
/// </summary>
public interface IMessageMockableAgentThread
{
void MockableOnNewMessage(ChatMessageContent newMessage, CancellationToken cancellationToken = default);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
// Copyright (c) Microsoft. All rights reserved.

using System.Threading;
using System.Threading.Tasks;
using Azure.AI.Projects;
using Microsoft.SemanticKernel;
using Microsoft.SemanticKernel.Agents.AzureAI;

namespace SemanticKernel.IntegrationTests.Agents.CommonInterfaceConformance.AgentThreadMocks;

/// <summary>
/// Mock implementation of <see cref="AzureAIAgentThread"/> to allow
/// checking of messages received.
/// </summary>
public class MockAzureAIAgentThread(AgentsClient client, string id) : AzureAIAgentThread(client, id), IMessageMockableAgentThread
{
protected override Task OnNewMessageInternalAsync(ChatMessageContent newMessage, CancellationToken cancellationToken = default)
{
this.MockableOnNewMessage(newMessage, cancellationToken);
return base.OnNewMessageInternalAsync(newMessage, cancellationToken);
}

public virtual void MockableOnNewMessage(ChatMessageContent newMessage, CancellationToken cancellationToken = default)
{
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
// Copyright (c) Microsoft. All rights reserved.

using System.Threading;
using System.Threading.Tasks;
using Amazon.BedrockAgentRuntime;
using Microsoft.SemanticKernel;
using Microsoft.SemanticKernel.Agents.Bedrock;

namespace SemanticKernel.IntegrationTests.Agents.CommonInterfaceConformance.AgentThreadMocks;

/// <summary>
/// Mock implementation of <see cref="BedrockAgentThread"/> to allow
/// checking of messages received.
/// </summary>
public class MockBedrockAgentThread(AmazonBedrockAgentRuntimeClient client, string id) : BedrockAgentThread(client, id), IMessageMockableAgentThread
{
protected override Task OnNewMessageInternalAsync(ChatMessageContent newMessage, CancellationToken cancellationToken = default)
{
this.MockableOnNewMessage(newMessage, cancellationToken);
return base.OnNewMessageInternalAsync(newMessage, cancellationToken);
}

public virtual void MockableOnNewMessage(ChatMessageContent newMessage, CancellationToken cancellationToken = default)
{
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
// Copyright (c) Microsoft. All rights reserved.

using System.Threading;
using System.Threading.Tasks;
using Microsoft.SemanticKernel;
using Microsoft.SemanticKernel.Agents;

namespace SemanticKernel.IntegrationTests.Agents.CommonInterfaceConformance.AgentThreadMocks;

/// <summary>
/// Mock implementation of <see cref="ChatHistoryAgentThread"/> to allow
/// checking of messages received.
/// </summary>
public class MockChatHistoryAgentThread : ChatHistoryAgentThread, IMessageMockableAgentThread
{
protected override Task OnNewMessageInternalAsync(ChatMessageContent newMessage, CancellationToken cancellationToken = default)
{
this.MockableOnNewMessage(newMessage, cancellationToken);
return base.OnNewMessageInternalAsync(newMessage, cancellationToken);
}

public virtual void MockableOnNewMessage(ChatMessageContent newMessage, CancellationToken cancellationToken = default)
{
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
// Copyright (c) Microsoft. All rights reserved.

using System.Threading;
using System.Threading.Tasks;
using Microsoft.SemanticKernel;
using Microsoft.SemanticKernel.Agents.OpenAI;
using OpenAI.Assistants;

namespace SemanticKernel.IntegrationTests.Agents.CommonInterfaceConformance.AgentThreadMocks;

/// <summary>
/// Mock implementation of <see cref="OpenAIAssistantAgentThread"/> to allow
/// checking of messages received.
/// </summary>
public class MockOpenAIAssistantAgentThread(AssistantClient client, string id) : OpenAIAssistantAgentThread(client, id), IMessageMockableAgentThread
{
protected override Task OnNewMessageInternalAsync(ChatMessageContent newMessage, CancellationToken cancellationToken = default)
{
this.MockableOnNewMessage(newMessage, cancellationToken);
return base.OnNewMessageInternalAsync(newMessage, cancellationToken);
}

public virtual void MockableOnNewMessage(ChatMessageContent newMessage, CancellationToken cancellationToken = default)
{
}
}
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
// Copyright (c) Microsoft. All rights reserved.

using System.Threading;
using System.Threading.Tasks;
using Azure;
using Azure.Identity;
Expand All @@ -8,6 +9,8 @@
using Microsoft.SemanticKernel.Agents;
using Microsoft.SemanticKernel.Agents.AzureAI;
using Microsoft.SemanticKernel.ChatCompletion;
using Moq;
using SemanticKernel.IntegrationTests.Agents.CommonInterfaceConformance.AgentThreadMocks;
using SemanticKernel.IntegrationTests.TestSettings;
using AAIP = Azure.AI.Projects;

Expand All @@ -27,15 +30,22 @@ public class AzureAIAgentFixture : AgentFixture
private AzureAIAgent? _agent;
private AzureAIAgentThread? _thread;
private AzureAIAgentThread? _createdThread;
private Mock<MockAzureAIAgentThread>? _mockCreatedAgentThread;
private AzureAIAgentThread? _serviceFailingAgentThread;
private AzureAIAgentThread? _createdServiceFailingAgentThread;

public AAIP.AgentsClient AgentsClient => this._agentsClient!;

public override Agent Agent => this._agent!;

public override AgentThread AgentThread => this._thread!;

public override AgentThread CreatedAgentThread => this._createdThread!;

public override AgentThread MockCreatedAgentThread => this._mockCreatedAgentThread!.Object;

public override Mock<IMessageMockableAgentThread> MockableMessageCreatedAgentThread => this._mockCreatedAgentThread!.As<IMessageMockableAgentThread>();

public override AgentThread ServiceFailingAgentThread => this._serviceFailingAgentThread!;

public override AgentThread CreatedServiceFailingAgentThread => this._createdServiceFailingAgentThread!;
Expand Down Expand Up @@ -109,6 +119,9 @@ await this._agentsClient.CreateAgentAsync(
this._createdThread = new AzureAIAgentThread(this._agentsClient);
await this._createdThread.CreateAsync();

this._mockCreatedAgentThread = new Mock<MockAzureAIAgentThread>(this._agentsClient, this._createdThread.Id) { CallBase = true };
this._mockCreatedAgentThread.Setup(x => x.MockableOnNewMessage(It.IsAny<ChatMessageContent>(), It.IsAny<CancellationToken>()));

var serviceFailingClient = AzureAIAgent.CreateAzureAIClient("swedencentral.api.azureml.ms;<subscription_id>;<resource_group_name>;<project_name>", new AzureCliCredential());
this._serviceFailingAgentThread = new AzureAIAgentThread(serviceFailingClient.GetAgentsClient());

Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
// Copyright (c) Microsoft. All rights reserved.

using System;
using System.Threading;
using System.Threading.Tasks;
using Amazon.BedrockAgent;
using Amazon.BedrockAgent.Model;
Expand All @@ -13,12 +14,14 @@
using Microsoft.SemanticKernel.Agents;
using Microsoft.SemanticKernel.Agents.Bedrock;
using Microsoft.SemanticKernel.ChatCompletion;
using Moq;
using SemanticKernel.IntegrationTests.Agents.CommonInterfaceConformance.AgentThreadMocks;
using SemanticKernel.IntegrationTests.TestSettings;
using Xunit;

namespace SemanticKernel.IntegrationTests.Agents.CommonInterfaceConformance;

internal sealed class BedrockAgentFixture : AgentFixture, IAsyncDisposable
public sealed class BedrockAgentFixture : AgentFixture, IAsyncDisposable
{
private readonly IConfigurationRoot _configuration = new ConfigurationBuilder()
.AddJsonFile(path: "testsettings.json", optional: true, reloadOnChange: true)
Expand All @@ -31,18 +34,25 @@ internal sealed class BedrockAgentFixture : AgentFixture, IAsyncDisposable
private BedrockAgent? _agent;
private BedrockAgentThread? _thread;
private BedrockAgentThread? _createdThread;
private Mock<MockBedrockAgentThread>? _mockCreatedAgentThread;
private BedrockAgentThread? _serviceFailingAgentThread;
private BedrockAgentThread? _createdServiceFailingAgentThread;
private AmazonBedrockAgentRuntimeClient? _serviceFailingAgentClient;
private readonly AmazonBedrockAgentClient _client = new();
private readonly AmazonBedrockAgentRuntimeClient _runtimeClient = new();

public AmazonBedrockAgentRuntimeClient AmazonBedrockAgentRuntimeClient => this._runtimeClient;

public override Microsoft.SemanticKernel.Agents.Agent Agent => this._agent!;

public override AgentThread AgentThread => this._thread!;

public override AgentThread CreatedAgentThread => this._createdThread!;

public override AgentThread MockCreatedAgentThread => this._mockCreatedAgentThread!.Object;

public override Mock<IMessageMockableAgentThread> MockableMessageCreatedAgentThread => this._mockCreatedAgentThread!.As<IMessageMockableAgentThread>();

public override AgentThread ServiceFailingAgentThread => this._serviceFailingAgentThread!;

public override AgentThread CreatedServiceFailingAgentThread => this._createdServiceFailingAgentThread!;
Expand Down Expand Up @@ -121,6 +131,9 @@ public override async Task InitializeAsync()
this._createdThread = new BedrockAgentThread(this._runtimeClient);
await this._createdThread.CreateAsync();

this._mockCreatedAgentThread = new Mock<MockBedrockAgentThread>(this._runtimeClient, this._createdThread.Id) { CallBase = true };
this._mockCreatedAgentThread.Setup(x => x.MockableOnNewMessage(It.IsAny<ChatMessageContent>(), It.IsAny<CancellationToken>()));

this._serviceFailingAgentClient = new AmazonBedrockAgentRuntimeClient(new BasicAWSCredentials("", ""));
this._serviceFailingAgentThread = new BedrockAgentThread(this._serviceFailingAgentClient);

Expand Down
Original file line number Diff line number Diff line change
@@ -1,11 +1,14 @@
// Copyright (c) Microsoft. All rights reserved.

using System.Threading;
using System.Threading.Tasks;
using Azure.Identity;
using Microsoft.Extensions.Configuration;
using Microsoft.SemanticKernel;
using Microsoft.SemanticKernel.Agents;
using Microsoft.SemanticKernel.ChatCompletion;
using Moq;
using SemanticKernel.IntegrationTests.Agents.CommonInterfaceConformance.AgentThreadMocks;
using SemanticKernel.IntegrationTests.TestSettings;

namespace SemanticKernel.IntegrationTests.Agents.CommonInterfaceConformance;
Expand All @@ -25,13 +28,18 @@ public class ChatCompletionAgentFixture : AgentFixture
private ChatCompletionAgent? _agent;
private ChatHistoryAgentThread? _thread;
private ChatHistoryAgentThread? _createdThread;
private Mock<MockChatHistoryAgentThread>? _mockCreatedAgentThread;

public override Agent Agent => this._agent!;

public override AgentThread AgentThread => this._thread!;

public override AgentThread CreatedAgentThread => this._createdThread!;

public override AgentThread MockCreatedAgentThread => this._mockCreatedAgentThread!.Object;

public override Mock<IMessageMockableAgentThread> MockableMessageCreatedAgentThread => this._mockCreatedAgentThread!.As<IMessageMockableAgentThread>();

public override AgentThread ServiceFailingAgentThread => null!;

public override AgentThread CreatedServiceFailingAgentThread => null!;
Expand Down Expand Up @@ -75,5 +83,8 @@ public async override Task InitializeAsync()
this._thread = new ChatHistoryAgentThread();
this._createdThread = new ChatHistoryAgentThread();
await this._createdThread.CreateAsync();

this._mockCreatedAgentThread = new Mock<MockChatHistoryAgentThread>() { CallBase = true };
this._mockCreatedAgentThread.Setup(x => x.MockableOnNewMessage(It.IsAny<ChatMessageContent>(), It.IsAny<CancellationToken>()));
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -80,8 +80,14 @@ public override Task MultiStepInvokeWithPluginAndArgOverridesAsync()
}

[Fact(Skip = "This test is for manual verification.")]
public override Task InvokeWithPluginNotifiesForAllMessagesAsync()
public override Task InvokeWithPluginNotifiesCallbackForAllMessagesAsync()
{
return base.InvokeWithPluginNotifiesForAllMessagesAsync();
return base.InvokeWithPluginNotifiesCallbackForAllMessagesAsync();
}

[Fact(Skip = "This test is for manual verification.")]
public override Task InvokeWithPluginNotifiesThreadForAllMessagesBaseAsync()
{
return base.InvokeWithPluginNotifiesThreadForAllMessagesBaseAsync();
}
}
Loading
Loading