offgrid-ai 0.3.28 → 0.3.29

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 CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "offgrid-ai",
3
- "version": "0.3.28",
3
+ "version": "0.3.29",
4
4
  "description": "Privacy-first CLI for running local LLMs — discover, configure, run, benchmark",
5
5
  "author": "Eeshan Srivastava (https://eeshans.com)",
6
6
  "type": "module",
@@ -1,6 +1,11 @@
1
+ import { execFile } from "node:child_process";
2
+ import { promisify } from "node:util";
1
3
  import { estimateMemory } from "./estimate.mjs";
4
+ import { findLlamaServer } from "./config.mjs";
2
5
  import { pc, formatBytes, renderRows, renderSection } from "./ui.mjs";
3
6
 
7
+ const execFileAsync = promisify(execFile);
8
+
4
9
  const CACHE_CHOICES = [
5
10
  { value: "bf16", label: "bf16", hint: "default: stable, good quality" },
6
11
  { value: "f16", label: "f16", hint: "stable fallback, similar memory to bf16" },
@@ -57,13 +62,14 @@ export async function configureLocalProfile(prompt, profile) {
57
62
  if (caps.vision && profile.mmprojPath) {
58
63
  console.log("");
59
64
  const gemma4Unified = isGemma4UnifiedProjector(caps.mmprojProjectorType);
65
+ const supported = !gemma4Unified || await runtimeSupportsGemma4Unified();
60
66
  console.log(renderSection("Vision projector detected", renderRows([
61
67
  ["Projector", caps.mmprojProjectorType ?? "unknown"],
62
68
  ["Flag", `--mmproj ${profile.mmprojPath}`],
63
- ...(gemma4Unified ? [["Note", pc.yellow("Gemma 4 unified projectors need newer llama.cpp than current Homebrew stable.")]] : []),
69
+ ...(gemma4Unified && !supported ? [["Note", pc.yellow("Gemma 4 unified projectors need llama.cpp b9549+.")]] : []),
64
70
  ])));
65
- const useVision = await prompt.yesNo("Enable vision with --mmproj?", !gemma4Unified);
66
- configured = useVision ? applyVisionDefaults(configured) : removeVisionDefaults(configured, gemma4Unified ? "gemma4-unified-unsupported" : "user-disabled");
71
+ const useVision = await prompt.yesNo("Enable vision with --mmproj?", supported);
72
+ configured = useVision ? applyVisionDefaults(configured) : removeVisionDefaults(configured, gemma4Unified && !supported ? "gemma4-unified-unsupported" : "user-disabled");
67
73
  }
68
74
 
69
75
  if (caps.thinking) {
@@ -212,6 +218,19 @@ function isGemma4UnifiedProjector(projectorType) {
212
218
  return /gemma4u[va]/i.test(String(projectorType ?? ""));
213
219
  }
214
220
 
221
+ async function runtimeSupportsGemma4Unified() {
222
+ try {
223
+ const binary = await findLlamaServer();
224
+ if (!binary) return false;
225
+ const { stdout, stderr } = await execFileAsync(binary, ["--version"]);
226
+ const output = `${stdout}\n${stderr}`;
227
+ const version = Number(output.match(/version:\s*(\d+)/i)?.[1]);
228
+ return Number.isFinite(version) && version >= 9549;
229
+ } catch {
230
+ return false;
231
+ }
232
+ }
233
+
215
234
  function detectionSummary(caps) {
216
235
  const parts = [];
217
236
  if (caps.architecture) parts.push(caps.architecture);