@theia/ai-ide 1.63.0-next.24 → 1.63.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (93) 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 +7 -2
  3. package/lib/browser/ai-configuration/agent-configuration-widget.js.map +1 -1
  4. package/lib/browser/ai-configuration/ai-configuration-view-contribution.js +1 -1
  5. package/lib/browser/ai-configuration/ai-configuration-view-contribution.js.map +1 -1
  6. package/lib/browser/ai-configuration/ai-configuration-widget.d.ts +0 -1
  7. package/lib/browser/ai-configuration/ai-configuration-widget.d.ts.map +1 -1
  8. package/lib/browser/ai-configuration/ai-configuration-widget.js +0 -1
  9. package/lib/browser/ai-configuration/ai-configuration-widget.js.map +1 -1
  10. package/lib/browser/ai-configuration/mcp-configuration-widget.d.ts +4 -1
  11. package/lib/browser/ai-configuration/mcp-configuration-widget.d.ts.map +1 -1
  12. package/lib/browser/ai-configuration/mcp-configuration-widget.js +59 -11
  13. package/lib/browser/ai-configuration/mcp-configuration-widget.js.map +1 -1
  14. package/lib/browser/ai-configuration/prompt-fragments-configuration-widget.d.ts +0 -1
  15. package/lib/browser/ai-configuration/prompt-fragments-configuration-widget.d.ts.map +1 -1
  16. package/lib/browser/ai-configuration/prompt-fragments-configuration-widget.js +1 -4
  17. package/lib/browser/ai-configuration/prompt-fragments-configuration-widget.js.map +1 -1
  18. package/lib/browser/ai-configuration/template-settings-renderer.js +1 -1
  19. package/lib/browser/ai-configuration/template-settings-renderer.js.map +1 -1
  20. package/lib/browser/ai-configuration/tools-configuration-widget.d.ts +0 -1
  21. package/lib/browser/ai-configuration/tools-configuration-widget.d.ts.map +1 -1
  22. package/lib/browser/ai-configuration/tools-configuration-widget.js +6 -21
  23. package/lib/browser/ai-configuration/tools-configuration-widget.js.map +1 -1
  24. package/lib/browser/app-tester-chat-agent.d.ts +5 -3
  25. package/lib/browser/app-tester-chat-agent.d.ts.map +1 -1
  26. package/lib/browser/app-tester-chat-agent.js +41 -31
  27. package/lib/browser/app-tester-chat-agent.js.map +1 -1
  28. package/lib/browser/architect-agent.d.ts.map +1 -1
  29. package/lib/browser/architect-agent.js +6 -3
  30. package/lib/browser/architect-agent.js.map +1 -1
  31. package/lib/browser/frontend-module.d.ts +1 -0
  32. package/lib/browser/frontend-module.d.ts.map +1 -1
  33. package/lib/browser/frontend-module.js +1 -0
  34. package/lib/browser/frontend-module.js.map +1 -1
  35. package/lib/browser/summarize-session-command-contribution.d.ts +8 -1
  36. package/lib/browser/summarize-session-command-contribution.d.ts.map +1 -1
  37. package/lib/browser/summarize-session-command-contribution.js +60 -6
  38. package/lib/browser/summarize-session-command-contribution.js.map +1 -1
  39. package/lib/browser/task-context-file-storage-service.d.ts +4 -2
  40. package/lib/browser/task-context-file-storage-service.d.ts.map +1 -1
  41. package/lib/browser/task-context-file-storage-service.js +19 -9
  42. package/lib/browser/task-context-file-storage-service.js.map +1 -1
  43. package/lib/browser/workspace-preferences.d.ts +1 -0
  44. package/lib/browser/workspace-preferences.d.ts.map +1 -1
  45. package/lib/browser/workspace-preferences.js +9 -1
  46. package/lib/browser/workspace-preferences.js.map +1 -1
  47. package/lib/browser/workspace-search-provider.d.ts +5 -1
  48. package/lib/browser/workspace-search-provider.d.ts.map +1 -1
  49. package/lib/browser/workspace-search-provider.js +57 -17
  50. package/lib/browser/workspace-search-provider.js.map +1 -1
  51. package/lib/browser/workspace-search-provider.spec.d.ts +2 -0
  52. package/lib/browser/workspace-search-provider.spec.d.ts.map +1 -0
  53. package/lib/browser/workspace-search-provider.spec.js +227 -0
  54. package/lib/browser/workspace-search-provider.spec.js.map +1 -0
  55. package/lib/common/architect-prompt-template.d.ts +4 -2
  56. package/lib/common/architect-prompt-template.d.ts.map +1 -1
  57. package/lib/common/architect-prompt-template.js +201 -35
  58. package/lib/common/architect-prompt-template.js.map +1 -1
  59. package/lib/common/coder-replace-prompt-template.d.ts +4 -4
  60. package/lib/common/coder-replace-prompt-template.d.ts.map +1 -1
  61. package/lib/common/coder-replace-prompt-template.js +8 -8
  62. package/lib/common/coder-replace-prompt-template.js.map +1 -1
  63. package/lib/common/summarize-session-commands.d.ts +1 -0
  64. package/lib/common/summarize-session-commands.d.ts.map +1 -1
  65. package/lib/common/summarize-session-commands.js +5 -1
  66. package/lib/common/summarize-session-commands.js.map +1 -1
  67. package/lib/common/universal-chat-agent.js +2 -2
  68. package/lib/common/workspace-search-provider-util.d.ts +17 -0
  69. package/lib/common/workspace-search-provider-util.d.ts.map +1 -0
  70. package/lib/common/workspace-search-provider-util.js +51 -0
  71. package/lib/common/workspace-search-provider-util.js.map +1 -0
  72. package/package.json +19 -18
  73. package/src/browser/ai-configuration/agent-configuration-widget.tsx +7 -5
  74. package/src/browser/ai-configuration/ai-configuration-view-contribution.ts +1 -1
  75. package/src/browser/ai-configuration/ai-configuration-widget.tsx +0 -1
  76. package/src/browser/ai-configuration/mcp-configuration-widget.tsx +82 -14
  77. package/src/browser/ai-configuration/prompt-fragments-configuration-widget.tsx +1 -4
  78. package/src/browser/ai-configuration/template-settings-renderer.tsx +1 -1
  79. package/src/browser/ai-configuration/tools-configuration-widget.tsx +8 -23
  80. package/src/browser/app-tester-chat-agent.ts +43 -33
  81. package/src/browser/architect-agent.ts +8 -5
  82. package/src/browser/frontend-module.ts +2 -0
  83. package/src/browser/style/index.css +23 -28
  84. package/src/browser/summarize-session-command-contribution.ts +64 -8
  85. package/src/browser/task-context-file-storage-service.ts +20 -10
  86. package/src/browser/workspace-preferences.ts +9 -0
  87. package/src/browser/workspace-search-provider.spec.ts +255 -0
  88. package/src/browser/workspace-search-provider.ts +62 -16
  89. package/src/common/architect-prompt-template.ts +201 -35
  90. package/src/common/coder-replace-prompt-template.ts +8 -8
  91. package/src/common/summarize-session-commands.ts +5 -0
  92. package/src/common/universal-chat-agent.ts +2 -2
  93. package/src/common/workspace-search-provider-util.ts +50 -0
