Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ internal static class ActivityNames
{
public const string WorkflowBuild = "workflow.build";
public const string WorkflowSession = "workflow.session";
public const string WorkflowInvoke = "workflow_invoke";
public const string WorkflowInvoke = "invoke_workflow";
public const string MessageSend = "message.send";
public const string ExecutorProcess = "executor.process";
public const string EdgeGroupProcess = "edge_group.process";
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ public sealed class WorkflowTelemetryOptions
/// Gets or sets a value indicating whether workflow run activities should be disabled.
/// </summary>
/// <value>
/// <see langword="true"/> to disable <c>workflow_invoke</c> activities;
/// <see langword="true"/> to disable <c>invoke_workflow</c> activities;
/// <see langword="false"/> to enable them. The default value is <see langword="false"/>.
/// </value>
public bool DisableWorkflowRun { get; set; }
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ public sealed class DeclarativeWorkflowOptionsTest : IDisposable
// These constants mirror Microsoft.Agents.AI.Workflows.Observability.ActivityNames
// which is internal and not accessible from this test project.
private const string WorkflowBuildActivityName = "workflow.build";
private const string WorkflowRunActivityName = "workflow_invoke";
private const string WorkflowRunActivityName = "invoke_workflow";

// The default activity source name used by the workflow telemetry context.
private const string DefaultTelemetrySourceName = "Microsoft.Agents.AI.Workflows";
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -158,6 +158,41 @@ public async Task CreatesWorkflowEndToEndActivities_WithCorrectName_LockstepAsyn
await this.TestWorkflowEndToEndActivitiesAsync("Lockstep");
}

[Theory]
[InlineData("Lockstep", false)]
[InlineData("Lockstep", true)]
[InlineData("OffThread", false)]
[InlineData("OffThread", true)]
[InlineData("Concurrent", false)]
[InlineData("Concurrent", true)]
public async Task WorkflowRunActivity_UsesSemanticConventionNameAsync(string executionEnvironmentName, bool streaming)
{
// Arrange
using var testActivity = new Activity("WorkflowRunSpanNameTest").Start();
var workflow = CreateWorkflow();
var executionEnvironment = GetExecutionEnvironment(executionEnvironmentName);

// Act
if (streaming)
{
await using StreamingRun run = await executionEnvironment.RunStreamingAsync(workflow, "Hello, World!");
await foreach (WorkflowEvent evt in run.WatchStreamAsync())
{
// Drain the stream to complete the workflow invocation.
}
}
else
{
await using Run run = await executionEnvironment.RunAsync(workflow, "Hello, World!");
}

// Assert
var workflowRunActivity = Assert.Single(this._capturedActivities, a =>
a.RootId == testActivity.RootId &&
a.Events.Any(e => e.Name == EventNames.WorkflowStarted));
Assert.Equal("invoke_workflow", workflowRunActivity.OperationName);
}

[Fact]
public async Task CreatesWorkflowActivities_WithCorrectNameAsync()
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,8 @@ namespace Microsoft.Agents.AI.Workflows.UnitTests;

/// <summary>
/// Regression test for https://github.com/microsoft/agent-framework/issues/4155
/// Verifies that the workflow_invoke Activity is properly stopped/disposed so it gets exported
/// to telemetry backends. The ActivityStopped callback must fire for the workflow_invoke span.
/// Verifies that the invoke_workflow Activity is properly stopped/disposed so it gets exported
/// to telemetry backends. The ActivityStopped callback must fire for the invoke_workflow span.
/// </summary>
[Collection("ObservabilityTests")]
public sealed class WorkflowRunActivityStopTests : IDisposable
Expand Down Expand Up @@ -61,7 +61,7 @@ private static Workflow CreateWorkflow()
}

/// <summary>
/// Verifies that the workflow_invoke Activity is stopped (and thus exportable) when
/// Verifies that the invoke_workflow Activity is stopped (and thus exportable) when
/// using the Lockstep execution environment.
/// Bug: The Activity created by LockstepRunEventStream.TakeEventStreamAsync is never
/// disposed because yield break in async iterators does not trigger using disposal.
Expand Down Expand Up @@ -90,7 +90,7 @@ public async Task WorkflowRunActivity_IsStopped_LockstepAsync()
.ToList();
Assert.Single(stoppedSessions ?? []);

