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,
),
);
}