diff --git a/dotnet/src/Agents/Abstractions/Agent.cs b/dotnet/src/Agents/Abstractions/Agent.cs
index 833bea6b4987..5f21f83bb6c0 100644
--- a/dotnet/src/Agents/Abstractions/Agent.cs
+++ b/dotnet/src/Agents/Abstractions/Agent.cs
@@ -384,4 +384,38 @@ protected Task NotifyThreadOfNewMessage(AgentThread thread, ChatMessageContent m
{
return thread.OnNewMessageAsync(message, cancellationToken);
}
+
+ ///
+ /// Default formatting for additional instructions for the AI agent based on the provided context and invocation options.
+ ///
+ /// The context containing relevant information for the AI agent's operation.
+ /// Optional parameters that influence the invocation behavior. Can be .
+ /// A formatted string representing the additional instructions for the AI agent.
+#pragma warning disable SKEXP0130 // Type is for evaluation purposes only and is subject to change or removal in future updates. Suppress this diagnostic to proceed.
+ protected static string FormatAdditionalInstructions(AIContext context, AgentInvokeOptions? options)
+#pragma warning restore SKEXP0130 // Type is for evaluation purposes only and is subject to change or removal in future updates. Suppress this diagnostic to proceed.
+ {
+ return string.Concat(ProcessInstructions());
+
+ IEnumerable ProcessInstructions()
+ {
+ bool hasInstructions = false;
+ if (options?.AdditionalInstructions is not null)
+ {
+ yield return options!.AdditionalInstructions;
+ hasInstructions = true;
+ }
+
+ if (!string.IsNullOrWhiteSpace(context.Instructions))
+ {
+ if (hasInstructions)
+ {
+ yield return Environment.NewLine;
+ yield return Environment.NewLine;
+ }
+
+ yield return context.Instructions!;
+ }
+ }
+ }
}
diff --git a/dotnet/src/Agents/AzureAI/AzureAIAgent.cs b/dotnet/src/Agents/AzureAI/AzureAIAgent.cs
index eeab8434a682..a942eae8ba73 100644
--- a/dotnet/src/Agents/AzureAI/AzureAIAgent.cs
+++ b/dotnet/src/Agents/AzureAI/AzureAIAgent.cs
@@ -1,6 +1,5 @@
// Copyright (c) Microsoft. All rights reserved.
-using System;
using System.Collections.Generic;
using System.Runtime.CompilerServices;
using System.Threading;
@@ -131,21 +130,21 @@ public async IAsyncEnumerable> InvokeAsync
{
Verify.NotNull(messages);
- var azureAIAgentThread = await this.EnsureThreadExistsWithMessagesAsync(
+ AzureAIAgentThread azureAIAgentThread = await this.EnsureThreadExistsWithMessagesAsync(
messages,
thread,
() => new AzureAIAgentThread(this.Client),
cancellationToken).ConfigureAwait(false);
- var kernel = (options?.Kernel ?? this.Kernel).Clone();
+ Kernel kernel = (options?.Kernel ?? this.Kernel).Clone();
// Get the context contributions from the AIContextProviders.
-#pragma warning disable SKEXP0110 // Type is for evaluation purposes only and is subject to change or removal in future updates. Suppress this diagnostic to proceed.
- var providersContext = await azureAIAgentThread.AIContextProviders.ModelInvokingAsync(messages, cancellationToken).ConfigureAwait(false);
+#pragma warning disable SKEXP0110, SKEXP0130 // Type is for evaluation purposes only and is subject to change or removal in future updates. Suppress this diagnostic to proceed.
+ AIContext providersContext = await azureAIAgentThread.AIContextProviders.ModelInvokingAsync(messages, cancellationToken).ConfigureAwait(false);
kernel.Plugins.AddFromAIContext(providersContext, "Tools");
-#pragma warning restore SKEXP0110 // Type is for evaluation purposes only and is subject to change or removal in future updates. Suppress this diagnostic to proceed.
+#pragma warning restore SKEXP0110, SKEXP0130 // Type is for evaluation purposes only and is subject to change or removal in future updates. Suppress this diagnostic to proceed.
- var mergedAdditionalInstructions = MergeAdditionalInstructions(options?.AdditionalInstructions, providersContext.Instructions);
+ string mergedAdditionalInstructions = FormatAdditionalInstructions(providersContext, options);
var extensionsContextOptions = options is null ?
new AzureAIAgentInvokeOptions() { AdditionalInstructions = mergedAdditionalInstructions } :
new AzureAIAgentInvokeOptions(options) { AdditionalInstructions = mergedAdditionalInstructions };
@@ -223,7 +222,7 @@ public async IAsyncEnumerable> In
{
Verify.NotNull(messages);
- var azureAIAgentThread = await this.EnsureThreadExistsWithMessagesAsync(
+ AzureAIAgentThread azureAIAgentThread = await this.EnsureThreadExistsWithMessagesAsync(
messages,
thread,
() => new AzureAIAgentThread(this.Client),
@@ -232,19 +231,19 @@ public async IAsyncEnumerable> In
var kernel = (options?.Kernel ?? this.Kernel).Clone();
// Get the context contributions from the AIContextProviders.
-#pragma warning disable SKEXP0110 // Type is for evaluation purposes only and is subject to change or removal in future updates. Suppress this diagnostic to proceed.
- var providersContext = await azureAIAgentThread.AIContextProviders.ModelInvokingAsync(messages, cancellationToken).ConfigureAwait(false);
+#pragma warning disable SKEXP0110, SKEXP0130 // Type is for evaluation purposes only and is subject to change or removal in future updates. Suppress this diagnostic to proceed.
+ AIContext providersContext = await azureAIAgentThread.AIContextProviders.ModelInvokingAsync(messages, cancellationToken).ConfigureAwait(false);
kernel.Plugins.AddFromAIContext(providersContext, "Tools");
-#pragma warning restore SKEXP0110 // Type is for evaluation purposes only and is subject to change or removal in future updates. Suppress this diagnostic to proceed.
+#pragma warning restore SKEXP0110, SKEXP0130 // Type is for evaluation purposes only and is subject to change or removal in future updates. Suppress this diagnostic to proceed.
- var mergedAdditionalInstructions = MergeAdditionalInstructions(options?.AdditionalInstructions, providersContext.Instructions);
+ string mergedAdditionalInstructions = FormatAdditionalInstructions(providersContext, options);
var extensionsContextOptions = options is null ?
new AzureAIAgentInvokeOptions() { AdditionalInstructions = mergedAdditionalInstructions } :
new AzureAIAgentInvokeOptions(options) { AdditionalInstructions = mergedAdditionalInstructions };
// Invoke the Agent with the thread that we already added our message to, and with
// a chat history to receive complete messages.
- var newMessagesReceiver = new ChatHistory();
+ ChatHistory newMessagesReceiver = [];
var invokeResults = ActivityExtensions.RunWithActivityAsync(
() => ModelDiagnostics.StartAgentInvocationActivity(this.Id, this.GetDisplayName(), this.Description),
() => AgentThreadActions.InvokeStreamingAsync(
@@ -324,19 +323,4 @@ protected override async Task RestoreChannelAsync(string channelSt
return new AzureAIChannel(this.Client, thread.Id);
}
-
- private static string MergeAdditionalInstructions(string? optionsAdditionalInstructions, string? extensionsContext) =>
- (optionsAdditionalInstructions, extensionsContext) switch
- {
- (string ai, string ec) when !string.IsNullOrWhiteSpace(ai) && !string.IsNullOrWhiteSpace(ec) => string.Concat(
- ai,
- Environment.NewLine,
- Environment.NewLine,
- ec),
- (string ai, string ec) when string.IsNullOrWhiteSpace(ai) => ec,
- (string ai, string ec) when string.IsNullOrWhiteSpace(ec) => ai,
- (null, string ec) => ec,
- (string ai, null) => ai,
- _ => string.Empty
- };
}
diff --git a/dotnet/src/Agents/Bedrock/BedrockAgent.cs b/dotnet/src/Agents/Bedrock/BedrockAgent.cs
index 2a34e5c0503f..815ec1a859f3 100644
--- a/dotnet/src/Agents/Bedrock/BedrockAgent.cs
+++ b/dotnet/src/Agents/Bedrock/BedrockAgent.cs
@@ -121,16 +121,16 @@ public override async IAsyncEnumerable> In
cancellationToken).ConfigureAwait(false);
// Get the context contributions from the AIContextProviders.
-#pragma warning disable SKEXP0110 // Type is for evaluation purposes only and is subject to change or removal in future updates. Suppress this diagnostic to proceed.
- var providersContext = await bedrockThread.AIContextProviders.ModelInvokingAsync(messages, cancellationToken).ConfigureAwait(false);
-#pragma warning restore SKEXP0110 // Type is for evaluation purposes only and is subject to change or removal in future updates. Suppress this diagnostic to proceed.
+#pragma warning disable SKEXP0110, SKEXP0130 // Type is for evaluation purposes only and is subject to change or removal in future updates. Suppress this diagnostic to proceed.
+ AIContext providersContext = await bedrockThread.AIContextProviders.ModelInvokingAsync(messages, cancellationToken).ConfigureAwait(false);
+#pragma warning restore SKEXP0110, SKEXP0130 // Type is for evaluation purposes only and is subject to change or removal in future updates. Suppress this diagnostic to proceed.
// Ensure that the last message provided is a user message
string message = this.ExtractUserMessage(messages.Last());
// Build session state with conversation history and override instructions if needed
SessionState sessionState = this.ExtractSessionState(messages);
- var mergedAdditionalInstructions = MergeAdditionalInstructions(options?.AdditionalInstructions, providersContext.Instructions);
+ string mergedAdditionalInstructions = FormatAdditionalInstructions(providersContext, options);
sessionState.PromptSessionAttributes = new() { [AdditionalInstructionsSessionAttributeName] = mergedAdditionalInstructions };
// Configure the agent request with the provided options
@@ -196,7 +196,7 @@ public async IAsyncEnumerable> InvokeAsync
thread = new BedrockAgentThread(this.RuntimeClient, invokeAgentRequest.SessionId);
}
- var bedrockThread = await this.EnsureThreadExistsWithMessagesAsync(
+ BedrockAgentThread bedrockThread = await this.EnsureThreadExistsWithMessagesAsync(
[],
thread,
() => new BedrockAgentThread(this.RuntimeClient),
@@ -255,23 +255,23 @@ public override async IAsyncEnumerable new BedrockAgentThread(this.RuntimeClient),
cancellationToken).ConfigureAwait(false);
// Get the context contributions from the AIContextProviders.
-#pragma warning disable SKEXP0110 // Type is for evaluation purposes only and is subject to change or removal in future updates. Suppress this diagnostic to proceed.
- var providersContext = await bedrockThread.AIContextProviders.ModelInvokingAsync(messages, cancellationToken).ConfigureAwait(false);
-#pragma warning restore SKEXP0110 // Type is for evaluation purposes only and is subject to change or removal in future updates. Suppress this diagnostic to proceed.
+#pragma warning disable SKEXP0110, SKEXP0130 // Type is for evaluation purposes only and is subject to change or removal in future updates. Suppress this diagnostic to proceed.
+ AIContext providersContext = await bedrockThread.AIContextProviders.ModelInvokingAsync(messages, cancellationToken).ConfigureAwait(false);
+#pragma warning restore SKEXP0110, SKEXP0130 // Type is for evaluation purposes only and is subject to change or removal in future updates. Suppress this diagnostic to proceed.
// Ensure that the last message provided is a user message
string? message = this.ExtractUserMessage(messages.Last());
// Build session state with conversation history and override instructions if needed
SessionState sessionState = this.ExtractSessionState(messages);
- var mergedAdditionalInstructions = MergeAdditionalInstructions(options?.AdditionalInstructions, providersContext.Instructions);
+ string mergedAdditionalInstructions = FormatAdditionalInstructions(providersContext, options);
sessionState.PromptSessionAttributes = new() { [AdditionalInstructionsSessionAttributeName] = mergedAdditionalInstructions };
// Configure the agent request with the provided options
@@ -579,20 +579,5 @@ private Amazon.BedrockAgentRuntime.ConversationRole MapBedrockAgentUser(AuthorRo
throw new ArgumentOutOfRangeException($"Invalid role: {authorRole}");
}
- private static string MergeAdditionalInstructions(string? optionsAdditionalInstructions, string? extensionsContext) =>
- (optionsAdditionalInstructions, extensionsContext) switch
- {
- (string ai, string ec) when !string.IsNullOrWhiteSpace(ai) && !string.IsNullOrWhiteSpace(ec) => string.Concat(
- ai,
- Environment.NewLine,
- Environment.NewLine,
- ec),
- (string ai, string ec) when string.IsNullOrWhiteSpace(ai) => ec,
- (string ai, string ec) when string.IsNullOrWhiteSpace(ec) => ai,
- (null, string ec) => ec,
- (string ai, null) => ai,
- _ => string.Empty
- };
-
#endregion
}
diff --git a/dotnet/src/Agents/Core/ChatCompletionAgent.cs b/dotnet/src/Agents/Core/ChatCompletionAgent.cs
index 85cebf8fa4c0..56c8712ab50f 100644
--- a/dotnet/src/Agents/Core/ChatCompletionAgent.cs
+++ b/dotnet/src/Agents/Core/ChatCompletionAgent.cs
@@ -67,22 +67,22 @@ public override async IAsyncEnumerable> In
{
Verify.NotNull(messages);
- var chatHistoryAgentThread = await this.EnsureThreadExistsWithMessagesAsync(
+ ChatHistoryAgentThread chatHistoryAgentThread = await this.EnsureThreadExistsWithMessagesAsync(
messages,
thread,
() => new ChatHistoryAgentThread(),
cancellationToken).ConfigureAwait(false);
- var kernel = (options?.Kernel ?? this.Kernel).Clone();
+ Kernel kernel = (options?.Kernel ?? this.Kernel).Clone();
// Get the context contributions from the AIContextProviders.
-#pragma warning disable SKEXP0110 // Type is for evaluation purposes only and is subject to change or removal in future updates. Suppress this diagnostic to proceed.
- var providersContext = await chatHistoryAgentThread.AIContextProviders.ModelInvokingAsync(messages, cancellationToken).ConfigureAwait(false);
+#pragma warning disable SKEXP0110, SKEXP0130 // Type is for evaluation purposes only and is subject to change or removal in future updates. Suppress this diagnostic to proceed.
+ AIContext providersContext = await chatHistoryAgentThread.AIContextProviders.ModelInvokingAsync(messages, cancellationToken).ConfigureAwait(false);
kernel.Plugins.AddFromAIContext(providersContext, "Tools");
-#pragma warning restore SKEXP0110 // Type is for evaluation purposes only and is subject to change or removal in future updates. Suppress this diagnostic to proceed.
+#pragma warning restore SKEXP0110, SKEXP0130 // Type is for evaluation purposes only and is subject to change or removal in future updates. Suppress this diagnostic to proceed.
// Invoke Chat Completion with the updated chat history.
- var chatHistory = new ChatHistory();
+ ChatHistory chatHistory = [];
await foreach (var existingMessage in chatHistoryAgentThread.GetMessagesAsync(cancellationToken).ConfigureAwait(false))
{
chatHistory.Add(existingMessage);
@@ -100,9 +100,7 @@ public override async IAsyncEnumerable> In
},
options?.KernelArguments,
kernel,
- options?.AdditionalInstructions == null ?
- providersContext.Instructions :
- string.Concat(options.AdditionalInstructions, Environment.NewLine, Environment.NewLine, providersContext.Instructions),
+ FormatAdditionalInstructions(providersContext, options),
cancellationToken);
// Notify the thread of new messages and return them to the caller.
@@ -164,22 +162,22 @@ public override async IAsyncEnumerable new ChatHistoryAgentThread(),
cancellationToken).ConfigureAwait(false);
- var kernel = (options?.Kernel ?? this.Kernel).Clone();
+ Kernel kernel = (options?.Kernel ?? this.Kernel).Clone();
// Get the context contributions from the AIContextProviders.
-#pragma warning disable SKEXP0110 // Type is for evaluation purposes only and is subject to change or removal in future updates. Suppress this diagnostic to proceed.
- var providersContext = await chatHistoryAgentThread.AIContextProviders.ModelInvokingAsync(messages, cancellationToken).ConfigureAwait(false);
+#pragma warning disable SKEXP0110, SKEXP0130 // Type is for evaluation purposes only and is subject to change or removal in future updates. Suppress this diagnostic to proceed.
+ AIContext providersContext = await chatHistoryAgentThread.AIContextProviders.ModelInvokingAsync(messages, cancellationToken).ConfigureAwait(false);
kernel.Plugins.AddFromAIContext(providersContext, "Tools");
-#pragma warning restore SKEXP0110 // Type is for evaluation purposes only and is subject to change or removal in future updates. Suppress this diagnostic to proceed.
+#pragma warning restore SKEXP0110, SKEXP0130 // Type is for evaluation purposes only and is subject to change or removal in future updates. Suppress this diagnostic to proceed.
// Invoke Chat Completion with the updated chat history.
- var chatHistory = new ChatHistory();
+ ChatHistory chatHistory = [];
await foreach (var existingMessage in chatHistoryAgentThread.GetMessagesAsync(cancellationToken).ConfigureAwait(false))
{
chatHistory.Add(existingMessage);
@@ -198,9 +196,7 @@ public override async IAsyncEnumerable> InvokeAsync
{
Verify.NotNull(messages);
- var openAIAssistantAgentThread = await this.EnsureThreadExistsWithMessagesAsync(
+ OpenAIAssistantAgentThread openAIAssistantAgentThread = await this.EnsureThreadExistsWithMessagesAsync(
messages,
thread,
() => new OpenAIAssistantAgentThread(this.Client),
@@ -138,13 +138,13 @@ public async IAsyncEnumerable> InvokeAsync
AdditionalInstructions = options?.AdditionalInstructions,
});
- var kernel = (options?.Kernel ?? this.Kernel).Clone();
+ Kernel kernel = (options?.Kernel ?? this.Kernel).Clone();
// Get the context contributions from the AIContextProviders.
-#pragma warning disable SKEXP0110 // Type is for evaluation purposes only and is subject to change or removal in future updates. Suppress this diagnostic to proceed.
- var providersContext = await openAIAssistantAgentThread.AIContextProviders.ModelInvokingAsync(messages, cancellationToken).ConfigureAwait(false);
+#pragma warning disable SKEXP0110, SKEXP0130 // Type is for evaluation purposes only and is subject to change or removal in future updates. Suppress this diagnostic to proceed.
+ AIContext providersContext = await openAIAssistantAgentThread.AIContextProviders.ModelInvokingAsync(messages, cancellationToken).ConfigureAwait(false);
kernel.Plugins.AddFromAIContext(providersContext, "Tools");
-#pragma warning restore SKEXP0110 // Type is for evaluation purposes only and is subject to change or removal in future updates. Suppress this diagnostic to proceed.
+#pragma warning restore SKEXP0110, SKEXP0130 // Type is for evaluation purposes only and is subject to change or removal in future updates. Suppress this diagnostic to proceed.
var invokeResults = ActivityExtensions.RunWithActivityAsync(
() => ModelDiagnostics.StartAgentInvocationActivity(this.Id, this.GetDisplayName(), this.Description),
@@ -220,19 +220,19 @@ public async IAsyncEnumerable> In
{
Verify.NotNull(messages);
- var openAIAssistantAgentThread = await this.EnsureThreadExistsWithMessagesAsync(
+ OpenAIAssistantAgentThread openAIAssistantAgentThread = await this.EnsureThreadExistsWithMessagesAsync(
messages,
thread,
() => new OpenAIAssistantAgentThread(this.Client),
cancellationToken).ConfigureAwait(false);
- var kernel = (options?.Kernel ?? this.Kernel).Clone();
+ Kernel kernel = (options?.Kernel ?? this.Kernel).Clone();
// Get the context contributions from the AIContextProviders.
-#pragma warning disable SKEXP0110 // Type is for evaluation purposes only and is subject to change or removal in future updates. Suppress this diagnostic to proceed.
- var providersContext = await openAIAssistantAgentThread.AIContextProviders.ModelInvokingAsync(messages, cancellationToken).ConfigureAwait(false);
+#pragma warning disable SKEXP0110, SKEXP0130 // Type is for evaluation purposes only and is subject to change or removal in future updates. Suppress this diagnostic to proceed.
+ AIContext providersContext = await openAIAssistantAgentThread.AIContextProviders.ModelInvokingAsync(messages, cancellationToken).ConfigureAwait(false);
kernel.Plugins.AddFromAIContext(providersContext, "Tools");
-#pragma warning restore SKEXP0110 // Type is for evaluation purposes only and is subject to change or removal in future updates. Suppress this diagnostic to proceed.
+#pragma warning restore SKEXP0110, SKEXP0130 // Type is for evaluation purposes only and is subject to change or removal in future updates. Suppress this diagnostic to proceed.
// Create options that use the RunCreationOptions from the options param if provided or
// falls back to creating a new RunCreationOptions if additional instructions is provided
@@ -243,7 +243,7 @@ public async IAsyncEnumerable> In
});
#pragma warning disable SKEXP0001 // ModelDiagnostics is marked experimental.
- var newMessagesReceiver = new ChatHistory();
+ ChatHistory newMessagesReceiver = [];
var invokeResults = ActivityExtensions.RunWithActivityAsync(
() => ModelDiagnostics.StartAgentInvocationActivity(this.Id, this.GetDisplayName(), this.Description),
() => InternalInvokeStreamingAsync(),