@theia/ai-chat 1.63.0-next.24 → 1.63.0-next.52

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.
Files changed (80) hide show
  1. package/lib/browser/agent-delegation-tool.d.ts +25 -0
  2. package/lib/browser/agent-delegation-tool.d.ts.map +1 -0
  3. package/lib/browser/agent-delegation-tool.js +171 -0
  4. package/lib/browser/agent-delegation-tool.js.map +1 -0
  5. package/lib/browser/ai-chat-frontend-module.d.ts.map +1 -1
  6. package/lib/browser/ai-chat-frontend-module.js +8 -0
  7. package/lib/browser/ai-chat-frontend-module.js.map +1 -1
  8. package/lib/browser/change-set-file-element.d.ts +19 -1
  9. package/lib/browser/change-set-file-element.d.ts.map +1 -1
  10. package/lib/browser/change-set-file-element.js +63 -8
  11. package/lib/browser/change-set-file-element.js.map +1 -1
  12. package/lib/browser/chat-tool-preferences.d.ts +1 -1
  13. package/lib/browser/chat-tool-preferences.d.ts.map +1 -1
  14. package/lib/browser/chat-tool-preferences.js +4 -4
  15. package/lib/browser/chat-tool-preferences.js.map +1 -1
  16. package/lib/browser/chat-tool-request-service.js +1 -1
  17. package/lib/browser/chat-tool-request-service.js.map +1 -1
  18. package/lib/browser/delegation-response-content.d.ts +20 -0
  19. package/lib/browser/delegation-response-content.d.ts.map +1 -0
  20. package/lib/browser/delegation-response-content.js +51 -0
  21. package/lib/browser/delegation-response-content.js.map +1 -0
  22. package/lib/browser/file-chat-variable-contribution.d.ts +15 -1
  23. package/lib/browser/file-chat-variable-contribution.d.ts.map +1 -1
  24. package/lib/browser/file-chat-variable-contribution.js +111 -5
  25. package/lib/browser/file-chat-variable-contribution.js.map +1 -1
  26. package/lib/browser/image-context-variable-contribution.d.ts +27 -0
  27. package/lib/browser/image-context-variable-contribution.d.ts.map +1 -0
  28. package/lib/browser/image-context-variable-contribution.js +149 -0
  29. package/lib/browser/image-context-variable-contribution.js.map +1 -0
  30. package/lib/browser/task-context-service.d.ts +9 -3
  31. package/lib/browser/task-context-service.d.ts.map +1 -1
  32. package/lib/browser/task-context-service.js +111 -9
  33. package/lib/browser/task-context-service.js.map +1 -1
  34. package/lib/browser/task-context-storage-service.d.ts +1 -0
  35. package/lib/browser/task-context-storage-service.d.ts.map +1 -1
  36. package/lib/browser/task-context-storage-service.js +4 -1
  37. package/lib/browser/task-context-storage-service.js.map +1 -1
  38. package/lib/common/change-set.js +1 -1
  39. package/lib/common/change-set.js.map +1 -1
  40. package/lib/common/chat-agent-service.d.ts +1 -0
  41. package/lib/common/chat-agent-service.d.ts.map +1 -1
  42. package/lib/common/chat-agent-service.js +2 -1
  43. package/lib/common/chat-agent-service.js.map +1 -1
  44. package/lib/common/chat-agents.d.ts +2 -2
  45. package/lib/common/chat-agents.d.ts.map +1 -1
  46. package/lib/common/chat-agents.js +21 -5
  47. package/lib/common/chat-agents.js.map +1 -1
  48. package/lib/common/chat-model.d.ts +2 -2
  49. package/lib/common/chat-model.d.ts.map +1 -1
  50. package/lib/common/chat-model.js +1 -1
  51. package/lib/common/chat-model.js.map +1 -1
  52. package/lib/common/chat-request-parser.d.ts.map +1 -1
  53. package/lib/common/chat-request-parser.js +3 -0
  54. package/lib/common/chat-request-parser.js.map +1 -1
  55. package/lib/common/chat-service.d.ts +3 -2
  56. package/lib/common/chat-service.d.ts.map +1 -1
  57. package/lib/common/chat-service.js +4 -3
  58. package/lib/common/chat-service.js.map +1 -1
  59. package/lib/common/image-context-variable.d.ts +29 -0
  60. package/lib/common/image-context-variable.d.ts.map +1 -0
  61. package/lib/common/image-context-variable.js +99 -0
  62. package/lib/common/image-context-variable.js.map +1 -0
  63. package/package.json +10 -9
  64. package/src/browser/agent-delegation-tool.ts +207 -0
  65. package/src/browser/ai-chat-frontend-module.ts +20 -2
  66. package/src/browser/change-set-file-element.ts +69 -9
  67. package/src/browser/chat-tool-preferences.ts +4 -4
  68. package/src/browser/chat-tool-request-service.ts +1 -1
  69. package/src/browser/delegation-response-content.ts +55 -0
  70. package/src/browser/file-chat-variable-contribution.ts +120 -6
  71. package/src/browser/image-context-variable-contribution.ts +153 -0
  72. package/src/browser/task-context-service.ts +115 -9
  73. package/src/browser/task-context-storage-service.ts +5 -1
  74. package/src/common/change-set.ts +1 -1
  75. package/src/common/chat-agent-service.ts +1 -0
  76. package/src/common/chat-agents.ts +26 -9
  77. package/src/common/chat-model.ts +11 -3
  78. package/src/common/chat-request-parser.ts +3 -0
  79. package/src/common/chat-service.ts +5 -4
  80. package/src/common/image-context-variable.ts +116 -0