@@ -18,7 +18,14 @@ import { ReactWidget } 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 { HoverService } from '@theia/core/lib/browser/hover-service';
21
- import { MCPFrontendNotificationService, MCPFrontendService, MCPServerDescription, MCPServerStatus } from '@theia/ai-mcp/lib/common/mcp-server-manager';
21
+ import {
22
+ isLocalMCPServerDescription,
23
+ isRemoteMCPServerDescription,
24
+ MCPFrontendNotificationService,
25
+ MCPFrontendService,
26
+ MCPServerDescription,
27
+ MCPServerStatus
28
+ } from '@theia/ai-mcp/lib/common/mcp-server-manager';
22
29
  import { MessageService, nls } from '@theia/core';
23
30
  import { PROMPT_VARIABLE } from '@theia/ai-core/lib/common/prompt-variable-contribution';
24
31
 
@@ -67,12 +74,15 @@ export class AIMCPConfigurationWidget extends ReactWidget {
67
74
  }
68
75
  switch (status) {
69
76
  case MCPServerStatus.Running:
77
+ case MCPServerStatus.Connected:
70
78
  return { bg: 'var(--theia-successBackground)', fg: 'var(--theia-successForeground)' };
71
79
  case MCPServerStatus.Starting:
80
+ case MCPServerStatus.Connecting:
72
81
  return { bg: 'var(--theia-warningBackground)', fg: 'var(--theia-warningForeground)' };
73
82
  case MCPServerStatus.Errored:
74
83
  return { bg: 'var(--theia-errorBackground)', fg: 'var(--theia-errorForeground)' };
75
84
  case MCPServerStatus.NotRunning:
85
+ case MCPServerStatus.NotConnected:
76
86
  default:
77
87
  return { bg: 'var(--theia-inputValidation-infoBackground)', fg: 'var(--theia-inputValidation-infoForeground)' };
78
88
  }
@@ -106,10 +116,14 @@ export class AIMCPConfigurationWidget extends ReactWidget {
106
116
  );
107
117
  }
108
118
 
