// Copyright (c) Microsoft. All rights reserved. using System.Collections.Generic; using System.Linq; using System.Text.Json; using System.Threading; using System.Threading.Tasks; using Microsoft.Extensions.AI; namespace Microsoft.Agents.AI.Workflows; internal sealed class WorkflowChatHistoryProvider : ChatHistoryProvider { private readonly ProviderSessionState _sessionState; private IReadOnlyList? _stateKeys; /// /// Initializes a new instance of the class. /// /// /// Optional JSON serializer options for serializing the state of this provider. /// This is valuable for cases like when the chat history contains custom types /// and source generated serializers are required, or Native AOT / Trimming is required. /// public WorkflowChatHistoryProvider(JsonSerializerOptions? jsonSerializerOptions = null) { this._sessionState = new ProviderSessionState( _ => new StoreState(), this.GetType().Name, jsonSerializerOptions); } /// public override IReadOnlyList StateKeys => this._stateKeys ??= [this._sessionState.StateKey]; internal sealed class StoreState { public int Bookmark { get; set; } public List Messages { get; set; } = []; } internal void AddMessages(AgentSession session, params IEnumerable messages) => this._sessionState.GetOrInitializeState(session).Messages.AddRange(messages); protected override ValueTask> ProvideChatHistoryAsync(InvokingContext context, CancellationToken cancellationToken = default) => new(this._sessionState.GetOrInitializeState(context.Session).Messages.AsReadOnly()); protected override ValueTask StoreChatHistoryAsync(InvokedContext context, CancellationToken cancellationToken = default) { var allNewMessages = context.RequestMessages.Concat(context.ResponseMessages ?? []); this._sessionState.GetOrInitializeState(context.Session).Messages.AddRange(allNewMessages); return default; } public IEnumerable GetFromBookmark(AgentSession session) { var state = this._sessionState.GetOrInitializeState(session); for (int i = state.Bookmark; i < state.Messages.Count; i++) { yield return state.Messages[i]; } } public IEnumerable GetAllMessages(AgentSession session) { var state = this._sessionState.GetOrInitializeState(session); return state.Messages.AsReadOnly(); } public void UpdateBookmark(AgentSession session) { var state = this._sessionState.GetOrInitializeState(session); state.Bookmark = state.Messages.Count; } }