chore: import upstream snapshot with attribution
dotnet-build-and-test / dotnet-test-functions (push) Has been cancelled
dotnet-build-and-test / paths-filter (push) Has been cancelled
dotnet-build-and-test / dotnet-build (Debug, windows-latest, net9.0) (push) Has been cancelled
dotnet-build-and-test / dotnet-build (Release, ubuntu-latest, net10.0) (push) Has been cancelled
dotnet-build-and-test / dotnet-build (Release, ubuntu-latest, net8.0) (push) Has been cancelled
dotnet-build-and-test / dotnet-build (Release, windows-latest, net472) (push) Has been cancelled
dotnet-build-and-test / dotnet-test (Release, integration, true, ubuntu-latest, net10.0) (push) Has been cancelled
dotnet-build-and-test / dotnet-test (Release, integration, true, windows-latest, net472) (push) Has been cancelled
dotnet-build-and-test / dotnet-foundry-hosted-it (push) Has been cancelled
dotnet-build-and-test / dotnet-build-and-test-check (push) Has been cancelled
dotnet-build-and-test / Integration Test Report (push) Has been cancelled
CodeQL / Analyze (csharp) (push) Has been cancelled
CodeQL / Analyze (python) (push) Has been cancelled

This commit is contained in:
wehub-resource-sync
2026-07-13 13:39:25 +08:00
commit db620d33df
5151 changed files with 925932 additions and 0 deletions
@@ -0,0 +1,289 @@
// Copyright (c) Microsoft. All rights reserved.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using FluentAssertions;
using Microsoft.Extensions.AI;
namespace Microsoft.Agents.AI.Workflows.UnitTests.Futures;
/// <summary>
/// Runner-level coverage for <see cref="Workflows.Futures.EnableAgentResponseOutputTaggingAndFiltering"/>.
/// Exercises every combination of (flag on/off) × (designation kind) × (payload shape) to pin the
/// runner's behavior in both the legacy bypass path and the unified filter-and-tag path.
/// </summary>
public static partial class FuturesTests
{
[Collection(FuturesSerialCollection.Name)]
public class AgentResponseOutputFilteringAndTaggingTests
{
private const string SourceId = "yielder";
private static AgentResponse SampleResponse(string text = "hi")
=> new(new ChatMessage(ChatRole.Assistant, text));
private static AgentResponseUpdate SampleUpdate(string text = "tick")
=> new(ChatRole.Assistant, text);
private static async Task<List<WorkflowEvent>> RunAsync<T>(Workflow workflow, T input) where T : notnull
{
List<WorkflowEvent> events = [];
await using StreamingRun run = await InProcessExecution.RunStreamingAsync(workflow, input).ConfigureAwait(false);
await foreach (WorkflowEvent evt in run.WatchStreamAsync().ConfigureAwait(false))
{
events.Add(evt);
}
return events;
}
private static Workflow BuildAgentResponseWorkflow(Action<WorkflowBuilder, YieldAgentResponseExecutor>? designate = null)
{
YieldAgentResponseExecutor exec = new(SourceId);
WorkflowBuilder builder = new(exec);
designate?.Invoke(builder, exec);
return builder.Build();
}
private static Workflow BuildAgentResponseUpdateWorkflow(Action<WorkflowBuilder, YieldAgentResponseUpdateExecutor>? designate = null)
{
YieldAgentResponseUpdateExecutor exec = new(SourceId);
WorkflowBuilder builder = new(exec);
designate?.Invoke(builder, exec);
return builder.Build();
}
private static Workflow BuildPocoWorkflow(Action<WorkflowBuilder, YieldPocoExecutor>? designate = null)
{
YieldPocoExecutor exec = new(SourceId);
WorkflowBuilder builder = new(exec);
designate?.Invoke(builder, exec);
return builder.Build();
}
// F1
[Fact]
public async Task Test_Runner_LegacyAgentResponseBypass_RaisesUntaggedEventAsync()
{
using FuturesScope _ = new(enabled: false);
Workflow workflow = BuildAgentResponseWorkflow(designate: null);
List<WorkflowEvent> events = await RunAsync(workflow, "go");
AgentResponseEvent emitted = events.OfType<AgentResponseEvent>().Should().ContainSingle().Subject;
emitted.ExecutorId.Should().Be(SourceId);
emitted.Tags.Should().BeEmpty("legacy bypass attaches no tags");
emitted.IsIntermediate().Should().BeFalse();
}
// F2
[Fact]
public async Task Test_Runner_LegacyAgentResponseUpdateBypass_RaisesUntaggedEventAsync()
{
using FuturesScope _ = new(enabled: false);
Workflow workflow = BuildAgentResponseUpdateWorkflow(designate: null);
List<WorkflowEvent> events = await RunAsync(workflow, "go");
AgentResponseUpdateEvent emitted = events.OfType<AgentResponseUpdateEvent>().Should().ContainSingle().Subject;
emitted.Tags.Should().BeEmpty();
}
// F3
[Fact]
public async Task Test_Runner_LegacyBypassIgnoresDesignationAsync()
{
using FuturesScope _ = new(enabled: false);
Workflow workflow = BuildAgentResponseWorkflow(static (b, e) => b.WithIntermediateOutputFrom([e]));
List<WorkflowEvent> events = await RunAsync(workflow, "go");
AgentResponseEvent emitted = events.OfType<AgentResponseEvent>().Should().ContainSingle().Subject;
emitted.Tags.Should().BeEmpty("legacy bypass ignores the designation entirely");
emitted.IsIntermediate().Should().BeFalse("legacy bypass does not propagate tags");
}
// F4
[Fact]
public async Task Test_Runner_LegacyPocoIsFilteredAsync()
{
using FuturesScope _ = new(enabled: false);
Workflow workflow = BuildPocoWorkflow(designate: null);
List<WorkflowEvent> events = await RunAsync(workflow, "go");
events.OfType<WorkflowOutputEvent>().Should().BeEmpty("POCO outputs always go through the filter; undesignated source is dropped");
}
// F5
[Fact]
public async Task Test_Runner_UndesignatedAgentResponseIsFilteredWhenFuturesOnAsync()
{
using FuturesScope _ = new(enabled: true);
Workflow workflow = BuildAgentResponseWorkflow(designate: null);
List<WorkflowEvent> events = await RunAsync(workflow, "go");
events.OfType<WorkflowOutputEvent>().Should().BeEmpty(
"with the future on, AgentResponse must be designated to surface");
}
// F6
[Fact]
public async Task Test_Runner_DesignatedTerminalAgentResponseHasEmptyTagsAsync()
{
using FuturesScope _ = new(enabled: true);
Workflow workflow = BuildAgentResponseWorkflow(static (b, e) => b.WithOutputFrom(e));
List<WorkflowEvent> events = await RunAsync(workflow, "go");
AgentResponseEvent emitted = events.OfType<AgentResponseEvent>().Should().ContainSingle().Subject;
emitted.Tags.Should().BeEmpty("terminal designation carries no tag");
emitted.IsIntermediate().Should().BeFalse();
}
// F7
[Fact]
public async Task Test_Runner_DesignatedIntermediateAgentResponseHasIntermediateTagAsync()
{
using FuturesScope _ = new(enabled: true);
Workflow workflow = BuildAgentResponseWorkflow(static (b, e) => b.WithIntermediateOutputFrom([e]));
List<WorkflowEvent> events = await RunAsync(workflow, "go");
AgentResponseEvent emitted = events.OfType<AgentResponseEvent>().Should().ContainSingle().Subject;
emitted.Tags.Should().BeEquivalentTo(new[] { OutputTag.Intermediate });
emitted.IsIntermediate().Should().BeTrue();
}
// F8
[Fact]
public async Task Test_Runner_DesignatedIntermediateAgentResponseUpdateHasIntermediateTagAsync()
{
using FuturesScope _ = new(enabled: true);
Workflow workflow = BuildAgentResponseUpdateWorkflow(static (b, e) => b.WithIntermediateOutputFrom([e]));
List<WorkflowEvent> events = await RunAsync(workflow, "go");
AgentResponseUpdateEvent emitted = events.OfType<AgentResponseUpdateEvent>().Should().ContainSingle().Subject;
emitted.Tags.Should().BeEquivalentTo(new[] { OutputTag.Intermediate });
emitted.IsIntermediate().Should().BeTrue();
}
// F9
[Fact]
public async Task Test_Runner_TagsAccumulateOutputThenIntermediateAsync()
{
using FuturesScope _ = new(enabled: true);
Workflow workflow = BuildAgentResponseWorkflow(static (b, e) =>
{
b.WithOutputFrom(e);
b.WithIntermediateOutputFrom([e]);
});
List<WorkflowEvent> events = await RunAsync(workflow, "go");
AgentResponseEvent emitted = events.OfType<AgentResponseEvent>().Should().ContainSingle().Subject;
emitted.Tags.Should().BeEquivalentTo(new[] { OutputTag.Intermediate },
"terminal+intermediate union is {{ Intermediate }} (terminal contributes the entry but no tag)");
emitted.IsIntermediate().Should().BeTrue();
}
// F10
[Fact]
public async Task Test_Runner_TagsAccumulateIntermediateThenOutputAsync()
{
using FuturesScope _ = new(enabled: true);
Workflow workflow = BuildAgentResponseWorkflow(static (b, e) =>
{
b.WithIntermediateOutputFrom([e]);
b.WithOutputFrom(e);
});
List<WorkflowEvent> events = await RunAsync(workflow, "go");
AgentResponseEvent emitted = events.OfType<AgentResponseEvent>().Should().ContainSingle().Subject;
emitted.Tags.Should().BeEquivalentTo(new[] { OutputTag.Intermediate }, "designation order is irrelevant");
emitted.IsIntermediate().Should().BeTrue();
}
// F11
[Fact]
public async Task Test_Runner_DesignatedIntermediatePocoHasIntermediateTagAsync()
{
using FuturesScope _ = new(enabled: true);
Workflow workflow = BuildPocoWorkflow(static (b, e) => b.WithIntermediateOutputFrom([e]));
List<WorkflowEvent> events = await RunAsync(workflow, "go");
WorkflowOutputEvent emitted = events.OfType<WorkflowOutputEvent>().Should().ContainSingle().Subject;
emitted.Should().NotBeOfType<AgentResponseEvent>();
emitted.Tags.Should().BeEquivalentTo(new[] { OutputTag.Intermediate });
emitted.IsIntermediate().Should().BeTrue();
}
// F12
[Fact]
public async Task Test_Runner_DesignatedTerminalPocoHasEmptyTagsAsync()
{
using FuturesScope _ = new(enabled: true);
Workflow workflow = BuildPocoWorkflow(static (b, e) => b.WithOutputFrom(e));
List<WorkflowEvent> events = await RunAsync(workflow, "go");
WorkflowOutputEvent emitted = events.OfType<WorkflowOutputEvent>().Should().ContainSingle().Subject;
emitted.Tags.Should().BeEmpty();
emitted.IsIntermediate().Should().BeFalse();
}
// F13
[Fact]
public async Task Test_Runner_RepeatedTerminalDesignationDedupesAsync()
{
using FuturesScope _ = new(enabled: true);
Workflow workflow = BuildAgentResponseWorkflow(static (b, e) =>
{
b.WithOutputFrom(e);
b.WithOutputFrom(e);
});
List<WorkflowEvent> events = await RunAsync(workflow, "go");
AgentResponseEvent emitted = events.OfType<AgentResponseEvent>().Should().ContainSingle().Subject;
emitted.Tags.Should().BeEmpty("repeated terminal designation contributes no tag");
}
// ---- Executors -----------------------------------------------------------
internal sealed class YieldAgentResponseExecutor(string id) : Executor(id)
{
protected override ProtocolBuilder ConfigureProtocol(ProtocolBuilder protocolBuilder)
=> protocolBuilder.ConfigureRoutes(rb => rb.AddHandler<string, AgentResponse>(this.HandleAsync));
private ValueTask<AgentResponse> HandleAsync(string input, IWorkflowContext context, CancellationToken cancellationToken)
=> new(SampleResponse(input));
}
internal sealed class YieldAgentResponseUpdateExecutor(string id) : Executor(id)
{
protected override ProtocolBuilder ConfigureProtocol(ProtocolBuilder protocolBuilder)
=> protocolBuilder.ConfigureRoutes(rb => rb.AddHandler<string, AgentResponseUpdate>(this.HandleAsync));
private ValueTask<AgentResponseUpdate> HandleAsync(string input, IWorkflowContext context, CancellationToken cancellationToken)
=> new(SampleUpdate(input));
}
public sealed record Poco(string Value);
internal sealed class YieldPocoExecutor(string id) : Executor(id)
{
protected override ProtocolBuilder ConfigureProtocol(ProtocolBuilder protocolBuilder)
=> protocolBuilder.ConfigureRoutes(rb => rb.AddHandler<string, Poco>(this.HandleAsync));
private ValueTask<Poco> HandleAsync(string input, IWorkflowContext context, CancellationToken cancellationToken)
=> new(new Poco(input));
}
}
}
@@ -0,0 +1,27 @@
// Copyright (c) Microsoft. All rights reserved.
using System;
namespace Microsoft.Agents.AI.Workflows.UnitTests.Futures;
/// <summary>
/// Sets <see cref="Workflows.Futures.EnableAgentResponseOutputTaggingAndFiltering"/> for
/// the lifetime of the scope, restoring the prior value on dispose. Pair every use with
/// <c>using</c> and run inside the <c>FuturesSerial</c> xUnit collection to avoid leaking
/// state across parallel tests.
/// </summary>
internal sealed class FuturesScope : IDisposable
{
private readonly bool _previous;
public FuturesScope(bool enabled)
{
this._previous = Workflows.Futures.EnableAgentResponseOutputTaggingAndFiltering;
Workflows.Futures.EnableAgentResponseOutputTaggingAndFiltering = enabled;
}
public void Dispose()
{
Workflows.Futures.EnableAgentResponseOutputTaggingAndFiltering = this._previous;
}
}
@@ -0,0 +1,19 @@
// Copyright (c) Microsoft. All rights reserved.
using System.Diagnostics.CodeAnalysis;
namespace Microsoft.Agents.AI.Workflows.UnitTests.Futures;
/// <summary>
/// xUnit collection marker for tests that mutate the process-global
/// <see cref="Workflows.Futures"/> switches. Membership in this collection serializes
/// the tests against each other so that <see cref="FuturesScope"/> cannot leak state
/// into a concurrently running test.
/// </summary>
[CollectionDefinition(Name, DisableParallelization = true)]
[SuppressMessage("Naming", "CA1711:Identifiers should not have incorrect suffix",
Justification = "xUnit's [CollectionDefinition] pattern names the marker type after the collection's purpose; the 'Collection' suffix is idiomatic.")]
public sealed class FuturesSerialCollection
{
public const string Name = "FuturesSerial";
}