mirror of
https://github.com/Niko1221/Strata.git
synced 2026-11-09 17:36:14 -10:00
The UI source from the 14 October handoff (src/, public/, index.html, vite and tsconfig, tests, audit-fixes, design docs) and the App Host (server/*.mjs): model import and monitor routes, API-provider catalog and streaming (OpenAI chat, OpenAI Responses, the Messages API), serving, tunnel, tasks, plus the host routes for Time-skip (server/timeskip.mjs) and the tuning plan/reports. src/lib/time-skip.ts renders a real job's own record. The UI design is unchanged. The rebuild routed #/tuning to a new TunePanel; that is reverted: src/screens/ModelRun.tsx and src/main.tsx are the handoff's again (#/tuning goes where the handoff sends it), and src/components/TunePanel.tsx and src/styles/tuning.css, which only that route used, are not carried over. Left out of git on purpose: dist/ (build output), node_modules, and docs/evidence + docs/checkpoints (170 MB of screenshots, kept in StrataSplit\evidence-archive). From the owner's rebuild branch strata/rebuild-2026-10.
35 lines
1.3 KiB
JavaScript
35 lines
1.3 KiB
JavaScript
/** One active inference request; queued work is cancellable and never survives host exit. */
|
|
export class RequestQueue {
|
|
#pending = [];
|
|
#active = false;
|
|
constructor(onChange = () => {}) { this.onChange = onChange; }
|
|
get waiting() { return this.#pending.length; }
|
|
run(signal, task) {
|
|
return new Promise((resolve, reject) => {
|
|
const entry = { signal, task, resolve, reject, abort: null };
|
|
entry.abort = () => {
|
|
const index = this.#pending.indexOf(entry);
|
|
if (index < 0) return;
|
|
this.#pending.splice(index, 1);
|
|
reject(signal.reason ?? new DOMException('Request cancelled', 'AbortError'));
|
|
this.onChange(this.waiting);
|
|
};
|
|
if (signal.aborted) { reject(signal.reason); return; }
|
|
signal.addEventListener('abort', entry.abort, { once: true });
|
|
this.#pending.push(entry);
|
|
this.#drain();
|
|
});
|
|
}
|
|
async #drain() {
|
|
if (this.#active) { this.onChange(this.waiting); return; }
|
|
const entry = this.#pending.shift();
|
|
if (!entry) { this.onChange(0); return; }
|
|
this.#active = true;
|
|
entry.signal.removeEventListener('abort', entry.abort);
|
|
this.onChange(this.waiting);
|
|
try { entry.signal.throwIfAborted(); entry.resolve(await entry.task()); }
|
|
catch (error) { entry.reject(error); }
|
|
finally { this.#active = false; this.#drain(); }
|
|
}
|
|
}
|