Taylor commited on
Commit
a902eca
Β·
1 Parent(s): d903d74

feat: deep diagnostics + uncapped tokens (up to 512)

Browse files

Three diagnostic panels:
- Glossolalia Agent Diagnostics: per-token perplexity, vocab coverage,
deficit weights, entropy, top-3 per agent
- Standard Sampling Diagnostics: per-token perplexity, confidence,
vocab coverage, top-3 predictions
- Layer Health: per-layer hidden state norms and residual contribution
through all 32 transformer layers

Token limit raised to 512 (slider) / 8192 (server). Zero cost --
all Aether, no API calls.

Files changed (2) hide show
  1. aether-server.mjs +66 -18
  2. app.py +109 -49
aether-server.mjs CHANGED
@@ -131,13 +131,17 @@ function forwardPass(prompt) {
131
  // Returns a function that generates one token at a time
132
  return {
133
  inputTokens,
134
- step(allToks, kvC) {
135
  const pos = allToks.length - 1;
136
  const tid = allToks[allToks.length - 1];
137
  const x0 = model.tokenEmbd.slice(tid*C.hiddenDim,(tid+1)*C.hiddenDim);
138
  let x = x0;
 
 
 
139
  for (let l=0;l<C.numLayers;l++) {
140
  const ly=model.layers[l];
 
141
  const normed=o.rmsNorm(x,ly.an,C.rmsNormEps);
142
  const q=o.matVec(ly.qw,normed,C.hiddenDim,C.hiddenDim);
143
  const k=o.matVec(ly.kw,normed,kvDim,C.hiddenDim);
@@ -146,16 +150,29 @@ function forwardPass(prompt) {
146
  for(let h=0;h<C.numKvHeads;h++)applyRoPE(k.subarray(h*C.headDim,(h+1)*C.headDim),C.headDim,pos,C.ropeTheta);
147
  kvC[l].k.push(new Float32Array(k));kvC[l].v.push(new Float32Array(v));
148
  const seqLen=kvC[l].k.length;const attnOut=new Float32Array(C.hiddenDim);
 
149
  for(let h=0;h<C.numHeads;h++){const kvH=Math.floor(h/gqaRatio);const qH=q.subarray(h*C.headDim,(h+1)*C.headDim);const scores=new Float32Array(seqLen);
150
  for(let s=0;s<seqLen;s++){const kH=kvC[l].k[s].subarray(kvH*C.headDim,(kvH+1)*C.headDim);let dot=0;for(let d=0;d<C.headDim;d++)dot+=qH[d]*kH[d];scores[s]=dot/Math.sqrt(C.headDim);}
151
- const w=softmaxJS(scores);for(let s=0;s<seqLen;s++){const vH=kvC[l].v[s].subarray(kvH*C.headDim,(kvH+1)*C.headDim);const wt=w[s];for(let d=0;d<C.headDim;d++)attnOut[h*C.headDim+d]+=wt*vH[d];}}
 
 
 
 
152
  const projected=o.matVec(ly.ow,attnOut,C.hiddenDim,C.hiddenDim);const postAttn=o.add(x,projected);
153
  const ffnIn=o.rmsNorm(postAttn,ly.fn,C.rmsNormEps);const gate=o.matVec(ly.gw,ffnIn,C.intermediateSize,C.hiddenDim);
154
  const up=o.matVec(ly.uw,ffnIn,C.intermediateSize,C.hiddenDim);const activated=o.fusedSiluMul(gate,up);
155
  const down=o.matVec(ly.dw,activated,C.hiddenDim,C.intermediateSize);x=o.add(postAttn,down);
 
 
 
 
 
 
 
156
  }
157
  const finalNormed=o.rmsNorm(x,model.outNorm,C.rmsNormEps);
158
- return o.matVec(model.outWeight,finalNormed,C.vocabSize,C.hiddenDim);
 
159
  }
160
  };
161
  }
@@ -230,7 +247,7 @@ function sampleGlossolalia(logits) {
230
 
231
  // ─── Generation Loops ───────────────────────────────────────────────────────
232
 
233
- function generateStandard(prompt, maxTokens = 48) {
234
  const t0 = performance.now();
235
  const fwd = forwardPass(prompt);
236
  const allTokens = [...fwd.inputTokens];
@@ -239,15 +256,35 @@ function generateStandard(prompt, maxTokens = 48) {
239
 
240
  // Prefill
241
  for (let i = 0; i < fwd.inputTokens.length; i++) {
242
- fwd.step(allTokens.slice(0, i+1), kvC);
243
  }
244
 
 
 
245
  // Decode
246
  for (let i = 0; i < maxTokens; i++) {
247
  const ts = performance.now();
248
- const logits = fwd.step(allTokens, kvC);
 
 
 
 
 
249
  const chosen = sampleStandard(logits);
 
 
 
 
 
 
 
 
 
 
 
250
  tokenTimes.push(performance.now() - ts);
 
 
251
  if (chosen === C.eosToken) break;
252
  allTokens.push(chosen);
253
  }
@@ -260,10 +297,11 @@ function generateStandard(prompt, maxTokens = 48) {
260
  text: model.tokenizer.decode(genTokens), tokens: genTokens.length,
261
  totalTimeMs: Math.round(totalTime), avgTokenMs: Math.round(avgMs),
262
  mode: 'standard', temperature: 0.7, topP: 0.9,
 
263
  };
264
  }
265
 
266
- function generateGlossolalia(prompt, maxTokens = 48) {
267
  const t0 = performance.now();
268
  const fwd = forwardPass(prompt);
269
  const allTokens = [...fwd.inputTokens];
@@ -273,25 +311,35 @@ function generateGlossolalia(prompt, maxTokens = 48) {
273
 
274
  // Prefill
275
  for (let i = 0; i < fwd.inputTokens.length; i++) {
276
- fwd.step(allTokens.slice(0, i+1), kvC);
277
  }
278
 
279
  // Decode with Glossolalia
280
  for (let i = 0; i < maxTokens; i++) {
281
  const ts = performance.now();
282
- const logits = fwd.step(allTokens, kvC);
283
  const { tokenId, agents } = sampleGlossolalia(logits);
 
 
 
 
 
 
 
 
284
  tokenTimes.push(performance.now() - ts);
285
 
286
- perTokenDiag.push(agents.map(a => ({
287
- tau: a.tau,
288
- entropy: Math.round(a.entropy * 1000) / 1000,
289
- weight: Math.round(a.weight * 1000) / 1000,
290
- top3: a.top5.slice(0, 3).map(t => ({
291
- token: model.tokenizer.decode([t.i]),
292
- prob: Math.round(t.p * 1000) / 1000,
293
  })),
294
- })));
 
 
 
 
 
295
 
296
  if (tokenId === C.eosToken) break;
297
  allTokens.push(tokenId);
@@ -317,7 +365,7 @@ const server = createServer((req, res) => {
317
  req.on('end', () => {
318
  try {
319
  const { prompt, max_tokens } = JSON.parse(body);
320
- const result = genFn(prompt, max_tokens || 48);
321
  res.writeHead(200, { 'Content-Type': 'application/json' });
322
  res.end(JSON.stringify(result));
323
  } catch (e) {
 
131
  // Returns a function that generates one token at a time
132
  return {
133
  inputTokens,
134
+ step(allToks, kvC, diag) {
135
  const pos = allToks.length - 1;
136
  const tid = allToks[allToks.length - 1];
137
  const x0 = model.tokenEmbd.slice(tid*C.hiddenDim,(tid+1)*C.hiddenDim);
138
  let x = x0;
139
+ const layerNorms = diag ? [] : null;
140
+ const attnEntropies = diag ? [] : null;
141
+
142
  for (let l=0;l<C.numLayers;l++) {
143
  const ly=model.layers[l];
144
+ const xPrev = x;
145
  const normed=o.rmsNorm(x,ly.an,C.rmsNormEps);
146
  const q=o.matVec(ly.qw,normed,C.hiddenDim,C.hiddenDim);
147
  const k=o.matVec(ly.kw,normed,kvDim,C.hiddenDim);
 
150
  for(let h=0;h<C.numKvHeads;h++)applyRoPE(k.subarray(h*C.headDim,(h+1)*C.headDim),C.headDim,pos,C.ropeTheta);
151
  kvC[l].k.push(new Float32Array(k));kvC[l].v.push(new Float32Array(v));
152
  const seqLen=kvC[l].k.length;const attnOut=new Float32Array(C.hiddenDim);
153
+ const headEntropies = diag ? [] : null;
154
  for(let h=0;h<C.numHeads;h++){const kvH=Math.floor(h/gqaRatio);const qH=q.subarray(h*C.headDim,(h+1)*C.headDim);const scores=new Float32Array(seqLen);
155
  for(let s=0;s<seqLen;s++){const kH=kvC[l].k[s].subarray(kvH*C.headDim,(kvH+1)*C.headDim);let dot=0;for(let d=0;d<C.headDim;d++)dot+=qH[d]*kH[d];scores[s]=dot/Math.sqrt(C.headDim);}
156
+ const w=softmaxJS(scores);
157
+ // Attention entropy per head
158
+ if (diag) { let he=0; for(let s=0;s<seqLen;s++) if(w[s]>1e-10) he-=w[s]*Math.log(w[s]); headEntropies.push(Math.round(he*1000)/1000); }
159
+ for(let s=0;s<seqLen;s++){const vH=kvC[l].v[s].subarray(kvH*C.headDim,(kvH+1)*C.headDim);const wt=w[s];for(let d=0;d<C.headDim;d++)attnOut[h*C.headDim+d]+=wt*vH[d];}}
160
+ if (diag) attnEntropies.push(headEntropies);
161
  const projected=o.matVec(ly.ow,attnOut,C.hiddenDim,C.hiddenDim);const postAttn=o.add(x,projected);
162
  const ffnIn=o.rmsNorm(postAttn,ly.fn,C.rmsNormEps);const gate=o.matVec(ly.gw,ffnIn,C.intermediateSize,C.hiddenDim);
163
  const up=o.matVec(ly.uw,ffnIn,C.intermediateSize,C.hiddenDim);const activated=o.fusedSiluMul(gate,up);
164
  const down=o.matVec(ly.dw,activated,C.hiddenDim,C.intermediateSize);x=o.add(postAttn,down);
165
+
166
+ // Layer norms + residual contribution
167
+ if (diag) {
168
+ let norm=0, delta=0, prevNorm=0;
169
+ for(let i=0;i<C.hiddenDim;i++) { norm+=x[i]*x[i]; delta+=(x[i]-xPrev[i])**2; prevNorm+=xPrev[i]*xPrev[i]; }
170
+ layerNorms.push({ norm: Math.round(Math.sqrt(norm)*100)/100, residual: prevNorm>0 ? Math.round(Math.sqrt(delta/prevNorm)*1000)/1000 : 0 });
171
+ }
172
  }
173
  const finalNormed=o.rmsNorm(x,model.outNorm,C.rmsNormEps);
174
+ const logits = o.matVec(model.outWeight,finalNormed,C.vocabSize,C.hiddenDim);
175
+ return { logits, layerNorms, attnEntropies };
176
  }
177
  };
178
  }
 
247
 
248
  // ─── Generation Loops ───────────────────────────────────────────────────────
249
 
250
+ function generateStandard(prompt, maxTokens = 8192) {
251
  const t0 = performance.now();
252
  const fwd = forwardPass(prompt);
253
  const allTokens = [...fwd.inputTokens];
 
256
 
257
  // Prefill
258
  for (let i = 0; i < fwd.inputTokens.length; i++) {
259
+ fwd.step(allTokens.slice(0, i+1), kvC, false);
260
  }
261
 
262
+ const perTokenInfo = [];
263
+
264
  // Decode
265
  for (let i = 0; i < maxTokens; i++) {
266
  const ts = performance.now();
267
+ const { logits, layerNorms, attnEntropies } = fwd.step(allTokens, kvC, true);
268
+ const o2 = op();
269
+ const scaled = new Float32Array(logits.length);
270
+ for (let j = 0; j < logits.length; j++) scaled[j] = logits[j] / 0.7;
271
+ const probs = o2.softmax(scaled);
272
+
273
  const chosen = sampleStandard(logits);
274
+ const chosenProb = probs[chosen];
275
+ const perplexity = chosenProb > 0 ? -Math.log2(chosenProb) : 99;
276
+
277
+ // Vocab coverage: tokens with >0.1% probability
278
+ let vocabCoverage = 0;
279
+ for (let j = 0; j < probs.length; j++) if (probs[j] > 0.001) vocabCoverage++;
280
+
281
+ // Top-5
282
+ const top5 = Array.from(probs).map((p,j)=>({p,i:j})).sort((a,b)=>b.p-a.p).slice(0,5)
283
+ .map(t => ({ token: model.tokenizer.decode([t.i]), prob: Math.round(t.p*1000)/1000 }));
284
+
285
  tokenTimes.push(performance.now() - ts);
286
+ perTokenInfo.push({ perplexity: Math.round(perplexity*100)/100, chosenProb: Math.round(chosenProb*1000)/1000, vocabCoverage, top5, layerNorms, attnEntropies });
287
+
288
  if (chosen === C.eosToken) break;
289
  allTokens.push(chosen);
290
  }
 
297
  text: model.tokenizer.decode(genTokens), tokens: genTokens.length,
298
  totalTimeMs: Math.round(totalTime), avgTokenMs: Math.round(avgMs),
299
  mode: 'standard', temperature: 0.7, topP: 0.9,
300
+ tokenDiagnostics: perTokenInfo,
301
  };
302
  }
303
 
304
+ function generateGlossolalia(prompt, maxTokens = 8192) {
305
  const t0 = performance.now();
306
  const fwd = forwardPass(prompt);
307
  const allTokens = [...fwd.inputTokens];
 
311
 
312
  // Prefill
313
  for (let i = 0; i < fwd.inputTokens.length; i++) {
314
+ fwd.step(allTokens.slice(0, i+1), kvC, false);
315
  }
316
 
317
  // Decode with Glossolalia
318
  for (let i = 0; i < maxTokens; i++) {
319
  const ts = performance.now();
320
+ const { logits, layerNorms, attnEntropies } = fwd.step(allTokens, kvC, true);
321
  const { tokenId, agents } = sampleGlossolalia(logits);
322
+
323
+ // Token-level perplexity from merged distribution
324
+ const { merged } = glossolaliaMerge(logits);
325
+ const chosenProb = merged[tokenId] || 0;
326
+ const perplexity = chosenProb > 0 ? -Math.log2(chosenProb) : 99;
327
+ let vocabCoverage = 0;
328
+ for (let j = 0; j < merged.length; j++) if (merged[j] > 0.001) vocabCoverage++;
329
+
330
  tokenTimes.push(performance.now() - ts);
331
 
332
+ perTokenDiag.push({
333
+ agents: agents.map(a => ({
334
+ tau: a.tau, entropy: Math.round(a.entropy*1000)/1000, weight: Math.round(a.weight*1000)/1000,
335
+ top3: a.top5.slice(0,3).map(t => ({ token: model.tokenizer.decode([t.i]), prob: Math.round(t.p*1000)/1000 })),
 
 
 
336
  })),
337
+ perplexity: Math.round(perplexity*100)/100,
338
+ chosenProb: Math.round(chosenProb*1000)/1000,
339
+ vocabCoverage,
340
+ layerNorms,
341
+ attnEntropies,
342
+ });
343
 
344
  if (tokenId === C.eosToken) break;
345
  allTokens.push(tokenId);
 
365
  req.on('end', () => {
366
  try {
367
  const { prompt, max_tokens } = JSON.parse(body);
368
+ const result = genFn(prompt, max_tokens || 256);
369
  res.writeHead(200, { 'Content-Type': 'application/json' });
370
  res.end(JSON.stringify(result));
371
  } catch (e) {
app.py CHANGED
@@ -2,9 +2,9 @@
2
  Glossolalia -- Semiotic Ensemble Inference
3
  Act 2: Fork/Race/Fold at the decoder level.
4
 
5
- Standard sampling vs Glossolalia (temperature-ensemble MOA with
6
- deficit-weighted complement merge). Same model, same forward pass,
7
- different decoder. All inference via Aether WASM-SIMD engine.
8
  """
9
 
10
  import gradio as gr
@@ -44,14 +44,14 @@ else:
44
  print("[Glossolalia] WARNING: Aether not ready after 180s", flush=True)
45
 
46
 
47
- def call_aether(endpoint, prompt, max_tokens=48):
48
  try:
49
  data = json.dumps({"prompt": prompt, "max_tokens": max_tokens}).encode()
50
  req = urllib.request.Request(
51
  f"http://127.0.0.1:7861/{endpoint}", data=data,
52
  headers={"Content-Type": "application/json"},
53
  )
54
- resp = urllib.request.urlopen(req, timeout=300)
55
  return json.loads(resp.read())
56
  except urllib.error.HTTPError as e:
57
  body = e.read().decode() if e.fp else str(e)
@@ -62,24 +62,73 @@ def call_aether(endpoint, prompt, max_tokens=48):
62
  return {"error": str(e), "text": f"[Error: {e}]", "tokens": 0, "totalTimeMs": 0, "avgTokenMs": 0}
63
 
64
 
65
- def format_diagnostics(diag_list):
 
 
66
  if not diag_list:
67
- return "No diagnostics available."
68
- lines = ["PER-TOKEN AGENT DIAGNOSTICS", "=" * 60, "",
69
- "Three agents at tau={0.4, 0.7, 1.0}. Weight = 1 - H/log(V):",
70
- "low entropy => high confidence => high weight in fold.", ""]
71
- for step, agents in enumerate(diag_list[:20]): # limit to 20 tokens
72
- lines.append(f"--- Token {step + 1} ---")
73
- for a in agents:
 
 
 
 
 
 
74
  top_str = ", ".join(f"'{t['token']}' ({t['prob']:.3f})" for t in a.get("top3", []))
75
- lines.append(f" tau={a['tau']:.1f} | H={a['entropy']:.3f} | w={a['weight']:.3f} | {top_str}")
76
  lines.append("")
77
  return "\n".join(lines)
78
 
79
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
80
  def compare(prompt, max_tokens):
 
81
  if not prompt or not prompt.strip():
82
- yield "", "", "", "", ""
83
  return
84
 
85
  max_tokens = int(max_tokens)
@@ -91,33 +140,34 @@ def compare(prompt, max_tokens):
91
  def run_glo():
92
  glo_result[0] = call_aether("generate-glossolalia", prompt, max_tokens)
93
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
94
  with ThreadPoolExecutor(max_workers=2) as pool:
95
  futures = {pool.submit(run_std): "std", pool.submit(run_glo): "glo"}
96
  for future in as_completed(futures):
97
- name = futures[future]
98
  future.result()
99
- if name == "std" and std_result[0]:
100
- r = std_result[0]
101
- st = f"{r['tokens']} tokens in {r['totalTimeMs']/1000:.1f}s ({r['avgTokenMs']}ms/tok)"
102
- gt = glo_result[0]["text"] if glo_result[0] else "generating..."
103
- gs = f"{glo_result[0]['tokens']} tokens in {glo_result[0]['totalTimeMs']/1000:.1f}s ({glo_result[0]['avgTokenMs']}ms/tok)" if glo_result[0] else "running..."
104
- diag = format_diagnostics(glo_result[0].get("diagnostics", [])) if glo_result[0] else ""
105
- yield r["text"], gt, st, gs, diag
106
- elif name == "glo" and glo_result[0]:
107
- r = glo_result[0]
108
- gs = f"{r['tokens']} tokens in {r['totalTimeMs']/1000:.1f}s ({r['avgTokenMs']}ms/tok)"
109
- bt = std_result[0]["text"] if std_result[0] else "generating..."
110
- bs = f"{std_result[0]['tokens']} tokens in {std_result[0]['totalTimeMs']/1000:.1f}s ({std_result[0]['avgTokenMs']}ms/tok)" if std_result[0] else "running..."
111
- yield bt, r["text"], bs, gs, format_diagnostics(r.get("diagnostics", []))
112
-
113
- if std_result[0] and glo_result[0]:
114
- sr, gr_ = std_result[0], glo_result[0]
115
- yield (sr["text"], gr_["text"],
116
- f"{sr['tokens']} tokens in {sr['totalTimeMs']/1000:.1f}s ({sr['avgTokenMs']}ms/tok)",
117
- f"{gr_['tokens']} tokens in {gr_['totalTimeMs']/1000:.1f}s ({gr_['avgTokenMs']}ms/tok)",
118
- format_diagnostics(gr_.get("diagnostics", [])))
119
 
120
 
 
 
121
  CSS = """
122
  .gradio-container { max-width: 1060px !important; margin: 0 auto !important; }
123
  .gradio-container, .dark { background: #09090b !important; }
@@ -144,20 +194,22 @@ footer.svelte-1ax1toq { display: none !important; }
144
  .built-with { display: none !important; }
145
  """
146
 
 
 
147
  with gr.Blocks(css=CSS, theme=gr.themes.Base(primary_hue="purple", neutral_hue="zinc"), title="Glossolalia") as demo:
148
 
149
  gr.HTML("""
150
  <div id="hero">
151
  <h1><span class="accent">Glossolalia</span></h1>
152
- <p class="subtitle">Semiotic ensemble inference. Same model, same forward pass, different decoder.<br/>
153
- Left: standard top-p sampling. Right: fork/race/fold with deficit-weighted complement merge.<br/>
154
- All inference via Aether -- pure JS + 14KB WASM SIMD. Zero ML dependencies.</p>
155
  </div>
156
  """)
157
 
158
  with gr.Row():
159
  prompt = gr.Textbox(elem_id="prompt-input", placeholder="What is the shape of failure?", lines=2, label="Prompt", show_label=False, interactive=True, scale=4)
160
- max_tok = gr.Slider(minimum=8, maximum=64, value=48, step=1, label="Max tokens", scale=1)
161
 
162
  btn = gr.Button("Generate", elem_id="gen-btn", variant="primary")
163
 
@@ -173,28 +225,36 @@ with gr.Blocks(css=CSS, theme=gr.themes.Base(primary_hue="purple", neutral_hue="
173
  glo_out = gr.Textbox(lines=10, show_label=False, interactive=False, elem_classes=["response-card"])
174
  glo_stats = gr.HTML('<p class="stats-text">--</p>')
175
 
176
- with gr.Accordion("Agent Diagnostics (per-token)", open=False):
177
- diag_out = gr.Textbox(lines=15, show_label=False, interactive=False, )
 
 
 
 
 
 
 
 
178
 
179
  def run(prompt_text, max_tokens):
180
- for st, gt, ss, gs, diag in compare(prompt_text, max_tokens):
181
- yield st, gt, f'<p class="stats-text">{ss}</p>', f'<p class="stats-text">{gs}</p>', diag
 
182
 
183
- btn.click(run, [prompt, max_tok], [std_out, glo_out, std_stats, glo_stats, diag_out])
184
- prompt.submit(run, [prompt, max_tok], [std_out, glo_out, std_stats, glo_stats, diag_out])
185
 
186
  gr.HTML('<p style="color:#52525b; font-size:0.8rem; margin-top:1.5rem; margin-bottom:0.5rem;">Try these:</p>')
187
  with gr.Row():
188
  for p in ["What is the shape of failure?", "The theory of everything begins with", "If silence had a color", "Write a haiku about parallel universes"]:
189
  gr.Button(p, size="sm", elem_classes=["prompt-chip"]).click(
190
  fn=lambda x=p: x, outputs=[prompt]
191
- ).then(fn=run, inputs=[prompt, max_tok], outputs=[std_out, glo_out, std_stats, glo_stats, diag_out])
192
 
193
  gr.HTML("""
194
  <div id="footer">
195
  <p style="color:#a1a1aa; font-size:0.85rem; margin-bottom:0.5rem;">
196
- SmolLM2-360M-Instruct &middot; Q8_0 GGUF &middot; Aether WASM-SIMD &middot;
197
- THM-SEMIOTIC-ERASURE (Lean 4)
198
  </p>
199
  <p>
200
  <a href="https://forkracefold.com/">Whitepaper</a> &middot;
 
2
  Glossolalia -- Semiotic Ensemble Inference
3
  Act 2: Fork/Race/Fold at the decoder level.
4
 
5
+ Standard sampling vs Glossolalia. Same forward pass, different decoder.
6
+ All inference via Aether WASM-SIMD engine. Deep diagnostics: per-token
7
+ perplexity, per-layer norms, attention entropy, vocabulary coverage.
8
  """
9
 
10
  import gradio as gr
 
44
  print("[Glossolalia] WARNING: Aether not ready after 180s", flush=True)
45
 
46
 
47
+ def call_aether(endpoint, prompt, max_tokens=256):
48
  try:
49
  data = json.dumps({"prompt": prompt, "max_tokens": max_tokens}).encode()
50
  req = urllib.request.Request(
51
  f"http://127.0.0.1:7861/{endpoint}", data=data,
52
  headers={"Content-Type": "application/json"},
53
  )
54
+ resp = urllib.request.urlopen(req, timeout=600)
55
  return json.loads(resp.read())
56
  except urllib.error.HTTPError as e:
57
  body = e.read().decode() if e.fp else str(e)
 
62
  return {"error": str(e), "text": f"[Error: {e}]", "tokens": 0, "totalTimeMs": 0, "avgTokenMs": 0}
63
 
64
 
65
+ # ─── Diagnostic Formatters ───────────────────────────────────────────────────
66
+
67
+ def format_glossolalia_diag(diag_list):
68
  if not diag_list:
69
+ return "No diagnostics."
70
+ lines = ["GLOSSOLALIA DEEP DIAGNOSTICS", "=" * 60, "",
71
+ "tau={0.4, 0.7, 1.0} | w = 1-H/log(V) | ppl = -log2(P)", ""]
72
+ for step, d in enumerate(diag_list):
73
+ if not isinstance(d, dict):
74
+ continue
75
+ ppl = d.get("perplexity", "?")
76
+ prob = d.get("chosenProb", "?")
77
+ vc = d.get("vocabCoverage", "?")
78
+ lines.append(f"--- Token {step+1} | ppl={ppl} | P={prob} | vocabCov={vc} ---")
79
+ for a in d.get("agents", []):
80
+ if not isinstance(a, dict):
81
+ continue
82
  top_str = ", ".join(f"'{t['token']}' ({t['prob']:.3f})" for t in a.get("top3", []))
83
+ lines.append(f" tau={a.get('tau','?'):.1f} | H={a.get('entropy',0):.3f} | w={a.get('weight',0):.3f} | {top_str}")
84
  lines.append("")
85
  return "\n".join(lines)
86
 
87
 
88
+ def format_standard_diag(token_diag):
89
+ if not token_diag:
90
+ return "No diagnostics."
91
+ lines = ["STANDARD SAMPLING DIAGNOSTICS", "=" * 60,
92
+ "ppl = -log2(P(chosen)) | vocabCov = tokens with P>0.1%", ""]
93
+ for step, d in enumerate(token_diag):
94
+ if not isinstance(d, dict):
95
+ continue
96
+ ppl = d.get("perplexity", "?")
97
+ prob = d.get("chosenProb", "?")
98
+ vc = d.get("vocabCoverage", "?")
99
+ top5 = d.get("top5", [])
100
+ top_str = ", ".join(f"'{t['token']}' ({t['prob']:.3f})" for t in top5[:3])
101
+ lines.append(f"Token {step+1} | ppl={ppl} | P={prob} | vc={vc} | {top_str}")
102
+ return "\n".join(lines)
103
+
104
+
105
+ def format_layer_health(diag_list):
106
+ if not diag_list:
107
+ return "No layer data."
108
+ last = diag_list[-1] if diag_list else {}
109
+ if not isinstance(last, dict):
110
+ return "No layer data."
111
+ norms = last.get("layerNorms", [])
112
+ if not norms:
113
+ return "No layer norms."
114
+ lines = ["LAYER HEALTH (last generated token)", "=" * 60,
115
+ "Layer | Hidden Norm | Residual Contribution", "-" * 50]
116
+ for i, n in enumerate(norms):
117
+ if not isinstance(n, dict):
118
+ continue
119
+ norm_val = n.get("norm", 0)
120
+ res_val = n.get("residual", 0)
121
+ bar = "#" * min(int(res_val * 40), 40)
122
+ lines.append(f" {i:2d} | {norm_val:9.2f} | {res_val:.4f} {bar}")
123
+ return "\n".join(lines)
124
+
125
+
126
+ # ─── Compare Function ────────────────────────────────────────────────────────
127
+
128
  def compare(prompt, max_tokens):
129
+ empty = ("", "", "", "", "", "", "")
130
  if not prompt or not prompt.strip():
131
+ yield empty
132
  return
133
 
134
  max_tokens = int(max_tokens)
 
140
  def run_glo():
141
  glo_result[0] = call_aether("generate-glossolalia", prompt, max_tokens)
142
 
143
+ def fmt_stats(r):
144
+ if not r:
145
+ return "running..."
146
+ return f"{r['tokens']} tokens in {r['totalTimeMs']/1000:.1f}s ({r['avgTokenMs']}ms/tok)"
147
+
148
+ def build():
149
+ sr, gr_ = std_result[0], glo_result[0]
150
+ return (
151
+ sr["text"] if sr else "generating...",
152
+ gr_["text"] if gr_ else "generating...",
153
+ fmt_stats(sr),
154
+ fmt_stats(gr_),
155
+ format_glossolalia_diag(gr_.get("diagnostics", [])) if gr_ else "",
156
+ format_standard_diag(sr.get("tokenDiagnostics", [])) if sr else "",
157
+ format_layer_health(gr_.get("diagnostics", [])) if gr_ else "",
158
+ )
159
+
160
  with ThreadPoolExecutor(max_workers=2) as pool:
161
  futures = {pool.submit(run_std): "std", pool.submit(run_glo): "glo"}
162
  for future in as_completed(futures):
 
163
  future.result()
164
+ yield build()
165
+
166
+ yield build()
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
167
 
168
 
169
+ # ─── CSS ─────────────────────────────────────────────────────────────────────
170
+
171
  CSS = """
172
  .gradio-container { max-width: 1060px !important; margin: 0 auto !important; }
173
  .gradio-container, .dark { background: #09090b !important; }
 
194
  .built-with { display: none !important; }
195
  """
196
 
197
+ # ─── Gradio UI ───────────────────────────────────────────────────────────────
198
+
199
  with gr.Blocks(css=CSS, theme=gr.themes.Base(primary_hue="purple", neutral_hue="zinc"), title="Glossolalia") as demo:
200
 
201
  gr.HTML("""
202
  <div id="hero">
203
  <h1><span class="accent">Glossolalia</span></h1>
204
+ <p class="subtitle">Semiotic ensemble inference. Same forward pass, different decoder.<br/>
205
+ Left: standard top-p. Right: fork/race/fold with deficit-weighted complement merge.<br/>
206
+ All inference via Aether. Zero ML dependencies. Full diagnostic visibility.</p>
207
  </div>
208
  """)
209
 
210
  with gr.Row():
211
  prompt = gr.Textbox(elem_id="prompt-input", placeholder="What is the shape of failure?", lines=2, label="Prompt", show_label=False, interactive=True, scale=4)
212
+ max_tok = gr.Slider(minimum=8, maximum=512, value=64, step=1, label="Max tokens", scale=1)
213
 
214
  btn = gr.Button("Generate", elem_id="gen-btn", variant="primary")
215
 
 
225
  glo_out = gr.Textbox(lines=10, show_label=False, interactive=False, elem_classes=["response-card"])
226
  glo_stats = gr.HTML('<p class="stats-text">--</p>')
227
 
228
+ with gr.Accordion("Glossolalia Agent Diagnostics", open=False):
229
+ glo_diag = gr.Textbox(lines=18, show_label=False, interactive=False)
230
+
231
+ with gr.Accordion("Standard Sampling Diagnostics", open=False):
232
+ std_diag = gr.Textbox(lines=12, show_label=False, interactive=False)
233
+
234
+ with gr.Accordion("Layer Health (32 transformer layers)", open=False):
235
+ layer_health = gr.Textbox(lines=18, show_label=False, interactive=False)
236
+
237
+ outputs = [std_out, glo_out, std_stats, glo_stats, glo_diag, std_diag, layer_health]
238
 
239
  def run(prompt_text, max_tokens):
240
+ for vals in compare(prompt_text, max_tokens):
241
+ st, gt, ss, gs, gd, sd, lh = vals
242
+ yield st, gt, f'<p class="stats-text">{ss}</p>', f'<p class="stats-text">{gs}</p>', gd, sd, lh
243
 
244
+ btn.click(run, [prompt, max_tok], outputs)
245
+ prompt.submit(run, [prompt, max_tok], outputs)
246
 
247
  gr.HTML('<p style="color:#52525b; font-size:0.8rem; margin-top:1.5rem; margin-bottom:0.5rem;">Try these:</p>')
248
  with gr.Row():
249
  for p in ["What is the shape of failure?", "The theory of everything begins with", "If silence had a color", "Write a haiku about parallel universes"]:
250
  gr.Button(p, size="sm", elem_classes=["prompt-chip"]).click(
251
  fn=lambda x=p: x, outputs=[prompt]
252
+ ).then(fn=run, inputs=[prompt, max_tok], outputs=outputs)
253
 
254
  gr.HTML("""
255
  <div id="footer">
256
  <p style="color:#a1a1aa; font-size:0.85rem; margin-bottom:0.5rem;">
257
+ SmolLM2-360M-Instruct &middot; Q8_0 GGUF &middot; Aether WASM-SIMD &middot; THM-SEMIOTIC-ERASURE (Lean 4)
 
258
  </p>
259
  <p>
260
  <a href="https://forkracefold.com/">Whitepaper</a> &middot;