Humuhumu33 commited on
Commit
e683441
·
verified ·
1 Parent(s): a1e9430

retire-provenance: superseded Q b/ objects (sha256 CAS, HOLO-LEAN-RESOLVER P1.3)

Browse files
sha256/36da31e3e35bee518360dccc573f3f97cfaec70a004de7ee6324b0343df0c25c ADDED
@@ -0,0 +1,407 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <!doctype html>
2
+ <meta charset="utf-8">
3
+ <meta name="viewport" content="width=device-width,initial-scale=1">
4
+ <title>Bonsai</title>
5
+ <style>
6
+ /* Claude-desktop look: warm charcoal stage, 11% hairlines, 12-14px radii, serif display, coral accent.
7
+ Type floor is 15px everywhere. Everything fits ONE viewport at 1280×800 AND 375×812 (dvh + clamp). */
8
+ :root { --bg:#262624; --ink:#eceae4; --muted:#b8b5ad; --faint:rgba(232,230,224,.45);
9
+ --hair:rgba(255,255,255,.11); --coral:#d97757; --coral-hi:#e8987a; --lav:#c4b5fd; --r:13px;
10
+ --serif:"Tiempos Text","Charter","Iowan Old Style",Georgia,serif; }
11
+ * { box-sizing:border-box; margin:0; padding:0; }
12
+ html,body { height:100%; }
13
+ body { background:var(--bg); color:var(--ink); font:15px/1.55 system-ui,-apple-system,"Segoe UI",Inter,sans-serif;
14
+ -webkit-font-smoothing:antialiased; overflow:hidden; }
15
+ .num { font-family:ui-monospace,SFMono-Regular,Menlo,Consolas,monospace; font-size:15px; }
16
+ .stage { position:fixed; inset:0; height:100dvh; display:flex; flex-direction:column; align-items:center;
17
+ justify-content:center; padding:24px; opacity:0; pointer-events:none; transition:opacity .6s ease; }
18
+ .stage.on { opacity:1; pointer-events:auto; }
19
+
20
+ /* ── arrival: full-bleed hologram canvas behind left-aligned copy ── */
21
+ #arrive { flex-direction:row; align-items:center; justify-content:flex-start; padding:0; }
22
+ #holo { position:absolute; inset:0; width:100%; height:100%; display:block; }
23
+ #arrive .copy { position:relative; z-index:1; max-width:620px; padding:0 clamp(24px,6vw,96px); }
24
+ #arrive h1 { font-family:var(--serif); font-weight:500; font-size:clamp(40px,7vw,84px); line-height:1.06;
25
+ letter-spacing:-.015em; text-wrap:balance; }
26
+ #arrive .sub { margin-top:22px; font-size:clamp(18px,1.6vw,20px); line-height:1.5; color:var(--muted); max-width:46ch; }
27
+ #arrive button { margin-top:34px; background:var(--coral); border:none; color:#faf9f5; border-radius:999px;
28
+ padding:16px 34px; font:500 17px/1 system-ui,sans-serif; cursor:pointer;
29
+ transition:transform .2s ease, filter .2s ease; }
30
+ #arrive button:hover { filter:brightness(1.08); transform:translateY(-1px); }
31
+ #arrive button:disabled { filter:saturate(.3) brightness(.8); cursor:default; transform:none; }
32
+ #arrive .fine { margin-top:16px; font-size:15px; color:var(--faint); }
33
+ @media (max-width:760px) { /* stacked: hologram floats in the upper half, copy anchors low */
34
+ #arrive { align-items:flex-end; }
35
+ #arrive .copy { padding-bottom:max(44px, env(safe-area-inset-bottom, 0px) + 36px); }
36
+ }
37
+
38
+ /* ── stream (the loading film): big serif number over the signature shard grid ── */
39
+ #stream { justify-content:center; }
40
+ #stream .big { font-family:var(--serif); font-weight:500; font-size:clamp(36px,5.5vw,58px); line-height:1;
41
+ letter-spacing:-.01em; margin-bottom:20px; min-height:1em; }
42
+ #stream .big small { font-size:.45em; color:var(--muted); font-family:system-ui,sans-serif; font-weight:400; }
43
+ #grid { display:grid; grid-template-columns:repeat(21,1fr); gap:2px; width:min(88vw,540px); }
44
+ #grid i { display:block; aspect-ratio:1; border-radius:1.5px; background:rgba(255,255,255,.06); transition:background .35s; }
45
+ #grid i.on { background:var(--coral); }
46
+ #grid i.hot { background:var(--coral-hi); }
47
+ #stream .stats { margin-top:18px; color:var(--muted); }
48
+ #stream .kap { margin-top:8px; color:var(--faint); }
49
+ #stream .law { margin-top:20px; font-size:15px; color:var(--muted); text-align:center; max-width:480px; }
50
+ #stream .phase { margin-top:6px; font-size:15px; color:var(--coral-hi); min-height:20px; }
51
+
52
+ /* ── chat: the Claude-desktop room — serif greeting, ONE centered input card, quiet metrics ── */
53
+ #chat { justify-content:center; padding:0; }
54
+ #chat .col { display:flex; flex-direction:column; width:min(100%,760px); height:100%; padding:0 22px; justify-content:center; }
55
+ #chat .col.started { justify-content:flex-start; }
56
+ #hello { text-align:center; margin-bottom:26px; }
57
+ #hello .mark { display:inline-block; width:30px; height:30px; vertical-align:-4px; margin-right:12px; color:var(--coral); }
58
+ #hello h2 { display:inline; font-family:var(--serif); font-weight:500; font-size:clamp(30px,4.4vw,44px); letter-spacing:-.01em; }
59
+ .col.started #hello { display:none; }
60
+ #log { display:none; }
61
+ .col.started #log { display:block; flex:1; overflow-y:auto; padding:30px 4px 16px; }
62
+ .msg { margin:0 0 20px; }
63
+ .msg .who { font-size:15px; color:var(--faint); margin-bottom:4px; }
64
+ .msg.user .who { color:var(--muted); }
65
+ .msg .body { white-space:pre-wrap; font-size:16px; line-height:1.6; }
66
+ details.think { margin:0 0 8px; border-left:2px solid var(--hair); padding-left:10px; }
67
+ details.think summary { list-style:none; cursor:pointer; font-size:15px; color:var(--faint); }
68
+ details.think summary::-webkit-details-marker { display:none; }
69
+ details.think .t { color:var(--faint); font-size:15px; white-space:pre-wrap; margin-top:4px; }
70
+ .note { text-align:center; font-size:15px; color:var(--faint); margin:6px 0 12px; }
71
+ #card { background:rgba(255,255,255,.03); border:1px solid var(--hair); border-radius:18px; padding:6px 8px 8px; }
72
+ #card:focus-within { border-color:rgba(217,119,87,.5); }
73
+ #inp { width:100%; background:none; border:none; color:var(--ink); padding:14px 12px 10px;
74
+ font:16px/1.45 system-ui,sans-serif; outline:none; }
75
+ #cardrow { display:flex; align-items:center; gap:12px; padding:0 8px 4px 12px; }
76
+ #modelname { font-size:15px; color:var(--muted); }
77
+ #cardrow .grow { flex:1; }
78
+ #send { background:var(--coral); border:none; color:#faf9f5; border-radius:999px; width:38px; height:38px;
79
+ font:500 17px/1 system-ui,sans-serif; cursor:pointer; transition:filter .2s ease; }
80
+ #send:hover { filter:brightness(1.08); }
81
+ #send:disabled { background:rgba(255,255,255,.06); color:var(--faint); cursor:default; }
82
+ #metrics { text-align:center; font-size:15px; color:var(--faint); padding:12px 0 16px; min-height:22px; }
83
+ #metrics b { color:var(--muted); font-weight:500; }
84
+ #err { color:#f87171; font-size:15px; margin-top:16px; max-width:560px; text-align:center; white-space:pre-wrap; }
85
+ </style>
86
+ <body>
87
+
88
+ <div class="stage on" id="arrive">
89
+ <canvas id="holo"></canvas>
90
+ <div class="copy">
91
+ <h1>An AI<br>that&rsquo;s yours.</h1>
92
+ <p class="sub">Bonsai streams into your browser like a film. Every piece is checked before it runs. After one visit it answers on your device, even offline.</p>
93
+ <button id="go">Stream the mind</button>
94
+ <div class="fine" id="fine">Free &middot; open weights by Prism ML &middot; nothing leaves your device</div>
95
+ </div>
96
+ </div>
97
+
98
+ <div class="stage" id="stream">
99
+ <div class="big" id="big">&nbsp;</div>
100
+ <div id="grid"></div>
101
+ <div class="stats num" id="stats">&nbsp;</div>
102
+ <div class="kap num" id="kap">&nbsp;</div>
103
+ <div class="phase" id="phase">&nbsp;</div>
104
+ <div class="law">Every block is verified against its content address before it touches the GPU.</div>
105
+ <div id="err" hidden></div>
106
+ </div>
107
+
108
+ <div class="stage" id="chat">
109
+ <div class="col" id="col">
110
+ <div id="hello">
111
+ <svg class="mark" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.6" stroke-linecap="round" aria-hidden="true"><path d="M12 3v18M3 12h18M5.6 5.6l12.8 12.8M18.4 5.6L5.6 18.4"/></svg><h2>Ready when you are.</h2>
112
+ </div>
113
+ <div id="log"></div>
114
+ <div id="card">
115
+ <input id="inp" placeholder="Ask Bonsai anything" autocomplete="off">
116
+ <div id="cardrow">
117
+ <span id="modelname">Bonsai</span>
118
+ <span class="grow"></span>
119
+ <button id="send" aria-label="Send">&uarr;</button>
120
+ </div>
121
+ </div>
122
+ <div id="metrics">on your device</div>
123
+ </div>
124
+ </div>
125
+
126
+ <script type="module">
127
+ // ── the holographic centerpiece ─────────────────────────────────────────────────────────────
128
+ // Fresnel rim + animated scan stripes + occasional slice glitch, additive-blended over the warm
129
+ // charcoal. In the spirit of ektogamat/threejs-vanilla-holographic-material (MIT) — this GLSL is
130
+ // written fresh for this page. three.js is VENDORED (no CDN) and imported AFTER first paint so
131
+ // the hero text never waits on it. On "Stream the mind" the loop stops and the GL context is
132
+ // released (dispose + lose-context) — the model engine gets the whole GPU.
133
+ const cv = document.getElementById("holo");
134
+ const reduced = matchMedia("(prefers-reduced-motion: reduce)").matches;
135
+ window.__holoOff = null;
136
+ try {
137
+ // hero paints first: two rAFs when the tab is visible, 250ms fallback when rAF is starved
138
+ // (hidden/embedded tabs never fire rAF — the hologram must still initialize for their return).
139
+ await new Promise((r) => { requestAnimationFrame(() => requestAnimationFrame(r)); setTimeout(r, 250); });
140
+ if (!document.getElementById("arrive").classList.contains("on")) throw new Error("past landing");
141
+ const THREE = await import("./vendor/three.module.min.js");
142
+ const renderer = new THREE.WebGLRenderer({ canvas: cv, antialias: true, alpha: true, powerPreference: "high-performance" });
143
+ renderer.setPixelRatio(Math.min(devicePixelRatio || 1, 2));
144
+ const scene = new THREE.Scene();
145
+ const cam = new THREE.PerspectiveCamera(45, 1, 0.1, 30); cam.position.z = 5;
146
+ const uni = {
147
+ uTime: { value: 0 },
148
+ uSpeed: { value: 0.35 }, // stripe scroll; boosted on hover
149
+ uGlitch: { value: reduced ? 0 : 1 },
150
+ uBase: { value: new THREE.Color("#d97757") }, // Claude coral core
151
+ uRim: { value: new THREE.Color("#c4b5fd") }, // lavender at the fresnel rim
152
+ };
153
+ const mat = new THREE.ShaderMaterial({
154
+ uniforms: uni, transparent: true, blending: THREE.AdditiveBlending, side: THREE.DoubleSide, depthWrite: false,
155
+ vertexShader: /* glsl */`
156
+ uniform float uTime; uniform float uGlitch;
157
+ varying vec3 vN; varying vec3 vW;
158
+ float rnd(float n){ return fract(sin(n)*43758.5453123); }
159
+ void main(){
160
+ vec3 p = position;
161
+ float gate = step(0.72, rnd(floor(uTime*1.8))) * uGlitch; // a burst every few seconds
162
+ float band = step(0.94, rnd(floor(p.y*9.0) + floor(uTime*7.0))); // thin horizontal slices
163
+ float g = gate * band;
164
+ p.x += (rnd(p.y*13.7 + floor(uTime*7.0)) - 0.5) * 0.22 * g;
165
+ p.z += (rnd(p.y*7.1 - floor(uTime*7.0)) - 0.5) * 0.22 * g;
166
+ vec4 w = modelMatrix * vec4(p, 1.0);
167
+ vW = w.xyz; vN = normalize(mat3(modelMatrix) * normal);
168
+ gl_Position = projectionMatrix * viewMatrix * w;
169
+ }`,
170
+ fragmentShader: /* glsl */`
171
+ uniform float uTime; uniform float uSpeed; uniform vec3 uBase; uniform vec3 uRim;
172
+ varying vec3 vN; varying vec3 vW;
173
+ void main(){
174
+ vec3 V = normalize(cameraPosition - vW);
175
+ vec3 N = normalize(vN); if (!gl_FrontFacing) N = -N;
176
+ float f = pow(1.0 - clamp(dot(V, N), 0.0, 1.0), 2.2); // fresnel rim
177
+ float s = pow(fract(vW.y * 6.0 - uTime * uSpeed), 3.0); // scan stripes
178
+ gl_FragColor = vec4(mix(uBase, uRim, f), f * 0.85 + s * 0.28 + 0.03);
179
+ }`,
180
+ });
181
+ const mesh = new THREE.Mesh(new THREE.IcosahedronGeometry(1.35, 12), mat);
182
+ scene.add(mesh);
183
+ // pointer parallax: mesh tilts toward the cursor (eased); stripes speed up when the cursor is near.
184
+ let tx = 0, ty = 0, rx = 0, ry = 0, boost = 0, tBoost = 0;
185
+ if (!reduced) addEventListener("pointermove", (e) => {
186
+ const nx = e.clientX / innerWidth * 2 - 1, ny = e.clientY / innerHeight * 2 - 1;
187
+ tx = nx * 0.45; ty = ny * 0.35;
188
+ const c = mesh.position.clone().project(cam); // mesh center in NDC
189
+ tBoost = Math.hypot(nx - c.x, ny - c.y) < 0.55 ? 1 : 0;
190
+ }, { passive: true });
191
+ const size = () => { // right-of-center desktop · upper-half mobile
192
+ renderer.setSize(innerWidth, innerHeight, false);
193
+ cam.aspect = innerWidth / innerHeight; cam.updateProjectionMatrix();
194
+ const hw = Math.tan(cam.fov * Math.PI / 360) * cam.position.z; // half-height of the frustum at z=0
195
+ if (cam.aspect > 0.92) { mesh.position.set(hw * cam.aspect * 0.48, 0, 0); mesh.scale.setScalar(1); }
196
+ else { mesh.position.set(0, hw * 0.42, 0); mesh.scale.setScalar(0.78); }
197
+ };
198
+ size(); addEventListener("resize", size);
199
+ let raf = 0, dead = false;
200
+ const loop = () => {
201
+ const t = performance.now() / 1000;
202
+ uni.uTime.value = t;
203
+ boost += (tBoost - boost) * 0.06;
204
+ uni.uSpeed.value = 0.35 + boost * 1.1;
205
+ rx += (ty - rx) * 0.05; ry += (tx - ry) * 0.05; // eased parallax
206
+ mesh.rotation.x = rx * 0.6; mesh.rotation.y = t * 0.12 + ry; // + constant slow spin
207
+ renderer.render(scene, cam);
208
+ raf = requestAnimationFrame(loop);
209
+ };
210
+ document.addEventListener("visibilitychange", () => {
211
+ if (dead) return;
212
+ if (document.hidden) cancelAnimationFrame(raf); else raf = requestAnimationFrame(loop);
213
+ });
214
+ loop();
215
+ // verification hook: force one frame at time t and return it as a PNG (rAF is starved in
216
+ // hidden/embedded panes — this is how an agent proves the hologram actually draws pixels).
217
+ window.__holoFrame = (t) => { uni.uTime.value = t || 0; renderer.render(scene, cam); return cv.toDataURL("image/png"); };
218
+ window.__holoOff = () => { // MANDATORY before the engine loads
219
+ dead = true; cancelAnimationFrame(raf); window.__holoFrame = null;
220
+ mesh.geometry.dispose(); mat.dispose(); renderer.dispose();
221
+ try { renderer.getContext().getExtension("WEBGL_lose_context").loseContext(); } catch {}
222
+ cv.remove();
223
+ };
224
+ } catch {} // no WebGL / past landing → hero still perfect
225
+ </script>
226
+
227
+ <script type="module">
228
+ import init, { qvac_load_gpu, qvac_gpu_free } from "../q/pkg/holospaces_web.js";
229
+ import { loadKappaObject } from "../q/holo-load2bit.mjs";
230
+ import { createQvacGPU } from "../q/qvac-gpu.js?v=68";
231
+ import { createEngine } from "../q/core/engine.js";
232
+
233
+ const $ = (id) => document.getElementById(id);
234
+ const show = (id) => { for (const s of document.querySelectorAll(".stage")) s.classList.toggle("on", s.id === id); };
235
+ const short = (k) => String(k).replace(/^(did:holo:)?sha256:/, "").slice(0, 12) + "…";
236
+
237
+ // model source: ?src=<κ-object dir> for dev, HF mirror by default; ?m=27b flips to the 27B
238
+ // κ-object (engine support for its hybrid layers lands separately — the guard below is honest).
239
+ // Everything shown to the user (name, size) is READ FROM THE MANIFEST — swapping the κ URL is a
240
+ // zero-code model change. The manifest pin is the Law-L5 anchor.
241
+ const QS = new URLSearchParams(location.search);
242
+ const SRC = QS.get("src");
243
+ const M27 = QS.get("m") === "27b";
244
+ const BASE = SRC || (M27 ? "https://huggingface.co/HOLOGRAMTECH/q-bonsai-27b/resolve/main" : "https://huggingface.co/HOLOGRAMTECH/q-bonsai-8b/resolve/main");
245
+ const PIN = M27 ? "did:holo:sha256:00beea03509a79f6567879f019c04bb15dda8721f6320f8295d9ea1dd9ba54af" : "did:holo:sha256:a0dc81f26ec5ce98b28ee9c1fab620e91c20720f777e1de6bc416317f54d27e2";
246
+ const CTX = 640;
247
+
248
+ let engine = null, gpu = null, rootK = "", warm = false, mind = [], thinkOpen = -1, thinkClose = -1;
249
+ let modelName = "Bonsai"; // set from the manifest once loaded
250
+
251
+ async function stream() {
252
+ try { if (window.__holoOff) { window.__holoOff(); window.__holoOff = null; } } catch {} // hand the GPU to the engine
253
+ show("stream");
254
+ const t0 = performance.now();
255
+ const phase = (s) => { $("phase").textContent = s; };
256
+ try {
257
+ if (!navigator.gpu) throw new Error("This browser has no WebGPU. Chrome or Edge 113+ required.");
258
+ // warm-load detect (honest offline copy): the κ-cache already holds the manifest → this visit is disk-speed.
259
+ try { const c = await caches.open("holo-kappa-v1"); warm = !!(await c.match(BASE + "/manifest.json")); } catch {}
260
+ phase(warm ? "welcome back · reading from your disk" : "first visit · streaming");
261
+ await init();
262
+ // PARALLEL κ-BLOCKS FIRST (the measured Netflix path on CDN origins): 399 content-addressed
263
+ // blocks race over 12 connections (HF cdn-lfs caps a single stream ~2 MB/s; the parallel parts
264
+ // path measured 6.8 MB/s on the same line). The ONE-file .holo stays as the fallback for
265
+ // origins that only host the wafer (and its OPFS warm store makes revisits 0-network either way).
266
+ let r, pinned = true, holo = false;
267
+ try {
268
+ r = await loadKappaObject(BASE, { expectKappa: PIN, blake3: false });
269
+ } catch (e1) {
270
+ try {
271
+ const hs = await import("../q/core/holo-stream-load.mjs");
272
+ r = await hs.openHoloKappa(BASE + "/q-bonsai-8b.v1.holo", {});
273
+ holo = true; warm = !!r.warm;
274
+ } catch (e) { if (!SRC) throw e; pinned = false; r = await loadKappaObject(BASE, { allowUnpinned: true, blake3: false }); } // dev fallback only under ?src
275
+ }
276
+ rootK = (r.info && r.info.root) || PIN;
277
+ modelName = String((r.info && r.info.model) || "Bonsai").replace(/-/g, " ");
278
+ $("modelname").textContent = modelName;
279
+ $("kap").textContent = "κ " + rootK + (holo || pinned ? " · verified" : " · unpinned (dev)");
280
+ // HONESTY GATE: the hybrid (27B) engine ships separately — never pretend to run what we can't.
281
+ if (r.manifest.hybrid) throw new Error(modelName + " uses a hybrid engine this build does not include yet. It is arriving; the 8B runs today.");
282
+ // shard grid: one cell per tensor block; a cell lights when its block has arrived, re-derived, and decompressed.
283
+ const names = (r.manifest.tensors || []).map((t) => t.name);
284
+ const grid = $("grid"); grid.style.gridTemplateColumns = `repeat(${Math.ceil(Math.sqrt(names.length * 21 / 19))},1fr)`;
285
+ const cells = names.map(() => { const i = document.createElement("i"); grid.appendChild(i); return i; });
286
+ const idx = new Map(names.map((n, i) => [n, i]));
287
+ let done = 0, bytes = 0, hot = null;
288
+ const tick = () => {
289
+ const dt = (performance.now() - t0) / 1000;
290
+ $("big").innerHTML = `${(bytes / 1e6).toFixed(0)}<small> MB</small>`;
291
+ $("stats").textContent = `${(bytes / 1e6 / Math.max(dt, .1)).toFixed(1)} MB/s · ${dt.toFixed(1)}s · ${done}/${names.length} tensors`;
292
+ };
293
+ const iv = setInterval(tick, 250);
294
+ const fetchT = async (name) => { // wrap fetchTensor: the per-block progress driver
295
+ const b = await r.fetchTensor(name);
296
+ bytes += b.byteLength; done++;
297
+ const c = cells[idx.get(name)];
298
+ if (c) { if (hot) hot.className = "on"; c.className = "hot"; hot = c; }
299
+ return b;
300
+ };
301
+ // tokenizer header (arch + vocab) — embedded in the .holo (0 extra fetches), else same κ-object dir.
302
+ const hdr = r.tokenizerBytes || new Uint8Array(await (await fetch(BASE + "/tokenizer.gguf")).arrayBuffer());
303
+ const lr = JSON.parse(qvac_load_gpu(hdr));
304
+ if (lr.error) throw new Error("tokenizer: " + lr.error);
305
+ try { qvac_gpu_free(); } catch {}
306
+ r.manifest.kv4 = false; // exact f32 KV (the proven first-light config)
307
+ gpu = await createQvacGPU(r.manifest, fetchT, CTX, lr.eos ?? 2, false);
308
+ clearInterval(iv); tick(); if (hot) hot.className = "on";
309
+ phase("waking the mind");
310
+ const m = { fam: "Bonsai", name: modelName, size: "1.16 GB", fmt: "q1 1-bit κ", cap: 200, ctx: CTX, qwen: true, chat: true, rep: 1.05, gpu: true, gpuOnly: true };
311
+ engine = await createEngine(m, { gpu, info: lr, imageKappa: r.info.root });
312
+ // Qwen3 thinking markers are atomic tokens and clean() strips them from text — split by token id instead.
313
+ const o = engine.tokenize("<think>"), c2 = engine.tokenize("</think>");
314
+ thinkOpen = o.length === 1 ? o[0] : -1; thinkClose = c2.length === 1 ? c2[0] : -1;
315
+ enterChat();
316
+ } catch (e) {
317
+ $("phase").textContent = ""; $("err").hidden = false;
318
+ $("err").textContent = String(e && e.message || e);
319
+ console.error(e);
320
+ }
321
+ }
322
+
323
+ // the ONLY chat metrics, one quiet line: model · time to first word · tok/s (operator spec)
324
+ let lastTTFT = null, lastTokps = null;
325
+ function metrics(state) {
326
+ const bits = [`<b>${modelName}</b>`];
327
+ if (lastTTFT != null) bits.push(`${lastTTFT.toFixed(1)}s to first word`);
328
+ if (lastTokps != null) bits.push(`<b>${lastTokps.toFixed(0)}</b> tokens a second`);
329
+ if (!lastTTFT && !lastTokps) bits.push(state || (warm ? "from your disk · works offline" : "on your device"));
330
+ $("metrics").innerHTML = bits.join(" &nbsp;&middot;&nbsp; ");
331
+ }
332
+ function enterChat() {
333
+ show("chat"); metrics(); $("inp").focus();
334
+ }
335
+
336
+ const log = $("log");
337
+ function msg(who, cls) {
338
+ const d = document.createElement("div"); d.className = "msg " + cls;
339
+ d.innerHTML = `<div class="who">${who}</div>`;
340
+ const think = document.createElement("details"); think.className = "think"; think.hidden = true;
341
+ think.innerHTML = `<summary>thinking…</summary><div class="t"></div>`;
342
+ const body = document.createElement("div"); body.className = "body";
343
+ d.appendChild(think); d.appendChild(body); log.appendChild(d);
344
+ log.scrollTop = log.scrollHeight;
345
+ return { body, think, t: think.querySelector(".t") };
346
+ }
347
+ function note(s) { const d = document.createElement("div"); d.className = "note"; d.textContent = s; log.appendChild(d); }
348
+
349
+ // split streamed outIds into thinking + answer segments by the <think> token ids (robust: no
350
+ // tags at position 0 → everything is answer; unclosed → everything so far is thinking).
351
+ function splitThink(outIds) {
352
+ if (thinkOpen < 0 || outIds[0] !== thinkOpen) return { think: [], ans: outIds };
353
+ const c = outIds.indexOf(thinkClose);
354
+ if (c < 0) return { think: outIds.slice(1), ans: [] };
355
+ return { think: outIds.slice(1, c), ans: outIds.slice(c + 1) };
356
+ }
357
+
358
+ let busy = false;
359
+ async function send() {
360
+ const q = $("inp").value.trim();
361
+ if (!q || busy || !engine) return;
362
+ busy = true; $("inp").value = ""; $("send").disabled = true;
363
+ $("col").classList.add("started"); // the greeting yields to the conversation (Claude-room transition)
364
+ msg("You", "user").body.textContent = q;
365
+ const turn = engine.tokenize(engine.frameTurn(q, mind.length > 0));
366
+ if (mind.length + turn.length + 256 > CTX) { mind = []; note("fresh context"); } // keep ≥256 tokens of room (thinking model)
367
+ const ids = mind.concat(mind.length ? turn : engine.tokenize(engine.frameTurn(q, false)));
368
+ const ui = msg(modelName, "bot"); ui.body.textContent = "…";
369
+ const tSend = performance.now(); let ttftSet = false;
370
+ lastTTFT = null; lastTokps = null; metrics("thinking");
371
+ try {
372
+ const res = await engine.generate(ids, {
373
+ maxNew: CTX - ids.length - 8, // the whole remaining KV window (eos stops early)
374
+ onToken: (t) => {
375
+ if (!ttftSet) { ttftSet = true; lastTTFT = (performance.now() - tSend) / 1000; } // TTFT = send → first visible token
376
+ if (t.stats && t.stats.tokps) lastTokps = t.stats.tokps;
377
+ metrics();
378
+ const s = splitThink(t.outIds);
379
+ if (s.think.length) { ui.think.hidden = false; ui.t.textContent = engine.detokenize(s.think); }
380
+ ui.body.textContent = s.ans.length ? engine.detokenize(s.ans) : (s.think.length ? "" : t.text);
381
+ log.scrollTop = log.scrollHeight;
382
+ },
383
+ });
384
+ const s = splitThink(res.outIds || []);
385
+ if (s.think.length) { ui.think.hidden = false; ui.t.textContent = engine.detokenize(s.think); }
386
+ if (s.ans.length) {
387
+ ui.body.textContent = engine.detokenize(s.ans);
388
+ mind = ids.concat(s.ans); // history carries the ANSWER only (Qwen3 convention: prior-turn thinking dropped)
389
+ } else if (s.think.length) {
390
+ ui.body.textContent = "I ran out of room while thinking. Ask again, a bit shorter."; // unclosed <think> at the window edge; turn not kept
391
+ } else {
392
+ ui.body.textContent = res.text;
393
+ mind = ids.concat(res.outIds || []);
394
+ }
395
+ if (res.stats && res.stats.tokps) lastTokps = res.stats.tokps;
396
+ metrics();
397
+ } catch (e) { ui.body.textContent = "Something broke: " + (e && e.message || e); }
398
+ busy = false; $("send").disabled = false; $("inp").focus();
399
+ log.scrollTop = log.scrollHeight;
400
+ }
401
+
402
+ $("go").addEventListener("click", stream);
403
+ $("send").addEventListener("click", send);
404
+ $("inp").addEventListener("keydown", (e) => { if (e.key === "Enter") send(); });
405
+ if (!navigator.gpu) { $("go").disabled = true; $("fine").textContent = "This browser has no WebGPU. Chrome or Edge 113 or newer required."; }
406
+ </script>
407
+ </body>
sha256/76176bccfe41c62993cecbd659a2f03a4d3029664b3946f9a0e91c325f29b589 ADDED
The diff for this file is too large to render. See raw diff
 
