Skip to content

Adds Open-AI compatible provider #4270

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Apr 30, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 7 additions & 7 deletions docs/telemetry-events.md
Original file line number Diff line number Diff line change
Expand Up @@ -124,7 +124,7 @@
'failed.reason': 'user-declined' | 'user-cancelled' | 'error',
'input.length': number,
'model.id': string,
'model.provider.id': 'anthropic' | 'deepseek' | 'gemini' | 'github' | 'gitkraken' | 'huggingface' | 'ollama' | 'openai' | 'openrouter' | 'vscode' | 'xai',
'model.provider.id': 'anthropic' | 'deepseek' | 'gemini' | 'github' | 'gitkraken' | 'huggingface' | 'ollama' | 'openai' | 'openaicompatible' | 'openrouter' | 'vscode' | 'xai',
'model.provider.name': string,
'output.length': number,
'retry.count': number,
Expand Down Expand Up @@ -155,7 +155,7 @@
'failed.reason': 'user-declined' | 'user-cancelled' | 'error',
'input.length': number,
'model.id': string,
'model.provider.id': 'anthropic' | 'deepseek' | 'gemini' | 'github' | 'gitkraken' | 'huggingface' | 'ollama' | 'openai' | 'openrouter' | 'vscode' | 'xai',
'model.provider.id': 'anthropic' | 'deepseek' | 'gemini' | 'github' | 'gitkraken' | 'huggingface' | 'ollama' | 'openai' | 'openaicompatible' | 'openrouter' | 'vscode' | 'xai',
'model.provider.name': string,
'output.length': number,
'retry.count': number,
Expand Down Expand Up @@ -185,7 +185,7 @@ or
'failed.reason': 'user-declined' | 'user-cancelled' | 'error',
'input.length': number,
'model.id': string,
'model.provider.id': 'anthropic' | 'deepseek' | 'gemini' | 'github' | 'gitkraken' | 'huggingface' | 'ollama' | 'openai' | 'openrouter' | 'vscode' | 'xai',
'model.provider.id': 'anthropic' | 'deepseek' | 'gemini' | 'github' | 'gitkraken' | 'huggingface' | 'ollama' | 'openai' | 'openaicompatible' | 'openrouter' | 'vscode' | 'xai',
'model.provider.name': string,
'output.length': number,
'retry.count': number,
Expand Down Expand Up @@ -214,7 +214,7 @@ or
'failed.reason': 'user-declined' | 'user-cancelled' | 'error',
'input.length': number,
'model.id': string,
'model.provider.id': 'anthropic' | 'deepseek' | 'gemini' | 'github' | 'gitkraken' | 'huggingface' | 'ollama' | 'openai' | 'openrouter' | 'vscode' | 'xai',
'model.provider.id': 'anthropic' | 'deepseek' | 'gemini' | 'github' | 'gitkraken' | 'huggingface' | 'ollama' | 'openai' | 'openaicompatible' | 'openrouter' | 'vscode' | 'xai',
'model.provider.name': string,
'output.length': number,
'retry.count': number,
Expand Down Expand Up @@ -243,7 +243,7 @@ or
'failed.reason': 'user-declined' | 'user-cancelled' | 'error',
'input.length': number,
'model.id': string,
'model.provider.id': 'anthropic' | 'deepseek' | 'gemini' | 'github' | 'gitkraken' | 'huggingface' | 'ollama' | 'openai' | 'openrouter' | 'vscode' | 'xai',
'model.provider.id': 'anthropic' | 'deepseek' | 'gemini' | 'github' | 'gitkraken' | 'huggingface' | 'ollama' | 'openai' | 'openaicompatible' | 'openrouter' | 'vscode' | 'xai',
'model.provider.name': string,
'output.length': number,
'retry.count': number,
Expand Down Expand Up @@ -272,7 +272,7 @@ or
'failed.reason': 'user-declined' | 'user-cancelled' | 'error',
'input.length': number,
'model.id': string,
'model.provider.id': 'anthropic' | 'deepseek' | 'gemini' | 'github' | 'gitkraken' | 'huggingface' | 'ollama' | 'openai' | 'openrouter' | 'vscode' | 'xai',
'model.provider.id': 'anthropic' | 'deepseek' | 'gemini' | 'github' | 'gitkraken' | 'huggingface' | 'ollama' | 'openai' | 'openaicompatible' | 'openrouter' | 'vscode' | 'xai',
'model.provider.name': string,
'output.length': number,
'retry.count': number,
Expand All @@ -295,7 +295,7 @@ or
```typescript
{
'model.id': string,
'model.provider.id': 'anthropic' | 'deepseek' | 'gemini' | 'github' | 'gitkraken' | 'huggingface' | 'ollama' | 'openai' | 'openrouter' | 'vscode' | 'xai',
'model.provider.id': 'anthropic' | 'deepseek' | 'gemini' | 'github' | 'gitkraken' | 'huggingface' | 'ollama' | 'openai' | 'openaicompatible' | 'openrouter' | 'vscode' | 'xai',
'model.provider.name': string
}
```
Expand Down
15 changes: 14 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -4047,7 +4047,7 @@
"null"
],
"default": null,
"pattern": "^((anthropic|deepseek|gemini|github|huggingface|ollama|openai|openrouter|xai):([\\w.-:]+)|gitkraken|vscode)$",
"pattern": "^((anthropic|deepseek|gemini|github|huggingface|ollama|openai|openaicompatible|openrouter|xai):([\\w.-:]+)|gitkraken|vscode)$",
"markdownDescription": "Specifies the AI provider and model to use for GitLens' AI features. Should be formatted as `provider:model` (e.g. `openai:gpt-4o` or `anthropic:claude-3-5-sonnet-latest`), `gitkraken` for GitKraken AI provided models, or `vscode` for models provided by the VS Code extension API (e.g. Copilot)",
"scope": "window",
"order": 10,
Expand Down Expand Up @@ -4109,6 +4109,19 @@
"preview"
]
},
"gitlens.ai.openaicompatible.url": {
"type": [
"string",
"null"
],
"default": null,
"markdownDescription": "Specifies a custom URL to use for access to an OpenAI-compatible model. Azure URLs should be in the following format: https://{your-resource-name}.openai.azure.com/openai/deployments/{deployment-id}/chat/completions?api-version={api-version}",
"scope": "window",
"order": 31,
"tags": [
"preview"
]
},
"gitlens.ai.largePromptWarningThreshold": {
"type": "number",
"default": 20000,
Expand Down
3 changes: 3 additions & 0 deletions src/config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -249,6 +249,9 @@ interface AIConfig {
readonly openai: {
readonly url: string | null;
};
readonly openaicompatible: {
readonly url: string | null;
};
readonly vscode: {
readonly model: AIProviderAndModel | null;
};
Expand Down
8 changes: 8 additions & 0 deletions src/constants.ai.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ export type AIProviders =
| 'huggingface'
| 'ollama'
| 'openai'
| 'openaicompatible'
| 'openrouter'
| 'vscode'
| 'xai';
Expand Down Expand Up @@ -38,6 +39,13 @@ export const openAIProviderDescriptor: AIProviderDescriptor<'openai'> = {
requiresAccount: true,
requiresUserKey: true,
} as const;
export const openAICompatibleProviderDescriptor: AIProviderDescriptor<'openaicompatible'> = {
id: 'openaicompatible',
name: 'OpenAI-Compatible Provider (Azure, etc.)',
primary: false,
requiresAccount: true,
requiresUserKey: true,
} as const;
export const anthropicProviderDescriptor: AIProviderDescriptor<'anthropic'> = {
id: 'anthropic',
name: 'Anthropic',
Expand Down
11 changes: 11 additions & 0 deletions src/plus/ai/aiProviderService.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import {
gitKrakenProviderDescriptor,
huggingFaceProviderDescriptor,
ollamaProviderDescriptor,
openAICompatibleProviderDescriptor,
openAIProviderDescriptor,
openRouterProviderDescriptor,
vscodeProviderDescriptor,
Expand Down Expand Up @@ -148,6 +149,16 @@ const supportedAIProviders = new Map<AIProviders, AIProviderDescriptorWithType>(
type: lazy(async () => (await import(/* webpackChunkName: "ai" */ './openaiProvider')).OpenAIProvider),
},
],
[
'openaicompatible',
{
...openAICompatibleProviderDescriptor,
type: lazy(
async () =>
(await import(/* webpackChunkName: "ai" */ './openAICompatibleProvider')).OpenAICompatibleProvider,
),
},
],
[
'ollama',
{
Expand Down
4 changes: 2 additions & 2 deletions src/plus/ai/anthropicProvider.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import type { Response } from '@env/fetch';
import { anthropicProviderDescriptor as provider } from '../../constants.ai';
import { AIError, AIErrorReason } from '../../errors';
import type { AIActionType, AIModel } from './models/model';
import { OpenAICompatibleProvider } from './openAICompatibleProvider';
import { OpenAICompatibleProviderBase } from './openAICompatibleProviderBase';

type AnthropicModel = AIModel<typeof provider.id>;
const models: AnthropicModel[] = [
Expand Down Expand Up @@ -103,7 +103,7 @@ const models: AnthropicModel[] = [
},
];

export class AnthropicProvider extends OpenAICompatibleProvider<typeof provider.id> {
export class AnthropicProvider extends OpenAICompatibleProviderBase<typeof provider.id> {
readonly id = provider.id;
readonly name = provider.name;
protected readonly descriptor = provider;
Expand Down
4 changes: 2 additions & 2 deletions src/plus/ai/deepSeekProvider.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { deepSeekProviderDescriptor as provider } from '../../constants.ai';
import type { AIModel } from './models/model';
import { OpenAICompatibleProvider } from './openAICompatibleProvider';
import { OpenAICompatibleProviderBase } from './openAICompatibleProviderBase';

type DeepSeekModel = AIModel<typeof provider.id>;
const models: DeepSeekModel[] = [
Expand All @@ -21,7 +21,7 @@ const models: DeepSeekModel[] = [
},
];

export class DeepSeekProvider extends OpenAICompatibleProvider<typeof provider.id> {
export class DeepSeekProvider extends OpenAICompatibleProviderBase<typeof provider.id> {
readonly id = provider.id;
readonly name = provider.name;
protected readonly descriptor = provider;
Expand Down
4 changes: 2 additions & 2 deletions src/plus/ai/geminiProvider.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import type { CancellationToken } from 'vscode';
import type { Response } from '@env/fetch';
import { geminiProviderDescriptor as provider } from '../../constants.ai';
import type { AIActionType, AIModel } from './models/model';
import { OpenAICompatibleProvider } from './openAICompatibleProvider';
import { OpenAICompatibleProviderBase } from './openAICompatibleProviderBase';

type GeminiModel = AIModel<typeof provider.id>;
const models: GeminiModel[] = [
Expand Down Expand Up @@ -111,7 +111,7 @@ const models: GeminiModel[] = [
},
];

export class GeminiProvider extends OpenAICompatibleProvider<typeof provider.id> {
export class GeminiProvider extends OpenAICompatibleProviderBase<typeof provider.id> {
readonly id = provider.id;
readonly name = provider.name;
protected readonly descriptor = provider;
Expand Down
4 changes: 2 additions & 2 deletions src/plus/ai/githubModelsProvider.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,11 @@ import { fetch } from '@env/fetch';
import { githubProviderDescriptor as provider } from '../../constants.ai';
import { AIError, AIErrorReason } from '../../errors';
import type { AIActionType, AIModel } from './models/model';
import { OpenAICompatibleProvider } from './openAICompatibleProvider';
import { OpenAICompatibleProviderBase } from './openAICompatibleProviderBase';

type GitHubModelsModel = AIModel<typeof provider.id>;

export class GitHubModelsProvider extends OpenAICompatibleProvider<typeof provider.id> {
export class GitHubModelsProvider extends OpenAICompatibleProviderBase<typeof provider.id> {
readonly id = provider.id;
readonly name = provider.name;
protected readonly descriptor = provider;
Expand Down
4 changes: 2 additions & 2 deletions src/plus/ai/gitkrakenProvider.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,12 +6,12 @@ import { debug } from '../../system/decorators/log';
import { Logger } from '../../system/logger';
import { getLogScope } from '../../system/logger.scope';
import type { AIActionType, AIModel } from './models/model';
import { OpenAICompatibleProvider } from './openAICompatibleProvider';
import { OpenAICompatibleProviderBase } from './openAICompatibleProviderBase';
import { ensureAccount } from './utils/-webview/ai.utils';

type GitKrakenModel = AIModel<typeof provider.id>;

export class GitKrakenProvider extends OpenAICompatibleProvider<typeof provider.id> {
export class GitKrakenProvider extends OpenAICompatibleProviderBase<typeof provider.id> {
readonly id = provider.id;
readonly name = provider.name;
protected readonly descriptor = provider;
Expand Down
4 changes: 2 additions & 2 deletions src/plus/ai/huggingFaceProvider.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
import { fetch } from '@env/fetch';
import { huggingFaceProviderDescriptor as provider } from '../../constants.ai';
import type { AIModel } from './models/model';
import { OpenAICompatibleProvider } from './openAICompatibleProvider';
import { OpenAICompatibleProviderBase } from './openAICompatibleProviderBase';

type HuggingFaceModel = AIModel<typeof provider.id>;

export class HuggingFaceProvider extends OpenAICompatibleProvider<typeof provider.id> {
export class HuggingFaceProvider extends OpenAICompatibleProviderBase<typeof provider.id> {
readonly id = provider.id;
readonly name = provider.name;
protected readonly descriptor = provider;
Expand Down
4 changes: 2 additions & 2 deletions src/plus/ai/ollamaProvider.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,13 @@ import { ollamaProviderDescriptor as provider } from '../../constants.ai';
import { configuration } from '../../system/-webview/configuration';
import type { AIActionType, AIModel } from './models/model';
import type { AIChatMessage, AIRequestResult } from './models/provider';
import { OpenAICompatibleProvider } from './openAICompatibleProvider';
import { OpenAICompatibleProviderBase } from './openAICompatibleProviderBase';

type OllamaModel = AIModel<typeof provider.id>;

const defaultBaseUrl = 'http://localhost:11434';

export class OllamaProvider extends OpenAICompatibleProvider<typeof provider.id> {
export class OllamaProvider extends OpenAICompatibleProviderBase<typeof provider.id> {
readonly id = provider.id;
readonly name = provider.name;
protected readonly descriptor = provider;
Expand Down
Loading