offgrid-ai 0.3.20 → 0.3.21
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/package.json +1 -1
- package/src/backends.mjs +19 -10
- package/src/cli.mjs +4 -4
- package/src/profile-setup.mjs +3 -3
- package/src/ui.mjs +2 -2
package/package.json
CHANGED
package/src/backends.mjs
CHANGED
|
@@ -72,16 +72,18 @@ async function scanOllamaModels() {
|
|
|
72
72
|
if (!response.ok) return [];
|
|
73
73
|
const body = await response.json();
|
|
74
74
|
if (!Array.isArray(body?.models)) return [];
|
|
75
|
-
return body.models
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
75
|
+
return body.models
|
|
76
|
+
.filter((model) => isLocalOllamaModel(model))
|
|
77
|
+
.map((model) => ({
|
|
78
|
+
id: model.name,
|
|
79
|
+
label: ollamaLabel(model.name),
|
|
80
|
+
aliasSuggestion: model.name,
|
|
81
|
+
sizeBytes: model.size ?? 0,
|
|
82
|
+
quant: model.details?.quantization_level,
|
|
83
|
+
family: model.details?.family,
|
|
84
|
+
backend: "ollama",
|
|
85
|
+
source: "ollama",
|
|
86
|
+
})).sort((a, b) => a.label.localeCompare(b.label));
|
|
85
87
|
} catch {
|
|
86
88
|
return [];
|
|
87
89
|
}
|
|
@@ -112,6 +114,13 @@ async function scanOmlxModels() {
|
|
|
112
114
|
|
|
113
115
|
// ── Labels ──────────────────────────────────────────────────────────────
|
|
114
116
|
|
|
117
|
+
function isLocalOllamaModel(model) {
|
|
118
|
+
const name = String(model?.name ?? "");
|
|
119
|
+
if (/:cloud(?:$|\b)/i.test(name)) return false;
|
|
120
|
+
if (!Number.isFinite(model?.size) || model.size <= 0) return false;
|
|
121
|
+
return true;
|
|
122
|
+
}
|
|
123
|
+
|
|
115
124
|
function ollamaLabel(name) {
|
|
116
125
|
return name.replace(/[-_]/g, " ").replace(/^gemma\b/i, "Gemma").replace(/^qwen/i, "Qwen");
|
|
117
126
|
}
|
package/src/cli.mjs
CHANGED
|
@@ -280,7 +280,7 @@ async function printModelCatalog({ profiles, newModels, managedItems }, items =
|
|
|
280
280
|
const backendItems = managedItems.filter((item) => item.backendId === backendId);
|
|
281
281
|
if (backendItems.length === 0) continue;
|
|
282
282
|
const be = BACKENDS[backendId];
|
|
283
|
-
console.log("\n" + pc.bold(`
|
|
283
|
+
console.log("\n" + pc.bold(`Local models via ${be.label}`));
|
|
284
284
|
for (const { model } of backendItems.slice(0, 10)) {
|
|
285
285
|
const num = itemNumber((item) => item.type === "managed" && item.backendId === backendId && item.model.id === model.id);
|
|
286
286
|
console.log(managedModelCard(num, model, be));
|
|
@@ -307,13 +307,13 @@ function downloadedModelCard(num, model, caps) {
|
|
|
307
307
|
["Good for", humanCapabilitySummary(caps)],
|
|
308
308
|
["Size", formatBytes(model.sizeBytes)],
|
|
309
309
|
["When selected", "offgrid-ai will recommend safe local settings"],
|
|
310
|
-
]), { formatBorder:
|
|
310
|
+
]), { formatBorder: pc.yellow });
|
|
311
311
|
}
|
|
312
312
|
|
|
313
313
|
function managedModelCard(num, model, backend) {
|
|
314
314
|
return renderCard(`${num}. ${model.label}`, renderRows([
|
|
315
|
-
["Status", statusText("info",
|
|
316
|
-
["
|
|
315
|
+
["Status", statusText("info", `Local model via ${backend.label}`)],
|
|
316
|
+
["Runs with", backend.label],
|
|
317
317
|
["Model ID", pc.cyan(model.id)],
|
|
318
318
|
...(model.quant ? [["Size/type", model.quant]] : []),
|
|
319
319
|
]), { formatBorder: pc.magenta });
|
package/src/profile-setup.mjs
CHANGED
|
@@ -36,14 +36,14 @@ export async function configureLocalProfile(prompt, profile) {
|
|
|
36
36
|
console.log(pc.dim("You can accept the recommended settings. Bigger conversation memory uses more RAM.\n"));
|
|
37
37
|
|
|
38
38
|
if (caps.mtp) {
|
|
39
|
-
console.log(renderSection("
|
|
40
|
-
const useMtp = await prompt.yesNo("Use
|
|
39
|
+
console.log(renderSection("MTP available", "This model supports multi-token prediction (MTP). offgrid-ai can run it with llama.cpp MTP on port 8081."));
|
|
40
|
+
const useMtp = await prompt.yesNo("Use MTP for this model?", true);
|
|
41
41
|
configured = useMtp ? applyMtpDefaults(configured) : removeMtpDefaults(configured);
|
|
42
42
|
}
|
|
43
43
|
|
|
44
44
|
if (caps.qat) {
|
|
45
45
|
console.log("");
|
|
46
|
-
console.log(renderSection("
|
|
46
|
+
console.log(renderSection("QAT model", "This model is marked as quantization-aware trained (QAT). No extra runtime settings are needed."));
|
|
47
47
|
}
|
|
48
48
|
|
|
49
49
|
if (caps.thinking) {
|
package/src/ui.mjs
CHANGED
|
@@ -83,8 +83,8 @@ export function humanCapabilitySummary(caps = {}) {
|
|
|
83
83
|
const parts = [];
|
|
84
84
|
if (caps.thinking) parts.push(pc.magenta("Reasoning"));
|
|
85
85
|
if (caps.vision) parts.push(pc.cyan("Vision"));
|
|
86
|
-
if (caps.mtp) parts.push(pc.blue("
|
|
87
|
-
if (caps.qat) parts.push(pc.green("
|
|
86
|
+
if (caps.mtp) parts.push(pc.blue("MTP"));
|
|
87
|
+
if (caps.qat) parts.push(pc.green("QAT"));
|
|
88
88
|
return parts.length > 0 ? parts.join(" · ") : "General chat";
|
|
89
89
|
}
|
|
90
90
|
|