@theia/ai-ide 1.64.0-next.35 → 1.64.1

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 (145) 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.js +1 -1
  37. package/lib/browser/app-tester-chat-agent.js.map +1 -1
  38. package/lib/browser/architect-agent.js +1 -1
  39. package/lib/browser/architect-agent.js.map +1 -1
  40. package/lib/browser/coder-agent.js +1 -1
  41. package/lib/browser/coder-agent.js.map +1 -1
  42. package/lib/browser/context-functions.d.ts.map +1 -1
  43. package/lib/browser/context-functions.js +12 -0
  44. package/lib/browser/context-functions.js.map +1 -1
  45. package/lib/browser/context-functions.spec.d.ts +2 -0
  46. package/lib/browser/context-functions.spec.d.ts.map +1 -0
  47. package/lib/browser/context-functions.spec.js +93 -0
  48. package/lib/browser/context-functions.spec.js.map +1 -0
  49. package/lib/browser/file-changeset-function.spec.d.ts +2 -0
  50. package/lib/browser/file-changeset-function.spec.d.ts.map +1 -0
  51. package/lib/browser/file-changeset-function.spec.js +45 -0
  52. package/lib/browser/file-changeset-function.spec.js.map +1 -0
  53. package/lib/browser/file-changeset-functions.d.ts +13 -3
  54. package/lib/browser/file-changeset-functions.d.ts.map +1 -1
  55. package/lib/browser/file-changeset-functions.js +100 -29
  56. package/lib/browser/file-changeset-functions.js.map +1 -1
  57. package/lib/browser/file-changeset-functions.spec.d.ts +2 -0
  58. package/lib/browser/file-changeset-functions.spec.d.ts.map +1 -0
  59. package/lib/browser/file-changeset-functions.spec.js +161 -0
  60. package/lib/browser/file-changeset-functions.spec.js.map +1 -0
  61. package/lib/browser/frontend-module.d.ts.map +1 -1
  62. package/lib/browser/frontend-module.js +20 -0
  63. package/lib/browser/frontend-module.js.map +1 -1
  64. package/lib/browser/ide-chat-welcome-message-provider.js +2 -2
  65. package/lib/browser/ide-chat-welcome-message-provider.js.map +1 -1
  66. package/lib/browser/test/tool-provider-cancellation-test-util.spec.d.ts +2 -0
  67. package/lib/browser/test/tool-provider-cancellation-test-util.spec.d.ts.map +1 -0
  68. package/lib/browser/test/tool-provider-cancellation-test-util.spec.js +52 -0
  69. package/lib/browser/test/tool-provider-cancellation-test-util.spec.js.map +1 -0
  70. package/lib/browser/workspace-functions.d.ts +3 -3
  71. package/lib/browser/workspace-functions.d.ts.map +1 -1
  72. package/lib/browser/workspace-functions.js +79 -28
  73. package/lib/browser/workspace-functions.js.map +1 -1
  74. package/lib/browser/workspace-functions.spec.d.ts +2 -0
  75. package/lib/browser/workspace-functions.spec.d.ts.map +1 -0
  76. package/lib/browser/workspace-functions.spec.js +161 -0
  77. package/lib/browser/workspace-functions.spec.js.map +1 -0
  78. package/lib/browser/workspace-launch-provider.d.ts +24 -0
  79. package/lib/browser/workspace-launch-provider.d.ts.map +1 -0
  80. package/lib/browser/workspace-launch-provider.js +216 -0
  81. package/lib/browser/workspace-launch-provider.js.map +1 -0
  82. package/lib/browser/workspace-launch-provider.spec.d.ts +2 -0
  83. package/lib/browser/workspace-launch-provider.spec.d.ts.map +1 -0
  84. package/lib/browser/workspace-launch-provider.spec.js +245 -0
  85. package/lib/browser/workspace-launch-provider.spec.js.map +1 -0
  86. package/lib/browser/workspace-search-provider.d.ts.map +1 -1
  87. package/lib/browser/workspace-search-provider.js +9 -0
  88. package/lib/browser/workspace-search-provider.js.map +1 -1
  89. package/lib/browser/workspace-search-provider.spec.js +59 -203
  90. package/lib/browser/workspace-search-provider.spec.js.map +1 -1
  91. package/lib/browser/workspace-task-provider.d.ts.map +1 -1
  92. package/lib/browser/workspace-task-provider.js +8 -1
  93. package/lib/browser/workspace-task-provider.js.map +1 -1
  94. package/lib/browser/workspace-task-provider.spec.d.ts +2 -0
  95. package/lib/browser/workspace-task-provider.spec.d.ts.map +1 -0
  96. package/lib/browser/workspace-task-provider.spec.js +109 -0
  97. package/lib/browser/workspace-task-provider.spec.js.map +1 -0
  98. package/lib/common/architect-prompt-template.d.ts.map +1 -1
  99. package/lib/common/architect-prompt-template.js +11 -0
  100. package/lib/common/architect-prompt-template.js.map +1 -1
  101. package/lib/common/command-chat-agents.js +1 -1
  102. package/lib/common/command-chat-agents.js.map +1 -1
  103. package/lib/common/orchestrator-chat-agent.js +1 -1
  104. package/lib/common/orchestrator-chat-agent.js.map +1 -1
  105. package/lib/common/universal-chat-agent.js +1 -1
  106. package/lib/common/universal-chat-agent.js.map +1 -1
  107. package/lib/common/workspace-functions.d.ts +3 -0
  108. package/lib/common/workspace-functions.d.ts.map +1 -1
  109. package/lib/common/workspace-functions.js +4 -1
  110. package/lib/common/workspace-functions.js.map +1 -1
  111. package/package.json +18 -17
  112. package/src/browser/ai-configuration/agent-configuration-widget.tsx +18 -2
  113. package/src/browser/ai-configuration/ai-configuration-service.ts +14 -1
  114. package/src/browser/ai-configuration/ai-configuration-widget.tsx +7 -1
  115. package/src/browser/ai-configuration/language-model-renderer.tsx +87 -59
  116. package/src/browser/ai-configuration/model-aliases-configuration-widget.tsx +279 -0
  117. package/src/browser/ai-configuration/prompt-fragments-configuration-widget.tsx +43 -13
  118. package/src/browser/ai-configuration/template-settings-renderer.tsx +11 -7
  119. package/src/browser/ai-ide-activation-service.ts +65 -0
  120. package/src/browser/ai-ide-preferences.ts +44 -0
  121. package/src/browser/app-tester-chat-agent.ts +1 -1
  122. package/src/browser/architect-agent.ts +1 -1
  123. package/src/browser/coder-agent.ts +1 -1
  124. package/src/browser/context-functions.spec.ts +102 -0
  125. package/src/browser/context-functions.ts +11 -0
  126. package/src/browser/file-changeset-function.spec.ts +52 -0
  127. package/src/browser/file-changeset-functions.spec.ts +212 -0
  128. package/src/browser/file-changeset-functions.ts +102 -25
  129. package/src/browser/frontend-module.ts +29 -1
  130. package/src/browser/ide-chat-welcome-message-provider.tsx +4 -4
  131. package/src/browser/style/index.css +111 -6
  132. package/src/browser/test/tool-provider-cancellation-test-util.spec.ts +60 -0
  133. package/src/browser/workspace-functions.spec.ts +199 -0
  134. package/src/browser/workspace-functions.ts +105 -32
  135. package/src/browser/workspace-launch-provider.spec.ts +320 -0
  136. package/src/browser/workspace-launch-provider.ts +231 -0
  137. package/src/browser/workspace-search-provider.spec.ts +79 -229
  138. package/src/browser/workspace-search-provider.ts +10 -1
  139. package/src/browser/workspace-task-provider.spec.ts +125 -0
  140. package/src/browser/workspace-task-provider.ts +7 -2
  141. package/src/common/architect-prompt-template.ts +11 -0
  142. package/src/common/command-chat-agents.ts +1 -1
  143. package/src/common/orchestrator-chat-agent.ts +1 -1
  144. package/src/common/universal-chat-agent.ts +1 -1
  145. package/src/common/workspace-functions.ts +3 -0
