@theia/ai-ide 1.66.0-next.41 → 1.66.0-next.67

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 (78) hide show
  1. package/lib/browser/ai-configuration/agent-configuration-widget.d.ts.map +1 -1
  2. package/lib/browser/ai-configuration/agent-configuration-widget.js +5 -3
  3. package/lib/browser/ai-configuration/agent-configuration-widget.js.map +1 -1
  4. package/lib/browser/ai-configuration/language-model-renderer.d.ts.map +1 -1
  5. package/lib/browser/ai-configuration/language-model-renderer.js +4 -3
  6. package/lib/browser/ai-configuration/language-model-renderer.js.map +1 -1
  7. package/lib/browser/ai-configuration/model-aliases-configuration-widget.d.ts.map +1 -1
  8. package/lib/browser/ai-configuration/model-aliases-configuration-widget.js +4 -3
  9. package/lib/browser/ai-configuration/model-aliases-configuration-widget.js.map +1 -1
  10. package/lib/browser/ai-configuration/template-settings-renderer.js +1 -1
  11. package/lib/browser/ai-configuration/template-settings-renderer.js.map +1 -1
  12. package/lib/browser/ai-configuration/token-usage-configuration-widget.js +1 -1
  13. package/lib/browser/ai-configuration/token-usage-configuration-widget.js.map +1 -1
  14. package/lib/browser/ai-configuration/tools-configuration-widget.d.ts +1 -1
  15. package/lib/browser/ai-configuration/tools-configuration-widget.d.ts.map +1 -1
  16. package/lib/browser/ai-configuration/tools-configuration-widget.js +12 -12
  17. package/lib/browser/ai-configuration/tools-configuration-widget.js.map +1 -1
  18. package/lib/browser/ai-configuration/variable-configuration-widget.d.ts +1 -1
  19. package/lib/browser/ai-configuration/variable-configuration-widget.d.ts.map +1 -1
  20. package/lib/browser/ai-configuration/variable-configuration-widget.js +4 -3
  21. package/lib/browser/ai-configuration/variable-configuration-widget.js.map +1 -1
  22. package/lib/browser/app-tester-chat-agent.d.ts.map +1 -1
  23. package/lib/browser/app-tester-chat-agent.js +10 -7
  24. package/lib/browser/app-tester-chat-agent.js.map +1 -1
  25. package/lib/browser/architect-agent.d.ts.map +1 -1
  26. package/lib/browser/architect-agent.js +2 -2
  27. package/lib/browser/architect-agent.js.map +1 -1
  28. package/lib/browser/coder-agent.d.ts.map +1 -1
  29. package/lib/browser/coder-agent.js +6 -5
  30. package/lib/browser/coder-agent.js.map +1 -1
  31. package/lib/browser/file-changeset-functions.d.ts +10 -0
  32. package/lib/browser/file-changeset-functions.d.ts.map +1 -1
  33. package/lib/browser/file-changeset-functions.js +51 -3
  34. package/lib/browser/file-changeset-functions.js.map +1 -1
  35. package/lib/browser/file-changeset-functions.spec.js +18 -0
  36. package/lib/browser/file-changeset-functions.spec.js.map +1 -1
  37. package/lib/browser/frontend-module.d.ts.map +1 -1
  38. package/lib/browser/frontend-module.js +2 -0
  39. package/lib/browser/frontend-module.js.map +1 -1
  40. package/lib/browser/github-chat-agent.d.ts.map +1 -1
  41. package/lib/browser/github-chat-agent.js +18 -16
  42. package/lib/browser/github-chat-agent.js.map +1 -1
  43. package/lib/common/coder-replace-prompt-template.d.ts +2 -0
  44. package/lib/common/coder-replace-prompt-template.d.ts.map +1 -1
  45. package/lib/common/coder-replace-prompt-template.js +20 -8
  46. package/lib/common/coder-replace-prompt-template.js.map +1 -1
  47. package/lib/common/command-chat-agents.d.ts.map +1 -1
  48. package/lib/common/command-chat-agents.js +9 -9
  49. package/lib/common/command-chat-agents.js.map +1 -1
  50. package/lib/common/file-changeset-function-ids.d.ts +1 -0
  51. package/lib/common/file-changeset-function-ids.d.ts.map +1 -1
  52. package/lib/common/file-changeset-function-ids.js +2 -1
  53. package/lib/common/file-changeset-function-ids.js.map +1 -1
  54. package/lib/common/orchestrator-chat-agent.d.ts.map +1 -1
  55. package/lib/common/orchestrator-chat-agent.js +4 -4
  56. package/lib/common/orchestrator-chat-agent.js.map +1 -1
  57. package/lib/common/workspace-preferences.js +2 -2
  58. package/lib/common/workspace-preferences.js.map +1 -1
  59. package/package.json +21 -21
  60. package/src/browser/ai-configuration/agent-configuration-widget.tsx +5 -3
  61. package/src/browser/ai-configuration/language-model-renderer.tsx +9 -4
  62. package/src/browser/ai-configuration/model-aliases-configuration-widget.tsx +8 -4
  63. package/src/browser/ai-configuration/template-settings-renderer.tsx +1 -1
  64. package/src/browser/ai-configuration/token-usage-configuration-widget.tsx +1 -1
  65. package/src/browser/ai-configuration/tools-configuration-widget.tsx +15 -14
  66. package/src/browser/ai-configuration/variable-configuration-widget.tsx +4 -3
  67. package/src/browser/app-tester-chat-agent.ts +15 -7
  68. package/src/browser/architect-agent.ts +4 -2
  69. package/src/browser/coder-agent.ts +10 -6
  70. package/src/browser/file-changeset-functions.spec.ts +28 -1
  71. package/src/browser/file-changeset-functions.ts +47 -3
  72. package/src/browser/frontend-module.ts +5 -1
  73. package/src/browser/github-chat-agent.ts +23 -17
  74. package/src/common/coder-replace-prompt-template.ts +23 -8
  75. package/src/common/command-chat-agents.ts +13 -9
  76. package/src/common/file-changeset-function-ids.ts +1 -0
  77. package/src/common/orchestrator-chat-agent.ts +5 -4
  78. package/src/common/workspace-preferences.ts +2 -2
