@theia/ai-chat 1.63.0-next.52 → 1.63.1

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 (37) hide show
  1. package/lib/browser/ai-chat-frontend-module.d.ts.map +1 -1
  2. package/lib/browser/ai-chat-frontend-module.js +0 -1
  3. package/lib/browser/ai-chat-frontend-module.js.map +1 -1
  4. package/lib/browser/change-set-file-element.d.ts +28 -7
  5. package/lib/browser/change-set-file-element.d.ts.map +1 -1
  6. package/lib/browser/change-set-file-element.js +145 -24
  7. package/lib/browser/change-set-file-element.js.map +1 -1
  8. package/lib/browser/frontend-chat-service.d.ts +1 -1
  9. package/lib/browser/frontend-chat-service.d.ts.map +1 -1
  10. package/lib/browser/frontend-chat-service.js +2 -13
  11. package/lib/browser/frontend-chat-service.js.map +1 -1
  12. package/lib/common/chat-model.d.ts +5 -5
  13. package/lib/common/chat-model.d.ts.map +1 -1
  14. package/lib/common/chat-model.js.map +1 -1
  15. package/lib/common/chat-request-parser.d.ts.map +1 -1
  16. package/lib/common/chat-request-parser.js +0 -6
  17. package/lib/common/chat-request-parser.js.map +1 -1
  18. package/lib/common/chat-service.d.ts +11 -0
  19. package/lib/common/chat-service.d.ts.map +1 -1
  20. package/lib/common/chat-service.js +32 -7
  21. package/lib/common/chat-service.js.map +1 -1
  22. package/lib/common/chat-session-naming-service.js +2 -2
  23. package/lib/common/chat-session-naming-service.js.map +1 -1
  24. package/lib/common/chat-session-summary-agent-prompt.js +3 -3
  25. package/lib/common/chat-session-summary-agent-prompt.js.map +1 -1
  26. package/lib/common/chat-tool-request-service.d.ts +2 -2
  27. package/lib/common/chat-tool-request-service.d.ts.map +1 -1
  28. package/package.json +10 -10
  29. package/src/browser/ai-chat-frontend-module.ts +0 -1
  30. package/src/browser/change-set-file-element.ts +168 -24
  31. package/src/browser/frontend-chat-service.ts +2 -11
  32. package/src/common/chat-model.ts +5 -4
  33. package/src/common/chat-request-parser.ts +0 -12
  34. package/src/common/chat-service.ts +35 -6
  35. package/src/common/chat-session-naming-service.ts +2 -2
  36. package/src/common/chat-session-summary-agent-prompt.ts +3 -3
  37. package/src/common/chat-tool-request-service.ts +2 -2
@@ -14,16 +14,29 @@
14
14
  // SPDX-License-Identifier: EPL-2.0 OR GPL-2.0-only WITH Classpath-exception-2.0
15
15
  // *****************************************************************************
16
16
 
17
- import { DisposableCollection, Emitter, URI } from '@theia/core';
18
- import { inject, injectable, postConstruct } from '@theia/core/shared/inversify';
19
- import { Replacement } from '@theia/core/lib/common/content-replacer';
20
17
  import { ConfigurableInMemoryResources, ConfigurableMutableReferenceResource } from '@theia/ai-core';
18
+ import { CancellationToken, DisposableCollection, Emitter, URI } from '@theia/core';
19
+ import { ConfirmDialog } from '@theia/core/lib/browser';
20
+ import { Replacement } from '@theia/core/lib/common/content-replacer';
21
+ import { inject, injectable, postConstruct } from '@theia/core/shared/inversify';
22
+ import { EditorPreferences } from '@theia/editor/lib/browser';
23
+ import { FileSystemPreferences } from '@theia/filesystem/lib/browser';
24
+ import { FileService } from '@theia/filesystem/lib/browser/file-service';
25
+ import { IReference } from '@theia/monaco-editor-core/esm/vs/base/common/lifecycle';
26
+ import { TrimTrailingWhitespaceCommand } from '@theia/monaco-editor-core/esm/vs/editor/common/commands/trimTrailingWhitespaceCommand';
27
+ import { Selection } from '@theia/monaco-editor-core/esm/vs/editor/common/core/selection';
28
+ import { CommandExecutor } from '@theia/monaco-editor-core/esm/vs/editor/common/cursor/cursor';
29
+ import { formatDocumentWithSelectedProvider, FormattingMode } from '@theia/monaco-editor-core/esm/vs/editor/contrib/format/browser/format';
30
+ import { StandaloneServices } from '@theia/monaco-editor-core/esm/vs/editor/standalone/browser/standaloneServices';
31
+ import { IInstantiationService } from '@theia/monaco-editor-core/esm/vs/platform/instantiation/common/instantiation';
32
+ import { MonacoTextModelService } from '@theia/monaco/lib/browser/monaco-text-model-service';
33
+ import { insertFinalNewline } from '@theia/monaco/lib/browser/monaco-utilities';
34
+ import { MonacoEditorModel } from '@theia/monaco/lib/browser/monaco-editor-model';
21
35
  import { ChangeSetElement } from '../common';
