Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
97 commits
Select commit Hold shift + click to select a range
1cffe7f
wip / ai: scratch pool
SBrandeis Jul 20, 2026
7556ac7
scratch pool iteration
SBrandeis Jul 21, 2026
b5ef46f
implement word cache
SBrandeis Jul 21, 2026
8000719
lint
SBrandeis Jul 21, 2026
ee332b0
change defaults + max length + capacity bump
SBrandeis Jul 21, 2026
75f796c
more sensible values
SBrandeis Jul 21, 2026
d42d866
rewrite without hashmap
SBrandeis Jul 21, 2026
4106c3f
iteration
SBrandeis Jul 21, 2026
96a1778
iteration
SBrandeis Jul 21, 2026
40d37b3
fmt
SBrandeis Jul 21, 2026
6b26583
review comments
SBrandeis Jul 22, 2026
c87102d
draft first commit
ArthurZucker Jul 24, 2026
dfde37a
nits
ArthurZucker Jul 24, 2026
1436856
proper bpe only benches
ArthurZucker Jul 24, 2026
6759ed1
proper features
ArthurZucker Jul 24, 2026
3c532af
update
ArthurZucker Jul 24, 2026
43ac1ab
update what we balckbox
ArthurZucker Jul 24, 2026
062c6f8
comments
ArthurZucker Jul 27, 2026
cb4123a
commetn
ArthurZucker Jul 27, 2026
311eec7
first drafts
ArthurZucker Jul 27, 2026
330972f
fix glue
ArthurZucker Jul 27, 2026
3449330
draft table builds
ArthurZucker Jul 28, 2026
5a9cd45
start mphf draft
ArthurZucker Jul 28, 2026
8e3347b
impl get
ArthurZucker Jul 28, 2026
f11a5f9
fix mphf
ArthurZucker Jul 28, 2026
e0a073d
nits
ArthurZucker Jul 28, 2026
8c667db
fixes
ArthurZucker Jul 28, 2026
6ffbfba
slowly but surely
ArthurZucker Jul 28, 2026
346e99e
fixes
ArthurZucker Jul 28, 2026
2227c40
table tests pass
ArthurZucker Jul 28, 2026
12690e9
create top merges
ArthurZucker Jul 28, 2026
3474720
update
ArthurZucker Jul 28, 2026
d66b177
up
ArthurZucker Jul 28, 2026
14c0a2f
progress in the conversion table build
ArthurZucker Jul 29, 2026
b1f44bc
update
ArthurZucker Jul 29, 2026
519bbcc
fixes
ArthurZucker Jul 29, 2026
9f23a46
dman
ArthurZucker Jul 29, 2026
795131c
...
ArthurZucker Jul 29, 2026
07efea6
eager flag was missing
ArthurZucker Jul 29, 2026
4066919
update
ArthurZucker Jul 29, 2026
33d0001
design a manual example
ArthurZucker Jul 30, 2026
836bcfe
with / without thief
ArthurZucker Jul 30, 2026
1b498e3
remove some shit
ArthurZucker Jul 30, 2026
b432729
more simplifications
ArthurZucker Jul 30, 2026
b3fcd70
single test move it
ArthurZucker Jul 30, 2026
d542edc
draft engine
ArthurZucker Jul 30, 2026
1965a6c
remove complication
ArthurZucker Jul 30, 2026
7ae223c
remove one flag that was not worth it
ArthurZucker Jul 30, 2026
ec119a6
current status
ArthurZucker Jul 31, 2026
3a7aa8f
monomorphize for perfs
ArthurZucker Jul 31, 2026
c3aad7a
fixes
ArthurZucker Jul 31, 2026
abae229
rename
ArthurZucker Aug 3, 2026
8a616f3
start drafting the two tier merge
ArthurZucker Aug 3, 2026
f0e6031
todo is getting fixed
ArthurZucker Aug 3, 2026
5df6783
nit
ArthurZucker Aug 3, 2026
678b9f6
SparseFold for table!
ArthurZucker Aug 3, 2026
27ab17b
move stuff around
ArthurZucker Aug 3, 2026
4b3f37b
multipass bpe
ArthurZucker Aug 3, 2026
d3a8b02
scratches
ArthurZucker Aug 3, 2026
d0d6e41
isolate pipeline bpe
ArthurZucker Aug 3, 2026
ba35ffc
remove unused mergemap
ArthurZucker Aug 3, 2026
99e0846
u16 is faster
ArthurZucker Aug 3, 2026
3603372
add convert.rs
ArthurZucker Aug 3, 2026
563ab9b
update
ArthurZucker Aug 3, 2026
e474cdb
less branches
ArthurZucker Aug 3, 2026
6fa4281
update
ArthurZucker Aug 3, 2026
23542bd
it was not worth it
ArthurZucker Aug 3, 2026
abbb762
finally
ArthurZucker Aug 3, 2026
088e329
nits, renaming and moving files here and there
ArthurZucker Aug 3, 2026
bd95276
renaming
ArthurZucker Aug 3, 2026
06dbb96
fix more of the renaming
ArthurZucker Aug 3, 2026
1fee23b
pipeline vs legacy
ArthurZucker Aug 3, 2026
93bd4ac
Merge remote-tracking branch 'origin/feat/train_encode_split' into pe…
ArthurZucker Aug 3, 2026
703e37f
first fix for the gate
ArthurZucker Aug 3, 2026
8523274
update the local bench
ArthurZucker Aug 3, 2026
0bde560
up
ArthurZucker Aug 3, 2026
11e1786
bit better benches
ArthurZucker Aug 3, 2026
1ce1f6c
update
ArthurZucker Aug 3, 2026
a6bea80
revert unrelated changes
ArthurZucker Aug 3, 2026
47098dc
more reverts
ArthurZucker Aug 3, 2026
a42edc9
more reversion!
ArthurZucker Aug 3, 2026
9dc69e3
cleanup
ArthurZucker Aug 3, 2026
490e3f0
nits
ArthurZucker Aug 3, 2026
4d2b037
more clippy
ArthurZucker Aug 3, 2026
2624c43
rewrite + document multipass
SBrandeis Aug 3, 2026
db1798d
rename
SBrandeis Aug 3, 2026
7598fb2
perf: save a lookup when there is no merge
SBrandeis Aug 3, 2026
ff4d576
perf: compiler gotchas
SBrandeis Aug 3, 2026
e9fe3ca
Idiomacy:
SBrandeis Aug 3, 2026
087240a
feat(.tok): a tokenizer container with no parser
ArthurZucker Aug 5, 2026
4c98f40
perf(.tok): build the pipeline directly, without the config wrappers
ArthurZucker Aug 5, 2026
e2e6403
perf(tk-encode): make the config layer strippable
ArthurZucker Aug 5, 2026
0438c2a
feat(tk-encode): serde is not a dependency of encoding
ArthurZucker Aug 5, 2026
d98cc45
refactor: tk-encode is the v1 crate; v0 moves to tk-convert
ArthurZucker Aug 5, 2026
7b1d64a
feat(.tok): v1 carries all four models, not just BPE
ArthurZucker Aug 5, 2026
0add52d
feat: gate the Unicode tables, and build against ptr_hash without ray…
ArthurZucker Aug 5, 2026
054bdf4
bench: add tok_bench, a single-thread throughput probe over a .tok
ArthurZucker Aug 5, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1,620 changes: 1,620 additions & 0 deletions bindings/node-tok/Cargo.lock

