export function seededRandom(seed) { let state = Number(seed) >>> 0; return () => { state = (state + 0x6D2B79F5) >>> 0; let x = Math.imul(state ^ (state >>> 15), state | 1); x ^= x + Math.imul(x ^ (x >>> 7), x | 61); return ((x ^ (x >>> 14)) >>> 0) / 4294967296; }; } export function validateSettings(settings) { const { seed, temperature, topP, topK, maxTokens } = settings; if (!Number.isInteger(seed) || seed < 0 || seed > 0xffffffff) throw new Error('Seed must be an integer from 0 to 4,294,967,295.'); if (!Number.isFinite(temperature) || temperature < 0 || temperature > 2) throw new Error('Temperature must be between 0 and 2.'); if (!Number.isFinite(topP) || topP <= 0 || topP > 1) throw new Error('Top-p must be between 0 (exclusive) and 1.'); if (!Number.isInteger(topK) || topK < 0 || topK > 378) throw new Error('Top-k must be an integer from 0 to 378.'); if (!Number.isInteger(maxTokens) || maxTokens < 1 || maxTokens > 2047) throw new Error('Token limit must be an integer from 1 to 2,047.'); } export function sample(logits, settings, random) { const { temperature, topP, topK } = settings; if (temperature === 0) { let best = 0; for (let i = 1; i < logits.length; i++) if (logits[i] > logits[best]) best = i; return best; } let candidates = Array.from(logits, (value, id) => ({ id, value })).sort((a, b) => b.value - a.value); // Same order as Transformers: temperature, top-k, then nucleus filtering. if (topK > 0 && topK < candidates.length) { const cutoff = candidates[topK - 1].value; candidates = candidates.filter(c => c.value >= cutoff); } const maximum = candidates[0].value; let total = 0; for (const c of candidates) { c.prob = Math.exp((c.value - maximum) / temperature); total += c.prob; } let cumulative = 0; let keep = candidates.length; for (let i = 0; i < candidates.length; i++) { cumulative += candidates[i].prob / total; if (cumulative >= topP) { keep = i + 1; break; } } candidates = candidates.slice(0, keep); total = candidates.reduce((sum, c) => sum + c.prob, 0); let draw = random() * total; for (const c of candidates) { draw -= c.prob; if (draw < 0) return c.id; } return candidates.at(-1).id; }