@trazum/core 1.8.0
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/LICENSE +21 -0
- package/README.md +163 -0
- package/dist/advisories.d.ts +23 -0
- package/dist/advisories.d.ts.map +1 -0
- package/dist/advisories.js +376 -0
- package/dist/advisories.js.map +1 -0
- package/dist/aws-sigv4.d.ts +88 -0
- package/dist/aws-sigv4.d.ts.map +1 -0
- package/dist/aws-sigv4.js +117 -0
- package/dist/aws-sigv4.js.map +1 -0
- package/dist/baseline.d.ts +171 -0
- package/dist/baseline.d.ts.map +1 -0
- package/dist/baseline.js +273 -0
- package/dist/baseline.js.map +1 -0
- package/dist/cache.d.ts +26 -0
- package/dist/cache.d.ts.map +1 -0
- package/dist/cache.js +28 -0
- package/dist/cache.js.map +1 -0
- package/dist/changes.d.ts +29 -0
- package/dist/changes.d.ts.map +1 -0
- package/dist/changes.js +142 -0
- package/dist/changes.js.map +1 -0
- package/dist/compare.d.ts +65 -0
- package/dist/compare.d.ts.map +1 -0
- package/dist/compare.js +58 -0
- package/dist/compare.js.map +1 -0
- package/dist/config-schema.d.ts +118 -0
- package/dist/config-schema.d.ts.map +1 -0
- package/dist/config-schema.js +315 -0
- package/dist/config-schema.js.map +1 -0
- package/dist/config.d.ts +47 -0
- package/dist/config.d.ts.map +1 -0
- package/dist/config.js +112 -0
- package/dist/config.js.map +1 -0
- package/dist/detect.d.ts +70 -0
- package/dist/detect.d.ts.map +1 -0
- package/dist/detect.js +228 -0
- package/dist/detect.js.map +1 -0
- package/dist/evaluate.d.ts +98 -0
- package/dist/evaluate.d.ts.map +1 -0
- package/dist/evaluate.js +110 -0
- package/dist/evaluate.js.map +1 -0
- package/dist/extract.d.ts +81 -0
- package/dist/extract.d.ts.map +1 -0
- package/dist/extract.js +280 -0
- package/dist/extract.js.map +1 -0
- package/dist/gcp-auth.d.ts +58 -0
- package/dist/gcp-auth.d.ts.map +1 -0
- package/dist/gcp-auth.js +113 -0
- package/dist/gcp-auth.js.map +1 -0
- package/dist/glob.d.ts +49 -0
- package/dist/glob.d.ts.map +1 -0
- package/dist/glob.js +154 -0
- package/dist/glob.js.map +1 -0
- package/dist/host.d.ts +30 -0
- package/dist/host.d.ts.map +1 -0
- package/dist/host.js +69 -0
- package/dist/host.js.map +1 -0
- package/dist/i18n/en.d.ts +4 -0
- package/dist/i18n/en.d.ts.map +1 -0
- package/dist/i18n/en.js +168 -0
- package/dist/i18n/en.js.map +1 -0
- package/dist/i18n/es.d.ts +4 -0
- package/dist/i18n/es.d.ts.map +1 -0
- package/dist/i18n/es.js +168 -0
- package/dist/i18n/es.js.map +1 -0
- package/dist/i18n/index.d.ts +36 -0
- package/dist/i18n/index.d.ts.map +1 -0
- package/dist/i18n/index.js +50 -0
- package/dist/i18n/index.js.map +1 -0
- package/dist/i18n/types.d.ts +180 -0
- package/dist/i18n/types.d.ts.map +1 -0
- package/dist/i18n/types.js +11 -0
- package/dist/i18n/types.js.map +1 -0
- package/dist/index.d.ts +66 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +69 -0
- package/dist/index.js.map +1 -0
- package/dist/llm.d.ts +226 -0
- package/dist/llm.d.ts.map +1 -0
- package/dist/llm.js +485 -0
- package/dist/llm.js.map +1 -0
- package/dist/nearest.d.ts +20 -0
- package/dist/nearest.d.ts.map +1 -0
- package/dist/nearest.js +54 -0
- package/dist/nearest.js.map +1 -0
- package/dist/net.d.ts +90 -0
- package/dist/net.d.ts.map +1 -0
- package/dist/net.js +203 -0
- package/dist/net.js.map +1 -0
- package/dist/node.d.ts +32 -0
- package/dist/node.d.ts.map +1 -0
- package/dist/node.js +33 -0
- package/dist/node.js.map +1 -0
- package/dist/openrouter.d.ts +25 -0
- package/dist/openrouter.d.ts.map +1 -0
- package/dist/openrouter.js +72 -0
- package/dist/openrouter.js.map +1 -0
- package/dist/optimize.d.ts +38 -0
- package/dist/optimize.d.ts.map +1 -0
- package/dist/optimize.js +183 -0
- package/dist/optimize.js.map +1 -0
- package/dist/otlp.d.ts +91 -0
- package/dist/otlp.d.ts.map +1 -0
- package/dist/otlp.js +102 -0
- package/dist/otlp.js.map +1 -0
- package/dist/phrases.d.ts +169 -0
- package/dist/phrases.d.ts.map +1 -0
- package/dist/phrases.js +939 -0
- package/dist/phrases.js.map +1 -0
- package/dist/pricing-overlay.d.ts +55 -0
- package/dist/pricing-overlay.d.ts.map +1 -0
- package/dist/pricing-overlay.js +241 -0
- package/dist/pricing-overlay.js.map +1 -0
- package/dist/pricing.d.ts +115 -0
- package/dist/pricing.d.ts.map +1 -0
- package/dist/pricing.js +400 -0
- package/dist/pricing.js.map +1 -0
- package/dist/profile.d.ts +71 -0
- package/dist/profile.d.ts.map +1 -0
- package/dist/profile.js +55 -0
- package/dist/profile.js.map +1 -0
- package/dist/promptfoo.d.ts +58 -0
- package/dist/promptfoo.d.ts.map +1 -0
- package/dist/promptfoo.js +149 -0
- package/dist/promptfoo.js.map +1 -0
- package/dist/prune.d.ts +91 -0
- package/dist/prune.d.ts.map +1 -0
- package/dist/prune.js +110 -0
- package/dist/prune.js.map +1 -0
- package/dist/reorder.d.ts +82 -0
- package/dist/reorder.d.ts.map +1 -0
- package/dist/reorder.js +215 -0
- package/dist/reorder.js.map +1 -0
- package/dist/review.d.ts +54 -0
- package/dist/review.d.ts.map +1 -0
- package/dist/review.js +131 -0
- package/dist/review.js.map +1 -0
- package/dist/rules.d.ts +5 -0
- package/dist/rules.d.ts.map +1 -0
- package/dist/rules.js +279 -0
- package/dist/rules.js.map +1 -0
- package/dist/savings.d.ts +36 -0
- package/dist/savings.d.ts.map +1 -0
- package/dist/savings.js +83 -0
- package/dist/savings.js.map +1 -0
- package/dist/segment.d.ts +8 -0
- package/dist/segment.d.ts.map +1 -0
- package/dist/segment.js +74 -0
- package/dist/segment.js.map +1 -0
- package/dist/shared-prefix.d.ts +63 -0
- package/dist/shared-prefix.d.ts.map +1 -0
- package/dist/shared-prefix.js +151 -0
- package/dist/shared-prefix.js.map +1 -0
- package/dist/similarity.d.ts +13 -0
- package/dist/similarity.d.ts.map +1 -0
- package/dist/similarity.js +30 -0
- package/dist/similarity.js.map +1 -0
- package/dist/structure.d.ts +144 -0
- package/dist/structure.d.ts.map +1 -0
- package/dist/structure.js +455 -0
- package/dist/structure.js.map +1 -0
- package/dist/suggest.d.ts +100 -0
- package/dist/suggest.d.ts.map +1 -0
- package/dist/suggest.js +151 -0
- package/dist/suggest.js.map +1 -0
- package/dist/tokenizer.d.ts +57 -0
- package/dist/tokenizer.d.ts.map +1 -0
- package/dist/tokenizer.js +157 -0
- package/dist/tokenizer.js.map +1 -0
- package/dist/types.d.ts +296 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +3 -0
- package/dist/types.js.map +1 -0
- package/dist/walk.d.ts +40 -0
- package/dist/walk.d.ts.map +1 -0
- package/dist/walk.js +95 -0
- package/dist/walk.js.map +1 -0
- package/package.json +56 -0
- package/src/advisories.ts +431 -0
- package/src/aws-sigv4.ts +174 -0
- package/src/baseline.ts +390 -0
- package/src/cache.ts +54 -0
- package/src/changes.ts +158 -0
- package/src/compare.ts +131 -0
- package/src/config-schema.ts +451 -0
- package/src/config.ts +161 -0
- package/src/detect.ts +312 -0
- package/src/evaluate.ts +188 -0
- package/src/extract.ts +336 -0
- package/src/gcp-auth.ts +166 -0
- package/src/glob.ts +160 -0
- package/src/host.ts +90 -0
- package/src/i18n/en.ts +236 -0
- package/src/i18n/es.ts +236 -0
- package/src/i18n/index.ts +68 -0
- package/src/i18n/types.ts +230 -0
- package/src/index.ts +228 -0
- package/src/llm.ts +708 -0
- package/src/nearest.ts +61 -0
- package/src/net.ts +233 -0
- package/src/node.ts +63 -0
- package/src/openrouter.ts +125 -0
- package/src/optimize.ts +228 -0
- package/src/otlp.ts +179 -0
- package/src/phrases.ts +1047 -0
- package/src/pricing-overlay.ts +319 -0
- package/src/pricing.ts +468 -0
- package/src/profile.ts +124 -0
- package/src/promptfoo.ts +213 -0
- package/src/prune.ts +211 -0
- package/src/reorder.ts +307 -0
- package/src/review.ts +180 -0
- package/src/rules.ts +324 -0
- package/src/savings.ts +121 -0
- package/src/segment.ts +106 -0
- package/src/shared-prefix.ts +198 -0
- package/src/similarity.ts +28 -0
- package/src/structure.ts +652 -0
- package/src/suggest.ts +254 -0
- package/src/tokenizer.ts +190 -0
- package/src/types.ts +323 -0
- package/src/walk.ts +117 -0
package/dist/suggest.js
ADDED
|
@@ -0,0 +1,151 @@
|
|
|
1
|
+
import { getMessages } from './i18n/index.js';
|
|
2
|
+
import { segment } from './segment.js';
|
|
3
|
+
import { estimateTokens } from './tokenizer.js';
|
|
4
|
+
export const SUGGEST_SYSTEM_PROMPT = `You find phrases in a prompt that say something in more words than they need.
|
|
5
|
+
|
|
6
|
+
Return ONLY a JSON array. Each element is {"before": "...", "after": "..."}.
|
|
7
|
+
|
|
8
|
+
Rules:
|
|
9
|
+
- "before" MUST be copied character for character from the prompt. Do not paraphrase it, do not fix its punctuation, do not change its capitalisation. If you cannot copy it exactly, leave it out.
|
|
10
|
+
- "after" says the same thing in fewer words. Use "" to delete the phrase entirely.
|
|
11
|
+
- Preserve meaning exactly. Never change what the prompt asks for, its constraints, its output format or its success criteria.
|
|
12
|
+
- Never touch code, URLs, template placeholders ({{x}}, \${x}, {x}) or XML/HTML tags — do not include them in "before" at all.
|
|
13
|
+
- Keep the original language of the prompt.
|
|
14
|
+
- Prefer a few high-value rewrites to many trivial ones. Return [] if there is nothing worth changing.
|
|
15
|
+
|
|
16
|
+
No explanation, no code fences, no commentary. The array alone.`;
|
|
17
|
+
/** Strips a code fence if the model wrapped its JSON despite being told not to. */
|
|
18
|
+
function unwrap(text) {
|
|
19
|
+
const trimmed = text.trim();
|
|
20
|
+
const fenced = /^(?:```|~~~)[a-zA-Z]*\n([\s\S]*?)\n?(?:```|~~~)$/.exec(trimmed);
|
|
21
|
+
return (fenced?.[1] ?? trimmed).trim();
|
|
22
|
+
}
|
|
23
|
+
/**
|
|
24
|
+
* Character ranges that must not be edited.
|
|
25
|
+
*
|
|
26
|
+
* `segment` returns the pieces in order without offsets, so they are
|
|
27
|
+
* accumulated here rather than recomputed per suggestion.
|
|
28
|
+
*/
|
|
29
|
+
function protectedRanges(prompt) {
|
|
30
|
+
const ranges = [];
|
|
31
|
+
let at = 0;
|
|
32
|
+
for (const piece of segment(prompt)) {
|
|
33
|
+
if (piece.kind === 'protected')
|
|
34
|
+
ranges.push([at, at + piece.text.length]);
|
|
35
|
+
at += piece.text.length;
|
|
36
|
+
}
|
|
37
|
+
return ranges;
|
|
38
|
+
}
|
|
39
|
+
const overlaps = (a, b) => a[0] < b[1] && b[0] < a[1];
|
|
40
|
+
/** Every offset at which `needle` occurs in `haystack`. */
|
|
41
|
+
function occurrences(haystack, needle) {
|
|
42
|
+
if (needle === '')
|
|
43
|
+
return [];
|
|
44
|
+
const found = [];
|
|
45
|
+
let at = haystack.indexOf(needle);
|
|
46
|
+
while (at !== -1) {
|
|
47
|
+
found.push(at);
|
|
48
|
+
at = haystack.indexOf(needle, at + needle.length);
|
|
49
|
+
}
|
|
50
|
+
return found;
|
|
51
|
+
}
|
|
52
|
+
/**
|
|
53
|
+
* Asks the provider for rewrites and returns the ones that survive checking.
|
|
54
|
+
*
|
|
55
|
+
* A provider that returns something unparseable yields an empty result rather
|
|
56
|
+
* than throwing: the deterministic rules have already run, and a malformed
|
|
57
|
+
* answer from an optional pass should cost the caller nothing.
|
|
58
|
+
*/
|
|
59
|
+
export async function suggestRewrites(prompt, provider, options = {}) {
|
|
60
|
+
const count = options.tokenCounter ?? estimateTokens;
|
|
61
|
+
const max = options.max ?? 20;
|
|
62
|
+
const raw = await provider.complete({ system: SUGGEST_SYSTEM_PROMPT, user: prompt });
|
|
63
|
+
let proposed;
|
|
64
|
+
try {
|
|
65
|
+
const parsed = JSON.parse(unwrap(raw));
|
|
66
|
+
proposed = Array.isArray(parsed) ? parsed : [];
|
|
67
|
+
}
|
|
68
|
+
catch {
|
|
69
|
+
return { suggestions: [], rejected: [], provider: provider.name, model: provider.model };
|
|
70
|
+
}
|
|
71
|
+
const guarded = protectedRanges(prompt);
|
|
72
|
+
const suggestions = [];
|
|
73
|
+
const rejected = [];
|
|
74
|
+
const taken = [];
|
|
75
|
+
for (const item of proposed) {
|
|
76
|
+
if (typeof item?.before !== 'string' || typeof item?.after !== 'string')
|
|
77
|
+
continue;
|
|
78
|
+
const before = item.before;
|
|
79
|
+
const after = item.after;
|
|
80
|
+
if (before.trim() === '')
|
|
81
|
+
continue;
|
|
82
|
+
const reject = (reason) => rejected.push({ before, after, reason });
|
|
83
|
+
const at = occurrences(prompt, before);
|
|
84
|
+
if (at.length === 0) {
|
|
85
|
+
reject('not-found');
|
|
86
|
+
continue;
|
|
87
|
+
}
|
|
88
|
+
// Occurrences that sit clear of protected content. A phrase that appears
|
|
89
|
+
// three times, once inside a code block, is still worth rewriting in the
|
|
90
|
+
// other two — refusing the whole suggestion would be the easier answer and
|
|
91
|
+
// the wrong one.
|
|
92
|
+
const usable = at.filter((start) => !guarded.some((range) => overlaps([start, start + before.length], range)));
|
|
93
|
+
if (usable.length === 0) {
|
|
94
|
+
reject('touches-protected');
|
|
95
|
+
continue;
|
|
96
|
+
}
|
|
97
|
+
// The replacement must not bring protected content in with it.
|
|
98
|
+
if (after !== '' && segment(after).some((piece) => piece.kind === 'protected')) {
|
|
99
|
+
reject('introduces-protected');
|
|
100
|
+
continue;
|
|
101
|
+
}
|
|
102
|
+
const saved = (count(before) - count(after)) * usable.length;
|
|
103
|
+
if (saved <= 0) {
|
|
104
|
+
reject('no-saving');
|
|
105
|
+
continue;
|
|
106
|
+
}
|
|
107
|
+
const free = usable.filter((start) => !taken.some((range) => overlaps([start, start + before.length], range)));
|
|
108
|
+
if (free.length === 0) {
|
|
109
|
+
reject('overlaps');
|
|
110
|
+
continue;
|
|
111
|
+
}
|
|
112
|
+
for (const start of free)
|
|
113
|
+
taken.push([start, start + before.length]);
|
|
114
|
+
suggestions.push({
|
|
115
|
+
before,
|
|
116
|
+
after,
|
|
117
|
+
offsets: free,
|
|
118
|
+
tokensSaved: (count(before) - count(after)) * free.length,
|
|
119
|
+
});
|
|
120
|
+
}
|
|
121
|
+
suggestions.sort((a, b) => b.tokensSaved - a.tokensSaved);
|
|
122
|
+
return {
|
|
123
|
+
suggestions: suggestions.slice(0, max),
|
|
124
|
+
rejected,
|
|
125
|
+
provider: provider.name,
|
|
126
|
+
model: provider.model,
|
|
127
|
+
};
|
|
128
|
+
}
|
|
129
|
+
/**
|
|
130
|
+
* Applies suggestions to the prompt.
|
|
131
|
+
*
|
|
132
|
+
* Right to left, so an earlier edit cannot move the offsets of a later one —
|
|
133
|
+
* the bug that makes every naive implementation of this corrupt long prompts,
|
|
134
|
+
* and one that shows up only when two suggestions are far enough apart that a
|
|
135
|
+
* short test never notices.
|
|
136
|
+
*/
|
|
137
|
+
export function applyRewrites(prompt, suggestions) {
|
|
138
|
+
const edits = suggestions
|
|
139
|
+
.flatMap((s) => s.offsets.map((start) => ({ start, end: start + s.before.length, after: s.after })))
|
|
140
|
+
.sort((a, b) => b.start - a.start);
|
|
141
|
+
let text = prompt;
|
|
142
|
+
for (const edit of edits) {
|
|
143
|
+
text = text.slice(0, edit.start) + edit.after + text.slice(edit.end);
|
|
144
|
+
}
|
|
145
|
+
return text;
|
|
146
|
+
}
|
|
147
|
+
/** A reason code turned into a sentence, for a report. */
|
|
148
|
+
export function rejectionText(reason, locale) {
|
|
149
|
+
return getMessages(locale).suggest[reason]();
|
|
150
|
+
}
|
|
151
|
+
//# sourceMappingURL=suggest.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"suggest.js","sourceRoot":"","sources":["../src/suggest.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Dependency-free token estimator.
|
|
3
|
+
*
|
|
4
|
+
* This is NOT a real tokenizer: it is a heuristic calibrated per character
|
|
5
|
+
* class. It is built to keep the typical error on ordinary text
|
|
6
|
+
* (English/Spanish, markdown, code) inside ±15%, which is plenty for comparing
|
|
7
|
+
* two versions of the same prompt — but do NOT bill anyone from it.
|
|
8
|
+
*
|
|
9
|
+
* **That band is a design target that has not been measured.** It is printed on
|
|
10
|
+
* every report and every dollar figure descends from it, and until
|
|
11
|
+
* `scripts/measure-token-band.mjs` has been run against the official counting
|
|
12
|
+
* endpoint, nothing in this repository establishes that it holds. It is stated
|
|
13
|
+
* as one number for all text, which is a further assumption: the branches below
|
|
14
|
+
* treat CJK, digits and punctuation quite differently from words, and there is
|
|
15
|
+
* no reason those should land on the same accuracy.
|
|
16
|
+
*
|
|
17
|
+
* `test/token-band.test.js` asserts the band per text type as soon as the ground
|
|
18
|
+
* truth exists. Until then it says so rather than passing quietly.
|
|
19
|
+
*
|
|
20
|
+
* For exact numbers use `countTokensAnthropic` (the official token-counting
|
|
21
|
+
* endpoint, which is free) or pass your own `TokenCounter`.
|
|
22
|
+
*/
|
|
23
|
+
/**
|
|
24
|
+
* Estimates how many tokens `text` occupies.
|
|
25
|
+
*
|
|
26
|
+
* Rules per character class:
|
|
27
|
+
* - words: ~4 effective characters per token (minimum 1)
|
|
28
|
+
* - numbers: ~3 digits per token
|
|
29
|
+
* - punctuation: ~2 marks per token
|
|
30
|
+
* - newlines: ~1 token per 2 consecutive newlines
|
|
31
|
+
* - CJK: 1 token per character
|
|
32
|
+
* - emoji and symbols outside the BMP: 2 tokens
|
|
33
|
+
* - spaces: 0 (absorbed into the following token)
|
|
34
|
+
*/
|
|
35
|
+
export declare function estimateTokens(text: string): number;
|
|
36
|
+
/** Asynchronous token counter, for remote sources. */
|
|
37
|
+
export type AsyncTokenCounter = (text: string) => Promise<number>;
|
|
38
|
+
export interface AnthropicCounterOptions {
|
|
39
|
+
apiKey: string;
|
|
40
|
+
/** Model to count against. Token counts are model-specific. */
|
|
41
|
+
model?: string;
|
|
42
|
+
baseUrl?: string;
|
|
43
|
+
fetchImpl?: typeof fetch;
|
|
44
|
+
/** See `OpenAiCompatibleOptions.allowInsecure`: only when you chose the URL. */
|
|
45
|
+
allowInsecure?: boolean;
|
|
46
|
+
}
|
|
47
|
+
/**
|
|
48
|
+
* Exact counter using the official `/v1/messages/count_tokens` endpoint.
|
|
49
|
+
* The endpoint does not bill tokens, so you can use it freely to measure.
|
|
50
|
+
*
|
|
51
|
+
* The third door, and the one nobody had looked at: this takes a `baseUrl` and
|
|
52
|
+
* sends an `x-api-key` to it. Both providers were hardened at the boundary and
|
|
53
|
+
* this was left with no check at all, because it is called a counter rather
|
|
54
|
+
* than a provider. It goes through the same gate now.
|
|
55
|
+
*/
|
|
56
|
+
export declare function countTokensAnthropic(options: AnthropicCounterOptions): AsyncTokenCounter;
|
|
57
|
+
//# sourceMappingURL=tokenizer.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"tokenizer.d.ts","sourceRoot":"","sources":["../src/tokenizer.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;GAqBG;AAeH;;;;;;;;;;;GAWG;AACH,wBAAgB,cAAc,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAwFnD;AAED,sDAAsD;AACtD,MAAM,MAAM,iBAAiB,GAAG,CAAC,IAAI,EAAE,MAAM,KAAK,OAAO,CAAC,MAAM,CAAC,CAAC;AAElE,MAAM,WAAW,uBAAuB;IACtC,MAAM,EAAE,MAAM,CAAC;IACf,+DAA+D;IAC/D,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,SAAS,CAAC,EAAE,OAAO,KAAK,CAAC;IACzB,gFAAgF;IAChF,aAAa,CAAC,EAAE,OAAO,CAAC;CACzB;AAED;;;;;;;;GAQG;AACH,wBAAgB,oBAAoB,CAAC,OAAO,EAAE,uBAAuB,GAAG,iBAAiB,CA6BxF"}
|
|
@@ -0,0 +1,157 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Dependency-free token estimator.
|
|
3
|
+
*
|
|
4
|
+
* This is NOT a real tokenizer: it is a heuristic calibrated per character
|
|
5
|
+
* class. It is built to keep the typical error on ordinary text
|
|
6
|
+
* (English/Spanish, markdown, code) inside ±15%, which is plenty for comparing
|
|
7
|
+
* two versions of the same prompt — but do NOT bill anyone from it.
|
|
8
|
+
*
|
|
9
|
+
* **That band is a design target that has not been measured.** It is printed on
|
|
10
|
+
* every report and every dollar figure descends from it, and until
|
|
11
|
+
* `scripts/measure-token-band.mjs` has been run against the official counting
|
|
12
|
+
* endpoint, nothing in this repository establishes that it holds. It is stated
|
|
13
|
+
* as one number for all text, which is a further assumption: the branches below
|
|
14
|
+
* treat CJK, digits and punctuation quite differently from words, and there is
|
|
15
|
+
* no reason those should land on the same accuracy.
|
|
16
|
+
*
|
|
17
|
+
* `test/token-band.test.js` asserts the band per text type as soon as the ground
|
|
18
|
+
* truth exists. Until then it says so rather than passing quietly.
|
|
19
|
+
*
|
|
20
|
+
* For exact numbers use `countTokensAnthropic` (the official token-counting
|
|
21
|
+
* endpoint, which is free) or pass your own `TokenCounter`.
|
|
22
|
+
*/
|
|
23
|
+
import { SAFE_FETCH_INIT, checkedEndpoint } from './net.js';
|
|
24
|
+
const CJK = /[-ヿ㐀-䶿一-鿿가-]/;
|
|
25
|
+
const LETTER = /[A-Za-zÀ-ɏͰ-ϿЀ-ӿ]/;
|
|
26
|
+
const DIGIT = /[0-9]/;
|
|
27
|
+
/** Effective word length: non-ASCII characters split into more tokens. */
|
|
28
|
+
function effectiveLength(word) {
|
|
29
|
+
let len = 0;
|
|
30
|
+
for (const ch of word)
|
|
31
|
+
len += ch.charCodeAt(0) > 127 ? 2 : 1;
|
|
32
|
+
return len;
|
|
33
|
+
}
|
|
34
|
+
/**
|
|
35
|
+
* Estimates how many tokens `text` occupies.
|
|
36
|
+
*
|
|
37
|
+
* Rules per character class:
|
|
38
|
+
* - words: ~4 effective characters per token (minimum 1)
|
|
39
|
+
* - numbers: ~3 digits per token
|
|
40
|
+
* - punctuation: ~2 marks per token
|
|
41
|
+
* - newlines: ~1 token per 2 consecutive newlines
|
|
42
|
+
* - CJK: 1 token per character
|
|
43
|
+
* - emoji and symbols outside the BMP: 2 tokens
|
|
44
|
+
* - spaces: 0 (absorbed into the following token)
|
|
45
|
+
*/
|
|
46
|
+
export function estimateTokens(text) {
|
|
47
|
+
if (!text)
|
|
48
|
+
return 0;
|
|
49
|
+
let total = 0;
|
|
50
|
+
let i = 0;
|
|
51
|
+
const chars = Array.from(text);
|
|
52
|
+
while (i < chars.length) {
|
|
53
|
+
const ch = chars[i];
|
|
54
|
+
if (ch === ' ' || ch === '\t' || ch === '\r') {
|
|
55
|
+
i++;
|
|
56
|
+
continue;
|
|
57
|
+
}
|
|
58
|
+
if (ch === '\n') {
|
|
59
|
+
let n = 0;
|
|
60
|
+
while (i < chars.length && chars[i] === '\n') {
|
|
61
|
+
n++;
|
|
62
|
+
i++;
|
|
63
|
+
}
|
|
64
|
+
total += Math.ceil(n / 2);
|
|
65
|
+
continue;
|
|
66
|
+
}
|
|
67
|
+
if (CJK.test(ch)) {
|
|
68
|
+
let n = 0;
|
|
69
|
+
while (i < chars.length && CJK.test(chars[i])) {
|
|
70
|
+
n++;
|
|
71
|
+
i++;
|
|
72
|
+
}
|
|
73
|
+
total += n;
|
|
74
|
+
continue;
|
|
75
|
+
}
|
|
76
|
+
if (LETTER.test(ch)) {
|
|
77
|
+
let word = '';
|
|
78
|
+
while (i < chars.length && (LETTER.test(chars[i]) || DIGIT.test(chars[i]))) {
|
|
79
|
+
word += chars[i];
|
|
80
|
+
i++;
|
|
81
|
+
}
|
|
82
|
+
total += Math.max(1, Math.ceil(effectiveLength(word) / 4));
|
|
83
|
+
continue;
|
|
84
|
+
}
|
|
85
|
+
if (DIGIT.test(ch)) {
|
|
86
|
+
let n = 0;
|
|
87
|
+
while (i < chars.length && DIGIT.test(chars[i])) {
|
|
88
|
+
n++;
|
|
89
|
+
i++;
|
|
90
|
+
}
|
|
91
|
+
total += Math.ceil(n / 3);
|
|
92
|
+
continue;
|
|
93
|
+
}
|
|
94
|
+
// Outside the BMP (emoji, unusual symbols): usually 2+ tokens.
|
|
95
|
+
if (ch.codePointAt(0) > 0xffff) {
|
|
96
|
+
total += 2;
|
|
97
|
+
i++;
|
|
98
|
+
continue;
|
|
99
|
+
}
|
|
100
|
+
// ASCII punctuation and symbols.
|
|
101
|
+
let n = 0;
|
|
102
|
+
while (i < chars.length &&
|
|
103
|
+
!LETTER.test(chars[i]) &&
|
|
104
|
+
!DIGIT.test(chars[i]) &&
|
|
105
|
+
!CJK.test(chars[i]) &&
|
|
106
|
+
chars[i] !== ' ' &&
|
|
107
|
+
chars[i] !== '\n' &&
|
|
108
|
+
chars[i] !== '\t' &&
|
|
109
|
+
chars[i] !== '\r' &&
|
|
110
|
+
chars[i].codePointAt(0) <= 0xffff) {
|
|
111
|
+
n++;
|
|
112
|
+
i++;
|
|
113
|
+
}
|
|
114
|
+
if (n === 0) {
|
|
115
|
+
// Unclassified character: count it as 1 and advance so the loop cannot stall.
|
|
116
|
+
total += 1;
|
|
117
|
+
i++;
|
|
118
|
+
}
|
|
119
|
+
else {
|
|
120
|
+
total += Math.ceil(n / 2);
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
return total;
|
|
124
|
+
}
|
|
125
|
+
/**
|
|
126
|
+
* Exact counter using the official `/v1/messages/count_tokens` endpoint.
|
|
127
|
+
* The endpoint does not bill tokens, so you can use it freely to measure.
|
|
128
|
+
*
|
|
129
|
+
* The third door, and the one nobody had looked at: this takes a `baseUrl` and
|
|
130
|
+
* sends an `x-api-key` to it. Both providers were hardened at the boundary and
|
|
131
|
+
* this was left with no check at all, because it is called a counter rather
|
|
132
|
+
* than a provider. It goes through the same gate now.
|
|
133
|
+
*/
|
|
134
|
+
export function countTokensAnthropic(options) {
|
|
135
|
+
const { apiKey, model = 'claude-opus-5', baseUrl = 'https://api.anthropic.com', fetchImpl = fetch, allowInsecure = false, } = options;
|
|
136
|
+
const endpoint = checkedEndpoint(baseUrl, { allowInsecure, name: 'anthropic-count-tokens' });
|
|
137
|
+
return async (text) => {
|
|
138
|
+
if (!text.trim())
|
|
139
|
+
return 0;
|
|
140
|
+
const res = await fetchImpl(`${endpoint}/v1/messages/count_tokens`, {
|
|
141
|
+
...SAFE_FETCH_INIT,
|
|
142
|
+
method: 'POST',
|
|
143
|
+
headers: {
|
|
144
|
+
'content-type': 'application/json',
|
|
145
|
+
'x-api-key': apiKey,
|
|
146
|
+
'anthropic-version': '2023-06-01',
|
|
147
|
+
},
|
|
148
|
+
body: JSON.stringify({ model, messages: [{ role: 'user', content: text }] }),
|
|
149
|
+
});
|
|
150
|
+
if (!res.ok) {
|
|
151
|
+
throw new Error(`count_tokens failed (${res.status}): ${await res.text()}`);
|
|
152
|
+
}
|
|
153
|
+
const data = (await res.json());
|
|
154
|
+
return data.input_tokens;
|
|
155
|
+
};
|
|
156
|
+
}
|
|
157
|
+
//# sourceMappingURL=tokenizer.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"tokenizer.js","sourceRoot":"","sources":["../src/tokenizer.ts"],"names":[],"mappings":"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"}
|