// Copyright (c) Microsoft. All rights reserved. using System; using System.Collections.Generic; using System.Diagnostics.CodeAnalysis; using System.Text.Json.Serialization; using Microsoft.Extensions.AI; using Microsoft.Shared.DiagnosticIds; using Microsoft.Shared.Diagnostics; namespace Microsoft.Agents.AI; /// /// Represents the response to an run request, containing messages and metadata about the interaction. /// /// /// /// provides one or more response messages and metadata about the response. /// A typical response will contain a single message, however a response may contain multiple messages /// in a variety of scenarios. For example, if the agent internally invokes functions or tools, performs /// RAG retrievals or has other complex logic, a single run by the agent may produce many messages showing /// the intermediate progress that the agent made towards producing the agent result. /// /// /// To get the text result of the response, use the property or simply call on the . /// /// public class AgentResponse { /// The response messages. private IList? _messages; /// Initializes a new instance of the class. public AgentResponse() { } /// Initializes a new instance of the class. /// The response message to include in this response. /// is . public AgentResponse(ChatMessage message) { _ = Throw.IfNull(message); this.Messages.Add(message); } /// /// Initializes a new instance of the class from an existing . /// /// The from which to populate this . /// is . /// /// This constructor creates an agent response that wraps an existing , preserving all /// metadata and storing the original response in for access to /// the underlying implementation details. /// public AgentResponse(ChatResponse response) { _ = Throw.IfNull(response); this.AdditionalProperties = response.AdditionalProperties; this.CreatedAt = response.CreatedAt; this.Messages = response.Messages; this.RawRepresentation = response; this.ResponseId = response.ResponseId; this.Usage = response.Usage; this.ContinuationToken = response.ContinuationToken; } /// /// Initializes a new instance of the class from an existing . /// /// The from which to copy properties. /// is . /// /// This constructor creates a copy of an existing agent response, preserving all /// metadata and storing the original response in for access to /// the underlying implementation details. /// protected AgentResponse(AgentResponse response) { _ = Throw.IfNull(response); this.AdditionalProperties = response.AdditionalProperties; this.CreatedAt = response.CreatedAt; this.Messages = response.Messages; this.RawRepresentation = response; this.ResponseId = response.ResponseId; this.Usage = response.Usage; this.ContinuationToken = response.ContinuationToken; } /// /// Initializes a new instance of the class with the specified collection of messages. /// /// The collection of response messages, or to create an empty response. public AgentResponse(IList? messages) { this._messages = messages; } /// /// Gets or sets the collection of messages to be represented by this response. /// /// /// A collection of instances representing the agent's response. /// If the backing collection is , accessing this property will create an empty list. /// /// /// /// This property provides access to all messages generated during the agent's execution. While most /// responses contain a single assistant message, complex agent behaviors may produce multiple messages /// showing intermediate steps, function calls, or different types of content. /// /// /// The collection is mutable and can be modified after creation. Setting this property to /// will cause subsequent access to return an empty list. /// /// [AllowNull] public IList Messages { get => this._messages ??= new List(1); set => this._messages = value; } /// /// Gets the concatenated text content of all messages in this response. /// /// /// A string containing the combined text from all instances /// across all messages in , or an empty string if no text content is present. /// /// /// This property provides a convenient way to access the textual response without needing to /// iterate through individual messages and content items. Non-text content is ignored. /// [JsonIgnore] public string Text => this._messages?.ConcatText() ?? string.Empty; /// /// Gets or sets the identifier of the agent that generated this response. /// /// /// A unique string identifier for the agent, or if not specified. /// /// /// This identifier helps track which agent generated the response in multi-agent scenarios /// or for debugging and telemetry purposes. /// public string? AgentId { get; set; } /// /// Gets or sets the unique identifier for this specific response. /// /// /// A unique string identifier for this response instance, or if not assigned. /// public string? ResponseId { get; set; } /// /// Gets or sets the continuation token for getting the result of a background agent response. /// /// /// implementations that support background responses will return /// a continuation token if background responses are allowed in /// and the result of the response has not been obtained yet. If the response has completed and the result has been obtained, /// the token will be . /// /// This property should be used in conjunction with to /// continue to poll for the completion of the response. Pass this token to /// on subsequent calls to /// to poll for completion. /// /// [Experimental(DiagnosticIds.Experiments.AIResponseContinuations)] public ResponseContinuationToken? ContinuationToken { get; set; } /// /// Gets or sets the timestamp indicating when this response was created. /// /// /// A representing when the response was generated, /// or if not specified. /// /// /// The creation timestamp is useful for auditing, logging, and understanding /// the chronology of agentic interactions. /// public DateTimeOffset? CreatedAt { get; set; } /// /// Gets or sets the resource usage information for generating this response. /// /// /// A instance containing token counts and other usage metrics, /// or if usage information is not available. /// public UsageDetails? Usage { get; set; } /// Gets or sets the raw representation of the run response 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 associated with this response. /// /// /// An containing custom properties, /// or if no additional properties are present. /// /// /// Additional properties provide a way to include custom metadata or provider-specific /// information that doesn't fit into the standard response schema. This is useful for /// preserving implementation-specific details or extending the response with custom data. /// public AdditionalPropertiesDictionary? AdditionalProperties { get; set; } /// public override string ToString() => this.Text; /// /// Converts this into a collection of instances /// suitable for streaming scenarios. /// /// /// An array of instances that collectively represent /// the same information as this response. /// /// /// /// This method is useful for converting complete responses back into streaming format, /// which may be needed for scenarios that require uniform handling of both streaming /// and non-streaming agent responses. /// /// /// Each message in becomes a separate update, and usage information /// is included as an additional update if present. The order of updates preserves the /// original message sequence. /// /// public AgentResponseUpdate[] ToAgentResponseUpdates() { AgentResponseUpdate? extra = null; if (this.AdditionalProperties is not null || this.Usage is not null) { extra = new AgentResponseUpdate { AdditionalProperties = this.AdditionalProperties, }; if (this.Usage is { } usage) { extra.Contents.Add(new UsageContent(usage)); } } int messageCount = this._messages?.Count ?? 0; var updates = new AgentResponseUpdate[messageCount + (extra is not null ? 1 : 0)]; int i; for (i = 0; i < messageCount; i++) { ChatMessage message = this._messages![i]; updates[i] = new AgentResponseUpdate { AdditionalProperties = message.AdditionalProperties, AuthorName = message.AuthorName, Contents = message.Contents, RawRepresentation = message.RawRepresentation, Role = message.Role, AgentId = this.AgentId, ResponseId = this.ResponseId, MessageId = message.MessageId, CreatedAt = this.CreatedAt, }; } if (extra is not null) { updates[i] = extra; } return updates; } }