File: OpenAIResponsesContinuationToken.cs
Web Access
Project: src\src\Libraries\Microsoft.Extensions.AI.OpenAI\Microsoft.Extensions.AI.OpenAI.csproj (Microsoft.Extensions.AI.OpenAI)
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
 
using System;
using System.IO;
using System.Text.Json;
using Microsoft.Shared.Diagnostics;
 
namespace Microsoft.Extensions.AI;
 
/// <summary>Represents a continuation token for OpenAI responses.</summary>
/// <remarks>
/// The token is used for resuming streamed background responses and continuing
/// non-streamed background responses until completion.
/// </remarks>
internal sealed class OpenAIResponsesContinuationToken : ResponseContinuationToken
{
    /// <summary>Initializes a new instance of the <see cref="OpenAIResponsesContinuationToken"/> class.</summary>
    internal OpenAIResponsesContinuationToken(string responseId)
    {
        ResponseId = responseId;
    }
 
    /// <summary>Gets the Id of the response.</summary>
    internal string ResponseId { get; }
 
    /// <summary>Gets or sets the sequence number of a streamed update.</summary>
    internal int? SequenceNumber { get; set; }
 
    /// <inheritdoc/>
    public override ReadOnlyMemory<byte> ToBytes()
    {
        using MemoryStream stream = new();
        using Utf8JsonWriter writer = new(stream);
 
        writer.WriteStartObject();
 
        writer.WriteString("responseId", ResponseId);
 
        if (SequenceNumber.HasValue)
        {
            writer.WriteNumber("sequenceNumber", SequenceNumber.Value);
        }
 
        writer.WriteEndObject();
 
        writer.Flush();
 
        return stream.ToArray();
    }
 
    /// <summary>Create a new instance of <see cref="OpenAIResponsesContinuationToken"/> from the provided <paramref name="token"/>.
    /// </summary>
    /// <param name="token">The token to create the <see cref="OpenAIResponsesContinuationToken"/> from.</param>
    /// <returns>A <see cref="OpenAIResponsesContinuationToken"/> equivalent of the provided <paramref name="token"/>.</returns>
    internal static OpenAIResponsesContinuationToken FromToken(object token)
    {
        if (token is OpenAIResponsesContinuationToken openAIResponsesContinuationToken)
        {
            return openAIResponsesContinuationToken;
        }
 
        if (token is not ResponseContinuationToken)
        {
            Throw.ArgumentException(nameof(token), "Failed to create OpenAIResponsesResumptionToken from provided token because it is not of type ResponseContinuationToken.");
        }
 
        ReadOnlyMemory<byte> data = ((ResponseContinuationToken)token).ToBytes();
 
        if (data.Length == 0)
        {
            Throw.ArgumentException(nameof(token), "Failed to create OpenAIResponsesResumptionToken from provided token because it does not contain any data.");
        }
 
        Utf8JsonReader reader = new(data.Span);
 
        string? responseId = null;
        int? sequenceNumber = null;
 
        _ = reader.Read();
 
        while (reader.Read())
        {
            if (reader.TokenType == JsonTokenType.EndObject)
            {
                break;
            }
 
            string propertyName = reader.GetString()!;
 
            switch (propertyName)
            {
                case "responseId":
                    _ = reader.Read();
                    responseId = reader.GetString();
                    break;
                case "sequenceNumber":
                    _ = reader.Read();
                    sequenceNumber = reader.GetInt32();
                    break;
                default:
                    Throw.ArgumentException(nameof(token), $"Unrecognized property '{propertyName}'.");
                    break;
            }
        }
 
        if (responseId is null)
        {
            Throw.ArgumentException(nameof(token), "Failed to create MessagesPageToken from provided pageToken because it does not contain a responseId.");
        }
 
        return new(responseId)
        {
            SequenceNumber = sequenceNumber
        };
    }
}