Skip to content

Commit 0d6f551

Browse files
authored
Allow experiment model to be default (#268)
* Use exp model when available as the default model * only override default for known models
1 parent 73dfcaa commit 0d6f551

File tree

2 files changed

+52
-20
lines changed

2 files changed

+52
-20
lines changed

src/extension/prompt/vscode-node/endpointProviderImpl.ts

Lines changed: 14 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ import { AutoChatEndpoint, resolveAutoChatEndpoint } from '../../../platform/end
1313
import { ChatEndpoint } from '../../../platform/endpoint/node/chatEndpoint';
1414
import { EmbeddingEndpoint } from '../../../platform/endpoint/node/embeddingsEndpoint';
1515
import { IModelMetadataFetcher, ModelMetadataFetcher } from '../../../platform/endpoint/node/modelMetadataFetcher';
16-
import { ProxyExperimentEndpoint } from '../../../platform/endpoint/node/proxyExperimentEndpoint';
16+
import { applyExperimentModifications, getCustomDefaultModelExperimentConfig, ProxyExperimentEndpoint } from '../../../platform/endpoint/node/proxyExperimentEndpoint';
1717
import { ExtensionContributedChatEndpoint } from '../../../platform/endpoint/vscode-node/extChatEndpoint';
1818
import { IEnvService } from '../../../platform/env/common/envService';
1919
import { ILogService } from '../../../platform/log/common/logService';
@@ -24,6 +24,7 @@ import { ITelemetryService } from '../../../platform/telemetry/common/telemetry'
2424
import { TokenizerType } from '../../../util/common/tokenizer';
2525
import { IInstantiationService, ServicesAccessor } from '../../../util/vs/platform/instantiation/common/instantiation';
2626

27+
2728
export class ProductionEndpointProvider implements IEndpointProvider {
2829

2930
declare readonly _serviceBrand: undefined;
@@ -90,7 +91,7 @@ export class ProductionEndpointProvider implements IEndpointProvider {
9091
private getOrCreateProxyExperimentEndpointInstance(name: string, id: string, endpoint: IChatEndpoint): IChatEndpoint {
9192
let chatEndpoint = this._chatEndpoints.get(id);
9293
if (!chatEndpoint) {
93-
chatEndpoint = new ProxyExperimentEndpoint(name, id, endpoint);
94+
chatEndpoint = new ProxyExperimentEndpoint(name, id, endpoint, /* isDefault: */ true);
9495
this._chatEndpoints.set(id, chatEndpoint);
9596
}
9697
return chatEndpoint;
@@ -104,22 +105,11 @@ export class ProductionEndpointProvider implements IEndpointProvider {
104105
this._embeddingEndpoints.set(modelId, embeddingEndpoint);
105106
}
106107
return embeddingEndpoint;
107-
108-
}
109-
110-
private getExperimentData(): { selected: string; name: string; id: string } | undefined {
111-
const selected = this._expService.getTreatmentVariable<string>('vscode', 'custommodel1');
112-
const id = this._expService.getTreatmentVariable<string>('vscode', 'custommodel1.id');
113-
const name = this._expService.getTreatmentVariable<string>('vscode', 'custommodel1.name');
114-
if (selected && id && name) {
115-
return { selected, id, name };
116-
}
117-
return undefined;
118108
}
119109

120110
async getChatEndpoint(requestOrFamilyOrModel: LanguageModelChat | ChatRequest | ChatEndpointFamily): Promise<IChatEndpoint> {
121111
this._logService.logger.trace(`Resolving chat model`);
122-
const experimentModelConfig = this.getExperimentData();
112+
const experimentModelConfig = getCustomDefaultModelExperimentConfig(this._expService);
123113

124114
if (this._overridenChatModel) {
125115
// Override, only allowed by internal users. Sets model based on setting
@@ -142,16 +132,20 @@ export class ProductionEndpointProvider implements IEndpointProvider {
142132
let endpoint: IChatEndpoint;
143133
if (typeof requestOrFamilyOrModel === 'string') {
144134
// The family case, resolve the chat model for the passed in family
145-
const modelMetadata = await this._modelFetcher.getChatModelFromFamily(requestOrFamilyOrModel);
146-
endpoint = this.getOrCreateChatEndpointInstance(modelMetadata);
135+
let modelMetadata = await this._modelFetcher.getChatModelFromFamily(requestOrFamilyOrModel);
136+
modelMetadata = applyExperimentModifications(modelMetadata, experimentModelConfig);
137+
endpoint = this.getOrCreateChatEndpointInstance(modelMetadata!);
147138
} else {
148139
const model = 'model' in requestOrFamilyOrModel ? requestOrFamilyOrModel.model : requestOrFamilyOrModel;
149140
if (experimentModelConfig && model && model.id === experimentModelConfig.id) {
150141
endpoint = (await this.getAllChatEndpoints()).find(e => e.model === experimentModelConfig.selected) || await this.getChatEndpoint('gpt-4.1');
151142
} else if (model && model.vendor === 'copilot' && model.id === AutoChatEndpoint.id) {
152143
return resolveAutoChatEndpoint(this, this._expService, (requestOrFamilyOrModel as ChatRequest)?.prompt);
153144
} else if (model && model.vendor === 'copilot') {
154-
const modelMetadata = await this._modelFetcher.getChatModelFromApiModel(model);
145+
let modelMetadata = await this._modelFetcher.getChatModelFromApiModel(model);
146+
if (modelMetadata) {
147+
modelMetadata = applyExperimentModifications(modelMetadata, experimentModelConfig);
148+
}
155149
// If we fail to resolve a model since this is panel we give GPT-4.1. This really should never happen as the picker is powered by the same service.
156150
endpoint = modelMetadata ? this.getOrCreateChatEndpointInstance(modelMetadata) : await this.getChatEndpoint('gpt-4.1');
157151
} else if (model) {
@@ -194,9 +188,10 @@ export class ProductionEndpointProvider implements IEndpointProvider {
194188
const models: IChatModelInformation[] = await this._modelFetcher.getAllChatModels();
195189
const chatEndpoints = [];
196190

197-
const experimentModelConfig = this.getExperimentData();
191+
const experimentModelConfig = getCustomDefaultModelExperimentConfig(this._expService);
198192

199-
for (const model of models) {
193+
for (let model of models) {
194+
model = applyExperimentModifications(model, experimentModelConfig) ?? model;
200195
const chatEndpoint = this.getOrCreateChatEndpointInstance(model);
201196
chatEndpoints.push(chatEndpoint);
202197
if (experimentModelConfig && chatEndpoint.model === experimentModelConfig.selected) {

src/platform/endpoint/node/proxyExperimentEndpoint.ts

Lines changed: 38 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,14 +15,21 @@ import { FinishedCallback, OptionalChatRequestParams } from '../../networking/co
1515
import { Response } from '../../networking/common/fetcherService';
1616
import { IChatEndpoint, IEndpointBody } from '../../networking/common/networking';
1717
import { ChatCompletion } from '../../networking/common/openai';
18+
import { IExperimentationService } from '../../telemetry/common/nullExperimentationService';
1819
import { ITelemetryService, TelemetryProperties } from '../../telemetry/common/telemetry';
1920
import { TelemetryData } from '../../telemetry/common/telemetryData';
21+
import { IChatModelInformation } from '../common/endpointProvider';
2022

2123
export class ProxyExperimentEndpoint implements IChatEndpoint {
2224
public readonly showInModelPicker: boolean;
2325
public readonly family: string;
2426

25-
constructor(public readonly name: string, public readonly model: string, public readonly selectedEndpoint: IChatEndpoint) {
27+
constructor(
28+
public readonly name: string,
29+
public readonly model: string,
30+
public readonly selectedEndpoint: IChatEndpoint,
31+
private readonly _isDefault: boolean
32+
) {
2633
// This is a proxy endpoint that wraps another endpoint, typically used for experiments.
2734
// This should be used to show the endpoint in the model picker, when in experiment.
2835
this.showInModelPicker = true;
@@ -69,6 +76,9 @@ export class ProxyExperimentEndpoint implements IChatEndpoint {
6976
}
7077

7178
get isDefault(): boolean {
79+
if (this._isDefault !== undefined) {
80+
return this._isDefault;
81+
}
7282
return this.selectedEndpoint.isDefault;
7383
}
7484

@@ -115,5 +125,32 @@ export class ProxyExperimentEndpoint implements IChatEndpoint {
115125
acquireTokenizer(): ITokenizer {
116126
return this.selectedEndpoint.acquireTokenizer();
117127
}
128+
}
129+
130+
131+
interface ExperimentConfig {
132+
selected: string;
133+
name: string;
134+
id: string;
135+
}
136+
137+
export function getCustomDefaultModelExperimentConfig(expService: IExperimentationService): ExperimentConfig | undefined {
138+
const selected = expService.getTreatmentVariable<string>('vscode', 'custommodel1');
139+
const id = expService.getTreatmentVariable<string>('vscode', 'custommodel1.id');
140+
const name = expService.getTreatmentVariable<string>('vscode', 'custommodel1.name');
141+
if (selected && id && name) {
142+
return { selected, id, name };
143+
}
144+
return undefined;
145+
}
118146

147+
export function applyExperimentModifications(
148+
modelMetadata: IChatModelInformation,
149+
experimentConfig: ExperimentConfig | undefined
150+
): IChatModelInformation {
151+
const knownDefaults = ['gpt-4.1'];
152+
if (modelMetadata && experimentConfig && modelMetadata.is_chat_default && knownDefaults.includes(modelMetadata.id)) {
153+
return { ...modelMetadata, is_chat_default: false };
154+
}
155+
return modelMetadata;
119156
}

0 commit comments

Comments
 (0)