"Open" takes .ll, .qir and .jeff beside .qasm: the engine reads the file to OpenQASM 3 in the page (engine_convert, in the worker), the program goes into the editor as a version from the file, and the line under it names the format and its version, the check (written back to its format and read again) and each of the reader's notes with its code. A module the reader refuses leaves the editor as it was, the refusal and its code in the status line. The desktop app answers the same request with a convert command. The Studio e2e opens a QIR module, a jeff module and a module its profile forbids; the desktop's test is pinned in CI. Co-Authored-By: Claude Opus 5.5 <[email protected]>
107 lines
7 KiB
JavaScript
107 lines
7 KiB
JavaScript
// The job service's engine, compiled for the browser, off the page's thread.
|
|
// The page posts {id, op, pkg, seed, memoryMb, ...}; the first message loads
|
|
// the engine package from `pkg`. Answers are {id, ok, value} or {id, ok: false,
|
|
// error}. The page ends a long job by ending this worker.
|
|
let loaded = null;
|
|
let mod = null;
|
|
let engine = null;
|
|
let engineKey = null;
|
|
|
|
async function load(pkg) {
|
|
loaded ??= import(pkg).then(async (m) => { await m.default(); mod = m; });
|
|
await loaded;
|
|
}
|
|
|
|
function engineFor(seed, memoryMb) {
|
|
const key = seed.join(',') + '/' + memoryMb;
|
|
if (!engine || engineKey !== key) {
|
|
engine?.free?.();
|
|
engine = new mod.QuantumEngine(new Uint8Array(seed), memoryMb);
|
|
engineKey = key;
|
|
}
|
|
return engine;
|
|
}
|
|
|
|
self.onmessage = async (ev) => {
|
|
const { id, op, pkg, seed, memoryMb } = ev.data;
|
|
try {
|
|
await load(pkg);
|
|
const e = () => engineFor(seed, memoryMb);
|
|
let text;
|
|
switch (op) {
|
|
case 'run': text = e().run(JSON.stringify(ev.data.request)); break;
|
|
case 'plan': text = e().plan(JSON.stringify(ev.data.request)); break;
|
|
case 'methods': text = e().methods(); break;
|
|
case 'signer': text = JSON.stringify({ did: e().signer_did() }); break;
|
|
case 'lint': text = mod.engine_lint(ev.data.qasm); break;
|
|
case 'draw': text = mod.engine_draw(ev.data.qasm, ev.data.width ?? 100); break;
|
|
case 'layout': text = mod.engine_layout(ev.data.qasm); break;
|
|
case 'verify': text = mod.engine_verify(JSON.stringify(ev.data.job)); break;
|
|
case 'critique': text = mod.engine_critique(ev.data.qasm); break;
|
|
case 'equivalent': text = mod.engine_equivalent(ev.data.a, ev.data.b); break;
|
|
case 'convert': text = mod.engine_convert(JSON.stringify(ev.data.request)); break;
|
|
case 'variants': text = mod.engine_variants(ev.data.qasm); break;
|
|
case 'shortcuts': text = mod.engine_shortcuts(ev.data.qasm, !!ev.data.thorough); break;
|
|
case 'compile': text = e().compile(JSON.stringify(ev.data.request)); break;
|
|
case 'targets': text = mod.engine_targets(); break;
|
|
case 'target': text = mod.engine_target(ev.data.spec); break;
|
|
case 'target_place': text = mod.engine_target_place(ev.data.qasm, JSON.stringify(ev.data.target)); break;
|
|
case 'estimate': text = e().estimate(JSON.stringify(ev.data.request)); break;
|
|
case 'estimate_verify': text = mod.engine_estimate_verify(JSON.stringify(ev.data.body)); break;
|
|
case 'qec': text = e().qec(ev.data.name, JSON.stringify(ev.data.args ?? {})); break;
|
|
case 'pulse': text = e().pulse(ev.data.name, JSON.stringify(ev.data.args ?? {})); break;
|
|
case 'verdict': text = mod.engine_verdict(JSON.stringify(ev.data.job), ev.data.intent ? JSON.stringify(ev.data.intent) : '', memoryMb); break;
|
|
case 'repair': text = mod.engine_repair(ev.data.qasm, JSON.stringify(ev.data.options ?? {})); break;
|
|
case 'lint_with': text = mod.engine_lint_with(ev.data.qasm, JSON.stringify(ev.data.inputs ?? {})); break;
|
|
case 'critique_with': text = mod.engine_critique_with(ev.data.qasm, JSON.stringify(ev.data.inputs ?? {})); break;
|
|
case 'instantiate': text = mod.engine_instantiate(ev.data.qasm, JSON.stringify(ev.data.inputs ?? {})); break;
|
|
case 'discover_evaluate': text = mod.engine_discover_evaluate(JSON.stringify(ev.data.spec), ev.data.source); break;
|
|
case 'discover_start': text = e().discover_start(JSON.stringify(ev.data.spec)); break;
|
|
case 'discover_submit': text = e().discover_submit(JSON.stringify(ev.data.spec), JSON.stringify(ev.data.archive), ev.data.source, ev.data.parent ?? undefined, ev.data.proposer, ev.data.note ?? undefined); break;
|
|
case 'discover_search': text = e().discover_search(JSON.stringify(ev.data.spec), JSON.stringify(ev.data.archive), ev.data.from >>> 0, ev.data.evaluations >>> 0); break;
|
|
case 'history': text = e().history(ev.data.name, JSON.stringify(ev.data.args ?? {})); break;
|
|
case 'locks': text = mod.engine_locks(ev.data.name, JSON.stringify(ev.data.args ?? {})); break;
|
|
case 'novelty': text = mod.engine_novelty(JSON.stringify(ev.data.args ?? {})); break;
|
|
case 'study': text = e().study(ev.data.name, JSON.stringify(ev.data.args ?? {})); break;
|
|
case 'converge': text = mod.engine_converge(ev.data.name, JSON.stringify(ev.data.args ?? {})); break;
|
|
case 'rewrite': text = mod.engine_rewrite(ev.data.name, JSON.stringify(ev.data.args ?? {})); break;
|
|
case 'taste': text = mod.engine_taste(ev.data.name, JSON.stringify(ev.data.args ?? {})); break;
|
|
case 'debug': text = mod.engine_debug(ev.data.name, JSON.stringify(ev.data.args ?? {})); break;
|
|
case 'visual_edit': text = mod.engine_visual_edit(ev.data.qasm, JSON.stringify(ev.data.edit ?? {})); break;
|
|
case 'picture': text = mod.engine_picture(ev.data.qasm, ev.data.format); break;
|
|
case 'discover_novelty': text = mod.engine_discover_novelty(JSON.stringify(ev.data.spec), JSON.stringify(ev.data.archive), ev.data.entry); break;
|
|
case 'answer': {
|
|
const a = ev.data.args ?? {};
|
|
switch (ev.data.name) {
|
|
case 'parse': text = mod.engine_answer_parse(a.text); break;
|
|
case 'snapshot': { const s = new mod.AnswerStream(); s.push(a.text); text = s.snapshot(); s.free(); break; }
|
|
case 'value': text = e().answer_value(a.text, a.name, !!a.complete); break;
|
|
case 'evaluate': text = e().answer_evaluate(a.text); break;
|
|
case 'verify': text = mod.engine_answer_verify(a.text, memoryMb); break;
|
|
case 'marker': text = mod.engine_answer_marker(a.statement, JSON.stringify(a.sealed)); break;
|
|
case 'prompt': text = mod.engine_answer_prompt(); break;
|
|
default: throw new Error(`no answer call ${ev.data.name}`);
|
|
}
|
|
break;
|
|
}
|
|
case 'telemetry': {
|
|
const a = ev.data.args ?? {};
|
|
if (ev.data.name === 'record') text = mod.engine_telemetry_record(JSON.stringify(a.fields ?? {}));
|
|
else if (ev.data.name === 'corpus') text = mod.engine_telemetry_corpus(JSON.stringify(a.records ?? []));
|
|
else throw new Error(`no telemetry call ${ev.data.name}`);
|
|
break;
|
|
}
|
|
case 'course': text = mod.engine_course(ev.data.locale ?? 'en'); break;
|
|
case 'course_lesson': text = mod.engine_course_lesson(ev.data.lesson, ev.data.locale ?? 'en'); break;
|
|
case 'course_check': text = mod.engine_course_check(ev.data.lesson, ev.data.qasm, ev.data.locale ?? 'en', memoryMb); break;
|
|
case 'course_hint': text = mod.engine_course_hint(ev.data.lesson, ev.data.qasm ?? '', ev.data.level >>> 0, ev.data.locale ?? 'en', memoryMb); break;
|
|
default: throw new Error(`no operation ${op}`);
|
|
}
|
|
const value = JSON.parse(text);
|
|
// A lint or a critique of a program that does not read is an answer that names the problem.
|
|
if (value && value.error && !['lint', 'critique', 'lint_with', 'critique_with', 'answer', 'telemetry'].includes(op)) self.postMessage({ id, ok: false, error: value.error });
|
|
else self.postMessage({ id, ok: true, value });
|
|
} catch (err) {
|
|
self.postMessage({ id, ok: false, error: String(err && err.message ? err.message : err) });
|
|
}
|
|
};
|