22
36
  import { createChangeSetFileUri } from './change-set-file-resource';
23
37
  import { ChangeSetFileService } from './change-set-file-service';
24
- import { FileService } from '@theia/filesystem/lib/browser/file-service';
25
- import { ConfirmDialog } from '@theia/core/lib/browser';
26
- import { ChangeSetDecoratorService } from './change-set-decorator-service';
38
+ import { Deferred } from '@theia/core/lib/common/promise-util';
39
+ import { MonacoCodeActionService } from '@theia/monaco/lib/browser';
27
40
 
28
41
  export const ChangeSetFileElementFactory = Symbol('ChangeSetFileElementFactory');
29
42
  export type ChangeSetFileElementFactory = (elementProps: ChangeSetElementArgs) => ChangeSetFileElement;
@@ -62,16 +75,23 @@ export class ChangeSetFileElement implements ChangeSetElement {
62
75
  @inject(ChangeSetFileService)
63
76
  protected readonly changeSetFileService: ChangeSetFileService;
64
77
 
65
- @inject(ChangeSetDecoratorService)
66
- protected readonly changeSetDecoratorService: ChangeSetDecoratorService;
67
-
68
78
  @inject(FileService)
69
79
  protected readonly fileService: FileService;
70
80
 
71
81
  @inject(ConfigurableInMemoryResources)
72
82
  protected readonly inMemoryResources: ConfigurableInMemoryResources;
73
83
 
74
- @inject(ChangeSetFileElementFactory) protected readonly factory: ChangeSetFileElementFactory;
84
+ @inject(MonacoTextModelService)
85
+ protected readonly monacoTextModelService: MonacoTextModelService;
86
+
87
+ @inject(EditorPreferences)
88
+ protected readonly editorPreferences: EditorPreferences;
89
+
90
+ @inject(FileSystemPreferences)
91
+ protected readonly fileSystemPreferences: FileSystemPreferences;
92
+
93
+ @inject(MonacoCodeActionService)
94
+ protected readonly codeActionService: MonacoCodeActionService;
75
95
 
76
96
  protected readonly toDispose = new DisposableCollection();
77
97
  protected _state: ChangeSetElementState;
@@ -79,11 +99,13 @@ export class ChangeSetFileElement implements ChangeSetElement {
79
99
  private _originalContent: string | undefined;
80
100
  protected _initialized = false;
81
101
  protected _initializationPromise: Promise<void> | undefined;
102
+ protected _targetStateWithCodeActions: string | undefined;
103
+ protected codeActionDeferred?: Deferred<string>;
82
104
 
83
105
  protected readonly onDidChangeEmitter = new Emitter<void>();
84
106
  readonly onDidChange = this.onDidChangeEmitter.event;
85
- protected _readOnlyResource: ConfigurableMutableReferenceResource;
86
- protected _changeResource: ConfigurableMutableReferenceResource;
107
+ protected _readOnlyResource?: ConfigurableMutableReferenceResource;
108
+ protected _changeResource?: ConfigurableMutableReferenceResource;
87
109
 
88
110
  @postConstruct()
89
111
  init(): void {
@@ -174,7 +196,8 @@ export class ChangeSetFileElement implements ChangeSetElement {
174
196
  protected get changeResource(): ConfigurableMutableReferenceResource {
175
197
  if (!this._changeResource) {
176
198
  this._changeResource = this.getInMemoryUri(createChangeSetFileUri(this.elementProps.chatSessionId, this.uri));
177
- this._changeResource.update({ autosaveable: false });
199
+ this._changeResource.update({ autosaveable: false, contents: this.targetState });
200
+ this.applyCodeActionsToTargetState();
178
201
  this.toDispose.push(this._changeResource);
179
202
  }
180
203
  return this._changeResource;
@@ -236,6 +259,10 @@ export class ChangeSetFileElement implements ChangeSetElement {
236
259
  }
237
260
 
238
261
  get targetState(): string {
262
+ return this._targetStateWithCodeActions ?? this.elementProps.targetState ?? '';
263
+ }
264
+
265
+ get originalTargetState(): string {
239
266
  return this.elementProps.targetState ?? '';
240
267
  }
241
268
 
@@ -255,14 +282,16 @@ export class ChangeSetFileElement implements ChangeSetElement {
255
282
  async apply(contents?: string): Promise<void> {
256
283
  await this.ensureInitialized();
257
284
  if (!await this.confirm('Apply')) { return; }
258
- if (!(await this.changeSetFileService.trySave(this.changedUri))) {
259
- if (this.type === 'delete') {
260
- await this.changeSetFileService.delete(this.uri);
261
- this.state = 'applied';
262
- } else {
263
- await this.writeChanges(contents);
264
- }
285
+
286
+ if (this.type === 'delete') {
287
+ await this.changeSetFileService.delete(this.uri);
288
+ this.state = 'applied';
289
+ this.changeSetFileService.closeDiff(this.readOnlyUri);
290
+ return;
265
291
  }
292
+
293
+ // Load Monaco model for the base file URI and apply changes
294
+ await this.applyChangesWithMonaco(contents);
266
295
  this.changeSetFileService.closeDiff(this.readOnlyUri);
267
296
  }
268
297
 
@@ -271,9 +300,124 @@ export class ChangeSetFileElement implements ChangeSetElement {
271
300
  this.state = 'applied';
272
301
  }
273
302
 
303
+ /**
304
+ * Applies changes using Monaco utilities, including loading the model for the base file URI,
305
+ * setting the value to the intended state, and running code actions on save.
306
+ */
307
+ protected async applyChangesWithMonaco(contents?: string): Promise<void> {
308
+ let modelReference: IReference<MonacoEditorModel> | undefined;
309
+
310
+ try {
311
+ modelReference = await this.monacoTextModelService.createModelReference(this.uri);
312
+ const model = modelReference.object;
313
+ const targetContent = contents ?? this.targetState;
314
+ model.textEditorModel.setValue(targetContent);
315
+
316
+ const languageId = model.languageId;
317
+ const uriStr = this.uri.toString();
318
+
319
+ await this.codeActionService.applyOnSaveCodeActions(model.textEditorModel, languageId, uriStr, CancellationToken.None);
320
+ await this.applyFormatting(model, languageId, uriStr);
321
+
322
+ await model.save();
323
+ this.state = 'applied';
324
+
325
+ } catch (error) {
326
+ console.error('Failed to apply changes with Monaco:', error);
327
+ await this.writeChanges(contents);
328
+ } finally {
329
+ modelReference?.dispose();
330
+ }
331
+ }
332
+
333
+ protected applyCodeActionsToTargetState(): Promise<string> {
334
+ if (!this.codeActionDeferred) {
335
+ this.codeActionDeferred = new Deferred();
336
+ this.codeActionDeferred.resolve(this.doApplyCodeActionsToTargetState());
337
+ }
338
+ return this.codeActionDeferred.promise;
339
+ }
340
+
341
+ protected async doApplyCodeActionsToTargetState(): Promise<string> {
342
+ const targetState = this.originalTargetState;
343
+ if (!targetState) {
344
+ this._targetStateWithCodeActions = '';
345
+ return this._targetStateWithCodeActions;
346
+ }
347
+
348
+ let tempResource: ConfigurableMutableReferenceResource | undefined;
349
+ let tempModel: IReference<MonacoEditorModel> | undefined;
350
+ try {
351
+ // Create a temporary model to apply code actions
352
+ const tempUri = new URI(`untitled://changeset/${Date.now()}${this.uri.path.ext}`);
353
+ tempResource = this.inMemoryResources.add(tempUri, { contents: this.targetState });
354
+ tempModel = await this.monacoTextModelService.createModelReference(tempUri);
355
+ tempModel.object.suppressOpenEditorWhenDirty = true;
356
+ tempModel.object.textEditorModel.setValue(this.targetState);
357
+
358
+ const languageId = tempModel.object.languageId;
359
+ const uriStr = this.uri.toString();
360
+
361
+ await this.codeActionService.applyOnSaveCodeActions(tempModel.object.textEditorModel, languageId, uriStr, CancellationToken.None);
362
+
363
+ // Apply formatting and other editor preferences
364
+ await this.applyFormatting(tempModel.object, languageId, uriStr);
365
+
366
+ this._targetStateWithCodeActions = tempModel.object.textEditorModel.getValue();
367
+ if (this._changeResource?.contents === this.elementProps.targetState) {
368
+ this._changeResource?.update({ contents: this.targetState });
369
+ }
370
+ } catch (error) {
371
+ console.warn('Failed to apply code actions to target state:', error);
372
+ this._targetStateWithCodeActions = targetState;
373
+ } finally {
374
+ tempModel?.dispose();
375
+ tempResource?.dispose();
376
+ }
377
+
378
+ return this.targetState;
379
+ }
380
+
381
+ /**
382
+ * Applies formatting preferences like format on save, trim trailing whitespace, and insert final newline.
383
+ */
384
+ protected async applyFormatting(model: MonacoEditorModel, languageId: string, uriStr: string): Promise<void> {
385
+ try {
386
+ const formatOnSave = this.editorPreferences.get({ preferenceName: 'editor.formatOnSave', overrideIdentifier: languageId }, undefined, uriStr);
387
+ if (formatOnSave) {
388
+ const instantiation = StandaloneServices.get(IInstantiationService);
389
+ await instantiation.invokeFunction(
390
+ formatDocumentWithSelectedProvider,
391
+ model.textEditorModel,
392
+ FormattingMode.Explicit,
393
+ { report(): void { } },
394
+ CancellationToken.None, true
395
+ );
396
+ }
397
+
398
+ const trimTrailingWhitespace = this.fileSystemPreferences.get({ preferenceName: 'files.trimTrailingWhitespace', overrideIdentifier: languageId }, undefined, uriStr);
399
+ if (trimTrailingWhitespace) {
400
+ const ttws = new TrimTrailingWhitespaceCommand(new Selection(1, 1, 1, 1), [], false);
401
+ CommandExecutor.executeCommands(model.textEditorModel, [], [ttws]);
402
+ }
403
+
404
+ const shouldInsertFinalNewline = this.fileSystemPreferences.get({ preferenceName: 'files.insertFinalNewline', overrideIdentifier: languageId }, undefined, uriStr);
405
+ if (shouldInsertFinalNewline) {
406
+ insertFinalNewline(model);
407
+ }
408
+ } catch (error) {
409
+ console.warn('Failed to apply formatting:', error);
410
+ }
411
+ }
412
+
274
413
  onShow(): void {
275
- // Ensure we have the latest state when showing
276
- this.changeResource.update({ contents: this.targetState, onSave: content => this.writeChanges(content) });
414
+ this.changeResource.update({
415
+ contents: this.targetState,
416
+ onSave: async content => {
417
+ // Use Monaco utilities when saving from the change resource
418
+ await this.applyChangesWithMonaco(content);
419
+ }
420
+ });
277
421
  }
278
422
 
279
423
  async revert(): Promise<void> {
@@ -290,11 +434,11 @@ export class ChangeSetFileElement implements ChangeSetElement {
290
434
  async confirm(verb: string): Promise<boolean> {
291
435
  if (this._state !== 'stale') { return true; }
292
436
  await this.openChange();
293
- const thing = await new ConfirmDialog({
437
+ const answer = await new ConfirmDialog({
294
438
  title: `${verb} suggestion.`,
295
439
  msg: `The file ${this.uri.path.toString()} has changed since this suggestion was created. Are you certain you wish to ${verb.toLowerCase()} the change?`
296
440
  }).open(true);
297
- return !!thing;
441
+ return !!answer;
298
442
  }
299
443
 
300
444
  dispose(): void {
@@ -32,17 +32,8 @@ export class FrontendChatServiceImpl extends ChatServiceImpl {
32
32
  @inject(ChangeSetFileService)
33
33
  protected readonly changeSetFileService: ChangeSetFileService;
34
34
 
35
- protected override getAgent(parsedRequest: ParsedChatRequest, session: ChatSession): ChatAgent | undefined {
36
- let agent = this.initialAgentSelection(parsedRequest);
37
- if (!this.preferenceService.get<boolean>(PIN_CHAT_AGENT_PREF)) {
38
- return agent;
39
- }
40
- if (!session.pinnedAgent && agent && agent.id !== this.defaultChatAgentId?.id) {
41
- session.pinnedAgent = agent;
42
- } else if (session.pinnedAgent && this.getMentionedAgent(parsedRequest) === undefined) {
43
- agent = session.pinnedAgent;
44
- }
45
- return agent;
35
+ protected override isPinChatAgentEnabled(): boolean {
36
+ return this.preferenceService.get<boolean>(PIN_CHAT_AGENT_PREF, true);
46
37
  }
47
38
 
48
39
  protected override initialAgentSelection(parsedRequest: ParsedChatRequest): ChatAgent | undefined {
@@ -25,6 +25,7 @@ import {
25
25
  ResolvedAIContextVariable,
26
26
  TextMessage,
27
27
  ThinkingMessage,
28
+ ToolCallResult,
28
29
  ToolResultMessage,
29
30
  ToolUseMessage
30
31
  } from '@theia/ai-core';
@@ -389,7 +390,7 @@ export interface ToolCallChatResponseContent extends Required<ChatResponseConten
389
390
  name?: string;
390
391
  arguments?: string;
391
392
  finished: boolean;
392
- result?: string;
393
+ result?: ToolCallResult;
393
394
  confirmed: Promise<boolean>;
394
395
  confirm(): void;
395
396
  deny(): void;
@@ -1497,12 +1498,12 @@ export class ToolCallChatResponseContentImpl implements ToolCallChatResponseCont
1497
1498
  protected _name?: string;
1498
1499
  protected _arguments?: string;
1499
1500
  protected _finished?: boolean;
1500
- protected _result?: string;
1501
+ protected _result?: ToolCallResult;
1501
1502
  protected _confirmed: Promise<boolean>;
1502
1503
  protected _confirmationResolver?: (value: boolean) => void;
1503
1504
  protected _confirmationRejecter?: (reason?: unknown) => void;
1504
1505
 
1505
- constructor(id?: string, name?: string, arg_string?: string, finished?: boolean, result?: string) {
1506
+ constructor(id?: string, name?: string, arg_string?: string, finished?: boolean, result?: ToolCallResult) {
1506
1507
  this._id = id;
1507
1508
  this._name = name;
1508
1509
  this._arguments = arg_string;
@@ -1527,7 +1528,7 @@ export class ToolCallChatResponseContentImpl implements ToolCallChatResponseCont
1527
1528
  get finished(): boolean {
1528
1529
  return this._finished === undefined ? false : this._finished;
1529
1530
  }
1530
- get result(): string | undefined {
1531
+ get result(): ToolCallResult | undefined {
1531
1532
  return this._result;
1532
1533
  }
1533
1534
 
@@ -228,18 +228,6 @@ export class ChatRequestParserImpl implements ChatRequestParser {
228
228
  return;
229
229
  }
230
230
 
231
- // The agent must come first
232
- if (
233
- parts.some(
234
- p =>
235
- (p instanceof ParsedChatRequestTextPart &&
236
- p.text.trim() !== '') ||
237
- !(p instanceof ParsedChatRequestAgentPart)
238
- )
239
- ) {
240
- return;
241
- }
242
-
243
231
  return new ParsedChatRequestAgentPart(agentRange, agent.id, agent.name);
244
232
  }
245
233
 
@@ -313,15 +313,44 @@ export class ChatServiceImpl implements ChatService {
313
313
  }
314
314
 
315
315
  protected getAgent(parsedRequest: ParsedChatRequest, session: ChatSession): ChatAgent | undefined {
316
- let agent = this.initialAgentSelection(parsedRequest);
317
- if (this.pinChatAgent === false) {
316
+ const agent = this.initialAgentSelection(parsedRequest);
317
+ if (!this.isPinChatAgentEnabled()) {
318
318
  return agent;
319
319
  }
320
- if (!session.pinnedAgent && agent && agent.id !== this.defaultChatAgentId?.id) {
321
- session.pinnedAgent = agent;
322
- } else if (session.pinnedAgent && this.getMentionedAgent(parsedRequest) === undefined) {
323
- agent = session.pinnedAgent;
320
+
321
+ return this.handlePinnedAgent(parsedRequest, session, agent);
322
+ }
323
+
324
+ /**
325
+ * Determines if chat agent pinning is enabled.
326
+ * Can be overridden by subclasses to provide different logic (e.g., using preferences).
327
+ */
328
+ protected isPinChatAgentEnabled(): boolean {
329
+ return this.pinChatAgent !== false;
330
+ }
331
+
332
+ /**
333
+ * Handle pinned agent by:
334
+ * - checking if an agent is pinned, and use it if no other agent is mentioned
335
+ * - pinning the current agent
336
+ */
337
+ protected handlePinnedAgent(parsedRequest: ParsedChatRequest, session: ChatSession, agent: ChatAgent | undefined): ChatAgent | undefined {
338
+ const mentionedAgentPart = this.getMentionedAgent(parsedRequest);
339
+ const mentionedAgent = mentionedAgentPart ? this.chatAgentService.getAgent(mentionedAgentPart.agentId) : undefined;
340
+ if (mentionedAgent) {
341
+ // If an agent is explicitly mentioned, it becomes the new pinned agent
342
+ session.pinnedAgent = mentionedAgent;
343
+ return mentionedAgent;
344
+ } else if (session.pinnedAgent) {
345
+ // If we have a valid pinned agent, use it (pinned agent may become stale
346
+ // if it was disabled; so we always need to recheck)
347
+ const pinnedAgent = this.chatAgentService.getAgent(session.pinnedAgent.id);
348
+ if (pinnedAgent) {
349
+ return pinnedAgent;
350
+ }
324
351
  }
352
+ // Otherwise, override the pinned agent and return the suggested one
353
+ session.pinnedAgent = agent;
325
354
  return agent;
326
355
  }
327
356
 
@@ -30,9 +30,9 @@ import { ChatSession } from './chat-service';
30
30
  import { generateUuid } from '@theia/core';
31
31
 
32
32
  const CHAT_SESSION_NAMING_PROMPT: PromptVariantSet = {
33
- id: 'chat-session-naming-prompt',
33
+ id: 'chat-session-naming-system',
34
34
  defaultVariant: {
35
- id: 'chat-session-naming-prompt',
35
+ id: 'chat-session-naming-system-default',
36
36
  template: '{{!-- Made improvements or adaptations to this prompt template? We\'d love for you to share it with the community! Contribute back here: ' +
37
37
  'https://github.com/eclipse-theia/theia/discussions/new?category=prompt-template-contribution --}}\n\n' +
38
38
  'Provide a short and descriptive name for the given AI chat conversation of an AI-powered tool based on the conversation below.\n\n' +
@@ -11,9 +11,9 @@
11
11
  import { CHANGE_SET_SUMMARY_VARIABLE_ID } from './context-variables';
12
12
 
13
13
  export const CHAT_SESSION_SUMMARY_PROMPT = {
14
- id: 'chat-session-summary-system-prompt',
14
+ id: 'chat-session-summary-system',
15
15
  defaultVariant: {
16
- id: 'chat-session-summary-prompt',
16
+ id: 'chat-session-summary-system-default',
17
17
  template: '{{!-- !-- This prompt is licensed under the MIT License (https://opensource.org/license/mit).\n' +
18
18
  'Made improvements or adaptations to this prompt template? We\'d love for you to share it with the community! Contribute back here: ' +
19
19
  'https://github.com/eclipse-theia/theia/discussions/new?category=prompt-template-contribution --}}\n\n' +
@@ -23,7 +23,7 @@ export const CHAT_SESSION_SUMMARY_PROMPT = {
23
23
  'Ensure that the summary is sufficiently comprehensive to allow seamless continuation of the workflow. ' +
24
24
  'The summary will primarily be used by other AI agents, so tailor your response for use by AI agents. ' +
25
25
  'Also consider the system message. ' +
26
- 'Make sure you include all necessary context information and use unique references(such as URIs, file paths, etc.). ' +
26
+ 'Make sure you include all necessary context information and use unique references (such as URIs, file paths, etc.). ' +
27
27
  'If the conversation was about a task, describe the state of the task, i.e.what has been completed and what is open. ' +
28
28
  'If a changeset is open in the session, describe the state of the suggested changes. ' +
29
29
  `\n\n{{${CHANGE_SET_SUMMARY_VARIABLE_ID}}}`,
@@ -19,8 +19,8 @@ import { injectable } from '@theia/core/shared/inversify';
19
19
  import { MutableChatRequestModel } from './chat-model';
20
20
 
21
21
  export interface ChatToolRequest extends ToolRequest {
22
- handler(arg_string: string, context: MutableChatRequestModel): Promise<unknown>;
23
- handler(arg_string: string, ctx?: unknown): Promise<unknown>;
22
+ handler(arg_string: string, context: MutableChatRequestModel): ReturnType<ToolRequest['handler']>;
23
+ handler(arg_string: string, ctx?: unknown): ReturnType<ToolRequest['handler']>;
24
24
  }
25
25
 
26
26
  /**