Skip to content

Commit 0d50d0e

Browse files
michalharakalclaude
andcommitted
refactor: move GGUFTokenizer to llm-core, add TokenizerFactory
Phase 3 of the unified pipeline plan. Tokenization is now a standalone pipeline stage in llm-core, independent of any specific runner. - Move GGUFTokenizer from kllama to llm-core/tokenizer package - Add typealias in kllama for backwards compatibility - Create TokenizerFactory with fromGGUF(), fromTokenizerJson(), fromHuggingFace() - Add skainet-io-gguf and kotlinx-io-core dependencies to llm-core Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
1 parent f42617a commit 0d50d0e

5 files changed

Lines changed: 818 additions & 769 deletions

File tree

PLAN-unified-pipeline.md

Lines changed: 12 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -83,31 +83,23 @@ ChatPipeline (template formatting, tool calling, agent loop)
8383
- `llm-core/.../weights/LLMWeightNameResolvers.kt` — already maps DSL paths -> GGUF names
8484
- New: per-model DSL network definitions
8585

86-
## Phase 3: Tokenization as Pipeline Stage
86+
## Phase 3: Tokenization as Pipeline Stage -- DONE
8787

88-
**Problem:** Tokenization is split between `GGUFTokenizer` (kllama module), `QwenByteLevelBPETokenizer` (llm-core), and model-specific code. The byte-level BPE fix we just made shows the fragility.
88+
**What was done:**
8989

90-
**Changes:**
90+
1. **Enhanced `Tokenizer` interface** with `eosTokenId`, `bosTokenId`, `vocabSize` (done in Phase 1)
9191

92-
1. **Enhance `Tokenizer` interface** (`llm-core`):
93-
```kotlin
94-
interface Tokenizer {
95-
fun encode(text: String): IntArray
96-
fun decode(token: Int): String
97-
fun decode(tokens: IntArray): String
98-
val eosTokenId: Int
99-
val bosTokenId: Int
100-
val vocabSize: Int
101-
val specialTokens: Set<String>
102-
}
103-
```
92+
2. **Moved `GGUFTokenizer` from kllama to `llm-core`**
93+
- New location: `llm-core/.../tokenizer/GGUFTokenizer.kt`
94+
- Old location has a typealias for backwards compatibility
95+
- Added `skainet-io-gguf` and `kotlinx-io-core` dependencies to `llm-core`
10496

105-
2. **Unified tokenizer factory:**
106-
- `TokenizerFactory.fromGGUF(source)`auto-detects BPE/SentencePiece/WordPiece
107-
- `TokenizerFactory.fromTokenizerJson(json)` — HuggingFace format
108-
- Returns the correct implementation (byte-level BPE for GPT-2/Qwen, SentencePiece for LLaMA, etc.)
97+
3. **Created `TokenizerFactory`** in `llm-core/.../tokenizer/TokenizerFactory.kt`
98+
- `TokenizerFactory.fromGGUF(source)`from GGUF file metadata
99+
- `TokenizerFactory.fromTokenizerJson(json)`from HuggingFace tokenizer.json
100+
- `TokenizerFactory.fromHuggingFace(json, config)` — full HF BPE tokenizer
109101

110-
3. **Move `GGUFTokenizer` to `llm-core`** so all runners can use it without depending on kllama
102+
4. All runners can now use `GGUFTokenizer` and `TokenizerFactory` directly from `llm-core`
111103

112104
## Phase 4: Unified Runner (single CLI entry point)
113105

llm-core/build.gradle.kts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,8 @@ kotlin {
4848
implementation(libs.skainet.compile.dag)
4949
implementation(libs.skainet.compile.opt)
5050
implementation(libs.skainet.io.core)
51+
implementation(libs.skainet.io.gguf)
52+
implementation(libs.kotlinx.io.core)
5153
}
5254

5355
commonTest.dependencies {

0 commit comments

Comments
 (0)