OptionalencodeRaw: (text: string) => number[]Tokens emitted via jumpForward() this generation — telemetry/test hook.
Advance the matcher by the just-sampled token and fire async mask precompute for the NEXT step (overlaps the GPU forward). Call AFTER the token is read back to JS. No-op once terminated.
Apply the ready bitmask to logits [1, V]. Invalid token ids → -inf. Sync — the mask is already materialized. Returns a NEW array (caller disposes the input). Mirrors oMLX's apply_token_bitmask_mlx. Both paths read the grammar-owned readyMask, so ids the matcher does not know are never valid.
Jump-forward decoding (SGLang's technique via xgrammar's
findJumpForwardString; opt-in — the composition's grammarJump): when the grammar
admits exactly one continuation string (JSON keys/punctuation, enum
bodies — longest with any_whitespace:false compact schemas), return its
token ids so the decode loop can carry them into the KV with ONE
multi-token forward instead of one masked forward per token.
Contract: MUTATES the matcher for every id it returns (and only those) — the caller MUST emit exactly the returned ids, then await ready() before the next applyMask. Call only after ready() has resolved (no WASM fill in flight — the matcher calls here are sync). Returns null (matcher untouched) when: no hook, terminated, the jump retokenizes to <2 ids (a 1-token jump saves no forward), maxIds < 2, or the first id is rejected. If a LATER id is rejected the accepted prefix is returned — those ids already advanced the matcher, so they must be emitted; the loop resumes masked decoding after them (no rollback needed by construction).
Fidelity note (why opt-in, no oracle): encode(jumpStr) standalone can tokenize the forced span differently than the model would have sampled it. The emitted STRING is identical (token strings concatenate to the jump string) and grammar validity is preserved (every id is matcher-accepted), but the token STREAM — and, conditioning on it, content generated AFTER the forced span — may differ from an unjumped run. SentencePiece-family tokenizers whose raw encode prepends a space simply never jump (the first id gets rejected) — the guard degrades to normal decoding, never to invalid output.
Precompute the step-0 mask. Must be awaited before the first applyMask().
Propose the forced string without advancing the matcher. Tokenization can differ at its first boundary; verification and the normal grammar sampler accept or reject the candidates before anything is committed.
Await the mask precompute fired by accept(). Should be called before the next applyMask(); usually resolves immediately (overlapped the forward).
Stateful grammar masker. Driven explicitly by generate()'s decode loop (see module doc): accept(tokenId) advances the matcher + fires async mask precompute; ready() awaits it; applyMask(logits) sets invalid ids to -inf.