mirror of
https://github.com/microsoft/agent-framework.git
synced 2026-06-16 21:04:09 +08:00
.NET Workflows - Add unit tests for QuestionExecutor (#3892)
* Initial plan * Add comprehensive unit tests for QuestionExecutor Co-authored-by: crickman <66376200+crickman@users.noreply.github.com> * Address code review feedback and add additional test for default value logic Co-authored-by: crickman <66376200+crickman@users.noreply.github.com> * Checkpoint * Polished --------- Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com> Co-authored-by: crickman <66376200+crickman@users.noreply.github.com> Co-authored-by: Chris Rickman <crickman@microsoft.com>
This commit is contained in:
committed by
GitHub
Unverified
parent
6fa912decf
commit
79b4680cec
+14
-11
@@ -44,18 +44,17 @@ internal sealed class QuestionExecutor(Question model, ResponseAgentProvider age
|
||||
await this._promptCount.WriteAsync(context, 0).ConfigureAwait(false);
|
||||
|
||||
InitializablePropertyPath variable = Throw.IfNull(this.Model.Variable);
|
||||
bool hasValue = context.ReadState(variable.Path) is BlankValue;
|
||||
bool alwaysPrompt = this.Evaluator.GetValue(this.Model.AlwaysPrompt).Value;
|
||||
bool isValueUndefined = context.ReadState(variable.Path) is BlankValue;
|
||||
bool proceed = this.Evaluator.GetValue(this.Model.AlwaysPrompt).Value;
|
||||
|
||||
bool proceed = !alwaysPrompt || hasValue;
|
||||
if (proceed)
|
||||
if (!proceed)
|
||||
{
|
||||
SkipQuestionMode mode = this.Evaluator.GetValue(this.Model.SkipQuestionMode).Value;
|
||||
proceed =
|
||||
mode switch
|
||||
{
|
||||
SkipQuestionMode.SkipOnFirstExecutionIfVariableHasValue => !await this._hasExecuted.ReadAsync(context).ConfigureAwait(false),
|
||||
SkipQuestionMode.AlwaysSkipIfVariableHasValue => hasValue,
|
||||
SkipQuestionMode.SkipOnFirstExecutionIfVariableHasValue => isValueUndefined && !await this._hasExecuted.ReadAsync(context).ConfigureAwait(false),
|
||||
SkipQuestionMode.AlwaysSkipIfVariableHasValue => isValueUndefined,
|
||||
SkipQuestionMode.AlwaysAsk => true,
|
||||
_ => true,
|
||||
};
|
||||
@@ -86,7 +85,7 @@ internal sealed class QuestionExecutor(Question model, ResponseAgentProvider age
|
||||
FormulaValue? extractedValue = null;
|
||||
if (!response.HasMessages)
|
||||
{
|
||||
string unrecognizedResponse = this.FormatPrompt(this.Model.UnrecognizedPrompt);
|
||||
string unrecognizedResponse = this.Model.UnrecognizedPrompt is not null ? this.FormatPrompt(this.Model.UnrecognizedPrompt) : "Invalid response";
|
||||
await context.AddEventAsync(new MessageActivityEvent(unrecognizedResponse.Trim()), cancellationToken).ConfigureAwait(false);
|
||||
}
|
||||
else
|
||||
@@ -128,7 +127,7 @@ internal sealed class QuestionExecutor(Question model, ResponseAgentProvider age
|
||||
}
|
||||
}
|
||||
|
||||
await this.AssignAsync(this.Model.Variable?.Path, extractedValue, context).ConfigureAwait(false);
|
||||
await this.AssignAsync(Throw.IfNull(this.Model.Variable).Path, extractedValue, context).ConfigureAwait(false);
|
||||
await this._hasExecuted.WriteAsync(context, true).ConfigureAwait(false);
|
||||
await context.SendResultMessageAsync(this.Id, cancellationToken).ConfigureAwait(false);
|
||||
}
|
||||
@@ -145,9 +144,13 @@ internal sealed class QuestionExecutor(Question model, ResponseAgentProvider age
|
||||
int actualCount = await this._promptCount.ReadAsync(context).ConfigureAwait(false);
|
||||
if (actualCount >= repeatCount)
|
||||
{
|
||||
ValueExpression defaultValueExpression = Throw.IfNull(this.Model.DefaultValue);
|
||||
DataValue defaultValue = this.Evaluator.GetValue(defaultValueExpression).Value;
|
||||
await this.AssignAsync(this.Model.Variable?.Path, defaultValue.ToFormula(), context).ConfigureAwait(false);
|
||||
DataValue defaultValue = DataValue.Blank();
|
||||
if (this.Model.DefaultValue is not null)
|
||||
{
|
||||
ValueExpression defaultValueExpression = Throw.IfNull(this.Model.DefaultValue);
|
||||
defaultValue = this.Evaluator.GetValue(defaultValueExpression).Value;
|
||||
}
|
||||
await this.AssignAsync(Throw.IfNull(this.Model.Variable).Path, defaultValue.ToFormula(), context).ConfigureAwait(false);
|
||||
string defaultValueResponse = this.FormatPrompt(this.Model.DefaultValueResponse);
|
||||
await context.AddEventAsync(new MessageActivityEvent(defaultValueResponse.Trim()), cancellationToken).ConfigureAwait(false);
|
||||
await context.SendResultMessageAsync(this.Id, cancellationToken).ConfigureAwait(false);
|
||||
|
||||
+502
@@ -0,0 +1,502 @@
|
||||
// Copyright (c) Microsoft. All rights reserved.
|
||||
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.Agents.AI.Workflows.Declarative.Events;
|
||||
using Microsoft.Agents.AI.Workflows.Declarative.Extensions;
|
||||
using Microsoft.Agents.AI.Workflows.Declarative.Interpreter;
|
||||
using Microsoft.Agents.AI.Workflows.Declarative.Kit;
|
||||
using Microsoft.Agents.AI.Workflows.Declarative.ObjectModel;
|
||||
using Microsoft.Agents.AI.Workflows.Declarative.PowerFx;
|
||||
using Microsoft.Agents.ObjectModel;
|
||||
using Microsoft.Extensions.AI;
|
||||
using Microsoft.PowerFx.Types;
|
||||
using Moq;
|
||||
using Xunit.Abstractions;
|
||||
|
||||
namespace Microsoft.Agents.AI.Workflows.Declarative.UnitTests.ObjectModel;
|
||||
|
||||
/// <summary>
|
||||
/// Tests for <see cref="QuestionExecutor"/>.
|
||||
/// </summary>
|
||||
public sealed class QuestionExecutorTest(ITestOutputHelper output) : WorkflowActionExecutorTest(output)
|
||||
{
|
||||
[Fact]
|
||||
public void QuestionNamingConvention()
|
||||
{
|
||||
// Arrange
|
||||
string testId = this.CreateActionId().Value;
|
||||
|
||||
// Act
|
||||
string prepareStep = QuestionExecutor.Steps.Prepare(testId);
|
||||
string inputStep = QuestionExecutor.Steps.Input(testId);
|
||||
string captureStep = QuestionExecutor.Steps.Capture(testId);
|
||||
|
||||
// Assert
|
||||
Assert.Equal($"{testId}_{nameof(QuestionExecutor.Steps.Prepare)}", prepareStep);
|
||||
Assert.Equal($"{testId}_{nameof(QuestionExecutor.Steps.Input)}", inputStep);
|
||||
Assert.Equal($"{testId}_{nameof(QuestionExecutor.Steps.Capture)}", captureStep);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData(true, false)]
|
||||
[InlineData("anything", false)]
|
||||
[InlineData(null, true)]
|
||||
public void QuestionIsComplete(object? result, bool expectIsComplete)
|
||||
{
|
||||
// Arrange - "Complete" result corresponds to null value
|
||||
ActionExecutorResult executorResult = new(nameof(QuestionIsComplete), result);
|
||||
|
||||
// Act
|
||||
bool isComplete = QuestionExecutor.IsComplete(executorResult);
|
||||
|
||||
// Assert
|
||||
Assert.Equal(expectIsComplete, isComplete);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task QuestionExecuteWithResultUndefinedAsync()
|
||||
{
|
||||
// Arrange
|
||||
Question model = this.CreateModel(
|
||||
displayName: nameof(QuestionExecuteWithResultUndefinedAsync),
|
||||
"TestVariable");
|
||||
|
||||
// Act & Assert
|
||||
await this.ExecuteTestAsync(model, expectPrompt: true);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task QuestionExecuteWithAlwaysPromptAsync()
|
||||
{
|
||||
// Arrange
|
||||
this.State.Set("TestVariable", FormulaValue.New("existing-value"));
|
||||
Question model = this.CreateModel(
|
||||
displayName: nameof(QuestionExecuteWithAlwaysPromptAsync),
|
||||
"TestVariable",
|
||||
alwaysPrompt: true);
|
||||
|
||||
// Act & Assert
|
||||
await this.ExecuteTestAsync(model, expectPrompt: true);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData(SkipQuestionMode.AlwaysSkipIfVariableHasValue)]
|
||||
[InlineData(SkipQuestionMode.SkipOnFirstExecutionIfVariableHasValue)]
|
||||
[InlineData(SkipQuestionMode.AlwaysAsk)]
|
||||
public async Task QuestionExecuteWithSkipModeAsyncWithResultUndefinedAsync(SkipQuestionMode skipMode)
|
||||
{
|
||||
// Arrange
|
||||
Question model = this.CreateModel(
|
||||
displayName: nameof(QuestionExecuteWithSkipModeAsyncWithResultUndefinedAsync),
|
||||
variableName: "TestVariable",
|
||||
skipMode: skipMode);
|
||||
|
||||
// Act & Assert
|
||||
await this.ExecuteTestAsync(model, expectPrompt: true);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData(SkipQuestionMode.AlwaysSkipIfVariableHasValue, false)]
|
||||
[InlineData(SkipQuestionMode.SkipOnFirstExecutionIfVariableHasValue, false)]
|
||||
[InlineData(SkipQuestionMode.AlwaysAsk, true)]
|
||||
public async Task QuestionExecuteWithSkipModeAsyncWithResultDefinedAsync(SkipQuestionMode skipMode, bool expectPrompt)
|
||||
{
|
||||
// Arrange
|
||||
this.State.Set("TestVariable", FormulaValue.New("existing-value"));
|
||||
Question model = this.CreateModel(
|
||||
displayName: nameof(QuestionExecuteWithSkipModeAsyncWithResultDefinedAsync),
|
||||
variableName: "TestVariable",
|
||||
skipMode: skipMode);
|
||||
|
||||
// Act & Assert
|
||||
await this.ExecuteTestAsync(model, expectPrompt);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task QuestionPrepareResponseAsync()
|
||||
{
|
||||
// Arrange
|
||||
Question model = this.CreateModel(
|
||||
displayName: nameof(QuestionPrepareResponseAsync),
|
||||
variableName: "TestVariable",
|
||||
promptText: "Provide input:");
|
||||
|
||||
// Act & Assert
|
||||
await this.PrepareResponseTestAsync(model, expectedPrompt: "Provide input:");
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task QuestionCaptureResponseWithValidEntityAsync()
|
||||
{
|
||||
// Arrange
|
||||
Question model = this.CreateModel(
|
||||
displayName: nameof(QuestionCaptureResponseWithValidEntityAsync),
|
||||
variableName: "TestVariable",
|
||||
alwaysPrompt: true,
|
||||
skipMode: SkipQuestionMode.AlwaysAsk,
|
||||
entity: new NumberPrebuiltEntity());
|
||||
|
||||
// Act & Assert
|
||||
await this.CaptureResponseTestAsync(
|
||||
model,
|
||||
variableName: "TestVariable",
|
||||
responseText: "42",
|
||||
expectAutoSend: true);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData(null)]
|
||||
[InlineData("Invalid input, please try again.")]
|
||||
public async Task QuestionCaptureResponseWithInvalidEntityAsync(string? invalidResponse)
|
||||
{
|
||||
// Arrange
|
||||
Question model = this.CreateModel(
|
||||
displayName: nameof(QuestionCaptureResponseWithInvalidEntityAsync),
|
||||
variableName: "TestVariable",
|
||||
invalidResponseText: invalidResponse,
|
||||
entity: new NumberPrebuiltEntity());
|
||||
|
||||
// Act & Assert
|
||||
await this.CaptureResponseTestAsync(
|
||||
model,
|
||||
variableName: "TestVariable",
|
||||
responseText: "not-a-number",
|
||||
expectResponse: false);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData(null)]
|
||||
[InlineData("Invalid input, please try again.")]
|
||||
public async Task QuestionCaptureResponseWithUnrecognizedResponseAsync(string? unrecognizedResponse)
|
||||
{
|
||||
// Arrange
|
||||
Question model = this.CreateModel(
|
||||
displayName: nameof(QuestionCaptureResponseWithUnrecognizedResponseAsync),
|
||||
variableName: "TestVariable",
|
||||
unrecognizedResponseText: unrecognizedResponse);
|
||||
|
||||
// Act & Assert
|
||||
await this.CaptureResponseTestAsync(
|
||||
model,
|
||||
variableName: "TestVariable",
|
||||
responseText: null,
|
||||
expectResponse: false);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task QuestionCaptureResponseWithUnsupportedPromptAsync()
|
||||
{
|
||||
// Arrange
|
||||
Question.Builder actionBuilder = new()
|
||||
{
|
||||
Id = this.CreateActionId(),
|
||||
DisplayName = this.FormatDisplayName(nameof(QuestionCaptureResponseWithUnsupportedPromptAsync)),
|
||||
Variable = PropertyPath.Create(FormatVariablePath("TestVariable")),
|
||||
Prompt = new UnknownActivityTemplateBase.Builder(),
|
||||
UnrecognizedPrompt = new UnknownActivityTemplateBase.Builder(),
|
||||
Entity = new StringPrebuiltEntity(),
|
||||
};
|
||||
|
||||
Question model = actionBuilder.Build();
|
||||
|
||||
// Act & Assert
|
||||
await this.CaptureResponseTestAsync(
|
||||
model,
|
||||
variableName: "TestVariable",
|
||||
responseText: null,
|
||||
expectResponse: false);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData(true)]
|
||||
[InlineData(false)]
|
||||
public async Task QuestionCaptureResponseExceedingRepeatCountAsync(bool hasDefault)
|
||||
{
|
||||
// Arrange
|
||||
Question model = this.CreateModel(
|
||||
displayName: nameof(QuestionCaptureResponseExceedingRepeatCountAsync),
|
||||
variableName: "TestVariable",
|
||||
repeatCount: 0,
|
||||
defaultValue: hasDefault ? new NumberDataValue(0) : null,
|
||||
entity: new NumberPrebuiltEntity());
|
||||
|
||||
// Act & Assert
|
||||
await this.CaptureResponseTestAsync(
|
||||
model,
|
||||
variableName: "TestVariable",
|
||||
responseText: "not-a-number",
|
||||
expectResponse: false);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task QuestionCaptureResponseWithAutoSendFalseAsync()
|
||||
{
|
||||
// Arrange
|
||||
Question model = this.CreateModel(
|
||||
displayName: nameof(QuestionCaptureResponseWithAutoSendFalseAsync),
|
||||
variableName: "TestVariable",
|
||||
autoSend: new BooleanDataValue(false));
|
||||
|
||||
// Act & Assert
|
||||
await this.CaptureResponseTestAsync(
|
||||
model,
|
||||
variableName: "TestVariable",
|
||||
responseText: "test response");
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task QuestionCaptureResponseWithAutoSendTrueAsync()
|
||||
{
|
||||
// Arrange
|
||||
Question model = this.CreateModel(
|
||||
displayName: nameof(QuestionCaptureResponseWithAutoSendTrueAsync),
|
||||
variableName: "TestVariable",
|
||||
autoSend: new BooleanDataValue(true));
|
||||
|
||||
// Act & Assert
|
||||
await this.CaptureResponseTestAsync(
|
||||
model,
|
||||
variableName: "TestVariable",
|
||||
responseText: "test response",
|
||||
expectAutoSend: true);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task QuestionCaptureResponseWithAutoSendInvalidAsync()
|
||||
{
|
||||
// Arrange
|
||||
Question model = this.CreateModel(
|
||||
displayName: nameof(QuestionCaptureResponseWithAutoSendInvalidAsync),
|
||||
variableName: "TestVariable",
|
||||
autoSend: new NumberDataValue(33));
|
||||
|
||||
// Act & Assert
|
||||
await this.CaptureResponseTestAsync(
|
||||
model,
|
||||
variableName: "TestVariable",
|
||||
responseText: "test response");
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task QuestionCompleteAsync()
|
||||
{
|
||||
// Arrange
|
||||
Question model =
|
||||
this.CreateModel(
|
||||
displayName: nameof(QuestionCompleteAsync),
|
||||
variableName: "TestVariable");
|
||||
|
||||
// Act & Assert
|
||||
await this.CompleteTestAsync(model);
|
||||
}
|
||||
|
||||
private async Task ExecuteTestAsync(Question model, bool expectPrompt)
|
||||
{
|
||||
// Arrange
|
||||
bool? sentMessage = null;
|
||||
Mock<ResponseAgentProvider> mockProvider = new(MockBehavior.Loose);
|
||||
QuestionExecutor action = new(model, mockProvider.Object, this.State);
|
||||
|
||||
// Act
|
||||
WorkflowEvent[] events =
|
||||
await this.ExecuteAsync(
|
||||
action,
|
||||
QuestionExecutor.Steps.Capture(action.Id),
|
||||
CaptureResultAsync);
|
||||
|
||||
// Assert
|
||||
VerifyModel(model, action);
|
||||
VerifyInvocationEvent(events);
|
||||
Assert.NotNull(sentMessage);
|
||||
Assert.Equal(expectPrompt, sentMessage);
|
||||
|
||||
ValueTask CaptureResultAsync(IWorkflowContext context, ActionExecutorResult message, CancellationToken cancellationToken)
|
||||
{
|
||||
Assert.Null(sentMessage); // Should only be called once
|
||||
sentMessage = message.Result is not null;
|
||||
return default;
|
||||
}
|
||||
}
|
||||
|
||||
private async Task PrepareResponseTestAsync(
|
||||
Question model,
|
||||
string expectedPrompt)
|
||||
{
|
||||
// Arrange
|
||||
Mock<ResponseAgentProvider> mockProvider = new(MockBehavior.Loose);
|
||||
QuestionExecutor action = new(model, mockProvider.Object, this.State);
|
||||
string? capturedPrompt = null;
|
||||
|
||||
// Act
|
||||
await this.ExecuteAsync(
|
||||
[
|
||||
action,
|
||||
new DelegateActionExecutor(
|
||||
QuestionExecutor.Steps.Prepare(action.Id),
|
||||
this.State,
|
||||
action.PrepareResponseAsync),
|
||||
new DelegateActionExecutor<ExternalInputRequest>(
|
||||
QuestionExecutor.Steps.Capture(action.Id),
|
||||
this.State,
|
||||
CaptureExternalRequestAsync)
|
||||
],
|
||||
isDiscrete: false);
|
||||
|
||||
// Assert
|
||||
VerifyModel(model, action);
|
||||
Assert.NotNull(capturedPrompt);
|
||||
Assert.Equal(expectedPrompt, capturedPrompt);
|
||||
|
||||
ValueTask CaptureExternalRequestAsync(IWorkflowContext context, ExternalInputRequest request, CancellationToken cancellationToken)
|
||||
{
|
||||
Assert.Null(capturedPrompt);
|
||||
capturedPrompt = request.AgentResponse.Text;
|
||||
return default;
|
||||
}
|
||||
}
|
||||
|
||||
private async Task CaptureResponseTestAsync(
|
||||
Question model,
|
||||
string variableName,
|
||||
string? responseText,
|
||||
bool expectResponse = true,
|
||||
bool expectAutoSend = false)
|
||||
{
|
||||
// Arrange
|
||||
this.State.Set(SystemScope.Names.ConversationId, FormulaValue.New("ExternalConversationId"), VariableScopeNames.System);
|
||||
|
||||
Mock<ResponseAgentProvider> mockProvider = new(MockBehavior.Loose);
|
||||
mockProvider
|
||||
.Setup(p => p.CreateMessageAsync(
|
||||
It.IsAny<string>(),
|
||||
It.IsAny<ChatMessage>(),
|
||||
It.IsAny<CancellationToken>()))
|
||||
.ReturnsAsync((string cid, ChatMessage msg, CancellationToken ct) => msg);
|
||||
|
||||
QuestionExecutor action = new(model, mockProvider.Object, this.State);
|
||||
ExternalInputResponse response = responseText is not null
|
||||
? new ExternalInputResponse(new ChatMessage(ChatRole.User, responseText))
|
||||
: new ExternalInputResponse([]);
|
||||
|
||||
// Act
|
||||
WorkflowEvent[] events = await this.ExecuteAsync(
|
||||
action,
|
||||
QuestionExecutor.Steps.Capture(action.Id),
|
||||
(context, message, cancellationToken) =>
|
||||
action.CaptureResponseAsync(context, response, cancellationToken));
|
||||
|
||||
// Assert
|
||||
VerifyModel(model, action);
|
||||
|
||||
if (expectResponse)
|
||||
{
|
||||
// Variable should be set with the extracted value
|
||||
FormulaValue actualValue = this.State.Get(variableName);
|
||||
Assert.Equal(responseText, actualValue.Format());
|
||||
}
|
||||
else
|
||||
{
|
||||
// Should have prompted again or sent unrecognized/invalid message
|
||||
Assert.Contains(events, e => e is MessageActivityEvent);
|
||||
}
|
||||
|
||||
if (expectAutoSend)
|
||||
{
|
||||
this.VerifyState(SystemScope.Names.LastMessageText, VariableScopeNames.System, FormulaValue.New(responseText ?? string.Empty));
|
||||
}
|
||||
else
|
||||
{
|
||||
this.VerifyUndefined(SystemScope.Names.LastMessageText, VariableScopeNames.System);
|
||||
}
|
||||
}
|
||||
|
||||
private async Task CompleteTestAsync(Question model)
|
||||
{
|
||||
// Arrange
|
||||
Mock<ResponseAgentProvider> mockProvider = new(MockBehavior.Loose);
|
||||
QuestionExecutor action = new(model, mockProvider.Object, this.State);
|
||||
|
||||
// Act
|
||||
WorkflowEvent[] events = await this.ExecuteAsync(
|
||||
QuestionExecutor.Steps.Input(action.Id),
|
||||
action.CompleteAsync);
|
||||
|
||||
// Assert
|
||||
VerifyModel(model, action);
|
||||
VerifyCompletionEvent(events);
|
||||
}
|
||||
|
||||
private Question CreateModel(
|
||||
string displayName,
|
||||
string variableName,
|
||||
string promptText = "Please provide a value",
|
||||
string? invalidResponseText = null,
|
||||
string? unrecognizedResponseText = null,
|
||||
string? defaultValueResponseText = null,
|
||||
DataValue? defaultValue = null,
|
||||
bool? alwaysPrompt = null,
|
||||
SkipQuestionMode? skipMode = null,
|
||||
int? repeatCount = null,
|
||||
EntityReference? entity = null,
|
||||
DataValue? autoSend = null)
|
||||
{
|
||||
BoolExpression.Builder? alwaysPromptExpression = null;
|
||||
if (alwaysPrompt is not null)
|
||||
{
|
||||
alwaysPromptExpression = BoolExpression.Literal(alwaysPrompt.Value).ToBuilder();
|
||||
}
|
||||
|
||||
IntExpression.Builder? repeatCountExpression = null;
|
||||
if (repeatCount is not null)
|
||||
{
|
||||
repeatCountExpression = IntExpression.Literal(repeatCount.Value).ToBuilder();
|
||||
}
|
||||
|
||||
ValueExpression.Builder? defaultValueExpression = null;
|
||||
if (defaultValue is not null)
|
||||
{
|
||||
defaultValueExpression = ValueExpression.Literal(defaultValue).ToBuilder();
|
||||
}
|
||||
|
||||
EnumExpression<SkipQuestionModeWrapper>.Builder? skipModeExpression = null;
|
||||
if (skipMode is not null)
|
||||
{
|
||||
skipModeExpression = EnumExpression<SkipQuestionModeWrapper>.Literal(skipMode).ToBuilder();
|
||||
}
|
||||
|
||||
Question.Builder actionBuilder = new()
|
||||
{
|
||||
Id = this.CreateActionId(),
|
||||
DisplayName = this.FormatDisplayName(displayName),
|
||||
AlwaysPrompt = alwaysPromptExpression,
|
||||
SkipQuestionMode = skipModeExpression,
|
||||
Variable = PropertyPath.Create(FormatVariablePath(variableName)),
|
||||
Prompt = CreateMessageActivity(promptText),
|
||||
InvalidPrompt = CreateOptionalMessageActivity(invalidResponseText),
|
||||
UnrecognizedPrompt = CreateOptionalMessageActivity(unrecognizedResponseText),
|
||||
DefaultValue = defaultValueExpression,
|
||||
DefaultValueResponse = CreateOptionalMessageActivity(defaultValueResponseText),
|
||||
RepeatCount = repeatCountExpression,
|
||||
Entity = entity ?? new StringPrebuiltEntity(),
|
||||
};
|
||||
|
||||
if (autoSend is not null)
|
||||
{
|
||||
RecordDataValue.Builder extensionDataBuilder = new();
|
||||
extensionDataBuilder.Properties.Add("autoSend", autoSend);
|
||||
actionBuilder.ExtensionData = extensionDataBuilder.Build();
|
||||
}
|
||||
|
||||
return AssignParent<Question>(actionBuilder);
|
||||
}
|
||||
|
||||
private static MessageActivityTemplate.Builder? CreateOptionalMessageActivity(string? text) =>
|
||||
text is null ? null : CreateMessageActivity(text);
|
||||
|
||||
private static MessageActivityTemplate.Builder CreateMessageActivity(string text) =>
|
||||
new()
|
||||
{
|
||||
Text = { TemplateLine.Parse(text) },
|
||||
};
|
||||
}
|
||||
Reference in New Issue
Block a user