@@ -0,0 +1,207 @@
1
+ // *****************************************************************************
2
+ // Copyright (C) 2025 EclipseSource GmbH.
3
+ //
4
+ // This program and the accompanying materials are made available under the
5
+ // terms of the Eclipse Public License v. 2.0 which is available at
6
+ // http://www.eclipse.org/legal/epl-2.0.
7
+ //
8
+ // This Source Code may also be made available under the following Secondary
9
+ // Licenses when the conditions for such availability set forth in the Eclipse
10
+ // Public License v. 2.0 are satisfied: GNU General Public License, version 2
11
+ // with the GNU Classpath Exception which is available at
12
+ // https://www.gnu.org/software/classpath/license.html.
13
+ //
14
+ // SPDX-License-Identifier: EPL-2.0 OR GPL-2.0-only WITH Classpath-exception-2.0
15
+ // *****************************************************************************
16
+
17
+ import { ToolProvider, ToolRequest } from '@theia/ai-core';
18
+ import { inject, injectable } from '@theia/core/shared/inversify';
19
+ import {
20
+ ChatAgentService,
21
+ ChatAgentServiceFactory,
22
+ ChatRequest,
23
+ ChatService,
24
+ ChatServiceFactory,
25
+ MutableChatRequestModel,
26
+ MutableChatModel,
27
+ ChatSession,
28
+ } from '../common';
29
+ import { DelegationResponseContent } from './delegation-response-content';
30
+
31
+ export const AGENT_DELEGATION_FUNCTION_ID = 'delegateToAgent';
32
+
33
+ @injectable()
34
+ export class AgentDelegationTool implements ToolProvider {
35
+ static ID = AGENT_DELEGATION_FUNCTION_ID;
36
+
37
+ @inject(ChatAgentServiceFactory)
38
+ protected readonly getChatAgentService: () => ChatAgentService;
39
+
40
+ @inject(ChatServiceFactory)
41
+ protected readonly getChatService: () => ChatService;
42
+
43
+ getTool(): ToolRequest {
44
+ return {
45
+ id: AgentDelegationTool.ID,
46
+ name: AgentDelegationTool.ID,
47
+ description:
48
+ 'Delegate a task or question to a specific AI agent. This tool allows you to submit requests to specialized agents based on their capabilities.',
49
+ parameters: {
50
+ type: 'object',
51
+ properties: {
52
+ agentId: {
53
+ type: 'string',
54
+ description:
55
+ 'The ID of the AI agent to delegate the task to.',
56
+ },
57
+ prompt: {
58
+ type: 'string',
59
+ description:
60
+ 'The task, question, or prompt to pass to the specified agent.',
61
+ },
62
+ },
63
+ required: ['agentId', 'prompt'],
64
+ },
65
+ handler: (arg_string: string, ctx: MutableChatRequestModel) =>
66
+ this.delegateToAgent(arg_string, ctx),
67
+ };
68
+ }
69
+
70
+ private async delegateToAgent(
71
+ arg_string: string,
72
+ ctx: MutableChatRequestModel
73
+ ): Promise<string> {
74
+ try {
75
+ const args = JSON.parse(arg_string);
76
+ const { agentId, prompt } = args;
77
+
78
+ if (!agentId || !prompt) {
79
+ const errorMsg = 'Both agentId and prompt parameters are required.';
80
+ console.error(errorMsg, { agentId, prompt });
81
+ return errorMsg;
82
+ }
83
+
84
+ // Check if the specified agent exists
85
+ const agent = this.getChatAgentService().getAgent(agentId);
86
+ if (!agent) {
87
+ const availableAgents = this.getChatAgentService()
88
+ .getAgents()
89
+ .map(a => a.id);
90
+ const errorMsg = `Agent '${agentId}' not found or not enabled. Available agents: ${availableAgents.join(', ')}`;
91
+ console.error(errorMsg);
92
+ return errorMsg;
93
+ }
94
+
95
+ let newSession;
96
+ try {
97
+ // FIXME: this creates a new conversation visible in the UI (Panel), which we don't want
98
+ // It is not possible to start a session without specifying a location (default=Panel)
99
+ const chatService = this.getChatService();
100
+
101
+ // Store the current active session to restore it after delegation
102
+ const currentActiveSession = chatService.getActiveSession();
103
+
104
+ newSession = chatService.createSession(
105
+ undefined,
106
+ { focus: false },
107
+ agent
108
+ );
109
+
110
+ // Immediately restore the original active session to avoid confusing the user
111
+ if (currentActiveSession) {
112
+ chatService.setActiveSession(currentActiveSession.id, { focus: false });
113
+ }
114
+
115
+ // Setup ChangeSet bubbling from delegated session to parent session
116
+ this.setupChangeSetBubbling(newSession, ctx.session, agent.name);
117
+ } catch (sessionError) {
118
+ const errorMsg = `Failed to create chat session for agent '${agentId}': ${sessionError instanceof Error ? sessionError.message : sessionError}`;
119
+ console.error(errorMsg, sessionError);
120
+ return errorMsg;
121
+ }
122
+
123
+ // Send the request
124
+ const chatRequest: ChatRequest = {
125
+ text: prompt,
126
+ };
127
+
128
+ let response;
129
+ try {
130
+ const chatService = this.getChatService();
131
+ response = await chatService.sendRequest(
132
+ newSession.id,
133
+ chatRequest
134
+ );
135
+ } catch (sendError) {
136
+ const errorMsg = `Failed to send request to agent '${agentId}': ${sendError instanceof Error ? sendError.message : sendError}`;
137
+ console.error(errorMsg, sendError);
138
+ return errorMsg;
139
+ }
140
+
141
+ if (response) {
142
+ // Add the response content immediately to enable streaming
143
+ // The renderer will handle the streaming updates
144
+ ctx.response.response.addContent(
145
+ new DelegationResponseContent(agent.name, prompt, response)
146
+ );
147
+
148
+ try {
149
+ // Wait for completion to return the final result as tool output
150
+ const result = await response.responseCompleted;
151
+ const stringResult = result.response.asString();
152
+ // Return the raw text to the top-level Agent, as a tool result
153
+ return stringResult;
154
+ } catch (completionError) {
155
+ const errorMsg = `Failed to complete response from agent '${agentId}': ${completionError instanceof Error ? completionError.message : completionError}`;
156
+ console.error(errorMsg, completionError);
157
+ return errorMsg;
158
+ }
159
+ } else {
160
+ const errorMsg = `Delegation to agent '${agentId}' has failed: no response returned.`;
161
+ console.error(errorMsg);
162
+ return errorMsg;
163
+ }
164
+ } catch (error) {
165
+ console.error('Failed to delegate to agent', error);
166
+ return JSON.stringify({
167
+ error: `Failed to parse arguments or delegate to agent: ${error instanceof Error ? error.message : 'Unknown error'}`,
168
+ });
169
+ }
170
+ }
171
+
172
+ /**
173
+ * Sets up monitoring of the ChangeSet in the delegated session and bubbles changes to the parent session.
174
+ * @param delegatedSession The session created for the delegated agent
175
+ * @param parentModel The parent session model that should receive the bubbled changes
176
+ * @param agentName The name of the agent for attribution purposes
177
+ */
178
+ private setupChangeSetBubbling(
179
+ delegatedSession: ChatSession,
180
+ parentModel: MutableChatModel,
181
+ agentName: string
182
+ ): void {
183
+ // Monitor ChangeSet for bubbling
184
+ delegatedSession.model.changeSet.onDidChange(_event => {
185
+ this.bubbleChangeSet(delegatedSession, parentModel, agentName);
186
+ });
187
+ }
188
+
189
+ /**
190
+ * Bubbles the ChangeSet from the delegated session to the parent session.
191
+ * @param delegatedSession The session from which to bubble changes
192
+ * @param parentModel The parent session model to receive the bubbled changes
193
+ * @param agentName The name of the agent for attribution purposes
194
+ */
195
+ private bubbleChangeSet(
196
+ delegatedSession: ChatSession,
197
+ parentModel: MutableChatModel,
198
+ agentName: string
199
+ ): void {
200
+ const delegatedElements = delegatedSession.model.changeSet.getElements();
201
+ if (delegatedElements.length > 0) {
202
+ const bubbledTitle = `Changes from ${agentName}`;
203
+ parentModel.changeSet.setTitle(bubbledTitle);
204
+ parentModel.changeSet.addElements(...delegatedElements);
205
+ }
206
+ }
207
+ }
@@ -14,7 +14,7 @@
14
14
  // SPDX-License-Identifier: EPL-2.0 OR GPL-2.0-only WITH Classpath-exception-2.0
