diff --git a/src/extension/tools/common/agentMemoryService.ts b/src/extension/tools/common/agentMemoryService.ts index 9fa68435e6..d3d740f219 100644 --- a/src/extension/tools/common/agentMemoryService.ts +++ b/src/extension/tools/common/agentMemoryService.ts @@ -104,6 +104,22 @@ export interface IAgentMemoryService { export const IAgentMemoryService = createServiceIdentifier('IAgentMemoryService'); +/** + * Returns true if the chat.copilotMemory.enabled config is enabled and editor preview features + * are allowed by organization policy. Defaults to false when the Copilot token is unavailable + * (conservative behavior when authentication hasn't completed yet). + */ +export function isCopilotMemoryConfigEnabled( + authenticationService: IAuthenticationService, + configurationService: IConfigurationService, + experimentationService: IExperimentationService +): boolean { + if (!authenticationService.copilotToken?.isEditorPreviewFeaturesEnabled()) { + return false; + } + return configurationService.getExperimentBasedConfig(ConfigKey.CopilotMemoryEnabled, experimentationService); +} + export class AgentMemoryService extends Disposable implements IAgentMemoryService { declare readonly _serviceBrand: undefined; @@ -153,9 +169,10 @@ export class AgentMemoryService extends Disposable implements IAgentMemoryServic /** * Check if the chat.copilotMemory.enabled config is enabled. * Uses experiment-based configuration for gradual rollout. + * Returns false if editor preview features are disabled by organization policy. */ private isCAPIMemorySyncConfigEnabled(): boolean { - return this.configService.getExperimentBasedConfig(ConfigKey.CopilotMemoryEnabled, this.experimentationService); + return isCopilotMemoryConfigEnabled(this.authenticationService, this.configService, this.experimentationService); } async checkMemoryEnabled(): Promise { diff --git a/src/extension/tools/node/memoryContextPrompt.tsx b/src/extension/tools/node/memoryContextPrompt.tsx index 3cc48df8dc..63d9f8da02 100644 --- a/src/extension/tools/node/memoryContextPrompt.tsx +++ b/src/extension/tools/node/memoryContextPrompt.tsx @@ -4,6 +4,7 @@ *--------------------------------------------------------------------------------------------*/ import { BasePromptElementProps, PromptElement, PromptElementProps, PromptSizing } from '@vscode/prompt-tsx'; +import { IAuthenticationService } from '../../../platform/authentication/common/authentication'; import { ConfigKey, IConfigurationService } from '../../../platform/configuration/common/configurationService'; import { IVSCodeExtensionContext } from '../../../platform/extContext/common/extensionContext'; import { IFileSystemService } from '../../../platform/filesystem/common/fileSystemService'; @@ -12,7 +13,7 @@ import { IExperimentationService } from '../../../platform/telemetry/common/null import { ITelemetryService } from '../../../platform/telemetry/common/telemetry'; import { URI } from '../../../util/vs/base/common/uri'; import { Tag } from '../../prompts/node/base/tag'; -import { IAgentMemoryService, normalizeCitations, RepoMemoryEntry } from '../common/agentMemoryService'; +import { IAgentMemoryService, isCopilotMemoryConfigEnabled, normalizeCitations, RepoMemoryEntry } from '../common/agentMemoryService'; import { ToolName } from '../common/toolNames'; import { extractSessionId } from './memoryTool'; @@ -27,6 +28,7 @@ export class MemoryContextPrompt extends PromptElement constructor( props: any, @IAgentMemoryService private readonly agentMemoryService: IAgentMemoryService, + @IAuthenticationService private readonly authenticationService: IAuthenticationService, @IConfigurationService private readonly configurationService: IConfigurationService, @IExperimentationService private readonly experimentationService: IExperimentationService, @IVSCodeExtensionContext private readonly extensionContext: IVSCodeExtensionContext, @@ -37,7 +39,7 @@ export class MemoryContextPrompt extends PromptElement } async render() { - const enableCopilotMemory = this.configurationService.getExperimentBasedConfig(ConfigKey.CopilotMemoryEnabled, this.experimentationService); + const enableCopilotMemory = isCopilotMemoryConfigEnabled(this.authenticationService, this.configurationService, this.experimentationService); const enableMemoryTool = this.configurationService.getExperimentBasedConfig(ConfigKey.MemoryToolEnabled, this.experimentationService); const userMemoryContent = enableMemoryTool ? await this.getUserMemoryContent() : undefined; @@ -250,6 +252,7 @@ export class MemoryContextPrompt extends PromptElement export class MemoryInstructionsPrompt extends PromptElement { constructor( props: PromptElementProps, + @IAuthenticationService private readonly authenticationService: IAuthenticationService, @IConfigurationService private readonly configurationService: IConfigurationService, @IExperimentationService private readonly experimentationService: IExperimentationService, ) { @@ -257,7 +260,7 @@ export class MemoryInstructionsPrompt extends PromptElement { @IMemoryCleanupService private readonly memoryCleanupService: IMemoryCleanupService, @IVSCodeExtensionContext private readonly extensionContext: IVSCodeExtensionContext, @ILogService private readonly logService: ILogService, + @IAuthenticationService private readonly authenticationService: IAuthenticationService, @IConfigurationService private readonly configurationService: IConfigurationService, @IExperimentationService private readonly experimentationService: IExperimentationService, @ITelemetryService private readonly telemetryService: ITelemetryService, @@ -542,7 +544,7 @@ export class MemoryTool implements ICopilotTool { } // List local repo memory files under repo/ (only when CAPI is not enabled) - const capiEnabled = this.configurationService.getExperimentBasedConfig(ConfigKey.CopilotMemoryEnabled, this.experimentationService); + const capiEnabled = isCopilotMemoryConfigEnabled(this.authenticationService, this.configurationService, this.experimentationService); if (!capiEnabled) { try { const repoUri = this._resolveUri('/memories/repo/', 'repo'); diff --git a/src/extension/tools/vscode-node/tools.ts b/src/extension/tools/vscode-node/tools.ts index 29b6b8eff7..46a8e44554 100644 --- a/src/extension/tools/vscode-node/tools.ts +++ b/src/extension/tools/vscode-node/tools.ts @@ -5,7 +5,8 @@ import * as vscode from 'vscode'; import { l10n } from 'vscode'; -import { ConfigKey, IConfigurationService } from '../../../platform/configuration/common/configurationService'; +import { IAuthenticationService } from '../../../platform/authentication/common/authentication'; +import { IConfigurationService } from '../../../platform/configuration/common/configurationService'; import { IVSCodeExtensionContext } from '../../../platform/extContext/common/extensionContext'; import { IFileSystemService } from '../../../platform/filesystem/common/fileSystemService'; import { FileType } from '../../../platform/filesystem/common/fileTypes'; @@ -13,6 +14,7 @@ import { IExperimentationService } from '../../../platform/telemetry/common/null import { Disposable, DisposableMap } from '../../../util/vs/base/common/lifecycle'; import { autorun, autorunIterableDelta } from '../../../util/vs/base/common/observableInternal'; import { URI } from '../../../util/vs/base/common/uri'; +import { isCopilotMemoryConfigEnabled } from '../common/agentMemoryService'; import { getContributedToolName } from '../common/toolNames'; import { isVscodeLanguageModelTool } from '../common/toolsRegistry'; import { IToolsService } from '../common/toolsService'; @@ -27,6 +29,7 @@ export class ToolsContribution extends Disposable { @IToolGroupingCache toolGrouping: IToolGroupingCache, @IToolGroupingService toolGroupingService: IToolGroupingService, @IVSCodeExtensionContext private readonly extensionContext: IVSCodeExtensionContext, + @IAuthenticationService private readonly authenticationService: IAuthenticationService, @IConfigurationService private readonly configurationService: IConfigurationService, @IExperimentationService private readonly experimentationService: IExperimentationService, @IFileSystemService private readonly fileSystemService: IFileSystemService, @@ -92,7 +95,7 @@ export class ToolsContribution extends Disposable { } // Collect local repo-scoped memories only when CAPI memory is disabled - const capiMemoryEnabled = this.configurationService.getExperimentBasedConfig(ConfigKey.CopilotMemoryEnabled, this.experimentationService); + const capiMemoryEnabled = isCopilotMemoryConfigEnabled(this.authenticationService, this.configurationService, this.experimentationService); if (storageUri && !capiMemoryEnabled) { const repoMemoryUri = URI.joinPath(storageUri, 'memory-tool/memories/repo'); try { diff --git a/test/base/extHostContext/simulationExtHostToolsService.ts b/test/base/extHostContext/simulationExtHostToolsService.ts index 0cd2eb1b96..2d18a53a1c 100644 --- a/test/base/extHostContext/simulationExtHostToolsService.ts +++ b/test/base/extHostContext/simulationExtHostToolsService.ts @@ -65,7 +65,7 @@ export class SimulationExtHostToolsService extends BaseToolsService implements I } private ensureToolsRegistered() { - this._lmToolRegistration ??= new ToolsContribution(this, {} as any, { threshold: observableValue(this, 128) } as any, {} as any, {} as any, {} as any, {} as any); + this._lmToolRegistration ??= new ToolsContribution(this, {} as any, { threshold: observableValue(this, 128) } as any, {} as any, {} as any, {} as any, {} as any, {} as any); } getCopilotTool(name: string): ICopilotTool | undefined {