mirror of
https://github.com/microsoft/agent-framework.git
synced 2026-06-16 21:04:09 +08:00
.NET: Improve AIAgent and Workflow registrations for DevUI integration (#2227)
* wip * resolve non-agent workflows as well! * add tests for devui registrations and resolving * fixes * devui for net8 as well! * simplify TFM * update tfm... * tfm rules.... * wip * roll * verify entities are registered with a devui call * tests * add a proper support for non-keyed workflows * resolve default aiagent registration * sort usings :) * cleanup tests
This commit is contained in:
@@ -1,10 +1,7 @@
|
||||
// Copyright (c) Microsoft. All rights reserved.
|
||||
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Text.Json;
|
||||
|
||||
using Microsoft.Agents.AI.DevUI.Entities;
|
||||
using Microsoft.Agents.AI.Hosting;
|
||||
using Microsoft.Agents.AI.Workflows;
|
||||
using Microsoft.Extensions.AI;
|
||||
|
||||
@@ -27,21 +24,26 @@ internal static class EntitiesApiExtensions
|
||||
/// <item><description>GET /v1/entities/{entityId}/info - Get detailed information about a specific entity</description></item>
|
||||
/// </list>
|
||||
/// The endpoints are compatible with the Python DevUI frontend and automatically discover entities
|
||||
/// from the registered <see cref="AgentCatalog"/> and <see cref="WorkflowCatalog"/> services.
|
||||
/// from the registered <see cref="AIAgent">agents</see> and <see cref="Workflow">workflows</see> in the dependency injection container.
|
||||
/// </remarks>
|
||||
public static IEndpointConventionBuilder MapEntities(this IEndpointRouteBuilder endpoints)
|
||||
{
|
||||
var registeredAIAgents = GetRegisteredEntities<AIAgent>(endpoints.ServiceProvider);
|
||||
var registeredWorkflows = GetRegisteredEntities<Workflow>(endpoints.ServiceProvider);
|
||||
|
||||
var group = endpoints.MapGroup("/v1/entities")
|
||||
.WithTags("Entities");
|
||||
|
||||
// List all entities
|
||||
group.MapGet("", ListEntitiesAsync)
|
||||
group.MapGet("", (CancellationToken cancellationToken)
|
||||
=> ListEntitiesAsync(registeredAIAgents, registeredWorkflows, cancellationToken))
|
||||
.WithName("ListEntities")
|
||||
.WithSummary("List all registered entities (agents and workflows)")
|
||||
.Produces<DiscoveryResponse>(StatusCodes.Status200OK, contentType: "application/json");
|
||||
|
||||
// Get detailed entity information
|
||||
group.MapGet("{entityId}/info", GetEntityInfoAsync)
|
||||
group.MapGet("{entityId}/info", (string entityId, string? type, CancellationToken cancellationToken)
|
||||
=> GetEntityInfoAsync(entityId, type, registeredAIAgents, registeredWorkflows, cancellationToken))
|
||||
.WithName("GetEntityInfo")
|
||||
.WithSummary("Get detailed information about a specific entity")
|
||||
.Produces<EntityInfo>(StatusCodes.Status200OK, contentType: "application/json")
|
||||
@@ -51,8 +53,8 @@ internal static class EntitiesApiExtensions
|
||||
}
|
||||
|
||||
private static async Task<IResult> ListEntitiesAsync(
|
||||
AgentCatalog? agentCatalog,
|
||||
WorkflowCatalog? workflowCatalog,
|
||||
IEnumerable<AIAgent> agents,
|
||||
IEnumerable<Workflow> workflows,
|
||||
CancellationToken cancellationToken)
|
||||
{
|
||||
try
|
||||
@@ -60,13 +62,13 @@ internal static class EntitiesApiExtensions
|
||||
var entities = new Dictionary<string, EntityInfo>();
|
||||
|
||||
// Discover agents
|
||||
await foreach (var agentInfo in DiscoverAgentsAsync(agentCatalog, entityIdFilter: null, cancellationToken).ConfigureAwait(false))
|
||||
foreach (var agentInfo in DiscoverAgents(agents, entityIdFilter: null))
|
||||
{
|
||||
entities[agentInfo.Id] = agentInfo;
|
||||
}
|
||||
|
||||
// Discover workflows
|
||||
await foreach (var workflowInfo in DiscoverWorkflowsAsync(workflowCatalog, entityIdFilter: null, cancellationToken).ConfigureAwait(false))
|
||||
foreach (var workflowInfo in DiscoverWorkflows(workflows, entityIdFilter: null))
|
||||
{
|
||||
entities[workflowInfo.Id] = workflowInfo;
|
||||
}
|
||||
@@ -85,15 +87,15 @@ internal static class EntitiesApiExtensions
|
||||
private static async Task<IResult> GetEntityInfoAsync(
|
||||
string entityId,
|
||||
string? type,
|
||||
AgentCatalog? agentCatalog,
|
||||
WorkflowCatalog? workflowCatalog,
|
||||
IEnumerable<AIAgent> agents,
|
||||
IEnumerable<Workflow> workflows,
|
||||
CancellationToken cancellationToken)
|
||||
{
|
||||
try
|
||||
{
|
||||
if (type is null || string.Equals(type, "workflow", StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
await foreach (var workflowInfo in DiscoverWorkflowsAsync(workflowCatalog, entityId, cancellationToken).ConfigureAwait(false))
|
||||
foreach (var workflowInfo in DiscoverWorkflows(workflows, entityId))
|
||||
{
|
||||
return Results.Json(workflowInfo, EntitiesJsonContext.Default.EntityInfo);
|
||||
}
|
||||
@@ -101,7 +103,7 @@ internal static class EntitiesApiExtensions
|
||||
|
||||
if (type is null || string.Equals(type, "agent", StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
await foreach (var agentInfo in DiscoverAgentsAsync(agentCatalog, entityId, cancellationToken).ConfigureAwait(false))
|
||||
foreach (var agentInfo in DiscoverAgents(agents, entityId))
|
||||
{
|
||||
return Results.Json(agentInfo, EntitiesJsonContext.Default.EntityInfo);
|
||||
}
|
||||
@@ -118,17 +120,9 @@ internal static class EntitiesApiExtensions
|
||||
}
|
||||
}
|
||||
|
||||
private static async IAsyncEnumerable<EntityInfo> DiscoverAgentsAsync(
|
||||
AgentCatalog? agentCatalog,
|
||||
string? entityIdFilter,
|
||||
[EnumeratorCancellation] CancellationToken cancellationToken)
|
||||
private static IEnumerable<EntityInfo> DiscoverAgents(IEnumerable<AIAgent> agents, string? entityIdFilter)
|
||||
{
|
||||
if (agentCatalog is null)
|
||||
{
|
||||
yield break;
|
||||
}
|
||||
|
||||
await foreach (var agent in agentCatalog.GetAgentsAsync(cancellationToken).ConfigureAwait(false))
|
||||
foreach (var agent in agents)
|
||||
{
|
||||
// If filtering by entity ID, skip non-matching agents
|
||||
if (entityIdFilter is not null &&
|
||||
@@ -148,17 +142,9 @@ internal static class EntitiesApiExtensions
|
||||
}
|
||||
}
|
||||
|
||||
private static async IAsyncEnumerable<EntityInfo> DiscoverWorkflowsAsync(
|
||||
WorkflowCatalog? workflowCatalog,
|
||||
string? entityIdFilter,
|
||||
[EnumeratorCancellation] CancellationToken cancellationToken)
|
||||
private static IEnumerable<EntityInfo> DiscoverWorkflows(IEnumerable<Workflow> workflows, string? entityIdFilter)
|
||||
{
|
||||
if (workflowCatalog is null)
|
||||
{
|
||||
yield break;
|
||||
}
|
||||
|
||||
await foreach (var workflow in workflowCatalog.GetWorkflowsAsync(cancellationToken).ConfigureAwait(false))
|
||||
foreach (var workflow in workflows)
|
||||
{
|
||||
var workflowId = workflow.Name ?? workflow.StartExecutorId;
|
||||
|
||||
@@ -304,4 +290,14 @@ internal static class EntitiesApiExtensions
|
||||
StartExecutorId = workflow.StartExecutorId
|
||||
};
|
||||
}
|
||||
|
||||
private static IEnumerable<T> GetRegisteredEntities<T>(IServiceProvider serviceProvider)
|
||||
{
|
||||
var keyedEntities = serviceProvider.GetKeyedServices<T>(KeyedService.AnyKey);
|
||||
var defaultEntities = serviceProvider.GetServices<T>() ?? [];
|
||||
|
||||
return keyedEntities
|
||||
.Concat(defaultEntities)
|
||||
.Where(entity => entity is not null);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,23 @@
|
||||
// Copyright (c) Microsoft. All rights reserved.
|
||||
|
||||
namespace Microsoft.Extensions.Hosting;
|
||||
|
||||
/// <summary>
|
||||
/// Extension methods for <see cref="IHostApplicationBuilder"/> to configure DevUI.
|
||||
/// </summary>
|
||||
public static class MicrosoftAgentAIDevUIHostApplicationBuilderExtensions
|
||||
{
|
||||
/// <summary>
|
||||
/// Adds DevUI services to the host application builder.
|
||||
/// </summary>
|
||||
/// <param name="builder">The <see cref="IHostApplicationBuilder"/> to configure.</param>
|
||||
/// <returns>The <see cref="IHostApplicationBuilder"/> for method chaining.</returns>
|
||||
public static IHostApplicationBuilder AddDevUI(this IHostApplicationBuilder builder)
|
||||
{
|
||||
ArgumentNullException.ThrowIfNull(builder);
|
||||
|
||||
builder.Services.AddDevUI();
|
||||
|
||||
return builder;
|
||||
}
|
||||
}
|
||||
@@ -1,7 +1,8 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk.Web">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFrameworks>net9.0</TargetFrameworks>
|
||||
<TargetFrameworks>$(ProjectsCoreTargetFrameworks)</TargetFrameworks>
|
||||
<TargetFrameworks Condition="'$(Configuration)' == 'Debug'">$(ProjectsDebugCoreTargetFrameworks)</TargetFrameworks>
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
<Nullable>enable</Nullable>
|
||||
<RootNamespace>Microsoft.Agents.AI.DevUI</RootNamespace>
|
||||
@@ -12,6 +13,10 @@
|
||||
<NoWarn>$(NoWarn);CS1591;CA1852;CA1050;RCS1037;RCS1036;RCS1124;RCS1021;RCS1146;RCS1211;CA2007;CA1308;IL2026;IL3050;CA1812</NoWarn>
|
||||
</PropertyGroup>
|
||||
|
||||
<PropertyGroup>
|
||||
<InjectSharedThrow>true</InjectSharedThrow>
|
||||
</PropertyGroup>
|
||||
|
||||
<!-- Import nuget packaging properties -->
|
||||
<Import Project="$(RepoRoot)/dotnet/nuget/nuget-package.props" />
|
||||
|
||||
@@ -33,4 +38,7 @@
|
||||
<Description>Provides Microsoft Agent Framework support for developer UI.</Description>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<InternalsVisibleTo Include="Microsoft.Agents.AI.DevUI.UnitTests"/>
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
|
||||
@@ -24,9 +24,15 @@ var builder = WebApplication.CreateBuilder(args);
|
||||
// Register your agents
|
||||
builder.AddAIAgent("assistant", "You are a helpful assistant.");
|
||||
|
||||
// Register DevUI services
|
||||
if (builder.Environment.IsDevelopment())
|
||||
{
|
||||
builder.AddDevUI();
|
||||
}
|
||||
|
||||
// Register services for OpenAI responses and conversations (also required for DevUI)
|
||||
builder.Services.AddOpenAIResponses();
|
||||
builder.Services.AddOpenAIConversations();
|
||||
builder.AddOpenAIResponses();
|
||||
builder.AddOpenAIConversations();
|
||||
|
||||
var app = builder.Build();
|
||||
|
||||
|
||||
@@ -0,0 +1,61 @@
|
||||
// Copyright (c) Microsoft. All rights reserved.
|
||||
|
||||
using Microsoft.Agents.AI;
|
||||
using Microsoft.Agents.AI.Workflows;
|
||||
using Microsoft.Shared.Diagnostics;
|
||||
|
||||
namespace Microsoft.Extensions.DependencyInjection;
|
||||
|
||||
/// <summary>
|
||||
/// Extension methods for <see cref="IServiceCollection"/> to configure DevUI.
|
||||
/// </summary>
|
||||
public static class MicrosoftAgentAIDevUIServiceCollectionsExtensions
|
||||
{
|
||||
/// <summary>
|
||||
/// Adds services required for DevUI integration.
|
||||
/// </summary>
|
||||
/// <param name="services">The <see cref="IServiceCollection"/> to configure.</param>
|
||||
/// <returns>The <see cref="IServiceCollection"/> for method chaining.</returns>
|
||||
public static IServiceCollection AddDevUI(this IServiceCollection services)
|
||||
{
|
||||
ArgumentNullException.ThrowIfNull(services);
|
||||
|
||||
// a factory that tries to construct an AIAgent from Workflow,
|
||||
// even if workflow was not explicitly registered as an AIAgent.
|
||||
|
||||
#pragma warning disable IDE0001 // Simplify Names
|
||||
services.AddKeyedSingleton<AIAgent>(KeyedService.AnyKey, (sp, key) =>
|
||||
{
|
||||
var keyAsStr = key as string;
|
||||
Throw.IfNullOrEmpty(keyAsStr);
|
||||
|
||||
var workflow = sp.GetKeyedService<Workflow>(keyAsStr);
|
||||
if (workflow is not null)
|
||||
{
|
||||
return workflow.AsAgent(name: workflow.Name);
|
||||
}
|
||||
|
||||
// another thing we can do is resolve a non-keyed workflow.
|
||||
// however, we can't rely on anything than key to be equal to the workflow.Name.
|
||||
// so we try: if we fail, we return null.
|
||||
workflow = sp.GetService<Workflow>();
|
||||
if (workflow is not null && workflow.Name?.Equals(keyAsStr, StringComparison.Ordinal) == true)
|
||||
{
|
||||
return workflow.AsAgent(name: workflow.Name);
|
||||
}
|
||||
|
||||
// and it's possible to lookup at the default-registered AIAgent
|
||||
// with the condition of same name as the key.
|
||||
var agent = sp.GetService<AIAgent>();
|
||||
if (agent is not null && agent.Name?.Equals(keyAsStr, StringComparison.Ordinal) == true)
|
||||
{
|
||||
return agent;
|
||||
}
|
||||
|
||||
return null!;
|
||||
});
|
||||
#pragma warning restore IDE0001 // Simplify Names
|
||||
|
||||
return services;
|
||||
}
|
||||
}
|
||||
+5
-1
@@ -63,7 +63,11 @@ internal sealed class HostedAgentResponseExecutor : IResponseExecutor
|
||||
return ValueTask.FromResult<ResponseError?>(new ResponseError
|
||||
{
|
||||
Code = "agent_not_found",
|
||||
Message = $"Agent '{agentName}' not found. Ensure the agent is registered with AddAIAgent()."
|
||||
Message = $"""
|
||||
Agent '{agentName}' not found.
|
||||
Ensure the agent is registered with '{agentName}' name in the dependency injection container.
|
||||
We recommend using 'builder.AddAIAgent()' for simplicity.
|
||||
"""
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@@ -1,38 +0,0 @@
|
||||
// Copyright (c) Microsoft. All rights reserved.
|
||||
|
||||
using System.Collections.Generic;
|
||||
using System.Threading;
|
||||
|
||||
namespace Microsoft.Agents.AI.Hosting;
|
||||
|
||||
/// <summary>
|
||||
/// Provides a catalog of registered AI agents within the hosting environment.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// The agent catalog allows enumeration of all registered agents in the dependency injection container.
|
||||
/// This is useful for scenarios where you need to discover and interact with multiple agents programmatically.
|
||||
/// </remarks>
|
||||
public abstract class AgentCatalog
|
||||
{
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="AgentCatalog"/> class.
|
||||
/// </summary>
|
||||
protected AgentCatalog()
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Asynchronously retrieves all registered AI agents from the catalog.
|
||||
/// </summary>
|
||||
/// <param name="cancellationToken">The <see cref="CancellationToken"/> to monitor for cancellation requests. The default is <see cref="CancellationToken.None"/>.</param>
|
||||
/// <returns>
|
||||
/// An asynchronous enumerable of <see cref="AIAgent"/> instances representing all registered agents.
|
||||
/// The enumeration will only include agents that are successfully resolved from the service provider.
|
||||
/// </returns>
|
||||
/// <remarks>
|
||||
/// This method enumerates through all registered agent names and attempts to resolve each agent
|
||||
/// from the dependency injection container. Only successfully resolved agents are yielded.
|
||||
/// The enumeration is lazy and agents are resolved on-demand during iteration.
|
||||
/// </remarks>
|
||||
public abstract IAsyncEnumerable<AIAgent> GetAgentsAsync(CancellationToken cancellationToken = default);
|
||||
}
|
||||
@@ -2,7 +2,6 @@
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using Microsoft.Agents.AI.Hosting.Local;
|
||||
using Microsoft.Extensions.AI;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
@@ -126,31 +125,9 @@ public static class AgentHostingServiceCollectionExtensions
|
||||
return agent;
|
||||
});
|
||||
|
||||
// Register the agent by name for discovery.
|
||||
var agentHostBuilder = GetAgentRegistry(services);
|
||||
agentHostBuilder.AgentNames.Add(name);
|
||||
|
||||
return new HostedAgentBuilder(name, services);
|
||||
}
|
||||
|
||||
private static LocalAgentRegistry GetAgentRegistry(IServiceCollection services)
|
||||
{
|
||||
var descriptor = services.FirstOrDefault(s => !s.IsKeyedService && s.ServiceType.Equals(typeof(LocalAgentRegistry)));
|
||||
if (descriptor?.ImplementationInstance is not LocalAgentRegistry instance)
|
||||
{
|
||||
instance = new LocalAgentRegistry();
|
||||
ConfigureHostBuilder(services, instance);
|
||||
}
|
||||
|
||||
return instance;
|
||||
}
|
||||
|
||||
private static void ConfigureHostBuilder(IServiceCollection services, LocalAgentRegistry agentHostBuilderContext)
|
||||
{
|
||||
services.Add(ServiceDescriptor.Singleton(agentHostBuilderContext));
|
||||
services.AddSingleton<AgentCatalog, LocalAgentCatalog>();
|
||||
}
|
||||
|
||||
private static IList<AITool> GetRegisteredToolsForAgent(IServiceProvider serviceProvider, string agentName)
|
||||
{
|
||||
var registry = serviceProvider.GetService<LocalAgentToolRegistry>();
|
||||
|
||||
@@ -1,8 +1,6 @@
|
||||
// Copyright (c) Microsoft. All rights reserved.
|
||||
|
||||
using System;
|
||||
using System.Linq;
|
||||
using Microsoft.Agents.AI.Hosting.Local;
|
||||
using Microsoft.Agents.AI.Workflows;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Microsoft.Extensions.Hosting;
|
||||
@@ -47,28 +45,6 @@ public static class HostApplicationBuilderWorkflowExtensions
|
||||
return workflow;
|
||||
});
|
||||
|
||||
// Register the workflow by name for discovery.
|
||||
var workflowRegistry = GetWorkflowRegistry(builder);
|
||||
workflowRegistry.WorkflowNames.Add(name);
|
||||
|
||||
return new HostedWorkflowBuilder(name, builder);
|
||||
}
|
||||
|
||||
private static LocalWorkflowRegistry GetWorkflowRegistry(IHostApplicationBuilder builder)
|
||||
{
|
||||
var descriptor = builder.Services.FirstOrDefault(s => !s.IsKeyedService && s.ServiceType.Equals(typeof(LocalWorkflowRegistry)));
|
||||
if (descriptor?.ImplementationInstance is not LocalWorkflowRegistry instance)
|
||||
{
|
||||
instance = new LocalWorkflowRegistry();
|
||||
ConfigureHostBuilder(builder, instance);
|
||||
}
|
||||
|
||||
return instance;
|
||||
}
|
||||
|
||||
private static void ConfigureHostBuilder(IHostApplicationBuilder builder, LocalWorkflowRegistry agentHostBuilderContext)
|
||||
{
|
||||
builder.Services.Add(ServiceDescriptor.Singleton(agentHostBuilderContext));
|
||||
builder.Services.AddSingleton<WorkflowCatalog, LocalWorkflowCatalog>();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,37 +0,0 @@
|
||||
// Copyright (c) Microsoft. All rights reserved.
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
|
||||
namespace Microsoft.Agents.AI.Hosting.Local;
|
||||
|
||||
// Implementation of an AgentCatalog which enumerates agents registered in the local service provider.
|
||||
internal sealed class LocalAgentCatalog : AgentCatalog
|
||||
{
|
||||
public readonly HashSet<string> _registeredAgents;
|
||||
private readonly IServiceProvider _serviceProvider;
|
||||
|
||||
public LocalAgentCatalog(LocalAgentRegistry agentHostBuilder, IServiceProvider serviceProvider)
|
||||
{
|
||||
this._registeredAgents = [.. agentHostBuilder.AgentNames];
|
||||
this._serviceProvider = serviceProvider;
|
||||
}
|
||||
|
||||
public override async IAsyncEnumerable<AIAgent> GetAgentsAsync([EnumeratorCancellation] CancellationToken cancellationToken = default)
|
||||
{
|
||||
await Task.CompletedTask.ConfigureAwait(false);
|
||||
|
||||
foreach (var name in this._registeredAgents)
|
||||
{
|
||||
var agent = this._serviceProvider.GetKeyedService<AIAgent>(name);
|
||||
if (agent is not null)
|
||||
{
|
||||
yield return agent;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,10 +0,0 @@
|
||||
// Copyright (c) Microsoft. All rights reserved.
|
||||
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Microsoft.Agents.AI.Hosting.Local;
|
||||
|
||||
internal sealed class LocalAgentRegistry
|
||||
{
|
||||
public HashSet<string> AgentNames { get; } = [];
|
||||
}
|
||||
@@ -1,37 +0,0 @@
|
||||
// Copyright (c) Microsoft. All rights reserved.
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.Agents.AI.Workflows;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
|
||||
namespace Microsoft.Agents.AI.Hosting.Local;
|
||||
|
||||
internal sealed class LocalWorkflowCatalog : WorkflowCatalog
|
||||
{
|
||||
public readonly HashSet<string> _registeredWorkflows;
|
||||
private readonly IServiceProvider _serviceProvider;
|
||||
|
||||
public LocalWorkflowCatalog(LocalWorkflowRegistry workflowRegistry, IServiceProvider serviceProvider)
|
||||
{
|
||||
this._registeredWorkflows = [.. workflowRegistry.WorkflowNames];
|
||||
this._serviceProvider = serviceProvider;
|
||||
}
|
||||
|
||||
public override async IAsyncEnumerable<Workflow> GetWorkflowsAsync([EnumeratorCancellation] CancellationToken cancellationToken = default)
|
||||
{
|
||||
await Task.CompletedTask.ConfigureAwait(false);
|
||||
|
||||
foreach (var name in this._registeredWorkflows)
|
||||
{
|
||||
var workflow = this._serviceProvider.GetKeyedService<Workflow>(name);
|
||||
if (workflow is not null)
|
||||
{
|
||||
yield return workflow;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,10 +0,0 @@
|
||||
// Copyright (c) Microsoft. All rights reserved.
|
||||
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Microsoft.Agents.AI.Hosting.Local;
|
||||
|
||||
internal sealed class LocalWorkflowRegistry
|
||||
{
|
||||
public HashSet<string> WorkflowNames { get; } = [];
|
||||
}
|
||||
Reference in New Issue
Block a user