async getCompletions()

in src/common/code_suggestions/code_suggestions_provider.ts [201:353]


  async getCompletions({
    document,
    position,
    cancellationToken,
  }: {
    document: vscode.TextDocument;
    position: vscode.Position;
    cancellationToken: vscode.CancellationToken;
  }): Promise<vscode.InlineCompletionItem[]> {
    if (!this.#stateManager.isActive()) {
      return [];
    }
    if (this.#circuitBreaker.isOpen()) {
      CodeSuggestionsTelemetryManager.rejectOpenedSuggestions();
      return [];
    }

    const platform = await this.#manager.getGitLabPlatform();
    if (!platform) {
      log.warn(
        'AI Assist: could not obtain suggestions, there is no active project or GitLab account registered. Open GitLab project or authorise to GitLab account with code suggestions enabled to continue.',
      );
      this.#stateManager.setError(true);
      return [];
    }

    const { instanceUrl } = platform.account;

    const gitlabRealm = instanceUrl.startsWith(GITLAB_COM_URL) ? 'saas' : 'self-managed';

    const prompt = CodeSuggestionsProvider.#getPrompt(document, position, platform.project);

    if (!prompt) {
      return [];
    }

    log.debug(
      `AI Assist: fetching completions ... (telemetry: ${prettyJson(
        codeSuggestionsTelemetry.toArray(),
        0,
      )})`,
    );

    // if previous suggestion exists (user has not accepted it) it means it was rejected and user request new one
    const traceID = CodeSuggestionsTelemetryManager.createSuggestion(
      document.languageId,
      gitlabRealm,
    );

    let response: CodeSuggestionsResponse;
    let model: Model = { engine: '', name: '', lang: '' }; // Defaults for telemetry of failed requests
    let experiments: Experiment[] = [];

    const gitlabMonolithApiAvailable =
      !this.#legacyApiFallbackConfig.shouldUseModelGateway() ||
      getLocalFeatureFlagService().isEnabled(FeatureFlag.ForceCodeSuggestionsViaMonolith);

    try {
      this.#stateManager.setLoading(true);
      if (gitlabMonolithApiAvailable) {
        response = await CodeSuggestionsProvider.fetchCompletionsFromGitLab(platform, prompt);
      } else {
        // FIXME: when we start supporting SM, we need to get the token from the **platform**, now the project might not match the token
        // Also, passing the project to the API might get deprecated: https://gitlab.com/gitlab-org/modelops/applied-ml/code-suggestions/ai-assist/-/merge_requests/143#note_1419849871
        const token = await this.#tokenManager.getToken();
        if (!token) {
          log.error('AI Assist: Could not fetch token');
          return [];
        }

        response = await this.fetchCompletions(platform, token, prompt, traceID);
      }

      if (response.model !== undefined) model = response.model;
      if (response.experiments !== undefined) experiments = response.experiments;
      CodeSuggestionsTelemetryManager.setSuggestionModel(traceID, model.name, model.engine);

      // right after request with suggestion comes back emit: suggestion_loaded
      CodeSuggestionsTelemetryManager.updateSuggestionState(
        traceID,
        CodeSuggestionTelemetryState.LOADED,
      );

      this.#stateManager.setError(false);
      this.#circuitBreaker.success();

      // The previous counts were successfully sent...
      codeSuggestionsTelemetry.resetCounts();

      if (!cancellationToken.isCancellationRequested) {
        // Keep track of this request for next send..
        codeSuggestionsTelemetry.storeExperiments(model, experiments);
        codeSuggestionsTelemetry.incRequestCount(model);
      } else {
        //  emit: suggestion_cancelled
        CodeSuggestionsTelemetryManager.updateSuggestionState(
          traceID,
          CodeSuggestionTelemetryState.CANCELLED,
        );
        log.debug(
          'Code suggestions result is discarded because the completion request has been cancelled by the VS Code',
        );
        return [];
      }
    } catch (e) {
      log.error(`AI Assist: Error fetching completions: ${e.toString()}`);
      this.#stateManager.setError(true);
      this.#circuitBreaker.error();

      codeSuggestionsTelemetry.storeExperiments(model, experiments);
      codeSuggestionsTelemetry.incRequestCount(model);
      codeSuggestionsTelemetry.incErrorCount(model);
      // emit: suggestion_error
      CodeSuggestionsTelemetryManager.updateSuggestionState(
        traceID,
        CodeSuggestionTelemetryState.ERROR,
      );
      return [];
    } finally {
      this.#stateManager.setLoading(false);
    }
    const choices = response.choices || [];

    log.debug(`AI Assist: got ${choices.length} completions`);

    // This command will be called when a suggestion is accepted
    const acceptedCommand: vscode.Command = {
      title: 'Code Suggestion Accepted',
      command: COMMAND_CODE_SUGGESTION_ACCEPTED,
      arguments: [model, traceID],
    };

    if (choices.length > 0 && choices.some(choice => choice.text.length > 0)) {
      CodeSuggestionsTelemetryManager.updateSuggestionState(
        traceID,
        CodeSuggestionTelemetryState.SHOWN,
      );
    } else {
      CodeSuggestionsTelemetryManager.updateSuggestionState(
        traceID,
        CodeSuggestionTelemetryState.NOT_PROVIDED,
      );
    }

    return choices.map(
      choice =>
        new vscode.InlineCompletionItem(
          choice.text,
          new vscode.Range(position, position),
          acceptedCommand,
        ),
    );
  }