tokenfold 0.5.2__tar.gz → 0.5.3__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (44) hide show
  1. {tokenfold-0.5.2 → tokenfold-0.5.3}/Cargo.lock +14 -14
  2. {tokenfold-0.5.2 → tokenfold-0.5.3}/Cargo.toml +1 -1
  3. {tokenfold-0.5.2 → tokenfold-0.5.3}/PKG-INFO +195 -97
  4. {tokenfold-0.5.2 → tokenfold-0.5.3}/README.md +194 -96
  5. {tokenfold-0.5.2 → tokenfold-0.5.3}/crates/tokenfold-py/Cargo.toml +1 -1
  6. {tokenfold-0.5.2 → tokenfold-0.5.3}/LICENSE +0 -0
  7. {tokenfold-0.5.2 → tokenfold-0.5.3}/crates/tokenfold-core/Cargo.toml +0 -0
  8. {tokenfold-0.5.2 → tokenfold-0.5.3}/crates/tokenfold-core/README.md +0 -0
  9. {tokenfold-0.5.2 → tokenfold-0.5.3}/crates/tokenfold-core/benches/THRESHOLDS.toml +0 -0
  10. {tokenfold-0.5.2 → tokenfold-0.5.3}/crates/tokenfold-core/benches/compression_bench.rs +0 -0
  11. {tokenfold-0.5.2 → tokenfold-0.5.3}/crates/tokenfold-core/src/allocation.rs +0 -0
  12. {tokenfold-0.5.2 → tokenfold-0.5.3}/crates/tokenfold-core/src/budget.rs +0 -0
  13. {tokenfold-0.5.2 → tokenfold-0.5.3}/crates/tokenfold-core/src/codec.rs +0 -0
  14. {tokenfold-0.5.2 → tokenfold-0.5.3}/crates/tokenfold-core/src/errors.rs +0 -0
  15. {tokenfold-0.5.2 → tokenfold-0.5.3}/crates/tokenfold-core/src/filters.rs +0 -0
  16. {tokenfold-0.5.2 → tokenfold-0.5.3}/crates/tokenfold-core/src/holdout.rs +0 -0
  17. {tokenfold-0.5.2 → tokenfold-0.5.3}/crates/tokenfold-core/src/input.rs +0 -0
  18. {tokenfold-0.5.2 → tokenfold-0.5.3}/crates/tokenfold-core/src/lib.rs +0 -0
  19. {tokenfold-0.5.2 → tokenfold-0.5.3}/crates/tokenfold-core/src/measurement.rs +0 -0
  20. {tokenfold-0.5.2 → tokenfold-0.5.3}/crates/tokenfold-core/src/modes.rs +0 -0
  21. {tokenfold-0.5.2 → tokenfold-0.5.3}/crates/tokenfold-core/src/pipeline/mod.rs +0 -0
  22. {tokenfold-0.5.2 → tokenfold-0.5.3}/crates/tokenfold-core/src/pipeline/tests.rs +0 -0
  23. {tokenfold-0.5.2 → tokenfold-0.5.3}/crates/tokenfold-core/src/profiles.rs +0 -0
  24. {tokenfold-0.5.2 → tokenfold-0.5.3}/crates/tokenfold-core/src/report.rs +0 -0
  25. {tokenfold-0.5.2 → tokenfold-0.5.3}/crates/tokenfold-core/src/retrieval_store.rs +0 -0
  26. {tokenfold-0.5.2 → tokenfold-0.5.3}/crates/tokenfold-core/src/safety.rs +0 -0
  27. {tokenfold-0.5.2 → tokenfold-0.5.3}/crates/tokenfold-core/src/stats.rs +0 -0
  28. {tokenfold-0.5.2 → tokenfold-0.5.3}/crates/tokenfold-core/src/status.rs +0 -0
  29. {tokenfold-0.5.2 → tokenfold-0.5.3}/crates/tokenfold-core/src/token_estimator.rs +0 -0
  30. {tokenfold-0.5.2 → tokenfold-0.5.3}/crates/tokenfold-core/src/transforms/diff.rs +0 -0
  31. {tokenfold-0.5.2 → tokenfold-0.5.3}/crates/tokenfold-core/src/transforms/json.rs +0 -0
  32. {tokenfold-0.5.2 → tokenfold-0.5.3}/crates/tokenfold-core/src/transforms/json_dict.rs +0 -0
  33. {tokenfold-0.5.2 → tokenfold-0.5.3}/crates/tokenfold-core/src/transforms/json_fold.rs +0 -0
  34. {tokenfold-0.5.2 → tokenfold-0.5.3}/crates/tokenfold-core/src/transforms/json_prune.rs +0 -0
  35. {tokenfold-0.5.2 → tokenfold-0.5.3}/crates/tokenfold-core/src/transforms/log_fold.rs +0 -0
  36. {tokenfold-0.5.2 → tokenfold-0.5.3}/crates/tokenfold-core/src/transforms/logs.rs +0 -0
  37. {tokenfold-0.5.2 → tokenfold-0.5.3}/crates/tokenfold-core/src/transforms/mod.rs +0 -0
  38. {tokenfold-0.5.2 → tokenfold-0.5.3}/crates/tokenfold-core/src/transforms/redaction.rs +0 -0
  39. {tokenfold-0.5.2 → tokenfold-0.5.3}/crates/tokenfold-core/src/transforms/schema.rs +0 -0
  40. {tokenfold-0.5.2 → tokenfold-0.5.3}/crates/tokenfold-core/tests/golden.rs +0 -0
  41. {tokenfold-0.5.2 → tokenfold-0.5.3}/crates/tokenfold-core/tests/integration.rs +0 -0
  42. {tokenfold-0.5.2 → tokenfold-0.5.3}/crates/tokenfold-core/tests/property_tests.rs +0 -0
  43. {tokenfold-0.5.2 → tokenfold-0.5.3}/crates/tokenfold-py/src/lib.rs +0 -0
  44. {tokenfold-0.5.2 → tokenfold-0.5.3}/pyproject.toml +0 -0
