mirror of
https://github.com/microsoft/agent-framework.git
synced 2026-06-16 21:04:09 +08:00
331c750515
* refactor: remove unused internals * feat: Execution Mode for sharing a workflow among concurrent runs * feat: Update WorkflowHostAgent to support concurrent execution * Also update AsAgent APIs to support injecting a CheckpointManager and an IWorkflowExecutionEnvironment * fix: Make Read logic consistent in DeclarativeWorkflowContext
68 lines
2.8 KiB
C#
68 lines
2.8 KiB
C#
// Copyright (c) Microsoft. All rights reserved.
|
|
|
|
using System;
|
|
using System.Threading.Tasks;
|
|
using Microsoft.Shared.Diagnostics;
|
|
|
|
using ExecutorFactoryF = System.Func<string, System.Threading.Tasks.ValueTask<Microsoft.Agents.AI.Workflows.Executor>>;
|
|
|
|
namespace Microsoft.Agents.AI.Workflows;
|
|
|
|
internal sealed class ExecutorRegistration(string id, Type executorType, ExecutorFactoryF provider, object? rawData)
|
|
{
|
|
public string Id { get; } = Throw.IfNullOrEmpty(id);
|
|
public Type ExecutorType { get; } = Throw.IfNull(executorType);
|
|
private ExecutorFactoryF ProviderAsync { get; } = Throw.IfNull(provider);
|
|
public bool IsNotExecutorInstance { get; } = rawData is not Executor;
|
|
public bool IsUnresettableSharedInstance { get; } = rawData is Executor executor &&
|
|
// Cross-Run Shareable executors are "trivially" resettable, since they
|
|
// have no on-object state.
|
|
!executor.IsCrossRunShareable &&
|
|
rawData is not IResettableExecutor;
|
|
public bool SupportsConcurrent { get; } = (rawData is not Executor executor || executor.IsCrossRunShareable) &&
|
|
(rawData is not Workflow workflow || workflow.AllowConcurrent);
|
|
|
|
internal async ValueTask<bool> TryResetAsync()
|
|
{
|
|
if (this.IsUnresettableSharedInstance)
|
|
{
|
|
return false;
|
|
}
|
|
|
|
// If the executor supports concurrent use, then resetting is a no-op.
|
|
if (this.SupportsConcurrent)
|
|
{
|
|
return true;
|
|
}
|
|
|
|
// Technically we definitely know this is true, since if rawData is an Executor, if it was not resettable
|
|
// then we would have returned in the first condition, and if rawData is not an Executor, we would have
|
|
// returned in the second condition. That only leaves the possibility of rawData is Executor and also
|
|
// IResettableExecutor.
|
|
if (this.RawExecutorishData is IResettableExecutor resettableExecutor)
|
|
{
|
|
await resettableExecutor.ResetAsync().ConfigureAwait(false);
|
|
return true;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
internal object? RawExecutorishData { get; } = rawData;
|
|
|
|
public override string ToString() => $"{this.ExecutorType.Name}({this.Id})";
|
|
|
|
private Executor CheckId(Executor executor)
|
|
{
|
|
if (executor.Id != this.Id)
|
|
{
|
|
throw new InvalidOperationException(
|
|
$"Executor ID mismatch: expected '{this.Id}', but got '{executor.Id}'.");
|
|
}
|
|
|
|
return executor;
|
|
}
|
|
|
|
public async ValueTask<Executor> CreateInstanceAsync(string runId) => this.CheckId(await this.ProviderAsync(runId).ConfigureAwait(false));
|
|
}
|