in CSharp/Library/Microsoft.Bot.Builder/FormFlow/Steps.cs [142:318]
public async Task<StepResult> ProcessAsync(IDialogContext context, T state, FormState form, IMessageActivity input, IEnumerable<TermMatch> matches)
{
var inputText = MessageActivityHelper.GetSanitizedTextInput(input);
ValidateResult feedback = new ValidateResult();
feedback.IsValid = true;
feedback.Feedback = null;
feedback.FeedbackCard = null;
feedback.Choices = null;
FormPrompt prompt = null;
FormPrompt feedbackPrompt = null;
var iprompt = _field.Prompt;
var fieldState = (FieldStepState)form.StepState;
object response = null;
if (fieldState.State == FieldStepStates.SentPrompt)
{
// Response to prompt
var firstMatch = matches.FirstOrDefault();
if (matches.Count() == 1)
{
response = firstMatch.Value;
if (_field.AllowsMultiple && response != null
&& (response.GetType() == typeof(string) || !response.GetType().IsIEnumerable()))
{
response = new List<object>() { response };
}
feedback = await SetValueAsync(state, response, form);
if (!feedback.IsValid && feedback.Choices != null)
{
var choices = new Ambiguous(inputText.Substring(firstMatch.Start, firstMatch.Length), feedback.Choices);
fieldState.State = FieldStepStates.SentClarify;
fieldState.Settled = new List<object>();
fieldState.Clarifications = new List<Ambiguous>() { choices };
response = SetValue(state, null);
prompt = ClarifyPrompt((FieldStepState)form.StepState, iprompt.Recognizer, state);
}
}
else if (matches.Count() > 1)
{
// Check multiple matches for ambiguity
var groups = MatchAnalyzer.GroupedMatches(matches);
// 1) Could be multiple match groups like for ingredients.
// 2) Could be overlapping matches like "onion".
// 3) Could be multiple matches where only one is expected.
if (!_field.AllowsMultiple)
{
// Create a single group of all possibilities if only want one value
var mergedGroup = groups.SelectMany((group) => group).ToList();
groups = new List<List<TermMatch>>() { mergedGroup };
}
var ambiguous = new List<Ambiguous>();
var settled = new List<object>();
foreach (var choices in groups)
{
if (choices.Count > 1)
{
var unclearResponses = string.Join(" ", (from choice in choices select inputText.Substring(choice.Start, choice.Length)).Distinct());
var values = from match in choices select match.Value;
ambiguous.Add(new Ambiguous(unclearResponses, values));
}
else
{
var matchValue = choices.First().Value;
if (matchValue != null && matchValue.GetType() != typeof(string) && matchValue.GetType().IsIEnumerable())
{
foreach (var value in (System.Collections.IEnumerable)matchValue)
{
settled.Add(value);
}
}
else
{
settled.Add(choices.First().Value);
}
}
}
if (settled.Count > 1)
{
// Remove no preference if present
settled.Remove(null);
}
if (ambiguous.Count > 0)
{
// Need 1 or more clarifications
fieldState.State = FieldStepStates.SentClarify;
fieldState.Settled = settled;
fieldState.Clarifications = ambiguous;
response = SetValue(state, null);
prompt = ClarifyPrompt((FieldStepState)form.StepState, iprompt.Recognizer, state);
}
else
{
if (_field.AllowsMultiple)
{
response = settled;
feedback = await SetValueAsync(state, response, form);
}
else
{
Debug.Assert(settled.Count == 1);
response = settled.First();
feedback = await SetValueAsync(state, response, form);
}
}
}
var unmatched = MatchAnalyzer.Unmatched(inputText, matches);
var unmatchedWords = string.Join(" ", unmatched);
var nonNoise = Language.NonNoiseWords(Language.WordBreak(unmatchedWords)).ToArray();
fieldState.Unmatched = null;
if (_field.Prompt.Annotation.Feedback == FeedbackOptions.Always)
{
fieldState.Unmatched = string.Join(" ", nonNoise);
}
else if (_field.Prompt.Annotation.Feedback == FeedbackOptions.Auto
&& nonNoise.Any()
&& unmatched.Any())
{
fieldState.Unmatched = string.Join(" ", nonNoise);
}
}
else if (fieldState.State == FieldStepStates.SentClarify)
{
if (matches.Count() == 1)
{
// Clarified ambiguity
var clarify = NeedsClarification(fieldState);
fieldState.Settled.Add(matches.First().Value);
fieldState.Clarifications.Remove(clarify);
if (prompt == null)
{
// No clarification left, so set the field
if (_field.AllowsMultiple)
{
response = fieldState.Settled;
feedback = await SetValueAsync(state, response, form);
}
else
{
Debug.Assert(fieldState.Settled.Count == 1);
response = fieldState.Settled.First();
feedback = await SetValueAsync(state, response, form);
}
form.SetPhase(StepPhase.Completed);
}
}
}
if (form.Phase() == StepPhase.Completed)
{
form.StepState = null;
if (fieldState.Unmatched != null)
{
if (feedback.FeedbackCard != null)
{
feedbackPrompt = feedback.FeedbackCard;
}
else if (feedback.Feedback != null)
{
feedbackPrompt = new FormPrompt { Prompt = feedback.Feedback };
}
else
{
if (fieldState.Unmatched != "")
{
feedbackPrompt = new Prompter<T>(_field.Template(TemplateUsage.Feedback), _field.Form, null).Prompt(state, _field, fieldState.Unmatched);
}
else
{
feedbackPrompt = new Prompter<T>(_field.Template(TemplateUsage.Feedback), _field.Form, null).Prompt(state, _field);
}
}
}
}
var next = _field.Next(response, state);
return new StepResult(feedback.IsValid, next, feedbackPrompt ?? (feedback.FeedbackCard ?? new FormPrompt { Prompt = feedback.Feedback }), prompt);
}