mirror of
https://github.com/microsoft/agent-framework.git
synced 2026-06-16 21:04:09 +08:00
Cleanup
This commit is contained in:
@@ -79,7 +79,7 @@ public sealed class DurableWorkflowOptions
|
||||
|
||||
private static void RegisterExecutors(Workflow workflow, ExecutorRegistry registry)
|
||||
{
|
||||
foreach (KeyValuePair<string, ExecutorInfo> executor in workflow.ReflectExecutors())
|
||||
foreach (KeyValuePair<string, ExecutorBinding> executor in workflow.ReflectExecutors())
|
||||
{
|
||||
int underscoreIndex = executor.Key.IndexOf('_');
|
||||
string executorName = underscoreIndex > 0 ? executor.Key[..underscoreIndex] : executor.Key;
|
||||
@@ -89,9 +89,9 @@ public sealed class DurableWorkflowOptions
|
||||
|
||||
private static void RegisterAgenticExecutors(Workflow workflow, DurableAgentsOptions agentOptions)
|
||||
{
|
||||
foreach (AIAgent agent in workflow.EnumerateAgentExecutors())
|
||||
foreach (KeyValuePair<string, ExecutorBinding> executor in workflow.ReflectExecutors())
|
||||
{
|
||||
if (agent.Name is not null && !agentOptions.ContainsAgent(agent.Name))
|
||||
if (executor.Value.RawValue is AIAgent agent && agent.Name is not null && !agentOptions.ContainsAgent(agent.Name))
|
||||
{
|
||||
agentOptions.AddAIAgent(agent, workflowOnly: true);
|
||||
}
|
||||
|
||||
@@ -39,7 +39,13 @@ internal sealed class ExecutorRegistry
|
||||
ArgumentException.ThrowIfNullOrEmpty(executorId);
|
||||
ArgumentNullException.ThrowIfNull(workflow);
|
||||
|
||||
this._executors.TryAdd(executorName, new ExecutorRegistration(executorId, workflow));
|
||||
Dictionary<string, ExecutorBinding> bindings = workflow.ReflectExecutors();
|
||||
if (!bindings.TryGetValue(executorId, out ExecutorBinding? binding))
|
||||
{
|
||||
throw new InvalidOperationException($"Executor '{executorId}' not found in workflow.");
|
||||
}
|
||||
|
||||
this._executors.TryAdd(executorName, new ExecutorRegistration(executorId, binding));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -47,8 +53,8 @@ internal sealed class ExecutorRegistry
|
||||
/// Represents a registered executor with its associated workflow.
|
||||
/// </summary>
|
||||
/// <param name="ExecutorId">The full executor ID (may include GUID suffix).</param>
|
||||
/// <param name="Workflow">The workflow containing the executor.</param>
|
||||
internal sealed record ExecutorRegistration(string ExecutorId, Workflow Workflow)
|
||||
/// <param name="Binding">The executor binding from the workflow.</param>
|
||||
internal sealed record ExecutorRegistration(string ExecutorId, ExecutorBinding Binding)
|
||||
{
|
||||
/// <summary>
|
||||
/// Creates an instance of the executor.
|
||||
@@ -56,8 +62,13 @@ internal sealed record ExecutorRegistration(string ExecutorId, Workflow Workflow
|
||||
/// <param name="runId">A unique identifier for the run context.</param>
|
||||
/// <param name="cancellationToken">The cancellation token.</param>
|
||||
/// <returns>The created executor instance.</returns>
|
||||
public ValueTask<Executor> CreateExecutorInstanceAsync(string runId, CancellationToken cancellationToken = default)
|
||||
public async ValueTask<Executor> CreateExecutorInstanceAsync(string runId, CancellationToken cancellationToken = default)
|
||||
{
|
||||
return this.Workflow.CreateExecutorInstanceAsync(this.ExecutorId, runId, cancellationToken);
|
||||
if (this.Binding.FactoryAsync is null)
|
||||
{
|
||||
throw new InvalidOperationException($"Cannot create executor '{this.ExecutorId}': Binding is a placeholder.");
|
||||
}
|
||||
|
||||
return await this.Binding.FactoryAsync(runId).ConfigureAwait(false);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -87,7 +87,7 @@ public static class WorkflowHelper
|
||||
{
|
||||
ArgumentNullException.ThrowIfNull(workflow);
|
||||
|
||||
Dictionary<string, ExecutorInfo> executors = workflow.ReflectExecutors();
|
||||
Dictionary<string, ExecutorBinding> executors = workflow.ReflectExecutors();
|
||||
Dictionary<string, HashSet<EdgeInfo>> edges = workflow.ReflectEdges();
|
||||
|
||||
WorkflowExecutionPlan plan = new();
|
||||
@@ -177,9 +177,9 @@ public static class WorkflowHelper
|
||||
{
|
||||
processed.Add(executorId);
|
||||
|
||||
if (executors.TryGetValue(executorId, out ExecutorInfo? executorInfo))
|
||||
if (executors.TryGetValue(executorId, out ExecutorBinding? executorBinding))
|
||||
{
|
||||
bool isAgentic = IsAgentExecutorType(executorInfo.ExecutorType);
|
||||
bool isAgentic = IsAgentExecutorType(executorBinding.ExecutorType);
|
||||
levelExecutors.Add(new WorkflowExecutorInfo(executorId, isAgentic));
|
||||
}
|
||||
|
||||
@@ -202,13 +202,13 @@ public static class WorkflowHelper
|
||||
/// </summary>
|
||||
/// <param name="executorType">The executor type to check.</param>
|
||||
/// <returns><c>true</c> if the executor is an agentic executor; otherwise, <c>false</c>.</returns>
|
||||
internal static bool IsAgentExecutorType(TypeId executorType)
|
||||
internal static bool IsAgentExecutorType(Type executorType)
|
||||
{
|
||||
// hack for now. In the future, the MAF type could expose something which can help with this.
|
||||
// Check if the type name or assembly indicates it's an agent executor
|
||||
// This includes AgentRunStreamingExecutor, AgentExecutor, ChatClientAgent wrappers, etc.
|
||||
string typeName = executorType.TypeName;
|
||||
string assemblyName = executorType.AssemblyName;
|
||||
string typeName = executorType.FullName ?? executorType.Name;
|
||||
string assemblyName = executorType.Assembly.GetName().Name ?? string.Empty;
|
||||
|
||||
return typeName.Contains("AIAgentHostExecutor", StringComparison.OrdinalIgnoreCase) &&
|
||||
assemblyName.Contains("Microsoft.Agents.AI", StringComparison.OrdinalIgnoreCase);
|
||||
|
||||
+6
-6
@@ -1,7 +1,7 @@
|
||||
// Copyright (c) Microsoft. All rights reserved.
|
||||
|
||||
using Microsoft.Agents.AI.DurableTask;
|
||||
using Microsoft.Agents.AI.Workflows.Checkpointing;
|
||||
using Microsoft.Agents.AI.Workflows;
|
||||
using Microsoft.Azure.Functions.Worker.Core.FunctionMetadata;
|
||||
using Microsoft.Extensions.Logging;
|
||||
|
||||
@@ -66,11 +66,11 @@ internal sealed class DurableWorkflowFunctionMetadataTransformer : IFunctionMeta
|
||||
}
|
||||
}
|
||||
|
||||
Dictionary<string, ExecutorInfo> executorInfos = workflow.Value.ReflectExecutors();
|
||||
Dictionary<string, ExecutorBinding> executorBindings = workflow.Value.ReflectExecutors();
|
||||
|
||||
foreach (string executorId in executorIds)
|
||||
{
|
||||
if (executorInfos.TryGetValue(executorId, out ExecutorInfo? executorInfo))
|
||||
if (executorBindings.TryGetValue(executorId, out ExecutorBinding? executorBinding))
|
||||
{
|
||||
string executorName = WorkflowNamingHelper.GetExecutorName(executorId);
|
||||
string functionName = WorkflowNamingHelper.ToOrchestrationFunctionName(executorName);
|
||||
@@ -83,14 +83,14 @@ internal sealed class DurableWorkflowFunctionMetadataTransformer : IFunctionMeta
|
||||
}
|
||||
|
||||
// Check if the executor type is an agent-related type
|
||||
if (WorkflowHelper.IsAgentExecutorType(executorInfo.ExecutorType))
|
||||
if (WorkflowHelper.IsAgentExecutorType(executorBinding.ExecutorType))
|
||||
{
|
||||
this._logger.LogAddingAgentEntityFunction(executorId, executorInfo.ExecutorType.TypeName, workflow.Key);
|
||||
this._logger.LogAddingAgentEntityFunction(executorId, executorBinding.ExecutorType.FullName ?? executorBinding.ExecutorType.Name, workflow.Key);
|
||||
//original.Add(CreateAgentTrigger(functionName));
|
||||
}
|
||||
else
|
||||
{
|
||||
this._logger.LogAddingActivityFunction(executorId, executorInfo.ExecutorType.TypeName, workflow.Key);
|
||||
this._logger.LogAddingActivityFunction(executorId, executorBinding.ExecutorType.FullName ?? executorBinding.ExecutorType.Name, workflow.Key);
|
||||
original.Add(CreateActivityTrigger(functionName));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,36 +2,16 @@
|
||||
|
||||
namespace Microsoft.Agents.AI.Workflows.Checkpointing;
|
||||
|
||||
/// <summary>
|
||||
/// Represents information about an executor in a workflow, including its type and identifier.
|
||||
/// </summary>
|
||||
/// <param name="ExecutorType">The type identifier of the executor.</param>
|
||||
/// <param name="ExecutorId">The unique identifier of the executor instance.</param>
|
||||
public sealed record class ExecutorInfo(TypeId ExecutorType, string ExecutorId)
|
||||
internal sealed record class ExecutorInfo(TypeId ExecutorType, string ExecutorId)
|
||||
{
|
||||
/// <summary>
|
||||
/// Determines whether this executor info matches a specific executor type by generic parameter.
|
||||
/// </summary>
|
||||
/// <typeparam name="T">The executor type to match against.</typeparam>
|
||||
/// <returns><c>true</c> if the executor type and ID match; otherwise, <c>false</c>.</returns>
|
||||
public bool IsMatch<T>() where T : Executor =>
|
||||
this.ExecutorType.IsMatch<T>()
|
||||
&& this.ExecutorId == typeof(T).Name;
|
||||
|
||||
/// <summary>
|
||||
/// Determines whether this executor info matches a given executor instance.
|
||||
/// </summary>
|
||||
/// <param name="executor">The executor instance to match against.</param>
|
||||
/// <returns><c>true</c> if the executor type and ID match; otherwise, <c>false</c>.</returns>
|
||||
public bool IsMatch(Executor executor) =>
|
||||
this.ExecutorType.IsMatch(executor.GetType())
|
||||
&& this.ExecutorId == executor.Id;
|
||||
|
||||
/// <summary>
|
||||
/// Determines whether this executor info matches a given executor binding.
|
||||
/// </summary>
|
||||
/// <param name="binding">The executor binding to match against.</param>
|
||||
/// <returns><c>true</c> if the executor type and ID match; otherwise, <c>false</c>.</returns>
|
||||
public bool IsMatch(ExecutorBinding binding) =>
|
||||
this.ExecutorType.IsMatch(binding.ExecutorType)
|
||||
&& this.ExecutorId == binding.Id;
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Copyright (c) Microsoft. All rights reserved.
|
||||
// Copyright (c) Microsoft. All rights reserved.
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
@@ -37,15 +37,12 @@ public class Workflow
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets information about all executors in the workflow, keyed by their ID.
|
||||
/// Gets all executor bindings in the workflow, keyed by their ID.
|
||||
/// </summary>
|
||||
/// <returns>A dictionary mapping executor IDs to their <see cref="ExecutorInfo"/>.</returns>
|
||||
public Dictionary<string, ExecutorInfo> ReflectExecutors()
|
||||
/// <returns>A dictionary mapping executor IDs to their <see cref="ExecutorBinding"/>.</returns>
|
||||
public Dictionary<string, ExecutorBinding> ReflectExecutors()
|
||||
{
|
||||
return this.ExecutorBindings.Values.ToDictionary(
|
||||
keySelector: binding => binding.Id,
|
||||
elementSelector: RepresentationExtensions.ToExecutorInfo
|
||||
);
|
||||
return new Dictionary<string, ExecutorBinding>(this.ExecutorBindings);
|
||||
}
|
||||
|
||||
internal Dictionary<string, RequestPort> Ports { get; init; } = [];
|
||||
@@ -226,45 +223,4 @@ public class Workflow
|
||||
|
||||
return startExecutor.DescribeProtocol();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Enumerates all AIAgent instances that are directly bound in this workflow.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// This method only returns agents that are directly bound as executor values.
|
||||
/// It does not include agents created by factory functions, as those require
|
||||
/// an IServiceProvider to instantiate.
|
||||
/// </remarks>
|
||||
/// <returns>An enumerable collection of AIAgent instances found in the workflow.</returns>
|
||||
public IEnumerable<AIAgent> EnumerateAgentExecutors()
|
||||
{
|
||||
foreach (ExecutorBinding binding in this.ExecutorBindings.Values)
|
||||
{
|
||||
if (binding.RawValue is AIAgent agent)
|
||||
{
|
||||
yield return agent;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates an instance of the specified executor.
|
||||
/// </summary>
|
||||
/// <param name="executorId">The identifier of the executor to create.</param>
|
||||
/// <param name="runId">A unique identifier for the run context.</param>
|
||||
/// <param name="cancellationToken">The <see cref="CancellationToken"/> to monitor for cancellation requests.</param>
|
||||
/// <returns>A <see cref="ValueTask{Executor}"/> representing the asynchronous operation.</returns>
|
||||
/// <remarks>
|
||||
/// This method is useful for Azure Functions scenarios where you need to create executor instances
|
||||
/// outside of the normal workflow execution flow.
|
||||
/// </remarks>
|
||||
public async ValueTask<Executor> CreateExecutorInstanceAsync(string executorId, string runId, CancellationToken cancellationToken = default)
|
||||
{
|
||||
if (!this.ExecutorBindings.TryGetValue(executorId, out ExecutorBinding? binding))
|
||||
{
|
||||
throw new InvalidOperationException($"Executor '{executorId}' not found in workflow.");
|
||||
}
|
||||
|
||||
return await binding.CreateInstanceAsync(runId).ConfigureAwait(false);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user