Skip to content

Commit

Permalink
Add new agent setting and experiment (#239439)
Browse files Browse the repository at this point in the history
Add new agent setting and experiment (#239277)

* Contribute agent setting from vscode, with experiment to control visibility

* Check agent experiment when submitting request, too

* log

* Fix race in test

* Add separate context key mirroring the experiment, so the picker can be hidden even when the user set the setting
  • Loading branch information
roblourens authored Feb 2, 2025
1 parent d1e9445 commit e89638c
Show file tree
Hide file tree
Showing 4 changed files with 77 additions and 5 deletions.
64 changes: 62 additions & 2 deletions src/vs/workbench/contrib/chat/browser/chat.contribution.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,13 +13,13 @@ import { registerEditorFeature } from '../../../../editor/common/editorFeatures.
import * as nls from '../../../../nls.js';
import { AccessibleViewRegistry } from '../../../../platform/accessibility/browser/accessibleViewRegistry.js';
import { ICommandService } from '../../../../platform/commands/common/commands.js';
import { Extensions as ConfigurationExtensions, ConfigurationScope, IConfigurationRegistry } from '../../../../platform/configuration/common/configurationRegistry.js';
import { Extensions as ConfigurationExtensions, ConfigurationScope, IConfigurationNode, IConfigurationRegistry } from '../../../../platform/configuration/common/configurationRegistry.js';
import { SyncDescriptor } from '../../../../platform/instantiation/common/descriptors.js';
import { InstantiationType, registerSingleton } from '../../../../platform/instantiation/common/extensions.js';
import { IInstantiationService } from '../../../../platform/instantiation/common/instantiation.js';
import { Registry } from '../../../../platform/registry/common/platform.js';
import { EditorPaneDescriptor, IEditorPaneRegistry } from '../../../browser/editor.js';
import { WorkbenchPhase, registerWorkbenchContribution2 } from '../../../common/contributions.js';
import { IWorkbenchContribution, WorkbenchPhase, registerWorkbenchContribution2 } from '../../../common/contributions.js';
import { EditorExtensions, IEditorFactoryRegistry } from '../../../common/editor.js';
import { IEditorResolverService, RegisteredEditorPriority } from '../../../services/editor/common/editorResolverService.js';
import { ChatAgentLocation, ChatAgentNameService, ChatAgentService, IChatAgentNameService, IChatAgentService } from '../common/chatAgents.js';
Expand Down Expand Up @@ -84,6 +84,10 @@ import { ChatEditorOverlayController } from './chatEditorOverlay.js';
import '../common/promptSyntax/languageFeatures/promptLinkProvider.js';
import { PromptFilesConfig } from '../common/promptSyntax/config.js';
import { BuiltinToolsContribution } from '../common/tools/tools.js';
import { IWorkbenchAssignmentService } from '../../../services/assignment/common/assignmentService.js';
import { IProductService } from '../../../../platform/product/common/productService.js';
import { IContextKeyService } from '../../../../platform/contextkey/common/contextkey.js';
import { ChatContextKeys } from '../common/chatContextKeys.js';

// Register configuration
const configurationRegistry = Registry.as<IConfigurationRegistry>(ConfigurationExtensions.Configuration);
Expand Down Expand Up @@ -212,6 +216,61 @@ class ChatResolverContribution extends Disposable {
}
}

class ChatAgentSettingContribution implements IWorkbenchContribution {

static readonly ID = 'workbench.contrib.chatAgentSetting';

private registeredNode: IConfigurationNode | undefined;

constructor(
@IWorkbenchAssignmentService experimentService: IWorkbenchAssignmentService,
@IProductService private readonly productService: IProductService,
@IContextKeyService contextKeyService: IContextKeyService,
) {
if (this.productService.quality !== 'stable') {
this.registerSetting();
}

const expDisabledKey = ChatContextKeys.Editing.agentModeDisallowed.bindTo(contextKeyService);
experimentService.getTreatment<boolean>('chatAgentEnabled').then(value => {
if (value) {
this.registerSetting();
} else if (value === false) {
this.deregisterSetting();
expDisabledKey.set(true);
}
});
}

private registerSetting() {
if (this.registeredNode) {
return;
}

this.registeredNode = {
id: 'chatAgent',
title: nls.localize('interactiveSessionConfigurationTitle', "Chat"),
type: 'object',
properties: {
'chat.agent.enabled': {
type: 'boolean',
description: nls.localize('chat.agent.enabled.description', "Enable agent mode for {0}. When this is enabled, a dropdown appears in the {0} view to toggle agent mode.", 'Copilot Edits'),
default: this.productService.quality !== 'stable',
tags: ['experimental', 'onExp'],
},
}
};
configurationRegistry.registerConfiguration(this.registeredNode);
}

private deregisterSetting() {
if (this.registeredNode) {
configurationRegistry.deregisterConfigurations([this.registeredNode]);
this.registeredNode = undefined;
}
}
}

AccessibleViewRegistry.register(new ChatResponseAccessibleView());
AccessibleViewRegistry.register(new PanelChatAccessibilityHelp());
AccessibleViewRegistry.register(new QuickChatAccessibilityHelp());
Expand Down Expand Up @@ -329,6 +388,7 @@ registerWorkbenchContribution2(ChatGettingStartedContribution.ID, ChatGettingSta
registerWorkbenchContribution2(ChatSetupContribution.ID, ChatSetupContribution, WorkbenchPhase.BlockRestore);
registerWorkbenchContribution2(ChatQuotasStatusBarEntry.ID, ChatQuotasStatusBarEntry, WorkbenchPhase.Eventually);
registerWorkbenchContribution2(BuiltinToolsContribution.ID, BuiltinToolsContribution, WorkbenchPhase.Eventually);
registerWorkbenchContribution2(ChatAgentSettingContribution.ID, ChatAgentSettingContribution, WorkbenchPhase.BlockRestore);

registerChatActions();
registerChatCopyActions();
Expand Down
1 change: 1 addition & 0 deletions src/vs/workbench/contrib/chat/common/chatContextKeys.ts
Original file line number Diff line number Diff line change
Expand Up @@ -83,5 +83,6 @@ export namespace ChatContextKeys {
export const Editing = {
hasToolsAgent: new RawContextKey<boolean>('chatHasToolsAgent', false, { type: 'boolean', description: localize('chatEditingHasToolsAgent', "True when a tools agent is registered.") }),
agentMode: new RawContextKey<boolean>('chatAgentMode', false, { type: 'boolean', description: localize('chatEditingAgentMode', "True when edits is in agent mode.") }),
agentModeDisallowed: new RawContextKey<boolean>('chatAgentModeDisallowed', false, { type: 'boolean', description: localize('chatAgentModeDisallowed', "True when agent mode is not allowed.") }), // experiment-driven disablement
};
}
14 changes: 13 additions & 1 deletion src/vs/workbench/contrib/chat/common/chatServiceImpl.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ import { Progress } from '../../../../platform/progress/common/progress.js';
import { IStorageService, StorageScope, StorageTarget } from '../../../../platform/storage/common/storage.js';
import { ITelemetryService } from '../../../../platform/telemetry/common/telemetry.js';
import { IWorkspaceContextService } from '../../../../platform/workspace/common/workspace.js';
import { IWorkbenchAssignmentService } from '../../../services/assignment/common/assignmentService.js';
import { IExtensionService } from '../../../services/extensions/common/extensions.js';
import { ChatAgentLocation, IChatAgent, IChatAgentCommand, IChatAgentData, IChatAgentHistoryEntry, IChatAgentRequest, IChatAgentResult, IChatAgentService } from './chatAgents.js';
import { ChatModel, ChatRequestModel, ChatRequestRemovalReason, IChatModel, IChatRequestModel, IChatRequestVariableData, IChatResponseModel, IExportableChatData, ISerializableChatData, ISerializableChatDataIn, ISerializableChatsData, normalizeSerializableChatData, toChatHistoryContent, updateRanges } from './chatModel.js';
Expand Down Expand Up @@ -138,7 +139,8 @@ export class ChatService extends Disposable implements IChatService {
@IChatSlashCommandService private readonly chatSlashCommandService: IChatSlashCommandService,
@IChatVariablesService private readonly chatVariablesService: IChatVariablesService,
@IChatAgentService private readonly chatAgentService: IChatAgentService,
@IConfigurationService private readonly configurationService: IConfigurationService
@IConfigurationService private readonly configurationService: IConfigurationService,
@IWorkbenchAssignmentService private readonly experimentService: IWorkbenchAssignmentService,
) {
super();

Expand Down Expand Up @@ -687,6 +689,7 @@ export class ChatService extends Disposable implements IChatService {
const agent = (detectedAgent ?? agentPart?.agent ?? defaultAgent)!;
const command = detectedCommand ?? agentSlashCommandPart?.command;
await this.extensionService.activateByEvent(`onChatParticipant:${agent.id}`);
await this.checkAgentAllowed(agent);

// Recompute history in case the agent or command changed
const history = this.getHistoryEntriesFromModel(requests, model.sessionId, location, agent.id);
Expand Down Expand Up @@ -811,6 +814,15 @@ export class ChatService extends Disposable implements IChatService {
};
}

private async checkAgentAllowed(agent: IChatAgentData): Promise<void> {
if (agent.isToolsAgent) {
const enabled = await this.experimentService.getTreatment<boolean>('chatAgentEnabled');
if (enabled === false) {
throw new Error('Agent is currently disabled');
}
}
}

private attachmentKindsForTelemetry(variableData: IChatRequestVariableData): string[] {
// TODO this shows why attachments still have to be cleaned up somewhat
return variableData.variables.map(v => {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -841,8 +841,7 @@ suite('InlineChatController', function () {
const newSession = await inlineChatSessionService.createSession(editor, {}, CancellationToken.None);
assertType(newSession);

await chatService.sendRequest(newSession.chatModel.sessionId, 'Existing', { location: ChatAgentLocation.Editor });

await (await chatService.sendRequest(newSession.chatModel.sessionId, 'Existing', { location: ChatAgentLocation.Editor }))?.responseCreatedPromise;

assert.strictEqual(newSession.chatModel.requestInProgress, true);

Expand Down

0 comments on commit e89638c

Please sign in to comment.