@theia/ai-ide 1.64.0-next.28 → 1.64.0

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 (152) hide show
  1. package/lib/browser/ai-configuration/agent-configuration-widget.d.ts +5 -2
  2. package/lib/browser/ai-configuration/agent-configuration-widget.d.ts.map +1 -1
  3. package/lib/browser/ai-configuration/agent-configuration-widget.js +15 -1
  4. package/lib/browser/ai-configuration/agent-configuration-widget.js.map +1 -1
  5. package/lib/browser/ai-configuration/ai-configuration-service.d.ts +6 -1
  6. package/lib/browser/ai-configuration/ai-configuration-service.d.ts.map +1 -1
  7. package/lib/browser/ai-configuration/ai-configuration-service.js +10 -1
  8. package/lib/browser/ai-configuration/ai-configuration-service.js.map +1 -1
  9. package/lib/browser/ai-configuration/ai-configuration-widget.d.ts +2 -0
  10. package/lib/browser/ai-configuration/ai-configuration-widget.d.ts.map +1 -1
  11. package/lib/browser/ai-configuration/ai-configuration-widget.js +7 -1
  12. package/lib/browser/ai-configuration/ai-configuration-widget.js.map +1 -1
  13. package/lib/browser/ai-configuration/language-model-renderer.d.ts +4 -2
  14. package/lib/browser/ai-configuration/language-model-renderer.d.ts.map +1 -1
  15. package/lib/browser/ai-configuration/language-model-renderer.js +49 -71
  16. package/lib/browser/ai-configuration/language-model-renderer.js.map +1 -1
  17. package/lib/browser/ai-configuration/model-aliases-configuration-widget.d.ts +41 -0
  18. package/lib/browser/ai-configuration/model-aliases-configuration-widget.d.ts.map +1 -0
  19. package/lib/browser/ai-configuration/model-aliases-configuration-widget.js +225 -0
  20. package/lib/browser/ai-configuration/model-aliases-configuration-widget.js.map +1 -0
  21. package/lib/browser/ai-configuration/prompt-fragments-configuration-widget.d.ts +7 -3
  22. package/lib/browser/ai-configuration/prompt-fragments-configuration-widget.d.ts.map +1 -1
  23. package/lib/browser/ai-configuration/prompt-fragments-configuration-widget.js +35 -13
  24. package/lib/browser/ai-configuration/prompt-fragments-configuration-widget.js.map +1 -1
  25. package/lib/browser/ai-configuration/template-settings-renderer.d.ts.map +1 -1
  26. package/lib/browser/ai-configuration/template-settings-renderer.js +11 -6
  27. package/lib/browser/ai-configuration/template-settings-renderer.js.map +1 -1
  28. package/lib/browser/ai-ide-activation-service.d.ts +18 -0
  29. package/lib/browser/ai-ide-activation-service.d.ts.map +1 -0
  30. package/lib/browser/ai-ide-activation-service.js +72 -0
  31. package/lib/browser/ai-ide-activation-service.js.map +1 -0
  32. package/lib/browser/ai-ide-preferences.d.ts +4 -0
  33. package/lib/browser/ai-ide-preferences.d.ts.map +1 -0
  34. package/lib/browser/ai-ide-preferences.js +43 -0
  35. package/lib/browser/ai-ide-preferences.js.map +1 -0
  36. package/lib/browser/app-tester-chat-agent.d.ts +3 -6
  37. package/lib/browser/app-tester-chat-agent.d.ts.map +1 -1
  38. package/lib/browser/app-tester-chat-agent.js +6 -71
  39. package/lib/browser/app-tester-chat-agent.js.map +1 -1
  40. package/lib/browser/app-tester-prompt-template.d.ts +6 -0
  41. package/lib/browser/app-tester-prompt-template.d.ts.map +1 -0
  42. package/lib/browser/app-tester-prompt-template.js +79 -0
  43. package/lib/browser/app-tester-prompt-template.js.map +1 -0
  44. package/lib/browser/architect-agent.js +1 -1
  45. package/lib/browser/architect-agent.js.map +1 -1
  46. package/lib/browser/coder-agent.js +1 -1
  47. package/lib/browser/coder-agent.js.map +1 -1
  48. package/lib/browser/context-functions.d.ts.map +1 -1
  49. package/lib/browser/context-functions.js +12 -0
  50. package/lib/browser/context-functions.js.map +1 -1
  51. package/lib/browser/context-functions.spec.d.ts +2 -0
  52. package/lib/browser/context-functions.spec.d.ts.map +1 -0
  53. package/lib/browser/context-functions.spec.js +93 -0
  54. package/lib/browser/context-functions.spec.js.map +1 -0
  55. package/lib/browser/file-changeset-function.spec.d.ts +2 -0
  56. package/lib/browser/file-changeset-function.spec.d.ts.map +1 -0
  57. package/lib/browser/file-changeset-function.spec.js +45 -0
  58. package/lib/browser/file-changeset-function.spec.js.map +1 -0
  59. package/lib/browser/file-changeset-functions.d.ts +13 -3
  60. package/lib/browser/file-changeset-functions.d.ts.map +1 -1
  61. package/lib/browser/file-changeset-functions.js +100 -29
  62. package/lib/browser/file-changeset-functions.js.map +1 -1
  63. package/lib/browser/file-changeset-functions.spec.d.ts +2 -0
  64. package/lib/browser/file-changeset-functions.spec.d.ts.map +1 -0
  65. package/lib/browser/file-changeset-functions.spec.js +161 -0
  66. package/lib/browser/file-changeset-functions.spec.js.map +1 -0
  67. package/lib/browser/frontend-module.d.ts.map +1 -1
  68. package/lib/browser/frontend-module.js +20 -0
  69. package/lib/browser/frontend-module.js.map +1 -1
  70. package/lib/browser/ide-chat-welcome-message-provider.js +2 -2
  71. package/lib/browser/ide-chat-welcome-message-provider.js.map +1 -1
  72. package/lib/browser/test/tool-provider-cancellation-test-util.spec.d.ts +2 -0
  73. package/lib/browser/test/tool-provider-cancellation-test-util.spec.d.ts.map +1 -0
  74. package/lib/browser/test/tool-provider-cancellation-test-util.spec.js +52 -0
  75. package/lib/browser/test/tool-provider-cancellation-test-util.spec.js.map +1 -0
  76. package/lib/browser/workspace-functions.d.ts +3 -3
  77. package/lib/browser/workspace-functions.d.ts.map +1 -1
  78. package/lib/browser/workspace-functions.js +79 -28
  79. package/lib/browser/workspace-functions.js.map +1 -1
  80. package/lib/browser/workspace-functions.spec.d.ts +2 -0
  81. package/lib/browser/workspace-functions.spec.d.ts.map +1 -0
  82. package/lib/browser/workspace-functions.spec.js +161 -0
  83. package/lib/browser/workspace-functions.spec.js.map +1 -0
  84. package/lib/browser/workspace-launch-provider.d.ts +24 -0
  85. package/lib/browser/workspace-launch-provider.d.ts.map +1 -0
  86. package/lib/browser/workspace-launch-provider.js +216 -0
  87. package/lib/browser/workspace-launch-provider.js.map +1 -0
  88. package/lib/browser/workspace-launch-provider.spec.d.ts +2 -0
  89. package/lib/browser/workspace-launch-provider.spec.d.ts.map +1 -0
  90. package/lib/browser/workspace-launch-provider.spec.js +245 -0
  91. package/lib/browser/workspace-launch-provider.spec.js.map +1 -0
  92. package/lib/browser/workspace-search-provider.d.ts.map +1 -1
  93. package/lib/browser/workspace-search-provider.js +9 -0
  94. package/lib/browser/workspace-search-provider.js.map +1 -1
  95. package/lib/browser/workspace-search-provider.spec.js +59 -203
  96. package/lib/browser/workspace-search-provider.spec.js.map +1 -1
  97. package/lib/browser/workspace-task-provider.d.ts.map +1 -1
  98. package/lib/browser/workspace-task-provider.js +8 -1
  99. package/lib/browser/workspace-task-provider.js.map +1 -1
  100. package/lib/browser/workspace-task-provider.spec.d.ts +2 -0
  101. package/lib/browser/workspace-task-provider.spec.d.ts.map +1 -0
  102. package/lib/browser/workspace-task-provider.spec.js +109 -0
  103. package/lib/browser/workspace-task-provider.spec.js.map +1 -0
  104. package/lib/common/architect-prompt-template.d.ts.map +1 -1
  105. package/lib/common/architect-prompt-template.js +11 -0
  106. package/lib/common/architect-prompt-template.js.map +1 -1
  107. package/lib/common/command-chat-agents.js +1 -1
  108. package/lib/common/command-chat-agents.js.map +1 -1
  109. package/lib/common/orchestrator-chat-agent.js +1 -1
  110. package/lib/common/orchestrator-chat-agent.js.map +1 -1
  111. package/lib/common/universal-chat-agent.js +1 -1
  112. package/lib/common/universal-chat-agent.js.map +1 -1
  113. package/lib/common/workspace-functions.d.ts +3 -0
  114. package/lib/common/workspace-functions.d.ts.map +1 -1
  115. package/lib/common/workspace-functions.js +4 -1
  116. package/lib/common/workspace-functions.js.map +1 -1
  117. package/package.json +18 -17
  118. package/src/browser/ai-configuration/agent-configuration-widget.tsx +18 -2
  119. package/src/browser/ai-configuration/ai-configuration-service.ts +14 -1
  120. package/src/browser/ai-configuration/ai-configuration-widget.tsx +7 -1
  121. package/src/browser/ai-configuration/language-model-renderer.tsx +87 -59
  122. package/src/browser/ai-configuration/model-aliases-configuration-widget.tsx +279 -0
  123. package/src/browser/ai-configuration/prompt-fragments-configuration-widget.tsx +43 -13
  124. package/src/browser/ai-configuration/template-settings-renderer.tsx +11 -7
  125. package/src/browser/ai-ide-activation-service.ts +65 -0
  126. package/src/browser/ai-ide-preferences.ts +44 -0
  127. package/src/browser/app-tester-chat-agent.ts +5 -73
  128. package/src/browser/app-tester-prompt-template.ts +81 -0
  129. package/src/browser/architect-agent.ts +1 -1
  130. package/src/browser/coder-agent.ts +1 -1
  131. package/src/browser/context-functions.spec.ts +102 -0
  132. package/src/browser/context-functions.ts +11 -0
  133. package/src/browser/file-changeset-function.spec.ts +52 -0
  134. package/src/browser/file-changeset-functions.spec.ts +212 -0
  135. package/src/browser/file-changeset-functions.ts +102 -25
  136. package/src/browser/frontend-module.ts +29 -1
  137. package/src/browser/ide-chat-welcome-message-provider.tsx +4 -4
  138. package/src/browser/style/index.css +111 -6
  139. package/src/browser/test/tool-provider-cancellation-test-util.spec.ts +60 -0
  140. package/src/browser/workspace-functions.spec.ts +199 -0
  141. package/src/browser/workspace-functions.ts +105 -32
  142. package/src/browser/workspace-launch-provider.spec.ts +320 -0
  143. package/src/browser/workspace-launch-provider.ts +231 -0
  144. package/src/browser/workspace-search-provider.spec.ts +79 -229
  145. package/src/browser/workspace-search-provider.ts +10 -1
  146. package/src/browser/workspace-task-provider.spec.ts +125 -0
  147. package/src/browser/workspace-task-provider.ts +7 -2
  148. package/src/common/architect-prompt-template.ts +11 -0
  149. package/src/common/command-chat-agents.ts +1 -1
  150. package/src/common/orchestrator-chat-agent.ts +1 -1
  151. package/src/common/universal-chat-agent.ts +1 -1
  152. package/src/common/workspace-functions.ts +3 -0
