@theia/ai-ide 1.66.0-next.44 → 1.66.0-next.73

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 (97) 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 +7 -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/browser/github-repo-variable-contribution.d.ts +8 -10
  44. package/lib/browser/github-repo-variable-contribution.d.ts.map +1 -1
  45. package/lib/browser/github-repo-variable-contribution.js +22 -41
  46. package/lib/browser/github-repo-variable-contribution.js.map +1 -1
  47. package/lib/common/coder-replace-prompt-template.d.ts +2 -0
  48. package/lib/common/coder-replace-prompt-template.d.ts.map +1 -1
  49. package/lib/common/coder-replace-prompt-template.js +20 -8
  50. package/lib/common/coder-replace-prompt-template.js.map +1 -1
  51. package/lib/common/command-chat-agents.d.ts.map +1 -1
  52. package/lib/common/command-chat-agents.js +9 -9
  53. package/lib/common/command-chat-agents.js.map +1 -1
  54. package/lib/common/file-changeset-function-ids.d.ts +1 -0
  55. package/lib/common/file-changeset-function-ids.d.ts.map +1 -1
  56. package/lib/common/file-changeset-function-ids.js +2 -1
  57. package/lib/common/file-changeset-function-ids.js.map +1 -1
  58. package/lib/common/github-repo-protocol.d.ts +15 -0
  59. package/lib/common/github-repo-protocol.d.ts.map +1 -0
  60. package/lib/common/github-repo-protocol.js +21 -0
  61. package/lib/common/github-repo-protocol.js.map +1 -0
  62. package/lib/common/orchestrator-chat-agent.d.ts.map +1 -1
  63. package/lib/common/orchestrator-chat-agent.js +4 -4
  64. package/lib/common/orchestrator-chat-agent.js.map +1 -1
  65. package/lib/common/workspace-preferences.js +2 -2
  66. package/lib/common/workspace-preferences.js.map +1 -1
  67. package/lib/node/backend-module.d.ts.map +1 -1
  68. package/lib/node/backend-module.js +4 -0
  69. package/lib/node/backend-module.js.map +1 -1
  70. package/lib/node/github-repo-service-impl.d.ts +7 -0
  71. package/lib/node/github-repo-service-impl.d.ts.map +1 -0
  72. package/lib/node/github-repo-service-impl.js +86 -0
  73. package/lib/node/github-repo-service-impl.js.map +1 -0
  74. package/package.json +23 -23
  75. package/src/browser/ai-configuration/agent-configuration-widget.tsx +5 -3
  76. package/src/browser/ai-configuration/language-model-renderer.tsx +9 -4
  77. package/src/browser/ai-configuration/model-aliases-configuration-widget.tsx +8 -4
  78. package/src/browser/ai-configuration/template-settings-renderer.tsx +1 -1
  79. package/src/browser/ai-configuration/token-usage-configuration-widget.tsx +1 -1
  80. package/src/browser/ai-configuration/tools-configuration-widget.tsx +15 -14
  81. package/src/browser/ai-configuration/variable-configuration-widget.tsx +4 -3
  82. package/src/browser/app-tester-chat-agent.ts +15 -7
  83. package/src/browser/architect-agent.ts +4 -2
  84. package/src/browser/coder-agent.ts +10 -6
  85. package/src/browser/file-changeset-functions.spec.ts +28 -1
  86. package/src/browser/file-changeset-functions.ts +47 -3
  87. package/src/browser/frontend-module.ts +11 -1
  88. package/src/browser/github-chat-agent.ts +23 -17
  89. package/src/browser/github-repo-variable-contribution.ts +23 -50
  90. package/src/common/coder-replace-prompt-template.ts +23 -8
  91. package/src/common/command-chat-agents.ts +13 -9
  92. package/src/common/file-changeset-function-ids.ts +1 -0
  93. package/src/common/github-repo-protocol.ts +32 -0
  94. package/src/common/orchestrator-chat-agent.ts +5 -4
  95. package/src/common/workspace-preferences.ts +2 -2
  96. package/src/node/backend-module.ts +7 -0
  97. package/src/node/github-repo-service-impl.ts +98 -0
