// Etichette riservate del gate HITL e helper di deduplica. Modulo PURO (nessuna // dipendenza da pi-tui): condiviso da tht-gate.js e testabile in isolamento con // node --test .pi/extensions/test_reserved_labels.mjs // `Altro — specifica…` e le due vie di fuga (torna indietro / esci) vengono // SEMPRE aggiunte dal gate alle opzioni in arrivo: se il modello ri-propone uno // step con queste etichette gia' presenti, stripReserved evita il duplicato. export const ALTRO = "Altro — specifica…"; export const QUIT_LABEL = "Esci da Pi (/quit)"; export const BACK_LABEL = "Torna indietro (fase precedente)"; export const CONTROL_LABELS = new Set([QUIT_LABEL, BACK_LABEL]); // Normalize a label to lowercase ASCII tokens: strip diacritics, turn every run // of punctuation/space into a single space, trim. "Altro — specifica…" -> "altro specifica". function normalize(label) { return String(label) .normalize("NFD") .replace(/[̀-ͯ]/g, "") .toLowerCase() .replace(/[^a-z0-9]+/g, " ") .trim(); } const NORM_QUIT = normalize(QUIT_LABEL); const NORM_BACK = normalize(BACK_LABEL); // true if the label is one the gate adds itself. Robust to the variants models // emit ("Altro - specificare", "altro", English "Other — specify"): reserved when // the FIRST normalized token is exactly "altro"/"other", or the whole normalized // label equals the canonical quit/back labels. First-token match keeps real // options like "altrove" out of the reserved set. export function isReserved(label) { const n = normalize(label); if (!n) return false; const first = n.split(" ")[0]; return first === "altro" || first === "other" || n === NORM_QUIT || n === NORM_BACK; } // removes every reserved entry from a list of labels, preserving order and normal // entries. Idempotent. export function stripReserved(labels) { return labels.filter((label) => !isReserved(label)); }