diff --git a/lib/shared/src/configuration.ts b/lib/shared/src/configuration.ts index fc5d5dcbfe95..c5d1219977b9 100644 --- a/lib/shared/src/configuration.ts +++ b/lib/shared/src/configuration.ts @@ -107,7 +107,7 @@ interface RawClientConfiguration { experimentalSupercompletions: boolean experimentalAutoeditsRendererTesting: boolean experimentalAutoeditsConfigOverride: AutoEditsModelConfig | undefined - experimentalAutoeditsEnabled: boolean | undefined + experimentalAutoeditsEnabled: boolean experimentalCommitMessage: boolean experimentalNoodle: boolean experimentalMinionAnthropicKey: string | undefined diff --git a/vscode/src/autoedits/autoedit-onboarding.ts b/vscode/src/autoedits/autoedit-onboarding.ts index 60dc81b3772d..b689f33ede7c 100644 --- a/vscode/src/autoedits/autoedit-onboarding.ts +++ b/vscode/src/autoedits/autoedit-onboarding.ts @@ -1,68 +1,89 @@ import { FeatureFlag, currentAuthStatus, + currentResolvedConfig, + currentUserProductSubscription, featureFlagProvider, - isDotComAuthed, - isS2, + storeLastValue, } from '@sourcegraph/cody-shared' import * as vscode from 'vscode' -import { isRunningInsideAgent } from './../jsonrpc/isRunningInsideAgent' +import { localStorage } from '../services/LocalStorageProvider' +import { isUserEligibleForAutoeditsFeature } from './create-autoedits-provider' -export async function showAutoeditOnboardingIfEligible(): Promise { - // Determine if we should show the onboarding popup - if (!shouldShowAutoeditsOnboardingPopup()) { - return - } +export class AutoeditsOnboarding implements vscode.Disposable { + private readonly MAX_AUTO_EDITS_ONBOARDING_NOTIFICATIONS = 3 - const selection = await vscode.window.showInformationMessage( - '✨ Try Cody Autoedits - experimental feature which suggest smarter code edits as you type.', - 'Enable Autoedits' + private featureFlagAutoeditsExperimental = storeLastValue( + featureFlagProvider.evaluatedFeatureFlag(FeatureFlag.CodyAutoeditExperimentEnabledFeatureFlag) ) - if (selection === 'Enable Autoedits') { - // Enable the setting programmatically - await vscode.workspace - .getConfiguration() - .update('cody.experimental.autoedits.enabled', true, vscode.ConfigurationTarget.Global) + private async showAutoeditOnboardingIfEligible(): Promise { + const shouldShowOnboardingPopup = await this.shouldShowAutoeditsOnboardingPopup() + if (shouldShowOnboardingPopup) { + await this.showAutoeditsOnboardingPopup() + await this.incrementAutoEditsOnboardingNotificationCount() + } + } - // Open VS Code settings UI and focus on the Cody Autoedits setting - await vscode.commands.executeCommand( - 'workbench.action.openSettings', - 'cody.experimental.autoedits' + private async showAutoeditsOnboardingPopup(): Promise { + const selection = await vscode.window.showInformationMessage( + '✨ Try Cody auto-edits. Experimental feature which suggests advanced context-aware code edits as you navigate the codebase', + 'Enable auto-edits' ) + + if (selection === 'Enable auto-edits') { + // Enable the setting programmatically + await vscode.workspace + .getConfiguration() + .update('cody.suggestions.mode', true, vscode.ConfigurationTarget.Global) + + // Open VS Code settings UI and focus on the Cody Autoedits setting + await vscode.commands.executeCommand( + 'workbench.action.openSettings', + 'cody.suggestions.mode' + ) + } + } + + private async shouldShowAutoeditsOnboardingPopup(): Promise { + const isUserEligible = await this.isUserEligibleForAutoeditsOnboarding() + const isAutoeditsDisabled = await this.isAutoeditsDisabled() + const isUnderNotificationLimit = + (await this.getAutoEditsOnboardingNotificationCount()) < + this.MAX_AUTO_EDITS_ONBOARDING_NOTIFICATIONS + return isUserEligible && isAutoeditsDisabled && isUnderNotificationLimit } -} -function shouldShowAutoeditsOnboardingPopup(): boolean { - const isAutoeditsConfigEnabled = vscode.workspace - .getConfiguration() - .get('cody.experimental.autoedits.enabled', false) + private async incrementAutoEditsOnboardingNotificationCount(): Promise { + const count = await this.getAutoEditsOnboardingNotificationCount() + await localStorage.setAutoEditsOnboardingNotificationCount(count + 1) + } - // Do not show the onboarding popup if the feature is already enabled or any other editor than vscode. - if (isRunningInsideAgent() || isAutoeditsConfigEnabled) { - return false + private async isAutoeditsDisabled(): Promise { + const config = await currentResolvedConfig() + return !config.configuration.experimentalAutoeditsEnabled } - if (isDotComAuthed()) { - return shouldShowAutoeditsOnboardingPopupForDotComUser() + private async getAutoEditsOnboardingNotificationCount(): Promise { + return localStorage.getAutoEditsOnboardingNotificationCount() } - const authStatus = currentAuthStatus() - if (isS2(authStatus)) { - // All the S2 users should see the onboarding popup for dogfooding - return true + private async isUserEligibleForAutoeditsOnboarding(): Promise { + const authStatus = currentAuthStatus() + const productSubsubscription = await currentUserProductSubscription() + const autoeditsFeatureFlag = this.isAutoeditsFeatureFlagEnabled() + return isUserEligibleForAutoeditsFeature( + autoeditsFeatureFlag, + authStatus, + productSubsubscription + ) } - // Decide later if we want to show the pop-up for the enterprise - return false -} + private isAutoeditsFeatureFlagEnabled(): boolean { + return !!this.featureFlagAutoeditsExperimental.value.last + } -function shouldShowAutoeditsOnboardingPopupForDotComUser(): boolean { - const isUserEligibleForFeature = featureFlagProvider.evaluatedFeatureFlag( - FeatureFlag.CodyAutoeditExperimentEnabledFeatureFlag - ) - if (!isUserEligibleForFeature) { - return false + dispose(): void { + this.featureFlagAutoeditsExperimental.subscription.unsubscribe() } - return true } diff --git a/vscode/src/services/LocalStorageProvider.ts b/vscode/src/services/LocalStorageProvider.ts index ea2187c46cb1..1fa94f5336b3 100644 --- a/vscode/src/services/LocalStorageProvider.ts +++ b/vscode/src/services/LocalStorageProvider.ts @@ -36,6 +36,9 @@ class LocalStorage implements LocalStorageForModelPreferences { public readonly LAST_USED_ENDPOINT = 'SOURCEGRAPH_CODY_ENDPOINT' private readonly MODEL_PREFERENCES_KEY = 'cody-model-preferences' private readonly CODY_CHAT_MEMORY = 'cody-chat-memory' + private readonly AUTO_EDITS_ONBOARDING_NOTIFICATION_COUNT = + 'cody-auto-edits-onboarding-notification-count' + public readonly keys = { // LLM waitlist for the 09/12/2024 openAI o1 models waitlist_o1: 'CODY_WAITLIST_LLM_09122024', @@ -238,6 +241,14 @@ class LocalStorage implements LocalStorageForModelPreferences { } } + public async getAutoEditsOnboardingNotificationCount(): Promise { + return this.get(this.AUTO_EDITS_ONBOARDING_NOTIFICATION_COUNT) ?? 0 + } + + public async setAutoEditsOnboardingNotificationCount(count: number): Promise { + await this.set(this.AUTO_EDITS_ONBOARDING_NOTIFICATION_COUNT, count) + } + public async setGitHubRepoAccessibility(data: GitHubDotComRepoMetaData[]): Promise { await this.set(this.GIT_REPO_ACCESSIBILITY_KEY, data) }