Skip to content

tok: o200k pre-tokenizer support, auto-detected, with download-free test coverage#330

Open
nbeerbower wants to merge 3 commits into
JustVugg:devfrom
nbeerbower:tok-o200k
Open

tok: o200k pre-tokenizer support, auto-detected, with download-free test coverage#330
nbeerbower wants to merge 3 commits into
JustVugg:devfrom
nbeerbower:tok-o200k

Conversation

@nbeerbower

Copy link
Copy Markdown

This carves the tokenizer change out of #312 so it can be reviewed and verified on its own β€” it's the part of that PR you said you'd check hardest, so here it is with its own proof.

tok.h learns the o200k Split-regex family (case-aware letter runs, attached contractions, \p{N}{1,3}, the [\r\n/]* punctuation tail), selected per-tokenizer by detecting \p{Lu} in the tokenizer.json's own Split pattern. cl100k tokenizers can never take the new branch, so glm's path is unchanged by construction. New Unicode range tables live in tok_unicode_o200k.h (Lu+Lt and Lm+Lo+M, generated from unicodedata).

Verification, all runnable here:

  • tests/test_tok_o200k (added to TEST_BINS): a synthetic byte-level BPE (tests/tok_o200k_tiny.json, ~4 KB, committed) carries the o200k regex; expected ids were generated by HF tokenizers against that same file. 40/40 encode, 40/40 round-trip β€” case transitions, contractions, digit groups, slash tails, whitespace branches, CJK/Greek/Cyrillic, added-token atomicity.
  • GLM oracle on this branch: 32/32 token-exact. make check: 70/70. 0 warnings.
  • (On the full 27 MB Inkling tokenizer, the same code scores 357/357 against HF tokenizers including 300 fuzz cases β€” not CI'd here since that file isn't committable, but reproducible with tests/test_tok.)

If this lands, #312 rebases to purely additive files (new engine + new backend + new tools), per your comment there.

πŸ€– Generated with Claude Code

https://claude.ai/code/session_016KLDCYJSyHxd39ChTr4T27

nbeerbower and others added 3 commits July 16, 2026 15:14
Inkling ships an o200k-family tokenizer (case-aware Split regex, GPT-4o
lineage) rather than cl100k. tok_load now detects the family from the
pattern itself (\p{Lu} appears only in the o200k regex) so GLM behavior
is untouched, and encode dispatches to a new pretok_chunk_o200k that
replays the regex engine's backtracking order exactly: greedy optional
prefix, maximally-greedy uppercase run given back until the lowercase
run can match, contractions attached to letter runs, \p{N}{1,3}, and
the [\r\n/]* punctuation tail.

tok_unicode_o200k.h adds the two range tables the new classes need
(Lu+Lt and Lm+Lo+M), generated from Python unicodedata.

Validated against HF tokenizers on 357 adversarial strings (case
transitions, contractions, CJK, combining marks, emoji + modifiers,
zero-width chars, 300 mixed-charset fuzz cases): 357/357 identical.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
tests/tok_o200k_tiny.json is a synthetic byte-level BPE (274 vocab, a
few KB) whose Split regex is the o200k pattern; expected ids in
tok_o200k_cases.txt were generated by HF tokenizers on that same file.
test_tok_o200k (in TEST_BINS) scores 40/40 encode + 40/40 round-trip:
case-transition splits, contractions, digit groups, the [\r\n/]* tail,
whitespace branches, CJK/Greek/Cyrillic, added-token atomicity.

The cl100k path is untouched by construction β€” dispatch requires
\p{Lu} in the tokenizer's own Split pattern, which cl100k lacks β€” and
stays covered by the GLM oracle (verified on this branch: 32/32).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
MinGW's UCRT has no getline; fixed-buffer fgets with CRLF trimming
reads the same case file everywhere.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant