// 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; }