Files
sglang/docs/src/snippets/_playground.jsx
T

2804 lines
125 KiB
React
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
// Engine half of the SGLang cookbook playground widget. Pairs with a
// per-model config under `/src/snippets/configs/<vendor>/<model>.jsx`.
// See the cookbook-add-model skill (.claude/skills/cookbook-add-model/) for the
// authoring workflow; references/engine-axis.md covers adding a new axis.
//
// Consumes the same config shape as `_deployment.jsx`, plus
// `config.playgroundFeatures` — a keyed map where each present key opts that
// axis in. Recognised axes:
// attention — TP/CP/DP-Attention knobs
// moe — backend (+ MegaMoE quantization sub-select) + EP
// parsers — per-item toggle flags
// speculative — single-select preset; an option may carry `note` (a
// prerequisite line rendered under the chips while that option
// is the one in effect)
//
// Axis-level `showWhen(base)` (any axis): the card is not rendered when the Deploy
// panel has not switched that feature on. `base` carries the cell match dims plus
// the Deploy panel's overlay dims, so an axis can gate on either.
// flagSelects extras: `control: "slider"` renders the option list as a range input
// (option order is the scale), and a per-select `showWhen(base)` gates one row.
// A row may set `default` (initial pick instead of inherit) and options may carry
// `env` (stripped/re-added like the MoE backend card) or `flags` as a FUNCTION
// `(rowValues, base) => [...]` for cross-row composition (e.g. preset x cluster
// size); a function returning null means "leave the base untouched".
// Changing the Deploy selection resets every axis back to inherit-from-base.
// pdDisagg — role + transfer backend + IB device + optional router
// hicache — enable + backend + write policy
// hisparse — enable + host ratio (decode-only)
// flagSelects — generic: a config-declared LIST of single-selects, each with
// its own title + strip-prefixes + options (no per-feature code)
//
// Adding an axis = one entry in AXIS_HANDLERS below; nothing else switches on
// an axis id. Each handler implements initState / apply /
// render, plus optional deriveFromBase (recover state from base cell flags)
// and getRenderHints.
//
// Mintlify caveats (same as _deployment.jsx):
// - Module-level statements are stripped → everything lives in the wrapper.
// - Capitalized JSX tags get rebound → lowercase HTML tags only.
// - `!(x in y)` crashes the AST walker → use `obj.key === undefined`.
export const Playground = ({ config }) => {
if (!config) {
return <div style={{padding: 12, color: "#b91c1c"}}>Playground: missing <code>config</code> prop</div>;
}
// ==========================================================================
// 1. Constants
// ==========================================================================
const DIMENSIONS = ["hw", ...((config.matchDims
|| [{ id: "variant" }, { id: "quant" }, { id: "strategy" }, { id: "nodes" }])
.map((d) => d.id))];
// The Deploy panel layers its overlay dims (speculation, hicache, ...) on top of
// the matched cell, so the playground's "base" is cell + overlay — otherwise the
// diff shows overlay flags as playground additions and deriveFromBase can't see
// what Deploy already resolved.
//
// ==== MIRROR in _deployment.jsx — keep the two copies identical ====
// Snippets cannot import each other, so the overlay-resolution rule is written
// twice. A divergence makes the Deploy command and the playground base disagree,
// which shows up as phantom +/- lines in the diff and no error anywhere.
// Guarded by docs/scripts/check_cookbook_configs.mjs.
const optionVisible = (opt, sel) =>
typeof opt.showWhen !== "function" || opt.showWhen(sel);
const optionDisabled = (opt, sel) =>
typeof opt.disabled === "function" ? opt.disabled(sel) : !!opt.disabled;
const visibleOptions = (spec, sel) =>
(spec.options || []).filter((o) => optionVisible(o, sel));
const rowVisible = (spec, sel) =>
(typeof spec.showWhen !== "function" || spec.showWhen(sel)) &&
visibleOptions(spec, sel).length > 0;
const overlayPick = (sel) => {
const picked = [];
for (const spec of (config.overlayDims || [])) {
if (!rowVisible(spec, sel)) continue;
const opt = (spec.options || []).find((o) => o.id === sel[spec.id]);
if (opt && !optionDisabled(opt, sel)) picked.push(opt);
}
return picked;
};
const overlayPart = (sel, key) => {
const out = [];
for (const opt of overlayPick(sel)) {
const add = typeof opt[key] === "function" ? opt[key](sel) : opt[key];
if (add) out.push(...add);
}
return out;
};
// An overlay option may also REMOVE cell flags, declared as `stripPrefixes`
// (a static list, or a function of the selection). L3 uses it to drop the
// whole DCP operating point, which the server rejects with an L3 backend.
//
// Overlay flags append, except a flag whose family the same overlay stripped:
// that one is spliced back where the stripped flag was, so a rewritten
// parallelism block (DSPARK folding a pipeline flat) stays put instead of
// landing past the --host/--port tail with the multi-node trio behind it.
const overlayCompose = (cellFlags, sel) => {
const strip = overlayPart(sel, "stripPrefixes");
const add = overlayPart(sel, "flags");
if (!strip.length) return [...(cellFlags || []), ...add];
const used = new Set();
// Consumed once, so a family the cell carries twice is not emitted twice.
const replacementsFor = (tok) => {
const out = [];
add.forEach((f, i) => {
if (used.has(i) || f.split(/[\s=]/)[0] !== tok) return;
used.add(i);
out.push(f);
});
return out;
};
const out = [];
for (const f of (cellFlags || [])) {
const tok = f.split(/[\s=]/)[0];
if (!strip.includes(tok)) out.push(f);
else out.push(...replacementsFor(tok));
}
add.forEach((f, i) => { if (!used.has(i)) out.push(f); });
return out;
};
// ==== end MIRROR ====
const withOverlay = (cell, sel) => (cell && {
...cell,
flags: overlayCompose(cell.flags, sel),
env: [...(cell.env || []), ...overlayPart(sel, "env")],
}) || cell;
// Shared with `_deployment.jsx` (HOST/PORT/etc. unified across the page).
const STORAGE_KEY = "sglang-deploy-env";
// ==== MIRROR of DEPLOYMENT_COMPONENT_ID in _deployment.jsx — keep identical ====
// Snippets cannot import each other. The Deploy panel puts this id on its
// root (carrying its own scrollMarginTop), which is what "jump to the base"
// should land on.
const DEPLOYMENT_COMPONENT_ID = "deployment-configurator";
const pgFeatures = config.playgroundFeatures || {};
// Single-host PD runs prefill + decode as two engines on one box. Each derives
// 5 consecutive ZMQ/dist ports from its --port (port+233, see server_args.py
// ZMQ_TCP_PORT_DELTA), so the serve ports are spaced 100 apart to keep those
// derived ranges from overlapping — no --dist-init-addr needed single-host.
// `dist` is only used by the multi-node renderer (cross-node rendezvous).
const PD_PORTS = {
prefill: { serve: 30000, dist: 30335 },
decode: { serve: 30100, dist: 30435 },
};
// ==========================================================================
// 2. Pure data helpers
// ==========================================================================
const findCell = (cells, sel) =>
cells.find((c) => DIMENSIONS.every((d) => c.match[d] === sel[d]));
// After applying overrides, the resulting (env, flags) may equal another
// cell sharing every match dim except strategy. Keep this generic so custom
// grids (for example K3's PD mode) cannot match across unrelated base cells.
// flags compared ordered; env compared as a set.
const findMatchingCell = (cells, sel, pgEnv, pgFlags) => {
const fixedDims = DIMENSIONS.filter((d) => d !== "strategy");
const flagsEq = (a, b) =>
a.length === b.length && a.every((x, i) => x === b[i]);
const envEq = (a, b) => {
if (a.length !== b.length) return false;
const set = new Set(a);
for (const x of b) if (!set.has(x)) return false;
return true;
};
for (const c of cells) {
if (fixedDims.some((d) => c.match[d] !== sel[d])) continue;
if (flagsEq(c.flags || [], pgFlags || []) && envEq(c.env || [], pgEnv || [])) {
return c;
}
}
return null;
};
// hw|variant|quant → variant|quant → hw|quant → quant → hw → default.
const resolveModelName = (sel) => {
const keys = [
`${sel.hw}|${sel.variant}|${sel.quant}`,
`${sel.variant}|${sel.quant}`,
`${sel.hw}|${sel.quant}`,
sel.quant,
sel.hw,
"default",
];
for (const k of keys) {
const hit = config.modelNames[k];
if (hit) return hit;
}
return "";
};
const interpolate = (text, env, modelName) =>
text.replace(/{{(\w+)}}/g, (_, key) =>
key === "MODEL_NAME" ? modelName : (env[key] ?? `{{${key}}}`));
const parseNnodes = (id) => {
if (id === "single") return 1;
const m = /^multi-(\d+)$/.exec(id);
return m ? parseInt(m[1], 10) : 1;
};
const placeholderDefaults = (schema) => {
const out = {};
for (const [k, v] of Object.entries(schema || {})) out[k] = v.default ?? "";
return out;
};
// ==========================================================================
// 3. Per-chip constraint evaluation
// ==========================================================================
// A chip entry is a bare value, a `{value, hide?, disable?, ...}` wrapper,
// or a rich `{id, ...}` option. `hide`/`disable` are constraint objects
// mapping base-cell dims to allowed-value arrays; matches when every key
// matches (AND across keys, OR within a key). Empty/malformed never match.
// `disabled: true` / `disable: true` are static always-disabled forms.
// `disable` may also be an ARRAY of `{when: constraint, reason?}` items
// (OR across items, first match wins and supplies its own reason) for
// conditions that need OR across keys or per-condition tooltips.
const matchConstraint = (base, constraint) => {
if (!constraint || typeof constraint !== "object") return false;
const entries = Object.entries(constraint);
if (entries.length === 0) return false;
return entries.every(([k, vs]) =>
Array.isArray(vs) && vs.includes(base[k]));
};
// Normalize a chip entry into `{value, label?, hidden, disabled,
// disableReason, ...rest}`. `value` resolves to `entry.id` (rich form) or
// `entry.value` (wrapper form), or the entry itself for bare values.
const evaluateChip = (entry, base) => {
if (entry === null || typeof entry !== "object") {
return {
value: entry, label: undefined,
hidden: false, disabled: false, disableReason: "",
};
}
const hidden = entry.hide ? matchConstraint(base, entry.hide) : false;
let disabled = entry.disabled === true || entry.disable === true;
let disableReason = typeof entry.disableReason === "function"
? entry.disableReason(base)
: entry.disableReason || "";
if (!disabled && entry.disable && typeof entry.disable === "object") {
if (Array.isArray(entry.disable)) {
for (const item of entry.disable) {
const cond = (item && item.when) || item;
if (matchConstraint(base, cond)) {
disabled = true;
if (item && item.reason) disableReason = item.reason;
break;
}
}
} else {
disabled = matchConstraint(base, entry.disable);
}
}
return {
...entry,
value: entry.id !== undefined ? entry.id : entry.value,
label: entry.label,
hidden,
disabled,
disableReason,
};
};
const findEntry = (entries, picked) => {
for (const e of (entries || [])) {
const v = (e === null || typeof e !== "object")
? e : (e.id !== undefined ? e.id : e.value);
if (v === picked) return e;
}
return null;
};
const isHidden = (entries, picked, base) => {
const e = findEntry(entries, picked);
if (e === null || e === undefined) return false;
return evaluateChip(e, base).hidden;
};
// ==========================================================================
// 4. Flag/env mutation primitives
// ==========================================================================
// Strip flags whose first whitespace/equals-delimited token is in `prefixes`.
const stripFlagsByFirstToken = (flags, prefixes) => {
const set = new Set(prefixes);
return flags.filter((f) => !set.has(f.split(/[\s=]/)[0]));
};
// Strip env entries whose name (before `=`) is in `prefixes`.
const stripEnvByPrefix = (envList, prefixes) => {
if (!prefixes || !prefixes.length) return envList;
const set = new Set(prefixes);
return envList.filter((e) => !set.has(e.split("=")[0]));
};
// Insert new flags just before the trailing --host/--port pair.
const insertBeforeTail = (flags, additions) => {
const idx = flags.findIndex((f) => f.startsWith("--host"));
const at = idx === -1 ? flags.length : idx;
const out = flags.slice();
out.splice(at, 0, ...additions);
return out;
};
// Insert after the first present anchor in priority-ordered `afterAnyOf`,
// falling back to right-after --model-path. Priority order keeps insertion
// position-stable so the diff doesn't drop shared lines around the swap.
const insertAfter = (flags, afterAnyOf, additions) => {
let idx = -1;
for (const anchor of afterAnyOf) {
idx = flags.findIndex((f) => f.split(/[\s=]/)[0] === anchor);
if (idx !== -1) break;
}
if (idx === -1) idx = flags.findIndex((f) => f.startsWith("--model-path"));
const out = flags.slice();
out.splice(idx + 1, 0, ...additions);
return out;
};
// -------- Flag-reading helpers (used by `deriveFromBase` methods) ------
// First integer arg of `--prefix N` (space/`=`-delimited), or null.
const parseIntFlag = (flags, prefix) => {
for (const f of (flags || [])) {
if (f.split(/[\s=]/)[0] !== prefix) continue;
const rest = f.slice(prefix.length).replace(/^[\s=]+/, "");
const n = parseInt(rest, 10);
if (!isNaN(n)) return n;
}
return null;
};
// True if any flag's first token equals `name` (boolean flags).
const hasFlag = (flags, name) =>
(flags || []).some((f) => f.split(/[\s=]/)[0] === name);
// String arg of `--prefix arg` (space/`=`-delimited), or null.
const findFlagArg = (flags, prefix) => {
for (const f of (flags || [])) {
if (f.split(/[\s=]/)[0] !== prefix) continue;
const rest = f.slice(prefix.length).replace(/^[\s=]+/, "");
return rest.length ? rest : null;
}
return null;
};
// --tp / --ep / --dp spelling families: configs write either the canonical
// --tp-size / --ep-size / --dp-size, a short alias, or the long form. Parse
// and strip every spelling; when re-emitting, keep the spelling the base
// already uses.
const TP_HEADS = ["--tp-size", "--tp", "--tensor-parallel-size"];
const EP_HEADS = ["--ep-size", "--ep", "--expert-parallel-size"];
const DP_HEADS = ["--dp-size", "--dp", "--data-parallel-size"];
const parseIntFlagAny = (flags, heads) => {
for (const head of heads) {
const n = parseIntFlag(flags, head);
if (n !== null) return n;
}
return null;
};
const flagSpelling = (flags, heads, fallback) =>
heads.find((head) =>
(flags || []).some((f) => f.split(/[\s=]/)[0] === head)) || fallback;
// Insertion-anchor sets (priority-ordered; each includes siblings so
// insertion still works in partial cells).
const ANCHOR_NEAR_MODEL_PATH = ["--model-path"];
const ANCHOR_NEAR_TP = ["--tp-size", "--tp", "--model-path"];
const ANCHOR_NEAR_DP = ["--dp-size", "--dp", "--tp-size", "--tp", "--model-path"];
const ANCHOR_NEAR_DPATTN = ["--enable-dp-attention", "--dp-size", "--dp", "--tp-size", "--tp", "--model-path"];
const ANCHOR_NEAR_MOE = ["--moe-a2a-backend", "--moe-runner-backend",
"--enable-dp-attention", "--dp-size", "--dp", "--tp-size", "--tp", "--model-path"];
// Helper bundle passed to every axis handler.
const helpers = {
matchConstraint, evaluateChip, findEntry, isHidden,
stripFlagsByFirstToken, stripEnvByPrefix, insertBeforeTail, insertAfter,
parseIntFlag, hasFlag, findFlagArg,
TP_HEADS, EP_HEADS, DP_HEADS, parseIntFlagAny, flagSpelling,
ANCHOR_NEAR_MODEL_PATH, ANCHOR_NEAR_TP, ANCHOR_NEAR_DP,
ANCHOR_NEAR_DPATTN, ANCHOR_NEAR_MOE,
};
// -------- Prefill-CP flag family (shared by the attention axis) --------
// Every flag head that toggles/parameterizes prefill context parallelism:
// the canonical pair plus all per-family legacy spellings.
const CP_ENABLE_HEADS = [
"--enable-prefill-cp",
"--enable-nsa-prefill-context-parallel",
"--enable-dsa-prefill-context-parallel",
"--enable-prefill-context-parallel",
];
const CP_MODE_HEADS = [
"--nsa-prefill-cp-mode", "--dsa-prefill-cp-mode", "--prefill-cp-mode",
];
const CP_OWNED_HEADS = [
...CP_ENABLE_HEADS, ...CP_MODE_HEADS, "--cp-strategy", "--attn-cp-size",
];
// Legacy mode spellings → new-style --cp-strategy values.
const CP_MODE_TO_STRATEGY = {
"in-seq-split": "zigzag",
"round-robin-split": "interleave",
};
const cpEnabledIn = (flags) =>
CP_ENABLE_HEADS.some((head) => hasFlag(flags, head));
// Strategy a cell's flags carry: --cp-strategy first, else a mapped legacy
// mode flag, else null (no strategy baked).
const bakedCpStrategy = (flags) =>
findFlagArg(flags, "--cp-strategy")
|| CP_MODE_TO_STRATEGY[findFlagArg(flags, "--nsa-prefill-cp-mode")]
|| CP_MODE_TO_STRATEGY[findFlagArg(flags, "--dsa-prefill-cp-mode")]
|| CP_MODE_TO_STRATEGY[findFlagArg(flags, "--prefill-cp-mode")]
|| null;
// ==========================================================================
// 5. AXIS_HANDLERS — the built-in playground axis registry
// ==========================================================================
// Each entry implements initState / apply / render (plus
// optional deriveFromBase / getRenderHints). Iterated in insertion order;
// axes absent from config.playgroundFeatures are skipped.
// - inherit-from-base sentinels: null / "current" / "auto" / "off" /
// "disabled" / false — apply no-ops on these (except always-strip axes).
// - apply must not mutate its inputs.
// - strip policy: most axes strip ONLY when overridden; pdDisagg and
// hicache strip unconditionally.
const AXIS_HANDLERS = {
// ---- Axis: Attention Parallelism ----------------------------------------
// TP / CP / DP-Attention sub-knobs; `null` = inherit. DP-Attention is
// combined: a numeric value emits `--dp N --enable-dp-attention`, `false`
// strips both. An optional `cpStrategy` knob (values from --cp-strategy:
// "zigzag" / "interleave") picks the CP layout; without it the strategy
// baked in the base is preserved, defaulting to "interleave" (the legacy
// knob's round-robin-split).
attention: {
initState: () => ({ tp: null, cp: null, cpStrategy: null, dpAttn: null }),
// DP-Attention: `--dp N --enable-dp-attention` → N; neither → false;
// bare `--enable-dp-attention` → 1. CP: any enable spelling →
// `--attn-cp-size N` (bare enable → 2, the legacy convention), plus the
// baked strategy (legacy mode flags mapped to zigzag/interleave).
deriveFromBase: (cell, fc, h) => {
const flags = (cell && cell.flags) || [];
const dpVal = h.parseIntFlagAny(flags, h.DP_HEADS);
const hasDpAttn = h.hasFlag(flags, "--enable-dp-attention");
let dpAttn;
if (dpVal !== null) dpAttn = dpVal;
else if (hasDpAttn) dpAttn = 1;
else dpAttn = false;
const cpSize = h.parseIntFlag(flags, "--attn-cp-size");
return {
tp: h.parseIntFlagAny(flags, h.TP_HEADS),
cp: cpEnabledIn(flags) ? (cpSize !== null ? cpSize : 2) : null,
cpStrategy: bakedCpStrategy(flags),
dpAttn,
};
},
apply: ({ flags, env, value, fc, sel, h }) => {
// Live facts for constraint checks (same keys the render-side
// constraintBase exposes), recomputed after each mutation.
const knobEntry = (id) => (fc.knobs || []).find((k) => k.id === id) || {};
const factsNow = () => ({
...(sel || {}),
dpAttnOn: h.hasFlag(flags, "--enable-dp-attention"),
cpOn: cpEnabledIn(flags),
cpStrategy: bakedCpStrategy(flags) || "interleave",
effTp: h.parseIntFlagAny(flags, h.TP_HEADS),
});
// The runtime derives the prefill-CP size as attn_cp_size = tp/dp
// (a mismatched --attn-cp-size is overridden), so with DP-Attention
// off only CP == TP is real. With DP-Attention on the sizes are NOT
// gated: CP + DP-Attention is an allowed experiment (warning hint
// below the command box). Mirrors the render-side auto-gating; a
// config opts out entirely with `freeSize: true` on the cp knob.
const cpSizeTargetNow = () => {
if (knobEntry("cp").freeSize) return null;
const dpIntent = (value.dpAttn !== null && value.dpAttn !== undefined)
? value.dpAttn
: (h.hasFlag(flags, "--enable-dp-attention")
? (h.parseIntFlagAny(flags, h.DP_HEADS) ?? 1) : false);
if (typeof dpIntent === "number" && dpIntent > 1) return null;
return h.parseIntFlagAny(flags, h.TP_HEADS);
};
// Skip a knob whose entry or picked value is hidden/disabled under
// the live facts — mirrors the grayed controls, so stale state never
// emits a blocked combination.
const blocked = (id, v) => {
const facts = factsNow();
const kc = h.evaluateChip(knobEntry(id), facts);
if (kc.hidden || kc.disabled) return true;
if (id === "cp" && typeof v === "number" && v > 1) {
const target = cpSizeTargetNow();
if (target !== null && v !== target) return true;
}
const e = h.findEntry(knobEntry(id).values || [], v);
return !!(e !== null && e !== undefined
&& h.evaluateChip(e, facts).disabled);
};
// NOTE: interleave prefill-CP + DP-Attention currently fails the
// runtime's dp_size == 1 assert, but combined support is planned
// upstream — the combination is allowed here (with a warning hint
// below the command box) rather than banned.
if (value.tp !== null && !blocked("tp", value.tp)) {
const tpHead = h.flagSpelling(flags, h.TP_HEADS, "--tp");
flags = h.stripFlagsByFirstToken(flags, h.TP_HEADS);
flags = h.insertAfter(flags, h.ANCHOR_NEAR_MODEL_PATH, [`${tpHead} ${value.tp}`]);
}
// CP override: an explicit size pick, or a strategy-only pick on a
// base that already carries CP. Strategy precedence: explicit knob >
// baked-in-base > "interleave" (the legacy knob's round-robin-split).
const cpStrategyOverride =
(value.cpStrategy && !blocked("cpStrategy", value.cpStrategy))
? value.cpStrategy : null;
const cpPick = (value.cp !== null)
? value.cp
: ((cpStrategyOverride && cpEnabledIn(flags))
? (h.parseIntFlag(flags, "--attn-cp-size") ?? 2)
: null);
const cpStrategyPick =
cpStrategyOverride || bakedCpStrategy(flags) || "interleave";
if (cpPick !== null && !blocked("cp", cpPick)) {
// Own the whole CP flag family (canonical + every legacy spelling)
// so an override fully replaces (or removes) whatever the base
// recipe baked in.
flags = h.stripFlagsByFirstToken(flags, CP_OWNED_HEADS);
if (cpPick > 1) {
flags = h.insertAfter(flags, h.ANCHOR_NEAR_DPATTN, [
`--attn-cp-size ${cpPick}`,
"--enable-prefill-cp",
`--cp-strategy ${cpStrategyPick}`,
]);
}
}
if (value.dpAttn !== null && value.dpAttn !== undefined
&& !blocked("dpAttn", value.dpAttn)) {
// Capture the spelling before stripping — the TP/EP handlers do the
// same, and a lookup on the stripped array always hits the fallback.
const dpHead = h.flagSpelling(flags, h.DP_HEADS, "--dp-size");
flags = h.stripFlagsByFirstToken(flags, [...h.DP_HEADS, "--enable-dp-attention"]);
if (typeof value.dpAttn === "number" && value.dpAttn > 0) {
flags = h.insertAfter(flags, h.ANCHOR_NEAR_TP, [
`${dpHead} ${value.dpAttn}`,
"--enable-dp-attention",
]);
}
}
return { flags, env };
},
render: ({ axisId, value, setValue, fc, base, s, h, renderSelect, derived }) => {
const knobs = fc.knobs || [];
if (!knobs.length) return null;
const setKnob = (k, v) => setValue({ ...value, [k]: v });
// Interleave prefill-CP + DP-Attention is deliberately NOT grayed:
// current releases assert dp_size == 1 for interleave, but combined
// support is planned upstream — a warning hint below the command box
// covers it instead.
const labelFor = (knob) => (c) => {
if (c.label !== undefined) return c.label;
if (knob.id === "dpAttn") {
const labelMap = knob.labels || { "auto": "Auto", "false": "Off" };
const k = c.value === null ? "auto" : String(c.value);
return labelMap[k] || k;
}
return c.value === null ? "Auto" : String(c.value);
};
// Display: explicit pick > derived > null sentinel.
const knobDisplay = (knob) => {
const v = value[knob.id];
if (v !== null && v !== undefined) return v;
if (derived && derived[knob.id] !== undefined) return derived[knob.id];
return null;
};
const hideNullFor = (knob) => {
const d = derived ? derived[knob.id] : null;
return (d !== null && d !== undefined) ? [null] : [];
};
// Auto-gate CP sizes to the runtime derivation attn_cp_size = tp/dp
// (mirrors apply's cpSizeTargetNow; `freeSize: true` opts out).
const entriesFor = (knob) => {
const vals = knob.values || [null];
if (knob.id !== "cp" || knob.freeSize) return vals;
const target = base.cpSizeTarget;
if (target === null || target === undefined) return vals;
return vals.map((entry) => {
const v = (entry === null || typeof entry !== "object")
? entry : (entry.id !== undefined ? entry.id : entry.value);
if (typeof v !== "number" || v <= 1 || v === target) return entry;
const wrapped = (entry === null || typeof entry !== "object")
? { value: entry } : { ...entry };
return {
...wrapped,
disabled: true,
disableReason: `SGLang derives the prefill-CP size as attn_cp_size = TP / DP-Attention (= ${target} here), so only that size can be enabled.`,
};
});
};
return (
<div key={axisId} style={s.card}>
<div style={s.compactRow}>
<span style={s.axisTitle}>Attention</span>
{knobs.map((knob) => {
const kc = h.evaluateChip(knob, base);
if (kc.hidden) return null;
return (
<span key={knob.id} style={s.field}>
<span style={s.fieldLabel}>{knob.label || knob.id.toUpperCase()}</span>
{renderSelect(knobDisplay(knob), entriesFor(knob),
(nv) => setKnob(knob.id, nv), base, labelFor(knob),
{ hideValues: hideNullFor(knob),
disabled: kc.disabled,
disabledReason: kc.disableReason })}
</span>
);
})}
</div>
</div>
);
},
},
// ---- Axis: MoE Parallelism ----------------------------------------------
// Backend single-select + EP numeric knob; either is optional. Picking the
// "megamoe" backend reveals a Quantization sub-select (W4A8 / W4A4) in the same
// row — W4A4 adds the FP4-activations server flag.
moe: {
initState: () => ({ backend: null, ep: null, mmQuant: null }),
// Prefer --moe-a2a-backend over --moe-runner-backend when both present.
// mmQuant is derived from the base flag (FP4 activations present → W4A4).
deriveFromBase: (cell, fc, h) => {
const flags = (cell && cell.flags) || [];
const a2a = h.findFlagArg(flags, "--moe-a2a-backend");
const runner = h.findFlagArg(flags, "--moe-runner-backend");
const w4a4 = h.hasFlag(flags, "--enable-w4a4-mxfp4-megamoe");
return {
backend: a2a || runner || null,
ep: h.parseIntFlagAny(flags, h.EP_HEADS),
mmQuant: w4a4 ? "w4a4" : "w4a8",
};
},
apply: ({ flags, env, value, fc, h, derived }) => {
if (value.backend !== null) {
flags = h.stripFlagsByFirstToken(flags, [
"--moe-a2a-backend", "--moe-runner-backend",
]);
// Backend options may carry their own env (e.g. the FlashInfer MXFP4
// backend-specific path): strip every backend option's env keys, then
// re-add the selected option's.
const backendEnvKeys = [];
for (const o of (fc.backend?.options || [])) {
for (const e of (o.env || [])) backendEnvKeys.push(e.split("=")[0]);
}
if (backendEnvKeys.length) env = h.stripEnvByPrefix(env, backendEnvKeys);
const opt = (fc.backend?.options || []).find((o) => o.id === value.backend);
if (opt?.flags?.length) {
flags = h.insertAfter(flags, h.ANCHOR_NEAR_DPATTN, opt.flags);
}
if (opt?.env?.length) env = [...env, ...opt.env];
}
// MegaMoE owns the MoE path: when the effective backend is megamoe, strip the
// DeepEP dispatch + any prior MegaMoE quant settings, then re-add the
// selected quant's flags/env. When the backend is explicitly switched
// away from MegaMoE, only drop the MegaMoE quant settings (leave DeepEP
// dispatch intact).
const mq = fc.megamoeQuant;
if (mq) {
const quantKeys = [];
const quantFlagHeads = [];
for (const o of (mq.options || [])) {
for (const e of (o.env || [])) quantKeys.push(e.split("=")[0]);
for (const f of (o.flags || [])) quantFlagHeads.push(f.split(/[\s=]/)[0]);
}
flags = h.stripFlagsByFirstToken(flags, quantFlagHeads);
const effBackend = value.backend !== null
? value.backend : (derived && derived.backend);
if (effBackend === "megamoe") {
env = h.stripEnvByPrefix(env, [...(mq.stripEnv || []), ...quantKeys]);
const quant = value.mmQuant != null
? value.mmQuant : ((derived && derived.mmQuant) || "w4a8");
const opt = (mq.options || []).find((o) => o.id === quant);
if (opt?.flags?.length) {
flags = h.insertAfter(flags, h.ANCHOR_NEAR_MOE, opt.flags);
}
if (opt?.env?.length) env = [...env, ...opt.env];
} else if (value.backend !== null) {
env = h.stripEnvByPrefix(env, quantKeys);
}
}
if (value.ep !== null) {
const epHead = h.flagSpelling(flags, h.EP_HEADS, "--ep");
flags = h.stripFlagsByFirstToken(flags, h.EP_HEADS);
if (value.ep > 1) {
flags = h.insertAfter(flags, h.ANCHOR_NEAR_MOE, [`${epHead} ${value.ep}`]);
}
}
return { flags, env };
},
render: ({ axisId, value, setValue, fc, base, s, renderSelect, derived }) => {
if (!fc.backend && !fc.ep) return null;
const setSlot = (k, v) => setValue({ ...value, [k]: v });
// Display: explicit > derived > null.
const slotDisplay = (k) => {
const v = value[k];
if (v !== null && v !== undefined) return v;
if (derived && derived[k] !== undefined) return derived[k];
return null;
};
const hideNull = (k) => {
const d = derived ? derived[k] : null;
return (d !== null && d !== undefined) ? [null] : [];
};
// Hide the MegaMoE backend option where its requiresHw / excludesStrategy exclude this base.
const mmOpt = (fc.backend?.options || []).find((o) => o.id === "megamoe");
const mmAvail = !!mmOpt
&& (!mmOpt.requiresHw || mmOpt.requiresHw.includes(base.hw))
&& (!mmOpt.excludesStrategy || !mmOpt.excludesStrategy.includes(base.strategy));
const backendIsMega = slotDisplay("backend") === "megamoe";
// `ep.showWhen` (function of base) drops the whole EP select on bases
// where EP is not a supported lever (e.g. the single-shape A3 recipe).
const epShown = !!fc.ep
&& !(typeof fc.ep.showWhen === "function" && !fc.ep.showWhen(base));
return (
<div key={axisId} style={s.card}>
<div style={s.compactRow}>
<span style={s.axisTitle}>MoE</span>
{fc.backend && (
<span style={s.field}>
<span style={s.fieldLabel}>Backend</span>
{renderSelect(slotDisplay("backend"), fc.backend.options || [],
(v) => setSlot("backend", v), base, undefined,
{ hideValues: [...hideNull("backend"), ...(mmAvail ? [] : ["megamoe"])] })}
</span>
)}
{fc.megamoeQuant && backendIsMega && (
<span style={s.field}>
<span style={s.fieldLabel}>Quantization</span>
{renderSelect(
value.mmQuant != null ? value.mmQuant : ((derived && derived.mmQuant) || "w4a8"),
fc.megamoeQuant.options || [],
(v) => setSlot("mmQuant", v), base)}
</span>
)}
{epShown && (
<span style={s.field}>
<span style={s.fieldLabel}>{fc.ep.label || "EP"}</span>
{renderSelect(slotDisplay("ep"), fc.ep.values || [null],
(v) => setSlot("ep", v), base, undefined,
{ hideValues: hideNull("ep") })}
</span>
)}
</div>
</div>
);
},
},
// ---- Axis: Parsers ------------------------------------------------------
// Per-item toggles (tri-state: null = inherit). Strips only when overridden,
// then re-emits one item.flag per toggled-on item.
parsers: {
initState: (fc) => {
const out = {};
for (const item of (fc.items || [])) out[item.id] = null;
return out;
},
deriveFromBase: (cell, fc, h) => {
const flags = (cell && cell.flags) || [];
const out = {};
for (const item of (fc.items || [])) {
const prefix = item.flag.split(/[\s=]/)[0];
out[item.id] = h.hasFlag(flags, prefix);
}
return out;
},
apply: ({ flags, env, value, fc, h, derived }) => {
const items = fc.items || [];
// Effective state per item: explicit > derived > false. Skip
// strip+emit when nothing differs from base.
const eff = {};
const baseOf = {};
for (const item of items) {
baseOf[item.id] = derived ? !!derived[item.id] : false;
const v = value[item.id];
eff[item.id] = (v === null || v === undefined) ? baseOf[item.id] : v;
}
const anyOverride = items.some((it) => eff[it.id] !== baseOf[it.id]);
if (!anyOverride) return { flags, env };
flags = h.stripFlagsByFirstToken(flags, ["--reasoning-parser", "--tool-call-parser"]);
const adds = [];
for (const item of items) {
if (eff[item.id]) adds.push(item.flag);
}
if (adds.length) flags = h.insertBeforeTail(flags, adds);
return { flags, env };
},
render: ({ axisId, value, setValue, fc, base, s, h, renderChip, derived }) => {
const visible = (fc.items || [])
.map((item) => ({ item, c: h.evaluateChip(item, base) }))
.filter(({ c }) => !c.hidden);
if (visible.length === 0) return null;
// Effective on/off: explicit pick > derived > off.
const effOn = (id) => {
const v = value[id];
if (v !== null && v !== undefined) return v;
if (derived && derived[id] !== undefined) return derived[id];
return false;
};
return (
<div key={axisId} style={s.card}>
<div style={s.compactRow}>
<span style={s.axisTitle}>Parsers</span>
{visible.map(({ item, c }) => (
<span key={item.id} style={s.field}>
{renderChip(item.label, effOn(item.id), true,
() => setValue({ ...value, [item.id]: !effOn(item.id) }),
{ disabled: c.disabled, disabledReason: c.disableReason })}
</span>
))}
</div>
</div>
);
},
},
// ---- Axis: Speculative Decoding -----------------------------------------
// Single-select. "current" = leave base untouched, "off" = strip (greedy),
// <other> = strip + splice option.flags.
speculative: {
initState: () => "current",
// Match base's `--speculative-*` set against each option. No spec flags
// → "off"; some but no match → "current".
deriveFromBase: (cell, fc) => {
const flags = (cell && cell.flags) || [];
const baseSpec = flags.filter((f) => {
const head = f.split(/[\s=]/)[0];
return head === "--speculative-algorithm"
|| head === "--speculative-num-steps"
|| head === "--speculative-eagle-topk"
|| head === "--speculative-num-draft-tokens"
// Adaptive draft depth is part of an EAGLE preset, not a
// separate knob: a base that carries it must strip it when
// another algorithm is picked, or the flag survives and the
// server warns it away (only EAGLE/EAGLE3 honor it).
|| head === "--speculative-adaptive"
|| head === "--speculative-dspark-block-size"
|| head === "--enable-linear-replayssm-spec"
|| head === "--linear-replayssm-cache-len"
|| head === "--speculative-ngram-max-bfs-breadth";
});
if (baseSpec.length === 0) return "off";
for (const opt of (fc.options || [])) {
if (!opt.flags || opt.flags.length !== baseSpec.length) continue;
const ok = opt.flags.every((pf) => baseSpec.includes(pf));
if (ok) return opt.id;
}
return "current";
},
apply: ({ flags, env, value, fc, sel, h, derived }) => {
if (value === "current") return { flags, env };
// No-op when the pick already matches base (preserves flag position).
if (derived && value === derived) return { flags, env };
const picked = (fc.options || []).find((p) => p.id === value);
if (picked && h.evaluateChip(picked, {
...sel,
dpAttnOn: h.hasFlag(flags, "--enable-dp-attention"),
}).disabled) {
return { flags, env };
}
flags = h.stripFlagsByFirstToken(flags, [
"--speculative-algorithm", "--speculative-num-steps",
"--speculative-eagle-topk", "--speculative-num-draft-tokens",
"--speculative-adaptive",
"--speculative-dspark-block-size", "--enable-linear-replayssm-spec",
"--linear-replayssm-cache-len",
"--speculative-ngram-max-bfs-breadth",
]);
const preset = (fc.options || []).find((p) => p.id === value);
if (preset?.flags?.length) flags = h.insertBeforeTail(flags, preset.flags);
return { flags, env };
},
render: ({ axisId, value, setValue, fc, base, s, h, renderChip, derived }) => {
const opts = fc.options || [];
if (!opts.length) return null;
// Display: explicit pick (!= "current") > derived.
const display = (value !== "current") ? value
: (derived ? derived : "current");
// Hide "current" when derive resolved to a real preset.
const hideCurrent = !!(derived && derived !== "current");
const visible = opts
.map((opt) => h.evaluateChip(opt, base))
.filter((c) => !c.hidden && !(hideCurrent && c.value === "current"));
if (visible.length === 0) return null;
// An option may carry a `note`: a prerequisite the reader must act on
// before the composed command runs at all (an algorithm whose support
// is not in the page's pinned image yet, a draft checkpoint to fetch).
// Shown only for the option in effect, so the card stays a chip row
// until the pick actually needs something.
const note = (visible.find((c) => c.value === display) || {}).note;
return (
<div key={axisId} style={s.card}>
<div style={s.compactRow}>
<span style={s.axisTitle}>Speculative</span>
{visible.map((c) => (
<span key={c.value} style={s.field}>
{renderChip(c.label, display, c.value,
() => setValue(c.value),
{ disabled: c.disabled, disabledReason: c.disableReason })}
</span>
))}
</div>
{note && <div style={s.axisNote}>{note}</div>}
</div>
);
},
},
// ---- Axis: PD Disaggregation --------------------------------------------
// Role (off/prefill/decode) + transfer backend + optional IB device.
// Owns the `--disaggregation-*` flags (unconditional strip). A backend may
// carry hw-gated env (transferBackends[].env + .envWhen).
pdDisagg: {
// The transport default is the config's first entry, so a model whose
// recipes standardize on one backend does not silently start on another.
initState: (fc) => ({
mode: "off",
transferBackend: (fc && (fc.transferBackends || [])[0] || {}).id || "mooncake",
ibDevice: "auto",
}),
apply: ({ flags, env, value, sel, fc, h }) => {
// The bootstrap port is the base cell's to choose — the router's
// --prefill positional has to match it — so carry it across the strip
// rather than dropping it and silently falling back to the default.
const bootstrapPort = h.findFlagArg(flags, "--disaggregation-bootstrap-port");
flags = h.stripFlagsByFirstToken(flags, [
"--disaggregation-mode", "--disaggregation-transfer-backend",
"--disaggregation-ib-device", "--disaggregation-bootstrap-port",
]);
const backends = fc.transferBackends || [];
// A config that omits `modes` has the role on the Deploy panel instead;
// this card then only tunes the transport for whatever role is selected.
const mode = (fc.modes || []).length
? value.mode
: ((sel && sel.pdMode) || "off");
if (mode === "prefill" || mode === "decode") {
// PD and some speculative algorithms cannot run together. Keep the
// PD card reachable for a speculative base recipe, then make the
// user's explicit PD-role selection win by removing the whole
// speculative flag family before composing the role command.
const specAlgorithm = (h.findFlagArg(
flags, "--speculative-algorithm") || "").toUpperCase();
if ((fc.incompatibleSpeculativeAlgorithms || []).includes(specAlgorithm)) {
flags = flags.filter((flag) =>
!flag.split(/[\s=]/)[0].startsWith("--speculative-"));
}
const backend = value.transferBackend || (backends[0] || {}).id || "mooncake";
const adds = [
`--disaggregation-mode ${mode}`,
`--disaggregation-transfer-backend ${backend}`,
];
// Re-emitted in the base cell's own order, so an untouched Prefill
// recipe renders byte-identical to the Deploy panel.
if (bootstrapPort) {
adds.push(`--disaggregation-bootstrap-port ${bootstrapPort}`);
}
if (value.ibDevice && value.ibDevice !== "auto") {
adds.push(`--disaggregation-ib-device ${value.ibDevice}`);
}
// A `modes[]` entry may declare `flags` / `env` that only the PD role
// it names needs (the prefill worker's balance policy, the decode
// worker's polling interval, ...). Strip the same heads first so the
// role's value wins over a base cell that sets one for its own
// reasons, instead of emitting the flag twice. This runs only inside
// the role branch: applyAllDeltas re-seeds from the base cell on every
// render, so a base flag is never left over from an earlier selection
// and must not be stripped when the role is Off.
const modeMeta = (fc.modes || []).find((m) => m.id === mode);
if (modeMeta && modeMeta.flags && modeMeta.flags.length) {
flags = h.stripFlagsByFirstToken(
flags, modeMeta.flags.map((f) => f.split(/[\s=]/)[0]));
adds.push(...modeMeta.flags);
}
// Single-host needs no --dist-init-addr: prefill/decode derive their
// ZMQ/dist ports from the role-specific --port (spaced 100 apart, see
// PD_PORTS), so the ranges don't overlap. Multi-node still gets a
// cross-node --dist-init-addr from the renderer.
flags = h.insertBeforeTail(flags, adds);
// Role-specific serving port so the router's prefill / decode targets
// line up (and prefill+decode don't collide on a single host).
const servePort = PD_PORTS[mode].serve;
flags = flags.map((f) =>
f.split(/[\s=]/)[0] === "--port" ? `--port ${servePort}` : f);
// Add the selected backend's env (gated by hw via `envWhen`), keeping
// any the base cell already carries in place. We don't strip base env
// (e.g. gb200 NCCL_*): a blanket strip would drop it when PD is off and
// show a spurious remove+add in the diff. apply is pure from baseEnv, so
// no stale backend env accumulates across renders.
const meta = backends.find((b) => b.id === backend);
if (meta && meta.env && meta.env.length) {
const gate = meta.envWhen;
const ok = !gate || Object.keys(gate).every(
(k) => (gate[k] || []).includes(sel[k]));
if (ok) env = [...env, ...meta.env.filter((e) => !env.includes(e))];
}
// Same for env declared on the selected role.
if (modeMeta && modeMeta.env && modeMeta.env.length) {
env = [...env, ...modeMeta.env.filter((e) => !env.includes(e))];
}
}
return { flags, env };
},
getRenderHints: (value, fc, context) => {
const specAlgorithm = (context.h.findFlagArg(
context.flags, "--speculative-algorithm") || "").toUpperCase();
if ((fc.incompatibleSpeculativeAlgorithms || []).includes(specAlgorithm)) {
return null;
}
if (value.mode === "prefill" || value.mode === "decode") {
return { pdMode: value.mode };
}
return null;
},
render: ({ axisId, value, setValue, fc, base, s, renderSelect }) => {
const setSlot = (k, v) => setValue({ ...value, [k]: v });
const showModes = (fc.modes || []).length > 0;
const showBackends = (fc.transferBackends || []).length > 0;
const showIb = (fc.ibDevices || []).length > 0;
if (!showModes && !showBackends && !showIb) return null;
return (
<div key={axisId} style={s.card}>
<div style={s.compactRow}>
<span style={s.axisTitle}>PD Disagg</span>
{showModes && (
<span style={s.field}>
<span style={s.fieldLabel}>Mode</span>
{renderSelect(value.mode, fc.modes,
(v) => setSlot("mode", v), base)}
</span>
)}
{showBackends && (
<span style={s.field}>
<span style={s.fieldLabel}>Transfer Backend</span>
{renderSelect(value.transferBackend, fc.transferBackends,
(v) => setSlot("transferBackend", v), base)}
</span>
)}
{showIb && (
<span style={s.field}>
<span style={s.fieldLabel}>IB Device</span>
{renderSelect(value.ibDevice, fc.ibDevices,
(v) => setSlot("ibDevice", v), base)}
</span>
)}
</div>
</div>
);
},
},
// ---- Axis: HiSparse (hierarchical sparse attention) ---------------------
// Enable + host_to_device_ratio. Owns `--enable-hisparse`/`--hisparse-config`
// plus fc.requiredFlags (unconditional strip, re-added when enabled).
// Decode-only: gated on PD-Disagg mode == "decode" in both render and apply.
hisparse: {
initState: (fc) => ({ enable: false, hostRatio: (fc && fc.defaultHostRatio) || null }),
apply: ({ flags, env, value, fc, h }) => {
const ownedHeads = [
"--enable-hisparse", "--hisparse-config",
...((fc.requiredFlags || []).map((f) => f.split(/\s/)[0])),
];
flags = h.stripFlagsByFirstToken(flags, ownedHeads);
// Decode gate: pdDisagg runs first and inserts this flag.
const isDecode = flags.includes("--disaggregation-mode decode");
if (value.enable && isDecode) {
const ratio = (value.hostRatio !== null && value.hostRatio !== undefined)
? value.hostRatio
: (fc.defaultHostRatio || 10);
const cfg = { ...(fc.config || {}), host_to_device_ratio: ratio };
const adds = [
...(fc.requiredFlags || []),
"--enable-hisparse",
`--hisparse-config '${JSON.stringify(cfg)}'`,
];
flags = h.insertBeforeTail(flags, adds);
}
return { flags, env };
},
render: ({ axisId, value, setValue, fc, base, s, renderChip, renderSelect }) => {
if (base.pdMode !== "decode") return null;
const setSlot = (k, v) => setValue({ ...value, [k]: v });
const hasRatios = (fc.hostRatios || []).length > 0;
return (
<div key={axisId} style={s.card}>
<div style={s.compactRow}>
<span style={s.axisTitle}>HiSparse</span>
{typeof fc.showWhen !== "function" && (
<span style={s.field}>
{renderChip("Enable", value.enable, true,
() => setSlot("enable", !value.enable))}
</span>
)}
{hasRatios && (
<span style={s.field}>
<span style={s.fieldLabel}>Host ratio</span>
{renderSelect(value.hostRatio, fc.hostRatios,
(v) => setSlot("hostRatio", v), base)}
</span>
)}
</div>
</div>
);
},
},
// ---- Axis: Hierarchical KV Cache ----------------------------------------
// Enable + optional backend + write policy. `null` inherits the base cell,
// so a verified HiCache recipe remains byte-identical until it is changed.
hicache: {
initState: () => ({ enable: null, backend: null, writePolicy: "auto" }),
deriveFromBase: (cell, fc, h) => {
const flags = (cell && cell.flags) || [];
return {
enable: h.hasFlag(flags, "--enable-hierarchical-cache"),
backend: h.findFlagArg(flags, "--hicache-storage-backend"),
writePolicy: h.findFlagArg(flags, "--hicache-write-policy") || "auto",
};
},
apply: ({ flags, env, value, fc, sel, h, derived }) => {
if (fc.excludesHw && sel && fc.excludesHw.includes(sel.hw)) return { flags, env };
// When the Deploy panel owns enablement (`showWhen`), the base already
// carries a complete, verified hicache recipe. Rebuilding it from this
// axis's own defaults would silently swap ratio/layout/io-backend, so
// only the two knobs this card actually exposes are touched.
if (typeof fc.showWhen === "function") {
const set = (name, val) => {
flags = h.stripFlagsByFirstToken(flags, [name]);
if (val) flags = h.insertBeforeTail(flags, [`${name} ${val}`]);
};
if (value.backend) set("--hicache-storage-backend", value.backend);
if (value.writePolicy && value.writePolicy !== "auto") {
set("--hicache-write-policy", value.writePolicy);
}
return { flags, env };
}
const hasOverride = value.enable !== null
|| value.backend !== null
|| (value.writePolicy && value.writePolicy !== "auto");
if (!hasOverride) return { flags, env };
const backendOptions = fc.backends || [];
const ownedHeads = [
"--enable-hierarchical-cache", "--hicache-ratio", "--hicache-size",
"--hicache-write-policy", "--hicache-mem-layout", "--hicache-io-backend",
"--hicache-storage-backend", "--hicache-storage-prefetch-policy",
"--hicache-storage-backend-extra-config",
...((fc.requiredFlags || []).map((f) => f.split(/\s/)[0])),
...backendOptions.flatMap((o) => (o.flags || []).map((f) => f.split(/\s/)[0])),
];
const ownedEnvKeys = [
...(fc.requiredEnv || []),
...backendOptions.flatMap((o) => o.env || []),
].map((e) => e.split("=")[0]);
flags = h.stripFlagsByFirstToken(flags, ownedHeads);
if (ownedEnvKeys.length) env = h.stripEnvByPrefix(env, ownedEnvKeys);
const enabled = value.enable !== null
? value.enable : !!(derived && derived.enable);
const backend = value.backend !== null
? value.backend
: ((derived && derived.backend) || fc.defaultBackend || null);
if (enabled) {
const isAmd = sel && /^mi\d/.test(sel.hw);
const pdMode = h.findFlagArg(flags, "--disaggregation-mode") || "off";
const pdBackend = h.findFlagArg(flags, "--disaggregation-transfer-backend");
const roleOverride = (fc.roleOverrides || []).find((item) => {
if (!item || item.mode !== pdMode) return false;
if (item.transferBackend && item.transferBackend !== pdBackend) return false;
return !item.when || h.matchConstraint(sel, item.when);
});
const amdIo = roleOverride || (isAmd && fc.amdIo);
const ratio = (amdIo && amdIo.ratio) || 2;
const useAmdIo = isAmd && amdIo;
const adds = [
"--enable-hierarchical-cache",
`--hicache-ratio ${ratio}`,
];
if (!useAmdIo) {
adds.push("--hicache-size 0");
}
// Per-model configs can declare fc.amdIo = { memLayout, ioBackend, ratio }
// for AMD ROCm overrides (e.g. page_first_direct + direct on MI355X).
// Default (NVIDIA): page_first_direct + direct, ratio 2.
if (useAmdIo) {
adds.push(`--hicache-mem-layout ${amdIo.memLayout}`,
`--hicache-io-backend ${amdIo.ioBackend}`);
} else if (backend) {
adds.push("--hicache-mem-layout page_first_direct",
"--hicache-io-backend direct");
}
const writePolicy = (value.writePolicy && value.writePolicy !== "auto")
? value.writePolicy : ((amdIo && amdIo.writePolicy) || "write_through");
adds.push(`--hicache-write-policy ${writePolicy}`);
// When amdStorageFileOnly is set, AMD emits storage flags only for "file".
if ((isAmd && fc.amdStorageFileOnly) ? backend === "file" : !!backend) {
adds.push(`--hicache-storage-backend ${backend}`,
`--hicache-storage-prefetch-policy ${(amdIo && amdIo.prefetchPolicy) || "wait_complete"}`);
} else if (amdIo && amdIo.prefetchPolicy) {
adds.push(`--hicache-storage-prefetch-policy ${amdIo.prefetchPolicy}`);
}
const backendOption = backendOptions.find((o) => o.id === backend);
adds.push(...(backendOption?.flags || []), ...(fc.requiredFlags || []));
flags = h.insertBeforeTail(flags, adds);
env = [
...env,
...(backendOption?.env || []),
...(fc.requiredEnv || []),
];
}
return { flags, env };
},
render: ({ axisId, value, setValue, fc, base, s, renderChip, renderSelect, derived }) => {
if (fc.excludesHw && fc.excludesHw.includes(base.hw)) return null;
const setSlot = (k, v) => setValue({ ...value, [k]: v });
const hasBackends = (fc.backends || []).length > 0;
const hasPolicies = (fc.writePolicies || []).length > 0;
const enabled = value.enable !== null
? value.enable : !!(derived && derived.enable);
const hasAutoBackend = (fc.backends || []).some((o) => o.id === null);
const backend = value.backend !== null
? value.backend
: (hasAutoBackend ? null : ((derived && derived.backend) || fc.defaultBackend || null));
const writePolicy = value.writePolicy !== "auto"
? value.writePolicy : ((derived && derived.writePolicy) || "auto");
return (
<div key={axisId} style={s.card}>
<div style={s.compactRow}>
<span style={s.axisTitle}>HiCache</span>
{typeof fc.showWhen !== "function" && (
<span style={s.field}>
{renderChip("Enable", enabled, true,
() => setSlot("enable", !enabled))}
</span>
)}
{hasBackends && (
<span style={s.field}>
<span style={s.fieldLabel}>Storage</span>
{renderSelect(backend, fc.backends,
(v) => setSlot("backend", v), base)}
</span>
)}
{hasPolicies && (
<span style={s.field}>
<span style={s.fieldLabel}>Write</span>
{renderSelect(writePolicy, fc.writePolicies,
(v) => setSlot("writePolicy", v), base)}
</span>
)}
</div>
</div>
);
},
},
// ---- Axis: Flag Selects (generic, config-declared) ----------------------
// A LIST of single-selects, each declared entirely in config:
// { id, title, stripPrefixes: [...], stripEnv?: [...],
// options: [{ id, label, flags?, env? }] }
// Same shape as `speculative` minus its hardcoded title + strip list: pick
// an option → strip the family, splice the option's flags. A flagless
// option is the "none" / accuracy-safe choice (matches a base carrying none
// of the family). Model-specific controls (KV-cache dtype, mamba scheduler
// strategy, …) live here as DATA — no per-feature engine code. Supports
// multiple selects per page. State: { [selectId]: optionId | null }
// (null = inherit base). `default` may be an option id or a function of the
// base selection (re-evaluated on every base change).
flagSelects: {
initState: (fc, base) => {
const out = {};
for (const spec of (fc || [])) {
const d = typeof spec.default === "function" ? spec.default(base) : spec.default;
out[spec.id] = d ?? null;
}
return out;
},
// Per select: match base's family flags (first token ∈ stripPrefixes)
// against each option's flags. A flagless option matches an empty family.
// Function-flag options (computed from the row values) never match.
deriveFromBase: (cell, fc) => {
const flags = (cell && cell.flags) || [];
const out = {};
for (const spec of (fc || [])) {
const prefixes = spec.stripPrefixes || [];
const fam = flags.filter((f) => prefixes.includes(f.split(/[\s=]/)[0]));
let hit = null;
for (const opt of (spec.options || [])) {
if (typeof opt.flags === "function") continue;
const of = opt.flags || [];
if (of.length === fam.length && of.every((x) => fam.includes(x))) {
hit = opt.id; break;
}
}
out[spec.id] = hit;
}
return out;
},
apply: ({ flags, env, value, fc, sel, h, derived }) => {
const evalBase = {
...(sel || {}),
dpAttnOn: h.hasFlag(flags, "--enable-dp-attention"),
pdMode: h.findFlagArg(flags, "--disaggregation-mode") || "off",
};
for (const spec of (fc || [])) {
// Hidden rows must not emit: showWhen also receives the sibling row
// values (explicit picks + derived), so a row can gate on another's pick.
if (typeof spec.showWhen === "function" && !spec.showWhen(sel, value, derived)) continue;
const v = value ? value[spec.id] : null;
if (v === null || v === undefined) continue; // inherit base
const d = derived ? derived[spec.id] : null;
if (v === d) continue; // already == base
const opt = (spec.options || []).find((o) => o.id === v);
if (!opt) continue;
if (h.evaluateChip(opt, evalBase).disabled) continue;
// `flags` may be a function of the whole row-value object (cross-row
// presets, e.g. preset x cluster-size). A function returning null
// means "leave the base untouched" (a true no-op Off).
const optFlags = typeof opt.flags === "function"
? opt.flags(value, evalBase)
: (opt.flags || []);
if (optFlags === null) continue;
// In-place substitution keeps the rendered diff minimal: a family the
// base already carries changes value at its original position; families
// stripped and not re-emitted vanish in place; only net-new flags
// append as a block before the tail.
const strip = new Set(spec.stripPrefixes || []);
const byTok = new Map();
for (const f of optFlags) {
const t = f.split(/[\s=]/)[0];
if (!byTok.has(t)) byTok.set(t, []);
byTok.get(t).push(f);
}
const consumed = new Set();
const next = [];
for (const f of flags) {
const t = f.split(/[\s=]/)[0];
if (byTok.has(t)) {
if (!consumed.has(t)) {
next.push(...byTok.get(t));
consumed.add(t);
}
} else if (!strip.has(t)) {
next.push(f);
}
}
const fresh = [];
for (const [t, fs] of byTok) {
if (!consumed.has(t)) fresh.push(...fs);
}
flags = fresh.length ? h.insertBeforeTail(next, fresh) : next;
// Option env (env-var toggles, preset env): strip spec.stripEnv plus
// every option's env keys, then add the picked option's — mirrors the
// MoE backend card's strip-then-emit shape.
const envKeys = [...(spec.stripEnv || [])];
for (const o of (spec.options || [])) {
for (const e of (o.env || [])) envKeys.push(e.split("=")[0]);
}
if (envKeys.length) env = h.stripEnvByPrefix(env, envKeys);
if (opt.env && opt.env.length) env = [...env, ...opt.env];
}
return { flags, env };
},
render: ({ axisId, value, setValue, fc, base, s, h, renderChip, derived }) => {
const cards = [];
for (const spec of (fc || [])) {
// Row-level gate: a select whose whole family is meaningless under the
// current base (e.g. draft tokens with speculation off) is not rendered.
// Also receives (rowValues, derived) for sibling-dependent rows.
if (typeof spec.showWhen === "function" && !spec.showWhen(base, value, derived)) continue;
const opts = (spec.options || [])
.map((o) => h.evaluateChip(o, base))
.filter((c) => !c.hidden);
if (!opts.length) continue;
const explicit = value ? value[spec.id] : null;
const display = (explicit !== null && explicit !== undefined)
? explicit : (derived ? derived[spec.id] : null);
// `control: "slider"` renders the same option list as a range input —
// for dense ordered scales (1..7) where chips are just noise. Option
// ORDER is the scale; the option id is still what apply() consumes.
if (spec.control === "slider") {
const idx = Math.max(0, opts.findIndex((c) => c.value === display));
const cur = opts[idx];
cards.push(
<div key={`${axisId}-${spec.id}`} style={s.card}>
<div style={s.compactRow}>
<span style={s.axisTitle}>{spec.title}</span>
<input
type="range"
min={0} max={opts.length - 1} step={1}
value={idx}
onChange={(e) => setValue({
...value,
[spec.id]: opts[Number(e.target.value)].value,
})}
style={{ flex: 1, minWidth: "120px", accentColor: "#D45D44" }}
/>
<span style={{ ...s.axisTitle, minWidth: "24px", textAlign: "right" }}>
{cur ? cur.label : "-"}
</span>
</div>
</div>
);
continue;
}
cards.push(
<div key={`${axisId}-${spec.id}`} style={s.card}>
<div style={s.compactRow}>
<span style={s.axisTitle}>{spec.title}</span>
{opts.map((c) => (
<span key={c.value} style={s.field}>
{renderChip(c.label, display, c.value,
() => setValue({ ...value, [spec.id]: c.value }),
{ disabled: c.disabled, disabledReason: c.disableReason })}
</span>
))}
</div>
</div>
);
}
return cards.length ? cards : null;
},
},
};
// ==========================================================================
// 6. Apply pipeline + render command
// ==========================================================================
// Thread the base cell's (flags, env) through every declared axis's apply,
// in declaration order; collect render hints (pdDisagg's role banner).
const applyAllDeltas = (baseFlags, baseEnv, allDeltas, sel, derivedMap) => {
let flags = [...baseFlags];
let env = [...(baseEnv || [])];
let pdMode = null;
for (const [axisId, handler] of Object.entries(AXIS_HANDLERS)) {
const fc = pgFeatures[axisId];
if (!fc) continue;
const value = allDeltas[axisId];
if (value === undefined) continue;
const derived = derivedMap ? derivedMap[axisId] : null;
const specAlgorithm = (findFlagArg(
flags, "--speculative-algorithm") || "").toUpperCase() || null;
const liveSel = { ...sel, specAlgorithm };
const out = handler.apply({ flags, env, value, fc, sel: liveSel, h: helpers, derived });
flags = out.flags;
env = out.env;
if (handler.getRenderHints) {
const hints = handler.getRenderHints(
value, fc, { flags, env, sel: liveSel, h: helpers }) || {};
if (hints.pdMode) pdMode = hints.pdMode;
}
}
return { flags, env, pdMode };
};
// Renderer (same shape as _deployment.jsx). pdMode prepends a PD-role
// banner; mode is "python" | "docker"; cellEnv is decoupled from cell so
// callers can pass a modified env (e.g. MegaMoE's stripEnv + append).
const renderCommandLines = (cell, flags, cellEnv, sel, envValues, pdMode = null, mode = "python") => {
const modelName = resolveModelName(sel);
let f = [...flags];
// Presets may replace the base cell's topology by emitting --nnodes
// directly (for example, B300 1-node -> large-scale 4/8-node). Use that
// effective value for Docker networking, hints, and the command banner.
const nnodesFlag = f.find((x) => x.split(/[\s=]/)[0] === "--nnodes");
const nnodesMatch = nnodesFlag && /^--nnodes(?:\s+|=)(\d+)$/.exec(nnodesFlag.trim());
const baseNnodes = sel.nodes !== undefined
? parseNnodes(sel.nodes)
: ((cell && cell.nnodes) || 1);
const nnodes = nnodesMatch ? parseInt(nnodesMatch[1], 10) : baseNnodes;
const multinode = nnodes > 1;
if (multinode && !f.some((x) => x.startsWith("--nnodes"))) {
// Insert the multi-node trio after the last parallelism flag (matches
// _deployment.jsx so untouched-base output is byte-identical).
const PARALLELISM_ANCHORS = ["--enable-dp-attention", "--dp-size", "--dp", "--tp-size", "--tp"];
let at = -1;
for (const anchor of PARALLELISM_ANCHORS) {
at = f.findIndex((x) => x.split(/[\s=]/)[0] === anchor);
if (at !== -1) break;
}
if (at === -1) at = f.findIndex((x) => x.startsWith("--model-path"));
// PD roles need distinct rendezvous ports so prefill+decode don't collide on a
// shared head host; non-PD multi-node keeps :20000 (matches _deployment.jsx).
const distPort = (pdMode && PD_PORTS[pdMode]) ? PD_PORTS[pdMode].dist : 20000;
f.splice(at + 1, 0,
`--nnodes ${nnodes}`,
`--node-rank {{NODE_RANK}}`,
`--dist-init-addr {{NODE0_IP}}:${distPort}`);
}
let cmd;
if (mode === "docker") {
// Image keyed by `hw|quant|strategy` (most specific), then `hw|quant`, then
// `hw`; `:dev` if unmapped (matches _deployment.jsx). The strategy key covers
// a tier that needs its own build (e.g. a spec-decoding preview image), so the
// playground base must resolve it too or it hands back an image that cannot
// run the command.
const di = config.dockerImages || {};
const image = di[`${sel.hw}|${sel.quant}|${sel.strategy}`]
|| di[`${sel.hw}|${sel.quant}`] || di[sel.hw] || "lmsysorg/sglang:dev";
const dockerRunCommand = typeof config.dockerRunCommand === "function"
? config.dockerRunCommand(sel)
: (config.dockerRunCommand || "sglang serve");
const portFlag = f.find((x) => x.split(/[\s=]/)[0] === "--port");
const servePort = portFlag ? portFlag.slice("--port".length).trim() : "{{PORT}}";
const hostNetwork = multinode || pdMode || (typeof config.dockerHostNetworkWhen === "function"
&& config.dockerHostNetworkWhen(sel, { flags: f, env: cellEnv }));
// Mirrors `multiNodeDockerFlags` on the _deployment.jsx HARDWARE_CATALOG
// (Mintlify strips module state, so the engines cannot share it).
const HW_MULTINODE_DOCKER_FLAGS = {
"dgx-spark": [
"--ulimit memlock=-1:-1", "--cap-add IPC_LOCK", "--device /dev/infiniband",
],
};
const fabricFlags = HW_MULTINODE_DOCKER_FLAGS[sel.hw] || [];
const dockerLines = [
"docker run --gpus all",
" --shm-size 32g",
hostNetwork ? " --network host" : ` -p ${servePort}:${servePort}`,
...(multinode ? fabricFlags.map((x) => " " + x) : []),
" -v ~/.cache/huggingface:/root/.cache/huggingface",
...(config.dockerMounts || []).map((mount) => ` -v ${mount}`),
` --env "HF_TOKEN={{HF_TOKEN}}"`,
...cellEnv.map((e) => ` --env ${e}`),
" --ipc=host",
` ${image}`,
` ${dockerRunCommand}`,
...f.map((x) => " " + x),
];
cmd = dockerLines.join(" \\\n");
} else {
const flagBlock = f.map((x) => " " + x).join(" \\\n");
const envBlock = cellEnv.length ? cellEnv.join(" \\\n") + " \\\n" : "";
cmd = `${envBlock}sglang serve \\\n${flagBlock}`;
}
if (multinode && config.multiNodeHints && config.multiNodeHints[sel.hw]) {
const hint = config.multiNodeHints[sel.hw]
.map((line) => (line.length ? "# " + line : "#")).join("\n");
cmd = `${hint}\n${cmd}`;
}
cmd = interpolate(cmd, envValues, modelName);
if (multinode) {
const header =
`# Multi-node (${nnodes} nodes). Run the same command on every node with:\n` +
`# <node-rank> = 0 on the head node, 1..${nnodes - 1} on the others\n` +
`# <node0-ip> = IP of the head node (reachable from all others)`;
cmd = `${header}\n${cmd}`;
}
if (pdMode === "prefill" || pdMode === "decode") {
const sibling = pdMode === "prefill" ? "decode" : "prefill";
const routerCfg = config.playgroundFeatures
&& config.playgroundFeatures.pdDisagg
&& config.playgroundFeatures.pdDisagg.router;
const routerPort = (routerCfg && routerCfg.port) || 8000;
const routerLine = routerCfg
? `# then front BOTH with the Router shown below.\n`
+ `# Client traffic (cURL) targets the router (:${routerPort}), not this role server.`
: `# then front BOTH with a router; client traffic targets the router, not this role server.`;
const hicacheCfg = config.playgroundFeatures
&& config.playgroundFeatures.hicache;
const pdBackend = findFlagArg(f, "--disaggregation-transfer-backend");
const hicacheEnabled = f.some((x) => x === "--enable-hierarchical-cache");
const hicacheNotice = hicacheEnabled && hicacheCfg
? (hicacheCfg.notices || []).find((item) => {
if (!item || item.mode !== pdMode) return false;
if (item.transferBackend && item.transferBackend !== pdBackend) return false;
return !item.when || matchConstraint(sel, item.when);
})
: null;
const noticeLine = hicacheNotice && hicacheNotice.text
? `# Note: ${hicacheNotice.text}\n` : "";
const banner =
`# === PD Disaggregation: ${pdMode.toUpperCase()} role ===\n` +
noticeLine +
`# Runs the ${pdMode} server. Also run the ${sibling} role on its peer host,\n` +
routerLine;
cmd = `${banner}\n${cmd}`;
}
return cmd;
};
// ==========================================================================
// 7. Diff (line-level, true LCS)
// ==========================================================================
// DP LCS + backtrace → unchanged / added / removed lines. Full LCS (not
// greedy) because apply may reorder flags; greedy would drop shared lines
// around a swap. Commands are ~15 lines so O(m·n) is trivial.
const computeDiff = (baseStr, pgStr) => {
const a = baseStr.split("\n");
const b = pgStr.split("\n");
const m = a.length, n = b.length;
const dp = Array(m + 1).fill(null).map(() => new Array(n + 1).fill(0));
for (let i = 1; i <= m; i++) {
for (let j = 1; j <= n; j++) {
if (a[i - 1] === b[j - 1]) dp[i][j] = dp[i - 1][j - 1] + 1;
else dp[i][j] = Math.max(dp[i - 1][j], dp[i][j - 1]);
}
}
const out = [];
let i = m, j = n;
while (i > 0 || j > 0) {
if (i > 0 && j > 0 && a[i - 1] === b[j - 1]) {
out.unshift({ line: a[i - 1], kind: "unchanged" });
i--; j--;
} else if (j > 0 && (i === 0 || dp[i][j - 1] >= dp[i - 1][j])) {
out.unshift({ line: b[j - 1], kind: "added" });
j--;
} else {
out.unshift({ line: a[i - 1], kind: "removed" });
i--;
}
}
return out;
};
// ==========================================================================
// 7b. Verified-cell submission helpers
// ==========================================================================
// Format a cell object as the cookbook config does, for paste into
// `cells: [...]`. Keeps {{MODEL_NAME}} etc. as raw placeholders.
const serializeCell = (sel, env, flags) => {
const matchEntries = [
`hw: ${JSON.stringify(sel.hw)}`,
`variant: ${JSON.stringify(sel.variant)}`,
`quant: ${JSON.stringify(sel.quant)}`,
`strategy: ${JSON.stringify(sel.strategy)}`,
`nodes: ${JSON.stringify(sel.nodes)}`,
].join(", ");
const fmtList = (items) => {
if (!items || items.length === 0) return "[]";
const lines = items.map((s) => ` ${JSON.stringify(s)},`).join("\n");
return `[\n${lines}\n ]`;
};
return [
" {",
` match: { ${matchEntries} },`,
" verified: true,",
` env: ${fmtList(env)},`,
` flags: ${fmtList(flags)},`,
" },",
].join("\n");
};
// GitHub Issue prefill URL. Query keys must match the `id:` values in
// .github/ISSUE_TEMPLATE/3-playground-verified-cell.yml. `config.github`
// overrides the repo/template; defaults match the SGLang repo.
const buildSubmitUrl = (sel, fields) => {
const gh = (config.github) || {};
const owner = gh.owner || "sgl-project";
const repo = gh.repo || "sglang";
const tmpl = gh.issueTemplate || "3-playground-verified-cell.yml";
const cookbookModel = gh.cookbookModel || "deepseek-ai/deepseek-v4";
const combo = `${sel.hw} / ${sel.variant} / ${sel.quant} / ${sel.strategy} / ${sel.nodes}`;
const params = new URLSearchParams({
template: tmpl,
title: `[Playground] Verified cell: ${combo}`,
model: cookbookModel,
combination: combo,
"cell-snippet": fields.cellSnippet || "",
"existing-cell": fields.existingCell || "",
"sglang-version": fields.sglangVersion || "",
"bench-result": fields.benchResult || "",
notes: fields.notes || "",
});
return `https://github.com/${owner}/${repo}/issues/new?${params.toString()}`;
};
// ==========================================================================
// 8. Style helper (dark-mode-aware)
// ==========================================================================
const makeStyles = (isDark) => ({
container: { maxWidth: "900px", margin: "0 auto", display: "flex", flexDirection: "column", gap: "6px" },
card: {
padding: "6px 10px",
border: `1px solid ${isDark ? "#374151" : "#e5e7eb"}`,
borderLeft: `3px solid ${isDark ? "#FDBA74" : "#FB923C"}`,
borderRadius: "4px",
background: isDark ? "#1f2937" : "#fff",
},
cardStack: { display: "flex", flexDirection: "column", gap: "6px" },
baseStrip: {
padding: "8px 12px",
borderRadius: "4px",
background: isDark ? "#064e3b" : "#d1fae5",
color: isDark ? "#a7f3d0" : "#065f46",
fontSize: "12px",
display: "flex", alignItems: "center", gap: "10px",
},
title: { fontSize: "13px", fontWeight: "600", color: isDark ? "#e5e7eb" : "inherit", marginBottom: "8px" },
compactRow: {
display: "flex", flexWrap: "wrap", alignItems: "center",
gap: "10px", rowGap: "4px",
},
axisTitle: {
fontSize: "12px", fontWeight: 700,
color: isDark ? "#FDBA74" : "#C2410C",
letterSpacing: "0.02em",
minWidth: "100px", flexShrink: 0,
},
field: { display: "inline-flex", alignItems: "center", gap: "4px" },
fieldLabel: {
fontSize: "11px", fontWeight: 500,
color: isDark ? "#9ca3af" : "#6b7280",
},
select: {
padding: "2px 6px",
border: `1px solid ${isDark ? "#4b5563" : "#d1d5db"}`,
borderRadius: "3px",
fontSize: "12px",
background: isDark ? "#111827" : "#fff",
color: isDark ? "#e5e7eb" : "#111827",
cursor: "pointer",
lineHeight: "1.4",
},
rowFlex: { display: "flex", flexWrap: "wrap", gap: "6px", alignItems: "center", flex: 1 },
subRow: { display: "flex", alignItems: "center", gap: "10px" },
subLabel: {
fontSize: "11px", fontWeight: 600,
color: isDark ? "#9ca3af" : "#6b7280",
minWidth: "96px", flexShrink: 0,
letterSpacing: "0.02em",
},
chipRow: { display: "flex", flexWrap: "wrap", gap: "6px", flex: 1 },
chip: {
padding: "3px 9px",
border: `1px solid ${isDark ? "#9ca3af" : "#d1d5db"}`,
borderRadius: "3px",
cursor: "pointer",
fontSize: "12px",
userSelect: "none",
background: isDark ? "#374151" : "#fff",
color: isDark ? "#e5e7eb" : "inherit",
textAlign: "center",
},
// Terracotta matches _deployment.jsx's selected button.
chipChecked: {
background: "#D45D44", color: "white", borderColor: "#D45D44",
},
chipDisabled: { cursor: "not-allowed", opacity: 0.4 },
commandWrap: {
position: "relative",
background: isDark ? "#111827" : "#f5f5f5",
borderRadius: "6px",
border: `1px solid ${isDark ? "#374151" : "#e5e7eb"}`,
overflow: "hidden",
},
commandHeader: {
display: "flex", flexWrap: "wrap", justifyContent: "space-between", alignItems: "center",
gap: "6px 10px",
padding: "6px 10px",
borderBottom: `1px solid ${isDark ? "#374151" : "#e5e7eb"}`,
background: isDark ? "#1f2937" : "#fafafa",
},
commandPre: {
padding: "12px 16px",
fontFamily: "'Menlo', 'Monaco', 'Courier New', monospace",
fontSize: "12px", lineHeight: "1.5",
color: isDark ? "#e5e7eb" : "#374151",
whiteSpace: "pre-wrap", overflowX: "auto", margin: 0,
},
// Amber callout for a prerequisite an axis option carries — rendered
// inside the axis card, so it reads as a condition on the pick rather
// than on the composed command.
axisNote: {
margin: "6px 0 0", padding: "6px 10px", borderRadius: "6px",
fontSize: "11px", lineHeight: "1.45",
background: isDark ? "#78350f" : "#fef3c7",
color: isDark ? "#fde68a" : "#92400e",
border: `1px solid ${isDark ? "#92400e" : "#fcd34d"}`,
},
// Amber callout under the playground command when the effective (post-
// override) command turns speculative decoding on without setting
// --max-running-requests (SGLang then caps it at 48).
mtpWarn: {
margin: "8px 0 0", padding: "8px 12px", borderRadius: "8px",
fontSize: "12px", lineHeight: "1.45",
background: isDark ? "#78350f" : "#fef3c7",
color: isDark ? "#fde68a" : "#92400e",
border: `1px solid ${isDark ? "#92400e" : "#fcd34d"}`,
},
diffLineUnchanged: { display: "block" },
diffLineAdded: {
display: "block",
background: isDark ? "rgba(16,185,129,0.15)" : "rgba(16,185,129,0.18)",
color: isDark ? "#a7f3d0" : "#065f46",
borderLeft: `3px solid #10b981`,
paddingLeft: "8px", marginLeft: "-8px",
},
diffLineRemoved: {
display: "block",
background: isDark ? "rgba(239,68,68,0.10)" : "rgba(239,68,68,0.10)",
color: isDark ? "#fca5a5" : "#991b1b",
textDecoration: "line-through",
opacity: 0.7,
borderLeft: `3px solid #ef4444`,
paddingLeft: "8px", marginLeft: "-8px",
},
// Two-state badge — matches _deployment.jsx's verified/unverified badge.
badge: (verified) => ({
display: "inline-flex", alignItems: "center", gap: "6px",
padding: "2px 8px", borderRadius: "10px",
background: verified ? (isDark ? "#064e3b" : "#d1fae5")
: (isDark ? "#78350f" : "#fef3c7"),
color: verified ? (isDark ? "#a7f3d0" : "#065f46")
: (isDark ? "#fde68a" : "#92400e"),
fontSize: "11px", fontWeight: 600,
}),
badgeDot: (verified) => ({
width: "8px", height: "8px", borderRadius: "50%",
background: verified ? "#10b981" : "#f59e0b",
}),
iconButton: {
padding: "4px 10px",
border: `1px solid ${isDark ? "#4b5563" : "#d1d5db"}`,
borderRadius: "4px",
background: isDark ? "#1f2937" : "#fff",
color: isDark ? "#e5e7eb" : "#374151",
fontSize: "11px", fontWeight: 500, cursor: "pointer",
display: "inline-flex", alignItems: "center", gap: "4px",
},
iconRow: { display: "inline-flex", flexWrap: "wrap", gap: "6px" },
runModeWrap: {
display: "inline-flex",
border: `1px solid ${isDark ? "#4b5563" : "#d1d5db"}`,
borderRadius: "10px",
overflow: "hidden",
fontSize: "11px", fontWeight: 600,
userSelect: "none",
},
runModeChip: (active) => ({
padding: "2px 10px", cursor: "pointer",
background: active ? (isDark ? "#1f2937" : "#fff") : "transparent",
color: active ? (isDark ? "#e5e7eb" : "#111827") : (isDark ? "#9ca3af" : "#6b7280"),
borderRight: `1px solid ${isDark ? "#4b5563" : "#d1d5db"}`,
}),
runModeChipLast: (active) => ({
padding: "2px 10px", cursor: "pointer",
background: active ? (isDark ? "#1f2937" : "#fff") : "transparent",
color: active ? (isDark ? "#e5e7eb" : "#111827") : (isDark ? "#9ca3af" : "#6b7280"),
}),
headerLeft: { display: "inline-flex", flexWrap: "wrap", alignItems: "center", gap: "8px" },
// Native <dialog> in top-layer mode (.showModal()) escapes Mintlify's
// `container-type: inline-size` trap that catches plain fixed-position
// modals. ::backdrop can't be styled inline (injected via useEffect).
dialog: {
background: isDark ? "#1f2937" : "#fff",
color: isDark ? "#e5e7eb" : "#111827",
borderRadius: "8px", padding: "20px",
maxWidth: "720px", width: "92%",
maxHeight: "calc(100vh - 80px)", overflowY: "auto",
border: `1px solid ${isDark ? "#374151" : "#e5e7eb"}`,
boxShadow: "0 10px 25px rgba(0,0,0,0.25)",
margin: "auto",
},
modalHeader: { display: "flex", justifyContent: "space-between", alignItems: "center", marginBottom: "12px" },
modalTitle: { fontSize: "15px", fontWeight: 600 },
modalCloseBtn: {
background: "transparent", border: "none", color: "inherit",
fontSize: "20px", cursor: "pointer", padding: "0 6px", lineHeight: 1,
},
formField: { display: "flex", flexDirection: "column", gap: "4px", marginBottom: "10px" },
formLabel: { fontSize: "12px", fontWeight: 500, color: isDark ? "#9ca3af" : "#4b5563" },
formInput: {
padding: "6px 10px", fontSize: "13px",
border: `1px solid ${isDark ? "#4b5563" : "#d1d5db"}`,
borderRadius: "4px",
background: isDark ? "#111827" : "#fff",
color: isDark ? "#e5e7eb" : "#111827",
fontFamily: "'Menlo', 'Monaco', 'Courier New', monospace",
},
sectionHeading: {
fontSize: "12px", fontWeight: 600, textTransform: "uppercase",
letterSpacing: "0.04em",
color: isDark ? "#9ca3af" : "#6b7280",
margin: "12px 0 6px 0",
},
primaryBtn: {
padding: "6px 14px",
background: isDark ? "#FDBA74" : "#FB923C",
color: isDark ? "#7C2D12" : "white",
border: "none", borderRadius: "4px", cursor: "pointer",
fontSize: "13px", fontWeight: 500,
},
resetBtn: {
marginLeft: "auto", padding: "2px 8px", fontSize: "11px",
border: `1px solid ${isDark ? "#4b5563" : "#d1d5db"}`,
borderRadius: "3px",
background: "transparent",
color: isDark ? "#9ca3af" : "#6b7280",
cursor: "pointer",
},
switchBaseBtn: {
padding: "2px 8px", fontSize: "11px", fontWeight: 600,
border: `1px solid ${isDark ? "#FDBA74" : "#FB923C"}`,
borderRadius: "3px",
background: "transparent",
color: isDark ? "#FDBA74" : "#C2410C",
cursor: "pointer",
},
// Annotation next to the verified pill when the command matches a
// sibling cell (different strategy).
matchedHint: {
fontSize: "11px",
color: isDark ? "#9ca3af" : "#6b7280",
marginLeft: "8px",
display: "inline-flex", alignItems: "center", gap: "4px",
},
matchedSwitchBtn: {
marginLeft: "4px",
background: "transparent",
border: "none",
padding: 0,
color: isDark ? "#FDBA74" : "#C2410C",
cursor: "pointer",
fontSize: "11px", fontWeight: 600,
textDecoration: "underline",
textUnderlineOffset: "2px",
},
});
// ==========================================================================
// 9. React state + effects
// ==========================================================================
const [isDark, setIsDark] = useState(false);
useEffect(() => {
const check = () => {
const html = document.documentElement;
setIsDark(
html.classList.contains("dark") ||
html.getAttribute("data-theme") === "dark" ||
html.style.colorScheme === "dark"
);
};
check();
const observer = new MutationObserver(check);
observer.observe(document.documentElement, {
attributes: true,
attributeFilter: ["class", "data-theme", "style"],
});
return () => observer.disconnect();
}, []);
// Env / placeholder values, shared with _deployment.jsx via STORAGE_KEY.
const [env, setEnv] = useState(() => placeholderDefaults(config.placeholders));
useEffect(() => {
try {
const raw = window.localStorage.getItem(STORAGE_KEY);
if (raw) {
const parsed = JSON.parse(raw);
setEnv({ ...placeholderDefaults(config.placeholders), ...parsed });
}
} catch {}
}, []);
const saveEnv = (next) => {
setEnv(next);
try { window.localStorage.setItem(STORAGE_KEY, JSON.stringify(next)); } catch {}
};
// Base selection — live-linked to the Deployment panel via URL hash + custom event
// (history.replaceState doesn't fire hashchange, hence the event too).
const overlayDefaults = () => {
const out = {};
for (const d of (config.overlayDims || [])) {
const opts = d.options || [];
out[d.id] = d.default !== undefined ? d.default : ((opts[0] && opts[0].id) || "");
}
return out;
};
const baseFallback = () => ({ ...config.cells[0].match, ...overlayDefaults() });
const initialBaseFromHash = () => {
const fallback = baseFallback();
if (typeof window === "undefined") return { ...fallback };
const raw = window.location.hash.replace(/^#/, "");
if (!raw) return { ...fallback };
const params = new URLSearchParams(raw);
const out = { ...fallback };
params.forEach((value, key) => { if (key in out) out[key] = value; });
return out;
};
const [base, setBase] = useState(() => initialBaseFromHash());
useEffect(() => {
const onHash = () => setBase(initialBaseFromHash());
const onSelEvent = (e) => {
const fallback = baseFallback();
const incoming = (e && e.detail) || {};
const next = { ...fallback };
for (const k of Object.keys(next)) {
if (incoming[k] !== undefined) next[k] = incoming[k];
}
setBase(next);
};
window.addEventListener("hashchange", onHash);
window.addEventListener("sglang-deploy-sel", onSelEvent);
return () => {
window.removeEventListener("hashchange", onHash);
window.removeEventListener("sglang-deploy-sel", onSelEvent);
};
}, []);
// Calculator-computed --mamba-full-memory-ratio pair (K3): `eff` matches the
// composed command (with playground overrides), `base` matches the base view.
// Rendered into the command views below; never part of the broadcast flags.
const [pgRatios, setPgRatios] = useState({ eff: null, base: null });
useEffect(() => {
const onRatio = (e) => setPgRatios({
eff: (e.detail && e.detail.ratio) || null,
base: (e.detail && (e.detail.baseRatio || e.detail.ratio)) || null,
});
window.addEventListener("sglang-k3-mamba-ratio", onRatio);
return () => window.removeEventListener("sglang-k3-mamba-ratio", onRatio);
}, []);
// Deltas: one slot per declared axis.
const initialDeltas = () => {
const out = {};
for (const [axisId, handler] of Object.entries(AXIS_HANDLERS)) {
const fc = pgFeatures[axisId];
if (fc) out[axisId] = handler.initState(fc, base);
}
return out;
};
const [deltas, setDeltas] = useState(initialDeltas);
// Picking a different base is picking a different starting point, so the
// playground goes back to inheriting everything. Carrying overrides across a
// base change silently mixes knobs from a config the reader already left.
useEffect(() => {
setDeltas(initialDeltas());
}, [Object.keys(base).sort().map((k) => `${k}=${base[k]}`).join("&")]);
const [modal, setModal] = useState(null); // 'curl' | 'env' | 'submit' | null
// Callback-ref: show on mount. .showModal() (not .show()) gives the top
// layer plus native ESC / focus-trap / scroll-lock.
const openDialog = (el) => {
if (el && !el.open) {
try { el.showModal(); } catch { /* already open or unsupported */ }
}
};
// Click-outside-to-close: backdrop clicks hit the dialog element with
// coordinates outside its rect.
const onDialogClick = (e) => {
if (e.target !== e.currentTarget) return;
const r = e.currentTarget.getBoundingClientRect();
const { clientX: x, clientY: y } = e;
if (x < r.left || x > r.right || y < r.top || y > r.bottom) setModal(null);
};
// ::backdrop can't be styled inline — inject one dim-overlay rule.
useEffect(() => {
const ID = "__playground_dialog_backdrop";
if (document.getElementById(ID)) return undefined;
const style = document.createElement("style");
style.id = ID;
style.textContent = `dialog::backdrop { background: rgba(0, 0, 0, 0.5); }`;
document.head.appendChild(style);
return () => { const el = document.getElementById(ID); if (el) el.remove(); };
}, []);
const [copied, setCopied] = useState(false);
const [curlCopied, setCurlCopied] = useState(false);
const [routerCopied, setRouterCopied] = useState(false);
const [envDraft, setEnvDraft] = useState(env);
useEffect(() => { if (modal === "env") setEnvDraft(env); }, [modal, env]);
const [runMode, setRunMode] = useState("python");
// Submit-verified-cell modal state, reset each time the modal opens.
const [submitDraft, setSubmitDraft] = useState({
sglangVersion: "", benchResult: "", notes: "",
});
const [submitAttest, setSubmitAttest] = useState({
ranCommand: false, reachedReady: false, outputCorrect: false,
});
useEffect(() => {
if (modal === "submit") {
setSubmitDraft({ sglangVersion: "", benchResult: "", notes: "" });
setSubmitAttest({ ranCommand: false, reachedReady: false, outputCorrect: false });
}
}, [modal]);
// ==========================================================================
// 10. Derived values
// ==========================================================================
const s = makeStyles(isDark);
const baseCell = withOverlay(findCell(config.cells, base), base);
const modelName = resolveModelName(base);
// Per-axis state recovered from the base cell's flags (deriveFromBase).
const derivedMap = {};
if (baseCell) {
for (const [axisId, handler] of Object.entries(AXIS_HANDLERS)) {
const fc = pgFeatures[axisId];
if (!fc || !handler.deriveFromBase) continue;
derivedMap[axisId] = handler.deriveFromBase(baseCell, fc, helpers);
}
}
// Cross-axis facts folded into the `base` handed to chip-constraint
// matching, so `hide`/`disable` can react to another axis's live state
// (render path only; the raw base stays untouched).
// dpAttnOn — effective DP-Attention resolves to "on" (positive degree
// or true), explicit override else derived-from-base.
// cpOn — effective prefill-CP resolves to "on" (degree > 1),
// explicit override else derived-from-base.
// cpStrategy — effective CP layout ("zigzag" / "interleave"; explicit
// override else baked-in-base else "interleave").
// cpSizeTarget — the only enable-able CP size (runtime derives
// attn_cp_size = tp/dp); null when TP is unknown or the cp
// knob opts out via `freeSize: true`.
// effTp — effective TP degree (override else derived).
// pdMode — live PD-Disagg role; gates the decode-only HiSparse card.
const attnDelta = deltas.attention || {};
const attnDerived = derivedMap.attention || {};
const attnKnobs = ((pgFeatures.attention || {}).knobs) || [];
const effTp = (attnDelta.tp !== null && attnDelta.tp !== undefined)
? attnDelta.tp
: (attnDerived.tp !== undefined ? attnDerived.tp : null);
// A picked value whose entry is disabled under the live facts is skipped
// by apply() and must not count as "on" (stale-state corner: e.g. CP=8
// picked, then TP switched to 4). Only explicit picks can go stale;
// derived-from-base values are always real.
const staleExplicit = (knobId, picked) => {
const knob = attnKnobs.find((k) => k.id === knobId);
const e = knob ? findEntry(knob.values || [], picked) : null;
return !!(e !== null && e !== undefined
&& evaluateChip(e, { ...base, effTp }).disabled);
};
const effDpAttn = (attnDelta.dpAttn !== null && attnDelta.dpAttn !== undefined)
? (staleExplicit("dpAttn", attnDelta.dpAttn) ? null : attnDelta.dpAttn)
: (attnDerived.dpAttn !== undefined ? attnDerived.dpAttn : null);
const dpAttnOn = (effDpAttn === true)
|| (typeof effDpAttn === "number" && effDpAttn > 0);
// Runtime derivation attn_cp_size = tp/dp: with DP-Attention off, the only
// enable-able CP size is TP. With DP-Attention on, sizes are NOT gated —
// CP + DP-Attention is an allowed experiment covered by a warning hint
// (null also when TP is unknown or the cp knob opts out via `freeSize`).
const dpDegEff = (typeof effDpAttn === "number" && effDpAttn > 0)
? effDpAttn : 1;
const cpKnobFreeSize = !!(attnKnobs.find((k) => k.id === "cp") || {}).freeSize;
const cpSizeTarget =
(!cpKnobFreeSize && dpDegEff === 1
&& typeof effTp === "number" && effTp > 0)
? effTp : null;
const cpSizeStale = (v) => typeof v === "number" && v > 1
&& cpSizeTarget !== null && v !== cpSizeTarget;
const effCp = (attnDelta.cp !== null && attnDelta.cp !== undefined)
? ((staleExplicit("cp", attnDelta.cp) || cpSizeStale(attnDelta.cp))
? null : attnDelta.cp)
: (attnDerived.cp !== undefined ? attnDerived.cp : null);
const cpOn = typeof effCp === "number" && effCp > 1;
const cpStrategy = ((attnDelta.cpStrategy
&& !staleExplicit("cpStrategy", attnDelta.cpStrategy))
? attnDelta.cpStrategy
: (attnDerived.cpStrategy !== undefined ? attnDerived.cpStrategy : null))
|| "interleave";
const constraintEffective = baseCell
? applyAllDeltas(baseCell.flags, baseCell.env, deltas, base, derivedMap)
: null;
const pdCardOwnsMode = ((pgFeatures.pdDisagg && pgFeatures.pdDisagg.modes) || []).length > 0;
const pdMode = pdCardOwnsMode
? ((constraintEffective && constraintEffective.pdMode) || "off")
: (base.pdMode || "off");
const specAlgorithm = constraintEffective
? ((findFlagArg(constraintEffective.flags,
"--speculative-algorithm") || "").toUpperCase() || null)
: null;
const constraintBase = {
...base, dpAttnOn, cpOn, cpStrategy, cpSizeTarget, effTp, pdMode,
specAlgorithm,
};
let baseCommand = "";
let playgroundCommand = "";
let diffLines = [];
let pgFlagsLatest = [];
let pgEnvLatest = [];
// Render-only ratio injection (before the host/port tail); skipped if the
// flags already carry the family, or the base cell sizes the pool explicitly
// with --max-mamba-cache-size (the ratio would contradict its slot count).
const withRatio = (fl, value) => {
if (!value) return fl;
if (fl.some((f) =>
f.startsWith("--mamba-full-memory-ratio") || f.startsWith("--max-mamba-cache-size"))) return fl;
const out = [...fl];
const line = `--mamba-full-memory-ratio ${value}`;
const i = out.findIndex((f) => f.startsWith("--host"));
if (i >= 0) out.splice(i, 0, line);
else out.push(line);
return out;
};
if (baseCell) {
baseCommand = renderCommandLines(baseCell, withRatio(baseCell.flags, pgRatios.base), baseCell.env, base, env, null, runMode);
const { flags: pgFlags, env: pgEnv, pdMode } = applyAllDeltas(baseCell.flags, baseCell.env, deltas, base, derivedMap);
pgFlagsLatest = pgFlags;
pgEnvLatest = pgEnv;
playgroundCommand = renderCommandLines(baseCell, withRatio(pgFlags, pgRatios.eff), pgEnv, base, env, pdMode, runMode);
diffLines = computeDiff(baseCommand, playgroundCommand);
}
// Broadcast both configs for outside consumers (the mamba ratio calculator):
// `baseFlags`/`baseEnv` = cell + Deploy overlays (what the Deploy command
// shows); `flags`/`env` = that plus playground overrides. Keyed on content
// so re-renders don't spam events.
const effectiveKey =
pgFlagsLatest.join("\n") + " " + pgEnvLatest.join("\n") + " " +
(baseCell ? baseCell.flags.join("\n") + " " + baseCell.env.join("\n") : "");
useEffect(() => {
if (typeof window === "undefined" || !baseCell) return;
window.dispatchEvent(
new CustomEvent("sglang-k3-effective-config", {
detail: {
flags: pgFlagsLatest,
env: pgEnvLatest,
baseFlags: baseCell.flags,
baseEnv: baseCell.env,
},
})
);
}, [effectiveKey]);
// Cross-cell verified detection: the emitted (env, flags) may match the
// base cell itself or a sibling (different strategy). A sibling match
// still shows Verified, plus a "switch base" link.
const matchedCell = baseCell
? findMatchingCell(config.cells, base, pgEnvLatest, pgFlagsLatest)
: null;
const playgroundVerified = !!(matchedCell && matchedCell.verified);
const matchedSiblingCell = (matchedCell
&& DIMENSIONS.some((d) => matchedCell.match[d] !== base[d]))
? matchedCell : null;
const pgSpecAlgoFlag = pgFlagsLatest.find(
(f) => f.split(/[\s=]/)[0] === "--speculative-algorithm");
const pgSpecHint =
!!pgSpecAlgoFlag &&
!pgFlagsLatest.some((f) => f.split(/[\s=]/)[0] === "--max-running-requests");
const specAlgoLabels = {
EAGLE: "MTP", EAGLE3: "MTP", FROZEN_KV_MTP: "MTP",
DSPARK: "DSpark", DFLASH: "DFlash", NGRAM: "N-gram",
STANDALONE: "standalone draft",
};
const pgSpecAlgoValue = pgSpecAlgoFlag
? (pgSpecAlgoFlag.split(/[\s=]/).filter(Boolean)[1] || "") : "";
const pgSpecAlgoName = specAlgoLabels[pgSpecAlgoValue.toUpperCase()]
|| pgSpecAlgoValue || "MTP";
// Interleave prefill-CP + DP-Attention hint on the EFFECTIVE command:
// deliberately allowed (combined support is planned upstream), but current
// releases assert dp_size == 1 for the interleave layout at startup.
const pgCpDpHint =
cpEnabledIn(pgFlagsLatest)
&& (bakedCpStrategy(pgFlagsLatest) || "interleave") === "interleave"
&& pgFlagsLatest.some((f) => f.split(/[\s=]/)[0] === "--enable-dp-attention");
// Submission snippets: proposed cell + existing cell at the same match.
const proposedCellSnippet = baseCell
? serializeCell(base, pgEnvLatest, pgFlagsLatest) : "";
const existingCellSnippet = baseCell
? serializeCell(base, baseCell.env || [], baseCell.flags) : "";
const submitUrl = baseCell ? buildSubmitUrl(base, {
cellSnippet: proposedCellSnippet,
existingCell: existingCellSnippet,
sglangVersion: submitDraft.sglangVersion,
benchResult: submitDraft.benchResult,
notes: submitDraft.notes,
}) : "";
const submitReady =
submitAttest.ranCommand && submitAttest.reachedReady && submitAttest.outputCorrect
&& submitDraft.sglangVersion.trim().length > 0;
// PD-Disagg router, if configured. When a PD role is active, cURL retargets
// to the router port and a companion router block renders below the command.
const pdRouter = (pdMode !== "off"
&& config.playgroundFeatures
&& config.playgroundFeatures.pdDisagg
&& config.playgroundFeatures.pdDisagg.router) || null;
const curlEnv = (pdRouter && pdRouter.port != null)
? { ...env, CURL_PORT: String(pdRouter.port) }
: env;
const curlText = interpolate(config.curl || "", curlEnv, modelName);
const routerText = pdRouter && pdRouter.command
? interpolate(pdRouter.command, {
...env,
PREFILL_PORT: PD_PORTS.prefill.serve,
DECODE_PORT: PD_PORTS.decode.serve,
ROUTER_PORT: pdRouter.port,
}, modelName)
: "";
const resetAll = () => setDeltas(initialDeltas());
const placeholderGroups = (() => {
const out = { command: [], curl: [] };
for (const [key, meta] of Object.entries(config.placeholders || {})) {
(out[meta.target] || (out[meta.target] = [])).push({ key, ...meta });
}
return out;
})();
const handleCopy = () => {
navigator.clipboard.writeText(playgroundCommand);
setCopied(true);
setTimeout(() => setCopied(false), 1200);
};
const copyCurl = () => {
navigator.clipboard.writeText(curlText);
setCurlCopied(true);
setTimeout(() => setCurlCopied(false), 1200);
};
// Summarize whichever dims the Deploy panel actually has — a config may drop
// variant/quant/nodes or add its own (PD mode, ...), so nothing is hardcoded.
const baseSummary = baseCell
? Object.entries(base)
.filter(([, v]) => v !== undefined && v !== "")
.map(([k, v]) => (k === "hw" ? String(v).toUpperCase() : String(v)))
.join(" · ")
: "(no verified cell at the current Deploy selection — showing playground only)";
// ==========================================================================
// 11. Render helpers
// ==========================================================================
// Chip: checked when `current === value`; disabled chips are unclickable.
const renderChip = (label, current, value, onPick, opts = {}) => {
const checked = current === value;
const disabled = !!opts.disabled;
return (
<span
key={`${label}-${value === null ? "auto" : value}`}
style={{
...s.chip,
...(checked ? s.chipChecked : {}),
...(disabled ? s.chipDisabled : {}),
}}
title={disabled ? (opts.disabledReason || "Not available") : ""}
onClick={() => { if (!disabled) onPick(value); }}
>
{label}
</span>
);
};
// Dropdown over a chip-schema `entries` array. Hidden entries excluded;
// disabled get a "(n/a)" suffix. Uses the option index as the <select>
// value to dodge form-value serialization; `onPick` gets the original
// value. `labelFor` is an optional label resolver; `opts.hideValues`
// suppresses values (e.g. the inherit sentinel when a base default exists).
// `opts.disabled` grays the whole select (knob-level gating), with
// `opts.disabledReason` as the hover tooltip.
const renderSelect = (current, entries, onPick, base, labelFor, opts = {}) => {
const hideSet = new Set(opts.hideValues || []);
const items = [];
for (const entry of (entries || [])) {
const c = helpers.evaluateChip(entry, base);
if (c.hidden) continue;
if (hideSet.has(c.value)) continue;
const lbl = labelFor
? labelFor(c)
: (c.label !== undefined ? c.label
: c.value === null ? "Auto" : String(c.value));
items.push({ ...c, label: lbl });
}
let idx = items.findIndex((c) => c.value === current);
if (idx === -1) idx = 0;
return (
<select
style={{ ...s.select, ...(opts.disabled ? s.chipDisabled : {}) }}
disabled={!!opts.disabled}
title={opts.disabled ? (opts.disabledReason || "Not available") : ""}
value={idx}
onChange={(e) => {
const next = items[parseInt(e.target.value, 10)];
if (next && !next.disabled) onPick(next.value);
}}
>
{items.map((c, i) => (
<option
key={i}
value={i}
disabled={c.disabled}
>
{c.label}{c.disabled ? " (n/a)" : ""}
</option>
))}
</select>
);
};
// ==========================================================================
// 12. JSX render
// ==========================================================================
return (
<div style={s.container} className="not-prose">
{/* Inherited base summary */}
<div style={s.baseStrip}>
<span style={{ fontWeight: 600 }}>Inherited base from Deployment:</span>
<code style={{ fontFamily: "Menlo, monospace" }}>{baseSummary}</code>
{/* scrollIntoView (not hash nav) so the base-cell hash survives.
Target the configurator ITSELF: the "## Deployment" heading sits
above the install accordion and a screenful of prose, so landing on
the heading leaves the panel you came for off-screen. The heading
slugs stay as fallbacks for a page that renders no configurator. */}
<button
type="button"
style={s.switchBaseBtn}
onClick={() => {
const el = document.getElementById(DEPLOYMENT_COMPONENT_ID)
|| document.getElementById("deployment")
|| document.getElementById("deploy");
if (el) el.scrollIntoView({ behavior: "smooth", block: "start" });
}}
>
Switch base
</button>
<button style={s.resetBtn} onClick={resetAll}>Reset all overrides</button>
</div>
{/* One card per declared axis (render() may return null to gate). */}
{Object.entries(AXIS_HANDLERS).map(([axisId, handler]) => {
const fc = pgFeatures[axisId];
if (!fc) return null;
// An axis whose feature is not switched on in the Deploy panel has
// nothing to tune — declared per config as `showWhen(base)`.
if (typeof fc.showWhen === "function" && !fc.showWhen(constraintBase)) return null;
const setValue = (next) => setDeltas((d) => ({ ...d, [axisId]: next }));
return handler.render({
axisId, value: deltas[axisId], setValue,
// constraintBase = 5 cell dims + cross-axis facts (dpAttnOn, pdMode).
fc, base: constraintBase, s, h: helpers, renderChip, renderSelect,
derived: derivedMap[axisId] || null,
});
})}
{/* Command box (diff vs verified base) */}
<div style={s.card}>
<div style={s.title}>Playground Command (compare with base)</div>
<div style={s.commandWrap}>
<div style={s.commandHeader}>
<div style={s.headerLeft}>
<div style={s.badge(playgroundVerified)}>
<span style={s.badgeDot(playgroundVerified)} />
{playgroundVerified ? "Verified" : "Not Verified"}
</div>
{/* Sibling-cell match: offer to switch the Deployment panel's base to it. */}
{matchedSiblingCell && (
<span style={s.matchedHint}>
matches <code style={{ fontFamily: "Menlo, monospace" }}>
{matchedSiblingCell.match.strategy}
</code>
<button
type="button"
style={s.matchedSwitchBtn}
onClick={() => {
const m = matchedSiblingCell.match;
setDeltas(initialDeltas());
const hash = new URLSearchParams(m).toString();
window.location.hash = hash;
window.dispatchEvent(new CustomEvent("sglang-deploy-sel",
{ detail: m }));
}}
>
switch base
</button>
</span>
)}
<div style={s.runModeWrap} role="tablist" aria-label="Output format">
<span
style={s.runModeChip(runMode === "python")}
onClick={() => setRunMode("python")}
role="tab"
aria-selected={runMode === "python"}
>
Python
</span>
<span
style={s.runModeChipLast(runMode === "docker")}
onClick={() => setRunMode("docker")}
role="tab"
aria-selected={runMode === "docker"}
>
Docker
</span>
</div>
</div>
<div style={s.iconRow}>
<button style={s.iconButton} onClick={handleCopy}>
{copied ? "✓ Copied" : "⧉ Copy"}
</button>
<button style={s.iconButton} onClick={() => setModal("curl")}>$ cURL</button>
<button style={s.iconButton} onClick={() => setModal("env")}> Env</button>
{/* Submit only when the playground differs from the verified base. */}
{!playgroundVerified && baseCell && (
<button
style={{ ...s.iconButton, borderColor: isDark ? "#FDBA74" : "#FB923C",
color: isDark ? "#FDBA74" : "#C2410C", fontWeight: 600 }}
onClick={() => setModal("submit")}
title="I verified this command on my hardware — open a pre-filled GitHub issue to land it as a cookbook cell."
>
Submit
</button>
)}
</div>
</div>
<pre style={s.commandPre}>
{baseCell ? diffLines.map((d, i) => (
<span
key={i}
style={
d.kind === "added" ? s.diffLineAdded :
d.kind === "removed" ? s.diffLineRemoved :
s.diffLineUnchanged
}
>
{d.kind === "added" ? "+ " : d.kind === "removed" ? "- " : " "}
{d.line}{"\n"}
</span>
)) : "# No verified base cell at the current Deployment selection.\n# Pick a supported hardware/variant in the Deployment panel to populate the playground base."}
</pre>
{pgSpecHint && (
<div style={s.mtpWarn}>
⚠️ Speculative decoding ({pgSpecAlgoName}) is on SGLang resets <code>--max-running-requests</code> to <strong>48</strong> when it isn't set. Add <code>--max-running-requests &lt;N&gt;</code> sized for your target concurrency.
</div>
)}
{pgCpDpHint && (
<div style={s.mtpWarn}>
⚠️ Interleave prefill-CP together with DP-Attention: current SGLang releases assert <code>dp_size == 1</code> for the interleave layout, so this command fails at startup. Combined CP + DP-Attention support is planned upstream — keep one of the two off until it lands.
</div>
)}
</div>
</div>
{/* PD-Disagg router companion (separate block so the role diff stays pure). */}
{pdRouter && routerText && (
<div style={s.card}>
<div style={s.title}>Router</div>
<div style={{ fontSize: 11, opacity: 0.7, margin: "0 0 6px" }}>
Run after both roles are up. Substitute <code>{"<prefill-host>"}</code> /{" "}
<code>{"<decode-host>"}</code> with reachable hosts (both <code>127.0.0.1</code>{" "}
on a same-host deployment). Client traffic (cURL) targets this router.
</div>
<div style={s.commandWrap}>
<div style={s.commandHeader}>
<div style={{ fontSize: 11, opacity: 0.7 }}>port {pdRouter.port}</div>
<button
style={s.iconButton}
onClick={() => {
navigator.clipboard.writeText(routerText);
setRouterCopied(true);
setTimeout(() => setRouterCopied(false), 1200);
}}
>
{routerCopied ? "✓ Copied" : "⧉ Copy"}
</button>
</div>
<pre style={s.commandPre}>{routerText}</pre>
</div>
</div>
)}
{/* cURL modal — native <dialog> in top layer (escapes @container) */}
{modal === "curl" && (
<dialog ref={openDialog} style={s.dialog}
onClose={() => setModal(null)} onClick={onDialogClick}>
<div style={s.modalHeader}>
<div style={s.modalTitle}>cURL example</div>
<button style={s.modalCloseBtn} onClick={() => setModal(null)} aria-label="Close">×</button>
</div>
<div style={s.commandWrap}>
<div style={s.commandHeader}>
<div style={{ fontSize: 11, opacity: 0.7 }}>
Model: <code>{modelName || "(unresolved)"}</code>
</div>
<button style={s.iconButton} onClick={copyCurl}>
{curlCopied ? "✓ Copied" : "⧉ Copy"}
</button>
</div>
<pre style={s.commandPre}>{curlText}</pre>
</div>
{pdRouter && (
<p style={{ fontSize: 11, opacity: 0.85, marginTop: 8 }}>
<strong>PD-Disaggregation active</strong> — this targets the router on
{" "}<code>:{pdRouter.port}</code>; client traffic must not hit the role
servers directly.
</p>
)}
<p style={{ fontSize: 11, opacity: 0.7, marginTop: 8 }}>
Edit <code>CURL_HOST</code> / <code>CURL_PORT</code> in the Env panel.
</p>
</dialog>
)}
{/* Env modal — native <dialog> in top layer */}
{modal === "env" && (
<dialog ref={openDialog} style={s.dialog}
onClose={() => setModal(null)} onClick={onDialogClick}>
<div style={s.modalHeader}>
<div style={s.modalTitle}>Env / placeholder values</div>
<button style={s.modalCloseBtn} onClick={() => setModal(null)} aria-label="Close">×</button>
</div>
{placeholderGroups.curl.length > 0 && (
<div>
<div style={s.sectionHeading}>cURL placeholders</div>
{placeholderGroups.curl.map(({ key, label }) => (
<div key={key} style={s.formField}>
<label style={s.formLabel}>
{label} <code style={{ opacity: 0.6 }}>{`{{${key}}}`}</code>
</label>
<input
style={s.formInput}
value={envDraft[key] ?? ""}
onChange={(e) => setEnvDraft({ ...envDraft, [key]: e.target.value })}
/>
</div>
))}
</div>
)}
{placeholderGroups.command.length > 0 && (
<div>
<div style={s.sectionHeading}>Command placeholders</div>
{placeholderGroups.command.map(({ key, label }) => (
<div key={key} style={s.formField}>
<label style={s.formLabel}>
{label} <code style={{ opacity: 0.6 }}>{`{{${key}}}`}</code>
</label>
<input
style={s.formInput}
value={envDraft[key] ?? ""}
onChange={(e) => setEnvDraft({ ...envDraft, [key]: e.target.value })}
/>
</div>
))}
</div>
)}
<div style={{ display: "flex", justifyContent: "flex-end", gap: 8, marginTop: 16 }}>
<button style={{ ...s.iconButton, padding: "6px 14px" }} onClick={() => setModal(null)}>Cancel</button>
<button style={s.primaryBtn} onClick={() => { saveEnv(envDraft); setModal(null); }}>Save</button>
</div>
<p style={{ fontSize: 11, opacity: 0.7, marginTop: 10 }}>
Values persist in localStorage and are shared with the Deployment panel.
</p>
</dialog>
)}
{/* Submit-verified-cell modal — native <dialog> in top layer */}
{modal === "submit" && (
<dialog ref={openDialog} style={s.dialog}
onClose={() => setModal(null)} onClick={onDialogClick}>
<div style={s.modalHeader}>
<div style={s.modalTitle}>Submit verified cell</div>
<button style={s.modalCloseBtn} onClick={() => setModal(null)} aria-label="Close">×</button>
</div>
<p style={{ fontSize: 12, opacity: 0.85, marginTop: 0, marginBottom: 12 }}>
You've put together a combination that isn't in the verified
catalog yet. After you've run the command end-to-end on the
target hardware, this submits a pre-filled GitHub Issue that a
maintainer can convert into a PR.
</p>
<div style={s.sectionHeading}>Combination</div>
<code style={{ fontFamily: "Menlo, monospace", fontSize: 12 }}>
{base.hw} / {base.variant} / {base.quant} / {base.strategy} / {base.nodes}
</code>
{/* Overrides summary — the diff vs base in flag form. */}
{(() => {
const adds = diffLines.filter((d) => d.kind === "added");
const rems = diffLines.filter((d) => d.kind === "removed");
if (adds.length === 0 && rems.length === 0) return null;
return (
<>
<div style={{ ...s.sectionHeading, marginTop: 10 }}>
Overrides vs base ({adds.length} added · {rems.length} removed)
</div>
<pre style={{
margin: 0, padding: "8px 10px",
background: isDark ? "#111827" : "#f5f5f5",
border: `1px solid ${isDark ? "#374151" : "#e5e7eb"}`,
borderRadius: 4,
fontFamily: "'Menlo', 'Monaco', 'Courier New', monospace",
fontSize: 12, lineHeight: 1.4,
maxHeight: 160, overflowY: "auto",
whiteSpace: "pre-wrap",
}}>
{[...rems, ...adds].map((d, i) => (
<div
key={i}
style={d.kind === "added" ? s.diffLineAdded : s.diffLineRemoved}
>
{d.kind === "added" ? "+ " : "- "}
{d.line.replace(/^\s*/, "")}
</div>
))}
</pre>
</>
);
})()}
<div style={{ ...s.sectionHeading, marginTop: 14 }}>Attestation (all required)</div>
<div style={s.formField}>
<label style={{ fontSize: 12, display: "flex", alignItems: "flex-start", gap: 6 }}>
<input type="checkbox" checked={submitAttest.ranCommand}
onChange={(e) => setSubmitAttest({ ...submitAttest, ranCommand: e.target.checked })} />
I ran this exact command on the listed hardware.
</label>
<label style={{ fontSize: 12, display: "flex", alignItems: "flex-start", gap: 6 }}>
<input type="checkbox" checked={submitAttest.reachedReady}
onChange={(e) => setSubmitAttest({ ...submitAttest, reachedReady: e.target.checked })} />
The server reached READY and answered a cURL request successfully.
</label>
<label style={{ fontSize: 12, display: "flex", alignItems: "flex-start", gap: 6 }}>
<input type="checkbox" checked={submitAttest.outputCorrect}
onChange={(e) => setSubmitAttest({ ...submitAttest, outputCorrect: e.target.checked })} />
Output looked correct on at least one prompt.
</label>
</div>
<div style={{ ...s.sectionHeading, marginTop: 14 }}>SGLang version (required)</div>
<input
style={{ ...s.formInput, width: "100%", boxSizing: "border-box" }}
placeholder="sglang==0.5.4 (or git SHA abc1234)"
value={submitDraft.sglangVersion}
onChange={(e) => setSubmitDraft({ ...submitDraft, sglangVersion: e.target.value })}
/>
<div style={{ ...s.sectionHeading, marginTop: 14 }}>Benchmark result (optional)</div>
<input
style={{ ...s.formInput, width: "100%", boxSizing: "border-box" }}
placeholder="TTFT 95 ms / TPOT 18 ms / 1820 tok/s @ bs=64"
value={submitDraft.benchResult}
onChange={(e) => setSubmitDraft({ ...submitDraft, benchResult: e.target.value })}
/>
<div style={{ ...s.sectionHeading, marginTop: 14 }}>Notes / caveats (optional)</div>
<textarea
style={{ ...s.formInput, width: "100%", boxSizing: "border-box",
minHeight: 110, resize: "vertical", fontFamily: "inherit" }}
placeholder="Cluster config, env-var quirks, NIC mappings, multi-node bootstrap details, …"
value={submitDraft.notes}
onChange={(e) => setSubmitDraft({ ...submitDraft, notes: e.target.value })}
/>
<div style={{ display: "flex", justifyContent: "flex-end", gap: 8, marginTop: 16, alignItems: "center" }}>
{!submitReady && (
<span style={{ fontSize: 11, opacity: 0.7, marginRight: "auto" }}>
Tick all attestations and fill SGLang version to enable submit.
</span>
)}
<button style={{ ...s.iconButton, padding: "6px 14px" }} onClick={() => setModal(null)}>Cancel</button>
<a
href={submitReady ? submitUrl : undefined}
target="_blank" rel="noopener noreferrer"
onClick={(e) => { if (!submitReady) e.preventDefault(); else setModal(null); }}
style={{
...s.primaryBtn,
textDecoration: "none",
display: "inline-flex", alignItems: "center",
opacity: submitReady ? 1 : 0.4,
cursor: submitReady ? "pointer" : "not-allowed",
}}
>
Open submission on GitHub
</a>
</div>
<p style={{ fontSize: 11, opacity: 0.7, marginTop: 10 }}>
The CTA opens a pre-filled GitHub Issue using the
<code> 3-playground-verified-cell.yml</code> template. A
maintainer with the listed hardware will review and convert it
into a cookbook PR.
</p>
</dialog>
)}
</div>
);
};