mirror of
https://github.com/microsoft/agent-framework.git
synced 2026-06-16 21:04:09 +08:00
150 lines
6.3 KiB
C#
150 lines
6.3 KiB
C#
// Copyright (c) Microsoft. All rights reserved.
|
|
|
|
using Microsoft.Agents.AI.DurableTask;
|
|
using Microsoft.Agents.AI.Workflows.Checkpointing;
|
|
using Microsoft.Azure.Functions.Worker.Core.FunctionMetadata;
|
|
using Microsoft.Extensions.Logging;
|
|
|
|
namespace Microsoft.Agents.AI.Hosting.AzureFunctions;
|
|
|
|
internal sealed class DurableWorkflowFunctionMetadataTransformer : IFunctionMetadataTransformer
|
|
{
|
|
private readonly ILogger<DurableWorkflowFunctionMetadataTransformer> _logger;
|
|
private readonly DurableWorkflowOptions _options;
|
|
|
|
public DurableWorkflowFunctionMetadataTransformer(ILogger<DurableWorkflowFunctionMetadataTransformer> logger, DurableOptions durableOptions)
|
|
{
|
|
this._logger = logger ?? throw new ArgumentNullException(nameof(logger));
|
|
ArgumentNullException.ThrowIfNull(durableOptions);
|
|
this._options = durableOptions.Workflows;
|
|
}
|
|
|
|
public string Name => nameof(DurableWorkflowFunctionMetadataTransformer);
|
|
|
|
public void Transform(IList<IFunctionMetadata> original)
|
|
{
|
|
this._logger.LogTransformStart(original.Count);
|
|
|
|
foreach (var workflow in this._options.Workflows)
|
|
{
|
|
this._logger.LogAddingWorkflowFunction(workflow.Key);
|
|
|
|
// Currently due to how durable executor is registered, we are not able to bind TaskOrechestrationContext parameter properly
|
|
// because the InputBinding for TOC happens inside the DurableExecutor (rathen than in an input converter).
|
|
// So for now, we are going to use single orchestration function for all workflows.
|
|
//original.Add(CreateOrchestrationTrigger(workflow.Key));
|
|
|
|
// We also want to create an HTTP trigger for this orchestration so users can start it via HTTP.
|
|
this._logger.LogAddingHttpTrigger(workflow.Key);
|
|
original.Add(CreateHttpTrigger(workflow.Key, $"workflows/{workflow.Key}/run"));
|
|
|
|
// Create activity/entity functions for each executor in the workflow based on their type
|
|
// Extract executor IDs from edges and start executor
|
|
var executorIds = new HashSet<string> { workflow.Value.StartExecutorId };
|
|
|
|
var reflectedEdges = workflow.Value.ReflectEdges();
|
|
foreach (var (sourceId, edgeSet) in reflectedEdges)
|
|
{
|
|
executorIds.Add(sourceId);
|
|
foreach (var edge in edgeSet)
|
|
{
|
|
foreach (var sinkId in edge.Connection.SinkIds)
|
|
{
|
|
executorIds.Add(sinkId);
|
|
}
|
|
}
|
|
}
|
|
|
|
Dictionary<string, ExecutorInfo> executorInfos = workflow.Value.ReflectExecutors();
|
|
|
|
foreach (string executorId in executorIds)
|
|
{
|
|
if (executorInfos.TryGetValue(executorId, out ExecutorInfo? executorInfo))
|
|
{
|
|
string functionName = $"dafx-{executorId.Split("_")[0]}";
|
|
|
|
// Check if the executor type is an agent-related type
|
|
if (WorkflowHelper.IsAgentExecutorType(executorInfo.ExecutorType))
|
|
{
|
|
this._logger.LogAddingAgentEntityFunction(executorId, executorInfo.ExecutorType.TypeName, workflow.Key);
|
|
//original.Add(CreateAgentTrigger(functionName));
|
|
}
|
|
else
|
|
{
|
|
this._logger.LogAddingActivityFunction(executorId, executorInfo.ExecutorType.TypeName, workflow.Key);
|
|
original.Add(CreateActivityTrigger(functionName));
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
this._logger.LogTransformFinished(original.Count);
|
|
}
|
|
|
|
private static DefaultFunctionMetadata CreateHttpTrigger(string name, string route)
|
|
{
|
|
return new DefaultFunctionMetadata()
|
|
{
|
|
Name = $"{BuiltInFunctions.HttpPrefix}{name}",
|
|
Language = "dotnet-isolated",
|
|
RawBindings =
|
|
[
|
|
$"{{\"name\":\"req\",\"type\":\"httpTrigger\",\"direction\":\"In\",\"authLevel\":\"function\",\"methods\": [\"post\"],\"route\":\"{route}\"}}",
|
|
"{\"name\":\"$return\",\"type\":\"http\",\"direction\":\"Out\"}",
|
|
"{\"name\":\"client\",\"type\":\"durableClient\",\"direction\":\"In\"}"
|
|
],
|
|
EntryPoint = BuiltInFunctions.RunWorkflowOrechstrtationHttpFunctionEntryPoint,
|
|
ScriptFile = BuiltInFunctions.ScriptFile
|
|
};
|
|
}
|
|
|
|
//private static DefaultFunctionMetadata CreateOrchestrationTrigger(string name)
|
|
//{
|
|
// return new DefaultFunctionMetadata()
|
|
// {
|
|
// Name = AgentSessionId.ToEntityName(name),
|
|
// Language = "dotnet-isolated",
|
|
// RawBindings =
|
|
// [
|
|
// // """{"name":"context","type":"orchestrationTrigger","direction":"In"}""",
|
|
// """{"name":"taskOrchestrationContext","type":"orchestrationTrigger","direction":"In"}""",
|
|
|
|
// ],
|
|
// EntryPoint = BuiltInFunctions.RunWorkflowOrechstrtationFunctionEntryPoint,
|
|
// ScriptFile = BuiltInFunctions.ScriptFile,
|
|
// };
|
|
//}
|
|
|
|
private static DefaultFunctionMetadata CreateActivityTrigger(string functionName)
|
|
{
|
|
return new DefaultFunctionMetadata()
|
|
{
|
|
Name = functionName,
|
|
Language = "dotnet-isolated",
|
|
RawBindings =
|
|
[
|
|
"""{"name":"input","type":"activityTrigger","direction":"In","dataType":"String"}""",
|
|
"""{"name":"durableTaskClient","type":"durableClient","direction":"In"}"""
|
|
],
|
|
EntryPoint = BuiltInFunctions.InvokeWorkflowActivityFunctionEntryPoint,
|
|
ScriptFile = BuiltInFunctions.ScriptFile,
|
|
};
|
|
}
|
|
|
|
//private static DefaultFunctionMetadata CreateAgentTrigger(string functionName)
|
|
//{
|
|
// return new DefaultFunctionMetadata()
|
|
// {
|
|
// Name = functionName,
|
|
// Language = "dotnet-isolated",
|
|
// RawBindings =
|
|
// [
|
|
// """{"name":"encodedEntityRequest","type":"entityTrigger","direction":"In"}""",
|
|
// """{"name":"client","type":"durableClient","direction":"In"}"""
|
|
// ],
|
|
// EntryPoint = BuiltInFunctions.RunAgentEntityFunctionEntryPoint,
|
|
// ScriptFile = BuiltInFunctions.ScriptFile,
|
|
// };
|
|
//}
|
|
}
|