sha256/d4a72f8a92575490949caef2abc2fc6c16ab5bf8eccbd4958b149c9a6da75dcd ADDED
@@ -0,0 +1 @@
 
 
1
+ {"@context":["https://www.w3.org/ns/did/v1","https://w3id.org/security/data-integrity/v2",{"dcterms":"http://purl.org/dc/terms/","links":{"@container":"@set","@id":"schema:hasPart"},"prov":"http://www.w3.org/ns/prov#","rel":"schema:additionalType","schema":"https://schema.org/"},{"holstr":"https://hologram.os/ns/strand#"}],"@type":["prov:Entity","holstr:Entry"],"holstr:kind":"release","holstr:op":"did:holo:sha256:87599792c7b13fad9d6c57d3b89d2cef35e4715869f5cde597ab60ca92699f0b","holstr:payload":{"apps":{"bonsai":"36da31e3e35bee518360dccc573f3f97cfaec70a004de7ee6324b0343df0c25c","carry":"9f44164b17e6b7e37f39623bb445d49b6608da5f2b04cef8b1a8b183362a6b9a","hello":"66c1ada5ac08a2d4f73851bbe7458ad5fb6e2226c5a131c3829abfe715900fed","holo-messenger":"5d655b5f914c8b64d5bd80d4f21bf99c49c7ebb5e457f696c1f7ecac19c6bdc3","jellyfin":"3fd2a00105ad0e8f01109dce52ff4c7a0cc6c9444532b0453ed9d770cce2d3a4","resolve":"23aec66382775f5773693615338f37c37a5f58257ec95aece33a664baa6fe0db","yourspace":"9ffc94e11c78fbe6b940bc04ac92f0f12238cf7ce82b5092c53d5761146a50df"},"boot":{"entry":"holo-portal.mjs","sha256":"caeb3e57b6eeab09bee6d67c022145a8e2dae610c929a7f51bc169898625e7e8"},"closure":"b4397f7ae09666bc885ee601a4013ca6f6a158735c2ac784bbaa858be52483c9","manifest":"ab44007528ca8be8e1f993a32fe3204d52ca99178946779ccd477f8b28641d8f","runtime":{"apps/q/pkg/holospaces_web.js":"b9f8a887de588c5193dc65ca9ce206a70c6df53595b848e0ce0299c2d88a5753","apps/q/pkg/holospaces_web_bg.wasm":"9d90b4ea8bccee8c239073c7ec7dd5158c6d11f1f668487570d17475d79e661e","apps/workspace/pkg/holospaces_web.js":"8c30aa5582dffe4548d27fa7863163eba689ed65126be472c003f5884fc8e534","usr/lib/holo/holowhat/holospaces_web.js":"a5b5d9c559a1d2812c33e9d7a4b1c24bb03059482503a23356e4c9c32d4d8b88","usr/lib/holo/holowhat/holospaces_web_bg.wasm":"00cfa4960b319ba1ba7291cddb20dea130a407ce8b42426218854f4f68f4dcd7","usr/lib/pkg/holospaces_web.js":"8c30aa5582dffe4548d27fa7863163eba689ed65126be472c003f5884fc8e534","usr/lib/pkg/holospaces_web_bg.wasm":"3370b22070b56218a57df6406e2e4ba7cc171e942d4d1f2ae4297ea2c4c08d9c"},"shell":"2f4939344e18c7eaceef9fc1b37ddb5409a33cc3e006789e5f40d7e93631a39f","world":"713606554d221f44a38c4d75d94f52cd66916b5b25d8acc27c0e5c6f76d9e581"},"holstr:prev":"did:holo:sha256:ea9db53ff699b0236f244eddcb7848f4dea74c4d13f709f6115052960b1b8920","holstr:seq":381,"prov:generatedAtTime":"2026-07-15T20:04:50.195Z"}
sha256/da8fd904aa4a1cde4ab5c3f64f7fc9a697606b4881007802b671a3d1b3f01d79 ADDED
The diff for this file is too large to render. See raw diff