Skip to content

Commit 7a051d6

Browse files
authored
Merge pull request #563 from rajbos/feature/suppress-unknown-tool-names
Add per-tool suppression for unknown tool name notifications (#560)
2 parents 80f8996 + 6be3e81 commit 7a051d6

File tree

3 files changed

+42
-3
lines changed

3 files changed

+42
-3
lines changed

vscode-extension/package.json

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -275,6 +275,14 @@
275275
"type": "string",
276276
"default": "",
277277
"description": "Screenshot/demo mode: when set to a folder path, overrides all session file scanning and returns only .json/.jsonl files from this directory. Leave empty for normal operation."
278+
},
279+
"copilotTokenTracker.suppressedUnknownTools": {
280+
"type": "array",
281+
"items": {
282+
"type": "string"
283+
},
284+
"default": [],
285+
"description": "List of tool names to suppress from the 'Unknown Tools Found' section in the Usage Analysis dashboard. Useful for tools you are testing that don't yet have friendly display names."
278286
}
279287
}
280288
}

vscode-extension/src/extension.ts

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4169,6 +4169,19 @@ class CopilotTokenTracker implements vscode.Disposable {
41694169
vscode.commands.executeCommand('workbench.action.chat.open', { query: message.prompt, isNewChat: true })
41704170
);
41714171
break;
4172+
case 'suppressUnknownTool': {
4173+
const toolName = message.toolName as string;
4174+
if (toolName) {
4175+
const config = vscode.workspace.getConfiguration('copilotTokenTracker');
4176+
const current = config.get<string[]>('suppressedUnknownTools', []);
4177+
if (!current.includes(toolName)) {
4178+
await config.update('suppressedUnknownTools', [...current, toolName], vscode.ConfigurationTarget.Global);
4179+
this.log(`🔇 Suppressed unknown tool: ${toolName}`);
4180+
}
4181+
await this.dispatch('refresh:analysis', () => this.refreshAnalysisPanel());
4182+
}
4183+
break;
4184+
}
41724185
}
41734186
});
41744187

@@ -7411,6 +7424,10 @@ ${hashtag}`;
74117424
`[Usage Analysis] Test format 1234567.89: ${new Intl.NumberFormat(detectedLocale).format(1234567.89)}`,
74127425
);
74137426

7427+
const suppressedUnknownTools = vscode.workspace
7428+
.getConfiguration('copilotTokenTracker')
7429+
.get<string[]>('suppressedUnknownTools', []);
7430+
74147431
const initialData = JSON.stringify({
74157432
today: stats.today,
74167433
last30Days: stats.last30Days,
@@ -7421,6 +7438,7 @@ ${hashtag}`;
74217438
lastUpdated: stats.lastUpdated.toISOString(),
74227439
backendConfigured: this.isBackendConfigured(),
74237440
currentWorkspacePaths: vscode.workspace.workspaceFolders?.map(f => f.uri.fsPath) ?? [],
7441+
suppressedUnknownTools,
74247442
}).replace(/</g, "\\u003c");
74257443

74267444
return `<!DOCTYPE html>

vscode-extension/src/webview/usage/main.ts

Lines changed: 16 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,7 @@ type UsageAnalysisStats = {
4747
missedPotential?: MissedPotentialWorkspace[];
4848
backendConfigured?: boolean;
4949
currentWorkspacePaths?: string[];
50+
suppressedUnknownTools?: string[];
5051
};
5152

5253
declare function acquireVsCodeApi<TState = unknown>(): {
@@ -159,9 +160,11 @@ function getUnknownMcpTools(stats: UsageAnalysisStats): string[] {
159160
Object.entries(stats.today.toolCalls.byTool).forEach(([tool]) => allTools.add(tool));
160161
Object.entries(stats.last30Days.toolCalls.byTool).forEach(([tool]) => allTools.add(tool));
161162
Object.entries(stats.month.toolCalls.byTool).forEach(([tool]) => allTools.add(tool));
163+
164+
const suppressed = new Set<string>(stats.suppressedUnknownTools ?? []);
162165

163-
// Filter to only unknown tools (where lookupToolName returns the same value)
164-
return Array.from(allTools).filter(tool => lookupToolName(tool) === tool).sort();
166+
// Filter to only unknown tools (where lookupToolName returns the same value) and not suppressed
167+
return Array.from(allTools).filter(tool => lookupToolName(tool) === tool && !suppressed.has(tool)).sort();
165168
}
166169

167170
function createMcpToolIssueUrl(unknownTools: string[]): string {
@@ -948,7 +951,8 @@ function renderLayout(stats: UsageAnalysisStats): void {
948951
if (last30Count > todayCount) { countParts.push(`${last30Count} in the last 30d`); }
949952
if (monthCount > last30Count) { countParts.push(`${monthCount} this month`); }
950953
const countHtml = countParts.length > 0 ? `<span style="color:var(--text-muted);"> (${countParts.join(' | ')})</span>` : '';
951-
return `<span style="display:inline-flex; align-items:center; gap:4px; padding:2px 6px; background:var(--bg-primary); border:1px solid var(--border-color); border-radius:3px; font-family:monospace; font-size:11px;">${escapeHtml(tool)}${countHtml}</span>`;
954+
const suppressBtn = `<button data-suppress-tool="${escapeHtml(tool)}" title="Suppress this tool from the unknown list" style="background:none; border:none; cursor:pointer; padding:0 2px; color:var(--text-muted); font-size:11px; line-height:1;" aria-label="Suppress ${escapeHtml(tool)}">🔇</button>`;
955+
return `<span style="display:inline-flex; align-items:center; gap:4px; padding:2px 6px; background:var(--bg-primary); border:1px solid var(--border-color); border-radius:3px; font-family:monospace; font-size:11px;">${escapeHtml(tool)}${countHtml}${suppressBtn}</span>`;
952956
}).join(' ');
953957
return `
954958
<div id="unknown-mcp-tools-section" style="margin-bottom: 12px; padding: 10px; background: var(--bg-secondary); border: 1px solid var(--border-color); border-radius: 6px;">
@@ -1702,6 +1706,15 @@ async function bootstrap(): Promise<void> {
17021706
console.log('[Usage Analysis] Test format 1234567.89 with received locale:', new Intl.NumberFormat(initialData.locale).format(1234567.89));
17031707
setFormatLocale(initialData.locale);
17041708
renderLayout(initialData);
1709+
1710+
// Event delegation for suppress-tool buttons (rendered dynamically in the tools section)
1711+
document.addEventListener('click', (event) => {
1712+
const target = event.target as HTMLElement;
1713+
const toolName = target.getAttribute('data-suppress-tool');
1714+
if (toolName) {
1715+
vscode.postMessage({ command: 'suppressUnknownTool', toolName });
1716+
}
1717+
});
17051718
}
17061719

17071720
void bootstrap();

0 commit comments

Comments
 (0)