@theia/ai-core 1.60.0-next.47 → 1.60.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 (71) hide show
  1. package/lib/browser/ai-core-frontend-module.d.ts.map +1 -1
  2. package/lib/browser/ai-core-frontend-module.js +4 -0
  3. package/lib/browser/ai-core-frontend-module.js.map +1 -1
  4. package/lib/browser/ai-core-preferences.d.ts +22 -8
  5. package/lib/browser/ai-core-preferences.d.ts.map +1 -1
  6. package/lib/browser/ai-core-preferences.js +90 -10
  7. package/lib/browser/ai-core-preferences.js.map +1 -1
  8. package/lib/browser/frontend-language-model-registry.d.ts.map +1 -1
  9. package/lib/browser/frontend-language-model-registry.js +1 -1
  10. package/lib/browser/frontend-language-model-registry.js.map +1 -1
  11. package/lib/browser/frontend-language-model-service.d.ts +10 -0
  12. package/lib/browser/frontend-language-model-service.d.ts.map +1 -0
  13. package/lib/browser/frontend-language-model-service.js +66 -0
  14. package/lib/browser/frontend-language-model-service.js.map +1 -0
  15. package/lib/browser/frontend-prompt-customization-service.d.ts +99 -2
  16. package/lib/browser/frontend-prompt-customization-service.d.ts.map +1 -1
  17. package/lib/browser/frontend-prompt-customization-service.js +245 -23
  18. package/lib/browser/frontend-prompt-customization-service.js.map +1 -1
  19. package/lib/browser/index.d.ts +1 -0
  20. package/lib/browser/index.d.ts.map +1 -1
  21. package/lib/browser/index.js +1 -0
  22. package/lib/browser/index.js.map +1 -1
  23. package/lib/browser/prompttemplate-contribution.d.ts +4 -0
  24. package/lib/browser/prompttemplate-contribution.d.ts.map +1 -1
  25. package/lib/browser/prompttemplate-contribution.js +61 -2
  26. package/lib/browser/prompttemplate-contribution.js.map +1 -1
  27. package/lib/browser/theia-variable-contribution.d.ts +9 -4
  28. package/lib/browser/theia-variable-contribution.d.ts.map +1 -1
  29. package/lib/browser/theia-variable-contribution.js +67 -38
  30. package/lib/browser/theia-variable-contribution.js.map +1 -1
  31. package/lib/common/communication-recording-service.d.ts +8 -7
  32. package/lib/common/communication-recording-service.d.ts.map +1 -1
  33. package/lib/common/communication-recording-service.js.map +1 -1
  34. package/lib/common/index.d.ts +1 -0
  35. package/lib/common/index.d.ts.map +1 -1
  36. package/lib/common/index.js +1 -0
  37. package/lib/common/index.js.map +1 -1
  38. package/lib/common/language-model-service.d.ts +15 -0
  39. package/lib/common/language-model-service.d.ts.map +1 -0
  40. package/lib/common/language-model-service.js +51 -0
  41. package/lib/common/language-model-service.js.map +1 -0
  42. package/lib/common/language-model-util.d.ts.map +1 -1
  43. package/lib/common/language-model-util.js +1 -2
  44. package/lib/common/language-model-util.js.map +1 -1
  45. package/lib/common/language-model.d.ts +56 -15
  46. package/lib/common/language-model.d.ts.map +1 -1
  47. package/lib/common/language-model.js +27 -2
  48. package/lib/common/language-model.js.map +1 -1
  49. package/lib/common/tool-invocation-registry.d.ts +3 -0
  50. package/lib/common/tool-invocation-registry.d.ts.map +1 -1
  51. package/lib/common/tool-invocation-registry.js +7 -1
  52. package/lib/common/tool-invocation-registry.js.map +1 -1
  53. package/lib/common/variable-service.d.ts +1 -1
  54. package/lib/common/variable-service.d.ts.map +1 -1
  55. package/lib/common/variable-service.js.map +1 -1
  56. package/package.json +10 -10
  57. package/src/browser/ai-core-frontend-module.ts +4 -0
  58. package/src/browser/ai-core-preferences.ts +106 -15
  59. package/src/browser/frontend-language-model-registry.ts +2 -1
  60. package/src/browser/frontend-language-model-service.ts +67 -0
  61. package/src/browser/frontend-prompt-customization-service.ts +348 -27
  62. package/src/browser/index.ts +1 -0
  63. package/src/browser/prompttemplate-contribution.ts +80 -3
  64. package/src/browser/theia-variable-contribution.ts +81 -40
  65. package/src/common/communication-recording-service.ts +9 -7
  66. package/src/common/index.ts +1 -0
  67. package/src/common/language-model-service.ts +59 -0
  68. package/src/common/language-model-util.ts +9 -2
  69. package/src/common/language-model.ts +72 -15
  70. package/src/common/tool-invocation-registry.ts +7 -2
  71. package/src/common/variable-service.ts +2 -1
