@sohqureshi/tokenwise 1.0.7 → 1.0.9

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.
package/README.md CHANGED
@@ -210,10 +210,24 @@ LLMs charge and reason over tokens. Sending raw JSON often includes repeated key
210
210
  node demo.js
211
211
  ```
212
212
 
213
- Use `--analyze` to compare serialized input and output with TokenWise's
214
- four-characters-per-token heuristic. For model-accurate counts, pass
215
- `exact: true` and a `model` name to `estimateTokens()` or `analyze()`.
216
- This is still only as exact as the tokenizer implementation you use.
213
+ Use `--analyze` to compare serialized input and output with the model's
214
+ `tiktoken` encoding. `estimateTokens()` and `analyze()` use exact
215
+ model-aware counts by default; pass `exact: false` to opt into the
216
+ four-characters-per-token heuristic. Use `model` to select the tokenizer
217
+ used by `tiktoken`.
218
+
219
+ ---
220
+
221
+ ## Release Notes
222
+
223
+ ### v1.0.8 — 2026-09-06
224
+
225
+ - Expose exact tokenizer metadata when available (model + encoding), and fall back to a clear, model-aware estimator in browser demos.
226
+ - Demo updated to show selected model and expected encoding when the exact tokenizer (tiktoken) is not available in-browser.
227
+ - Updated analyze() to surface tokenizer encoding in analysis output so the demo shows "Estimator: model=gpt-4 expected_encoding=cl100k_base" even when using the heuristic fallback.
228
+ - Misc: build artifacts updated and docs demo import bumped to v1.0.7 CDN bundle.
229
+
230
+ If you want the browser demo to display truly exact token counts, run the demo against a small Node endpoint (or local server) that has tiktoken installed and uses analyze(..., { exact: true }). The estimator will display the real tokenizer encoding when tiktoken is present.
217
231
 
218
232
  ---
219
233
 
@@ -13,12 +13,12 @@ import {
13
13
  import {
14
14
  estimateTokensWithMeta,
15
15
  serializeForTokenEstimate
16
- } from "./chunk-U433WUUT.js";
16
+ } from "./chunk-L3HY6AWL.js";
17
17
 
18
18
  // src/core/analyze.ts
19
19
  function analyze(input, options = {}) {
20
20
  const {
21
- exact = false,
21
+ exact = true,
22
22
  model = "gpt-4o-mini",
23
23
  fallbackToHeuristic = true
24
24
  } = options;
@@ -0,0 +1,69 @@
1
+ // src/core/token.ts
2
+ import { createRequire } from "module";
3
+ var require2 = createRequire(import.meta.url);
4
+ function serializeForTokenEstimate(value) {
5
+ if (typeof value === "string") return value;
6
+ const serialized = JSON.stringify(value);
7
+ return serialized ?? "";
8
+ }
9
+ function estimateTokensHeuristic(value) {
10
+ return Math.ceil(serializeForTokenEstimate(value).length / 4);
11
+ }
12
+ function expectedEncodingForModel(model) {
13
+ const normalizedModel = model.toLowerCase();
14
+ if (normalizedModel.includes("gpt-4o") || normalizedModel.includes("gpt-4.1") || normalizedModel.includes("o1") || normalizedModel.includes("o3") || normalizedModel.includes("o4")) {
15
+ return "o200k_base";
16
+ }
17
+ if (normalizedModel.includes("davinci") || normalizedModel.startsWith("text-") || normalizedModel.includes("babbage") || normalizedModel.includes("curie")) {
18
+ return "r50k_base";
19
+ }
20
+ return "cl100k_base";
21
+ }
22
+ function estimateTokens(value, options = {}) {
23
+ return estimateTokensWithMeta(value, options).count;
24
+ }
25
+ function estimateTokensWithMeta(value, options = {}) {
26
+ const { exact = true, model = "gpt-4o-mini", fallbackToHeuristic = true } = options;
27
+ const heuristic = estimateTokensHeuristic(value);
28
+ const heuristicEstimator = "heuristic: 1 token \u2248 4 characters";
29
+ if (!exact) {
30
+ return { count: heuristic, estimator: heuristicEstimator };
31
+ }
32
+ try {
33
+ const tiktoken = require2("tiktoken");
34
+ const encoder = tiktoken.encoding_for_model(model);
35
+ const count = encoder.encode(serializeForTokenEstimate(value)).length;
36
+ let encodingName = encoder.name;
37
+ if (!encodingName && typeof tiktoken.model_to_encoding === "function") {
38
+ try {
39
+ encodingName = tiktoken.model_to_encoding(model);
40
+ } catch {
41
+ encodingName = void 0;
42
+ }
43
+ }
44
+ encodingName ?? (encodingName = expectedEncodingForModel(model));
45
+ encoder.free?.();
46
+ return {
47
+ count,
48
+ estimator: `exact tokenizer: model=${model} encoding=${encodingName}`
49
+ };
50
+ } catch {
51
+ const expectedEncoding = expectedEncodingForModel(model);
52
+ if (!fallbackToHeuristic) {
53
+ return {
54
+ count: heuristic,
55
+ estimator: `exact requested but tokenizer unavailable (expected encoding=${expectedEncoding} for model=${model})`
56
+ };
57
+ }
58
+ return {
59
+ count: heuristic,
60
+ estimator: `${heuristicEstimator} (model=${model} expected_encoding=${expectedEncoding})`
61
+ };
62
+ }
63
+ }
64
+
65
+ export {
66
+ serializeForTokenEstimate,
67
+ estimateTokens,
68
+ estimateTokensWithMeta
69
+ };
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  analyze
3
- } from "./chunk-IOMOVRC7.js";
3
+ } from "./chunk-2TDVL6BJ.js";
4
4
  import {
5
5
  toTOON
6
6
  } from "./chunk-6VRLDRJK.js";
package/dist/cli.cjs CHANGED
@@ -153,8 +153,18 @@ function serializeForTokenEstimate(value) {
153
153
  function estimateTokensHeuristic(value) {
154
154
  return Math.ceil(serializeForTokenEstimate(value).length / 4);
155
155
  }
156
+ function expectedEncodingForModel(model) {
157
+ const normalizedModel = model.toLowerCase();
158
+ if (normalizedModel.includes("gpt-4o") || normalizedModel.includes("gpt-4.1") || normalizedModel.includes("o1") || normalizedModel.includes("o3") || normalizedModel.includes("o4")) {
159
+ return "o200k_base";
160
+ }
161
+ if (normalizedModel.includes("davinci") || normalizedModel.startsWith("text-") || normalizedModel.includes("babbage") || normalizedModel.includes("curie")) {
162
+ return "r50k_base";
163
+ }
164
+ return "cl100k_base";
165
+ }
156
166
  function estimateTokensWithMeta(value, options = {}) {
157
- const { exact = false, model = "gpt-4o-mini", fallbackToHeuristic = true } = options;
167
+ const { exact = true, model = "gpt-4o-mini", fallbackToHeuristic = true } = options;
158
168
  const heuristic = estimateTokensHeuristic(value);
159
169
  const heuristicEstimator = "heuristic: 1 token \u2248 4 characters";
160
170
  if (!exact) {
@@ -163,36 +173,40 @@ function estimateTokensWithMeta(value, options = {}) {
163
173
  try {
164
174
  const tiktoken = require2("tiktoken");
165
175
  const encoder = tiktoken.encoding_for_model(model);
166
- const text = serializeForTokenEstimate(value);
167
- const count = encoder.encode(text).length;
168
- let encodingName = null;
169
- if (encoder.name) encodingName = encoder.name;
176
+ const count = encoder.encode(serializeForTokenEstimate(value)).length;
177
+ let encodingName = encoder.name;
170
178
  if (!encodingName && typeof tiktoken.model_to_encoding === "function") {
171
179
  try {
172
180
  encodingName = tiktoken.model_to_encoding(model);
173
- } catch (e) {
174
- encodingName = null;
181
+ } catch {
182
+ encodingName = void 0;
175
183
  }
176
184
  }
177
- if (!encodingName) {
178
- const m = String(model || "").toLowerCase();
179
- if (m.includes("davinci") || m.startsWith("text-")) encodingName = "r50k_base";
180
- else encodingName = "cl100k_base";
181
- }
182
- const estimator = `exact tokenizer: model=${model} encoding=${encodingName}`;
183
- return { count, estimator };
184
- } catch (e) {
185
+ encodingName ?? (encodingName = expectedEncodingForModel(model));
186
+ encoder.free?.();
187
+ return {
188
+ count,
189
+ estimator: `exact tokenizer: model=${model} encoding=${encodingName}`
190
+ };
191
+ } catch {
192
+ const expectedEncoding = expectedEncodingForModel(model);
185
193
  if (!fallbackToHeuristic) {
186
- return { count: heuristic, estimator: "exact requested but tokenizer unavailable" };
194
+ return {
195
+ count: heuristic,
196
+ estimator: `exact requested but tokenizer unavailable (expected encoding=${expectedEncoding} for model=${model})`
197
+ };
187
198
  }
188
- return { count: heuristic, estimator: heuristicEstimator };
199
+ return {
200
+ count: heuristic,
201
+ estimator: `${heuristicEstimator} (model=${model} expected_encoding=${expectedEncoding})`
202
+ };
189
203
  }
190
204
  }
191
205
 
192
206
  // src/core/analyze.ts
193
207
  function analyze(input, options = {}) {
194
208
  const {
195
- exact = false,
209
+ exact = true,
196
210
  model = "gpt-4o-mini",
197
211
  fallbackToHeuristic = true
198
212
  } = options;
@@ -395,7 +409,7 @@ Usage:
395
409
  Options:
396
410
  --toon Convert JSON to TOON format
397
411
  --compact Convert JSON to compact format
398
- --analyze Show token analysis (heuristic estimate)
412
+ --analyze Show token analysis (tiktoken estimate)
399
413
  `);
