public async Task <Document[]> HandleUserInput(string userIdentity, Protocol.Message input, UserContext userContext, CancellationToken cancellationToken) { var userSemaphore = await _userSemaphoreService.GetSemaphoreByUserIdentity(userIdentity); try { await userSemaphore.WaitAsync(); var flow = await _botFlowService.GetBotFlow(); userContext = userContext ?? await UserContext.GetOrCreateAsync(userIdentity, cancellationToken); var state = _stateMachineService.GetCurrentUserState(userContext, flow); var oldInput = state.InteractionActions.Single(x => x.Input != default).Input; if (!string.IsNullOrEmpty(oldInput.Variable)) { userContext.SetVariable(oldInput.Variable, input); } userContext.SetVariable("input", input); userContext.PopulateNlpResponse(input.ToString(), _nlpProvider); var documents = new List <Document>(); do { state = await _stateMachineService.GetNextUserStateAsync(userContext, state, flow); await _customActionService.ExecuteCustomActions(state.EnteringCustomActions, userContext); state.InteractionActions.Where(x => x.Input == default).ForEach(async x => { var content = x.Action.Message.Content; content = await _variableService.ReplaceVariablesInDocumentAsync(content, userContext); documents.Add(content); }); await _customActionService.ExecuteCustomActions(state.LeavingCustomActions, userContext); } while (!state.InteractionActions.Any(x => x.Input?.Bypass == false)); userContext.StateId = state.Id; await userContext.AddOrUpdateAsync(cancellationToken); return(documents.ToArray()); } finally { userSemaphore.Release(); } }