// Copyright (c) Microsoft. All rights reserved.
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Diagnostics.CodeAnalysis;
using System.Text.Json.Serialization;
using Microsoft.Extensions.AI;
using Microsoft.Shared.Diagnostics;
namespace Microsoft.Agents.AI;
///
/// Represents a single streaming response chunk from an .
///
///
///
/// is so named because it represents updates
/// that layer on each other to form a single agent response. Conceptually, this combines the roles of
/// and in streaming output.
///
///
/// To get the text result of this response chunk, use the property or simply call on the .
///
///
/// The relationship between and is
/// codified in the and
/// , which enable bidirectional conversions
/// between the two. Note, however, that the provided conversions may be lossy, for example if multiple
/// updates all have different objects whereas there's only one slot for
/// such an object available in .
///
///
[DebuggerDisplay("[{Role}] {ContentForDebuggerDisplay}{EllipsesForDebuggerDisplay,nq}")]
public class AgentResponseUpdate
{
/// The response update content items.
private IList? _contents;
/// Initializes a new instance of the class.
[JsonConstructor]
public AgentResponseUpdate()
{
}
/// Initializes a new instance of the class.
/// The role of the author of the update.
/// The text content of the update.
public AgentResponseUpdate(ChatRole? role, string? content)
: this(role, content is null ? null : [new TextContent(content)])
{
}
/// Initializes a new instance of the class.
/// The role of the author of the update.
/// The contents of the update.
public AgentResponseUpdate(ChatRole? role, IList? contents)
{
this.Role = role;
this._contents = contents;
}
/// Initializes a new instance of the class.
/// The from which to seed this .
public AgentResponseUpdate(ChatResponseUpdate chatResponseUpdate)
{
_ = Throw.IfNull(chatResponseUpdate);
this.AdditionalProperties = chatResponseUpdate.AdditionalProperties;
this.AuthorName = chatResponseUpdate.AuthorName;
this.Contents = chatResponseUpdate.Contents;
this.CreatedAt = chatResponseUpdate.CreatedAt;
this.MessageId = chatResponseUpdate.MessageId;
this.RawRepresentation = chatResponseUpdate;
this.ResponseId = chatResponseUpdate.ResponseId;
this.Role = chatResponseUpdate.Role;
this.ContinuationToken = chatResponseUpdate.ContinuationToken;
}
/// Gets or sets the name of the author of the response update.
public string? AuthorName
{
get => field;
set => field = string.IsNullOrWhiteSpace(value) ? null : value;
}
/// Gets or sets the role of the author of the response update.
public ChatRole? Role { get; set; }
/// Gets the text of this update.
///
/// This property concatenates the text of all objects in .
///
[JsonIgnore]
public string Text => this._contents is not null ? this._contents.ConcatText() : string.Empty;
/// Gets or sets the agent run response update content items.
[AllowNull]
public IList Contents
{
get => this._contents ??= [];
set => this._contents = value;
}
/// Gets or sets the raw representation of the response update from an underlying implementation.
///
/// If a is created to represent some underlying object from another object
/// model, this property can be used to store that original object. This can be useful for debugging or
/// for enabling a consumer to access the underlying object model if needed.
///
[JsonIgnore]
public object? RawRepresentation { get; set; }
/// Gets or sets additional properties for the update.
public AdditionalPropertiesDictionary? AdditionalProperties { get; set; }
/// Gets or sets the ID of the agent that produced the response.
public string? AgentId { get; set; }
/// Gets or sets the ID of the response of which this update is a part.
public string? ResponseId { get; set; }
/// Gets or sets the ID of the message of which this update is a part.
///
/// A single streaming response may be composed of multiple messages, each of which may be represented
/// by multiple updates. This property is used to group those updates together into messages.
///
/// Some providers may consider streaming responses to be a single message, and in that case
/// the value of this property may be the same as the response ID.
///
/// This value is used when
/// groups instances into instances.
/// The value must be unique to each call to the underlying provider, and must be shared by
/// all updates that are part of the same logical message within a streaming response.
///
public string? MessageId { get; set; }
/// Gets or sets a timestamp for the response update.
public DateTimeOffset? CreatedAt { get; set; }
///
/// Gets or sets the continuation token for resuming the streamed agent response of which this update is a part.
///
///
/// implementations that support background responses will return
/// a continuation token on each update if background responses are allowed in
/// except for the last update, for which the token will be .
///
/// This property should be used for stream resumption, where the continuation token of the latest received update should be
/// passed to on subsequent calls to
/// to resume streaming from the point of interruption.
///
///
public ResponseContinuationToken? ContinuationToken { get; set; }
///
public override string ToString() => this.Text;
/// Gets a object to display in the debugger display.
[DebuggerBrowsable(DebuggerBrowsableState.Never)]
[ExcludeFromCodeCoverage]
private AIContent? ContentForDebuggerDisplay => this._contents is { Count: > 0 } ? this._contents[0] : null;
/// Gets an indication for the debugger display of whether there's more content.
[DebuggerBrowsable(DebuggerBrowsableState.Never)]
[ExcludeFromCodeCoverage]
private string EllipsesForDebuggerDisplay => this._contents is { Count: > 1 } ? ", ..." : string.Empty;
}