(text: string)
| 75 | * code fences, `---` banner sentinels, and `<|role|>` / `</system>` markers. |
| 76 | */ |
| 77 | export function datamark(text: string): string { |
| 78 | const ZWSP = "\u200b"; // zero-width space: breaks token recognition, near-invisible |
| 79 | return text |
| 80 | // strip C0/C1 control chars + Unicode line terminators (U+0085/2028/2029 render as |
| 81 | // newlines in many tokenizers/markdown; "strip newlines" must cover them) |
| 82 | .replace(/[\u0000-\u001f\u007f\u0085\u2028\u2029]/g, " ") |
| 83 | .replace(/`{3,}/g, "'''") // neutralize markdown code fences |
| 84 | .replace(/-{3,}/g, "\u2014") // neutralize `---` banner sentinels (em dash) |
| 85 | .replace(/<\|/g, `<${ZWSP}|`) // neutralize <|im_start|>-style chat markers |
| 86 | .replace(/\|>/g, `|${ZWSP}>`) |
| 87 | .replace(/<(\/?)(system|user|assistant|tool)>/gi, `<${ZWSP}$1$2>`) // neutralize role tags |
| 88 | // neutralize chat turn-prefixes (Human:/Assistant:/System:/User:) — defeat the |
| 89 | // angle-tag pass and are Claude's native turn delimiters |
| 90 | .replace(/\b(human|assistant|system|user)(\s*):/gi, `$1${ZWSP}$2:`); |
| 91 | } |
| 92 | |
| 93 | export type ValidateResult = |
| 94 | | { ok: true; event: DecisionEvent } |
no outgoing calls
no test coverage detected