@theia/ai-ide 1.63.0-next.0 → 1.63.0-next.52
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/lib/browser/ai-configuration/ai-configuration-view-contribution.js +1 -1
- package/lib/browser/ai-configuration/ai-configuration-view-contribution.js.map +1 -1
- package/lib/browser/ai-configuration/ai-configuration-widget.d.ts +2 -1
- package/lib/browser/ai-configuration/ai-configuration-widget.d.ts.map +1 -1
- package/lib/browser/ai-configuration/ai-configuration-widget.js +6 -1
- package/lib/browser/ai-configuration/ai-configuration-widget.js.map +1 -1
- package/lib/browser/ai-configuration/prompt-fragments-configuration-widget.d.ts +0 -1
- package/lib/browser/ai-configuration/prompt-fragments-configuration-widget.d.ts.map +1 -1
- package/lib/browser/ai-configuration/prompt-fragments-configuration-widget.js +0 -1
- package/lib/browser/ai-configuration/prompt-fragments-configuration-widget.js.map +1 -1
- package/lib/browser/ai-configuration/token-usage-configuration-widget.d.ts +1 -0
- package/lib/browser/ai-configuration/token-usage-configuration-widget.d.ts.map +1 -1
- package/lib/browser/ai-configuration/token-usage-configuration-widget.js +25 -3
- package/lib/browser/ai-configuration/token-usage-configuration-widget.js.map +1 -1
- package/lib/browser/ai-configuration/tools-configuration-widget.d.ts +28 -0
- package/lib/browser/ai-configuration/tools-configuration-widget.d.ts.map +1 -0
- package/lib/browser/ai-configuration/tools-configuration-widget.js +148 -0
- package/lib/browser/ai-configuration/tools-configuration-widget.js.map +1 -0
- package/lib/browser/app-tester-chat-agent.d.ts +36 -0
- package/lib/browser/app-tester-chat-agent.d.ts.map +1 -0
- package/lib/browser/app-tester-chat-agent.js +172 -0
- package/lib/browser/app-tester-chat-agent.js.map +1 -0
- package/lib/browser/architect-agent.d.ts.map +1 -1
- package/lib/browser/architect-agent.js +4 -1
- package/lib/browser/architect-agent.js.map +1 -1
- package/lib/browser/coder-agent.d.ts.map +1 -1
- package/lib/browser/coder-agent.js +3 -3
- package/lib/browser/coder-agent.js.map +1 -1
- package/lib/browser/file-changeset-functions.d.ts +25 -6
- package/lib/browser/file-changeset-functions.d.ts.map +1 -1
- package/lib/browser/file-changeset-functions.js +248 -106
- package/lib/browser/file-changeset-functions.js.map +1 -1
- package/lib/browser/frontend-module.d.ts +1 -0
- package/lib/browser/frontend-module.d.ts.map +1 -1
- package/lib/browser/frontend-module.js +21 -5
- package/lib/browser/frontend-module.js.map +1 -1
- package/lib/browser/summarize-session-command-contribution.d.ts +6 -1
- package/lib/browser/summarize-session-command-contribution.d.ts.map +1 -1
- package/lib/browser/summarize-session-command-contribution.js +53 -4
- package/lib/browser/summarize-session-command-contribution.js.map +1 -1
- package/lib/browser/task-context-file-storage-service.d.ts +4 -2
- package/lib/browser/task-context-file-storage-service.d.ts.map +1 -1
- package/lib/browser/task-context-file-storage-service.js +19 -9
- package/lib/browser/task-context-file-storage-service.js.map +1 -1
- package/lib/browser/workspace-functions.d.ts.map +1 -1
- package/lib/browser/workspace-functions.js +6 -10
- package/lib/browser/workspace-functions.js.map +1 -1
- package/lib/browser/workspace-preferences.d.ts +1 -0
- package/lib/browser/workspace-preferences.d.ts.map +1 -1
- package/lib/browser/workspace-preferences.js +9 -1
- package/lib/browser/workspace-preferences.js.map +1 -1
- package/lib/browser/workspace-search-provider.d.ts +7 -1
- package/lib/browser/workspace-search-provider.d.ts.map +1 -1
- package/lib/browser/workspace-search-provider.js +73 -11
- package/lib/browser/workspace-search-provider.js.map +1 -1
- package/lib/browser/workspace-search-provider.spec.d.ts +2 -0
- package/lib/browser/workspace-search-provider.spec.d.ts.map +1 -0
- package/lib/browser/workspace-search-provider.spec.js +227 -0
- package/lib/browser/workspace-search-provider.spec.js.map +1 -0
- package/lib/common/architect-prompt-template.d.ts +1 -0
- package/lib/common/architect-prompt-template.d.ts.map +1 -1
- package/lib/common/architect-prompt-template.js +166 -5
- package/lib/common/architect-prompt-template.js.map +1 -1
- package/lib/common/coder-replace-prompt-template.d.ts +4 -5
- package/lib/common/coder-replace-prompt-template.d.ts.map +1 -1
- package/lib/common/coder-replace-prompt-template.js +95 -67
- package/lib/common/coder-replace-prompt-template.js.map +1 -1
- package/lib/common/file-changeset-function-ids.d.ts +7 -0
- package/lib/common/file-changeset-function-ids.d.ts.map +1 -0
- package/lib/common/file-changeset-function-ids.js +25 -0
- package/lib/common/file-changeset-function-ids.js.map +1 -0
- package/lib/common/summarize-session-commands.d.ts +1 -0
- package/lib/common/summarize-session-commands.d.ts.map +1 -1
- package/lib/common/summarize-session-commands.js +5 -1
- package/lib/common/summarize-session-commands.js.map +1 -1
- package/lib/common/workspace-search-provider-util.d.ts +17 -0
- package/lib/common/workspace-search-provider-util.d.ts.map +1 -0
- package/lib/common/workspace-search-provider-util.js +51 -0
- package/lib/common/workspace-search-provider-util.js.map +1 -0
- package/package.json +19 -18
- package/src/browser/ai-configuration/ai-configuration-view-contribution.ts +1 -1
- package/src/browser/ai-configuration/ai-configuration-widget.tsx +6 -1
- package/src/browser/ai-configuration/prompt-fragments-configuration-widget.tsx +0 -1
- package/src/browser/ai-configuration/token-usage-configuration-widget.tsx +63 -4
- package/src/browser/ai-configuration/tools-configuration-widget.tsx +178 -0
- package/src/browser/app-tester-chat-agent.ts +178 -0
- package/src/browser/architect-agent.ts +5 -2
- package/src/browser/coder-agent.ts +5 -5
- package/src/browser/file-changeset-functions.ts +236 -89
- package/src/browser/frontend-module.ts +33 -10
- package/src/browser/style/index.css +84 -11
- package/src/browser/summarize-session-command-contribution.ts +58 -6
- package/src/browser/task-context-file-storage-service.ts +20 -10
- package/src/browser/workspace-functions.ts +7 -11
- package/src/browser/workspace-preferences.ts +9 -0
- package/src/browser/workspace-search-provider.spec.ts +255 -0
- package/src/browser/workspace-search-provider.ts +78 -11
- package/src/common/architect-prompt-template.ts +165 -5
- package/src/common/coder-replace-prompt-template.ts +101 -65
- package/src/common/file-changeset-function-ids.ts +22 -0
- package/src/common/summarize-session-commands.ts +5 -0
- package/src/common/workspace-search-provider-util.ts +50 -0
|
@@ -16,15 +16,24 @@
|
|
|
16
16
|
import { injectable, inject } from '@theia/core/shared/inversify';
|
|
17
17
|
import { ToolProvider, ToolRequest, ToolRequestParameters, ToolRequestParametersProperties } from '@theia/ai-core';
|
|
18
18
|
import { WorkspaceFunctionScope } from './workspace-functions';
|
|
19
|
-
import { ChangeSetFileElement, ChangeSetFileElementFactory } from '@theia/ai-chat/lib/browser/change-set-file-element';
|
|
20
|
-
import { ChangeSet,
|
|
19
|
+
import { ChangeSetElementArgs, ChangeSetFileElement, ChangeSetFileElementFactory } from '@theia/ai-chat/lib/browser/change-set-file-element';
|
|
20
|
+
import { ChangeSet, MutableChatRequestModel } from '@theia/ai-chat';
|
|
21
21
|
import { FileService } from '@theia/filesystem/lib/browser/file-service';
|
|
22
22
|
import { ContentReplacer, Replacement } from '@theia/core/lib/common/content-replacer';
|
|
23
23
|
import { URI } from '@theia/core/lib/common/uri';
|
|
24
24
|
|
|
25
|
+
import {
|
|
26
|
+
SUGGEST_FILE_CONTENT_ID,
|
|
27
|
+
WRITE_FILE_CONTENT_ID,
|
|
28
|
+
SUGGEST_FILE_REPLACEMENTS_ID,
|
|
29
|
+
WRITE_FILE_REPLACEMENTS_ID,
|
|
30
|
+
CLEAR_FILE_CHANGES_ID,
|
|
31
|
+
GET_PROPOSED_CHANGES_ID
|
|
32
|
+
} from '../common/file-changeset-function-ids';
|
|
33
|
+
|
|
25
34
|
@injectable()
|
|
26
|
-
export class
|
|
27
|
-
static ID =
|
|
35
|
+
export class SuggestFileContent implements ToolProvider {
|
|
36
|
+
static ID = SUGGEST_FILE_CONTENT_ID;
|
|
28
37
|
|
|
29
38
|
@inject(WorkspaceFunctionScope)
|
|
30
39
|
protected readonly workspaceFunctionScope: WorkspaceFunctionScope;
|
|
@@ -37,8 +46,8 @@ export class WriteChangeToFileProvider implements ToolProvider {
|
|
|
37
46
|
|
|
38
47
|
getTool(): ToolRequest {
|
|
39
48
|
return {
|
|
40
|
-
id:
|
|
41
|
-
name:
|
|
49
|
+
id: SuggestFileContent.ID,
|
|
50
|
+
name: SuggestFileContent.ID,
|
|
42
51
|
description: `Proposes writing content to a file. If the file exists, it will be overwritten with the provided content.\n
|
|
43
52
|
If the file does not exist, it will be created. This tool will automatically create any directories needed to write the file.\n
|
|
44
53
|
If the new content is empty, the file will be deleted. To move a file, delete it and re-create it at the new location.\n
|
|
@@ -61,35 +70,105 @@ export class WriteChangeToFileProvider implements ToolProvider {
|
|
|
61
70
|
handler: async (args: string, ctx: MutableChatRequestModel): Promise<string> => {
|
|
62
71
|
const { path, content } = JSON.parse(args);
|
|
63
72
|
const chatSessionId = ctx.session.id;
|
|
64
|
-
let changeSet = ctx.session.changeSet;
|
|
65
|
-
if (!changeSet) {
|
|
66
|
-
changeSet = new ChangeSetImpl('Changes proposed by Coder');
|
|
67
|
-
ctx.session.setChangeSet(changeSet);
|
|
68
|
-
}
|
|
69
73
|
const uri = await this.workspaceFunctionScope.resolveRelativePath(path);
|
|
70
|
-
let type = 'modify';
|
|
74
|
+
let type: ChangeSetElementArgs['type'] = 'modify';
|
|
71
75
|
if (content === '') {
|
|
72
76
|
type = 'delete';
|
|
73
77
|
}
|
|
74
78
|
if (!await this.fileService.exists(uri)) {
|
|
75
79
|
type = 'add';
|
|
76
80
|
}
|
|
77
|
-
changeSet.addElements(
|
|
81
|
+
ctx.session.changeSet.addElements(
|
|
78
82
|
this.fileChangeFactory({
|
|
79
83
|
uri: uri,
|
|
80
|
-
type
|
|
84
|
+
type,
|
|
81
85
|
state: 'pending',
|
|
82
86
|
targetState: content,
|
|
83
|
-
|
|
87
|
+
requestId: ctx.id,
|
|
84
88
|
chatSessionId
|
|
85
89
|
})
|
|
86
90
|
);
|
|
91
|
+
ctx.session.changeSet.setTitle('Changes proposed by Coder');
|
|
87
92
|
return `Proposed writing to file ${path}. The user will review and potentially apply the changes`;
|
|
88
93
|
}
|
|
89
94
|
};
|
|
90
95
|
}
|
|
91
96
|
}
|
|
92
97
|
|
|
98
|
+
@injectable()
|
|
99
|
+
export class WriteFileContent implements ToolProvider {
|
|
100
|
+
static ID = WRITE_FILE_CONTENT_ID;
|
|
101
|
+
|
|
102
|
+
@inject(WorkspaceFunctionScope)
|
|
103
|
+
protected readonly workspaceFunctionScope: WorkspaceFunctionScope;
|
|
104
|
+
|
|
105
|
+
@inject(FileService)
|
|
106
|
+
fileService: FileService;
|
|
107
|
+
|
|
108
|
+
@inject(ChangeSetFileElementFactory)
|
|
109
|
+
protected readonly fileChangeFactory: ChangeSetFileElementFactory;
|
|
110
|
+
|
|
111
|
+
getTool(): ToolRequest {
|
|
112
|
+
return {
|
|
113
|
+
id: WriteFileContent.ID,
|
|
114
|
+
name: WriteFileContent.ID,
|
|
115
|
+
description: `Immediately writes content to a file. If the file exists, it will be overwritten with the provided content.\n
|
|
116
|
+
If the file does not exist, it will be created. This tool will automatically create any directories needed to write the file.\n
|
|
117
|
+
If the new content is empty, the file will be deleted. To move a file, delete it and re-create it at the new location.\n
|
|
118
|
+
Unlike suggestFileContent, this function applies the changes immediately without user confirmation.`,
|
|
119
|
+
parameters: {
|
|
120
|
+
type: 'object',
|
|
121
|
+
properties: {
|
|
122
|
+
path: {
|
|
123
|
+
type: 'string',
|
|
124
|
+
description: 'The path of the file to write to.'
|
|
125
|
+
},
|
|
126
|
+
content: {
|
|
127
|
+
type: 'string',
|
|
128
|
+
description: `The content to write to the file. ALWAYS provide the COMPLETE intended content of the file, without any truncation or omissions.\n
|
|
129
|
+
You MUST include ALL parts of the file, even if they haven\'t been modified.`
|
|
130
|
+
}
|
|
131
|
+
},
|
|
132
|
+
required: ['path', 'content']
|
|
133
|
+
},
|
|
134
|
+
handler: async (args: string, ctx: MutableChatRequestModel): Promise<string> => {
|
|
135
|
+
const { path, content } = JSON.parse(args);
|
|
136
|
+
const chatSessionId = ctx.session.id;
|
|
137
|
+
const uri = await this.workspaceFunctionScope.resolveRelativePath(path);
|
|
138
|
+
let type = 'modify';
|
|
139
|
+
if (content === '') {
|
|
140
|
+
type = 'delete';
|
|
141
|
+
}
|
|
142
|
+
if (!await this.fileService.exists(uri)) {
|
|
143
|
+
type = 'add';
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
// Create the file change element
|
|
147
|
+
const fileElement = this.fileChangeFactory({
|
|
148
|
+
uri: uri,
|
|
149
|
+
type: type as 'modify' | 'add' | 'delete',
|
|
150
|
+
state: 'pending',
|
|
151
|
+
targetState: content,
|
|
152
|
+
requestId: ctx.id,
|
|
153
|
+
chatSessionId
|
|
154
|
+
});
|
|
155
|
+
|
|
156
|
+
ctx.session.changeSet.setTitle('Changes applied by Coder');
|
|
157
|
+
// Add the element to the change set
|
|
158
|
+
ctx.session.changeSet.addElements(fileElement);
|
|
159
|
+
|
|
160
|
+
try {
|
|
161
|
+
// Immediately apply the change
|
|
162
|
+
await fileElement.apply();
|
|
163
|
+
return `Successfully wrote content to file ${path}.`;
|
|
164
|
+
} catch (error) {
|
|
165
|
+
return `Failed to write content to file ${path}: ${error.message}`;
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
};
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
|
|
93
172
|
@injectable()
|
|
94
173
|
export class ReplaceContentInFileFunctionHelper {
|
|
95
174
|
@inject(WorkspaceFunctionScope)
|
|
@@ -107,7 +186,7 @@ export class ReplaceContentInFileFunctionHelper {
|
|
|
107
186
|
this.replacer = new ContentReplacer();
|
|
108
187
|
}
|
|
109
188
|
|
|
110
|
-
getToolMetadata(supportMultipleReplace: boolean = false): { description: string, parameters: ToolRequestParameters } {
|
|
189
|
+
getToolMetadata(supportMultipleReplace: boolean = false, immediateApplication: boolean = false): { description: string, parameters: ToolRequestParameters } {
|
|
111
190
|
const replacementProperties: ToolRequestParametersProperties = {
|
|
112
191
|
oldContent: {
|
|
113
192
|
type: 'string',
|
|
@@ -156,10 +235,14 @@ export class ReplaceContentInFileFunctionHelper {
|
|
|
156
235
|
: 'A single occurrence of each old content in the tuples is expected to be replaced. If the number of occurrences in the file does not match the expectation,\
|
|
157
236
|
the function will return an error. In that case try a different approach.';
|
|
158
237
|
|
|
238
|
+
const applicationText = immediateApplication
|
|
239
|
+
? 'The changes will be applied immediately without user confirmation.'
|
|
240
|
+
: 'The proposed changes will be applied when the user accepts.';
|
|
241
|
+
|
|
159
242
|
const replacementDescription = `Propose to replace sections of content in an existing file by providing a list of tuples with old content to be matched and replaced.
|
|
160
243
|
${replacementSentence}. For deletions, use an empty new content in the tuple.
|
|
161
|
-
Make sure you use the same line endings and whitespace as in the original file content.
|
|
162
|
-
Multiple calls for the same file will merge replacements unless the reset parameter is set to true. Use the reset parameter to clear previous changes and start
|
|
244
|
+
Make sure you use the same line endings and whitespace as in the original file content. ${applicationText}
|
|
245
|
+
Multiple calls for the same file will merge replacements unless the reset parameter is set to true. Use the reset parameter to clear previous changes and start
|
|
163
246
|
fresh if needed.`;
|
|
164
247
|
|
|
165
248
|
return {
|
|
@@ -171,82 +254,108 @@ export class ReplaceContentInFileFunctionHelper {
|
|
|
171
254
|
|
|
172
255
|
async createChangesetFromToolCall(toolCallString: string, ctx: MutableChatRequestModel): Promise<string> {
|
|
173
256
|
try {
|
|
174
|
-
const
|
|
175
|
-
const fileUri = await this.workspaceFunctionScope.resolveRelativePath(path);
|
|
257
|
+
const result = await this.processReplacementsCommon(toolCallString, ctx, 'Changes proposed by Coder');
|
|
176
258
|
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
259
|
+
if (result.errors.length > 0) {
|
|
260
|
+
return `Errors encountered: ${result.errors.join('; ')}`;
|
|
261
|
+
}
|
|
262
|
+
|
|
263
|
+
if (result.fileElement) {
|
|
264
|
+
const action = result.reset ? 'reset and applied' : 'applied';
|
|
265
|
+
return `Proposed replacements ${action} to file ${result.path}. The user will review and potentially apply the changes.`;
|
|
182
266
|
} else {
|
|
183
|
-
|
|
184
|
-
const existingElement = this.findExistingChangeElement(ctx.session.changeSet, fileUri);
|
|
185
|
-
if (existingElement) {
|
|
186
|
-
startingContent = existingElement.targetState || (await this.fileService.read(fileUri)).value.toString();
|
|
187
|
-
} else {
|
|
188
|
-
startingContent = (await this.fileService.read(fileUri)).value.toString();
|
|
189
|
-
}
|
|
267
|
+
return `No changes needed for file ${result.path}. Content already matches the requested state.`;
|
|
190
268
|
}
|
|
269
|
+
} catch (error) {
|
|
270
|
+
console.debug('Error processing replacements:', error.message);
|
|
271
|
+
return JSON.stringify({ error: error.message });
|
|
272
|
+
}
|
|
273
|
+
}
|
|
191
274
|
|
|
192
|
-
|
|
275
|
+
async writeChangesetFromToolCall(toolCallString: string, ctx: MutableChatRequestModel): Promise<string> {
|
|
276
|
+
try {
|
|
277
|
+
const result = await this.processReplacementsCommon(toolCallString, ctx, 'Changes applied by Coder');
|
|
193
278
|
|
|
194
|
-
if (errors.length > 0) {
|
|
195
|
-
return `Errors encountered: ${errors.join('; ')}`;
|
|
279
|
+
if (result.errors.length > 0) {
|
|
280
|
+
return `Errors encountered: ${result.errors.join('; ')}`;
|
|
196
281
|
}
|
|
197
282
|
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
let changeSet = ctx.session.changeSet;
|
|
202
|
-
if (!changeSet) {
|
|
203
|
-
changeSet = new ChangeSetImpl('Changes proposed by Coder');
|
|
204
|
-
ctx.session.setChangeSet(changeSet);
|
|
205
|
-
}
|
|
283
|
+
if (result.fileElement) {
|
|
284
|
+
// Immediately apply the change
|
|
285
|
+
await result.fileElement.apply();
|
|
206
286
|
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
state: 'pending',
|
|
212
|
-
targetState: updatedContent,
|
|
213
|
-
changeSet,
|
|
214
|
-
chatSessionId: ctx.session.id
|
|
215
|
-
})
|
|
216
|
-
);
|
|
287
|
+
const action = result.reset ? 'reset and' : '';
|
|
288
|
+
return `Successfully ${action} applied replacements to file ${result.path}.`;
|
|
289
|
+
} else {
|
|
290
|
+
return `No changes needed for file ${result.path}. Content already matches the requested state.`;
|
|
217
291
|
}
|
|
218
|
-
|
|
219
|
-
const action = reset ? 'reset and applied' : 'applied';
|
|
220
|
-
return `Proposed replacements ${action} to file ${path}. The user will review and potentially apply the changes.`;
|
|
221
292
|
} catch (error) {
|
|
222
293
|
console.debug('Error processing replacements:', error.message);
|
|
223
294
|
return JSON.stringify({ error: error.message });
|
|
224
295
|
}
|
|
225
296
|
}
|
|
226
297
|
|
|
298
|
+
private async processReplacementsCommon(
|
|
299
|
+
toolCallString: string,
|
|
300
|
+
ctx: MutableChatRequestModel,
|
|
301
|
+
changeSetTitle: string
|
|
302
|
+
): Promise<{ fileElement: ChangeSetFileElement | undefined, path: string, reset: boolean, errors: string[] }> {
|
|
303
|
+
const { path, replacements, reset } = JSON.parse(toolCallString) as { path: string, replacements: Replacement[], reset?: boolean };
|
|
304
|
+
const fileUri = await this.workspaceFunctionScope.resolveRelativePath(path);
|
|
305
|
+
|
|
306
|
+
// Get the starting content - either original file or existing proposed state
|
|
307
|
+
let startingContent: string;
|
|
308
|
+
if (reset || !ctx.session.changeSet) {
|
|
309
|
+
// Start from original file content
|
|
310
|
+
startingContent = (await this.fileService.read(fileUri)).value.toString();
|
|
311
|
+
} else {
|
|
312
|
+
// Start from existing proposed state if available
|
|
313
|
+
const existingElement = this.findExistingChangeElement(ctx.session.changeSet, fileUri);
|
|
314
|
+
if (existingElement) {
|
|
315
|
+
startingContent = existingElement.targetState || (await this.fileService.read(fileUri)).value.toString();
|
|
316
|
+
} else {
|
|
317
|
+
startingContent = (await this.fileService.read(fileUri)).value.toString();
|
|
318
|
+
}
|
|
319
|
+
}
|
|
320
|
+
|
|
321
|
+
const { updatedContent, errors } = this.replacer.applyReplacements(startingContent, replacements);
|
|
322
|
+
|
|
323
|
+
if (errors.length > 0) {
|
|
324
|
+
return { fileElement: undefined, path, reset: reset || false, errors };
|
|
325
|
+
}
|
|
326
|
+
|
|
327
|
+
// Only create/update changeset if content actually changed
|
|
328
|
+
const originalContent = (await this.fileService.read(fileUri)).value.toString();
|
|
329
|
+
if (updatedContent !== originalContent) {
|
|
330
|
+
ctx.session.changeSet.setTitle(changeSetTitle);
|
|
331
|
+
|
|
332
|
+
const fileElement = this.fileChangeFactory({
|
|
333
|
+
uri: fileUri,
|
|
334
|
+
type: 'modify',
|
|
335
|
+
state: 'pending',
|
|
336
|
+
targetState: updatedContent,
|
|
337
|
+
requestId: ctx.id,
|
|
338
|
+
chatSessionId: ctx.session.id
|
|
339
|
+
});
|
|
340
|
+
|
|
341
|
+
ctx.session.changeSet.addElements(fileElement);
|
|
342
|
+
|
|
343
|
+
return { fileElement, path, reset: reset || false, errors: [] };
|
|
344
|
+
} else {
|
|
345
|
+
return { fileElement: undefined, path, reset: reset || false, errors: [] };
|
|
346
|
+
}
|
|
347
|
+
}
|
|
348
|
+
|
|
227
349
|
private findExistingChangeElement(changeSet: ChangeSet, fileUri: URI): ChangeSetFileElement | undefined {
|
|
228
|
-
|
|
350
|
+
const element = changeSet.getElementByURI(fileUri);
|
|
351
|
+
if (element instanceof ChangeSetFileElement) { return element; }
|
|
229
352
|
}
|
|
230
353
|
|
|
231
354
|
async clearFileChanges(path: string, ctx: MutableChatRequestModel): Promise<string> {
|
|
232
355
|
try {
|
|
233
356
|
const fileUri = await this.workspaceFunctionScope.resolveRelativePath(path);
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
return `No pending changes found for file ${path}.`;
|
|
237
|
-
}
|
|
238
|
-
|
|
239
|
-
const elements = ctx.session.changeSet.getElements();
|
|
240
|
-
const indicesToRemove: number[] = [];
|
|
241
|
-
elements.forEach((element, index) => {
|
|
242
|
-
if (element.uri && element.uri.toString() === fileUri.toString()) {
|
|
243
|
-
indicesToRemove.push(index);
|
|
244
|
-
}
|
|
245
|
-
});
|
|
246
|
-
|
|
247
|
-
if (indicesToRemove.length > 0) {
|
|
248
|
-
ctx.session.changeSet.removeElements(...indicesToRemove);
|
|
249
|
-
return `Cleared ${indicesToRemove.length} pending change(s) for file ${path}.`;
|
|
357
|
+
if (ctx.session.changeSet.removeElements(fileUri)) {
|
|
358
|
+
return `Cleared pending change(s) for file ${path}.`;
|
|
250
359
|
} else {
|
|
251
360
|
return `No pending changes found for file ${path}.`;
|
|
252
361
|
}
|
|
@@ -282,16 +391,16 @@ export class ReplaceContentInFileFunctionHelper {
|
|
|
282
391
|
}
|
|
283
392
|
|
|
284
393
|
@injectable()
|
|
285
|
-
export class
|
|
286
|
-
static ID = '
|
|
394
|
+
export class SimpleSuggestFileReplacements implements ToolProvider {
|
|
395
|
+
static ID = 'simpleSuggestFileReplacements';
|
|
287
396
|
@inject(ReplaceContentInFileFunctionHelper)
|
|
288
397
|
protected readonly replaceContentInFileFunctionHelper: ReplaceContentInFileFunctionHelper;
|
|
289
398
|
|
|
290
399
|
getTool(): ToolRequest {
|
|
291
400
|
const metadata = this.replaceContentInFileFunctionHelper.getToolMetadata();
|
|
292
401
|
return {
|
|
293
|
-
id:
|
|
294
|
-
name:
|
|
402
|
+
id: SimpleSuggestFileReplacements.ID,
|
|
403
|
+
name: SimpleSuggestFileReplacements.ID,
|
|
295
404
|
description: metadata.description,
|
|
296
405
|
parameters: metadata.parameters,
|
|
297
406
|
handler: async (args: string, ctx: MutableChatRequestModel): Promise<string> =>
|
|
@@ -301,16 +410,35 @@ export class SimpleReplaceContentInFileProvider implements ToolProvider {
|
|
|
301
410
|
}
|
|
302
411
|
|
|
303
412
|
@injectable()
|
|
304
|
-
export class
|
|
305
|
-
static ID = '
|
|
413
|
+
export class SimpleWriteFileReplacements implements ToolProvider {
|
|
414
|
+
static ID = 'simpleWriteFileReplacements';
|
|
415
|
+
@inject(ReplaceContentInFileFunctionHelper)
|
|
416
|
+
protected readonly replaceContentInFileFunctionHelper: ReplaceContentInFileFunctionHelper;
|
|
417
|
+
|
|
418
|
+
getTool(): ToolRequest {
|
|
419
|
+
const metadata = this.replaceContentInFileFunctionHelper.getToolMetadata(false, true);
|
|
420
|
+
return {
|
|
421
|
+
id: SimpleWriteFileReplacements.ID,
|
|
422
|
+
name: SimpleWriteFileReplacements.ID,
|
|
423
|
+
description: metadata.description,
|
|
424
|
+
parameters: metadata.parameters,
|
|
425
|
+
handler: async (args: string, ctx: MutableChatRequestModel): Promise<string> =>
|
|
426
|
+
this.replaceContentInFileFunctionHelper.writeChangesetFromToolCall(args, ctx)
|
|
427
|
+
};
|
|
428
|
+
}
|
|
429
|
+
}
|
|
430
|
+
|
|
431
|
+
@injectable()
|
|
432
|
+
export class SuggestFileReplacements implements ToolProvider {
|
|
433
|
+
static ID = SUGGEST_FILE_REPLACEMENTS_ID;
|
|
306
434
|
@inject(ReplaceContentInFileFunctionHelper)
|
|
307
435
|
protected readonly replaceContentInFileFunctionHelper: ReplaceContentInFileFunctionHelper;
|
|
308
436
|
|
|
309
437
|
getTool(): ToolRequest {
|
|
310
438
|
const metadata = this.replaceContentInFileFunctionHelper.getToolMetadata(true);
|
|
311
439
|
return {
|
|
312
|
-
id:
|
|
313
|
-
name:
|
|
440
|
+
id: SuggestFileReplacements.ID,
|
|
441
|
+
name: SuggestFileReplacements.ID,
|
|
314
442
|
description: metadata.description,
|
|
315
443
|
parameters: metadata.parameters,
|
|
316
444
|
handler: async (args: string, ctx: MutableChatRequestModel): Promise<string> =>
|
|
@@ -320,15 +448,34 @@ export class ReplaceContentInFileProvider implements ToolProvider {
|
|
|
320
448
|
}
|
|
321
449
|
|
|
322
450
|
@injectable()
|
|
323
|
-
export class
|
|
324
|
-
static ID =
|
|
451
|
+
export class WriteFileReplacements implements ToolProvider {
|
|
452
|
+
static ID = WRITE_FILE_REPLACEMENTS_ID;
|
|
453
|
+
@inject(ReplaceContentInFileFunctionHelper)
|
|
454
|
+
protected readonly replaceContentInFileFunctionHelper: ReplaceContentInFileFunctionHelper;
|
|
455
|
+
|
|
456
|
+
getTool(): ToolRequest {
|
|
457
|
+
const metadata = this.replaceContentInFileFunctionHelper.getToolMetadata(true, true);
|
|
458
|
+
return {
|
|
459
|
+
id: WriteFileReplacements.ID,
|
|
460
|
+
name: WriteFileReplacements.ID,
|
|
461
|
+
description: metadata.description,
|
|
462
|
+
parameters: metadata.parameters,
|
|
463
|
+
handler: async (args: string, ctx: MutableChatRequestModel): Promise<string> =>
|
|
464
|
+
this.replaceContentInFileFunctionHelper.writeChangesetFromToolCall(args, ctx)
|
|
465
|
+
};
|
|
466
|
+
}
|
|
467
|
+
}
|
|
468
|
+
|
|
469
|
+
@injectable()
|
|
470
|
+
export class ClearFileChanges implements ToolProvider {
|
|
471
|
+
static ID = CLEAR_FILE_CHANGES_ID;
|
|
325
472
|
@inject(ReplaceContentInFileFunctionHelper)
|
|
326
473
|
protected readonly replaceContentInFileFunctionHelper: ReplaceContentInFileFunctionHelper;
|
|
327
474
|
|
|
328
475
|
getTool(): ToolRequest {
|
|
329
476
|
return {
|
|
330
|
-
id:
|
|
331
|
-
name:
|
|
477
|
+
id: ClearFileChanges.ID,
|
|
478
|
+
name: ClearFileChanges.ID,
|
|
332
479
|
description: 'Clears all pending changes for a specific file, allowing you to start fresh with new modifications.',
|
|
333
480
|
parameters: {
|
|
334
481
|
type: 'object',
|
|
@@ -349,15 +496,15 @@ export class ClearFileChangesProvider implements ToolProvider {
|
|
|
349
496
|
}
|
|
350
497
|
|
|
351
498
|
@injectable()
|
|
352
|
-
export class
|
|
353
|
-
static ID =
|
|
499
|
+
export class GetProposedFileState implements ToolProvider {
|
|
500
|
+
static ID = GET_PROPOSED_CHANGES_ID;
|
|
354
501
|
@inject(ReplaceContentInFileFunctionHelper)
|
|
355
502
|
protected readonly replaceContentInFileFunctionHelper: ReplaceContentInFileFunctionHelper;
|
|
356
503
|
|
|
357
504
|
getTool(): ToolRequest {
|
|
358
505
|
return {
|
|
359
|
-
id:
|
|
360
|
-
name:
|
|
506
|
+
id: GET_PROPOSED_CHANGES_ID,
|
|
507
|
+
name: GET_PROPOSED_CHANGES_ID,
|
|
361
508
|
description: 'Returns the current proposed state of a file, including all pending changes that have been proposed ' +
|
|
362
509
|
'but not yet applied. This allows you to inspect the current state before making additional changes.',
|
|
363
510
|
parameters: {
|
|
@@ -14,6 +14,8 @@
|
|
|
14
14
|
// SPDX-License-Identifier: EPL-2.0 OR GPL-2.0-only WITH Classpath-exception-2.0
|
|
15
15
|
// *****************************************************************************
|
|
16
16
|
|
|
17
|
+
import '../../src/browser/style/index.css';
|
|
18
|
+
|
|
17
19
|
import { ContainerModule } from '@theia/core/shared/inversify';
|
|
18
20
|
import { ChatAgent, DefaultChatAgentId, FallbackChatAgentId } from '@theia/ai-chat/lib/common';
|
|
19
21
|
import { Agent, AIVariableContribution, bindToolProvider } from '@theia/ai-core/lib/common';
|
|
@@ -26,15 +28,19 @@ import { FrontendApplicationContribution, PreferenceContribution, WidgetFactory,
|
|
|
26
28
|
import { TaskListProvider, TaskRunnerProvider } from './workspace-task-provider';
|
|
27
29
|
import { WorkspacePreferencesSchema } from './workspace-preferences';
|
|
28
30
|
import {
|
|
29
|
-
|
|
30
|
-
|
|
31
|
+
ClearFileChanges,
|
|
32
|
+
GetProposedFileState,
|
|
31
33
|
ReplaceContentInFileFunctionHelper,
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
34
|
+
SuggestFileReplacements,
|
|
35
|
+
SimpleSuggestFileReplacements,
|
|
36
|
+
SuggestFileContent,
|
|
37
|
+
WriteFileContent,
|
|
38
|
+
WriteFileReplacements,
|
|
39
|
+
SimpleWriteFileReplacements
|
|
35
40
|
} from './file-changeset-functions';
|
|
36
41
|
import { OrchestratorChatAgent, OrchestratorChatAgentId } from '../common/orchestrator-chat-agent';
|
|
37
42
|
import { UniversalChatAgent, UniversalChatAgentId } from '../common/universal-chat-agent';
|
|
43
|
+
import { AppTesterChatAgent } from './app-tester-chat-agent';
|
|
38
44
|
import { CommandChatAgent } from '../common/command-chat-agents';
|
|
39
45
|
import { ListChatContext, ResolveChatContext, AddFileToChatContext } from './context-functions';
|
|
40
46
|
import { AIAgentConfigurationWidget } from './ai-configuration/agent-configuration-widget';
|
|
@@ -43,6 +49,7 @@ import { AIAgentConfigurationViewContribution } from './ai-configuration/ai-conf
|
|
|
43
49
|
import { AIConfigurationContainerWidget } from './ai-configuration/ai-configuration-widget';
|
|
44
50
|
import { AIVariableConfigurationWidget } from './ai-configuration/variable-configuration-widget';
|
|
45
51
|
import { ContextFilesVariableContribution } from '../common/context-files-variable';
|
|
52
|
+
import { AIToolsConfigurationWidget } from './ai-configuration/tools-configuration-widget';
|
|
46
53
|
import { TabBarToolbarContribution } from '@theia/core/lib/browser/shell/tab-bar-toolbar';
|
|
47
54
|
import { AiConfigurationPreferences } from './ai-configuration/ai-configuration-preferences';
|
|
48
55
|
import { TemplatePreferenceContribution } from './template-preference-contribution';
|
|
@@ -75,6 +82,10 @@ export default new ContainerModule((bind, _unbind, _isBound, rebind) => {
|
|
|
75
82
|
bind(Agent).toService(UniversalChatAgent);
|
|
76
83
|
bind(ChatAgent).toService(UniversalChatAgent);
|
|
77
84
|
|
|
85
|
+
bind(AppTesterChatAgent).toSelf().inSingletonScope();
|
|
86
|
+
bind(Agent).toService(AppTesterChatAgent);
|
|
87
|
+
bind(ChatAgent).toService(AppTesterChatAgent);
|
|
88
|
+
|
|
78
89
|
bind(CommandChatAgent).toSelf().inSingletonScope();
|
|
79
90
|
bind(Agent).toService(CommandChatAgent);
|
|
80
91
|
bind(ChatAgent).toService(CommandChatAgent);
|
|
@@ -91,11 +102,13 @@ export default new ContainerModule((bind, _unbind, _isBound, rebind) => {
|
|
|
91
102
|
bind(WorkspaceFunctionScope).toSelf().inSingletonScope();
|
|
92
103
|
bindToolProvider(WorkspaceSearchProvider, bind);
|
|
93
104
|
|
|
94
|
-
bindToolProvider(
|
|
105
|
+
bindToolProvider(SuggestFileContent, bind);
|
|
106
|
+
bindToolProvider(WriteFileContent, bind);
|
|
95
107
|
bindToolProvider(TaskListProvider, bind);
|
|
96
108
|
bindToolProvider(TaskRunnerProvider, bind);
|
|
97
109
|
bind(ReplaceContentInFileFunctionHelper).toSelf().inSingletonScope();
|
|
98
|
-
bindToolProvider(
|
|
110
|
+
bindToolProvider(SuggestFileReplacements, bind);
|
|
111
|
+
bindToolProvider(WriteFileReplacements, bind);
|
|
99
112
|
bindToolProvider(ListChatContext, bind);
|
|
100
113
|
bindToolProvider(ResolveChatContext, bind);
|
|
101
114
|
bind(AIConfigurationSelectionService).toSelf().inSingletonScope();
|
|
@@ -126,10 +139,20 @@ export default new ContainerModule((bind, _unbind, _isBound, rebind) => {
|
|
|
126
139
|
}))
|
|
127
140
|
.inSingletonScope();
|
|
128
141
|
|
|
129
|
-
bindToolProvider(
|
|
130
|
-
bindToolProvider(
|
|
131
|
-
bindToolProvider(
|
|
142
|
+
bindToolProvider(SimpleSuggestFileReplacements, bind);
|
|
143
|
+
bindToolProvider(SimpleWriteFileReplacements, bind);
|
|
144
|
+
bindToolProvider(ClearFileChanges, bind);
|
|
145
|
+
bindToolProvider(GetProposedFileState, bind);
|
|
132
146
|
bindToolProvider(AddFileToChatContext, bind);
|
|
147
|
+
|
|
148
|
+
bind(AIToolsConfigurationWidget).toSelf();
|
|
149
|
+
bind(WidgetFactory)
|
|
150
|
+
.toDynamicValue(ctx => ({
|
|
151
|
+
id: AIToolsConfigurationWidget.ID,
|
|
152
|
+
createWidget: () => ctx.container.get(AIToolsConfigurationWidget)
|
|
153
|
+
}))
|
|
154
|
+
.inSingletonScope();
|
|
155
|
+
|
|
133
156
|
bind(AIVariableContribution).to(ContextFilesVariableContribution).inSingletonScope();
|
|
134
157
|
bind(PreferenceContribution).toConstantValue({ schema: AiConfigurationPreferences });
|
|
135
158
|
|