Skip to content

Commit 6e326e9

Browse files
authored
Remove confusing GitHub repository tip from chat tips (microsoft#295177)
1 parent 1e6c729 commit 6e326e9

2 files changed

Lines changed: 3 additions & 150 deletions

File tree

src/vs/workbench/contrib/chat/browser/chatTipService.ts

Lines changed: 2 additions & 81 deletions
Original file line numberDiff line numberDiff line change
@@ -106,18 +106,6 @@ export interface ITipDefinition {
106106
* The tip won't be shown if the tool it describes has already been used.
107107
*/
108108
readonly excludeWhenToolsInvoked?: string[];
109-
/**
110-
* Tool set reference names. If any tool belonging to one of these tool sets
111-
* has ever been invoked in this workspace, the tip becomes ineligible.
112-
* Unlike {@link excludeWhenToolsInvoked}, this does not require listing
113-
* individual tool IDs, it checks all tools that belong to the named sets.
114-
*/
115-
readonly excludeWhenAnyToolSetToolInvoked?: string[];
116-
/**
117-
* Tool set reference names where at least one must be registered for the tip to be eligible.
118-
* If none of the listed tool sets are registered, the tip is not shown.
119-
*/
120-
readonly requiresAnyToolSetRegistered?: string[];
121109
/**
122110
* If set, exclude this tip when prompt files of the specified type exist in the workspace.
123111
*/
@@ -210,16 +198,6 @@ const TIP_CATALOG: ITipDefinition[] = [
210198
when: ChatContextKeys.chatModeKind.isEqualTo(ChatModeKind.Agent),
211199
excludeWhenToolsInvoked: ['renderMermaidDiagram'],
212200
},
213-
{
214-
id: 'tip.githubRepo',
215-
message: localize('tip.githubRepo', "Tip: Mention a GitHub repository (@owner/repo) in your prompt to let the agent search code, browse issues, and explore pull requests from that repo."),
216-
when: ContextKeyExpr.and(
217-
ChatContextKeys.chatModeKind.isEqualTo(ChatModeKind.Agent),
218-
ContextKeyExpr.notEquals('gitOpenRepositoryCount', '0'),
219-
),
220-
excludeWhenAnyToolSetToolInvoked: ['github', 'github-pull-request'],
221-
requiresAnyToolSetRegistered: ['github', 'github-pull-request'],
222-
},
223201
{
224202
id: 'tip.subagents',
225203
message: localize('tip.subagents', "Tip: Ask the agent to work in parallel to complete large tasks faster."),
@@ -265,9 +243,6 @@ export class TipEligibilityTracker extends Disposable {
265243
private readonly _pendingModes: Set<string>;
266244
private readonly _pendingTools: Set<string>;
267245

268-
/** Tool set reference names monitored via {@link ITipDefinition.excludeWhenAnyToolSetToolInvoked}. */
269-
private readonly _monitoredToolSets: Set<string>;
270-
271246
private readonly _commandListener = this._register(new MutableDisposable());
272247
private readonly _toolListener = this._register(new MutableDisposable());
273248

@@ -333,13 +308,6 @@ export class TipEligibilityTracker extends Disposable {
333308
}
334309
}
335310

336-
this._monitoredToolSets = new Set<string>();
337-
for (const tip of tips) {
338-
for (const name of tip.excludeWhenAnyToolSetToolInvoked ?? []) {
339-
this._monitoredToolSets.add(name);
340-
}
341-
}
342-
343311
// --- Set up command listener (auto-disposes when all seen) --------------
344312

345313
if (this._pendingCommands.size > 0) {
@@ -358,44 +326,17 @@ export class TipEligibilityTracker extends Disposable {
358326

359327
// --- Set up tool listener (auto-disposes when all seen) -----------------
360328

361-
if (this._pendingTools.size > 0 || this._monitoredToolSets.size > 0) {
329+
if (this._pendingTools.size > 0) {
362330
this._toolListener.value = this._languageModelToolsService.onDidInvokeTool(e => {
363-
let changed = false;
364-
365331
// Track explicit tool IDs
366332
if (this._pendingTools.has(e.toolId)) {
367333
this._invokedTools.add(e.toolId);
368334
this._pendingTools.delete(e.toolId);
369-
changed = true;
370-
}
371-
372-
// Track tools belonging to monitored tool sets
373-
if (this._monitoredToolSets.size > 0 && !this._invokedTools.has(e.toolId)) {
374-
for (const setName of this._monitoredToolSets) {
375-
const toolSet = this._languageModelToolsService.getToolSetByName(setName);
376-
if (toolSet) {
377-
for (const tool of toolSet.getTools()) {
378-
if (tool.id === e.toolId) {
379-
this._invokedTools.add(e.toolId);
380-
// Remove set name from monitoring since ANY tool from the set excludes the tip.
381-
// The tip remains excluded via _invokedTools even after we stop monitoring.
382-
this._monitoredToolSets.delete(setName);
383-
changed = true;
384-
break;
385-
}
386-
}
387-
}
388-
if (changed) {
389-
break;
390-
}
391-
}
392-
}
393335

394-
if (changed) {
395336
this._persistSet(TipEligibilityTracker._TOOLS_STORAGE_KEY, this._invokedTools);
396337
}
397338

398-
if (this._pendingTools.size === 0 && this._monitoredToolSets.size === 0) {
339+
if (this._pendingTools.size === 0) {
399340
this._toolListener.clear();
400341
}
401342
});
@@ -477,30 +418,10 @@ export class TipEligibilityTracker extends Disposable {
477418
}
478419
}
479420
}
480-
if (tip.excludeWhenAnyToolSetToolInvoked) {
481-
for (const setName of tip.excludeWhenAnyToolSetToolInvoked) {
482-
const toolSet = this._languageModelToolsService.getToolSetByName(setName);
483-
if (toolSet) {
484-
for (const tool of toolSet.getTools()) {
485-
if (this._invokedTools.has(tool.id)) {
486-
this._logService.debug('#ChatTips: tip excluded because tool set tool was invoked', tip.id, setName, tool.id);
487-
return true;
488-
}
489-
}
490-
}
491-
}
492-
}
493421
if (tip.excludeWhenPromptFilesExist && this._excludedByFiles.has(tip.id)) {
494422
this._logService.debug('#ChatTips: tip excluded because prompt files exist', tip.id);
495423
return true;
496424
}
497-
if (tip.requiresAnyToolSetRegistered) {
498-
const hasAny = tip.requiresAnyToolSetRegistered.some(name => this._languageModelToolsService.getToolSetByName(name));
499-
if (!hasAny) {
500-
this._logService.debug('#ChatTips: tip excluded because no required tool sets are registered', tip.id);
501-
return true;
502-
}
503-
}
504425
return false;
505426
}
506427

src/vs/workbench/contrib/chat/test/browser/chatTipService.test.ts

Lines changed: 1 addition & 69 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ import { URI } from '../../../../../base/common/uri.js';
2121
import { ChatContextKeys } from '../../common/actions/chatContextKeys.js';
2222
import { ChatAgentLocation, ChatModeKind } from '../../common/constants.js';
2323
import { PromptsType } from '../../common/promptSyntax/promptTypes.js';
24-
import { ILanguageModelToolsService, IToolData, ToolDataSource } from '../../common/tools/languageModelToolsService.js';
24+
import { ILanguageModelToolsService } from '../../common/tools/languageModelToolsService.js';
2525
import { MockLanguageModelToolsService } from '../common/tools/mockLanguageModelToolsService.js';
2626

2727
class MockContextKeyServiceWithRulesMatching extends MockContextKeyService {
@@ -635,74 +635,6 @@ suite('ChatTipService', () => {
635635
assert.strictEqual(tracker.isExcluded(tip), false, 'Should not be excluded when no skill files exist');
636636
});
637637

638-
test('excludes tip when requiresAnyToolSetRegistered tool sets are not registered', () => {
639-
const tip: ITipDefinition = {
640-
id: 'tip.githubRepo',
641-
message: 'test',
642-
requiresAnyToolSetRegistered: ['github', 'github-pull-request'],
643-
};
644-
645-
const tracker = testDisposables.add(new TipEligibilityTracker(
646-
[tip],
647-
{ onDidExecuteCommand: Event.None, onWillExecuteCommand: Event.None } as Partial<ICommandService> as ICommandService,
648-
storageService,
649-
createMockPromptsService() as IPromptsService,
650-
createMockToolsService(),
651-
new NullLogService(),
652-
));
653-
654-
assert.strictEqual(tracker.isExcluded(tip), true, 'Should be excluded when no required tool sets are registered');
655-
});
656-
657-
test('excludes tip when a tool belonging to a monitored tool set has been invoked', () => {
658-
const mockToolsService = createMockToolsService();
659-
const toolInSet: IToolData = { id: 'mcp_github_get_me', source: ToolDataSource.Internal, displayName: 'Get Me', modelDescription: 'Get Me' };
660-
mockToolsService.addRegisteredToolSetName('github', [toolInSet]);
661-
662-
const tip: ITipDefinition = {
663-
id: 'tip.githubRepo',
664-
message: 'test',
665-
excludeWhenAnyToolSetToolInvoked: ['github'],
666-
};
667-
668-
const tracker = testDisposables.add(new TipEligibilityTracker(
669-
[tip],
670-
{ onDidExecuteCommand: Event.None, onWillExecuteCommand: Event.None } as Partial<ICommandService> as ICommandService,
671-
storageService,
672-
createMockPromptsService() as IPromptsService,
673-
mockToolsService,
674-
new NullLogService(),
675-
));
676-
677-
assert.strictEqual(tracker.isExcluded(tip), false, 'Should not be excluded before any tool set tool is invoked');
678-
679-
mockToolsService.fireOnDidInvokeTool({ toolId: 'mcp_github_get_me', sessionResource: undefined, requestId: undefined, subagentInvocationId: undefined });
680-
681-
assert.strictEqual(tracker.isExcluded(tip), true, 'Should be excluded after a tool from the monitored tool set is invoked');
682-
});
683-
684-
test('does not exclude tip when at least one requiresAnyToolSetRegistered tool set is registered', () => {
685-
const mockToolsService = createMockToolsService();
686-
mockToolsService.addRegisteredToolSetName('github');
687-
688-
const tip: ITipDefinition = {
689-
id: 'tip.githubRepo',
690-
message: 'test',
691-
requiresAnyToolSetRegistered: ['github', 'github-pull-request'],
692-
};
693-
694-
const tracker = testDisposables.add(new TipEligibilityTracker(
695-
[tip],
696-
{ onDidExecuteCommand: Event.None, onWillExecuteCommand: Event.None } as Partial<ICommandService> as ICommandService,
697-
storageService,
698-
createMockPromptsService() as IPromptsService,
699-
mockToolsService,
700-
new NullLogService(),
701-
));
702-
703-
assert.strictEqual(tracker.isExcluded(tip), false, 'Should not be excluded when at least one required tool set is registered');
704-
});
705-
706638
test('re-checks agent file exclusion when onDidChangeCustomAgents fires', async () => {
707639
const agentChangeEmitter = testDisposables.add(new Emitter<void>());
708640
let agentFiles: IPromptPath[] = [];

0 commit comments

Comments
 (0)