@vtstech/pi-shared 1.0.4-1 → 1.0.5

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.
Files changed (3) hide show
  1. package/format.js +49 -0
  2. package/ollama.js +38 -1
  3. package/package.json +2 -2
package/format.js CHANGED
@@ -63,8 +63,57 @@ function sanitizeForReport(s, maxLines = 40) {
63
63
  function padRight(s, n) {
64
64
  return s + " ".repeat(Math.max(0, n - s.length));
65
65
  }
66
+ function estimateVram(parameterSize, quantizationLevel) {
67
+ const params = parseParamCount(parameterSize);
68
+ if (params === void 0) return void 0;
69
+ const bitsPerParam = bitsPerParamForQuant(quantizationLevel);
70
+ const modelBytes = params * bitsPerParam / 8;
71
+ return Math.ceil(modelBytes * 1.1);
72
+ }
73
+ function parseParamCount(s) {
74
+ if (!s || typeof s !== "string") return void 0;
75
+ const str = s.trim().toLowerCase();
76
+ const match = str.match(/^([\d.]+)\s*([bmt]?|a(?:pple)?)$/);
77
+ if (!match) return void 0;
78
+ const num = parseFloat(match[1]);
79
+ if (isNaN(num) || num <= 0) return void 0;
80
+ const suffix = match[2];
81
+ switch (suffix) {
82
+ case "b":
83
+ return num * 1e9;
84
+ case "m":
85
+ return num * 1e6;
86
+ case "t":
87
+ return num * 1e12;
88
+ case "a":
89
+ return num * 1e9;
90
+ // Apple-style (e.g., "3a" = 3B parameters)
91
+ case "":
92
+ return num * 1e9;
93
+ // Bare number assumed to be billions
94
+ default:
95
+ return void 0;
96
+ }
97
+ }
98
+ function bitsPerParamForQuant(quant) {
99
+ const q = quant.toUpperCase().replace(/[-_.]/g, "");
100
+ if (q.startsWith("FP32") || q === "FP32") return 32;
101
+ if (q.startsWith("F16") || q === "F16" || q.startsWith("BF16")) return 16;
102
+ if (q.startsWith("Q8")) return 8;
103
+ if (q.startsWith("IQ4")) return 4.5;
104
+ if (q.startsWith("IQ3")) return 3.5;
105
+ if (q.startsWith("IQ2")) return 2.5;
106
+ if (q.startsWith("IQ1")) return 1.75;
107
+ if (q.startsWith("Q5") || q.startsWith("Q6")) return 5.5;
108
+ if (q.startsWith("Q4")) return 4.5;
109
+ if (q.startsWith("Q3")) return 3.5;
110
+ if (q.startsWith("Q2")) return 2.5;
111
+ if (q.startsWith("Q1")) return 1.75;
112
+ return 5;
113
+ }
66
114
  export {
67
115
  bytesHuman,
116
+ estimateVram,
68
117
  fail,
69
118
  fmtBytes,
70
119
  fmtDur,
package/ollama.js CHANGED
@@ -45,9 +45,44 @@ async function fetchOllamaModels(baseUrl) {
45
45
  const data = await res.json();
46
46
  return data.models ?? [];
47
47
  }
48
+ async function fetchModelContextLength(baseUrl, modelName) {
49
+ try {
50
+ const res = await fetch(`${baseUrl}/api/show`, {
51
+ method: "POST",
52
+ headers: { "Content-Type": "application/json" },
53
+ body: JSON.stringify({ name: modelName }),
54
+ signal: AbortSignal.timeout(3e4)
55
+ });
56
+ if (!res.ok) return void 0;
57
+ const data = await res.json();
58
+ for (const key of Object.keys(data?.model_info ?? {})) {
59
+ if (key.endsWith(".context_length")) {
60
+ const val = data.model_info[key];
61
+ if (typeof val === "number") return val;
62
+ }
63
+ }
64
+ const numCtx = data?.model_info?.["num_ctx"];
65
+ if (typeof numCtx === "number") return numCtx;
66
+ } catch {
67
+ return void 0;
68
+ }
69
+ }
70
+ async function fetchContextLengthsBatched(baseUrl, modelNames, batchSize = 3) {
71
+ const result = /* @__PURE__ */ new Map();
72
+ for (let i = 0; i < modelNames.length; i += batchSize) {
73
+ const batch = modelNames.slice(i, i + batchSize);
74
+ const results = await Promise.allSettled(
75
+ batch.map((name) => fetchModelContextLength(baseUrl, name))
76
+ );
77
+ results.forEach((r, idx) => {
78
+ result.set(batch[idx], r.status === "fulfilled" ? r.value : void 0);
79
+ });
80
+ }
81
+ return result;
82
+ }
48
83
  function isReasoningModel(name) {
49
84
  const lower = name.toLowerCase();
50
- return lower.includes("deepseek-r1") || lower.includes("qwq") || lower.includes("o1") || lower.includes("o3") || lower.includes("think") || lower.includes("reason");
85
+ return lower.includes("deepseek-r1") || lower.includes("qwq") || lower.includes("o1") || lower.includes("o3") || lower.includes("qwen3") || lower.includes("think") || lower.includes("reason");
51
86
  }
52
87
  function detectModelFamily(modelName) {
53
88
  const name = modelName.toLowerCase();
@@ -82,6 +117,8 @@ function detectModelFamily(modelName) {
82
117
  export {
83
118
  MODELS_JSON_PATH,
84
119
  detectModelFamily,
120
+ fetchContextLengthsBatched,
121
+ fetchModelContextLength,
85
122
  fetchOllamaModels,
86
123
  getOllamaBaseUrl,
87
124
  isReasoningModel,
package/package.json CHANGED
@@ -1,10 +1,10 @@
1
1
  {
2
2
  "name": "@vtstech/pi-shared",
3
- "version": "1.0.4-1",
3
+ "version": "1.0.5",
4
4
  "description": "Shared utilities for Pi Coding Agent extensions",
5
5
  "main": "index.js",
6
6
  "types": "index.d.ts",
7
- "keywords": ["pi-package", "pi-extensions"],
7
+ "keywords": ["pi-extensions"],
8
8
  "license": "MIT",
9
9
  "access": "public",
10
10
  "type": "module",