// Assert - workflow_invoke should have been started and stopped
// Assert - invoke_workflow should have been started and stopped
var startedWorkflowRuns = this._startedActivities
.Where(a => a.RootId == testActivity.RootId &&
a.OperationName.StartsWith(ActivityNames.WorkflowInvoke, StringComparison.Ordinal))
Expand All @@ -105,7 +105,7 @@ public async Task WorkflowRunActivity_IsStopped_LockstepAsync()
}

/// <summary>
/// Verifies that the workflow_invoke Activity is stopped when using the OffThread (Default)
/// Verifies that the invoke_workflow Activity is stopped when using the OffThread (Default)
/// execution environment (StreamingRunEventStream).
/// </summary>
[Fact]
Expand All @@ -132,7 +132,7 @@ public async Task WorkflowRunActivity_IsStopped_OffThreadAsync()
.ToList();
Assert.Single(stoppedSessions ?? []);

// Assert - workflow_invoke should have been started and stopped
// Assert - invoke_workflow should have been started and stopped
var startedWorkflowRuns = this._startedActivities
.Where(a => a.RootId == testActivity.RootId &&
a.OperationName.StartsWith(ActivityNames.WorkflowInvoke, StringComparison.Ordinal))
Expand All @@ -147,7 +147,7 @@ public async Task WorkflowRunActivity_IsStopped_OffThreadAsync()
}

/// <summary>
/// Verifies that the workflow_invoke Activity is stopped when using the streaming API
/// Verifies that the invoke_workflow Activity is stopped when using the streaming API
/// (StreamingRun.WatchStreamAsync) with the OffThread execution environment.
/// This matches the exact usage pattern described in the issue.
/// </summary>
Expand Down Expand Up @@ -177,14 +177,14 @@ public async Task WorkflowRunActivity_IsStopped_Streaming_OffThreadAsync()
.ToList();
Assert.Single(startedSessions ?? []);

// Assert - workflow_invoke should have been started
// Assert - invoke_workflow should have been started
var startedWorkflowRuns = this._startedActivities
.Where(a => a.RootId == testActivity.RootId &&
a.OperationName.StartsWith(ActivityNames.WorkflowInvoke, StringComparison.Ordinal))
.ToList();
Assert.Single(startedWorkflowRuns ?? []);

// Assert - workflow_invoke should have been stopped
// Assert - invoke_workflow should have been stopped
var stoppedWorkflowRuns = this._stoppedActivities
.Where(a => a.RootId == testActivity.RootId &&
a.OperationName.StartsWith(ActivityNames.WorkflowInvoke, StringComparison.Ordinal))
Expand All @@ -193,7 +193,7 @@ public async Task WorkflowRunActivity_IsStopped_Streaming_OffThreadAsync()
}

/// <summary>
/// Verifies that a new workflow_invoke activity is started and stopped for each
/// Verifies that a new invoke_workflow activity is started and stopped for each
/// streaming invocation, even when using the same workflow in a multi-turn pattern,
/// and that each session gets its own session activity.
/// </summary>
Expand Down Expand Up @@ -236,7 +236,7 @@ public async Task WorkflowRunActivity_IsStopped_Streaming_OffThread_MultiTurnAsy
.ToList();
Assert.Equal(2, stoppedSessions.Count);

// Assert - two workflow_invoke activities should have been started and stopped
// Assert - two invoke_workflow activities should have been started and stopped
var startedWorkflowRuns = this._startedActivities
.Where(a => a.RootId == testActivity.RootId &&
a.OperationName.StartsWith(ActivityNames.WorkflowInvoke, StringComparison.Ordinal))
Expand All @@ -251,7 +251,7 @@ public async Task WorkflowRunActivity_IsStopped_Streaming_OffThread_MultiTurnAsy
}

/// <summary>
/// Verifies that all started activities (not just workflow_invoke) are properly stopped.
/// Verifies that all started activities (not just invoke_workflow) are properly stopped.
/// This ensures no spans are "leaked" without being exported.
/// </summary>
[Fact]
Expand Down
Loading