// ***************************************************************************** // Copyright (C) 2025 EclipseSource GmbH. // // This program and the accompanying materials are made available under the // terms of the Eclipse Public License v. 2.0 which is available at // http://www.eclipse.org/legal/epl-2.0. // // This Source Code may also be made available under the following Secondary // Licenses when the conditions for such availability set forth in the Eclipse // Public License v. 2.0 are satisfied: GNU General Public License, version 2 // with the GNU Classpath Exception which is available at // https://www.gnu.org/software/classpath/license.html. // // SPDX-License-Identifier: EPL-2.0 OR GPL-2.0-only WITH Classpath-exception-2.0 // ***************************************************************************** import { injectable, inject } from '@theia/core/shared/inversify'; import { PreferenceService, } from '@theia/core/lib/common/preferences'; import { ToolConfirmationMode, TOOL_CONFIRMATION_PREFERENCE, ChatToolPreferences } from '../common/chat-tool-preferences'; import { ToolRequest } from '@theia/ai-core'; /** * Utility class to manage tool confirmation settings */ @injectable() export class ToolConfirmationManager { @inject(ChatToolPreferences) protected readonly preferences: ChatToolPreferences; @inject(PreferenceService) protected readonly preferenceService: PreferenceService; // In-memory session overrides (not persisted), per chat protected sessionOverrides: Map> = new Map(); /** * Get the confirmation mode for a specific tool, considering session overrides first (per chat). * * For tools with `confirmAlwaysAllow` flag: * - They default to CONFIRM mode instead of ALWAYS_ALLOW * - They don't inherit global ALWAYS_ALLOW from the '*' preference * * @param toolId - The tool identifier * @param chatId - The chat session identifier * @param toolRequest - Optional ToolRequest to check for confirmAlwaysAllow flag */ getConfirmationMode(toolId: string, chatId: string, toolRequest?: ToolRequest): ToolConfirmationMode { const chatMap = this.sessionOverrides.get(chatId); if (chatMap && chatMap.has(toolId)) { return chatMap.get(toolId)!; } const toolConfirmation = this.preferences[TOOL_CONFIRMATION_PREFERENCE]; if (toolConfirmation[toolId]) { return toolConfirmation[toolId]; } if (toolConfirmation['*']) { // For confirmAlwaysAllow tools, don't inherit global ALWAYS_ALLOW if (toolRequest?.confirmAlwaysAllow && toolConfirmation['*'] === ToolConfirmationMode.ALWAYS_ALLOW) { return ToolConfirmationMode.CONFIRM; } return toolConfirmation['*']; } // Default: ALWAYS_ALLOW for normal tools, CONFIRM for confirmAlwaysAllow tools return toolRequest?.confirmAlwaysAllow ? ToolConfirmationMode.CONFIRM : ToolConfirmationMode.ALWAYS_ALLOW; } /** * Set the confirmation mode for a specific tool (persisted) * * @param toolId - The tool identifier * @param mode - The confirmation mode to set * @param toolRequest - Optional ToolRequest to check for confirmAlwaysAllow flag */ setConfirmationMode(toolId: string, mode: ToolConfirmationMode, toolRequest?: ToolRequest): void { const current = this.preferences[TOOL_CONFIRMATION_PREFERENCE] || {}; let starMode = current['*']; if (starMode === undefined) { starMode = ToolConfirmationMode.ALWAYS_ALLOW; } // For confirmAlwaysAllow tools, the effective default is CONFIRM, not ALWAYS_ALLOW const effectiveDefault = (toolRequest?.confirmAlwaysAllow && starMode === ToolConfirmationMode.ALWAYS_ALLOW) ? ToolConfirmationMode.CONFIRM : starMode; if (mode === effectiveDefault) { if (toolId in current) { const { [toolId]: _, ...rest } = current; this.preferenceService.updateValue(TOOL_CONFIRMATION_PREFERENCE, rest); } } else { const updated = { ...current, [toolId]: mode }; this.preferenceService.updateValue(TOOL_CONFIRMATION_PREFERENCE, updated); } } /** * Set the confirmation mode for a specific tool for this session only (not persisted, per chat) */ setSessionConfirmationMode(toolId: string, mode: ToolConfirmationMode, chatId: string): void { let chatMap = this.sessionOverrides.get(chatId); if (!chatMap) { chatMap = new Map(); this.sessionOverrides.set(chatId, chatMap); } chatMap.set(toolId, mode); } /** * Clear all session overrides for a specific chat, or all if no chatId is given */ clearSessionOverrides(chatId?: string): void { if (chatId) { this.sessionOverrides.delete(chatId); } else { this.sessionOverrides.clear(); } } /** * Get all tool confirmation settings */ getAllConfirmationSettings(): { [toolId: string]: ToolConfirmationMode } { return this.preferences[TOOL_CONFIRMATION_PREFERENCE] || {}; } resetAllConfirmationModeSettings(): void { const current = this.preferences[TOOL_CONFIRMATION_PREFERENCE] || {}; if ('*' in current) { this.preferenceService.updateValue(TOOL_CONFIRMATION_PREFERENCE, { '*': current['*'] }); } else { this.preferenceService.updateValue(TOOL_CONFIRMATION_PREFERENCE, {}); } } }