Skip to content

Commit dc40dbb

Browse files
committed
Fixes #4071 adapts openai compat for anthropic
Ensures gemini still includes max_tokens
1 parent a186739 commit dc40dbb

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
@@ -256,7 +256,7 @@ export abstract class OpenAICompatibleProvider<T extends AIProviders> implements
256256
}
257257

258258
const data: ChatCompletionResponse = await rsp.json();
259-
const result = data.choices[0].message.content?.trim() ?? '';
259+
const result = data.choices?.[0].message.content?.trim() ?? data.content?.[0]?.text?.trim() ?? '';
260260
return [result, maxCodeCharacters];
261261
}
262262
}
@@ -331,24 +331,23 @@ interface ChatCompletionRequest {
331331
model: string;
332332
messages: ChatMessage<Role>[];
333333

334-
frequency_penalty?: number;
335-
logit_bias?: Record<string, number>;
334+
/** @deprecated */
335+
max_tokens?: number;
336336
max_completion_tokens?: number;
337-
n?: number;
338-
presence_penalty?: number;
339-
stop?: string | string[];
337+
metadata?: Record<string, string>;
340338
stream?: boolean;
341339
temperature?: number;
342340
top_p?: number;
343-
user?: string;
341+
342+
/** Not supported by many models/providers */
343+
reasoning_effort?: 'low' | 'medium' | 'high';
344344
}
345345

346346
interface ChatCompletionResponse {
347347
id: string;
348-
object: 'chat.completion';
349-
created: number;
350348
model: string;
351-
choices: {
349+
/** OpenAI compatible output */
350+
choices?: {
352351
index: number;
353352
message: {
354353
role: Role;
@@ -357,9 +356,15 @@ interface ChatCompletionResponse {
357356
};
358357
finish_reason: string;
359358
}[];
359+
/** Anthropic compatible output */
360+
content?: { type: 'text'; text: string }[];
360361
usage: {
361-
prompt_tokens: number;
362-
completion_tokens: number;
363-
total_tokens: number;
362+
input_tokens?: number;
363+
prompt_tokens?: number;
364+
365+
completion_tokens?: number;
366+
output_tokens?: number;
367+
368+
total_tokens?: number;
364369
};
365370
}

0 commit comments

Comments
 (0)