@@ -0,0 +1,86 @@
1
+ "use strict";
2
+ // *****************************************************************************
3
+ // Copyright (C) 2025 EclipseSource GmbH.
4
+ //
5
+ // This program and the accompanying materials are made available under the
6
+ // terms of the Eclipse Public License v. 2.0 which is available at
7
+ // http://www.eclipse.org/legal/epl-2.0.
8
+ //
9
+ // This Source Code may also be made available under the following Secondary
10
+ // Licenses when the conditions for such availability set forth in the Eclipse
11
+ // Public License v. 2.0 are satisfied: GNU General Public License, version 2
12
+ // with the GNU Classpath Exception which is available at
13
+ // https://www.gnu.org/software/classpath/license.html.
14
+ //
15
+ // SPDX-License-Identifier: EPL-2.0 OR GPL-2.0-only WITH Classpath-exception-2.0
16
+ // *****************************************************************************
17
+ Object.defineProperty(exports, "__esModule", { value: true });
18
+ exports.GitHubRepoServiceImpl = void 0;
19
+ const tslib_1 = require("tslib");
20
+ const inversify_1 = require("@theia/core/shared/inversify");
21
+ const simple_git_1 = require("simple-git");
22
+ let GitHubRepoServiceImpl = class GitHubRepoServiceImpl {
23
+ async getGitHubRepoInfo(workspacePath) {
24
+ try {
25
+ // Initialize simple-git with the workspace path
26
+ const git = (0, simple_git_1.simpleGit)(workspacePath);
27
+ // Check if this is a git repository
28
+ const isRepo = await git.checkIsRepo();
29
+ if (!isRepo) {
30
+ return undefined;
31
+ }
32
+ // Get all remotes with their URLs
33
+ const remotes = await git.getRemotes(true);
34
+ if (remotes.length === 0) {
35
+ return undefined;
36
+ }
37
+ // Find GitHub remote (prefer 'origin', then any GitHub remote)
38
+ const githubRemote = remotes.find(remote => remote.name === 'origin' && this.isGitHubRemote(remote.refs.fetch || remote.refs.push || '')) || remotes.find(remote => this.isGitHubRemote(remote.refs.fetch || remote.refs.push || ''));
39
+ if (!githubRemote) {
40
+ return undefined;
41
+ }
42
+ const remoteUrl = githubRemote.refs.fetch || githubRemote.refs.push || '';
43
+ const repoInfo = this.extractRepoInfoFromGitHubUrl(remoteUrl);
44
+ return repoInfo;
45
+ }
46
+ catch (error) {
47
+ console.warn('Failed to get GitHub repository info:', error);
48
+ return undefined;
49
+ }
50
+ }
51
+ isGitHubRemote(remoteUrl) {
52
+ return remoteUrl.includes('github.com');
53
+ }
54
+ extractRepoInfoFromGitHubUrl(url) {
55
+ // Handle HTTPS URLs: https://github.com/owner/repo or https://github.com/owner/repo.git
56
+ const httpsMatch = url.match(/https:\/\/github\.com\/([^\/]+)\/([^\/]+?)(?:\.git)?$/);
57
+ if (httpsMatch) {
58
+ return {
59
+ owner: httpsMatch[1],
60
+ repo: httpsMatch[2]
61
+ };
62
+ }
63
+ // Handle SSH URLs: git@github.com:owner/repo or git@github.com:owner/repo.git
64
+ const sshMatch = url.match(/git@github\.com:([^\/]+)\/([^\/]+?)(?:\.git)?$/);
65
+ if (sshMatch) {
66
+ return {
67
+ owner: sshMatch[1],
68
+ repo: sshMatch[2]
69
+ };
70
+ }
71
+ // Handle alternative SSH format: ssh://git@github.com/owner/repo or ssh://git@github.com/owner/repo.git
72
+ const sshAltMatch = url.match(/ssh:\/\/git@github\.com\/([^\/]+)\/([^\/]+?)(?:\.git)?$/);
73
+ if (sshAltMatch) {
74
+ return {
75
+ owner: sshAltMatch[1],
76
+ repo: sshAltMatch[2]
77
+ };
78
+ }
79
+ return undefined;
80
+ }
81
+ };
82
+ exports.GitHubRepoServiceImpl = GitHubRepoServiceImpl;
83
+ exports.GitHubRepoServiceImpl = GitHubRepoServiceImpl = tslib_1.__decorate([
84
+ (0, inversify_1.injectable)()
85
+ ], GitHubRepoServiceImpl);
86
+ //# sourceMappingURL=github-repo-service-impl.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"github-repo-service-impl.js","sourceRoot":"","sources":["../../src/node/github-repo-service-impl.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@theia/ai-ide",
3
- "version": "1.66.0-next.44+5b6e49d13",
3
+ "version": "1.66.0-next.73+6d82794da",
4
4
  "description": "AI IDE Agents Extension",
