Suggested tweaks to Agent (#88)

- Id should return a stable ID, not a different value per access
- The RunAsync virtuals needn't be virtuals... a derived type can/should override just the main worker abstract method
- The protected methods should do argument validation
This commit is contained in:
Stephen Toub
2025-06-24 11:57:40 -04:00
committed by GitHub
Unverified
parent feed6f4651
commit e7b559fa62
2 changed files with 20 additions and 7 deletions
@@ -21,7 +21,7 @@ public abstract class Agent
/// <value>
/// The identifier of the agent. The default is a random GUID value, but for service agents, it will match the id of the agent in the service.
/// </value>
public virtual string Id => Guid.NewGuid().ToString();
public virtual string Id { get; } = Guid.NewGuid().ToString();
/// <summary>
/// Gets the name of the agent (optional).
@@ -60,7 +60,7 @@ public abstract class Agent
/// <param name="options">Optional parameters for agent invocation.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> to monitor for cancellation requests. The default is <see cref="CancellationToken.None"/>.</param>
/// <returns>A <see cref="ChatResponse"/> containing the list of <see cref="ChatMessage"/> items.</returns>
public virtual Task<ChatResponse> RunAsync(
public Task<ChatResponse> RunAsync(
AgentThread? thread = null,
AgentRunOptions? options = null,
CancellationToken cancellationToken = default)
@@ -79,7 +79,7 @@ public abstract class Agent
/// <remarks>
/// The provided message string will be treated as a user message.
/// </remarks>
public virtual Task<ChatResponse> RunAsync(
public Task<ChatResponse> RunAsync(
string message,
AgentThread? thread = null,
AgentRunOptions? options = null,
@@ -98,7 +98,7 @@ public abstract class Agent
/// <param name="options">Optional parameters for agent invocation.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> to monitor for cancellation requests. The default is <see cref="CancellationToken.None"/>.</param>
/// <returns>A <see cref="ChatResponse"/> containing the list of <see cref="ChatMessage"/> items.</returns>
public virtual Task<ChatResponse> RunAsync(
public Task<ChatResponse> RunAsync(
ChatMessage message,
AgentThread? thread = null,
AgentRunOptions? options = null,
@@ -130,7 +130,7 @@ public abstract class Agent
/// <param name="options">Optional parameters for agent invocation.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> to monitor for cancellation requests. The default is <see cref="CancellationToken.None"/>.</param>
/// <returns>An async list of response items that each contain a <see cref="ChatResponseUpdate"/>.</returns>
public virtual IAsyncEnumerable<ChatResponseUpdate> RunStreamingAsync(
public IAsyncEnumerable<ChatResponseUpdate> RunStreamingAsync(
AgentThread? thread = null,
AgentRunOptions? options = null,
CancellationToken cancellationToken = default)
@@ -149,7 +149,7 @@ public abstract class Agent
/// <remarks>
/// The provided message string will be treated as a user message.
/// </remarks>
public virtual IAsyncEnumerable<ChatResponseUpdate> RunStreamingAsync(
public IAsyncEnumerable<ChatResponseUpdate> RunStreamingAsync(
string message,
AgentThread? thread = null,
AgentRunOptions? options = null,
@@ -168,7 +168,7 @@ public abstract class Agent
/// <param name="options">Optional parameters for agent invocation.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> to monitor for cancellation requests. The default is <see cref="CancellationToken.None"/>.</param>
/// <returns>An async list of response items that each contain a <see cref="ChatResponseUpdate"/>.</returns>
public virtual IAsyncEnumerable<ChatResponseUpdate> RunStreamingAsync(
public IAsyncEnumerable<ChatResponseUpdate> RunStreamingAsync(
ChatMessage message,
AgentThread? thread = null,
AgentRunOptions? options = null,
@@ -241,6 +241,9 @@ public abstract class Agent
/// <returns>An async task that completes once the notification is complete.</returns>
protected async Task NotifyThreadOfNewMessagesAsync(AgentThread thread, IReadOnlyCollection<ChatMessage> messages, CancellationToken cancellationToken)
{
_ = Throw.IfNull(thread);
_ = Throw.IfNull(messages);
if (messages.Count > 0)
{
await thread.OnNewMessagesAsync(messages, cancellationToken).ConfigureAwait(false);
@@ -211,6 +211,16 @@ public class AgentTests
Times.Once);
}
[Fact]
public void ValidateAgentIDIsIdempotent()
{
var agent = new MockAgent();
string id = agent.Id;
Assert.NotNull(id);
Assert.Equal(id, agent.Id);
}
[Fact]
public void ValidateOrCreateThreadTypeVerifiesAndCreatesThread()
{