freegate 0.6.22 → 0.6.23
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/lib/compactor.js +13 -8
- package/lib/dashboard.js +1 -1
- package/package.json +1 -1
- package/server.js +13 -2
package/lib/compactor.js
CHANGED
|
@@ -17,14 +17,19 @@ const KEEP_RECENT_TOKENS = 30000; // tokens — recent messages kept untouched (
|
|
|
17
17
|
const MAX_COMPACT_THRESHOLD = 100000; // est tokens — cap for window-aware thresholds (≈200k real,
|
|
18
18
|
// sits safely inside even 512k/1M windows without compacting too early)
|
|
19
19
|
const SUMMARY_MAX_TOKENS = 2000; // tokens — summary length cap (detailed enough to not lose the work)
|
|
20
|
-
const CHARS_PER_TOKEN = 1.
|
|
21
|
-
// (
|
|
22
|
-
//
|
|
23
|
-
|
|
24
|
-
//
|
|
20
|
+
const CHARS_PER_TOKEN = 1.0; // heuristic chars→tokens. Прежнее 1.5 ДВАЖДЫ завышало
|
|
21
|
+
// оценку (реально ~0.75-0.8 chars/token) → компакции
|
|
22
|
+
// срабатывали почти на каждый второй запрос (53%),
|
|
23
|
+
// каждый — доп. LLM-вызов = медленно + риск «замирания».
|
|
24
|
+
// 1.0 всё ещё с запасом, но почти вдвое меньше лишних
|
|
25
|
+
// компакций. keep-recent и оконные пороги не меняем.
|
|
26
|
+
|
|
27
|
+
// Reliability-ordered long-context summarizers. Порядок важен: getSummary идёт
|
|
28
|
+
// по списку и ждёт ПЕРВЫЙ отвечающий (до 30с). Медленные/непроверенные в начале
|
|
29
|
+
// = «думает и замирает» (компакция тормозит каждый вызов). Бытрые и надёжные вперёд.
|
|
25
30
|
const SUMMARIZERS = [
|
|
26
|
-
'or-
|
|
27
|
-
'or-lfm', '
|
|
31
|
+
'or-dots-3', 'deepseek', 'or-minimax-m2-7-free',
|
|
32
|
+
'or-lfm', 'or-nemotron-35',
|
|
28
33
|
];
|
|
29
34
|
|
|
30
35
|
// Summary cache: hash of compacted messages → summary string.
|
|
@@ -205,7 +210,7 @@ async function summarizeViaChain(messages) {
|
|
|
205
210
|
{ role: 'user', content: 'Сожми следующий диалог:\n\n' + textToSummarize },
|
|
206
211
|
],
|
|
207
212
|
max_tokens: SUMMARY_MAX_TOKENS,
|
|
208
|
-
},
|
|
213
|
+
}, 15000, 1); // 15с на summarizer — быстрое переползание, без «замирания»
|
|
209
214
|
const summary = result.data?.choices?.[0]?.message?.content;
|
|
210
215
|
if (summary && summary.trim().length >= 10) {
|
|
211
216
|
return summary.trim();
|
package/lib/dashboard.js
CHANGED
|
@@ -1112,7 +1112,7 @@ const HTML = `<!DOCTYPE html>
|
|
|
1112
1112
|
var st = health[k] || {};
|
|
1113
1113
|
return '<tr><td class="mono">' + esc(k) + '</td><td>' + errors[k] + '</td><td>' + esc(st.status || '?') + '</td><td>' + esc(st.reason || st.latency_ms || '') + '</td></tr>';
|
|
1114
1114
|
}).sort(function (a, b) {
|
|
1115
|
-
var ma = a.match(/<td>(
|
|
1115
|
+
var ma = a.match(/<td>(\\d+)<\\/td>/), mb = b.match(/<td>(\\d+)<\\/td>/);
|
|
1116
1116
|
return (mb ? parseInt(mb[1], 10) : 0) - (ma ? parseInt(ma[1], 10) : 0);
|
|
1117
1117
|
});
|
|
1118
1118
|
document.getElementById('diagErrorsTable').innerHTML = rows.length
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "freegate",
|
|
3
|
-
"version": "0.6.
|
|
3
|
+
"version": "0.6.23",
|
|
4
4
|
"description": "Free multi-provider LLM gateway with automatic failover. One OpenAI-compatible endpoint routes to many free models (Groq, Mistral, Gemini, NIM, OpenRouter, ZAI, Cerebras, DeepSeek and more). Never pay for LLMs.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"bin": {
|
package/server.js
CHANGED
|
@@ -595,6 +595,17 @@ async function handleChatCompletion(req, res, body) {
|
|
|
595
595
|
.filter(([_, p]) => p.enabled && !isCircuitOpen(p.key) && p.vision !== true &&
|
|
596
596
|
(getHealth()[p.key]?.status === 'up' || getHealth()[p.key]?.status === 'ratelimited'));
|
|
597
597
|
|
|
598
|
+
// Анти-«замирание»: провайдер, накопивший много ошибок сегодня (status остаётся
|
|
599
|
+
// 'up' — это не 429/401, а флап/долгие таймауты), по-прежнему попадает в цепочку
|
|
600
|
+
// и тормозит ответ. Исключаем его из активного пула до конца дня. Если так пул
|
|
601
|
+
// пустеет (все «ошибочные») — вернём их как крайний резерв, чтобы не отдать 503.
|
|
602
|
+
const todayErrors = getStats().errors || {};
|
|
603
|
+
const ERROR_POOL_THRESHOLD = 15;
|
|
604
|
+
const lowErrorProviders = healthyProviders.filter(
|
|
605
|
+
([k]) => (todayErrors[k] || 0) < ERROR_POOL_THRESHOLD
|
|
606
|
+
);
|
|
607
|
+
const healthy2 = lowErrorProviders.length > 0 ? lowErrorProviders : healthyProviders;
|
|
608
|
+
|
|
598
609
|
// Window-aware routing: estimate the request size and only consider providers
|
|
599
610
|
// whose context window can actually hold it. This stops large requests from
|
|
600
611
|
// burning time falling through lfm (65k) / groq (131k) providers that reject
|
|
@@ -603,10 +614,10 @@ async function handleChatCompletion(req, res, body) {
|
|
|
603
614
|
// requests keep the full fast pool.
|
|
604
615
|
const requestTokens = estimateTokens(body.messages);
|
|
605
616
|
const MIN_WINDOW = 50000; // below this we don't filter (typical requests)
|
|
606
|
-
let windowPool =
|
|
617
|
+
let windowPool = healthy2;
|
|
607
618
|
let upgradeNoCapable = false; // апгрейд, но ни один здоровый провайдер не держит запрос
|
|
608
619
|
if (requestTokens > MIN_WINDOW || windowUpgraded) {
|
|
609
|
-
const capable =
|
|
620
|
+
const capable = healthy2.filter(([_, p]) => {
|
|
610
621
|
const win = p.context_window || 0;
|
|
611
622
|
// Unknown/0 window providers are kept (heuristic) — better to try than drop.
|
|
612
623
|
return win === 0 || win >= requestTokens;
|