.NET Workflows - Add "CustomerSupport" sample (#2102)

This commit is contained in:
Chris
2025-11-13 11:27:02 -08:00
committed by GitHub
Unverified
parent 5303c700ef
commit 1d6f53b3df
24 changed files with 935 additions and 39 deletions
@@ -35,7 +35,7 @@ public sealed class DeclarativeWorkflowTest(ITestOutputHelper output) : Workflow
this.RunWorkflowAsync(GetWorkflowPath(workflowFileName, isSample: true), testcaseFileName, externalConveration);
[Theory]
[InlineData("ConfirmInput.yaml", "ConfirmInput.json", true)]
[InlineData("ConfirmInput.yaml", "ConfirmInput.json", false)]
[InlineData("RequestExternalInput.yaml", "RequestExternalInput.json", false)]
public Task ValidateMultiTurnAsync(string workflowFileName, string testcaseFileName, bool isSample) =>
this.RunWorkflowAsync(GetWorkflowPath(workflowFileName, isSample), testcaseFileName, useJsonCheckpoint: true);
@@ -0,0 +1,61 @@
#
# This workflow demonstrates how to use the Question action
# to request user input and confirm it matches the original input.
#
# Note: This workflow doesn't make use of any agents.
#
kind: Workflow
trigger:
kind: OnConversationStart
id: workflow_demo
actions:
# Capture original input
- kind: SetVariable
id: set_project
variable: Local.OriginalInput
value: =System.LastMessage.Text
# Request input from user
- kind: Question
id: question_confirm
alwaysPrompt: false
autoSend: false
property: Local.ConfirmedInput
prompt:
kind: Message
text:
- "CONFIRM:"
entity:
kind: StringPrebuiltEntity
# Confirm input
- kind: ConditionGroup
id: check_completion
conditions:
# Didn't match
- condition: =Local.OriginalInput <> Local.ConfirmedInput
id: check_confirm
actions:
- kind: SendActivity
id: sendActivity_mismatch
activity: |-
"{Local.ConfirmedInput}" does not match the original input of "{Local.OriginalInput}". Please try again.
- kind: GotoAction
id: goto_again
actionId: question_confirm
# Confirmed
elseActions:
- kind: SendActivity
id: sendActivity_confirmed
activity: |-
You entered:
{Local.OriginalInput}
Confirmed input:
{Local.ConfirmedInput}
@@ -117,7 +117,7 @@ public sealed class DeclarativeWorkflowTest(ITestOutputHelper output) : Workflow
this.AssertNotExecuted("sendActivity_even");
this.AssertMessage("ODD");
}
this.AssertExecuted("end_all");
this.AssertExecuted("activity_final");
}
[Theory]
@@ -141,7 +141,30 @@ public sealed class DeclarativeWorkflowTest(ITestOutputHelper output) : Workflow
this.AssertExecuted("sendActivity_odd");
this.AssertNotExecuted("sendActivity_else");
}
this.AssertExecuted("end_all");
this.AssertExecuted("activity_final");
}
[Theory]
[InlineData(12, 4)]
[InlineData(37, 9)]
public async Task ConditionActionWithFallThroughAsync(int input, int expectedActions)
{
await this.RunWorkflowAsync("ConditionFallThrough.yaml", input);
this.AssertExecutionCount(expectedActions);
this.AssertExecuted("setVariable_test");
this.AssertExecuted("conditionGroup_test", isScope: true);
if (input % 2 == 0)
{
this.AssertNotExecuted("conditionItem_odd");
this.AssertNotExecuted("sendActivity_odd");
}
else
{
this.AssertExecuted("conditionItem_odd", isScope: true);
this.AssertExecuted("sendActivity_odd");
this.AssertMessage("ODD");
}
this.AssertExecuted("activity_final");
}
[Theory]
@@ -1,4 +1,4 @@
// ------------------------------------------------------------------------------
// ------------------------------------------------------------------------------
// <auto-generated>
// This code was generated by a tool.
// </auto-generated>
@@ -129,6 +129,27 @@ public static class WorkflowProvider
}
}
/// <summary>
/// Formats a message template and sends an activity event.
/// </summary>
internal sealed class ActivityFinalExecutor(FormulaSession session) : ActionExecutor(id: "activity_final", session)
{
// <inheritdoc />
protected override async ValueTask<object?> ExecuteAsync(IWorkflowContext context, CancellationToken cancellationToken)
{
string activityText =
await context.FormatTemplateAsync(
"""
All done!
"""
);
AgentRunResponse response = new([new ChatMessage(ChatRole.Assistant, activityText)]);
await context.AddEventAsync(new AgentRunResponseEvent(this.Id, response)).ConfigureAwait(false);
return default;
}
}
public static Workflow CreateWorkflow<TInput>(
DeclarativeWorkflowOptions options,
Func<TInput, ChatMessage>? inputTransform = null)
@@ -147,7 +168,7 @@ public static class WorkflowProvider
DelegateExecutor conditionItemEvenactions = new(id: "conditionItem_evenActions", myWorkflowRoot.Session);
SendactivityEvenExecutor sendActivityEven = new(myWorkflowRoot.Session);
DelegateExecutor conditionGroupTestPost = new(id: "conditionGroup_test_Post", myWorkflowRoot.Session);
DelegateExecutor endAll = new(id: "end_all", myWorkflowRoot.Session);
ActivityFinalExecutor activityFinal = new(myWorkflowRoot.Session);
DelegateExecutor conditionItemOddPost = new(id: "conditionItem_odd_Post", myWorkflowRoot.Session);
DelegateExecutor conditionItemEvenPost = new(id: "conditionItem_even_Post", myWorkflowRoot.Session);
DelegateExecutor conditionItemOddactionsPost = new(id: "conditionItem_oddActions_Post", myWorkflowRoot.Session);
@@ -166,7 +187,7 @@ public static class WorkflowProvider
builder.AddEdge(conditionItemOddactions, sendActivityOdd);
builder.AddEdge(conditionItemEven, conditionItemEvenactions);
builder.AddEdge(conditionItemEvenactions, sendActivityEven);
builder.AddEdge(conditionGroupTestPost, endAll);
builder.AddEdge(conditionGroupTestPost, activityFinal);
builder.AddEdge(conditionItemOddPost, conditionGroupTestPost);
builder.AddEdge(conditionItemEvenPost, conditionGroupTestPost);
builder.AddEdge(sendActivityOdd, conditionItemOddactionsPost);
@@ -177,4 +198,4 @@ public static class WorkflowProvider
// Build the workflow
return builder.Build(validateOrphans: false);
}
}
}
@@ -27,5 +27,6 @@ trigger:
id: sendActivity_even
activity: EVEN
- kind: EndConversation
id: end_all
- kind: SendActivity
id: activity_final
activity: All done!
@@ -1,4 +1,4 @@
// ------------------------------------------------------------------------------
// ------------------------------------------------------------------------------
// <auto-generated>
// This code was generated by a tool.
// </auto-generated>
@@ -123,6 +123,27 @@ public static class WorkflowProvider
}
}
/// <summary>
/// Formats a message template and sends an activity event.
/// </summary>
internal sealed class ActivityFinalExecutor(FormulaSession session) : ActionExecutor(id: "activity_final", session)
{
// <inheritdoc />
protected override async ValueTask<object?> ExecuteAsync(IWorkflowContext context, CancellationToken cancellationToken)
{
string activityText =
await context.FormatTemplateAsync(
"""
All done!
"""
);
AgentRunResponse response = new([new ChatMessage(ChatRole.Assistant, activityText)]);
await context.AddEventAsync(new AgentRunResponseEvent(this.Id, response)).ConfigureAwait(false);
return default;
}
}
public static Workflow CreateWorkflow<TInput>(
DeclarativeWorkflowOptions options,
Func<TInput, ChatMessage>? inputTransform = null)
@@ -141,7 +162,7 @@ public static class WorkflowProvider
DelegateExecutor conditionItemOddRestart = new(id: "conditionItem_odd_Restart", myWorkflowRoot.Session);
SendactivityElseExecutor sendActivityElse = new(myWorkflowRoot.Session);
DelegateExecutor conditionGroupTestPost = new(id: "conditionGroup_test_Post", myWorkflowRoot.Session);
DelegateExecutor endAll = new(id: "end_all", myWorkflowRoot.Session);
ActivityFinalExecutor activityFinal = new(myWorkflowRoot.Session);
DelegateExecutor conditionItemOddPost = new(id: "conditionItem_odd_Post", myWorkflowRoot.Session);
DelegateExecutor conditionItemOddactionsPost = new(id: "conditionItem_oddActions_Post", myWorkflowRoot.Session);
DelegateExecutor conditionGroupTestelseactionsPost = new(id: "conditionGroup_testElseActions_Post", myWorkflowRoot.Session);
@@ -159,7 +180,7 @@ public static class WorkflowProvider
builder.AddEdge(conditionItemOddactions, sendActivityOdd);
builder.AddEdge(conditionItemOddRestart, conditionGroupTestelseactions);
builder.AddEdge(conditionGroupTestelseactions, sendActivityElse);
builder.AddEdge(conditionGroupTestPost, endAll);
builder.AddEdge(conditionGroupTestPost, activityFinal);
builder.AddEdge(conditionItemOddPost, conditionGroupTestPost);
builder.AddEdge(sendActivityOdd, conditionItemOddactionsPost);
builder.AddEdge(conditionItemOddactionsPost, conditionItemOddPost);
@@ -169,4 +190,4 @@ public static class WorkflowProvider
// Build the workflow
return builder.Build(validateOrphans: false);
}
}
}
@@ -24,5 +24,6 @@ trigger:
id: sendActivity_else
activity: EVEN
- kind: EndConversation
id: end_all
- kind: SendActivity
id: activity_final
activity: All done!
@@ -0,0 +1,25 @@
kind: Workflow
trigger:
kind: OnConversationStart
id: my_workflow
actions:
- kind: SetVariable
id: setVariable_test
variable: Local.TestValue
value: =Value(System.LastMessageText)
- kind: ConditionGroup
id: conditionGroup_test
conditions:
- id: conditionItem_odd
condition: =Mod(Local.TestValue, 2) = 1
actions:
- kind: SendActivity
id: sendActivity_odd
activity: ODD
- kind: SendActivity
id: activity_final
activity: All done!