Skip to content

Commit 3f88149

Browse files
committed
refactor: Picking copilot model restarts via configuration change hook
See discussion in #1053
1 parent c3d1c29 commit 3f88149

3 files changed

Lines changed: 21 additions & 13 deletions

File tree

src/commands/pickCopilotModel.ts

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,6 @@ export default class PickCopilotModelCommand {
2626
);
2727
if (!model) return;
2828

29-
await ExtensionSettings.setPreferredCopilotModel(model.details);
30-
return vscode.commands.executeCommand('appmap.rpc.restart');
29+
return ExtensionSettings.setPreferredCopilotModel(model.details);
3130
}
3231
}

src/services/chatCompletion.ts

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -120,12 +120,16 @@ export default class ChatCompletion implements Disposable {
120120
return this.models[0];
121121
}
122122

123+
// This is used to determine whether the preferred model has changed upon refreshing the models.
124+
private static previousModelId: string | undefined;
125+
123126
static async refreshModels(): Promise<boolean> {
124-
const previousBest = this.preferredModel?.id;
125127
this._models = (await vscode.lm.selectChatModels()).sort(
126128
(a, b) => b.maxInputTokens - a.maxInputTokens + b.family.localeCompare(a.family)
127129
);
128-
return this.preferredModel?.id !== previousBest;
130+
const hasChanged = this.previousModelId !== this.preferredModel?.id;
131+
this.previousModelId = this.preferredModel?.id;
132+
return hasChanged;
129133
}
130134

131135
static get instance(): Promise<ChatCompletion> | undefined {
@@ -238,7 +242,8 @@ export default class ChatCompletion implements Disposable {
238242
context.subscriptions.push(
239243
vscode.workspace.onDidChangeConfiguration(
240244
(e) =>
241-
e.affectsConfiguration('appMap.navie.useVSCodeLM') &&
245+
(e.affectsConfiguration('appMap.navie.useVSCodeLM') ||
246+
e.affectsConfiguration('appMap.copilot.preferredModel')) &&
242247
this.checkConfiguration(context, true)
243248
)
244249
);

test/unit/commands/pickCopilotModel.test.ts

Lines changed: 12 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -2,34 +2,43 @@ import vscode from '../mock/vscode';
22
import sinon from 'sinon';
33
import { expect } from 'chai';
44
import PickCopilotModelCommand from '../../../src/commands/pickCopilotModel';
5+
import { addMockChatModel, resetModelMocks } from '../mock/vscode/lm';
6+
import { LanguageModelChat } from 'vscode';
57

68
describe('pickCopilotModel', () => {
79
describe('execute', () => {
8-
let models: Record<string, unknown>[];
10+
let models: LanguageModelChat[];
911
let executeCommandStub: sinon.SinonStub;
1012
let showQuickPickStub: sinon.SinonStub;
1113
let showErrorMessageStub: sinon.SinonStub;
1214
const chosenModel = 'claude-3.5-sonnet';
1315
beforeEach(() => {
1416
models = [
15-
{ id: 'gpt-4o', name: 'GPT-4o', maxInputTokens: 325, family: 'copilot' },
17+
{
18+
id: 'gpt-4o',
19+
name: 'GPT-4o',
20+
maxInputTokens: 325,
21+
family: 'copilot',
22+
} as LanguageModelChat,
1623
{
1724
id: 'claude-3.5-sonnet',
1825
name: 'Claude 3.5 Sonnet',
1926
maxInputTokens: 325,
2027
family: 'copilot',
21-
},
28+
} as LanguageModelChat,
2229
];
2330
showQuickPickStub = sinon.stub(vscode.window, 'showQuickPick').callsFake(() => ({
2431
details: chosenModel,
2532
}));
2633
showErrorMessageStub = sinon.stub(vscode.window, 'showErrorMessage').resolves();
2734
executeCommandStub = sinon.stub(vscode.commands, 'executeCommand').resolves();
2835
sinon.stub(vscode.lm, 'selectChatModels').callsFake(() => models as any); // eslint-disable-line @typescript-eslint/no-explicit-any
36+
models.forEach((m) => addMockChatModel(m));
2937
});
3038

3139
afterEach(() => {
3240
sinon.restore();
41+
resetModelMocks();
3342
});
3443

3544
const setPreferredModel = (model: string | undefined) =>
@@ -51,11 +60,6 @@ describe('pickCopilotModel', () => {
5160
expect(executeCommandStub.called).to.be.false;
5261
});
5362

54-
it('restarts the RPC server', async () => {
55-
await PickCopilotModelCommand.execute();
56-
expect(executeCommandStub.calledWith('appmap.rpc.restart')).to.be.true;
57-
});
58-
5963
it('does nothing if the user cancels the quick pick', async () => {
6064
showQuickPickStub.resolves(undefined);
6165
setPreferredModel(chosenModel);

0 commit comments

Comments
 (0)