@theia/ai-core 1.64.0-next.28 → 1.64.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/README.md +3 -0
- package/lib/browser/ai-activation-service.d.ts +22 -9
- package/lib/browser/ai-activation-service.d.ts.map +1 -1
- package/lib/browser/ai-activation-service.js +18 -35
- package/lib/browser/ai-activation-service.js.map +1 -1
- package/lib/browser/ai-core-frontend-module.d.ts.map +1 -1
- package/lib/browser/ai-core-frontend-module.js +9 -4
- package/lib/browser/ai-core-frontend-module.js.map +1 -1
- package/lib/browser/ai-core-preferences.d.ts +1 -2
- package/lib/browser/ai-core-preferences.d.ts.map +1 -1
- package/lib/browser/ai-core-preferences.js +25 -20
- package/lib/browser/ai-core-preferences.js.map +1 -1
- package/lib/browser/ai-settings-service.d.ts +3 -1
- package/lib/browser/ai-settings-service.d.ts.map +1 -1
- package/lib/browser/ai-settings-service.js +24 -2
- package/lib/browser/ai-settings-service.js.map +1 -1
- package/lib/browser/ai-view-contribution.js +1 -1
- package/lib/browser/ai-view-contribution.js.map +1 -1
- package/lib/browser/frontend-language-model-alias-registry.d.ts +31 -0
- package/lib/browser/frontend-language-model-alias-registry.d.ts.map +1 -0
- package/lib/browser/frontend-language-model-alias-registry.js +170 -0
- package/lib/browser/frontend-language-model-alias-registry.js.map +1 -0
- package/lib/browser/frontend-language-model-registry.d.ts +11 -4
- package/lib/browser/frontend-language-model-registry.d.ts.map +1 -1
- package/lib/browser/frontend-language-model-registry.js +48 -6
- package/lib/browser/frontend-language-model-registry.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/common/index.d.ts +1 -0
- package/lib/common/index.d.ts.map +1 -1
- package/lib/common/index.js +1 -0
- package/lib/common/index.js.map +1 -1
- package/lib/common/language-model-alias.d.ts +58 -0
- package/lib/common/language-model-alias.d.ts.map +1 -0
- package/lib/common/language-model-alias.js +20 -0
- package/lib/common/language-model-alias.js.map +1 -0
- package/lib/common/language-model.d.ts +24 -2
- package/lib/common/language-model.d.ts.map +1 -1
- package/lib/common/language-model.js +15 -3
- package/lib/common/language-model.js.map +1 -1
- package/lib/common/prompt-service.d.ts +19 -9
- package/lib/common/prompt-service.d.ts.map +1 -1
- package/lib/common/prompt-service.js +77 -31
- package/lib/common/prompt-service.js.map +1 -1
- package/lib/common/protocol.d.ts +4 -0
- package/lib/common/protocol.d.ts.map +1 -1
- package/lib/common/protocol.js.map +1 -1
- package/lib/node/ai-core-backend-module.js +2 -2
- package/lib/node/ai-core-backend-module.js.map +1 -1
- package/lib/node/backend-language-model-registry.d.ts +2 -1
- package/lib/node/backend-language-model-registry.d.ts.map +1 -1
- package/lib/node/backend-language-model-registry.js +12 -5
- package/lib/node/backend-language-model-registry.js.map +1 -1
- package/lib/node/language-model-frontend-delegate.d.ts.map +1 -1
- package/lib/node/language-model-frontend-delegate.js +1 -1
- package/lib/node/language-model-frontend-delegate.js.map +1 -1
- package/package.json +10 -10
- package/src/browser/ai-activation-service.ts +26 -34
- package/src/browser/ai-core-frontend-module.ts +16 -8
- package/src/browser/ai-core-preferences.ts +28 -21
- package/src/browser/ai-settings-service.ts +23 -4
- package/src/browser/frontend-language-model-alias-registry.ts +166 -0
- package/src/browser/frontend-language-model-registry.ts +53 -9
- package/src/browser/index.ts +1 -0
- package/src/common/index.ts +1 -0
- package/src/common/language-model-alias.ts +76 -0
- package/src/common/language-model.ts +42 -4
- package/src/common/prompt-service.ts +91 -37
- package/src/common/protocol.ts +4 -0
- package/src/node/ai-core-backend-module.ts +3 -3
- package/src/node/backend-language-model-registry.ts +9 -1
- package/src/node/language-model-frontend-delegate.ts +2 -2
package/src/browser/index.ts
CHANGED
|
@@ -25,6 +25,7 @@ export * from './ai-core-preferences';
|
|
|
25
25
|
export * from './ai-settings-service';
|
|
26
26
|
export * from './ai-view-contribution';
|
|
27
27
|
export * from './frontend-language-model-registry';
|
|
28
|
+
export * from './frontend-language-model-alias-registry';
|
|
28
29
|
export * from './frontend-variable-service';
|
|
29
30
|
export * from './prompttemplate-contribution';
|
|
30
31
|
export * from './theia-variable-contribution';
|
package/src/common/index.ts
CHANGED
|
@@ -20,6 +20,7 @@ export * from './tool-invocation-registry';
|
|
|
20
20
|
export * from './language-model-delegate';
|
|
21
21
|
export * from './language-model-util';
|
|
22
22
|
export * from './language-model';
|
|
23
|
+
export * from './language-model-alias';
|
|
23
24
|
export * from './prompt-service';
|
|
24
25
|
export * from './prompt-service-util';
|
|
25
26
|
export * from './prompt-text';
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
// *****************************************************************************
|
|
2
|
+
// Copyright (C) 2024-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 { Event } from '@theia/core';
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
* Represents an alias for a language model, allowing fallback and selection.
|
|
21
|
+
*/
|
|
22
|
+
export interface LanguageModelAlias {
|
|
23
|
+
/**
|
|
24
|
+
* The unique identifier for the alias.
|
|
25
|
+
*/
|
|
26
|
+
id: string;
|
|
27
|
+
/**
|
|
28
|
+
* The list of default model IDs to use if no selectedModelId is set.
|
|
29
|
+
* Ordered by priority. The first entry also serves as fallback.
|
|
30
|
+
*/
|
|
31
|
+
defaultModelIds: string[];
|
|
32
|
+
/**
|
|
33
|
+
* A human-readable description of the alias.
|
|
34
|
+
*/
|
|
35
|
+
description?: string;
|
|
36
|
+
/**
|
|
37
|
+
* The currently selected model ID, if any.
|
|
38
|
+
*/
|
|
39
|
+
selectedModelId?: string;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
export const LanguageModelAliasRegistry = Symbol('LanguageModelAliasRegistry');
|
|
43
|
+
/**
|
|
44
|
+
* Registry for managing language model aliases.
|
|
45
|
+
*/
|
|
46
|
+
export interface LanguageModelAliasRegistry {
|
|
47
|
+
/**
|
|
48
|
+
* Promise that resolves when the registry is ready for use (preferences loaded).
|
|
49
|
+
*/
|
|
50
|
+
ready: Promise<void>;
|
|
51
|
+
|
|
52
|
+
/**
|
|
53
|
+
* Event that is fired when the alias list changes.
|
|
54
|
+
*/
|
|
55
|
+
onDidChange: Event<void>;
|
|
56
|
+
/**
|
|
57
|
+
* Add a new alias or update an existing one.
|
|
58
|
+
*/
|
|
59
|
+
addAlias(alias: LanguageModelAlias): void;
|
|
60
|
+
/**
|
|
61
|
+
* Remove an alias by its id.
|
|
62
|
+
*/
|
|
63
|
+
removeAlias(id: string): void;
|
|
64
|
+
/**
|
|
65
|
+
* Get all aliases.
|
|
66
|
+
*/
|
|
67
|
+
getAliases(): LanguageModelAlias[];
|
|
68
|
+
/**
|
|
69
|
+
* Resolve an alias or model id to a prioritized list of model ids.
|
|
70
|
+
* If the id is not an alias, returns [id].
|
|
71
|
+
* If the alias exists and has a selectedModelId, returns [selectedModelId].
|
|
72
|
+
* If the alias exists and has no selectedModelId, returns defaultModelIds.
|
|
73
|
+
* If the alias does not exist, returns undefined.
|
|
74
|
+
*/
|
|
75
|
+
resolveAlias(id: string): string[] | undefined;
|
|
76
|
+
}
|
|
@@ -295,6 +295,7 @@ export interface LanguageModelMetaData {
|
|
|
295
295
|
readonly family?: string;
|
|
296
296
|
readonly maxInputTokens?: number;
|
|
297
297
|
readonly maxOutputTokens?: number;
|
|
298
|
+
readonly status: LanguageModelStatus;
|
|
298
299
|
}
|
|
299
300
|
|
|
300
301
|
export namespace LanguageModelMetaData {
|
|
@@ -303,6 +304,11 @@ export namespace LanguageModelMetaData {
|
|
|
303
304
|
}
|
|
304
305
|
}
|
|
305
306
|
|
|
307
|
+
export interface LanguageModelStatus {
|
|
308
|
+
status: 'ready' | 'unavailable';
|
|
309
|
+
message?: string;
|
|
310
|
+
}
|
|
311
|
+
|
|
306
312
|
export interface LanguageModel extends LanguageModelMetaData {
|
|
307
313
|
request(request: UserRequest, cancellationToken?: CancellationToken): Promise<LanguageModelResponse>;
|
|
308
314
|
}
|
|
@@ -331,6 +337,10 @@ export interface LanguageModelSelector extends VsCodeLanguageModelSelector {
|
|
|
331
337
|
export type LanguageModelRequirement = Omit<LanguageModelSelector, 'agent'>;
|
|
332
338
|
|
|
333
339
|
export const LanguageModelRegistry = Symbol('LanguageModelRegistry');
|
|
340
|
+
|
|
341
|
+
/**
|
|
342
|
+
* Base interface for language model registries (frontend and backend).
|
|
343
|
+
*/
|
|
334
344
|
export interface LanguageModelRegistry {
|
|
335
345
|
onChange: Event<{ models: LanguageModel[] }>;
|
|
336
346
|
addLanguageModels(models: LanguageModel[]): void;
|
|
@@ -338,7 +348,22 @@ export interface LanguageModelRegistry {
|
|
|
338
348
|
getLanguageModel(id: string): Promise<LanguageModel | undefined>;
|
|
339
349
|
removeLanguageModels(id: string[]): void;
|
|
340
350
|
selectLanguageModel(request: LanguageModelSelector): Promise<LanguageModel | undefined>;
|
|
341
|
-
selectLanguageModels(request: LanguageModelSelector): Promise<LanguageModel[]>;
|
|
351
|
+
selectLanguageModels(request: LanguageModelSelector): Promise<LanguageModel[] | undefined>;
|
|
352
|
+
patchLanguageModel<T extends LanguageModel = LanguageModel>(id: string, patch: Partial<T>): Promise<void>;
|
|
353
|
+
}
|
|
354
|
+
|
|
355
|
+
export const FrontendLanguageModelRegistry = Symbol('FrontendLanguageModelRegistry');
|
|
356
|
+
|
|
357
|
+
/**
|
|
358
|
+
* Frontend-specific language model registry interface (supports alias resolution).
|
|
359
|
+
*/
|
|
360
|
+
export interface FrontendLanguageModelRegistry extends LanguageModelRegistry {
|
|
361
|
+
/**
|
|
362
|
+
* If an id of a language model is provded, returns the LanguageModel if it is `ready`.
|
|
363
|
+
* If an alias is provided, finds the highest-priority ready model from that alias.
|
|
364
|
+
* If none are ready returns undefined.
|
|
365
|
+
*/
|
|
366
|
+
getReadyLanguageModel(idOrAlias: string): Promise<LanguageModel | undefined>;
|
|
342
367
|
}
|
|
343
368
|
|
|
344
369
|
@injectable()
|
|
@@ -405,15 +430,28 @@ export class DefaultLanguageModelRegistryImpl implements LanguageModelRegistry {
|
|
|
405
430
|
});
|
|
406
431
|
}
|
|
407
432
|
|
|
408
|
-
async selectLanguageModels(request: LanguageModelSelector): Promise<LanguageModel[]> {
|
|
433
|
+
async selectLanguageModels(request: LanguageModelSelector): Promise<LanguageModel[] | undefined> {
|
|
409
434
|
await this.initialized;
|
|
410
435
|
// TODO check for actor and purpose against settings
|
|
411
|
-
return this.languageModels.filter(model => isModelMatching(request, model));
|
|
436
|
+
return this.languageModels.filter(model => model.status.status === 'ready' && isModelMatching(request, model));
|
|
412
437
|
}
|
|
413
438
|
|
|
414
439
|
async selectLanguageModel(request: LanguageModelSelector): Promise<LanguageModel | undefined> {
|
|
415
|
-
|
|
440
|
+
const models = await this.selectLanguageModels(request);
|
|
441
|
+
return models ? models[0] : undefined;
|
|
442
|
+
}
|
|
443
|
+
|
|
444
|
+
async patchLanguageModel<T extends LanguageModel = LanguageModel>(id: string, patch: Partial<T>): Promise<void> {
|
|
445
|
+
await this.initialized;
|
|
446
|
+
const model = this.languageModels.find(m => m.id === id);
|
|
447
|
+
if (!model) {
|
|
448
|
+
this.logger.warn(`Language model with id ${id} not found for patch.`);
|
|
449
|
+
return;
|
|
450
|
+
}
|
|
451
|
+
Object.assign(model, patch);
|
|
452
|
+
this.changeEmitter.fire({ models: this.languageModels });
|
|
416
453
|
}
|
|
454
|
+
|
|
417
455
|
}
|
|
418
456
|
|
|
419
457
|
export function isModelMatching(request: LanguageModelSelector, model: LanguageModel): boolean {
|
|
@@ -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 { Event, Emitter, URI, ILogger } from '@theia/core';
|
|
17
|
+
import { Event, Emitter, URI, ILogger, DisposableCollection } from '@theia/core';
|
|
18
18
|
import { inject, injectable, optional, postConstruct } from '@theia/core/shared/inversify';
|
|
19
19
|
import { AIVariableArg, AIVariableContext, AIVariableService, createAIResolveVariableCache, ResolvedAIVariable } from './variable-service';
|
|
20
20
|
import { ToolInvocationRegistry } from './tool-invocation-registry';
|
|
@@ -283,7 +283,7 @@ export interface PromptService {
|
|
|
283
283
|
/**
|
|
284
284
|
* Event fired when the selected variant for a prompt variant set changes
|
|
285
285
|
*/
|
|
286
|
-
readonly onSelectedVariantChange: Event<{ promptVariantSetId: string, variantId: string }>;
|
|
286
|
+
readonly onSelectedVariantChange: Event<{ promptVariantSetId: string, variantId: string | undefined }>;
|
|
287
287
|
|
|
288
288
|
/**
|
|
289
289
|
* Gets the raw prompt fragment with comments
|
|
@@ -368,7 +368,7 @@ export interface PromptService {
|
|
|
368
368
|
* @param promptVariantSetId The prompt variant set id
|
|
369
369
|
* @returns The selected variant ID from settings, or undefined if none is selected
|
|
370
370
|
*/
|
|
371
|
-
getSelectedVariantId(promptVariantSetId: string):
|
|
371
|
+
getSelectedVariantId(promptVariantSetId: string): string | undefined;
|
|
372
372
|
|
|
373
373
|
/**
|
|
374
374
|
* Gets the effective variant ID that is guaranteed to be valid if one exists.
|
|
@@ -376,7 +376,7 @@ export interface PromptService {
|
|
|
376
376
|
* @param promptVariantSetId The prompt variant set id
|
|
377
377
|
* @returns A valid variant ID if one exists, or undefined if no valid variant can be found
|
|
378
378
|
*/
|
|
379
|
-
getEffectiveVariantId(promptVariantSetId: string):
|
|
379
|
+
getEffectiveVariantId(promptVariantSetId: string): string | undefined;
|
|
380
380
|
|
|
381
381
|
/**
|
|
382
382
|
* Gets the default variant ID of the given set
|
|
@@ -419,12 +419,16 @@ export interface PromptService {
|
|
|
419
419
|
export class PromptServiceImpl implements PromptService {
|
|
420
420
|
@inject(ILogger)
|
|
421
421
|
protected readonly logger: ILogger;
|
|
422
|
+
|
|
422
423
|
@inject(AISettingsService) @optional()
|
|
423
424
|
protected readonly settingsService: AISettingsService | undefined;
|
|
424
425
|
|
|
425
426
|
@inject(PromptFragmentCustomizationService) @optional()
|
|
426
427
|
protected readonly customizationService: PromptFragmentCustomizationService | undefined;
|
|
427
428
|
|
|
429
|
+
// Map to store selected variant for each prompt variant set (key: promptVariantSetId, value: variantId)
|
|
430
|
+
protected _selectedVariantsMap = new Map<string, string>();
|
|
431
|
+
|
|
428
432
|
@inject(AIVariableService) @optional()
|
|
429
433
|
protected readonly variableService: AIVariableService | undefined;
|
|
430
434
|
|
|
@@ -445,21 +449,80 @@ export class PromptServiceImpl implements PromptService {
|
|
|
445
449
|
readonly onPromptsChange = this._onPromptsChangeEmitter.event;
|
|
446
450
|
|
|
447
451
|
// Event emitter for selected variant changes
|
|
448
|
-
protected _onSelectedVariantChangeEmitter = new Emitter<{ promptVariantSetId: string, variantId: string }>();
|
|
452
|
+
protected _onSelectedVariantChangeEmitter = new Emitter<{ promptVariantSetId: string, variantId: string | undefined }>();
|
|
449
453
|
readonly onSelectedVariantChange = this._onSelectedVariantChangeEmitter.event;
|
|
450
454
|
|
|
455
|
+
protected promptChangeDebounceTimer?: NodeJS.Timeout;
|
|
456
|
+
|
|
457
|
+
protected toDispose = new DisposableCollection();
|
|
458
|
+
|
|
459
|
+
protected fireOnPromptsChangeDebounced(): void {
|
|
460
|
+
if (this.promptChangeDebounceTimer) {
|
|
461
|
+
clearTimeout(this.promptChangeDebounceTimer);
|
|
462
|
+
}
|
|
463
|
+
this.promptChangeDebounceTimer = setTimeout(() => {
|
|
464
|
+
this._onPromptsChangeEmitter.fire();
|
|
465
|
+
}, 300);
|
|
466
|
+
}
|
|
467
|
+
|
|
451
468
|
@postConstruct()
|
|
452
469
|
protected init(): void {
|
|
453
470
|
if (this.customizationService) {
|
|
454
|
-
this.
|
|
455
|
-
this.
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
this.
|
|
459
|
-
|
|
471
|
+
this.toDispose.pushAll([
|
|
472
|
+
this.customizationService.onDidChangePromptFragmentCustomization(() => {
|
|
473
|
+
this.fireOnPromptsChangeDebounced();
|
|
474
|
+
}),
|
|
475
|
+
this.customizationService.onDidChangeCustomAgents(() => {
|
|
476
|
+
this.fireOnPromptsChangeDebounced();
|
|
477
|
+
})
|
|
478
|
+
]);
|
|
479
|
+
}
|
|
480
|
+
if (this.settingsService) {
|
|
481
|
+
this.recalculateSelectedVariantsMap();
|
|
482
|
+
this.toDispose.push(
|
|
483
|
+
this.settingsService!.onDidChange(async () => {
|
|
484
|
+
await this.recalculateSelectedVariantsMap();
|
|
485
|
+
})
|
|
486
|
+
);
|
|
460
487
|
}
|
|
461
488
|
}
|
|
462
489
|
|
|
490
|
+
/**
|
|
491
|
+
* Recalculates the selected variants map for all variant sets and fires the onSelectedVariantChangeEmitter
|
|
492
|
+
* if the selectedVariants field has changed.
|
|
493
|
+
*/
|
|
494
|
+
protected async recalculateSelectedVariantsMap(): Promise<void> {
|
|
495
|
+
if (!this.settingsService) {
|
|
496
|
+
return;
|
|
497
|
+
}
|
|
498
|
+
const agentSettingsMap = await this.settingsService.getSettings();
|
|
499
|
+
const newSelectedVariants = new Map<string, string>();
|
|
500
|
+
for (const agentSettings of Object.values(agentSettingsMap)) {
|
|
501
|
+
if (agentSettings.selectedVariants) {
|
|
502
|
+
for (const [variantSetId, variantId] of Object.entries(agentSettings.selectedVariants)) {
|
|
503
|
+
if (!newSelectedVariants.has(variantSetId)) {
|
|
504
|
+
newSelectedVariants.set(variantSetId, variantId);
|
|
505
|
+
}
|
|
506
|
+
}
|
|
507
|
+
}
|
|
508
|
+
}
|
|
509
|
+
// Compare with the old map and fire events for changes and removed variant sets
|
|
510
|
+
for (const [variantSetId, newVariantId] of newSelectedVariants.entries()) {
|
|
511
|
+
const oldVariantId = this._selectedVariantsMap.get(variantSetId);
|
|
512
|
+
if (oldVariantId !== newVariantId) {
|
|
513
|
+
this._onSelectedVariantChangeEmitter.fire({ promptVariantSetId: variantSetId, variantId: newVariantId });
|
|
514
|
+
}
|
|
515
|
+
}
|
|
516
|
+
for (const oldVariantSetId of this._selectedVariantsMap.keys()) {
|
|
517
|
+
if (!newSelectedVariants.has(oldVariantSetId)) {
|
|
518
|
+
this._onSelectedVariantChangeEmitter.fire({ promptVariantSetId: oldVariantSetId, variantId: undefined });
|
|
519
|
+
}
|
|
520
|
+
}
|
|
521
|
+
this._selectedVariantsMap = newSelectedVariants;
|
|
522
|
+
// Also fire a full prompts change, because other fields (like effectiveVariantId) might have changed
|
|
523
|
+
this.fireOnPromptsChangeDebounced();
|
|
524
|
+
}
|
|
525
|
+
|
|
463
526
|
// ===== Fragment Retrieval Methods =====
|
|
464
527
|
|
|
465
528
|
/**
|
|
@@ -506,54 +569,45 @@ export class PromptServiceImpl implements PromptService {
|
|
|
506
569
|
return commentRegex.test(templateText) ? templateText.replace(commentRegex, '').trimStart() : templateText;
|
|
507
570
|
}
|
|
508
571
|
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
const agentSettingsMap = await this.settingsService.getSettings();
|
|
512
|
-
|
|
513
|
-
for (const agentSettings of Object.values(agentSettingsMap)) {
|
|
514
|
-
if (agentSettings.selectedVariants && agentSettings.selectedVariants[fragmentId]) {
|
|
515
|
-
return agentSettings.selectedVariants[fragmentId];
|
|
516
|
-
}
|
|
517
|
-
}
|
|
518
|
-
}
|
|
519
|
-
return undefined;
|
|
572
|
+
getSelectedVariantId(variantSetId: string): string | undefined {
|
|
573
|
+
return this._selectedVariantsMap.get(variantSetId);
|
|
520
574
|
}
|
|
521
575
|
|
|
522
|
-
|
|
523
|
-
const selectedVariantId =
|
|
576
|
+
getEffectiveVariantId(variantSetId: string): string | undefined {
|
|
577
|
+
const selectedVariantId = this.getSelectedVariantId(variantSetId);
|
|
524
578
|
|
|
525
579
|
// Check if the selected variant actually exists
|
|
526
580
|
if (selectedVariantId) {
|
|
527
|
-
const variantIds = this.getVariantIds(
|
|
581
|
+
const variantIds = this.getVariantIds(variantSetId);
|
|
528
582
|
if (!variantIds.includes(selectedVariantId)) {
|
|
529
|
-
this.logger.warn(`Selected variant '${selectedVariantId}' for prompt set '${
|
|
583
|
+
this.logger.warn(`Selected variant '${selectedVariantId}' for prompt set '${variantSetId}' does not exist. Falling back to default variant.`);
|
|
530
584
|
} else {
|
|
531
585
|
return selectedVariantId;
|
|
532
586
|
}
|
|
533
587
|
}
|
|
534
588
|
|
|
535
589
|
// Fall back to default variant
|
|
536
|
-
const defaultVariantId = this.getDefaultVariantId(
|
|
590
|
+
const defaultVariantId = this.getDefaultVariantId(variantSetId);
|
|
537
591
|
if (defaultVariantId) {
|
|
538
|
-
const variantIds = this.getVariantIds(
|
|
592
|
+
const variantIds = this.getVariantIds(variantSetId);
|
|
539
593
|
if (!variantIds.includes(defaultVariantId)) {
|
|
540
|
-
this.logger.error(`Default variant '${defaultVariantId}' for prompt set '${
|
|
594
|
+
this.logger.error(`Default variant '${defaultVariantId}' for prompt set '${variantSetId}' does not exist.`);
|
|
541
595
|
return undefined;
|
|
542
596
|
}
|
|
543
597
|
return defaultVariantId;
|
|
544
598
|
}
|
|
545
599
|
|
|
546
600
|
// No valid selected or default variant
|
|
547
|
-
if (this.getVariantIds(
|
|
548
|
-
this.logger.error(`No valid selected or default variant found for prompt set '${
|
|
601
|
+
if (this.getVariantIds(variantSetId).length > 0) {
|
|
602
|
+
this.logger.error(`No valid selected or default variant found for prompt set '${variantSetId}'.`);
|
|
549
603
|
}
|
|
550
604
|
return undefined;
|
|
551
605
|
}
|
|
552
606
|
|
|
553
|
-
protected
|
|
607
|
+
protected resolvePotentialSystemPrompt(promptFragmentId: string): PromptFragment | undefined {
|
|
554
608
|
if (this._promptVariantSetsMap.has(promptFragmentId)) {
|
|
555
609
|
// This is a systemPrompt find the effective variant
|
|
556
|
-
const effectiveVariantId =
|
|
610
|
+
const effectiveVariantId = this.getEffectiveVariantId(promptFragmentId);
|
|
557
611
|
if (effectiveVariantId === undefined) {
|
|
558
612
|
return undefined;
|
|
559
613
|
}
|
|
@@ -565,7 +619,7 @@ export class PromptServiceImpl implements PromptService {
|
|
|
565
619
|
// ===== Fragment Resolution Methods =====
|
|
566
620
|
|
|
567
621
|
async getResolvedPromptFragment(systemOrFragmentId: string, args?: { [key: string]: unknown }, context?: AIVariableContext): Promise<ResolvedPromptFragment | undefined> {
|
|
568
|
-
const promptFragment =
|
|
622
|
+
const promptFragment = this.resolvePotentialSystemPrompt(systemOrFragmentId);
|
|
569
623
|
if (promptFragment === undefined) {
|
|
570
624
|
return undefined;
|
|
571
625
|
}
|
|
@@ -609,7 +663,7 @@ export class PromptServiceImpl implements PromptService {
|
|
|
609
663
|
context?: AIVariableContext,
|
|
610
664
|
resolveVariable?: (variable: AIVariableArg) => Promise<ResolvedAIVariable | undefined>
|
|
611
665
|
): Promise<Omit<ResolvedPromptFragment, 'functionDescriptions'> | undefined> {
|
|
612
|
-
const promptFragment =
|
|
666
|
+
const promptFragment = this.resolvePotentialSystemPrompt(systemOrFragmentId);
|
|
613
667
|
if (promptFragment === undefined) {
|
|
614
668
|
return undefined;
|
|
615
669
|
}
|
|
@@ -764,7 +818,7 @@ export class PromptServiceImpl implements PromptService {
|
|
|
764
818
|
}
|
|
765
819
|
}
|
|
766
820
|
|
|
767
|
-
this.
|
|
821
|
+
this.fireOnPromptsChangeDebounced();
|
|
768
822
|
}
|
|
769
823
|
|
|
770
824
|
getVariantIds(variantSetId: string): string[] {
|
|
@@ -839,7 +893,7 @@ export class PromptServiceImpl implements PromptService {
|
|
|
839
893
|
this.addFragmentVariant(promptVariantSetId, promptFragment.id, isDefault);
|
|
840
894
|
}
|
|
841
895
|
|
|
842
|
-
this.
|
|
896
|
+
this.fireOnPromptsChangeDebounced();
|
|
843
897
|
}
|
|
844
898
|
|
|
845
899
|
// ===== Variant Management Methods =====
|
package/src/common/protocol.ts
CHANGED
|
@@ -22,6 +22,10 @@ export const LanguageModelRegistryClient = Symbol('LanguageModelRegistryClient')
|
|
|
22
22
|
export interface LanguageModelRegistryClient {
|
|
23
23
|
languageModelAdded(metadata: LanguageModelMetaData): void;
|
|
24
24
|
languageModelRemoved(id: string): void;
|
|
25
|
+
/**
|
|
26
|
+
* Notify the client that a language model was updated.
|
|
27
|
+
*/
|
|
28
|
+
onLanguageModelUpdated(id: string): void;
|
|
25
29
|
}
|
|
26
30
|
|
|
27
31
|
export const TOKEN_USAGE_SERVICE_PATH = '/services/token-usage';
|
|
@@ -41,14 +41,14 @@ import {
|
|
|
41
41
|
TokenUsageServiceClient,
|
|
42
42
|
TOKEN_USAGE_SERVICE_PATH
|
|
43
43
|
} from '../common';
|
|
44
|
-
import {
|
|
44
|
+
import { BackendLanguageModelRegistryImpl } from './backend-language-model-registry';
|
|
45
45
|
import { TokenUsageServiceImpl } from './token-usage-service-impl';
|
|
46
46
|
|
|
47
47
|
// We use a connection module to handle AI services separately for each frontend.
|
|
48
48
|
const aiCoreConnectionModule = ConnectionContainerModule.create(({ bind, bindBackendService, bindFrontendService }) => {
|
|
49
49
|
bindContributionProvider(bind, LanguageModelProvider);
|
|
50
|
-
bind(
|
|
51
|
-
bind(LanguageModelRegistry).toService(
|
|
50
|
+
bind(BackendLanguageModelRegistryImpl).toSelf().inSingletonScope();
|
|
51
|
+
bind(LanguageModelRegistry).toService(BackendLanguageModelRegistryImpl);
|
|
52
52
|
|
|
53
53
|
bind(TokenUsageService).to(TokenUsageServiceImpl).inSingletonScope();
|
|
54
54
|
|
|
@@ -21,7 +21,7 @@ import { DefaultLanguageModelRegistryImpl, LanguageModel, LanguageModelMetaData,
|
|
|
21
21
|
* Notifies a client whenever a model is added or removed
|
|
22
22
|
*/
|
|
23
23
|
@injectable()
|
|
24
|
-
export class
|
|
24
|
+
export class BackendLanguageModelRegistryImpl extends DefaultLanguageModelRegistryImpl {
|
|
25
25
|
|
|
26
26
|
private client: LanguageModelRegistryClient | undefined;
|
|
27
27
|
|
|
@@ -45,10 +45,18 @@ export class BackendLanguageModelRegistry extends DefaultLanguageModelRegistryIm
|
|
|
45
45
|
}
|
|
46
46
|
}
|
|
47
47
|
|
|
48
|
+
override async patchLanguageModel<T extends LanguageModel = LanguageModel>(id: string, patch: Partial<T>): Promise<void> {
|
|
49
|
+
await super.patchLanguageModel(id, patch);
|
|
50
|
+
if (this.client) {
|
|
51
|
+
this.client.onLanguageModelUpdated(id);
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
|
|
48
55
|
mapToMetaData(model: LanguageModel): LanguageModelMetaData {
|
|
49
56
|
return {
|
|
50
57
|
id: model.id,
|
|
51
58
|
name: model.name,
|
|
59
|
+
status: model.status,
|
|
52
60
|
vendor: model.vendor,
|
|
53
61
|
version: model.version,
|
|
54
62
|
family: model.family,
|
|
@@ -30,13 +30,13 @@ import {
|
|
|
30
30
|
isLanguageModelParsedResponse,
|
|
31
31
|
UserRequest,
|
|
32
32
|
} from '../common';
|
|
33
|
-
import {
|
|
33
|
+
import { BackendLanguageModelRegistryImpl } from './backend-language-model-registry';
|
|
34
34
|
|
|
35
35
|
@injectable()
|
|
36
36
|
export class LanguageModelRegistryFrontendDelegateImpl implements LanguageModelRegistryFrontendDelegate {
|
|
37
37
|
|
|
38
38
|
@inject(LanguageModelRegistry)
|
|
39
|
-
private registry:
|
|
39
|
+
private registry: BackendLanguageModelRegistryImpl;
|
|
40
40
|
|
|
41
41
|
setClient(client: LanguageModelRegistryClient): void {
|
|
42
42
|
this.registry.setClient(client);
|