tokenfold 0.4.0 → 0.5.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/README.md +34 -5
- package/dist/index.d.ts +101 -64
- package/dist/index.js +77 -47
- package/package.json +6 -6
package/README.md
CHANGED
|
@@ -1,19 +1,48 @@
|
|
|
1
|
-
# tokenfold for Node.js
|
|
1
|
+
# tokenfold for Node.js
|
|
2
2
|
|
|
3
|
-
Zero-runtime-dependency TypeScript bindings for the
|
|
3
|
+
Zero-runtime-dependency TypeScript bindings for the Tokenfold Rust CLI.
|
|
4
4
|
|
|
5
5
|
```sh
|
|
6
6
|
npm install tokenfold
|
|
7
7
|
```
|
|
8
8
|
|
|
9
9
|
```ts
|
|
10
|
-
import { compress } from "tokenfold";
|
|
10
|
+
import { compress, decode, inspect } from "tokenfold";
|
|
11
11
|
|
|
12
|
-
const
|
|
12
|
+
const receipt = await inspect(input, { format: "json", preset: "balanced" });
|
|
13
|
+
const { payload, report, text } = await compress(input, {
|
|
13
14
|
format: "json",
|
|
14
|
-
|
|
15
|
+
preset: "balanced",
|
|
15
16
|
});
|
|
16
17
|
```
|
|
17
18
|
|
|
19
|
+
Payloads are `Uint8Array`; the `text` convenience getter decodes UTF-8 strictly.
|
|
20
|
+
`inspect` returns only the side-effect-free receipt.
|
|
21
|
+
|
|
22
|
+
Recoverable pruning is explicit and generic-JSON-only:
|
|
23
|
+
|
|
24
|
+
```ts
|
|
25
|
+
import { compress, retrieve } from "tokenfold";
|
|
26
|
+
|
|
27
|
+
const result = await compress(feed, {
|
|
28
|
+
format: "json",
|
|
29
|
+
targetTokens: 2_000,
|
|
30
|
+
pruning: {
|
|
31
|
+
keepRatio: 0.35,
|
|
32
|
+
preservePaths: ["meta"],
|
|
33
|
+
retrievalStore: ".tokenfold/retrieve",
|
|
34
|
+
},
|
|
35
|
+
});
|
|
36
|
+
const marker = JSON.parse(result.text).items.find((item) => item.$tf_ref);
|
|
37
|
+
const original = await retrieve(marker, { retrievalStore: ".tokenfold/retrieve" });
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
Explicit TOON output is verified before emission and restored with `decode`:
|
|
41
|
+
|
|
42
|
+
```ts
|
|
43
|
+
const encoded = await compress(input, { format: "json", encoding: "toon" });
|
|
44
|
+
const jsonBytes = await decode(encoded.payload, { from: "toon" });
|
|
45
|
+
```
|
|
46
|
+
|
|
18
47
|
Requires Node.js 22 or newer. The matching native CLI is installed through an
|
|
19
48
|
optional platform package; set `TOKENFOLD_BINARY_PATH` to use a custom binary.
|
package/dist/index.d.ts
CHANGED
|
@@ -3,17 +3,23 @@ import { TokenFoldProcessError } from "./errors.js";
|
|
|
3
3
|
import { run, type Input, type ProcessResult, type RunOptions } from "./process.js";
|
|
4
4
|
export { binaryPath, run, TokenFoldProcessError };
|
|
5
5
|
export type { Input, ProcessResult, RunOptions };
|
|
6
|
-
export type
|
|
7
|
-
export type
|
|
6
|
+
export type Preset = "conservative" | "balanced" | "aggressive";
|
|
7
|
+
export type OutputEncoding = "json" | "toon";
|
|
8
|
+
export type InputFormat = "auto" | "openai" | "anthropic" | "json" | "text" | "command" | "diff";
|
|
9
|
+
export type DecodeFormat = "auto" | "json" | "toon" | "text";
|
|
10
|
+
export interface PruningPolicy {
|
|
11
|
+
keepRatio?: number;
|
|
12
|
+
preservePaths?: readonly string[];
|
|
13
|
+
retrievalStore?: string;
|
|
14
|
+
retrievalNamespace?: string;
|
|
15
|
+
}
|
|
8
16
|
export interface CompressionOptions {
|
|
9
|
-
format?:
|
|
10
|
-
|
|
17
|
+
format?: InputFormat;
|
|
18
|
+
preset?: Preset;
|
|
11
19
|
targetTokens?: number;
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
storeOriginals?: boolean;
|
|
16
|
-
retrieveNamespace?: string;
|
|
20
|
+
requireTarget?: boolean;
|
|
21
|
+
encoding?: OutputEncoding;
|
|
22
|
+
pruning?: PruningPolicy;
|
|
17
23
|
configPath?: string;
|
|
18
24
|
signal?: AbortSignal;
|
|
19
25
|
}
|
|
@@ -22,19 +28,6 @@ export interface EstimatorInfo {
|
|
|
22
28
|
model: string | null;
|
|
23
29
|
is_exact: boolean;
|
|
24
30
|
}
|
|
25
|
-
export interface BudgetReport {
|
|
26
|
-
target_tokens: number | null;
|
|
27
|
-
protected_floor: number;
|
|
28
|
-
achieved_tokens: number;
|
|
29
|
-
}
|
|
30
|
-
export interface QualityReport {
|
|
31
|
-
eval_profile_id: string;
|
|
32
|
-
task_scope: string;
|
|
33
|
-
validated_ratio_band: string | null;
|
|
34
|
-
quality_retention: number;
|
|
35
|
-
contrastive_failure_rate: number;
|
|
36
|
-
gate_passed: boolean;
|
|
37
|
-
}
|
|
38
31
|
export interface Warning {
|
|
39
32
|
code: string;
|
|
40
33
|
severity: "info" | "warn" | "critical";
|
|
@@ -53,12 +46,39 @@ export interface TransformReport {
|
|
|
53
46
|
skipped_reason: string | null;
|
|
54
47
|
warnings: readonly Warning[];
|
|
55
48
|
}
|
|
56
|
-
export interface
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
49
|
+
export interface BudgetReport {
|
|
50
|
+
status: "not_requested" | "met" | "best_effort" | "unreachable";
|
|
51
|
+
target_tokens: number | null;
|
|
52
|
+
protected_floor: number;
|
|
53
|
+
achieved_tokens: number;
|
|
54
|
+
}
|
|
55
|
+
export interface EncodingReport {
|
|
56
|
+
codec: string;
|
|
57
|
+
version: string;
|
|
58
|
+
roundtrip_verified: boolean;
|
|
59
|
+
tokens_before: number;
|
|
60
|
+
tokens_after: number;
|
|
61
|
+
token_delta: number;
|
|
60
62
|
warnings: readonly Warning[];
|
|
61
63
|
}
|
|
64
|
+
export interface PruningReport {
|
|
65
|
+
requested: boolean;
|
|
66
|
+
applied: boolean;
|
|
67
|
+
preview: boolean;
|
|
68
|
+
candidate_items: number;
|
|
69
|
+
retained_items: number;
|
|
70
|
+
pruned_items: number;
|
|
71
|
+
evidence_refs: number;
|
|
72
|
+
preserve_paths: readonly string[];
|
|
73
|
+
}
|
|
74
|
+
export interface QualityReport {
|
|
75
|
+
eval_profile_id: string;
|
|
76
|
+
task_scope: string;
|
|
77
|
+
validated_ratio_band: string | null;
|
|
78
|
+
quality_retention: number | null;
|
|
79
|
+
contrastive_failure_rate: number | null;
|
|
80
|
+
gate_passed: boolean;
|
|
81
|
+
}
|
|
62
82
|
export interface RetrievalReport {
|
|
63
83
|
store_namespace: string;
|
|
64
84
|
hash_algorithm: string;
|
|
@@ -67,64 +87,81 @@ export interface RetrievalReport {
|
|
|
67
87
|
persisted_original_bytes: number;
|
|
68
88
|
skipped_original_bytes: number;
|
|
69
89
|
}
|
|
70
|
-
export interface
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
child_exit_code: number | null;
|
|
83
|
-
duration_ms: number;
|
|
84
|
-
raw_output_bytes: number;
|
|
85
|
-
stdout_bytes: number;
|
|
86
|
-
stderr_bytes: number;
|
|
87
|
-
stderr_mode: string;
|
|
88
|
-
stderr_truncated: boolean;
|
|
89
|
-
compressed_output_bytes: number;
|
|
90
|
-
filter_pack_id: string | null;
|
|
91
|
-
filter_version: string | null;
|
|
92
|
-
never_worse_applied: boolean;
|
|
90
|
+
export interface PipelineStageReport {
|
|
91
|
+
id: string;
|
|
92
|
+
version: string | null;
|
|
93
|
+
input_bytes: number | null;
|
|
94
|
+
output_bytes: number | null;
|
|
95
|
+
saved_bytes: number | null;
|
|
96
|
+
input_tokens: number | null;
|
|
97
|
+
output_tokens: number | null;
|
|
98
|
+
saved_tokens: number | null;
|
|
99
|
+
estimator: EstimatorInfo | null;
|
|
100
|
+
status: string;
|
|
101
|
+
duration_ms: number | null;
|
|
93
102
|
bypass_reason: string | null;
|
|
103
|
+
provenance: string;
|
|
104
|
+
recoverability: string;
|
|
105
|
+
evidence_ref: string | null;
|
|
94
106
|
}
|
|
95
|
-
export interface
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
107
|
+
export interface PipelineReport {
|
|
108
|
+
raw_input_bytes: number | null;
|
|
109
|
+
raw_input_tokens: number | null;
|
|
110
|
+
final_output_bytes: number;
|
|
111
|
+
final_output_tokens: number;
|
|
112
|
+
total_saved_tokens: number | null;
|
|
113
|
+
raw_capture: string;
|
|
114
|
+
upstream_recoverability: string;
|
|
115
|
+
stages: readonly PipelineStageReport[];
|
|
100
116
|
}
|
|
101
|
-
export interface
|
|
117
|
+
export interface CompressionReceipt {
|
|
102
118
|
schema_version: string;
|
|
119
|
+
status: "compressed" | "passthrough";
|
|
103
120
|
original_tokens: number;
|
|
104
121
|
compressed_tokens: number;
|
|
105
122
|
saved_tokens: number;
|
|
106
123
|
savings_ratio: number;
|
|
107
124
|
savings_pct: number;
|
|
108
125
|
estimator: EstimatorInfo;
|
|
109
|
-
|
|
110
|
-
mode: string;
|
|
126
|
+
preset: Preset;
|
|
111
127
|
format: string;
|
|
128
|
+
output_encoding: string;
|
|
112
129
|
task_scope: string;
|
|
113
130
|
request_id: string | null;
|
|
131
|
+
pipeline: PipelineReport | null;
|
|
114
132
|
quality: QualityReport | null;
|
|
115
133
|
budget: BudgetReport | null;
|
|
116
|
-
|
|
134
|
+
encoding: EncodingReport | null;
|
|
135
|
+
pruning: PruningReport | null;
|
|
117
136
|
retrieval: RetrievalReport | null;
|
|
118
|
-
output_savings: OutputSavingsReport | null;
|
|
119
|
-
bypass: BypassReport | null;
|
|
120
|
-
command: CommandReport | null;
|
|
121
|
-
ledger: LedgerReport | null;
|
|
122
137
|
transforms: readonly TransformReport[];
|
|
123
138
|
warnings: readonly Warning[];
|
|
139
|
+
cache: unknown;
|
|
140
|
+
output_savings: unknown;
|
|
141
|
+
bypass: unknown;
|
|
142
|
+
command: unknown;
|
|
143
|
+
ledger: unknown;
|
|
124
144
|
}
|
|
145
|
+
export type CompressionReport = CompressionReceipt;
|
|
125
146
|
export interface CompressionResult {
|
|
126
147
|
payload: Uint8Array;
|
|
127
|
-
|
|
148
|
+
readonly text: string;
|
|
149
|
+
report: CompressionReceipt;
|
|
150
|
+
}
|
|
151
|
+
export declare class BudgetUnmetError extends Error {
|
|
152
|
+
readonly receipt: CompressionReceipt;
|
|
153
|
+
constructor(receipt: CompressionReceipt);
|
|
128
154
|
}
|
|
129
155
|
export declare function compress(input: Input, options?: CompressionOptions): Promise<CompressionResult>;
|
|
130
|
-
export declare function inspect(input: Input, options?: CompressionOptions): Promise<
|
|
156
|
+
export declare function inspect(input: Input, options?: CompressionOptions): Promise<CompressionReceipt>;
|
|
157
|
+
export declare function decode(input: Input, options?: {
|
|
158
|
+
from?: DecodeFormat;
|
|
159
|
+
signal?: AbortSignal;
|
|
160
|
+
}): Promise<Uint8Array>;
|
|
161
|
+
export interface RetrieveOptions {
|
|
162
|
+
retrievalStore?: string;
|
|
163
|
+
namespace?: string;
|
|
164
|
+
configPath?: string;
|
|
165
|
+
signal?: AbortSignal;
|
|
166
|
+
}
|
|
167
|
+
export declare function retrieve(reference: string | Record<string, unknown>, options?: RetrieveOptions): Promise<Uint8Array>;
|
package/dist/index.js
CHANGED
|
@@ -2,68 +2,98 @@ import { binaryPath } from "./binary.js";
|
|
|
2
2
|
import { TokenFoldProcessError } from "./errors.js";
|
|
3
3
|
import { run } from "./process.js";
|
|
4
4
|
export { binaryPath, run, TokenFoldProcessError };
|
|
5
|
+
export class BudgetUnmetError extends Error {
|
|
6
|
+
receipt;
|
|
7
|
+
constructor(receipt) { super(`token budget unmet: achieved ${receipt.compressed_tokens} tokens`); this.name = "BudgetUnmetError"; this.receipt = receipt; }
|
|
8
|
+
}
|
|
5
9
|
function argumentsFor(command, options) {
|
|
6
|
-
const args = [command, "--json"];
|
|
10
|
+
const args = [command, "--receipt-format", "json"];
|
|
7
11
|
if (options.format)
|
|
8
12
|
args.push("--format", options.format);
|
|
9
|
-
if (options.
|
|
10
|
-
args.push("--
|
|
13
|
+
if (options.preset)
|
|
14
|
+
args.push("--preset", options.preset);
|
|
11
15
|
if (options.targetTokens !== undefined)
|
|
12
16
|
args.push("--target-tokens", String(options.targetTokens));
|
|
13
|
-
if (options.
|
|
14
|
-
args.push("--
|
|
15
|
-
if (options.
|
|
16
|
-
args.push("--
|
|
17
|
-
if (options.
|
|
18
|
-
args.push("--
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
17
|
+
if (options.requireTarget)
|
|
18
|
+
args.push("--require-target");
|
|
19
|
+
if (options.encoding)
|
|
20
|
+
args.push("--encoding", options.encoding);
|
|
21
|
+
if (options.pruning) {
|
|
22
|
+
args.push("--prune");
|
|
23
|
+
if (options.pruning.keepRatio !== undefined)
|
|
24
|
+
args.push("--keep-ratio", String(options.pruning.keepRatio));
|
|
25
|
+
for (const path of options.pruning.preservePaths ?? [])
|
|
26
|
+
args.push("--preserve", path);
|
|
27
|
+
if (options.pruning.retrievalStore)
|
|
28
|
+
args.push("--retrieval-store", options.pruning.retrievalStore);
|
|
29
|
+
if (options.pruning.retrievalNamespace)
|
|
30
|
+
args.push("--retrieval-namespace", options.pruning.retrievalNamespace);
|
|
23
31
|
}
|
|
24
32
|
if (options.configPath)
|
|
25
33
|
args.push("--config", options.configPath);
|
|
26
34
|
return args;
|
|
27
35
|
}
|
|
28
|
-
function
|
|
36
|
+
function parseReceipt(bytes, result) {
|
|
37
|
+
const text = Buffer.from(bytes).toString("utf8");
|
|
38
|
+
const json = text.split("\ntokenfold:", 1)[0] ?? "";
|
|
29
39
|
try {
|
|
30
|
-
return JSON.parse(
|
|
40
|
+
return JSON.parse(json);
|
|
31
41
|
}
|
|
32
42
|
catch (cause) {
|
|
33
|
-
throw new TokenFoldProcessError("tokenfold returned an invalid JSON
|
|
34
|
-
code: "invalid_report",
|
|
35
|
-
exitCode: result.exitCode,
|
|
36
|
-
signal: result.signal,
|
|
37
|
-
stderr: result.stderr,
|
|
38
|
-
cause,
|
|
39
|
-
});
|
|
43
|
+
throw new TokenFoldProcessError("tokenfold returned an invalid JSON receipt", { code: "invalid_report", exitCode: result.exitCode, signal: result.signal, stderr: result.stderr, cause });
|
|
40
44
|
}
|
|
41
45
|
}
|
|
42
|
-
|
|
43
|
-
const
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
report: parseReport(reportBytes, result),
|
|
62
|
-
};
|
|
46
|
+
function optionsFor(input, signal) {
|
|
47
|
+
const options = { env: { TOKENFOLD_ANALYTICS_ENABLED: "false" } };
|
|
48
|
+
if (input !== undefined)
|
|
49
|
+
options.stdin = input;
|
|
50
|
+
if (signal)
|
|
51
|
+
options.signal = signal;
|
|
52
|
+
return options;
|
|
53
|
+
}
|
|
54
|
+
function withText(payload, report) {
|
|
55
|
+
return { payload, report, get text() { return new TextDecoder("utf-8", { fatal: true }).decode(payload); } };
|
|
56
|
+
}
|
|
57
|
+
export async function compress(input, options = {}) {
|
|
58
|
+
const result = await run(argumentsFor("compress", options), optionsFor(input, options.signal));
|
|
59
|
+
if (result.exitCode !== 0 && result.exitCode !== 7)
|
|
60
|
+
throwProcess(result);
|
|
61
|
+
const receipt = parseReceipt(result.stderr, result);
|
|
62
|
+
if (result.exitCode === 7)
|
|
63
|
+
throw new BudgetUnmetError(receipt);
|
|
64
|
+
return withText(result.stdout, receipt);
|
|
63
65
|
}
|
|
64
|
-
export function
|
|
65
|
-
|
|
66
|
+
export async function inspect(input, options = {}) {
|
|
67
|
+
const result = await run(argumentsFor("inspect", options), optionsFor(input, options.signal));
|
|
68
|
+
if (result.exitCode !== 0 && result.exitCode !== 7)
|
|
69
|
+
throwProcess(result);
|
|
70
|
+
const receipt = parseReceipt(result.stdout, result);
|
|
71
|
+
if (result.exitCode === 7)
|
|
72
|
+
throw new BudgetUnmetError(receipt);
|
|
73
|
+
return receipt;
|
|
74
|
+
}
|
|
75
|
+
export async function decode(input, options = {}) {
|
|
76
|
+
const args = ["decode"];
|
|
77
|
+
if (options.from)
|
|
78
|
+
args.push("--from", options.from);
|
|
79
|
+
const result = await run(args, optionsFor(input, options.signal));
|
|
80
|
+
if (result.exitCode !== 0)
|
|
81
|
+
throwProcess(result);
|
|
82
|
+
return result.stdout;
|
|
83
|
+
}
|
|
84
|
+
export async function retrieve(reference, options = {}) {
|
|
85
|
+
const args = ["retrieve", typeof reference === "string" ? reference : JSON.stringify(reference)];
|
|
86
|
+
if (options.retrievalStore)
|
|
87
|
+
args.push("--retrieval-store", options.retrievalStore);
|
|
88
|
+
if (options.namespace)
|
|
89
|
+
args.push("--retrieval-namespace", options.namespace);
|
|
90
|
+
if (options.configPath)
|
|
91
|
+
args.push("--config", options.configPath);
|
|
92
|
+
const result = await run(args, optionsFor(undefined, options.signal));
|
|
93
|
+
if (result.exitCode !== 0)
|
|
94
|
+
throwProcess(result);
|
|
95
|
+
return result.stdout;
|
|
66
96
|
}
|
|
67
|
-
|
|
68
|
-
|
|
97
|
+
function throwProcess(result) {
|
|
98
|
+
throw new TokenFoldProcessError(`tokenfold exited with status ${result.exitCode ?? result.signal}`, { code: "tokenfold_exit", exitCode: result.exitCode, signal: result.signal, stderr: result.stderr });
|
|
69
99
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "tokenfold",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.5.0",
|
|
4
4
|
"description": "Token-aware compression for LLM payloads, backed by the tokenfold Rust CLI.",
|
|
5
5
|
"license": "Apache-2.0",
|
|
6
6
|
"repository": {
|
|
@@ -49,11 +49,11 @@
|
|
|
49
49
|
"prepack": "npm run build"
|
|
50
50
|
},
|
|
51
51
|
"optionalDependencies": {
|
|
52
|
-
"@tokenfold/cli-darwin-x64": "0.
|
|
53
|
-
"@tokenfold/cli-darwin-arm64": "0.
|
|
54
|
-
"@tokenfold/cli-linux-x64": "0.
|
|
55
|
-
"@tokenfold/cli-linux-arm64": "0.
|
|
56
|
-
"@tokenfold/cli-win32-x64": "0.
|
|
52
|
+
"@tokenfold/cli-darwin-x64": "0.5.0",
|
|
53
|
+
"@tokenfold/cli-darwin-arm64": "0.5.0",
|
|
54
|
+
"@tokenfold/cli-linux-x64": "0.5.0",
|
|
55
|
+
"@tokenfold/cli-linux-arm64": "0.5.0",
|
|
56
|
+
"@tokenfold/cli-win32-x64": "0.5.0"
|
|
57
57
|
},
|
|
58
58
|
"devDependencies": {
|
|
59
59
|
"@types/node": "^24.0.0",
|