15
15
  // *****************************************************************************
16
16
 
17
- import { Agent, AgentService, AIVariableContribution } from '@theia/ai-core/lib/common';
17
+ import { Agent, AgentService, AIVariableContribution, bindToolProvider } from '@theia/ai-core/lib/common';
18
18
  import { bindContributionProvider, CommandContribution } from '@theia/core';
19
19
  import { FrontendApplicationContribution, LabelProviderContribution, PreferenceContribution } from '@theia/core/lib/browser';
20
20
  import { ContainerModule } from '@theia/core/shared/inversify';
@@ -26,7 +26,9 @@ import {
26
26
  ChatRequestParserImpl,
27
27
  ChatService,
28
28
  ToolCallChatResponseContentFactory,
29
- PinChatAgent
29
+ PinChatAgent,
30
+ ChatServiceFactory,
31
+ ChatAgentServiceFactory
30
32
  } from '../common';
31
33
  import { ChatAgentsVariableContribution } from '../common/chat-agents-variable-contribution';
32
34
  import { CustomChatAgent } from '../common/custom-chat-agent';
@@ -54,6 +56,8 @@ import { TaskContextVariableLabelProvider } from './task-context-variable-label-
54
56
  import { TaskContextService, TaskContextStorageService } from './task-context-service';
