mirror of
https://github.com/microsoft/agent-framework.git
synced 2026-06-16 21:04:09 +08:00
.NET: Require thread for background responses (#2498)
* require thread for backgraund responses * address pr review feedback
This commit is contained in:
committed by
GitHub
Unverified
parent
257e717608
commit
e769256976
@@ -75,11 +75,7 @@ internal sealed class A2AAgent : AIAgent
|
||||
{
|
||||
_ = Throw.IfNull(messages);
|
||||
|
||||
thread ??= this.GetNewThread();
|
||||
if (thread is not A2AAgentThread typedThread)
|
||||
{
|
||||
throw new InvalidOperationException("The provided thread is not compatible with the agent. Only threads created by the agent can be used.");
|
||||
}
|
||||
A2AAgentThread typedThread = this.GetA2AThread(thread, options);
|
||||
|
||||
this._logger.LogA2AAgentInvokingAgent(nameof(RunAsync), this.Id, this.Name);
|
||||
|
||||
@@ -142,11 +138,7 @@ internal sealed class A2AAgent : AIAgent
|
||||
{
|
||||
_ = Throw.IfNull(messages);
|
||||
|
||||
thread ??= this.GetNewThread();
|
||||
if (thread is not A2AAgentThread typedThread)
|
||||
{
|
||||
throw new InvalidOperationException("The provided thread is not compatible with the agent. Only threads created by the agent can be used.");
|
||||
}
|
||||
A2AAgentThread typedThread = this.GetA2AThread(thread, options);
|
||||
|
||||
this._logger.LogA2AAgentInvokingAgent(nameof(RunStreamingAsync), this.Id, this.Name);
|
||||
|
||||
@@ -217,6 +209,26 @@ internal sealed class A2AAgent : AIAgent
|
||||
/// <inheritdoc/>
|
||||
public override string? Description => this._description ?? base.Description;
|
||||
|
||||
private A2AAgentThread GetA2AThread(AgentThread? thread, AgentRunOptions? options)
|
||||
{
|
||||
// Aligning with other agent implementations that support background responses, where
|
||||
// a thread is required for background responses to prevent inconsistent experience
|
||||
// for callers if they forget to provide the thread for initial or follow-up runs.
|
||||
if (options?.AllowBackgroundResponses is true && thread is null)
|
||||
{
|
||||
throw new InvalidOperationException("A thread must be provided when AllowBackgroundResponses is enabled.");
|
||||
}
|
||||
|
||||
thread ??= this.GetNewThread();
|
||||
|
||||
if (thread is not A2AAgentThread typedThread)
|
||||
{
|
||||
throw new InvalidOperationException($"The provided thread type {thread.GetType()} is not compatible with the agent. Only A2A agent created threads are supported.");
|
||||
}
|
||||
|
||||
return typedThread;
|
||||
}
|
||||
|
||||
private static void UpdateThread(A2AAgentThread? thread, string? contextId, string? taskId = null)
|
||||
{
|
||||
if (thread is null)
|
||||
|
||||
@@ -799,12 +799,80 @@ public sealed class A2AAgentTests : IDisposable
|
||||
Assert.Equal(TaskId, a2aThread.TaskId);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task RunAsync_WithAllowBackgroundResponsesAndNoThread_ThrowsInvalidOperationExceptionAsync()
|
||||
{
|
||||
// Arrange
|
||||
var inputMessages = new List<ChatMessage>
|
||||
{
|
||||
new(ChatRole.User, "Test message")
|
||||
};
|
||||
|
||||
var options = new AgentRunOptions { AllowBackgroundResponses = true };
|
||||
|
||||
// Act & Assert
|
||||
await Assert.ThrowsAsync<InvalidOperationException>(() => this._agent.RunAsync(inputMessages, null, options));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task RunStreamingAsync_WithAllowBackgroundResponsesAndNoThread_ThrowsInvalidOperationExceptionAsync()
|
||||
{
|
||||
// Arrange
|
||||
var inputMessages = new List<ChatMessage>
|
||||
{
|
||||
new(ChatRole.User, "Test message")
|
||||
};
|
||||
|
||||
var options = new AgentRunOptions { AllowBackgroundResponses = true };
|
||||
|
||||
// Act & Assert
|
||||
await Assert.ThrowsAsync<InvalidOperationException>(async () =>
|
||||
{
|
||||
await foreach (var _ in this._agent.RunStreamingAsync(inputMessages, null, options))
|
||||
{
|
||||
// Just iterate through to trigger the exception
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task RunAsync_WithInvalidThreadType_ThrowsInvalidOperationExceptionAsync()
|
||||
{
|
||||
// Arrange
|
||||
// Create a thread from a different agent type
|
||||
var invalidThread = new CustomAgentThread();
|
||||
|
||||
// Act & Assert
|
||||
await Assert.ThrowsAsync<InvalidOperationException>(() => this._agent.RunAsync(invalidThread));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task RunStreamingAsync_WithInvalidThreadType_ThrowsInvalidOperationExceptionAsync()
|
||||
{
|
||||
// Arrange
|
||||
var inputMessages = new List<ChatMessage>
|
||||
{
|
||||
new(ChatRole.User, "Test message")
|
||||
};
|
||||
|
||||
// Create a thread from a different agent type
|
||||
var invalidThread = new CustomAgentThread();
|
||||
|
||||
// Act & Assert
|
||||
await Assert.ThrowsAsync<InvalidOperationException>(async () => await this._agent.RunStreamingAsync(inputMessages, invalidThread).ToListAsync());
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
this._handler.Dispose();
|
||||
this._httpClient.Dispose();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Custom agent thread class for testing invalid thread type scenario.
|
||||
/// </summary>
|
||||
private sealed class CustomAgentThread : AgentThread;
|
||||
|
||||
internal sealed class A2AClientHttpMessageHandlerStub : HttpMessageHandler
|
||||
{
|
||||
public JsonRpcRequest? CapturedJsonRpcRequest { get; set; }
|
||||
|
||||
Reference in New Issue
Block a user