mirror of
https://github.com/microsoft/vscode.git
synced 2026-02-04 01:44:44 -06:00
candidate: Restrict set of tools when agent mode setting is disabled (#282871)
* Restrict set of tools when agent mode setting is disabled (#282623) * restrict set of tools when agent mode setting is disabled (https://github.com/microsoft/vscode-internalbacklog/issues/6432) * include read/search/web * tweaks to #282623 (#282889) * update chat.agent.enabled description * code suggestions * includeDisabled bug
This commit is contained in:
parent
a1e5f6c336
commit
b791a56d01
@ -163,7 +163,7 @@
|
||||
"localization": {
|
||||
"description": {
|
||||
"key": "chat.agent.enabled.description",
|
||||
"value": "Enable agent mode for chat. When this is enabled, agent mode can be activated via the dropdown in the view."
|
||||
"value": "When enabled, agent mode can be activated from chat and tools in agentic contexts with side effects can be used."
|
||||
}
|
||||
},
|
||||
"type": "boolean",
|
||||
|
||||
@ -538,7 +538,7 @@ configurationRegistry.registerConfiguration({
|
||||
},
|
||||
[ChatConfiguration.AgentEnabled]: {
|
||||
type: 'boolean',
|
||||
description: nls.localize('chat.agent.enabled.description', "Enable agent mode for chat. When this is enabled, agent mode can be activated via the dropdown in the view."),
|
||||
description: nls.localize('chat.agent.enabled.description', "When enabled, agent mode can be activated from chat and tools in agentic contexts with side effects can be used."),
|
||||
default: true,
|
||||
policy: {
|
||||
name: 'ChatAgentMode',
|
||||
@ -548,7 +548,7 @@ configurationRegistry.registerConfiguration({
|
||||
localization: {
|
||||
description: {
|
||||
key: 'chat.agent.enabled.description',
|
||||
value: nls.localize('chat.agent.enabled.description', "Enable agent mode for chat. When this is enabled, agent mode can be activated via the dropdown in the view."),
|
||||
value: nls.localize('chat.agent.enabled.description', "When enabled, agent mode can be activated from chat and tools in agentic contexts with side effects can be used."),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -16,7 +16,7 @@ import { Emitter, Event } from '../../../../base/common/event.js';
|
||||
import { createMarkdownCommandLink, MarkdownString } from '../../../../base/common/htmlContent.js';
|
||||
import { Iterable } from '../../../../base/common/iterator.js';
|
||||
import { combinedDisposable, Disposable, DisposableStore, IDisposable, toDisposable } from '../../../../base/common/lifecycle.js';
|
||||
import { derived, IObservable, observableFromEventOpts, ObservableSet } from '../../../../base/common/observable.js';
|
||||
import { derived, IObservable, IReader, observableFromEventOpts, ObservableSet } from '../../../../base/common/observable.js';
|
||||
import Severity from '../../../../base/common/severity.js';
|
||||
import { StopWatch } from '../../../../base/common/stopwatch.js';
|
||||
import { ThemeIcon } from '../../../../base/common/themables.js';
|
||||
@ -29,6 +29,7 @@ import { IDialogService } from '../../../../platform/dialogs/common/dialogs.js';
|
||||
import { IInstantiationService } from '../../../../platform/instantiation/common/instantiation.js';
|
||||
import * as JSONContributionRegistry from '../../../../platform/jsonschemas/common/jsonContributionRegistry.js';
|
||||
import { ILogService } from '../../../../platform/log/common/log.js';
|
||||
import { observableConfigValue } from '../../../../platform/observable/common/platformObservableUtils.js';
|
||||
import { Registry } from '../../../../platform/registry/common/platform.js';
|
||||
import { IStorageService, StorageScope, StorageTarget } from '../../../../platform/storage/common/storage.js';
|
||||
import { ITelemetryService } from '../../../../platform/telemetry/common/telemetry.js';
|
||||
@ -93,6 +94,8 @@ export class LanguageModelToolsService extends Disposable implements ILanguageMo
|
||||
|
||||
private readonly _callsByRequestId = new Map<string, ITrackedCall[]>();
|
||||
|
||||
private readonly _isAgentModeEnabled: IObservable<boolean>;
|
||||
|
||||
constructor(
|
||||
@IInstantiationService private readonly _instantiationService: IInstantiationService,
|
||||
@IExtensionService private readonly _extensionService: IExtensionService,
|
||||
@ -109,6 +112,8 @@ export class LanguageModelToolsService extends Disposable implements ILanguageMo
|
||||
) {
|
||||
super();
|
||||
|
||||
this._isAgentModeEnabled = observableConfigValue(ChatConfiguration.AgentEnabled, true, this._configurationService);
|
||||
|
||||
this._register(this._contextKeyService.onDidChangeContext(e => {
|
||||
if (e.affectsSome(this._toolContextKeys)) {
|
||||
// Not worth it to compute a delta here unless we have many tools changing often
|
||||
@ -117,7 +122,7 @@ export class LanguageModelToolsService extends Disposable implements ILanguageMo
|
||||
}));
|
||||
|
||||
this._register(this._configurationService.onDidChangeConfiguration(e => {
|
||||
if (e.affectsConfiguration(ChatConfiguration.ExtensionToolsEnabled)) {
|
||||
if (e.affectsConfiguration(ChatConfiguration.ExtensionToolsEnabled) || e.affectsConfiguration(ChatConfiguration.AgentEnabled)) {
|
||||
this._onDidChangeToolsScheduler.schedule();
|
||||
}
|
||||
}));
|
||||
@ -166,6 +171,27 @@ export class LanguageModelToolsService extends Disposable implements ILanguageMo
|
||||
}
|
||||
));
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns if the given tool or toolset is permitted in the current context.
|
||||
* When agent mode is enabled, all tools are permitted (no restriction)
|
||||
* When agent mode is disabled only a subset of read-only tools are permitted in agentic-loop contexts.
|
||||
*/
|
||||
private isPermitted(toolOrToolSet: IToolData | ToolSet, reader?: IReader): boolean {
|
||||
const agentModeEnabled = this._isAgentModeEnabled.read(reader);
|
||||
if (agentModeEnabled !== false) {
|
||||
return true;
|
||||
}
|
||||
const permittedInternalToolSetIds = [SpecedToolAliases.read, SpecedToolAliases.search, SpecedToolAliases.web];
|
||||
if (toolOrToolSet instanceof ToolSet) {
|
||||
const permitted = toolOrToolSet.source.type === 'internal' && permittedInternalToolSetIds.includes(toolOrToolSet.referenceName);
|
||||
this._logService.trace(`LanguageModelToolsService#isPermitted: ToolSet ${toolOrToolSet.id} (${toolOrToolSet.referenceName}) permitted=${permitted}`);
|
||||
return permitted;
|
||||
}
|
||||
this._logService.trace(`LanguageModelToolsService#isPermitted: Tool ${toolOrToolSet.id} (${toolOrToolSet.toolReferenceName}) permitted=false`);
|
||||
return false;
|
||||
}
|
||||
|
||||
override dispose(): void {
|
||||
super.dispose();
|
||||
|
||||
@ -243,7 +269,8 @@ export class LanguageModelToolsService extends Disposable implements ILanguageMo
|
||||
toolData => {
|
||||
const satisfiesWhenClause = includeDisabled || !toolData.when || this._contextKeyService.contextMatchesRules(toolData.when);
|
||||
const satisfiesExternalToolCheck = toolData.source.type !== 'extension' || !!extensionToolsEnabled;
|
||||
return satisfiesWhenClause && satisfiesExternalToolCheck;
|
||||
const satisfiesPermittedCheck = includeDisabled || this.isPermitted(toolData);
|
||||
return satisfiesWhenClause && satisfiesExternalToolCheck && satisfiesPermittedCheck;
|
||||
});
|
||||
}
|
||||
|
||||
@ -853,7 +880,10 @@ export class LanguageModelToolsService extends Disposable implements ILanguageMo
|
||||
|
||||
private readonly _toolSets = new ObservableSet<ToolSet>();
|
||||
|
||||
readonly toolSets: IObservable<Iterable<ToolSet>> = this._toolSets.observable;
|
||||
readonly toolSets: IObservable<Iterable<ToolSet>> = derived(this, reader => {
|
||||
const allToolSets = Array.from(this._toolSets.observable.read(reader));
|
||||
return allToolSets.filter(toolSet => this.isPermitted(toolSet, reader));
|
||||
});
|
||||
|
||||
getToolSet(id: string): ToolSet | undefined {
|
||||
for (const toolSet of this._toolSets) {
|
||||
@ -916,7 +946,7 @@ export class LanguageModelToolsService extends Disposable implements ILanguageMo
|
||||
}
|
||||
}
|
||||
for (const tool of this.toolsObservable.read(reader)) {
|
||||
if (tool.canBeReferencedInPrompt && !coveredByToolSets.has(tool)) {
|
||||
if (tool.canBeReferencedInPrompt && !coveredByToolSets.has(tool) && this.isPermitted(tool, reader)) {
|
||||
result.push([tool, getToolFullReferenceName(tool)]);
|
||||
}
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user