mirror of
https://github.com/microsoft/agent-framework.git
synced 2026-06-16 21:04:09 +08:00
0086d38f58
* refactor: Normalize Run/RunStreaming with AIAgent * refactor: Clarify Session vs. Run -level concepts * Rename RunId to SessionId to better match Run/Session terminology in AIAgent * [BREAKING]: Will break existing checkpointed sessions in CosmosDb due to field rename * refactor: Rename and simplify interface around getting typed data out of ExternalRequest/Response * Also adds hints around using value types in PortableValue * refactor: Rename AddFanInEdge to AddFanInBarrierEdge This will prevent a breaking change later when we introduce a programmable FanIn edge, analogous to the FanOut edge's EdgeSelector. The goal, in the long run is to support a number of different FanIn scenarios, with naive FanIn (no barrier) by default, similar to FanOut. * refactor: AsAgent(this Workflow, ...) => AsAIAgent(...) * misc - part1: SwitchBuilder internal --------- Co-authored-by: Dmytro Struk <13853051+dmytrostruk@users.noreply.github.com>
444 lines
34 KiB
C#
444 lines
34 KiB
C#
// Copyright (c) Microsoft. All rights reserved.
|
|
|
|
using System;
|
|
using System.ComponentModel;
|
|
using System.Threading;
|
|
using System.Threading.Tasks;
|
|
using Microsoft.Shared.Diagnostics;
|
|
|
|
namespace Microsoft.Agents.AI.Workflows;
|
|
|
|
/// <summary>
|
|
/// Extension methods for configuring executors and functions as <see cref="ExecutorBinding"/> instances.
|
|
/// </summary>
|
|
public static class ExecutorBindingExtensions
|
|
{
|
|
/// <summary>
|
|
/// Configures an <see cref="Executor"/> instance for use in a workflow.
|
|
/// </summary>
|
|
/// <remarks>
|
|
/// Note that Executor Ids must be unique within a workflow.
|
|
/// </remarks>
|
|
/// <param name="executor">The executor instance.</param>
|
|
/// <returns>An <see cref="ExecutorBinding"/> instance wrapping the specified <see cref="Executor"/>.</returns>
|
|
public static ExecutorBinding BindExecutor(this Executor executor)
|
|
=> new ExecutorInstanceBinding(executor);
|
|
|
|
/// <summary>
|
|
/// Configures a factory method for creating an <see cref="Executor"/> of type <typeparamref name="TExecutor"/>, using the
|
|
/// type name as the id.
|
|
/// </summary>
|
|
/// <remarks>
|
|
/// Note that Executor Ids must be unique within a workflow.
|
|
///
|
|
/// Although this will generally result in a delay-instantiated <see cref="Executor"/> once messages are available
|
|
/// for it, it will be instantiated if a <see cref="ProtocolDescriptor"/> for the <see cref="Workflow"/> is requested,
|
|
/// and it is the starting executor.
|
|
/// </remarks>
|
|
/// <typeparam name="TExecutor">The type of the resulting executor</typeparam>
|
|
/// <param name="factoryAsync">The factory method.</param>
|
|
/// <returns>An <see cref="ExecutorBinding"/> instance that resolves to the result of the factory call when messages get sent to it.</returns>
|
|
public static ExecutorBinding BindExecutor<TExecutor>(this Func<string, string, ValueTask<TExecutor>> factoryAsync)
|
|
where TExecutor : Executor
|
|
=> BindExecutor<TExecutor, ExecutorOptions>((config, sessionId) => factoryAsync(config.Id, sessionId), id: typeof(TExecutor).Name, options: null);
|
|
|
|
/// <summary>
|
|
/// Configures a factory method for creating an <see cref="Executor"/> of type <typeparamref name="TExecutor"/>, using the
|
|
/// type name as the id.
|
|
/// </summary>
|
|
/// <remarks>
|
|
/// Note that Executor Ids must be unique within a workflow.
|
|
///
|
|
/// Although this will generally result in a delay-instantiated <see cref="Executor"/> once messages are available
|
|
/// for it, it will be instantiated if a <see cref="ProtocolDescriptor"/> for the <see cref="Workflow"/> is requested,
|
|
/// and it is the starting executor.
|
|
/// </remarks>
|
|
/// <typeparam name="TExecutor">The type of the resulting executor</typeparam>
|
|
/// <param name="factoryAsync">The factory method.</param>
|
|
/// <returns>An <see cref="ExecutorBinding"/> instance that resolves to the result of the factory call when messages get sent to it.</returns>
|
|
[Obsolete("Use BindExecutor() instead.")]
|
|
[EditorBrowsable(EditorBrowsableState.Never)]
|
|
public static ExecutorBinding ConfigureFactory<TExecutor>(this Func<string, string, ValueTask<TExecutor>> factoryAsync)
|
|
where TExecutor : Executor
|
|
=> factoryAsync.BindExecutor();
|
|
|
|
/// <summary>
|
|
/// Configures a factory method for creating an <see cref="Executor"/> of type <typeparamref name="TExecutor"/>, with
|
|
/// the specified id.
|
|
/// </summary>
|
|
/// <remarks>
|
|
/// Although this will generally result in a delay-instantiated <see cref="Executor"/> once messages are available
|
|
/// for it, it will be instantiated if a <see cref="ProtocolDescriptor"/> for the <see cref="Workflow"/> is requested,
|
|
/// and it is the starting executor.
|
|
/// </remarks>
|
|
/// <typeparam name="TExecutor">The type of the resulting executor</typeparam>
|
|
/// <param name="factoryAsync">The factory method.</param>
|
|
/// <param name="id">An id for the executor to be instantiated.</param>
|
|
/// <returns>An <see cref="ExecutorBinding"/> instance that resolves to the result of the factory call when messages get sent to it.</returns>
|
|
public static ExecutorBinding BindExecutor<TExecutor>(this Func<string, string, ValueTask<TExecutor>> factoryAsync, string id)
|
|
where TExecutor : Executor
|
|
=> BindExecutor<TExecutor, ExecutorOptions>((_, sessionId) => factoryAsync(id, sessionId), id, options: null);
|
|
|
|
/// <summary>
|
|
/// Configures a factory method for creating an <see cref="Executor"/> of type <typeparamref name="TExecutor"/>, with
|
|
/// the specified id.
|
|
/// </summary>
|
|
/// <remarks>
|
|
/// Although this will generally result in a delay-instantiated <see cref="Executor"/> once messages are available
|
|
/// for it, it will be instantiated if a <see cref="ProtocolDescriptor"/> for the <see cref="Workflow"/> is requested,
|
|
/// and it is the starting executor.
|
|
/// </remarks>
|
|
/// <typeparam name="TExecutor">The type of the resulting executor</typeparam>
|
|
/// <param name="factoryAsync">The factory method.</param>
|
|
/// <param name="id">An id for the executor to be instantiated.</param>
|
|
/// <returns>An <see cref="ExecutorBinding"/> instance that resolves to the result of the factory call when messages get sent to it.</returns>
|
|
[Obsolete("Use BindExecutor() instead.")]
|
|
[EditorBrowsable(EditorBrowsableState.Never)]
|
|
public static ExecutorBinding ConfigureFactory<TExecutor>(this Func<string, string, ValueTask<TExecutor>> factoryAsync, string id)
|
|
where TExecutor : Executor
|
|
=> factoryAsync.BindExecutor(id);
|
|
|
|
/// <summary>
|
|
/// Configures a factory method for creating an <see cref="Executor"/> of type <typeparamref name="TExecutor"/>, with
|
|
/// the specified id and options.
|
|
/// </summary>
|
|
/// <remarks>
|
|
/// Although this will generally result in a delay-instantiated <see cref="Executor"/> once messages are available
|
|
/// for it, it will be instantiated if a <see cref="ProtocolDescriptor"/> for the <see cref="Workflow"/> is requested,
|
|
/// and it is the starting executor.
|
|
/// </remarks>
|
|
/// <typeparam name="TExecutor">The type of the resulting executor</typeparam>
|
|
/// <typeparam name="TOptions">The type of options object to be passed to the factory method.</typeparam>
|
|
/// <param name="factoryAsync">The factory method.</param>
|
|
/// <param name="id">An id for the executor to be instantiated.</param>
|
|
/// <param name="options">An optional parameter specifying the options.</param>
|
|
/// <returns>An <see cref="ExecutorBinding"/> instance that resolves to the result of the factory call when messages get sent to it.</returns>
|
|
public static ExecutorBinding BindExecutor<TExecutor, TOptions>(this Func<Config<TOptions>, string, ValueTask<TExecutor>> factoryAsync, string id, TOptions? options = null)
|
|
where TExecutor : Executor
|
|
where TOptions : ExecutorOptions
|
|
{
|
|
Configured<TExecutor, TOptions> configured = new(factoryAsync, id, options);
|
|
|
|
return new ConfiguredExecutorBinding(configured.Super<TExecutor, Executor, TOptions>(), typeof(TExecutor));
|
|
}
|
|
|
|
/// <summary>
|
|
/// Configures a factory method for creating an <see cref="Executor"/> of type <typeparamref name="TExecutor"/>, with
|
|
/// the specified id and options.
|
|
/// </summary>
|
|
/// <remarks>
|
|
/// Although this will generally result in a delay-instantiated <see cref="Executor"/> once messages are available
|
|
/// for it, it will be instantiated if a <see cref="ProtocolDescriptor"/> for the <see cref="Workflow"/> is requested,
|
|
/// and it is the starting executor.
|
|
/// </remarks>
|
|
/// <typeparam name="TExecutor">The type of the resulting executor</typeparam>
|
|
/// <typeparam name="TOptions">The type of options object to be passed to the factory method.</typeparam>
|
|
/// <param name="factoryAsync">The factory method.</param>
|
|
/// <param name="id">An id for the executor to be instantiated.</param>
|
|
/// <param name="options">An optional parameter specifying the options.</param>
|
|
/// <returns>An <see cref="ExecutorBinding"/> instance that resolves to the result of the factory call when messages get sent to it.</returns>
|
|
[Obsolete("Use BindExecutor() instead")]
|
|
[EditorBrowsable(EditorBrowsableState.Never)]
|
|
public static ExecutorBinding ConfigureFactory<TExecutor, TOptions>(this Func<Config<TOptions>, string, ValueTask<TExecutor>> factoryAsync, string id, TOptions? options = null)
|
|
where TExecutor : Executor
|
|
where TOptions : ExecutorOptions
|
|
=> factoryAsync.BindExecutor(id, options);
|
|
|
|
private static ConfiguredExecutorBinding ToBinding<TInput>(this FunctionExecutor<TInput> executor, Delegate raw)
|
|
=> new(Configured.FromInstance(executor, raw: raw)
|
|
.Super<FunctionExecutor<TInput>, Executor>(),
|
|
typeof(FunctionExecutor<TInput>));
|
|
|
|
private static ConfiguredExecutorBinding ToBinding<TInput, TOutput>(this FunctionExecutor<TInput, TOutput> executor, Delegate raw)
|
|
=> new(Configured.FromInstance(executor, raw: raw)
|
|
.Super<FunctionExecutor<TInput, TOutput>, Executor>(),
|
|
typeof(FunctionExecutor<TInput, TOutput>));
|
|
|
|
/// <summary>
|
|
/// Configures a sub-workflow executor for the specified workflow, using the provided identifier and options.
|
|
/// </summary>
|
|
/// <param name="workflow">The workflow instance to be executed as a sub-workflow. Cannot be null.</param>
|
|
/// <param name="id">A unique identifier for the sub-workflow execution. Used to distinguish this sub-workflow instance.</param>
|
|
/// <param name="options">Optional configuration options for the sub-workflow executor. If null, default options are used.</param>
|
|
/// <returns>An ExecutorRegistration instance representing the configured sub-workflow executor.</returns>
|
|
[Obsolete("Use BindAsExecutor() instead")]
|
|
[EditorBrowsable(EditorBrowsableState.Never)]
|
|
public static ExecutorBinding ConfigureSubWorkflow(this Workflow workflow, string id, ExecutorOptions? options = null)
|
|
=> workflow.BindAsExecutor(id, options);
|
|
|
|
/// <summary>
|
|
/// Configures a sub-workflow executor for the specified workflow, using the provided identifier and options.
|
|
/// </summary>
|
|
/// <param name="workflow">The workflow instance to be executed as a sub-workflow. Cannot be null.</param>
|
|
/// <param name="id">A unique identifier for the sub-workflow execution. Used to distinguish this sub-workflow instance.</param>
|
|
/// <param name="options">Optional configuration options for the sub-workflow executor. If null, default options are used.</param>
|
|
/// <returns>An <see cref="ExecutorBinding"/> instance representing the configured sub-workflow executor.</returns>
|
|
public static ExecutorBinding BindAsExecutor(this Workflow workflow, string id, ExecutorOptions? options = null)
|
|
=> new SubworkflowBinding(workflow, id, options);
|
|
|
|
/// <summary>
|
|
/// Configures a function-based asynchronous message handler as an executor with the specified identifier and
|
|
/// options.
|
|
/// </summary>
|
|
/// <typeparam name="TInput">The type of input message.</typeparam>
|
|
/// <param name="messageHandlerAsync">A delegate that defines the asynchronous function to execute for each input message.</param>
|
|
/// <param name="id">An optional unique identifier for the executor. If <c>null</c>, will use the function argument as an id.</param>
|
|
/// <param name="options">Configuration options for the executor. If <c>null</c>, default options will be used.</param>
|
|
/// <param name="threadsafe">Declare that the message handler may be used simultaneously by multiple runs concurrently.</param>
|
|
/// <returns>An <see cref="ExecutorBinding"/> instance that wraps the provided asynchronous message handler and configuration.</returns>
|
|
public static ExecutorBinding BindAsExecutor<TInput>(this Func<TInput, IWorkflowContext, CancellationToken, ValueTask> messageHandlerAsync, string id, ExecutorOptions? options = null, bool threadsafe = false)
|
|
=> new FunctionExecutor<TInput>(id, messageHandlerAsync, options, declareCrossRunShareable: threadsafe).ToBinding(messageHandlerAsync);
|
|
|
|
/// <summary>
|
|
/// Configures a function-based asynchronous message handler as an executor with the specified identifier and
|
|
/// options.
|
|
/// </summary>
|
|
/// <typeparam name="TInput">The type of input message.</typeparam>
|
|
/// <param name="messageHandlerAsync">A delegate that defines the asynchronous function to execute for each input message.</param>
|
|
/// <param name="id">An optional unique identifier for the executor. If <c>null</c>, will use the function argument as an id.</param>
|
|
/// <param name="options">Configuration options for the executor. If <c>null</c>, default options will be used.</param>
|
|
/// <param name="threadsafe">Declare that the message handler may be used simultaneously by multiple runs concurrently.</param>
|
|
/// <returns>An <see cref="ExecutorBinding"/> instance that wraps the provided asynchronous message handler and configuration.</returns>
|
|
public static ExecutorBinding BindAsExecutor<TInput>(this Func<TInput, ValueTask> messageHandlerAsync, string id, ExecutorOptions? options = null, bool threadsafe = false)
|
|
=> ((Func<TInput, IWorkflowContext, CancellationToken, ValueTask>)((input, _, __) => messageHandlerAsync(input)))
|
|
.BindAsExecutor(id, options, threadsafe);
|
|
|
|
/// <summary>
|
|
/// Configures a function-based asynchronous message handler as an executor with the specified identifier and
|
|
/// options.
|
|
/// </summary>
|
|
/// <typeparam name="TInput">The type of input message.</typeparam>
|
|
/// <param name="messageHandlerAsync">A delegate that defines the asynchronous function to execute for each input message.</param>
|
|
/// <param name="id">An optional unique identifier for the executor. If <c>null</c>, will use the function argument as an id.</param>
|
|
/// <param name="options">Configuration options for the executor. If <c>null</c>, default options will be used.</param>
|
|
/// <param name="threadsafe">Declare that the message handler may be used simultaneously by multiple runs concurrently.</param>
|
|
/// <returns>An <see cref="ExecutorBinding"/> instance that wraps the provided asynchronous message handler and configuration.</returns>
|
|
public static ExecutorBinding BindAsExecutor<TInput>(this Func<TInput, IWorkflowContext, ValueTask> messageHandlerAsync, string id, ExecutorOptions? options = null, bool threadsafe = false)
|
|
=> ((Func<TInput, IWorkflowContext, CancellationToken, ValueTask>)((input, ctx, __) => messageHandlerAsync(input, ctx)))
|
|
.BindAsExecutor(id, options, threadsafe);
|
|
|
|
/// <summary>
|
|
/// Configures a function-based asynchronous message handler as an executor with the specified identifier and
|
|
/// options.
|
|
/// </summary>
|
|
/// <typeparam name="TInput">The type of input message.</typeparam>
|
|
/// <param name="messageHandlerAsync">A delegate that defines the asynchronous function to execute for each input message.</param>
|
|
/// <param name="id">An optional unique identifier for the executor. If <c>null</c>, will use the function argument as an id.</param>
|
|
/// <param name="options">Configuration options for the executor. If <c>null</c>, default options will be used.</param>
|
|
/// <param name="threadsafe">Declare that the message handler may be used simultaneously by multiple runs concurrently.</param>
|
|
/// <returns>An <see cref="ExecutorBinding"/> instance that wraps the provided asynchronous message handler and configuration.</returns>
|
|
public static ExecutorBinding BindAsExecutor<TInput>(this Func<TInput, CancellationToken, ValueTask> messageHandlerAsync, string id, ExecutorOptions? options = null, bool threadsafe = false)
|
|
=> ((Func<TInput, IWorkflowContext, CancellationToken, ValueTask>)((input, _, ct) => messageHandlerAsync(input, ct)))
|
|
.BindAsExecutor(id, options, threadsafe);
|
|
|
|
/// <summary>
|
|
/// Configures a function-based message handler as an executor with the specified identifier and
|
|
/// options.
|
|
/// </summary>
|
|
/// <typeparam name="TInput">The type of input message.</typeparam>
|
|
/// <param name="messageHandler">A delegate that defines the function to execute for each input message.</param>
|
|
/// <param name="id">An optional unique identifier for the executor. If <c>null</c>, will use the function argument as an id.</param>
|
|
/// <param name="options">Configuration options for the executor. If <c>null</c>, default options will be used.</param>
|
|
/// <param name="threadsafe">Declare that the message handler may be used simultaneously by multiple runs concurrently.</param>
|
|
/// <returns>An <see cref="ExecutorBinding"/> instance that wraps the provided asynchronous message handler and configuration.</returns>
|
|
public static ExecutorBinding BindAsExecutor<TInput>(this Action<TInput, IWorkflowContext, CancellationToken> messageHandler, string id, ExecutorOptions? options = null, bool threadsafe = false)
|
|
=> new FunctionExecutor<TInput>(id, messageHandler, options, declareCrossRunShareable: threadsafe).ToBinding(messageHandler);
|
|
|
|
/// <summary>
|
|
/// Configures a function-based message handler as an executor with the specified identifier and
|
|
/// options.
|
|
/// </summary>
|
|
/// <typeparam name="TInput">The type of input message.</typeparam>
|
|
/// <param name="messageHandler">A delegate that defines the function to execute for each input message.</param>
|
|
/// <param name="id">An optional unique identifier for the executor. If <c>null</c>, will use the function argument as an id.</param>
|
|
/// <param name="options">Configuration options for the executor. If <c>null</c>, default options will be used.</param>
|
|
/// <param name="threadsafe">Declare that the message handler may be used simultaneously by multiple runs concurrently.</param>
|
|
/// <returns>An <see cref="ExecutorBinding"/> instance that wraps the provided asynchronous message handler and configuration.</returns>
|
|
public static ExecutorBinding BindAsExecutor<TInput>(this Action<TInput> messageHandler, string id, ExecutorOptions? options = null, bool threadsafe = false)
|
|
=> ((Action<TInput, IWorkflowContext, CancellationToken>)((input, _, __) => messageHandler(input)))
|
|
.BindAsExecutor(id, options, threadsafe);
|
|
|
|
/// <summary>
|
|
/// Configures a function-based message handler as an executor with the specified identifier and
|
|
/// options.
|
|
/// </summary>
|
|
/// <typeparam name="TInput">The type of input message.</typeparam>
|
|
/// <param name="messageHandler">A delegate that defines the function to execute for each input message.</param>
|
|
/// <param name="id">An optional unique identifier for the executor. If <c>null</c>, will use the function argument as an id.</param>
|
|
/// <param name="options">Configuration options for the executor. If <c>null</c>, default options will be used.</param>
|
|
/// <param name="threadsafe">Declare that the message handler may be used simultaneously by multiple runs concurrently.</param>
|
|
/// <returns>An <see cref="ExecutorBinding"/> instance that wraps the provided asynchronous message handler and configuration.</returns>
|
|
public static ExecutorBinding BindAsExecutor<TInput>(this Action<TInput, IWorkflowContext> messageHandler, string id, ExecutorOptions? options = null, bool threadsafe = false)
|
|
=> ((Action<TInput, IWorkflowContext, CancellationToken>)((input, ctx, __) => messageHandler(input, ctx)))
|
|
.BindAsExecutor(id, options, threadsafe);
|
|
|
|
/// <summary>
|
|
/// Configures a function-based message handler as an executor with the specified identifier and
|
|
/// options.
|
|
/// </summary>
|
|
/// <typeparam name="TInput">The type of input message.</typeparam>
|
|
/// <param name="messageHandler">A delegate that defines the function to execute for each input message.</param>
|
|
/// <param name="id">An optional unique identifier for the executor. If <c>null</c>, will use the function argument as an id.</param>
|
|
/// <param name="options">Configuration options for the executor. If <c>null</c>, default options will be used.</param>
|
|
/// <param name="threadsafe">Declare that the message handler may be used simultaneously by multiple runs concurrently.</param>
|
|
/// <returns>An <see cref="ExecutorBinding"/> instance that wraps the provided asynchronous message handler and configuration.</returns>
|
|
public static ExecutorBinding BindAsExecutor<TInput>(this Action<TInput, CancellationToken> messageHandler, string id, ExecutorOptions? options = null, bool threadsafe = false)
|
|
=> ((Action<TInput, IWorkflowContext, CancellationToken>)((input, _, ct) => messageHandler(input, ct)))
|
|
.BindAsExecutor(id, options, threadsafe);
|
|
|
|
/// <summary>
|
|
/// Configures a function-based asynchronous message handler as an executor with the specified identifier and
|
|
/// options.
|
|
/// </summary>
|
|
/// <typeparam name="TInput">The type of input message.</typeparam>
|
|
/// <typeparam name="TOutput">The type of output message.</typeparam>
|
|
/// <param name="messageHandlerAsync">A delegate that defines the asynchronous function to execute for each input message.</param>
|
|
/// <param name="id">A unique identifier for the executor.</param>
|
|
/// <param name="options">Configuration options for the executor. If <c>null</c>, default options will be used.</param>
|
|
/// <param name="threadsafe">Declare that the message handler may be used simultaneously by multiple runs concurrently.</param>
|
|
/// <returns>An <see cref="ExecutorBinding"/> instance that wraps the provided asynchronous message handler and configuration.</returns>
|
|
public static ExecutorBinding BindAsExecutor<TInput, TOutput>(this Func<TInput, IWorkflowContext, CancellationToken, ValueTask<TOutput>> messageHandlerAsync, string id, ExecutorOptions? options = null, bool threadsafe = false)
|
|
=> new FunctionExecutor<TInput, TOutput>(Throw.IfNull(id), messageHandlerAsync, options, declareCrossRunShareable: threadsafe).ToBinding(messageHandlerAsync);
|
|
|
|
/// <summary>
|
|
/// Configures a function-based asynchronous message handler as an executor with the specified identifier and
|
|
/// options.
|
|
/// </summary>
|
|
/// <typeparam name="TInput">The type of input message.</typeparam>
|
|
/// <typeparam name="TOutput">The type of output message.</typeparam>
|
|
/// <param name="messageHandlerAsync">A delegate that defines the asynchronous function to execute for each input message.</param>
|
|
/// <param name="id">An optional unique identifier for the executor. If <c>null</c>, will use the function argument as an id.</param>
|
|
/// <param name="options">Configuration options for the executor. If <c>null</c>, default options will be used.</param>
|
|
/// <param name="threadsafe">Declare that the message handler may be used simultaneously by multiple runs concurrently.</param>
|
|
/// <returns>An <see cref="ExecutorBinding"/> instance that wraps the provided asynchronous message handler and configuration.</returns>
|
|
public static ExecutorBinding BindAsExecutor<TInput, TOutput>(this Func<TInput, ValueTask<TOutput>> messageHandlerAsync, string id, ExecutorOptions? options = null, bool threadsafe = false)
|
|
=> ((Func<TInput, IWorkflowContext, CancellationToken, ValueTask<TOutput>>)((input, _, __) => messageHandlerAsync(input)))
|
|
.BindAsExecutor(id, options, threadsafe);
|
|
|
|
/// <summary>
|
|
/// Configures a function-based asynchronous message handler as an executor with the specified identifier and
|
|
/// options.
|
|
/// </summary>
|
|
/// <typeparam name="TInput">The type of input message.</typeparam>
|
|
/// <typeparam name="TOutput">The type of output message.</typeparam>
|
|
/// <param name="messageHandlerAsync">A delegate that defines the asynchronous function to execute for each input message.</param>
|
|
/// <param name="id">An optional unique identifier for the executor. If <c>null</c>, will use the function argument as an id.</param>
|
|
/// <param name="options">Configuration options for the executor. If <c>null</c>, default options will be used.</param>
|
|
/// <param name="threadsafe">Declare that the message handler may be used simultaneously by multiple runs concurrently.</param>
|
|
/// <returns>An <see cref="ExecutorBinding"/> instance that wraps the provided asynchronous message handler and configuration.</returns>
|
|
public static ExecutorBinding BindAsExecutor<TInput, TOutput>(this Func<TInput, IWorkflowContext, ValueTask<TOutput>> messageHandlerAsync, string id, ExecutorOptions? options = null, bool threadsafe = false)
|
|
=> ((Func<TInput, IWorkflowContext, CancellationToken, ValueTask<TOutput>>)((input, ctx, __) => messageHandlerAsync(input, ctx)))
|
|
.BindAsExecutor(id, options, threadsafe);
|
|
|
|
/// <summary>
|
|
/// Configures a function-based asynchronous message handler as an executor with the specified identifier and
|
|
/// options.
|
|
/// </summary>
|
|
/// <typeparam name="TInput">The type of input message.</typeparam>
|
|
/// <typeparam name="TOutput">The type of output message.</typeparam>
|
|
/// <param name="messageHandlerAsync">A delegate that defines the asynchronous function to execute for each input message.</param>
|
|
/// <param name="id">An optional unique identifier for the executor. If <c>null</c>, will use the function argument as an id.</param>
|
|
/// <param name="options">Configuration options for the executor. If <c>null</c>, default options will be used.</param>
|
|
/// <param name="threadsafe">Declare that the message handler may be used simultaneously by multiple runs concurrently.</param>
|
|
/// <returns>An <see cref="ExecutorBinding"/> instance that wraps the provided asynchronous message handler and configuration.</returns>
|
|
public static ExecutorBinding BindAsExecutor<TInput, TOutput>(this Func<TInput, CancellationToken, ValueTask<TOutput>> messageHandlerAsync, string id, ExecutorOptions? options = null, bool threadsafe = false)
|
|
=> ((Func<TInput, IWorkflowContext, CancellationToken, ValueTask<TOutput>>)((input, _, ct) => messageHandlerAsync(input, ct)))
|
|
.BindAsExecutor(id, options, threadsafe);
|
|
|
|
/// <summary>
|
|
/// Configures a function-based message handler as an executor with the specified identifier and options.
|
|
/// </summary>
|
|
/// <typeparam name="TInput">The type of input message.</typeparam>
|
|
/// <typeparam name="TOutput">The type of output message.</typeparam>
|
|
/// <param name="messageHandler">A delegate that defines the function to execute for each input message.</param>
|
|
/// <param name="id">An optional unique identifier for the executor. If <c>null</c>, will use the function argument as an id.</param>
|
|
/// <param name="options">Configuration options for the executor. If <c>null</c>, default options will be used.</param>
|
|
/// <param name="threadsafe">Declare that the message handler may be used simultaneously by multiple runs concurrently.</param>
|
|
/// <returns>An <see cref="ExecutorBinding"/> instance that wraps the provided asynchronous message handler and configuration.</returns>
|
|
public static ExecutorBinding BindAsExecutor<TInput, TOutput>(this Func<TInput, IWorkflowContext, CancellationToken, TOutput> messageHandler, string id, ExecutorOptions? options = null, bool threadsafe = false)
|
|
=> new FunctionExecutor<TInput, TOutput>(id, messageHandler, options, declareCrossRunShareable: threadsafe).ToBinding(messageHandler);
|
|
|
|
/// <summary>
|
|
/// Configures a function-based message handler as an executor with the specified identifier and options.
|
|
/// </summary>
|
|
/// <typeparam name="TInput">The type of input message.</typeparam>
|
|
/// <typeparam name="TOutput">The type of output message.</typeparam>
|
|
/// <param name="messageHandler">A delegate that defines the function to execute for each input message.</param>
|
|
/// <param name="id">An optional unique identifier for the executor. If <c>null</c>, will use the function argument as an id.</param>
|
|
/// <param name="options">Configuration options for the executor. If <c>null</c>, default options will be used.</param>
|
|
/// <param name="threadsafe">Declare that the message handler may be used simultaneously by multiple runs concurrently.</param>
|
|
/// <returns>An <see cref="ExecutorBinding"/> instance that wraps the provided asynchronous message handler and configuration.</returns>
|
|
public static ExecutorBinding BindAsExecutor<TInput, TOutput>(this Func<TInput, TOutput> messageHandler, string id, ExecutorOptions? options = null, bool threadsafe = false)
|
|
=> ((Func<TInput, IWorkflowContext, CancellationToken, TOutput>)((input, _, __) => messageHandler(input)))
|
|
.BindAsExecutor(id, options, threadsafe);
|
|
|
|
/// <summary>
|
|
/// Configures a function-based message handler as an executor with the specified identifier and options.
|
|
/// </summary>
|
|
/// <typeparam name="TInput">The type of input message.</typeparam>
|
|
/// <typeparam name="TOutput">The type of output message.</typeparam>
|
|
/// <param name="messageHandler">A delegate that defines the function to execute for each input message.</param>
|
|
/// <param name="id">An optional unique identifier for the executor. If <c>null</c>, will use the function argument as an id.</param>
|
|
/// <param name="options">Configuration options for the executor. If <c>null</c>, default options will be used.</param>
|
|
/// <param name="threadsafe">Declare that the message handler may be used simultaneously by multiple runs concurrently.</param>
|
|
/// <returns>An <see cref="ExecutorBinding"/> instance that wraps the provided asynchronous message handler and configuration.</returns>
|
|
public static ExecutorBinding BindAsExecutor<TInput, TOutput>(this Func<TInput, IWorkflowContext, TOutput> messageHandler, string id, ExecutorOptions? options = null, bool threadsafe = false)
|
|
=> ((Func<TInput, IWorkflowContext, CancellationToken, TOutput>)((input, ctx, __) => messageHandler(input, ctx)))
|
|
.BindAsExecutor(id, options, threadsafe);
|
|
|
|
/// <summary>
|
|
/// Configures a function-based message handler as an executor with the specified identifier and options.
|
|
/// </summary>
|
|
/// <typeparam name="TInput">The type of input message.</typeparam>
|
|
/// <typeparam name="TOutput">The type of output message.</typeparam>
|
|
/// <param name="messageHandler">A delegate that defines the function to execute for each input message.</param>
|
|
/// <param name="id">An optional unique identifier for the executor. If <c>null</c>, will use the function argument as an id.</param>
|
|
/// <param name="options">Configuration options for the executor. If <c>null</c>, default options will be used.</param>
|
|
/// <param name="threadsafe">Declare that the message handler may be used simultaneously by multiple runs concurrently.</param>
|
|
/// <returns>An <see cref="ExecutorBinding"/> instance that wraps the provided asynchronous message handler and configuration.</returns>
|
|
public static ExecutorBinding BindAsExecutor<TInput, TOutput>(this Func<TInput, CancellationToken, TOutput> messageHandler, string id, ExecutorOptions? options = null, bool threadsafe = false)
|
|
=> ((Func<TInput, IWorkflowContext, CancellationToken, TOutput>)((input, _, ct) => messageHandler(input, ct)))
|
|
.BindAsExecutor(id, options, threadsafe);
|
|
|
|
/// <summary>
|
|
/// Configures a function-based aggregating executor with the specified identifier and options.
|
|
/// </summary>
|
|
/// <typeparam name="TInput">The type of input message.</typeparam>
|
|
/// <typeparam name="TAccumulate">The type of the accumulating object.</typeparam>
|
|
/// <param name="aggregatorFunc">A delegate the defines the aggregation procedure</param>
|
|
/// <param name="id">A unique identifier for the executor.</param>
|
|
/// <param name="options">Configuration options for the executor. If <c>null</c>, default options will be used.</param>
|
|
/// <param name="threadsafe">Declare that the message handler may be used simultaneously by multiple runs concurrently.</param>
|
|
/// <returns>An <see cref="ExecutorBinding"/> instance that wraps the provided asynchronous message handler and configuration.</returns>
|
|
public static ExecutorBinding BindAsExecutor<TInput, TAccumulate>(this Func<TAccumulate?, TInput, TAccumulate?> aggregatorFunc, string id, ExecutorOptions? options = null, bool threadsafe = false)
|
|
=> new AggregatingExecutor<TInput, TAccumulate>(id, aggregatorFunc, options, declareCrossRunShareable: threadsafe);
|
|
|
|
/// <summary>
|
|
/// Configure an <see cref="AIAgent"/> as an executor for use in a workflow.
|
|
/// </summary>
|
|
/// <param name="agent">The agent instance.</param>
|
|
/// <param name="emitEvents">Specifies whether the agent should emit streaming events.</param>
|
|
/// <returns>An <see cref="AIAgentBinding"/> instance that wraps the provided agent.</returns>
|
|
public static ExecutorBinding BindAsExecutor(this AIAgent agent, bool emitEvents)
|
|
=> new AIAgentBinding(agent, emitEvents);
|
|
|
|
/// <summary>
|
|
/// Configure an <see cref="AIAgent"/> as an executor for use in a workflow.
|
|
/// </summary>
|
|
/// <param name="agent">The agent instance.</param>
|
|
/// <param name="options">Optional configuration options for the AI agent executor. If null, default options are used.</param>
|
|
/// <returns>An <see cref="AIAgentBinding"/> instance that wraps the provided agent.</returns>
|
|
public static ExecutorBinding BindAsExecutor(this AIAgent agent, AIAgentHostOptions? options = null)
|
|
=> new AIAgentBinding(agent, options);
|
|
|
|
/// <summary>
|
|
/// Configure a <see cref="RequestPort"/> as an executor for use in a workflow.
|
|
/// </summary>
|
|
/// <param name="port">The port configuration.</param>
|
|
/// <param name="allowWrappedRequests">Specifies whether the port should accept requests already wrapped in
|
|
/// <see cref="ExternalRequest"/>.</param>
|
|
/// <returns>A <see cref="RequestPortBinding"/> instance that wraps the provided port.</returns>
|
|
public static ExecutorBinding BindAsExecutor(this RequestPort port, bool allowWrappedRequests = true)
|
|
=> new RequestPortBinding(port, allowWrappedRequests);
|
|
}
|