400
414
  process.exit(0);
401
415
  }
package/dist/cli.js CHANGED
@@ -1,14 +1,14 @@
1
1
  #!/usr/bin/env node
2
2
  import {
3
3
  AIChain
4
- } from "./chunk-P6KXISNT.js";
5
- import "./chunk-IOMOVRC7.js";
4
+ } from "./chunk-QHCUNOUH.js";
5
+ import "./chunk-2TDVL6BJ.js";
6
6
  import "./chunk-6VRLDRJK.js";
7
7
  import "./chunk-XE36GLJP.js";
8
8
  import "./chunk-L7BC62MT.js";
9
9
  import "./chunk-D4CFTFM3.js";
10
10
  import "./chunk-ZD536GZF.js";
11
- import "./chunk-U433WUUT.js";
11
+ import "./chunk-L3HY6AWL.js";
12
12
 
13
13
  // src/cli.ts
14
14
  import fs from "fs";
@@ -22,7 +22,7 @@ Usage:
22
22
  Options:
23
23
  --toon Convert JSON to TOON format
24
24
  --compact Convert JSON to compact format
25
- --analyze Show token analysis (heuristic estimate)
25
+ --analyze Show token analysis (tiktoken estimate)
26
26
  `);
27
27
  process.exit(0);
28
28
  }
@@ -150,8 +150,18 @@ function serializeForTokenEstimate(value) {
150
150
  function estimateTokensHeuristic(value) {
151
151
  return Math.ceil(serializeForTokenEstimate(value).length / 4);
152
152
  }
153
+ function expectedEncodingForModel(model) {
154
+ const normalizedModel = model.toLowerCase();
155
+ if (normalizedModel.includes("gpt-4o") || normalizedModel.includes("gpt-4.1") || normalizedModel.includes("o1") || normalizedModel.includes("o3") || normalizedModel.includes("o4")) {
156
+ return "o200k_base";
157
+ }
158
+ if (normalizedModel.includes("davinci") || normalizedModel.startsWith("text-") || normalizedModel.includes("babbage") || normalizedModel.includes("curie")) {
159
+ return "r50k_base";
160
+ }
161
+ return "cl100k_base";
162
+ }
153
163
  function estimateTokensWithMeta(value, options = {}) {
154
- const { exact = false, model = "gpt-4o-mini", fallbackToHeuristic = true } = options;
164
+ const { exact = true, model = "gpt-4o-mini", fallbackToHeuristic = true } = options;
155
165
  const heuristic = estimateTokensHeuristic(value);
156
166
  const heuristicEstimator = "heuristic: 1 token \u2248 4 characters";
157
167
  if (!exact) {
@@ -160,36 +170,40 @@ function estimateTokensWithMeta(value, options = {}) {
160
170
  try {
161
171
  const tiktoken = require2("tiktoken");
162
172
  const encoder = tiktoken.encoding_for_model(model);
163
- const text = serializeForTokenEstimate(value);
164
- const count = encoder.encode(text).length;
165
- let encodingName = null;
166
- if (encoder.name) encodingName = encoder.name;
173
+ const count = encoder.encode(serializeForTokenEstimate(value)).length;
174
+ let encodingName = encoder.name;
167
175
  if (!encodingName && typeof tiktoken.model_to_encoding === "function") {
168
176
  try {
169
177
  encodingName = tiktoken.model_to_encoding(model);
170
- } catch (e) {
171
- encodingName = null;
178
+ } catch {
179
+ encodingName = void 0;
172
180
  }
173
181
  }
174
- if (!encodingName) {
175
- const m = String(model || "").toLowerCase();
176
- if (m.includes("davinci") || m.startsWith("text-")) encodingName = "r50k_base";
177
- else encodingName = "cl100k_base";
178
- }
179
- const estimator = `exact tokenizer: model=${model} encoding=${encodingName}`;
180
- return { count, estimator };
181
- } catch (e) {
182
+ encodingName ?? (encodingName = expectedEncodingForModel(model));
183
+ encoder.free?.();
184
+ return {
185
+ count,
186
+ estimator: `exact tokenizer: model=${model} encoding=${encodingName}`
187
+ };
188
+ } catch {
189
+ const expectedEncoding = expectedEncodingForModel(model);
182
190
  if (!fallbackToHeuristic) {
183
- return { count: heuristic, estimator: "exact requested but tokenizer unavailable" };
191
+ return {
192
+ count: heuristic,
193
+ estimator: `exact requested but tokenizer unavailable (expected encoding=${expectedEncoding} for model=${model})`
194
+ };
184
195
  }
185
- return { count: heuristic, estimator: heuristicEstimator };
196
+ return {
197
+ count: heuristic,
198
+ estimator: `${heuristicEstimator} (model=${model} expected_encoding=${expectedEncoding})`
199
+ };
186
200
  }
187
201
  }
188
202
 
189
203
  // src/core/analyze.ts
190
204
  function analyze(input, options = {}) {
191
205
  const {
192
- exact = false,
206
+ exact = true,
193
207
  model = "gpt-4o-mini",
194
208
  fallbackToHeuristic = true
195
209
  } = options;
@@ -1,11 +1,11 @@
1
1
  import {
2
2
  analyze
3
- } from "../chunk-IOMOVRC7.js";
3
+ } from "../chunk-2TDVL6BJ.js";
4
4
  import "../chunk-6VRLDRJK.js";
5
5
  import "../chunk-XE36GLJP.js";
6
6
  import "../chunk-L7BC62MT.js";
7
7
  import "../chunk-ZD536GZF.js";
8
- import "../chunk-U433WUUT.js";
8
+ import "../chunk-L3HY6AWL.js";
9
9
  export {
10
10
  analyze
11
11
  };
@@ -36,11 +36,21 @@ function serializeForTokenEstimate(value) {
36
36
  function estimateTokensHeuristic(value) {
37
37
  return Math.ceil(serializeForTokenEstimate(value).length / 4);
38
38
  }
39
+ function expectedEncodingForModel(model) {
40
+ const normalizedModel = model.toLowerCase();
41
+ if (normalizedModel.includes("gpt-4o") || normalizedModel.includes("gpt-4.1") || normalizedModel.includes("o1") || normalizedModel.includes("o3") || normalizedModel.includes("o4")) {
42
+ return "o200k_base";
43
+ }
44
+ if (normalizedModel.includes("davinci") || normalizedModel.startsWith("text-") || normalizedModel.includes("babbage") || normalizedModel.includes("curie")) {
45
+ return "r50k_base";
46
+ }
47
+ return "cl100k_base";
48
+ }
39
49
  function estimateTokens(value, options = {}) {
40
50
  return estimateTokensWithMeta(value, options).count;
41
51
  }
42
52
  function estimateTokensWithMeta(value, options = {}) {
43
- const { exact = false, model = "gpt-4o-mini", fallbackToHeuristic = true } = options;
53
+ const { exact = true, model = "gpt-4o-mini", fallbackToHeuristic = true } = options;
44
54
  const heuristic = estimateTokensHeuristic(value);
45
55
  const heuristicEstimator = "heuristic: 1 token \u2248 4 characters";
46
56
  if (!exact) {
@@ -49,29 +59,33 @@ function estimateTokensWithMeta(value, options = {}) {
49
59
  try {
50
60
  const tiktoken = require2("tiktoken");
51
61
  const encoder = tiktoken.encoding_for_model(model);
52
- const text = serializeForTokenEstimate(value);
53
- const count = encoder.encode(text).length;
54
- let encodingName = null;
55
- if (encoder.name) encodingName = encoder.name;
62
+ const count = encoder.encode(serializeForTokenEstimate(value)).length;
63
+ let encodingName = encoder.name;
56
64
  if (!encodingName && typeof tiktoken.model_to_encoding === "function") {
57
65
  try {
58
66
  encodingName = tiktoken.model_to_encoding(model);
59
- } catch (e) {
60
- encodingName = null;
67
+ } catch {
68
+ encodingName = void 0;
61
69
  }
62
70
  }
63
- if (!encodingName) {
64
- const m = String(model || "").toLowerCase();
65
- if (m.includes("davinci") || m.startsWith("text-")) encodingName = "r50k_base";
66
- else encodingName = "cl100k_base";
67
- }
68
- const estimator = `exact tokenizer: model=${model} encoding=${encodingName}`;
69
- return { count, estimator };
70
- } catch (e) {
71
+ encodingName ?? (encodingName = expectedEncodingForModel(model));
72
+ encoder.free?.();
73
+ return {
74
+ count,
75
+ estimator: `exact tokenizer: model=${model} encoding=${encodingName}`
76
+ };
77
+ } catch {
78
+ const expectedEncoding = expectedEncodingForModel(model);
71
79
  if (!fallbackToHeuristic) {
72
- return { count: heuristic, estimator: "exact requested but tokenizer unavailable" };
80
+ return {
81
+ count: heuristic,
82
+ estimator: `exact requested but tokenizer unavailable (expected encoding=${expectedEncoding} for model=${model})`
83
+ };
73
84
  }
74
- return { count: heuristic, estimator: heuristicEstimator };
85
+ return {
86
+ count: heuristic,
87
+ estimator: `${heuristicEstimator} (model=${model} expected_encoding=${expectedEncoding})`
88
+ };
75
89
  }
76
90
  }
77
91
  // Annotate the CommonJS export names for ESM import in node:
@@ -4,20 +4,14 @@ interface TokenEstimateOptions {
4
4
  fallbackToHeuristic?: boolean;
5
5
  }
6
6
  declare function serializeForTokenEstimate(value: unknown): string;
7
- /**
8
- * Estimates tokens using a transparent four-characters-per-token heuristic.
9
- * JSON values are serialized first, matching the compact form normally sent
10
- * to an API. Set exact=true to attempt a model-specific tokenizer count when
11
- * the runtime has the tokenizer installed.
12
- */
13
7
  type TokenEstimateResult = {
14
8
  count: number;
15
9
  estimator: string;
16
10
  };
17
11
  declare function estimateTokens(value: unknown, options?: TokenEstimateOptions): number;
18
12
  /**
19
- * Returns both a token count and an estimator string describing how the count was
20
- * obtained (exact tokenizer + encoding when available, or heuristic otherwise).
13
+ * Returns an exact model tokenizer count by default. Set exact=false to use the
14
+ * lightweight four-characters-per-token fallback explicitly.
21
15
  */
22
16
  declare function estimateTokensWithMeta(value: unknown, options?: TokenEstimateOptions): TokenEstimateResult;
23
17
 
@@ -4,20 +4,14 @@ interface TokenEstimateOptions {
4
4
  fallbackToHeuristic?: boolean;
5
5
  }
6
6
  declare function serializeForTokenEstimate(value: unknown): string;
7
- /**
8
- * Estimates tokens using a transparent four-characters-per-token heuristic.
9
- * JSON values are serialized first, matching the compact form normally sent
10
- * to an API. Set exact=true to attempt a model-specific tokenizer count when
11
- * the runtime has the tokenizer installed.
12
- */
13
7
  type TokenEstimateResult = {
14
8
  count: number;
15
9
  estimator: string;
16
10
  };
17
11
  declare function estimateTokens(value: unknown, options?: TokenEstimateOptions): number;
18
12
  /**
19
- * Returns both a token count and an estimator string describing how the count was
20
- * obtained (exact tokenizer + encoding when available, or heuristic otherwise).
13
+ * Returns an exact model tokenizer count by default. Set exact=false to use the
14
+ * lightweight four-characters-per-token fallback explicitly.
21
15
  */
22
16
  declare function estimateTokensWithMeta(value: unknown, options?: TokenEstimateOptions): TokenEstimateResult;
23
17
 
@@ -2,7 +2,7 @@ import {
2
2
  estimateTokens,
3
3
  estimateTokensWithMeta,
4
4
  serializeForTokenEstimate
5
- } from "../chunk-U433WUUT.js";
5
+ } from "../chunk-L3HY6AWL.js";
6
6
  export {
7
7
  estimateTokens,
8
8
  estimateTokensWithMeta,
package/dist/index.cjs CHANGED
@@ -159,11 +159,21 @@ function serializeForTokenEstimate(value) {
159
159
  function estimateTokensHeuristic(value) {
160
160
  return Math.ceil(serializeForTokenEstimate(value).length / 4);
161
161
  }
162
+ function expectedEncodingForModel(model) {
163
+ const normalizedModel = model.toLowerCase();
164
+ if (normalizedModel.includes("gpt-4o") || normalizedModel.includes("gpt-4.1") || normalizedModel.includes("o1") || normalizedModel.includes("o3") || normalizedModel.includes("o4")) {
165
+ return "o200k_base";
166
+ }
167
+ if (normalizedModel.includes("davinci") || normalizedModel.startsWith("text-") || normalizedModel.includes("babbage") || normalizedModel.includes("curie")) {
168
+ return "r50k_base";
169
+ }
170
+ return "cl100k_base";
171
+ }
162
172
  function estimateTokens(value, options = {}) {
163
173
  return estimateTokensWithMeta(value, options).count;
164
174
  }
165
175
  function estimateTokensWithMeta(value, options = {}) {
166
- const { exact = false, model = "gpt-4o-mini", fallbackToHeuristic = true } = options;
176
+ const { exact = true, model = "gpt-4o-mini", fallbackToHeuristic = true } = options;
167
177
  const heuristic = estimateTokensHeuristic(value);
168
178
  const heuristicEstimator = "heuristic: 1 token \u2248 4 characters";
169
179
  if (!exact) {
@@ -172,36 +182,40 @@ function estimateTokensWithMeta(value, options = {}) {
172
182
  try {
173
183
  const tiktoken = require2("tiktoken");
174
184
  const encoder = tiktoken.encoding_for_model(model);
175
- const text = serializeForTokenEstimate(value);
176
- const count = encoder.encode(text).length;
177
- let encodingName = null;
178
- if (encoder.name) encodingName = encoder.name;
185
+ const count = encoder.encode(serializeForTokenEstimate(value)).length;
186
+ let encodingName = encoder.name;
179
187
  if (!encodingName && typeof tiktoken.model_to_encoding === "function") {
180
188
  try {
181
189
  encodingName = tiktoken.model_to_encoding(model);
182
- } catch (e) {
183
- encodingName = null;
190
+ } catch {
191
+ encodingName = void 0;
184
192
  }
185
193
  }
186
- if (!encodingName) {
187
- const m = String(model || "").toLowerCase();
188
- if (m.includes("davinci") || m.startsWith("text-")) encodingName = "r50k_base";
189
- else encodingName = "cl100k_base";
190
- }
191
- const estimator = `exact tokenizer: model=${model} encoding=${encodingName}`;
192
- return { count, estimator };
193
- } catch (e) {
194
+ encodingName ?? (encodingName = expectedEncodingForModel(model));
195
+ encoder.free?.();
196
+ return {
197
+ count,
198
+ estimator: `exact tokenizer: model=${model} encoding=${encodingName}`
199
+ };
200
+ } catch {
201
+ const expectedEncoding = expectedEncodingForModel(model);
194
202
  if (!fallbackToHeuristic) {
195
- return { count: heuristic, estimator: "exact requested but tokenizer unavailable" };
203
+ return {
204
+ count: heuristic,
205
+ estimator: `exact requested but tokenizer unavailable (expected encoding=${expectedEncoding} for model=${model})`
206
+ };
196
207
  }
197
- return { count: heuristic, estimator: heuristicEstimator };
208
+ return {
209
+ count: heuristic,
210
+ estimator: `${heuristicEstimator} (model=${model} expected_encoding=${expectedEncoding})`
211
+ };
198
212
  }
199
213
  }
200
214
 
201
215
  // src/core/analyze.ts
202
216
  function analyze(input, options = {}) {
203
217
  const {
204
- exact = false,
218
+ exact = true,
205
219
  model = "gpt-4o-mini",
206
220
  fallbackToHeuristic = true
207
221
  } = options;
package/dist/index.js CHANGED
@@ -1,9 +1,9 @@
1
1
  import {
2
2
  AIChain
3
- } from "./chunk-P6KXISNT.js";
3
+ } from "./chunk-QHCUNOUH.js";
4
4
  import {
5
5
  analyze
6
- } from "./chunk-IOMOVRC7.js";
6
+ } from "./chunk-2TDVL6BJ.js";
7
7
  import {
8
8
  toTOON
9
9
  } from "./chunk-6VRLDRJK.js";
@@ -22,7 +22,7 @@ import {
22
22
  import {
23
23
  estimateTokens,
24
24
  serializeForTokenEstimate
25
- } from "./chunk-U433WUUT.js";
25
+ } from "./chunk-L3HY6AWL.js";
26
26
 
27
27
  // src/index.ts
28
28
  function ai(data) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@sohqureshi/tokenwise",
3
- "version": "1.0.7",
3
+ "version": "1.0.9",
4
4
  "description": "Optimize JSON data for AI by reducing token usage",
5
5
  "repository": {
6
6
  "type": "git",
@@ -1,55 +0,0 @@
1
- // src/core/token.ts
2
- import { createRequire } from "module";
3
- var require2 = createRequire(import.meta.url);
4
- function serializeForTokenEstimate(value) {
5
- if (typeof value === "string") return value;
6
- const serialized = JSON.stringify(value);
7
- return serialized ?? "";
8
- }
9
- function estimateTokensHeuristic(value) {
10
- return Math.ceil(serializeForTokenEstimate(value).length / 4);
11
- }
12
- function estimateTokens(value, options = {}) {
13
- return estimateTokensWithMeta(value, options).count;
14
- }
15
- function estimateTokensWithMeta(value, options = {}) {
16
- const { exact = false, model = "gpt-4o-mini", fallbackToHeuristic = true } = options;
17
- const heuristic = estimateTokensHeuristic(value);
18
- const heuristicEstimator = "heuristic: 1 token \u2248 4 characters";
19
- if (!exact) {
20
- return { count: heuristic, estimator: heuristicEstimator };
21
- }
22
- try {
23
- const tiktoken = require2("tiktoken");
24
- const encoder = tiktoken.encoding_for_model(model);
25
- const text = serializeForTokenEstimate(value);
26
- const count = encoder.encode(text).length;
27
- let encodingName = null;
28
- if (encoder.name) encodingName = encoder.name;
29
- if (!encodingName && typeof tiktoken.model_to_encoding === "function") {
30
- try {
31
- encodingName = tiktoken.model_to_encoding(model);
32
- } catch (e) {
33
- encodingName = null;
34
- }
35
- }
36
- if (!encodingName) {
37
- const m = String(model || "").toLowerCase();
38
- if (m.includes("davinci") || m.startsWith("text-")) encodingName = "r50k_base";
39
- else encodingName = "cl100k_base";
40
- }
41
- const estimator = `exact tokenizer: model=${model} encoding=${encodingName}`;
42
- return { count, estimator };
43
- } catch (e) {
44
- if (!fallbackToHeuristic) {
45
- return { count: heuristic, estimator: "exact requested but tokenizer unavailable" };
46
- }
47
- return { count: heuristic, estimator: heuristicEstimator };
48
- }
49
- }
50
-
51
- export {
52
- serializeForTokenEstimate,
53
- estimateTokens,
54
- estimateTokensWithMeta
55
- };