@@ -14,242 +14,92 @@
14
14
  // SPDX-License-Identifier: EPL-2.0 OR GPL-2.0-only WITH Classpath-exception-2.0
15
15
  // *****************************************************************************
16
16
 
17
- import { FrontendApplicationConfigProvider } from '@theia/core/lib/browser/frontend-application-config-provider';
18
- import { enableJSDOM } from '@theia/core/lib/browser/test/jsdom';
19
- let disableJSDOM = enableJSDOM();
20
- FrontendApplicationConfigProvider.set({});
21
-
22
17
  import { expect } from 'chai';
23
- import { URI } from '@theia/core';
24
- import { SearchInWorkspaceResult, LinePreview } from '@theia/search-in-workspace/lib/common/search-in-workspace-interface';
25
- import { optimizeSearchResults } from '../common/workspace-search-provider-util';
26
-
27
- disableJSDOM();
28
-
29
- describe('WorkspaceSearchProvider - Token Optimization', () => {
30
-
31
- before(() => {
32
- disableJSDOM = enableJSDOM();
18
+ import { CancellationTokenSource } from '@theia/core';
19
+ import { WorkspaceSearchProvider } from './workspace-search-provider';
20
+ import { MutableChatRequestModel, MutableChatResponseModel } from '@theia/ai-chat';
21
+ import { Container } from '@theia/core/shared/inversify';
22
+ import { SearchInWorkspaceService, SearchInWorkspaceCallbacks } from '@theia/search-in-workspace/lib/browser/search-in-workspace-service';
23
+ import { WorkspaceFunctionScope } from './workspace-functions';
24
+ import { PreferenceService } from '@theia/core/lib/browser';
25
+ import { FileService } from '@theia/filesystem/lib/browser/file-service';
26
+ import { URI } from '@theia/core/lib/common/uri';
27
+ import { SearchInWorkspaceOptions } from '@theia/search-in-workspace/lib/common/search-in-workspace-interface';
28
+
29
+ describe('Workspace Search Provider Cancellation Tests', () => {
30
+ let cancellationTokenSource: CancellationTokenSource;
31
+ let mockCtx: Partial<MutableChatRequestModel>;
32
+ let container: Container;
33
+ let searchService: SearchInWorkspaceService;
34
+
35
+ beforeEach(() => {
36
+ cancellationTokenSource = new CancellationTokenSource();
37
+
38
+ // Setup mock context
39
+ mockCtx = {
40
+ response: {
41
+ cancellationToken: cancellationTokenSource.token
42
+ } as MutableChatResponseModel
43
+ };
44
+
45
+ // Create a new container for each test
46
+ container = new Container();
47
+
48
+ // Mock dependencies
49
+ searchService = {
50
+ searchWithCallback: async (
51
+ query: string,
52
+ rootUris: string[],
53
+ callbacks: SearchInWorkspaceCallbacks,
54
+ options: SearchInWorkspaceOptions
55
+ ) => {
56
+ const searchId = 1;
57
+ return searchId;
58
+ },
59
+ cancel: (searchId: number) => {
60
+ // Mock cancellation
61
+ }
62
+ } as unknown as SearchInWorkspaceService;
63
+
64
+ const mockWorkspaceScope = {
65
+ getWorkspaceRoot: async () => new URI('file:///workspace'),
66
+ ensureWithinWorkspace: () => { },
67
+ resolveRelativePath: async (path: string) => new URI(`file:///workspace/${path}`)
68
+ } as unknown as WorkspaceFunctionScope;
69
+
70
+ const mockPreferenceService = {
71
+ get: () => 30
72
+ };
73
+
74
+ const mockFileService = {
75
+ exists: async () => true,
76
+ resolve: async () => ({ isDirectory: true })
77
+ } as unknown as FileService;
78
+
79
+ // Register mocks in the container
80
+ container.bind(SearchInWorkspaceService).toConstantValue(searchService);
81
+ container.bind(WorkspaceFunctionScope).toConstantValue(mockWorkspaceScope);
82
+ container.bind(PreferenceService).toConstantValue(mockPreferenceService);
83
+ container.bind(FileService).toConstantValue(mockFileService);
84
+ container.bind(WorkspaceSearchProvider).toSelf();
33
85
  });
34
86
 
35
- after(() => {
36
- disableJSDOM();
87
+ afterEach(() => {
88
+ cancellationTokenSource.dispose();
37
89
  });
38
90
 
39
- describe('optimizeSearchResults method', () => {
40
- it('should preserve all information while optimizing format', () => {
41
- const workspaceRoot = new URI('file:///workspace');
42
- const mockResults: SearchInWorkspaceResult[] = [
43
- {
44
- root: 'file:///workspace',
45
- fileUri: 'file:///workspace/src/test.ts',
46
- matches: [
47
- {
48
- line: 1,
49
- character: 5,
50
- length: 8,
51
- lineText: ' const test = "hello"; '
52
- },
53
- {
54
- line: 5,
55
- character: 10,
56
- length: 4,
57
- lineText: '\t\tfunction test() { }\n'
58
- }
59
- ]
60
- },
61
- {
62
- root: 'file:///workspace',
63
- fileUri: 'file:///workspace/lib/utils.js',
64
- matches: [
65
- {
66
- line: 10,
67
- character: 0,
68
- length: 6,
69
- lineText: 'export default function() {}'
70
- }
71
- ]
72
- }
73
- ];
74
-
75
- const result = optimizeSearchResults(mockResults, workspaceRoot);
76
-
77
- expect(result).to.have.length(2);
78
-
79
- // First file
80
- expect(result[0]).to.deep.equal({
81
- file: 'src/test.ts',
82
- matches: [
83
- {
84
- line: 1,
85
- text: 'const test = "hello";'
86
- },
87
- {
88
- line: 5,
89
- text: 'function test() { }'
90
- }
91
- ]
92
- });
93
-
94
- // Second file
95
- expect(result[1]).to.deep.equal({
96
- file: 'lib/utils.js',
97
- matches: [
98
- {
99
- line: 10,
100
- text: 'export default function() {}'
101
- }
102
- ]
103
- });
104
- });
105
-
106
- it('should handle LinePreview objects correctly', () => {
107
- const workspaceRoot = new URI('file:///workspace');
108
- const linePreview: LinePreview = {
109
- text: ' preview text with spaces ',
110
- character: 5
111
- };
112
-
113
- const mockResults: SearchInWorkspaceResult[] = [
114
- {
115
- root: 'file:///workspace',
116
- fileUri: 'file:///workspace/preview.ts',
117
- matches: [
118
- {
119
- line: 3,
120
- character: 5,
121
- length: 7,
122
- lineText: linePreview
123
- }
124
- ]
125
- }
126
- ];
127
-
128
- const result = optimizeSearchResults(mockResults, workspaceRoot);
129
-
130
- expect(result[0].matches[0]).to.deep.equal({
131
- line: 3,
132
- text: 'preview text with spaces'
133
- });
134
- });
135
-
136
- it('should handle empty LinePreview text gracefully', () => {
137
- const workspaceRoot = new URI('file:///workspace');
138
- const linePreview: LinePreview = {
139
- text: '',
140
- character: 0
141
- };
91
+ it('should respect cancellation token at the beginning of the search', async () => {
92
+ const searchProvider = container.get(WorkspaceSearchProvider);
93
+ cancellationTokenSource.cancel();
142
94
 
143
- const mockResults: SearchInWorkspaceResult[] = [
144
- {
145
- root: 'file:///workspace',
146
- fileUri: 'file:///workspace/empty.ts',
147
- matches: [
148
- {
149
- line: 1,
150
- character: 0,
151
- length: 0,
152
- lineText: linePreview
153
- }
154
- ]
155
- }
156
- ];
95
+ const handler = searchProvider.getTool().handler;
96
+ const result = await handler(
97
+ JSON.stringify({ query: 'test', useRegExp: false }),
98
+ mockCtx as MutableChatRequestModel
99
+ );
157
100
 
158
- const result = optimizeSearchResults(mockResults, workspaceRoot);
159
-
160
- expect(result[0].matches[0]).to.deep.equal({
161
- line: 1,
162
- text: ''
163
- });
164
- });
165
-
166
- it('should preserve semantic whitespace within lines', () => {
167
- const workspaceRoot = new URI('file:///workspace');
168
- const mockResults: SearchInWorkspaceResult[] = [
169
- {
170
- root: 'file:///workspace',
171
- fileUri: 'file:///workspace/spaces.ts',
172
- matches: [
173
- {
174
- line: 1,
175
- character: 0,
176
- length: 20,
177
- lineText: ' if (a && b) { '
178
- }
179
- ]
180
- }
181
- ];
182
-
183
- const result = optimizeSearchResults(mockResults, workspaceRoot);
184
-
185
- expect(result[0].matches[0].text).to.equal('if (a && b) {');
186
- });
187
-
188
- it('should use absolute URI when relative path cannot be determined', () => {
189
- const workspaceRoot = new URI('file:///different-workspace');
190
- const mockResults: SearchInWorkspaceResult[] = [
191
- {
192
- root: 'file:///workspace',
193
- fileUri: 'file:///workspace/outside.ts',
194
- matches: [
195
- {
196
- line: 1,
197
- character: 0,
198
- length: 4,
199
- lineText: 'test'
200
- }
201
- ]
202
- }
203
- ];
204
-
205
- const result = optimizeSearchResults(mockResults, workspaceRoot);
206
-
207
- expect(result[0].file).to.equal('file:///workspace/outside.ts');
208
- });
101
+ const jsonResponse = JSON.parse(result as string);
102
+ expect(jsonResponse.error).to.equal('Operation cancelled by user');
209
103
  });
210
104
 
211
- describe('token efficiency validation', () => {
212
- it('should produce more compact JSON than original format', () => {
213
- const workspaceRoot = new URI('file:///workspace');
214
- const mockResults: SearchInWorkspaceResult[] = [
215
- {
216
- root: 'file:///workspace',
217
- fileUri: 'file:///workspace/src/test.ts',
218
- matches: [
219
- {
220
- line: 1,
221
- character: 5,
222
- length: 8,
223
- lineText: ' const test = "hello"; '
224
- }
225
- ]
226
- }
227
- ];
228
-
229
- // Original format (simulated)
230
- const originalFormat = JSON.stringify([{
231
- root: 'file:///workspace',
232
- fileUri: 'file:///workspace/src/test.ts',
233
- matches: [{
234
- line: 1,
235
- character: 5,
236
- length: 8,
237
- lineText: ' const test = "hello"; '
238
- }]
239
- }]);
240
-
241
- // Optimized format
242
- const optimizedResults = optimizeSearchResults(mockResults, workspaceRoot);
243
- const optimizedFormat = JSON.stringify(optimizedResults);
244
-
245
- // The optimized format should be significantly shorter
246
- expect(optimizedFormat.length).to.be.lessThan(originalFormat.length);
247
-
248
- // But should preserve essential information
249
- const parsed = JSON.parse(optimizedFormat);
250
- expect(parsed[0].file).to.equal('src/test.ts');
251
- expect(parsed[0].matches[0].line).to.equal(1);
252
- expect(parsed[0].matches[0].text).to.equal('const test = "hello";');
253
- });
254
- });
255
105
  });
@@ -111,6 +111,16 @@ export class WorkspaceSearchProvider implements ToolProvider {
111
111
  let expectedSearchId: number | undefined;
112
112
  let searchCompleted = false;
113
113
 
114
+ cancellationToken?.onCancellationRequested(() => {
115
+ if (expectedSearchId !== undefined && !searchCompleted) {
116
+ this.searchService.cancel(expectedSearchId);
117
+ searchCompleted = true;
118
+ }
119
+ });
120
+ if (cancellationToken?.isCancellationRequested) {
121
+ return JSON.stringify({ error: 'Operation cancelled by user' });
122
+ }
123
+
114
124
  const searchPromise = new Promise<SearchInWorkspaceResult[]>(async (resolve, reject) => {
115
125
  const callbacks: SearchInWorkspaceCallbacks = {
116
126
  onResult: (id, result) => {
@@ -167,7 +177,6 @@ export class WorkspaceSearchProvider implements ToolProvider {
167
177
  searchCompleted = true;
168
178
  reject(err);
169
179
  });
170
-
171
180
  });
172
181
 
173
182
  const timeoutPromise = new Promise<SearchInWorkspaceResult[]>((_, reject) => {
@@ -0,0 +1,125 @@
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 { expect } from 'chai';
18
+ import { CancellationTokenSource } from '@theia/core';
19
+ import { TaskListProvider, TaskRunnerProvider } from './workspace-task-provider';
20
+ import { MutableChatRequestModel, MutableChatResponseModel } from '@theia/ai-chat';
21
+ import { Container } from '@theia/core/shared/inversify';
22
+ import { TaskService } from '@theia/task/lib/browser/task-service';
23
+ import { TerminalService } from '@theia/terminal/lib/browser/base/terminal-service';
24
+ import { TaskConfiguration, TaskInfo } from '@theia/task/lib/common';
25
+ import { TerminalWidget } from '@theia/terminal/lib/browser/base/terminal-widget';
26
+
27
+ describe('Workspace Task Provider Cancellation Tests', () => {
28
+ let cancellationTokenSource: CancellationTokenSource;
29
+ let mockCtx: Partial<MutableChatRequestModel>;
30
+ let container: Container;
31
+ let mockTaskService: TaskService;
32
+ let mockTerminalService: TerminalService;
33
+
34
+ beforeEach(() => {
35
+ cancellationTokenSource = new CancellationTokenSource();
36
+
37
+ // Setup mock context
38
+ mockCtx = {
39
+ response: {
40
+ cancellationToken: cancellationTokenSource.token
41
+ } as MutableChatResponseModel
42
+ };
43
+
44
+ // Create a new container for each test
45
+ container = new Container();
46
+
47
+ // Mock dependencies
48
+ mockTaskService = {
49
+ startUserAction: () => 123,
50
+ getTasks: async (token: number) => [
51
+ {
52
+ label: 'build',
53
+ _scope: 'workspace',
54
+ type: 'shell'
55
+ } as TaskConfiguration,
56
+ {
57
+ label: 'test',
58
+ _scope: 'workspace',
59
+ type: 'shell'
60
+ } as TaskConfiguration
61
+ ],
62
+ runTaskByLabel: async (token: number, taskLabel: string) => {
63
+ if (taskLabel === 'build' || taskLabel === 'test') {
64
+ return {
65
+ taskId: 0,
66
+ terminalId: 0,
67
+ config: {
68
+ label: taskLabel,
69
+ _scope: 'workspace',
70
+ type: 'shell'
71
+ }
72
+ } as TaskInfo;
73
+ }
74
+ return undefined;
75
+ },
76
+ terminateTask: async (activeTaskInfo: TaskInfo) => {
77
+ // Track termination
78
+ },
79
+ getTerminateSignal: async () => 'SIGTERM'
80
+ } as unknown as TaskService;
81
+
82
+ mockTerminalService = {
83
+ getByTerminalId: () => ({
84
+ buffer: {
85
+ length: 10,
86
+ getLines: () => ['line1', 'line2', 'line3'],
87
+ },
88
+ clearOutput: () => { }
89
+ } as unknown as TerminalWidget)
90
+ } as unknown as TerminalService;
91
+
92
+ // Register mocks in the container
93
+ container.bind(TaskService).toConstantValue(mockTaskService);
94
+ container.bind(TerminalService).toConstantValue(mockTerminalService);
95
+ container.bind(TaskListProvider).toSelf();
96
+ container.bind(TaskRunnerProvider).toSelf();
97
+ });
98
+
99
+ afterEach(() => {
100
+ cancellationTokenSource.dispose();
101
+ });
102
+
103
+ it('TaskListProvider should respect cancellation token', async () => {
104
+ const taskListProvider = container.get(TaskListProvider);
105
+ cancellationTokenSource.cancel();
106
+
107
+ const handler = taskListProvider.getTool().handler;
108
+ const result = await handler(JSON.stringify({ filter: '' }), mockCtx as MutableChatRequestModel);
109
+
110
+ const jsonResponse = JSON.parse(result as string);
111
+ expect(jsonResponse.error).to.equal('Operation cancelled by user');
112
+ });
113
+
114
+ it('TaskRunnerProvider should respect cancellation token at the beginning', async () => {
115
+ const taskRunnerProvider = container.get(TaskRunnerProvider);
116
+ cancellationTokenSource.cancel();
117
+
118
+ const handler = taskRunnerProvider.getTool().handler;
119
+ const result = await handler(JSON.stringify({ taskName: 'build' }), mockCtx as MutableChatRequestModel);
120
+
121
+ const jsonResponse = JSON.parse(result as string);
122
+ expect(jsonResponse.error).to.equal('Operation cancelled by user');
123
+ });
124
+
125
+ });
@@ -43,7 +43,10 @@ export class TaskListProvider implements ToolProvider {
43
43
  },
44
44
  required: ['filter']
45
45
  },
46
- handler: async (argString: string) => {
46
+ handler: async (argString: string, ctx: MutableChatRequestModel) => {
47
+ if (ctx?.response?.cancellationToken?.isCancellationRequested) {
48
+ return JSON.stringify({ error: 'Operation cancelled by user' });
49
+ }
47
50
  const filterArgs: { filter: string } = JSON.parse(argString);
48
51
  const tasks = await this.getAvailableTasks(filterArgs.filter);
49
52
  const taskString = JSON.stringify(tasks);
@@ -101,7 +104,9 @@ export class TaskRunnerProvider implements ToolProvider {
101
104
  cancellationToken?.onCancellationRequested(() => {
102
105
  this.taskService.terminateTask(taskInfo);
103
106
  });
104
-
107
+ if (cancellationToken?.isCancellationRequested) {
108
+ return JSON.stringify({ error: 'Operation cancelled by user' });
109
+ }
105
110
  const signal = await this.taskService.getTerminateSignal(taskInfo.taskId);
106
111
  if (taskInfo.terminalId) {
107
112
  const terminal = this.terminalService.getByTerminalId(taskInfo.terminalId!);
@@ -109,6 +109,7 @@ Skip irrelevant information, e.g. for discussions, only sum up the final result.
109
109
  2. Identify the main coding objective and requirements.
110
110
  3. Propose a clear approach to implement the requested functionality in task steps.
111
111
  4. If any part of the task is ambiguous, note the ambiguity so that it can be clarified later.
112
+ 5. If there are any relevant examples on how to implement something correctly, add them
112
113
 
113
114
  Focus on providing actionable steps and implementation guidance. The coding agent needs practical help with this specific coding task.
114
115
 
@@ -144,6 +145,16 @@ Use the following format, but only include the sections that were discussed in t
144
145
  **Technology Choices:**
145
146
  - [Frameworks, libraries, services, tools]
146
147
 
148
+ **Files expected to be changed**
149
+ List all files that are expected to be changed (using relative file path) and quickly explain what is expected to be changed in this file.
150
+
151
+ ### Examples
152
+
153
+ List all examples of existing code that are useful to understand the design and do the implementation.
154
+ These examples are not the files supposed to be changed, but code that shows how to implement specific things.
155
+ Prefer to mention files instead of adding their content.
156
+ Explain the purpose of every example.
157
+
147
158
  ---
148
159
 
149
160
  ## 3. 🧪 Testing
@@ -51,7 +51,7 @@ export class CommandChatAgent extends AbstractTextToModelParsingChatAgent<Parsed
51
51
  name = 'Command';
52
52
  languageModelRequirements: LanguageModelRequirement[] = [{
53
53
  purpose: 'command',
54
- identifier: 'openai/gpt-4o',
54
+ identifier: 'default/universal',
55
55
  }];
56
56
  protected defaultLanguageModelPurpose: string = 'command';
57
57
 
@@ -32,7 +32,7 @@ export class OrchestratorChatAgent extends AbstractStreamParsingChatAgent {
32
32
  name = OrchestratorChatAgentId;
33
33
  languageModelRequirements: LanguageModelRequirement[] = [{
34
34
  purpose: 'agent-selection',
35
- identifier: 'openai/gpt-4o',
35
+ identifier: 'default/universal',
36
36
  }];
37
37
  protected defaultLanguageModelPurpose: string = 'agent-selection';
38
38
 
@@ -27,7 +27,7 @@ export class UniversalChatAgent extends AbstractStreamParsingChatAgent {
27
27
  name = UniversalChatAgentId;
28
28
  languageModelRequirements: LanguageModelRequirement[] = [{
29
29
  purpose: 'chat',
30
- identifier: 'openai/gpt-4o',
30
+ identifier: 'default/universal',
31
31
  }];
32
32
  protected defaultLanguageModelPurpose: string = 'chat';
33
33
  override description = nls.localize('theia/ai/chat/universal/description', 'This agent is designed to help software developers by providing concise and accurate '
@@ -20,3 +20,6 @@ export const GET_FILE_DIAGNOSTICS_ID = 'getFileDiagnostics';
20
20
  export const SEARCH_IN_WORKSPACE_FUNCTION_ID = 'searchInWorkspace';
21
21
  export const LIST_TASKS_FUNCTION_ID = 'listTasks';
22
22
  export const RUN_TASK_FUNCTION_ID = 'runTask';
23
+ export const LIST_LAUNCH_CONFIGURATIONS_FUNCTION_ID = 'listLaunchConfigurations';
24
+ export const RUN_LAUNCH_CONFIGURATION_FUNCTION_ID = 'runLaunchConfiguration';
25
+ export const STOP_LAUNCH_CONFIGURATION_FUNCTION_ID = 'stopLaunchConfiguration';