Sandy081/forward-amphibian (#290292)

* Enhance language models configuration to support snippets and options

* handle ^ prefix
This commit is contained in:
Sandeep Somavarapu
2026-01-25 22:15:39 +01:00
committed by GitHub
parent cc0ced7949
commit 301f5e8acf
3 changed files with 54 additions and 9 deletions

View File

@@ -20,7 +20,8 @@ import { ITextModel } from '../../../../editor/common/model.js';
import { ITextModelService } from '../../../../editor/common/services/resolverService.js';
import { ITextFileService } from '../../../services/textfile/common/textfiles.js';
import { getCodeEditor } from '../../../../editor/browser/editorBrowser.js';
import { ILanguageModelsConfigurationService, ILanguageModelsProviderGroup } from '../common/languageModelsConfiguration.js';
import { SnippetController2 } from '../../../../editor/contrib/snippet/browser/snippetController2.js';
import { ConfigureLanguageModelsOptions, ILanguageModelsConfigurationService, ILanguageModelsProviderGroup } from '../common/languageModelsConfiguration.js';
import { IJSONContributionRegistry, Extensions as JSONExtensions } from '../../../../platform/jsonschemas/common/jsonContributionRegistry.js';
import { Registry } from '../../../../platform/registry/common/platform.js';
import { IWorkbenchContribution } from '../../../common/contributions.js';
@@ -148,9 +149,9 @@ export class LanguageModelsConfigurationService extends Disposable implements IL
await this.updateLanguageModelsConfiguration();
}
async configureLanguageModels(range?: IRange): Promise<void> {
async configureLanguageModels(options?: ConfigureLanguageModelsOptions): Promise<void> {
const editor = await this.editorGroupsService.activeGroup.openEditor(this.textEditorService.createTextEditor({ resource: this.modelsConfigurationFile }));
if (!editor || !range) {
if (!editor || !options?.group) {
return;
}
@@ -159,10 +160,29 @@ export class LanguageModelsConfigurationService extends Disposable implements IL
return;
}
const position = { lineNumber: range.startLineNumber, column: range.startColumn };
codeEditor.setPosition(position);
codeEditor.revealPositionNearTop(position);
codeEditor.focus();
if (!options.group.range) {
return;
}
if (options.snippet) {
// Insert snippet at the end of the last property line (before the closing brace line), with comma prepended
const model = codeEditor.getModel();
if (!model) {
return;
}
const lastPropertyLine = options.group.range.endLineNumber - 1;
const lastPropertyLineLength = model.getLineLength(lastPropertyLine);
const insertPosition = { lineNumber: lastPropertyLine, column: lastPropertyLineLength + 1 };
codeEditor.setPosition(insertPosition);
codeEditor.revealPositionNearTop(insertPosition);
codeEditor.focus();
SnippetController2.get(codeEditor)?.insert(',\n' + options.snippet);
} else {
const position = { lineNumber: options.group.range.startLineNumber, column: options.group.range.startColumn };
codeEditor.setPosition(position);
codeEditor.revealPositionNearTop(position);
codeEditor.focus();
}
}
private async withLanguageModelsProviderGroups(update?: (languageModelsProviderGroups: LanguageModelsProviderGroups) => Promise<LanguageModelsProviderGroups>): Promise<LanguageModelsProviderGroups> {

View File

@@ -849,7 +849,8 @@ export class LanguageModelsService implements ILanguageModelsService {
: await this._languageModelsConfigurationService.addLanguageModelsProviderGroup(languageModelProviderGroup);
if (vendor.configuration && this.canConfigure(configuration ?? {}, vendor.configuration)) {
await this._languageModelsConfigurationService.configureLanguageModels(saved.range);
const snippet = this.getSnippetForFirstUnconfiguredProperty(configuration ?? {}, vendor.configuration);
await this._languageModelsConfigurationService.configureLanguageModels({ group: saved, snippet });
}
} catch (error) {
if (isCancellationError(error)) {
@@ -901,6 +902,25 @@ export class LanguageModelsService implements ILanguageModelsService {
return false;
}
private getSnippetForFirstUnconfiguredProperty(configuration: IStringDictionary<unknown>, schema: IJSONSchema): string | undefined {
if (!schema.properties) {
return undefined;
}
for (const property of Object.keys(schema.properties)) {
if (configuration[property] === undefined) {
const propertySchema = schema.properties[property];
if (propertySchema && typeof propertySchema !== 'boolean' && propertySchema.defaultSnippets?.[0]) {
const snippet = propertySchema.defaultSnippets[0];
let bodyText = snippet.bodyText ?? JSON.stringify(snippet.body, null, '\t');
// Handle ^ prefix for raw values (numbers/booleans) - remove quotes around ^-prefixed values
bodyText = bodyText.replace(/"(\^[^"]*)"/g, (_, value) => value.substring(1));
return `"${property}": ${bodyText}`;
}
}
}
return undefined;
}
private async promptForName(languageModelProviderGroups: readonly ILanguageModelsProviderGroup[], vendor: IUserFriendlyLanguageModel, existing: ILanguageModelsProviderGroup | undefined): Promise<string | undefined> {
let providerGroupName = existing?.name;
if (!providerGroupName) {

View File

@@ -11,6 +11,11 @@ import { IStringDictionary } from '../../../../base/common/collections.js';
export const ILanguageModelsConfigurationService = createDecorator<ILanguageModelsConfigurationService>('ILanguageModelsConfigurationService');
export interface ConfigureLanguageModelsOptions {
group: ILanguageModelsProviderGroup;
snippet?: string;
}
export interface ILanguageModelsConfigurationService {
readonly _serviceBrand: undefined;
@@ -26,7 +31,7 @@ export interface ILanguageModelsConfigurationService {
removeLanguageModelsProviderGroup(languageModelGroup: ILanguageModelsProviderGroup): Promise<void>;
configureLanguageModels(range?: IRange): Promise<void>;
configureLanguageModels(options?: ConfigureLanguageModelsOptions): Promise<void>;
}
export interface ILanguageModelsProviderGroup extends IStringDictionary<unknown> {