agentgui 1.0.362 → 1.0.364
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/build-portable.js +3 -3
- package/package.json +1 -1
- package/lib/download-metrics.js +0 -67
- package/lib/file-verification.js +0 -26
- package/lib/model-downloader.js +0 -116
package/build-portable.js
CHANGED
|
@@ -149,11 +149,11 @@ if (process.env.NO_BUNDLE_MODELS === 'true') {
|
|
|
149
149
|
console.error('[BUILD] Failed to clone models from GitHub:', e.message);
|
|
150
150
|
}
|
|
151
151
|
}
|
|
152
|
-
if (fs.existsSync(
|
|
153
|
-
copyDir(
|
|
152
|
+
if (fs.existsSync(modelsDir)) {
|
|
153
|
+
copyDir(modelsDir, path.join(out, 'models'));
|
|
154
154
|
log(`Models bundled: ${Math.round(sizeOf(path.join(out, 'models')) / 1024 / 1024)}MB`);
|
|
155
155
|
} else {
|
|
156
|
-
log(`WARNING: No models found at ${
|
|
156
|
+
log(`WARNING: No models found at ${modelsDir} - portable build will download on first use`);
|
|
157
157
|
}
|
|
158
158
|
}
|
|
159
159
|
|
package/package.json
CHANGED
package/lib/download-metrics.js
DELETED
|
@@ -1,67 +0,0 @@
|
|
|
1
|
-
import fs from 'fs';
|
|
2
|
-
import path from 'path';
|
|
3
|
-
import os from 'os';
|
|
4
|
-
|
|
5
|
-
const METRICS_PATH = path.join(os.homedir(), '.gmgui', 'models', '.metrics.json');
|
|
6
|
-
|
|
7
|
-
export function recordMetric(metric) {
|
|
8
|
-
const metricsDir = path.dirname(METRICS_PATH);
|
|
9
|
-
if (!fs.existsSync(metricsDir)) {
|
|
10
|
-
fs.mkdirSync(metricsDir, { recursive: true });
|
|
11
|
-
}
|
|
12
|
-
|
|
13
|
-
let metrics = [];
|
|
14
|
-
if (fs.existsSync(METRICS_PATH)) {
|
|
15
|
-
try {
|
|
16
|
-
metrics = JSON.parse(fs.readFileSync(METRICS_PATH, 'utf8'));
|
|
17
|
-
} catch (e) {
|
|
18
|
-
metrics = [];
|
|
19
|
-
}
|
|
20
|
-
}
|
|
21
|
-
|
|
22
|
-
metrics.push({
|
|
23
|
-
...metric,
|
|
24
|
-
timestamp: new Date().toISOString()
|
|
25
|
-
});
|
|
26
|
-
|
|
27
|
-
const oneDayAgo = Date.now() - 24 * 60 * 60 * 1000;
|
|
28
|
-
metrics = metrics.filter(m => new Date(m.timestamp).getTime() > oneDayAgo);
|
|
29
|
-
|
|
30
|
-
fs.writeFileSync(METRICS_PATH, JSON.stringify(metrics, null, 2));
|
|
31
|
-
}
|
|
32
|
-
|
|
33
|
-
export function getMetrics() {
|
|
34
|
-
if (!fs.existsSync(METRICS_PATH)) {
|
|
35
|
-
return [];
|
|
36
|
-
}
|
|
37
|
-
return JSON.parse(fs.readFileSync(METRICS_PATH, 'utf8'));
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
export function getMetricsSummary() {
|
|
41
|
-
const metrics = getMetrics();
|
|
42
|
-
|
|
43
|
-
const summary = {
|
|
44
|
-
total: metrics.length,
|
|
45
|
-
cache_hits: metrics.filter(m => m.layer === 'cache' && m.status === 'hit').length,
|
|
46
|
-
huggingface: {
|
|
47
|
-
success: metrics.filter(m => m.layer === 'huggingface' && m.status === 'success').length,
|
|
48
|
-
error: metrics.filter(m => m.layer === 'huggingface' && m.status === 'error').length,
|
|
49
|
-
avg_latency: 0
|
|
50
|
-
}
|
|
51
|
-
};
|
|
52
|
-
|
|
53
|
-
const hfSuccess = metrics.filter(m => m.layer === 'huggingface' && m.status === 'success');
|
|
54
|
-
if (hfSuccess.length > 0) {
|
|
55
|
-
summary.huggingface.avg_latency = Math.round(
|
|
56
|
-
hfSuccess.reduce((sum, m) => sum + m.latency_ms, 0) / hfSuccess.length
|
|
57
|
-
);
|
|
58
|
-
}
|
|
59
|
-
|
|
60
|
-
return summary;
|
|
61
|
-
}
|
|
62
|
-
|
|
63
|
-
export function resetMetrics() {
|
|
64
|
-
if (fs.existsSync(METRICS_PATH)) {
|
|
65
|
-
fs.unlinkSync(METRICS_PATH);
|
|
66
|
-
}
|
|
67
|
-
}
|
package/lib/file-verification.js
DELETED
|
@@ -1,26 +0,0 @@
|
|
|
1
|
-
import fs from 'fs';
|
|
2
|
-
import crypto from 'crypto';
|
|
3
|
-
|
|
4
|
-
export function verifyFileIntegrity(filepath, expectedHash, minBytes) {
|
|
5
|
-
if (!fs.existsSync(filepath)) {
|
|
6
|
-
return { valid: false, reason: 'file_not_found' };
|
|
7
|
-
}
|
|
8
|
-
|
|
9
|
-
const stats = fs.statSync(filepath);
|
|
10
|
-
if (minBytes && stats.size < minBytes) {
|
|
11
|
-
return { valid: false, reason: 'size_too_small', actual: stats.size, expected: minBytes };
|
|
12
|
-
}
|
|
13
|
-
|
|
14
|
-
if (expectedHash) {
|
|
15
|
-
const hash = crypto.createHash('sha256');
|
|
16
|
-
const data = fs.readFileSync(filepath);
|
|
17
|
-
hash.update(data);
|
|
18
|
-
const actualHash = hash.digest('hex');
|
|
19
|
-
|
|
20
|
-
if (actualHash !== expectedHash) {
|
|
21
|
-
return { valid: false, reason: 'hash_mismatch', actual: actualHash, expected: expectedHash };
|
|
22
|
-
}
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
return { valid: true };
|
|
26
|
-
}
|
package/lib/model-downloader.js
DELETED
|
@@ -1,116 +0,0 @@
|
|
|
1
|
-
import { createRequire } from 'module';
|
|
2
|
-
import fs from 'fs';
|
|
3
|
-
import path from 'path';
|
|
4
|
-
import { recordMetric } from './download-metrics.js';
|
|
5
|
-
import { verifyFileIntegrity } from './file-verification.js';
|
|
6
|
-
|
|
7
|
-
const require = createRequire(import.meta.url);
|
|
8
|
-
|
|
9
|
-
const GATEWAYS = [
|
|
10
|
-
'https://cloudflare-huggingface.com/huggingface/',
|
|
11
|
-
'https://dweb.link/huggingface/',
|
|
12
|
-
'https://gateway.pinata.cloud/huggingface/',
|
|
13
|
-
'https://huggingface.io/huggingface/'
|
|
14
|
-
];
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
async function downloadFromHuggingFace(url, destPath, minBytes, onProgress) {
|
|
19
|
-
const startTime = Date.now();
|
|
20
|
-
|
|
21
|
-
try {
|
|
22
|
-
if (onProgress) {
|
|
23
|
-
onProgress({
|
|
24
|
-
layer: 'huggingface',
|
|
25
|
-
status: 'attempting'
|
|
26
|
-
});
|
|
27
|
-
}
|
|
28
|
-
|
|
29
|
-
const { downloadFile } = require('webtalk/whisper-models');
|
|
30
|
-
await downloadFile(url, destPath);
|
|
31
|
-
|
|
32
|
-
const verification = verifyFileIntegrity(destPath, null, minBytes);
|
|
33
|
-
if (!verification.valid) {
|
|
34
|
-
if (fs.existsSync(destPath)) fs.unlinkSync(destPath);
|
|
35
|
-
throw new Error(`Verification failed: ${verification.reason}`);
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
recordMetric({
|
|
39
|
-
modelType: 'model',
|
|
40
|
-
layer: 'huggingface',
|
|
41
|
-
status: 'success',
|
|
42
|
-
latency_ms: Date.now() - startTime,
|
|
43
|
-
bytes_downloaded: fs.statSync(destPath).size
|
|
44
|
-
});
|
|
45
|
-
|
|
46
|
-
return { success: true, source: 'huggingface' };
|
|
47
|
-
} catch (error) {
|
|
48
|
-
recordMetric({
|
|
49
|
-
modelType: 'model',
|
|
50
|
-
layer: 'huggingface',
|
|
51
|
-
status: 'error',
|
|
52
|
-
error_type: error.name,
|
|
53
|
-
error_message: error.message,
|
|
54
|
-
latency_ms: Date.now() - startTime
|
|
55
|
-
});
|
|
56
|
-
|
|
57
|
-
throw error;
|
|
58
|
-
}
|
|
59
|
-
}
|
|
60
|
-
|
|
61
|
-
export async function downloadWithFallback(options, onProgress) {
|
|
62
|
-
const {
|
|
63
|
-
huggingfaceCid,
|
|
64
|
-
huggingfaceUrl,
|
|
65
|
-
destPath,
|
|
66
|
-
manifest,
|
|
67
|
-
minBytes,
|
|
68
|
-
preferredLayer = } = options;
|
|
69
|
-
|
|
70
|
-
const dir = path.dirname(destPath);
|
|
71
|
-
if (!fs.existsSync(dir)) {
|
|
72
|
-
fs.mkdirSync(dir, { recursive: true });
|
|
73
|
-
}
|
|
74
|
-
|
|
75
|
-
if (fs.existsSync(destPath)) {
|
|
76
|
-
const verification = verifyFileIntegrity(destPath, manifest?.sha256, minBytes);
|
|
77
|
-
if (verification.valid) {
|
|
78
|
-
recordMetric({
|
|
79
|
-
modelType: 'model',
|
|
80
|
-
layer: 'cache',
|
|
81
|
-
status: 'hit'
|
|
82
|
-
});
|
|
83
|
-
return { success: true, source: 'cache' };
|
|
84
|
-
} else {
|
|
85
|
-
console.warn(`Cache invalid (${verification.reason}), re-downloading...`);
|
|
86
|
-
const backupPath = `${destPath}.bak`;
|
|
87
|
-
if (fs.existsSync(backupPath)) fs.unlinkSync(backupPath);
|
|
88
|
-
fs.renameSync(destPath, backupPath);
|
|
89
|
-
}
|
|
90
|
-
}
|
|
91
|
-
|
|
92
|
-
const layers = preferredLayer === ? ['huggingface']
|
|
93
|
-
: ['huggingface', ];
|
|
94
|
-
|
|
95
|
-
for (const layer of layers) {
|
|
96
|
-
try {
|
|
97
|
-
if (layer === && huggingfaceCid) {
|
|
98
|
-
return await downloadFromhuggingface(huggingfaceCid, destPath, manifest, onProgress);
|
|
99
|
-
} else if (layer === 'huggingface' && huggingfaceUrl) {
|
|
100
|
-
return await downloadFromHuggingFace(huggingfaceUrl, destPath, minBytes, onProgress);
|
|
101
|
-
}
|
|
102
|
-
} catch (error) {
|
|
103
|
-
console.warn(`${layer} layer failed:`, error.message);
|
|
104
|
-
continue;
|
|
105
|
-
}
|
|
106
|
-
}
|
|
107
|
-
|
|
108
|
-
recordMetric({
|
|
109
|
-
modelType: 'model',
|
|
110
|
-
status: 'all_layers_exhausted'
|
|
111
|
-
});
|
|
112
|
-
|
|
113
|
-
throw new Error('All download layers exhausted');
|
|
114
|
-
}
|
|
115
|
-
|
|
116
|
-
export { getMetrics, getMetricsSummary, resetMetrics } from './download-metrics.js';
|