55
57
  import { InMemoryTaskContextStorage } from './task-context-storage-service';
56
58
  import { AIChatFrontendContribution } from './ai-chat-frontend-contribution';
59
+ import { ImageContextVariableContribution } from './image-context-variable-contribution';
60
+ import { AgentDelegationTool } from './agent-delegation-tool';
57
61
 
58
62
  export default new ContainerModule(bind => {
59
63
  bindContributionProvider(bind, Agent);
@@ -83,6 +87,13 @@ export default new ContainerModule(bind => {
83
87
  bind(FrontendChatServiceImpl).toSelf().inSingletonScope();
84
88
  bind(ChatService).toService(FrontendChatServiceImpl);
85
89
 
90
+ bind(ChatServiceFactory).toDynamicValue(ctx => () =>
91
+ ctx.container.get<ChatService>(ChatService)
92
+ );
93
+ bind(ChatAgentServiceFactory).toDynamicValue(ctx => () =>
94
+ ctx.container.get<ChatAgentService>(ChatAgentService)
95
+ );
96
+
86
97
  bind(PreferenceContribution).toConstantValue({ schema: aiChatPreferences });
87
98
 
88
99
  // Tool confirmation preferences
@@ -131,14 +142,21 @@ export default new ContainerModule(bind => {
131
142
 
132
143
  bind(ChatSessionSummaryAgent).toSelf().inSingletonScope();
133
144
  bind(Agent).toService(ChatSessionSummaryAgent);
145
+
134
146
  bind(TaskContextVariableContribution).toSelf().inSingletonScope();
135
147
  bind(AIVariableContribution).toService(TaskContextVariableContribution);
136
148
  bind(TaskContextVariableLabelProvider).toSelf().inSingletonScope();
137
149
  bind(LabelProviderContribution).toService(TaskContextVariableLabelProvider);
138
150
 
151
+ bind(ImageContextVariableContribution).toSelf().inSingletonScope();
152
+ bind(AIVariableContribution).toService(ImageContextVariableContribution);
153
+ bind(LabelProviderContribution).toService(ImageContextVariableContribution);
154
+
139
155
  bind(TaskContextService).toSelf().inSingletonScope();
140
156
  bind(InMemoryTaskContextStorage).toSelf().inSingletonScope();
141
157
  bind(TaskContextStorageService).toService(InMemoryTaskContextStorage);
142
158
  bind(AIChatFrontendContribution).toSelf().inSingletonScope();
143
159
  bind(CommandContribution).toService(AIChatFrontendContribution);
160
+
161
+ bindToolProvider(AgentDelegationTool, bind);
144
162
  });
@@ -76,7 +76,9 @@ export class ChangeSetFileElement implements ChangeSetElement {
76
76
  protected readonly toDispose = new DisposableCollection();
77
77
  protected _state: ChangeSetElementState;
78
78
 
79
- protected originalContent: string | undefined;
79
+ private _originalContent: string | undefined;
80
+ protected _initialized = false;
81
+ protected _initializationPromise: Promise<void> | undefined;
80
82
 
81
83
  protected readonly onDidChangeEmitter = new Emitter<void>();
82
84
  readonly onDidChange = this.onDidChangeEmitter.event;
@@ -85,12 +87,36 @@ export class ChangeSetFileElement implements ChangeSetElement {
85
87
 
86
88
  @postConstruct()
87
89
  init(): void {
90
+ this._initializationPromise = this.initializeAsync();
88
91
  this.toDispose.push(this.onDidChangeEmitter);
89
92
  }
90
93
 
94
+ protected async initializeAsync(): Promise<void> {
95
+ await this.obtainOriginalContent();
96
+ this.listenForOriginalFileChanges();
97
+ this._initialized = true;
98
+ }
99
+
100
+ /**
101
+ * Ensures that the element is fully initialized before proceeding.
102
+ * This includes loading the original content from the file system.
103
+ */
104
+ async ensureInitialized(): Promise<void> {
105
+ await this._initializationPromise;
106
+ }
107
+
108
+ /**
109
+ * Returns true if the element has been fully initialized.
110
+ */
111
+ get isInitialized(): boolean {
112
+ return this._initialized;
113
+ }
114
+
91
115
  protected async obtainOriginalContent(): Promise<void> {
92
- this.originalContent = await this.changeSetFileService.read(this.uri);
93
- this.readOnlyResource.update({ contents: this.originalContent ?? '' });
116
+ this._originalContent = await this.changeSetFileService.read(this.uri);
117
+ if (this._readOnlyResource) {
118
+ this.readOnlyResource.update({ contents: this._originalContent ?? '' });
119
+ }
94
120
  }
95
121
 
96
122
  protected getInMemoryUri(uri: URI): ConfigurableMutableReferenceResource {
@@ -100,10 +126,14 @@ export class ChangeSetFileElement implements ChangeSetElement {
100
126
  protected listenForOriginalFileChanges(): void {
101
127
  this.toDispose.push(this.fileService.onDidFilesChange(async event => {
102
128
  if (!event.contains(this.uri)) { return; }
129
+ if (!this._initialized && this._initializationPromise) {
130
+ // make sure we are initialized
131
+ await this._initializationPromise;
132
+ }
103
133
  // If we are applied, the tricky thing becomes the question what to revert to; otherwise, what to apply.
104
134
  const newContent = await this.changeSetFileService.read(this.uri).catch(() => '');
105
135
  this.readOnlyResource.update({ contents: newContent });
106
- if (newContent === this.originalContent) {
136
+ if (newContent === this._originalContent) {
107
137
  this.state = 'pending';
108
138
  } else if (newContent === this.targetState) {
109
139
  this.state = 'applied';
@@ -120,10 +150,19 @@ export class ChangeSetFileElement implements ChangeSetElement {
120
150
  protected get readOnlyResource(): ConfigurableMutableReferenceResource {
121
151
  if (!this._readOnlyResource) {
122
152
  this._readOnlyResource = this.getInMemoryUri(ChangeSetFileElement.toReadOnlyUri(this.uri, this.elementProps.chatSessionId));
123
- this._readOnlyResource.update({ autosaveable: false, readOnly: true });
153
+ this._readOnlyResource.update({
154
+ autosaveable: false,
155
+ readOnly: true,
156
+ contents: this._originalContent ?? ''
157
+ });
124
158
  this.toDispose.push(this._readOnlyResource);
125
- this.obtainOriginalContent();
126
- this.listenForOriginalFileChanges();
159
+
160
+ // If not yet initialized, update the resource once initialization completes
161
+ if (!this._initialized) {
162
+ this._initializationPromise?.then(() => {
163
+ this._readOnlyResource?.update({ contents: this._originalContent ?? '' });
164
+ });
165
+ }
127
166
  }
128
167
  return this._readOnlyResource;
129
168
  }
@@ -180,15 +219,33 @@ export class ChangeSetFileElement implements ChangeSetElement {
180
219
  return this.elementProps.data;
181
220
  };
182
221
 
222
+ get originalContent(): string | undefined {
223
+ if (!this._initialized && this._initializationPromise) {
224
+ console.warn('Accessing originalContent before initialization is complete. Consider using async methods.');
225
+ }
226
+ return this._originalContent;
227
+ }
228
+
229
+ /**
230
+ * Gets the original content of the file asynchronously.
231
+ * Ensures initialization is complete before returning the content.
232
+ */
233
+ async getOriginalContent(): Promise<string | undefined> {
234
+ await this.ensureInitialized();
235
+ return this._originalContent;
236
+ }
237
+
183
238
  get targetState(): string {
184
239
  return this.elementProps.targetState ?? '';
185
240
  }
186
241
 
187
242
  async open(): Promise<void> {
243
+ await this.ensureInitialized();
188
244
  this.changeSetFileService.open(this);
189
245
  }
190
246
 
191
247
  async openChange(): Promise<void> {
248
+ await this.ensureInitialized();
192
249
  this.changeSetFileService.openDiff(
193
250
  this.readOnlyUri,
194
251
  this.changedUri
@@ -196,6 +253,7 @@ export class ChangeSetFileElement implements ChangeSetElement {
196
253
  }
197
254
 
198
255
  async apply(contents?: string): Promise<void> {
256
+ await this.ensureInitialized();
199
257
  if (!await this.confirm('Apply')) { return; }
200
258
  if (!(await this.changeSetFileService.trySave(this.changedUri))) {
201
259
  if (this.type === 'delete') {
@@ -214,16 +272,18 @@ export class ChangeSetFileElement implements ChangeSetElement {
214
272
  }
215
273
 
216
274
  onShow(): void {
275
+ // Ensure we have the latest state when showing
217
276
  this.changeResource.update({ contents: this.targetState, onSave: content => this.writeChanges(content) });
218
277
  }
219
278
 
220
279
  async revert(): Promise<void> {
280
+ await this.ensureInitialized();
221
281
  if (!await this.confirm('Revert')) { return; }
222
282
  this.state = 'pending';
223
283
  if (this.type === 'add') {
224
284
  await this.changeSetFileService.delete(this.uri);
225
- } else if (this.originalContent) {
226
- await this.changeSetFileService.write(this.uri, this.originalContent);
285
+ } else if (this._originalContent) {
286
+ await this.changeSetFileService.write(this.uri, this._originalContent);
227
287
  }
228
288
  }
229
289
 
@@ -29,7 +29,7 @@ import {
29
29
  * Enum for tool confirmation modes
30
30
  */
31
31
  export enum ToolConfirmationMode {
32
- YOLO = 'yolo',
32
+ ALWAYS_ALLOW = 'always_allow',
33
33
  CONFIRM = 'confirm',
34
34
  DISABLED = 'disabled'
35
35
  }
@@ -43,7 +43,7 @@ export const chatToolPreferences: PreferenceSchema = {
43
43
  type: 'object',
44
44
  additionalProperties: {
45
45
  type: 'string',
46
- enum: [ToolConfirmationMode.YOLO, ToolConfirmationMode.CONFIRM, ToolConfirmationMode.DISABLED],
46
+ enum: [ToolConfirmationMode.ALWAYS_ALLOW, ToolConfirmationMode.CONFIRM, ToolConfirmationMode.DISABLED],
47
47
  enumDescriptions: [
48
48
  nls.localize('theia/ai/chat/toolConfirmation/yolo/description', 'Execute tools automatically without confirmation'),
49
49
  nls.localize('theia/ai/chat/toolConfirmation/confirm/description', 'Ask for confirmation before executing tools'),
@@ -110,7 +110,7 @@ export class ToolConfirmationManager {
110
110
  if (toolConfirmation['*']) {
111
111
  return toolConfirmation['*'];
112
112
  }
113
- return ToolConfirmationMode.YOLO; // Default to YOLO
113
+ return ToolConfirmationMode.ALWAYS_ALLOW; // Default to Always Allow
114
114
  }
115
115
 
116
116
  /**
@@ -121,7 +121,7 @@ export class ToolConfirmationManager {
121
121
  // Determine the global default (star entry), or fallback to schema default
122
122
  let starMode = current['*'];
123
123
  if (starMode === undefined) {
124
- starMode = ToolConfirmationMode.YOLO;
124
+ starMode = ToolConfirmationMode.ALWAYS_ALLOW;
125
125
  }
126
126
  if (mode === starMode) {
127
127
  // Remove the toolId entry if it exists
@@ -42,7 +42,7 @@ export class FrontendChatToolRequestService extends ChatToolRequestService {
42
42
  case ToolConfirmationMode.DISABLED:
43
43
  return { denied: true, message: `Tool ${toolRequest.id} is disabled` };
44
44
 
45
- case ToolConfirmationMode.YOLO:
45
+ case ToolConfirmationMode.ALWAYS_ALLOW:
46
46
  // Execute immediately without confirmation
47
47
  return toolRequest.handler(arg_string, request);
48
48
 
@@ -0,0 +1,55 @@
1
+ // *****************************************************************************
2
+ // Copyright (C) 2025 EclipseSource GmbH.
3
+ //
4
+ // This program and the accompanying materials are made available under the
5
+ // terms of the Eclipse Public License v. 2.0 which is available at
6
+ // http://www.eclipse.org/legal/epl-2.0.
7
+ //
8
+ // This Source Code may also be made available under the following Secondary
9
+ // Licenses when the conditions for such availability set forth in the Eclipse
10
+ // Public License v. 2.0 are satisfied: GNU General Public License, version 2
11
+ // with the GNU Classpath Exception which is available at
12
+ // https://www.gnu.org/software/classpath/license.html.
13
+ //
14
+ // SPDX-License-Identifier: EPL-2.0 OR GPL-2.0-only WITH Classpath-exception-2.0
15
+ // *****************************************************************************
16
+ import { isObject } from '@theia/core';
17
+ import { ChatRequestInvocation, ChatResponseContent } from '../common';
18
+
19
+ /**
20
+ * Response Content created when an Agent delegates a prompt to another agent.
21
+ * Contains agent id, delegated prompt, and the response.
22
+ */
23
+ export class DelegationResponseContent implements ChatResponseContent {
24
+ kind = 'AgentDelegation';
25
+
26
+ /**
27
+ * @param agentId The id of the agent to whom the task was delegated
28
+ * @param prompt The prompt that was delegated
29
+ * @param response The response from the delegated agent
30
+ */
31
+ constructor(
32
+ public agentId: string,
33
+ public prompt: string,
34
+ public response: ChatRequestInvocation
35
+ ) {
36
+ // Empty
37
+ }
38
+
39
+ asString(): string {
40
+ const json = {
41
+ agentId: this.agentId,
42
+ prompt: this.prompt
43
+ };
44
+ return JSON.stringify(json);
45
+ }
46
+ }
47
+
48
+ export function isDelegationResponseContent(
49
+ value: unknown
50
+ ): value is DelegationResponseContent {
51
+ return (
52
+ isObject<DelegationResponseContent>(value) &&
53
+ value.kind === 'AgentDelegation'
54
+ );
55
+ }