109
- protected renderStatusBadge(status?: MCPServerStatus, error?: string): React.ReactNode {
110
- const colors = this.getStatusColor(status);
111
- const displayStatus = status || MCPServerStatus.NotRunning;
119
+ protected renderStatusBadge(server: MCPServerDescription): React.ReactNode {
120
+ const colors = this.getStatusColor(server.status);
121
+ let displayStatus = server.status;
122
+ if (!displayStatus) {
123
+ displayStatus = isRemoteMCPServerDescription(server) ? MCPServerStatus.NotConnected : MCPServerStatus.NotRunning;
124
+ }
112
125
  const spanRef = React.createRef<HTMLSpanElement>();
126
+ const error = server.error;
113
127
  return (
114
128
  <div className="mcp-status-container">
115
129
  <span className="mcp-status-badge" style={{
@@ -136,12 +150,15 @@ export class AIMCPConfigurationWidget extends ReactWidget {
136
150
  return (
137
151
  <div className="mcp-server-header">
138
152
  <div className="mcp-server-name">{server.name}</div>
139
- {this.renderStatusBadge(server.status, server.error)}
153
+ {this.renderStatusBadge(server)}
140
154
  </div>
141
155
  );
142
156
  }
143
157
 
144
158
  protected renderCommandSection(server: MCPServerDescription): React.ReactNode {
159
+ if (!isLocalMCPServerDescription(server)) {
160
+ return;
161
+ }
145
162
  return (
146
163
  <div className="mcp-server-section">
147
164
  <span className="mcp-section-label">{nls.localize('theia/ai/mcpConfiguration/command', 'Command: ')}</span>
@@ -151,7 +168,7 @@ export class AIMCPConfigurationWidget extends ReactWidget {
151
168
  }
152
169
 
153
170
  protected renderArgumentsSection(server: MCPServerDescription): React.ReactNode {
154
- if (!server.args || server.args.length === 0) {
171
+ if (!isLocalMCPServerDescription(server) || !server.args || server.args.length === 0) {
155
172
  return;
156
173
  }
157
174
  return (
@@ -163,7 +180,7 @@ export class AIMCPConfigurationWidget extends ReactWidget {
163
180
  }
164
181
 
165
182
  protected renderEnvironmentSection(server: MCPServerDescription): React.ReactNode {
166
- if (!server.env || Object.keys(server.env).length === 0) {
183
+ if (!isLocalMCPServerDescription(server) || !server.env || Object.keys(server.env).length === 0) {
167
184
  return;
168
185
  }
169
186
  return (
@@ -172,7 +189,7 @@ export class AIMCPConfigurationWidget extends ReactWidget {
172
189
  <div className="mcp-env-block">
173
190
  {Object.entries(server.env).map(([key, value]) => (
174
191
  <div key={key}>
175
- {key}={key.toLowerCase().includes('token') ? '******' : value}
192
+ {key}={key.toLowerCase().includes('token') ? '******' : String(value)}
176
193
  </div>
177
194
  ))}
178
195
  </div>
@@ -180,6 +197,42 @@ export class AIMCPConfigurationWidget extends ReactWidget {
180
197
  );
181
198
  }
182
199
 
200
+ protected renderServerUrlSection(server: MCPServerDescription): React.ReactNode {
201
+ if (!isRemoteMCPServerDescription(server)) {
202
+ return;
203
+ }
204
+ return (
205
+ <div className="mcp-server-section">
206
+ <span className="mcp-section-label">{nls.localize('theia/ai/mcpConfiguration/serverUrl', 'Server URL: ')}</span>
207
+ <code className="mcp-code-block">{server.serverUrl}</code>
208
+ </div>
209
+ );
210
+ }
211
+
212
+ protected renderServerAuthTokenHeaderSection(server: MCPServerDescription): React.ReactNode {
213
+ if (!isRemoteMCPServerDescription(server) || !server.serverAuthTokenHeader) {
214
+ return;
215
+ }
216
+ return (
217
+ <div className="mcp-server-section">
218
+ <span className="mcp-section-label">{nls.localize('theia/ai/mcpConfiguration/serverAuthTokenHeader', 'Authentication Header Name: ')}</span>
219
+ <code className="mcp-code-block">{server.serverAuthTokenHeader}</code>
220
+ </div>
221
+ );
222
+ }
223
+
224
+ protected renderServerAuthTokenSection(server: MCPServerDescription): React.ReactNode {
225
+ if (!isRemoteMCPServerDescription(server) || !server.serverAuthToken) {
226
+ return;
227
+ }
228
+ return (
229
+ <div className="mcp-server-section">
230
+ <span className="mcp-section-label">{nls.localize('theia/ai/mcpConfiguration/serverAuthToken', 'Authentication Token: ')}</span>
231
+ <code className="mcp-code-block">******</code>
232
+ </div>
233
+ );
234
+ }
235
+
183
236
  protected renderAutostartSection(server: MCPServerDescription): React.ReactNode {
184
237
  return (
185
238
  <div className="mcp-server-section">
@@ -286,19 +339,31 @@ export class AIMCPConfigurationWidget extends ReactWidget {
286
339
  }
287
340
 
288
341
  protected renderServerControls(server: MCPServerDescription): React.ReactNode {
289
- const isStoppable = server.status === MCPServerStatus.Running || server.status === MCPServerStatus.Starting;
290
- const isStartable = server.status === MCPServerStatus.NotRunning || server.status === MCPServerStatus.Errored;
342
+ const isStoppable = server.status === MCPServerStatus.Running
343
+ || server.status === MCPServerStatus.Connected
344
+ || server.status === MCPServerStatus.Starting
345
+ || server.status === MCPServerStatus.Connecting;
346
+ const isStartable = server.status === MCPServerStatus.NotRunning
347
+ || server.status === MCPServerStatus.NotConnected
348
+ || server.status === MCPServerStatus.Errored;
349
+
350
+ const startLabel = isRemoteMCPServerDescription(server)
351
+ ? nls.localize('theia/ai/mcpConfiguration/connectServer', 'Connnect')
352
+ : nls.localize('theia/ai/mcpConfiguration/startServer', 'Start Server');
353
+ const stopLabel = isRemoteMCPServerDescription(server)
354
+ ? nls.localize('theia/ai/mcpConfiguration/disconnectServer', 'Disconnnect')
355
+ : nls.localize('theia/ai/mcpConfiguration/stopServer', 'Stop Server');
291
356
  return (
292
357
  <div className="mcp-server-controls">
293
358
  {isStartable && this.renderButton(
294
- <><i className="codicon codicon-play"></i> {nls.localize('theia/ai/mcpConfiguration/startServer', 'Start Server')}</>,
295
- nls.localize('theia/ai/mcpConfiguration/startServer', 'Start Server'),
359
+ <><i className="codicon codicon-play"></i> {startLabel}</>,
360
+ startLabel,
296
361
  () => this.handleStartServer(server.name),
297
362
  'mcp-server-button play-button'
298
363
  )}
299
364
  {isStoppable && this.renderButton(
300
- <><i className="codicon codicon-close"></i> {nls.localize('theia/ai/mcpConfiguration/stopServer', 'Stop Server')}</>,
301
- nls.localize('theia/ai/mcpConfiguration/stopServer', 'Stop Server'),
365
+ <><i className="codicon codicon-close"></i> {stopLabel}</>,
366
+ stopLabel,
302
367
  () => this.handleStopServer(server.name),
303
368
  'mcp-server-button stop-button'
304
369
  )}
@@ -313,6 +378,9 @@ export class AIMCPConfigurationWidget extends ReactWidget {
313
378
  {this.renderCommandSection(server)}
314
379
  {this.renderArgumentsSection(server)}
315
380
  {this.renderEnvironmentSection(server)}
381
+ {this.renderServerUrlSection(server)}
382
+ {this.renderServerAuthTokenHeaderSection(server)}
383
+ {this.renderServerAuthTokenSection(server)}
316
384
  {this.renderAutostartSection(server)}
317
385
  {this.renderToolsSection(server)}
318
386
  {this.renderServerControls(server)}
@@ -26,7 +26,6 @@ import {
26
26
  BasePromptFragment
27
27
  } from '@theia/ai-core/lib/common/prompt-service';
28
28
  import * as React from '@theia/core/shared/react';
29
- import '../../../src/browser/style/index.css';
30
29
  import { AgentService } from '@theia/ai-core/lib/common/agent-service';
31
30
  import { Agent } from '@theia/ai-core/lib/common/agent';
32
31
  import { CustomizationSource } from '@theia/ai-core/lib/browser/frontend-prompt-customization-service';
@@ -347,9 +346,7 @@ export class AIPromptFragmentsConfigurationWidget extends ReactWidget {
347
346
 
348
347
  const shouldReset = await dialog.open();
349
348
  if (shouldReset) {
350
- this.promptFragmentMap.forEach(fragments => {
351
- this.promptService.resetToBuiltIn(fragments[0].id);
352
- });
349
+ this.promptService.resetAllToBuiltIn();
353
350
  }
354
351
  };
355
352
 
@@ -77,7 +77,7 @@ export const PromptVariantRenderer: React.FC<PromptVariantRendererProps> = ({
77
77
  >
78
78
  {isInvalidVariant && (
79
79
  <option value="invalid" disabled>
80
- {nls.localize('theia/ai/core/templateSettings/unavailableVariant', 'The selected variant is no longer available')}
80
+ {nls.localize('theia/ai/core/templateSettings/unavailableVariant', 'Selected variant not available, default will be used')}
81
81
  </option>
82
82
  )}
83
83
  {variantIds.map(variantId => (
@@ -20,10 +20,10 @@ import * as React from '@theia/core/shared/react';
20
20
  import { ToolConfirmationManager, ToolConfirmationMode } from '@theia/ai-chat/lib/browser/chat-tool-preferences';
21
21
  import { ToolInvocationRegistry } from '@theia/ai-core';
22
22
 
23
- const TOOL_OPTIONS: { value: ToolConfirmationMode, label: string, icon: string, color: string }[] = [
24
- { value: ToolConfirmationMode.DISABLED, label: 'Disabled', icon: 'close', color: 'var(--theia-errorForeground)' },
25
- { value: ToolConfirmationMode.CONFIRM, label: 'Confirm', icon: 'question', color: 'var(--theia-descriptionForeground)' },
26
- { value: ToolConfirmationMode.YOLO, label: 'Yolo', icon: 'thumbsup', color: 'var(--theia-successForeground)' },
23
+ const TOOL_OPTIONS: { value: ToolConfirmationMode, label: string, icon: string }[] = [
24
+ { value: ToolConfirmationMode.DISABLED, label: 'Disabled', icon: 'close' },
25
+ { value: ToolConfirmationMode.CONFIRM, label: 'Confirm', icon: 'question' },
26
+ { value: ToolConfirmationMode.ALWAYS_ALLOW, label: 'Always Allow', icon: 'thumbsup' },
27
27
  ];
28
28
 
29
29
  @injectable()
@@ -102,18 +102,6 @@ export class AIToolsConfigurationWidget extends ReactWidget {
102
102
  await this.updateDefaultConfirmation(newState);
103
103
  };
104
104
 
105
- protected getColoring(mode: ToolConfirmationMode, renderDefault = false): string {
106
- if (!renderDefault && mode === this.defaultState) {
107
- return '';
108
- }
109
- if (mode === ToolConfirmationMode.YOLO) {
110
- return ' ai-tools-configuration-tool-select--yolo';
111
- } else if (mode === ToolConfirmationMode.DISABLED) {
112
- return ' ai-tools-configuration-tool-select--disabled';
113
- }
114
- return ' ai-tools-configuration-tool-select--confirm';
115
- }
116
-
117
105
  protected async resetAllToolsToDefault(): Promise<void> {
118
106
  const dialog = new ConfirmDialog({
119
107
  title: 'Reset All Tool Confirmation Modes',
@@ -135,13 +123,13 @@ export class AIToolsConfigurationWidget extends ReactWidget {
135
123
  <div className='ai-tools-configuration-default-section' style={{ display: 'flex', alignItems: 'center', gap: 8 }}>
136
124
  <div className='ai-tools-configuration-default-label'>Default Tool Confirmation Mode:</div>
137
125
  <select
138
- className={`ai-tools-configuration-default-select ${this.getColoring(this.defaultState, true)}`}
126
+ className="ai-tools-configuration-default-select"
139
127
  value={this.defaultState}
140
128
  onChange={this.handleDefaultStateChange}
141
129
  style={{ marginLeft: 8 }}
142
130
  >
143
131
  {TOOL_OPTIONS.map(opt => (
144
- <option className={this.getColoring(opt.value, true)} key={opt.value} value={opt.value}>{opt.label}</option>
132
+ <option key={opt.value} value={opt.value}>{opt.label}</option>
145
133
  ))}
146
134
  </select>
147
135
  <button
@@ -159,10 +147,7 @@ export class AIToolsConfigurationWidget extends ReactWidget {
159
147
  {this.tools.map(tool => {
160
148
  const state = this.toolConfirmationModes[tool] || this.defaultState;
161
149
  const isDefault = state === this.defaultState;
162
- let selectClass = 'ai-tools-configuration-tool-select';
163
- if (!isDefault) {
164
- selectClass += `${this.getColoring(state)}`;
165
- }
150
+ const selectClass = 'ai-tools-configuration-tool-select';
166
151
  return (
167
152
  <li
168
153
  key={tool}
@@ -178,7 +163,7 @@ export class AIToolsConfigurationWidget extends ReactWidget {
178
163
  onChange={e => this.handleToolConfirmationModeChange(tool, e)}
179
164
  >
180
165
  {TOOL_OPTIONS.map(opt => (
181
- <option className={this.getColoring(opt.value, true)} key={opt.value} value={opt.value}>
166
+ <option key={opt.value} value={opt.value}>
182
167
  {opt.label}
183
168
  </option>
184
169
  ))}
@@ -26,7 +26,22 @@ import { inject, injectable } from '@theia/core/shared/inversify';
26
26
  import { MCP_SERVERS_PREF } from '@theia/ai-mcp/lib/browser/mcp-preferences';
27
27
  import { PreferenceScope, PreferenceService } from '@theia/core/lib/browser';
28
28
 
29
- export const EXPECTED_MCP_SERVER_NAME = 'playwright';
29
+ export const REQUIRED_MCP_SERVERS: MCPServerDescription[] = [
30
+ {
31
+ name: 'playwright',
32
+ command: 'npx',
33
+ args: ['-y', '@playwright/mcp@latest'],
34
+ autostart: false,
35
+ env: {},
36
+ },
37
+ {
38
+ name: 'playwright-visual',
39
+ command: 'npx',
40
+ args: ['-y', '@playwright/mcp@latest', '--vision'],
41
+ autostart: false,
42
+ env: {},
43
+ }
44
+ ];
30
45
 
31
46
  // Prompt templates
32
47
  export const appTesterTemplate: BasePromptFragment = {
@@ -45,7 +60,8 @@ Your role is to inspect the application for user-specified test scenarios throug
45
60
  4. Help fix issues when needed
46
61
 
47
62
  ## Available Playwright Testing Tools
48
- You have access to these powerful automation tools: {{prompt:mcp_${EXPECTED_MCP_SERVER_NAME}_tools}}
63
+ You have access to these powerful automation tools:
64
+ ${REQUIRED_MCP_SERVERS.map(server => `{{prompt:mcp_${server.name}_tools}}`)}
49
65
 
50
66
  ## Workflow Approach
51
67
  1. **Understand Requirements**: Ask the user to clearly define what needs to be tested
@@ -86,30 +102,29 @@ export class AppTesterChatAgent extends AbstractStreamParsingChatAgent {
86
102
  + 'It can automate testing workflows and provide detailed feedback on application functionality.');
87
103
 
88
104
  override iconClass: string = 'codicon codicon-beaker';
89
- protected override systemPromptId: string = 'app-tester-prompt';
90
- override prompts = [{ id: 'app-tester-prompt', defaultVariant: appTesterTemplate, variants: [appTesterTemplateVariant] }];
105
+ protected override systemPromptId: string = 'app-tester-system';
106
+ override prompts = [{ id: 'app-tester-system', defaultVariant: appTesterTemplate, variants: [appTesterTemplateVariant] }];
91
107
 
92
108
  /**
93
109
  * Override invoke to check if the Playwright MCP server is running, and if not, ask the user if it should be started.
94
110
  */
95
111
  override async invoke(request: MutableChatRequestModel): Promise<void> {
96
112
  try {
97
- const startedServers = await this.mcpService.getStartedServers();
98
- if (!startedServers.includes(EXPECTED_MCP_SERVER_NAME)) {
113
+ if (await this.requiresStartingServers()) {
99
114
  // Ask the user if they want to start the server
100
115
  request.response.response.addContent(new QuestionResponseContentImpl(
101
- 'The Playwright MCP server is not running. Would you like to start it now? This may install the Playwright MCP server.',
116
+ 'The Playwright MCP servers are not running. Would you like to start them now? This may install the Playwright MCP servers.',
102
117
  [
103
- { text: 'Yes, start the server', value: 'yes' },
118
+ { text: 'Yes, start the servers', value: 'yes' },
104
119
  { text: 'No, cancel', value: 'no' }
105
120
  ],
106
121
  request,
107
122
  async selectedOption => {
108
123
  if (selectedOption.value === 'yes') {
109
124
  // Show progress
110
- const progress = request.response.addProgressMessage({ content: 'Starting Playwright MCP server.', show: 'whileIncomplete' });
125
+ const progress = request.response.addProgressMessage({ content: 'Starting Playwright MCP servers.', show: 'whileIncomplete' });
111
126
  try {
112
- await this.startPlaywrightMCPServer();
127
+ await this.startServers();
113
128
  // Remove progress, continue with normal flow
114
129
  request.response.updateProgressMessage({ ...progress, show: 'whileIncomplete', status: 'completed' });
115
130
  await super.invoke(request);
@@ -121,7 +136,7 @@ export class AppTesterChatAgent extends AbstractStreamParsingChatAgent {
121
136
  }
122
137
  } else {
123
138
  // Continue without starting the server
124
- request.response.response.addContent(new MarkdownChatResponseContentImpl('Please setup the MCP server.'));
139
+ request.response.response.addContent(new MarkdownChatResponseContentImpl('Please setup the MCP servers.'));
125
140
  request.response.complete();
126
141
  }
127
142
  }
@@ -139,39 +154,34 @@ export class AppTesterChatAgent extends AbstractStreamParsingChatAgent {
139
154
  }
140
155
  }
141
156
 
157
+ protected async requiresStartingServers(): Promise<boolean> {
158
+ const allStarted = await Promise.all(REQUIRED_MCP_SERVERS.map(server => this.mcpService.isServerStarted(server.name)));
159
+ return allStarted.some(started => !started);
160
+ }
161
+
162
+ protected async startServers(): Promise<void> {
163
+ await Promise.all(REQUIRED_MCP_SERVERS.map(server => this.ensureServerStarted(server)));
164
+
165
+ }
166
+
142
167
  /**
143
168
  * Starts the Playwright MCP server if it doesn't exist or isn't running.
144
169
  *
145
170
  * @returns A promise that resolves when the server is started
146
171
  */
147
- async startPlaywrightMCPServer(): Promise<void> {
172
+ async ensureServerStarted(server: MCPServerDescription): Promise<void> {
148
173
  try {
149
- const startedServers = await this.mcpService.getStartedServers();
150
- if (startedServers.includes(EXPECTED_MCP_SERVER_NAME)) {
174
+ if ((await this.mcpService.isServerStarted(server.name))) {
151
175
  return;
152
176
  }
153
-
154
- const mcpServer: MCPServerDescription = {
155
- name: EXPECTED_MCP_SERVER_NAME,
156
- command: 'npx',
157
- args: ['-y', '@playwright/mcp@latest'],
158
- autostart: false,
159
- env: {},
160
- };
161
-
162
- const availableServers = await this.mcpService.getServerNames();
163
- if (!availableServers.includes(EXPECTED_MCP_SERVER_NAME)) {
177
+ if (!(await this.mcpService.hasServer(server.name))) {
164
178
  const currentServers = this.preferenceService.get<Record<string, MCPServerDescription>>(MCP_SERVERS_PREF, {});
165
- await this.preferenceService.set(MCP_SERVERS_PREF, {
166
- ...currentServers,
167
- mcpServer
168
- }, PreferenceScope.User);
169
-
170
- await this.mcpService.addOrUpdateServer(mcpServer);
179
+ await this.preferenceService.set(MCP_SERVERS_PREF, { ...currentServers, server }, PreferenceScope.User);
180
+ await this.mcpService.addOrUpdateServer(server);
171
181
  }
172
- await this.mcpService.startServer(EXPECTED_MCP_SERVER_NAME);
182
+ await this.mcpService.startServer(server.name);
173
183
  } catch (error) {
174
- this.logger.error(`Error starting Playwright MCP server: ${error}`);
184
+ this.logger.error(`Error starting MCP server ${server.name}: ${error}`);
175
185
  throw error;
176
186
  }
177
187
  }
@@ -16,11 +16,11 @@
16
16
  import { AbstractStreamParsingChatAgent, ChatRequestModel, ChatService, ChatSession, MutableChatModel, MutableChatRequestModel } from '@theia/ai-chat/lib/common';
17
17
  import { LanguageModelRequirement } from '@theia/ai-core';
18
18
  import { inject, injectable } from '@theia/core/shared/inversify';
19
- import { architectVariants } from '../common/architect-prompt-template';
19
+ import { architectSystemVariants, architectTaskSummaryVariants } from '../common/architect-prompt-template';
20
20
  import { FILE_CONTENT_FUNCTION_ID, GET_WORKSPACE_FILE_LIST_FUNCTION_ID } from '../common/workspace-functions';
21
21
  import { nls } from '@theia/core';
22
22
  import { MarkdownStringImpl } from '@theia/core/lib/common/markdown-rendering';
23
- import { AI_SUMMARIZE_SESSION_AS_TASK_FOR_CODER } from '../common/summarize-session-commands';
23
+ import { AI_SUMMARIZE_SESSION_AS_TASK_FOR_CODER, AI_UPDATE_TASK_CONTEXT_COMMAND } from '../common/summarize-session-commands';
24
24
 
25
25
  @injectable()
26
26
  export class ArchitectAgent extends AbstractStreamParsingChatAgent {
@@ -38,9 +38,9 @@ export class ArchitectAgent extends AbstractStreamParsingChatAgent {
38
38
  'An AI assistant integrated into Theia IDE, designed to assist software developers. This agent can access the users workspace, it can get a list of all available files \
39
39
  and folders and retrieve their content. It cannot modify files. It can therefore answer questions about the current project, project files and source code in the \
40
40
  workspace, such as how to build the project, where to put source code, where to find specific code or configurations, etc.');
41
- override prompts = [architectVariants];
41
+ override prompts = [architectSystemVariants, architectTaskSummaryVariants];
42
42
  override functions = [GET_WORKSPACE_FILE_LIST_FUNCTION_ID, FILE_CONTENT_FUNCTION_ID];
43
- protected override systemPromptId: string | undefined = architectVariants.id;
43
+ protected override systemPromptId: string | undefined = architectSystemVariants.id;
44
44
 
45
45
  override async invoke(request: MutableChatRequestModel): Promise<void> {
46
46
  await super.invoke(request);
@@ -52,7 +52,10 @@ export class ArchitectAgent extends AbstractStreamParsingChatAgent {
52
52
  const session = this.chatService.getSessions().find(candidate => candidate.model.id === model.id);
53
53
  if (!(model instanceof MutableChatModel) || !session) { return; }
54
54
  if (!model.isEmpty()) {
55
- model.setSuggestions([new MarkdownStringImpl(`[Summarize this session as a task for Coder](command:${AI_SUMMARIZE_SESSION_AS_TASK_FOR_CODER.id}).`)]);
55
+ model.setSuggestions([
56
+ new MarkdownStringImpl(`[Summarize this session as a task for Coder](command:${AI_SUMMARIZE_SESSION_AS_TASK_FOR_CODER.id}).`),
57
+ new MarkdownStringImpl(`[Update current task context](command:${AI_UPDATE_TASK_CONTEXT_COMMAND.id}).`)
58
+ ]);
56
59
  }
57
60
  }
58
61
  }
@@ -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';
@@ -2,6 +2,14 @@
2
2
  padding: var(--theia-ui-padding);
3
3
  }
4
4
 
5
+ .ai-configuration-widget [role="tablist"] {
6
+ overflow: scroll;
7
+ }
8
+
9
+ .ai-configuration-widget [role="tablist"]::-webkit-scrollbar {
10
+ height: 4px;
11
+ }
12
+
5
13
  .theia-ai-settings-container {
6
14
  padding: var(--theia-ui-padding);
7
15
  }
@@ -90,8 +98,15 @@
90
98
  flex-direction: row;
91
99
  }
92
100
 
93
- .configuration-agents-list {
94
- width: 128px;
101
+ #ai-agent-configuration-container-widget
102
+ .ai-agent-configuration-main
103
+ .configuration-agents-list {
104
+ min-width: 160px;
105
+ overflow: hidden;
106
+ white-space: nowrap;
107
+ text-overflow: ellipsis;
108
+ padding-left: 0;
109
+ padding: var(--theia-ui-padding);
95
110
  }
96
111
 
97
112
  .configuration-agent-panel {
@@ -128,9 +143,12 @@
128
143
  }
129
144
 
130
145
  /* Prompt Fragments Configuration Styles */
146
+ .configuration-variables-list,
147
+ .token-usage-configuration-container,
148
+ .ai-tools-configuration-container,
131
149
  .ai-prompt-fragments-configuration {
132
150
  padding: var(--theia-ui-padding);
133
- max-width: 1200px;
151
+ max-width: 600px;
134
152
  margin: 0 auto;
135
153
  }
136
154
 
@@ -422,7 +440,8 @@
422
440
  gap: 8px;
423
441
  }
424
442
 
425
- .prompt-fragment-title h2, h4 {
443
+ .prompt-fragment-title h2,
444
+ h4 {
426
445
  margin-right: 8px;
427
446
  margin: 0;
428
447
  }
@@ -448,10 +467,6 @@
448
467
  }
449
468
 
450
469
  /* MCP Configuration Styles */
451
- .mcp-configuration-container {
452
- padding: 16px;
453
- }
454
-
455
470
  .mcp-configuration-title {
456
471
  margin: 0 0 16px 0;
457
472
  border-bottom: 1px solid var(--theia-panelTitle-activeBorder);
@@ -673,11 +688,6 @@
673
688
  * AI Tools Configuration Widget Styles
674
689
  * Only touch styles in this section for the tools configuration widget
675
690
  */
676
- .ai-tools-configuration-container {
677
- padding: 16px;
678
- max-width: 600px;
679
- }
680
-
681
691
  .ai-tools-configuration-default-section {
682
692
  margin-bottom: 24px;
683
693
  }
@@ -688,7 +698,6 @@
688
698
  }
689
699
 
690
700
  .ai-tools-configuration-default-select {
691
- font-weight: bold;
692
701
  font-size: 14px;
693
702
  padding: 4px;
694
703
  }
@@ -728,7 +737,6 @@
728
737
  }
729
738
 
730
739
  .ai-tools-configuration-tool-select {
731
- font-weight: bold;
732
740
  margin-right: 8px;
733
741
  }
734
742
 
@@ -736,22 +744,9 @@
736
744
  font-size: 18px;
737
745
  }
738
746
 
739
- .ai-tools-configuration-tool-select--yolo {
740
- color: green !important;
741
- }
742
- .ai-tools-configuration-tool-select--disabled {
743
- color: red !important;
744
- }
745
- .ai-tools-configuration-tool-select--confirm {
746
- color: orange !important;
747
- }
748
747
  /* End AI Tools Configuration Widget Styles */
749
748
 
750
749
  /* Token Usage Configuration Styles */
751
- .token-usage-configuration-container {
752
- padding: 16px;
753
- }
754
-
755
750
  .token-usage-configuration-title {
756
751
  margin: 0 0 16px 0;
757
752
  border-bottom: 1px solid var(--theia-widget-border);