freegate 0.6.17 → 0.6.20
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/.env.example +13 -1
- package/README.md +19 -7
- package/README.ru.md +21 -7
- package/assets/dashboard-en.gif +0 -0
- package/assets/dashboard-en.png +0 -0
- package/assets/dashboard-models-en.png +0 -0
- package/assets/dashboard-models.png +0 -0
- package/assets/dashboard.gif +0 -0
- package/assets/dashboard.png +0 -0
- package/bin/freegate.js +122 -0
- package/config.example.json +39 -0
- package/lib/cache.js +19 -4
- package/lib/compress.js +85 -0
- package/lib/contextstats.js +2 -2
- package/lib/dashboard.js +378 -135
- package/lib/doctor.js +106 -0
- package/lib/health.js +48 -0
- package/lib/methodology.js +23 -2
- package/lib/modelscan.js +7 -2
- package/lib/onboarding.js +79 -0
- package/lib/setup.js +136 -0
- package/lib/strategy.js +57 -0
- package/lib/taskclassify.js +44 -3
- package/lib/vetting.js +91 -0
- package/lib/websearch.js +75 -0
- package/package.json +1 -1
- package/providers.json +264 -0
- package/server.js +127 -9
package/lib/vetting.js
ADDED
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
// lib/vetting.js — самопроверка ответа второй моделью.
|
|
2
|
+
// После получения ответа от free-модели (не-stream) отправляем краткий чек
|
|
3
|
+
// другой модели: выявить фактические/логические ошибки. Экономит free-лимиты:
|
|
4
|
+
// включается только по конфигу и только когда ответ достаточно содержательный.
|
|
5
|
+
const logger = require('./logger');
|
|
6
|
+
|
|
7
|
+
const VETTING_DEFAULTS = {
|
|
8
|
+
enabled: false, // выкл по умолчанию — жжёт 2-й лимит на каждый запрос
|
|
9
|
+
minAnswerLen: 120, // мельче — нечего проверять
|
|
10
|
+
maxChecksPerMin: 4, // троттлинг: не больше N проверок в минуту
|
|
11
|
+
complexityOnly: true, // только сложные/кодинг-задачи
|
|
12
|
+
};
|
|
13
|
+
|
|
14
|
+
const SYSTEM = 'Ты — строгий проверяльщик. Перечитай ответ, который дал другой ИИ, и найди ФАКТИЧЕСКИЕ или ЛОГИЧЕСКИЕ ошибки. Отвечай ТОЛЬКО одним из: "OK" (если ошибок нет) или "Замечание: <кратко, 1 фраза>" (если есть реальная ошибка). Не выдумывай — проверяй только то, что очевидно неверно. Не хвали и не повторяй ответ.';
|
|
15
|
+
|
|
16
|
+
// Проверить, стоит ли вообще запускать проверку.
|
|
17
|
+
function shouldVet({ config = {}, complexity = 0, answerLen = 0, category = '' } = {}) {
|
|
18
|
+
const cfg = Object.assign({}, VETTING_DEFAULTS, config);
|
|
19
|
+
if (!cfg.enabled) return false;
|
|
20
|
+
if (answerLen < cfg.minAnswerLen) return false;
|
|
21
|
+
// complexityOnly: vetting только для coding/design/reasoning (сложных задач);
|
|
22
|
+
// поиск/чат не тратим лишний лимит.
|
|
23
|
+
if (cfg.complexityOnly) {
|
|
24
|
+
const complexCats = new Set(['coding', 'design', 'reasoning']);
|
|
25
|
+
if (complexCats.has(category)) return true;
|
|
26
|
+
if (complexity >= 0.5) return true;
|
|
27
|
+
return false;
|
|
28
|
+
}
|
|
29
|
+
return true;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
// Разобрать ответ проверяльщика → { ok:boolean, note:string }
|
|
33
|
+
function parseVerdict(text) {
|
|
34
|
+
const s = String(text || '').trim();
|
|
35
|
+
if (!s) return { ok: true, note: '' };
|
|
36
|
+
if (/^\s*ok\b/i.test(s)) return { ok: true, note: '' };
|
|
37
|
+
const m = s.match(/замечание\s*[:\-]?\s*(.*)/i);
|
|
38
|
+
if (m && m[1] && m[1].trim()) return { ok: false, note: m[1].trim().slice(0, 200) };
|
|
39
|
+
// Иначе считаем OK (неопределённый ответ не блокируем).
|
|
40
|
+
return { ok: true, note: '' };
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
// Троттлинг: кольцевой буфер времени последних проверок.
|
|
44
|
+
let lastChecks = [];
|
|
45
|
+
|
|
46
|
+
function allowCheck(now = Date.now(), maxPerMin = VETTING_DEFAULTS.maxChecksPerMin) {
|
|
47
|
+
if (!Array.isArray(lastChecks)) lastChecks = [];
|
|
48
|
+
const cutoff = now - 60000;
|
|
49
|
+
lastChecks = lastChecks.filter((t) => t > cutoff);
|
|
50
|
+
if (lastChecks.length >= maxPerMin) return false;
|
|
51
|
+
lastChecks.push(now);
|
|
52
|
+
return true;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
function resetThrottle() { lastChecks = []; }
|
|
56
|
+
|
|
57
|
+
// Запустить проверку: body = второй вызов к провайдеру (callProvider).
|
|
58
|
+
// Вернёт { checked:boolean, ok:boolean, note:string }.
|
|
59
|
+
async function vetAnswer({ answer, callProvider, picks = [], config = {}, now = Date.now() }) {
|
|
60
|
+
const cfg = Object.assign({}, VETTING_DEFAULTS, config);
|
|
61
|
+
if (!answer || typeof answer !== 'string') return { checked: false, ok: true, note: '' };
|
|
62
|
+
if (!picks || picks.length === 0) return { checked: false, ok: true, note: '' };
|
|
63
|
+
if (!allowCheck(now, cfg.maxChecksPerMin)) return { checked: false, ok: true, note: '' };
|
|
64
|
+
|
|
65
|
+
// Пробуем других провайдеров (не тот, что дал ответ), пока один не проверит.
|
|
66
|
+
for (const provider of picks) {
|
|
67
|
+
try {
|
|
68
|
+
const result = await callProvider(provider, {
|
|
69
|
+
model: provider.model,
|
|
70
|
+
messages: [
|
|
71
|
+
{ role: 'system', content: SYSTEM },
|
|
72
|
+
{ role: 'user', content: 'Проверь этот ответ на ошибки. Ответ:\n\n' + answer.slice(0, 4000) },
|
|
73
|
+
],
|
|
74
|
+
temperature: 0,
|
|
75
|
+
max_tokens: 120,
|
|
76
|
+
}, 20000, 1);
|
|
77
|
+
const text = result && result.data && result.data.choices && result.data.choices[0] &&
|
|
78
|
+
result.data.choices[0].message && result.data.choices[0].message.content;
|
|
79
|
+
if (text && text.trim()) {
|
|
80
|
+
const verdict = parseVerdict(text);
|
|
81
|
+
return { checked: true, ok: verdict.ok, note: verdict.note, by: provider.key || provider.model };
|
|
82
|
+
}
|
|
83
|
+
} catch (err) {
|
|
84
|
+
// пробуем следующего
|
|
85
|
+
logger.debug('vetting failed', { provider: provider.key, error: err.message });
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
return { checked: false, ok: true, note: '' };
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
module.exports = { shouldVet, parseVerdict, vetAnswer, allowCheck, resetThrottle, VETTING_DEFAULTS, SYSTEM };
|
package/lib/websearch.js
ADDED
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
// lib/websearch.js — веб-поиск для search-задач (бесплатно, без ключа).
|
|
2
|
+
// Используется, чтобы Freegate находил факты вместо галлюцинаций («что такое
|
|
3
|
+
// минимакс дизайн» → реальные данные о MiniMax, а не «минимализм»).
|
|
4
|
+
// Источник: DuckDuckGo HTML (без API-ключа). Вся сеть через injectable fetchImpl.
|
|
5
|
+
// parseDdg() — парсер HTML; search() — обёртка с таймаутом и защитой от сбоев.
|
|
6
|
+
|
|
7
|
+
const DDG_URL = 'https://html.duckduckgo.com/html/';
|
|
8
|
+
|
|
9
|
+
const isObject = (v) => v && typeof v === 'object';
|
|
10
|
+
|
|
11
|
+
// Декодирует URL, обфусцированный DDG (//duckduckgo.com/l/?uddg=<enc>&rut=..).
|
|
12
|
+
function decodeUrl(raw) {
|
|
13
|
+
if (!raw) return '';
|
|
14
|
+
if (!raw.includes('uddg=')) return raw;
|
|
15
|
+
try {
|
|
16
|
+
const m = raw.match(/[?&]uddg=([^&]+)/);
|
|
17
|
+
if (!m) return raw;
|
|
18
|
+
return decodeURIComponent(m[1]);
|
|
19
|
+
} catch {
|
|
20
|
+
return raw;
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
// Извлекает блоки результатов: title, url, snippet.
|
|
25
|
+
function parseDdg(html) {
|
|
26
|
+
const out = [];
|
|
27
|
+
if (!html || typeof html !== 'string') return out;
|
|
28
|
+
// Каждый результат — блок с result__a (заголовок+ссылка) и опц. result__snippet.
|
|
29
|
+
const blocks = html.split('class="result results_links').slice(1);
|
|
30
|
+
for (const b of blocks) {
|
|
31
|
+
const titleM = b.match(/class="result__a"[^>]*>([^<]+)</);
|
|
32
|
+
const hrefM = b.match(/class="result__a"[^>]*href="([^"]+)"/);
|
|
33
|
+
const snipM = b.match(/class="result__snippet"[^>]*>([\s\S]*?)<\/a>/);
|
|
34
|
+
if (!titleM) continue;
|
|
35
|
+
const title = titleM[1].replace(/&/g, '&').replace(/</g, '<').replace(/>/g, '>').trim();
|
|
36
|
+
const url = decodeUrl(hrefM ? hrefM[1] : '');
|
|
37
|
+
const snippet = snipM
|
|
38
|
+
? snipM[1].replace(/<[^>]+>/g, '').replace(/&/g, '&').replace(/\.\.\./g, '').trim()
|
|
39
|
+
: '';
|
|
40
|
+
if (title && url) out.push({ title, url, snippet: snippet.slice(0, 300) });
|
|
41
|
+
}
|
|
42
|
+
return out;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
// Поиск. Возвращает [{title,url,snippet}]; при любой ошибке — [] (не бросает).
|
|
46
|
+
async function search(query, { fetchImpl, limit = 5, timeout = 8000 } = {}) {
|
|
47
|
+
if (!fetchImpl || !query) return [];
|
|
48
|
+
// DDG предпочитает '+' для пробелов (encodeURIComponent даёт %20 → может вернуть
|
|
49
|
+
// anti-bot 202 без результатов). Кодируем, затем пробелы → '+'.
|
|
50
|
+
const p = encodeURIComponent(query).replace(/%20/g, '+');
|
|
51
|
+
const url = DDG_URL + '?q=' + p;
|
|
52
|
+
try {
|
|
53
|
+
const controller = typeof AbortController !== 'undefined' ? new AbortController() : null;
|
|
54
|
+
const timer = controller ? setTimeout(() => controller.abort(), timeout) : null;
|
|
55
|
+
const res = await fetchImpl(url, {
|
|
56
|
+
headers: { 'User-Agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120 Safari/537.36' },
|
|
57
|
+
signal: controller ? controller.signal : undefined,
|
|
58
|
+
});
|
|
59
|
+
if (timer) clearTimeout(timer);
|
|
60
|
+
if (!res || !res.ok) return [];
|
|
61
|
+
const html = await res.text();
|
|
62
|
+
return parseDdg(html).slice(0, limit);
|
|
63
|
+
} catch {
|
|
64
|
+
return [];
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
// Собирает контекст для промпта: заголовки + ссылки + сниппеты.
|
|
69
|
+
function toContext(results, query) {
|
|
70
|
+
if (!Array.isArray(results) || results.length === 0) return '';
|
|
71
|
+
const lines = results.map((r, i) => `${i + 1}. ${r.title} — ${r.url}${r.snippet ? ' | ' + r.snippet : ''}`);
|
|
72
|
+
return 'Актуальные данные из веб-поиска («' + query + '»):\n' + lines.join('\n');
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
module.exports = { DDG_URL, decodeUrl, parseDdg, search, toContext, isObject };
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "freegate",
|
|
3
|
-
"version": "0.6.
|
|
3
|
+
"version": "0.6.20",
|
|
4
4
|
"description": "Free multi-provider LLM gateway with automatic failover. One OpenAI-compatible endpoint routes to 25 free models (Groq, Mistral, Gemini, NIM, OpenRouter, ZAI, Cerebras, DeepSeek). Never pay for LLMs.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"bin": {
|
package/providers.json
CHANGED
|
@@ -370,5 +370,269 @@
|
|
|
370
370
|
"envVar": "PROVIDER_MISTRAL_APIKEY",
|
|
371
371
|
"free": true,
|
|
372
372
|
"category": "coding"
|
|
373
|
+
},
|
|
374
|
+
"sambanova-gpt-oss-120b": {
|
|
375
|
+
"endpoint": "https://api.sambanova.ai/v1/chat/completions",
|
|
376
|
+
"model": "gpt-oss-120b",
|
|
377
|
+
"priority": 12,
|
|
378
|
+
"dailyLimit": 100000,
|
|
379
|
+
"keyHint": "cloud.sambanova.ai → API Keys",
|
|
380
|
+
"envVar": "PROVIDER_SAMBANOVA_APIKEY",
|
|
381
|
+
"free": true,
|
|
382
|
+
"category": "general",
|
|
383
|
+
"context_window": 131072
|
|
384
|
+
},
|
|
385
|
+
"sambanova-minimax-m2": {
|
|
386
|
+
"endpoint": "https://api.sambanova.ai/v1/chat/completions",
|
|
387
|
+
"model": "MiniMax-M2.7",
|
|
388
|
+
"priority": 13,
|
|
389
|
+
"dailyLimit": 100000,
|
|
390
|
+
"keyHint": "cloud.sambanova.ai → API Keys",
|
|
391
|
+
"envVar": "PROVIDER_SAMBANOVA_APIKEY",
|
|
392
|
+
"free": true,
|
|
393
|
+
"category": "reasoning",
|
|
394
|
+
"context_window": 131072
|
|
395
|
+
},
|
|
396
|
+
"sambanova-deepseek-v3": {
|
|
397
|
+
"endpoint": "https://api.sambanova.ai/v1/chat/completions",
|
|
398
|
+
"model": "DeepSeek-V3.2",
|
|
399
|
+
"priority": 13,
|
|
400
|
+
"dailyLimit": 100000,
|
|
401
|
+
"keyHint": "cloud.sambanova.ai → API Keys",
|
|
402
|
+
"envVar": "PROVIDER_SAMBANOVA_APIKEY",
|
|
403
|
+
"free": true,
|
|
404
|
+
"category": "reasoning",
|
|
405
|
+
"context_window": 131072
|
|
406
|
+
},
|
|
407
|
+
"sambanova-llama4-maverick": {
|
|
408
|
+
"endpoint": "https://api.sambanova.ai/v1/chat/completions",
|
|
409
|
+
"model": "Llama-4-Maverick-17B-128E-Instruct",
|
|
410
|
+
"priority": 13,
|
|
411
|
+
"dailyLimit": 100000,
|
|
412
|
+
"keyHint": "cloud.sambanova.ai → API Keys",
|
|
413
|
+
"envVar": "PROVIDER_SAMBANOVA_APIKEY",
|
|
414
|
+
"free": true,
|
|
415
|
+
"category": "general",
|
|
416
|
+
"context_window": 1000000
|
|
417
|
+
},
|
|
418
|
+
"sambanova-llama3.3-70b": {
|
|
419
|
+
"endpoint": "https://api.sambanova.ai/v1/chat/completions",
|
|
420
|
+
"model": "Meta-Llama-3.3-70B-Instruct",
|
|
421
|
+
"priority": 14,
|
|
422
|
+
"dailyLimit": 100000,
|
|
423
|
+
"keyHint": "cloud.sambanova.ai → API Keys",
|
|
424
|
+
"envVar": "PROVIDER_SAMBANOVA_APIKEY",
|
|
425
|
+
"free": true,
|
|
426
|
+
"category": "general",
|
|
427
|
+
"context_window": 131072
|
|
428
|
+
},
|
|
429
|
+
"siliconflow-deepseek-r1": {
|
|
430
|
+
"endpoint": "https://api.siliconflow.com/v1/chat/completions",
|
|
431
|
+
"model": "deepseek-ai/DeepSeek-R1",
|
|
432
|
+
"priority": 12,
|
|
433
|
+
"dailyLimit": 100000,
|
|
434
|
+
"keyHint": "cloud.siliconflow.com → API Keys",
|
|
435
|
+
"envVar": "PROVIDER_SILICONFLOW_APIKEY",
|
|
436
|
+
"free": true,
|
|
437
|
+
"category": "reasoning",
|
|
438
|
+
"context_window": 131072
|
|
439
|
+
},
|
|
440
|
+
"siliconflow-qwen3-coder": {
|
|
441
|
+
"endpoint": "https://api.siliconflow.com/v1/chat/completions",
|
|
442
|
+
"model": "Qwen/Qwen3-Coder-480B-A35B-Instruct",
|
|
443
|
+
"priority": 12,
|
|
444
|
+
"dailyLimit": 100000,
|
|
445
|
+
"keyHint": "cloud.siliconflow.com → API Keys",
|
|
446
|
+
"envVar": "PROVIDER_SILICONFLOW_APIKEY",
|
|
447
|
+
"free": true,
|
|
448
|
+
"category": "coding",
|
|
449
|
+
"context_window": 131072
|
|
450
|
+
},
|
|
451
|
+
"siliconflow-qwen3-235b": {
|
|
452
|
+
"endpoint": "https://api.siliconflow.com/v1/chat/completions",
|
|
453
|
+
"model": "Qwen/Qwen3-235B-A22B-Instruct-2507",
|
|
454
|
+
"priority": 13,
|
|
455
|
+
"dailyLimit": 100000,
|
|
456
|
+
"keyHint": "cloud.siliconflow.com → API Keys",
|
|
457
|
+
"envVar": "PROVIDER_SILICONFLOW_APIKEY",
|
|
458
|
+
"free": true,
|
|
459
|
+
"category": "reasoning",
|
|
460
|
+
"context_window": 131072
|
|
461
|
+
},
|
|
462
|
+
"siliconflow-kimi-k2": {
|
|
463
|
+
"endpoint": "https://api.siliconflow.com/v1/chat/completions",
|
|
464
|
+
"model": "moonshotai/Kimi-K2.5",
|
|
465
|
+
"priority": 13,
|
|
466
|
+
"dailyLimit": 100000,
|
|
467
|
+
"keyHint": "cloud.siliconflow.com → API Keys",
|
|
468
|
+
"envVar": "PROVIDER_SILICONFLOW_APIKEY",
|
|
469
|
+
"free": true,
|
|
470
|
+
"category": "general",
|
|
471
|
+
"context_window": 131072
|
|
472
|
+
},
|
|
473
|
+
"siliconflow-glm": {
|
|
474
|
+
"endpoint": "https://api.siliconflow.com/v1/chat/completions",
|
|
475
|
+
"model": "zai-org/GLM-4.7",
|
|
476
|
+
"priority": 14,
|
|
477
|
+
"dailyLimit": 100000,
|
|
478
|
+
"keyHint": "cloud.siliconflow.com → API Keys",
|
|
479
|
+
"envVar": "PROVIDER_SILICONFLOW_APIKEY",
|
|
480
|
+
"free": true,
|
|
481
|
+
"category": "general",
|
|
482
|
+
"context_window": 131072
|
|
483
|
+
},
|
|
484
|
+
"deepinfra-gpt-oss-120b": {
|
|
485
|
+
"endpoint": "https://api.deepinfra.com/v1/openai/chat/completions",
|
|
486
|
+
"model": "openai/gpt-oss-120b",
|
|
487
|
+
"priority": 12,
|
|
488
|
+
"dailyLimit": 100000,
|
|
489
|
+
"keyHint": "deepinfra.com → API Keys",
|
|
490
|
+
"envVar": "PROVIDER_DEEPINFRA_APIKEY",
|
|
491
|
+
"free": true,
|
|
492
|
+
"category": "general",
|
|
493
|
+
"context_window": 131072
|
|
494
|
+
},
|
|
495
|
+
"deepinfra-gpt-oss-20b": {
|
|
496
|
+
"endpoint": "https://api.deepinfra.com/v1/openai/chat/completions",
|
|
497
|
+
"model": "openai/gpt-oss-20b",
|
|
498
|
+
"priority": 13,
|
|
499
|
+
"dailyLimit": 100000,
|
|
500
|
+
"keyHint": "deepinfra.com → API Keys",
|
|
501
|
+
"envVar": "PROVIDER_DEEPINFRA_APIKEY",
|
|
502
|
+
"free": true,
|
|
503
|
+
"category": "general",
|
|
504
|
+
"context_window": 131072
|
|
505
|
+
},
|
|
506
|
+
"deepinfra-nemotron-super-120b": {
|
|
507
|
+
"endpoint": "https://api.deepinfra.com/v1/openai/chat/completions",
|
|
508
|
+
"model": "nvidia/NVIDIA-Nemotron-3-Super-120B-A12B",
|
|
509
|
+
"priority": 12,
|
|
510
|
+
"dailyLimit": 100000,
|
|
511
|
+
"keyHint": "deepinfra.com → API Keys",
|
|
512
|
+
"envVar": "PROVIDER_DEEPINFRA_APIKEY",
|
|
513
|
+
"free": true,
|
|
514
|
+
"category": "reasoning",
|
|
515
|
+
"context_window": 131072
|
|
516
|
+
},
|
|
517
|
+
"deepinfra-llama-4-maverick": {
|
|
518
|
+
"endpoint": "https://api.deepinfra.com/v1/openai/chat/completions",
|
|
519
|
+
"model": "meta-llama/Llama-4-Maverick-17B-128E-Instruct",
|
|
520
|
+
"priority": 14,
|
|
521
|
+
"dailyLimit": 100000,
|
|
522
|
+
"keyHint": "deepinfra.com → API Keys",
|
|
523
|
+
"envVar": "PROVIDER_DEEPINFRA_APIKEY",
|
|
524
|
+
"free": true,
|
|
525
|
+
"category": "general",
|
|
526
|
+
"context_window": 1000000
|
|
527
|
+
},
|
|
528
|
+
"hyperbolic-deepseek-v3": {
|
|
529
|
+
"endpoint": "https://api.hyperbolic.xyz/v1/chat/completions",
|
|
530
|
+
"model": "deepseek-ai/DeepSeek-V3",
|
|
531
|
+
"priority": 14,
|
|
532
|
+
"dailyLimit": 100000,
|
|
533
|
+
"keyHint": "app.hyperbolic.xyz → API Keys",
|
|
534
|
+
"envVar": "PROVIDER_HYPERBOLIC_APIKEY",
|
|
535
|
+
"free": true,
|
|
536
|
+
"category": "reasoning",
|
|
537
|
+
"context_window": 131072
|
|
538
|
+
},
|
|
539
|
+
"hyperbolic-qwen3-coder": {
|
|
540
|
+
"endpoint": "https://api.hyperbolic.xyz/v1/chat/completions",
|
|
541
|
+
"model": "Qwen/Qwen2.5-Coder-32B-Instruct",
|
|
542
|
+
"priority": 14,
|
|
543
|
+
"dailyLimit": 100000,
|
|
544
|
+
"keyHint": "app.hyperbolic.xyz → API Keys",
|
|
545
|
+
"envVar": "PROVIDER_HYPERBOLIC_APIKEY",
|
|
546
|
+
"free": true,
|
|
547
|
+
"category": "coding",
|
|
548
|
+
"context_window": 131072
|
|
549
|
+
},
|
|
550
|
+
"hyperbolic-llama-70b": {
|
|
551
|
+
"endpoint": "https://api.hyperbolic.xyz/v1/chat/completions",
|
|
552
|
+
"model": "meta-llama/Llama-3.3-70B-Instruct",
|
|
553
|
+
"priority": 15,
|
|
554
|
+
"dailyLimit": 100000,
|
|
555
|
+
"keyHint": "app.hyperbolic.xyz → API Keys",
|
|
556
|
+
"envVar": "PROVIDER_HYPERBOLIC_APIKEY",
|
|
557
|
+
"free": true,
|
|
558
|
+
"category": "general",
|
|
559
|
+
"context_window": 131072
|
|
560
|
+
},
|
|
561
|
+
"cohere-command-a": {
|
|
562
|
+
"endpoint": "https://api.cohere.com/compatibility/v1/chat/completions",
|
|
563
|
+
"model": "command-a-03-2025",
|
|
564
|
+
"priority": 15,
|
|
565
|
+
"dailyLimit": 100000,
|
|
566
|
+
"keyHint": "dashboard.cohere.com → API Keys",
|
|
567
|
+
"envVar": "PROVIDER_COHERE_APIKEY",
|
|
568
|
+
"free": true,
|
|
569
|
+
"category": "reasoning",
|
|
570
|
+
"context_window": 131072
|
|
571
|
+
},
|
|
572
|
+
"cohere-command-r-plus": {
|
|
573
|
+
"endpoint": "https://api.cohere.com/compatibility/v1/chat/completions",
|
|
574
|
+
"model": "command-r-plus-08-2024",
|
|
575
|
+
"priority": 16,
|
|
576
|
+
"dailyLimit": 100000,
|
|
577
|
+
"keyHint": "dashboard.cohere.com → API Keys",
|
|
578
|
+
"envVar": "PROVIDER_COHERE_APIKEY",
|
|
579
|
+
"free": true,
|
|
580
|
+
"category": "general",
|
|
581
|
+
"context_window": 131072
|
|
582
|
+
},
|
|
583
|
+
"llm7-gpt4o-mini": {
|
|
584
|
+
"endpoint": "https://api.llm7.io/v1/chat/completions",
|
|
585
|
+
"model": "gpt-4o-mini-2024-07-18",
|
|
586
|
+
"priority": 13,
|
|
587
|
+
"dailyLimit": 100000,
|
|
588
|
+
"keyHint": "llm7.io (бесплатный ключ при регистрации)",
|
|
589
|
+
"envVar": "PROVIDER_LLM7_APIKEY",
|
|
590
|
+
"free": true,
|
|
591
|
+
"category": "general",
|
|
592
|
+
"context_window": 131072
|
|
593
|
+
},
|
|
594
|
+
"llm7-deepseek-r1": {
|
|
595
|
+
"endpoint": "https://api.llm7.io/v1/chat/completions",
|
|
596
|
+
"model": "deepseek-r1-0528",
|
|
597
|
+
"priority": 13,
|
|
598
|
+
"dailyLimit": 100000,
|
|
599
|
+
"keyHint": "llm7.io (бесплатный ключ при регистрации)",
|
|
600
|
+
"envVar": "PROVIDER_LLM7_APIKEY",
|
|
601
|
+
"free": true,
|
|
602
|
+
"category": "reasoning",
|
|
603
|
+
"context_window": 131072
|
|
604
|
+
},
|
|
605
|
+
"nara-mistral-large": {
|
|
606
|
+
"endpoint": "https://router.bynara.id/v1/chat/completions",
|
|
607
|
+
"model": "mistral-large",
|
|
608
|
+
"priority": 13,
|
|
609
|
+
"dailyLimit": 100000,
|
|
610
|
+
"keyHint": "nara — бесплатный ключ через Telegram-канал",
|
|
611
|
+
"envVar": "PROVIDER_NARA_APIKEY",
|
|
612
|
+
"free": true,
|
|
613
|
+
"category": "general",
|
|
614
|
+
"context_window": 252000
|
|
615
|
+
},
|
|
616
|
+
"nara-mistral-medium": {
|
|
617
|
+
"endpoint": "https://router.bynara.id/v1/chat/completions",
|
|
618
|
+
"model": "mistral-medium-3-5",
|
|
619
|
+
"priority": 14,
|
|
620
|
+
"dailyLimit": 100000,
|
|
621
|
+
"keyHint": "nara — бесплатный ключ через Telegram-канал",
|
|
622
|
+
"envVar": "PROVIDER_NARA_APIKEY",
|
|
623
|
+
"free": true,
|
|
624
|
+
"category": "general",
|
|
625
|
+
"context_window": 256000
|
|
626
|
+
},
|
|
627
|
+
"nara-tencent-hy3": {
|
|
628
|
+
"endpoint": "https://router.bynara.id/v1/chat/completions",
|
|
629
|
+
"model": "tencent-hy3",
|
|
630
|
+
"priority": 14,
|
|
631
|
+
"dailyLimit": 100000,
|
|
632
|
+
"keyHint": "nara — бесплатный ключ через Telegram-канал",
|
|
633
|
+
"envVar": "PROVIDER_NARA_APIKEY",
|
|
634
|
+
"free": true,
|
|
635
|
+
"category": "general",
|
|
636
|
+
"context_window": 1000000
|
|
373
637
|
}
|
|
374
638
|
}
|