toolgz 0.2.6 → 0.2.7

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 (3) hide show
  1. package/README.md +13 -8
  2. package/dist/index.js +22 -1
  3. package/package.json +1 -1
package/README.md CHANGED
@@ -767,8 +767,8 @@ console.log(c.stats);
767
767
  // originalChars: 61461, compressedChars: 2211, savedPct: 96.4 }
768
768
  ```
769
769
 
770
- `savedPct` is a character-count proxy, not a token count useful for a quick
771
- sanity check, not for billing.
770
+ `savedPct` estimates the token saving (calibrated against `count_tokens`, ~1–2pp
771
+ accurate). `originalChars` and `compressedChars` give the raw character counts.
772
772
 
773
773
  **I need the real token numbers.**
774
774
  Count them with the provider's own endpoint. Never use `tiktoken` for Claude —
@@ -842,11 +842,16 @@ Returns:
842
842
  | `codeFor(name)` | `→ string` | real name → level-3 code; throws below level 3 |
843
843
  | `stats` | `CompressStats` | `level`, `mapStyle`, `requestedMapStyle`, `fallbackReason`, `toolCount`, `wireToolCount`, `originalChars`, `compressedChars`, `savedPct` |
844
844
 
845
- > **`savedPct` counts characters, not tokens and it overstates.** It is derived from
846
- > `countSchemaTokensApprox`, which is just `JSON.stringify(x).length`. On our real corpus
847
- > it reports ~97.8% where `count_tokens` measures **95.6%**. Use it as a cheap sanity
848
- > signal, never as a published figure; for anything you quote, measure with your
849
- > provider's token counter.
845
+ > **`savedPct` estimates tokens, and is accurate to a point or two.** It used to be a raw
846
+ > character ratio, which overstated by 7.6 points at level 1. Characters per token differs
847
+ > between the two sides uncompressed JSON is punctuation-dense, a signature line reads
848
+ > more like prose so it now divides each side by a ratio calibrated against
849
+ > `count_tokens` on two unrelated corpora. Current error on the real corpus: **+1.5pp at
850
+ > level 1, −0.3pp at level 2, +0.1pp at level 3.**
851
+ >
852
+ > It is still a local estimate with no API call. For a figure you publish, measure with
853
+ > your provider's token counter; `originalChars` and `compressedChars` are also on `stats`
854
+ > if you want the raw counts.
850
855
  | `encodeCallForTest(name, args)` | `→ {name, args}` | build the raw call a model would emit; test aid |
851
856
 
852
857
  ### `recommendLevel(tools, namespaceOf?) → Recommendation`
@@ -955,7 +960,7 @@ and it does not get deleted.
955
960
  ## Development
956
961
 
957
962
  ```bash
958
- npm test # 272 tests, offline, no cost
963
+ npm test # 277 tests, offline, no cost
959
964
  npm run build # tsc → dist/ with .d.ts
960
965
 
961
966
  npx tsx bench/harness/run-multi.ts --provider=all --reps=3 --variants # costs money
package/dist/index.js CHANGED
@@ -160,6 +160,27 @@ export function compress(input, options = {}) {
160
160
  };
161
161
  const finish = (wire, systemPreamble, cachePreamble, resolve, encode) => {
162
162
  const compressedChars = countSchemaTokensApprox(wire) + systemPreamble.length;
163
+ // `savedPct` is meant to answer "how much of my tool block did I get back", which is
164
+ // a TOKEN question. Deriving it from a raw character ratio answered a different one
165
+ // and overstated: on the real corpus it reported 46.8% at level 1 where count_tokens
166
+ // measures 39.2% — 7.6 points high, and the field was documented as "do not publish
167
+ // this" rather than fixed.
168
+ //
169
+ // Characters per token is not constant across the two sides. Uncompressed JSON is
170
+ // punctuation-dense; a signature line or a map row reads more like prose. Measured
171
+ // against count_tokens on two unrelated corpora (149 real MCP tools and a 100-tool
172
+ // synthetic fixture) the ratios are stable per level:
173
+ //
174
+ // uncompressed 2.39 / 2.45 level 2 2.20 / 1.99
175
+ // level 1 2.15 / 2.19 level 3 1.92 / 1.91
176
+ //
177
+ // Dividing by these brings the error to ~1.5 points at level 1 and ~0.1 at level 3.
178
+ // Still an estimate — it is a local calculation with no API call — but now an
179
+ // estimate of the right quantity.
180
+ const CHARS_PER_TOKEN = { 0: 2.42, 1: 2.17, 2: 2.1, 3: 1.92 };
181
+ const estTokens = (chars, at) => chars / CHARS_PER_TOKEN[at];
182
+ const originalTokens = estTokens(originalChars, 0);
183
+ const compressedTokens = estTokens(compressedChars, level);
163
184
  return {
164
185
  tools: wire,
165
186
  systemPreamble,
@@ -183,7 +204,7 @@ export function compress(input, options = {}) {
183
204
  compressedChars,
184
205
  savedPct: originalChars === 0
185
206
  ? 0
186
- : Math.round((1 - compressedChars / originalChars) * 1000) / 10,
207
+ : Math.round((1 - compressedTokens / originalTokens) * 1000) / 10,
187
208
  },
188
209
  };
189
210
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "toolgz",
3
- "version": "0.2.6",
3
+ "version": "0.2.7",
4
4
  "description": "Compress LLM tool definitions to reclaim context window. Measured across Anthropic, OpenAI, Google and xAI.",
5
5
  "main": "dist/index.js",
6
6
  "scripts": {