/* Smaug-Flash Explorer — static Space logic. * No backend: benchmarks are the model card's numbers, the encoder runs the * model repo's own encoding_dsv4.py inside Pyodide, and the chat client speaks * OpenAI-compatible SSE straight to an endpoint you choose. */ 'use strict'; const MODEL_ID = 'abacusai/Smaug-Flash'; const BASE_ID = 'deepseek-ai/DeepSeek-V4-Flash-0731'; const MODEL_URL = 'https://huggingface.co/' + MODEL_ID; const PYODIDE_VERSION = 'v314.0.7'; // pyodide release tag on jsdelivr // ---- model facts (config.json + Hub safetensors metadata) ------------------- const N_LAYERS = 43, N_ROUTED = 256, N_SHARED = 1, MOE_INTER = 2048, HIDDEN = 4096; const MAX_POSITIONS = 1048576; const TOTAL_PARAMS = 304180418494; // 304.18 B const EXPERT_PARAMS = N_LAYERS * (N_ROUTED + N_SHARED) * 3 * HIDDEN * MOE_INTER; const OTHER_PARAMS = TOTAL_PARAMS - EXPERT_PARAMS; const CHECKPOINT_GB = 166.89; // ---- benchmark data (digitized from the model card's figures) -------------- const BENCHMARKS = [ { name: 'LiveBench overall-7', smaug: 77.4, base: 74.2, starred: false }, { name: 'LiveBench agentic coding', smaug: 61.1, base: 46.8, starred: false }, { name: 'Terminal Bench 2.1 (DeepSeek harness)', smaug: 76.4, base: 66.3, starred: false }, { name: 'Terminal Bench 2.1 (terminus-2)', smaug: 70.8, base: 68.2, starred: false }, { name: 'AutomationBench Public', smaug: 38.8, base: 25.1, starred: true }, { name: 'NL2Repo-Bench', smaug: 73.3, base: 54.2, starred: true }, { name: 'DeepSWE v1.1', smaug: 56.6, base: 54.4, starred: true }, { name: 'AA-LCR (long-context, 100 q)', smaug: 74.0, base: 75.5, starred: false } ]; const LIVEBENCH = [ { name: 'Agentic Coding', smaug: 61.1, base: 46.8 }, { name: 'Instruction Following', smaug: 69.3, base: 65.5 }, { name: 'Mathematics', smaug: 90.1, base: 86.8 }, { name: 'Coding', smaug: 77.1, base: 75.0 }, { name: 'Language', smaug: 79.2, base: 79.2 }, { name: 'Data Analysis', smaug: 79.1, base: 79.3 }, { name: 'Reasoning', smaug: 86.2, base: 86.6 }, { name: 'Overall', smaug: 77.4, base: 74.2 } ]; const HARDWARE = [ { name: 'cpu-basic', note: '2 vCPU / 16 GB — no GPU', gpu: 0, usd: 0 }, { name: 'zero-a10g (ZeroGPU)', note: '96 GB full MIG, dynamic — this Space', gpu: 96, usd: 0 }, { name: 't4-small', note: '1× T4 16 GB', gpu: 16, usd: 0.40 }, { name: 'a10g-largex2', note: '2× A10G', gpu: 48, usd: 3.00 }, { name: 'a10g-largex4', note: '4× A10G', gpu: 96, usd: 5.00 }, { name: 'a100-large', note: '1× A100 80 GB', gpu: 80, usd: 2.50 }, { name: 'a100x4', note: '4× A100 80 GB', gpu: 320, usd: 10.00 }, { name: 'a100x8', note: '8× A100 80 GB', gpu: 640, usd: 20.00 }, { name: 'rtx-pro-6000x2', note: '2× RTX PRO 6000 96 GB', gpu: 192, usd: 5.50 }, { name: 'rtx-pro-6000x4', note: '4× RTX PRO 6000 96 GB', gpu: 384, usd: 11.00 }, { name: 'rtx-pro-6000x8', note: '8× RTX PRO 6000 96 GB', gpu: 768, usd: 22.00 }, { name: 'l40sx8', note: '8× L40S 48 GB', gpu: 384, usd: 23.50 } ]; const RECIPES = { 'sglang-cmd': `sglang serve \\ --trust-remote-code \\ --model-path abacusai/Smaug-Flash \\ --tp 4 \\ --enable-dp-attention \\ --moe-runner-backend flashinfer_mxfp4 \\ --speculative-algorithm DSPARK \\ --mem-fraction-static 0.90 \\ --chunked-prefill-size 4096 \\ --swa-full-tokens-ratio 0.1`, 'vllm-cmd': `vllm serve abacusai/Smaug-Flash \\ --trust-remote-code --kv-cache-dtype fp8 --block-size 256 \\ --data-parallel-size 4 --enable-expert-parallel \\ --moe-backend deep_gemm_mega_moe \\ --attention-config '{"use_fp4_indexer_cache": true}' \\ --speculative-config '{"method":"dspark","num_speculative_tokens":7,"draft_sample_method":"greedy"}'`, 'torch-cmd': `export EXPERTS=256 export MP=4 export CONFIG=config.json python convert.py --hf-ckpt-path \${HF_CKPT_PATH} --save-path \${SAVE_PATH} \\ --n-experts \${EXPERTS} --model-parallel \${MP} torchrun --nproc-per-node \${MP} generate.py --ckpt-path \${SAVE_PATH} --config \${CONFIG} --interactive`, 'py-cmd': `from encoding_dsv4 import encode_messages, parse_message_from_completion_text from openai import OpenAI messages = [{"role": "user", "content": "Write a Python one-liner that reverses a string."}] prompt = encode_messages(messages, thinking_mode="thinking", reasoning_effort="max") client = OpenAI(base_url="http://localhost:8000/v1", api_key="EMPTY") out = client.completions.create(model="abacusai/Smaug-Flash", prompt=prompt, max_tokens=8192) print(parse_message_from_completion_text(out.choices[0].text, thinking_mode="thinking"))` }; const EXAMPLES = { chat: [ { role: 'system', content: 'You are a helpful assistant.' }, { role: 'user', content: 'What is 2+2? Think it through.' } ], agentic: [ { role: 'system', content: 'You are an autonomous coding agent. Use the tools you are given.' }, { role: 'user', content: 'Add a --verbose flag to cmd/cli.py and run the tests.' }, { role: 'assistant', content: "I'll read the file first.", reasoning_content: 'Need the current CLI definition before editing.', tool_calls: [{ id: 'call_1', type: 'function', function: { name: 'read_file', arguments: { path: 'cmd/cli.py' } } }] }, { role: 'tool', tool_call_id: 'call_1', content: 'def main():\n pass\n' }, { role: 'user', content: 'Also keep the exit code at 0 on success.' } ], custom: [ { role: 'system', content: 'You are a senior Python reviewer. Be terse.' }, { role: 'latest_reminder', content: 'Date: 2026-10-31, locale: en-ZA, timezone: UTC+02:00' }, { role: 'user', content: 'Review this diff:\n- return x\n+ return x or 0' } ] }; const EXAMPLE_TOOLS = [ { type: 'function', function: { name: 'read_file', description: 'Read a UTF-8 text file from the repo.', parameters: { type: 'object', properties: { path: { type: 'string', description: 'repo-relative path' } }, required: ['path'] } } } ]; // ============================================================ small helpers const $ = (id) => document.getElementById(id); function escapeHtml(s) { return String(s).replace(/[&<>"']/g, (c) => ({ '&': '&', '<': '<', '>': '>', '"': '"', "'": ''' }[c])); } function gb(bytes) { return (bytes / 1e9).toFixed(1) + ' GB'; } // ============================================================ tab switching document.querySelectorAll('.tab').forEach((btn) => { btn.addEventListener('click', () => showTab(btn.dataset.tab)); }); function showTab(name) { document.querySelectorAll('.tab').forEach((b) => b.classList.toggle('active', b.dataset.tab === name)); document.querySelectorAll('.panel').forEach((p) => p.classList.toggle('active', p.id === 'tab-' + name)); if (showTab._mounted === undefined) showTab._mounted = {}; if (!showTab._mounted[name]) { showTab._mounted[name] = true; if (name === 'benchmarks') { drawBenchCharts(); } if (name === 'deploy') { drawSizeChart(); } if (name === 'encoder') { mountEncoder(); } } } document.querySelectorAll('[data-goto]').forEach((a) => { a.addEventListener('click', (e) => { e.preventDefault(); showTab(a.dataset.goto); }); }); // ============================================================ live Hub stats (async function hubStats() { const el = $('hub-live'); try { const info = await (await fetch('https://huggingface.co/api/models/' + MODEL_ID)).json(); el.textContent = 'Live Hub stats: ' + (info.downloads ?? 0).toLocaleString() + ' downloads · ' + (info.likes ?? 0).toLocaleString() + ' likes · last modified ' + String(info.lastModified || '').slice(0, 10) + ' · sha ' + String(info.sha || '').slice(0, 8) + ' · license ' + ((info.cardData && info.cardData.license) || 'mit'); } catch (err) { el.textContent = 'Live Hub stats unavailable offline — the numbers in this page were captured from the model card.'; } })(); // ============================================================ charts const PLOTLY_LAYOUT = { paper_bgcolor: 'rgba(0,0,0,0)', plot_bgcolor: 'rgba(0,0,0,0)', font: { color: '#e8ecf8' }, margin: { l: 10, r: 10, t: 50, b: 40 } }; function drawBenchCharts() { const labels = BENCHMARKS.map((b) => b.name + ' (' + (b.smaug - b.base >= 0 ? '+' : '') + (b.smaug - b.base).toFixed(1) + ')'); Plotly.newPlot('chart-bars', [ { type: 'bar', orientation: 'h', name: 'Smaug-Flash', y: labels, x: BENCHMARKS.map((b) => b.smaug), marker: { color: '#6d7cff' }, text: BENCHMARKS.map((b) => b.smaug.toFixed(1)), textposition: 'outside', hovertemplate: '%{y}
Smaug-Flash: %{x:.1f}' }, { type: 'bar', orientation: 'h', name: BASE_ID + ' (base)', y: labels, x: BENCHMARKS.map((b) => b.base), marker: { color: '#f59e0b' }, text: BENCHMARKS.map((b) => b.base.toFixed(1) + (b.starred ? '*' : '')), textposition: 'outside', hovertemplate: '%{y}
base: %{x:.1f}' } ], Object.assign({}, PLOTLY_LAYOUT, { title: 'Smaug-Flash vs DeepSeek-V4-Flash-0731 (Δ in the axis label)', barmode: 'group', height: 520, legend: { orientation: 'h' }, xaxis: { title: 'score (higher is better)' } }), { responsive: true, displayModeBar: false }); Plotly.newPlot('chart-delta', [ { type: 'bar', orientation: 'h', y: BENCHMARKS.map((b) => b.name), x: BENCHMARKS.map((b) => b.smaug - b.base), marker: { color: BENCHMARKS.map((b) => (b.smaug - b.base >= 0 ? '#34d399' : '#f87171')) }, text: BENCHMARKS.map((b) => (b.smaug - b.base >= 0 ? '+' : '') + (b.smaug - b.base).toFixed(1)), textposition: 'outside', hovertemplate: '%{y}: %{x:+.1f}' } ], Object.assign({}, PLOTLY_LAYOUT, { title: 'Δ vs base — 7 of 8 up, AA-LCR down 1.5', height: 520, xaxis: { title: 'points' }, showlegend: false }), { responsive: true, displayModeBar: false }); const cats = LIVEBENCH.filter((c) => c.name !== 'Overall'); const theta = cats.map((c) => c.name).concat([cats[0].name]); Plotly.newPlot('chart-radar', [ { type: 'scatterpolar', r: cats.map((c) => c.smaug).concat([cats[0].smaug]), theta: theta, fill: 'toself', name: 'Smaug-Flash', line: { color: '#6d7cff' } }, { type: 'scatterpolar', r: cats.map((c) => c.base).concat([cats[0].base]), theta: theta, fill: 'toself', name: 'DSV4-Flash-0731 (base)', line: { color: '#f59e0b' }, opacity: 0.65 } ], Object.assign({}, PLOTLY_LAYOUT, { title: 'LiveBench 2026-06-25 categories (0–100)', height: 520, legend: { orientation: 'h' }, polar: { radialaxis: { visible: true, range: [40, 100], ticks: '' } } }), { responsive: true, displayModeBar: false }); const tbody = document.querySelector('#bench-table tbody'); tbody.innerHTML = BENCHMARKS.map((b) => { const d = b.smaug - b.base; return '' + escapeHtml(b.name) + '' + b.smaug.toFixed(1) + '' + b.base.toFixed(1) + (b.starred ? '*' : '') + '' + (d >= 0 ? '+' : '') + d.toFixed(1) + ''; }).join(''); const lbody = document.querySelector('#lb-table tbody'); lbody.innerHTML = LIVEBENCH.map((c) => { const d = c.smaug - c.base; return '' + escapeHtml(c.name) + '' + c.smaug.toFixed(1) + '' + c.base.toFixed(1) + '' + (d === 0 ? 'par' : (d > 0 ? '+' : '') + d.toFixed(1)) + ''; }).join(''); } showTab._mounted = { overview: true }; // ============================================================ sizing calculator function computeSize(attnBpe, expertBpe, headroomPct) { const expertGb = EXPERT_PARAMS * expertBpe / 1e9; const otherGb = OTHER_PARAMS * attnBpe / 1e9; const weightsGb = expertGb + otherGb; const totalGb = weightsGb * (1 + headroomPct / 100); return { expertGb, otherGb, weightsGb, totalGb }; } function updateSize() { const attnBpe = parseFloat($('attn-bits').value); const expertBpe = parseFloat($('expert-bits').value); const headroom = parseFloat($('headroom').value); $('headroom-v').textContent = String(headroom); const s = computeSize(attnBpe, expertBpe, headroom); $('size-out').innerHTML = '' + '' + '' + '' + '' + '' + '
Expert FFNs (43 layers × 257 experts × 3 matrices × 4096 × 2048)' + (EXPERT_PARAMS / 1e9).toFixed(1) + ' B params → ' + s.expertGb.toFixed(1) + ' GB
Attention + embeddings + DSpark' + (OTHER_PARAMS / 1e9).toFixed(1) + ' B params → ' + s.otherGb.toFixed(1) + ' GB
Weights subtotal' + s.weightsGb.toFixed(1) + ' GB
+ ' + headroom + '% headroom (KV cache, activations, overhead)+' + (s.totalGb - s.weightsGb).toFixed(1) + ' GB
Budget to fit' + s.totalGb.toFixed(1) + ' GB
' + '