@@ -13,24 +13,31 @@
13
13
  //
14
14
  // SPDX-License-Identifier: EPL-2.0 OR GPL-2.0-only WITH Classpath-exception-2.0
15
15
  // *****************************************************************************
16
- import { injectable, inject } from '@theia/core/shared/inversify';
17
- import { ToolProvider, ToolRequest, ToolRequestParameters, ToolRequestParametersProperties } from '@theia/ai-core';
18
- import { WorkspaceFunctionScope } from './workspace-functions';
19
- import { ChangeSetElementArgs, ChangeSetFileElement, ChangeSetFileElementFactory } from '@theia/ai-chat/lib/browser/change-set-file-element';
20
16
  import { ChangeSet, MutableChatRequestModel } from '@theia/ai-chat';
21
- import { FileService } from '@theia/filesystem/lib/browser/file-service';
17
+ import { ChangeSetElementArgs, ChangeSetFileElement, ChangeSetFileElementFactory } from '@theia/ai-chat/lib/browser/change-set-file-element';
18
+ import { ToolProvider, ToolRequest, ToolRequestParameters, ToolRequestParametersProperties } from '@theia/ai-core';
22
19
  import { ContentReplacer, Replacement } from '@theia/core/lib/common/content-replacer';
23
20
  import { URI } from '@theia/core/lib/common/uri';
