Merge branch 'main' into feat/durable_task

This commit is contained in:
Shyju Krishnankutty
2026-03-11 10:04:38 -07:00
committed by GitHub
Unverified
14 changed files with 120 additions and 13 deletions
@@ -127,6 +127,7 @@ public sealed class A2AAgent : AIAgent
{
AgentId = this.Id,
ResponseId = message.MessageId,
FinishReason = ChatFinishReason.Stop,
RawRepresentation = message,
Messages = [message.ToChatMessage()],
AdditionalProperties = message.Metadata?.ToAdditionalProperties(),
@@ -141,6 +142,7 @@ public sealed class A2AAgent : AIAgent
{
AgentId = this.Id,
ResponseId = agentTask.Id,
FinishReason = MapTaskStateToFinishReason(agentTask.Status.State),
RawRepresentation = agentTask,
Messages = agentTask.ToChatMessages() ?? [],
ContinuationToken = CreateContinuationToken(agentTask.Id, agentTask.Status.State),
@@ -328,6 +330,7 @@ public sealed class A2AAgent : AIAgent
{
AgentId = this.Id,
ResponseId = message.MessageId,
FinishReason = ChatFinishReason.Stop,
RawRepresentation = message,
Role = ChatRole.Assistant,
MessageId = message.MessageId,
@@ -342,6 +345,7 @@ public sealed class A2AAgent : AIAgent
{
AgentId = this.Id,
ResponseId = task.Id,
FinishReason = MapTaskStateToFinishReason(task.Status.State),
RawRepresentation = task,
Role = ChatRole.Assistant,
Contents = task.ToAIContents(),
@@ -365,7 +369,16 @@ public sealed class A2AAgent : AIAgent
responseUpdate.Contents = artifactUpdateEvent.Artifact.ToAIContents();
responseUpdate.RawRepresentation = artifactUpdateEvent;
}
else if (taskUpdateEvent is TaskStatusUpdateEvent statusUpdateEvent)
{
responseUpdate.FinishReason = MapTaskStateToFinishReason(statusUpdateEvent.Status.State);
}
return responseUpdate;
}
private static ChatFinishReason? MapTaskStateToFinishReason(TaskState state)
{
return state == TaskState.Completed ? ChatFinishReason.Stop : null;
}
}
@@ -61,6 +61,7 @@ public class AgentResponse
this.AdditionalProperties = response.AdditionalProperties;
this.CreatedAt = response.CreatedAt;
this.FinishReason = response.FinishReason;
this.Messages = response.Messages;
this.RawRepresentation = response;
this.ResponseId = response.ResponseId;
@@ -84,6 +85,7 @@ public class AgentResponse
this.AdditionalProperties = response.AdditionalProperties;
this.CreatedAt = response.CreatedAt;
this.FinishReason = response.FinishReason;
this.Messages = response.Messages;
this.RawRepresentation = response;
this.ResponseId = response.ResponseId;
@@ -190,6 +192,21 @@ public class AgentResponse
/// </remarks>
public DateTimeOffset? CreatedAt { get; set; }
/// <summary>
/// Gets or sets the reason for the agent response finishing.
/// </summary>
/// <value>
/// A <see cref="ChatFinishReason"/> value indicating why the response finished (e.g., stop, length, content filter, tool calls),
/// or <see langword="null"/> if the finish reason is not available.
/// </value>
/// <remarks>
/// <para>
/// This property is particularly useful for detecting non-normal completions, such as content filtering
/// or token limit truncation, which may require special handling by the caller.
/// </para>
/// </remarks>
public ChatFinishReason? FinishReason { get; set; }
/// <summary>
/// Gets or sets the resource usage information for generating this response.
/// </summary>
@@ -276,6 +293,7 @@ public class AgentResponse
RawRepresentation = message.RawRepresentation,
Role = message.Role,
FinishReason = this.FinishReason,
AgentId = this.AgentId,
ResponseId = this.ResponseId,
MessageId = message.MessageId,
@@ -38,6 +38,7 @@ public static class AgentResponseExtensions
{
AdditionalProperties = response.AdditionalProperties,
CreatedAt = response.CreatedAt,
FinishReason = response.FinishReason,
Messages = response.Messages,
RawRepresentation = response,
ResponseId = response.ResponseId,
@@ -71,6 +72,7 @@ public static class AgentResponseExtensions
AuthorName = responseUpdate.AuthorName,
Contents = responseUpdate.Contents,
CreatedAt = responseUpdate.CreatedAt,
FinishReason = responseUpdate.FinishReason,
MessageId = responseUpdate.MessageId,
RawRepresentation = responseUpdate,
ResponseId = responseUpdate.ResponseId,
@@ -70,6 +70,7 @@ public class AgentResponseUpdate
this.AuthorName = chatResponseUpdate.AuthorName;
this.Contents = chatResponseUpdate.Contents;
this.CreatedAt = chatResponseUpdate.CreatedAt;
this.FinishReason = chatResponseUpdate.FinishReason;
this.MessageId = chatResponseUpdate.MessageId;
this.RawRepresentation = chatResponseUpdate;
this.ResponseId = chatResponseUpdate.ResponseId;
@@ -153,6 +154,15 @@ public class AgentResponseUpdate
/// </remarks>
public ResponseContinuationToken? ContinuationToken { get; set; }
/// <summary>
/// Gets or sets the reason for the agent response finishing.
/// </summary>
/// <value>
/// A <see cref="ChatFinishReason"/> value indicating why the response finished (e.g., stop, length, content filter, tool calls),
/// or <see langword="null"/> if the finish reason is not available or not yet determined (mid-stream).
/// </value>
public ChatFinishReason? FinishReason { get; set; }
/// <inheritdoc/>
public override string ToString() => this.Text;
@@ -72,9 +72,7 @@ internal static class AIAgentChatCompletionsProcessor
await foreach (var agentResponseUpdate in agent.RunStreamingAsync(chatMessages, options: options, cancellationToken: cancellationToken).WithCancellation(cancellationToken))
{
var finishReason = (agentResponseUpdate.RawRepresentation is ChatResponseUpdate { FinishReason: not null } chatResponseUpdate)
? chatResponseUpdate.FinishReason.ToString()
: "stop";
var finishReason = agentResponseUpdate.FinishReason?.ToString() ?? "stop";
var choiceChunks = new List<ChatCompletionChoiceChunk>();
CompletionUsage? usageDetails = null;
@@ -34,9 +34,7 @@ internal static class AgentResponseExtensions
var chatCompletionChoices = new List<ChatCompletionChoice>();
var index = 0;
var finishReason = (agentResponse.RawRepresentation is ChatResponse { FinishReason: not null } chatResponse)
? chatResponse.FinishReason.ToString()
: "stop"; // "stop" is a natural stop point; returning this by-default
var finishReason = agentResponse.FinishReason?.ToString() ?? ChatFinishReason.Stop.Value; // "stop" is a natural stop point; returning this by-default
foreach (var message in agentResponse.Messages)
{
@@ -124,6 +124,7 @@ internal sealed class MessageMerger
List<ChatMessage> messages = [];
Dictionary<string, AgentResponse> responses = [];
HashSet<string> agentIds = [];
HashSet<ChatFinishReason> finishReasons = [];
foreach (string responseId in this._mergeStates.Keys)
{
@@ -156,6 +157,11 @@ internal sealed class MessageMerger
createdTimes.Add(response.CreatedAt.Value);
}
if (response.FinishReason.HasValue)
{
finishReasons.Add(response.FinishReason.Value);
}
usage = MergeUsage(usage, response.Usage);
additionalProperties = MergeProperties(additionalProperties, response.AdditionalProperties);
}
@@ -182,6 +188,7 @@ internal sealed class MessageMerger
AgentId = primaryAgentId
?? primaryAgentName
?? (agentIds.Count == 1 ? agentIds.First() : null),
FinishReason = finishReasons.Count == 1 ? finishReasons.First() : null,
CreatedAt = DateTimeOffset.UtcNow,
Usage = usage,
AdditionalProperties = additionalProperties
@@ -207,6 +214,7 @@ internal sealed class MessageMerger
AgentId = incoming.AgentId ?? current.AgentId,
AdditionalProperties = MergeProperties(current.AdditionalProperties, incoming.AdditionalProperties),
CreatedAt = incoming.CreatedAt ?? current.CreatedAt,
FinishReason = incoming.FinishReason ?? current.FinishReason,
Messages = current.Messages.Concat(incoming.Messages).ToList(),
ResponseId = current.ResponseId,
RawRepresentation = rawRepresentation,