mirror of
https://github.com/microsoft/agent-framework.git
synced 2026-06-16 21:04:09 +08:00
* feat: Implement Polymorphic Routing * feat: Add support for Send/Yield annotations with basic Executor * Adds annotations to Declarative workflow executors * fix: Address PR Comments * Implicit filter in collection loops * Remove debug / usused / superfluous code * Fix ProtocolBuilder implicit output registrations * Fix logic error in ExecuteRouteGeneratorTests.ClassWithManualConfigureProtocol_DoesNotGenerate * fix: Solidify type checks and send/yield type registrations * fix: Suppress generation of TurnTokens out of AggregateTurnMessagesExecutor * Fixes an issue where ConcurrentEndExecutor is not expecting TurnTokens. * fix: Add ProtocolBuilder support for chained-delegation * Updates Declarative pacakge to rely on chained-delegation Send/Yield registration * Renames DeclarativeActionExectuor's new ExecuteAsync to ExecuteActionAsync to avoid colliding with Executor.ExecutoeAsync * fix: Address PR Comments * Fixes type mapping in FanInEdgeRunner * Fixes and expalins send/yield type registration in FunctionExecutor * fixup: build-break * fix: Add missing SendsMesage declaration to InvokeAzureAgentExecutor
71 lines
2.3 KiB
C#
71 lines
2.3 KiB
C#
// Copyright (c) Microsoft. All rights reserved.
|
|
|
|
using System;
|
|
using System.Collections.Generic;
|
|
using System.Threading.Tasks;
|
|
using Microsoft.Extensions.AI;
|
|
using Microsoft.Shared.Diagnostics;
|
|
|
|
namespace Microsoft.Agents.AI.Workflows.Specialized;
|
|
|
|
/// <summary>
|
|
/// Provides an executor that accepts the output messages from each of the concurrent agents
|
|
/// and produces a result list containing the last message from each.
|
|
/// </summary>
|
|
internal sealed class ConcurrentEndExecutor : Executor, IResettableExecutor
|
|
{
|
|
public const string ExecutorId = "ConcurrentEnd";
|
|
|
|
private readonly int _expectedInputs;
|
|
private readonly Func<IList<List<ChatMessage>>, List<ChatMessage>> _aggregator;
|
|
private List<List<ChatMessage>> _allResults;
|
|
private int _remaining;
|
|
|
|
public ConcurrentEndExecutor(int expectedInputs, Func<IList<List<ChatMessage>>, List<ChatMessage>> aggregator) : base(ExecutorId)
|
|
{
|
|
this._expectedInputs = expectedInputs;
|
|
this._aggregator = Throw.IfNull(aggregator);
|
|
|
|
this._allResults = new List<List<ChatMessage>>(expectedInputs);
|
|
this._remaining = expectedInputs;
|
|
}
|
|
|
|
private void Reset()
|
|
{
|
|
this._allResults = new List<List<ChatMessage>>(this._expectedInputs);
|
|
this._remaining = this._expectedInputs;
|
|
}
|
|
|
|
protected override ProtocolBuilder ConfigureProtocol(ProtocolBuilder protocolBuilder)
|
|
{
|
|
protocolBuilder.RouteBuilder.AddHandler<List<ChatMessage>>(async (messages, context, cancellationToken) =>
|
|
{
|
|
// TODO: https://github.com/microsoft/agent-framework/issues/784
|
|
// This locking should not be necessary.
|
|
bool done;
|
|
lock (this._allResults)
|
|
{
|
|
this._allResults.Add(messages);
|
|
done = --this._remaining == 0;
|
|
}
|
|
|
|
if (done)
|
|
{
|
|
this._remaining = this._expectedInputs;
|
|
|
|
var results = this._allResults;
|
|
this._allResults = new List<List<ChatMessage>>(this._expectedInputs);
|
|
await context.YieldOutputAsync(this._aggregator(results), cancellationToken).ConfigureAwait(false);
|
|
}
|
|
});
|
|
|
|
return protocolBuilder.YieldsOutput<List<ChatMessage>>();
|
|
}
|
|
|
|
public ValueTask ResetAsync()
|
|
{
|
|
this.Reset();
|
|
return default;
|
|
}
|
|
}
|