21
+ import { inject, injectable } from '@theia/core/shared/inversify';
22
+ import { FileService } from '@theia/filesystem/lib/browser/file-service';
23
+ import { WorkspaceFunctionScope } from './workspace-functions';
24
24
 
25
+ import { nls } from '@theia/core';
25
26
  import {
27
+ CLEAR_FILE_CHANGES_ID,
28
+ GET_PROPOSED_CHANGES_ID,
26
29
  SUGGEST_FILE_CONTENT_ID,
27
- WRITE_FILE_CONTENT_ID,
28
30
  SUGGEST_FILE_REPLACEMENTS_ID,
29
- WRITE_FILE_REPLACEMENTS_ID,
30
- CLEAR_FILE_CHANGES_ID,
31
- GET_PROPOSED_CHANGES_ID
31
+ WRITE_FILE_CONTENT_ID,
32
+ WRITE_FILE_REPLACEMENTS_ID
32
33
  } from '../common/file-changeset-function-ids';
33
34
 
35
+ export const FileChangeSetTitleProvider = Symbol('FileChangeSetTitleProvider');
36
+
37
+ export interface FileChangeSetTitleProvider {
38
+ getChangeSetTitle(ctx: MutableChatRequestModel): string;
39
+ }
40
+
34
41
  @injectable()
