.NET: [Breaking] Introduce RunCoreAsync/RunCoreStreamingAsync delegation pattern in AIAgent (#2749)

* Initial plan

* Refactor AIAgent: Make RunAsync and RunStreamingAsync non-abstract, add RunCoreAsync and RunCoreStreamingAsync

Co-authored-by: SergeyMenshykh <68852919+SergeyMenshykh@users.noreply.github.com>

* Fix infinite recursion in test implementations

Co-authored-by: SergeyMenshykh <68852919+SergeyMenshykh@users.noreply.github.com>

* Make RunAsync and RunStreamingAsync non-virtual as requested

Co-authored-by: SergeyMenshykh <68852919+SergeyMenshykh@users.noreply.github.com>

* Fix DelegatingAIAgent subclasses to use RunCoreAsync/RunCoreStreamingAsync

Co-authored-by: SergeyMenshykh <68852919+SergeyMenshykh@users.noreply.github.com>

* Fix XML documentation references in AnonymousDelegatingAIAgent

Co-authored-by: SergeyMenshykh <68852919+SergeyMenshykh@users.noreply.github.com>

* Restore <see cref> tags with proper qualified signatures in AnonymousDelegatingAIAgent

Co-authored-by: SergeyMenshykh <68852919+SergeyMenshykh@users.noreply.github.com>

* Rollback unnecessary XML documentation changes in AnonymousDelegatingAIAgent

Co-authored-by: SergeyMenshykh <68852919+SergeyMenshykh@users.noreply.github.com>

* Remove pragma and update crefs to RunCoreAsync/RunCoreStreamingAsync

Co-authored-by: SergeyMenshykh <68852919+SergeyMenshykh@users.noreply.github.com>

* Fix EntityAgentWrapper to call base.RunCoreAsync/RunCoreStreamingAsync

Co-authored-by: SergeyMenshykh <68852919+SergeyMenshykh@users.noreply.github.com>

* fix compilation issues

* fix compilatio issue

* fix tests

* fix unit tests

* fix unit test

---------

Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
Co-authored-by: SergeyMenshykh <68852919+SergeyMenshykh@users.noreply.github.com>
Co-authored-by: SergeyMenshykh <sergemenshikh@gmail.com>
Co-authored-by: Chris <66376200+crickman@users.noreply.github.com>
This commit is contained in:
Copilot
2025-12-30 12:24:09 +00:00
committed by GitHub
Unverified
parent 4b8a545589
commit 8b4f7d5e29
44 changed files with 372 additions and 257 deletions
@@ -19,12 +19,12 @@ internal sealed class AgenticUIAgent : DelegatingAIAgent
this._jsonSerializerOptions = jsonSerializerOptions;
}
public override Task<AgentRunResponse> RunAsync(IEnumerable<ChatMessage> messages, AgentThread? thread = null, AgentRunOptions? options = null, CancellationToken cancellationToken = default)
protected override Task<AgentRunResponse> RunCoreAsync(IEnumerable<ChatMessage> messages, AgentThread? thread = null, AgentRunOptions? options = null, CancellationToken cancellationToken = default)
{
return this.RunStreamingAsync(messages, thread, options, cancellationToken).ToAgentRunResponseAsync(cancellationToken);
return this.RunCoreStreamingAsync(messages, thread, options, cancellationToken).ToAgentRunResponseAsync(cancellationToken);
}
public override async IAsyncEnumerable<AgentRunResponseUpdate> RunStreamingAsync(
protected override async IAsyncEnumerable<AgentRunResponseUpdate> RunCoreStreamingAsync(
IEnumerable<ChatMessage> messages,
AgentThread? thread = null,
AgentRunOptions? options = null,
@@ -20,12 +20,12 @@ internal sealed class PredictiveStateUpdatesAgent : DelegatingAIAgent
this._jsonSerializerOptions = jsonSerializerOptions;
}
public override Task<AgentRunResponse> RunAsync(IEnumerable<ChatMessage> messages, AgentThread? thread = null, AgentRunOptions? options = null, CancellationToken cancellationToken = default)
protected override Task<AgentRunResponse> RunCoreAsync(IEnumerable<ChatMessage> messages, AgentThread? thread = null, AgentRunOptions? options = null, CancellationToken cancellationToken = default)
{
return this.RunStreamingAsync(messages, thread, options, cancellationToken).ToAgentRunResponseAsync(cancellationToken);
return this.RunCoreStreamingAsync(messages, thread, options, cancellationToken).ToAgentRunResponseAsync(cancellationToken);
}
public override async IAsyncEnumerable<AgentRunResponseUpdate> RunStreamingAsync(
protected override async IAsyncEnumerable<AgentRunResponseUpdate> RunCoreStreamingAsync(
IEnumerable<ChatMessage> messages,
AgentThread? thread = null,
AgentRunOptions? options = null,
@@ -19,12 +19,12 @@ internal sealed class SharedStateAgent : DelegatingAIAgent
this._jsonSerializerOptions = jsonSerializerOptions;
}
public override Task<AgentRunResponse> RunAsync(IEnumerable<ChatMessage> messages, AgentThread? thread = null, AgentRunOptions? options = null, CancellationToken cancellationToken = default)
protected override Task<AgentRunResponse> RunCoreAsync(IEnumerable<ChatMessage> messages, AgentThread? thread = null, AgentRunOptions? options = null, CancellationToken cancellationToken = default)
{
return this.RunStreamingAsync(messages, thread, options, cancellationToken).ToAgentRunResponseAsync(cancellationToken);
return this.RunCoreStreamingAsync(messages, thread, options, cancellationToken).ToAgentRunResponseAsync(cancellationToken);
}
public override async IAsyncEnumerable<AgentRunResponseUpdate> RunStreamingAsync(
protected override async IAsyncEnumerable<AgentRunResponseUpdate> RunCoreStreamingAsync(
IEnumerable<ChatMessage> messages,
AgentThread? thread = null,
AgentRunOptions? options = null,
@@ -22,17 +22,17 @@ internal sealed class ServerFunctionApprovalClientAgent : DelegatingAIAgent
this._jsonSerializerOptions = jsonSerializerOptions;
}
public override Task<AgentRunResponse> RunAsync(
protected override Task<AgentRunResponse> RunCoreAsync(
IEnumerable<ChatMessage> messages,
AgentThread? thread = null,
AgentRunOptions? options = null,
CancellationToken cancellationToken = default)
{
return this.RunStreamingAsync(messages, thread, options, cancellationToken)
return this.RunCoreStreamingAsync(messages, thread, options, cancellationToken)
.ToAgentRunResponseAsync(cancellationToken);
}
public override async IAsyncEnumerable<AgentRunResponseUpdate> RunStreamingAsync(
protected override async IAsyncEnumerable<AgentRunResponseUpdate> RunCoreStreamingAsync(
IEnumerable<ChatMessage> messages,
AgentThread? thread = null,
AgentRunOptions? options = null,
@@ -22,17 +22,17 @@ internal sealed class ServerFunctionApprovalAgent : DelegatingAIAgent
this._jsonSerializerOptions = jsonSerializerOptions;
}
public override Task<AgentRunResponse> RunAsync(
protected override Task<AgentRunResponse> RunCoreAsync(
IEnumerable<ChatMessage> messages,
AgentThread? thread = null,
AgentRunOptions? options = null,
CancellationToken cancellationToken = default)
{
return this.RunStreamingAsync(messages, thread, options, cancellationToken)
return this.RunCoreStreamingAsync(messages, thread, options, cancellationToken)
.ToAgentRunResponseAsync(cancellationToken);
}
public override async IAsyncEnumerable<AgentRunResponseUpdate> RunStreamingAsync(
protected override async IAsyncEnumerable<AgentRunResponseUpdate> RunCoreStreamingAsync(
IEnumerable<ChatMessage> messages,
AgentThread? thread = null,
AgentRunOptions? options = null,
@@ -35,18 +35,18 @@ internal sealed class StatefulAgent<TState> : DelegatingAIAgent
}
/// <inheritdoc />
public override Task<AgentRunResponse> RunAsync(
protected override Task<AgentRunResponse> RunCoreAsync(
IEnumerable<ChatMessage> messages,
AgentThread? thread = null,
AgentRunOptions? options = null,
CancellationToken cancellationToken = default)
{
return this.RunStreamingAsync(messages, thread, options, cancellationToken)
return this.RunCoreStreamingAsync(messages, thread, options, cancellationToken)
.ToAgentRunResponseAsync(cancellationToken);
}
/// <inheritdoc />
public override async IAsyncEnumerable<AgentRunResponseUpdate> RunStreamingAsync(
protected override async IAsyncEnumerable<AgentRunResponseUpdate> RunCoreStreamingAsync(
IEnumerable<ChatMessage> messages,
AgentThread? thread = null,
AgentRunOptions? options = null,
@@ -17,17 +17,17 @@ internal sealed class SharedStateAgent : DelegatingAIAgent
this._jsonSerializerOptions = jsonSerializerOptions;
}
public override Task<AgentRunResponse> RunAsync(
protected override Task<AgentRunResponse> RunCoreAsync(
IEnumerable<ChatMessage> messages,
AgentThread? thread = null,
AgentRunOptions? options = null,
CancellationToken cancellationToken = default)
{
return this.RunStreamingAsync(messages, thread, options, cancellationToken)
return this.RunCoreStreamingAsync(messages, thread, options, cancellationToken)
.ToAgentRunResponseAsync(cancellationToken);
}
public override async IAsyncEnumerable<AgentRunResponseUpdate> RunStreamingAsync(
protected override async IAsyncEnumerable<AgentRunResponseUpdate> RunCoreStreamingAsync(
IEnumerable<ChatMessage> messages,
AgentThread? thread = null,
AgentRunOptions? options = null,
@@ -34,7 +34,7 @@ namespace SampleApp
public override AgentThread DeserializeThread(JsonElement serializedThread, JsonSerializerOptions? jsonSerializerOptions = null)
=> new CustomAgentThread(serializedThread, jsonSerializerOptions);
public override async Task<AgentRunResponse> RunAsync(IEnumerable<ChatMessage> messages, AgentThread? thread = null, AgentRunOptions? options = null, CancellationToken cancellationToken = default)
protected override async Task<AgentRunResponse> RunCoreAsync(IEnumerable<ChatMessage> messages, AgentThread? thread = null, AgentRunOptions? options = null, CancellationToken cancellationToken = default)
{
// Create a thread if the user didn't supply one.
thread ??= this.GetNewThread();
@@ -58,7 +58,7 @@ namespace SampleApp
};
}
public override async IAsyncEnumerable<AgentRunResponseUpdate> RunStreamingAsync(IEnumerable<ChatMessage> messages, AgentThread? thread = null, AgentRunOptions? options = null, [EnumeratorCancellation] CancellationToken cancellationToken = default)
protected override async IAsyncEnumerable<AgentRunResponseUpdate> RunCoreStreamingAsync(IEnumerable<ChatMessage> messages, AgentThread? thread = null, AgentRunOptions? options = null, [EnumeratorCancellation] CancellationToken cancellationToken = default)
{
// Create a thread if the user didn't supply one.
thread ??= this.GetNewThread();
@@ -87,10 +87,10 @@ public class OpenAIChatClientAgent : DelegatingAIAgent
}
/// <inheritdoc/>
public sealed override Task<AgentRunResponse> RunAsync(IEnumerable<Microsoft.Extensions.AI.ChatMessage> messages, AgentThread? thread = null, AgentRunOptions? options = null, CancellationToken cancellationToken = default) =>
base.RunAsync(messages, thread, options, cancellationToken);
protected sealed override Task<AgentRunResponse> RunCoreAsync(IEnumerable<Microsoft.Extensions.AI.ChatMessage> messages, AgentThread? thread = null, AgentRunOptions? options = null, CancellationToken cancellationToken = default) =>
base.RunCoreAsync(messages, thread, options, cancellationToken);
/// <inheritdoc/>
public override IAsyncEnumerable<AgentRunResponseUpdate> RunStreamingAsync(IEnumerable<Microsoft.Extensions.AI.ChatMessage> messages, AgentThread? thread = null, AgentRunOptions? options = null, CancellationToken cancellationToken = default) =>
base.RunStreamingAsync(messages, thread, options, cancellationToken);
protected override IAsyncEnumerable<AgentRunResponseUpdate> RunCoreStreamingAsync(IEnumerable<Microsoft.Extensions.AI.ChatMessage> messages, AgentThread? thread = null, AgentRunOptions? options = null, CancellationToken cancellationToken = default) =>
base.RunCoreStreamingAsync(messages, thread, options, cancellationToken);
}
@@ -105,10 +105,10 @@ public class OpenAIResponseClientAgent : DelegatingAIAgent
}
/// <inheritdoc/>
public sealed override Task<AgentRunResponse> RunAsync(IEnumerable<ChatMessage> messages, AgentThread? thread = null, AgentRunOptions? options = null, CancellationToken cancellationToken = default) =>
base.RunAsync(messages, thread, options, cancellationToken);
protected sealed override Task<AgentRunResponse> RunCoreAsync(IEnumerable<ChatMessage> messages, AgentThread? thread = null, AgentRunOptions? options = null, CancellationToken cancellationToken = default) =>
base.RunCoreAsync(messages, thread, options, cancellationToken);
/// <inheritdoc/>
public sealed override IAsyncEnumerable<AgentRunResponseUpdate> RunStreamingAsync(IEnumerable<ChatMessage> messages, AgentThread? thread = null, AgentRunOptions? options = null, CancellationToken cancellationToken = default) =>
base.RunStreamingAsync(messages, thread, options, cancellationToken);
protected sealed override IAsyncEnumerable<AgentRunResponseUpdate> RunCoreStreamingAsync(IEnumerable<ChatMessage> messages, AgentThread? thread = null, AgentRunOptions? options = null, CancellationToken cancellationToken = default) =>
base.RunCoreStreamingAsync(messages, thread, options, cancellationToken);
}
@@ -48,9 +48,9 @@ public class WeatherForecastAgent : DelegatingAIAgent
{
}
public override async Task<AgentRunResponse> RunAsync(IEnumerable<ChatMessage> messages, AgentThread? thread = null, AgentRunOptions? options = null, CancellationToken cancellationToken = default)
protected override async Task<AgentRunResponse> RunCoreAsync(IEnumerable<ChatMessage> messages, AgentThread? thread = null, AgentRunOptions? options = null, CancellationToken cancellationToken = default)
{
var response = await base.RunAsync(messages, thread, options, cancellationToken);
var response = await base.RunCoreAsync(messages, thread, options, cancellationToken);
// If the agent returned a valid structured output response
// we might be able to enhance the response with an adaptive card.
@@ -68,7 +68,7 @@ internal sealed class A2AAgent : AIAgent
=> new A2AAgentThread(serializedThread, jsonSerializerOptions);
/// <inheritdoc/>
public override async Task<AgentRunResponse> RunAsync(IEnumerable<ChatMessage> messages, AgentThread? thread = null, AgentRunOptions? options = null, CancellationToken cancellationToken = default)
protected override async Task<AgentRunResponse> RunCoreAsync(IEnumerable<ChatMessage> messages, AgentThread? thread = null, AgentRunOptions? options = null, CancellationToken cancellationToken = default)
{
_ = Throw.IfNull(messages);
@@ -131,7 +131,7 @@ internal sealed class A2AAgent : AIAgent
}
/// <inheritdoc/>
public override async IAsyncEnumerable<AgentRunResponseUpdate> RunStreamingAsync(IEnumerable<ChatMessage> messages, AgentThread? thread = null, AgentRunOptions? options = null, [EnumeratorCancellation] CancellationToken cancellationToken = default)
protected override async IAsyncEnumerable<AgentRunResponseUpdate> RunCoreStreamingAsync(IEnumerable<ChatMessage> messages, AgentThread? thread = null, AgentRunOptions? options = null, [EnumeratorCancellation] CancellationToken cancellationToken = default)
{
_ = Throw.IfNull(messages);
@@ -218,6 +218,35 @@ public abstract class AIAgent
/// <returns>A task that represents the asynchronous operation. The task result contains an <see cref="AgentRunResponse"/> with the agent's output.</returns>
/// <remarks>
/// <para>
/// This method delegates to <see cref="RunCoreAsync"/> to perform the actual agent invocation. It handles collections of messages,
/// allowing for complex conversational scenarios including multi-turn interactions, function calls, and
/// context-rich conversations.
/// </para>
/// <para>
/// The messages are processed in the order provided and become part of the conversation history.
/// The agent's response will also be added to <paramref name="thread"/> if one is provided.
/// </para>
/// </remarks>
public Task<AgentRunResponse> RunAsync(
IEnumerable<ChatMessage> messages,
AgentThread? thread = null,
AgentRunOptions? options = null,
CancellationToken cancellationToken = default) =>
this.RunCoreAsync(messages, thread, options, cancellationToken);
/// <summary>
/// Core implementation of the agent invocation logic with a collection of chat messages.
/// </summary>
/// <param name="messages">The collection of messages to send to the agent for processing.</param>
/// <param name="thread">
/// The conversation thread to use for this invocation. If <see langword="null"/>, a new thread will be created.
/// The thread will be updated with the input messages and any response messages generated during invocation.
/// </param>
/// <param name="options">Optional configuration parameters for controlling the agent's invocation behavior.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> to monitor for cancellation requests. The default is <see cref="CancellationToken.None"/>.</param>
/// <returns>A task that represents the asynchronous operation. The task result contains an <see cref="AgentRunResponse"/> with the agent's output.</returns>
/// <remarks>
/// <para>
/// This is the primary invocation method that implementations must override. It handles collections of messages,
/// allowing for complex conversational scenarios including multi-turn interactions, function calls, and
/// context-rich conversations.
@@ -227,7 +256,7 @@ public abstract class AIAgent
/// The agent's response will also be added to <paramref name="thread"/> if one is provided.
/// </para>
/// </remarks>
public abstract Task<AgentRunResponse> RunAsync(
protected abstract Task<AgentRunResponse> RunCoreAsync(
IEnumerable<ChatMessage> messages,
AgentThread? thread = null,
AgentRunOptions? options = null,
@@ -312,6 +341,34 @@ public abstract class AIAgent
/// <returns>An asynchronous enumerable of <see cref="AgentRunResponseUpdate"/> instances representing the streaming response.</returns>
/// <remarks>
/// <para>
/// This method delegates to <see cref="RunCoreStreamingAsync"/> to perform the actual streaming invocation. It provides real-time
/// updates as the agent processes the input and generates its response, enabling more responsive user experiences.
/// </para>
/// <para>
/// Each <see cref="AgentRunResponseUpdate"/> represents a portion of the complete response, allowing consumers
/// to display partial results, implement progressive loading, or provide immediate feedback to users.
/// </para>
/// </remarks>
public IAsyncEnumerable<AgentRunResponseUpdate> RunStreamingAsync(
IEnumerable<ChatMessage> messages,
AgentThread? thread = null,
AgentRunOptions? options = null,
CancellationToken cancellationToken = default) =>
this.RunCoreStreamingAsync(messages, thread, options, cancellationToken);
/// <summary>
/// Core implementation of the agent streaming invocation logic with a collection of chat messages.
/// </summary>
/// <param name="messages">The collection of messages to send to the agent for processing.</param>
/// <param name="thread">
/// The conversation thread to use for this invocation. If <see langword="null"/>, a new thread will be created.
/// The thread will be updated with the input messages and any response updates generated during invocation.
/// </param>
/// <param name="options">Optional configuration parameters for controlling the agent's invocation behavior.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> to monitor for cancellation requests. The default is <see cref="CancellationToken.None"/>.</param>
/// <returns>An asynchronous enumerable of <see cref="AgentRunResponseUpdate"/> instances representing the streaming response.</returns>
/// <remarks>
/// <para>
/// This is the primary streaming invocation method that implementations must override. It provides real-time
/// updates as the agent processes the input and generates its response, enabling more responsive user experiences.
/// </para>
@@ -320,7 +377,7 @@ public abstract class AIAgent
/// to display partial results, implement progressive loading, or provide immediate feedback to users.
/// </para>
/// </remarks>
public abstract IAsyncEnumerable<AgentRunResponseUpdate> RunStreamingAsync(
protected abstract IAsyncEnumerable<AgentRunResponseUpdate> RunCoreStreamingAsync(
IEnumerable<ChatMessage> messages,
AgentThread? thread = null,
AgentRunOptions? options = null,
@@ -81,7 +81,7 @@ public abstract class DelegatingAIAgent : AIAgent
=> this.InnerAgent.DeserializeThread(serializedThread, jsonSerializerOptions);
/// <inheritdoc />
public override Task<AgentRunResponse> RunAsync(
protected override Task<AgentRunResponse> RunCoreAsync(
IEnumerable<ChatMessage> messages,
AgentThread? thread = null,
AgentRunOptions? options = null,
@@ -89,7 +89,7 @@ public abstract class DelegatingAIAgent : AIAgent
=> this.InnerAgent.RunAsync(messages, thread, options, cancellationToken);
/// <inheritdoc />
public override IAsyncEnumerable<AgentRunResponseUpdate> RunStreamingAsync(
protected override IAsyncEnumerable<AgentRunResponseUpdate> RunCoreStreamingAsync(
IEnumerable<ChatMessage> messages,
AgentThread? thread = null,
AgentRunOptions? options = null,
@@ -58,7 +58,7 @@ public class CopilotStudioAgent : AIAgent
=> new CopilotStudioAgentThread(serializedThread, jsonSerializerOptions);
/// <inheritdoc/>
public override async Task<AgentRunResponse> RunAsync(
protected override async Task<AgentRunResponse> RunCoreAsync(
IEnumerable<ChatMessage> messages,
AgentThread? thread = null,
AgentRunOptions? options = null,
@@ -96,7 +96,7 @@ public class CopilotStudioAgent : AIAgent
}
/// <inheritdoc/>
public override async IAsyncEnumerable<AgentRunResponseUpdate> RunStreamingAsync(
protected override async IAsyncEnumerable<AgentRunResponseUpdate> RunCoreStreamingAsync(
IEnumerable<ChatMessage> messages,
AgentThread? thread = null,
AgentRunOptions? options = null,
@@ -63,7 +63,7 @@ public sealed class DurableAIAgent : AIAgent
/// <exception cref="AgentNotRegisteredException">Thrown when the agent has not been registered.</exception>
/// <exception cref="ArgumentException">Thrown when the provided thread is not valid for a durable agent.</exception>
/// <exception cref="NotSupportedException">Thrown when cancellation is requested (cancellation is not supported for durable agents).</exception>
public override async Task<AgentRunResponse> RunAsync(
protected override async Task<AgentRunResponse> RunCoreAsync(
IEnumerable<ChatMessage> messages,
AgentThread? thread = null,
AgentRunOptions? options = null,
@@ -128,7 +128,7 @@ public sealed class DurableAIAgent : AIAgent
/// <param name="options">Optional run options.</param>
/// <param name="cancellationToken">The cancellation token.</param>
/// <returns>A streaming response enumerable.</returns>
public override async IAsyncEnumerable<AgentRunResponseUpdate> RunStreamingAsync(
protected override async IAsyncEnumerable<AgentRunResponseUpdate> RunCoreStreamingAsync(
IEnumerable<ChatMessage> messages,
AgentThread? thread = null,
AgentRunOptions? options = null,
@@ -23,7 +23,7 @@ internal class DurableAIAgentProxy(string name, IDurableAgentClient agentClient)
return new DurableAgentThread(AgentSessionId.WithRandomKey(this.Name!));
}
public override async Task<AgentRunResponse> RunAsync(
protected override async Task<AgentRunResponse> RunCoreAsync(
IEnumerable<ChatMessage> messages,
AgentThread? thread = null,
AgentRunOptions? options = null,
@@ -70,7 +70,7 @@ internal class DurableAIAgentProxy(string name, IDurableAgentClient agentClient)
return await agentRunHandle.ReadAgentResponseAsync(cancellationToken);
}
public override IAsyncEnumerable<AgentRunResponseUpdate> RunStreamingAsync(
protected override IAsyncEnumerable<AgentRunResponseUpdate> RunCoreStreamingAsync(
IEnumerable<ChatMessage> messages,
AgentThread? thread = null,
AgentRunOptions? options = null,
@@ -21,13 +21,13 @@ internal sealed class EntityAgentWrapper(
// The ID of the agent is always the entity ID.
protected override string? IdCore => this._entityContext.Id.ToString();
public override async Task<AgentRunResponse> RunAsync(
protected override async Task<AgentRunResponse> RunCoreAsync(
IEnumerable<ChatMessage> messages,
AgentThread? thread = null,
AgentRunOptions? options = null,
CancellationToken cancellationToken = default)
{
AgentRunResponse response = await base.RunAsync(
AgentRunResponse response = await base.RunCoreAsync(
messages,
thread,
this.GetAgentEntityRunOptions(options),
@@ -37,13 +37,13 @@ internal sealed class EntityAgentWrapper(
return response;
}
public override async IAsyncEnumerable<AgentRunResponseUpdate> RunStreamingAsync(
protected override async IAsyncEnumerable<AgentRunResponseUpdate> RunCoreStreamingAsync(
IEnumerable<ChatMessage> messages,
AgentThread? thread = null,
AgentRunOptions? options = null,
[EnumeratorCancellation] CancellationToken cancellationToken = default)
{
await foreach (AgentRunResponseUpdate update in base.RunStreamingAsync(
await foreach (AgentRunResponseUpdate update in base.RunCoreStreamingAsync(
messages,
thread,
this.GetAgentEntityRunOptions(options),
@@ -42,13 +42,13 @@ internal class PurviewAgent : AIAgent, IDisposable
}
/// <inheritdoc/>
public override Task<AgentRunResponse> RunAsync(IEnumerable<ChatMessage> messages, AgentThread? thread = null, AgentRunOptions? options = null, CancellationToken cancellationToken = default)
protected override Task<AgentRunResponse> RunCoreAsync(IEnumerable<ChatMessage> messages, AgentThread? thread = null, AgentRunOptions? options = null, CancellationToken cancellationToken = default)
{
return this._purviewWrapper.ProcessAgentContentAsync(messages, thread, options, this._innerAgent, cancellationToken);
}
/// <inheritdoc/>
public override async IAsyncEnumerable<AgentRunResponseUpdate> RunStreamingAsync(IEnumerable<ChatMessage> messages, AgentThread? thread = null, AgentRunOptions? options = null, [EnumeratorCancellation] CancellationToken cancellationToken = default)
protected override async IAsyncEnumerable<AgentRunResponseUpdate> RunCoreStreamingAsync(IEnumerable<ChatMessage> messages, AgentThread? thread = null, AgentRunOptions? options = null, [EnumeratorCancellation] CancellationToken cancellationToken = default)
{
var response = await this._purviewWrapper.ProcessAgentContentAsync(messages, thread, options, this._innerAgent, cancellationToken).ConfigureAwait(false);
foreach (var update in response.ToAgentRunResponseUpdates())
@@ -79,8 +79,8 @@ internal sealed class WorkflowHostAgent : AIAgent
return workflowThread;
}
public override async
Task<AgentRunResponse> RunAsync(
protected override async
Task<AgentRunResponse> RunCoreAsync(
IEnumerable<ChatMessage> messages,
AgentThread? thread = null,
AgentRunOptions? options = null,
@@ -101,8 +101,8 @@ internal sealed class WorkflowHostAgent : AIAgent
return merger.ComputeMerged(workflowThread.LastResponseId!, this.Id, this.Name);
}
public override async
IAsyncEnumerable<AgentRunResponseUpdate> RunStreamingAsync(
protected override async
IAsyncEnumerable<AgentRunResponseUpdate> RunCoreStreamingAsync(
IEnumerable<ChatMessage> messages,
AgentThread? thread = null,
AgentRunOptions? options = null,
@@ -17,18 +17,18 @@ namespace Microsoft.Agents.AI;
/// </remarks>
internal sealed class AnonymousDelegatingAIAgent : DelegatingAIAgent
{
/// <summary>The delegate to use as the implementation of <see cref="RunAsync"/>.</summary>
/// <summary>The delegate to use as the implementation of <see cref="RunCoreAsync"/>.</summary>
private readonly Func<IEnumerable<ChatMessage>, AgentThread?, AgentRunOptions?, AIAgent, CancellationToken, Task<AgentRunResponse>>? _runFunc;
/// <summary>The delegate to use as the implementation of <see cref="RunStreamingAsync"/>.</summary>
/// <summary>The delegate to use as the implementation of <see cref="RunCoreStreamingAsync"/>.</summary>
/// <remarks>
/// When non-<see langword="null"/>, this delegate is used as the implementation of <see cref="RunStreamingAsync"/> and
/// When non-<see langword="null"/>, this delegate is used as the implementation of <see cref="RunCoreStreamingAsync"/> and
/// will be invoked with the same arguments as the method itself.
/// When <see langword="null"/>, <see cref="RunStreamingAsync"/> will delegate directly to the inner agent.
/// When <see langword="null"/>, <see cref="RunCoreStreamingAsync"/> will delegate directly to the inner agent.
/// </remarks>
private readonly Func<IEnumerable<ChatMessage>, AgentThread?, AgentRunOptions?, AIAgent, CancellationToken, IAsyncEnumerable<AgentRunResponseUpdate>>? _runStreamingFunc;
/// <summary>The delegate to use as the implementation of both <see cref="RunAsync"/> and <see cref="RunStreamingAsync"/>.</summary>
/// <summary>The delegate to use as the implementation of both <see cref="RunCoreAsync"/> and <see cref="RunCoreStreamingAsync"/>.</summary>
private readonly Func<IEnumerable<ChatMessage>, AgentThread?, AgentRunOptions?, Func<IEnumerable<ChatMessage>, AgentThread?, AgentRunOptions?, CancellationToken, Task>, CancellationToken, Task>? _sharedFunc;
/// <summary>
@@ -36,7 +36,7 @@ internal sealed class AnonymousDelegatingAIAgent : DelegatingAIAgent
/// </summary>
/// <param name="innerAgent">The inner agent.</param>
/// <param name="sharedFunc">
/// A delegate that provides the implementation for both <see cref="RunAsync"/> and <see cref="RunStreamingAsync"/>.
/// A delegate that provides the implementation for both <see cref="RunCoreAsync"/> and <see cref="RunCoreStreamingAsync"/>.
/// In addition to the arguments for the operation, it's provided with a delegate to the inner agent that should be
/// used to perform the operation on the inner agent. It will handle both the non-streaming and streaming cases.
/// </param>
@@ -61,13 +61,13 @@ internal sealed class AnonymousDelegatingAIAgent : DelegatingAIAgent
/// </summary>
/// <param name="innerAgent">The inner agent.</param>
/// <param name="runFunc">
/// A delegate that provides the implementation for <see cref="RunAsync"/>. When <see langword="null"/>,
/// <paramref name="runStreamingFunc"/> must be non-null, and the implementation of <see cref="RunAsync"/>
/// A delegate that provides the implementation for <see cref="RunCoreAsync"/>. When <see langword="null"/>,
/// <paramref name="runStreamingFunc"/> must be non-null, and the implementation of <see cref="RunCoreAsync"/>
/// will use <paramref name="runStreamingFunc"/> for the implementation.
/// </param>
/// <param name="runStreamingFunc">
/// A delegate that provides the implementation for <see cref="RunStreamingAsync"/>. When <see langword="null"/>,
/// <paramref name="runFunc"/> must be non-null, and the implementation of <see cref="RunStreamingAsync"/>
/// A delegate that provides the implementation for <see cref="RunCoreStreamingAsync"/>. When <see langword="null"/>,
/// <paramref name="runFunc"/> must be non-null, and the implementation of <see cref="RunCoreStreamingAsync"/>
/// will use <paramref name="runFunc"/> for the implementation.
/// </param>
/// <exception cref="ArgumentNullException"><paramref name="innerAgent"/> is <see langword="null"/>.</exception>
@@ -85,7 +85,7 @@ internal sealed class AnonymousDelegatingAIAgent : DelegatingAIAgent
}
/// <inheritdoc/>
public override Task<AgentRunResponse> RunAsync(
protected override Task<AgentRunResponse> RunCoreAsync(
IEnumerable<ChatMessage> messages,
AgentThread? thread = null,
AgentRunOptions? options = null,
@@ -132,7 +132,7 @@ internal sealed class AnonymousDelegatingAIAgent : DelegatingAIAgent
}
/// <inheritdoc/>
public override IAsyncEnumerable<AgentRunResponseUpdate> RunStreamingAsync(
protected override IAsyncEnumerable<AgentRunResponseUpdate> RunCoreStreamingAsync(
IEnumerable<ChatMessage> messages,
AgentThread? thread = null,
AgentRunOptions? options = null,
@@ -149,7 +149,7 @@ public sealed partial class ChatClientAgent : AIAgent
internal ChatOptions? ChatOptions => this._agentOptions?.ChatOptions;
/// <inheritdoc/>
public override Task<AgentRunResponse> RunAsync(
protected override Task<AgentRunResponse> RunCoreAsync(
IEnumerable<ChatMessage> messages,
AgentThread? thread = null,
AgentRunOptions? options = null,
@@ -193,7 +193,7 @@ public sealed partial class ChatClientAgent : AIAgent
}
/// <inheritdoc/>
public override async IAsyncEnumerable<AgentRunResponseUpdate> RunStreamingAsync(
protected override async IAsyncEnumerable<AgentRunResponseUpdate> RunCoreStreamingAsync(
IEnumerable<ChatMessage> messages,
AgentThread? thread = null,
AgentRunOptions? options = null,
@@ -21,10 +21,10 @@ internal sealed class FunctionInvocationDelegatingAgent : DelegatingAIAgent
this._delegateFunc = delegateFunc;
}
public override Task<AgentRunResponse> RunAsync(IEnumerable<ChatMessage> messages, AgentThread? thread = null, AgentRunOptions? options = null, CancellationToken cancellationToken = default)
protected override Task<AgentRunResponse> RunCoreAsync(IEnumerable<ChatMessage> messages, AgentThread? thread = null, AgentRunOptions? options = null, CancellationToken cancellationToken = default)
=> this.InnerAgent.RunAsync(messages, thread, this.AgentRunOptionsWithFunctionMiddleware(options), cancellationToken);
public override IAsyncEnumerable<AgentRunResponseUpdate> RunStreamingAsync(IEnumerable<ChatMessage> messages, AgentThread? thread = null, AgentRunOptions? options = null, CancellationToken cancellationToken = default)
protected override IAsyncEnumerable<AgentRunResponseUpdate> RunCoreStreamingAsync(IEnumerable<ChatMessage> messages, AgentThread? thread = null, AgentRunOptions? options = null, CancellationToken cancellationToken = default)
=> this.InnerAgent.RunStreamingAsync(messages, thread, this.AgentRunOptionsWithFunctionMiddleware(options), cancellationToken);
// Decorate options to add the middleware function
@@ -55,7 +55,7 @@ public sealed partial class LoggingAgent : DelegatingAIAgent
}
/// <inheritdoc/>
public override async Task<AgentRunResponse> RunAsync(
protected override async Task<AgentRunResponse> RunCoreAsync(
IEnumerable<ChatMessage> messages, AgentThread? thread = null, AgentRunOptions? options = null, CancellationToken cancellationToken = default)
{
if (this._logger.IsEnabled(LogLevel.Debug))
@@ -72,7 +72,7 @@ public sealed partial class LoggingAgent : DelegatingAIAgent
try
{
AgentRunResponse response = await base.RunAsync(messages, thread, options, cancellationToken).ConfigureAwait(false);
AgentRunResponse response = await base.RunCoreAsync(messages, thread, options, cancellationToken).ConfigureAwait(false);
if (this._logger.IsEnabled(LogLevel.Debug))
{
@@ -101,7 +101,7 @@ public sealed partial class LoggingAgent : DelegatingAIAgent
}
/// <inheritdoc/>
public override async IAsyncEnumerable<AgentRunResponseUpdate> RunStreamingAsync(
protected override async IAsyncEnumerable<AgentRunResponseUpdate> RunCoreStreamingAsync(
IEnumerable<ChatMessage> messages, AgentThread? thread = null, AgentRunOptions? options = null, [EnumeratorCancellation] CancellationToken cancellationToken = default)
{
if (this._logger.IsEnabled(LogLevel.Debug))
@@ -119,7 +119,7 @@ public sealed partial class LoggingAgent : DelegatingAIAgent
IAsyncEnumerator<AgentRunResponseUpdate> e;
try
{
e = base.RunStreamingAsync(messages, thread, options, cancellationToken).GetAsyncEnumerator(cancellationToken);
e = base.RunCoreStreamingAsync(messages, thread, options, cancellationToken).GetAsyncEnumerator(cancellationToken);
}
catch (OperationCanceledException)
{
@@ -78,7 +78,7 @@ public sealed class OpenTelemetryAgent : DelegatingAIAgent, IDisposable
}
/// <inheritdoc/>
public override async Task<AgentRunResponse> RunAsync(
protected override async Task<AgentRunResponse> RunCoreAsync(
IEnumerable<ChatMessage> messages, AgentThread? thread = null, AgentRunOptions? options = null, CancellationToken cancellationToken = default)
{
ChatOptions co = new ForwardedOptions(options, thread, Activity.Current);
@@ -89,7 +89,7 @@ public sealed class OpenTelemetryAgent : DelegatingAIAgent, IDisposable
}
/// <inheritdoc/>
public override async IAsyncEnumerable<AgentRunResponseUpdate> RunStreamingAsync(
protected override async IAsyncEnumerable<AgentRunResponseUpdate> RunCoreStreamingAsync(
IEnumerable<ChatMessage> messages, AgentThread? thread = null, AgentRunOptions? options = null, [EnumeratorCancellation] CancellationToken cancellationToken = default)
{
ChatOptions co = new ForwardedOptions(options, thread, Activity.Current);
@@ -8,6 +8,7 @@ using System.Threading;
using System.Threading.Tasks;
using Microsoft.Extensions.AI;
using Moq;
using Moq.Protected;
namespace Microsoft.Agents.AI.Abstractions.UnitTests;
@@ -33,18 +34,20 @@ public class AIAgentTests
this._agentMock = new Mock<AIAgent> { CallBase = true };
this._agentMock
.Setup(x => x.RunAsync(
It.IsAny<IReadOnlyCollection<ChatMessage>>(),
this._agentThreadMock.Object,
It.IsAny<AgentRunOptions?>(),
It.IsAny<CancellationToken>()))
.Protected()
.Setup<Task<AgentRunResponse>>("RunCoreAsync",
ItExpr.IsAny<IEnumerable<ChatMessage>>(),
ItExpr.Is<AgentThread?>(t => t == this._agentThreadMock.Object),
ItExpr.IsAny<AgentRunOptions?>(),
ItExpr.IsAny<CancellationToken>())
.ReturnsAsync(this._invokeResponse);
this._agentMock
.Setup(x => x.RunStreamingAsync(
It.IsAny<IReadOnlyCollection<ChatMessage>>(),
this._agentThreadMock.Object,
It.IsAny<AgentRunOptions?>(),
It.IsAny<CancellationToken>()))
.Protected()
.Setup<IAsyncEnumerable<AgentRunResponseUpdate>>("RunCoreStreamingAsync",
ItExpr.IsAny<IEnumerable<ChatMessage>>(),
ItExpr.Is<AgentThread?>(t => t == this._agentThreadMock.Object),
ItExpr.IsAny<AgentRunOptions?>(),
ItExpr.IsAny<CancellationToken>())
.Returns(ToAsyncEnumerableAsync(this._invokeStreamingResponses));
}
@@ -64,13 +67,14 @@ public class AIAgentTests
Assert.Equal(this._invokeResponse, response);
// Verify that the mocked method was called with the expected parameters
this._agentMock.Verify(
x => x.RunAsync(
It.Is<IReadOnlyCollection<ChatMessage>>(messages => messages.Count == 0),
this._agentThreadMock.Object,
options,
cancellationToken),
Times.Once);
this._agentMock
.Protected()
.Verify<Task<AgentRunResponse>>("RunCoreAsync",
Times.Once(),
ItExpr.Is<IEnumerable<ChatMessage>>(messages => !messages.Any()),
ItExpr.Is<AgentThread?>(t => t == this._agentThreadMock.Object),
ItExpr.Is<AgentRunOptions?>(o => o == options),
ItExpr.Is<CancellationToken>(ct => ct == cancellationToken));
}
/// <summary>
@@ -90,13 +94,14 @@ public class AIAgentTests
Assert.Equal(this._invokeResponse, response);
// Verify that the mocked method was called with the expected parameters
this._agentMock.Verify(
x => x.RunAsync(
It.Is<IReadOnlyCollection<ChatMessage>>(messages => messages.Count == 1 && messages.First().Text == Message),
this._agentThreadMock.Object,
options,
cancellationToken),
Times.Once);
this._agentMock
.Protected()
.Verify<Task<AgentRunResponse>>("RunCoreAsync",
Times.Once(),
ItExpr.Is<IEnumerable<ChatMessage>>(messages => messages.Count() == 1 && messages.First().Text == Message),
ItExpr.Is<AgentThread?>(t => t == this._agentThreadMock.Object),
ItExpr.Is<AgentRunOptions?>(o => o == options),
ItExpr.Is<CancellationToken>(ct => ct == cancellationToken));
}
/// <summary>
@@ -116,13 +121,14 @@ public class AIAgentTests
Assert.Equal(this._invokeResponse, response);
// Verify that the mocked method was called with the expected parameters
this._agentMock.Verify(
x => x.RunAsync(
It.Is<IReadOnlyCollection<ChatMessage>>(messages => messages.Count == 1 && messages.First() == message),
this._agentThreadMock.Object,
options,
cancellationToken),
Times.Once);
this._agentMock
.Protected()
.Verify<Task<AgentRunResponse>>("RunCoreAsync",
Times.Once(),
ItExpr.Is<IEnumerable<ChatMessage>>(messages => messages.Count() == 1 && messages.First() == message),
ItExpr.Is<AgentThread?>(t => t == this._agentThreadMock.Object),
ItExpr.Is<AgentRunOptions?>(o => o == options),
ItExpr.Is<CancellationToken>(ct => ct == cancellationToken));
}
/// <summary>
@@ -144,13 +150,14 @@ public class AIAgentTests
}
// Verify that the mocked method was called with the expected parameters
this._agentMock.Verify(
x => x.RunStreamingAsync(
It.Is<IReadOnlyCollection<ChatMessage>>(messages => messages.Count == 0),
this._agentThreadMock.Object,
options,
cancellationToken),
Times.Once);
this._agentMock
.Protected()
.Verify<IAsyncEnumerable<AgentRunResponseUpdate>>("RunCoreStreamingAsync",
Times.Once(),
ItExpr.Is<IEnumerable<ChatMessage>>(messages => !messages.Any()),
ItExpr.Is<AgentThread?>(t => t == this._agentThreadMock.Object),
ItExpr.Is<AgentRunOptions?>(o => o == options),
ItExpr.Is<CancellationToken>(ct => ct == cancellationToken));
}
/// <summary>
@@ -173,13 +180,14 @@ public class AIAgentTests
}
// Verify that the mocked method was called with the expected parameters
this._agentMock.Verify(
x => x.RunStreamingAsync(
It.Is<IReadOnlyCollection<ChatMessage>>(messages => messages.Count == 1 && messages.First().Text == Message),
this._agentThreadMock.Object,
options,
cancellationToken),
Times.Once);
this._agentMock
.Protected()
.Verify<IAsyncEnumerable<AgentRunResponseUpdate>>("RunCoreStreamingAsync",
Times.Once(),
ItExpr.Is<IEnumerable<ChatMessage>>(messages => messages.Count() == 1 && messages.First().Text == Message),
ItExpr.Is<AgentThread?>(t => t == this._agentThreadMock.Object),
ItExpr.Is<AgentRunOptions?>(o => o == options),
ItExpr.Is<CancellationToken>(ct => ct == cancellationToken));
}
/// <summary>
@@ -202,13 +210,14 @@ public class AIAgentTests
}
// Verify that the mocked method was called with the expected parameters
this._agentMock.Verify(
x => x.RunStreamingAsync(
It.Is<IReadOnlyCollection<ChatMessage>>(messages => messages.Count == 1 && messages.First() == message),
this._agentThreadMock.Object,
options,
cancellationToken),
Times.Once);
this._agentMock
.Protected()
.Verify<IAsyncEnumerable<AgentRunResponseUpdate>>("RunCoreStreamingAsync",
Times.Once(),
ItExpr.Is<IEnumerable<ChatMessage>>(messages => messages.Count() == 1 && messages.First() == message),
ItExpr.Is<AgentThread?>(t => t == this._agentThreadMock.Object),
ItExpr.Is<AgentRunOptions?>(o => o == options),
ItExpr.Is<CancellationToken>(ct => ct == cancellationToken));
}
[Fact]
@@ -375,14 +384,14 @@ public class AIAgentTests
public override AgentThread DeserializeThread(JsonElement serializedThread, JsonSerializerOptions? jsonSerializerOptions = null)
=> throw new NotImplementedException();
public override Task<AgentRunResponse> RunAsync(
protected override Task<AgentRunResponse> RunCoreAsync(
IEnumerable<ChatMessage> messages,
AgentThread? thread = null,
AgentRunOptions? options = null,
CancellationToken cancellationToken = default) =>
throw new NotImplementedException();
public override IAsyncEnumerable<AgentRunResponseUpdate> RunStreamingAsync(
protected override IAsyncEnumerable<AgentRunResponseUpdate> RunCoreStreamingAsync(
IEnumerable<ChatMessage> messages,
AgentThread? thread = null,
AgentRunOptions? options = null,
@@ -38,19 +38,21 @@ public class DelegatingAIAgentTests
this._innerAgentMock.Setup(x => x.GetNewThread()).Returns(this._testThread);
this._innerAgentMock
.Setup(x => x.RunAsync(
It.IsAny<IReadOnlyCollection<ChatMessage>>(),
It.IsAny<AgentThread?>(),
It.IsAny<AgentRunOptions?>(),
It.IsAny<CancellationToken>()))
.Protected()
.Setup<Task<AgentRunResponse>>("RunCoreAsync",
ItExpr.IsAny<IEnumerable<ChatMessage>>(),
ItExpr.IsAny<AgentThread?>(),
ItExpr.IsAny<AgentRunOptions?>(),
ItExpr.IsAny<CancellationToken>())
.ReturnsAsync(this._testResponse);
this._innerAgentMock
.Setup(x => x.RunStreamingAsync(
It.IsAny<IReadOnlyCollection<ChatMessage>>(),
It.IsAny<AgentThread?>(),
It.IsAny<AgentRunOptions?>(),
It.IsAny<CancellationToken>()))
.Protected()
.Setup<IAsyncEnumerable<AgentRunResponseUpdate>>("RunCoreStreamingAsync",
ItExpr.IsAny<IEnumerable<ChatMessage>>(),
ItExpr.IsAny<AgentThread?>(),
ItExpr.IsAny<AgentRunOptions?>(),
ItExpr.IsAny<CancellationToken>())
.Returns(ToAsyncEnumerableAsync(this._testStreamingResponses));
this._delegatingAgent = new TestDelegatingAIAgent(this._innerAgentMock.Object);
@@ -159,7 +161,12 @@ public class DelegatingAIAgentTests
var innerAgentMock = new Mock<AIAgent>();
innerAgentMock
.Setup(x => x.RunAsync(expectedMessages, expectedThread, expectedOptions, expectedCancellationToken))
.Protected()
.Setup<Task<AgentRunResponse>>("RunCoreAsync",
ItExpr.Is<IEnumerable<ChatMessage>>(m => m == expectedMessages),
ItExpr.Is<AgentThread?>(t => t == expectedThread),
ItExpr.Is<AgentRunOptions?>(o => o == expectedOptions),
ItExpr.Is<CancellationToken>(ct => ct == expectedCancellationToken))
.Returns(expectedResult.Task);
var delegatingAgent = new TestDelegatingAIAgent(innerAgentMock.Object);
@@ -193,7 +200,12 @@ public class DelegatingAIAgentTests
var innerAgentMock = new Mock<AIAgent>();
innerAgentMock
.Setup(x => x.RunStreamingAsync(expectedMessages, expectedThread, expectedOptions, expectedCancellationToken))
.Protected()
.Setup<IAsyncEnumerable<AgentRunResponseUpdate>>("RunCoreStreamingAsync",
ItExpr.Is<IEnumerable<ChatMessage>>(m => m == expectedMessages),
ItExpr.Is<AgentThread?>(t => t == expectedThread),
ItExpr.Is<AgentRunOptions?>(o => o == expectedOptions),
ItExpr.Is<CancellationToken>(ct => ct == expectedCancellationToken))
.Returns(ToAsyncEnumerableAsync(expectedResults));
var delegatingAgent = new TestDelegatingAIAgent(innerAgentMock.Object);
@@ -76,12 +76,12 @@ public sealed class AggregatorPromptAgentFactoryTests
throw new NotImplementedException();
}
public override Task<AgentRunResponse> RunAsync(IEnumerable<ChatMessage> messages, AgentThread? thread = null, AgentRunOptions? options = null, CancellationToken cancellationToken = default)
protected override Task<AgentRunResponse> RunCoreAsync(IEnumerable<ChatMessage> messages, AgentThread? thread = null, AgentRunOptions? options = null, CancellationToken cancellationToken = default)
{
throw new NotImplementedException();
}
public override IAsyncEnumerable<AgentRunResponseUpdate> RunStreamingAsync(IEnumerable<ChatMessage> messages, AgentThread? thread = null, AgentRunOptions? options = null, CancellationToken cancellationToken = default)
protected override IAsyncEnumerable<AgentRunResponseUpdate> RunCoreStreamingAsync(IEnumerable<ChatMessage> messages, AgentThread? thread = null, AgentRunOptions? options = null, CancellationToken cancellationToken = default)
{
throw new NotImplementedException();
}
@@ -290,7 +290,7 @@ internal sealed class FakeChatClientAgent : AIAgent
return new FakeInMemoryAgentThread(serializedThread, jsonSerializerOptions);
}
public override async Task<AgentRunResponse> RunAsync(
protected override async Task<AgentRunResponse> RunCoreAsync(
IEnumerable<ChatMessage> messages,
AgentThread? thread = null,
AgentRunOptions? options = null,
@@ -305,7 +305,7 @@ internal sealed class FakeChatClientAgent : AIAgent
return updates.ToAgentRunResponse();
}
public override async IAsyncEnumerable<AgentRunResponseUpdate> RunStreamingAsync(
protected override async IAsyncEnumerable<AgentRunResponseUpdate> RunCoreStreamingAsync(
IEnumerable<ChatMessage> messages,
AgentThread? thread = null,
AgentRunOptions? options = null,
@@ -358,7 +358,7 @@ internal sealed class FakeMultiMessageAgent : AIAgent
return new FakeInMemoryAgentThread(serializedThread, jsonSerializerOptions);
}
public override async Task<AgentRunResponse> RunAsync(
protected override async Task<AgentRunResponse> RunCoreAsync(
IEnumerable<ChatMessage> messages,
AgentThread? thread = null,
AgentRunOptions? options = null,
@@ -373,7 +373,7 @@ internal sealed class FakeMultiMessageAgent : AIAgent
return updates.ToAgentRunResponse();
}
public override async IAsyncEnumerable<AgentRunResponseUpdate> RunStreamingAsync(
protected override async IAsyncEnumerable<AgentRunResponseUpdate> RunCoreStreamingAsync(
IEnumerable<ChatMessage> messages,
AgentThread? thread = null,
AgentRunOptions? options = null,
@@ -303,12 +303,12 @@ internal sealed class FakeForwardedPropsAgent : AIAgent
public JsonElement ReceivedForwardedProperties { get; private set; }
public override Task<AgentRunResponse> RunAsync(IEnumerable<ChatMessage> messages, AgentThread? thread = null, AgentRunOptions? options = null, CancellationToken cancellationToken = default)
protected override Task<AgentRunResponse> RunCoreAsync(IEnumerable<ChatMessage> messages, AgentThread? thread = null, AgentRunOptions? options = null, CancellationToken cancellationToken = default)
{
return this.RunStreamingAsync(messages, thread, options, cancellationToken).ToAgentRunResponseAsync(cancellationToken);
return this.RunCoreStreamingAsync(messages, thread, options, cancellationToken).ToAgentRunResponseAsync(cancellationToken);
}
public override async IAsyncEnumerable<AgentRunResponseUpdate> RunStreamingAsync(
protected override async IAsyncEnumerable<AgentRunResponseUpdate> RunCoreStreamingAsync(
IEnumerable<ChatMessage> messages,
AgentThread? thread = null,
AgentRunOptions? options = null,
@@ -342,12 +342,12 @@ internal sealed class FakeStateAgent : AIAgent
{
public override string? Description => "Agent for state testing";
public override Task<AgentRunResponse> RunAsync(IEnumerable<ChatMessage> messages, AgentThread? thread = null, AgentRunOptions? options = null, CancellationToken cancellationToken = default)
protected override Task<AgentRunResponse> RunCoreAsync(IEnumerable<ChatMessage> messages, AgentThread? thread = null, AgentRunOptions? options = null, CancellationToken cancellationToken = default)
{
return this.RunStreamingAsync(messages, thread, options, cancellationToken).ToAgentRunResponseAsync(cancellationToken);
return this.RunCoreStreamingAsync(messages, thread, options, cancellationToken).ToAgentRunResponseAsync(cancellationToken);
}
public override async IAsyncEnumerable<AgentRunResponseUpdate> RunStreamingAsync(
protected override async IAsyncEnumerable<AgentRunResponseUpdate> RunCoreStreamingAsync(
IEnumerable<ChatMessage> messages,
AgentThread? thread = null,
AgentRunOptions? options = null,
@@ -430,12 +430,12 @@ public sealed class AGUIEndpointRouteBuilderExtensionsTests
public override AgentThread DeserializeThread(JsonElement serializedThread, JsonSerializerOptions? jsonSerializerOptions = null) =>
new TestInMemoryAgentThread(serializedThread, jsonSerializerOptions);
public override Task<AgentRunResponse> RunAsync(IEnumerable<ChatMessage> messages, AgentThread? thread = null, AgentRunOptions? options = null, CancellationToken cancellationToken = default)
protected override Task<AgentRunResponse> RunCoreAsync(IEnumerable<ChatMessage> messages, AgentThread? thread = null, AgentRunOptions? options = null, CancellationToken cancellationToken = default)
{
throw new NotImplementedException();
}
public override async IAsyncEnumerable<AgentRunResponseUpdate> RunStreamingAsync(
protected override async IAsyncEnumerable<AgentRunResponseUpdate> RunCoreStreamingAsync(
IEnumerable<ChatMessage> messages,
AgentThread? thread = null,
AgentRunOptions? options = null,
@@ -519,12 +519,12 @@ public sealed class AGUIEndpointRouteBuilderExtensionsTests
public override AgentThread DeserializeThread(JsonElement serializedThread, JsonSerializerOptions? jsonSerializerOptions = null) =>
new TestInMemoryAgentThread(serializedThread, jsonSerializerOptions);
public override Task<AgentRunResponse> RunAsync(IEnumerable<ChatMessage> messages, AgentThread? thread = null, AgentRunOptions? options = null, CancellationToken cancellationToken = default)
protected override Task<AgentRunResponse> RunCoreAsync(IEnumerable<ChatMessage> messages, AgentThread? thread = null, AgentRunOptions? options = null, CancellationToken cancellationToken = default)
{
throw new NotImplementedException();
}
public override async IAsyncEnumerable<AgentRunResponseUpdate> RunStreamingAsync(
protected override async IAsyncEnumerable<AgentRunResponseUpdate> RunCoreStreamingAsync(
IEnumerable<ChatMessage> messages,
AgentThread? thread = null,
AgentRunOptions? options = null,
@@ -17,13 +17,13 @@ internal sealed class TestAgent(string name, string description) : AIAgent
JsonElement serializedThread,
JsonSerializerOptions? jsonSerializerOptions = null) => new DummyAgentThread();
public override Task<AgentRunResponse> RunAsync(
protected override Task<AgentRunResponse> RunCoreAsync(
IEnumerable<ChatMessage> messages,
AgentThread? thread = null,
AgentRunOptions? options = null,
CancellationToken cancellationToken = default) => Task.FromResult(new AgentRunResponse([.. messages]));
public override IAsyncEnumerable<AgentRunResponseUpdate> RunStreamingAsync(
protected override IAsyncEnumerable<AgentRunResponseUpdate> RunCoreStreamingAsync(
IEnumerable<ChatMessage> messages,
AgentThread? thread = null,
AgentRunOptions? options = null,
@@ -6,6 +6,7 @@ using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using Moq;
using Moq.Protected;
using ChatMessage = Microsoft.Extensions.AI.ChatMessage;
using ChatRole = Microsoft.Extensions.AI.ChatRole;
using OpenAIChatMessage = OpenAI.Chat.ChatMessage;
@@ -76,22 +77,28 @@ public sealed class AIAgentWithOpenAIExtensionsTests
var responseMessage = new ChatMessage(ChatRole.Assistant, [new TextContent(ResponseText)]);
mockAgent
.Setup(a => a.RunAsync(It.IsAny<IEnumerable<ChatMessage>>(), It.IsAny<AgentThread?>(), It.IsAny<AgentRunOptions?>(), It.IsAny<CancellationToken>()))
.Protected()
.Setup<Task<AgentRunResponse>>("RunCoreAsync",
ItExpr.IsAny<IEnumerable<ChatMessage>>(),
ItExpr.IsAny<AgentThread?>(),
ItExpr.IsAny<AgentRunOptions?>(),
ItExpr.IsAny<CancellationToken>())
.ReturnsAsync(new AgentRunResponse([responseMessage]));
// Act
var result = await mockAgent.Object.RunAsync(openAiMessages, mockThread.Object, options, cancellationToken);
// Assert
mockAgent.Verify(
a => a.RunAsync(
It.Is<IEnumerable<ChatMessage>>(msgs =>
mockAgent.Protected()
.Verify("RunCoreAsync",
Times.Once(),
ItExpr.Is<IEnumerable<ChatMessage>>(msgs =>
msgs.ToList().Count == 1 &&
msgs.ToList()[0].Text == TestMessageText),
mockThread.Object,
options,
cancellationToken),
Times.Once);
cancellationToken
);
Assert.NotNull(result);
Assert.NotEmpty(result.Content);
@@ -160,7 +167,12 @@ public sealed class AIAgentWithOpenAIExtensionsTests
};
mockAgent
.Setup(a => a.RunStreamingAsync(It.IsAny<IEnumerable<ChatMessage>>(), It.IsAny<AgentThread?>(), It.IsAny<AgentRunOptions?>(), It.IsAny<CancellationToken>()))
.Protected()
.Setup<IAsyncEnumerable<AgentRunResponseUpdate>>("RunCoreStreamingAsync",
ItExpr.IsAny<IEnumerable<ChatMessage>>(),
ItExpr.IsAny<AgentThread?>(),
ItExpr.IsAny<AgentRunOptions?>(),
ItExpr.IsAny<CancellationToken>())
.Returns(ToAsyncEnumerableAsync(responseUpdates));
// Act
@@ -172,15 +184,16 @@ public sealed class AIAgentWithOpenAIExtensionsTests
}
// Assert
mockAgent.Verify(
a => a.RunStreamingAsync(
It.Is<IEnumerable<ChatMessage>>(msgs =>
mockAgent.Protected()
.Verify("RunCoreStreamingAsync",
Times.Once(),
ItExpr.Is<IEnumerable<ChatMessage>>(msgs =>
msgs.ToList().Count == 1 &&
msgs.ToList()[0].Text == TestMessageText),
mockThread.Object,
options,
cancellationToken),
Times.Once);
cancellationToken
);
Assert.True(updateCount > 0, "Expected at least one streaming update");
}
@@ -8,6 +8,7 @@ using Microsoft.Agents.AI.Purview.Models.Common;
using Microsoft.Extensions.AI;
using Microsoft.Extensions.Logging.Abstractions;
using Moq;
using Moq.Protected;
namespace Microsoft.Agents.AI.Purview.UnitTests;
@@ -277,11 +278,13 @@ public sealed class PurviewWrapperTests : IDisposable
Assert.Single(result.Messages);
Assert.Equal(ChatRole.System, result.Messages[0].Role);
Assert.Equal("Prompt blocked by policy", result.Messages[0].Text);
mockAgent.Verify(x => x.RunAsync(
It.IsAny<IEnumerable<ChatMessage>>(),
It.IsAny<AgentThread>(),
It.IsAny<AgentRunOptions>(),
It.IsAny<CancellationToken>()), Times.Never);
mockAgent.Protected().Verify("RunCoreAsync",
Times.Never(),
ItExpr.IsAny<IEnumerable<ChatMessage>>(),
ItExpr.IsAny<AgentThread>(),
ItExpr.IsAny<AgentRunOptions>(),
ItExpr.IsAny<CancellationToken>());
}
[Fact]
@@ -295,11 +298,12 @@ public sealed class PurviewWrapperTests : IDisposable
var mockAgent = new Mock<AIAgent>();
var innerResponse = new AgentRunResponse(new ChatMessage(ChatRole.Assistant, "Sensitive response"));
mockAgent.Setup(x => x.RunAsync(
It.IsAny<IEnumerable<ChatMessage>>(),
It.IsAny<AgentThread>(),
It.IsAny<AgentRunOptions>(),
It.IsAny<CancellationToken>()))
mockAgent.Protected()
.Setup<Task<AgentRunResponse>>("RunCoreAsync",
ItExpr.IsAny<IEnumerable<ChatMessage>>(),
ItExpr.IsAny<AgentThread>(),
ItExpr.IsAny<AgentRunOptions>(),
ItExpr.IsAny<CancellationToken>())
.ReturnsAsync(innerResponse);
this._mockProcessor.SetupSequence(x => x.ProcessMessagesAsync(
@@ -333,11 +337,12 @@ public sealed class PurviewWrapperTests : IDisposable
var mockAgent = new Mock<AIAgent>();
var innerResponse = new AgentRunResponse(new ChatMessage(ChatRole.Assistant, "Safe response"));
mockAgent.Setup(x => x.RunAsync(
It.IsAny<IEnumerable<ChatMessage>>(),
It.IsAny<AgentThread>(),
It.IsAny<AgentRunOptions>(),
It.IsAny<CancellationToken>()))
mockAgent.Protected()
.Setup<Task<AgentRunResponse>>("RunCoreAsync",
ItExpr.IsAny<IEnumerable<ChatMessage>>(),
ItExpr.IsAny<AgentThread>(),
ItExpr.IsAny<AgentRunOptions>(),
ItExpr.IsAny<CancellationToken>())
.ReturnsAsync(innerResponse);
this._mockProcessor.Setup(x => x.ProcessMessagesAsync(
@@ -375,11 +380,12 @@ public sealed class PurviewWrapperTests : IDisposable
var expectedResponse = new AgentRunResponse(new ChatMessage(ChatRole.Assistant, "Response from inner agent"));
var mockAgent = new Mock<AIAgent>();
mockAgent.Setup(x => x.RunAsync(
It.IsAny<IEnumerable<ChatMessage>>(),
It.IsAny<AgentThread>(),
It.IsAny<AgentRunOptions>(),
It.IsAny<CancellationToken>()))
mockAgent.Protected()
.Setup<Task<AgentRunResponse>>("RunCoreAsync",
ItExpr.IsAny<IEnumerable<ChatMessage>>(),
ItExpr.IsAny<AgentThread>(),
ItExpr.IsAny<AgentRunOptions>(),
ItExpr.IsAny<CancellationToken>())
.ReturnsAsync(expectedResponse);
this._mockProcessor.SetupSequence(x => x.ProcessMessagesAsync(
@@ -441,11 +447,12 @@ public sealed class PurviewWrapperTests : IDisposable
var expectedResponse = new AgentRunResponse(new ChatMessage(ChatRole.Assistant, "Response"));
var mockAgent = new Mock<AIAgent>();
mockAgent.Setup(x => x.RunAsync(
It.IsAny<IEnumerable<ChatMessage>>(),
It.IsAny<AgentThread>(),
It.IsAny<AgentRunOptions>(),
It.IsAny<CancellationToken>()))
mockAgent.Protected()
.Setup<Task<AgentRunResponse>>("RunCoreAsync",
ItExpr.IsAny<IEnumerable<ChatMessage>>(),
ItExpr.IsAny<AgentThread>(),
ItExpr.IsAny<AgentRunOptions>(),
ItExpr.IsAny<CancellationToken>())
.ReturnsAsync(expectedResponse);
this._mockProcessor.Setup(x => x.ProcessMessagesAsync(
@@ -482,11 +489,12 @@ public sealed class PurviewWrapperTests : IDisposable
var expectedResponse = new AgentRunResponse(new ChatMessage(ChatRole.Assistant, "Response"));
var mockAgent = new Mock<AIAgent>();
mockAgent.Setup(x => x.RunAsync(
It.IsAny<IEnumerable<ChatMessage>>(),
It.IsAny<AgentThread>(),
It.IsAny<AgentRunOptions>(),
It.IsAny<CancellationToken>()))
mockAgent.Protected()
.Setup<Task<AgentRunResponse>>("RunCoreAsync",
ItExpr.IsAny<IEnumerable<ChatMessage>>(),
ItExpr.IsAny<AgentThread>(),
ItExpr.IsAny<AgentRunOptions>(),
ItExpr.IsAny<CancellationToken>())
.ReturnsAsync(expectedResponse);
string? capturedThreadId = null;
@@ -521,11 +529,12 @@ public sealed class PurviewWrapperTests : IDisposable
var mockAgent = new Mock<AIAgent>();
var innerResponse = new AgentRunResponse(new ChatMessage(ChatRole.Assistant, "Response"));
mockAgent.Setup(x => x.RunAsync(
It.IsAny<IEnumerable<ChatMessage>>(),
It.IsAny<AgentThread>(),
It.IsAny<AgentRunOptions>(),
It.IsAny<CancellationToken>()))
mockAgent.Protected()
.Setup<Task<AgentRunResponse>>("RunCoreAsync",
ItExpr.IsAny<IEnumerable<ChatMessage>>(),
ItExpr.IsAny<AgentThread>(),
ItExpr.IsAny<AgentRunOptions>(),
ItExpr.IsAny<CancellationToken>())
.ReturnsAsync(innerResponse);
var callCount = 0;
@@ -337,7 +337,7 @@ public class AgentExtensionsTests
public CancellationToken LastCancellationToken { get; private set; }
public int RunAsyncCallCount { get; private set; }
public override Task<AgentRunResponse> RunAsync(
protected override Task<AgentRunResponse> RunCoreAsync(
IEnumerable<ChatMessage> messages,
AgentThread? thread = null,
AgentRunOptions? options = null,
@@ -355,7 +355,7 @@ public class AgentExtensionsTests
return Task.FromResult(this._responseToReturn!);
}
public override async IAsyncEnumerable<AgentRunResponseUpdate> RunStreamingAsync(
protected override async IAsyncEnumerable<AgentRunResponseUpdate> RunCoreStreamingAsync(
IEnumerable<ChatMessage> messages,
AgentThread? thread = null,
AgentRunOptions? options = null,
@@ -8,6 +8,7 @@ using System.Threading;
using System.Threading.Tasks;
using Microsoft.Extensions.AI;
using Moq;
using Moq.Protected;
namespace Microsoft.Agents.AI.UnitTests;
@@ -35,18 +36,22 @@ public class AnonymousDelegatingAIAgentTests
new AgentRunResponseUpdate(ChatRole.Assistant, "Response 2")
];
this._innerAgentMock.Setup(x => x.RunAsync(
It.IsAny<IEnumerable<ChatMessage>>(),
It.IsAny<AgentThread?>(),
It.IsAny<AgentRunOptions?>(),
It.IsAny<CancellationToken>()))
this._innerAgentMock
.Protected()
.Setup<Task<AgentRunResponse>>("RunCoreAsync",
ItExpr.IsAny<IEnumerable<ChatMessage>>(),
ItExpr.IsAny<AgentThread?>(),
ItExpr.IsAny<AgentRunOptions?>(),
ItExpr.IsAny<CancellationToken>())
.ReturnsAsync(this._testResponse);
this._innerAgentMock.Setup(x => x.RunStreamingAsync(
It.IsAny<IEnumerable<ChatMessage>>(),
It.IsAny<AgentThread?>(),
It.IsAny<AgentRunOptions?>(),
It.IsAny<CancellationToken>()))
this._innerAgentMock
.Protected()
.Setup<IAsyncEnumerable<AgentRunResponseUpdate>>("RunCoreStreamingAsync",
ItExpr.IsAny<IEnumerable<ChatMessage>>(),
ItExpr.IsAny<AgentThread?>(),
ItExpr.IsAny<AgentRunOptions?>(),
ItExpr.IsAny<CancellationToken>())
.Returns(ToAsyncEnumerableAsync(this._testStreamingResponses));
}
@@ -184,11 +189,14 @@ public class AnonymousDelegatingAIAgentTests
Assert.Same(this._testOptions, capturedOptions);
Assert.Equal(expectedCancellationToken, capturedCancellationToken);
this._innerAgentMock.Verify(x => x.RunAsync(
this._testMessages,
this._testThread,
this._testOptions,
expectedCancellationToken), Times.Once);
this._innerAgentMock
.Protected()
.Verify<Task<AgentRunResponse>>("RunCoreAsync",
Times.Once(),
ItExpr.Is<IEnumerable<ChatMessage>>(m => m == this._testMessages),
ItExpr.Is<AgentThread?>(t => t == this._testThread),
ItExpr.Is<AgentRunOptions?>(o => o == this._testOptions),
ItExpr.Is<CancellationToken>(ct => ct == expectedCancellationToken));
}
/// <summary>
@@ -458,11 +466,13 @@ public class AnonymousDelegatingAIAgentTests
capturedValue = asyncLocal.Value;
});
this._innerAgentMock.Setup(x => x.RunAsync(
It.IsAny<IEnumerable<ChatMessage>>(),
It.IsAny<AgentThread?>(),
It.IsAny<AgentRunOptions?>(),
It.IsAny<CancellationToken>()))
this._innerAgentMock
.Protected()
.Setup<Task<AgentRunResponse>>("RunCoreAsync",
ItExpr.IsAny<IEnumerable<ChatMessage>>(),
ItExpr.IsAny<AgentThread?>(),
ItExpr.IsAny<AgentRunOptions?>(),
ItExpr.IsAny<CancellationToken>())
.Returns(() =>
{
// Verify AsyncLocal value is available in inner agent call
@@ -926,11 +936,13 @@ public class AnonymousDelegatingAIAgentTests
var capturedTokens = new List<CancellationToken>();
// Setup mock to throw OperationCanceledException when cancelled token is used
this._innerAgentMock.Setup(x => x.RunAsync(
It.IsAny<IEnumerable<ChatMessage>>(),
It.IsAny<AgentThread?>(),
It.IsAny<AgentRunOptions?>(),
It.Is<CancellationToken>(ct => ct.IsCancellationRequested)))
this._innerAgentMock
.Protected()
.Setup<Task<AgentRunResponse>>("RunCoreAsync",
ItExpr.IsAny<IEnumerable<ChatMessage>>(),
ItExpr.IsAny<AgentThread?>(),
ItExpr.IsAny<AgentRunOptions?>(),
ItExpr.Is<CancellationToken>(ct => ct.IsCancellationRequested))
.ThrowsAsync(new OperationCanceledException());
var agent = new AIAgentBuilder(this._innerAgentMock.Object)
@@ -993,11 +1005,14 @@ public class AnonymousDelegatingAIAgentTests
Assert.Equal(expectedOrder, executionOrder);
// Verify inner agent was never called
this._innerAgentMock.Verify(x => x.RunAsync(
It.IsAny<IEnumerable<ChatMessage>>(),
It.IsAny<AgentThread?>(),
It.IsAny<AgentRunOptions?>(),
It.IsAny<CancellationToken>()), Times.Never);
this._innerAgentMock
.Protected()
.Verify<Task<AgentRunResponse>>("RunCoreAsync",
Times.Never(),
ItExpr.IsAny<IEnumerable<ChatMessage>>(),
ItExpr.IsAny<AgentThread?>(),
ItExpr.IsAny<AgentRunOptions?>(),
ItExpr.IsAny<CancellationToken>());
}
#endregion
@@ -30,10 +30,10 @@ internal sealed class TestAIAgent : AIAgent
public override AgentThread GetNewThread() =>
this.GetNewThreadFunc();
public override Task<AgentRunResponse> RunAsync(IEnumerable<ChatMessage> messages, AgentThread? thread = null, AgentRunOptions? options = null, CancellationToken cancellationToken = default) =>
protected override Task<AgentRunResponse> RunCoreAsync(IEnumerable<ChatMessage> messages, AgentThread? thread = null, AgentRunOptions? options = null, CancellationToken cancellationToken = default) =>
this.RunAsyncFunc(messages, thread, options, cancellationToken);
public override IAsyncEnumerable<AgentRunResponseUpdate> RunStreamingAsync(IEnumerable<ChatMessage> messages, AgentThread? thread = null, AgentRunOptions? options = null, CancellationToken cancellationToken = default) =>
protected override IAsyncEnumerable<AgentRunResponseUpdate> RunCoreStreamingAsync(IEnumerable<ChatMessage> messages, AgentThread? thread = null, AgentRunOptions? options = null, CancellationToken cancellationToken = default) =>
this.RunStreamingAsyncFunc(messages, thread, options, cancellationToken);
public override object? GetService(Type serviceType, object? serviceKey = null) =>
@@ -141,11 +141,11 @@ public class AgentWorkflowBuilderTests
public override AgentThread DeserializeThread(JsonElement serializedThread, JsonSerializerOptions? jsonSerializerOptions = null)
=> new DoubleEchoAgentThread();
public override Task<AgentRunResponse> RunAsync(
protected override Task<AgentRunResponse> RunCoreAsync(
IEnumerable<ChatMessage> messages, AgentThread? thread = null, AgentRunOptions? options = null, CancellationToken cancellationToken = default) =>
throw new NotImplementedException();
public override async IAsyncEnumerable<AgentRunResponseUpdate> RunStreamingAsync(
protected override async IAsyncEnumerable<AgentRunResponseUpdate> RunCoreStreamingAsync(
IEnumerable<ChatMessage> messages, AgentThread? thread = null, AgentRunOptions? options = null, [EnumeratorCancellation] CancellationToken cancellationToken = default)
{
await Task.Yield();
@@ -409,7 +409,7 @@ public class AgentWorkflowBuilderTests
private sealed class DoubleEchoAgentWithBarrier(string name, StrongBox<TaskCompletionSource<bool>> barrier, StrongBox<int> remaining) : DoubleEchoAgent(name)
{
public override async IAsyncEnumerable<AgentRunResponseUpdate> RunStreamingAsync(
protected override async IAsyncEnumerable<AgentRunResponseUpdate> RunCoreStreamingAsync(
IEnumerable<ChatMessage> messages, AgentThread? thread = null, AgentRunOptions? options = null, [EnumeratorCancellation] CancellationToken cancellationToken = default)
{
if (Interlocked.Decrement(ref remaining.Value) == 0)
@@ -419,7 +419,7 @@ public class AgentWorkflowBuilderTests
await barrier.Value!.Task.ConfigureAwait(false);
await foreach (var update in base.RunStreamingAsync(messages, thread, options, cancellationToken))
await foreach (var update in base.RunCoreStreamingAsync(messages, thread, options, cancellationToken))
{
await Task.Yield();
yield return update;
@@ -149,7 +149,7 @@ public class InProcessExecutionTests
public override AgentThread DeserializeThread(System.Text.Json.JsonElement serializedThread,
System.Text.Json.JsonSerializerOptions? jsonSerializerOptions = null) => new SimpleTestAgentThread();
public override Task<AgentRunResponse> RunAsync(
protected override Task<AgentRunResponse> RunCoreAsync(
IEnumerable<ChatMessage> messages,
AgentThread? thread = null,
AgentRunOptions? options = null,
@@ -160,7 +160,7 @@ public class InProcessExecutionTests
return Task.FromResult(new AgentRunResponse(responseMessage));
}
public override async IAsyncEnumerable<AgentRunResponseUpdate> RunStreamingAsync(
protected override async IAsyncEnumerable<AgentRunResponseUpdate> RunCoreStreamingAsync(
IEnumerable<ChatMessage> messages,
AgentThread? thread = null,
AgentRunOptions? options = null,
@@ -30,10 +30,10 @@ public class RepresentationTests
public override AgentThread DeserializeThread(JsonElement serializedThread, JsonSerializerOptions? jsonSerializerOptions = null)
=> throw new NotImplementedException();
public override Task<AgentRunResponse> RunAsync(IEnumerable<ChatMessage> messages, AgentThread? thread = null, AgentRunOptions? options = null, CancellationToken cancellationToken = default) =>
protected override Task<AgentRunResponse> RunCoreAsync(IEnumerable<ChatMessage> messages, AgentThread? thread = null, AgentRunOptions? options = null, CancellationToken cancellationToken = default) =>
throw new NotImplementedException();
public override IAsyncEnumerable<AgentRunResponseUpdate> RunStreamingAsync(IEnumerable<ChatMessage> messages, AgentThread? thread = null, AgentRunOptions? options = null, CancellationToken cancellationToken = default) =>
protected override IAsyncEnumerable<AgentRunResponseUpdate> RunCoreStreamingAsync(IEnumerable<ChatMessage> messages, AgentThread? thread = null, AgentRunOptions? options = null, CancellationToken cancellationToken = default) =>
throw new NotImplementedException();
}
@@ -66,17 +66,17 @@ internal sealed class HelloAgent(string id = nameof(HelloAgent)) : AIAgent
public override AgentThread DeserializeThread(JsonElement serializedThread, JsonSerializerOptions? jsonSerializerOptions = null)
=> new HelloAgentThread();
public override async Task<AgentRunResponse> RunAsync(IEnumerable<ChatMessage> messages, AgentThread? thread = null, AgentRunOptions? options = null, CancellationToken cancellationToken = default)
protected override async Task<AgentRunResponse> RunCoreAsync(IEnumerable<ChatMessage> messages, AgentThread? thread = null, AgentRunOptions? options = null, CancellationToken cancellationToken = default)
{
IEnumerable<AgentRunResponseUpdate> update = [
await this.RunStreamingAsync(messages, thread, options, cancellationToken)
await this.RunCoreStreamingAsync(messages, thread, options, cancellationToken)
.SingleAsync(cancellationToken)
.ConfigureAwait(false)];
return update.ToAgentRunResponse();
}
public override async IAsyncEnumerable<AgentRunResponseUpdate> RunStreamingAsync(IEnumerable<ChatMessage> messages, AgentThread? thread = null, AgentRunOptions? options = null, [EnumeratorCancellation] CancellationToken cancellationToken = default)
protected override async IAsyncEnumerable<AgentRunResponseUpdate> RunCoreStreamingAsync(IEnumerable<ChatMessage> messages, AgentThread? thread = null, AgentRunOptions? options = null, [EnumeratorCancellation] CancellationToken cancellationToken = default)
{
yield return new(ChatRole.Assistant, "Hello World!")
{
@@ -62,14 +62,14 @@ public class SpecializedExecutorSmokeTests
public List<ChatMessage> Messages { get; } = Validate(messages) ?? [];
public override Task<AgentRunResponse> RunAsync(IEnumerable<ChatMessage> messages, AgentThread? thread = null, AgentRunOptions? options = null, CancellationToken cancellationToken = default) =>
protected override Task<AgentRunResponse> RunCoreAsync(IEnumerable<ChatMessage> messages, AgentThread? thread = null, AgentRunOptions? options = null, CancellationToken cancellationToken = default) =>
Task.FromResult(new AgentRunResponse(this.Messages)
{
AgentId = this.Id,
ResponseId = Guid.NewGuid().ToString("N")
});
public override async IAsyncEnumerable<AgentRunResponseUpdate> RunStreamingAsync(IEnumerable<ChatMessage> messages, AgentThread? thread = null, AgentRunOptions? options = null, [EnumeratorCancellation] CancellationToken cancellationToken = default)
protected override async IAsyncEnumerable<AgentRunResponseUpdate> RunCoreStreamingAsync(IEnumerable<ChatMessage> messages, AgentThread? thread = null, AgentRunOptions? options = null, [EnumeratorCancellation] CancellationToken cancellationToken = default)
{
string responseId = Guid.NewGuid().ToString("N");
foreach (ChatMessage message in this.Messages)
@@ -60,7 +60,7 @@ internal class TestEchoAgent(string? id = null, string? name = null, string? pre
return [];
}
public override Task<AgentRunResponse> RunAsync(IEnumerable<ChatMessage> messages, AgentThread? thread = null, AgentRunOptions? options = null, CancellationToken cancellationToken = default)
protected override Task<AgentRunResponse> RunCoreAsync(IEnumerable<ChatMessage> messages, AgentThread? thread = null, AgentRunOptions? options = null, CancellationToken cancellationToken = default)
{
AgentRunResponse result =
new(this.EchoMessages(messages, thread, options).ToList())
@@ -73,7 +73,7 @@ internal class TestEchoAgent(string? id = null, string? name = null, string? pre
return Task.FromResult(result);
}
public override async IAsyncEnumerable<AgentRunResponseUpdate> RunStreamingAsync(IEnumerable<ChatMessage> messages, AgentThread? thread = null, AgentRunOptions? options = null, [EnumeratorCancellation] CancellationToken cancellationToken = default)
protected override async IAsyncEnumerable<AgentRunResponseUpdate> RunCoreStreamingAsync(IEnumerable<ChatMessage> messages, AgentThread? thread = null, AgentRunOptions? options = null, [EnumeratorCancellation] CancellationToken cancellationToken = default)
{
string responseId = Guid.NewGuid().ToString("N");