Skip to content
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

.Net: Removing KernelAgent.cs and moving its functionality into Agent.cs #11244

Merged
merged 9 commits into from
Apr 2, 2025
Merged
Show file tree
Hide file tree
Changes from 7 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
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ namespace Agents;

/// <summary>
/// Demonstrate service selection for <see cref="ChatCompletionAgent"/> through setting service-id
/// on <see cref="KernelAgent.Arguments"/> and also providing override <see cref="KernelArguments"/>
/// on <see cref="Agent.Arguments"/> and also providing override <see cref="KernelArguments"/>
/// when calling <see cref="ChatCompletionAgent.InvokeAsync(ChatHistory, KernelArguments?, Kernel?, CancellationToken)"/>
/// </summary>
public class ChatCompletion_ServiceSelection(ITestOutputHelper output) : BaseAgentsTest(output)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ Always state the requested style of the poem.
// Create the agent
OpenAIAssistantAgent agent = new(assistant, this.AssistantClient)
{
Arguments =
Arguments = new()
{
{"style", "haiku"}
},
Expand Down Expand Up @@ -105,7 +105,7 @@ await this.AssistantClient.CreateAssistantFromTemplateAsync(
// Create the agent
OpenAIAssistantAgent agent = new(assistant, this.AssistantClient, plugins: null, templateFactory, templateFormat)
{
Arguments =
Arguments = new()
{
{"style", "haiku"}
},
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ public async Task UseTemplateForAzureAgentAsync()
templateFactory: new KernelPromptTemplateFactory(),
templateFormat: PromptTemplateConfig.SemanticKernelTemplateFormat)
{
Arguments =
Arguments = new()
{
{ "topic", "Dog" },
{ "length", "3" }
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ public async Task UseTemplateForAssistantAgentAsync()
templateFactory: new KernelPromptTemplateFactory(),
templateFormat: PromptTemplateConfig.SemanticKernelTemplateFormat)
{
Arguments =
Arguments = new()
{
{ "topic", "Dog" },
{ "length", "3" }
Expand Down
2 changes: 1 addition & 1 deletion dotnet/samples/GettingStartedWithAgents/Step01_Agent.cs
Original file line number Diff line number Diff line change
Expand Up @@ -151,7 +151,7 @@ public async Task UseTemplateForChatCompletionAgentAsync()
new(templateConfig, templateFactory)
{
Kernel = this.CreateKernelWithChatCompletion(),
Arguments =
Arguments = new()
{
{ "topic", "Dog" },
{ "length", "3" },
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ public static IChatHistoryProvider GetHistory(this Kernel kernel) =>
/// <summary>
/// Access an agent as a keyed service.
/// </summary>
public static TAgent GetAgent<TAgent>(this Kernel kernel, string key) where TAgent : KernelAgent =>
public static TAgent GetAgent<TAgent>(this Kernel kernel, string key) where TAgent : Agent =>
kernel.Services.GetRequiredKeyedService<TAgent>(key);

/// <summary>
Expand Down
48 changes: 48 additions & 0 deletions dotnet/src/Agents/Abstractions/Agent.cs
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
using System.Threading.Tasks;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Logging.Abstractions;
using Microsoft.SemanticKernel.Arguments.Extensions;
using Microsoft.SemanticKernel.ChatCompletion;

namespace Microsoft.SemanticKernel.Agents;
Expand Down Expand Up @@ -44,6 +45,32 @@ public abstract class Agent
/// </summary>
public ILoggerFactory? LoggerFactory { get; init; }

/// <summary>
/// Gets the arguments for the agent instruction parameters (optional).
/// </summary>
/// <remarks>
/// Also includes <see cref="PromptExecutionSettings"/>.
/// </remarks>
public KernelArguments? Arguments { get; init; }

/// <summary>
/// Gets the instructions for the agent (optional).
/// </summary>
public string? Instructions { get; init; }

/// <summary>
/// Gets the <see cref="Kernel"/> containing services, plugins, and filters for use throughout the agent lifetime.
/// </summary>
/// <value>
/// The <see cref="Kernel"/> containing services, plugins, and filters for use throughout the agent lifetime. The default value is an empty Kernel, but that can be overridden.
/// </value>
public Kernel Kernel { get; init; } = new();

/// <summary>
/// Gets or sets a prompt template based on the agent instructions.
/// </summary>
protected IPromptTemplate? Template { get; set; }

/// <summary>
/// Invoke the agent with no message assuming that all required instructions are already provided to the agent or on the thread.
/// </summary>
Expand Down Expand Up @@ -222,6 +249,27 @@ public abstract IAsyncEnumerable<AgentResponseItem<StreamingChatMessageContent>>
/// </summary>
protected virtual ILoggerFactory ActiveLoggerFactory => this.LoggerFactory ?? NullLoggerFactory.Instance;

/// <summary>
/// Formats the system instructions for the agent.
/// </summary>
/// <param name="kernel">The <see cref="Kernel"/> containing services, plugins, and other state for use by the agent.</param>
/// <param name="arguments">Optional arguments to pass to the agents's invocation, including any <see cref="PromptExecutionSettings"/>.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> to monitor for cancellation requests. The default is <see cref="CancellationToken.None"/>.</param>
/// <returns>The formatted system instructions for the agent.</returns>
protected async Task<string?> RenderInstructionsAsync(Kernel kernel, KernelArguments? arguments, CancellationToken cancellationToken)
{
if (this.Template is null)
{
// Use the instructions as-is
return this.Instructions;
}

var mergedArguments = this.Arguments.Merge(arguments);

// Use the provided template as the instructions
return await this.Template.RenderAsync(kernel, mergedArguments, cancellationToken).ConfigureAwait(false);
}

/// <summary>
/// Set of keys to establish channel affinity. Minimum expected key-set:
/// <example>
Expand Down
3 changes: 2 additions & 1 deletion dotnet/src/Agents/Abstractions/Agents.Abstractions.csproj
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
<Project Sdk="Microsoft.NET.Sdk">
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<!-- THIS PROPERTY GROUP MUST COME FIRST -->
Expand All @@ -21,6 +21,7 @@
<Compile Include="$(RepoRoot)/dotnet/src/InternalUtilities/src/Diagnostics/*" Link="%(RecursiveDir)Utilities/%(Filename)%(Extension)" />
<Compile Include="$(RepoRoot)/dotnet/src/InternalUtilities/src/System/AppContextSwitchHelper.cs" Link="%(RecursiveDir)Utilities/%(Filename)%(Extension)" />
<Compile Include="$(RepoRoot)/dotnet/src/InternalUtilities/agents/Extensions/AgentExtensions.cs" Link="%(RecursiveDir)Utilities/%(Filename)%(Extension)" />
<Compile Include="$(RepoRoot)/dotnet/src/InternalUtilities/arguments/Extensions/KernelArgumentsExtensions.cs" Link="%(RecursiveDir)Utilities/%(Filename)%(Extension)" />
</ItemGroup>

<ItemGroup>
Expand Down
100 changes: 0 additions & 100 deletions dotnet/src/Agents/Abstractions/KernelAgent.cs

This file was deleted.

2 changes: 1 addition & 1 deletion dotnet/src/Agents/AzureAI/AzureAIAgent.ClientFactory.cs
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ namespace Microsoft.SemanticKernel.Agents.AzureAI;
/// <summary>
/// Provides an <see cref="AIProjectClient"/> for use by <see cref="AzureAIAgent"/>.
/// </summary>
public sealed partial class AzureAIAgent : KernelAgent
public sealed partial class AzureAIAgent : Agent
{
/// <summary>
/// Produces a <see cref="AIProjectClient"/>.
Expand Down
14 changes: 5 additions & 9 deletions dotnet/src/Agents/AzureAI/AzureAIAgent.cs
Original file line number Diff line number Diff line change
Expand Up @@ -16,9 +16,9 @@
namespace Microsoft.SemanticKernel.Agents.AzureAI;

/// <summary>
/// Provides a specialized <see cref="KernelAgent"/> based on an Azure AI agent.
/// Provides a specialized <see cref="Agent"/> based on an Azure AI agent.
/// </summary>
public sealed partial class AzureAIAgent : KernelAgent
public sealed partial class AzureAIAgent : Agent
{
/// <summary>
/// Provides tool definitions used when associating a file attachment to an input message:
Expand Down Expand Up @@ -200,7 +200,7 @@ async IAsyncEnumerable<ChatMessageContent> InternalInvokeAsync()
options?.ToAzureAIInvocationOptions(),
this.Logger,
options?.Kernel ?? this.Kernel,
this.MergeArguments(options?.KernelArguments),
options?.KernelArguments,
cancellationToken).ConfigureAwait(false))
{
// The thread and the caller should be notified of all messages regardless of visibility.
Expand Down Expand Up @@ -252,8 +252,6 @@ public IAsyncEnumerable<ChatMessageContent> InvokeAsync(
async IAsyncEnumerable<ChatMessageContent> InternalInvokeAsync()
{
kernel ??= this.Kernel;
arguments = this.MergeArguments(arguments);

await foreach ((bool isVisible, ChatMessageContent message) in AgentThreadActions.InvokeAsync(this, this.Client, threadId, options, this.Logger, kernel, arguments, cancellationToken).ConfigureAwait(false))
{
if (isVisible)
Expand Down Expand Up @@ -311,7 +309,7 @@ public async IAsyncEnumerable<AgentResponseItem<StreamingChatMessageContent>> In
var invokeResults = this.InvokeStreamingAsync(
azureAIAgentThread.Id!,
options?.ToAzureAIInvocationOptions(),
this.MergeArguments(options?.KernelArguments),
options?.KernelArguments,
options?.Kernel ?? this.Kernel,
newMessagesReceiver,
cancellationToken);
Expand Down Expand Up @@ -388,8 +386,6 @@ public IAsyncEnumerable<StreamingChatMessageContent> InvokeStreamingAsync(
IAsyncEnumerable<StreamingChatMessageContent> InternalInvokeStreamingAsync()
{
kernel ??= this.Kernel;
arguments = this.MergeArguments(arguments);

return AgentThreadActions.InvokeStreamingAsync(this, this.Client, threadId, messages, options, this.Logger, kernel, arguments, cancellationToken);
}
}
Expand Down Expand Up @@ -425,7 +421,7 @@ protected override async Task<AgentChannel> CreateChannelAsync(CancellationToken

internal Task<string?> GetInstructionsAsync(Kernel kernel, KernelArguments? arguments, CancellationToken cancellationToken)
{
return this.FormatInstructionsAsync(kernel, arguments, cancellationToken);
return this.RenderInstructionsAsync(kernel, arguments, cancellationToken);
}

/// <inheritdoc/>
Expand Down
18 changes: 6 additions & 12 deletions dotnet/src/Agents/Bedrock/BedrockAgent.cs
Original file line number Diff line number Diff line change
Expand Up @@ -16,9 +16,9 @@
namespace Microsoft.SemanticKernel.Agents.Bedrock;

/// <summary>
/// Provides a specialized <see cref="KernelAgent"/> for the Bedrock Agent service.
/// Provides a specialized <see cref="Agent"/> for the Bedrock Agent service.
/// </summary>
public sealed class BedrockAgent : KernelAgent
public sealed class BedrockAgent : Agent
{
/// <summary>
/// The client used to interact with the Bedrock Agent service.
Expand Down Expand Up @@ -136,8 +136,7 @@ public override async IAsyncEnumerable<AgentResponseItem<ChatMessageContent>> In
});

// Invoke the agent
var arguments = this.MergeArguments(options?.KernelArguments);
var invokeResults = this.InvokeInternalAsync(invokeAgentRequest, arguments, cancellationToken);
var invokeResults = this.InvokeInternalAsync(invokeAgentRequest, options?.KernelArguments, cancellationToken);

// Return the results to the caller in AgentResponseItems.
await foreach (var result in invokeResults.ConfigureAwait(false))
Expand Down Expand Up @@ -180,8 +179,6 @@ public async IAsyncEnumerable<AgentResponseItem<ChatMessageContent>> InvokeAsync
AgentInvokeOptions? options = null,
[EnumeratorCancellation] CancellationToken cancellationToken = default)
{
var arguments = this.MergeArguments(options?.KernelArguments);

// The provided thread is used to continue the conversation. If the thread is not provided and the session id is provided,
// a new thread is created with the provided session id. If neither is provided, a new thread is created.
if (thread is null && invokeAgentRequest.SessionId is not null)
Expand All @@ -200,7 +197,7 @@ public async IAsyncEnumerable<AgentResponseItem<ChatMessageContent>> InvokeAsync
invokeAgentRequest = this.ConfigureAgentRequest(options, () => invokeAgentRequest);

// Invoke the agent
var invokeResults = this.InvokeInternalAsync(invokeAgentRequest, arguments, cancellationToken);
var invokeResults = this.InvokeInternalAsync(invokeAgentRequest, options?.KernelArguments, cancellationToken);

// Return the results to the caller in AgentResponseItems.
await foreach (var result in invokeResults.ConfigureAwait(false))
Expand Down Expand Up @@ -368,8 +365,7 @@ public override async IAsyncEnumerable<AgentResponseItem<StreamingChatMessageCon
});

// Invoke the agent
var arguments = this.MergeArguments(options?.KernelArguments);
var invokeResults = this.InvokeStreamingInternalAsync(invokeAgentRequest, bedrockThread, arguments, cancellationToken);
var invokeResults = this.InvokeStreamingInternalAsync(invokeAgentRequest, bedrockThread, options?.KernelArguments, cancellationToken);

// Return the results to the caller in AgentResponseItems.
await foreach (var result in invokeResults.ConfigureAwait(false))
Expand Down Expand Up @@ -413,8 +409,6 @@ public async IAsyncEnumerable<AgentResponseItem<StreamingChatMessageContent>> In
AgentInvokeOptions? options = null,
[EnumeratorCancellation] CancellationToken cancellationToken = default)
{
var arguments = this.MergeArguments(options?.KernelArguments);

// The provided thread is used to continue the conversation. If the thread is not provided and the session id is provided,
// a new thread is created with the provided session id. If neither is provided, a new thread is created.
if (thread is null && invokeAgentRequest.SessionId is not null)
Expand All @@ -432,7 +426,7 @@ public async IAsyncEnumerable<AgentResponseItem<StreamingChatMessageContent>> In
invokeAgentRequest.SessionId = bedrockThread.Id;
invokeAgentRequest = this.ConfigureAgentRequest(options, () => invokeAgentRequest);

var invokeResults = this.InvokeStreamingInternalAsync(invokeAgentRequest, bedrockThread, arguments, cancellationToken);
var invokeResults = this.InvokeStreamingInternalAsync(invokeAgentRequest, bedrockThread, options?.KernelArguments, cancellationToken);

// The Bedrock agent service has the same API for both streaming and non-streaming responses.
// We are invoking the same method as the non-streaming response with the streaming configuration set,
Expand Down
2 changes: 1 addition & 1 deletion dotnet/src/Agents/Core/AgentGroupChat.cs
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ public sealed class AgentGroupChat : AgentChat
/// <summary>
/// Add an <see cref="Agent"/> to the chat.
/// </summary>
/// <param name="agent">The <see cref="KernelAgent"/> to add.</param>
/// <param name="agent">The <see cref="Agent"/> to add.</param>
public void AddAgent(Agent agent)
{
if (this._agentIds.Add(agent.Id))
Expand Down
Loading
Loading