commons-proxy 2.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +757 -0
- package/bin/cli.js +146 -0
- package/package.json +97 -0
- package/public/Complaint Details.pdf +0 -0
- package/public/Cyber Crime Portal.pdf +0 -0
- package/public/app.js +229 -0
- package/public/css/src/input.css +523 -0
- package/public/css/style.css +1 -0
- package/public/favicon.png +0 -0
- package/public/index.html +549 -0
- package/public/js/components/account-manager.js +356 -0
- package/public/js/components/add-account-modal.js +414 -0
- package/public/js/components/claude-config.js +420 -0
- package/public/js/components/dashboard/charts.js +605 -0
- package/public/js/components/dashboard/filters.js +362 -0
- package/public/js/components/dashboard/stats.js +110 -0
- package/public/js/components/dashboard.js +236 -0
- package/public/js/components/logs-viewer.js +100 -0
- package/public/js/components/models.js +36 -0
- package/public/js/components/server-config.js +349 -0
- package/public/js/config/constants.js +102 -0
- package/public/js/data-store.js +375 -0
- package/public/js/settings-store.js +58 -0
- package/public/js/store.js +99 -0
- package/public/js/translations/en.js +367 -0
- package/public/js/translations/id.js +412 -0
- package/public/js/translations/pt.js +308 -0
- package/public/js/translations/tr.js +358 -0
- package/public/js/translations/zh.js +373 -0
- package/public/js/utils/account-actions.js +189 -0
- package/public/js/utils/error-handler.js +96 -0
- package/public/js/utils/model-config.js +42 -0
- package/public/js/utils/ui-logger.js +143 -0
- package/public/js/utils/validators.js +77 -0
- package/public/js/utils.js +69 -0
- package/public/proxy-server-64.png +0 -0
- package/public/views/accounts.html +361 -0
- package/public/views/dashboard.html +484 -0
- package/public/views/logs.html +97 -0
- package/public/views/models.html +331 -0
- package/public/views/settings.html +1327 -0
- package/src/account-manager/credentials.js +378 -0
- package/src/account-manager/index.js +462 -0
- package/src/account-manager/onboarding.js +112 -0
- package/src/account-manager/rate-limits.js +369 -0
- package/src/account-manager/storage.js +160 -0
- package/src/account-manager/strategies/base-strategy.js +109 -0
- package/src/account-manager/strategies/hybrid-strategy.js +339 -0
- package/src/account-manager/strategies/index.js +79 -0
- package/src/account-manager/strategies/round-robin-strategy.js +76 -0
- package/src/account-manager/strategies/sticky-strategy.js +138 -0
- package/src/account-manager/strategies/trackers/health-tracker.js +162 -0
- package/src/account-manager/strategies/trackers/index.js +9 -0
- package/src/account-manager/strategies/trackers/quota-tracker.js +120 -0
- package/src/account-manager/strategies/trackers/token-bucket-tracker.js +155 -0
- package/src/auth/database.js +169 -0
- package/src/auth/oauth.js +548 -0
- package/src/auth/token-extractor.js +117 -0
- package/src/cli/accounts.js +648 -0
- package/src/cloudcode/index.js +29 -0
- package/src/cloudcode/message-handler.js +510 -0
- package/src/cloudcode/model-api.js +248 -0
- package/src/cloudcode/rate-limit-parser.js +235 -0
- package/src/cloudcode/request-builder.js +93 -0
- package/src/cloudcode/session-manager.js +47 -0
- package/src/cloudcode/sse-parser.js +121 -0
- package/src/cloudcode/sse-streamer.js +293 -0
- package/src/cloudcode/streaming-handler.js +615 -0
- package/src/config.js +125 -0
- package/src/constants.js +407 -0
- package/src/errors.js +242 -0
- package/src/fallback-config.js +29 -0
- package/src/format/content-converter.js +193 -0
- package/src/format/index.js +20 -0
- package/src/format/request-converter.js +255 -0
- package/src/format/response-converter.js +120 -0
- package/src/format/schema-sanitizer.js +673 -0
- package/src/format/signature-cache.js +88 -0
- package/src/format/thinking-utils.js +648 -0
- package/src/index.js +148 -0
- package/src/modules/usage-stats.js +205 -0
- package/src/providers/anthropic-provider.js +258 -0
- package/src/providers/base-provider.js +157 -0
- package/src/providers/cloudcode.js +94 -0
- package/src/providers/copilot.js +399 -0
- package/src/providers/github-provider.js +287 -0
- package/src/providers/google-provider.js +192 -0
- package/src/providers/index.js +211 -0
- package/src/providers/openai-compatible.js +265 -0
- package/src/providers/openai-provider.js +271 -0
- package/src/providers/openrouter-provider.js +325 -0
- package/src/providers/setup.js +83 -0
- package/src/server.js +870 -0
- package/src/utils/claude-config.js +245 -0
- package/src/utils/helpers.js +51 -0
- package/src/utils/logger.js +142 -0
- package/src/utils/native-module-helper.js +162 -0
- package/src/webui/index.js +1134 -0
|
@@ -0,0 +1,325 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* OpenRouter API Provider
|
|
3
|
+
*
|
|
4
|
+
* Implements authentication via OpenRouter API keys.
|
|
5
|
+
* OpenRouter provides a unified API for hundreds of AI models
|
|
6
|
+
* through a single OpenAI-compatible endpoint.
|
|
7
|
+
*
|
|
8
|
+
* API Base: https://openrouter.ai/api/v1
|
|
9
|
+
* Auth: Bearer token (API key)
|
|
10
|
+
* Models endpoint: GET /api/v1/models
|
|
11
|
+
* Chat endpoint: POST /api/v1/chat/completions
|
|
12
|
+
*/
|
|
13
|
+
|
|
14
|
+
import BaseProvider from './base-provider.js';
|
|
15
|
+
|
|
16
|
+
export class OpenRouterProvider extends BaseProvider {
|
|
17
|
+
constructor(config = {}) {
|
|
18
|
+
super('openrouter', 'OpenRouter', {
|
|
19
|
+
apiEndpoint: config.apiEndpoint || 'https://openrouter.ai/api/v1',
|
|
20
|
+
...config
|
|
21
|
+
});
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
/**
|
|
25
|
+
* Validate OpenRouter API key by fetching the auth/key endpoint
|
|
26
|
+
*
|
|
27
|
+
* @param {Object} account - Account with apiKey
|
|
28
|
+
* @returns {Promise<{valid: boolean, error?: string, email?: string}>}
|
|
29
|
+
*/
|
|
30
|
+
async validateCredentials(account) {
|
|
31
|
+
if (!account.apiKey) {
|
|
32
|
+
return { valid: false, error: 'Missing API key' };
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
try {
|
|
36
|
+
// OpenRouter provides an auth/key endpoint to validate keys
|
|
37
|
+
const response = await fetch('https://openrouter.ai/api/v1/auth/key', {
|
|
38
|
+
method: 'GET',
|
|
39
|
+
headers: {
|
|
40
|
+
'Authorization': `Bearer ${account.apiKey}`,
|
|
41
|
+
'HTTP-Referer': 'https://github.com/AryanVBW/CommonsProxy',
|
|
42
|
+
'X-Title': 'CommonsProxy'
|
|
43
|
+
}
|
|
44
|
+
});
|
|
45
|
+
|
|
46
|
+
if (!response.ok) {
|
|
47
|
+
const error = await response.text();
|
|
48
|
+
return { valid: false, error: `API key validation failed (${response.status}): ${error}` };
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
const data = await response.json();
|
|
52
|
+
|
|
53
|
+
// Use the label from the key data, or generate an identifier
|
|
54
|
+
const email = account.email || data.data?.label || `openrouter-${account.apiKey.slice(-8)}`;
|
|
55
|
+
|
|
56
|
+
return { valid: true, email };
|
|
57
|
+
} catch (error) {
|
|
58
|
+
this.error('Credential validation failed', error);
|
|
59
|
+
return { valid: false, error: error.message };
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
/**
|
|
64
|
+
* Get API key (for OpenRouter, API key IS the access token)
|
|
65
|
+
*
|
|
66
|
+
* @param {Object} account - Account with apiKey
|
|
67
|
+
* @returns {Promise<string>} API key
|
|
68
|
+
*/
|
|
69
|
+
async getAccessToken(account) {
|
|
70
|
+
if (!account.apiKey) {
|
|
71
|
+
throw new Error('Account missing API key');
|
|
72
|
+
}
|
|
73
|
+
return account.apiKey;
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
/**
|
|
77
|
+
* Fetch usage/quota information from OpenRouter
|
|
78
|
+
* OpenRouter provides credit-based usage info via /api/v1/auth/key
|
|
79
|
+
*
|
|
80
|
+
* @param {Object} account - Account object
|
|
81
|
+
* @param {string} token - API key
|
|
82
|
+
* @returns {Promise<Object>} Quota data
|
|
83
|
+
*/
|
|
84
|
+
async getQuotas(account, token) {
|
|
85
|
+
try {
|
|
86
|
+
// Fetch key info for credit/usage data
|
|
87
|
+
const keyResponse = await fetch('https://openrouter.ai/api/v1/auth/key', {
|
|
88
|
+
method: 'GET',
|
|
89
|
+
headers: {
|
|
90
|
+
'Authorization': `Bearer ${token}`,
|
|
91
|
+
'HTTP-Referer': 'https://github.com/AryanVBW/CommonsProxy',
|
|
92
|
+
'X-Title': 'CommonsProxy'
|
|
93
|
+
}
|
|
94
|
+
});
|
|
95
|
+
|
|
96
|
+
let creditFraction = 1.0;
|
|
97
|
+
if (keyResponse.ok) {
|
|
98
|
+
const keyData = await keyResponse.json();
|
|
99
|
+
// keyData.data has: { label, usage, limit, is_free_tier, rate_limit }
|
|
100
|
+
const usage = keyData.data?.usage || 0;
|
|
101
|
+
const limit = keyData.data?.limit || null;
|
|
102
|
+
if (limit && limit > 0) {
|
|
103
|
+
creditFraction = Math.max(0, (limit - usage) / limit);
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
// Fetch available models
|
|
108
|
+
const modelsResponse = await fetch('https://openrouter.ai/api/v1/models', {
|
|
109
|
+
method: 'GET',
|
|
110
|
+
headers: {
|
|
111
|
+
'Authorization': `Bearer ${token}`,
|
|
112
|
+
'HTTP-Referer': 'https://github.com/AryanVBW/CommonsProxy',
|
|
113
|
+
'X-Title': 'CommonsProxy'
|
|
114
|
+
}
|
|
115
|
+
});
|
|
116
|
+
|
|
117
|
+
const models = {};
|
|
118
|
+
|
|
119
|
+
if (modelsResponse.ok) {
|
|
120
|
+
const modelsData = await modelsResponse.json();
|
|
121
|
+
if (modelsData.data && Array.isArray(modelsData.data)) {
|
|
122
|
+
// Include popular Claude, GPT, and other models
|
|
123
|
+
const relevantModels = modelsData.data.filter(model => {
|
|
124
|
+
const id = model.id.toLowerCase();
|
|
125
|
+
return id.includes('claude') ||
|
|
126
|
+
id.includes('gpt') ||
|
|
127
|
+
id.includes('gemini') ||
|
|
128
|
+
id.includes('llama') ||
|
|
129
|
+
id.includes('mistral') ||
|
|
130
|
+
id.includes('deepseek') ||
|
|
131
|
+
id.includes('qwen');
|
|
132
|
+
});
|
|
133
|
+
|
|
134
|
+
// Limit to top 50 most relevant models to avoid overwhelming the UI
|
|
135
|
+
relevantModels.slice(0, 50).forEach(model => {
|
|
136
|
+
models[model.id] = {
|
|
137
|
+
remainingFraction: creditFraction,
|
|
138
|
+
resetTime: null
|
|
139
|
+
};
|
|
140
|
+
});
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
// If no models found, add common defaults
|
|
145
|
+
if (Object.keys(models).length === 0) {
|
|
146
|
+
const defaultModels = [
|
|
147
|
+
'anthropic/claude-sonnet-4',
|
|
148
|
+
'anthropic/claude-3.5-sonnet',
|
|
149
|
+
'openai/gpt-4o',
|
|
150
|
+
'openai/gpt-4o-mini',
|
|
151
|
+
'google/gemini-2.5-pro-preview',
|
|
152
|
+
'meta-llama/llama-3.1-405b-instruct',
|
|
153
|
+
'deepseek/deepseek-r1'
|
|
154
|
+
];
|
|
155
|
+
defaultModels.forEach(modelId => {
|
|
156
|
+
models[modelId] = {
|
|
157
|
+
remainingFraction: creditFraction,
|
|
158
|
+
resetTime: null
|
|
159
|
+
};
|
|
160
|
+
});
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
return { models };
|
|
164
|
+
} catch (error) {
|
|
165
|
+
this.error('Failed to fetch quotas', error);
|
|
166
|
+
return {
|
|
167
|
+
models: {
|
|
168
|
+
'anthropic/claude-sonnet-4': { remainingFraction: 1.0, resetTime: null },
|
|
169
|
+
'openai/gpt-4o': { remainingFraction: 1.0, resetTime: null }
|
|
170
|
+
}
|
|
171
|
+
};
|
|
172
|
+
}
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
/**
|
|
176
|
+
* Get subscription tier from OpenRouter key info
|
|
177
|
+
*
|
|
178
|
+
* @param {Object} account - Account object
|
|
179
|
+
* @param {string} token - API key
|
|
180
|
+
* @returns {Promise<{tier: string, projectId: null}>}
|
|
181
|
+
*/
|
|
182
|
+
async getSubscriptionTier(account, token) {
|
|
183
|
+
try {
|
|
184
|
+
const response = await fetch('https://openrouter.ai/api/v1/auth/key', {
|
|
185
|
+
method: 'GET',
|
|
186
|
+
headers: {
|
|
187
|
+
'Authorization': `Bearer ${token}`,
|
|
188
|
+
'HTTP-Referer': 'https://github.com/AryanVBW/CommonsProxy',
|
|
189
|
+
'X-Title': 'CommonsProxy'
|
|
190
|
+
}
|
|
191
|
+
});
|
|
192
|
+
|
|
193
|
+
if (response.ok) {
|
|
194
|
+
const data = await response.json();
|
|
195
|
+
const isFreeTier = data.data?.is_free_tier || false;
|
|
196
|
+
return {
|
|
197
|
+
tier: isFreeTier ? 'free' : 'paid',
|
|
198
|
+
projectId: null
|
|
199
|
+
};
|
|
200
|
+
}
|
|
201
|
+
} catch (error) {
|
|
202
|
+
this.debug('Failed to fetch subscription tier', error.message);
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
return { tier: 'unknown', projectId: null };
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
/**
|
|
209
|
+
* Get available models from OpenRouter
|
|
210
|
+
*
|
|
211
|
+
* @param {Object} account - Account object
|
|
212
|
+
* @param {string} token - API key
|
|
213
|
+
* @returns {Promise<Array>} List of available models
|
|
214
|
+
*/
|
|
215
|
+
async getAvailableModels(account, token) {
|
|
216
|
+
try {
|
|
217
|
+
const response = await fetch('https://openrouter.ai/api/v1/models', {
|
|
218
|
+
method: 'GET',
|
|
219
|
+
headers: {
|
|
220
|
+
'Authorization': `Bearer ${token}`,
|
|
221
|
+
'HTTP-Referer': 'https://github.com/AryanVBW/CommonsProxy',
|
|
222
|
+
'X-Title': 'CommonsProxy'
|
|
223
|
+
}
|
|
224
|
+
});
|
|
225
|
+
|
|
226
|
+
if (!response.ok) {
|
|
227
|
+
throw new Error(`Failed to fetch models: ${response.status}`);
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
const data = await response.json();
|
|
231
|
+
if (data.data && Array.isArray(data.data)) {
|
|
232
|
+
return data.data.map(model => {
|
|
233
|
+
const id = model.id.toLowerCase();
|
|
234
|
+
let family = 'other';
|
|
235
|
+
if (id.includes('claude')) family = 'claude';
|
|
236
|
+
else if (id.includes('gpt')) family = 'gpt';
|
|
237
|
+
else if (id.includes('gemini')) family = 'gemini';
|
|
238
|
+
else if (id.startsWith('o1') || id.startsWith('o3')) family = 'o1';
|
|
239
|
+
else if (id.includes('llama')) family = 'llama';
|
|
240
|
+
else if (id.includes('mistral')) family = 'mistral';
|
|
241
|
+
else if (id.includes('deepseek')) family = 'deepseek';
|
|
242
|
+
|
|
243
|
+
return {
|
|
244
|
+
id: model.id,
|
|
245
|
+
name: model.name || model.id,
|
|
246
|
+
family
|
|
247
|
+
};
|
|
248
|
+
});
|
|
249
|
+
}
|
|
250
|
+
|
|
251
|
+
return [];
|
|
252
|
+
} catch (error) {
|
|
253
|
+
this.error('Failed to fetch available models', error);
|
|
254
|
+
return [];
|
|
255
|
+
}
|
|
256
|
+
}
|
|
257
|
+
|
|
258
|
+
/**
|
|
259
|
+
* Parse OpenRouter rate limit headers
|
|
260
|
+
* OpenRouter uses standard rate limit headers
|
|
261
|
+
*
|
|
262
|
+
* @param {Response} response - Fetch response
|
|
263
|
+
* @param {Object} errorData - Error data from response body
|
|
264
|
+
* @returns {Object|null} Rate limit info
|
|
265
|
+
*/
|
|
266
|
+
parseRateLimitInfo(response, errorData = null) {
|
|
267
|
+
// OpenRouter uses these headers:
|
|
268
|
+
// x-ratelimit-limit-requests
|
|
269
|
+
// x-ratelimit-remaining-requests
|
|
270
|
+
// x-ratelimit-reset-requests
|
|
271
|
+
const resetRequests = response.headers.get('x-ratelimit-reset-requests');
|
|
272
|
+
const retryAfter = response.headers.get('retry-after');
|
|
273
|
+
|
|
274
|
+
if (retryAfter) {
|
|
275
|
+
const seconds = parseInt(retryAfter, 10);
|
|
276
|
+
if (!isNaN(seconds)) {
|
|
277
|
+
return {
|
|
278
|
+
resetTime: new Date(Date.now() + seconds * 1000),
|
|
279
|
+
retryAfter: seconds
|
|
280
|
+
};
|
|
281
|
+
}
|
|
282
|
+
}
|
|
283
|
+
|
|
284
|
+
if (resetRequests) {
|
|
285
|
+
const resetDate = new Date(resetRequests);
|
|
286
|
+
if (!isNaN(resetDate.getTime())) {
|
|
287
|
+
return {
|
|
288
|
+
resetTime: resetDate,
|
|
289
|
+
retryAfter: Math.max(0, Math.floor((resetDate - Date.now()) / 1000))
|
|
290
|
+
};
|
|
291
|
+
}
|
|
292
|
+
}
|
|
293
|
+
|
|
294
|
+
// Check error response for rate limit info
|
|
295
|
+
if (errorData?.error?.code === 429 || errorData?.error?.message?.includes('rate limit')) {
|
|
296
|
+
return {
|
|
297
|
+
resetTime: new Date(Date.now() + 60000),
|
|
298
|
+
retryAfter: 60
|
|
299
|
+
};
|
|
300
|
+
}
|
|
301
|
+
|
|
302
|
+
return null;
|
|
303
|
+
}
|
|
304
|
+
|
|
305
|
+
/**
|
|
306
|
+
* Check if error indicates invalid API key
|
|
307
|
+
*
|
|
308
|
+
* @param {Error} error - Error object
|
|
309
|
+
* @returns {boolean}
|
|
310
|
+
*/
|
|
311
|
+
shouldInvalidateCredentials(error) {
|
|
312
|
+
if (error.message && (
|
|
313
|
+
error.message.includes('invalid_api_key') ||
|
|
314
|
+
error.message.includes('Invalid API key') ||
|
|
315
|
+
error.message.includes('No auth credentials found') ||
|
|
316
|
+
error.message.includes('authentication')
|
|
317
|
+
)) {
|
|
318
|
+
return true;
|
|
319
|
+
}
|
|
320
|
+
|
|
321
|
+
return super.shouldInvalidateCredentials(error);
|
|
322
|
+
}
|
|
323
|
+
}
|
|
324
|
+
|
|
325
|
+
export default OpenRouterProvider;
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Provider Setup
|
|
3
|
+
*
|
|
4
|
+
* Initializes and registers all available providers.
|
|
5
|
+
* Called during server startup.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
import { registerProvider, listProviders, getAllAuthProviders } from './index.js';
|
|
9
|
+
import { CloudCodeProvider } from './cloudcode.js';
|
|
10
|
+
import { createOpenAICompatibleProvider } from './openai-compatible.js';
|
|
11
|
+
import { config } from '../config.js';
|
|
12
|
+
import { logger } from '../utils/logger.js';
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* Initialize all providers
|
|
16
|
+
* Registers built-in messaging providers and any custom providers from config.
|
|
17
|
+
* Note: Authentication providers (Google, Anthropic, OpenAI, GitHub, Copilot)
|
|
18
|
+
* are registered automatically in providers/index.js
|
|
19
|
+
*/
|
|
20
|
+
export function initializeProviders() {
|
|
21
|
+
logger.info('[Providers] Initializing provider system...');
|
|
22
|
+
|
|
23
|
+
// Register built-in messaging providers (for request routing)
|
|
24
|
+
registerProvider(CloudCodeProvider);
|
|
25
|
+
|
|
26
|
+
// Register custom OpenAI-compatible providers from config
|
|
27
|
+
const customProviders = config?.providers?.custom || [];
|
|
28
|
+
for (const providerConfig of customProviders) {
|
|
29
|
+
if (providerConfig.enabled !== false) {
|
|
30
|
+
try {
|
|
31
|
+
const provider = createOpenAICompatibleProvider(providerConfig);
|
|
32
|
+
registerProvider(provider);
|
|
33
|
+
} catch (error) {
|
|
34
|
+
logger.error(`[Providers] Failed to register custom provider ${providerConfig.id}: ${error.message}`);
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
// Log registered providers
|
|
40
|
+
const messagingProviders = listProviders();
|
|
41
|
+
const authProviders = getAllAuthProviders();
|
|
42
|
+
logger.success(`[Providers] Initialized ${messagingProviders.length} messaging provider(s): ${messagingProviders.map(p => p.id).join(', ')}`);
|
|
43
|
+
logger.success(`[Providers] ${authProviders.length} auth provider(s) available: ${authProviders.map(p => p.id).join(', ')}`);
|
|
44
|
+
|
|
45
|
+
return messagingProviders;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
/**
|
|
49
|
+
* Get provider configuration schema
|
|
50
|
+
* Used for WebUI settings
|
|
51
|
+
*/
|
|
52
|
+
export function getProviderConfigSchema() {
|
|
53
|
+
return {
|
|
54
|
+
cloudcode: {
|
|
55
|
+
name: 'Google Cloud Code',
|
|
56
|
+
description: 'Default provider using Google Cloud Code API',
|
|
57
|
+
configurable: false // Always enabled
|
|
58
|
+
},
|
|
59
|
+
copilot: {
|
|
60
|
+
name: 'GitHub Copilot',
|
|
61
|
+
description: 'Use GitHub Copilot API for model access',
|
|
62
|
+
fields: [
|
|
63
|
+
{ key: 'enabled', type: 'boolean', label: 'Enable GitHub Copilot', default: false }
|
|
64
|
+
]
|
|
65
|
+
},
|
|
66
|
+
custom: {
|
|
67
|
+
name: 'Custom OpenAI-Compatible',
|
|
68
|
+
description: 'Add custom OpenAI-compatible API endpoints',
|
|
69
|
+
fields: [
|
|
70
|
+
{ key: 'id', type: 'string', label: 'Provider ID', required: true },
|
|
71
|
+
{ key: 'name', type: 'string', label: 'Display Name', required: true },
|
|
72
|
+
{ key: 'baseUrl', type: 'string', label: 'API Base URL', required: true },
|
|
73
|
+
{ key: 'apiKey', type: 'password', label: 'API Key', required: false },
|
|
74
|
+
{ key: 'enabled', type: 'boolean', label: 'Enabled', default: true }
|
|
75
|
+
]
|
|
76
|
+
}
|
|
77
|
+
};
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
export default {
|
|
81
|
+
initializeProviders,
|
|
82
|
+
getProviderConfigSchema
|
|
83
|
+
};
|