Large diffs are not rendered by default.

33 changes: 33 additions & 0 deletions bindings/node-tok/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
[package]
name = "node-tok"
version = "0.23.2-dev.0"
edition = "2024"
authors = ["Arthur Zucker <arthur@huggingface.co>"]
license = "Apache-2.0"
description = "Node binding whose entire surface is the `.tok` read path, so no JSON parser links."

[lib]
crate-type = ["cdylib"]

[dependencies]
napi = { version = "3", default-features = false, features = ["napi6"] }
napi-derive = "3"
# No `config`: this binding loads `.tok` and nothing else, so the JSON layer and every
# enum arm that only it can construct stay out of the binary.
tk-encode = { path = "../../tokenizers/tk-encode", default-features = false }
tk-serialization = { path = "../../tokenizers/tk-serialization" }

[build-dependencies]
napi-build = "2"

[profile.release]
lto = "fat"
strip = true
panic = "abort"
codegen-units = 1
opt-level = "z"

# This package is outside the workspace, so it needs the patch spelled out again.
# https://github.com/RagnarGrootKoerkamp/PtrHash/pull/32 — drop once it lands.
[patch.crates-io]
ptr_hash = { git = "https://github.com/ArthurZucker/PtrHash", branch = "feat/optional-rayon" }
3 changes: 3 additions & 0 deletions bindings/node-tok/build.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
fn main() {
napi_build::setup();
}
72 changes: 72 additions & 0 deletions bindings/node-tok/src/lib.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
//! A Node binding whose entire surface is the `.tok` read path.
//!
//! There is deliberately no `fromFile`, no `fromString`, no config accessors: the moment one
//! exists, `serde_json` is reachable and LTO has to keep the whole JSON stack. Converting a
//! `tokenizer.json` is `tk-convert`'s job, offline.