@@ -19,6 +19,14 @@ import { inject, injectable } from '@theia/core/shared/inversify';
19
19
  import { VariableRegistry, VariableResolverService } from '@theia/variable-resolver/lib/browser';
20
20
  import { AIVariableContribution, AIVariableResolver, AIVariableService, AIVariableResolutionRequest, AIVariableContext, ResolvedAIVariable } from '../common';
21
21
 
22
+ /**
23
+ * Mapping configuration for a Theia variable to one or more AI variables
24
+ */
25
+ interface VariableMapping {
26
+ name?: string;
27
+ description?: string;
28
+ }
29
+
22
30
  /**
23
31
  * Integrates the Theia VariableRegistry with the Theia AI VariableService
24
32
  */
@@ -36,33 +44,52 @@ export class TheiaVariableContribution implements AIVariableContribution, AIVari
36
44
  @inject(FrontendApplicationStateService)
37
45
  protected readonly stateService: FrontendApplicationStateService;
38
46
 
39
- // Map original variable name to new name and description. If a mapped value is not present then the original will be kept.
47
+ // Map original variable name to one or more mappings with new name and description.
40
48
  // Only variables present in this map are registered.
41
- protected variableRenameMap: Map<string, { name?: string, description?: string }> = new Map([
42
- ['file', {
43
- name: 'currentAbsoluteFilePath', description: nls.localize('theia/ai/core/variable-contribution/currentAbsoluteFilePath', 'The absolute path of the \
44
- currently opened file. Please note that most agents will expect a relative file path (relative to the current workspace).')
45
- }],
46
- ['selectedText', {
47
- description: nls.localize('theia/ai/core/variable-contribution/currentSelectedText', 'The plain text that is currently selected in the \
48
- opened file. This excludes the information where the content is coming from. Please note that most agents will work better with a relative file path \
49
- (relative to the current workspace).')
50
- }],
51
- ['currentText', {
52
- name: 'currentFileContent', description: nls.localize('theia/ai/core/variable-contribution/currentFileContent', 'The plain content of the \
53
- currently opened file. This excludes the information where the content is coming from. Please note that most agents will work better with a relative file path \
54
- (relative to the current workspace).')
55
- }],
56
- ['relativeFile', {
57
- name: 'currentRelativeFilePath', description: nls.localize('theia/ai/core/variable-contribution/currentRelativeFilePath', 'The relative path of the \
58
- currently opened file.')
59
- }],
60
- ['relativeFileDirname', {
61
- name: 'currentRelativeDirPath', description: nls.localize('theia/ai/core/variable-contribution/currentRelativeDirPath', 'The relative path of the directory \
62
- containing the currently opened file.')
63
- }],
64
- ['lineNumber', {}],
65
- ['workspaceFolder', {}]
49
+ protected variableRenameMap: Map<string, VariableMapping[]> = new Map([
50
+ ['file', [
51
+ {
52
+ name: 'currentAbsoluteFilePath',
53
+ description: nls.localize('theia/ai/core/variable-contribution/currentAbsoluteFilePath', 'The absolute path of the \
54
+ currently opened file. Please note that most agents will expect a relative file path (relative to the current workspace).')
55
+ }
56
+ ]],
57
+ ['selectedText', [
58
+ {
59
+ description: nls.localize('theia/ai/core/variable-contribution/currentSelectedText', 'The plain text that is currently selected in the \
60
+ opened file. This excludes the information where the content is coming from. Please note that most agents will work better with a relative file path \
61
+ (relative to the current workspace).')
62
+ }
63
+ ]],
64
+ ['currentText', [
65
+ {
66
+ name: 'currentFileContent',
67
+ description: nls.localize('theia/ai/core/variable-contribution/currentFileContent', 'The plain content of the \
68
+ currently opened file. This excludes the information where the content is coming from. Please note that most agents will work better with a relative file path \
69
+ (relative to the current workspace).')
70
+ }
71
+ ]],
72
+ ['relativeFile', [
73
+ {
74
+ name: 'currentRelativeFilePath',
75
+ description: nls.localize('theia/ai/core/variable-contribution/currentRelativeFilePath', 'The relative path of the \
76
+ currently opened file.')
77
+ },
78
+ {
79
+ name: '_f',
80
+ description: nls.localize('theia/ai/core/variable-contribution/dotRelativePath', 'Short reference to the relative path of the \
81
+ currently opened file (\'currentRelativeFilePath\').')
82
+ }
83
+ ]],
84
+ ['relativeFileDirname', [
85
+ {
86
+ name: 'currentRelativeDirPath',
87
+ description: nls.localize('theia/ai/core/variable-contribution/currentRelativeDirPath', 'The relative path of the directory \
88
+ containing the currently opened file.')
89
+ }
90
+ ]],
91
+ ['lineNumber', [{}]],
92
+ ['workspaceFolder', [{}]]
66
93
  ]);
67
94
 
68
95
  registerVariables(service: AIVariableService): void {
@@ -73,25 +100,39 @@ export class TheiaVariableContribution implements AIVariableContribution, AIVari
73
100
  if (!this.variableRenameMap.has(variable.name)) {
74
101
  return; // Do not register variables not part of the map
75
102
  }
76
- const mapping = this.variableRenameMap.get(variable.name)!;
77
- const newName = (mapping.name && mapping.name.trim() !== '') ? mapping.name : variable.name;
78
- const newDescription = (mapping.description && mapping.description.trim() !== '') ? mapping.description
79
- : (variable.description && variable.description.trim() !== '' ? variable.description
80
- : nls.localize('theia/ai/core/variable-contribution/builtInVariable', 'Theia Built-in Variable'));
81
-
82
- service.registerResolver({
83
- id: `${TheiaVariableContribution.THEIA_PREFIX}${variable.name}`,
84
- name: newName,
85
- description: newDescription
86
- }, this);
103
+
104
+ const mappings = this.variableRenameMap.get(variable.name)!;
105
+
106
+ // Register each mapping for this variable
107
+ mappings.forEach((mapping, index) => {
108
+ const newName = (mapping.name && mapping.name.trim() !== '') ? mapping.name : variable.name;
109
+ const newDescription = (mapping.description && mapping.description.trim() !== '') ? mapping.description
110
+ : (variable.description && variable.description.trim() !== '' ? variable.description
111
+ : nls.localize('theia/ai/core/variable-contribution/builtInVariable', 'Theia Built-in Variable'));
112
+
113
+ // For multiple mappings of the same variable, add a suffix to the ID to make it unique
114
+ const idSuffix = mappings.length > 1 ? `-${index}` : '';
115
+ const id = `${TheiaVariableContribution.THEIA_PREFIX}${variable.name}${idSuffix}`;
116
+
117
+ service.registerResolver({
118
+ id,
119
+ name: newName,
120
+ description: newDescription
121
+ }, this);
122
+ });
87
123
  });
88
124
  });
89
125
  }
90
126
 
91
127
  protected toTheiaVariable(request: AIVariableResolutionRequest): string {
92
- // Remove the THEIA_PREFIX if present before constructing the variable string
93
- const variableId = request.variable.id.startsWith(TheiaVariableContribution.THEIA_PREFIX) ? request.variable.id.slice(TheiaVariableContribution.THEIA_PREFIX.length) :
94
- request.variable.id;
128
+ // Extract the base variable name by removing the THEIA_PREFIX and any potential index suffix
129
+ let variableId = request.variable.id;
130
+ if (variableId.startsWith(TheiaVariableContribution.THEIA_PREFIX)) {
131
+ variableId = variableId.slice(TheiaVariableContribution.THEIA_PREFIX.length);
132
+ // Remove any potential index suffix (e.g., -0, -1)
133
+ variableId = variableId.replace(/-\d+$/, '');
134
+ }
135
+
95
136
  return `\${${variableId}${request.arg ? ':' + request.arg : ''}}`;
96
137
  }
97
138
 
@@ -15,26 +15,28 @@
15
15
  // *****************************************************************************
16
16
 
17
17
  import { Event } from '@theia/core';
18
+ import { LanguageModelMessage } from './language-model';
18
19
 
19
20
  export type CommunicationHistory = CommunicationHistoryEntry[];
20
21
 
21
- export interface CommunicationHistoryEntry {
22
+ export interface CommunicationHistoryEntryBase {
22
23
  agentId: string;
23
24
  sessionId: string;
24
25
  timestamp: number;
25
26
  requestId: string;
26
- request?: string;
27
- response?: string;
27
+ }
28
+
29
+ export interface CommunicationHistoryEntry extends CommunicationHistoryEntryBase {
30
+ request?: LanguageModelMessage[];
31
+ response?: LanguageModelMessage[];
28
32
  responseTime?: number;
29
- systemMessage?: string;
30
- messages?: unknown[];
31
33
  }
32
34
 
33
35
  export type CommunicationRequestEntry = Omit<CommunicationHistoryEntry, 'response' | 'responseTime'>;
34
36
  export type CommunicationResponseEntry = Omit<CommunicationHistoryEntry, 'request'>;
35
37
 
36
- export type CommunicationRequestEntryParam = Omit<CommunicationRequestEntry, 'timestamp'> & Partial<Pick<CommunicationHistoryEntry, 'timestamp'>>;
37
- export type CommunicationResponseEntryParam = Omit<CommunicationResponseEntry, 'timestamp'> & Partial<Pick<CommunicationHistoryEntry, 'timestamp'>>;
38
+ export type CommunicationRequestEntryParam = Omit<CommunicationRequestEntry, 'timestamp'> & Partial<Pick<CommunicationRequestEntry, 'timestamp'>>;
39
+ export type CommunicationResponseEntryParam = Omit<CommunicationResponseEntry, 'timestamp'> & Partial<Pick<CommunicationResponseEntry, 'timestamp'>>;
38
40
 
39
41
  export const CommunicationRecordingService = Symbol('CommunicationRecordingService');
40
42
  export interface CommunicationRecordingService {
@@ -28,3 +28,4 @@ export * from './protocol';
28
28
  export * from './today-variable-contribution';
29
29
  export * from './variable-service';
30
30
  export * from './settings-service';
31
+ export * from './language-model-service';
@@ -0,0 +1,59 @@
1
+ // *****************************************************************************
2
+ // Copyright (C) 2025 EclipseSource GmbH.
3
+ //
4
+ // This program and the accompanying materials are made available under the
5
+ // terms of the Eclipse Public License v. 2.0 which is available at
6
+ // http://www.eclipse.org/legal/epl-2.0.
7
+ //
8
+ // This Source Code may also be made available under the following Secondary
9
+ // Licenses when the conditions for such availability set forth in the Eclipse
10
+ // Public License v. 2.0 are satisfied: GNU General Public License, version 2
11
+ // with the GNU Classpath Exception which is available at
12
+ // https://www.gnu.org/software/classpath/license.html.
13
+ //
14
+ // SPDX-License-Identifier: EPL-2.0 OR GPL-2.0-only WITH Classpath-exception-2.0
15
+ // *****************************************************************************
16
+
17
+ import { inject } from '@theia/core/shared/inversify';
18
+ import { LanguageModel, LanguageModelRegistry, LanguageModelResponse, UserRequest } from './language-model';
19
+ import { CommunicationRecordingService } from './communication-recording-service';
20
+
21
+ export const LanguageModelService = Symbol('LanguageModelService');
22
+ export interface LanguageModelService {
23
+ /**
24
+ * Submit a language model request in the context of the given `chatRequest`.
25
+ */
26
+ sendRequest(
27
+ languageModel: LanguageModel,
28
+ languageModelRequest: UserRequest
29
+ ): Promise<LanguageModelResponse>;
30
+ }
31
+ export class LanguageModelServiceImpl implements LanguageModelService {
32
+
33
+ @inject(LanguageModelRegistry)
34
+ protected languageModelRegistry: LanguageModelRegistry;
35
+
36
+ @inject(CommunicationRecordingService)
37
+ protected recordingService: CommunicationRecordingService;
38
+
39
+ async sendRequest(
40
+ languageModel: LanguageModel,
41
+ languageModelRequest: UserRequest
42
+ ): Promise<LanguageModelResponse> {
43
+ // Filter messages based on client settings
44
+ languageModelRequest.messages = languageModelRequest.messages.filter(message => {
45
+ if (message.type === 'thinking' && languageModelRequest.clientSettings?.keepThinking === false) {
46
+ return false;
47
+ }
48
+ if ((message.type === 'tool_result' || message.type === 'tool_use') &&
49
+ languageModelRequest.clientSettings?.keepToolCalls === false) {
50
+ return false;
51
+ }
52
+ // Keep all other messages
53
+ return true;
54
+ });
55
+
56
+ return languageModel.request(languageModelRequest, languageModelRequest.cancellationToken);
57
+ }
58
+
59
+ }
@@ -14,7 +14,14 @@
14
14
  // SPDX-License-Identifier: EPL-2.0 OR GPL-2.0-only WITH Classpath-exception-2.0
15
15
  // *****************************************************************************
16
16
 
17
- import { isLanguageModelParsedResponse, isLanguageModelStreamResponse, isLanguageModelTextResponse, LanguageModelResponse, ToolRequest } from './language-model';
17
+ import {
18
+ isLanguageModelParsedResponse,
19
+ isLanguageModelStreamResponse,
20
+ isLanguageModelTextResponse,
21
+ isTextResponsePart,
22
+ LanguageModelResponse,
23
+ ToolRequest
24
+ } from './language-model';
18
25
 
19
26
  /**
20
27
  * Retrieves the text content from a `LanguageModelResponse` object.
@@ -32,7 +39,7 @@ export const getTextOfResponse = async (response: LanguageModelResponse): Promis
32
39
  } else if (isLanguageModelStreamResponse(response)) {
33
40
  let result = '';
34
41
  for await (const chunk of response.stream) {
35
- result += chunk.content ?? '';
42
+ result += (isTextResponsePart(chunk) && chunk.content) ? chunk.content : '';
36
43
  }
37
44
  return result;
38
45
  } else if (isLanguageModelParsedResponse(response)) {
@@ -1,5 +1,5 @@
1
1
  // *****************************************************************************
2
- // Copyright (C) 2024 EclipseSource GmbH.
2
+ // Copyright (C) 2024-2025 EclipseSource GmbH.
3
3
  //
4
4
  // This program and the accompanying materials are made available under the
5
5
  // terms of the Eclipse Public License v. 2.0 which is available at
@@ -19,12 +19,52 @@ import { inject, injectable, named, postConstruct } from '@theia/core/shared/inv
19
19
 
20
20
  export type MessageActor = 'user' | 'ai' | 'system';
21
21
 
22
- export interface LanguageModelRequestMessage {
22
+ export type LanguageModelMessage = TextMessage | ThinkingMessage | ToolUseMessage | ToolResultMessage;
23
+ export namespace LanguageModelMessage {
24
+
25
+ export function isTextMessage(obj: LanguageModelMessage): obj is TextMessage {
26
+ return obj.type === 'text';
27
+ }
28
+ export function isThinkingMessage(obj: LanguageModelMessage): obj is ThinkingMessage {
29
+ return obj.type === 'thinking';
30
+ }
31
+ export function isToolUseMessage(obj: LanguageModelMessage): obj is ToolUseMessage {
32
+ return obj.type === 'tool_use';
33
+ }
34
+ export function isToolResultMessage(obj: LanguageModelMessage): obj is ToolResultMessage {
35
+ return obj.type === 'tool_result';
36
+ }
37
+ }
38
+ export interface TextMessage {
23
39
  actor: MessageActor;
24
40
  type: 'text';
25
- query: string;
41
+ text: string;
42
+ }
43
+ export interface ThinkingMessage {
44
+ actor: 'ai'
45
+ type: 'thinking';
46
+ thinking: string;
47
+ signature: string;
48
+ }
49
+
50
+ export interface ToolResultMessage {
51
+ actor: 'user';
52
+ tool_use_id: string;
53
+ name: string;
54
+ type: 'tool_result';
55
+ content?: string;
56
+ is_error?: boolean;
57
+ }
58
+
59
+ export interface ToolUseMessage {
60
+ actor: 'ai';
61
+ type: 'tool_use';
62
+ id: string;
63
+ input: unknown;
64
+ name: string;
26
65
  }
27
- export const isLanguageModelRequestMessage = (obj: unknown): obj is LanguageModelRequestMessage =>
66
+
67
+ export const isLanguageModelRequestMessage = (obj: unknown): obj is LanguageModelMessage =>
28
68
  !!(obj && typeof obj === 'object' &&
29
69
  'type' in obj &&
30
70
  typeof (obj as { type: unknown }).type === 'string' &&
@@ -48,7 +88,7 @@ export interface ToolRequestParameters {
48
88
  export interface ToolRequest {
49
89
  id: string;
50
90
  name: string;
51
- parameters?: ToolRequestParameters
91
+ parameters: ToolRequestParameters
52
92
  description?: string;
53
93
  handler: (arg_string: string, ctx?: unknown) => Promise<unknown>;
54
94
  providerName?: string;
@@ -102,12 +142,12 @@ export namespace ToolRequest {
102
142
  (!('required' in obj) || (Array.isArray(obj.required) && obj.required.every(prop => typeof prop === 'string')));
103
143
  }
104
144
  }
105
-
106
145
  export interface LanguageModelRequest {
107
- messages: LanguageModelRequestMessage[],
146
+ messages: LanguageModelMessage[],
108
147
  tools?: ToolRequest[];
109
148
  response_format?: { type: 'text' } | { type: 'json_object' } | ResponseFormatJsonSchema;
110
149
  settings?: { [key: string]: unknown };
150
+ clientSettings?: { keepToolCalls: boolean; keepThinking: boolean }
111
151
  }
112
152
  export interface ResponseFormatJsonSchema {
113
153
  type: 'json_schema';
@@ -119,16 +159,38 @@ export interface ResponseFormatJsonSchema {
119
159
  };
120
160
  }
121
161
 
162
+ export interface UserRequest extends LanguageModelRequest {
163
+ sessionId: string;
164
+ requestId: string;
165
+ agentId: string;
166
+ cancellationToken?: CancellationToken;
167
+ }
168
+
122
169
  export interface LanguageModelTextResponse {
123
170
  text: string;
124
171
  }
125
172
  export const isLanguageModelTextResponse = (obj: unknown): obj is LanguageModelTextResponse =>
126
173
  !!(obj && typeof obj === 'object' && 'text' in obj && typeof (obj as { text: unknown }).text === 'string');
127
174
 
128
- export interface LanguageModelStreamResponsePart {
129
- content?: string | null;
130
- tool_calls?: ToolCall[];
175
+ export type LanguageModelStreamResponsePart = TextResponsePart | ToolCallResponsePart | ThinkingResponsePart;
176
+ export interface TextResponsePart {
177
+ content: string;
178
+ }
179
+ export const isTextResponsePart = (part: unknown): part is TextResponsePart =>
180
+ !!(part && typeof part === 'object' && 'content' in part && typeof part.content === 'string');
181
+
182
+ export interface ToolCallResponsePart {
183
+ tool_calls: ToolCall[];
184
+ }
185
+ export const isToolCallResponsePart = (part: unknown): part is ToolCallResponsePart =>
186
+ !!(part && typeof part === 'object' && 'tool_calls' in part && Array.isArray(part.tool_calls));
187
+
188
+ export interface ThinkingResponsePart {
189
+ thought: string;
190
+ signature: string;
131
191
  }
192
+ export const isThinkingResponsePart = (part: unknown): part is ThinkingResponsePart =>
193
+ !!(part && typeof part === 'object' && 'thought' in part && typeof part.thought === 'string');
132
194
 
133
195
  export interface ToolCall {
134
196
  id?: string;
@@ -171,11 +233,6 @@ export interface LanguageModelMetaData {
171
233
  readonly family?: string;
172
234
  readonly maxInputTokens?: number;
173
235
  readonly maxOutputTokens?: number;
174
- /**
175
- * Default request settings for the language model. These settings can be set by a user preferences.
176
- * Settings in a request will override these default settings.
177
- */
178
- readonly defaultRequestSettings?: { [key: string]: unknown };
179
236
  }
180
237
 
181
238
  export namespace LanguageModelMetaData {
@@ -14,7 +14,7 @@
14
14
  // SPDX-License-Identifier: EPL-2.0 OR GPL-2.0-only WITH Classpath-exception-2.0
15
15
  // *****************************************************************************
16
16
 
17
- import { inject, injectable, named, postConstruct } from '@theia/core/shared/inversify';
17
+ import { inject, injectable, named, postConstruct, interfaces } from '@theia/core/shared/inversify';
18
18
  import { ToolRequest } from './language-model';
19
19
  import { ContributionProvider } from '@theia/core';
20
20
 
@@ -69,6 +69,12 @@ export interface ToolProvider {
69
69
  getTool(): ToolRequest;
70
70
  }
71
71
 
72
+ /** Binds the identifier to self in singleton scope and then binds `ToolProvider` to that service. */
73
+ export function bindToolProvider(identifier: interfaces.Newable<ToolProvider>, bind: interfaces.Bind): void {
74
+ bind(identifier).toSelf().inSingletonScope();
75
+ bind(ToolProvider).toService(identifier);
76
+ }
77
+
72
78
  @injectable()
73
79
  export class ToolInvocationRegistryImpl implements ToolInvocationRegistry {
74
80
 
@@ -122,4 +128,3 @@ export class ToolInvocationRegistryImpl implements ToolInvocationRegistry {
122
128
  return tools;
123
129
  }
124
130
  }
125
-
@@ -128,7 +128,8 @@ export interface AIVariableContext {
128
128
  export type AIVariableArg = string | { variable: string, arg?: string } | AIVariableResolutionRequest;
129
129
 
130
130
  export type AIVariableArgPicker = (context: AIVariableContext) => MaybePromise<string | undefined>;
131
- export type AIVariableArgCompletionProvider = (model: monaco.editor.ITextModel, position: monaco.Position) => MaybePromise<monaco.languages.CompletionItem[] | undefined>;
131
+ export type AIVariableArgCompletionProvider =
132
+ (model: monaco.editor.ITextModel, position: monaco.Position, matchString?: string) => MaybePromise<monaco.languages.CompletionItem[] | undefined>;
132
133
 
133
134
  export interface AIVariableResolver {
134
135
  canResolve(request: AIVariableResolutionRequest, context: AIVariableContext): MaybePromise<number>,