Files
bare-operating-system/packages/bare-os-booter/lib/bare-os-qvac-gguf-diagnose.mjs
T
Raven Scott 2661b3ee3d
Release rolling / release (push) Successful in 8m32s
Update
2026-07-31 17:43:19 -04:00

128 lines
3.7 KiB
JavaScript

/**
* Diagnose a GGUF on disk after load failure (magic / size / sha256).
*/
/** @type {Record<string, { size: number, sha256: string }>} */
export const BARE_OS_QVAC_KNOWN_GGUF = {
'Qwen3-0.6B-Q4_0.gguf': {
size: 382156480,
sha256: '33bcc57074ec7b6eada5a90651ee546ec0c2b271002c22baf9f1b2dd1e8f75cb'
},
'Qwen3-1.7B-Q4_0.gguf': {
size: 1056782912,
sha256: 'c876f159707a4e4f70e045106c69db15bfc935a4981706fd4f65c6e7ea1e81c5'
}
}
/**
* @param {string} filePath
* @returns {Promise<string>}
*/
export async function bareOsQvacDiagnoseGguf(filePath) {
const p = String(filePath || '').trim()
if (!p) return 'gguf: (no path)'
/** @type {string[]} */
const lines = ['gguf path: ' + p]
try {
let fs
try {
fs = await import('bare-fs')
} catch {
fs = await import('fs')
}
const fsp = fs.promises || fs
const st = await fsp.stat(p)
lines.push('size: ' + st.size + ' bytes')
const base =
p.split(/[/\\]/).pop() ||
''
const known = BARE_OS_QVAC_KNOWN_GGUF[base.replace(/^[0-9a-f]+_/i, '')] ||
Object.entries(BARE_OS_QVAC_KNOWN_GGUF).find(([name]) =>
base.endsWith(name)
)?.[1]
if (known) {
lines.push(
'expectedSize: ' +
known.size +
(st.size === known.size ? ' (ok)' : ' (MISMATCH)')
)
}
const buf = Buffer.alloc(4)
let fh
try {
if (typeof fsp.open === 'function') {
fh = await fsp.open(p, 'r')
if (typeof fh.read === 'function') {
await fh.read(buf, 0, 4, 0)
} else if (typeof fs.read === 'function' && fh.fd != null) {
await new Promise((resolve, reject) => {
fs.read(fh.fd, buf, 0, 4, 0, (err) => (err ? reject(err) : resolve()))
})
}
} else {
const fd = fs.openSync(p, 'r')
fs.readSync(fd, buf, 0, 4, 0)
fs.closeSync(fd)
}
} finally {
try {
if (fh && typeof fh.close === 'function') await fh.close()
} catch {
/* ignore */
}
}
const magic = buf.toString('utf8')
lines.push('magic: ' + JSON.stringify(magic) + (magic === 'GGUF' ? ' (ok)' : ' (BAD)'))
if (known && st.size === known.size && st.size <= 2 * 1024 * 1024 * 1024) {
try {
let crypto
try {
crypto = await import('bare-crypto')
} catch {
crypto = await import('crypto')
}
const createHash = crypto.createHash || crypto.default?.createHash
if (typeof createHash === 'function') {
const hash = createHash('sha256')
const stream = fs.createReadStream
? fs.createReadStream(p)
: null
if (stream) {
await new Promise((resolve, reject) => {
stream.on('data', (c) => hash.update(c))
stream.on('error', reject)
stream.on('end', resolve)
})
const dig = hash.digest('hex')
lines.push(
'sha256: ' +
dig +
(dig === known.sha256 ? ' (ok)' : ' (MISMATCH want ' + known.sha256 + ')')
)
}
}
} catch (e) {
lines.push('sha256: (skip ' + String(e && e.message ? e.message : e) + ')')
}
}
} catch (e) {
lines.push('diagnose error: ' + String(e && e.message ? e.message : e))
}
return lines.join('; ')
}
/**
* Extract a GGUF path from a QVAC / llama error string.
* @param {string} msg
* @returns {string}
*/
export function bareOsQvacExtractGgufPath(msg) {
const m = /failed to load model '([^']+\.gguf)'/i.exec(String(msg || ''))
if (m) return m[1]
const m2 = /(\/[^\s']+\.gguf)/i.exec(String(msg || ''))
return m2 ? m2[1] : ''
}