5
5
  "license": "EPL-2.0 OR GPL-2.0-only WITH Classpath-exception-2.0",
6
6
  "repository": {
@@ -15,36 +15,36 @@
15
15
  "theia-extension"
16
16
  ],
17
17
  "dependencies": {
18
- "@theia/ai-chat": "1.66.0-next.44+5b6e49d13",
19
- "@theia/ai-chat-ui": "1.66.0-next.44+5b6e49d13",
20
- "@theia/ai-core": "1.66.0-next.44+5b6e49d13",
21
- "@theia/ai-mcp": "1.66.0-next.44+5b6e49d13",
22
- "@theia/core": "1.66.0-next.44+5b6e49d13",
23
- "@theia/debug": "1.66.0-next.44+5b6e49d13",
24
- "@theia/editor": "1.66.0-next.44+5b6e49d13",
25
- "@theia/filesystem": "1.66.0-next.44+5b6e49d13",
26
- "@theia/git": "1.65.0",
27
- "@theia/markers": "1.66.0-next.44+5b6e49d13",
28
- "@theia/monaco": "1.66.0-next.44+5b6e49d13",
29
- "@theia/navigator": "1.66.0-next.44+5b6e49d13",
30
- "@theia/preferences": "1.66.0-next.44+5b6e49d13",
31
- "@theia/scm": "1.66.0-next.44+5b6e49d13",
32
- "@theia/search-in-workspace": "1.66.0-next.44+5b6e49d13",
33
- "@theia/task": "1.66.0-next.44+5b6e49d13",
34
- "@theia/terminal": "1.66.0-next.44+5b6e49d13",
35
- "@theia/workspace": "1.66.0-next.44+5b6e49d13",
18
+ "@theia/ai-chat": "1.66.0-next.73+6d82794da",
19
+ "@theia/ai-chat-ui": "1.66.0-next.73+6d82794da",
20
+ "@theia/ai-core": "1.66.0-next.73+6d82794da",
21
+ "@theia/ai-mcp": "1.66.0-next.73+6d82794da",
22
+ "@theia/core": "1.66.0-next.73+6d82794da",
23
+ "@theia/debug": "1.66.0-next.73+6d82794da",
24
+ "@theia/editor": "1.66.0-next.73+6d82794da",
25
+ "@theia/filesystem": "1.66.0-next.73+6d82794da",
26
+ "@theia/markers": "1.66.0-next.73+6d82794da",
27
+ "@theia/monaco": "1.66.0-next.73+6d82794da",
28
+ "@theia/navigator": "1.66.0-next.73+6d82794da",
29
+ "@theia/preferences": "1.66.0-next.73+6d82794da",
30
+ "@theia/scm": "1.66.0-next.73+6d82794da",
31
+ "@theia/search-in-workspace": "1.66.0-next.73+6d82794da",
32
+ "@theia/task": "1.66.0-next.73+6d82794da",
33
+ "@theia/terminal": "1.66.0-next.73+6d82794da",
34
+ "@theia/workspace": "1.66.0-next.73+6d82794da",
36
35
  "date-fns": "^4.1.0",
37
36
  "ignore": "^6.0.0",
38
37
  "js-yaml": "^4.1.0",
39
38
  "minimatch": "^10.0.3",
40
- "puppeteer-core": "^24.10.0"
39
+ "puppeteer-core": "^24.10.0",
40
+ "simple-git": "^3.25.0"
41
41
  },
