mirror of
https://github.com/microsoft/agent-framework.git
synced 2026-06-16 21:04:09 +08:00
dfc3079d68
* .NET: Add A2A input-request content for human-in-the-loop scenarios Adds first-class support for handling user input requests from A2A agents when they return an `input-required` task state. - Add `A2AInputRequestContent` (wraps the requested `AIContent`) and `A2AInputResponseContent` (wraps the user's `AIContent` reply), with `CreateResponse` helper overloads on the request type. - Surface input requests on `AgentResponse` / `AgentResponseUpdate` via `AgentTask` and `TaskStatusUpdateEvent` mappings. - Link follow-up messages containing `A2AInputResponseContent` to the existing task via `TaskId` instead of `ReferenceTaskIds`. - Add `A2AAgent_HumanInTheLoop` sample and register it in the solution and parent README. - Add unit tests for the new types, extensions, and `A2AAgent` paths. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * Remove unnecessary using directive flagged by CI format check Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * address feedback * Guard against null TaskId when sending A2AInputResponseContent Throw InvalidOperationException if TaskId is missing when the message contains A2AInputResponseContent, preventing silent no-op responses. Also adds tests for both RunAsync and RunStreamingAsync paths. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * Leave Contents null for non-InputRequired status updates Remove unnecessary '?? []' fallback so Contents stays null when there are no input requests, matching the other update mapping patterns. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * Use consistent GUID format for request IDs Use ToString("N") to match message ID format used elsewhere in the A2A component. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * Remove Debug build exclusion for the HumanInTheLoop sample so it participates in normal solution validation. * Add missing using Microsoft.Extensions.AI to A2AAgent_HumanInTheLoop The sample uses ChatMessage, TextContent, and ChatRole types from Microsoft.Extensions.AI but was missing the using directive, causing CS0246 build errors on all CI jobs. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * change the way user input requests are handled based on pr review comments --------- Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
71 lines
2.3 KiB
C#
71 lines
2.3 KiB
C#
// Copyright (c) Microsoft. All rights reserved.
|
|
|
|
using System;
|
|
using System.Diagnostics;
|
|
using System.Text.Json;
|
|
using System.Text.Json.Serialization;
|
|
|
|
using TaskState = A2A.TaskState;
|
|
|
|
namespace Microsoft.Agents.AI.A2A;
|
|
|
|
/// <summary>
|
|
/// Session for A2A based agents.
|
|
/// </summary>
|
|
[DebuggerDisplay("{DebuggerDisplay,nq}")]
|
|
public sealed class A2AAgentSession : AgentSession
|
|
{
|
|
internal A2AAgentSession()
|
|
{
|
|
}
|
|
|
|
[JsonConstructor]
|
|
internal A2AAgentSession(string? contextId, string? taskId, TaskState? taskState, AgentSessionStateBag? stateBag) : base(stateBag ?? new())
|
|
{
|
|
this.ContextId = contextId;
|
|
this.TaskId = taskId;
|
|
this.TaskState = taskState;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Gets the ID for the current conversation with the A2A agent.
|
|
/// </summary>
|
|
[JsonPropertyName("contextId")]
|
|
public string? ContextId { get; internal set; }
|
|
|
|
/// <summary>
|
|
/// Gets the ID for the task the agent is currently working on.
|
|
/// </summary>
|
|
[JsonPropertyName("taskId")]
|
|
public string? TaskId { get; internal set; }
|
|
|
|
/// <summary>
|
|
/// Gets the state of the task the agent is currently working on.
|
|
/// </summary>
|
|
[JsonPropertyName("taskState")]
|
|
public TaskState? TaskState { get; internal set; }
|
|
|
|
/// <inheritdoc/>
|
|
internal JsonElement Serialize(JsonSerializerOptions? jsonSerializerOptions = null)
|
|
{
|
|
var jso = jsonSerializerOptions ?? A2AJsonUtilities.DefaultOptions;
|
|
return JsonSerializer.SerializeToElement(this, jso.GetTypeInfo(typeof(A2AAgentSession)));
|
|
}
|
|
|
|
internal static A2AAgentSession Deserialize(JsonElement serializedState, JsonSerializerOptions? jsonSerializerOptions = null)
|
|
{
|
|
if (serializedState.ValueKind != JsonValueKind.Object)
|
|
{
|
|
throw new ArgumentException("The serialized session state must be a JSON object.", nameof(serializedState));
|
|
}
|
|
|
|
var jso = jsonSerializerOptions ?? A2AJsonUtilities.DefaultOptions;
|
|
return serializedState.Deserialize(jso.GetTypeInfo(typeof(A2AAgentSession))) as A2AAgentSession
|
|
?? new A2AAgentSession();
|
|
}
|
|
|
|
[DebuggerBrowsable(DebuggerBrowsableState.Never)]
|
|
private string DebuggerDisplay =>
|
|
$"ContextId = {this.ContextId}, TaskId = {this.TaskId}, TaskState = {this.TaskState}, StateBag Count = {this.StateBag.Count}";
|
|
}
|