Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 2 additions & 5 deletions src/extension/conversation/vscode-node/languageModelAccess.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,7 @@ import { IAutomodeService } from '../../../platform/endpoint/common/automodeServ
import { IEndpointProvider } from '../../../platform/endpoint/common/endpointProvider';
import { CustomDataPartMimeTypes } from '../../../platform/endpoint/common/endpointTypes';
import { encodeStatefulMarker } from '../../../platform/endpoint/common/statefulMarkerContainer';
import { IEnvService, isScenarioAutomation } from '../../../platform/env/common/envService';
import { IVSCodeExtensionContext } from '../../../platform/extContext/common/extensionContext';
import { IEnvService } from '../../../platform/env/common/envService';
import { ILogService } from '../../../platform/log/common/logService';
import { FinishedCallback, OpenAiFunctionTool, OptionalChatRequestParams } from '../../../platform/networking/common/fetch';
import { IChatEndpoint, IEndpoint } from '../../../platform/networking/common/networking';
Expand All @@ -31,7 +30,6 @@ import { isDefined, isNumber, isString, isStringArray } from '../../../util/vs/b
import { generateUuid } from '../../../util/vs/base/common/uuid';
import { localize } from '../../../util/vs/nls';
import { IInstantiationService } from '../../../util/vs/platform/instantiation/common/instantiation';
import { ExtensionMode } from '../../../vscodeTypes';
import type { LMResponsePart } from '../../byok/common/byokProvider';
import { IExtensionContribution } from '../../common/contributions';
import { PromptRenderer } from '../../prompts/node/base/promptRenderer';
Expand All @@ -55,7 +53,6 @@ export class LanguageModelAccess extends Disposable implements IExtensionContrib
@IAuthenticationService private readonly _authenticationService: IAuthenticationService,
@IEndpointProvider private readonly _endpointProvider: IEndpointProvider,
@IEmbeddingsComputer private readonly _embeddingsComputer: IEmbeddingsComputer,
@IVSCodeExtensionContext private readonly _vsCodeExtensionContext: IVSCodeExtensionContext,
@IExperimentationService private readonly _expService: IExperimentationService,
@IAutomodeService private readonly _automodeService: IAutomodeService,
@IEnvService private readonly _envService: IEnvService
Expand All @@ -64,7 +61,7 @@ export class LanguageModelAccess extends Disposable implements IExtensionContrib

this._lmWrapper = this._instantiationService.createInstance(CopilotLanguageModelWrapper);

