Files
agent-framework/dotnet/src/Microsoft.Agents.AI.Workflows/Execution/EdgeConnection.cs
T
Jacob AlberandGitHub 32e7ff00b5 .NET: Add support for Subworkflows and many threading fixes (#1066)
* 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
2025-10-03 17:26:30 +00:00

124 lines
4.3 KiB
C#

// Copyright (c) Microsoft. All rights reserved.
using System;
using System.Collections.Generic;
using System.Linq;
using Microsoft.Shared.Diagnostics;
namespace Microsoft.Agents.AI.Workflows.Execution;
/// <summary>
/// A representation for the connection structure of an edge of any multiplicity, defined by an ordered list
/// of sources and sinks connected by this edge. Can also function as a unique identifier for the edge.
/// </summary>
/// <remarks>
/// Ordering is relevant because in at least one case, the order of sinks is significant for the execution of
/// the edge: <see cref="FanOutEdgeData"/>.
/// </remarks>
public sealed class EdgeConnection : IEquatable<EdgeConnection>
{
/// <summary>
/// Create an <see cref="EdgeConnection"/> instance with the specified source and sink IDs.
/// </summary>
/// <param name="sourceIds">An ordered list of unique identifiers of the sources connected by this edge.</param>
/// <param name="sinkIds">An ordered list of unique identifiers of the sinks connected by this edge.</param>
public EdgeConnection(List<string> sourceIds, List<string> sinkIds)
{
this.SourceIds = Throw.IfNull(sourceIds);
this.SinkIds = Throw.IfNull(sinkIds);
}
/// <summary>
/// Creates a new <see cref="EdgeConnection"/> instance with the specified source and sink IDs, ensuring that all
/// IDs are unique.
/// </summary>
/// <param name="sourceIds">A list of source IDs. Each ID must be unique within the list.</param>
/// <param name="sinkIds">A list of sink IDs. Each ID must be unique within the list.</param>
/// <returns>An <see cref="EdgeConnection"/> instance containing the specified source and sink IDs.</returns>
/// <exception cref="ArgumentNullException">Throw if <paramref name="sourceIds"/> or <paramref name="sinkIds"/>
/// is <see langword="null"/></exception>
/// <exception cref="ArgumentException">Thrown if <paramref name="sourceIds"/> or <paramref name="sinkIds"/>
/// contains duplicate values.</exception>
public static EdgeConnection CreateChecked(List<string> sourceIds, List<string> sinkIds)
{
HashSet<string> sourceSet = new(Throw.IfNull(sourceIds));
HashSet<string> sinkSet = new(Throw.IfNull(sinkIds));
if (sourceSet.Count != sourceIds.Count)
{
throw new ArgumentException("Source IDs must be unique.", nameof(sourceIds));
}
if (sinkSet.Count != sinkIds.Count)
{
throw new ArgumentException("Sink IDs must be unique.", nameof(sinkIds));
}
return new EdgeConnection(sourceIds, sinkIds);
}
/// <inheritdoc />
public bool Equals(EdgeConnection? other)
{
if (other is null)
{
return false;
}
if (ReferenceEquals(this, other))
{
return true;
}
return this.SourceIds.SequenceEqual(other.SourceIds) &&
this.SinkIds.SequenceEqual(other.SinkIds);
}
/// <inheritdoc />
public override bool Equals(object? obj)
{
return this.Equals(obj as EdgeConnection);
}
/// <inheritdoc />
public override int GetHashCode()
{
return HashCode.Combine(
this.SourceIds.Count,
this.SinkIds.Count,
this.SourceIds.Aggregate(0, (hash, id) => HashCode.Combine(hash, id.GetHashCode())),
this.SinkIds.Aggregate(0, (hash, id) => HashCode.Combine(hash, id.GetHashCode()))
);
}
/// <inheritdoc />
public static bool operator ==(EdgeConnection? left, EdgeConnection? right)
{
if (left is null)
{
return right is null;
}
return left.Equals(right);
}
/// <inheritdoc />
public static bool operator !=(EdgeConnection? left, EdgeConnection? right) => !(left == right);
/// <summary>
/// The unique identifiers of the sources connected by this edge.
/// </summary>
public List<string> SourceIds { get; }
/// <summary>
/// The unique identifiers of the sinks connected by this edge.
/// </summary>
public List<string> SinkIds { get; }
/// <inheritdoc />
public override string ToString()
{
return $"[{string.Join(",", this.SourceIds)}] => [{string.Join(",", this.SinkIds)}]";
}
}