Reference: the shipped checkpoint is ' + CHECKPOINT_GB + ' GB on the Hub — block-FP8 ' + 'attention × packed-FP4 experts (' + computeSize(1, 0.5, 0).weightsGb.toFixed(1) + ' GB here, the rest is index/tokenizer overhead and the BF16/FP8 mix).

'; const rows = HARDWARE.slice().sort((a, b) => a.usd - b.usd).map((hw) => { let verdict; if (hw.gpu <= 0) verdict = '— no GPU'; else if (hw.gpu >= s.totalGb) verdict = '✅ fits on paper'; else verdict = '❌ short by ' + (s.totalGb - hw.gpu).toFixed(0) + ' GB'; return '' + escapeHtml(hw.name) + '' + escapeHtml(hw.note) + '' + hw.gpu + ' GB' + (hw.usd === 0 ? 'free' : '$' + hw.usd.toFixed(2) + '/h') + '' + verdict + ''; }).join(''); $('hw-table').querySelector('tbody').innerHTML = rows; $('chart-size').dataset.budget = String(s.totalGb); drawSizeChart(); } function drawSizeChart() { const el = $('chart-size'); if (!el || !el.dataset.budget) return; const attnBpe = parseFloat($('attn-bits').value); const expertBpe = parseFloat($('expert-bits').value); const headroom = parseFloat($('headroom').value); const s = computeSize(attnBpe, expertBpe, headroom); Plotly.newPlot('chart-size', [ { type: 'bar', x: ['weights', '+' + headroom + '% headroom'], y: [s.weightsGb, s.totalGb - s.weightsGb], marker: { color: ['#6d7cff', '#a5b4fc'] }, text: [s.weightsGb.toFixed(0) + ' GB', (s.totalGb - s.weightsGb).toFixed(0) + ' GB'], textposition: 'inside', hovertemplate: '%{x}: %{y:.1f} GB' } ], Object.assign({}, PLOTLY_LAYOUT, { title: 'Budget vs the 96 GB ZeroGPU ceiling', height: 420, showlegend: false, yaxis: { title: 'GB (decimal)' }, shapes: [{ type: 'line', x0: -0.5, x1: 1.5, y0: 96, y1: 96, line: { color: '#f87171', dash: 'dash', width: 2 } }], annotations: [{ x: 1, y: 96, text: 'ZeroGPU xlarge 96 GB', showarrow: false, yshift: 10 }] }), { responsive: true, displayModeBar: false }); } ['attn-bits', 'expert-bits', 'headroom'].forEach((id) => { const el = $(id); el.addEventListener('input', updateSize); el.addEventListener('change', updateSize); }); // ============================================================ recipes + copy Object.keys(RECIPES).forEach((id) => { const pre = $(id); if (pre) pre.textContent = RECIPES[id]; }); document.querySelectorAll('button.copy').forEach((btn) => { btn.addEventListener('click', async () => { const pre = $(btn.dataset.copy); if (!pre) return; try { await navigator.clipboard.writeText(pre.textContent); btn.textContent = 'copied'; } catch (err) { btn.textContent = 'select + Ctrl-C'; } setTimeout(() => { btn.textContent = 'copy'; }, 1600); }); }); // ============================================================ Pyodide encoder const PY_SETUP = ` import sys, json sys.path.insert(0, "/home/pyodide") import encoding_dsv4 as _dsv4 def smaug_encode(args_json): try: args = json.loads(args_json) messages = args.get("messages") or [] tools = args.get("tools") or None if tools and messages: messages = [dict(m) for m in messages] messages[0] = dict(messages[0], tools=tools) prompt = _dsv4.encode_messages( messages, thinking_mode=args["thinking"], reasoning_effort=(args.get("effort") or None), drop_thinking=bool(args.get("drop", True)), ) return json.dumps({"ok": True, "prompt": prompt, "n_messages": len(messages)}) except Exception as exc: return json.dumps({"ok": False, "error": type(exc).__name__ + ": " + str(exc)}) def smaug_decode(args_json): try: args = json.loads(args_json) parsed = _dsv4.parse_message_from_completion_text(args["text"], thinking_mode=args["thinking"]) return json.dumps({"ok": True, "parsed": parsed}) except Exception as exc: return json.dumps({"ok": False, "error": type(exc).__name__ + ": " + str(exc)}) def smaug_effort_sizes(): return json.dumps({k: len(v) for k, v in _dsv4.REASONING_EFFORT_PROMPTS.items()}) def smaug_tokens(): return json.dumps({ "bos": _dsv4.bos_token, "eos": _dsv4.eos_token, "think_start": _dsv4.thinking_start_token, "think_end": _dsv4.thinking_end_token, "dsml": _dsv4.dsml_token, }) def smaug_repair_delimiters(args_json): # The repo delimits special tokens with U+FF5C, not ASCII '|'. Repair pipes # typed by hand (or copied from a rendering of the model card), and report it. import re as _re text = json.loads(args_json)["text"] repaired = _re.sub(r"<\|([^|<>{]{0,24})\|>", lambda m: "<" + chr(0xff5c) + m.group(1) + chr(0xff5c) + ">", text) return json.dumps({"text": repaired, "repaired": repaired != text}) `; let pyodidePromise = null; const DEFAULT_COMPLETION = document.getElementById('completion-in') ? document.getElementById('completion-in').value : ''; function setPyStatus(text, cls) { const el = $('py-status'); if (!el) return; el.textContent = text; el.className = 'status' + (cls ? ' ' + cls : ''); } function loadScript(src) { return new Promise((resolve, reject) => { const s = document.createElement('script'); s.src = src; s.onload = resolve; s.onerror = () => reject(new Error('failed to load ' + src)); document.head.appendChild(s); }); } async function loadPyodideRuntime(indexURL) { // Prefer the ES module build. Older releases only expose a `loadPyodide` // global from the classic script, so keep that as the fallback. try { const mod = await import(indexURL + 'pyodide.mjs'); if (typeof mod.loadPyodide === 'function') return await mod.loadPyodide({ indexURL }); } catch (err) { console.warn('pyodide.mjs unavailable, falling back to classic pyodide.js:', err); } await loadScript(indexURL + 'pyodide.js'); if (typeof window.loadPyodide !== 'function') { throw new Error('neither pyodide.mjs nor a loadPyodide global is available at ' + indexURL); } return await window.loadPyodide({ indexURL }); } async function ensurePyodide() { if (pyodidePromise) return pyodidePromise; pyodidePromise = (async () => { setPyStatus('loading Python in your browser (≈ 10 MB, one time)...'); const indexURL = 'https://cdn.jsdelivr.net/pyodide/' + PYODIDE_VERSION + '/full/'; const py = await loadPyodideRuntime(indexURL); const src = await (await fetch('encoding_dsv4.py')).text(); py.FS.writeFile('/home/pyodide/encoding_dsv4.py', src); await py.runPythonAsync(PY_SETUP); const sizes = JSON.parse(py.runPython('smaug_effort_sizes()')); window.__smaugTokens = JSON.parse(py.runPython('smaug_tokens()')); const box = $('completion-in'); if (box && box.value === DEFAULT_COMPLETION) { box.value = 'Let me add the two integers.' + window.__smaugTokens.think_end + 'The answer is 4.' + window.__smaugTokens.eos; } setPyStatus('runtime ready — encodes with the model repo’s own encoding_dsv4.py (' + sizes.low + '/' + sizes.high + '/' + sizes.max + ' char preambles for low/high/max)', 'badge-ok'); return py; })(); try { return await pyodidePromise; } catch (err) { pyodidePromise = null; setPyStatus('⚠️ Python runtime failed to load: ' + err.message + ' — check the browser console.', 'badge-bad'); throw err; } } function setMessagesExample(which) { $('messages-in').value = JSON.stringify(EXAMPLES[which], null, 2); if (which === 'agentic') $('tools-in').value = JSON.stringify(EXAMPLE_TOOLS, null, 2); else if ($('tools-in').value.trim() === JSON.stringify(EXAMPLE_TOOLS, null, 2)) $('tools-in').value = ''; } function mountEncoder() { if (!$('messages-in').value.trim()) setMessagesExample('chat'); if (!$('tools-in').value.trim()) $('tools-in').value = ''; } (async function initEncoder() { setMessagesExample('chat'); $('tools-in').value = ''; document.querySelectorAll('[data-example]').forEach((b) => { b.addEventListener('click', () => setMessagesExample(b.dataset.example)); }); $('encode-btn').addEventListener('click', async () => { const out = $('prompt-out'), stats = $('encode-stats'), notes = $('encode-notes'); out.value = ''; stats.textContent = ''; notes.innerHTML = ''; let messages, tools = null; try { messages = JSON.parse($('messages-in').value || '[]'); } catch (err) { stats.innerHTML = '⚠️ messages JSON is invalid: ' + escapeHtml(err.message) + ''; return; } if (!Array.isArray(messages) || messages.length === 0) { stats.innerHTML = '⚠️ provide a non-empty JSON array of messages.'; return; } const toolsRaw = $('tools-in').value.trim(); if (toolsRaw) { try { tools = JSON.parse(toolsRaw); } catch (err) { stats.innerHTML = '⚠️ tools JSON is invalid: ' + escapeHtml(err.message) + ''; return; } } const thinking = $('thinking-in').value; const effort = $('effort-in').value; const drop = $('drop-in').checked; let py; try { py = await ensurePyodide(); } catch (err) { return; } py.globals.set('ARGS_JSON', JSON.stringify({ messages, tools, thinking, effort, drop })); const result = JSON.parse(py.runPython('smaug_encode(ARGS_JSON)')); if (!result.ok) { stats.innerHTML = '⚠️ encoding failed — ' + escapeHtml(result.error) + ''; return; } const prompt = result.prompt; out.value = prompt; const dropNote = thinking === 'thinking' ? (drop ? 'Dropped' : 'Kept') + ' reasoning_content on assistant turns before the last user message.' : 'chat mode: no thinking blocks are rendered at all.'; stats.innerHTML = 'messages in: ' + result.n_messages + ' · chars: ' + prompt.length.toLocaleString() + ' · thinking_mode: ' + thinking + ' · reasoning_effort: ' + effort + '' + (tools ? ' · tools rendered: ' + tools.length + '' : ' · no tools'); notes.innerHTML = '
    ' + '
  1. Merged tool messages into the preceding user turn and sorted tool results by ' + 'call order — DeepSeek-V4 has no separate tool role slot in the prompt ' + '(merge_tool_messages() / sort_tool_results_by_call_order()).
  2. ' + '
  3. ' + escapeHtml(dropNote) + '
  4. ' + '
  5. Prepended the BOS token and closed the final assistant turn with <|Assistant|>' + (thinking === 'thinking' ? ' plus <think>.' : ' plus an immediate </think>.') + '
  6. ' + '
  7. Tokenize this string exactly as-is: tokenizer.encode(prompt) — no chat template, ' + 'no extra separators.
  8. ' + '
