@theia/ai-core 1.55.0 → 1.56.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.
- package/data/prompttemplate.tmLanguage.json +60 -5
- package/lib/browser/ai-configuration/agent-configuration-widget.d.ts.map +1 -1
- package/lib/browser/ai-configuration/agent-configuration-widget.js +10 -5
- package/lib/browser/ai-configuration/agent-configuration-widget.js.map +1 -1
- package/lib/browser/ai-configuration/language-model-renderer.js +1 -1
- package/lib/browser/ai-configuration/language-model-renderer.js.map +1 -1
- package/lib/browser/ai-configuration/template-settings-renderer.d.ts +6 -4
- package/lib/browser/ai-configuration/template-settings-renderer.d.ts.map +1 -1
- package/lib/browser/ai-configuration/template-settings-renderer.js +49 -11
- package/lib/browser/ai-configuration/template-settings-renderer.js.map +1 -1
- package/lib/browser/ai-core-preferences.d.ts +15 -0
- package/lib/browser/ai-core-preferences.d.ts.map +1 -1
- package/lib/browser/ai-core-preferences.js +30 -1
- package/lib/browser/ai-core-preferences.js.map +1 -1
- package/lib/browser/frontend-prompt-customization-service.d.ts +1 -0
- package/lib/browser/frontend-prompt-customization-service.d.ts.map +1 -1
- package/lib/browser/frontend-prompt-customization-service.js +6 -0
- package/lib/browser/frontend-prompt-customization-service.js.map +1 -1
- package/lib/common/agent-service.js +1 -1
- package/lib/common/agent-service.js.map +1 -1
- package/lib/common/agent.d.ts +1 -1
- package/lib/common/communication-recording-service.d.ts +5 -2
- package/lib/common/communication-recording-service.d.ts.map +1 -1
- package/lib/common/communication-recording-service.js.map +1 -1
- package/lib/common/language-model.d.ts +7 -0
- package/lib/common/language-model.d.ts.map +1 -1
- package/lib/common/language-model.js.map +1 -1
- package/lib/common/prompt-service-util.d.ts +5 -2
- package/lib/common/prompt-service-util.d.ts.map +1 -1
- package/lib/common/prompt-service-util.js +14 -3
- package/lib/common/prompt-service-util.js.map +1 -1
- package/lib/common/prompt-service.d.ts +36 -6
- package/lib/common/prompt-service.d.ts.map +1 -1
- package/lib/common/prompt-service.js +49 -6
- package/lib/common/prompt-service.js.map +1 -1
- package/lib/common/prompt-service.spec.js +176 -8
- package/lib/common/prompt-service.spec.js.map +1 -1
- package/lib/common/settings-service.d.ts +5 -0
- package/lib/common/settings-service.d.ts.map +1 -1
- package/package.json +10 -10
- package/src/browser/ai-configuration/agent-configuration-widget.tsx +28 -11
- package/src/browser/ai-configuration/language-model-renderer.tsx +1 -1
- package/src/browser/ai-configuration/template-settings-renderer.tsx +105 -16
- package/src/browser/ai-core-preferences.ts +40 -1
- package/src/browser/frontend-prompt-customization-service.ts +8 -0
- package/src/browser/style/index.css +37 -5
- package/src/common/agent-service.ts +1 -1
- package/src/common/agent.ts +1 -1
- package/src/common/communication-recording-service.ts +6 -2
- package/src/common/language-model.ts +5 -0
- package/src/common/prompt-service-util.ts +12 -2
- package/src/common/prompt-service.spec.ts +211 -8
- package/src/common/prompt-service.ts +85 -12
- package/src/common/settings-service.ts +5 -0
|
@@ -37,9 +37,10 @@ describe('PromptService', () => {
|
|
|
37
37
|
container.bind<AIVariableService>(AIVariableService).toConstantValue(variableService);
|
|
38
38
|
|
|
39
39
|
promptService = container.get<PromptService>(PromptService);
|
|
40
|
-
promptService.
|
|
41
|
-
promptService.
|
|
42
|
-
promptService.
|
|
40
|
+
promptService.storePromptTemplate({ id: '1', template: 'Hello, {{name}}!' });
|
|
41
|
+
promptService.storePromptTemplate({ id: '2', template: 'Goodbye, {{name}}!' });
|
|
42
|
+
promptService.storePromptTemplate({ id: '3', template: 'Ciao, {{invalid}}!' });
|
|
43
|
+
promptService.storePromptTemplate({ id: '8', template: 'Hello, {{{name}}}' });
|
|
43
44
|
});
|
|
44
45
|
|
|
45
46
|
it('should initialize prompts from PromptCollectionService', () => {
|
|
@@ -47,6 +48,7 @@ describe('PromptService', () => {
|
|
|
47
48
|
expect(allPrompts['1'].template).to.equal('Hello, {{name}}!');
|
|
48
49
|
expect(allPrompts['2'].template).to.equal('Goodbye, {{name}}!');
|
|
49
50
|
expect(allPrompts['3'].template).to.equal('Ciao, {{invalid}}!');
|
|
51
|
+
expect(allPrompts['8'].template).to.equal('Hello, {{{name}}}');
|
|
50
52
|
});
|
|
51
53
|
|
|
52
54
|
it('should retrieve raw prompt by id', () => {
|
|
@@ -60,7 +62,7 @@ describe('PromptService', () => {
|
|
|
60
62
|
});
|
|
61
63
|
|
|
62
64
|
it('should store a new prompt', () => {
|
|
63
|
-
promptService.
|
|
65
|
+
promptService.storePromptTemplate({ id: '3', template: 'Welcome, {{name}}!' });
|
|
64
66
|
const newPrompt = promptService.getRawPrompt('3');
|
|
65
67
|
expect(newPrompt?.template).to.equal('Welcome, {{name}}!');
|
|
66
68
|
});
|
|
@@ -86,13 +88,214 @@ describe('PromptService', () => {
|
|
|
86
88
|
});
|
|
87
89
|
|
|
88
90
|
it('should ignore whitespace in variables', async () => {
|
|
89
|
-
promptService.
|
|
90
|
-
promptService.
|
|
91
|
-
promptService.
|
|
92
|
-
promptService.
|
|
91
|
+
promptService.storePromptTemplate({ id: '4', template: 'Hello, {{name }}!' });
|
|
92
|
+
promptService.storePromptTemplate({ id: '5', template: 'Hello, {{ name}}!' });
|
|
93
|
+
promptService.storePromptTemplate({ id: '6', template: 'Hello, {{ name }}!' });
|
|
94
|
+
promptService.storePromptTemplate({ id: '7', template: 'Hello, {{ name }}!' });
|
|
93
95
|
for (let i = 4; i <= 7; i++) {
|
|
94
96
|
const prompt = await promptService.getPrompt(`${i}`, { name: 'John' });
|
|
95
97
|
expect(prompt?.text).to.equal('Hello, John!');
|
|
96
98
|
}
|
|
97
99
|
});
|
|
100
|
+
|
|
101
|
+
it('should retrieve raw prompt by id (three bracket)', () => {
|
|
102
|
+
const rawPrompt = promptService.getRawPrompt('8');
|
|
103
|
+
expect(rawPrompt?.template).to.equal('Hello, {{{name}}}');
|
|
104
|
+
});
|
|
105
|
+
|
|
106
|
+
it('should correctly replace variables (three brackets)', async () => {
|
|
107
|
+
const formattedPrompt = await promptService.getPrompt('8');
|
|
108
|
+
expect(formattedPrompt?.text).to.equal('Hello, Jane');
|
|
109
|
+
});
|
|
110
|
+
|
|
111
|
+
it('should ignore whitespace in variables (three bracket)', async () => {
|
|
112
|
+
promptService.storePromptTemplate({ id: '9', template: 'Hello, {{{name }}}' });
|
|
113
|
+
promptService.storePromptTemplate({ id: '10', template: 'Hello, {{{ name}}}' });
|
|
114
|
+
promptService.storePromptTemplate({ id: '11', template: 'Hello, {{{ name }}}' });
|
|
115
|
+
promptService.storePromptTemplate({ id: '12', template: 'Hello, {{{ name }}}' });
|
|
116
|
+
for (let i = 9; i <= 12; i++) {
|
|
117
|
+
const prompt = await promptService.getPrompt(`${i}`, { name: 'John' });
|
|
118
|
+
expect(prompt?.text).to.equal('Hello, John');
|
|
119
|
+
}
|
|
120
|
+
});
|
|
121
|
+
|
|
122
|
+
it('should ignore invalid prompts with unmatched brackets', async () => {
|
|
123
|
+
promptService.storePromptTemplate({ id: '9', template: 'Hello, {{name' });
|
|
124
|
+
promptService.storePromptTemplate({ id: '10', template: 'Hello, {{{name' });
|
|
125
|
+
promptService.storePromptTemplate({ id: '11', template: 'Hello, name}}}}' });
|
|
126
|
+
const prompt1 = await promptService.getPrompt('9', { name: 'John' });
|
|
127
|
+
expect(prompt1?.text).to.equal('Hello, {{name'); // Not matching due to missing closing brackets
|
|
128
|
+
const prompt2 = await promptService.getPrompt('10', { name: 'John' });
|
|
129
|
+
expect(prompt2?.text).to.equal('Hello, {{{name'); // Matches pattern due to valid three-start-two-end brackets
|
|
130
|
+
const prompt3 = await promptService.getPrompt('11', { name: 'John' });
|
|
131
|
+
expect(prompt3?.text).to.equal('Hello, name}}}}'); // Extra closing bracket, does not match cleanly
|
|
132
|
+
});
|
|
133
|
+
|
|
134
|
+
it('should handle a mixture of two and three brackets correctly', async () => {
|
|
135
|
+
promptService.storePromptTemplate({ id: '12', template: 'Hi, {{name}}}' }); // (invalid)
|
|
136
|
+
promptService.storePromptTemplate({ id: '13', template: 'Hello, {{{name}}' }); // (invalid)
|
|
137
|
+
promptService.storePromptTemplate({ id: '14', template: 'Greetings, {{{name}}}}' }); // (invalid)
|
|
138
|
+
promptService.storePromptTemplate({ id: '15', template: 'Bye, {{{{name}}}' }); // (invalid)
|
|
139
|
+
promptService.storePromptTemplate({ id: '16', template: 'Ciao, {{{{name}}}}' }); // (invalid)
|
|
140
|
+
promptService.storePromptTemplate({ id: '17', template: 'Hi, {{name}}! {{{name}}}' }); // Mixed valid patterns
|
|
141
|
+
|
|
142
|
+
const prompt12 = await promptService.getPrompt('12', { name: 'John' });
|
|
143
|
+
expect(prompt12?.text).to.equal('Hi, {{name}}}');
|
|
144
|
+
|
|
145
|
+
const prompt13 = await promptService.getPrompt('13', { name: 'John' });
|
|
146
|
+
expect(prompt13?.text).to.equal('Hello, {{{name}}');
|
|
147
|
+
|
|
148
|
+
const prompt14 = await promptService.getPrompt('14', { name: 'John' });
|
|
149
|
+
expect(prompt14?.text).to.equal('Greetings, {{{name}}}}');
|
|
150
|
+
|
|
151
|
+
const prompt15 = await promptService.getPrompt('15', { name: 'John' });
|
|
152
|
+
expect(prompt15?.text).to.equal('Bye, {{{{name}}}');
|
|
153
|
+
|
|
154
|
+
const prompt16 = await promptService.getPrompt('16', { name: 'John' });
|
|
155
|
+
expect(prompt16?.text).to.equal('Ciao, {{{{name}}}}');
|
|
156
|
+
|
|
157
|
+
const prompt17 = await promptService.getPrompt('17', { name: 'John' });
|
|
158
|
+
expect(prompt17?.text).to.equal('Hi, John! John');
|
|
159
|
+
});
|
|
160
|
+
|
|
161
|
+
it('should strip single-line comments at the start of the template', () => {
|
|
162
|
+
promptService.storePromptTemplate({ id: 'comment-basic', template: '{{!-- Comment --}}Hello, {{name}}!' });
|
|
163
|
+
const prompt = promptService.getUnresolvedPrompt('comment-basic');
|
|
164
|
+
expect(prompt?.template).to.equal('Hello, {{name}}!');
|
|
165
|
+
});
|
|
166
|
+
|
|
167
|
+
it('should remove line break after first-line comment', () => {
|
|
168
|
+
promptService.storePromptTemplate({ id: 'comment-line-break', template: '{{!-- Comment --}}\nHello, {{name}}!' });
|
|
169
|
+
const prompt = promptService.getUnresolvedPrompt('comment-line-break');
|
|
170
|
+
expect(prompt?.template).to.equal('Hello, {{name}}!');
|
|
171
|
+
});
|
|
172
|
+
|
|
173
|
+
it('should strip multiline comments at the start of the template', () => {
|
|
174
|
+
promptService.storePromptTemplate({ id: 'comment-multiline', template: '{{!--\nMultiline comment\n--}}\nGoodbye, {{name}}!' });
|
|
175
|
+
const prompt = promptService.getUnresolvedPrompt('comment-multiline');
|
|
176
|
+
expect(prompt?.template).to.equal('Goodbye, {{name}}!');
|
|
177
|
+
});
|
|
178
|
+
|
|
179
|
+
it('should not strip comments not in the first line', () => {
|
|
180
|
+
promptService.storePromptTemplate({ id: 'comment-second-line', template: 'Hello, {{name}}!\n{{!-- Comment --}}' });
|
|
181
|
+
const prompt = promptService.getUnresolvedPrompt('comment-second-line');
|
|
182
|
+
expect(prompt?.template).to.equal('Hello, {{name}}!\n{{!-- Comment --}}');
|
|
183
|
+
});
|
|
184
|
+
|
|
185
|
+
it('should treat unclosed comments as regular text', () => {
|
|
186
|
+
promptService.storePromptTemplate({ id: 'comment-unclosed', template: '{{!-- Unclosed comment' });
|
|
187
|
+
const prompt = promptService.getUnresolvedPrompt('comment-unclosed');
|
|
188
|
+
expect(prompt?.template).to.equal('{{!-- Unclosed comment');
|
|
189
|
+
});
|
|
190
|
+
|
|
191
|
+
it('should treat standalone closing delimiters as regular text', () => {
|
|
192
|
+
promptService.storePromptTemplate({ id: 'comment-standalone', template: '--}} Hello, {{name}}!' });
|
|
193
|
+
const prompt = promptService.getUnresolvedPrompt('comment-standalone');
|
|
194
|
+
expect(prompt?.template).to.equal('--}} Hello, {{name}}!');
|
|
195
|
+
});
|
|
196
|
+
|
|
197
|
+
it('should handle nested comments and stop at the first closing tag', () => {
|
|
198
|
+
promptService.storePromptTemplate({ id: 'nested-comment', template: '{{!-- {{!-- Nested comment --}} --}}text' });
|
|
199
|
+
const prompt = promptService.getUnresolvedPrompt('nested-comment');
|
|
200
|
+
expect(prompt?.template).to.equal('--}}text');
|
|
201
|
+
});
|
|
202
|
+
|
|
203
|
+
it('should handle templates with only comments', () => {
|
|
204
|
+
promptService.storePromptTemplate({ id: 'comment-only', template: '{{!-- Only comments --}}' });
|
|
205
|
+
const prompt = promptService.getUnresolvedPrompt('comment-only');
|
|
206
|
+
expect(prompt?.template).to.equal('');
|
|
207
|
+
});
|
|
208
|
+
|
|
209
|
+
it('should handle mixed delimiters on the same line', () => {
|
|
210
|
+
promptService.storePromptTemplate({ id: 'comment-mixed', template: '{{!-- Unclosed comment --}}' });
|
|
211
|
+
const prompt = promptService.getUnresolvedPrompt('comment-mixed');
|
|
212
|
+
expect(prompt?.template).to.equal('');
|
|
213
|
+
});
|
|
214
|
+
|
|
215
|
+
it('should resolve variables after stripping single-line comments', async () => {
|
|
216
|
+
promptService.storePromptTemplate({ id: 'comment-resolve', template: '{{!-- Comment --}}Hello, {{name}}!' });
|
|
217
|
+
const prompt = await promptService.getPrompt('comment-resolve', { name: 'John' });
|
|
218
|
+
expect(prompt?.text).to.equal('Hello, John!');
|
|
219
|
+
});
|
|
220
|
+
|
|
221
|
+
it('should resolve variables in multiline templates with comments', async () => {
|
|
222
|
+
promptService.storePromptTemplate({ id: 'comment-multiline-vars', template: '{{!--\nMultiline comment\n--}}\nHello, {{name}}!' });
|
|
223
|
+
const prompt = await promptService.getPrompt('comment-multiline-vars', { name: 'John' });
|
|
224
|
+
expect(prompt?.text).to.equal('Hello, John!');
|
|
225
|
+
});
|
|
226
|
+
|
|
227
|
+
it('should resolve variables with standalone closing delimiters', async () => {
|
|
228
|
+
promptService.storePromptTemplate({ id: 'comment-standalone-vars', template: '--}} Hello, {{name}}!' });
|
|
229
|
+
const prompt = await promptService.getPrompt('comment-standalone-vars', { name: 'John' });
|
|
230
|
+
expect(prompt?.text).to.equal('--}} Hello, John!');
|
|
231
|
+
});
|
|
232
|
+
|
|
233
|
+
it('should treat unclosed comments as text and resolve variables', async () => {
|
|
234
|
+
promptService.storePromptTemplate({ id: 'comment-unclosed-vars', template: '{{!-- Unclosed comment\nHello, {{name}}!' });
|
|
235
|
+
const prompt = await promptService.getPrompt('comment-unclosed-vars', { name: 'John' });
|
|
236
|
+
expect(prompt?.text).to.equal('{{!-- Unclosed comment\nHello, John!');
|
|
237
|
+
});
|
|
238
|
+
|
|
239
|
+
it('should handle templates with mixed comments and variables', async () => {
|
|
240
|
+
promptService.storePromptTemplate({ id: 'comment-mixed-vars', template: '{{!-- Comment --}}Hi, {{name}}! {{!-- Another comment --}}' });
|
|
241
|
+
const prompt = await promptService.getPrompt('comment-mixed-vars', { name: 'John' });
|
|
242
|
+
expect(prompt?.text).to.equal('Hi, John! {{!-- Another comment --}}');
|
|
243
|
+
});
|
|
244
|
+
|
|
245
|
+
it('should return all variant IDs of a given prompt', () => {
|
|
246
|
+
promptService.storePromptTemplate({ id: 'main', template: 'Main template' });
|
|
247
|
+
|
|
248
|
+
promptService.storePromptTemplate({
|
|
249
|
+
id: 'variant1',
|
|
250
|
+
template: 'Variant 1',
|
|
251
|
+
variantOf: 'main'
|
|
252
|
+
});
|
|
253
|
+
promptService.storePromptTemplate({
|
|
254
|
+
id: 'variant2',
|
|
255
|
+
template: 'Variant 2',
|
|
256
|
+
variantOf: 'main'
|
|
257
|
+
});
|
|
258
|
+
promptService.storePromptTemplate({
|
|
259
|
+
id: 'variant3',
|
|
260
|
+
template: 'Variant 3',
|
|
261
|
+
variantOf: 'main'
|
|
262
|
+
});
|
|
263
|
+
|
|
264
|
+
const variantIds = promptService.getVariantIds('main');
|
|
265
|
+
expect(variantIds).to.deep.equal(['variant1', 'variant2', 'variant3']);
|
|
266
|
+
});
|
|
267
|
+
|
|
268
|
+
it('should return an empty array if no variants exist for a given prompt', () => {
|
|
269
|
+
promptService.storePromptTemplate({ id: 'main', template: 'Main template' });
|
|
270
|
+
|
|
271
|
+
const variantIds = promptService.getVariantIds('main');
|
|
272
|
+
expect(variantIds).to.deep.equal([]);
|
|
273
|
+
});
|
|
274
|
+
|
|
275
|
+
it('should return an empty array if the main prompt ID does not exist', () => {
|
|
276
|
+
const variantIds = promptService.getVariantIds('nonExistent');
|
|
277
|
+
expect(variantIds).to.deep.equal([]);
|
|
278
|
+
});
|
|
279
|
+
|
|
280
|
+
it('should not influence prompts without variants when other prompts have variants', () => {
|
|
281
|
+
promptService.storePromptTemplate({ id: 'mainWithVariants', template: 'Main template with variants' });
|
|
282
|
+
promptService.storePromptTemplate({ id: 'mainWithoutVariants', template: 'Main template without variants' });
|
|
283
|
+
|
|
284
|
+
promptService.storePromptTemplate({
|
|
285
|
+
id: 'variant1',
|
|
286
|
+
template: 'Variant 1',
|
|
287
|
+
variantOf: 'mainWithVariants'
|
|
288
|
+
});
|
|
289
|
+
promptService.storePromptTemplate({
|
|
290
|
+
id: 'variant2',
|
|
291
|
+
template: 'Variant 2',
|
|
292
|
+
variantOf: 'mainWithVariants'
|
|
293
|
+
});
|
|
294
|
+
|
|
295
|
+
const variantsForMainWithVariants = promptService.getVariantIds('mainWithVariants');
|
|
296
|
+
const variantsForMainWithoutVariants = promptService.getVariantIds('mainWithoutVariants');
|
|
297
|
+
|
|
298
|
+
expect(variantsForMainWithVariants).to.deep.equal(['variant1', 'variant2']);
|
|
299
|
+
expect(variantsForMainWithoutVariants).to.deep.equal([]);
|
|
300
|
+
});
|
|
98
301
|
});
|
|
@@ -20,11 +20,17 @@ import { AIVariableService } from './variable-service';
|
|
|
20
20
|
import { ToolInvocationRegistry } from './tool-invocation-registry';
|
|
21
21
|
import { toolRequestToPromptText } from './language-model-util';
|
|
22
22
|
import { ToolRequest } from './language-model';
|
|
23
|
-
import {
|
|
23
|
+
import { matchFunctionsRegEx, matchVariablesRegEx } from './prompt-service-util';
|
|
24
|
+
import { AISettingsService } from './settings-service';
|
|
24
25
|
|
|
25
26
|
export interface PromptTemplate {
|
|
26
27
|
id: string;
|
|
27
28
|
template: string;
|
|
29
|
+
/**
|
|
30
|
+
* (Optional) The ID of the main template for which this template is a variant.
|
|
31
|
+
* If present, this indicates that the current template represents an alternative version of the specified main template.
|
|
32
|
+
*/
|
|
33
|
+
variantOf?: string;
|
|
28
34
|
}
|
|
29
35
|
|
|
30
36
|
export interface PromptMap { [id: string]: PromptTemplate }
|
|
@@ -40,10 +46,15 @@ export interface ResolvedPromptTemplate {
|
|
|
40
46
|
export const PromptService = Symbol('PromptService');
|
|
41
47
|
export interface PromptService {
|
|
42
48
|
/**
|
|
43
|
-
* Retrieve the raw {@link PromptTemplate} object.
|
|
49
|
+
* Retrieve the raw {@link PromptTemplate} object (unresolved variables, functions and including comments).
|
|
44
50
|
* @param id the id of the {@link PromptTemplate}
|
|
45
51
|
*/
|
|
46
52
|
getRawPrompt(id: string): PromptTemplate | undefined;
|
|
53
|
+
/**
|
|
54
|
+
* Retrieve the unresolved {@link PromptTemplate} object (unresolved variables, functions, excluding comments)
|
|
55
|
+
* @param id the id of the {@link PromptTemplate}
|
|
56
|
+
*/
|
|
57
|
+
getUnresolvedPrompt(id: string): PromptTemplate | undefined;
|
|
47
58
|
/**
|
|
48
59
|
* Retrieve the default raw {@link PromptTemplate} object.
|
|
49
60
|
* @param id the id of the {@link PromptTemplate}
|
|
@@ -58,11 +69,10 @@ export interface PromptService {
|
|
|
58
69
|
*/
|
|
59
70
|
getPrompt(id: string, args?: { [key: string]: unknown }): Promise<ResolvedPromptTemplate | undefined>;
|
|
60
71
|
/**
|
|
61
|
-
* Adds a
|
|
62
|
-
* @param
|
|
63
|
-
* @param prompt the prompt template to store
|
|
72
|
+
* Adds a {@link PromptTemplate} to the list of prompts.
|
|
73
|
+
* @param promptTemplate the prompt template to store
|
|
64
74
|
*/
|
|
65
|
-
|
|
75
|
+
storePromptTemplate(promptTemplate: PromptTemplate): void;
|
|
66
76
|
/**
|
|
67
77
|
* Removes a prompt from the list of prompts.
|
|
68
78
|
* @param id the id of the prompt
|
|
@@ -72,6 +82,20 @@ export interface PromptService {
|
|
|
72
82
|
* Return all known prompts as a {@link PromptMap map}.
|
|
73
83
|
*/
|
|
74
84
|
getAllPrompts(): PromptMap;
|
|
85
|
+
/**
|
|
86
|
+
* Retrieve all variant IDs of a given {@link PromptTemplate}.
|
|
87
|
+
* @param id the id of the main {@link PromptTemplate}
|
|
88
|
+
* @returns an array of string IDs representing the variants of the given template
|
|
89
|
+
*/
|
|
90
|
+
getVariantIds(id: string): string[];
|
|
91
|
+
/**
|
|
92
|
+
* Retrieve the currently selected variant ID for a given main prompt ID.
|
|
93
|
+
* If a variant is selected for the main prompt, it will be returned.
|
|
94
|
+
* Otherwise, the main prompt ID will be returned.
|
|
95
|
+
* @param id the id of the main prompt
|
|
96
|
+
* @returns the variant ID if one is selected, or the main prompt ID otherwise
|
|
97
|
+
*/
|
|
98
|
+
getVariantId(id: string): Promise<string>;
|
|
75
99
|
}
|
|
76
100
|
|
|
77
101
|
export interface CustomAgentDescription {
|
|
@@ -112,6 +136,7 @@ export interface PromptCustomizationService {
|
|
|
112
136
|
*/
|
|
113
137
|
getCustomizedPromptTemplate(id: string): string | undefined
|
|
114
138
|
|
|
139
|
+
getCustomPromptTemplateIDs(): string[];
|
|
115
140
|
/**
|
|
116
141
|
* Edit the template. If the content is specified, is will be
|
|
117
142
|
* used to customize the template. Otherwise, the behavior depends
|
|
@@ -158,6 +183,9 @@ export interface PromptCustomizationService {
|
|
|
158
183
|
|
|
159
184
|
@injectable()
|
|
160
185
|
export class PromptServiceImpl implements PromptService {
|
|
186
|
+
@inject(AISettingsService) @optional()
|
|
187
|
+
protected readonly settingsService: AISettingsService | undefined;
|
|
188
|
+
|
|
161
189
|
@inject(PromptCustomizationService) @optional()
|
|
162
190
|
protected readonly customizationService: PromptCustomizationService | undefined;
|
|
163
191
|
|
|
@@ -181,13 +209,44 @@ export class PromptServiceImpl implements PromptService {
|
|
|
181
209
|
getDefaultRawPrompt(id: string): PromptTemplate | undefined {
|
|
182
210
|
return this._prompts[id];
|
|
183
211
|
}
|
|
212
|
+
|
|
213
|
+
getUnresolvedPrompt(id: string): PromptTemplate | undefined {
|
|
214
|
+
const rawPrompt = this.getRawPrompt(id);
|
|
215
|
+
if (!rawPrompt) {
|
|
216
|
+
return undefined;
|
|
217
|
+
}
|
|
218
|
+
return {
|
|
219
|
+
id: rawPrompt.id,
|
|
220
|
+
template: this.stripComments(rawPrompt.template)
|
|
221
|
+
};
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
protected stripComments(template: string): string {
|
|
225
|
+
const commentRegex = /^\s*{{!--[\s\S]*?--}}\s*\n?/;
|
|
226
|
+
return commentRegex.test(template) ? template.replace(commentRegex, '').trimStart() : template;
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
async getVariantId(id: string): Promise<string> {
|
|
230
|
+
if (this.settingsService !== undefined) {
|
|
231
|
+
const agentSettingsMap = await this.settingsService.getSettings();
|
|
232
|
+
|
|
233
|
+
for (const agentSettings of Object.values(agentSettingsMap)) {
|
|
234
|
+
if (agentSettings.selectedVariants && agentSettings.selectedVariants[id]) {
|
|
235
|
+
return agentSettings.selectedVariants[id];
|
|
236
|
+
}
|
|
237
|
+
}
|
|
238
|
+
}
|
|
239
|
+
return id;
|
|
240
|
+
}
|
|
241
|
+
|
|
184
242
|
async getPrompt(id: string, args?: { [key: string]: unknown }): Promise<ResolvedPromptTemplate | undefined> {
|
|
185
|
-
const
|
|
243
|
+
const variantId = await this.getVariantId(id);
|
|
244
|
+
const prompt = this.getUnresolvedPrompt(variantId);
|
|
186
245
|
if (prompt === undefined) {
|
|
187
246
|
return undefined;
|
|
188
247
|
}
|
|
189
248
|
|
|
190
|
-
const matches =
|
|
249
|
+
const matches = matchVariablesRegEx(prompt.template);
|
|
191
250
|
const variableAndArgReplacements = await Promise.all(matches.map(async match => {
|
|
192
251
|
const completeText = match[0];
|
|
193
252
|
const variableAndArg = match[1];
|
|
@@ -207,7 +266,7 @@ export class PromptServiceImpl implements PromptService {
|
|
|
207
266
|
};
|
|
208
267
|
}));
|
|
209
268
|
|
|
210
|
-
const functionMatches =
|
|
269
|
+
const functionMatches = matchFunctionsRegEx(prompt.template);
|
|
211
270
|
const functions = new Map<string, ToolRequest>();
|
|
212
271
|
const functionReplacements = functionMatches.map(match => {
|
|
213
272
|
const completeText = match[0];
|
|
@@ -252,10 +311,24 @@ export class PromptServiceImpl implements PromptService {
|
|
|
252
311
|
return { ...this._prompts };
|
|
253
312
|
}
|
|
254
313
|
}
|
|
255
|
-
storePrompt(id: string, prompt: string): void {
|
|
256
|
-
this._prompts[id] = { id, template: prompt };
|
|
257
|
-
}
|
|
258
314
|
removePrompt(id: string): void {
|
|
259
315
|
delete this._prompts[id];
|
|
260
316
|
}
|
|
317
|
+
getVariantIds(id: string): string[] {
|
|
318
|
+
const allCustomPromptTemplateIds = this.customizationService?.getCustomPromptTemplateIDs() || [];
|
|
319
|
+
const knownPromptIds = Object.keys(this._prompts);
|
|
320
|
+
|
|
321
|
+
// We filter out known IDs from the custom prompt template IDs, these are no variants, but customizations. Then we retain IDs that start with the main ID
|
|
322
|
+
const customVariantIds = allCustomPromptTemplateIds.filter(customId =>
|
|
323
|
+
!knownPromptIds.includes(customId) && customId.startsWith(id)
|
|
324
|
+
);
|
|
325
|
+
const variantIds = Object.values(this._prompts)
|
|
326
|
+
.filter(prompt => prompt.variantOf === id)
|
|
327
|
+
.map(variant => variant.id);
|
|
328
|
+
|
|
329
|
+
return [...variantIds, ...customVariantIds];
|
|
330
|
+
}
|
|
331
|
+
storePromptTemplate(promptTemplate: PromptTemplate): void {
|
|
332
|
+
this._prompts[promptTemplate.id] = promptTemplate;
|
|
333
|
+
}
|
|
261
334
|
}
|
|
@@ -30,4 +30,9 @@ export type AISettings = Record<string, AgentSettings>;
|
|
|
30
30
|
export interface AgentSettings {
|
|
31
31
|
languageModelRequirements?: LanguageModelRequirement[];
|
|
32
32
|
enable?: boolean;
|
|
33
|
+
/**
|
|
34
|
+
* A mapping of main template IDs to their selected variant IDs.
|
|
35
|
+
* If a main template is not present in this mapping, it means the main template is used.
|
|
36
|
+
*/
|
|
37
|
+
selectedVariants?: Record<string, string>;
|
|
33
38
|
}
|