@@ -58,16 +58,20 @@ export class AppTesterChatAgent extends AbstractStreamParsingChatAgent {
58
58
  if (await this.requiresStartingServers()) {
59
59
  // Ask the user if they want to start the server
60
60
  request.response.response.addContent(new QuestionResponseContentImpl(
61
- 'The Playwright MCP servers are not running. Would you like to start them now? This may install the Playwright MCP servers.',
61
+ nls.localize('theia/ai/ide/app-tester/startPlaywrightServers/question',
62
+ 'The Playwright MCP servers are not running. Would you like to start them now? This may install the Playwright MCP servers.'),
62
63
  [
63
- { text: 'Yes, start the servers', value: 'yes' },
64
- { text: 'No, cancel', value: 'no' }
64
+ { text: nls.localize('theia/ai/ide/app-tester/startPlaywrightServers/yes', 'Yes, start the servers'), value: 'yes' },
65
+ { text: nls.localize('theia/ai/ide/app-tester/startPlaywrightServers/no', 'No, cancel'), value: 'no' }
65
66
  ],
66
67
  request,
67
68
  async selectedOption => {
68
69
  if (selectedOption.value === 'yes') {
69
70
  // Show progress
70
- const progress = request.response.addProgressMessage({ content: 'Starting Playwright MCP servers.', show: 'whileIncomplete' });
71
+ const progress = request.response.addProgressMessage({
72
+ content: nls.localize('theia/ai/ide/app-tester/startPlaywrightServers/progress', 'Starting Playwright MCP servers.'),
73
+ show: 'whileIncomplete'
74
+ });
71
75
  try {
72
76
  await this.startServers();
73
77
  // Remove progress, continue with normal flow
@@ -75,13 +79,16 @@ export class AppTesterChatAgent extends AbstractStreamParsingChatAgent {
75
79
  await super.invoke(request);
76
80
  } catch (error) {
77
81
  request.response.response.addContent(new ErrorChatResponseContentImpl(
78
- new Error('Failed to start Playwright MCP server: ' + (error instanceof Error ? error.message : String(error)))
82
+ new Error(nls.localize('theia/ai/ide/app-tester/startPlaywrightServers/error', 'Failed to start Playwright MCP server: {0}',
83
+ error instanceof Error ? error.message : String(error)))
79
84
  ));
80
85
  request.response.complete();
81
86
  }
82
87
  } else {
83
88
  // Continue without starting the server
84
- request.response.response.addContent(new MarkdownChatResponseContentImpl('Please setup the MCP servers.'));
89
+ request.response.response.addContent(new MarkdownChatResponseContentImpl(
90
+ nls.localize('theia/ai/ide/app-tester/startPlaywrightServers/canceled', 'Please setup the MCP servers.')
91
+ ));
85
92
  request.response.complete();
86
93
  }
87
94
  }
@@ -93,7 +100,8 @@ export class AppTesterChatAgent extends AbstractStreamParsingChatAgent {
93
100
  await super.invoke(request);
94
101
  } catch (error) {
95
102
  request.response.response.addContent(new ErrorChatResponseContentImpl(
96
- new Error('Error checking Playwright MCP server status: ' + (error instanceof Error ? error.message : String(error)))
103
+ new Error(nls.localize('theia/ai/ide/app-tester/errorCheckingPlaywrightServerStatus', 'Error checking Playwright MCP server status: {0}',
104
+ error instanceof Error ? error.message : String(error)))
97
105
  ));
98
106
  request.response.complete();
99
107
  }
@@ -51,8 +51,10 @@ export class ArchitectAgent extends AbstractStreamParsingChatAgent {
51
51
  if (!(model instanceof MutableChatModel) || !session) { return; }
52
52
  if (!model.isEmpty()) {
53
53
  model.setSuggestions([
54
- new MarkdownStringImpl(`[Summarize this session as a task for Coder](command:${AI_SUMMARIZE_SESSION_AS_TASK_FOR_CODER.id}).`),
55
- new MarkdownStringImpl(`[Update current task context](command:${AI_UPDATE_TASK_CONTEXT_COMMAND.id}).`)
54
+ new MarkdownStringImpl(`[${nls.localize('theia/ai/ide/architectAgent/suggestion/summarizeSessionAsTaskForCoder',
55
+ 'Summarize this session as a task for Coder')}](command:${AI_SUMMARIZE_SESSION_AS_TASK_FOR_CODER.id}).`),
56
+ new MarkdownStringImpl(`[${nls.localize('theia/ai/ide/architectAgent/suggestion/updateTaskContext',
57
+ 'Update current task context')}](command:${AI_UPDATE_TASK_CONTEXT_COMMAND.id}).`)
56
58
  ]);
57
59
  }
58
60
  }
@@ -15,7 +15,8 @@
15
15
  // *****************************************************************************
16
16
  import { AbstractStreamParsingChatAgent, ChatRequestModel, ChatService, ChatSession, MutableChatModel, MutableChatRequestModel } from '@theia/ai-chat/lib/common';
17
17
  import { inject, injectable } from '@theia/core/shared/inversify';
18
- import { CODER_SYSTEM_PROMPT_ID, getCoderAgentModePromptTemplate, getCoderPromptTemplateEdit, getCoderPromptTemplateSimpleEdit } from '../common/coder-replace-prompt-template';
18
+ import { CODER_SYSTEM_PROMPT_ID, getCoderAgentModePromptTemplate, getCoderPromptTemplateEdit, getCoderPromptTemplateEditNext, getCoderPromptTemplateSimpleEdit }
19
+ from '../common/coder-replace-prompt-template';
19
20
  import { LanguageModelRequirement, PromptVariantSet } from '@theia/ai-core';
20
21
  import { nls } from '@theia/core';
21
22
  import { MarkdownStringImpl } from '@theia/core/lib/common/markdown-rendering';
@@ -39,7 +40,7 @@ export class CoderAgent extends AbstractStreamParsingChatAgent {
39
40
  override prompts: PromptVariantSet[] = [{
40
41
  id: CODER_SYSTEM_PROMPT_ID,
41
42
  defaultVariant: getCoderPromptTemplateEdit(),
42
- variants: [getCoderPromptTemplateSimpleEdit(), getCoderAgentModePromptTemplate()]
43
+ variants: [getCoderPromptTemplateSimpleEdit(), getCoderAgentModePromptTemplate(), getCoderPromptTemplateEditNext()]
43
44
  }];
44
45
  protected override systemPromptId: string | undefined = CODER_SYSTEM_PROMPT_ID;
45
46
  override async invoke(request: MutableChatRequestModel): Promise<void> {
@@ -55,13 +56,16 @@ export class CoderAgent extends AbstractStreamParsingChatAgent {
55
56
  model.setSuggestions([
56
57
  {
57
58
  kind: 'callback',
58
- callback: () => this.chatService.sendRequest(session.id, { text: '@Coder please look at #_f and fix any problems.' }),
59
- content: '[Fix problems](_callback) in the current file.'
59
+ callback: () => this.chatService.sendRequest(session.id, {
60
+ text: `@Coder ${nls.localize('theia/ai/ide/coderAgent/suggestion/fixProblems/prompt', 'please look at {1} and fix any problems.', '#_f')}`
61
+ }),
62
+ content: nls.localize('theia/ai/ide/coderAgent/suggestion/fixProblems/content', '[Fix problems]({0}) in the current file.', '_callback')
60
63
  },
61
64
  ]);
62
65
  } else {
63
- model.setSuggestions([new MarkdownStringImpl(`Keep chats short and focused. [Start a new chat](command:${AI_CHAT_NEW_CHAT_WINDOW_COMMAND.id}) for a new task`
64
- + ` or [start a new chat with a summary of this one](command:${ChatCommands.AI_CHAT_NEW_WITH_TASK_CONTEXT.id}).`)]);
66
+ model.setSuggestions([new MarkdownStringImpl(nls.localize('theia/ai/ide/coderAgent/suggestion/startNewChat',
67
+ 'Keep chats short and focused. [Start a new chat]({0}) for a new task or [start a new chat with a summary of this one]({1}).',
68
+ `command:${AI_CHAT_NEW_CHAT_WINDOW_COMMAND.id}`, `command:${ChatCommands.AI_CHAT_NEW_WITH_TASK_CONTEXT.id}`))]);
65
69
  }
66
70
  }
67
71
 
@@ -30,7 +30,9 @@ import {
30
30
  GetProposedFileState,
31
31
  ReplaceContentInFileFunctionHelper,
32
32
  FileChangeSetTitleProvider,
33
- DefaultFileChangeSetTitleProvider
33
+ DefaultFileChangeSetTitleProvider,
34
+ ReplaceContentInFileFunctionHelperV2,
35
+ SuggestFileReplacements_Next
34
36
  } from './file-changeset-functions';
35
37
  import { MutableChatRequestModel, MutableChatResponseModel, ChangeSet, ChangeSetElement, MutableChatModel } from '@theia/ai-chat';
36
38
  import { Container } from '@theia/core/shared/inversify';
@@ -108,6 +110,8 @@ describe('File Changeset Functions Cancellation Tests', () => {
108
110
  container.bind(WriteFileReplacements).toSelf();
109
111
  container.bind(ClearFileChanges).toSelf();
110
112
  container.bind(GetProposedFileState).toSelf();
113
+ container.bind(ReplaceContentInFileFunctionHelperV2).toSelf();
114
+ container.bind(SuggestFileReplacements_Next).toSelf();
111
115
  });
112
116
 
113
117
  afterEach(() => {
@@ -209,4 +213,27 @@ describe('File Changeset Functions Cancellation Tests', () => {
209
213
  expect(jsonResponse.error).to.equal('Operation cancelled by user');
210
214
 
211
215
  });
216
+
217
+ it('SuggestFileReplacements_Next should respect cancellation token', async () => {
218
+ const suggestFileReplacementsNext = container.get(SuggestFileReplacements_Next);
219
+ cancellationTokenSource.cancel();
220
+
221
+ const handler = suggestFileReplacementsNext.getTool().handler;
222
+ const result = await handler(
223
+ JSON.stringify({
224
+ path: 'test.txt',
225
+ replacements: [{ oldContent: 'old', newContent: 'new', multiple: true }]
226
+ }),
227
+ mockCtx as MutableChatRequestModel
228
+ );
229
+
230
+ const jsonResponse = typeof result === 'string' ? JSON.parse(result) : result;
231
+ expect(jsonResponse.error).to.equal('Operation cancelled by user');
232
+ });
233
+
234
+ it('SuggestFileReplacements_Next should have correct ID', () => {
235
+ const suggestFileReplacementsNext = container.get(SuggestFileReplacements_Next);
236
+ expect(SuggestFileReplacements_Next.ID).to.equal('suggestFileReplacements_Next');
237
+ expect(suggestFileReplacementsNext.getTool().id).to.equal('suggestFileReplacements_Next');
238
+ });
212
239
  });
@@ -16,7 +16,8 @@
16
16
  import { ChangeSet, MutableChatRequestModel } from '@theia/ai-chat';
17
17
  import { ChangeSetElementArgs, ChangeSetFileElement, ChangeSetFileElementFactory } from '@theia/ai-chat/lib/browser/change-set-file-element';
18
18
  import { ToolProvider, ToolRequest, ToolRequestParameters, ToolRequestParametersProperties } from '@theia/ai-core';
19
- import { ContentReplacer, Replacement } from '@theia/core/lib/common/content-replacer';
19
+ import { ContentReplacerV1Impl, Replacement, ContentReplacer } from '@theia/core/lib/common/content-replacer';
20
+ import { ContentReplacerV2Impl } from '@theia/core/lib/common/content-replacer-v2-impl';
20
21
  import { URI } from '@theia/core/lib/common/uri';
21
22
  import { inject, injectable } from '@theia/core/shared/inversify';
22
23
  import { FileService } from '@theia/filesystem/lib/browser/file-service';
@@ -29,7 +30,8 @@ import {
29
30
  SUGGEST_FILE_CONTENT_ID,
30
31
  SUGGEST_FILE_REPLACEMENTS_ID,
31
32
  WRITE_FILE_CONTENT_ID,
32
- WRITE_FILE_REPLACEMENTS_ID
33
+ WRITE_FILE_REPLACEMENTS_ID,
34
+ SUGGEST_FILE_REPLACEMENTS_NEXT_ID
33
35
  } from '../common/file-changeset-function-ids';
34
36
 
35
37
  export const FileChangeSetTitleProvider = Symbol('FileChangeSetTitleProvider');
@@ -206,7 +208,11 @@ export class ReplaceContentInFileFunctionHelper {
206
208
  private replacer: ContentReplacer;
207
209
 
208
210
  constructor() {
209
- this.replacer = new ContentReplacer();
211
+ this.replacer = new ContentReplacerV1Impl();
212
+ }
213
+
214
+ protected setReplacer(replacer: ContentReplacer): void {
215
+ this.replacer = replacer;
210
216
  }
211
217
 
212
218
  getToolMetadata(supportMultipleReplace: boolean = false, immediateApplication: boolean = false): { description: string, parameters: ToolRequestParameters } {
@@ -596,6 +602,44 @@ export class GetProposedFileState implements ToolProvider {
596
602
  }
597
603
  }
598
604
 
605
+ @injectable()
606
+ export class ReplaceContentInFileFunctionHelperV2 extends ReplaceContentInFileFunctionHelper {
607
+ constructor() {
608
+ super();
609
+ this.setReplacer(new ContentReplacerV2Impl());
610
+ }
611
+ }
612
+
613
+ @injectable()
614
+ export class SuggestFileReplacements_Next implements ToolProvider {
615
+ static ID = SUGGEST_FILE_REPLACEMENTS_NEXT_ID;
616
+
617
+ @inject(ReplaceContentInFileFunctionHelperV2)
618
+ protected readonly replaceContentInFileFunctionHelper: ReplaceContentInFileFunctionHelperV2;
619
+
620
+ getTool(): ToolRequest {
621
+ const metadata = this.replaceContentInFileFunctionHelper.getToolMetadata(true);
622
+ return {
623
+ id: SuggestFileReplacements_Next.ID,
624
+ name: SuggestFileReplacements_Next.ID,
625
+ description: `Proposes to replace sections of content in an existing file by providing a list of replacements.
626
+ Each replacement consists of oldContent to be matched and newContent to insert in its place.
627
+ By default, a single occurrence of each oldContent is expected. If the 'multiple' flag is set to true, all occurrences will be replaced.
628
+ If the expected number of occurrences is not found, the function will return an error. In this case try a different approach.
629
+ For deletions, use an empty newContent.
630
+ The proposed changes will be applied when the user accepts.
631
+ Multiple calls for the same file will merge replacements unless the reset parameter is set to true.`,
632
+ parameters: metadata.parameters,
633
+ handler: async (args: string, ctx: MutableChatRequestModel): Promise<string> => {
634
+ if (ctx?.response?.cancellationToken?.isCancellationRequested) {
635
+ return JSON.stringify({ error: 'Operation cancelled by user' });
636
+ }
637
+ return this.replaceContentInFileFunctionHelper.createChangesetFromToolCall(args, ctx);
638
+ }
639
+ };
640
+ }
641
+ }
642
+
599
643
  @injectable()
600
644
  export class DefaultFileChangeSetTitleProvider implements FileChangeSetTitleProvider {
601
645
  getChangeSetTitle(ctx: MutableChatRequestModel): string {
@@ -56,7 +56,9 @@ import {
56
56
  WriteFileReplacements,
57
57
  SimpleWriteFileReplacements,
58
58
  FileChangeSetTitleProvider,
59
- DefaultFileChangeSetTitleProvider
59
+ DefaultFileChangeSetTitleProvider,
60
+ ReplaceContentInFileFunctionHelperV2,
61
+ SuggestFileReplacements_Next
60
62
  } from './file-changeset-functions';
61
63
  import { OrchestratorChatAgent, OrchestratorChatAgentId } from '../common/orchestrator-chat-agent';
62
64
  import { UniversalChatAgent, UniversalChatAgentId } from '../common/universal-chat-agent';
@@ -159,6 +161,8 @@ export default new ContainerModule((bind, _unbind, _isBound, rebind) => {
159
161
  bind(FileChangeSetTitleProvider).to(DefaultFileChangeSetTitleProvider).inSingletonScope();
160
162
  bindToolProvider(SuggestFileReplacements, bind);
161
163
  bindToolProvider(WriteFileReplacements, bind);
164
+ bind(ReplaceContentInFileFunctionHelperV2).toSelf().inSingletonScope();
165
+ bindToolProvider(SuggestFileReplacements_Next, bind);
162
166
  bindToolProvider(ListChatContext, bind);
163
167
  bindToolProvider(ResolveChatContext, bind);
164
168
  bind(AIConfigurationSelectionService).toSelf().inSingletonScope();
@@ -54,7 +54,7 @@ export class GitHubChatAgent extends AbstractStreamParsingChatAgent {
54
54
  identifier: 'default/code',
55
55
  }];
56
56
  protected defaultLanguageModelPurpose: string = 'chat';
57
- override description = nls.localize('theia/ai/chat/github/description', 'This agent helps you interact with GitHub repositories, issues, pull requests, and other GitHub '
57
+ override description = nls.localize('theia/ai/ide/github/description', 'This agent helps you interact with GitHub repositories, issues, pull requests, and other GitHub '
58
58
  + 'features through the GitHub MCP server. '
59
59
  + 'It can help you manage your repositories, create issues, handle pull requests, and perform various GitHub operations.');
60
60
 
@@ -70,26 +70,26 @@ export class GitHubChatAgent extends AbstractStreamParsingChatAgent {
70
70
  try {
71
71
  if (await this.requiresConfiguration()) {
72
72
  // Ask the user if they want to configure the GitHub server
73
- request.response.response.addContent(new QuestionResponseContentImpl(
73
+ request.response.response.addContent(new QuestionResponseContentImpl(nls.localize('theia/ai/ide/github/configureGitHubServer/question',
74
74
  'The GitHub MCP server is not configured. Would you like to configure it now? '
75
- + 'This will open the settings.json file where you can add your GitHub access token.',
75
+ + 'This will open the settings.json file where you can add your GitHub access token.'),
76
76
  [
77
- { text: 'Yes, configure GitHub server', value: 'configure' },
78
- { text: 'No, cancel', value: 'cancel' }
77
+ { text: nls.localize('theia/ai/ide/github/configureGitHubServer/yes', 'Yes, configure GitHub server'), value: 'configure' },
78
+ { text: nls.localize('theia/ai/ide/github/configureGitHubServer/no', 'No, cancel'), value: 'cancel' }
79
79
  ],
80
80
  request,
81
81
  async selectedOption => {
82
82
  if (selectedOption.value === 'configure') {
83
83
  await this.offerConfiguration();
84
- request.response.response.addContent(new MarkdownChatResponseContentImpl(
84
+ request.response.response.addContent(new MarkdownChatResponseContentImpl(nls.localize('theia/ai/ide/github/configureGitHubServer/followup',
85
85
  'Settings file opened. Please add your GitHub Personal Access Token to the `serverAuthToken` property in the GitHub server configuration, then '
86
86
  + ' save and try again.\n\n' +
87
87
  'You can create a Personal Access Token at: https://github.com/settings/tokens'
88
- ));
88
+ )));
89
89
  request.response.complete();
90
90
  } else {
91
- request.response.response.addContent(new MarkdownChatResponseContentImpl('GitHub server configuration cancelled.'
92
- + ' Please configure the GitHub MCP server to use this agent.'));
91
+ request.response.response.addContent(new MarkdownChatResponseContentImpl(nls.localize('theia/ai/ide/github/configureGitHubServer/canceled',
92
+ 'GitHub server configuration cancelled. Please configure the GitHub MCP server to use this agent.')));
93
93
  request.response.complete();
94
94
  }
95
95
  }
@@ -100,28 +100,33 @@ export class GitHubChatAgent extends AbstractStreamParsingChatAgent {
100
100
 
101
101
  if (await this.requiresStartingServer()) {
102
102
  // Ask the user if they want to start the server
103
- request.response.response.addContent(new QuestionResponseContentImpl(
104
- 'The GitHub MCP server is configured but not running. Would you like to start it now?',
103
+ request.response.response.addContent(new QuestionResponseContentImpl(nls.localize('theia/ai/ide/github/startGitHubServer/question',
104
+ 'The GitHub MCP server is configured but not running. Would you like to start it now?'),
105
105
  [
106
- { text: 'Yes, start the server', value: 'yes' },
107
- { text: 'No, cancel', value: 'no' }
106
+ { text: nls.localize('theia/ai/ide/github/startGitHubServer/yes', 'Yes, start the server'), value: 'yes' },
107
+ { text: nls.localize('theia/ai/ide/github/startGitHubServer/no', 'No, cancel'), value: 'no' }
108
108
  ],
109
109
  request,
110
110
  async selectedOption => {
111
111
  if (selectedOption.value === 'yes') {
112
- const progress = request.response.addProgressMessage({ content: 'Starting GitHub MCP server.', show: 'whileIncomplete' });
112
+ const progress = request.response.addProgressMessage({
113
+ content: nls.localize('theia/ai/ide/github/startGitHubServer/progress', 'Starting GitHub MCP server.'),
114
+ show: 'whileIncomplete'
115
+ });
113
116
  try {
114
117
  await this.startServer();
115
118
  request.response.updateProgressMessage({ ...progress, show: 'whileIncomplete', status: 'completed' });
116
119
  await super.invoke(request);
117
120
  } catch (error) {
118
121
  request.response.response.addContent(new ErrorChatResponseContentImpl(
119
- new Error('Failed to start GitHub MCP server: ' + (error instanceof Error ? error.message : String(error)))
122
+ new Error(nls.localize('theia/ai/ide/github/startGitHubServer/error', 'Failed to start GitHub MCP server: {0}',
123
+ error instanceof Error ? error.message : String(error)))
120
124
  ));
121
125
  request.response.complete();
122
126
  }
123
127
  } else {
124
- request.response.response.addContent(new MarkdownChatResponseContentImpl('Please start the GitHub MCP server to use this agent.'));
128
+ request.response.response.addContent(new MarkdownChatResponseContentImpl(nls.localize('theia/ai/ide/github/startGitHubServer/canceled',
129
+ 'Please start the GitHub MCP server to use this agent.')));
125
130
  request.response.complete();
126
131
  }
127
132
  }
@@ -134,7 +139,8 @@ export class GitHubChatAgent extends AbstractStreamParsingChatAgent {
134
139
  await super.invoke(request);
135
140
  } catch (error) {
136
141
  request.response.response.addContent(new ErrorChatResponseContentImpl(
137
- new Error('Error checking GitHub MCP server status: ' + (error instanceof Error ? error.message : String(error)))
142
+ new Error(nls.localize('theia/ai/ide/github/errorCheckingGitHubServerStatus', 'Error checking GitHub MCP server status: {0}',
143
+ error instanceof Error ? error.message : String(error)))
138
144
  ));
139
145
  request.response.complete();
140
146
  }
@@ -28,13 +28,15 @@ import {
28
28
  SUGGEST_FILE_REPLACEMENTS_ID,
29
29
  WRITE_FILE_REPLACEMENTS_ID,
30
30
  CLEAR_FILE_CHANGES_ID,
31
- GET_PROPOSED_CHANGES_ID
31
+ GET_PROPOSED_CHANGES_ID,
32
+ SUGGEST_FILE_REPLACEMENTS_NEXT_ID
32
33
  } from './file-changeset-function-ids';
33
34
 
34
35
  export const CODER_SYSTEM_PROMPT_ID = 'coder-system';
35
36
 
36
37
  export const CODER_SIMPLE_EDIT_TEMPLATE_ID = 'coder-system-simple-edit';
37
38
  export const CODER_EDIT_TEMPLATE_ID = 'coder-system-edit';
39
+ export const CODER_EDIT_NEXT_TEMPLATE_ID = 'coder-system-edit-next';
38
40
  export const CODER_AGENT_MODE_TEMPLATE_ID = 'coder-system-agent-mode';
39
41
 
40
42
  export function getCoderAgentModePromptTemplate(): BasePromptFragment {
@@ -159,10 +161,8 @@ You are an autonomous AI agent. Do not stop until:
159
161
  };
160
162
  }
161
163
 
162
- export function getCoderPromptTemplateEdit(): BasePromptFragment {
163
- return {
164
- id: CODER_EDIT_TEMPLATE_ID,
165
- template: `{{!-- This prompt is licensed under the MIT License (https://opensource.org/license/mit).
164
+ function getCoderEditPromptTemplate(suggestFileReplacementsId: string): string {
165
+ return `{{!-- This prompt is licensed under the MIT License (https://opensource.org/license/mit).
166
166
  Made improvements or adaptations to this prompt template? We'd love for you to share it with the community! Contribute back here:
167
167
  https://github.com/eclipse-theia/theia/discussions/new?category=prompt-template-contribution --}}
168
168
  You are an AI assistant integrated into Theia IDE, designed to assist software developers with code tasks. You can interact with the code base and suggest changes, \
@@ -189,9 +189,9 @@ This also applies for newly created files!
189
189
  - **Always Retrieve Current Content**: Use getFileContent to get the original content of the target file.
190
190
  - **View Pending Changes**: Use ~{${GET_PROPOSED_CHANGES_ID}} to see the current proposed state of a file, including all pending changes.
191
191
  - **Change Content**: Use one of these methods to propose changes:
192
- - ~{${SUGGEST_FILE_REPLACEMENTS_ID}}: For targeted replacements of specific text sections. Multiple calls will merge changes unless you set the reset parameter to true.
192
+ - ~{${suggestFileReplacementsId}}: For targeted replacements of specific text sections. Multiple calls will merge changes unless you set the reset parameter to true.
193
193
  - ~{${SUGGEST_FILE_CONTENT_ID}}: For complete file rewrites when you need to replace the entire content.
194
- - If ~{${SUGGEST_FILE_REPLACEMENTS_ID}} continuously fails use ~{${SUGGEST_FILE_CONTENT_ID}}.
194
+ - If ~{${suggestFileReplacementsId}} continuously fails use ~{${SUGGEST_FILE_CONTENT_ID}}.
195
195
  - ~{${CLEAR_FILE_CHANGES_ID}}: To clear all pending changes for a file and start fresh.
196
196
 
197
197
  The changes will be presented as an applicable diff to the user in any case. The user can then accept or reject each change individually. Before you run tasks that depend on the \
@@ -229,7 +229,22 @@ You have previously proposed changes for the following files. Some suggestions m
229
229
  - Tasks such as building or liniting run on the workspace state, the user has to accept the changes beforehand
230
230
  - Do not run a build or any error checking before the users asks you to
231
231
  - Focus on the task that the user described
232
- `};
232
+ `;
233
+ }
234
+
235
+ export function getCoderPromptTemplateEdit(): BasePromptFragment {
236
+ return {
237
+ id: CODER_EDIT_TEMPLATE_ID,
238
+ template: getCoderEditPromptTemplate(SUGGEST_FILE_REPLACEMENTS_ID)
239
+ };
240
+ }
241
+
242
+ export function getCoderPromptTemplateEditNext(): BasePromptFragment {
243
+ return {
244
+ id: CODER_EDIT_NEXT_TEMPLATE_ID,
245
+ template: getCoderEditPromptTemplate(SUGGEST_FILE_REPLACEMENTS_NEXT_ID),
246
+ ...({ variantOf: CODER_EDIT_TEMPLATE_ID })
247
+ };
233
248
  }
234
249
 
235
250
  export function getCoderPromptTemplateSimpleEdit(): BasePromptFragment {
@@ -29,6 +29,7 @@ import {
29
29
  CommandRegistry,
30
30
  MessageService,
31
31
  generateUuid,
32
+ nls,
32
33
  } from '@theia/core';
33
34
 
34
35
  import { commandTemplate } from './command-prompt-template';
@@ -55,12 +56,13 @@ export class CommandChatAgent extends AbstractTextToModelParsingChatAgent<Parsed
55
56
  }];
56
57
  protected defaultLanguageModelPurpose: string = 'command';
57
58
 
58
- override description = 'This agent is aware of all commands that the user can execute within the Theia IDE, the tool that the user is currently working with. \
59
- Based on the user request, it can find the right command and then let the user execute it.';
59
+ override description = nls.localize('theia/ai/ide/commandAgent/description',
60
+ 'This agent is aware of all commands that the user can execute within the Theia IDE, the tool that the user is currently working with. ' +
61
+ 'Based on the user request, it can find the right command and then let the user execute it.');
60
62
  override prompts = [commandTemplate];
61
63
  override agentSpecificVariables = [{
62
64
  name: 'command-ids',
63
- description: 'The list of available commands in Theia.',
65
+ description: nls.localize('theia/ai/ide/commandAgent/vars/commandIds/description', 'The list of available commands in Theia.'),
64
66
  usedInPrompt: true
65
67
  }];
66
68
 
@@ -107,7 +109,7 @@ export class CommandChatAgent extends AbstractTextToModelParsingChatAgent<Parsed
107
109
 
108
110
  return new HorizontalLayoutChatResponseContentImpl([
109
111
  new MarkdownChatResponseContentImpl(
110
- 'I found this command that might help you:'
112
+ nls.localize('theia/ai/ide/commandAgent/response/theiaCommand', 'I found this command that might help you:')
111
113
  ),
112
114
  new CommandChatResponseContentImpl(theiaCommand, undefined, args),
113
115
  ]);
@@ -116,22 +118,24 @@ export class CommandChatAgent extends AbstractTextToModelParsingChatAgent<Parsed
116
118
  const commandArgs = parsedCommand.arguments !== undefined && parsedCommand.arguments.length > 0 ? parsedCommand.arguments : [];
117
119
  const args = [id, ...commandArgs];
118
120
  const customCallback: CustomCallback = {
119
- label: 'AI command',
121
+ label: nls.localize('theia/ai/ide/commandAgent/commandCallback/label', 'AI command'),
120
122
  callback: () => this.commandCallback(...args),
121
123
  };
122
124
  return new HorizontalLayoutChatResponseContentImpl([
123
125
  new MarkdownChatResponseContentImpl(
124
- 'Try executing this:'
126
+ nls.localize('theia/ai/ide/commandAgent/response/customHandler', 'Try executing this:')
125
127
  ),
126
128
  new CommandChatResponseContentImpl(undefined, customCallback, args),
127
129
  ]);
128
130
  } else {
129
- return new MarkdownChatResponseContentImpl(parsedCommand.message ?? 'Sorry, I can\'t find such a command');
131
+ return new MarkdownChatResponseContentImpl(parsedCommand.message ?? nls.localize('theia/ai/ide/commandAgent/response/noCommand',
132
+ 'Sorry, I can\'t find such a command'));
130
133
  }
131
134
  }
132
135
 
133
136
  protected async commandCallback(...commandArgs: unknown[]): Promise<void> {
134
- this.messageService.info(`Executing callback with args ${commandArgs.join(', ')}. The first arg is the command id registered for the dynamically registered command. \
135
- The other args are the actual args for the handler.`, 'Got it');
137
+ this.messageService.info(nls.localize('theia/ai/ide/commandAgent/commandCallback/message',
138
+ 'Executing callback with args {0}. The first arg is the command id registered for the dynamically registered command. ' +
139
+ 'The other args are the actual args for the handler.', commandArgs.join(', ')), nls.localize('theia/ai/ide/commandAgent/commandCallback/confirmAction', 'Got it'));
136
140
  }
137
141
  }
@@ -20,3 +20,4 @@ export const SUGGEST_FILE_REPLACEMENTS_ID = 'suggestFileReplacements';
20
20
  export const WRITE_FILE_REPLACEMENTS_ID = 'writeFileReplacements';
21
21
  export const CLEAR_FILE_CHANGES_ID = 'clearFileChanges';
22
22
  export const GET_PROPOSED_CHANGES_ID = 'getProposedFileState';
23
+ export const SUGGEST_FILE_REPLACEMENTS_NEXT_ID = 'suggestFileReplacements_Next';
@@ -50,7 +50,7 @@ export class OrchestratorChatAgent extends AbstractStreamParsingChatAgent {
50
50
  protected chatAgentService: ChatAgentService;
51
51
 
52
52
  override async invoke(request: MutableChatRequestModel): Promise<void> {
53
- request.response.addProgressMessage({ content: 'Determining the most appropriate agent', status: 'inProgress' });
53
+ request.response.addProgressMessage({ content: nls.localize('theia/ai/ide/orchestrator/progressMessage', 'Determining the most appropriate agent'), status: 'inProgress' });
54
54
  // We use a dedicated id for the orchestrator request
55
55
  const orchestratorRequestId = generateUuid();
56
56
  request.addData(OrchestratorRequestIdKey, orchestratorRequestId);
@@ -114,15 +114,16 @@ export class OrchestratorChatAgent extends AbstractStreamParsingChatAgent {
114
114
  if (firstRegisteredAgent) {
115
115
  agentIds = [firstRegisteredAgent];
116
116
  } else {
117
- throw new Error('No chat agent available to handle request. Please check your configuration whether any are enabled.');
117
+ throw new Error(nls.localize('theia/ai/ide/orchestrator/error/noAgents',
118
+ 'No chat agent available to handle request. Please check your configuration whether any are enabled.'));
118
119
  }
119
120
  }
120
121
 
121
122
  // TODO support delegating to more than one agent
122
123
  const delegatedToAgent = agentIds[0];
123
124
  request.response.response.addContent(new InformationalChatResponseContentImpl(
124
- `*Orchestrator*: Delegating to \`@${delegatedToAgent}\`
125
-
125
+ `*Orchestrator*: ${nls.localize('theia/ai/ide/orchestrator/response/delegatingToAgent', 'Delegating to \`@{0}\`', delegatedToAgent)}
126
+
126
127
  ---
127
128
 
128
129
  `
@@ -34,13 +34,13 @@ export const WorkspacePreferencesSchema: PreferenceSchema = {
34
34
  title: nls.localize('theia/ai/workspace/considerGitignore/title', 'Consider .gitignore'),
35
35
  description: nls.localize('theia/ai/workspace/considerGitignore/description',
36
36
  'If enabled, excludes files/folders specified in a global .gitignore file (expected location is the workspace root).'),
37
- default: false
37
+ default: true
38
38
  },
39
39
  [USER_EXCLUDE_PATTERN_PREF]: {
40
40
  type: 'array',
41
41
  title: nls.localize('theia/ai/workspace/excludedPattern/title', 'Excluded File Patterns'),
42
42
  description: nls.localize('theia/ai/workspace/excludedPattern/description', 'List of patterns (glob or regex) for files/folders to exclude.'),
43
- default: ['node_modules', 'lib', '.*'],
43
+ default: ['node_modules', 'lib'],
44
44
  items: {
45
45
  type: 'string'
46
46
  }