use napi::bindgen_prelude::*;
use napi_derive::napi;

use tk_encode::pipeline::PipelineTokenizer as Pipeline;

#[napi]
pub struct TokTokenizer {
inner: Pipeline,
// Keeps the mapped bytes alive for as long as the tokenizer that was built from them.
_file: tk_serialization::TokFile,
}

#[napi]
impl TokTokenizer {
/// Load a `.tok` produced by `tk-convert`.
#[napi(factory)]
pub fn from_file(path: String) -> Result<Self> {
let file = tk_serialization::TokFile::open(&path)
.map_err(|e| Error::from_reason(format!("{path}: {e}")))?;
let inner = Pipeline::from_tok(file.bytes())
.map_err(|e| Error::from_reason(format!("{path}: {e}")))?;
Ok(Self { inner, _file: file })
}

/// Encode `text`, returning the ids. A `Uint32Array` rather than a `Vec<u32>`: the latter
/// marshals as a boxed JS array, one napi value per token, which costs more than the encode.
#[napi]
pub fn encode(&self, text: String, add_special_tokens: bool) -> Result<Uint32Array> {
let encoded = self
.inner
.encode(text.as_str(), add_special_tokens)
.map_err(|e| Error::from_reason(e.to_string()))?;
Ok(encoded.iter().map(|t| t.id).collect::<Vec<u32>>().into())
}

/// Encode UTF-8 bytes straight into a caller-owned buffer, returning how many ids were
/// written. Drops the JS string copy and the fresh ArrayBuffer.
#[napi]
pub fn encode_bytes_into(
&self,
text: Buffer,
mut out: Uint32Array,
add_special_tokens: bool,
) -> Result<u32> {
let text = std::str::from_utf8(&text)
.map_err(|e| Error::from_reason(format!("input is not valid UTF-8: {e}")))?;
let encoded = self
.inner
.encode(text, add_special_tokens)
.map_err(|e| Error::from_reason(e.to_string()))?;
if encoded.len() > out.len() {
return Err(Error::from_reason(format!(
"output buffer holds {} ids, needs {}",
out.len(),
encoded.len()
)));
}
// SAFETY: `out` is a JS-owned `Uint32Array` handed to this call; napi only marks the
// mutable view unsafe because JS could alias it, and nothing here re-enters JS.
let slots = unsafe { out.as_mut() };
for (slot, token) in slots.iter_mut().zip(&encoded) {
*slot = token.id;
}
Ok(encoded.len() as u32)
}
}
Loading