if (this._vsCodeExtensionContext.extensionMode === ExtensionMode.Test && !isScenarioAutomation) {
if (!this._envService.enableLanguageModels()) {
this._logService.warn('[LanguageModelAccess] LanguageModels and Embeddings are NOT AVAILABLE in test mode.');
return;
}
Expand Down
32 changes: 17 additions & 15 deletions src/extension/extension/vscode-node/services.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/

import { ExtensionContext, ExtensionMode } from 'vscode';
import { ExtensionContext } from 'vscode';
import { IAuthenticationService } from '../../../platform/authentication/common/authentication';
import { ICopilotTokenManager } from '../../../platform/authentication/common/copilotTokenManager';
import { StaticGitHubAuthenticationService } from '../../../platform/authentication/common/staticGitHubAuthenticationService';
Expand All @@ -23,7 +23,8 @@ import { IDomainService } from '../../../platform/endpoint/common/domainService'
import { IEndpointProvider } from '../../../platform/endpoint/common/endpointProvider';
import { CAPIClientImpl } from '../../../platform/endpoint/node/capiClientImpl';
import { DomainService } from '../../../platform/endpoint/node/domainServiceImpl';
import { isScenarioAutomation } from '../../../platform/env/common/envService';
import { IEnvService } from '../../../platform/env/common/envService';
import { EnvServiceImpl } from '../../../platform/env/vscode/envServiceImpl';
import { IGitCommitMessageService } from '../../../platform/git/common/gitCommitMessageService';
import { IGitDiffService } from '../../../platform/git/common/gitDiffService';
import { IGithubRepositoryService } from '../../../platform/github/common/githubService';
Expand Down Expand Up @@ -113,10 +114,10 @@ import { registerServices as registerCommonServices } from '../vscode/services';
// ###########################################################################################

export function registerServices(builder: IInstantiationServiceBuilder, extensionContext: ExtensionContext): void {
const isTestMode = extensionContext.extensionMode === ExtensionMode.Test;

registerCommonServices(builder, extensionContext);

const envService = new EnvServiceImpl(extensionContext);

builder.define(IConversationStore, new ConversationStore());
builder.define(IDiffService, new DiffServiceImpl());
builder.define(ITokenizerProvider, new SyncDescriptor(TokenizerProvider, [true]));
Expand All @@ -132,20 +133,21 @@ export function registerServices(builder: IInstantiationServiceBuilder, extensio
const internalAIKey = extensionContext.extension.packageJSON.internalAIKey ?? '';
const internalLargeEventAIKey = extensionContext.extension.packageJSON.internalLargeStorageAriaKey ?? '';
const ariaKey = extensionContext.extension.packageJSON.ariaKey ?? '';
if (isTestMode) {
setupTelemetry(builder, extensionContext, internalAIKey, internalLargeEventAIKey, ariaKey);

setupTelemetry(builder, extensionContext, internalAIKey, internalLargeEventAIKey, ariaKey, envService);

if (envService.useProductionTokenManager()) {
builder.define(ICopilotTokenManager, new SyncDescriptor(VSCodeCopilotTokenManager));
} else {
// If we're in testing mode, then most code will be called from an actual test,
// and not from here. However, some objects will capture the `accessor` we pass
// here and then re-use it later. This is particularly the case for those objects
// which implement VSCode interfaces so can't be changed to take `accessor` in their
// method parameters.
builder.define(ICopilotTokenManager, getOrCreateTestingCopilotTokenManager());
} else {
setupTelemetry(builder, extensionContext, internalAIKey, internalLargeEventAIKey, ariaKey);
builder.define(ICopilotTokenManager, new SyncDescriptor(VSCodeCopilotTokenManager));
}

if (isScenarioAutomation) {
if (envService.useStaticGitHubAuthenticationService()) {
builder.define(IAuthenticationService, new SyncDescriptor(StaticGitHubAuthenticationService, [getStaticGitHubToken]));
}
else {
Expand Down Expand Up @@ -198,18 +200,18 @@ export function registerServices(builder: IInstantiationServiceBuilder, extensio
builder.define(ITodoListContextProvider, new SyncDescriptor(TodoListContextProvider));
}

function setupMSFTExperimentationService(builder: IInstantiationServiceBuilder, extensionContext: ExtensionContext) {
if (ExtensionMode.Production === extensionContext.extensionMode) {
function setupMSFTExperimentationService(builder: IInstantiationServiceBuilder, extensionContext: ExtensionContext, envService: IEnvService) {
if (envService.useExperimentationService()) {
// Intitiate the experimentation service
builder.define(IExperimentationService, new SyncDescriptor(MicrosoftExperimentationService));
} else {
builder.define(IExperimentationService, new NullExperimentationService());
}
}

function setupTelemetry(builder: IInstantiationServiceBuilder, extensionContext: ExtensionContext, internalAIKey: string, internalLargeEventAIKey: string, externalAIKey: string) {
function setupTelemetry(builder: IInstantiationServiceBuilder, extensionContext: ExtensionContext, internalAIKey: string, internalLargeEventAIKey: string, externalAIKey: string, envService: IEnvService) {

if (ExtensionMode.Production === extensionContext.extensionMode) {
Copy link
Member Author

@rwoll rwoll Aug 18, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Without refactor we would need to write something like:

ExtensionMode.Production === extensionContext.extensionMode && !isScenarioAutomation

if (envService.useProductionTelemetry()) {
builder.define(ITelemetryService, new SyncDescriptor(TelemetryService, [
extensionContext.extension.packageJSON.name,
internalAIKey,
Expand All @@ -223,5 +225,5 @@ function setupTelemetry(builder: IInstantiationServiceBuilder, extensionContext:
builder.define(ITelemetryService, new NullTelemetryService());
}

setupMSFTExperimentationService(builder, extensionContext);
setupMSFTExperimentationService(builder, extensionContext, envService);
}
7 changes: 3 additions & 4 deletions src/extension/extension/vscode/extension.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,8 @@

import * as l10n from '@vscode/l10n';
import { commands, env, ExtensionContext, ExtensionMode, l10n as vscodeL10n } from 'vscode';
import { isScenarioAutomation } from '../../../platform/env/common/envService';
import { isProduction } from '../../../platform/env/common/packagejson';
import { EnvServiceImpl } from '../../../platform/env/vscode/envServiceImpl';
import { IHeatmapService } from '../../../platform/heatmap/common/heatmapService';
import { IIgnoreService } from '../../../platform/ignore/common/ignoreService';
import { IExperimentationService } from '../../../platform/telemetry/common/nullExperimentationService';
Expand All @@ -33,9 +33,8 @@ export interface IExtensionActivationConfiguration {

export async function baseActivate(configuration: IExtensionActivationConfiguration) {
const context = configuration.context;
if (context.extensionMode === ExtensionMode.Test && !configuration.forceActivation && !isScenarioAutomation) {
// FIXME Running in tests, don't activate the extension
// Avoid bundling the extension code in the test bundle
const envService = new EnvServiceImpl(context);
if (envService.activateExtension(configuration.forceActivation)) {
return context;
}

Expand Down
10 changes: 5 additions & 5 deletions src/extension/extension/vscode/services.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/

import { ExtensionContext, ExtensionMode, l10n } from 'vscode';
import { ExtensionContext, l10n } from 'vscode';
import { IAuthenticationChatUpgradeService } from '../../../platform/authentication/common/authenticationUpgrade';
import { AuthenticationChatUpgradeService } from '../../../platform/authentication/common/authenticationUpgradeService';
import { CopilotTokenStore, ICopilotTokenStore } from '../../../platform/authentication/common/copilotTokenStore';
Expand Down Expand Up @@ -105,14 +105,14 @@ import { IToolGroupingCache, IToolGroupingService } from '../../tools/common/vir
// ##########################################################################

export function registerServices(builder: IInstantiationServiceBuilder, extensionContext: ExtensionContext): void {
const isTestMode = extensionContext.extensionMode === ExtensionMode.Test;
const envService = new EnvServiceImpl(extensionContext);

builder.define(IInteractionService, new SyncDescriptor(InteractionService));
builder.define(IAutomodeService, new SyncDescriptor(AutomodeService));
builder.define(ICopilotTokenStore, new CopilotTokenStore());
builder.define(IDebugOutputService, new DebugOutputServiceImpl());
builder.define(IDialogService, new DialogServiceImpl());
builder.define(IEnvService, new EnvServiceImpl());
builder.define(IEnvService, envService);
builder.define(IFileSystemService, new VSCodeFileSystemService());
builder.define(IHeaderContributors, new HeaderContributors());
builder.define(INotebookService, new SyncDescriptor(NotebookService));
Expand All @@ -123,8 +123,8 @@ export function registerServices(builder: IInstantiationServiceBuilder, extensio
builder.define(ITabsAndEditorsService, new TabsAndEditorsServiceImpl());
builder.define(ITerminalService, new SyncDescriptor(TerminalServiceImpl));
builder.define(ITestProvider, new SyncDescriptor(TestProvider));
builder.define(IUrlOpener, isTestMode ? new NullUrlOpener() : new RealUrlOpener());
builder.define(INotificationService, isTestMode ? new NullNotificationService() : new NotificationService());
builder.define(IUrlOpener, envService.useRealUrlOpener() ? new RealUrlOpener() : new NullUrlOpener());
builder.define(INotificationService, envService.showNotifications() ? new NotificationService() : new NullNotificationService());
builder.define(IVSCodeExtensionContext, <any>/*force _serviceBrand*/extensionContext);
builder.define(IWorkbenchService, new WorkbenchServiceImpl());
builder.define(IConversationOptions, {
Expand Down
6 changes: 2 additions & 4 deletions src/extension/inlineChat/vscode-node/inlineChatCommands.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,6 @@ import { TextDocumentSnapshot } from '../../../platform/editing/common/textDocum
import { ICAPIClientService } from '../../../platform/endpoint/common/capiClient';
import { IDomainService } from '../../../platform/endpoint/common/domainService';
import { IEnvService } from '../../../platform/env/common/envService';
import { IVSCodeExtensionContext } from '../../../platform/extContext/common/extensionContext';
import { IGitExtensionService } from '../../../platform/git/common/gitExtensionService';
import { IIgnoreService } from '../../../platform/ignore/common/ignoreService';
import { ILogService } from '../../../platform/log/common/logService';
Expand Down Expand Up @@ -56,9 +55,9 @@ export function registerInlineChatCommands(accessor: ServicesAccessor): IDisposa
const reviewService = accessor.get(IReviewService);
const logService = accessor.get(ILogService);
const telemetryService = accessor.get(ITelemetryService);
const extensionContext = accessor.get(IVSCodeExtensionContext);
const configurationService = accessor.get(IConfigurationService);
const parserService = accessor.get(IParserService);
const envService = accessor.get(IEnvService);

const disposables = new DisposableStore();
const doExplain = async (arg0: any, fromPalette?: true) => {
Expand Down Expand Up @@ -219,8 +218,7 @@ ${message}`,
sendReviewActionTelemetry(reviewComment, totalComments, 'unhelpful', logService, telemetryService, instaService);
}
};
const extensionMode = extensionContext.extensionMode;
if (typeof extensionMode === 'number' && extensionMode !== vscode.ExtensionMode.Test) {
if (envService.updateReviewContextValues()) {
reviewService.updateContextValues();
}
const goToNextReview = (currentThread: vscode.CommentThread | undefined, direction: number) => {
Expand Down
10 changes: 5 additions & 5 deletions src/extension/log/vscode-node/loggingActions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ import { IAuthenticationService } from '../../../platform/authentication/common/
import { ConfigKey, IConfigurationService } from '../../../platform/configuration/common/configurationService';
import { ICAPIClientService } from '../../../platform/endpoint/common/capiClient';
import { IDomainService } from '../../../platform/endpoint/common/domainService';
import { CAPIClientImpl } from '../../../platform/endpoint/node/capiClientImpl';
import { IEnvService } from '../../../platform/env/common/envService';
import { IVSCodeExtensionContext } from '../../../platform/extContext/common/extensionContext';
import { collectErrorMessages, ILogService } from '../../../platform/log/common/logService';
Expand All @@ -23,17 +24,16 @@ import { getRequest, IFetcher } from '../../../platform/networking/common/networ
import { NodeFetcher } from '../../../platform/networking/node/nodeFetcher';
import { NodeFetchFetcher } from '../../../platform/networking/node/nodeFetchFetcher';
import { ElectronFetcher } from '../../../platform/networking/vscode-node/electronFetcher';
import { FetcherService } from '../../../platform/networking/vscode-node/fetcherServiceImpl';
import { IExperimentationService } from '../../../platform/telemetry/common/nullExperimentationService';
import { ITelemetryService } from '../../../platform/telemetry/common/telemetry';
import { createRequestHMAC } from '../../../util/common/crypto';
import { shuffle } from '../../../util/vs/base/common/arrays';
import { timeout } from '../../../util/vs/base/common/async';
import { generateUuid } from '../../../util/vs/base/common/uuid';
import { SyncDescriptor } from '../../../util/vs/platform/instantiation/common/descriptors';
import { IInstantiationService, ServicesAccessor } from '../../../util/vs/platform/instantiation/common/instantiation';
import { ServiceCollection } from '../../../util/vs/platform/instantiation/common/serviceCollection';
import { SyncDescriptor } from '../../../util/vs/platform/instantiation/common/descriptors';
import { FetcherService } from '../../../platform/networking/vscode-node/fetcherServiceImpl';
import { CAPIClientImpl } from '../../../platform/endpoint/node/capiClientImpl';
import { shuffle } from '../../../util/vs/base/common/arrays';
import { EXTENSION_ID } from '../../common/constants';

export interface ProxyAgentLog {
Expand Down Expand Up @@ -362,7 +362,7 @@ export function collectFetcherTelemetry(accessor: ServicesAccessor, error: any):
const expService = accessor.get(IExperimentationService);
const capiClientService = accessor.get(ICAPIClientService);
const instantiationService = accessor.get(IInstantiationService);
if (extensionContext.extensionMode === vscode.ExtensionMode.Test) {
if (!envService.enableLoggingActions()) {
return;
}

Expand Down
39 changes: 34 additions & 5 deletions src/platform/env/common/envService.ts
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,15 @@ export interface IEnvService {
isProduction(): boolean;
isPreRelease(): boolean;
isSimulation(): boolean;
useRealUrlOpener(): boolean;
showNotifications(): boolean;
enableLanguageModels(): boolean;
useProductionTelemetry(): boolean;
useExperimentationService(): boolean;
useProductionTokenManager(): boolean;
useStaticGitHubAuthenticationService(): boolean;
updateReviewContextValues(): boolean;
enableLoggingActions(): boolean;
getBuildType(): 'prod' | 'dev';
getVersion(): string;
getBuild(): string;
Expand Down Expand Up @@ -91,6 +100,30 @@ export abstract class AbstractEnvService implements IEnvService {
return env['SIMULATION'] === '1';
}

isScenarioAutomation(): boolean {
return env['IS_SCENARIO_AUTOMATION'] === '1';
}

abstract useRealUrlOpener(): boolean;

abstract showNotifications(): boolean;

abstract enableLanguageModels(): boolean;

abstract useProductionTelemetry(): boolean;

abstract useExperimentationService(): boolean;

abstract useProductionTokenManager(): boolean;

abstract useStaticGitHubAuthenticationService(): boolean;

abstract updateReviewContextValues(): boolean;

abstract enableLoggingActions(): boolean;

abstract activateExtension(force: boolean): boolean;

getBuildType(): 'prod' | 'dev' {
return packageJson.buildType;
}
Expand Down Expand Up @@ -127,8 +160,4 @@ export abstract class AbstractEnvService implements IEnvService {
}

abstract openExternal(target: URI): Promise<boolean>;
}

// FIXME: This needs to be used in locations where the EnvService is not yet available, so it's
// not part of the env service itself.
export const isScenarioAutomation = env['IS_SCENARIO_AUTOMATION'] === '1';
}
44 changes: 44 additions & 0 deletions src/platform/env/common/nullEnvService.ts
Original file line number Diff line number Diff line change
Expand Up @@ -65,4 +65,48 @@ export class NullEnvService extends AbstractEnvService {
override openExternal(target: URI): Promise<boolean> {
return Promise.resolve(false);
}

override isScenarioAutomation(): boolean {
return false;
}

override activateExtension(force: boolean): boolean {
Copy link

Copilot AI Aug 18, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Parameter type inconsistency: the interface defines force as boolean | undefined but the implementation uses boolean. This should match the interface definition to maintain type safety.

Suggested change
override activateExtension(force: boolean): boolean {
override activateExtension(force: boolean | undefined): boolean {

Copilot uses AI. Check for mistakes.
return false;
}

override useRealUrlOpener(): boolean {
return false;
}

override showNotifications(): boolean {
return false;
}

override enableLanguageModels(): boolean {
return false;
}

override useProductionTelemetry(): boolean {
return false;
}

override useExperimentationService(): boolean {
return false;
}

override useProductionTokenManager(): boolean {
return false;
}

override useStaticGitHubAuthenticationService(): boolean {
return false;
}

override updateReviewContextValues(): boolean {
return false;
}

override enableLoggingActions(): boolean {
return false;
}
}
Loading
Loading