@theia/ai-core 1.59.0 → 1.60.0-next.47
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/lib/browser/agent-preferences.d.ts +4 -0
- package/lib/browser/agent-preferences.d.ts.map +1 -0
- package/lib/browser/agent-preferences.js +74 -0
- package/lib/browser/agent-preferences.js.map +1 -0
- package/lib/browser/ai-activation-service.d.ts +1 -0
- package/lib/browser/ai-activation-service.d.ts.map +1 -1
- package/lib/browser/ai-activation-service.js +12 -2
- package/lib/browser/ai-activation-service.js.map +1 -1
- package/lib/browser/ai-core-command-contribution.d.ts +8 -0
- package/lib/browser/ai-core-command-contribution.d.ts.map +1 -0
- package/lib/browser/ai-core-command-contribution.js +44 -0
- package/lib/browser/ai-core-command-contribution.js.map +1 -0
- package/lib/browser/ai-core-frontend-module.d.ts.map +1 -1
- package/lib/browser/ai-core-frontend-module.js +8 -1
- package/lib/browser/ai-core-frontend-module.js.map +1 -1
- package/lib/browser/index.d.ts +1 -0
- package/lib/browser/index.d.ts.map +1 -1
- package/lib/browser/index.js +1 -0
- package/lib/browser/index.js.map +1 -1
- package/lib/browser/prompttemplate-contribution.d.ts.map +1 -1
- package/lib/browser/prompttemplate-contribution.js +4 -4
- package/lib/browser/prompttemplate-contribution.js.map +1 -1
- package/lib/common/prompt-service.d.ts +42 -1
- package/lib/common/prompt-service.d.ts.map +1 -1
- package/lib/common/prompt-service.js +68 -24
- package/lib/common/prompt-service.js.map +1 -1
- package/lib/common/prompt-service.spec.js +59 -1
- package/lib/common/prompt-service.spec.js.map +1 -1
- package/lib/common/prompt-variable-contribution.d.ts +16 -0
- package/lib/common/prompt-variable-contribution.d.ts.map +1 -0
- package/lib/common/prompt-variable-contribution.js +122 -0
- package/lib/common/prompt-variable-contribution.js.map +1 -0
- package/lib/common/variable-service.d.ts +26 -4
- package/lib/common/variable-service.d.ts.map +1 -1
- package/lib/common/variable-service.js +77 -16
- package/lib/common/variable-service.js.map +1 -1
- package/lib/common/variable-service.spec.d.ts +2 -0
- package/lib/common/variable-service.spec.d.ts.map +1 -0
- package/lib/common/variable-service.spec.js +237 -0
- package/lib/common/variable-service.spec.js.map +1 -0
- package/package.json +9 -9
- package/src/browser/agent-preferences.ts +74 -0
- package/src/browser/ai-activation-service.ts +13 -2
- package/src/browser/ai-core-command-contribution.ts +37 -0
- package/src/browser/ai-core-frontend-module.ts +10 -2
- package/src/browser/ai-settings-service.ts +1 -1
- package/src/browser/index.ts +1 -0
- package/src/browser/prompttemplate-contribution.ts +4 -4
- package/src/common/prompt-service.spec.ts +68 -1
- package/src/common/prompt-service.ts +109 -24
- package/src/common/prompt-variable-contribution.ts +138 -0
- package/src/common/variable-service.spec.ts +289 -0
- package/src/common/variable-service.ts +110 -13
|
@@ -20,6 +20,10 @@ import { expect } from 'chai';
|
|
|
20
20
|
import { Container } from 'inversify';
|
|
21
21
|
import { PromptService, PromptServiceImpl } from './prompt-service';
|
|
22
22
|
import { DefaultAIVariableService, AIVariableService } from './variable-service';
|
|
23
|
+
import { ToolInvocationRegistry } from './tool-invocation-registry';
|
|
24
|
+
import { ToolRequest } from './language-model';
|
|
25
|
+
import { Logger } from '@theia/core';
|
|
26
|
+
import * as sinon from 'sinon';
|
|
23
27
|
|
|
24
28
|
describe('PromptService', () => {
|
|
25
29
|
let promptService: PromptService;
|
|
@@ -27,8 +31,9 @@ describe('PromptService', () => {
|
|
|
27
31
|
beforeEach(() => {
|
|
28
32
|
const container = new Container();
|
|
29
33
|
container.bind<PromptService>(PromptService).to(PromptServiceImpl).inSingletonScope();
|
|
34
|
+
const logger = sinon.createStubInstance(Logger);
|
|
30
35
|
|
|
31
|
-
const variableService = new DefaultAIVariableService({ getContributions: () => [] });
|
|
36
|
+
const variableService = new DefaultAIVariableService({ getContributions: () => [] }, logger);
|
|
32
37
|
const nameVariable = { id: 'test', name: 'name', description: 'Test name ' };
|
|
33
38
|
variableService.registerResolver(nameVariable, {
|
|
34
39
|
canResolve: () => 100,
|
|
@@ -298,4 +303,66 @@ describe('PromptService', () => {
|
|
|
298
303
|
expect(variantsForMainWithVariants).to.deep.equal(['variant1', 'variant2']);
|
|
299
304
|
expect(variantsForMainWithoutVariants).to.deep.equal([]);
|
|
300
305
|
});
|
|
306
|
+
|
|
307
|
+
it('should resolve function references within resolved variable replacements', async () => {
|
|
308
|
+
// Mock the tool invocation registry
|
|
309
|
+
const toolInvocationRegistry = {
|
|
310
|
+
getFunction: sinon.stub()
|
|
311
|
+
};
|
|
312
|
+
|
|
313
|
+
// Create a test tool request that will be returned by the registry
|
|
314
|
+
const testFunction: ToolRequest = {
|
|
315
|
+
id: 'testFunction',
|
|
316
|
+
name: 'Test Function',
|
|
317
|
+
description: 'A test function',
|
|
318
|
+
parameters: {
|
|
319
|
+
type: 'object',
|
|
320
|
+
properties: {
|
|
321
|
+
param1: {
|
|
322
|
+
type: 'string',
|
|
323
|
+
description: 'Test parameter'
|
|
324
|
+
}
|
|
325
|
+
}
|
|
326
|
+
},
|
|
327
|
+
providerName: 'test-provider',
|
|
328
|
+
handler: sinon.stub()
|
|
329
|
+
};
|
|
330
|
+
toolInvocationRegistry.getFunction.withArgs('testFunction').returns(testFunction);
|
|
331
|
+
|
|
332
|
+
// Create a container with our mocked registry
|
|
333
|
+
const container = new Container();
|
|
334
|
+
container.bind<PromptService>(PromptService).to(PromptServiceImpl).inSingletonScope();
|
|
335
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
336
|
+
container.bind<ToolInvocationRegistry>(ToolInvocationRegistry).toConstantValue(toolInvocationRegistry as any);
|
|
337
|
+
|
|
338
|
+
// Set up a variable service that returns a fragment with a function reference
|
|
339
|
+
const variableService = new DefaultAIVariableService({ getContributions: () => [] }, sinon.createStubInstance(Logger));
|
|
340
|
+
const fragmentVariable = { id: 'test', name: 'fragment', description: 'Test fragment with function' };
|
|
341
|
+
variableService.registerResolver(fragmentVariable, {
|
|
342
|
+
canResolve: () => 100,
|
|
343
|
+
resolve: async () => ({
|
|
344
|
+
variable: fragmentVariable,
|
|
345
|
+
value: 'This fragment contains a function reference: ~{testFunction}'
|
|
346
|
+
})
|
|
347
|
+
});
|
|
348
|
+
container.bind<AIVariableService>(AIVariableService).toConstantValue(variableService);
|
|
349
|
+
|
|
350
|
+
const testPromptService = container.get<PromptService>(PromptService);
|
|
351
|
+
testPromptService.storePromptTemplate({ id: 'testPrompt', template: 'Template with fragment: {{fragment}}' });
|
|
352
|
+
|
|
353
|
+
// Get the resolved prompt
|
|
354
|
+
const resolvedPrompt = await testPromptService.getPrompt('testPrompt');
|
|
355
|
+
|
|
356
|
+
// Verify that the function was resolved
|
|
357
|
+
expect(resolvedPrompt).to.not.be.undefined;
|
|
358
|
+
expect(resolvedPrompt?.text).to.include('This fragment contains a function reference:');
|
|
359
|
+
expect(resolvedPrompt?.text).to.not.include('~{testFunction}');
|
|
360
|
+
|
|
361
|
+
// Verify that the function description was added to functionDescriptions
|
|
362
|
+
expect(resolvedPrompt?.functionDescriptions?.size).to.equal(1);
|
|
363
|
+
expect(resolvedPrompt?.functionDescriptions?.get('testFunction')).to.deep.equal(testFunction);
|
|
364
|
+
|
|
365
|
+
// Verify that the tool invocation registry was called
|
|
366
|
+
expect(toolInvocationRegistry.getFunction.calledWith('testFunction')).to.be.true;
|
|
367
|
+
});
|
|
301
368
|
});
|
|
@@ -16,7 +16,7 @@
|
|
|
16
16
|
|
|
17
17
|
import { URI, Event } from '@theia/core';
|
|
18
18
|
import { inject, injectable, optional } from '@theia/core/shared/inversify';
|
|
19
|
-
import { AIVariableContext, AIVariableService } from './variable-service';
|
|
19
|
+
import { AIVariableArg, AIVariableContext, AIVariableService, createAIResolveVariableCache, ResolvedAIVariable } 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';
|
|
@@ -41,6 +41,8 @@ export interface ResolvedPromptTemplate {
|
|
|
41
41
|
text: string;
|
|
42
42
|
/** All functions referenced in the prompt template. */
|
|
43
43
|
functionDescriptions?: Map<string, ToolRequest>;
|
|
44
|
+
/** All variables resolved in the prompt template */
|
|
45
|
+
variables?: ResolvedAIVariable[];
|
|
44
46
|
}
|
|
45
47
|
|
|
46
48
|
export const PromptService = Symbol('PromptService');
|
|
@@ -64,10 +66,34 @@ export interface PromptService {
|
|
|
64
66
|
* Allows to directly replace placeholders in the prompt. The supported format is 'Hi {{name}}!'.
|
|
65
67
|
* The placeholder is then searched inside the args object and replaced.
|
|
66
68
|
* Function references are also supported via format '~{functionId}'.
|
|
69
|
+
*
|
|
70
|
+
* All placeholders are replaced before function references are resolved.
|
|
71
|
+
* This allows to resolve function references contained in placeholders.
|
|
72
|
+
*
|
|
67
73
|
* @param id the id of the prompt
|
|
68
74
|
* @param args the object with placeholders, mapping the placeholder key to the value
|
|
69
75
|
*/
|
|
70
76
|
getPrompt(id: string, args?: { [key: string]: unknown }, context?: AIVariableContext): Promise<ResolvedPromptTemplate | undefined>;
|
|
77
|
+
|
|
78
|
+
/**
|
|
79
|
+
* Allows to directly replace placeholders in the prompt. The supported format is 'Hi {{name}}!'.
|
|
80
|
+
* The placeholder is then searched inside the args object and replaced.
|
|
81
|
+
*
|
|
82
|
+
* In contrast to {@link getPrompt}, this method does not resolve function references but leaves them as is.
|
|
83
|
+
* This allows resolving them later as part of the prompt or chat message containing the fragment.
|
|
84
|
+
*
|
|
85
|
+
* @param id the id of the prompt
|
|
86
|
+
* @param args the object with placeholders, mapping the placeholder key to the value
|
|
87
|
+
* @param context the {@link AIVariableContext} to use during variable resolvement
|
|
88
|
+
* @param resolveVariable the variable resolving method. Fall back to using the {@link AIVariableService} if not given.
|
|
89
|
+
*/
|
|
90
|
+
getPromptFragment(
|
|
91
|
+
id: string,
|
|
92
|
+
args?: { [key: string]: unknown },
|
|
93
|
+
context?: AIVariableContext,
|
|
94
|
+
resolveVariable?: (variable: AIVariableArg) => Promise<ResolvedAIVariable | undefined>
|
|
95
|
+
): Promise<Omit<ResolvedPromptTemplate, 'functionDescriptions'> | undefined>;
|
|
96
|
+
|
|
71
97
|
/**
|
|
72
98
|
* Adds a {@link PromptTemplate} to the list of prompts.
|
|
73
99
|
* @param promptTemplate the prompt template to store
|
|
@@ -246,27 +272,14 @@ export class PromptServiceImpl implements PromptService {
|
|
|
246
272
|
return undefined;
|
|
247
273
|
}
|
|
248
274
|
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
let variableName = variableAndArg;
|
|
254
|
-
let argument: string | undefined;
|
|
255
|
-
const parts = variableAndArg.split(':', 2);
|
|
256
|
-
if (parts.length > 1) {
|
|
257
|
-
variableName = parts[0];
|
|
258
|
-
argument = parts[1];
|
|
259
|
-
}
|
|
260
|
-
return {
|
|
261
|
-
placeholder: completeText,
|
|
262
|
-
value: String(args?.[variableAndArg] ?? (await this.variableService?.resolveVariable({
|
|
263
|
-
variable: variableName,
|
|
264
|
-
arg: argument
|
|
265
|
-
}, context ?? {}))?.value ?? completeText)
|
|
266
|
-
};
|
|
267
|
-
}));
|
|
275
|
+
// First resolve variables and arguments
|
|
276
|
+
let resolvedTemplate = prompt.template;
|
|
277
|
+
const variableAndArgReplacements = await this.getVariableAndArgReplacements(prompt.template, args, context);
|
|
278
|
+
variableAndArgReplacements.replacements.forEach(replacement => resolvedTemplate = resolvedTemplate.replace(replacement.placeholder, replacement.value));
|
|
268
279
|
|
|
269
|
-
|
|
280
|
+
// Then resolve function references with already resolved variables and arguments
|
|
281
|
+
// This allows to resolve function references contained in resolved variables (e.g. prompt fragments)
|
|
282
|
+
const functionMatches = matchFunctionsRegEx(resolvedTemplate);
|
|
270
283
|
const functions = new Map<string, ToolRequest>();
|
|
271
284
|
const functionReplacements = functionMatches.map(match => {
|
|
272
285
|
const completeText = match[0];
|
|
@@ -280,16 +293,88 @@ export class PromptServiceImpl implements PromptService {
|
|
|
280
293
|
value: toolRequest ? toolRequestToPromptText(toolRequest) : completeText
|
|
281
294
|
};
|
|
282
295
|
});
|
|
296
|
+
functionReplacements.forEach(replacement => resolvedTemplate = resolvedTemplate.replace(replacement.placeholder, replacement.value));
|
|
297
|
+
|
|
298
|
+
return {
|
|
299
|
+
id,
|
|
300
|
+
text: resolvedTemplate,
|
|
301
|
+
functionDescriptions: functions.size > 0 ? functions : undefined,
|
|
302
|
+
variables: variableAndArgReplacements.resolvedVariables
|
|
303
|
+
};
|
|
304
|
+
}
|
|
283
305
|
|
|
306
|
+
async getPromptFragment(
|
|
307
|
+
id: string,
|
|
308
|
+
args?: { [key: string]: unknown },
|
|
309
|
+
context?: AIVariableContext,
|
|
310
|
+
resolveVariable?: (variable: AIVariableArg) => Promise<ResolvedAIVariable | undefined>
|
|
311
|
+
): Promise<Omit<ResolvedPromptTemplate, 'functionDescriptions'> | undefined> {
|
|
312
|
+
const variantId = await this.getVariantId(id);
|
|
313
|
+
const prompt = this.getUnresolvedPrompt(variantId);
|
|
314
|
+
if (prompt === undefined) {
|
|
315
|
+
return undefined;
|
|
316
|
+
}
|
|
317
|
+
|
|
318
|
+
const replacements = await this.getVariableAndArgReplacements(prompt.template, args, context, resolveVariable);
|
|
284
319
|
let resolvedTemplate = prompt.template;
|
|
285
|
-
|
|
286
|
-
|
|
320
|
+
replacements.replacements.forEach(replacement => resolvedTemplate = resolvedTemplate.replace(replacement.placeholder, replacement.value));
|
|
321
|
+
|
|
287
322
|
return {
|
|
288
323
|
id,
|
|
289
324
|
text: resolvedTemplate,
|
|
290
|
-
|
|
325
|
+
variables: replacements.resolvedVariables
|
|
291
326
|
};
|
|
292
327
|
}
|
|
328
|
+
|
|
329
|
+
/**
|
|
330
|
+
* Calculates all variable and argument replacements for an unresolved template.
|
|
331
|
+
*
|
|
332
|
+
* @param template the unresolved template text
|
|
333
|
+
* @param args the object with placeholders, mapping the placeholder key to the value
|
|
334
|
+
* @param context the {@link AIVariableContext} to use during variable resolvement
|
|
335
|
+
* @param resolveVariable the variable resolving method. Fall back to using the {@link AIVariableService} if not given.
|
|
336
|
+
*/
|
|
337
|
+
protected async getVariableAndArgReplacements(
|
|
338
|
+
template: string,
|
|
339
|
+
args?: { [key: string]: unknown },
|
|
340
|
+
context?: AIVariableContext,
|
|
341
|
+
resolveVariable?: (variable: AIVariableArg) => Promise<ResolvedAIVariable | undefined>
|
|
342
|
+
): Promise<{ replacements: { placeholder: string; value: string }[], resolvedVariables: ResolvedAIVariable[] }> {
|
|
343
|
+
const matches = matchVariablesRegEx(template);
|
|
344
|
+
const variableCache = createAIResolveVariableCache();
|
|
345
|
+
const variableAndArgReplacements: { placeholder: string; value: string }[] = [];
|
|
346
|
+
const resolvedVariables: Set<ResolvedAIVariable> = new Set();
|
|
347
|
+
for (const match of matches) {
|
|
348
|
+
const completeText = match[0];
|
|
349
|
+
const variableAndArg = match[1];
|
|
350
|
+
let variableName = variableAndArg;
|
|
351
|
+
let argument: string | undefined;
|
|
352
|
+
const parts = variableAndArg.split(':', 2);
|
|
353
|
+
if (parts.length > 1) {
|
|
354
|
+
variableName = parts[0];
|
|
355
|
+
argument = parts[1];
|
|
356
|
+
}
|
|
357
|
+
let value: string;
|
|
358
|
+
if (args && args[variableAndArg] !== undefined) {
|
|
359
|
+
value = String(args[variableAndArg]);
|
|
360
|
+
} else {
|
|
361
|
+
const toResolve = { variable: variableName, arg: argument };
|
|
362
|
+
const resolved = resolveVariable
|
|
363
|
+
? await resolveVariable(toResolve)
|
|
364
|
+
: await this.variableService?.resolveVariable(toResolve, context ?? {}, variableCache);
|
|
365
|
+
// Track resolved variable and its dependencies in all resolved variables
|
|
366
|
+
if (resolved) {
|
|
367
|
+
resolvedVariables.add(resolved);
|
|
368
|
+
resolved.allResolvedDependencies?.forEach(v => resolvedVariables.add(v));
|
|
369
|
+
}
|
|
370
|
+
value = String(resolved?.value ?? completeText);
|
|
371
|
+
}
|
|
372
|
+
variableAndArgReplacements.push({ placeholder: completeText, value });
|
|
373
|
+
}
|
|
374
|
+
|
|
375
|
+
return { replacements: variableAndArgReplacements, resolvedVariables: Array.from(resolvedVariables) };
|
|
376
|
+
}
|
|
377
|
+
|
|
293
378
|
getAllPrompts(): PromptMap {
|
|
294
379
|
if (this.customizationService !== undefined) {
|
|
295
380
|
const myCustomization = this.customizationService;
|
|
@@ -0,0 +1,138 @@
|
|
|
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
|
+
import { CommandService, nls } from '@theia/core';
|
|
17
|
+
import { injectable, inject, optional } from '@theia/core/shared/inversify';
|
|
18
|
+
import * as monaco from '@theia/monaco-editor-core';
|
|
19
|
+
import {
|
|
20
|
+
AIVariable,
|
|
21
|
+
AIVariableContribution,
|
|
22
|
+
AIVariableService,
|
|
23
|
+
AIVariableResolutionRequest,
|
|
24
|
+
AIVariableContext,
|
|
25
|
+
ResolvedAIVariable,
|
|
26
|
+
AIVariableResolverWithVariableDependencies,
|
|
27
|
+
AIVariableArg
|
|
28
|
+
} from './variable-service';
|
|
29
|
+
import { PromptCustomizationService, PromptService } from './prompt-service';
|
|
30
|
+
import { PromptText } from './prompt-text';
|
|
31
|
+
|
|
32
|
+
export const PROMPT_VARIABLE: AIVariable = {
|
|
33
|
+
id: 'prompt-provider',
|
|
34
|
+
description: nls.localize('theia/ai/core/promptVariable/description', 'Resolves prompt templates via the prompt service'),
|
|
35
|
+
name: 'prompt',
|
|
36
|
+
args: [
|
|
37
|
+
{ name: 'id', description: nls.localize('theia/ai/core/promptVariable/argDescription', 'The prompt template id to resolve') }
|
|
38
|
+
]
|
|
39
|
+
};
|
|
40
|
+
|
|
41
|
+
@injectable()
|
|
42
|
+
export class PromptVariableContribution implements AIVariableContribution, AIVariableResolverWithVariableDependencies {
|
|
43
|
+
|
|
44
|
+
@inject(CommandService)
|
|
45
|
+
protected readonly commandService: CommandService;
|
|
46
|
+
|
|
47
|
+
@inject(PromptService)
|
|
48
|
+
protected readonly promptService: PromptService;
|
|
49
|
+
|
|
50
|
+
@inject(PromptCustomizationService) @optional()
|
|
51
|
+
protected readonly promptCustomizationService: PromptCustomizationService;
|
|
52
|
+
|
|
53
|
+
registerVariables(service: AIVariableService): void {
|
|
54
|
+
service.registerResolver(PROMPT_VARIABLE, this);
|
|
55
|
+
service.registerArgumentPicker(PROMPT_VARIABLE, this.triggerArgumentPicker.bind(this));
|
|
56
|
+
service.registerArgumentCompletionProvider(PROMPT_VARIABLE, this.provideArgumentCompletionItems.bind(this));
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
canResolve(request: AIVariableResolutionRequest, context: AIVariableContext): number {
|
|
60
|
+
if (request.variable.name === PROMPT_VARIABLE.name) {
|
|
61
|
+
return 1;
|
|
62
|
+
}
|
|
63
|
+
return -1;
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
async resolve(
|
|
67
|
+
request: AIVariableResolutionRequest,
|
|
68
|
+
context: AIVariableContext,
|
|
69
|
+
resolveDependency?: (variable: AIVariableArg) => Promise<ResolvedAIVariable | undefined>
|
|
70
|
+
): Promise<ResolvedAIVariable | undefined> {
|
|
71
|
+
if (request.variable.name === PROMPT_VARIABLE.name) {
|
|
72
|
+
const promptId = request.arg?.trim();
|
|
73
|
+
if (promptId) {
|
|
74
|
+
const resolvedPrompt = await this.promptService.getPromptFragment(promptId, undefined, context, resolveDependency);
|
|
75
|
+
if (resolvedPrompt) {
|
|
76
|
+
return {
|
|
77
|
+
variable: request.variable,
|
|
78
|
+
value: resolvedPrompt.text,
|
|
79
|
+
allResolvedDependencies: resolvedPrompt.variables
|
|
80
|
+
};
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
return undefined;
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
protected async triggerArgumentPicker(): Promise<string | undefined> {
|
|
88
|
+
// Trigger the suggestion command to show argument completions
|
|
89
|
+
this.commandService.executeCommand('editor.action.triggerSuggest');
|
|
90
|
+
// Return undefined because we don't actually pick the argument here.
|
|
91
|
+
// The argument is selected and inserted by the monaco editor's completion mechanism.
|
|
92
|
+
return undefined;
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
protected async provideArgumentCompletionItems(
|
|
96
|
+
model: monaco.editor.ITextModel,
|
|
97
|
+
position: monaco.Position
|
|
98
|
+
): Promise<monaco.languages.CompletionItem[] | undefined> {
|
|
99
|
+
const lineContent = model.getLineContent(position.lineNumber);
|
|
100
|
+
|
|
101
|
+
// Only provide completions once the variable argument separator is typed
|
|
102
|
+
const triggerCharIndex = lineContent.lastIndexOf(PromptText.VARIABLE_SEPARATOR_CHAR, position.column - 1);
|
|
103
|
+
if (triggerCharIndex === -1) {
|
|
104
|
+
return undefined;
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
// Check if the text immediately before the trigger is the prompt variable, i.e #prompt
|
|
108
|
+
const requiredVariable = `${PromptText.VARIABLE_CHAR}${PROMPT_VARIABLE.name}`;
|
|
109
|
+
if (triggerCharIndex < requiredVariable.length ||
|
|
110
|
+
lineContent.substring(triggerCharIndex - requiredVariable.length, triggerCharIndex) !== requiredVariable) {
|
|
111
|
+
return undefined;
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
const range = new monaco.Range(position.lineNumber, triggerCharIndex + 2, position.lineNumber, position.column);
|
|
115
|
+
|
|
116
|
+
const customPromptIds = this.promptCustomizationService?.getCustomPromptTemplateIDs() ?? [];
|
|
117
|
+
const builtinPromptIds = Object.keys(this.promptService.getAllPrompts());
|
|
118
|
+
|
|
119
|
+
const customPromptCompletions = customPromptIds.map(promptId => ({
|
|
120
|
+
label: promptId,
|
|
121
|
+
kind: monaco.languages.CompletionItemKind.Enum,
|
|
122
|
+
insertText: promptId,
|
|
123
|
+
range,
|
|
124
|
+
detail: nls.localize('theia/ai/core/promptVariable/completions/detail/custom', 'Custom prompt template'),
|
|
125
|
+
sortText: `AAA${promptId}` // Sort before everything else including all built-in prompts
|
|
126
|
+
}));
|
|
127
|
+
const builtinPromptCompletions = builtinPromptIds.map(promptId => ({
|
|
128
|
+
label: promptId,
|
|
129
|
+
kind: monaco.languages.CompletionItemKind.Variable,
|
|
130
|
+
insertText: promptId,
|
|
131
|
+
range,
|
|
132
|
+
detail: nls.localize('theia/ai/core/promptVariable/completions/detail/builtin', 'Built-in prompt template'),
|
|
133
|
+
sortText: `AAB${promptId}` // Sort after all custom prompts but before others
|
|
134
|
+
}));
|
|
135
|
+
|
|
136
|
+
return [...customPromptCompletions, ...builtinPromptCompletions];
|
|
137
|
+
}
|
|
138
|
+
}
|