Skip to content

Commit 1b74a41

Browse files
committed
Fixes #4071 adapts openai compat for anthropic
Ensures gemini still includes max_tokens
1 parent 75103e3 commit 1b74a41

File tree

4 files changed

+58
-97
lines changed

4 files changed

+58
-97
lines changed

CHANGELOG.md

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

99
### Fixed
1010

11+
- Fixes Generate Commit Message Error - Anthropic ([#4071](https://github.com/gitkraken/vscode-gitlens/issues/4071))
1112
- Fixes Settings editor breaking when dragging it to a new tab group ([#4061](https://github.com/gitkraken/vscode-gitlens/issues/4061))
1213
- Fixes regression where hovering over the Graph WIP row doesn't show up anymore ([#4062](https://github.com/gitkraken/vscode-gitlens/issues/4062))
1314
- Fixes Inspect & Graph Details: autolinks rendering when enabled setting is false ([#3841](https://github.com/gitkraken/vscode-gitlens/issues/3841))

src/ai/anthropicProvider.ts

Lines changed: 37 additions & 82 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
import type { CancellationToken } from 'vscode';
2+
import type { Response } from '@env/fetch';
23
import type { AIModel } from './aiProviderService';
3-
import { getMaxCharacters, getValidatedTemperature } from './aiProviderService';
4-
import type { ChatMessage } from './openAICompatibleProvider';
54
import { OpenAICompatibleProvider } from './openAICompatibleProvider';
65

76
const provider = { id: 'anthropic', name: 'Anthropic' } as const;
@@ -98,66 +97,50 @@ export class AnthropicProvider extends OpenAICompatibleProvider<typeof provider.
9897
};
9998
}
10099

101-
override async fetch(
100+
protected override fetchCore(
102101
model: AIModel<typeof provider.id>,
103102
apiKey: string,
104-
messages: (maxCodeCharacters: number, retries: number) => ChatMessage[],
105-
outputTokens: number,
103+
request: object,
106104
cancellation: CancellationToken | undefined,
107-
): Promise<[result: string, maxCodeCharacters: number]> {
108-
let retries = 0;
109-
let maxCodeCharacters = getMaxCharacters(model, 2600);
110-
111-
while (true) {
112-
// Split the system message from the rest of the messages
113-
const [system, ...msgs] = messages(maxCodeCharacters, retries);
114-
115-
const request: AnthropicMessageRequest = {
116-
model: model.id,
117-
messages: msgs,
118-
system: system.content,
119-
stream: false,
120-
max_tokens: Math.min(outputTokens, model.maxTokens.output),
121-
temperature: getValidatedTemperature(model.temperature),
122-
};
123-
124-
const rsp = await this.fetchCore(model, apiKey, request, cancellation);
125-
if (!rsp.ok) {
126-
if (rsp.status === 404) {
127-
throw new Error(`Your API key doesn't seem to have access to the selected '${model.id}' model`);
128-
}
129-
if (rsp.status === 429) {
130-
throw new Error(
131-
`(${this.name}) ${rsp.status}: Too many requests (rate limit exceeded) or your API key is associated with an expired trial`,
132-
);
133-
}
134-
135-
let json;
136-
try {
137-
json = (await rsp.json()) as AnthropicError | undefined;
138-
} catch {}
105+
): Promise<Response> {
106+
if ('max_completion_tokens' in request) {
107+
const { max_completion_tokens: max, ...rest } = request;
108+
request = max ? { max_tokens: max, ...rest } : rest;
109+
}
110+
return super.fetchCore(model, apiKey, request, cancellation);
111+
}
139112

140-
debugger;
113+
protected override async handleFetchFailure(
114+
rsp: Response,
115+
model: AIModel<typeof provider.id>,
116+
retries: number,
117+
maxCodeCharacters: number,
118+
): Promise<{ retry: boolean; maxCodeCharacters: number }> {
119+
if (rsp.status === 404) {
120+
throw new Error(`Your API key doesn't seem to have access to the selected '${model.id}' model`);
121+
}
122+
if (rsp.status === 429) {
123+
throw new Error(
124+
`(${this.name}) ${rsp.status}: Too many requests (rate limit exceeded) or your account is out of funds`,
125+
);
126+
}
141127

142-
if (
143-
retries++ < 2 &&
144-
json?.error?.type === 'invalid_request_error' &&
145-
json?.error?.message?.includes('prompt is too long')
146-
) {
147-
maxCodeCharacters -= 500 * retries;
148-
continue;
149-
}
128+
let json;
129+
try {
130+
json = (await rsp.json()) as AnthropicError | undefined;
131+
} catch {}
150132

151-
throw new Error(`(${this.name}) ${rsp.status}: ${json?.error?.message || rsp.statusText})`);
152-
}
133+
debugger;
153134

154-
const data: AnthropicMessageResponse = await rsp.json();
155-
const result = data.content
156-
.map(c => c.text)
157-
.join('\n')
158-
.trim();
159-
return [result, maxCodeCharacters];
135+
if (
136+
retries++ < 2 &&
137+
json?.error?.type === 'invalid_request_error' &&
138+
json?.error?.message?.includes('prompt is too long')
139+
) {
140+
return { retry: true, maxCodeCharacters: maxCodeCharacters - 500 * retries };
160141
}
142+
143+
throw new Error(`(${this.name}) ${rsp.status}: ${json?.error?.message || rsp.statusText})`);
161144
}
162145
}
163146

@@ -175,31 +158,3 @@ interface AnthropicError {
175158
message: string;
176159
};
177160
}
178-
179-
interface AnthropicMessageRequest {
180-
model: AnthropicModel['id'];
181-
messages: ChatMessage[];
182-
system?: string;
183-
184-
max_tokens: number;
185-
metadata?: object;
186-
stop_sequences?: string[];
187-
stream?: boolean;
188-
temperature?: number;
189-
top_p?: number;
190-
top_k?: number;
191-
}
192-
193-
interface AnthropicMessageResponse {
194-
id: string;
195-
type: 'message';
196-
role: 'assistant';
197-
content: { type: 'text'; text: string }[];
198-
model: string;
199-
stop_reason: 'end_turn' | 'max_tokens' | 'stop_sequence';
200-
stop_sequence: string | null;
201-
usage: {
202-
input_tokens: number;
203-
output_tokens: number;
204-
};
205-
}

src/ai/geminiProvider.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -99,8 +99,8 @@ export class GeminiProvider extends OpenAICompatibleProvider<typeof provider.id>
9999
cancellation: CancellationToken | undefined,
100100
): Promise<Response> {
101101
if ('max_completion_tokens' in request) {
102-
const { max_completion_tokens: _, ...rest } = request;
103-
request = rest;
102+
const { max_completion_tokens: max, ...rest } = request;
103+
request = max ? { max_tokens: max, ...rest } : rest;
104104
}
105105
return super.fetchCore(model, apiKey, request, cancellation);
106106
}

src/ai/openAICompatibleProvider.ts

Lines changed: 18 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -303,7 +303,7 @@ export abstract class OpenAICompatibleProvider<T extends AIProviders> implements
303303
}
304304

305305
const data: ChatCompletionResponse = await rsp.json();
306-
const result = data.choices[0].message.content?.trim() ?? '';
306+
const result = data.choices?.[0].message.content?.trim() ?? data.content?.[0]?.text?.trim() ?? '';
307307
return [result, maxCodeCharacters];
308308
}
309309
}
@@ -378,24 +378,23 @@ interface ChatCompletionRequest {
378378
model: string;
379379
messages: ChatMessage<Role>[];
380380

381-
frequency_penalty?: number;
382-
logit_bias?: Record<string, number>;
381+
/** @deprecated */
382+
max_tokens?: number;
383383
max_completion_tokens?: number;
384-
n?: number;
385-
presence_penalty?: number;
386-
stop?: string | string[];
384+
metadata?: Record<string, string>;
387385
stream?: boolean;
388386
temperature?: number;
389387
top_p?: number;
390-
user?: string;
388+
389+
/** Not supported by many models/providers */
390+
reasoning_effort?: 'low' | 'medium' | 'high';
391391
}
392392

393393
interface ChatCompletionResponse {
394394
id: string;
395-
object: 'chat.completion';
396-
created: number;
397395
model: string;
398-
choices: {
396+
/** OpenAI compatible output */
397+
choices?: {
399398
index: number;
400399
message: {
401400
role: Role;
@@ -404,9 +403,15 @@ interface ChatCompletionResponse {
404403
};
405404
finish_reason: string;
406405
}[];
406+
/** Anthropic compatible output */
407+
content?: { type: 'text'; text: string }[];
407408
usage: {
408-
prompt_tokens: number;
409-
completion_tokens: number;
410-
total_tokens: number;
409+
input_tokens?: number;
410+
prompt_tokens?: number;
411+
412+
completion_tokens?: number;
413+
output_tokens?: number;
414+
415+
total_tokens?: number;
411416
};
412417
}

0 commit comments

Comments
 (0)