コード例 #1
0
        cmd.IndexOf(AzPredictorConstants.AzCommandMoniker) > 0;        // This is the Az cmdlet.

        /// <summary>
        /// Requests a list of popular commands from service. These commands are used as fall back suggestion
        /// if none of the predictions fit for the current input. This method should be called once per session.
        /// </summary>
        protected virtual void RequestAllPredictiveCommands()
        {
            // We don't need to block on the task. We send the HTTP request and update commands and predictions list at the background.
            Task.Run(async() =>
            {
                var hasSentHttpRequest = false;
                Exception exception    = null;
                var requestId          = Guid.NewGuid().ToString();

                try
                {
                    AzPredictorService.SetHttpRequestHeader(_client.DefaultRequestHeaders, _azContext.HashUserId, requestId);

                    var httpResponseMessage = await _client.GetAsync(_commandsEndpoint);
                    hasSentHttpRequest      = true;

                    httpResponseMessage.EnsureSuccessStatusCode();
                    var reply         = await httpResponseMessage.Content.ReadAsStringAsync();
                    var commandsReply = JsonSerializer.Deserialize <List <PredictiveCommand> >(reply, JsonUtilities.DefaultSerializerOptions);
                    commandsReply.AddRange(_surveyCmdlets);
                    SetFallbackPredictor(commandsReply);
                }
                catch (Exception e) when(!(e is OperationCanceledException))
                {
                    exception = e;
                }
                finally
                {
                    _telemetryClient.RequestId = requestId;
                    _telemetryClient.OnRequestPrediction(new RequestPredictionTelemetryData(null,
                                                                                            new List <string>(),
                                                                                            hasSentHttpRequest,
                                                                                            exception));
                }

                // Initialize predictions
                var placeholderCommands = new string[] {
                    AzPredictorConstants.CommandPlaceholder,
                    AzPredictorConstants.CommandPlaceholder
                };

                return(AzPredictorUtilities.RequestPredictionAndCollectTelemetryAync(this, _telemetryClient, null, placeholderCommands, null, CancellationToken.None));
            });
        }
コード例 #2
0
        /// <inhericdoc />
        public void OnCommandLineAccepted(PredictionClient client, IReadOnlyList <string> history)
        {
            _commandLineExecutedCompletion = new TaskCompletionSource();

            SharedVariable.PredictorCorrelationId = _telemetryClient.CommandId;

            if (history.Count > 0)
            {
                // We try to find the commands to request predictions for.
                // We should only have "start_of_snippet" when there are no enough Az commands for prediction.
                // We only send the requests when Az commands are changed. So we'll never add "start_of_snippet" again
                // once we have enough Az commands.
                // This is the scenario.
                // 1. New-AzResourceGroup -Name ****
                // 2. $resourceName="Test"
                // 3. $resourceLocation="westus2"
                // 4. New-AzVM -Name $resourceName -Location $resourceLocation
                //
                // If the history only contains 1, we'll add "start_of_snippet" to the request.
                // We'll replace 2 and 3 with "start_of_snippet". But if we request prediction using 2 and 3, that'll reset the
                // workflow. We want to predict only by Az commands. So we don't send the request until the command 4.
                // That's to use commands 1 and 4 to request prediction.

                bool shouldRequestPrediction = false;

                if (_lastTwoMaskedCommands.Count == 0)
                {
                    // This is the first time we populate our record. Push the second to last command in history to the
                    // queue. If there is only one command in history, push the command placeholder.

                    if (history.Count() > 1)
                    {
                        string secondToLastLine    = history.TakeLast(AzPredictorConstants.CommandHistoryCountToProcess).First();
                        var    secondToLastCommand = GetAstAndMaskedCommandLine(secondToLastLine);
                        _lastTwoMaskedCommands.Enqueue(secondToLastCommand.IsSupported ? secondToLastCommand.MaskedCommandLine : AzPredictorConstants.CommandPlaceholder);

                        if (secondToLastCommand.IsSupported)
                        {
                            _service.RecordHistory(secondToLastCommand.Ast);
                        }
                    }
                    else
                    {
                        _lastTwoMaskedCommands.Enqueue(AzPredictorConstants.CommandPlaceholder);
                        // We only extract parameter values from the command line in _service.RecordHistory.
                        // So we don't need to do that for a placeholder.
                    }

                    shouldRequestPrediction = true;
                }

                string lastLine               = history.Last();
                var    lastCommand            = GetAstAndMaskedCommandLine(lastLine);
                bool   isLastCommandSupported = lastCommand.IsSupported;

                _parsedCommandLineHistory.TryAdd(lastLine, lastCommand);

                if (isLastCommandSupported)
                {
                    if (_lastTwoMaskedCommands.Count == 2)
                    {
                        // There are already two commands, dequeue the oldest one.
                        _lastTwoMaskedCommands.Dequeue();
                    }

                    _lastTwoMaskedCommands.Enqueue(lastCommand.MaskedCommandLine);
                    shouldRequestPrediction = true;

                    _service.RecordHistory(lastCommand.Ast);
                }
                else if (_lastTwoMaskedCommands.Count == 1)
                {
                    shouldRequestPrediction = true;
                    var existingInQueue = _lastTwoMaskedCommands.Dequeue();
                    _lastTwoMaskedCommands.Enqueue(AzPredictorConstants.CommandPlaceholder);
                    _lastTwoMaskedCommands.Enqueue(existingInQueue);
                }


                if (shouldRequestPrediction)
                {
                    // When it's called multiple times, we only need to keep the one for the latest command.

                    _predictionRequestCancellationSource?.Cancel();
                    _predictionRequestCancellationSource = new CancellationTokenSource();
                    // Need to create a new object to hold the string. They're used in a seperate thread the the contents in
                    // _lastTwoMaskedCommands may change when the method is called again.
                    var lastTwoMaskedCommands = new List <string>(_lastTwoMaskedCommands);

                    // We don't need to block on the task. It sends the HTTP request and update prediction list. That can run at the background.
                    var _ = AzPredictorUtilities.RequestPredictionAndCollectTelemetryAync(_service, _telemetryClient, client, lastTwoMaskedCommands, _commandLineExecutedCompletion, _predictionRequestCancellationSource.Token);
                }
            }
        }