mirror of
https://github.com/microsoft/vscode.git
synced 2026-04-02 08:15:56 +01:00
fix: correct terminal sandbox icon in thinking dropdown (#304327)
When sandbox is enabled, the tool-level icon was set to terminalSecure (lock) at registration time, which leaked into every rendering path during streaming before we knew if a specific command was actually sandboxed. This caused unsandboxed commands (requestUnsandboxedExecution=true) to show the lock icon. Fix: - Set toolData.icon to always be Codicon.terminal (no lock). The per-command isSandboxWrapped flag in toolSpecificData is the authoritative source. - In the existing autorun in trackToolMetadata, update the icon element when the tool transitions out of streaming and toolSpecificData becomes available. - Store icon elements in toolIconsByCallId map for direct access. Fixes #303505
This commit is contained in:
@@ -7,7 +7,7 @@ import { $, clearNode, getWindow, hide, scheduleAtNextAnimationFrame } from '../
|
||||
import { alert } from '../../../../../../base/browser/ui/aria/aria.js';
|
||||
import { DomScrollableElement } from '../../../../../../base/browser/ui/scrollbar/scrollableElement.js';
|
||||
import { ScrollbarVisibility } from '../../../../../../base/common/scrollable.js';
|
||||
import { IChatMarkdownContent, IChatThinkingPart, IChatToolInvocation, IChatToolInvocationSerialized } from '../../../common/chatService/chatService.js';
|
||||
import { IChatMarkdownContent, IChatTerminalToolInvocationData, IChatThinkingPart, IChatToolInvocation, IChatToolInvocationSerialized } from '../../../common/chatService/chatService.js';
|
||||
import { IChatContentPartRenderContext, IChatContentPart } from './chatContentParts.js';
|
||||
import { IChatRendererContent } from '../../../common/model/chatViewModel.js';
|
||||
import { ChatConfiguration, ThinkingDisplayMode } from '../../../common/constants.js';
|
||||
@@ -228,6 +228,7 @@ export class ChatThinkingContentPart extends ChatCollapsibleContentPart implemen
|
||||
private workingSpinnerLabel: HTMLElement | undefined;
|
||||
private availableMessagesByCategory = new Map<WorkingMessageCategory, string[]>();
|
||||
private readonly toolWrappersByCallId = new Map<string, HTMLElement>();
|
||||
private readonly toolIconsByCallId = new Map<string, HTMLElement>();
|
||||
private readonly toolLabelsByCallId = new Map<string, string>();
|
||||
private readonly toolDisposables = this._register(new DisposableMap<string, DisposableStore>());
|
||||
private readonly ownedToolParts = new Map<string, IDisposable>();
|
||||
@@ -1224,6 +1225,7 @@ ${this.hookCount > 0 ? `EXAMPLES WITH BLOCKED CONTENT (from hooks):
|
||||
const wrapper = this.toolWrappersByCallId.get(toolCallId);
|
||||
if (wrapper) {
|
||||
this.toolWrappersByCallId.delete(toolCallId);
|
||||
this.toolIconsByCallId.delete(toolCallId);
|
||||
}
|
||||
|
||||
this.appendedItemCount = Math.max(0, this.appendedItemCount - 1);
|
||||
@@ -1342,6 +1344,7 @@ ${this.hookCount > 0 ? `EXAMPLES WITH BLOCKED CONTENT (from hooks):
|
||||
if (wrapper) {
|
||||
wrapper.remove();
|
||||
this.toolWrappersByCallId.delete(toolCallId);
|
||||
this.toolIconsByCallId.delete(toolCallId);
|
||||
}
|
||||
|
||||
// make sure to remove any lazy item as well
|
||||
@@ -1470,6 +1473,18 @@ ${this.hookCount > 0 ? `EXAMPLES WITH BLOCKED CONTENT (from hooks):
|
||||
// queue item to be removed if it was streaming and presentation is hidden
|
||||
if (isStreaming && currentState.type !== IChatToolInvocation.StateKind.Streaming) {
|
||||
isStreaming = false;
|
||||
|
||||
// Update terminal tool icon based on sandbox wrapping state
|
||||
const termData = toolInvocationOrMarkdown.toolSpecificData as IChatTerminalToolInvocationData | undefined;
|
||||
if (termData?.kind === 'terminal') {
|
||||
const iconEl = this.toolIconsByCallId.get(toolCallId);
|
||||
if (iconEl) {
|
||||
const newIcon = termData.commandLine?.isSandboxWrapped ? Codicon.terminalSecure : Codicon.terminal;
|
||||
iconEl.className = 'chat-thinking-icon';
|
||||
iconEl.classList.add(...ThemeIcon.asClassNameArray(newIcon));
|
||||
}
|
||||
}
|
||||
|
||||
if (toolInvocationOrMarkdown.presentation === 'hidden') {
|
||||
this.pendingRemovals.push({ toolCallId: toolInvocationOrMarkdown.toolCallId, toolLabel: currentToolLabel });
|
||||
this.schedulePendingRemovalsFlush();
|
||||
@@ -1628,6 +1643,7 @@ ${this.hookCount > 0 ? `EXAMPLES WITH BLOCKED CONTENT (from hooks):
|
||||
const isToolInvocation = toolInvocationOrMarkdown && (toolInvocationOrMarkdown.kind === 'toolInvocation' || toolInvocationOrMarkdown.kind === 'toolInvocationSerialized');
|
||||
if (isToolInvocation && toolInvocationOrMarkdown.toolCallId) {
|
||||
this.toolWrappersByCallId.set(toolInvocationOrMarkdown.toolCallId, itemWrapper);
|
||||
this.toolIconsByCallId.set(toolInvocationOrMarkdown.toolCallId, iconElement);
|
||||
}
|
||||
|
||||
this.appendToWrapper(itemWrapper);
|
||||
|
||||
@@ -274,7 +274,7 @@ export async function createRunInTerminalToolData(
|
||||
modelDescription,
|
||||
userDescription: localize('runInTerminalTool.userDescription', 'Run commands in the terminal'),
|
||||
source: ToolDataSource.Internal,
|
||||
icon: isSandboxEnabled ? Codicon.terminalSecure : Codicon.terminal,
|
||||
icon: Codicon.terminal,
|
||||
inputSchema: {
|
||||
type: 'object',
|
||||
properties: {
|
||||
|
||||
Reference in New Issue
Block a user