42
42
  "publishConfig": {
43
43
  "access": "public"
44
44
  },
45
45
  "devDependencies": {
46
- "@theia/cli": "1.66.0-next.44+5b6e49d13",
47
- "@theia/test": "1.66.0-next.44+5b6e49d13"
46
+ "@theia/cli": "1.66.0-next.73+6d82794da",
47
+ "@theia/test": "1.66.0-next.73+6d82794da"
48
48
  },
49
49
  "theiaExtensions": [
50
50
  {
@@ -68,5 +68,5 @@
68
68
  "nyc": {
69
69
  "extends": "../../configs/nyc.json"
70
70
  },
71
- "gitHead": "5b6e49d139f9abbb18e233f138497a33a0758222"
71
+ "gitHead": "6d82794da24e16f75d70eaac3a4178a29e822e82"
72
72
  }
@@ -320,12 +320,14 @@ export class AIAgentConfigurationWidget extends ReactWidget {
320
320
 
321
321
  // Multiple locations - show quick picker
322
322
  const quickPick = this.quickInputService.createQuickPick();
323
- quickPick.title = 'Select Location for Custom Agents File';
324
- quickPick.placeholder = 'Choose where to create or open a custom agents file';
323
+ quickPick.title = nls.localize('theia/ai/ide/agentConfiguration/customAgentLocationQuickPick/title', 'Select Location for Custom Agents File');
324
+ quickPick.placeholder = nls.localize('theia/ai/ide/agentConfiguration/customAgentLocationQuickPick/placeholder', 'Choose where to create or open a custom agents file');
325
325
 
326
326
  quickPick.items = locations.map(location => ({
327
327
  label: location.uri.path.toString(),
328
- description: location.exists ? 'Open existing file' : 'Create new file',
328
+ description: location.exists
329
+ ? nls.localize('theia/ai/ide/agentConfiguration/customAgentLocationQuickPick/openExistingFile', 'Open existing file')
330
+ : nls.localize('theia/ai/ide/agentConfiguration/customAgentLocationQuickPick/createNewFile', 'Create new file'),
329
331
  location
330
332
  }));
331
333
 
@@ -103,7 +103,9 @@ export const LanguageModelRenderer: React.FC<LanguageModelSettingsProps> = (
103
103
  <option value=""></option>
104
104
  {/* Aliases first, then languange models */}
105
105
  {aliases?.sort((a, b) => a.id.localeCompare(b.id)).map(alias => (
106
- <option key={`alias/${alias.id}`} value={alias.id} className='ai-language-model-item-ready'>{`[alias] ${alias.id}`}</option>
106
+ <option key={`alias/${alias.id}`} value={alias.id} className='ai-language-model-item-ready'>
107
+ {nls.localize('theia/ai/core/languageModelRenderer/alias', '[alias] {0}', alias.id)}
108
+ </option>
107
109
  ))}
108
110
  {languageModels?.sort((a, b) => (a.name ?? a.id).localeCompare(b.name ?? b.id)).map(model => {
109
111
  const isNotReady = model.status.status !== 'ready';
@@ -128,15 +130,18 @@ export const LanguageModelRenderer: React.FC<LanguageModelSettingsProps> = (
128
130
  <span className="ai-alias-evaluates-to-value">
129
131
  {resolvedModel.name ?? resolvedModel.id}
130
132
  {resolvedModel.status.status === 'ready' ? (
131
- <span className="ai-model-status-ready" title="Ready">✓</span>
133
+ <span className="ai-model-status-ready"
134
+ title={nls.localize('theia/ai/core/modelAliasesConfiguration/modelReadyTooltip', 'Ready')}>✓</span>
132
135
  ) : (
133
- <span className="ai-model-status-not-ready" title={resolvedModel.status.message || 'Not ready'}>✗</span>
136
+ <span className="ai-model-status-not-ready" title={resolvedModel.status.message
137
+ || nls.localize('theia/ai/core/modelAliasesConfiguration/modelNotReadyTooltip', 'Not ready')}>✗</span>
134
138
  )}
135
139
  </span>
136
140
  ) : (
137
141
  <span className="ai-alias-evaluates-to-unresolved">
138
142
  {nls.localize('theia/ai/core/modelAliasesConfiguration/noResolvedModel', 'No model ready for this alias.')}
139
- <span className="ai-model-status-not-ready" title={'No model ready'}>✗</span>
143
+ <span className="ai-model-status-not-ready"
144
+ title={nls.localize('theia/ai/core/modelAliasesConfiguration/noModelReadyTooltip', 'No model ready')}>✗</span>
140
145
  </span>
141
146
  )}
142
147
  </div>
@@ -229,11 +229,13 @@ export class ModelAliasesConfigurationWidget extends ReactWidget {
229
229
  <li key={modelId}>
230
230
  {isReady ? (
231
231
  <span className={modelId === resolvedModel?.id ? 'ai-alias-priority-item-resolved' : 'ai-alias-priority-item-ready'}>
232
- {modelId} <span className="ai-model-status-ready" title="Ready">✓</span>
232
+ {modelId} <span className="ai-model-status-ready"
233
+ title={nls.localize('theia/ai/core/modelAliasesConfiguration/modelReadyTooltip', 'Ready')}>✓</span>
233
234
  </span>
234
235
  ) : (
235
236
  <span className="ai-model-default-not-ready">
236
- {modelId} <span className="ai-model-status-not-ready" title="Not ready">✗</span>
237
+ {modelId} <span className="ai-model-status-not-ready"
238
+ title={nls.localize('theia/ai/core/modelAliasesConfiguration/modelNotReadyTooltip', 'Not ready')}>✗</span>
237
239
  </span>
238
240
  )}
239
241
  </li>
@@ -246,9 +248,11 @@ export class ModelAliasesConfigurationWidget extends ReactWidget {
246
248
  <span className="ai-alias-evaluates-to-value">
247
249
  {resolvedModel.name ?? resolvedModel.id}
248
250
  {resolvedModel.status.status === 'ready' ? (
249
- <span className="ai-model-status-ready" title="Ready">✓</span>
251
+ <span className="ai-model-status-ready"
252
+ title={nls.localize('theia/ai/core/modelAliasesConfiguration/modelReadyTooltip', 'Ready')}>✓</span>
250
253
  ) : (
251
- <span className="ai-model-status-not-ready" title={resolvedModel.status.message || 'Not ready'}>✗</span>
254
+ <span className="ai-model-status-not-ready" title={resolvedModel.status.message
255
+ || nls.localize('theia/ai/core/modelAliasesConfiguration/modelNotReadyTooltip', 'Not ready')}>✗</span>
252
256
  )}
253
257
  </span>
254
258
  ) : (
@@ -86,7 +86,7 @@ export const PromptVariantRenderer: React.FC<PromptVariantRendererProps> = ({
86
86
  )}
87
87
  {variantIds.map(variantId => (
88
88
  <option key={variantId} value={variantId}>
89
- {variantId === defaultVariantId ? variantId + ' (default)' : variantId}
89
+ {variantId === defaultVariantId ? variantId + ' ' + nls.localizeByDefault('(default)') : variantId}
90
90
  </option>
91
91
  ))}
92
92
  </select>
@@ -57,7 +57,7 @@ export class AITokenUsageConfigurationWidget extends ReactWidget {
57
57
  this.tokenUsageData = await this.tokenUsageService.getTokenUsageData();
58
58
  this.update();
59
59
  } catch (error) {
60
- this.messageService.error(`Failed to fetch token usage data: ${error}`);
60
+ this.messageService.error(nls.localize('theia/ai/tokenUsage/failedToGetTokenUsageData', 'Failed to fetch token usage data: {0}', error));
61
61
  }
62
62
  }
63
63
 
@@ -18,20 +18,20 @@ import { ReactWidget, ConfirmDialog } from '@theia/core/lib/browser';
18
18
  import { inject, injectable, postConstruct } from '@theia/core/shared/inversify';
19
19
  import * as React from '@theia/core/shared/react';
20
20
  import { ToolInvocationRegistry } from '@theia/ai-core';
21
- import { PreferenceService } from '@theia/core';
21
+ import { nls, PreferenceService } from '@theia/core';
22
22
  import { ToolConfirmationManager } from '@theia/ai-chat/lib/browser/chat-tool-preference-bindings';
23
23
  import { ToolConfirmationMode } from '@theia/ai-chat/lib/common/chat-tool-preferences';
24
24
 
25
25
  const TOOL_OPTIONS: { value: ToolConfirmationMode, label: string, icon: string }[] = [
26
- { value: ToolConfirmationMode.DISABLED, label: 'Disabled', icon: 'close' },
27
- { value: ToolConfirmationMode.CONFIRM, label: 'Confirm', icon: 'question' },
28
- { value: ToolConfirmationMode.ALWAYS_ALLOW, label: 'Always Allow', icon: 'thumbsup' },
26
+ { value: ToolConfirmationMode.DISABLED, label: nls.localizeByDefault('Disabled'), icon: 'close' },
27
+ { value: ToolConfirmationMode.CONFIRM, label: nls.localize('theia/ai/ide/toolsConfiguration/toolOptions/confirm/label', 'Confirm'), icon: 'question' },
28
+ { value: ToolConfirmationMode.ALWAYS_ALLOW, label: nls.localize('theia/ai/ide/toolsConfiguration/toolOptions/alwaysAllow/label', 'Always Allow'), icon: 'thumbsup' },
29
29
  ];
30
30
 
31
31
  @injectable()
32
32
  export class AIToolsConfigurationWidget extends ReactWidget {
33
33
  static readonly ID = 'ai-tools-configuration-widget';
34
- static readonly LABEL = 'Tools';
34
+ static readonly LABEL = nls.localize('theia/ai/ide/toolsConfiguration/label', 'Tools');
35
35
 
36
36
  @inject(ToolConfirmationManager)
37
37
  protected readonly confirmationManager: ToolConfirmationManager;
@@ -106,10 +106,11 @@ export class AIToolsConfigurationWidget extends ReactWidget {
106
106
 
107
107
  protected async resetAllToolsToDefault(): Promise<void> {
108
108
  const dialog = new ConfirmDialog({
109
- title: 'Reset All Tool Confirmation Modes',
110
- msg: 'Are you sure you want to reset all tool confirmation modes to the default? This will remove all custom settings.',
111
- ok: 'Reset All',
112
- cancel: 'Cancel'
109
+ title: nls.localize('theia/ai/ide/toolsConfiguration/resetAllConfirmDialog/title', 'Reset All Tool Confirmation Modes'),
110
+ msg: nls.localize('theia/ai/ide/toolsConfiguration/resetAllConfirmDialog/msg',
111
+ 'Are you sure you want to reset all tool confirmation modes to the default? This will remove all custom settings.'),
112
+ ok: nls.localize('theia/ai/ide/toolsConfiguration/resetAll', 'Reset All'),
113
+ cancel: nls.localizeByDefault('Cancel')
113
114
  });
114
115
  const shouldReset = await dialog.open();
115
116
  if (shouldReset) {
@@ -119,11 +120,11 @@ export class AIToolsConfigurationWidget extends ReactWidget {
119
120
 
120
121
  protected render(): React.ReactNode {
121
122
  if (this.loading) {
122
- return <div>Loading tools...</div>;
123
+ return <div>{nls.localize('theia/ai/ide/toolsConfiguration/loading', 'Loading tools...')}</div>;
123
124
  }
124
125
  return <div className='ai-tools-configuration-container'>
125
126
  <div className='ai-tools-configuration-default-section' style={{ display: 'flex', alignItems: 'center', gap: 8 }}>
126
- <div className='ai-tools-configuration-default-label'>Default Tool Confirmation Mode:</div>
127
+ <div className='ai-tools-configuration-default-label'>{nls.localize('theia/ai/ide/toolsConfiguration/default/label', 'Default Tool Confirmation Mode:')}</div>
127
128
  <select
128
129
  className="ai-tools-configuration-default-select"
129
130
  value={this.defaultState}
@@ -137,14 +138,14 @@ export class AIToolsConfigurationWidget extends ReactWidget {
137
138
  <button
138
139
  className='ai-tools-configuration-reset-btn'
139
140
  style={{ marginLeft: 'auto' }}
140
- title='Reset all tools to default'
141
+ title={nls.localize('theia/ai/ide/toolsConfiguration/resetAllTooltip', 'Reset all tools to default')}
141
142
  onClick={() => this.resetAllToolsToDefault()}
142
143
  >
143
- Reset All
144
+ {nls.localize('theia/ai/ide/toolsConfiguration/resetAll', 'Reset All')}
144
145
  </button>
145
146
  </div>
146
147
  <div className='ai-tools-configuration-tools-section'>
147
- <div className='ai-tools-configuration-tools-label'>Tools</div>
148
+ <div className='ai-tools-configuration-tools-label'>{nls.localize('theia/ai/ide/toolsConfiguration/tools/label', 'Tools')}</div>
148
149
  <ul className='ai-tools-configuration-tools-list'>
149
150
  {this.tools.map(tool => {
150
151
  const state = this.toolConfirmationModes[tool] || this.defaultState;
@@ -20,12 +20,13 @@ import { inject, injectable, postConstruct } from '@theia/core/shared/inversify'
20
20
  import * as React from '@theia/core/shared/react';
21
21
  import { AIAgentConfigurationWidget } from './agent-configuration-widget';
22
22
  import { AIConfigurationSelectionService } from './ai-configuration-service';
23
+ import { nls } from '@theia/core';
23
24
 
24
25
  @injectable()
25
26
  export class AIVariableConfigurationWidget extends ReactWidget {
26
27
 
27
28
  static readonly ID = 'ai-variable-configuration-container-widget';
28
- static readonly LABEL = 'Variables';
29
+ static readonly LABEL = nls.localizeByDefault('Variables');
29
30
 
30
31
  @inject(AIVariableService)
31
32
  protected readonly variableService: AIVariableService;
@@ -68,7 +69,7 @@ export class AIVariableConfigurationWidget extends ReactWidget {
68
69
  }
69
70
 
70
71
  return <div>
71
- <h3>Agents</h3>
72
+ <h3>{nls.localize('theia/ai/ide/variableConfiguration/agents', 'Agents')}</h3>
72
73
  <ul className='variable-references'>
73
74
  {agents.map(agent => <li key={agent.id} className='theia-TreeNode theia-CompositeTreeNode theia-ExpandableTreeNode theia-mod-selected'>
74
75
  <div onClick={() => { this.showAgentConfiguration(agent); }} className='variable-reference'>
@@ -85,7 +86,7 @@ export class AIVariableConfigurationWidget extends ReactWidget {
85
86
  }
86
87
 
87
88
  return <div className='variable-args-container'>
88
- <h3>Variable Arguments</h3>
89
+ <h3>{nls.localize('theia/ai/ide/variableConfiguration/variableArgs', 'Variable Arguments')}</h3>
89
90
  <div className='variable-args'>
90
91
  {variable.args.map(arg =>
91
92
  <React.Fragment key={arg.name}>
@@ -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 {