This commit is contained in:
Chris Rickman
2026-03-24 13:45:33 -07:00
parent 2c000b032d
commit bd632f2a38
108 changed files with 3 additions and 8057 deletions
@@ -33,7 +33,8 @@ public sealed class DeclarativeWorkflowTest(ITestOutputHelper output) : Workflow
public Task ValidateScenarioAsync(string workflowFileName, string testcaseFileName, bool externalConveration = false) =>
this.RunWorkflowAsync(GetWorkflowPath(workflowFileName, isSample: true), testcaseFileName, externalConveration);
[Theory(Skip = "Multi-turn tests hang in CI - needs investigation")]
[Theory]
[Trait("Category", "IntegrationDisabled")] // Multi-turn tests hang in CI - needs investigation
[InlineData("ConfirmInput.yaml", "ConfirmInput.json", false)]
[InlineData("RequestExternalInput.yaml", "RequestExternalInput.json", false)]
public Task ValidateMultiTurnAsync(string workflowFileName, string testcaseFileName, bool isSample) =>
@@ -30,6 +30,7 @@
<None Include="$(MSBuildThisFileDirectory)\..\..\..\workflow-samples\Setup\*.yaml" LinkBase="Agents">
<CopyToOutputDirectory>Never</CopyToOutputDirectory>
</None>
<Compile Remove="DeclarativeCodeGenTest.cs" />
<None Update="Testcases\*.json">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</None>
@@ -1,151 +0,0 @@
// Copyright (c) Microsoft. All rights reserved.
using System.Collections.Generic;
using System.Collections.Immutable;
using Microsoft.Agents.AI.Workflows.Declarative.CodeGen;
using Microsoft.Agents.AI.Workflows.Declarative.Kit;
using Microsoft.Agents.ObjectModel;
namespace Microsoft.Agents.AI.Workflows.Declarative.UnitTests.CodeGen;
public class AddConversationMessageTemplateTest(ITestOutputHelper output) : WorkflowActionTemplateTest(output)
{
[Fact]
public void NoRole()
{
// Act, Assert
this.ExecuteTest(
nameof(AddConversationMessage),
"TestVariable",
conversation: StringExpression.Literal("#rev_9"),
content:
[
new AddConversationMessageContent.Builder()
{
Type = AgentMessageContentType.Text,
Value = TemplateLine.Parse("Hello! How can I help you today?"),
},
]);
}
[Fact]
public void WithRole()
{
// Act, Assert
this.ExecuteTest(
nameof(AddConversationMessage),
"TestVariable",
conversation: StringExpression.Variable(PropertyPath.Create("System.ConversationId")),
role: AgentMessageRoleWrapper.Get(AgentMessageRole.Agent),
content:
[
new AddConversationMessageContent.Builder()
{
Type = AgentMessageContentType.Text,
Value = TemplateLine.Parse("Hello! How can I help you today?"),
},
]);
}
[Fact]
public void WithMetadataLiteral()
{
// Act, Assert
this.ExecuteTest(
nameof(AddConversationMessage),
"TestVariable",
conversation: StringExpression.Variable(PropertyPath.Create("System.Conversation.Id")),
role: AgentMessageRoleWrapper.Get(AgentMessageRole.Agent),
metadata: ObjectExpression<RecordDataValue>.Literal(
new RecordDataValue(
new Dictionary<string, DataValue>
{
{ "key1", StringDataValue.Create("value1") },
{ "key2", NumberDataValue.Create(42) },
}.ToImmutableDictionary())),
content:
[
new AddConversationMessageContent.Builder()
{
Type = AgentMessageContentType.Text,
Value = TemplateLine.Parse("Hello! How can I help you today?"),
},
]);
}
[Fact]
public void WithMetadataVariable()
{
// Act, Assert
this.ExecuteTest(
nameof(AddConversationMessage),
"TestVariable",
conversation: StringExpression.Literal("#rev_9"),
role: AgentMessageRoleWrapper.Get(AgentMessageRole.Agent),
metadata: ObjectExpression<RecordDataValue>.Variable(PropertyPath.TopicVariable("MyMetadata")),
content:
[
new AddConversationMessageContent.Builder()
{
Type = AgentMessageContentType.Text,
Value = TemplateLine.Parse("Hello! How can I help you today?"),
},
]);
}
private void ExecuteTest(
string displayName,
string variableName,
StringExpression conversation,
IEnumerable<AddConversationMessageContent.Builder> content,
AgentMessageRoleWrapper? role = null,
ObjectExpression<RecordDataValue>.Builder? metadata = null)
{
// Arrange
AddConversationMessage model =
this.CreateModel(
displayName,
FormatVariablePath(variableName),
conversation,
content,
role,
metadata);
// Act
AddConversationMessageTemplate template = new(model);
string workflowCode = template.TransformText();
this.Output.WriteLine(workflowCode.Trim());
// Assert
AssertGeneratedCode<ActionExecutor>(template.Id, workflowCode);
AssertAgentProvider(template.UseAgentProvider, workflowCode);
AssertGeneratedAssignment(model.Message?.Path, workflowCode);
}
private AddConversationMessage CreateModel(
string displayName,
string variablePath,
StringExpression conversation,
IEnumerable<AddConversationMessageContent.Builder> contents,
AgentMessageRoleWrapper? role,
ObjectExpression<RecordDataValue>.Builder? metadata)
{
AddConversationMessage.Builder actionBuilder =
new()
{
Id = this.CreateActionId("add_message"),
DisplayName = this.FormatDisplayName(displayName),
ConversationId = conversation,
Message = PropertyPath.Create(variablePath),
Role = role,
Metadata = metadata,
};
foreach (AddConversationMessageContent.Builder content in contents)
{
actionBuilder.Content.Add(content);
}
return actionBuilder.Build();
}
}
@@ -1,43 +0,0 @@
// Copyright (c) Microsoft. All rights reserved.
using Microsoft.Agents.AI.Workflows.Declarative.CodeGen;
using Microsoft.Agents.ObjectModel;
namespace Microsoft.Agents.AI.Workflows.Declarative.UnitTests.CodeGen;
public class BreakLoopTemplateTest(ITestOutputHelper output) : WorkflowActionTemplateTest(output)
{
[Fact]
public void BreakLoop()
{
// Act, Assert
this.ExecuteTest(nameof(BreakLoop));
}
private void ExecuteTest(string displayName)
{
// Arrange
BreakLoop model = this.CreateModel(displayName);
// Act
DefaultTemplate template = new(model, "workflow_id");
string workflowCode = template.TransformText();
this.Output.WriteLine(workflowCode.Trim());
// Assert
AssertDelegate(template.Id, "workflow_id", workflowCode);
AssertAgentProvider(template.UseAgentProvider, workflowCode);
}
private BreakLoop CreateModel(string displayName)
{
BreakLoop.Builder actionBuilder =
new()
{
Id = this.CreateActionId("break_loop"),
DisplayName = this.FormatDisplayName(displayName),
};
return actionBuilder.Build();
}
}
@@ -1,75 +0,0 @@
// Copyright (c) Microsoft. All rights reserved.
using Microsoft.Agents.AI.Workflows.Declarative.CodeGen;
using Microsoft.Agents.AI.Workflows.Declarative.Kit;
using Microsoft.Agents.ObjectModel;
namespace Microsoft.Agents.AI.Workflows.Declarative.UnitTests.CodeGen;
public class ClearAllVariablesTemplateTest(ITestOutputHelper output) : WorkflowActionTemplateTest(output)
{
[Fact]
public void LiteralEnum()
{
// Arrange
EnumExpression<VariablesToClearWrapper>.Builder expressionBuilder = new(EnumExpression<VariablesToClearWrapper>.Literal(VariablesToClear.AllGlobalVariables));
// Act, Assert
this.ExecuteTest(nameof(LiteralEnum), expressionBuilder);
}
[Fact]
public void VariableEnum()
{
// Arrange
EnumExpression<VariablesToClearWrapper>.Builder expressionBuilder = new(EnumExpression<VariablesToClearWrapper>.Variable(PropertyPath.TopicVariable("MyClearEnum")));
// Act, Assert
this.ExecuteTest(nameof(VariableEnum), expressionBuilder);
}
[Fact]
public void UnsupportedEnum()
{
// Arrange
EnumExpression<VariablesToClearWrapper>.Builder expressionBuilder = new(EnumExpression<VariablesToClearWrapper>.Literal(VariablesToClear.UserScopedVariables));
// Act, Assert
this.ExecuteTest(nameof(UnsupportedEnum), expressionBuilder);
}
private void ExecuteTest(
string displayName,
EnumExpression<VariablesToClearWrapper>.Builder variablesExpression)
{
// Arrange
ClearAllVariables model =
this.CreateModel(
displayName,
variablesExpression);
// Act
ClearAllVariablesTemplate template = new(model);
string workflowCode = template.TransformText();
this.Output.WriteLine(workflowCode.Trim());
// Assert
AssertGeneratedCode<ActionExecutor>(template.Id, workflowCode);
AssertAgentProvider(template.UseAgentProvider, workflowCode);
}
private ClearAllVariables CreateModel(
string displayName,
EnumExpression<VariablesToClearWrapper>.Builder variablesExpression)
{
ClearAllVariables.Builder actionBuilder =
new()
{
Id = this.CreateActionId("set_variable"),
DisplayName = this.FormatDisplayName(displayName),
Variables = variablesExpression,
};
return actionBuilder.Build();
}
}
@@ -1,107 +0,0 @@
// Copyright (c) Microsoft. All rights reserved.
using Microsoft.Agents.AI.Workflows.Declarative.CodeGen;
using Microsoft.Agents.AI.Workflows.Declarative.Kit;
using Microsoft.Agents.ObjectModel;
namespace Microsoft.Agents.AI.Workflows.Declarative.UnitTests.CodeGen;
public class ConditionGroupTemplateTest(ITestOutputHelper output) : WorkflowActionTemplateTest(output)
{
[Fact]
public void NoElse()
{
// Act, Assert
this.ExecuteTest(
nameof(WithElse),
hasElse: false);
}
[Fact]
public void WithElse()
{
// Act, Assert
this.ExecuteTest(
nameof(WithElse),
hasElse: true);
}
private void ExecuteTest(string displayName, bool hasElse = false)
{
// Arrange
ConditionGroup model = this.CreateModel(displayName, hasElse);
// Act
ConditionGroupTemplate template = new(model);
string workflowCode = template.TransformText();
this.Output.WriteLine(workflowCode.Trim());
// Assert
AssertGeneratedCode<ActionExecutor>(template.Id, workflowCode);
AssertAgentProvider(template.UseAgentProvider, workflowCode);
foreach (ConditionItem condition in model.Conditions)
{
Assert.Contains(@$"""{condition.Id}""", workflowCode);
}
if (model.ElseActions?.Actions.Length > 0)
{
Assert.Contains(@$"""{model.ElseActions.Id}""", workflowCode);
}
}
private ConditionGroup CreateModel(string displayName, bool hasElse = false)
{
ConditionGroup.Builder actionBuilder =
new()
{
Id = this.CreateActionId("condition_group"),
DisplayName = this.FormatDisplayName(displayName),
};
actionBuilder.Conditions.Add(
new ConditionItem.Builder
{
Id = "condition_item_a",
Condition = BoolExpression.Expression("2 > 3"),
Actions = this.CreateActions("condition_a"),
});
actionBuilder.Conditions.Add(
new ConditionItem.Builder
{
Id = "condition_item_b",
Condition = BoolExpression.Expression("2 < 3"),
Actions = this.CreateActions("condition_b"),
});
if (hasElse)
{
actionBuilder.ElseActions = this.CreateActions("condition_else");
}
return actionBuilder.Build();
}
private ActionScope.Builder CreateActions(string prefix, int count = 2)
{
ActionScope.Builder actions =
new()
{
Id = this.CreateActionId("${prefix}_actions"),
};
for (int index = 1; index <= count; ++index)
{
actions.Actions.Add(
new SendActivity.Builder
{
Id = this.CreateActionId($"{prefix}_action_{index}"),
Activity = new MessageActivityTemplate
{
//Value = TemplateLine.Parse($"This is message #{index}"),
},
});
}
return actions;
}
}
@@ -1,43 +0,0 @@
// Copyright (c) Microsoft. All rights reserved.
using Microsoft.Agents.AI.Workflows.Declarative.CodeGen;
using Microsoft.Agents.ObjectModel;
namespace Microsoft.Agents.AI.Workflows.Declarative.UnitTests.CodeGen;
public class ContinueLoopTemplateTest(ITestOutputHelper output) : WorkflowActionTemplateTest(output)
{
[Fact]
public void ContinueLoop()
{
// Act, Assert
this.ExecuteTest(nameof(ContinueLoop));
}
private void ExecuteTest(string displayName)
{
// Arrange
ContinueLoop model = this.CreateModel(displayName);
// Act
DefaultTemplate template = new(model, "workflow_id");
string workflowCode = template.TransformText();
this.Output.WriteLine(workflowCode.Trim());
// Assert
AssertDelegate(template.Id, "workflow_id", workflowCode);
AssertAgentProvider(template.UseAgentProvider, workflowCode);
}
private ContinueLoop CreateModel(string displayName)
{
ContinueLoop.Builder actionBuilder =
new()
{
Id = this.CreateActionId("continue_loop"),
DisplayName = this.FormatDisplayName(displayName),
};
return actionBuilder.Build();
}
}
@@ -1,71 +0,0 @@
// Copyright (c) Microsoft. All rights reserved.
using Microsoft.Agents.AI.Workflows.Declarative.CodeGen;
using Microsoft.Agents.AI.Workflows.Declarative.Kit;
using Microsoft.Agents.ObjectModel;
namespace Microsoft.Agents.AI.Workflows.Declarative.UnitTests.CodeGen;
public class CopyConversationMessagesTemplateTest(ITestOutputHelper output) : WorkflowActionTemplateTest(output)
{
[Fact]
public void CopyConversationMessagesLiteral()
{
// Act, Assert
this.ExecuteTest(
nameof(CopyConversationMessagesLiteral),
StringExpression.Literal("#conv_dm99"),
ValueExpression.Variable(PropertyPath.TopicVariable("MyMessages")));
}
[Fact]
public void CopyConversationMessagesVariable()
{
// Act, Assert
this.ExecuteTest(
nameof(CopyConversationMessagesVariable),
StringExpression.Variable(PropertyPath.TopicVariable("TestConversation")),
ValueExpression.Variable(PropertyPath.TopicVariable("MyMessages")));
}
private void ExecuteTest(
string displayName,
StringExpression conversation,
ValueExpression messages,
ValueExpression? metadata = null)
{
// Arrange
CopyConversationMessages model =
this.CreateModel(
displayName,
conversation,
messages);
// Act
CopyConversationMessagesTemplate template = new(model);
string workflowCode = template.TransformText();
this.Output.WriteLine(workflowCode.Trim());
// Assert
AssertGeneratedCode<ActionExecutor>(template.Id, workflowCode);
AssertAgentProvider(template.UseAgentProvider, workflowCode);
}
private CopyConversationMessages CreateModel(
string displayName,
StringExpression conversation,
ValueExpression messages,
ValueExpression? metadata = null)
{
CopyConversationMessages.Builder actionBuilder =
new()
{
Id = this.CreateActionId("copy_messages"),
DisplayName = this.FormatDisplayName(displayName),
ConversationId = conversation,
Messages = messages,
};
return actionBuilder.Build();
}
}
@@ -1,82 +0,0 @@
// Copyright (c) Microsoft. All rights reserved.
using System.Collections.Generic;
using Microsoft.Agents.AI.Workflows.Declarative.CodeGen;
using Microsoft.Agents.AI.Workflows.Declarative.Extensions;
using Microsoft.Agents.AI.Workflows.Declarative.Kit;
using Microsoft.Agents.ObjectModel;
namespace Microsoft.Agents.AI.Workflows.Declarative.UnitTests.CodeGen;
public class CreateConversationTemplateTest(ITestOutputHelper output) : WorkflowActionTemplateTest(output)
{
[Fact]
public void Basic()
{
// Act, Assert
this.ExecuteTest(
nameof(Basic),
"TestVariable");
}
[Fact]
public void WithMetadata()
{
Dictionary<string, string> metadata =
new()
{
["key1"] = "value1",
["key2"] = "value2",
};
// Act, Assert
this.ExecuteTest(
nameof(WithMetadata),
"TestVariable",
ObjectExpression<RecordDataValue>.Literal(metadata.ToRecordValue()));
}
private void ExecuteTest(
string displayName,
string variableName,
ObjectExpression<RecordDataValue>? metadata = null)
{
// Arrange
CreateConversation model =
this.CreateModel(
displayName,
FormatVariablePath(variableName),
metadata);
// Act
CreateConversationTemplate template = new(model);
string workflowCode = template.TransformText();
this.Output.WriteLine(workflowCode.Trim());
// Assert
AssertGeneratedCode<ActionExecutor>(template.Id, workflowCode);
AssertAgentProvider(template.UseAgentProvider, workflowCode);
AssertGeneratedAssignment(model.ConversationId?.Path, workflowCode);
}
private CreateConversation CreateModel(
string displayName,
string variablePath,
ObjectExpression<RecordDataValue>? metadata = null)
{
CreateConversation.Builder actionBuilder =
new()
{
Id = this.CreateActionId("create_conversation"),
DisplayName = this.FormatDisplayName(displayName),
ConversationId = PropertyPath.Create(variablePath),
};
if (metadata is not null)
{
actionBuilder.Metadata = metadata;
}
return actionBuilder.Build();
}
}
@@ -1,74 +0,0 @@
// Copyright (c) Microsoft. All rights reserved.
using System;
using System.IO;
using System.Threading.Tasks;
using Shared.Code;
namespace Microsoft.Agents.AI.Workflows.Declarative.UnitTests.CodeGen;
/// <summary>
/// Tests execution of workflow created by <see cref="DeclarativeWorkflowBuilder"/>.
/// </summary>
public sealed class DeclarativeEjectionTest(ITestOutputHelper output) : WorkflowTest(output)
{
[Theory]
[InlineData("AddConversationMessage.yaml")]
[InlineData("CancelWorkflow.yaml")]
[InlineData("ClearAllVariables.yaml")]
[InlineData("CopyConversationMessages.yaml")]
[InlineData("Condition.yaml")]
[InlineData("ConditionElse.yaml")]
[InlineData("CreateConversation.yaml")]
[InlineData("EditTable.yaml")]
[InlineData("EditTableV2.yaml")]
[InlineData("EndConversation.yaml")]
[InlineData("EndWorkflow.yaml")]
[InlineData("Goto.yaml")]
[InlineData("InvokeAgent.yaml")]
[InlineData("LoopBreak.yaml")]
[InlineData("LoopContinue.yaml")]
[InlineData("LoopEach.yaml")]
[InlineData("ParseValue.yaml")]
[InlineData("ResetVariable.yaml")]
[InlineData("RetrieveConversationMessage.yaml")]
[InlineData("RetrieveConversationMessages.yaml")]
[InlineData("SendActivity.yaml")]
[InlineData("SetVariable.yaml")]
[InlineData("SetTextVariable.yaml")]
public Task ExecuteActionAsync(string workflowFile) =>
this.EjectWorkflowAsync(workflowFile);
private async Task EjectWorkflowAsync(string workflowFile)
{
using StreamReader yamlReader = File.OpenText(Path.Combine("Workflows", workflowFile));
string workflowCode = DeclarativeWorkflowBuilder.Eject(yamlReader, DeclarativeWorkflowLanguage.CSharp, "Test.WorkflowProviders");
string baselinePath = Path.Combine("Workflows", Path.ChangeExtension(workflowFile, ".cs"));
string generatedPath = Path.Combine("Workflows", Path.ChangeExtension(workflowFile, ".g.cs"));
this.Output.WriteLine($"WRITING BASELINE TO: {Path.GetFullPath(generatedPath)}\n");
try
{
File.WriteAllText(Path.GetFullPath(generatedPath), workflowCode);
Compiler.Build(workflowCode, Compiler.RepoDependencies(typeof(DeclarativeWorkflowBuilder))); // Throws if build fails
}
finally
{
Console.WriteLine(workflowCode);
}
string expectedCode = File.ReadAllText(baselinePath);
string[] expectedLines = expectedCode.Trim().Split('\n');
string[] workflowLines = workflowCode.Trim().Split('\n');
Assert.Equal(expectedLines.Length, workflowLines.Length);
for (int index = 0; index < workflowLines.Length; ++index)
{
this.Output.WriteLine($"Comparing line #{index + 1}/{workflowLines.Length}.");
Assert.Equal(expectedLines[index].Trim(), workflowLines[index].Trim());
}
}
}
@@ -1,27 +0,0 @@
// Copyright (c) Microsoft. All rights reserved.
using Microsoft.Agents.AI.Workflows.Declarative.CodeGen;
namespace Microsoft.Agents.AI.Workflows.Declarative.UnitTests.CodeGen;
public class EdgeTemplateTest(ITestOutputHelper output) : WorkflowActionTemplateTest(output)
{
[Fact]
public void InitializeNext()
{
this.ExecuteTest("set_variable_1", "invoke_agent_2");
}
private void ExecuteTest(string sourceId, string targetId)
{
// Arrange
EdgeTemplate template = new(sourceId, targetId);
// Act
string workflowCode = template.TransformText();
this.Output.WriteLine(workflowCode.Trim());
// Assert
Assert.Equal("builder.AddEdge(setVariable1, invokeAgent2);", workflowCode.Trim());
}
}
@@ -1,43 +0,0 @@
// Copyright (c) Microsoft. All rights reserved.
using Microsoft.Agents.AI.Workflows.Declarative.CodeGen;
using Microsoft.Agents.ObjectModel;
namespace Microsoft.Agents.AI.Workflows.Declarative.UnitTests.CodeGen;
public class EndConversationTest(ITestOutputHelper output) : WorkflowActionTemplateTest(output)
{
[Fact]
public void EndConversation()
{
// Act, Assert
this.ExecuteTest(nameof(EndConversation));
}
private void ExecuteTest(string displayName)
{
// Arrange
EndConversation model = this.CreateModel(displayName);
// Act
DefaultTemplate template = new(model, "workflow_id");
string workflowCode = template.TransformText();
this.Output.WriteLine(workflowCode.Trim());
// Assert
AssertDelegate(template.Id, "workflow_id", workflowCode);
AssertAgentProvider(template.UseAgentProvider, workflowCode);
}
private EndConversation CreateModel(string displayName)
{
EndConversation.Builder actionBuilder =
new()
{
Id = this.CreateActionId("end_conversation"),
DisplayName = this.FormatDisplayName(displayName),
};
return actionBuilder.Build();
}
}
@@ -1,43 +0,0 @@
// Copyright (c) Microsoft. All rights reserved.
using Microsoft.Agents.AI.Workflows.Declarative.CodeGen;
using Microsoft.Agents.ObjectModel;
namespace Microsoft.Agents.AI.Workflows.Declarative.UnitTests.CodeGen;
public class EndDialogTest(ITestOutputHelper output) : WorkflowActionTemplateTest(output)
{
[Fact]
public void EndDialog()
{
// Act, Assert
this.ExecuteTest(nameof(EndDialog));
}
private void ExecuteTest(string displayName)
{
// Arrange
EndDialog model = this.CreateModel(displayName);
// Act
DefaultTemplate template = new(model, "workflow_id");
string workflowCode = template.TransformText();
this.Output.WriteLine(workflowCode.Trim());
// Assert
AssertDelegate(template.Id, "workflow_id", workflowCode);
AssertAgentProvider(template.UseAgentProvider, workflowCode);
}
private EndDialog CreateModel(string displayName)
{
EndDialog.Builder actionBuilder =
new()
{
Id = this.CreateActionId("end_Dialog"),
DisplayName = this.FormatDisplayName(displayName),
};
return actionBuilder.Build();
}
}
@@ -1,81 +0,0 @@
// Copyright (c) Microsoft. All rights reserved.
using Microsoft.Agents.AI.Workflows.Declarative.CodeGen;
using Microsoft.Agents.AI.Workflows.Declarative.Kit;
using Microsoft.Agents.AI.Workflows.Declarative.ObjectModel;
using Microsoft.Agents.ObjectModel;
namespace Microsoft.Agents.AI.Workflows.Declarative.UnitTests.CodeGen;
public class ForeachTemplateTest(ITestOutputHelper output) : WorkflowActionTemplateTest(output)
{
[Fact]
public void LoopNoIndex()
{
// Act, Assert
this.ExecuteTest(
nameof(LoopNoIndex),
ValueExpression.Variable(PropertyPath.TopicVariable("MyItems")),
"LoopValue");
}
[Fact]
public void LoopWithIndex()
{
// Act, Assert
this.ExecuteTest(
nameof(LoopNoIndex),
ValueExpression.Variable(PropertyPath.TopicVariable("MyItems")),
"LoopValue",
"IndexValue");
}
private void ExecuteTest(
string displayName,
ValueExpression items,
string valueName,
string? indexName = null)
{
// Arrange
Foreach model =
this.CreateModel(
displayName,
items,
FormatVariablePath(valueName),
FormatOptionalPath(indexName));
// Act
ForeachTemplate template = new(model);
string workflowCode = template.TransformText();
this.Output.WriteLine(workflowCode.Trim());
// Assert
AssertGeneratedCode<ActionExecutor>(template.Id, workflowCode);
AssertAgentProvider(template.UseAgentProvider, workflowCode);
AssertGeneratedMethod(nameof(ForeachExecutor.TakeNextAsync), workflowCode);
AssertGeneratedMethod(nameof(ForeachExecutor.CompleteAsync), workflowCode);
}
private Foreach CreateModel(
string displayName,
ValueExpression items,
string valueName,
string? indexName = null)
{
Foreach.Builder actionBuilder =
new()
{
Id = this.CreateActionId("loop_action"),
DisplayName = this.FormatDisplayName(displayName),
Items = items,
Value = PropertyPath.Create(valueName),
};
if (indexName is not null)
{
actionBuilder.Index = PropertyPath.Create(indexName);
}
return actionBuilder.Build();
}
}
@@ -1,44 +0,0 @@
// Copyright (c) Microsoft. All rights reserved.
using Microsoft.Agents.AI.Workflows.Declarative.CodeGen;
using Microsoft.Agents.ObjectModel;
namespace Microsoft.Agents.AI.Workflows.Declarative.UnitTests.CodeGen;
public class GotoTemplateTest(ITestOutputHelper output) : WorkflowActionTemplateTest(output)
{
[Fact]
public void GotoAction()
{
// Act, Assert
this.ExecuteTest(nameof(GotoAction), "target_action_id");
}
private void ExecuteTest(string displayName, string targetId)
{
// Arrange
GotoAction model = this.CreateModel(displayName, targetId);
// Act
DefaultTemplate template = new(model, "workflow_id");
string workflowCode = template.TransformText();
this.Output.WriteLine(workflowCode.Trim());
// Assert
AssertDelegate(template.Id, "workflow_id", workflowCode);
AssertAgentProvider(template.UseAgentProvider, workflowCode);
}
private GotoAction CreateModel(string displayName, string targetId)
{
GotoAction.Builder actionBuilder =
new()
{
Id = this.CreateActionId("goto_action"),
DisplayName = this.FormatDisplayName(displayName),
ActionId = new ActionId(targetId),
};
return actionBuilder.Build();
}
}
@@ -1,139 +0,0 @@
// Copyright (c) Microsoft. All rights reserved.
using Microsoft.Agents.AI.Workflows.Declarative.CodeGen;
using Microsoft.Agents.AI.Workflows.Declarative.Kit;
using Microsoft.Agents.ObjectModel;
namespace Microsoft.Agents.AI.Workflows.Declarative.UnitTests.CodeGen;
public class InvokeAzureAgentTemplateTest(ITestOutputHelper output) : WorkflowActionTemplateTest(output)
{
[Fact]
public void LiteralConversation()
{
// Act, Assert
this.ExecuteTest(
nameof(LiteralConversation),
StringExpression.Literal("asst_123abc"),
StringExpression.Literal("conv_123abc"),
messagesVariable: null);
}
[Fact]
public void VariableConversation()
{
// Act, Assert
this.ExecuteTest(
nameof(VariableConversation),
StringExpression.Variable(PropertyPath.GlobalVariable("TestAgent")),
StringExpression.Variable(PropertyPath.TopicVariable("TestConversation")),
"MyMessages",
BoolExpression.Literal(true));
}
[Fact]
public void ExpressionAutosend()
{
// Act, Assert
this.ExecuteTest(
nameof(VariableConversation),
StringExpression.Literal("asst_123abc"),
StringExpression.Variable(PropertyPath.TopicVariable("TestConversation")),
"MyMessages",
BoolExpression.Expression("1 < 2"));
}
[Fact]
public void InputMessagesVariable()
{
// Act, Assert
this.ExecuteTest(
nameof(VariableConversation),
StringExpression.Literal("asst_123abc"),
StringExpression.Variable(PropertyPath.TopicVariable("TestConversation")),
"MyMessages",
messages: ValueExpression.Variable(PropertyPath.TopicVariable("TestConversation")));
}
[Fact]
public void InputMessagesExpression()
{
// Act, Assert
this.ExecuteTest(
nameof(VariableConversation),
StringExpression.Literal("asst_123abc"),
StringExpression.Literal("conv_123abc"),
"MyMessages",
messages: ValueExpression.Expression("[UserMessage(System.LastMessageText)]"));
}
private void ExecuteTest(
string displayName,
StringExpression.Builder agentName,
StringExpression.Builder conversation,
string? messagesVariable = null,
BoolExpression.Builder? autoSend = null,
ValueExpression.Builder? messages = null)
{
// Arrange
InvokeAzureAgent model =
this.CreateModel(
displayName,
agentName,
conversation,
messagesVariable,
autoSend,
messages);
// Act
InvokeAzureAgentTemplate template = new(model);
string workflowCode = template.TransformText();
this.Output.WriteLine(workflowCode.Trim());
// Assert
AssertGeneratedCode<AgentExecutor>(template.Id, workflowCode);
AssertAgentProvider(template.UseAgentProvider, workflowCode);
AssertOptionalAssignment(model.Output?.Messages?.Path, workflowCode);
}
private InvokeAzureAgent CreateModel(
string displayName,
StringExpression.Builder agentName,
StringExpression.Builder conversation,
string? messagesVariable = null,
BoolExpression.Builder? autoSend = null,
ValueExpression.Builder? messages = null)
{
InitializablePropertyPath? outputMessages = null;
if (messagesVariable is not null)
{
outputMessages = PropertyPath.Create(FormatVariablePath(messagesVariable));
}
InvokeAzureAgent.Builder actionBuilder =
new()
{
Id = this.CreateActionId("invoke_agent"),
DisplayName = this.FormatDisplayName(displayName),
ConversationId = conversation,
Agent =
new AzureAgentUsage.Builder
{
Name = agentName,
},
Input =
new AzureAgentInput.Builder
{
Messages = messages,
},
Output =
new AzureAgentOutput.Builder
{
AutoSend = autoSend,
Messages = outputMessages,
},
};
return actionBuilder.Build();
}
}
@@ -1,113 +0,0 @@
// Copyright (c) Microsoft. All rights reserved.
using System.Threading.Tasks;
using Microsoft.Agents.AI.Workflows.Declarative.CodeGen;
namespace Microsoft.Agents.AI.Workflows.Declarative.UnitTests.CodeGen;
public class ProviderTemplateTest(ITestOutputHelper output) : WorkflowActionTemplateTest(output)
{
[Fact]
public async Task WithNamespaceAsync()
{
await this.ExecuteTestAsync(
[
"""
internal sealed class TestExecutor1() : ActionExecutor(id: "test_1")
{
protected override ValueTask ExecuteAsync(IWorkflowContext context, CancellationToken cancellationToken)
{
// Nothing to do
return default;
}
}
"""
],
[
"""
TestExecutor1 test1 = new();
"""
],
[
"""
builder.AddEdge(builder.Root, test1);
"""
],
"Test.Workflows.Generated");
}
[Fact]
public async Task WithoutNamespaceAsync()
{
await this.ExecuteTestAsync(
[
"""
internal sealed class TestExecutor1() : ActionExecutor(id: "test_1")
{
protected override ValueTask ExecuteAsync(IWorkflowContext context, CancellationToken cancellationToken)
{
// Nothing to do
return default;
}
}
internal sealed class TestExecutor2() : ActionExecutor(id: "test_2")
{
protected override ValueTask ExecuteAsync(IWorkflowContext context, CancellationToken cancellationToken)
{
// Nothing to do
return default;
}
}
"""
],
[
"""
TestExecutor1 test1 = new();
TestExecutor2 test2 = new();
"""
],
[
"""
builder.AddEdge(builder.Root, test1);
builder.AddEdge(test1, test2);
"""
]);
}
private async Task ExecuteTestAsync(
string[] executors,
string[] instances,
string[] edges,
string? workflowNamespace = null)
{
// Arrange
ProviderTemplate template = new("worflow-id", executors, instances, edges) { Namespace = workflowNamespace };
// Act
string workflowCode = template.TransformText();
// Assert
this.Output.WriteLine(workflowCode);
Assert.True(Contains(executors));
Assert.True(Contains(instances));
Assert.True(Contains(edges));
bool Contains(string[] code)
{
foreach (string block in code)
{
foreach (string line in block.Split('\n'))
{
if (!workflowCode.Contains(line.Trim()))
{
return false;
}
}
}
return true;
}
}
}
@@ -1,48 +0,0 @@
// Copyright (c) Microsoft. All rights reserved.
using Microsoft.Agents.AI.Workflows.Declarative.CodeGen;
using Microsoft.Agents.AI.Workflows.Declarative.Kit;
using Microsoft.Agents.ObjectModel;
namespace Microsoft.Agents.AI.Workflows.Declarative.UnitTests.CodeGen;
public class ResetVariableTemplateTest(ITestOutputHelper output) : WorkflowActionTemplateTest(output)
{
[Fact]
public void ResetVariable()
{
// Act, Assert
this.ExecuteTest(nameof(ResetVariable), "TestVariable");
}
private void ExecuteTest(string displayName, string variableName)
{
// Arrange
ResetVariable model =
this.CreateModel(
displayName,
FormatVariablePath(variableName));
// Act
ResetVariableTemplate template = new(model);
string workflowCode = template.TransformText();
this.Output.WriteLine(workflowCode.Trim());
// Assert
AssertGeneratedCode<ActionExecutor>(template.Id, workflowCode);
AssertAgentProvider(template.UseAgentProvider, workflowCode);
}
private ResetVariable CreateModel(string displayName, string variablePath)
{
ResetVariable.Builder actionBuilder =
new()
{
Id = this.CreateActionId("set_variable"),
DisplayName = this.FormatDisplayName(displayName),
Variable = PropertyPath.Create(variablePath)
};
return actionBuilder.Build();
}
}
@@ -1,75 +0,0 @@
// Copyright (c) Microsoft. All rights reserved.
using Microsoft.Agents.AI.Workflows.Declarative.CodeGen;
using Microsoft.Agents.AI.Workflows.Declarative.Kit;
using Microsoft.Agents.ObjectModel;
namespace Microsoft.Agents.AI.Workflows.Declarative.UnitTests.CodeGen;
public class RetrieveConversationMessageTemplateTest(ITestOutputHelper output) : WorkflowActionTemplateTest(output)
{
[Fact]
public void RetrieveConversationVariable()
{
// Act, Assert
this.ExecuteTest(
nameof(RetrieveConversationVariable),
"TestVariable",
StringExpression.Variable(PropertyPath.TopicVariable("TestConversation")),
StringExpression.Literal("#mid_43"));
}
[Fact]
public void RetrieveMessageVariable()
{
// Act, Assert
this.ExecuteTest(
nameof(RetrieveMessageVariable),
"TestVariable",
StringExpression.Literal("#cid_3"),
StringExpression.Variable(PropertyPath.TopicVariable("TestMessage")));
}
private void ExecuteTest(
string displayName,
string variableName,
StringExpression conversationExpression,
StringExpression messageExpression)
{
// Arrange
RetrieveConversationMessage model =
this.CreateModel(
displayName,
FormatVariablePath(variableName),
conversationExpression,
messageExpression);
// Act
RetrieveConversationMessageTemplate template = new(model);
string workflowCode = template.TransformText();
this.Output.WriteLine(workflowCode.Trim());
// Assert
AssertGeneratedCode<ActionExecutor>(template.Id, workflowCode);
AssertAgentProvider(template.UseAgentProvider, workflowCode);
AssertGeneratedAssignment(model.Message?.Path, workflowCode);
}
private RetrieveConversationMessage CreateModel(
string displayName,
string variableName,
StringExpression conversationExpression,
StringExpression messageExpression)
{
RetrieveConversationMessage.Builder actionBuilder =
new()
{
Id = this.CreateActionId("retrieve_message"),
DisplayName = this.FormatDisplayName(displayName),
Message = PropertyPath.Create(variableName),
ConversationId = conversationExpression,
MessageId = messageExpression,
};
return actionBuilder.Build();
}
}
@@ -1,136 +0,0 @@
// Copyright (c) Microsoft. All rights reserved.
using Microsoft.Agents.AI.Workflows.Declarative.CodeGen;
using Microsoft.Agents.AI.Workflows.Declarative.Kit;
using Microsoft.Agents.ObjectModel;
namespace Microsoft.Agents.AI.Workflows.Declarative.UnitTests.CodeGen;
public class RetrieveConversationMessagesTemplateTest(ITestOutputHelper output) : WorkflowActionTemplateTest(output)
{
[Fact]
public void DefaultQuery()
{
// Act, Assert
this.ExecuteTest(
nameof(DefaultQuery),
"TestVariable",
StringExpression.Variable(PropertyPath.TopicVariable("TestConversation")));
}
[Fact]
public void LimitCountQuery()
{
// Act, Assert
this.ExecuteTest(
nameof(DefaultQuery),
"TestVariable",
StringExpression.Literal("#cid_3"),
limit: IntExpression.Literal(94));
}
[Fact]
public void AfterMessageQuery()
{
// Act, Assert
this.ExecuteTest(
nameof(DefaultQuery),
"TestVariable",
StringExpression.Literal("#cid_3"),
after: StringExpression.Literal("#mid_43"));
}
[Fact]
public void BeforeMessageQuery()
{
// Act, Assert
this.ExecuteTest(
nameof(DefaultQuery),
"TestVariable",
StringExpression.Literal("#cid_3"),
before: StringExpression.Literal("#mid_43"));
}
[Fact]
public void NewestFirstQuery()
{
// Act, Assert
this.ExecuteTest(
nameof(DefaultQuery),
"TestVariable",
StringExpression.Literal("#cid_3"),
sortOrder: EnumExpression<AgentMessageSortOrderWrapper>.Literal(AgentMessageSortOrderWrapper.Get(AgentMessageSortOrder.NewestFirst)));
}
private void ExecuteTest(
string displayName,
string variableName,
StringExpression conversation,
IntExpression? limit = null,
StringExpression? after = null,
StringExpression? before = null,
EnumExpression<AgentMessageSortOrderWrapper>? sortOrder = null)
{
// Arrange
RetrieveConversationMessages model =
this.CreateModel(
displayName,
FormatVariablePath(variableName),
conversation,
limit,
after,
before,
sortOrder);
// Act
RetrieveConversationMessagesTemplate template = new(model);
string workflowCode = template.TransformText();
this.Output.WriteLine(workflowCode.Trim());
// Assert
AssertGeneratedCode<ActionExecutor>(template.Id, workflowCode);
AssertAgentProvider(template.UseAgentProvider, workflowCode);
AssertGeneratedAssignment(model.Messages?.Path, workflowCode);
}
private RetrieveConversationMessages CreateModel(
string displayName,
string variableName,
StringExpression conversationExpression,
IntExpression? limitExpression,
StringExpression? afterExpression,
StringExpression? beforeExpression,
EnumExpression<AgentMessageSortOrderWrapper>? sortExpression)
{
RetrieveConversationMessages.Builder actionBuilder =
new()
{
Id = this.CreateActionId("retrieve_messages"),
DisplayName = this.FormatDisplayName(displayName),
Messages = PropertyPath.Create(variableName),
ConversationId = conversationExpression,
};
if (limitExpression is not null)
{
actionBuilder.Limit = limitExpression;
}
if (afterExpression is not null)
{
actionBuilder.MessageAfter = afterExpression;
}
if (beforeExpression is not null)
{
actionBuilder.MessageBefore = beforeExpression;
}
if (sortExpression is not null)
{
actionBuilder.SortOrder = sortExpression;
}
return actionBuilder.Build();
}
}
@@ -1,68 +0,0 @@
// Copyright (c) Microsoft. All rights reserved.
using Microsoft.Agents.AI.Workflows.Declarative.CodeGen;
using Microsoft.Agents.AI.Workflows.Declarative.Kit;
using Microsoft.Agents.ObjectModel;
using Microsoft.PowerFx.Types;
namespace Microsoft.Agents.AI.Workflows.Declarative.UnitTests.CodeGen;
public class SetMultipleVariablesTemplateTest(ITestOutputHelper output) : WorkflowActionTemplateTest(output)
{
[Fact]
public void InitializeMultipleValues()
{
// Act, Assert
this.ExecuteTest(
nameof(InitializeMultipleValues),
new AssignmentCase("TestVariable1", new ValueExpression.Builder(ValueExpression.Literal(new NumberDataValue(420))), FormulaValue.New(420)),
new AssignmentCase("TestVariable2", new ValueExpression.Builder(ValueExpression.Variable(PropertyPath.TopicVariable("MyValue"))), FormulaValue.New(6)),
new AssignmentCase("TestVariable3", new ValueExpression.Builder(ValueExpression.Expression("9 - 3")), FormulaValue.New(6)));
}
private void ExecuteTest(string displayName, params AssignmentCase[] assignments)
{
// Arrange
SetMultipleVariables model =
this.CreateModel(
displayName,
assignments);
// Act
SetMultipleVariablesTemplate template = new(model);
string workflowCode = template.TransformText();
this.Output.WriteLine(workflowCode.Trim());
// Assert
AssertGeneratedCode<ActionExecutor>(template.Id, workflowCode);
AssertAgentProvider(template.UseAgentProvider, workflowCode);
foreach (AssignmentCase assignment in assignments)
{
AssertGeneratedAssignment(PropertyPath.TopicVariable(assignment.Path), workflowCode);
}
}
private SetMultipleVariables CreateModel(string displayName, params AssignmentCase[] assignments)
{
SetMultipleVariables.Builder actionBuilder =
new()
{
Id = this.CreateActionId("set_multiple"),
DisplayName = this.FormatDisplayName(displayName),
};
foreach (AssignmentCase assignment in assignments)
{
actionBuilder.Assignments.Add(
new VariableAssignment.Builder()
{
Variable = PropertyPath.Create(FormatVariablePath(assignment.Path)),
Value = assignment.Expression,
});
}
return actionBuilder.Build();
}
private sealed record AssignmentCase(string Path, ValueExpression.Builder Expression, FormulaValue Expected);
}
@@ -1,55 +0,0 @@
// Copyright (c) Microsoft. All rights reserved.
using Microsoft.Agents.AI.Workflows.Declarative.CodeGen;
using Microsoft.Agents.AI.Workflows.Declarative.Kit;
using Microsoft.Agents.ObjectModel;
namespace Microsoft.Agents.AI.Workflows.Declarative.UnitTests.CodeGen;
public class SetTextVariableTemplateTest(ITestOutputHelper output) : WorkflowActionTemplateTest(output)
{
[Fact]
public void InitializeTemplate()
{
// Act, Assert
this.ExecuteTest(nameof(InitializeTemplate), "TestVariable", "Value: {OtherVar}");
}
private void ExecuteTest(
string displayName,
string variableName,
string textValue)
{
// Arrange
SetTextVariable model =
this.CreateModel(
displayName,
FormatVariablePath(variableName),
textValue);
// Act
SetTextVariableTemplate template = new(model);
string workflowCode = template.TransformText();
this.Output.WriteLine(workflowCode.Trim());
// Assert
AssertGeneratedCode<ActionExecutor>(template.Id, workflowCode);
AssertAgentProvider(template.UseAgentProvider, workflowCode);
AssertGeneratedAssignment(model.Variable?.Path, workflowCode);
Assert.Contains(textValue, workflowCode);
}
private SetTextVariable CreateModel(string displayName, string variablePath, string textValue)
{
SetTextVariable.Builder actionBuilder =
new()
{
Id = this.CreateActionId("set_variable"),
DisplayName = this.FormatDisplayName(displayName),
Variable = PropertyPath.Create(variablePath),
Value = TemplateLine.Parse(textValue),
};
return actionBuilder.Build();
}
}
@@ -1,78 +0,0 @@
// Copyright (c) Microsoft. All rights reserved.
using Microsoft.Agents.AI.Workflows.Declarative.CodeGen;
using Microsoft.Agents.AI.Workflows.Declarative.Kit;
using Microsoft.Agents.ObjectModel;
using Microsoft.PowerFx.Types;
namespace Microsoft.Agents.AI.Workflows.Declarative.UnitTests.CodeGen;
public class SetVariableTemplateTest(ITestOutputHelper output) : WorkflowActionTemplateTest(output)
{
[Fact]
public void InitializeLiteralValue()
{
// Arrange
ValueExpression.Builder expressionBuilder = new(ValueExpression.Literal(new NumberDataValue(420)));
// Act, Assert
this.ExecuteTest(nameof(InitializeLiteralValue), "TestVariable", expressionBuilder, FormulaValue.New(420));
}
[Fact]
public void InitializeVariable()
{
// Arrange
ValueExpression.Builder expressionBuilder = new(ValueExpression.Variable(PropertyPath.TopicVariable("MyValue")));
// Act, Assert
this.ExecuteTest(nameof(InitializeVariable), "TestVariable", expressionBuilder, FormulaValue.New(6));
}
[Fact]
public void InitializeExpression()
{
ValueExpression.Builder expressionBuilder = new(ValueExpression.Expression("9 - 3"));
// Act, Assert
this.ExecuteTest(nameof(InitializeExpression), "TestVariable", expressionBuilder, FormulaValue.New(6));
}
private void ExecuteTest(
string displayName,
string variableName,
ValueExpression.Builder valueExpression,
FormulaValue expectedValue)
{
// Arrange
SetVariable model =
this.CreateModel(
displayName,
FormatVariablePath(variableName),
valueExpression);
// Act
SetVariableTemplate template = new(model);
string workflowCode = template.TransformText();
this.Output.WriteLine(workflowCode.Trim());
// Assert
AssertGeneratedCode<ActionExecutor>(template.Id, workflowCode);
AssertAgentProvider(template.UseAgentProvider, workflowCode);
AssertGeneratedAssignment(model.Variable?.Path, workflowCode);
}
private SetVariable CreateModel(string displayName, string variablePath, ValueExpression.Builder valueExpression)
{
SetVariable.Builder actionBuilder =
new()
{
Id = this.CreateActionId("set_variable"),
DisplayName = this.FormatDisplayName(displayName),
Variable = PropertyPath.Create(variablePath),
Value = valueExpression,
};
return actionBuilder.Build();
}
}
@@ -1,66 +0,0 @@
// Copyright (c) Microsoft. All rights reserved.
using Microsoft.Agents.AI.Workflows.Declarative.Extensions;
using Microsoft.Agents.AI.Workflows.Declarative.Kit;
using Microsoft.Agents.ObjectModel;
namespace Microsoft.Agents.AI.Workflows.Declarative.UnitTests.CodeGen;
/// <summary>
/// Base test class for text template.
/// </summary>
public abstract class WorkflowActionTemplateTest(ITestOutputHelper output) : WorkflowTest(output)
{
private int ActionIndex { get; set; } = 1;
#pragma warning disable CA1308 // Normalize strings to uppercase
protected ActionId CreateActionId(string seed) => new($"{seed.ToLowerInvariant()}_{this.ActionIndex++}");
#pragma warning restore CA1308 // Normalize strings to uppercase
protected string FormatDisplayName(string name) => $"{this.GetType().Name}_{name}";
protected static void AssertGeneratedCode<TBase>(string actionId, string workflowCode) where TBase : class
{
Assert.Contains($"internal sealed class {actionId.FormatType()}", workflowCode);
Assert.Contains($") : {typeof(TBase).Name}(", workflowCode);
Assert.Contains(@$"""{actionId}""", workflowCode);
}
protected static void AssertGeneratedMethod(string methodName, string workflowCode) =>
Assert.Contains($"ValueTask {methodName}(", workflowCode);
protected static void AssertAgentProvider(bool expected, string workflowCode)
{
if (expected)
{
Assert.Contains($", {nameof(ResponseAgentProvider)} agentProvider", workflowCode);
}
else
{
Assert.DoesNotContain($", {nameof(ResponseAgentProvider)} agentProvider", workflowCode);
}
}
protected static void AssertOptionalAssignment(PropertyPath? variablePath, string workflowCode)
{
if (variablePath is not null)
{
Assert.Contains(@$"key: ""{variablePath.VariableName}""", workflowCode);
Assert.Contains(@$"scopeName: ""{variablePath.NamespaceAlias}""", workflowCode);
}
}
protected static void AssertGeneratedAssignment(PropertyPath? variablePath, string workflowCode)
{
Assert.NotNull(variablePath);
Assert.Contains(@$"key: ""{variablePath.VariableName}""", workflowCode);
Assert.Contains(@$"scopeName: ""{variablePath.NamespaceAlias}""", workflowCode);
}
protected static void AssertDelegate(string actionId, string rootId, string workflowCode)
{
Assert.Contains($"{nameof(DelegateExecutor)} {actionId.FormatName()} = new(", workflowCode);
Assert.Contains(@$"""{actionId}""", workflowCode);
Assert.Contains($"{rootId.FormatName()}.Session", workflowCode);
}
}