pikelet-wasm 0.7.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 ADDED
@@ -0,0 +1,590 @@
1
+ # Pikelet
2
+
3
+ Pikelet is a search engine you host like a file.
4
+
5
+ > Renamed from **Pancake** (2026-09). Same project, same wire format —
6
+ > existing `.pancake` artifacts and their identities remain valid, and the
7
+ > old package names are deprecated pointers to `pikelet-wasm` and
8
+ > `pikelet`.
9
+
10
+ At the bottom there's a small WebAssembly HNSW vector engine that runs
11
+ anywhere JavaScript does — Node, browsers, Cloudflare Workers — with no
12
+ native dependencies. On top of it sit immutable search artifact formats:
13
+ files that package an index, corpus records, query interpretation,
14
+ calibration, and evaluation data, and that can be served from any storage
15
+ that answers byte-range requests.
16
+
17
+ Where this has been heading is the **complete search artifact**: one
18
+ `.pikelet` file that answers natural-language queries with hydrated,
19
+ confidence-scored results, using nothing but the file, range reads, and a
20
+ reader.
21
+
22
+ ```text
23
+ query text
24
+ -> artifact-carried query interpreter
25
+ -> vector search over compressed sketch/index data
26
+ + BM25 over the embedded lexical index, rank-fused
27
+ -> lazy range reads for records
28
+ -> calibrated hydrated results
29
+ ```
30
+
31
+ The `pikelet-wasm` package carries both the vector engine and the artifact
32
+ runtime.
33
+
34
+ ## Knowledge Packs
35
+
36
+ The same file doubles as a **knowledge pack** for LLMs. A `.pikelet` is a
37
+ portable, immutable corpus that contains its own query encoder, semantic
38
+ and lexical indexes, calibrated abstention, provenance, and integrity
39
+ metadata. Publish it as a static file; an MCP client attaches and queries
40
+ it directly over HTTP range requests — no index to rebuild, no vector
41
+ database to run, no embedding service to call:
42
+
43
+ ```bash
44
+ npx pikelet mcp install --client claude-code \
45
+ --pack https://github.com/mcn92/pancake/releases/download/artifact-wiki-inline-v4/pancake-wiki-inline.pancake#1b180adf4c6cebb2dcd5615256df6a25dac5fda8738dbbc11d60af86046f97f3
46
+ ```
47
+
48
+ Then ask questions. That line pins 456,153 passages of Simple English
49
+ Wikipedia by content hash: the mount transfers a ~52 MiB resident slice
50
+ of the 649 MiB file, each question costs ~127 range reads, results carry
51
+ their provenance (pack identity, title, section, source), and a pack that
52
+ cannot answer says so instead of guessing. Details in the
53
+ pikelet README ("Attaching packs to an LLM") and `packs/`.
54
+
55
+ ## What's in This Repo
56
+
57
+ Three layers, bottom to top:
58
+
59
+ 1. **WASM vector engine**
60
+ - In-memory HNSW index with float32 and row-wise affine uint8 backends.
61
+ - JavaScript API: `Pikelet.create()`, `add()`, `search()`, `export()`,
62
+ `restore()`.
63
+ - Source in `src/`, package entrypoints at `pancake.js`,
64
+ `pancake.node.mjs`, `pancake.web.mjs`.
65
+
66
+ 2. **Search artifacts**
67
+ - Immutable, integrity-checked files built from indexes and corpus data,
68
+ range-readable from local files, R2, S3, CDNs — anything that serves
69
+ byte ranges.
70
+ - One product format, one index layer beneath it:
71
+ - `.pikelet`: the complete one-file search artifact — the product.
72
+ - `.pancake-sketch`: its index segment (resident sketch plus lazy
73
+ rerank rows), also usable standalone; format 2 (the builder's
74
+ default) interleaves per-row digests with the rows, so every row a
75
+ query fetches is verified on that read.
76
+ - Two adjacent formats that are not search artifacts in the contract
77
+ sense:
78
+ - `.pnck`: the engine's snapshot envelope (`export()`/`restore()`
79
+ serialization), consumed by the compilers and by layer-1 users.
80
+ - `.pancake-range`: **deprecated** range-readable index profile. The
81
+ sketch geometry replaced it (5x faster over real networks at a
82
+ third of the size); readers stay supported for existing artifacts,
83
+ but no new ones should be built.
84
+ - Specs: [spec/SEARCH_ARTIFACT_CONTRACT.md](spec/SEARCH_ARTIFACT_CONTRACT.md),
85
+ [spec/SKETCH_PROFILE.md](spec/SKETCH_PROFILE.md), and
86
+ [spec/COMPLETE_PROFILE.md](spec/COMPLETE_PROFILE.md).
87
+
88
+ 3. **Products and compilers**
89
+ - `pikelet/`: the fast path. One command compiles a docs
90
+ folder or a live site into a complete `.pikelet` file:
91
+ ```bash
92
+ npx pikelet compile --source ./docs --out search.pikelet
93
+ ```
94
+ or scaffolds a deployable search app:
95
+ ```bash
96
+ npx pikelet create --name my-docs-search --source ./docs --no-deploy --yes
97
+ ```
98
+ - `examples/05-one-file-search/`: the flagship path — the complete
99
+ `.pikelet` container, its compilers, and acceptance tests.
100
+ - `examples/04-static-wiki-pack/`: wiki-scale corpus preparation and the
101
+ sketch artifact pipeline.
102
+ - `examples/03-edge-docs-search/`: a Worker search app with a bundled
103
+ snapshot, distilled query encoder, and calibrated abstention.
104
+
105
+ ## Why Pikelet Exists
106
+
107
+ Most vector search libraries assume a server process, native binaries, or a
108
+ database service. Pikelet is built for a different deployment shape:
109
+
110
+ - static files instead of always-on index servers;
111
+ - byte-range reads instead of whole-index downloads;
112
+ - readers for browsers, Workers, and Node;
113
+ - explicit artifact identity and digest verification;
114
+ - query interpretation and evaluation data carried inside the artifact;
115
+ - compact corpus-side vector representations that keep memory and transfer
116
+ costs sane.
117
+
118
+ The result is search you can host like an asset instead of operating like a
119
+ database.
120
+
121
+ ## The Flagship: One-File Search
122
+
123
+ The complete profile (`.pikelet`) packs the five components of a search
124
+ application into one content-addressed file:
125
+
126
+ ```text
127
+ index embedded .pancake-sketch artifact
128
+ corpus JSON records behind an offsets table
129
+ encoder query interpreter declaration or inline model data
130
+ calibration abstention / match-quality model
131
+ evaluation golden queries and expected behavior
132
+ lexical BM25 inverted index for hybrid retrieval (optional; readers
133
+ that predate it serve vector-only from the same file)
134
+ ```
135
+
136
+ The reader verifies the manifest and eager segments, opens the sketch index
137
+ against a range source, and hydrates only the records the final results
138
+ need.
139
+
140
+ Query interpretation comes in three kinds. Each picks two of
141
+ **self-contained**, **small**, and **teacher-quality**, and gives up the
142
+ third — that trade-off, not history, is why all three exist:
143
+
144
+ - **kind 3: `inline-transformer-v1`** — self-contained + teacher quality.
145
+ The artifact carries the WordPiece vocab and quantized MiniLM teacher
146
+ weights as verified data; the reader ships the execution kernels. Costs
147
+ ~25 MB of encoder no matter how small the corpus. This is the default:
148
+ `pikelet compile` builds kind 3.
149
+ - **kind 1: `student-inline-v1`** — self-contained + small. A
150
+ corpus-distilled student encoder (~1 MiB), pure-JS execution. The only
151
+ way a small docs corpus compiles to a file measured in single-digit MB;
152
+ quality is bounded by the distillation.
153
+ - **kind 2: `external-transformers-v1`** — small + teacher quality, but
154
+ not self-contained: the artifact pins a host-supplied encoder (model id,
155
+ pooling, normalization, max tokens) and verifies it against embedded
156
+ test vectors before serving. The escape hatch for encoders too big to
157
+ inline and hosts that already run one.
158
+
159
+ Kind 3 is the flagship: the file carries the corpus, index, tokenizer,
160
+ encoder weights, calibration, and evaluation data — the reader supplies
161
+ code, the artifact supplies everything else. Ask it about volcanoes and no
162
+ service, model host, or network dependency is involved beyond range reads
163
+ of the file itself.
164
+
165
+ ```bash
166
+ cd examples/05-one-file-search
167
+ node compile-wiki.mjs --inline-encoder
168
+ node compile.mjs --inspect pancake-wiki-inline.pancake
169
+ node test-inline.mjs
170
+ ```
171
+
172
+ Where the inline wiki artifact currently stands:
173
+
174
+ ```text
175
+ 456,153 records
176
+ ~649 MiB complete artifact (680,029,254 bytes)
177
+ manifest identity: 1b180adf4c6cebb2dcd5615256df6a25dac5fda8738dbbc11d60af86046f97f3
178
+ recall@10: 95.2% at the recommended rerank (97.0% at C=600), against exact
179
+ fp32 brute-force ground truth on the 200-query pre-registered eval —
180
+ 98.5% on hand-written natural-language questions, 94.8% on single-title
181
+ lookups (augmented retrieval: hybrid candidates, distance order)
182
+ serves over HTTP range reads: opens on ~52 MiB of the file, ~127 range
183
+ requests per query (cluster-ordered row layout + manifest fetch hints)
184
+ natural-language query with no host encoder option, ~110 ms/query end to
185
+ end locally (the resident scan auto-stages the engine's SIMD kernel at
186
+ this scale; ~540 ms on the pure-JS scan it falls back to)
187
+ ```
188
+
189
+ Release asset (v4 — recovers the pack's canonical build: k-means
190
+ cluster-ordered rows and the 192-dim 2:1-pooled sketch, where v1–v3
191
+ embedded a 96-dim 4:1 sketch in unpermuted order and measured 82.4%; adds
192
+ the hybrid BM25 lexical segment and a format-2 sketch with per-row read
193
+ verification; earlier versions stay published for older checkouts):
194
+ `https://github.com/mcn92/pancake/releases/download/artifact-wiki-inline-v4/pancake-wiki-inline.pancake`
195
+
196
+ `node test-inline.mjs` downloads that file automatically when it is missing
197
+ locally, verifies the manifest identity, and then runs the acceptance
198
+ checks.
199
+
200
+ See [examples/05-one-file-search/README.md](examples/05-one-file-search/README.md)
201
+ for the full one-file walkthrough.
202
+
203
+ ## The Design Choice Everything Hangs On
204
+
205
+ The engine's quantized backend stores corpus vectors as row-wise affine
206
+ uint8:
207
+
208
+ ```text
209
+ value ~= offset[row] + scale[row] * byte
210
+ ```
211
+
212
+ That one constraint propagates through the whole system:
213
+
214
+ - HNSW search keeps the query as float32 and scores it against compressed
215
+ corpus rows.
216
+ - Distance kernels fuse dequantization with dot/L2 accumulation.
217
+ - SIMD paths load bytes, widen lanes, apply scale/offset, and accumulate.
218
+ - Graph maintenance uses symmetric node-to-node distances derived from the
219
+ compressed rows and row statistics.
220
+ - Snapshots serialize compact scale/offset/qdata arrays.
221
+ - Sketch artifacts scan compressed resident rows and fetch only rerank
222
+ candidates.
223
+ - Range-backed readers keep the large corpus side compressed while queries
224
+ stay precise and transient.
225
+
226
+ This is why the engine work and the artifact work belong in one project:
227
+ the same corpus-side representation serves in-memory search, serialized
228
+ snapshots, resident sketches, range reads, and reranking.
229
+
230
+ ## Install
231
+
232
+ From npm:
233
+
234
+ ```bash
235
+ npm install pancake-wasm
236
+ ```
237
+
238
+ From a checkout:
239
+
240
+ ```bash
241
+ git clone https://github.com/mcn92/pancake.git
242
+ cd pancake
243
+ npm install
244
+ ```
245
+
246
+ The checkout includes prebuilt WASM in `dist/`, so you don't need to
247
+ rebuild the engine unless you edit `src/`.
248
+
249
+ ## Runtime Entry Points
250
+
251
+ Published package:
252
+
253
+ ```js
254
+ // Node.js CJS
255
+ const Pikelet = require('pikelet-wasm');
256
+
257
+ // Node.js ESM
258
+ import Pikelet from 'pikelet-wasm';
259
+
260
+ // Explicit Node/browser entries
261
+ import Pikelet from 'pikelet-wasm/node';
262
+ import Pikelet from 'pikelet-wasm/web';
263
+
264
+ // Search Artifact layer (sketch readers/builders; the deprecated
265
+ // .pancake-range reader stays exported for existing artifacts)
266
+ import { PancakeSketchArtifact, buildSketchArtifact } from 'pikelet-wasm/artifact';
267
+
268
+ // Complete one-file profile: reader (any runtime) and builder (Node)
269
+ import { openPikeletFile } from 'pikelet-wasm/complete';
270
+ import { assemblePancakeFile } from 'pikelet-wasm/complete/builder';
271
+ ```
272
+
273
+ Repository checkout:
274
+
275
+ ```js
276
+ const Pikelet = require('./pancake.js');
277
+ import Pikelet from './pancake.node.mjs';
278
+ import Pikelet from './pancake.web.mjs';
279
+ ```
280
+
281
+ The browser entry expects the runtime or bundler to resolve
282
+ `dist/engine.wasm`.
283
+
284
+ ## Engine Quick Start
285
+
286
+ Use the core engine when you already have vectors and want an in-memory ANN
287
+ index.
288
+
289
+ ```js
290
+ import Pikelet from 'pikelet-wasm';
291
+
292
+ const index = await Pikelet.create({
293
+ dim: 384,
294
+ maxElements: 100000,
295
+ metric: 'cosine',
296
+ quantized: true,
297
+ });
298
+
299
+ const docVector = new Float32Array(384).fill(0.1); // your embedding here
300
+ const queryVector = new Float32Array(384).fill(0.1); // your query embedding here
301
+
302
+ const id = index.add(docVector);
303
+
304
+ const results = index.search(queryVector, 10);
305
+ // [{ id: 0, distance: 0.12 }, ...]
306
+
307
+ index.delete(id);
308
+ index.compact();
309
+
310
+ const snapshot = index.export();
311
+ const restored = await Pikelet.restore(snapshot, { maxElements: 100000 });
312
+
313
+ index.dispose();
314
+ restored.dispose();
315
+ ```
316
+
317
+ If you have records with vectors:
318
+
319
+ ```js
320
+ const rows = [
321
+ { id: 'doc-1', vector: embedding1 },
322
+ { id: 'doc-2', vector: embedding2 },
323
+ ];
324
+
325
+ const { index, idMap } = await Pikelet.fromVectors(rows, {
326
+ metric: 'cosine',
327
+ quantized: true,
328
+ });
329
+
330
+ const hits = index.search(queryEmbedding, 5);
331
+ console.log(idMap.get(hits[0].id));
332
+ ```
333
+
334
+ On Node entrypoints, file helpers are available:
335
+
336
+ ```js
337
+ const { index, idMap } = await Pikelet.loadJsonFile('vectors.jsonl', {
338
+ metric: 'cosine',
339
+ vectorKey: 'embedding',
340
+ idKey: 'docId',
341
+ maxFileBytes: 64 * 1024 * 1024,
342
+ });
343
+
344
+ const restored = await Pikelet.loadSnapshotFile('index.pnck', {
345
+ dim: 384,
346
+ maxElements: 100000,
347
+ metric: 'cosine',
348
+ quantized: true,
349
+ });
350
+ ```
351
+
352
+ ## Complete Artifact Quick Start
353
+
354
+ Use the complete reader when you want a file that is itself the search
355
+ application data plane. To build one from your own docs, see the compile
356
+ command above (`npx pikelet compile`).
357
+
358
+ ```js
359
+ import { openPikeletFile } from 'pikelet-wasm/complete'; // or './complete/index.mjs' in a checkout
360
+
361
+ const search = await openPikeletFile('examples/05-one-file-search/pancake-docs.pancake');
362
+
363
+ const out = await search.query('how do workers restore snapshots', { k: 5 });
364
+
365
+ console.log(out.matchQuality, out.confidence);
366
+ console.log(out.results[0].title);
367
+
368
+ await search.close();
369
+ ```
370
+
371
+ For kind-3 artifacts, no host encoder is needed:
372
+
373
+ ```js
374
+ const search = await openPikeletFile('pancake-wiki-inline.pancake');
375
+ const out = await search.query('how do volcanoes form', { k: 5 });
376
+ ```
377
+
378
+ For kind-2 artifacts, pass `options.encodeQuery`; the reader runs it
379
+ against the declaration's verification vectors before serving and refuses
380
+ the open if they disagree (`info().encoderVerified` reports the outcome).
381
+
382
+ The reader also accepts a range source, which is how a `.pikelet` on R2 or
383
+ a CDN gets queried without downloading it:
384
+
385
+ ```js
386
+ const search = await openPikeletFile({
387
+ size,
388
+ async read(offset, length) {
389
+ // return bytes for [offset, offset + length)
390
+ },
391
+ });
392
+ ```
393
+
394
+ On integrity: every artifact-derived read is bounds-checked and budgeted
395
+ (`maxReadBytes`, `maxRecordBytes`). Format-2 files (`pancake-complete-v2`,
396
+ the builder's default) verify each hydrated record against a per-record
397
+ digest on its own range read (`info().corpusIntegrity`), and an embedded
398
+ format-2 sketch verifies each lazily fetched index row the same way
399
+ (`info().indexRowIntegrity`) — so a tampered transport fails the query
400
+ instead of skewing its results. Older files with a format-1 sketch commit
401
+ the lazy index rows to the identity but don't verify them per read; for
402
+ those, pass `verifyIndexVectors: true` (or call `verifyVectors()`) to
403
+ authenticate them in one full pass before trusting results from an
404
+ untrusted transport (spec/COMPLETE_PROFILE.md section 6).
405
+
406
+ ### Attaching packs to an LLM
407
+
408
+ A complete artifact doubles as a portable knowledge pack: everything an
409
+ LLM needs to query a body of knowledge — corpus, indexes, encoder,
410
+ calibrated abstention, integrity commitments — in one immutable,
411
+ identity-pinned file. `pikelet mcp` serves packs over the
412
+ Model Context Protocol so Claude Code, Claude Desktop, or any agent
413
+ framework can attach them as a retrieval tool with one config line — no
414
+ vector database, no embedding service, no retrieval backend. Results
415
+ carry full provenance (pack, manifest identity, title, heading path,
416
+ source), and a pack that cannot answer says so instead of returning
417
+ plausible noise. See the pikelet README's
418
+ "Attaching packs to an LLM (MCP)" section.
419
+
420
+ ## Demos
421
+
422
+ Start with [DEMOS.md](DEMOS.md) for the maintained demo path.
423
+
424
+ Useful commands:
425
+
426
+ ```bash
427
+ npm run demo # synthetic engine validation
428
+ npm run demo:artifact # range artifact search
429
+ npm run demo:sketch # sketch artifact search/rerank path
430
+ npm run test:browser # browser smoke test
431
+ node examples/05-one-file-search/test-file.mjs
432
+ node examples/05-one-file-search/test-wiki.mjs
433
+ node examples/05-one-file-search/test-inline.mjs
434
+ ```
435
+
436
+ The one-file example is the closest thing to the project's current center
437
+ of gravity:
438
+
439
+ ```bash
440
+ cd examples/05-one-file-search
441
+ node compile.mjs
442
+ node test-file.mjs
443
+ node serve.mjs
444
+ ```
445
+
446
+ ## API Snapshot
447
+
448
+ Core index:
449
+
450
+ ```js
451
+ const index = await Pikelet.create(options);
452
+ index.add(vector);
453
+ index.addBatch(vectors);
454
+ index.search(query, k, options?);
455
+ index.searchFiltered(query, k, allowedIds, options?); // allowedIds: Set of ids
456
+ index.delete(id);
457
+ index.compact();
458
+ index.export();
459
+ index.dispose();
460
+ ```
461
+
462
+ Common options:
463
+
464
+ ```js
465
+ {
466
+ dim: 384,
467
+ maxElements: 100000,
468
+ metric: 'cosine', // 'cosine' or 'l2'
469
+ quantized: true,
470
+ M: 12,
471
+ efConstruction: 75,
472
+ efSearch: 100,
473
+ seed: 108
474
+ }
475
+ ```
476
+
477
+ Snapshot helpers:
478
+
479
+ ```js
480
+ await Pikelet.restore(bytes, options);
481
+ await Pikelet.loadSnapshotFile(path, options);
482
+ await Pikelet.loadJsonFile(path, options);
483
+ await Pikelet.fromVectors(rows, options);
484
+ ```
485
+
486
+ Range and sketch artifact APIs ship at `pikelet-wasm/artifact`; the
487
+ complete-profile reader and builder ship at `pikelet-wasm/complete` and
488
+ `pikelet-wasm/complete/builder`. The wiki-scale compilers and acceptance
489
+ tests live in `examples/05-one-file-search/`.
490
+
491
+ ## Building From Source
492
+
493
+ You only need this if you change the C++ engine under `src/`.
494
+
495
+ Requirements:
496
+
497
+ - Node.js
498
+ - Emscripten SDK
499
+
500
+ Build:
501
+
502
+ ```bash
503
+ npm run build
504
+ ```
505
+
506
+ Build scalar and SIMD variants:
507
+
508
+ ```bash
509
+ npm run build:all
510
+ ```
511
+
512
+ The build emits `dist/engine.js`, `dist/engine.wasm`, and scalar variants.
513
+
514
+ ## Tests
515
+
516
+ Core (`npm test` also runs the artifact and complete-profile conformance
517
+ suites):
518
+
519
+ ```bash
520
+ npm test
521
+ npm run test:fuzz
522
+ npm run test:simd
523
+ npm run test:browser
524
+ npm run test:scaffold
525
+ ```
526
+
527
+ Complete profile, end to end:
528
+
529
+ ```bash
530
+ node examples/05-one-file-search/test-file.mjs
531
+ node examples/05-one-file-search/test-wiki.mjs
532
+ node examples/05-one-file-search/test-inline.mjs
533
+ ```
534
+
535
+ The inline wiki acceptance test downloads the large release artifact on
536
+ demand when `examples/05-one-file-search/pancake-wiki-inline.pancake` is
537
+ missing.
538
+
539
+ ## Performance Notes
540
+
541
+ Performance is workload-dependent, but these are the knobs that matter:
542
+
543
+ - `quantized: true` for much smaller corpus-side vector storage.
544
+ - `efSearch` for the recall/latency tradeoff.
545
+ - sketch artifacts for depth-1 candidate selection before lazy rerank
546
+ reads.
547
+ - corpus layout and clustering for fewer remote read rounds.
548
+ - kind-3 inline encoders when deployment shouldn't depend on an external
549
+ ML runtime.
550
+
551
+ The older engine-level benchmarks are still useful for HNSW behavior. The
552
+ newer artifact-level benchmarks are more representative of what the project
553
+ is actually for: search from static files and range-readable storage.
554
+
555
+ The native baselines the engine benchmarks compare against (faiss-node,
556
+ hnswlib-node, usearch) are not dependencies of `pikelet-wasm`; install
557
+ them on demand with `cd benchmarks && npm install` before running those
558
+ scripts. See `benchmarks/`, `benchmark_results/`, and the example READMEs
559
+ for current numbers.
560
+
561
+ ## Tradeoffs
562
+
563
+ Pikelet is a good fit when:
564
+
565
+ - you want search in JavaScript runtimes without native addons;
566
+ - you want static-file or edge deployment;
567
+ - you need reproducible, inspectable search artifacts;
568
+ - your corpus can be built offline;
569
+ - byte-range reads are cheaper than operating a dedicated search service.
570
+
571
+ It's the wrong tool when:
572
+
573
+ - you need high-rate online mutation;
574
+ - you need a multi-tenant database server;
575
+ - you require exact nearest-neighbor search at large scale;
576
+ - your deployment can already use a mature native ANN service with no
577
+ portability constraints.
578
+
579
+ ## Status
580
+
581
+ The engine and the artifact readers/builders are published and usable
582
+ today (`pikelet-wasm`, with `pikelet` as the app scaffold).
583
+ The complete `.pikelet` profile's spec is still marked draft — Draft 2,
584
+ under review, not frozen — but its reader and builder ship in the package,
585
+ and it is the clearest expression of where the project is going: a search
586
+ engine packaged as one verified, range-readable file.
587
+
588
+ ## License
589
+
590
+ Apache-2.0. See [LICENSE](LICENSE).
@@ -0,0 +1,82 @@
1
+ /**
2
+ * pikelet-wasm/complete/builder — Node-only assembly of complete .pancake
3
+ * artifacts (spec/COMPLETE_PROFILE.md). The wire-format constants here are
4
+ * the same objects the reader uses (complete/format.mjs).
5
+ */
6
+
7
+ export declare const MAGIC: number;
8
+ export declare const HEADER_BYTES: number;
9
+ export declare const TABLE_ENTRY_BYTES: number;
10
+ export declare const KINDS: Record<string, number>;
11
+ export declare const KIND_NAMES: Record<number, string>;
12
+
13
+ export declare function sha256(bytes: Uint8Array | Buffer): Buffer;
14
+ export declare function canonicalJson(value: unknown): string;
15
+ export declare const align16: (n: number) => number;
16
+
17
+ /** Manifest profile strings and the header formatVersion each one implies. */
18
+ export declare const PROFILE_V1: 'pancake-complete-v1';
19
+ export declare const PROFILE_V2: 'pancake-complete-v2';
20
+ export declare const FORMAT_VERSIONS: Record<string, number>;
21
+ /** Corpus layout name for format 2 (per-record digests behind a page table). */
22
+ export declare const CORPUS_LAYOUT_V2: 'records-v2';
23
+ export declare const DEFAULT_CORPUS_PAGE_RECORDS: number;
24
+
25
+ export declare function buildQueryInterpSegment(kind: number, encoderBytes: Buffer | Uint8Array, calibrationBytes: Buffer | Uint8Array): Buffer;
26
+ /** Corpus layout v1 (format 1): count + offsets + records, whole-segment integrity only. */
27
+ export declare function buildCorpusSegmentFromBuffers(records: Array<Buffer | Uint8Array>): Buffer;
28
+ /**
29
+ * Corpus layout v2 (format 2): count, pageRecords, offsets, a page table of
30
+ * SHA-256s over runs of record digests, one SHA-256 per record, then the
31
+ * records. Spread the returned `corpus` block into manifest.corpus.
32
+ */
33
+ export declare function buildCorpusSegment(records: Array<Buffer | Uint8Array>, options?: { pageRecords?: number }): {
34
+ bytes: Buffer;
35
+ corpus: {
36
+ records: number;
37
+ layout: 'records-v2';
38
+ pageRecords: number;
39
+ pages: number;
40
+ recordDigest: 'sha256';
41
+ pageTableSha256: string;
42
+ };
43
+ };
44
+ export declare function buildInlineTransformerEncoderSegment(input: {
45
+ declaration: Record<string, unknown>;
46
+ vocabBytes: Buffer | Uint8Array;
47
+ weightBytes: Buffer | Uint8Array;
48
+ }): Buffer;
49
+ /**
50
+ * Writes the container. manifestFields.profile selects the header format
51
+ * version (PROFILE_V1 -> 1 with a v1 corpus, PROFILE_V2 -> 2 with a
52
+ * buildCorpusSegment() corpus); mismatches throw. Segments with a kind this
53
+ * spec does not name must carry an explicit kindNumber (readers skip them).
54
+ */
55
+ export declare function assemblePancakeFile(
56
+ manifestFields: Record<string, unknown> & { profile: string; corpus: { records: number } & Record<string, unknown> },
57
+ segments: Array<{ kind: string; bytes: Buffer | Uint8Array; kindNumber?: number }>,
58
+ outPath: string
59
+ ): { outPath: string; fileBytes: number; formatVersion: number; identity: string; manifest: Record<string, unknown> };
60
+
61
+ /** Measured recall-vs-rerank operating point (SKETCH_PROFILE.md section 5). */
62
+ export declare function measureRecommendedRerank(input: {
63
+ artifactModule: unknown;
64
+ sketchBytes: Uint8Array | ArrayBufferLike;
65
+ queryVectors?: Float32Array[] | null;
66
+ snapshotBytes?: Uint8Array | ArrayBufferLike | null;
67
+ k?: number;
68
+ targetRecall?: number;
69
+ maxQueries?: number;
70
+ sweep?: number[] | null;
71
+ }): Promise<{
72
+ recommendedRerank: number;
73
+ recall: number;
74
+ k: number;
75
+ targetRecall: number;
76
+ queries: number;
77
+ querySource: string;
78
+ curve: Array<{ rerank: number; recall: number }>;
79
+ }>;
80
+
81
+ /** Kind-3 kernel via the web glue with an explicit wasm binary (jiti-safe). */
82
+ export declare function loadInlineEncoderKernel(): Promise<() => unknown>;