Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
microsoft
GitHub Repository: microsoft/vscode
Path: blob/main/src/vs/workbench/contrib/chat/browser/defaultModelContribution.ts
13401 views
1
/*---------------------------------------------------------------------------------------------
2
* Copyright (c) Microsoft Corporation. All rights reserved.
3
* Licensed under the MIT License. See License.txt in the project root for license information.
4
*--------------------------------------------------------------------------------------------*/
5
6
import { Disposable } from '../../../../base/common/lifecycle.js';
7
import { localize } from '../../../../nls.js';
8
import { IConfigurationRegistry, Extensions as ConfigurationExtensions } from '../../../../platform/configuration/common/configurationRegistry.js';
9
import { ILogService } from '../../../../platform/log/common/log.js';
10
import { Registry } from '../../../../platform/registry/common/platform.js';
11
import { ILanguageModelChatMetadata, ILanguageModelsService } from '../common/languageModels.js';
12
import { DEFAULT_MODEL_PICKER_CATEGORY } from '../common/widget/input/modelPickerWidget.js';
13
14
const configurationRegistry = Registry.as<IConfigurationRegistry>(ConfigurationExtensions.Configuration);
15
16
export interface DefaultModelArrays {
17
readonly modelIds: string[];
18
readonly modelLabels: string[];
19
readonly modelDescriptions: string[];
20
}
21
22
export interface DefaultModelContributionOptions {
23
/** Configuration key for the setting (used in schema notification). */
24
readonly configKey: string;
25
/** Configuration section id for `notifyConfigurationSchemaUpdated`, or `undefined` to skip notification. */
26
readonly configSectionId: string | undefined;
27
/** Log prefix, e.g. `'[PlanAgentDefaultModel]'`. */
28
readonly logPrefix: string;
29
/** Additional filter beyond `isUserSelectable`. Return `true` to include the model. */
30
readonly filter?: (metadata: ILanguageModelChatMetadata) => boolean;
31
}
32
33
/**
34
* Creates the initial static arrays used by configuration registration code.
35
* The returned arrays are mutated in-place by {@link DefaultModelContribution}.
36
*/
37
export function createDefaultModelArrays(): DefaultModelArrays {
38
return {
39
modelIds: [''],
40
modelLabels: [localize('defaultModel', 'Auto (Vendor Default)')],
41
modelDescriptions: [localize('defaultModelDescription', "Use the vendor's default model")],
42
};
43
}
44
45
/**
46
* Shared base class for workbench contributions that populate a dynamic enum
47
* of language models for a settings picker.
48
*/
49
export abstract class DefaultModelContribution extends Disposable {
50
51
constructor(
52
private readonly _arrays: DefaultModelArrays,
53
private readonly _options: DefaultModelContributionOptions,
54
@ILanguageModelsService private readonly _languageModelsService: ILanguageModelsService,
55
@ILogService private readonly _logService: ILogService,
56
) {
57
super();
58
this._register(_languageModelsService.onDidChangeLanguageModels(() => this._updateModelValues()));
59
this._updateModelValues();
60
}
61
62
private _updateModelValues(): void {
63
const { modelIds, modelLabels, modelDescriptions } = this._arrays;
64
const { configKey, configSectionId, logPrefix, filter } = this._options;
65
66
try {
67
// Clear arrays
68
modelIds.length = 0;
69
modelLabels.length = 0;
70
modelDescriptions.length = 0;
71
72
// Add default/empty option
73
modelIds.push('');
74
modelLabels.push(localize('defaultModel', 'Auto (Vendor Default)'));
75
modelDescriptions.push(localize('defaultModelDescription', "Use the vendor's default model"));
76
77
const models: { identifier: string; metadata: ILanguageModelChatMetadata }[] = [];
78
const allModelIds = this._languageModelsService.getLanguageModelIds();
79
80
for (const modelId of allModelIds) {
81
try {
82
const metadata = this._languageModelsService.lookupLanguageModel(modelId);
83
if (metadata) {
84
models.push({ identifier: modelId, metadata });
85
} else {
86
this._logService.warn(`${logPrefix} No metadata found for model ID: ${modelId}`);
87
}
88
} catch (e) {
89
this._logService.error(`${logPrefix} Error looking up model ${modelId}:`, e);
90
}
91
}
92
93
const supportedModels = models.filter(model => {
94
if (!model.metadata?.isUserSelectable) {
95
return false;
96
}
97
if (filter && !filter(model.metadata)) {
98
return false;
99
}
100
return true;
101
});
102
103
supportedModels.sort((a, b) => {
104
const aCategory = a.metadata.modelPickerCategory ?? DEFAULT_MODEL_PICKER_CATEGORY;
105
const bCategory = b.metadata.modelPickerCategory ?? DEFAULT_MODEL_PICKER_CATEGORY;
106
107
if (aCategory.order !== bCategory.order) {
108
return aCategory.order - bCategory.order;
109
}
110
111
return a.metadata.name.localeCompare(b.metadata.name);
112
});
113
114
for (const model of supportedModels) {
115
try {
116
const qualifiedName = ILanguageModelChatMetadata.asQualifiedName(model.metadata);
117
modelIds.push(qualifiedName);
118
modelLabels.push(model.metadata.name);
119
modelDescriptions.push(model.metadata.tooltip ?? model.metadata.detail ?? '');
120
} catch (e) {
121
this._logService.error(`${logPrefix} Error adding model ${model.metadata.name}:`, e);
122
}
123
}
124
125
if (configSectionId) {
126
configurationRegistry.notifyConfigurationSchemaUpdated({
127
id: configSectionId,
128
properties: {
129
[configKey]: {}
130
}
131
});
132
}
133
} catch (e) {
134
this._logService.error(`${logPrefix} Error updating model values:`, e);
135
}
136
}
137
}
138
139