@tiens.nguyen/gu-cli 1.0.699 → 1.0.701
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/agent-model-command.mjs +117 -0
- package/client-expert-api.mjs +34 -0
- package/gonext_agent_chat.py +11 -8
- package/gu-repl.mjs +81 -32
- package/package.json +1 -1
package/agent-model-command.mjs
CHANGED
|
@@ -349,3 +349,120 @@ export function agentRecoveryOptions({ keyProblem = false, host = "" } = {}) {
|
|
|
349
349
|
{ action: "provider", label: "add an OpenAI-compatible provider for the agent…" },
|
|
350
350
|
];
|
|
351
351
|
}
|
|
352
|
+
|
|
353
|
+
// ---------------------------------------------------------------------------------------------
|
|
354
|
+
// #43 — /model's "change the Ollama server" flow, when the agent is NOT on an Ollama.
|
|
355
|
+
// ---------------------------------------------------------------------------------------------
|
|
356
|
+
|
|
357
|
+
/**
|
|
358
|
+
* Is this machine's agent model on an OpenAI-compatible PROVIDER rather than an Ollama?
|
|
359
|
+
*
|
|
360
|
+
* Reported (#43): client mode, /model → change the Ollama server offered the agent's URL —
|
|
361
|
+
* https://api.openai.com — as the "agent + embedding server", probed it for Ollama's /api/tags, got
|
|
362
|
+
* 404, said "check that Ollama is listening", and asked again, with no way forward but typing "no".
|
|
363
|
+
* A provider is known two ways: a provider row for that URL says so, or the URL is one of the hosted
|
|
364
|
+
* APIs everyone knows is not an Ollama.
|
|
365
|
+
*/
|
|
366
|
+
const KNOWN_PROVIDER_HOSTS = [
|
|
367
|
+
"api.openai.com",
|
|
368
|
+
"openrouter.ai",
|
|
369
|
+
"api.together.xyz",
|
|
370
|
+
"api.moonshot.ai",
|
|
371
|
+
"api.groq.com",
|
|
372
|
+
"api.deepseek.com",
|
|
373
|
+
"api.mistral.ai",
|
|
374
|
+
"generativelanguage.googleapis.com",
|
|
375
|
+
];
|
|
376
|
+
|
|
377
|
+
export function agentIsOnProvider(settings) {
|
|
378
|
+
const source = agentListSource(settings);
|
|
379
|
+
if (!source.url) return false;
|
|
380
|
+
if (source.dialect === "openai") return true;
|
|
381
|
+
let host = "";
|
|
382
|
+
try {
|
|
383
|
+
host = new URL(String(settings?.agentModelUrl ?? "")).hostname.toLowerCase();
|
|
384
|
+
} catch {
|
|
385
|
+
return false;
|
|
386
|
+
}
|
|
387
|
+
return KNOWN_PROVIDER_HOSTS.some((h) => host === h || host.endsWith(`.${h}`));
|
|
388
|
+
}
|
|
389
|
+
|
|
390
|
+
/**
|
|
391
|
+
* The address to offer for the CODING server: the coder's own URL when it is not a known provider,
|
|
392
|
+
* else this machine's Ollama. Never the agent's provider URL — that is what put api.openai.com in an
|
|
393
|
+
* Ollama prompt.
|
|
394
|
+
*/
|
|
395
|
+
export function coderServerDefault(settings) {
|
|
396
|
+
const coder = String(settings?.agentCodingModelUrl ?? "").trim();
|
|
397
|
+
if (coder && !agentIsOnProvider({ ...settings, agentModelUrl: coder })) return coder;
|
|
398
|
+
const agent = String(settings?.agentModelUrl ?? "").trim();
|
|
399
|
+
if (agent && !agentIsOnProvider(settings)) return agent;
|
|
400
|
+
return "http://127.0.0.1:11434";
|
|
401
|
+
}
|
|
402
|
+
|
|
403
|
+
/**
|
|
404
|
+
* A server that ANSWERED but has no /api/tags is not an Ollama — an OpenAI-compatible API answers 404
|
|
405
|
+
* there. That is a different fix from "not listening", and saying the wrong one sends people to check
|
|
406
|
+
* a server that is working fine.
|
|
407
|
+
*/
|
|
408
|
+
export function describeNotOllama(host, role) {
|
|
409
|
+
return role === "agent"
|
|
410
|
+
? [
|
|
411
|
+
`${host} answers, but it is not an Ollama server (no /api/tags).`,
|
|
412
|
+
"an OpenAI-compatible agent is changed with /agent-model — or type 'no' to skip this role.",
|
|
413
|
+
]
|
|
414
|
+
: [
|
|
415
|
+
`${host} answers, but it is not an Ollama server (no /api/tags).`,
|
|
416
|
+
"for an OpenAI-compatible coder use /model → add or change an OpenAI-compatible provider — or type 'no' to skip.",
|
|
417
|
+
];
|
|
418
|
+
}
|
|
419
|
+
|
|
420
|
+
// ---------------------------------------------------------------------------------------------
|
|
421
|
+
// #44 — WHAT TO CHANGE comes first.
|
|
422
|
+
// ---------------------------------------------------------------------------------------------
|
|
423
|
+
|
|
424
|
+
/**
|
|
425
|
+
* The first screen of /agent-model: what to change, before any model list.
|
|
426
|
+
*
|
|
427
|
+
* Reported (#44): client mode, agent on api.openai.com — /agent-model opened straight onto "130 on
|
|
428
|
+
* https://api.openai.com/v1" with the current model selected, and the ways to use an Ollama server
|
|
429
|
+
* or another provider sat after all 130 rows. Enter said "already using gpt-4.1-mini — nothing
|
|
430
|
+
* changed", and the only thing the screen seemed to allow was another OpenAI model. First-time setup
|
|
431
|
+
* worked; changing it afterwards did not look possible.
|
|
432
|
+
*
|
|
433
|
+
* So the choice of WHAT to change is its own short list, in the order it is most often wanted. The
|
|
434
|
+
* key entry appears only where a key applies. Returns [{ action, label }].
|
|
435
|
+
*/
|
|
436
|
+
export function agentMenuOptions({ host = "", modelCount = 0, needsKey = false } = {}) {
|
|
437
|
+
const where = host || "this server";
|
|
438
|
+
return [
|
|
439
|
+
{ action: "models", label: `pick another model on ${where}${modelCount ? ` (${modelCount})` : ""}` },
|
|
440
|
+
{ action: "ollama", label: "use an Ollama server for the agent…" },
|
|
441
|
+
{ action: "provider", label: "use another OpenAI-compatible provider…" },
|
|
442
|
+
...(needsKey ? [{ action: "key", label: `enter a new API key for ${where}…` }] : []),
|
|
443
|
+
];
|
|
444
|
+
}
|
|
445
|
+
|
|
446
|
+
/**
|
|
447
|
+
* The providers already saved on this machine that the agent could switch to — OpenAI-compatible
|
|
448
|
+
* rows, current one marked — then "add a new one". Switching to a provider you already set up must
|
|
449
|
+
* not mean typing its URL again. Returns [{ action: "row" | "add", row?, label }].
|
|
450
|
+
*/
|
|
451
|
+
export function agentProviderChoices(settings) {
|
|
452
|
+
const rows = Array.isArray(settings?.agentCodingBackends) ? settings.agentCodingBackends : [];
|
|
453
|
+
const current = ensureV1Root(String(settings?.agentModelUrl ?? "")).toLowerCase();
|
|
454
|
+
const out = [];
|
|
455
|
+
for (const row of rows) {
|
|
456
|
+
if (!row || row.kind !== "openai" || !row.url) continue;
|
|
457
|
+
let host = String(row.url);
|
|
458
|
+
try {
|
|
459
|
+
host = new URL(String(row.url)).host;
|
|
460
|
+
} catch {
|
|
461
|
+
/* keep the raw url */
|
|
462
|
+
}
|
|
463
|
+
const isCurrent = ensureV1Root(String(row.url)).toLowerCase() === current;
|
|
464
|
+
out.push({ action: "row", row, label: `${host}${isCurrent ? " (current)" : ""}` });
|
|
465
|
+
}
|
|
466
|
+
out.push({ action: "add", label: "add a new OpenAI-compatible provider…" });
|
|
467
|
+
return out;
|
|
468
|
+
}
|
package/client-expert-api.mjs
CHANGED
|
@@ -734,3 +734,37 @@ export async function seedSettings({
|
|
|
734
734
|
await client.close().catch(() => {});
|
|
735
735
|
}
|
|
736
736
|
}
|
|
737
|
+
|
|
738
|
+
/**
|
|
739
|
+
* THE NEW OLLAMA SERVER'S ROWS, MERGED INTO WHAT IS ALREADY THERE — never replacing it (#43).
|
|
740
|
+
*
|
|
741
|
+
* Found while fixing #43: choosing a coding server in /model → "change the Ollama server" saved
|
|
742
|
+
* codingBackendsForClientExpert(...) AS the whole list — one Ollama row and the Kimi row — deleting
|
|
743
|
+
* every provider the user had added: an api.openai.com row the AGENT's key is found through, an
|
|
744
|
+
* ollama.com cloud row. Their keys, bound to those row ids, were orphaned.
|
|
745
|
+
*
|
|
746
|
+
* Replaced: the local/LAN Ollama row(s) — that is what "the Ollama server this machine uses" means —
|
|
747
|
+
* with the new one, which keeps the first replaced row's id so anything bound to it still resolves.
|
|
748
|
+
* Kept, ids and all: every OpenAI-compatible row, and any Ollama CLOUD row (a paid provider, not
|
|
749
|
+
* "this machine's server"). The template's default provider row is added only when no row already
|
|
750
|
+
* has its URL.
|
|
751
|
+
*/
|
|
752
|
+
export function mergeOllamaServerBackends(existing, fresh, { isCloud } = {}) {
|
|
753
|
+
const cloud = typeof isCloud === "function" ? isCloud : () => false;
|
|
754
|
+
const norm = (u) => String(u ?? "").trim().replace(/\/+$/, "").toLowerCase();
|
|
755
|
+
const rows = Array.isArray(existing) ? existing.filter(Boolean) : [];
|
|
756
|
+
const replaced = rows.filter((b) => b.kind === "ollama" && !cloud(b.url));
|
|
757
|
+
const kept = rows.filter((b) => !(b.kind === "ollama" && !cloud(b.url)));
|
|
758
|
+
const out = [];
|
|
759
|
+
for (const f of Array.isArray(fresh) ? fresh : []) {
|
|
760
|
+
if (f.kind === "ollama") {
|
|
761
|
+
const id = replaced.find((b) => b.id)?.id;
|
|
762
|
+
out.push(id ? { ...f, id } : f);
|
|
763
|
+
}
|
|
764
|
+
}
|
|
765
|
+
out.push(...kept);
|
|
766
|
+
for (const f of Array.isArray(fresh) ? fresh : []) {
|
|
767
|
+
if (f.kind !== "ollama" && !out.some((b) => norm(b.url) === norm(f.url))) out.push(f);
|
|
768
|
+
}
|
|
769
|
+
return out;
|
|
770
|
+
}
|
package/gonext_agent_chat.py
CHANGED
|
@@ -9694,22 +9694,25 @@ def run_agent_chat(cfg):
|
|
|
9694
9694
|
f"{_host} refused: "
|
|
9695
9695
|
+ (_why or "the account is out of credit")
|
|
9696
9696
|
+ ". Nothing ran — top up the account, or switch the "
|
|
9697
|
-
"coding model in Settings → Agent."
|
|
9697
|
+
"coding model (in gu: /model; on the web: Settings → Agent)."
|
|
9698
9698
|
) from e
|
|
9699
|
+
# THE TERMINAL WAY FIRST (#44): a client-mode machine has no web app,
|
|
9700
|
+
# so "Settings → Agent" alone was advice it could not follow.
|
|
9699
9701
|
if coding_api_key:
|
|
9700
9702
|
raise _AgentConfigError(
|
|
9701
9703
|
f"The agent coding backend ({_host}) REJECTED the "
|
|
9702
|
-
"coding API key. Nothing ran.
|
|
9703
|
-
"
|
|
9704
|
-
"
|
|
9705
|
-
"save a fresh one
|
|
9704
|
+
"coding API key. Nothing ran. Enter a fresh key — in gu: "
|
|
9705
|
+
"press ctrl+k (or /model → the provider); on the web: "
|
|
9706
|
+
"Settings → Agent. The stored key is write-only, so a "
|
|
9707
|
+
"stale one can't be inspected — just save a fresh one."
|
|
9706
9708
|
) from e
|
|
9707
9709
|
raise _AgentConfigError(
|
|
9708
9710
|
f"The agent coding backend ({_host}) rejected the request: "
|
|
9709
9711
|
"NO coding API key was sent, so the local agent key was "
|
|
9710
|
-
"used instead. Enter the API key
|
|
9711
|
-
"
|
|
9712
|
-
"https://ollama.com URL —
|
|
9712
|
+
"used instead. Enter the API key for this coding backend — in "
|
|
9713
|
+
"gu: press ctrl+k; on the web: Settings → Agent "
|
|
9714
|
+
"(OpenAI-compatible, or Ollama with an https://ollama.com URL — "
|
|
9715
|
+
"local Ollama needs no key)."
|
|
9713
9716
|
) from e
|
|
9714
9717
|
if "404" in emsg and "not found" in emsg.lower():
|
|
9715
9718
|
# Probe with the CODING key when there is one: using the agent
|
package/gu-repl.mjs
CHANGED
|
@@ -4721,12 +4721,13 @@ async function reconfigureOllamaServer() {
|
|
|
4721
4721
|
const res = await withPendingStatus(`loading models from ${n.host}`, () =>
|
|
4722
4722
|
proxyFetch(os.tagsUrlFor(n), { signal: AbortSignal.timeout(8000) })
|
|
4723
4723
|
);
|
|
4724
|
-
|
|
4724
|
+
// The status is kept: a 404 here means "answered, but not an Ollama" (#43), not "unreachable".
|
|
4725
|
+
if (!res.ok) throw Object.assign(new Error(`HTTP ${res.status}`), { httpStatus: res.status });
|
|
4725
4726
|
return am.parseOllamaTags(await res.json().catch(() => null));
|
|
4726
4727
|
};
|
|
4727
4728
|
|
|
4728
4729
|
/** Ask for one server and load it. Returns {normalized, models} or null (declined/failed). */
|
|
4729
|
-
const askServer = async (label, dflt, { require = false, short = "server" } = {}) => {
|
|
4730
|
+
const askServer = async (label, dflt, { require = false, short = "server", role = "coder" } = {}) => {
|
|
4730
4731
|
for (let attempt = 0; attempt < 3; attempt++) {
|
|
4731
4732
|
// The address goes ABOVE, in full — it is long, it is the thing Enter accepts, and the
|
|
4732
4733
|
// frozen row is too narrow to hold it without truncating exactly that. The row itself
|
|
@@ -4766,6 +4767,12 @@ async function reconfigureOllamaServer() {
|
|
|
4766
4767
|
}
|
|
4767
4768
|
}
|
|
4768
4769
|
if (!n) {
|
|
4770
|
+
if (lastErr?.httpStatus === 404) {
|
|
4771
|
+
// IT ANSWERED — it is simply not an Ollama (#43). "Couldn't reach … is Ollama listening"
|
|
4772
|
+
// sent people to debug a server that was working.
|
|
4773
|
+
for (const l of am.describeNotOllama(candidates[0].host, role)) console.log(yellow(` ${l}`));
|
|
4774
|
+
continue;
|
|
4775
|
+
}
|
|
4769
4776
|
// One address typed, one failure reported — naming every candidate would be two errors
|
|
4770
4777
|
// for one mistake, and neither would be the address they gave.
|
|
4771
4778
|
console.log(red(` couldn't reach ${candidates[0].host}: ${os.networkReason(lastErr)}`));
|
|
@@ -4795,18 +4802,31 @@ async function reconfigureOllamaServer() {
|
|
|
4795
4802
|
return null;
|
|
4796
4803
|
};
|
|
4797
4804
|
|
|
4805
|
+
// AN AGENT ON A PROVIDER IS NOT ASKED ABOUT HERE (#43). This flow is for Ollama boxes; offering
|
|
4806
|
+
// https://api.openai.com as the "agent + embedding server" could only fail its /api/tags probe and
|
|
4807
|
+
// ask again. Keep it, say where it is changed, and go on to the coder.
|
|
4808
|
+
const agentOnProvider = am.agentIsOnProvider(settings);
|
|
4798
4809
|
const curAgent =
|
|
4799
4810
|
String(settings.agentModelUrl ?? "").trim() || "https://ollama1.gomarsic.cc/v1";
|
|
4800
|
-
const curCode =
|
|
4811
|
+
const curCode = am.coderServerDefault(settings);
|
|
4801
4812
|
|
|
4802
|
-
|
|
4803
|
-
|
|
4804
|
-
|
|
4805
|
-
|
|
4806
|
-
|
|
4807
|
-
}
|
|
4813
|
+
let agent = null;
|
|
4814
|
+
if (agentOnProvider) {
|
|
4815
|
+
const host = hostOf(String(settings.agentModelUrl ?? ""));
|
|
4816
|
+
console.log(dim(` The agent model is on ${host} (OpenAI-compatible) — kept as it is; change it with /agent-model.`));
|
|
4817
|
+
console.log(dim(" Enter keeps the current address; type 'no' to skip."));
|
|
4818
|
+
} else {
|
|
4819
|
+
console.log(dim(" TWO servers may be used: the agent + embedder on one, the coder on another."));
|
|
4820
|
+
console.log(dim(" Enter keeps the current address; type 'no' to skip a role."));
|
|
4821
|
+
agent = await askServer("Agent + embedding server", curAgent, {
|
|
4822
|
+
require: true,
|
|
4823
|
+
short: "agent + embed server",
|
|
4824
|
+
role: "agent",
|
|
4825
|
+
});
|
|
4826
|
+
}
|
|
4808
4827
|
const coder = await askServer("Coding-model server", agent?.normalized?.url ?? curCode, {
|
|
4809
4828
|
short: "coding server",
|
|
4829
|
+
role: "coder",
|
|
4810
4830
|
});
|
|
4811
4831
|
|
|
4812
4832
|
if (!agent && !coder) {
|
|
@@ -4912,12 +4932,18 @@ async function reconfigureOllamaServer() {
|
|
|
4912
4932
|
agentCodingModelName: code,
|
|
4913
4933
|
agentCodingModelKind: "ollama",
|
|
4914
4934
|
agentCodingDefaultKind: "ollama",
|
|
4915
|
-
|
|
4916
|
-
|
|
4917
|
-
|
|
4918
|
-
|
|
4919
|
-
|
|
4920
|
-
|
|
4935
|
+
// MERGED, not replaced (#43): the providers already configured — and the keys bound to them —
|
|
4936
|
+
// survive choosing a new Ollama server.
|
|
4937
|
+
agentCodingBackends: (await import("./client-expert-api.mjs")).mergeOllamaServerBackends(
|
|
4938
|
+
(await import("./coding-provider-setup.mjs")).existingBackendRows(settings),
|
|
4939
|
+
(await import("./client-expert-api.mjs")).codingBackendsForClientExpert({
|
|
4940
|
+
url: coder.normalized.url,
|
|
4941
|
+
chat: agent ? chat : code,
|
|
4942
|
+
code,
|
|
4943
|
+
altCoders: extras,
|
|
4944
|
+
}),
|
|
4945
|
+
{ isCloud: (await import("./coding-key-prompt.mjs")).isOllamaCloudUrl }
|
|
4946
|
+
),
|
|
4921
4947
|
});
|
|
4922
4948
|
}
|
|
4923
4949
|
|
|
@@ -6093,6 +6119,29 @@ async function pointAgentAtProvider(row, host) {
|
|
|
6093
6119
|
await saveAgentModel(url, model, host);
|
|
6094
6120
|
}
|
|
6095
6121
|
|
|
6122
|
+
/**
|
|
6123
|
+
* #44: switch the agent to a provider already saved on this machine, or add a new one.
|
|
6124
|
+
*/
|
|
6125
|
+
async function chooseAgentProvider() {
|
|
6126
|
+
const am = await import("./agent-model-command.mjs");
|
|
6127
|
+
const settings = await withPendingStatus("reading your providers", fetchWorkerSettings);
|
|
6128
|
+
if (!settings) {
|
|
6129
|
+
console.log(red(" couldn't reach the API to read your providers.\n"));
|
|
6130
|
+
return;
|
|
6131
|
+
}
|
|
6132
|
+
const choices = am.agentProviderChoices(settings);
|
|
6133
|
+
if (choices.length === 1) return addCodingProvider("agent");
|
|
6134
|
+
console.log(dim(` Which OpenAI-compatible provider should the agent use? (${PICK_HINT})`));
|
|
6135
|
+
const idx = await pickFromList(choices.map((c) => c.label), 0);
|
|
6136
|
+
if (idx < 0) {
|
|
6137
|
+
console.log(dim(" (cancelled)\n"));
|
|
6138
|
+
return;
|
|
6139
|
+
}
|
|
6140
|
+
const pick = choices[idx];
|
|
6141
|
+
if (pick.action === "add") return addCodingProvider("agent");
|
|
6142
|
+
await pointAgentAtProvider(pick.row, hostOf(String(pick.row.url ?? "")));
|
|
6143
|
+
}
|
|
6144
|
+
|
|
6096
6145
|
/**
|
|
6097
6146
|
* #41: the agent model on an OLLAMA server — this machine's, a LAN box, or the Ollama cloud.
|
|
6098
6147
|
*
|
|
@@ -6308,6 +6357,21 @@ async function chooseAgentModel() {
|
|
|
6308
6357
|
return;
|
|
6309
6358
|
}
|
|
6310
6359
|
|
|
6360
|
+
// WHAT TO CHANGE, FIRST (#44). The ways to use an Ollama server or another provider used to sit
|
|
6361
|
+
// after every model on this one — 130 rows down on api.openai.com — which read as "OpenAI models
|
|
6362
|
+
// are all you can choose". A short menu of what to change comes before any list.
|
|
6363
|
+
console.log(dim(` Agent model — the one that TALKS: ${current || "unset"} on ${listHost}`));
|
|
6364
|
+
const menu = am.agentMenuOptions({ host: listHost, modelCount: models.length, needsKey });
|
|
6365
|
+
const first = await pickFromList(menu.map((o) => o.label), 0);
|
|
6366
|
+
const firstAction = first >= 0 ? menu[first].action : "cancel";
|
|
6367
|
+
if (firstAction === "cancel") {
|
|
6368
|
+
console.log(dim(" (cancelled)\n"));
|
|
6369
|
+
return;
|
|
6370
|
+
}
|
|
6371
|
+
if (firstAction === "ollama") return addOllamaAgent();
|
|
6372
|
+
if (firstAction === "provider") return chooseAgentProvider();
|
|
6373
|
+
if (firstAction === "key") return enterAgentProviderKey(source.row, listHost);
|
|
6374
|
+
|
|
6311
6375
|
const rows = am.agentModelRows(models, current);
|
|
6312
6376
|
console.log(dim(` Agent model — the one that TALKS (currently ${current || "unset"})`));
|
|
6313
6377
|
// Strip whichever list endpoint was asked, so the header names the SERVER rather than the path.
|
|
@@ -6334,28 +6398,13 @@ async function chooseAgentModel() {
|
|
|
6334
6398
|
(r.current ? accent(" (current)") : "")
|
|
6335
6399
|
);
|
|
6336
6400
|
});
|
|
6337
|
-
//
|
|
6338
|
-
//
|
|
6339
|
-
// because "which model on the box I am pointed at" and "I want a different provider" are
|
|
6340
|
-
// different questions, and only the first is answered by the rows above.
|
|
6341
|
-
labels.push("add an OpenAI-compatible provider for the agent…");
|
|
6342
|
-
// #41, appended AFTER the provider entry so no existing index moves.
|
|
6343
|
-
labels.push("use an Ollama server for the agent…");
|
|
6401
|
+
// No other entries here any more (#44): the ways to change the provider are on the menu above,
|
|
6402
|
+
// where they can be seen, rather than after every model.
|
|
6344
6403
|
const idx = await pickFromList(labels, Math.max(0, rows.findIndex((r) => r.current)));
|
|
6345
6404
|
if (idx < 0) {
|
|
6346
6405
|
console.log(dim(" (cancelled)\n"));
|
|
6347
6406
|
return;
|
|
6348
6407
|
}
|
|
6349
|
-
// labels is now TWO LONGER than rows. Reading rows[idx] for an appended entry would
|
|
6350
|
-
// dereference undefined and take the picker down, so they are answered before rows is touched.
|
|
6351
|
-
if (idx === rows.length) {
|
|
6352
|
-
await addCodingProvider("agent");
|
|
6353
|
-
return;
|
|
6354
|
-
}
|
|
6355
|
-
if (idx === rows.length + 1) {
|
|
6356
|
-
await addOllamaAgent();
|
|
6357
|
-
return;
|
|
6358
|
-
}
|
|
6359
6408
|
const chosen = rows[idx].model;
|
|
6360
6409
|
if (chosen === current) {
|
|
6361
6410
|
console.log(dim(` already using ${current} — nothing changed.\n`));
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@tiens.nguyen/gu-cli",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.701",
|
|
4
4
|
"description": "Gu CLI — the gu terminal plus the local worker that runs agent / OCR / PDF / embedding jobs on your Mac (Ollama / MLX / OpenAI-compatible).",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"license": "MIT",
|