mirror of
https://github.com/microsoft/agent-framework.git
synced 2026-06-16 21:04:09 +08:00
32e7ff00b5
* feat: Add support for Workflow-as-Executor * Fixes routing of 'object' compile-typed variables to properly take in type information * Fixes a concurrency issue in StepTracer * fix: Make Subworkflow ExternalRequests work properly * fix: Threading and Concurrency fixes; prep for OffThread Mode * refactor: Remove dead code around OffStreamRunEventStream Currently not used, and will be replaced with a rewrite when brought back, so having it in the change is not valuable. * ci: Work around issues with dotnet-format not properly analyzing the source * fix: Fix the logic of AsyncCoordinator and AsyncBarrier * Prevent individual wait cancellations from canceling the entire barrier * Propagate information about whether the wait was completed or cancelled, and whether any waiters were present when released * fix: Remove superfluous acces to .Keys in InProcStepTracer * refactor: Clean up AsyncCoordinator's use of AsyncBarrier
154 lines
6.2 KiB
C#
154 lines
6.2 KiB
C#
// Copyright (c) Microsoft. All rights reserved.
|
|
|
|
using System;
|
|
using System.Threading.Tasks;
|
|
|
|
namespace Microsoft.Agents.AI.Workflows;
|
|
|
|
/// <summary>
|
|
/// Provides methods for creating <see cref="Configured{TSubject}"/> instances.
|
|
/// </summary>
|
|
public static class Configured
|
|
{
|
|
/// <summary>
|
|
/// Creates a <see cref="Configured{TSubject}"/> instance from an existing subject instance.
|
|
/// </summary>
|
|
/// <param name="subject">
|
|
/// The subject instance. If the subject implements <see cref="IIdentified"/>, its ID will be used
|
|
/// and checked against the provided ID (if any).
|
|
/// </param>
|
|
/// <param name="id">
|
|
/// A unique identifier for the configured subject. This is required if the subject does not implement
|
|
/// <see cref="IIdentified"/>
|
|
/// </param>
|
|
/// <param name="raw">
|
|
/// The raw representation of the subject instance.
|
|
/// </param>
|
|
/// <returns></returns>
|
|
public static Configured<TSubject> FromInstance<TSubject>(TSubject subject, string? id = null, object? raw = null)
|
|
{
|
|
if (subject is IIdentified identified)
|
|
{
|
|
if (id is not null && identified.Id != id)
|
|
{
|
|
throw new ArgumentException($"Provided ID '{id}' does not match subject's ID '{identified.Id}'.", nameof(id));
|
|
}
|
|
|
|
return new Configured<TSubject>((_, __) => new(subject), id: identified.Id, raw: raw ?? subject);
|
|
}
|
|
|
|
if (id is null)
|
|
{
|
|
throw new ArgumentNullException(nameof(id), "ID must be provided when the subject does not implement IIdentified.");
|
|
}
|
|
|
|
return new Configured<TSubject>((_, __) => new(subject), id, raw: raw ?? subject);
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// A representation of a preconfigured, lazy-instantiatable instance of <typeparamref name="TSubject"/>.
|
|
/// </summary>
|
|
/// <typeparam name="TSubject">The type of the preconfigured subject.</typeparam>
|
|
/// <param name="factoryAsync">A factory to intantiate the subject when desired.</param>
|
|
/// <param name="id">The unique identifier for the configured subject.</param>
|
|
/// <param name="raw"></param>
|
|
public class Configured<TSubject>(Func<Config, string, ValueTask<TSubject>> factoryAsync, string id, object? raw = null)
|
|
{
|
|
/// <summary>
|
|
/// Gets the raw representation of the configured object, if any.
|
|
/// </summary>
|
|
public object? Raw => raw;
|
|
|
|
/// <summary>
|
|
/// Gets the configured identifier for the subject.
|
|
/// </summary>
|
|
public string Id => id;
|
|
|
|
/// <summary>
|
|
/// Gets the factory function to create an instance of <typeparamref name="TSubject"/> given a <see cref="Config"/>.
|
|
/// </summary>
|
|
public Func<Config, string, ValueTask<TSubject>> FactoryAsync => factoryAsync;
|
|
|
|
/// <summary>
|
|
/// The configuration for this configured instance.
|
|
/// </summary>
|
|
public Config Configuration => new(this.Id);
|
|
|
|
/// <summary>
|
|
/// Gets a "partially" applied factory function that only requires no parameters to create an instance of
|
|
/// <typeparamref name="TSubject"/> with the provided <see cref="Configuration"/> instance.
|
|
/// </summary>
|
|
internal Func<string, ValueTask<TSubject>> BoundFactoryAsync => (runId) => this.FactoryAsync(this.Configuration, runId);
|
|
}
|
|
|
|
/// <summary>
|
|
/// A representation of a preconfigured, lazy-instantiatable instance of <typeparamref name="TSubject"/>.
|
|
/// </summary>
|
|
/// <typeparam name="TSubject">The type of the preconfigured subject.</typeparam>
|
|
/// <typeparam name="TOptions">The type of configuration options for the preconfigured subject.</typeparam>
|
|
/// <param name="factoryAsync">A factory to intantiate the subject when desired.</param>
|
|
/// <param name="id">The unique identifier for the configured subject.</param>
|
|
/// <param name="options">Additional configuration options for the subject.</param>
|
|
/// <param name="raw"></param>
|
|
public class Configured<TSubject, TOptions>(Func<Config<TOptions>, string, ValueTask<TSubject>> factoryAsync, string id, TOptions? options = default, object? raw = null)
|
|
{
|
|
/// <summary>
|
|
/// The raw representation of the configured object, if any.
|
|
/// </summary>
|
|
public object? Raw => raw;
|
|
|
|
/// <summary>
|
|
/// Gets the configured identifier for the subject.
|
|
/// </summary>
|
|
public string Id => id;
|
|
|
|
/// <summary>
|
|
/// Gets the options associated with this instance.
|
|
/// </summary>
|
|
public TOptions? Options => options;
|
|
|
|
/// <summary>
|
|
/// Gets the factory function to create an instance of <typeparamref name="TSubject"/> given a <see cref="Config{TOptions}"/>.
|
|
/// </summary>
|
|
public Func<Config<TOptions>, string, ValueTask<TSubject>> FactoryAsync => factoryAsync;
|
|
|
|
/// <summary>
|
|
/// The configuration for this configured instance.
|
|
/// </summary>
|
|
public Config<TOptions> Configuration => new(this.Id, this.Options);
|
|
|
|
/// <summary>
|
|
/// Gets a "partially" applied factory function that only requires no parameters to create an instance of
|
|
/// <typeparamref name="TSubject"/> with the provided <see cref="Configuration"/> instance.
|
|
/// </summary>
|
|
internal Func<string, ValueTask<TSubject>> BoundFactoryAsync => (runId) => this.CreateValidatingMemoizedFactory()(this.Configuration, runId);
|
|
|
|
private Func<Config, string, ValueTask<TSubject>> CreateValidatingMemoizedFactory()
|
|
{
|
|
return FactoryAsync;
|
|
|
|
async ValueTask<TSubject> FactoryAsync(Config configuration, string runId)
|
|
{
|
|
if (this.Id != configuration.Id)
|
|
{
|
|
throw new InvalidOperationException($"Requested instance ID '{configuration.Id}' does not match configured ID '{this.Id}'.");
|
|
}
|
|
|
|
TSubject subject = await this.FactoryAsync(this.Configuration, runId).ConfigureAwait(false);
|
|
|
|
if (this.Id is not null && subject is IIdentified identified && identified.Id != this.Id)
|
|
{
|
|
throw new InvalidOperationException($"Created instance ID '{identified.Id}' does not match configured ID '{this.Id}'.");
|
|
}
|
|
|
|
return subject;
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Memoizes and erases the typed configuration options for the subject.
|
|
/// </summary>
|
|
public Configured<TSubject> Memoize() => new(this.CreateValidatingMemoizedFactory(), this.Id);
|
|
}
|