// Copyright (c) Microsoft. All rights reserved. using System; using System.Collections.Generic; using System.Threading; using System.Threading.Tasks; using Microsoft.Extensions.AI; using Microsoft.Shared.Diagnostics; namespace Microsoft.Agents.AI.Workflows; /// /// Provides a that selects agents in a round-robin fashion. /// public class RoundRobinGroupChatManager : GroupChatManager { private readonly IReadOnlyList _agents; private readonly Func, CancellationToken, ValueTask>? _shouldTerminateFunc; private int _nextIndex; /// /// Initializes a new instance of the class. /// /// The agents to be managed as part of this workflow. /// /// An optional function that determines whether the group chat should terminate based on the chat history /// before factoring in the default behavior, which is to terminate based only on the iteration count. /// public RoundRobinGroupChatManager( IReadOnlyList agents, Func, CancellationToken, ValueTask>? shouldTerminateFunc = null) { Throw.IfNullOrEmpty(agents); foreach (var agent in agents) { Throw.IfNull(agent, nameof(agents)); } this._agents = agents; this._shouldTerminateFunc = shouldTerminateFunc; } /// protected internal override ValueTask SelectNextAgentAsync( IReadOnlyList history, CancellationToken cancellationToken = default) { AIAgent nextAgent = this._agents[this._nextIndex]; this._nextIndex = (this._nextIndex + 1) % this._agents.Count; return new ValueTask(nextAgent); } /// protected internal override async ValueTask ShouldTerminateAsync( IReadOnlyList history, CancellationToken cancellationToken = default) { if (this._shouldTerminateFunc is { } func && await func(this, history, cancellationToken).ConfigureAwait(false)) { return true; } return await base.ShouldTerminateAsync(history, cancellationToken).ConfigureAwait(false); } /// protected internal override void Reset() { base.Reset(); this._nextIndex = 0; } }