'; }); $('decode-btn').addEventListener('click', async () => { const status = $('decode-status'); const completion = $('completion-in').value; if (!completion.trim()) { status.innerHTML = '⚠️ paste a completion first.'; return; } let py; try { py = await ensurePyodide(); } catch (err) { return; } py.globals.set('ARGS_JSON', JSON.stringify({ text: completion })); const repair = JSON.parse(py.runPython('smaug_repair_delimiters(ARGS_JSON)')); if (repair.repaired) { $('completion-in').value = repair.text; } const repairNote = repair.repaired ? ' (repaired ASCII | to the repo’s U+FF5C delimiter)' : ''; py.globals.set('ARGS_JSON', JSON.stringify({ text: repair.text, thinking: $('decode-mode').value })); const result = JSON.parse(py.runPython('smaug_decode(ARGS_JSON)')); if (!result.ok) { $('parsed-out').value = ''; status.innerHTML = '⚠️ parse failed — ' + escapeHtml(result.error) + '
The parser only accepts well-formed output: close the think ' + 'block with </think> and end the turn with <|end▁of▁sentence|>.'; return; } $('parsed-out').value = JSON.stringify(result.parsed, null, 2); status.innerHTML = '✅ parsed cleanly into OpenAI-format fields' + repairNote; }); })(); // ============================================================ playground const PRESETS = { own: { baseUrl: 'http://your-host:8000/v1', model: MODEL_ID, key: 'EMPTY', hint: 'vLLM and SGLang both expose an OpenAI-compatible /v1 endpoint. The host must be reachable from ' + 'this browser: a laptop localhost is not, unless you opened this page locally or tunnelled it.' }, router: { baseUrl: 'https://router.huggingface.co/v1', model: 'deepseek-ai/DeepSeek-V4.1-Flash-1017', key: '', hint: 'Live and OpenAI-compatible, but the router does not serve Smaug-Flash — use it to sanity-check the ' + 'plumbing against a supported Flash-class model, then switch to your own deployment for the real thing. ' + 'Paste an HF token with Inference Providers permission as the key.' }, local: { baseUrl: 'http://127.0.0.1:11434/v1', model: 'smaug-flash', key: 'ollama', hint: 'Only resolves if this page runs on the same machine as the runtime (serve the repo folder locally).' }, custom: { baseUrl: '', model: MODEL_ID, key: '', hint: 'Any OpenAI-compatible /v1 base URL works.' } }; const chatHistory = []; let streaming = false; function applyPreset() { const p = PRESETS[$('preset').value] || PRESETS.own; $('base-url').value = p.baseUrl; $('model-name').value = p.model; $('api-key').value = p.key; $('preset-hint').textContent = p.hint; } function renderChat() { const log = $('chat-log'); if (!chatHistory.length) { log.innerHTML = '

