@theia/ai-chat 1.72.0-next.2 → 1.72.0-next.21

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -18,7 +18,11 @@ import { injectable, inject } from '@theia/core/shared/inversify';
18
18
  import {
19
19
  PreferenceService,
20
20
  } from '@theia/core/lib/common/preferences';
21
- import { ToolConfirmationMode, TOOL_CONFIRMATION_PREFERENCE } from '../common/chat-tool-preferences';
21
+ import {
22
+ ToolConfirmationMode,
23
+ TOOL_CONFIRMATION_PREFERENCE,
24
+ DEFAULT_TOOL_CONFIRMATION_PREFERENCE
25
+ } from '../common/chat-tool-preferences';
22
26
  import { ToolRequest } from '@theia/ai-core';
23
27
  import { TrustAwarePreferenceReader } from '@theia/ai-core/lib/browser/trust-aware-preference-reader';
24
28
 
@@ -36,12 +40,33 @@ export class ToolConfirmationManager {
36
40
  // In-memory session overrides (not persisted), per chat
37
41
  protected sessionOverrides: Map<string, Map<string, ToolConfirmationMode>> = new Map();
38
42
 
43
+ /**
44
+ * Get the global default confirmation mode (used when no tool-specific entry exists).
45
+ *
46
+ * Read through the trust-aware reader so that an untrusted workspace cannot override
47
+ * the default to a more permissive value.
48
+ */
49
+ getDefaultConfirmationMode(): ToolConfirmationMode {
50
+ const value = this.trustAwareReader.get<ToolConfirmationMode>(DEFAULT_TOOL_CONFIRMATION_PREFERENCE);
51
+ return value ?? this.getDefaultPreferenceSchemaDefault();
52
+ }
53
+
54
+ /**
55
+ * Set the global default confirmation mode.
56
+ *
57
+ * Returns the promise produced by the underlying preference update so callers can
58
+ * `await` completion and react to errors (e.g. show a notification on failure).
59
+ */
60
+ setDefaultConfirmationMode(mode: ToolConfirmationMode): Promise<void> {
61
+ return this.preferenceService.updateValue(DEFAULT_TOOL_CONFIRMATION_PREFERENCE, mode);
62
+ }
63
+
39
64
  /**
40
65
  * Get the confirmation mode for a specific tool, considering session overrides first (per chat).
41
66
  *
42
67
  * For tools with `confirmAlwaysAllow` flag:
43
- * - They default to CONFIRM mode instead of ALWAYS_ALLOW
44
- * - They don't inherit global ALWAYS_ALLOW from the '*' preference
68
+ * - They default to CONFIRM mode instead of inheriting ALWAYS_ALLOW from the global default.
69
+ * - Tool-specific preference entries are still respected (informed user consent).
45
70
  *
46
71
  * @param toolId - The tool identifier
47
72
  * @param chatId - The chat session identifier
@@ -55,21 +80,15 @@ export class ToolConfirmationManager {
55
80
  const toolConfirmation = this.trustAwareReader.get<Record<string, ToolConfirmationMode>>(
56
81
  TOOL_CONFIRMATION_PREFERENCE, {}
57
82
  ) ?? {};
58
- if (toolConfirmation[toolId]) {
83
+ if (toolId in toolConfirmation) {
59
84
  return toolConfirmation[toolId];
60
85
  }
61
- if (toolConfirmation['*']) {
62
- // For confirmAlwaysAllow tools, don't inherit global ALWAYS_ALLOW
63
- if (toolRequest?.confirmAlwaysAllow && toolConfirmation['*'] === ToolConfirmationMode.ALWAYS_ALLOW) {
64
- return ToolConfirmationMode.CONFIRM;
65
- }
66
- return toolConfirmation['*'];
86
+ const defaultMode = this.getDefaultConfirmationMode();
87
+ // For confirmAlwaysAllow tools, don't inherit a global ALWAYS_ALLOW default
88
+ if (toolRequest?.confirmAlwaysAllow && defaultMode === ToolConfirmationMode.ALWAYS_ALLOW) {
89
+ return ToolConfirmationMode.CONFIRM;
67
90
  }
68
-
69
- // Default: ALWAYS_ALLOW for normal tools, CONFIRM for confirmAlwaysAllow tools
70
- return toolRequest?.confirmAlwaysAllow
71
- ? ToolConfirmationMode.CONFIRM
72
- : ToolConfirmationMode.ALWAYS_ALLOW;
91
+ return defaultMode;
73
92
  }
74
93
 
75
94
  /**
@@ -79,30 +98,20 @@ export class ToolConfirmationManager {
79
98
  * @param mode - The confirmation mode to set
80
99
  * @param toolRequest - Optional ToolRequest to check for confirmAlwaysAllow flag
81
100
  */
82
- setConfirmationMode(toolId: string, mode: ToolConfirmationMode, toolRequest?: ToolRequest): void {
83
- const defaultPref = this.preferenceService.inspect(TOOL_CONFIRMATION_PREFERENCE)?.defaultValue as {
84
- [toolId: string]: ToolConfirmationMode;
85
- } || {};
101
+ setConfirmationMode(toolId: string, mode: ToolConfirmationMode, toolRequest?: ToolRequest): Promise<void> {
86
102
  const current = this.trustAwareReader.get<Record<string, ToolConfirmationMode>>(
87
103
  TOOL_CONFIRMATION_PREFERENCE, {}
88
104
  ) ?? {};
89
- let starMode = current['*'];
90
- if (starMode === undefined) {
91
- starMode = defaultPref['*'] ?? ToolConfirmationMode.ALWAYS_ALLOW;
92
- }
93
- // For confirmAlwaysAllow tools, the effective default is CONFIRM, not ALWAYS_ALLOW
94
- const effectiveDefault = (toolRequest?.confirmAlwaysAllow && starMode === ToolConfirmationMode.ALWAYS_ALLOW)
95
- ? ToolConfirmationMode.CONFIRM
96
- : defaultPref[toolId] ?? starMode;
105
+ const effectiveDefault = this.computeEffectiveDefaultForTool(toolId, toolRequest);
97
106
  if (mode === effectiveDefault) {
98
107
  if (toolId in current) {
99
108
  const { [toolId]: _, ...rest } = current;
100
- this.preferenceService.updateValue(TOOL_CONFIRMATION_PREFERENCE, rest);
109
+ return this.preferenceService.updateValue(TOOL_CONFIRMATION_PREFERENCE, rest);
101
110
  }
102
- } else {
103
- const updated = { ...current, [toolId]: mode };
104
- this.preferenceService.updateValue(TOOL_CONFIRMATION_PREFERENCE, updated);
111
+ return Promise.resolve();
105
112
  }
113
+ const updated = { ...current, [toolId]: mode };
114
+ return this.preferenceService.updateValue(TOOL_CONFIRMATION_PREFERENCE, updated);
106
115
  }
107
116
 
108
117
  /**
@@ -137,14 +146,37 @@ export class ToolConfirmationManager {
137
146
  ) ?? {};
138
147
  }
139
148
 
140
- resetAllConfirmationModeSettings(): void {
141
- const current = this.trustAwareReader.get<Record<string, ToolConfirmationMode>>(
142
- TOOL_CONFIRMATION_PREFERENCE, {}
143
- ) ?? {};
144
- if ('*' in current) {
145
- this.preferenceService.updateValue(TOOL_CONFIRMATION_PREFERENCE, { '*': current['*'] });
146
- } else {
147
- this.preferenceService.updateValue(TOOL_CONFIRMATION_PREFERENCE, {});
149
+ resetAllConfirmationModeSettings(): Promise<void> {
150
+ return this.preferenceService.updateValue(TOOL_CONFIRMATION_PREFERENCE, {});
151
+ }
152
+
153
+ /**
154
+ * Compute the effective default for a given tool, taking the schema-level default,
155
+ * any product-shipped per-tool default, and the confirmAlwaysAllow flag into account.
156
+ */
157
+ protected computeEffectiveDefaultForTool(toolId: string, toolRequest?: ToolRequest): ToolConfirmationMode {
158
+ const perToolDefaults = this.preferenceService.inspect(TOOL_CONFIRMATION_PREFERENCE)?.defaultValue as
159
+ | { [toolId: string]: ToolConfirmationMode }
160
+ | undefined;
161
+ const perToolDefault = perToolDefaults?.[toolId];
162
+ if (perToolDefault) {
163
+ return perToolDefault;
148
164
  }
165
+ const globalDefault = this.getDefaultConfirmationMode();
166
+ if (toolRequest?.confirmAlwaysAllow && globalDefault === ToolConfirmationMode.ALWAYS_ALLOW) {
167
+ return ToolConfirmationMode.CONFIRM;
168
+ }
169
+ return globalDefault;
170
+ }
171
+
172
+ /**
173
+ * Read the schema-level default for the default-confirmation preference.
174
+ * Falls back to CONFIRM if the preference service has not registered the schema yet.
175
+ */
176
+ protected getDefaultPreferenceSchemaDefault(): ToolConfirmationMode {
177
+ const schemaDefault = this.preferenceService.inspect(DEFAULT_TOOL_CONFIRMATION_PREFERENCE)?.defaultValue as
178
+ | ToolConfirmationMode
179
+ | undefined;
180
+ return schemaDefault ?? ToolConfirmationMode.CONFIRM;
149
181
  }
150
182
  }
@@ -54,25 +54,45 @@ export enum ToolConfirmationMode {
54
54
  }
55
55
 
56
56
  export const TOOL_CONFIRMATION_PREFERENCE = 'ai-features.chat.toolConfirmation';
57
+ export const DEFAULT_TOOL_CONFIRMATION_PREFERENCE = 'ai-features.chat.defaultToolConfirmation';
57
58
  export const TOOL_CONFIRMATION_TIMEOUT_PREFERENCE = 'ai-features.chat.toolConfirmationTimeout';
58
59
 
60
+ const TOOL_CONFIRMATION_MODE_VALUES = [
61
+ ToolConfirmationMode.ALWAYS_ALLOW,
62
+ ToolConfirmationMode.CONFIRM,
63
+ ToolConfirmationMode.DISABLED
64
+ ];
65
+
66
+ const TOOL_CONFIRMATION_MODE_DESCRIPTIONS = [
67
+ nls.localize('theia/ai/chat/toolConfirmation/alwaysAllow/description', 'Execute tools automatically without confirmation'),
68
+ nls.localize('theia/ai/chat/toolConfirmation/confirm/description', 'Ask for confirmation before executing tools'),
69
+ nls.localize('theia/ai/chat/toolConfirmation/disabled/description', 'Disable tool execution')
70
+ ];
71
+
59
72
  export const chatToolPreferences: PreferenceSchema = {
60
73
  properties: {
74
+ [DEFAULT_TOOL_CONFIRMATION_PREFERENCE]: {
75
+ type: 'string',
76
+ enum: TOOL_CONFIRMATION_MODE_VALUES,
77
+ enumDescriptions: TOOL_CONFIRMATION_MODE_DESCRIPTIONS,
78
+ default: ToolConfirmationMode.CONFIRM,
79
+ description: nls.localize('theia/ai/chat/defaultToolConfirmation/description',
80
+ 'Default confirmation behavior used for tools that do not have a tool-specific entry under ' +
81
+ '"ai-features.chat.toolConfirmation". Tools that explicitly require confirmation before being auto-approved ' +
82
+ 'always default to "confirm" regardless of this setting.'),
83
+ title: AI_CORE_PREFERENCES_TITLE,
84
+ },
61
85
  [TOOL_CONFIRMATION_PREFERENCE]: {
62
86
  type: 'object',
63
87
  additionalProperties: {
64
88
  type: 'string',
65
- enum: [ToolConfirmationMode.ALWAYS_ALLOW, ToolConfirmationMode.CONFIRM, ToolConfirmationMode.DISABLED],
66
- enumDescriptions: [
67
- nls.localize('theia/ai/chat/toolConfirmation/yolo/description', 'Execute tools automatically without confirmation'),
68
- nls.localize('theia/ai/chat/toolConfirmation/confirm/description', 'Ask for confirmation before executing tools'),
69
- nls.localize('theia/ai/chat/toolConfirmation/disabled/description', 'Disable tool execution')
70
- ]
89
+ enum: TOOL_CONFIRMATION_MODE_VALUES,
90
+ enumDescriptions: TOOL_CONFIRMATION_MODE_DESCRIPTIONS
71
91
  },
72
92
  default: {},
73
93
  description: nls.localize('theia/ai/chat/toolConfirmation/description',
74
- 'Configure confirmation behavior for different tools. Key is the tool ID, value is the confirmation mode. ' +
75
- 'Use "*" as the key to set a global default for all tools.'),
94
+ 'Configure confirmation behavior for individual tools. Key is the tool ID, value is the confirmation mode. ' +
95
+ 'To change the default for all tools, use "ai-features.chat.defaultToolConfirmation".'),
76
96
  title: AI_CORE_PREFERENCES_TITLE,
77
97
  },
78
98
  [TOOL_CONFIRMATION_TIMEOUT_PREFERENCE]: {
@@ -89,5 +109,6 @@ export const chatToolPreferences: PreferenceSchema = {
89
109
 
90
110
  export interface ChatToolConfiguration {
91
111
  [TOOL_CONFIRMATION_PREFERENCE]: { [toolId: string]: ToolConfirmationMode };
112
+ [DEFAULT_TOOL_CONFIRMATION_PREFERENCE]: ToolConfirmationMode;
92
113
  [TOOL_CONFIRMATION_TIMEOUT_PREFERENCE]: number;
93
114
  }