@tiens.nguyen/gonext-local-worker 1.0.333 → 1.0.335
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-repl.mjs +60 -13
- package/package.json +1 -1
package/gonext-repl.mjs
CHANGED
|
@@ -688,15 +688,33 @@ let wsSync = { enabled: false, name: "", path: "" };
|
|
|
688
688
|
const workspaceKeyFor = (cwd) =>
|
|
689
689
|
createHash("sha256").update(cwd).digest("hex").slice(0, 32);
|
|
690
690
|
|
|
691
|
-
// Task #104: agent CODE-model OUTPUT-token counters. The API keys the
|
|
692
|
-
// (userId + coding-model URL
|
|
693
|
-
//
|
|
691
|
+
// Task #104: agent CODE-model OUTPUT-token counters. The API keys the workspace total on
|
|
692
|
+
// workspaceKey and the GLOBAL total on (userId + coding-model URL). Task #125: the REPL
|
|
693
|
+
// now supplies the URL of the backend in EFFECT this session (activeCodingUrl) so the
|
|
694
|
+
// global total follows a /model backend switch; empty → the API falls back to the
|
|
695
|
+
// account-default URL from settings (older behaviour). All best-effort (never block a turn).
|
|
696
|
+
const activeCodingUrl = () => sessionCodingUrl || defaultCodingUrl;
|
|
697
|
+
|
|
698
|
+
// Task #126: the footer's global "↓" for the CURRENT backend. The saved-full-responses sum
|
|
699
|
+
// (savedResponsesTotal) is authoritative per-URL — and correct even for turns before #125,
|
|
700
|
+
// because each saved row carries its own url — so PREFER it when it has data. Fall back to
|
|
701
|
+
// the #125 incremental counter (globalTotal) when Save-Full-Response is off (no saved rows,
|
|
702
|
+
// so savedResponsesTotal is 0), which keeps a correct non-zero number instead of a
|
|
703
|
+
// surprising 0. Returns null when the response had neither, so callers keep the old value.
|
|
704
|
+
function pickGlobalTotal(t) {
|
|
705
|
+
if (!t) return null;
|
|
706
|
+
const saved = Number.isFinite(t.savedResponsesTotal) ? t.savedResponsesTotal : 0;
|
|
707
|
+
if (saved > 0) return saved;
|
|
708
|
+
return Number.isFinite(t.globalTotal) ? t.globalTotal : null;
|
|
709
|
+
}
|
|
710
|
+
|
|
694
711
|
async function fetchOutputTokenTotals(cwd) {
|
|
695
712
|
try {
|
|
696
|
-
const
|
|
697
|
-
|
|
698
|
-
|
|
699
|
-
|
|
713
|
+
const qs = new URLSearchParams({ workspaceKey: workspaceKeyFor(cwd) });
|
|
714
|
+
if (activeCodingUrl()) qs.set("codingUrl", activeCodingUrl());
|
|
715
|
+
const r = await fetch(`${apiBase}/api/worker/output-tokens?${qs.toString()}`, {
|
|
716
|
+
headers: { "X-Worker-Key": workerKey },
|
|
717
|
+
});
|
|
700
718
|
if (!r.ok) return null;
|
|
701
719
|
return await r.json();
|
|
702
720
|
} catch {
|
|
@@ -710,7 +728,11 @@ async function addOutputTokens(cwd, delta) {
|
|
|
710
728
|
const r = await fetch(`${apiBase}/api/worker/output-tokens`, {
|
|
711
729
|
method: "POST",
|
|
712
730
|
headers: { "Content-Type": "application/json", "X-Worker-Key": workerKey },
|
|
713
|
-
body: JSON.stringify({
|
|
731
|
+
body: JSON.stringify({
|
|
732
|
+
workspaceKey: workspaceKeyFor(cwd),
|
|
733
|
+
delta,
|
|
734
|
+
codingUrl: activeCodingUrl(),
|
|
735
|
+
}),
|
|
714
736
|
});
|
|
715
737
|
if (!r.ok) return null;
|
|
716
738
|
return await r.json();
|
|
@@ -724,6 +746,7 @@ async function resetGlobalOutputTokens() {
|
|
|
724
746
|
const r = await fetch(`${apiBase}/api/worker/output-tokens/reset-global`, {
|
|
725
747
|
method: "POST",
|
|
726
748
|
headers: { "Content-Type": "application/json", "X-Worker-Key": workerKey },
|
|
749
|
+
body: JSON.stringify({ codingUrl: activeCodingUrl() }),
|
|
727
750
|
});
|
|
728
751
|
return r.ok;
|
|
729
752
|
} catch {
|
|
@@ -918,10 +941,20 @@ async function chooseModel() {
|
|
|
918
941
|
// Remember the friendly name for the token footer, which should never show a raw
|
|
919
942
|
// "<kind>::<model>" wire id.
|
|
920
943
|
sessionCodingLabel = chosen.id === def ? "" : chosen.model;
|
|
944
|
+
// Task #125: remember the chosen backend's coding URL so the GLOBAL output-token total is
|
|
945
|
+
// keyed to it. Default pick → "" so activeCodingUrl() falls back to defaultCodingUrl.
|
|
946
|
+
sessionCodingUrl = chosen.id === def ? "" : (chosen.url ?? "");
|
|
921
947
|
const where = showKind ? ` (${KIND_LABEL[chosen.kind ?? ""] ?? chosen.kind})` : "";
|
|
922
948
|
console.log(
|
|
923
949
|
green(` ✓ coding model → ${chosen.model}${where}${chosen.id === def ? " (default)" : ""}\n`)
|
|
924
950
|
);
|
|
951
|
+
// Task #125: the GLOBAL lifetime total is per-backend, so re-fetch it for the newly
|
|
952
|
+
// selected backend NOW — otherwise the footer would keep showing the previous backend's
|
|
953
|
+
// total until the next turn. Zero the live tail so the switch can't add the last turn's
|
|
954
|
+
// output to the new backend's bucket on screen.
|
|
955
|
+
latestOutputTokens = 0;
|
|
956
|
+
const t = await fetchOutputTokenTotals(resolve(process.cwd()));
|
|
957
|
+
{ const g = pickGlobalTotal(t); if (g !== null) globalOutputTokens = g; }
|
|
925
958
|
}
|
|
926
959
|
|
|
927
960
|
// Probe whether SSH KEY auth already works for a server (so we can tell the user to run
|
|
@@ -1282,6 +1315,15 @@ let sessionCodingLabel = "";
|
|
|
1282
1315
|
// per-turn token footer next to the GLOBAL output total so it's clear which model that
|
|
1283
1316
|
// lifetime count belongs to. The /model override (sessionCodingModel) wins when set.
|
|
1284
1317
|
let defaultCodingModel = "";
|
|
1318
|
+
// Task #125: the coding-server URL of the backend in effect this session — the /model
|
|
1319
|
+
// pick's backend when one is chosen, else the account default. Sent to the output-token
|
|
1320
|
+
// endpoints so the GLOBAL lifetime total is keyed to the RIGHT backend (a /model switch to
|
|
1321
|
+
// another backend must not keep showing the previous backend's total). Empty = let the API
|
|
1322
|
+
// fall back to the account-default URL from settings (older behaviour).
|
|
1323
|
+
let sessionCodingUrl = "";
|
|
1324
|
+
// The account-default backend's URL (from the startup probe's codingChoices), used when no
|
|
1325
|
+
// /model override is active. Set once at startup alongside defaultCodingModel.
|
|
1326
|
+
let defaultCodingUrl = "";
|
|
1285
1327
|
// Auto-test mode (/test-auto): when on, the agent verifies its work (build/run/curl/…)
|
|
1286
1328
|
// and fixes → re-tests until it passes before finishing. Default off; remembered per
|
|
1287
1329
|
// folder in the session file; sent to /agent-ask as autoTest so python drives the loop.
|
|
@@ -2008,7 +2050,7 @@ async function runAgentTurn(history) {
|
|
|
2008
2050
|
if (latestOutputTokens > 0 && !outputTokensPosted) {
|
|
2009
2051
|
outputTokensPosted = true;
|
|
2010
2052
|
void addOutputTokens(resolve(process.cwd()), latestOutputTokens).then((t) => {
|
|
2011
|
-
|
|
2053
|
+
{ const g = pickGlobalTotal(t); if (g !== null) globalOutputTokens = g; }
|
|
2012
2054
|
// This turn's total is now folded into globalOutputTokens — zero the live
|
|
2013
2055
|
// per-turn tally so the ↓ (global + latest) doesn't double-count it.
|
|
2014
2056
|
latestOutputTokens = 0;
|
|
@@ -2166,14 +2208,17 @@ async function main() {
|
|
|
2166
2208
|
// Task #104: seed the ↓ global OUTPUT-token total (user + coding-URL) from the API.
|
|
2167
2209
|
{
|
|
2168
2210
|
const t = await fetchOutputTokenTotals(resolve(process.cwd()));
|
|
2169
|
-
|
|
2211
|
+
{ const g = pickGlobalTotal(t); if (g !== null) globalOutputTokens = g; }
|
|
2170
2212
|
}
|
|
2171
2213
|
// Show which models will answer, straight from user settings (also validates auth).
|
|
2172
2214
|
try {
|
|
2173
2215
|
const probe = await fetchAgentPayload([{ role: "user", content: "ping" }]);
|
|
2174
2216
|
const p = probe?.payload ?? {};
|
|
2175
|
-
// Remember the default coder id for the token footer's global-total label
|
|
2217
|
+
// Remember the default coder id for the token footer's global-total label, and the
|
|
2218
|
+
// default backend's coding URL so the GLOBAL output-token total is keyed to it (task
|
|
2219
|
+
// #125) when no /model override is active.
|
|
2176
2220
|
if (p.codingModelId) defaultCodingModel = p.codingModelId;
|
|
2221
|
+
if (p.codingBaseURL) defaultCodingUrl = p.codingBaseURL;
|
|
2177
2222
|
// RAG storage choice (task #97): ask ONCE per folder, and only when RAG is actually
|
|
2178
2223
|
// enabled in Settings. Default Yes = LOCAL (kept on this machine, no S3 needed).
|
|
2179
2224
|
if (p.ragEnabled && sessionRagMode === null) {
|
|
@@ -2322,9 +2367,11 @@ async function main() {
|
|
|
2322
2367
|
if (line === "/output-token") {
|
|
2323
2368
|
// Task #104: print the OUTPUT-token total for THIS workspace (and the global one).
|
|
2324
2369
|
const t = await fetchOutputTokenTotals(cwd);
|
|
2325
|
-
|
|
2370
|
+
{ const g = pickGlobalTotal(t); if (g !== null) globalOutputTokens = g; }
|
|
2326
2371
|
const ws = t && Number.isFinite(t.workspaceTotal) ? t.workspaceTotal : 0;
|
|
2327
|
-
|
|
2372
|
+
// Task #126: same saved-else-counter rule as the footer (pickGlobalTotal), not the
|
|
2373
|
+
// raw counter — so /output-token and the live ↓ footer agree.
|
|
2374
|
+
const gl = pickGlobalTotal(t) ?? globalOutputTokens;
|
|
2328
2375
|
console.log(
|
|
2329
2376
|
cyan(`↓ output tokens`) +
|
|
2330
2377
|
dim(` — this workspace: `) +
|
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.335",
|
|
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",
|