// Copyright (c) Microsoft. All rights reserved. using System; using System.Collections.Generic; using System.Text.Json; using System.Threading; using System.Threading.Tasks; namespace Microsoft.Extensions.AI.Agents; /// /// A base class for agent threads that operate entirely in memory without external storage. /// public abstract class InMemoryAgentThread : AgentThread { /// /// Initializes a new instance of the class. /// /// An optional to use for storing chat messages. If null, a new instance will be created. protected InMemoryAgentThread(InMemoryChatMessageStore? messageStore = null) { this.MessageStore = messageStore ?? []; } /// /// Initializes a new instance of the class with the specified initial messages. /// /// The messages to initialize the thread with. protected InMemoryAgentThread(IEnumerable messages) { this.MessageStore = [.. messages]; } /// /// Initializes a new instance of the class from serialized state. /// /// A representing the serialized state of the thread. /// Optional settings for customizing the JSON deserialization process. /// A factory function to create the from its serialized state. /// The is not a JSON object. /// The is invalid or cannot be deserialized to the expected type. protected InMemoryAgentThread( JsonElement serializedThreadState, JsonSerializerOptions? jsonSerializerOptions = null, Func? messageStoreFactory = null) { if (serializedThreadState.ValueKind != JsonValueKind.Object) { throw new ArgumentException("The serialized thread state must be a JSON object.", nameof(serializedThreadState)); } var state = serializedThreadState.Deserialize( AgentAbstractionsJsonUtilities.DefaultOptions.GetTypeInfo(typeof(InMemoryAgentThreadState))) as InMemoryAgentThreadState; this.MessageStore = messageStoreFactory?.Invoke(state?.StoreState ?? default, jsonSerializerOptions) ?? new InMemoryChatMessageStore(state?.StoreState ?? default, jsonSerializerOptions); } /// /// Gets or sets the used by this thread. /// public InMemoryChatMessageStore MessageStore { get; } /// /// Serializes the current object's state to a using the specified serialization options. /// /// The JSON serialization options to use. /// The to monitor for cancellation requests. The default is . /// A representation of the object's state. public override async Task SerializeAsync(JsonSerializerOptions? jsonSerializerOptions = null, CancellationToken cancellationToken = default) { var storeState = await this.MessageStore.SerializeStateAsync(jsonSerializerOptions, cancellationToken).ConfigureAwait(false); var state = new InMemoryAgentThreadState { StoreState = storeState, }; return JsonSerializer.SerializeToElement(state, AgentAbstractionsJsonUtilities.DefaultOptions.GetTypeInfo(typeof(InMemoryAgentThreadState))); } /// public override object? GetService(Type serviceType, object? serviceKey = null) => base.GetService(serviceType, serviceKey) ?? this.MessageStore?.GetService(serviceType, serviceKey); /// protected internal override Task MessagesReceivedAsync(IEnumerable newMessages, CancellationToken cancellationToken = default) => this.MessageStore.AddMessagesAsync(newMessages, cancellationToken); internal sealed class InMemoryAgentThreadState { public JsonElement? StoreState { get; set; } } }