@theia/ai-ide 1.64.0-next.35 → 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.
- package/lib/browser/ai-configuration/agent-configuration-widget.d.ts +5 -2
- package/lib/browser/ai-configuration/agent-configuration-widget.d.ts.map +1 -1
- package/lib/browser/ai-configuration/agent-configuration-widget.js +15 -1
- package/lib/browser/ai-configuration/agent-configuration-widget.js.map +1 -1
- package/lib/browser/ai-configuration/ai-configuration-service.d.ts +6 -1
- package/lib/browser/ai-configuration/ai-configuration-service.d.ts.map +1 -1
- package/lib/browser/ai-configuration/ai-configuration-service.js +10 -1
- package/lib/browser/ai-configuration/ai-configuration-service.js.map +1 -1
- package/lib/browser/ai-configuration/ai-configuration-widget.d.ts +2 -0
- package/lib/browser/ai-configuration/ai-configuration-widget.d.ts.map +1 -1
- package/lib/browser/ai-configuration/ai-configuration-widget.js +7 -1
- package/lib/browser/ai-configuration/ai-configuration-widget.js.map +1 -1
- package/lib/browser/ai-configuration/language-model-renderer.d.ts +4 -2
- package/lib/browser/ai-configuration/language-model-renderer.d.ts.map +1 -1
- package/lib/browser/ai-configuration/language-model-renderer.js +49 -71
- package/lib/browser/ai-configuration/language-model-renderer.js.map +1 -1
- package/lib/browser/ai-configuration/model-aliases-configuration-widget.d.ts +41 -0
- package/lib/browser/ai-configuration/model-aliases-configuration-widget.d.ts.map +1 -0
- package/lib/browser/ai-configuration/model-aliases-configuration-widget.js +225 -0
- package/lib/browser/ai-configuration/model-aliases-configuration-widget.js.map +1 -0
- package/lib/browser/ai-configuration/prompt-fragments-configuration-widget.d.ts +7 -3
- package/lib/browser/ai-configuration/prompt-fragments-configuration-widget.d.ts.map +1 -1
- package/lib/browser/ai-configuration/prompt-fragments-configuration-widget.js +35 -13
- package/lib/browser/ai-configuration/prompt-fragments-configuration-widget.js.map +1 -1
- package/lib/browser/ai-configuration/template-settings-renderer.d.ts.map +1 -1
- package/lib/browser/ai-configuration/template-settings-renderer.js +11 -6
- package/lib/browser/ai-configuration/template-settings-renderer.js.map +1 -1
- package/lib/browser/ai-ide-activation-service.d.ts +18 -0
- package/lib/browser/ai-ide-activation-service.d.ts.map +1 -0
- package/lib/browser/ai-ide-activation-service.js +72 -0
- package/lib/browser/ai-ide-activation-service.js.map +1 -0
- package/lib/browser/ai-ide-preferences.d.ts +4 -0
- package/lib/browser/ai-ide-preferences.d.ts.map +1 -0
- package/lib/browser/ai-ide-preferences.js +43 -0
- package/lib/browser/ai-ide-preferences.js.map +1 -0
- package/lib/browser/app-tester-chat-agent.js +1 -1
- package/lib/browser/app-tester-chat-agent.js.map +1 -1
- package/lib/browser/architect-agent.js +1 -1
- package/lib/browser/architect-agent.js.map +1 -1
- package/lib/browser/coder-agent.js +1 -1
- package/lib/browser/coder-agent.js.map +1 -1
- package/lib/browser/context-functions.d.ts.map +1 -1
- package/lib/browser/context-functions.js +12 -0
- package/lib/browser/context-functions.js.map +1 -1
- package/lib/browser/context-functions.spec.d.ts +2 -0
- package/lib/browser/context-functions.spec.d.ts.map +1 -0
- package/lib/browser/context-functions.spec.js +93 -0
- package/lib/browser/context-functions.spec.js.map +1 -0
- package/lib/browser/file-changeset-function.spec.d.ts +2 -0
- package/lib/browser/file-changeset-function.spec.d.ts.map +1 -0
- package/lib/browser/file-changeset-function.spec.js +45 -0
- package/lib/browser/file-changeset-function.spec.js.map +1 -0
- package/lib/browser/file-changeset-functions.d.ts +13 -3
- package/lib/browser/file-changeset-functions.d.ts.map +1 -1
- package/lib/browser/file-changeset-functions.js +100 -29
- package/lib/browser/file-changeset-functions.js.map +1 -1
- package/lib/browser/file-changeset-functions.spec.d.ts +2 -0
- package/lib/browser/file-changeset-functions.spec.d.ts.map +1 -0
- package/lib/browser/file-changeset-functions.spec.js +161 -0
- package/lib/browser/file-changeset-functions.spec.js.map +1 -0
- package/lib/browser/frontend-module.d.ts.map +1 -1
- package/lib/browser/frontend-module.js +20 -0
- package/lib/browser/frontend-module.js.map +1 -1
- package/lib/browser/ide-chat-welcome-message-provider.js +2 -2
- package/lib/browser/ide-chat-welcome-message-provider.js.map +1 -1
- package/lib/browser/test/tool-provider-cancellation-test-util.spec.d.ts +2 -0
- package/lib/browser/test/tool-provider-cancellation-test-util.spec.d.ts.map +1 -0
- package/lib/browser/test/tool-provider-cancellation-test-util.spec.js +52 -0
- package/lib/browser/test/tool-provider-cancellation-test-util.spec.js.map +1 -0
- package/lib/browser/workspace-functions.d.ts +3 -3
- package/lib/browser/workspace-functions.d.ts.map +1 -1
- package/lib/browser/workspace-functions.js +79 -28
- package/lib/browser/workspace-functions.js.map +1 -1
- package/lib/browser/workspace-functions.spec.d.ts +2 -0
- package/lib/browser/workspace-functions.spec.d.ts.map +1 -0
- package/lib/browser/workspace-functions.spec.js +161 -0
- package/lib/browser/workspace-functions.spec.js.map +1 -0
- package/lib/browser/workspace-launch-provider.d.ts +24 -0
- package/lib/browser/workspace-launch-provider.d.ts.map +1 -0
- package/lib/browser/workspace-launch-provider.js +216 -0
- package/lib/browser/workspace-launch-provider.js.map +1 -0
- package/lib/browser/workspace-launch-provider.spec.d.ts +2 -0
- package/lib/browser/workspace-launch-provider.spec.d.ts.map +1 -0
- package/lib/browser/workspace-launch-provider.spec.js +245 -0
- package/lib/browser/workspace-launch-provider.spec.js.map +1 -0
- package/lib/browser/workspace-search-provider.d.ts.map +1 -1
- package/lib/browser/workspace-search-provider.js +9 -0
- package/lib/browser/workspace-search-provider.js.map +1 -1
- package/lib/browser/workspace-search-provider.spec.js +59 -203
- package/lib/browser/workspace-search-provider.spec.js.map +1 -1
- package/lib/browser/workspace-task-provider.d.ts.map +1 -1
- package/lib/browser/workspace-task-provider.js +8 -1
- package/lib/browser/workspace-task-provider.js.map +1 -1
- package/lib/browser/workspace-task-provider.spec.d.ts +2 -0
- package/lib/browser/workspace-task-provider.spec.d.ts.map +1 -0
- package/lib/browser/workspace-task-provider.spec.js +109 -0
- package/lib/browser/workspace-task-provider.spec.js.map +1 -0
- package/lib/common/architect-prompt-template.d.ts.map +1 -1
- package/lib/common/architect-prompt-template.js +11 -0
- package/lib/common/architect-prompt-template.js.map +1 -1
- package/lib/common/command-chat-agents.js +1 -1
- package/lib/common/command-chat-agents.js.map +1 -1
- package/lib/common/orchestrator-chat-agent.js +1 -1
- package/lib/common/orchestrator-chat-agent.js.map +1 -1
- package/lib/common/universal-chat-agent.js +1 -1
- package/lib/common/universal-chat-agent.js.map +1 -1
- package/lib/common/workspace-functions.d.ts +3 -0
- package/lib/common/workspace-functions.d.ts.map +1 -1
- package/lib/common/workspace-functions.js +4 -1
- package/lib/common/workspace-functions.js.map +1 -1
- package/package.json +18 -17
- package/src/browser/ai-configuration/agent-configuration-widget.tsx +18 -2
- package/src/browser/ai-configuration/ai-configuration-service.ts +14 -1
- package/src/browser/ai-configuration/ai-configuration-widget.tsx +7 -1
- package/src/browser/ai-configuration/language-model-renderer.tsx +87 -59
- package/src/browser/ai-configuration/model-aliases-configuration-widget.tsx +279 -0
- package/src/browser/ai-configuration/prompt-fragments-configuration-widget.tsx +43 -13
- package/src/browser/ai-configuration/template-settings-renderer.tsx +11 -7
- package/src/browser/ai-ide-activation-service.ts +65 -0
- package/src/browser/ai-ide-preferences.ts +44 -0
- package/src/browser/app-tester-chat-agent.ts +1 -1
- package/src/browser/architect-agent.ts +1 -1
- package/src/browser/coder-agent.ts +1 -1
- package/src/browser/context-functions.spec.ts +102 -0
- package/src/browser/context-functions.ts +11 -0
- package/src/browser/file-changeset-function.spec.ts +52 -0
- package/src/browser/file-changeset-functions.spec.ts +212 -0
- package/src/browser/file-changeset-functions.ts +102 -25
- package/src/browser/frontend-module.ts +29 -1
- package/src/browser/ide-chat-welcome-message-provider.tsx +4 -4
- package/src/browser/style/index.css +111 -6
- package/src/browser/test/tool-provider-cancellation-test-util.spec.ts +60 -0
- package/src/browser/workspace-functions.spec.ts +199 -0
- package/src/browser/workspace-functions.ts +105 -32
- package/src/browser/workspace-launch-provider.spec.ts +320 -0
- package/src/browser/workspace-launch-provider.ts +231 -0
- package/src/browser/workspace-search-provider.spec.ts +79 -229
- package/src/browser/workspace-search-provider.ts +10 -1
- package/src/browser/workspace-task-provider.spec.ts +125 -0
- package/src/browser/workspace-task-provider.ts +7 -2
- package/src/common/architect-prompt-template.ts +11 -0
- package/src/common/command-chat-agents.ts +1 -1
- package/src/common/orchestrator-chat-agent.ts +1 -1
- package/src/common/universal-chat-agent.ts +1 -1
- 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 {
|
|
24
|
-
import {
|
|
25
|
-
import {
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
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
|
-
|
|
36
|
-
|
|
87
|
+
afterEach(() => {
|
|
88
|
+
cancellationTokenSource.dispose();
|
|
37
89
|
});
|
|
38
90
|
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
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
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
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
|
-
|
|
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: '
|
|
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: '
|
|
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: '
|
|
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';
|