35
42
  export class SuggestFileContent implements ToolProvider {
36
43
  static ID = SUGGEST_FILE_CONTENT_ID;
@@ -44,6 +51,9 @@ export class SuggestFileContent implements ToolProvider {
44
51
  @inject(ChangeSetFileElementFactory)
45
52
  protected readonly fileChangeFactory: ChangeSetFileElementFactory;
46
53
 
54
+ @inject(FileChangeSetTitleProvider)
55
+ protected readonly fileChangeSetTitleProvider: FileChangeSetTitleProvider;
56
+
47
57
  getTool(): ToolRequest {
48
58
  return {
49
59
  id: SuggestFileContent.ID,
@@ -68,6 +78,9 @@ export class SuggestFileContent implements ToolProvider {
68
78
  required: ['path', 'content']
69
79
  },
70
80
  handler: async (args: string, ctx: MutableChatRequestModel): Promise<string> => {
81
+ if (ctx?.response?.cancellationToken?.isCancellationRequested) {
82
+ return JSON.stringify({ error: 'Operation cancelled by user' });
83
+ }
71
84
  const { path, content } = JSON.parse(args);
72
85
  const chatSessionId = ctx.session.id;
73
86
  const uri = await this.workspaceFunctionScope.resolveRelativePath(path);
@@ -75,7 +88,7 @@ export class SuggestFileContent implements ToolProvider {
75
88
  if (content === '') {
76
89
  type = 'delete';
77
90
  }
78
- if (!await this.fileService.exists(uri)) {
91
+ if (!(await this.fileService.exists(uri))) {
79
92
  type = 'add';
80
93
  }
81
94
  ctx.session.changeSet.addElements(
@@ -88,7 +101,8 @@ export class SuggestFileContent implements ToolProvider {
88
101
  chatSessionId
89
102
  })
90
103
  );
91
- ctx.session.changeSet.setTitle('Changes proposed by Coder');
104
+
105
+ ctx.session.changeSet.setTitle(this.fileChangeSetTitleProvider.getChangeSetTitle(ctx));
92
106
  return `Proposed writing to file ${path}. The user will review and potentially apply the changes`;
93
107
  }
94
108
  };
@@ -108,6 +122,9 @@ export class WriteFileContent implements ToolProvider {
108
122
  @inject(ChangeSetFileElementFactory)
109
123
  protected readonly fileChangeFactory: ChangeSetFileElementFactory;
110
124
 
125
+ @inject(FileChangeSetTitleProvider)
126
+ protected readonly fileChangeSetTitleProvider: FileChangeSetTitleProvider;
127
+
111
128
  getTool(): ToolRequest {
112
129
  return {
113
130
  id: WriteFileContent.ID,
@@ -132,6 +149,9 @@ export class WriteFileContent implements ToolProvider {
132
149
  required: ['path', 'content']
133
150
  },
134
151
  handler: async (args: string, ctx: MutableChatRequestModel): Promise<string> => {
152
+ if (ctx?.response?.cancellationToken?.isCancellationRequested) {
153
+ return JSON.stringify({ error: 'Operation cancelled by user' });
154
+ }
135
155
  const { path, content } = JSON.parse(args);
136
156
  const chatSessionId = ctx.session.id;
137
157
  const uri = await this.workspaceFunctionScope.resolveRelativePath(path);
@@ -139,7 +159,7 @@ export class WriteFileContent implements ToolProvider {
139
159
  if (content === '') {
140
160
  type = 'delete';
141
161
  }
142
- if (!await this.fileService.exists(uri)) {
162
+ if (!(await this.fileService.exists(uri))) {
143
163
  type = 'add';
144
164
  }
145
165
 
@@ -153,7 +173,7 @@ export class WriteFileContent implements ToolProvider {
153
173
  chatSessionId
154
174
  });
155
175
 
156
- ctx.session.changeSet.setTitle('Changes applied by Coder');
176
+ ctx.session.changeSet.setTitle(this.fileChangeSetTitleProvider.getChangeSetTitle(ctx));
157
177
  // Add the element to the change set
158
178
  ctx.session.changeSet.addElements(fileElement);
159
179
 
@@ -180,6 +200,9 @@ export class ReplaceContentInFileFunctionHelper {
180
200
  @inject(ChangeSetFileElementFactory)
181
201
  protected readonly fileChangeFactory: ChangeSetFileElementFactory;
182
202
 
203
+ @inject(FileChangeSetTitleProvider)
204
+ protected readonly fileChangeSetTitleProvider: FileChangeSetTitleProvider;
205
+
183
206
  private replacer: ContentReplacer;
184
207
 
185
208
  constructor() {
@@ -249,12 +272,15 @@ export class ReplaceContentInFileFunctionHelper {
249
272
  description: replacementDescription,
250
273
  parameters: replacementParameters
251
274
  };
252
-
253
275
  }
254
276
 
255
277
  async createChangesetFromToolCall(toolCallString: string, ctx: MutableChatRequestModel): Promise<string> {
256
278
  try {
257
- const result = await this.processReplacementsCommon(toolCallString, ctx, 'Changes proposed by Coder');
279
+ if (ctx?.response?.cancellationToken?.isCancellationRequested) {
280
+ return JSON.stringify({ error: 'Operation cancelled by user' });
281
+ }
282
+
283
+ const result = await this.processReplacementsCommon(toolCallString, ctx, this.fileChangeSetTitleProvider.getChangeSetTitle(ctx));
258
284
 
259
285
  if (result.errors.length > 0) {
260
286
  return `Errors encountered: ${result.errors.join('; ')}`;
@@ -274,7 +300,11 @@ export class ReplaceContentInFileFunctionHelper {
274
300
 
275
301
  async writeChangesetFromToolCall(toolCallString: string, ctx: MutableChatRequestModel): Promise<string> {
276
302
  try {
277
- const result = await this.processReplacementsCommon(toolCallString, ctx, 'Changes applied by Coder');
303
+ if (ctx?.response?.cancellationToken?.isCancellationRequested) {
304
+ return JSON.stringify({ error: 'Operation cancelled by user' });
305
+ }
306
+
307
+ const result = await this.processReplacementsCommon(toolCallString, ctx, this.fileChangeSetTitleProvider.getChangeSetTitle(ctx));
278
308
 
279
309
  if (result.errors.length > 0) {
280
310
  return `Errors encountered: ${result.errors.join('; ')}`;
@@ -300,6 +330,10 @@ export class ReplaceContentInFileFunctionHelper {
300
330
  ctx: MutableChatRequestModel,
301
331
  changeSetTitle: string
302
332
  ): Promise<{ fileElement: ChangeSetFileElement | undefined, path: string, reset: boolean, errors: string[] }> {
333
+ if (ctx?.response?.cancellationToken?.isCancellationRequested) {
334
+ throw new Error('Operation cancelled by user');
335
+ }
336
+
303
337
  const { path, replacements, reset } = JSON.parse(toolCallString) as { path: string, replacements: Replacement[], reset?: boolean };
304
338
  const fileUri = await this.workspaceFunctionScope.resolveRelativePath(path);
305
339
 
@@ -318,6 +352,10 @@ export class ReplaceContentInFileFunctionHelper {
318
352
  }
319
353
  }
320
354
 
355
+ if (ctx?.response?.cancellationToken?.isCancellationRequested) {
356
+ throw new Error('Operation cancelled by user');
357
+ }
358
+
321
359
  const { updatedContent, errors } = this.replacer.applyReplacements(startingContent, replacements);
322
360
 
323
361
  if (errors.length > 0) {
@@ -348,11 +386,17 @@ export class ReplaceContentInFileFunctionHelper {
348
386
 
349
387
  private findExistingChangeElement(changeSet: ChangeSet, fileUri: URI): ChangeSetFileElement | undefined {
350
388
  const element = changeSet.getElementByURI(fileUri);
351
- if (element instanceof ChangeSetFileElement) { return element; }
389
+ if (element instanceof ChangeSetFileElement) {
390
+ return element;
391
+ }
352
392
  }
353
393
 
354
394
  async clearFileChanges(path: string, ctx: MutableChatRequestModel): Promise<string> {
355
395
  try {
396
+ if (ctx?.response?.cancellationToken?.isCancellationRequested) {
397
+ return JSON.stringify({ error: 'Operation cancelled by user' });
398
+ }
399
+
356
400
  const fileUri = await this.workspaceFunctionScope.resolveRelativePath(path);
357
401
  if (ctx.session.changeSet.removeElements(fileUri)) {
358
402
  return `Cleared pending change(s) for file ${path}.`;
@@ -367,6 +411,10 @@ export class ReplaceContentInFileFunctionHelper {
367
411
 
368
412
  async getProposedFileState(path: string, ctx: MutableChatRequestModel): Promise<string> {
369
413
  try {
414
+ if (ctx?.response?.cancellationToken?.isCancellationRequested) {
415
+ return JSON.stringify({ error: 'Operation cancelled by user' });
416
+ }
417
+
370
418
  const fileUri = await this.workspaceFunctionScope.resolveRelativePath(path);
371
419
 
372
420
  if (!ctx.session.changeSet) {
@@ -403,8 +451,12 @@ export class SimpleSuggestFileReplacements implements ToolProvider {
403
451
  name: SimpleSuggestFileReplacements.ID,
404
452
  description: metadata.description,
405
453
  parameters: metadata.parameters,
406
- handler: async (args: string, ctx: MutableChatRequestModel): Promise<string> =>
407
- this.replaceContentInFileFunctionHelper.createChangesetFromToolCall(args, ctx)
454
+ handler: async (args: string, ctx: MutableChatRequestModel): Promise<string> => {
455
+ if (ctx?.response?.cancellationToken?.isCancellationRequested) {
456
+ return JSON.stringify({ error: 'Operation cancelled by user' });
457
+ }
458
+ return this.replaceContentInFileFunctionHelper.createChangesetFromToolCall(args, ctx);
459
+ }
408
460
  };
409
461
  }
410
462
  }
@@ -422,8 +474,12 @@ export class SimpleWriteFileReplacements implements ToolProvider {
422
474
  name: SimpleWriteFileReplacements.ID,
423
475
  description: metadata.description,
424
476
  parameters: metadata.parameters,
425
- handler: async (args: string, ctx: MutableChatRequestModel): Promise<string> =>
426
- this.replaceContentInFileFunctionHelper.writeChangesetFromToolCall(args, ctx)
477
+ handler: async (args: string, ctx: MutableChatRequestModel): Promise<string> => {
478
+ if (ctx?.response?.cancellationToken?.isCancellationRequested) {
479
+ return JSON.stringify({ error: 'Operation cancelled by user' });
480
+ }
481
+ return this.replaceContentInFileFunctionHelper.writeChangesetFromToolCall(args, ctx);
482
+ }
427
483
  };
428
484
  }
429
485
  }
@@ -441,8 +497,12 @@ export class SuggestFileReplacements implements ToolProvider {
441
497
  name: SuggestFileReplacements.ID,
442
498
  description: metadata.description,
443
499
  parameters: metadata.parameters,
444
- handler: async (args: string, ctx: MutableChatRequestModel): Promise<string> =>
445
- this.replaceContentInFileFunctionHelper.createChangesetFromToolCall(args, ctx)
500
+ handler: async (args: string, ctx: MutableChatRequestModel): Promise<string> => {
501
+ if (ctx?.response?.cancellationToken?.isCancellationRequested) {
502
+ return JSON.stringify({ error: 'Operation cancelled by user' });
503
+ }
504
+ return this.replaceContentInFileFunctionHelper.createChangesetFromToolCall(args, ctx);
505
+ }
446
506
  };
447
507
  }
448
508
  }
@@ -460,8 +520,12 @@ export class WriteFileReplacements implements ToolProvider {
460
520
  name: WriteFileReplacements.ID,
461
521
  description: metadata.description,
462
522
  parameters: metadata.parameters,
463
- handler: async (args: string, ctx: MutableChatRequestModel): Promise<string> =>
464
- this.replaceContentInFileFunctionHelper.writeChangesetFromToolCall(args, ctx)
523
+ handler: async (args: string, ctx: MutableChatRequestModel): Promise<string> => {
524
+ if (ctx?.response?.cancellationToken?.isCancellationRequested) {
525
+ return JSON.stringify({ error: 'Operation cancelled by user' });
526
+ }
527
+ return this.replaceContentInFileFunctionHelper.writeChangesetFromToolCall(args, ctx);
528
+ }
465
529
  };
466
530
  }
467
531
  }
@@ -488,6 +552,9 @@ export class ClearFileChanges implements ToolProvider {
488
552
  required: ['path']
489
553
  },
490
554
  handler: async (args: string, ctx: MutableChatRequestModel): Promise<string> => {
555
+ if (ctx?.response?.cancellationToken?.isCancellationRequested) {
556
+ return JSON.stringify({ error: 'Operation cancelled by user' });
557
+ }
491
558
  const { path } = JSON.parse(args);
492
559
  return this.replaceContentInFileFunctionHelper.clearFileChanges(path, ctx);
493
560
  }
@@ -518,9 +585,19 @@ export class GetProposedFileState implements ToolProvider {
518
585
  required: ['path']
519
586
  },
520
587
  handler: async (args: string, ctx: MutableChatRequestModel): Promise<string> => {
588
+ if (ctx?.response?.cancellationToken?.isCancellationRequested) {
589
+ return JSON.stringify({ error: 'Operation cancelled by user' });
590
+ }
521
591
  const { path } = JSON.parse(args);
522
592
  return this.replaceContentInFileFunctionHelper.getProposedFileState(path, ctx);
523
593
  }
524
594
  };
525
595
  }
526
596
  }
597
+
598
+ @injectable()
599
+ export class DefaultFileChangeSetTitleProvider implements FileChangeSetTitleProvider {
600
+ getChangeSetTitle(ctx: MutableChatRequestModel): string {
601
+ return nls.localize('theia/ai-chat/fileChangeSetTitle', 'Changes proposed');
602
+ }
603
+ }
@@ -33,6 +33,11 @@ import {
33
33
  ServiceConnectionProvider
34
34
  } from '@theia/core/lib/browser';
35
35
  import { TaskListProvider, TaskRunnerProvider } from './workspace-task-provider';
36
+ import {
37
+ LaunchListProvider,
38
+ LaunchRunnerProvider,
39
+ LaunchStopProvider,
40
+ } from './workspace-launch-provider';
36
41
  import { WorkspacePreferencesSchema } from './workspace-preferences';
37
42
  import {
38
43
  ClearFileChanges,
@@ -43,7 +48,9 @@ import {
43
48
  SuggestFileContent,
44
49
  WriteFileContent,
45
50
  WriteFileReplacements,
46
- SimpleWriteFileReplacements
51
+ SimpleWriteFileReplacements,
52
+ FileChangeSetTitleProvider,
53
+ DefaultFileChangeSetTitleProvider
47
54
  } from './file-changeset-functions';
48
55
  import { OrchestratorChatAgent, OrchestratorChatAgentId } from '../common/orchestrator-chat-agent';
49
56
  import { UniversalChatAgent, UniversalChatAgentId } from '../common/universal-chat-agent';
@@ -71,10 +78,19 @@ import { CommandContribution } from '@theia/core';
71
78
  import { AIPromptFragmentsConfigurationWidget } from './ai-configuration/prompt-fragments-configuration-widget';
72
79
  import { BrowserAutomation, browserAutomationPath } from '../common/browser-automation-protocol';
73
80
  import { CloseBrowserProvider, IsBrowserRunningProvider, LaunchBrowserProvider, QueryDomProvider } from './app-tester-chat-functions';
81
+ import { ModelAliasesConfigurationWidget } from './ai-configuration/model-aliases-configuration-widget';
82
+ import { aiIdePreferenceSchema } from './ai-ide-preferences';
83
+ import { AIActivationService } from '@theia/ai-core/lib/browser';
84
+ import { AIIdeActivationServiceImpl } from './ai-ide-activation-service';
74
85
 
75
86
  export default new ContainerModule((bind, _unbind, _isBound, rebind) => {
87
+ bind(PreferenceContribution).toConstantValue({ schema: aiIdePreferenceSchema });
76
88
  bind(PreferenceContribution).toConstantValue({ schema: WorkspacePreferencesSchema });
77
89
 
90
+ bind(AIIdeActivationServiceImpl).toSelf().inSingletonScope();
91
+ // rebinds the default implementation of '@theia/ai-core'
92
+ rebind(AIActivationService).toService(AIIdeActivationServiceImpl);
93
+
78
94
  bind(ArchitectAgent).toSelf().inSingletonScope();
79
95
  bind(Agent).toService(ArchitectAgent);
80
96
  bind(ChatAgent).toService(ArchitectAgent);
@@ -119,7 +135,11 @@ export default new ContainerModule((bind, _unbind, _isBound, rebind) => {
119
135
  bindToolProvider(WriteFileContent, bind);
120
136
  bindToolProvider(TaskListProvider, bind);
121
137
  bindToolProvider(TaskRunnerProvider, bind);
138
+ bindToolProvider(LaunchListProvider, bind);
139
+ bindToolProvider(LaunchRunnerProvider, bind);
140
+ bindToolProvider(LaunchStopProvider, bind);
122
141
  bind(ReplaceContentInFileFunctionHelper).toSelf().inSingletonScope();
142
+ bind(FileChangeSetTitleProvider).to(DefaultFileChangeSetTitleProvider).inSingletonScope();
123
143
  bindToolProvider(SuggestFileReplacements, bind);
124
144
  bindToolProvider(WriteFileReplacements, bind);
125
145
  bindToolProvider(ListChatContext, bind);
@@ -157,6 +177,14 @@ export default new ContainerModule((bind, _unbind, _isBound, rebind) => {
157
177
  }))
158
178
  .inSingletonScope();
159
179
 
180
+ bind(ModelAliasesConfigurationWidget).toSelf();
181
+ bind(WidgetFactory)
182
+ .toDynamicValue(ctx => ({
183
+ id: ModelAliasesConfigurationWidget.ID,
184
+ createWidget: () => ctx.container.get(ModelAliasesConfigurationWidget)
185
+ }))
186
+ .inSingletonScope();
187
+
160
188
  bindToolProvider(SimpleSuggestFileReplacements, bind);
161
189
  bindToolProvider(SimpleWriteFileReplacements, bind);
162
190
  bindToolProvider(ClearFileChanges, bind);
@@ -85,7 +85,7 @@ export class IdeChatWelcomeMessageProvider implements ChatWelcomeMessageProvider
85
85
  <div className='theia-ResponseNode-Content' key={'disabled-message'}>
86
86
  <div className="disable-message">
87
87
  <span className="section-header">{
88
- nls.localize('theia/ai/chat-ui/chat-view-tree-widget/aiFeatureHeader', '🚀 AI Features Available (Alpha Version)!')}
88
+ nls.localize('theia/ai/chat-ui/chat-view-tree-widget/aiFeatureHeader', '🚀 AI Features Available (Beta Version)!')}
89
89
  </span>
90
90
  <div className="section-title">
91
91
  <p><code>{nls.localize('theia/ai/chat-ui/chat-view-tree-widget/featuresDisabled', 'Currently, all AI Features are disabled!')}</code></p>
@@ -96,14 +96,14 @@ export class IdeChatWelcomeMessageProvider implements ChatWelcomeMessageProvider
96
96
  <div className="section-content">
97
97
  <p>To enable the AI features, please go to the AI features section of the&nbsp;
98
98
  {this.renderLinkButton(nls.localize('theia/ai/chat-ui/chat-view-tree-widget/settingsMenu', 'the settings menu'),
99
- CommonCommands.OPEN_PREFERENCES.id, 'ai-features')}&nbsp;and
100
- </p>
99
+ CommonCommands.OPEN_PREFERENCES.id, 'ai-features')}&nbsp;and
100
+ </p>
101
101
  <ol>
102
102
  <li>Toggle the switch for <strong>{nls.localize('theia/ai/chat-ui/chat-view-tree-widget/aiFeaturesEnable', 'Ai-features: Enable')}</strong>.</li>
103
103
  <li>Provide at least one LLM provider (e.g. OpenAI). See <a href="https://theia-ide.org/docs/user_ai/" target="_blank">the documentation</a>
104
104
  &nbsp;for more information.</li>
105
105
  </ol>
106
- <p>This will activate the AI capabilities in the app. Please remember, these features are <strong>in an alpha state</strong>,
106
+ <p>This will activate the AI capabilities in the app. Please remember, these features are <strong>in a beta state</strong>,
107
107
  so they may change and we are working on improving them 🚧.<br></br>
108
108
  Please support us by <a href="https://github.com/eclipse-theia/theia">providing feedback
109
109
  </a>!</p>
@@ -64,7 +64,8 @@
64
64
  }
65
65
 
66
66
  #ai-variable-configuration-container-widget,
67
- #ai-agent-configuration-container-widget {
67
+ #ai-agent-configuration-container-widget,
68
+ #ai-model-aliases-configuration-widget {
68
69
  margin-top: 5px;
69
70
  }
70
71
 
@@ -86,21 +87,24 @@
86
87
  grid-template-columns: 1fr 2fr;
87
88
  }
88
89
 
89
- /* Agent Settings */
90
- #ai-agent-configuration-container-widget ul {
90
+ /* Agent and Model Alias Settings */
91
+ #ai-agent-configuration-container-widget ul,
92
+ #ai-model-aliases-configuration-widget .model-alias-configuration-list ul {
91
93
  list-style: none;
92
94
  padding: 0;
93
95
  margin: 0;
94
96
  }
95
97
 
96
- .ai-agent-configuration-main {
98
+ .ai-agent-configuration-main,
99
+ .model-alias-configuration-main {
97
100
  display: flex;
98
101
  flex-direction: row;
99
102
  }
100
103
 
101
104
  #ai-agent-configuration-container-widget
102
105
  .ai-agent-configuration-main
103
- .configuration-agents-list {
106
+ .configuration-agents-list,
107
+ #ai-model-aliases-configuration-widget .model-alias-configuration-list {
104
108
  min-width: 160px;
105
109
  overflow: hidden;
106
110
  white-space: nowrap;
@@ -109,7 +113,8 @@
109
113
  padding: var(--theia-ui-padding);
110
114
  }
111
115
 
112
- .configuration-agent-panel {
116
+ .configuration-agent-panel,
117
+ .model-alias-configuration-panel {
113
118
  flex: 1;
114
119
  }
115
120
 
@@ -337,6 +342,32 @@
337
342
  font-style: italic;
338
343
  }
339
344
 
345
+ .prompt-variant-warning {
346
+ color: var(--theia-warningForeground);
347
+ background: var(--theia-warningBackground);
348
+ border-left: 4px solid var(--theia-warningBorder);
349
+ padding: 6px 12px;
350
+ margin-bottom: 8px;
351
+ display: flex;
352
+ align-items: center;
353
+ gap: 8px;
354
+ border-radius: 3px;
355
+ font-size: 0.95em;
356
+ }
357
+
358
+ .prompt-variant-error {
359
+ color: var(--theia-errorForeground);
360
+ background: var(--theia-errorBackground);
361
+ border-left: 4px solid var(--theia-errorBorder);
362
+ padding: 6px 12px;
363
+ margin-bottom: 8px;
364
+ display: flex;
365
+ align-items: center;
366
+ gap: 8px;
367
+ border-radius: 3px;
368
+ font-size: 0.95em;
369
+ }
370
+
340
371
  /* Template content collapsable styles */
341
372
  .template-content-container {
342
373
  padding: 10px;
@@ -746,6 +777,80 @@ h4 {
746
777
 
747
778
  /* End AI Tools Configuration Widget Styles */
748
779
 
780
+ /* AI Model Aliases and Language Model Renderer extracted styles */
781
+ .ai-model-alias-list {
782
+ width: 25%;
783
+ }
784
+ .ai-alias-detail-title {
785
+ padding-left: 0;
786
+ padding-bottom: 10px;
787
+ }
788
+ .ai-alias-detail-description {
789
+ padding-bottom: 10px;
790
+ }
791
+ .ai-alias-detail-selected-model {
792
+ margin-bottom: 20px;
793
+ }
794
+ .ai-language-model-item-ready {
795
+ font-style: normal;
796
+ }
797
+ .ai-language-model-item-not-ready {
798
+ font-style: italic;
799
+ }
800
+ .ai-alias-priority-item-resolved {
801
+ font-weight: bold;
802
+ }
803
+ .ai-alias-priority-item-ready {
804
+ font-style: inherit;
805
+ }
806
+ .ai-alias-priority-item-not-ready {
807
+ font-style: italic;
808
+ }
809
+ .ai-alias-detail-defaults {
810
+ margin-bottom: 10px;
811
+ }
812
+ .ai-model-default-not-ready {
813
+ font-style: italic;
814
+ color: var(--theia-descriptionForeground);
815
+ }
816
+ .ai-alias-defaults-hint {
817
+ color: var(--theia-descriptionForeground);
818
+ margin-top: 8px;
819
+ }
820
+ .ai-alias-evaluates-to-container {
821
+ margin-top: 8px;
822
+ margin-bottom: 8px;
823
+ }
824
+ .ai-alias-evaluates-to-label {
825
+ font-weight: 600;
826
+ }
827
+ .ai-alias-evaluates-to-value {
828
+ margin-left: 8px;
829
+ }
830
+ .ai-model-status-ready {
831
+ color: green;
832
+ margin-left: 6px;
833
+ }
834
+ .ai-model-status-not-ready {
835
+ color: red;
836
+ margin-left: 6px;
837
+ }
838
+ .ai-alias-evaluates-to-unresolved {
839
+ margin-left: 8px;
840
+ color: var(--theia-descriptionForeground);
841
+ }
842
+ .ai-alias-detail-agents {
843
+ margin-bottom: 10px;
844
+ }
845
+ .ai-alias-agent-id {
846
+ color: var(--theia-descriptionForeground);
847
+ margin-left: 8px;
848
+ }
849
+ .ai-alias-no-agents {
850
+ color: var(--theia-descriptionForeground);
851
+ }
852
+ /* End AI Model Aliases and Language Model Renderer extracted styles */
853
+
749
854
  /* Token Usage Configuration Styles */
750
855
  .token-usage-configuration-title {
751
856
  margin: 0 0 16px 0;
@@ -0,0 +1,60 @@
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 { CancellationTokenSource } from '@theia/core';
18
+ import { expect } from 'chai';
19
+
20
+ // Simple test for cancellation handling
21
+ describe('Tool Provider Cancellation Tests', () => {
22
+ it('should verify basic cancellation token functionality', () => {
23
+ // Create a cancellation token source
24
+ const cts = new CancellationTokenSource();
25
+
26
+ // Initially the token should not be cancelled
27
+ expect(cts.token.isCancellationRequested).to.be.false;
28
+
29
+ // After cancellation, the token should report as cancelled
30
+ cts.cancel();
31
+ expect(cts.token.isCancellationRequested).to.be.true;
32
+
33
+ // Cleanup
34
+ cts.dispose();
35
+ });
36
+
37
+ it('should trigger cancellation callback when cancelled', async () => {
38
+ // Create a cancellation token source
39
+ const cts = new CancellationTokenSource();
40
+
41
+ // Create a flag to track if the callback was called
42
+ let callbackCalled = false;
43
+
44
+ // Register a cancellation callback
45
+ const disposable = cts.token.onCancellationRequested(() => {
46
+ callbackCalled = true;
47
+ });
48
+
49
+ // Initially the callback should not have been called
50
+ expect(callbackCalled).to.be.false;
51
+
52
+ // After cancellation, the callback should be called
53
+ cts.cancel();
54
+ expect(callbackCalled).to.be.true;
55
+
56
+ // Cleanup
57
+ disposable.dispose();
58
+ cts.dispose();
59
+ });
60
+ });