@@ -871,9 +871,9 @@ dependencies = [
871
871
 
872
872
  [[package]]
873
873
  name = "rustls-webpki"
874
- version = "0.103.15"
874
+ version = "0.103.16"
875
875
  source = "registry+https://github.com/rust-lang/crates.io-index"
876
- checksum = "f3c3cf1d8b1e7d4927e2d154c3fcb02979afb9939629c62cd9048d4f07b60ac2"
876
+ checksum = "4443b1b6d39d7c663139942cc4558262562d2c84123bb6282ef177009ca8b281"
877
877
  dependencies = [
878
878
  "ring",
879
879
  "rustls-pki-types",
@@ -1109,7 +1109,7 @@ dependencies = [
1109
1109
 
1110
1110
  [[package]]
1111
1111
  name = "tokenfold-adapters"
1112
- version = "0.5.2"
1112
+ version = "0.5.3"
1113
1113
  dependencies = [
1114
1114
  "serde",
1115
1115
  "serde_json",
@@ -1118,7 +1118,7 @@ dependencies = [
1118
1118
 
1119
1119
  [[package]]
1120
1120
  name = "tokenfold-admin"
1121
- version = "0.5.2"
1121
+ version = "0.5.3"
1122
1122
  dependencies = [
1123
1123
  "ed25519-dalek",
1124
1124
  "serde",
@@ -1128,7 +1128,7 @@ dependencies = [
1128
1128
 
1129
1129
  [[package]]
1130
1130
  name = "tokenfold-cli"
1131
- version = "0.5.2"
1131
+ version = "0.5.3"
1132
1132
  dependencies = [
1133
1133
  "clap",
1134
1134
  "serde",
@@ -1143,7 +1143,7 @@ dependencies = [
1143
1143
 
1144
1144
  [[package]]
1145
1145
  name = "tokenfold-core"
1146
- version = "0.5.2"
1146
+ version = "0.5.3"
1147
1147
  dependencies = [
1148
1148
  "proptest",
1149
1149
  "regex",
@@ -1158,25 +1158,25 @@ dependencies = [
1158
1158
 
1159
1159
  [[package]]
1160
1160
  name = "tokenfold-image"
1161
- version = "0.5.2"
1161
+ version = "0.5.3"
1162
1162
 
1163
1163
  [[package]]
1164
1164
  name = "tokenfold-learn"
1165
- version = "0.5.2"
1165
+ version = "0.5.3"
1166
1166
  dependencies = [
1167
1167
  "tokenfold-core",
1168
1168
  ]
1169
1169
 
1170
1170
  [[package]]
1171
1171
  name = "tokenfold-output"
1172
- version = "0.5.2"
1172
+ version = "0.5.3"
1173
1173
  dependencies = [
1174
1174
  "tokenfold-core",
1175
1175
  ]
1176
1176
 
1177
1177
  [[package]]
1178
1178
  name = "tokenfold-proxy"
1179
- version = "0.5.2"
1179
+ version = "0.5.3"
1180
1180
  dependencies = [
1181
1181
  "clap",
1182
1182
  "ctrlc",
@@ -1190,7 +1190,7 @@ dependencies = [
1190
1190
 
1191
1191
  [[package]]
1192
1192
  name = "tokenfold-py"
1193
- version = "0.5.2"
1193
+ version = "0.5.3"
1194
1194
  dependencies = [
1195
1195
  "pyo3",
1196
1196
  "serde_json",
@@ -1199,7 +1199,7 @@ dependencies = [
1199
1199
 
1200
1200
  [[package]]
1201
1201
  name = "tokenfold-rag"
1202
- version = "0.5.2"
1202
+ version = "0.5.3"
1203
1203
  dependencies = [
1204
1204
  "tokenfold-core",
1205
1205
  ]
@@ -1353,9 +1353,9 @@ dependencies = [
1353
1353
 
1354
1354
  [[package]]
1355
1355
  name = "webpki-roots"
1356
- version = "1.0.8"
1356
+ version = "1.0.10"
1357
1357
  source = "registry+https://github.com/rust-lang/crates.io-index"
1358
- checksum = "bf85cb06032201fa7c6f829d7db5a7e5aa45bcc0655327713065f6f0576731bf"
1358
+ checksum = "1c1c8e20c8a38fc7d65abfe74eb7280e4aa667e8eec8bc84996d2874810748d9"
1359
1359
  dependencies = [
1360
1360
  "rustls-pki-types",
1361
1361
  ]
@@ -3,7 +3,7 @@ resolver = "2"
3
3
  members = ["crates/tokenfold-core", "crates/tokenfold-py"]
4
4
 
5
5
  [workspace.package]
6
- version = "0.5.2"
6
+ version = "0.5.3"
7
7
  edition = "2024"
8
8
  rust-version = "1.98"
9
9
  license = "Apache-2.0"
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: tokenfold
3
- Version: 0.5.2
3
+ Version: 0.5.3
4
4
  Classifier: Development Status :: 4 - Beta
5
5
  Classifier: Intended Audience :: Developers
6
6
  Classifier: License :: OSI Approved :: Apache Software License
@@ -93,14 +93,14 @@ cargo add tokenfold-core # Rust library
93
93
  <br />
94
94
  <strong>Model-free &amp; deterministic</strong>
95
95
  <br /><br />
96
- No GPU, no semantic guesswork, no model in the Core path. Validate folded payloads on your workload: exact decode proves data recovery, not unchanged model behavior. Provider-neutral by design.
96
+ No GPU, no semantic guesswork, no model in the Core path. A Rust engine with Python, Node.js, CLI and proxy interfaces.
97
97
  <br /><br />
98
98
  </td>
99
99
  </tr>
100
100
  </table>
101
101
 
102
102
  > [!NOTE]
103
- > **Built for:** Developers and AI teams cutting latency and API costs on structured JSON, tool definitions, and RAG feeds. Exact decode proves data recovery, not unchanged downstream task accuracy - validate folded payloads with your representative workload. Ideal for applications sending large JSON tool payloads, tool-calling agent loops (Claude Code, Codex), and structured RAG feeds where token overhead drives latency and cost.
103
+ > **Built for:** Developers and AI teams sending structured JSON, tool definitions, and RAG feeds to LLMs. Start with a representative payload, inspect the receipt, and validate the result in your application.
104
104
 
105
105
  <br />
106
106
 
@@ -117,12 +117,17 @@ cargo add tokenfold-core # Rust library
117
117
  {"__tf_cols__":["id","role"],"__tf_rows__":[[1,"admin"],[2,"member"]]}
118
118
  ```
119
119
 
120
- ```mermaid
121
- %%{init: {"theme": "base", "themeVariables": {"primaryColor": "#22D3EE", "primaryTextColor": "#0b1020", "primaryBorderColor": "#A855F7", "lineColor": "#A855F7", "fontFamily": "ui-sans-serif, system-ui, sans-serif"}}}%%
122
- flowchart LR
123
- In["Repeated keys in every record<br/>id, role, id, role"] --> TF[Tokenfold Core]
124
- TF --> Out["Keys named once as columns<br/>values packed into rows"]
125
- ```
120
+ ![Terminal demo: Tokenfold reduces the bundled API response from 3,812 to 1,376 tokens.](https://raw.githubusercontent.com/snchimata/tokenfold/main/docs/assets/tokenfold-demo.gif)
121
+
122
+ <details>
123
+ <summary><strong>How this demo was generated (VHS tape)</strong></summary>
124
+
125
+ The [VHS tape](docs/tokenfold-demo.tape) runs `inspect`, `compress`, and
126
+ `decode` against the bundled API response, including the **63.9%** receipt.
127
+ Run `vhs docs/tokenfold-demo.tape` to regenerate the GIF; the tape requires
128
+ `tokenfold` on `PATH`.
129
+
130
+ </details>
126
131
 
127
132
  Send the folded JSON directly to the model: column names label each value's
128
133
  position in every row. Decode only when your application needs the original
@@ -133,7 +138,7 @@ object shape again.
133
138
  - **Targets structured JSON, not prose.** Folds repeated keys and columns
134
139
  mechanically rather than using semantic guesswork.
135
140
  - **Model-free and deterministic.** Zero models running in Core and zero GPU
136
- overhead. Exact decode proves data recovery, not unchanged model behavior.
141
+ overhead.
137
142
  - **Verified by exact decode.** Every lossless transform is verified by an
138
143
  in-memory round trip before emitting; lossy pruning is strictly opt-in and
139
144
  recoverable.
@@ -142,60 +147,38 @@ For tabular arrays, Tokenfold folds repeated keys into
142
147
  header columns (`__tf_cols__`). No model runs in the Core engine, and every
143
148
  lossless transform is verified by exact decode.
144
149
 
145
- > [!NOTE]
146
- > `schema_compaction` is not enabled by any preset. Unlike the default
147
- > transforms, it truncates `examples` arrays and is not reversible.
150
+ #### How Tokenfold decides what to fold
148
151
 
149
152
  ```mermaid
150
- %%{init: {"theme": "base", "themeVariables": {"primaryColor": "#22D3EE", "primaryTextColor": "#0b1020", "primaryBorderColor": "#A855F7", "lineColor": "#A855F7", "fontFamily": "ui-sans-serif, system-ui, sans-serif"}}}%%
153
+ %%{init: {"theme": "base", "themeVariables": {"primaryColor": "#f8fafc", "primaryTextColor": "#0f172a", "primaryBorderColor": "#94a3b8", "lineColor": "#64748b", "edgeLabelBackground": "#f8fafc", "fontFamily": "Arial", "fontSize": "15px"}, "flowchart": {"curve": "linear", "padding": 16, "nodeSpacing": 40, "rankSpacing": 32}}}%%
151
154
  flowchart LR
152
- App[Application / Agent] -->|Large JSON / tool schemas| TF[Tokenfold Core]
153
- TF -->|Lossless structural JSON| LLM[LLM provider]
154
- LLM -->|Completion / action| App
155
- TF -.->|Optional exact decode of folded payload| App
155
+ accTitle: Lossless first, pruning only when opted in
156
+ accDescr: Build a verified lossless baseline. Consider pruning only when opted in, eligible, and still needed. Store omissions before removal and use pruning only if it beats the lossless baseline; otherwise keep that baseline.
157
+ Lossless["Build lossless JSON baseline<br/>Verify folds; retain savings"] --> OptIn{"Pruning enabled,<br/>eligible and needed?"}
158
+ OptIn -->|No| Keep("Lossless payload<br/>+ receipt")
159
+ OptIn -->|Yes| Prune["Rank eligible rows<br/>Store before removal"]
160
+ Prune -->|No further savings| Keep
161
+ Prune -->|Fewer tokens than baseline| Emit("Pruned payload<br/>+ markers and receipt")
162
+
163
+ classDef core fill:#eff6ff,stroke:#2563eb,stroke-width:2px,color:#1e3a8a
164
+ classDef optional fill:#f8fafc,stroke:#64748b,stroke-dasharray:5 4,color:#334155
165
+ class Lossless,Keep core
166
+ class Prune optional
156
167
  ```
157
168
 
158
- #### How Tokenfold decides what to fold
159
-
160
- ![Flowchart: incoming JSON is folded when tabular, optionally pruned when heterogeneous, verified by exact round-trip, and emitted only when smaller; otherwise compact JSON is kept.](https://raw.githubusercontent.com/snchimata/tokenfold/b1ea4a545c174578adb3eaf7c39ab0b6fb1523f3/docs/assets/tokenfold-decision-flow.svg)
161
-
162
169
  <details>
163
170
  <summary><strong>Text version (screen readers / no-image fallback)</strong></summary>
164
171
 
165
- 1. Incoming JSON payload arrives.
166
- 2. Tabular shape? Yes: fold repeated keys into columns. No (heterogeneous
167
- feed): continue only when lossy pruning is opted in (rank rows, store
168
- dropped rows locally).
169
- 3. Verify with an exact decode round trip.
170
- 4. Smaller than input? Yes: emit folded payload + receipt. No: keep compact
171
- JSON (never larger).
172
-
173
- </details>
174
-
175
- #### Proxy / agent round trip
176
-
177
- ```mermaid
178
- %%{init: {"theme": "base", "themeVariables": {"primaryColor": "#22D3EE", "primaryTextColor": "#0b1020", "primaryBorderColor": "#A855F7", "lineColor": "#A855F7", "actorBkg": "#22D3EE", "actorTextColor": "#0b1020", "actorBorder": "#A855F7", "signalColor": "#A855F7", "signalTextColor": "#334155", "fontFamily": "ui-sans-serif, system-ui, sans-serif"}}}%%
179
- sequenceDiagram
180
- participant C as Client / Agent
181
- participant P as Tokenfold Proxy
182
- participant U as Upstream LLM
183
- C->>P: Provider-shaped request (large JSON)
184
- P->>P: Apply lossless transforms
185
- P->>U: Forwarded compact request
186
- U-->>P: Completion / action
187
- P-->>C: Response (Authorization forwarded unchanged)
188
- ```
189
-
190
- ![Terminal demo: Tokenfold reduces the bundled API response from 3,812 to 1,376 tokens.](https://raw.githubusercontent.com/snchimata/tokenfold/main/docs/assets/tokenfold-demo.gif)
191
-
192
- <details>
193
- <summary><strong>How this demo was generated (VHS tape)</strong></summary>
194
-
195
- The [VHS tape](docs/tokenfold-demo.tape) runs `inspect`, `compress`, and
196
- `decode` against the bundled API response, including the **63.9%** receipt.
197
- Run `vhs docs/tokenfold-demo.tape` to regenerate the GIF; the tape requires
198
- `tokenfold` on `PATH`.
172
+ 1. Build the lossless baseline using eligible transforms. Verify structural
173
+ folds with an exact decode round trip and keep only token reductions.
174
+ 2. Consider pruning only when explicitly opted in, the payload is eligible,
175
+ and the lossless baseline has not already met a requested token target.
176
+ 3. Rank eligible rows and store omissions locally before removing them.
177
+ Rows refused by storage stay inline.
178
+ 4. Use the pruned payload only if it has fewer tokens than the lossless
179
+ baseline; otherwise keep the lossless baseline.
180
+ 5. Emit the chosen payload and compression receipt. Pruned payloads include
181
+ retrieval markers for stored omissions.
199
182
 
200
183
  </details>
201
184
 
@@ -224,6 +207,24 @@ cargo install tokenfold-proxy
224
207
  tokenfold-proxy --upstream https://api.openai.com
225
208
  ```
226
209
 
210
+ ```python
211
+ from openai import OpenAI
212
+
213
+ # Your client's Authorization header is forwarded to upstream unchanged -
214
+ # no credential reconfiguration needed.
215
+ client = OpenAI(base_url="http://127.0.0.1:8787/v1")
216
+ # Existing calls work unchanged: client.chat.completions.create(...)
217
+ ```
218
+
219
+ The proxy listens on loopback (`127.0.0.1:8787`) by default.
220
+ Provider envelopes are minified, not columnar-folded.
221
+
222
+ Works out-of-the-box with any client or framework that accepts a custom base URL
223
+ (LangChain, LlamaIndex, LiteLLM, Instructor, or direct HTTP clients).
224
+
225
+ <details>
226
+ <summary><strong>Proxy routing, streaming, and stderr telemetry details</strong></summary>
227
+
227
228
  The proxy installs from source via Cargo and listens on `127.0.0.1:8787` by
228
229
  default (`--bind`; use `--allow-non-loopback-bind` to change that). Only
229
230
  chat-shaped JSON bodies (a non-empty `messages` array) are compressed on the
@@ -245,17 +246,25 @@ attempt ended. A provider that reports no usage, or a body whose usage cannot
245
246
  be read cleanly, records `usage_disposition: absent|malformed|oversized` with a
246
247
  `null` count rather than a zero -- and never changes what is forwarded.
247
248
 
248
- ```python
249
- from openai import OpenAI
249
+ </details>
250
250
 
251
- # Your client's Authorization header is forwarded to upstream unchanged -
252
- # no credential reconfiguration needed.
253
- client = OpenAI(base_url="http://127.0.0.1:8787/v1")
254
- # Existing calls work unchanged: client.chat.completions.create(...)
255
- ```
251
+ #### Proxy / agent round trip
256
252
 
257
- Works out-of-the-box with any client or framework that accepts a custom base URL
258
- (LangChain, LlamaIndex, LiteLLM, Instructor, or direct HTTP clients).
253
+ ```mermaid
254
+ %%{init: {"theme": "base", "themeVariables": {"fontFamily": "Arial", "fontSize": "15px", "actorBkg": "#f8fafc", "actorTextColor": "#0f172a", "actorBorder": "#94a3b8", "actorLineColor": "#94a3b8", "signalColor": "#64748b", "signalTextColor": "#334155", "activationBkgColor": "#eff6ff", "activationBorderColor": "#2563eb", "sequenceNumberColor": "#ffffff"}, "sequence": {"mirrorActors": false, "actorMargin": 56, "messageMargin": 36}}}%%
255
+ sequenceDiagram
256
+ accTitle: Proxy request and response lifecycle
257
+ accDescr: The client sends a provider-shaped request to Tokenfold Proxy, which applies lossless transforms and forwards the compact request with Authorization unchanged. The upstream response returns through the proxy.
258
+ autonumber
259
+ participant C as Client / Agent
260
+ participant P as Tokenfold Proxy
261
+ participant U as Upstream LLM
262
+ C->>+P: Provider-shaped request
263
+ P->>P: Apply lossless transforms
264
+ P->>+U: Compact request + unchanged Authorization
265
+ U-->>-P: Completion / action
266
+ P-->>-C: Response
267
+ ```
259
268
 
260
269
  ### Interfaces
261
270
 
@@ -298,8 +307,15 @@ print(f"Saved {result.report.saved_tokens} tokens ({result.saved_pct():.1f}%)")
298
307
  | `balanced` (default) | Minification plus reversible columnar folding (`json_field_fold`, `json_value_dict`, `log_field_fold`) on eligible formats. |
299
308
  | `aggressive` | Same default transform set as `balanced` today. |
300
309
 
301
- Provider message formats (`openai_json`, `anthropic_json`) never receive
302
- columnar folding: only minification applies, so API shapes stay intact.
310
+ Provider message formats (`openai_json`, `anthropic_json`) use minification
311
+ only; columnar folding applies to generic JSON (`--format json`). The default
312
+ proxy path follows this rule. Explicit `--observations` enables lossless
313
+ compression of eligible JSON tool-result strings on `/v1/chat/completions`
314
+ without folding the provider envelope; see [observation compression](docs/configuration.md#restart-safe-observation-commitments).
315
+
316
+ > [!NOTE]
317
+ > `schema_compaction` is not enabled by any preset. Unlike the default
318
+ > transforms, it truncates `examples` arrays and is not reversible.
303
319
 
304
320
  ### Runnable examples (Python >=3.9, Node.js >=22, Rust >=1.98)
305
321
 
@@ -349,7 +365,7 @@ are available through `tokenfold filters list`.
349
365
  ### Structural, not semantic compression
350
366
 
351
367
  Semantic prompt compressors such as [LLMLingua](https://github.com/microsoft/LLMLingua) use a smaller language model to identify and remove less-important prompt tokens.
352
- Tokenfold solves a different problem first: repeated keys, values, schemas, rows, and other structural redundancy. Core needs no model, is deterministic, and verifies an exact decode before accepting a lossless transform. Tokenfold does not inject prompt guidance or fine-tune models. Exact decode proves data recovery, not unchanged downstream task accuracy; validate folded payloads with your representative workload.
368
+ Tokenfold solves a different problem first: repeated keys, values, schemas, rows, and other structural redundancy. Core needs no model, is deterministic, and verifies an exact decode before accepting a lossless transform. Core does not inject prompt guidance or fine-tune models.
353
369
 
354
370
  [Tokenfold Select](#tokenfold-select) is Tokenfold's complementary query-aware offering: when structure ends, it ranks what matters under a token budget.
355
371
 
@@ -361,8 +377,31 @@ Tokenfold solves a different problem first: repeated keys, values, schemas, rows
361
377
 
362
378
  **When structure ends, rank what matters.**
363
379
 
380
+ [Tokenfold Select v3][tokenfold-select] is an Apache-2.0, **149.6M-parameter**
381
+ joint-group scorer built on the full 22-layer Ettin encoder. It scores groups
382
+ against the query and their neighbors within each window; your allocator keeps
383
+ selected source text unchanged, protects required content, and enforces the exact
384
+ token budget. The model returns scores, not a compressed string or calibrated
385
+ probabilities. Core remains model-free and neither loads nor invokes Select.
386
+
387
+ Use the [v3 model card][tokenfold-select] for the included custom loader and
388
+ explicit CPU/FP32 or CUDA/BF16 setup. The older Granite/LoRA model is Select v1,
389
+ not the v3 architecture or loader.
390
+
391
+ | | Tokenfold Core | Tokenfold Select |
392
+ | --- | --- | --- |
393
+ | Best at | Structural compression | Query-conditioned group ranking |
394
+ | Runtime | Static Rust binary | Ettin 150M encoder (v3), CPU or CUDA |
395
+ | Output | Compressed payload + exact receipt | Group relevance scores; caller-owned allocation |
396
+
397
+ <details>
398
+ <summary><strong>Released tokenfold-select 0.5.3 package: Select v2 setup</strong></summary>
399
+
400
+ V3 is provisioned separately through its model card. The released 0.5.3 package
401
+ continues to use the v2 backend below; this README update does not change it.
402
+
364
403
  **Select v2 is the default scorer backend in the optional `tokenfold-select`
365
- 0.5.2 package: local FP32 ONNX inference, original text, whole-group ranking.**
404
+ 0.5.3 package: local FP32 ONNX inference, original text, whole-group ranking.**
366
405
  Provision the separate pinned model artifact, generate explicit runtime approval,
367
406
  and invoke `tokenfold --experimental select`. Core remains model-free and
368
407
  deterministic; installing or upgrading Tokenfold does not silently load a model
@@ -377,7 +416,7 @@ keeps model execution off until you explicitly enable it.
377
416
  <details>
378
417
  <summary><strong>Python: try Tokenfold Select v2 (ONNX)</strong></summary>
379
418
 
380
- Install `tokenfold-select[onnx]==0.5.2` and `huggingface_hub==1.33.0`, then download
419
+ Install `tokenfold-select[onnx]==0.5.3` and `huggingface_hub==1.33.0`, then download
381
420
  only the ONNX profile at the pinned release commit:
382
421
 
383
422
  ```python
@@ -405,22 +444,10 @@ Transformers classification class. Neither format silently changes Core behavior
405
444
 
406
445
  </details>
407
446
 
408
- ### Tokenfold Select v1 (legacy model)
409
-
410
- The separately published Select v1 is an Apache-2.0 LoRA adapter on
411
- `ibm-granite/granite-embedding-reranker-english-r2`. It scores candidate spans
412
- against a query; your allocator applies the token budget and force-keeps
413
- required content. It is a separately distributed offering. Core remains
414
- model-free and deterministic and neither loads nor invokes Select.
415
-
416
- | | Tokenfold Core | Tokenfold Select |
417
- | --- | --- | --- |
418
- | Best at | Structural compression | Query-conditioned span ranking |
419
- | Runtime | Static Rust binary | Granite reranker + LoRA adapter |
420
- | Output | Compressed payload + exact receipt | Ranking logits |
447
+ </details>
421
448
 
422
449
  <details>
423
- <summary><strong>Legacy v1 Python: load the LoRA adapter and score spans</strong></summary>
450
+ <summary><strong>Archived Select v1: Granite + LoRA scoring example (not v3)</strong></summary>
424
451
 
425
452
  ```python
426
453
  from pathlib import Path
@@ -461,14 +488,79 @@ def score(query: str, spans: list[str]) -> list[float]:
461
488
 
462
489
  </details>
463
490
 
464
- ### Tokenfold Select v1 benchmarks (not v2 evidence)
491
+ ### Tokenfold Select v3 benchmarks
492
+
493
+ Saved results from the [published v3 benchmark snapshot](https://huggingface.co/snchimata/tokenfold-select-v3/blob/317d3424d3de78c1a708c42a47a7812ab877f1a8/README.md),
494
+ pinned to model-card revision `317d3424d3de78c1a708c42a47a7812ab877f1a8`.
495
+ These measurements include the scorer **and whole-group allocator**, not the
496
+ scoring model alone. Core's lossless benchmarks remain separate below.
497
+
498
+ #### Context-token reduction at a 50% budget
499
+
500
+ Select v3 removed **50.0-60.0%** of the original context tokens in these five
501
+ saved development examples. Both models had the same exact `o200k_base` output
502
+ cap for each workload; retained V3 groups were copied without rewriting.
503
+
504
+ | Workload | Original tokens | Select v3 output | V3 reduction | Kompress v2 output |
505
+ | --- | ---: | ---: | ---: | ---: |
506
+ | Code | 4,411 | 2,205 | **50.0%** | 2,149 |
507
+ | JSON | 1,303 | 651 | **50.0%** | Refused; 1,303 raw |
508
+ | Logs | 1,103 | 503 | **54.4%** | Refused; 1,103 raw |
509
+ | Multi-turn | 587 | 235 | **60.0%** | 284 |
510
+ | Retrieval | 4,498 | 2,217 | **50.7%** | 2,219 |
465
511
 
466
- [Tokenfold Select][tokenfold-select] is Tokenfold's query-aware model for choosing
467
- what fills a tight context window after structural compression ends.
468
- It is distributed and evaluated separately; Tokenfold Core does not invoke it.
469
- Headroom's generic JSON engine is evaluated above; this table evaluates
470
- Kompress-v2, Headroom Labs' query-aware selection baseline. These figures are
471
- source-reported external results, not Core CI results.
512
+ One exposed source per workload; JSON and logs share a source population.
513
+ Token reduction does not establish answer accuracy or semantic preservation.
514
+ Six of ten historical Kompress cells refused the budget across the 25%/50%
515
+ screen; refusals and raw fallbacks are **inconclusive, not V3 wins**. The
516
+ [full ten-cell history](https://huggingface.co/snchimata/tokenfold-select-v3/blob/317d3424d3de78c1a708c42a47a7812ab877f1a8/README.md#benchmark-methodology)
517
+ retains every result.
518
+
519
+ #### Resident-warm complete-request latency at a 50% budget
520
+
521
+ | Workload | Select v3 ms | Kompress v2 ms | V3 time difference | Measurement basis |
522
+ | --- | ---: | ---: | ---: | --- |
523
+ | Code | 146.088 | 200.304 | -27.1% | One historical request per model |
524
+ | Retrieval | 139.291 | 201.564 | -30.9% | One historical request per model |
525
+ | Multi-turn | 66.572 | 77.751 | -14.4% | Median of 5 requests per model |
526
+
527
+ Resident-warm RTX 5080 research pipelines, FP32 parameters/BF16 compute;
528
+ startup excluded. Separate time blocks, not controlled-idle or paired trials.
529
+ These are descriptive development observations, **not representative quality, population p50/p95, or superiority qualification**.
530
+
531
+ <details>
532
+ <summary><strong>Benchmark methodology and preserved history</strong></summary>
533
+
534
+ RTX 5080, FP32 parameters/BF16 compute, cache off, TF32 off, one Torch thread.
535
+ V3 used the serialized SDPA research runner; Kompress v2 used native EAGER.
536
+ Complete-request clocks include grouping, counting, IPC, scoring, allocation,
537
+ final recount and applicable teardown, but **exclude process/model startup and
538
+ conditioning**. They are not cold-CLI or quickstart-SDK latency measurements.
539
+
540
+ The models ran in separate time blocks. The five-request multi-turn repeat was
541
+ not controlled-idle: the GPU-busy admission gate was explicitly waived, with
542
+ pre-model busy observations of 25% and 38%. All five samples per model are
543
+ retained. The earlier multi-turn result was **69.362 ms vs 64.411 ms** (V3 time
544
+ 7.7% higher), and remains in the history rather than being replaced by the
545
+ repeat's sample medians.
546
+
547
+ The shared synthetic publisher-data pilot has incomplete comparator/answer
548
+ evaluation; its literal-substring checks are not answer accuracy. The separate
549
+ [partial answer-lookup evaluation](https://huggingface.co/snchimata/tokenfold-select-v3/blob/317d3424d3de78c1a708c42a47a7812ab877f1a8/QUALITY-EVAL.json)
550
+ also remains incomplete, with no overall quality score or qualified 90%
551
+ comparability claim.
552
+
553
+ Sources: [exact counts, timings, all repeat samples and refusals](https://huggingface.co/snchimata/tokenfold-select-v3/blob/317d3424d3de78c1a708c42a47a7812ab877f1a8/COMPARISON.json),
554
+ [validation](https://huggingface.co/snchimata/tokenfold-select-v3/blob/317d3424d3de78c1a708c42a47a7812ab877f1a8/VALIDATION.json), and
555
+ [full methodology](https://huggingface.co/snchimata/tokenfold-select-v3/blob/317d3424d3de78c1a708c42a47a7812ab877f1a8/README.md#benchmark-methodology).
556
+ </details>
557
+
558
+ <details>
559
+ <summary><strong>Historical Select v1 benchmarks (not v3 results)</strong></summary>
560
+
561
+ The original [Tokenfold Select v1][tokenfold-select-v1] model card reports the
562
+ following literal-answer-retention results against Kompress-v2 and BM25.
563
+ These are source-reported external results, not Core CI or v3 results.
472
564
 
473
565
  | Tokens kept | Tokenfold Select | Kompress-v2 (Headroom) native | Kompress-v2 (Headroom) relevance | BM25 | vs. best baseline |
474
566
  | ---: | ---: | ---: | ---: | ---: | ---: |
@@ -476,21 +568,23 @@ source-reported external results, not Core CI results.
476
568
  | 25% | **70.3%** | 47.2% | 61.5% | 60.7% | **+8.8 pp** |
477
569
  | 10% | **39.9%** | 30.4% | 37.7% | 37.7% | **+2.2 pp** |
478
570
 
479
- Tokenfold Select beat every measured baseline at every budget. At a 25% budget,
480
- the fine-tuned ranker keeps the answer **70.3% of the time**: an **8.8 percentage
481
- point** lead over the strongest baseline (Kompress-v2 relevance, 61.5%), and a
571
+ In this v1 evaluation, Select beat every measured baseline at every budget.
572
+ At a 25% budget, the fine-tuned ranker keeps the answer **70.3% of the time**:
573
+ an **8.8 percentage-point** lead over the strongest baseline (Kompress-v2 relevance, 61.5%), and a
482
574
  **15.8% relative lift** over BM25 (60.7% -> 70.3%). Critical-content survival is
483
575
  **100% at every measured budget** through allocator force-keep. Results are
484
576
  three-seed repeated subsampling over roughly 73,000 training and 24,000
485
- held-out fixtures per run; the [model card][tokenfold-select] publishes the
577
+ held-out fixtures per run; the [v1 model card][tokenfold-select-v1] publishes the
486
578
  training recipe and full baseline set. Here, task success means the literal
487
579
  gold answer survived selection under the stated budget.
488
580
  These are source-reported external results, pinned by model revision in the
489
581
  [metric manifest](tests/fixtures/readme_metrics.json); Core CI does not reproduce them.
490
582
 
491
- See the [Tokenfold Select model card][tokenfold-select] for setup, evaluation,
583
+ See the [Select v1 model card][tokenfold-select-v1] for its setup, evaluation,
492
584
  training data, and limitations.
493
585
 
586
+ </details>
587
+
494
588
  <br />
495
589
 
496
590
  ## Measured results
@@ -754,6 +848,9 @@ already-compressed JSON representation.
754
848
  - **Local control:** detected secrets are redacted before reports or storage;
755
849
  policy learning changes configuration only with `--apply`.
756
850
 
851
+ Exact decode proves data recovery, not unchanged downstream task accuracy.
852
+ Validate folded payloads with your representative workload.
853
+
757
854
  The offline fidelity gate uses deterministic lexical-overlap, critical-token,
758
855
  and containment proxies. Those checks catch regressions but do not establish
759
856
  semantic equivalence or downstream task success. Runtime `quality` fields are
@@ -830,5 +927,6 @@ If Tokenfold earns a place in your stack, a star on
830
927
 
831
928
  </div>
832
929
 
833
- [tokenfold-select]: https://huggingface.co/snchimata/tokenfold-select
930
+ [tokenfold-select]: https://huggingface.co/snchimata/tokenfold-select-v3
931
+ [tokenfold-select-v1]: https://huggingface.co/snchimata/tokenfold-select
834
932
 
@@ -71,14 +71,14 @@ cargo add tokenfold-core # Rust library
71
71
  <br />
72
72
  <strong>Model-free &amp; deterministic</strong>
73
73
  <br /><br />
74
- No GPU, no semantic guesswork, no model in the Core path. Validate folded payloads on your workload: exact decode proves data recovery, not unchanged model behavior. Provider-neutral by design.
74
+ No GPU, no semantic guesswork, no model in the Core path. A Rust engine with Python, Node.js, CLI and proxy interfaces.
75
75
  <br /><br />
76
76
  </td>
77
77
  </tr>
78
78
  </table>
79
79
 
80
80
  > [!NOTE]
81
- > **Built for:** Developers and AI teams cutting latency and API costs on structured JSON, tool definitions, and RAG feeds. Exact decode proves data recovery, not unchanged downstream task accuracy - validate folded payloads with your representative workload. Ideal for applications sending large JSON tool payloads, tool-calling agent loops (Claude Code, Codex), and structured RAG feeds where token overhead drives latency and cost.
81
+ > **Built for:** Developers and AI teams sending structured JSON, tool definitions, and RAG feeds to LLMs. Start with a representative payload, inspect the receipt, and validate the result in your application.
82
82
 
83
83
  <br />
84
84
 
@@ -95,12 +95,17 @@ cargo add tokenfold-core # Rust library
95
95
  {"__tf_cols__":["id","role"],"__tf_rows__":[[1,"admin"],[2,"member"]]}
96
96
  ```
97
97
 
98
- ```mermaid
99
- %%{init: {"theme": "base", "themeVariables": {"primaryColor": "#22D3EE", "primaryTextColor": "#0b1020", "primaryBorderColor": "#A855F7", "lineColor": "#A855F7", "fontFamily": "ui-sans-serif, system-ui, sans-serif"}}}%%
100
- flowchart LR
101
- In["Repeated keys in every record<br/>id, role, id, role"] --> TF[Tokenfold Core]
102
- TF --> Out["Keys named once as columns<br/>values packed into rows"]
103
- ```
98
+ ![Terminal demo: Tokenfold reduces the bundled API response from 3,812 to 1,376 tokens.](https://raw.githubusercontent.com/snchimata/tokenfold/main/docs/assets/tokenfold-demo.gif)
99
+
100
+ <details>
101
+ <summary><strong>How this demo was generated (VHS tape)</strong></summary>
102
+
103
+ The [VHS tape](docs/tokenfold-demo.tape) runs `inspect`, `compress`, and
104
+ `decode` against the bundled API response, including the **63.9%** receipt.
105
+ Run `vhs docs/tokenfold-demo.tape` to regenerate the GIF; the tape requires
106
+ `tokenfold` on `PATH`.
107
+
108
+ </details>
104
109
 
105
110
  Send the folded JSON directly to the model: column names label each value's
106
111
  position in every row. Decode only when your application needs the original
@@ -111,7 +116,7 @@ object shape again.
111
116
  - **Targets structured JSON, not prose.** Folds repeated keys and columns
112
117
  mechanically rather than using semantic guesswork.
113
118
  - **Model-free and deterministic.** Zero models running in Core and zero GPU
114
- overhead. Exact decode proves data recovery, not unchanged model behavior.
119
+ overhead.
115
120
  - **Verified by exact decode.** Every lossless transform is verified by an
116
121
  in-memory round trip before emitting; lossy pruning is strictly opt-in and
117
122
  recoverable.
@@ -120,60 +125,38 @@ For tabular arrays, Tokenfold folds repeated keys into
120
125
  header columns (`__tf_cols__`). No model runs in the Core engine, and every
121
126
  lossless transform is verified by exact decode.
122
127
 
123
- > [!NOTE]
124
- > `schema_compaction` is not enabled by any preset. Unlike the default
125
- > transforms, it truncates `examples` arrays and is not reversible.
128
+ #### How Tokenfold decides what to fold
126
129
 
127
130
  ```mermaid
128
- %%{init: {"theme": "base", "themeVariables": {"primaryColor": "#22D3EE", "primaryTextColor": "#0b1020", "primaryBorderColor": "#A855F7", "lineColor": "#A855F7", "fontFamily": "ui-sans-serif, system-ui, sans-serif"}}}%%
131
+ %%{init: {"theme": "base", "themeVariables": {"primaryColor": "#f8fafc", "primaryTextColor": "#0f172a", "primaryBorderColor": "#94a3b8", "lineColor": "#64748b", "edgeLabelBackground": "#f8fafc", "fontFamily": "Arial", "fontSize": "15px"}, "flowchart": {"curve": "linear", "padding": 16, "nodeSpacing": 40, "rankSpacing": 32}}}%%
129
132
  flowchart LR
130
- App[Application / Agent] -->|Large JSON / tool schemas| TF[Tokenfold Core]
131
- TF -->|Lossless structural JSON| LLM[LLM provider]
132
- LLM -->|Completion / action| App
133
- TF -.->|Optional exact decode of folded payload| App
133
+ accTitle: Lossless first, pruning only when opted in
134
+ accDescr: Build a verified lossless baseline. Consider pruning only when opted in, eligible, and still needed. Store omissions before removal and use pruning only if it beats the lossless baseline; otherwise keep that baseline.
135
+ Lossless["Build lossless JSON baseline<br/>Verify folds; retain savings"] --> OptIn{"Pruning enabled,<br/>eligible and needed?"}
136
+ OptIn -->|No| Keep("Lossless payload<br/>+ receipt")
137
+ OptIn -->|Yes| Prune["Rank eligible rows<br/>Store before removal"]
138
+ Prune -->|No further savings| Keep
139
+ Prune -->|Fewer tokens than baseline| Emit("Pruned payload<br/>+ markers and receipt")
140
+
141
+ classDef core fill:#eff6ff,stroke:#2563eb,stroke-width:2px,color:#1e3a8a
142
+ classDef optional fill:#f8fafc,stroke:#64748b,stroke-dasharray:5 4,color:#334155
143
+ class Lossless,Keep core
144
+ class Prune optional
134
145
  ```
135
146
 
136
- #### How Tokenfold decides what to fold
137
-
138
- ![Flowchart: incoming JSON is folded when tabular, optionally pruned when heterogeneous, verified by exact round-trip, and emitted only when smaller; otherwise compact JSON is kept.](https://raw.githubusercontent.com/snchimata/tokenfold/b1ea4a545c174578adb3eaf7c39ab0b6fb1523f3/docs/assets/tokenfold-decision-flow.svg)
139
-
140
147
  <details>
141
148
  <summary><strong>Text version (screen readers / no-image fallback)</strong></summary>
142
149
 
143
- 1. Incoming JSON payload arrives.
144
- 2. Tabular shape? Yes: fold repeated keys into columns. No (heterogeneous
145
- feed): continue only when lossy pruning is opted in (rank rows, store
146
- dropped rows locally).
147
- 3. Verify with an exact decode round trip.
148
- 4. Smaller than input? Yes: emit folded payload + receipt. No: keep compact
149
- JSON (never larger).
150
-
151
- </details>
152
-
153
- #### Proxy / agent round trip
154
-
155
- ```mermaid
156
- %%{init: {"theme": "base", "themeVariables": {"primaryColor": "#22D3EE", "primaryTextColor": "#0b1020", "primaryBorderColor": "#A855F7", "lineColor": "#A855F7", "actorBkg": "#22D3EE", "actorTextColor": "#0b1020", "actorBorder": "#A855F7", "signalColor": "#A855F7", "signalTextColor": "#334155", "fontFamily": "ui-sans-serif, system-ui, sans-serif"}}}%%
157
- sequenceDiagram
158
- participant C as Client / Agent
159
- participant P as Tokenfold Proxy
160
- participant U as Upstream LLM
161
- C->>P: Provider-shaped request (large JSON)
162
- P->>P: Apply lossless transforms
163
- P->>U: Forwarded compact request
164
- U-->>P: Completion / action
165
- P-->>C: Response (Authorization forwarded unchanged)
166
- ```
167
-
168
- ![Terminal demo: Tokenfold reduces the bundled API response from 3,812 to 1,376 tokens.](https://raw.githubusercontent.com/snchimata/tokenfold/main/docs/assets/tokenfold-demo.gif)
169
-
170
- <details>
171
- <summary><strong>How this demo was generated (VHS tape)</strong></summary>
172
-
173
- The [VHS tape](docs/tokenfold-demo.tape) runs `inspect`, `compress`, and
174
- `decode` against the bundled API response, including the **63.9%** receipt.
175
- Run `vhs docs/tokenfold-demo.tape` to regenerate the GIF; the tape requires
176
- `tokenfold` on `PATH`.
150
+ 1. Build the lossless baseline using eligible transforms. Verify structural
151
+ folds with an exact decode round trip and keep only token reductions.
152
+ 2. Consider pruning only when explicitly opted in, the payload is eligible,
153
+ and the lossless baseline has not already met a requested token target.
154
+ 3. Rank eligible rows and store omissions locally before removing them.
155
+ Rows refused by storage stay inline.
156
+ 4. Use the pruned payload only if it has fewer tokens than the lossless
157
+ baseline; otherwise keep the lossless baseline.
158
+ 5. Emit the chosen payload and compression receipt. Pruned payloads include
159
+ retrieval markers for stored omissions.
177
160
 
178
161
  </details>
179
162
 
@@ -202,6 +185,24 @@ cargo install tokenfold-proxy
202
185
  tokenfold-proxy --upstream https://api.openai.com
203
186
  ```
204
187
 
188
+ ```python
189
+ from openai import OpenAI
190
+
191
+ # Your client's Authorization header is forwarded to upstream unchanged -
192
+ # no credential reconfiguration needed.
193
+ client = OpenAI(base_url="http://127.0.0.1:8787/v1")
194
+ # Existing calls work unchanged: client.chat.completions.create(...)
195
+ ```
196
+
197
+ The proxy listens on loopback (`127.0.0.1:8787`) by default.
198
+ Provider envelopes are minified, not columnar-folded.
199
+
200
+ Works out-of-the-box with any client or framework that accepts a custom base URL
201
+ (LangChain, LlamaIndex, LiteLLM, Instructor, or direct HTTP clients).
202
+
203
+ <details>
204
+ <summary><strong>Proxy routing, streaming, and stderr telemetry details</strong></summary>
205
+
205
206
  The proxy installs from source via Cargo and listens on `127.0.0.1:8787` by
206
207
  default (`--bind`; use `--allow-non-loopback-bind` to change that). Only
207
208
  chat-shaped JSON bodies (a non-empty `messages` array) are compressed on the
@@ -223,17 +224,25 @@ attempt ended. A provider that reports no usage, or a body whose usage cannot
223
224
  be read cleanly, records `usage_disposition: absent|malformed|oversized` with a
224
225
  `null` count rather than a zero -- and never changes what is forwarded.
225
226
 
226
- ```python
227
- from openai import OpenAI
227
+ </details>
228
228
 
229
- # Your client's Authorization header is forwarded to upstream unchanged -
230
- # no credential reconfiguration needed.
231
- client = OpenAI(base_url="http://127.0.0.1:8787/v1")
232
- # Existing calls work unchanged: client.chat.completions.create(...)
233
- ```
229
+ #### Proxy / agent round trip
234
230
 
235
- Works out-of-the-box with any client or framework that accepts a custom base URL
236
- (LangChain, LlamaIndex, LiteLLM, Instructor, or direct HTTP clients).
231
+ ```mermaid
232
+ %%{init: {"theme": "base", "themeVariables": {"fontFamily": "Arial", "fontSize": "15px", "actorBkg": "#f8fafc", "actorTextColor": "#0f172a", "actorBorder": "#94a3b8", "actorLineColor": "#94a3b8", "signalColor": "#64748b", "signalTextColor": "#334155", "activationBkgColor": "#eff6ff", "activationBorderColor": "#2563eb", "sequenceNumberColor": "#ffffff"}, "sequence": {"mirrorActors": false, "actorMargin": 56, "messageMargin": 36}}}%%
233
+ sequenceDiagram
234
+ accTitle: Proxy request and response lifecycle
235
+ accDescr: The client sends a provider-shaped request to Tokenfold Proxy, which applies lossless transforms and forwards the compact request with Authorization unchanged. The upstream response returns through the proxy.
236
+ autonumber
237
+ participant C as Client / Agent
238
+ participant P as Tokenfold Proxy
239
+ participant U as Upstream LLM
240
+ C->>+P: Provider-shaped request
241
+ P->>P: Apply lossless transforms
242
+ P->>+U: Compact request + unchanged Authorization
243
+ U-->>-P: Completion / action
244
+ P-->>-C: Response
245
+ ```
237
246
 
238
247
  ### Interfaces
239
248
 
@@ -276,8 +285,15 @@ print(f"Saved {result.report.saved_tokens} tokens ({result.saved_pct():.1f}%)")
276
285
  | `balanced` (default) | Minification plus reversible columnar folding (`json_field_fold`, `json_value_dict`, `log_field_fold`) on eligible formats. |
277
286
  | `aggressive` | Same default transform set as `balanced` today. |
278
287
 
279
- Provider message formats (`openai_json`, `anthropic_json`) never receive
280
- columnar folding: only minification applies, so API shapes stay intact.
288
+ Provider message formats (`openai_json`, `anthropic_json`) use minification
289
+ only; columnar folding applies to generic JSON (`--format json`). The default
290
+ proxy path follows this rule. Explicit `--observations` enables lossless
291
+ compression of eligible JSON tool-result strings on `/v1/chat/completions`
292
+ without folding the provider envelope; see [observation compression](docs/configuration.md#restart-safe-observation-commitments).
293
+
294
+ > [!NOTE]
295
+ > `schema_compaction` is not enabled by any preset. Unlike the default
296
+ > transforms, it truncates `examples` arrays and is not reversible.
281
297
 
282
298
  ### Runnable examples (Python >=3.9, Node.js >=22, Rust >=1.98)
283
299
 
@@ -327,7 +343,7 @@ are available through `tokenfold filters list`.
327
343
  ### Structural, not semantic compression
328
344
 
329
345
  Semantic prompt compressors such as [LLMLingua](https://github.com/microsoft/LLMLingua) use a smaller language model to identify and remove less-important prompt tokens.
330
- Tokenfold solves a different problem first: repeated keys, values, schemas, rows, and other structural redundancy. Core needs no model, is deterministic, and verifies an exact decode before accepting a lossless transform. Tokenfold does not inject prompt guidance or fine-tune models. Exact decode proves data recovery, not unchanged downstream task accuracy; validate folded payloads with your representative workload.
346
+ Tokenfold solves a different problem first: repeated keys, values, schemas, rows, and other structural redundancy. Core needs no model, is deterministic, and verifies an exact decode before accepting a lossless transform. Core does not inject prompt guidance or fine-tune models.
331
347
 
332
348
  [Tokenfold Select](#tokenfold-select) is Tokenfold's complementary query-aware offering: when structure ends, it ranks what matters under a token budget.
333
349
 
@@ -339,8 +355,31 @@ Tokenfold solves a different problem first: repeated keys, values, schemas, rows
339
355
 
340
356
  **When structure ends, rank what matters.**
341
357
 
358
+ [Tokenfold Select v3][tokenfold-select] is an Apache-2.0, **149.6M-parameter**
359
+ joint-group scorer built on the full 22-layer Ettin encoder. It scores groups
360
+ against the query and their neighbors within each window; your allocator keeps
361
+ selected source text unchanged, protects required content, and enforces the exact
362
+ token budget. The model returns scores, not a compressed string or calibrated
363
+ probabilities. Core remains model-free and neither loads nor invokes Select.
364
+
365
+ Use the [v3 model card][tokenfold-select] for the included custom loader and
366
+ explicit CPU/FP32 or CUDA/BF16 setup. The older Granite/LoRA model is Select v1,
367
+ not the v3 architecture or loader.
368
+
369
+ | | Tokenfold Core | Tokenfold Select |
370
+ | --- | --- | --- |
371
+ | Best at | Structural compression | Query-conditioned group ranking |
372
+ | Runtime | Static Rust binary | Ettin 150M encoder (v3), CPU or CUDA |
373
+ | Output | Compressed payload + exact receipt | Group relevance scores; caller-owned allocation |
374
+
375
+ <details>
376
+ <summary><strong>Released tokenfold-select 0.5.3 package: Select v2 setup</strong></summary>
377
+
378
+ V3 is provisioned separately through its model card. The released 0.5.3 package
379
+ continues to use the v2 backend below; this README update does not change it.
380
+
342
381
  **Select v2 is the default scorer backend in the optional `tokenfold-select`
343
- 0.5.2 package: local FP32 ONNX inference, original text, whole-group ranking.**
382
+ 0.5.3 package: local FP32 ONNX inference, original text, whole-group ranking.**
344
383
  Provision the separate pinned model artifact, generate explicit runtime approval,
345
384
  and invoke `tokenfold --experimental select`. Core remains model-free and
346
385
  deterministic; installing or upgrading Tokenfold does not silently load a model
@@ -355,7 +394,7 @@ keeps model execution off until you explicitly enable it.
355
394
  <details>
356
395
  <summary><strong>Python: try Tokenfold Select v2 (ONNX)</strong></summary>
357
396
 
358
- Install `tokenfold-select[onnx]==0.5.2` and `huggingface_hub==1.33.0`, then download
397
+ Install `tokenfold-select[onnx]==0.5.3` and `huggingface_hub==1.33.0`, then download
359
398
  only the ONNX profile at the pinned release commit:
360
399
 
361
400
  ```python
@@ -383,22 +422,10 @@ Transformers classification class. Neither format silently changes Core behavior
383
422
 
384
423
  </details>
385
424
 
386
- ### Tokenfold Select v1 (legacy model)
387
-
388
- The separately published Select v1 is an Apache-2.0 LoRA adapter on
389
- `ibm-granite/granite-embedding-reranker-english-r2`. It scores candidate spans
390
- against a query; your allocator applies the token budget and force-keeps
391
- required content. It is a separately distributed offering. Core remains
392
- model-free and deterministic and neither loads nor invokes Select.
393
-
394
- | | Tokenfold Core | Tokenfold Select |
395
- | --- | --- | --- |
396
- | Best at | Structural compression | Query-conditioned span ranking |
397
- | Runtime | Static Rust binary | Granite reranker + LoRA adapter |
398
- | Output | Compressed payload + exact receipt | Ranking logits |
425
+ </details>
399
426
 
400
427
  <details>
401
- <summary><strong>Legacy v1 Python: load the LoRA adapter and score spans</strong></summary>
428
+ <summary><strong>Archived Select v1: Granite + LoRA scoring example (not v3)</strong></summary>
402
429
 
403
430
  ```python
404
431
  from pathlib import Path
@@ -439,14 +466,79 @@ def score(query: str, spans: list[str]) -> list[float]:
439
466
 
440
467
  </details>
441
468
 
442
- ### Tokenfold Select v1 benchmarks (not v2 evidence)
469
+ ### Tokenfold Select v3 benchmarks
470
+
471
+ Saved results from the [published v3 benchmark snapshot](https://huggingface.co/snchimata/tokenfold-select-v3/blob/317d3424d3de78c1a708c42a47a7812ab877f1a8/README.md),
472
+ pinned to model-card revision `317d3424d3de78c1a708c42a47a7812ab877f1a8`.
473
+ These measurements include the scorer **and whole-group allocator**, not the
474
+ scoring model alone. Core's lossless benchmarks remain separate below.
475
+
476
+ #### Context-token reduction at a 50% budget
477
+
478
+ Select v3 removed **50.0-60.0%** of the original context tokens in these five
479
+ saved development examples. Both models had the same exact `o200k_base` output
480
+ cap for each workload; retained V3 groups were copied without rewriting.
481
+
482
+ | Workload | Original tokens | Select v3 output | V3 reduction | Kompress v2 output |
483
+ | --- | ---: | ---: | ---: | ---: |
484
+ | Code | 4,411 | 2,205 | **50.0%** | 2,149 |
485
+ | JSON | 1,303 | 651 | **50.0%** | Refused; 1,303 raw |
486
+ | Logs | 1,103 | 503 | **54.4%** | Refused; 1,103 raw |
487
+ | Multi-turn | 587 | 235 | **60.0%** | 284 |
488
+ | Retrieval | 4,498 | 2,217 | **50.7%** | 2,219 |
443
489
 
444
- [Tokenfold Select][tokenfold-select] is Tokenfold's query-aware model for choosing
445
- what fills a tight context window after structural compression ends.
446
- It is distributed and evaluated separately; Tokenfold Core does not invoke it.
447
- Headroom's generic JSON engine is evaluated above; this table evaluates
448
- Kompress-v2, Headroom Labs' query-aware selection baseline. These figures are
449
- source-reported external results, not Core CI results.
490
+ One exposed source per workload; JSON and logs share a source population.
491
+ Token reduction does not establish answer accuracy or semantic preservation.
492
+ Six of ten historical Kompress cells refused the budget across the 25%/50%
493
+ screen; refusals and raw fallbacks are **inconclusive, not V3 wins**. The
494
+ [full ten-cell history](https://huggingface.co/snchimata/tokenfold-select-v3/blob/317d3424d3de78c1a708c42a47a7812ab877f1a8/README.md#benchmark-methodology)
495
+ retains every result.
496
+
497
+ #### Resident-warm complete-request latency at a 50% budget
498
+
499
+ | Workload | Select v3 ms | Kompress v2 ms | V3 time difference | Measurement basis |
500
+ | --- | ---: | ---: | ---: | --- |
501
+ | Code | 146.088 | 200.304 | -27.1% | One historical request per model |
502
+ | Retrieval | 139.291 | 201.564 | -30.9% | One historical request per model |
503
+ | Multi-turn | 66.572 | 77.751 | -14.4% | Median of 5 requests per model |
504
+
505
+ Resident-warm RTX 5080 research pipelines, FP32 parameters/BF16 compute;
506
+ startup excluded. Separate time blocks, not controlled-idle or paired trials.
507
+ These are descriptive development observations, **not representative quality, population p50/p95, or superiority qualification**.
508
+
509
+ <details>
510
+ <summary><strong>Benchmark methodology and preserved history</strong></summary>
511
+
512
+ RTX 5080, FP32 parameters/BF16 compute, cache off, TF32 off, one Torch thread.
513
+ V3 used the serialized SDPA research runner; Kompress v2 used native EAGER.
514
+ Complete-request clocks include grouping, counting, IPC, scoring, allocation,
515
+ final recount and applicable teardown, but **exclude process/model startup and
516
+ conditioning**. They are not cold-CLI or quickstart-SDK latency measurements.
517
+
518
+ The models ran in separate time blocks. The five-request multi-turn repeat was
519
+ not controlled-idle: the GPU-busy admission gate was explicitly waived, with
520
+ pre-model busy observations of 25% and 38%. All five samples per model are
521
+ retained. The earlier multi-turn result was **69.362 ms vs 64.411 ms** (V3 time
522
+ 7.7% higher), and remains in the history rather than being replaced by the
523
+ repeat's sample medians.
524
+
525
+ The shared synthetic publisher-data pilot has incomplete comparator/answer
526
+ evaluation; its literal-substring checks are not answer accuracy. The separate
527
+ [partial answer-lookup evaluation](https://huggingface.co/snchimata/tokenfold-select-v3/blob/317d3424d3de78c1a708c42a47a7812ab877f1a8/QUALITY-EVAL.json)
528
+ also remains incomplete, with no overall quality score or qualified 90%
529
+ comparability claim.
530
+
531
+ Sources: [exact counts, timings, all repeat samples and refusals](https://huggingface.co/snchimata/tokenfold-select-v3/blob/317d3424d3de78c1a708c42a47a7812ab877f1a8/COMPARISON.json),
532
+ [validation](https://huggingface.co/snchimata/tokenfold-select-v3/blob/317d3424d3de78c1a708c42a47a7812ab877f1a8/VALIDATION.json), and
533
+ [full methodology](https://huggingface.co/snchimata/tokenfold-select-v3/blob/317d3424d3de78c1a708c42a47a7812ab877f1a8/README.md#benchmark-methodology).
534
+ </details>
535
+
536
+ <details>
537
+ <summary><strong>Historical Select v1 benchmarks (not v3 results)</strong></summary>
538
+
539
+ The original [Tokenfold Select v1][tokenfold-select-v1] model card reports the
540
+ following literal-answer-retention results against Kompress-v2 and BM25.
541
+ These are source-reported external results, not Core CI or v3 results.
450
542
 
451
543
  | Tokens kept | Tokenfold Select | Kompress-v2 (Headroom) native | Kompress-v2 (Headroom) relevance | BM25 | vs. best baseline |
452
544
  | ---: | ---: | ---: | ---: | ---: | ---: |
@@ -454,21 +546,23 @@ source-reported external results, not Core CI results.
454
546
  | 25% | **70.3%** | 47.2% | 61.5% | 60.7% | **+8.8 pp** |
455
547
  | 10% | **39.9%** | 30.4% | 37.7% | 37.7% | **+2.2 pp** |
456
548
 
457
- Tokenfold Select beat every measured baseline at every budget. At a 25% budget,
458
- the fine-tuned ranker keeps the answer **70.3% of the time**: an **8.8 percentage
459
- point** lead over the strongest baseline (Kompress-v2 relevance, 61.5%), and a
549
+ In this v1 evaluation, Select beat every measured baseline at every budget.
550
+ At a 25% budget, the fine-tuned ranker keeps the answer **70.3% of the time**:
551
+ an **8.8 percentage-point** lead over the strongest baseline (Kompress-v2 relevance, 61.5%), and a
460
552
  **15.8% relative lift** over BM25 (60.7% -> 70.3%). Critical-content survival is
461
553
  **100% at every measured budget** through allocator force-keep. Results are
462
554
  three-seed repeated subsampling over roughly 73,000 training and 24,000
463
- held-out fixtures per run; the [model card][tokenfold-select] publishes the
555
+ held-out fixtures per run; the [v1 model card][tokenfold-select-v1] publishes the
464
556
  training recipe and full baseline set. Here, task success means the literal
465
557
  gold answer survived selection under the stated budget.
466
558
  These are source-reported external results, pinned by model revision in the
467
559
  [metric manifest](tests/fixtures/readme_metrics.json); Core CI does not reproduce them.
468
560
 
469
- See the [Tokenfold Select model card][tokenfold-select] for setup, evaluation,
561
+ See the [Select v1 model card][tokenfold-select-v1] for its setup, evaluation,
470
562
  training data, and limitations.
471
563
 
564
+ </details>
565
+
472
566
  <br />
473
567
 
474
568
  ## Measured results
@@ -732,6 +826,9 @@ already-compressed JSON representation.
732
826
  - **Local control:** detected secrets are redacted before reports or storage;
733
827
  policy learning changes configuration only with `--apply`.
734
828
 
829
+ Exact decode proves data recovery, not unchanged downstream task accuracy.
830
+ Validate folded payloads with your representative workload.
831
+
735
832
  The offline fidelity gate uses deterministic lexical-overlap, critical-token,
736
833
  and containment proxies. Those checks catch regressions but do not establish
737
834
  semantic equivalence or downstream task success. Runtime `quality` fields are
@@ -808,4 +905,5 @@ If Tokenfold earns a place in your stack, a star on
808
905
 
809
906
  </div>
810
907
 
811
- [tokenfold-select]: https://huggingface.co/snchimata/tokenfold-select
908
+ [tokenfold-select]: https://huggingface.co/snchimata/tokenfold-select-v3
909
+ [tokenfold-select-v1]: https://huggingface.co/snchimata/tokenfold-select
@@ -16,7 +16,7 @@ name = "tokenfold_py"
16
16
  crate-type = ["cdylib", "rlib"]
17
17
 
18
18
  [dependencies]
19
- tokenfold-core = { version = "0.5.2", path = "../tokenfold-core" }
19
+ tokenfold-core = { version = "0.5.3", path = "../tokenfold-core" }
20
20
  serde_json = { workspace = true }
21
21
  pyo3 = { version = "0.29.0", features = ["abi3-py39"] }
22
22
 
File without changes
File without changes