@tiens.nguyen/gonext-local-worker 1.0.152 → 1.0.155
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/gonext-local-worker.mjs +54 -23
- package/package.json +1 -1
package/gonext-local-worker.mjs
CHANGED
|
@@ -143,6 +143,8 @@ const OCR_CORRECT_TIMEOUT_MS = 120_000;
|
|
|
143
143
|
// cold load of a big/multimodal model into VRAM can take ~20s+; the request isn't
|
|
144
144
|
// awaited, so a long ceiling just avoids aborting an in-progress load.
|
|
145
145
|
const AGENT_WARMUP_TIMEOUT_MS = 180_000;
|
|
146
|
+
// How often the background keep-warm re-asserts the coding model's keep_alive:-1.
|
|
147
|
+
const AGENT_WARMUP_INTERVAL_MS = 240_000; // 4 min — under Ollama's 5-min default unload
|
|
146
148
|
// OCR translation/correction is hardcoded to a managed Ollama service + model.
|
|
147
149
|
// (The user-configurable "OCR translation model" chooser was removed.)
|
|
148
150
|
const OCR_TRANSLATE_OLLAMA_URL = "https://ollama1.gomarsic.cc";
|
|
@@ -1436,33 +1438,37 @@ async function runTranscribeJob(job) {
|
|
|
1436
1438
|
}
|
|
1437
1439
|
}
|
|
1438
1440
|
|
|
1439
|
-
|
|
1440
|
-
|
|
1441
|
-
|
|
1442
|
-
|
|
1443
|
-
|
|
1444
|
-
|
|
1445
|
-
|
|
1446
|
-
|
|
1447
|
-
|
|
1448
|
-
|
|
1449
|
-
|
|
1450
|
-
|
|
1451
|
-
|
|
1452
|
-
|
|
1453
|
-
|
|
1454
|
-
const root = String(codingBaseURL).replace(/\/+$/, "").replace(/\/v1$/i, "");
|
|
1441
|
+
// —— Ollama coding-model keep-warm ——————————————————————————————————————————————
|
|
1442
|
+
// Ollama evicts idle models (default OLLAMA_KEEP_ALIVE=5m), so a cold agent step
|
|
1443
|
+
// blocks ~20s+ while llama-server pages the weights into VRAM. Instead of warming on
|
|
1444
|
+
// EVERY question (noisy, redundant), we remember the coding model from agent jobs and
|
|
1445
|
+
// re-assert a keep_alive:-1 load on a BACKGROUND INTERVAL so it stays resident between
|
|
1446
|
+
// questions. The agent talks to Ollama over /v1 (which ignores keep_alive), so we hit
|
|
1447
|
+
// the NATIVE /api/generate (no prompt = load-only, returns once the model is resident).
|
|
1448
|
+
// Best-effort throughout: a non-Ollama coding server just 404s and it's swallowed.
|
|
1449
|
+
let _warmCoding = null; // { root, model }
|
|
1450
|
+
let _warmTimer = null;
|
|
1451
|
+
let _warmLoggedOk = false;
|
|
1452
|
+
|
|
1453
|
+
function _warmupPing(quiet) {
|
|
1454
|
+
if (!_warmCoding) return;
|
|
1455
|
+
const { root, model } = _warmCoding;
|
|
1455
1456
|
const url = `${root}/api/generate`;
|
|
1456
1457
|
fetch(url, {
|
|
1457
1458
|
method: "POST",
|
|
1458
1459
|
headers: { "Content-Type": "application/json" },
|
|
1459
|
-
body: JSON.stringify({ model
|
|
1460
|
+
body: JSON.stringify({ model, keep_alive: -1 }),
|
|
1460
1461
|
signal: AbortSignal.timeout(AGENT_WARMUP_TIMEOUT_MS),
|
|
1461
1462
|
})
|
|
1462
1463
|
.then((res) => {
|
|
1463
|
-
|
|
1464
|
-
`[gonext-worker] agent warm-up
|
|
1465
|
-
)
|
|
1464
|
+
if (!res.ok) {
|
|
1465
|
+
console.log(`[gonext-worker] agent warm-up HTTP ${res.status} → ${url} model=${model}`);
|
|
1466
|
+
} else if (!quiet || !_warmLoggedOk) {
|
|
1467
|
+
// Quiet interval pings only log the first success per model; a fresh/changed
|
|
1468
|
+
// model always logs so you can see it warm.
|
|
1469
|
+
console.log(`[gonext-worker] agent warm-up ok (model loading/resident) → ${url} model=${model}`);
|
|
1470
|
+
_warmLoggedOk = true;
|
|
1471
|
+
}
|
|
1466
1472
|
})
|
|
1467
1473
|
.catch((err) => {
|
|
1468
1474
|
const reason =
|
|
@@ -1471,12 +1477,37 @@ function warmUpOllamaCodingModel(codingBaseURL, codingModelId) {
|
|
|
1471
1477
|
});
|
|
1472
1478
|
}
|
|
1473
1479
|
|
|
1480
|
+
/**
|
|
1481
|
+
* Remember the agent's Ollama coding model (from a claimed agent_chat job) and keep it
|
|
1482
|
+
* resident via a background interval. Warms IMMEDIATELY only when the model is first
|
|
1483
|
+
* seen or CHANGES — not on every question — so repeat questions don't re-warm/re-log.
|
|
1484
|
+
*/
|
|
1485
|
+
function trackCodingModelForWarmup(codingBaseURL, codingModelId) {
|
|
1486
|
+
if (!codingBaseURL || !codingModelId) return;
|
|
1487
|
+
// codingBaseURL is normalized to …/v1 for OpenAI-compat; strip it to reach the
|
|
1488
|
+
// Ollama root where /api/generate lives.
|
|
1489
|
+
const root = String(codingBaseURL).replace(/\/+$/, "").replace(/\/v1$/i, "");
|
|
1490
|
+
const changed = !_warmCoding || _warmCoding.root !== root || _warmCoding.model !== codingModelId;
|
|
1491
|
+
_warmCoding = { root, model: codingModelId };
|
|
1492
|
+
if (changed) {
|
|
1493
|
+
_warmLoggedOk = false;
|
|
1494
|
+
_warmupPing(false); // warm the newly-seen/changed model now so the next question isn't cold
|
|
1495
|
+
}
|
|
1496
|
+
if (!_warmTimer) {
|
|
1497
|
+
// 4 min — under Ollama's 5-min default unload, so the model stays resident even
|
|
1498
|
+
// if a proxy strips keep_alive. unref() so this timer never blocks worker exit.
|
|
1499
|
+
_warmTimer = setInterval(() => _warmupPing(true), AGENT_WARMUP_INTERVAL_MS);
|
|
1500
|
+
if (typeof _warmTimer.unref === "function") _warmTimer.unref();
|
|
1501
|
+
}
|
|
1502
|
+
}
|
|
1503
|
+
|
|
1474
1504
|
async function runAgentChatJob(job) {
|
|
1475
1505
|
const { jobId, payload } = job;
|
|
1476
1506
|
const start = Date.now();
|
|
1477
|
-
//
|
|
1478
|
-
//
|
|
1479
|
-
|
|
1507
|
+
// Remember this job's Ollama coding model and keep it resident via a background
|
|
1508
|
+
// interval. Only warms now if the model is new/changed — repeat questions rely on
|
|
1509
|
+
// the interval, so we don't re-warm (or re-log) on every question.
|
|
1510
|
+
trackCodingModelForWarmup(payload?.codingBaseURL ?? "", payload?.codingModelId ?? "");
|
|
1480
1511
|
const runRes = await workerFetch(`/api/worker/jobs/${jobId}`, {
|
|
1481
1512
|
method: "PATCH",
|
|
1482
1513
|
body: JSON.stringify({ jobStatus: "running" }),
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@tiens.nguyen/gonext-local-worker",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.155",
|
|
4
4
|
"description": "Polls GoNext cloud API for async local LLM jobs and runs them against Ollama/OpenAI-compatible servers on this Mac",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"license": "MIT",
|