diff --git a/dotnet/src/Microsoft.Agents.AI.DurableTask/ServiceCollectionExtensions.cs b/dotnet/src/Microsoft.Agents.AI.DurableTask/ServiceCollectionExtensions.cs index a1ac7723a7..5d5859c8f2 100644 --- a/dotnet/src/Microsoft.Agents.AI.DurableTask/ServiceCollectionExtensions.cs +++ b/dotnet/src/Microsoft.Agents.AI.DurableTask/ServiceCollectionExtensions.cs @@ -112,6 +112,11 @@ public static class ServiceCollectionExtensions services.AddKeyedSingleton(factory.Key, (sp, _) => factory.Value(sp).AsDurableAgentProxy(sp)); } + // Register the agent factories dictionary for backward compatibility. + // This allows consumers to retrieve agents via services.GetService>>(). + services.TryAddSingleton( + sp => sp.GetRequiredService().GetAgentFactories()); + // A custom data converter is needed because the default chat client uses camel case for JSON properties, // which is not the default behavior for the Durable Task SDK. services.TryAddSingleton(); diff --git a/dotnet/src/Microsoft.Agents.AI.Hosting.AzureFunctions/BuiltInFunctionExecutor.cs b/dotnet/src/Microsoft.Agents.AI.Hosting.AzureFunctions/BuiltInFunctionExecutor.cs index 257ee972dd..b3169bd7fe 100644 --- a/dotnet/src/Microsoft.Agents.AI.Hosting.AzureFunctions/BuiltInFunctionExecutor.cs +++ b/dotnet/src/Microsoft.Agents.AI.Hosting.AzureFunctions/BuiltInFunctionExecutor.cs @@ -154,6 +154,18 @@ internal sealed class BuiltInFunctionExecutor : IFunctionExecutor return; } + // Handle workflow MCP tool trigger + if (context.FunctionDefinition.EntryPoint == BuiltInFunctions.RunWorkflowMcpToolFunctionEntryPoint) + { + if (mcpToolInvocationContext is null) + { + throw new InvalidOperationException($"MCP tool invocation context binding is missing for the invocation {context.InvocationId}."); + } + + context.GetInvocationResult().Value = await BuiltInFunctions.RunWorkflowMcpToolAsync(mcpToolInvocationContext, durableTaskClient, context); + return; + } + throw new InvalidOperationException($"Unsupported function entry point '{context.FunctionDefinition.EntryPoint}' for invocation {context.InvocationId}."); } } diff --git a/dotnet/src/Microsoft.Agents.AI.Hosting.AzureFunctions/CoreAgentConfigurationExtensions.cs b/dotnet/src/Microsoft.Agents.AI.Hosting.AzureFunctions/CoreAgentConfigurationExtensions.cs index 481d146f52..e81dbf924d 100644 --- a/dotnet/src/Microsoft.Agents.AI.Hosting.AzureFunctions/CoreAgentConfigurationExtensions.cs +++ b/dotnet/src/Microsoft.Agents.AI.Hosting.AzureFunctions/CoreAgentConfigurationExtensions.cs @@ -72,6 +72,7 @@ internal static class CoreAgentConfigurationExtensions { return string.Equals(entryPoint, BuiltInFunctions.RunAgentHttpFunctionEntryPoint, StringComparison.Ordinal) || string.Equals(entryPoint, BuiltInFunctions.RunAgentMcpToolFunctionEntryPoint, StringComparison.Ordinal) + || string.Equals(entryPoint, BuiltInFunctions.RunWorkflowMcpToolFunctionEntryPoint, StringComparison.Ordinal) || string.Equals(entryPoint, BuiltInFunctions.RunWorkflowOrechstrtationHttpFunctionEntryPoint, StringComparison.Ordinal) || string.Equals(entryPoint, BuiltInFunctions.InvokeWorkflowActivityFunctionEntryPoint, StringComparison.Ordinal) || string.Equals(entryPoint, BuiltInFunctions.RunAgentEntityFunctionEntryPoint, StringComparison.Ordinal); diff --git a/dotnet/tests/Microsoft.Agents.AI.Hosting.AzureFunctions.UnitTests/DurableAgentFunctionMetadataTransformerTests.cs b/dotnet/tests/Microsoft.Agents.AI.Hosting.AzureFunctions.UnitTests/DurableAgentFunctionMetadataTransformerTests.cs index 7d3a2ec13e..34d6943f4f 100644 --- a/dotnet/tests/Microsoft.Agents.AI.Hosting.AzureFunctions.UnitTests/DurableAgentFunctionMetadataTransformerTests.cs +++ b/dotnet/tests/Microsoft.Agents.AI.Hosting.AzureFunctions.UnitTests/DurableAgentFunctionMetadataTransformerTests.cs @@ -1,6 +1,7 @@ // Copyright (c) Microsoft. All rights reserved. using System.Diagnostics.CodeAnalysis; +using Microsoft.Agents.AI.DurableTask; using Microsoft.Azure.Functions.Worker.Core.FunctionMetadata; using Microsoft.Extensions.Logging.Abstractions; @@ -21,10 +22,8 @@ public sealed class DurableAgentFunctionMetadataTransformerTests int expectedMetadataCount) { // Arrange - Dictionary> agents = new() - { - { "testAgent", _ => new TestAgent("testAgent", "Test agent description") } - }; + DurableAgentsOptions durableAgentsOptions = new(); + durableAgentsOptions.AddAIAgentFactory("testAgent", _ => new TestAgent("testAgent", "Test agent description")); FunctionsAgentOptions options = new(); @@ -39,7 +38,7 @@ public sealed class DurableAgentFunctionMetadataTransformerTests List metadataList = BuildFunctionMetadataList(initialMetadataEntryCount); DurableAgentFunctionMetadataTransformer transformer = new( - agents, + durableAgentsOptions, NullLogger.Instance, new FakeServiceProvider(), agentOptionsProvider); @@ -74,12 +73,11 @@ public sealed class DurableAgentFunctionMetadataTransformerTests public void Transform_AddsTriggers_ForMultipleAgents() { // Arrange - Dictionary> agents = new() - { - { "agentA", _ => new TestAgent("testAgentA", "Test agent description") }, - { "agentB", _ => new TestAgent("testAgentB", "Test agent description") }, - { "agentC", _ => new TestAgent("testAgentC", "Test agent description") } - }; + string[] agentNames = ["agentA", "agentB", "agentC"]; + DurableAgentsOptions durableAgentsOptions = new(); + durableAgentsOptions.AddAIAgentFactory("agentA", _ => new TestAgent("testAgentA", "Test agent description")); + durableAgentsOptions.AddAIAgentFactory("agentB", _ => new TestAgent("testAgentB", "Test agent description")); + durableAgentsOptions.AddAIAgentFactory("agentC", _ => new TestAgent("testAgentC", "Test agent description")); // Helper to create options with configurable triggers static FunctionsAgentOptions CreateFunctionsAgentOptions(bool httpEnabled, bool mcpEnabled) @@ -103,7 +101,7 @@ public sealed class DurableAgentFunctionMetadataTransformerTests IFunctionsAgentOptionsProvider agentOptionsProvider = new FakeOptionsProvider(functionsAgentOptions); DurableAgentFunctionMetadataTransformer transformer = new( - agents, + durableAgentsOptions, NullLogger.Instance, new FakeServiceProvider(), agentOptionsProvider); @@ -115,9 +113,9 @@ public sealed class DurableAgentFunctionMetadataTransformerTests transformer.Transform(metadataList); // Assert - Assert.Equal(InitialMetadataEntryCount + (agents.Count * 2) + 2, metadataList.Count); + Assert.Equal(InitialMetadataEntryCount + (agentNames.Length * 2) + 2, metadataList.Count); - foreach (string agentName in agents.Keys) + foreach (string agentName in agentNames) { // The agent's entity trigger name is prefixed with "dafx-" DefaultFunctionMetadata entityMeta =