Nothing here yet — set an endpoint, then send a message.

'; return; } log.innerHTML = chatHistory.map((m) => { const cls = m.role === 'user' ? 'user' : (m.error ? 'error' : 'assistant'); return '
' + m.role + '' + escapeHtml(m.content) + '
'; }).join(''); log.scrollTop = log.scrollHeight; } ['pg-temp', 'pg-topp'].forEach((id) => { const el = $(id); el.addEventListener('input', () => { $('pg-temp-v').textContent = parseFloat($('pg-temp').value).toFixed(2); $('pg-topp-v').textContent = parseFloat($('pg-topp').value).toFixed(2); }); }); $('preset').addEventListener('change', applyPreset); applyPreset(); $('pg-temp-v').textContent = parseFloat($('pg-temp').value).toFixed(2); $('pg-topp-v').textContent = parseFloat($('pg-topp').value).toFixed(2); $('test-btn').addEventListener('click', async () => { const out = $('test-out'); const base = $('base-url').value.trim().replace(/\/+$/, ''); if (!base) { out.innerHTML = '⚠️ set a base URL first.'; return; } out.textContent = 'calling ' + base + '/models …'; try { const res = await fetch(base + '/models', { headers: $('api-key').value ? { Authorization: 'Bearer ' + $('api-key').value } : {} }); if (!res.ok) throw new Error('HTTP ' + res.status + ' ' + res.statusText); const json = await res.json(); const ids = (json.data || []).map((m) => m.id); out.innerHTML = '✅ ' + ids.length + ' model(s): ' + ids.slice(0, 20).map((i) => '' + escapeHtml(i) + '').join(' ') + (ids.length > 20 ? ' …' : ''); } catch (err) { out.innerHTML = '❌ ' + escapeHtml(err.message) + '
A browser-side "Failed to fetch" here usually means CORS or mixed ' + 'content (http endpoint on an https page), not that the server is down.'; } }); async function streamCompletion(body, onDelta, onReasoning) { const base = $('base-url').value.trim().replace(/\/+$/, ''); const key = $('api-key').value; const res = await fetch(base + '/chat/completions', { method: 'POST', headers: Object.assign({ 'Content-Type': 'application/json' }, key ? { Authorization: 'Bearer ' + key } : {}), body: JSON.stringify(body) }); if (!res.ok) { let detail = ''; try { detail = (await res.text()).slice(0, 400); } catch (err) { /* ignore */ } const err = new Error('HTTP ' + res.status + ' ' + res.statusText + (detail ? ' — ' + detail : '')); err.status = res.status; throw err; } if (!res.body) { // non-streaming fallback const json = await res.json(); const choice = (json.choices || [])[0] || {}; const msg = choice.message || {}; if (msg.reasoning_content) onReasoning(msg.reasoning_content); if (msg.content) onDelta(msg.content); return; } const reader = res.body.getReader(); const decoder = new TextDecoder(); let buffer = ''; for (;;) { const chunk = await reader.read(); if (chunk.done) break; buffer += decoder.decode(chunk.value, { stream: true }); const lines = buffer.split('\n'); buffer = lines.pop(); for (const line of lines) { const trimmed = line.trim(); if (!trimmed.startsWith('data:')) continue; const payload = trimmed.slice(5).trim(); if (payload === '[DONE]') continue; let json; try { json = JSON.parse(payload); } catch (err) { continue; } const delta = ((json.choices || [])[0] || {}).delta || {}; const reasoning = delta.reasoning_content || delta.reasoning || ''; if (reasoning) onReasoning(reasoning); if (delta.content) onDelta(delta.content); } } } $('send-btn').addEventListener('click', send); $('msg-in').addEventListener('keydown', (e) => { if (e.key === 'Enter' && (e.ctrlKey || e.metaKey)) { e.preventDefault(); send(); } }); async function send() { if (streaming) return; const text = $('msg-in').value.trim(); if (!text) return; if (!$('base-url').value.trim() || !$('model-name').value.trim()) { chatHistory.push({ role: 'assistant', error: true, content: '⚠️ Set a base URL and model first (or pick a preset).' }); renderChat(); return; } streaming = true; $('stream-status').textContent = 'streaming…'; chatHistory.push({ role: 'user', content: text }); chatHistory.push({ role: 'assistant', content: '' }); $('msg-in').value = ''; $('reasoning-out').value = ''; renderChat(); const messages = []; const sys = $('system-in').value.trim(); if (sys) messages.push({ role: 'system', content: sys }); chatHistory.slice(0, -1).forEach((m) => { if (!m.error) messages.push({ role: m.role, content: m.content }); }); const body = { model: $('model-name').value.trim(), messages: messages, temperature: parseFloat($('pg-temp').value), top_p: parseFloat($('pg-topp').value), max_tokens: parseInt($('pg-maxtok').value, 10) || 8192, stream: true }; if ($('pg-send').checked) { body.reasoning_effort = $('pg-effort').value; body.thinking_mode = $('pg-mode').value; } let answer = ''; let reasoning = ''; const onDelta = (piece) => { answer += piece; chatHistory[chatHistory.length - 1].content = answer; renderChat(); }; const onReasoning = (piece) => { reasoning += piece; $('reasoning-out').value = reasoning; }; try { await streamCompletion(body, onDelta, onReasoning); } catch (err) { if (body.reasoning_effort && /40[04]/.test(String(err.status))) { delete body.reasoning_effort; delete body.thinking_mode; chatHistory[chatHistory.length - 1].content = '_(endpoint rejected reasoning_effort/thinking_mode — retrying without)_\n\n'; renderChat(); try { await streamCompletion(body, onDelta, onReasoning); } catch (err2) { fail(err2); } } else { fail(err); } } function fail(err) { const msg = String(err && err.message ? err.message : err); chatHistory[chatHistory.length - 1] = { role: 'assistant', error: true, content: '❌ request failed — ' + msg + '\n\nChecklist: reachable from this browser? model name correct ' + '(use Test endpoint)? CORS / mixed-content? key valid?' }; renderChat(); } if (!chatHistory[chatHistory.length - 1].content) { chatHistory[chatHistory.length - 1].content = '⚠️ the endpoint streamed no content (check the model name).'; renderChat(); } $('stream-status').textContent = ''; streaming = false; } $('clear-btn').addEventListener('click', () => { chatHistory.length = 0; $('reasoning-out').value = ''; $('stream-status').textContent = ''; renderChat(); }); // ============================================================ boot updateSize(); mountEncoder(); renderChat();