import assert from 'node:assert/strict'; import { once } from 'node:events'; import { Worker } from 'node:worker_threads'; import test from 'node:test'; test('actual worker module initializes and serves shell/editor/export RPCs without loading a model', { timeout: 10_000 }, async t => { // Supply only browser worker messaging globals. The app's real module graph, // real shell, actual runtime imports, and RPC entrypoint execute unchanged. const url = new URL('../src/agent.worker.js', import.meta.url).href; const worker = new Worker(` const { parentPort } = require('node:worker_threads'); globalThis.self = globalThis; globalThis.postMessage = message => parentPort.postMessage(message); parentPort.on('message', data => globalThis.onmessage({ data })); import(${JSON.stringify(url)}).catch(error => { throw error; }); `, { eval: true }); t.after(() => worker.terminate()); const events = []; worker.on('message', message => events.push(message)); let initialized; while (!initialized) { const [event] = await once(worker, 'message'); if (event.type === 'fatal') throw new Error(event.error); if (event.type === 'initialized') initialized = event; } assert.match(initialized.files['/workspace/sales.csv'], /Notebook,12/); assert.deepEqual(initialized.messages, []); assert(events.some(event => event.type === 'persistence_error')); let id = 0; async function rpc(action, args) { const requestId = ++id; worker.postMessage({ id: requestId, action, args }); for (;;) { const [event] = await once(worker, 'message'); if (event.type === 'reply' && event.id === requestId) { if (event.error) throw Object.assign(new Error(event.error), { code: event.errorCode }); return event.value; } } } assert.equal(await rpc('cache_status'), false); const shell = await rpc('shell', { command: 'printf "verified\\n" > /workspace/worker-check.txt; cat /workspace/worker-check.txt' }); assert.equal(shell.exitCode, 0); assert.equal(shell.stdout, 'verified\n'); await rpc('write', { path: 'worker-check.txt', content: 'edited' }); assert.equal(await rpc('read', { path: 'worker-check.txt' }), 'edited'); const exported = await rpc('snapshot'); assert.equal(exported.runtime, 'minicpm5-gguf'); assert.equal(exported.files['/workspace/worker-check.txt'], 'edited'); assert(exported.entries.some(([path]) => path === '/workspace/worker-check.txt')); const fresh = await rpc('new_chat'); assert.deepEqual(fresh.messages, []); assert.equal(fresh.files['/workspace/worker-check.txt'], 'edited'); await assert.rejects(rpc('prompt', { text: 'hello' }), /Load the model first/); await assert.rejects(rpc('load', { cachedOnly: true }), error => error.code === 'MODEL_CACHE_MISS'); assert.equal(await rpc('stop'), true); assert(events.some(event => event.type === 'workspace')); assert(events.some(event => event.type === 'idle')); }); test('a failed worker initialization identifies the failure stage and rejects subsequent RPCs', { timeout: 10_000 }, async t => { const url = new URL('../src/agent.worker.js', import.meta.url).href; const worker = new Worker(` const { parentPort } = require('node:worker_threads'); globalThis.self = globalThis; globalThis.postMessage = message => parentPort.postMessage(message); parentPort.on('message', data => globalThis.onmessage({ data })); // Simulate an unreadable workspace rather than a model or storage outage. // Loading malformed saved entries fails after IndexedDB has opened. globalThis.indexedDB = { open() { const db = { transaction() { return { objectStore() { return { get() { const request = { result: { entries: [['/workspace/file', { type: 'file', base64: 'invalid!' }]] } }; queueMicrotask(() => request.onsuccess()); return request; } }; } }; } }; const request = { result: db }; queueMicrotask(() => request.onsuccess()); return request; } }; import(${JSON.stringify(url)}).catch(error => { throw error; }); `, { eval: true }); t.after(() => worker.terminate()); const [fatal] = await once(worker, 'message'); assert.equal(fatal.type, 'fatal'); assert.equal(fatal.stage, 'initialization'); assert.match(fatal.error, /Reload the page/); worker.postMessage({ id: 1, action: 'read', args: { path: 'README.md' } }); const [reply] = await once(worker, 'message'); assert.equal(reply.type, 'reply'); assert.equal(reply.id, 1); assert(reply.error); });