Skip to content

Commit f708219

Browse files
shoaib-fixesShoaib Ahmad
authored andcommitted
Fixes GitKraken AI model selection showing 'No models found' - fixes #4963
- Removes silent error swallowing in GitKrakenProvider.getModels() — errors now propagate so callers can handle them - Checks for a valid auth token (getApiKey) before making the API request, returning [] early if unauthenticated - Passes the access token explicitly to getGkHeaders() instead of relying on the internal lookup that threw AuthenticationRequiredError silently - Adds null guard for result.data to handle missing/null API response fields - Removes leftover debugger statement - Catches getModels() errors in showAIModelPicker and shows 'Unable to load models' with the error description instead of the generic 'No models found' - Adds defensive try/catch in getOrUpdateModel for getModels() call used to restore a previously configured model
1 parent 8b31f61 commit f708219

4 files changed

Lines changed: 64 additions & 52 deletions

File tree

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/) and this p
1212

1313
### Fixed
1414

15+
- Fixes _GitKraken AI_ model selection showing 'No models found' when switching AI provider/model ([#4963](https://github.com/gitkraken/vscode-gitlens/issues/4963))
1516
- Fixes provider id mismatch for cloud-connected self-hosted integrations ([#5031](https://github.com/gitkraken/vscode-gitlens/issues/5031))
1617
- Fixes an issue where the _Launchpad_ would fail to show any pull requests when one integration provider had an authentication failure — now shows partial results with an error indicator ([#4492](https://github.com/gitkraken/vscode-gitlens/issues/4492))
1718

src/plus/ai/aiProviderService.ts

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -561,7 +561,10 @@ export class AIProviderService implements AIService, Disposable {
561561
} else {
562562
changed = true;
563563

564-
const models = await this._provider.getModels();
564+
let models: readonly AIModel[] | undefined;
565+
try {
566+
models = await this._provider.getModels();
567+
} catch {}
565568
model = models?.find(m => m.id === modelId);
566569
if (model == null) {
567570
this._model = undefined;

src/plus/ai/gitkrakenProvider.ts

Lines changed: 45 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -32,55 +32,53 @@ export class GitKrakenProvider extends OpenAICompatibleProviderBase<typeof provi
3232
async getModels(): Promise<readonly AIModel<typeof provider.id>[]> {
3333
const scope = getScopedLogger();
3434

35-
try {
36-
const url = this.container.urls.getGkAIApiUrl('providers/message-prompt');
37-
const rsp = await fetch(url, {
38-
headers: await this.connection.getGkHeaders(undefined, undefined, {
39-
Accept: 'application/json',
40-
}),
41-
});
42-
if (!rsp.ok) {
43-
throw new Error(`Getting models (${url}) failed: ${rsp.status} (${rsp.statusText})`);
44-
}
45-
46-
interface ModelsResponse {
47-
data: {
48-
providerId: string;
49-
providerName: string;
50-
modelId: string;
51-
modelName: string;
52-
preferred: boolean;
53-
maxInputTokens: number;
54-
maxOutputTokens: number;
55-
}[];
56-
error?: null;
57-
}
58-
59-
const result: ModelsResponse = await rsp.json();
60-
if (result.error != null) {
61-
throw new Error(`Getting models (${url}) failed: ${String(result.error)}`);
62-
}
63-
64-
const models = result.data.map<GitKrakenModel>(
65-
m =>
66-
({
67-
id: m.modelId,
68-
name: m.modelName,
69-
maxTokens: { input: m.maxInputTokens, output: m.maxOutputTokens },
70-
provider: provider,
71-
default: m.preferred,
72-
temperature: null,
73-
}) satisfies GitKrakenModel,
74-
);
75-
return models;
76-
} catch (ex) {
77-
if (!(ex instanceof AuthenticationRequiredError)) {
78-
debugger;
79-
scope?.error(ex, `Unable to get models`);
80-
}
35+
const apiKey = await this.getApiKey(true);
36+
if (!apiKey) return [];
37+
38+
const url = this.container.urls.getGkAIApiUrl('providers/message-prompt');
39+
const rsp = await fetch(url, {
40+
headers: await this.connection.getGkHeaders(apiKey, undefined, {
41+
Accept: 'application/json',
42+
}),
43+
});
44+
if (!rsp.ok) {
45+
scope?.error(undefined, `Getting models (${url}) failed: ${rsp.status} (${rsp.statusText})`);
46+
throw new Error(`Getting models failed: (${rsp.status}) ${rsp.statusText}`);
47+
}
48+
49+
interface ModelsResponse {
50+
data: {
51+
providerId: string;
52+
providerName: string;
53+
modelId: string;
54+
modelName: string;
55+
preferred: boolean;
56+
maxInputTokens: number;
57+
maxOutputTokens: number;
58+
}[];
59+
error?: null;
60+
}
61+
62+
const result: ModelsResponse = await rsp.json();
63+
if (result.error != null) {
64+
scope?.error(undefined, `Getting models (${url}) failed: ${String(result.error)}`);
65+
throw new Error(`Getting models failed: ${String(result.error)}`);
8166
}
8267

83-
return [];
68+
if (!result.data) return [];
69+
70+
const models = result.data.map<GitKrakenModel>(
71+
m =>
72+
({
73+
id: m.modelId,
74+
name: m.modelName,
75+
maxTokens: { input: m.maxInputTokens, output: m.maxOutputTokens },
76+
provider: provider,
77+
default: m.preferred,
78+
temperature: null,
79+
}) satisfies GitKrakenModel,
80+
);
81+
return models;
8482
}
8583

8684
protected getUrl(_model: AIModel<typeof provider.id>): string {

src/quickpicks/aiModelPicker.ts

Lines changed: 14 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -136,15 +136,25 @@ export async function showAIModelPicker(
136136
): Promise<ModelQuickPickItem | Directive | undefined> {
137137
if (!(await ensureAccess(container, { showPicker: true }, source))) return undefined;
138138

139-
const models = (await container.ai.getModels(provider)) ?? [];
139+
let models: readonly AIModel[];
140+
let modelsError: string | undefined;
141+
try {
142+
models = (await container.ai.getModels(provider)) ?? [];
143+
} catch (ex) {
144+
models = [];
145+
modelsError = ex instanceof Error ? ex.message : String(ex);
146+
}
140147

141148
const items: Array<ModelQuickPickItem | DirectiveQuickPickItem> = [];
142149

143150
if (!models.length) {
144151
items.push({
145-
label: 'No models found',
146-
description:
147-
provider === 'ollama' ? 'Please install a model or check your Ollama server configuration' : undefined,
152+
label: modelsError ? 'Unable to load models' : 'No models found',
153+
description: modelsError
154+
? modelsError
155+
: provider === 'ollama'
156+
? 'Please install a model or check your Ollama server configuration'
157+
: undefined,
148158
iconPath: new ThemeIcon('error'),
149159
directive: Directive.Noop,
150160
} satisfies ModelQuickPickItem | DirectiveQuickPickItem);

0 commit comments

Comments
 (0)