pi-mega-compact 0.20.42 → 0.20.44
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/assets/vector-cortex/encoder-v1/manifest.json +1 -1
- package/assets/vector-cortex/encoder-v1/model-card.json +1 -1
- package/assets/vector-cortex/encoder-v1/model.onnx +0 -0
- package/assets/vector-cortex/encoder-v1/tokenizer.json +1 -1
- package/dist/config/vector-cortex-enc0a.js +32 -0
- package/dist/config/vector-cortex-enc0b.js +34 -0
- package/dist/config/vector-cortex.js +3 -3
- package/dist/config.js +1 -1
- package/dist/extensions/dashboard-server/routes-rag-settings-vector-cortex.js +2 -0
- package/dist/src/config/vector-cortex-enc0a.js +32 -0
- package/dist/src/config/vector-cortex-enc0b.js +34 -0
- package/dist/src/config/vector-cortex.js +3 -3
- package/dist/src/config.js +1 -1
- package/dist/src/vector-cortex/_acceptance-enc0a-contract.js +60 -0
- package/dist/src/vector-cortex/_acceptance-vc2a-conformance.js +90 -0
- package/dist/src/vector-cortex/_acceptance-vc2a-runtime.js +285 -0
- package/dist/src/vector-cortex/_acceptance-vc2b-conformance.js +92 -0
- package/dist/src/vector-cortex/_acceptance-vc2b-heads.js +221 -0
- package/dist/src/vector-cortex/encoder/asset.js +3 -2
- package/dist/src/vector-cortex/encoder/decision.js +75 -0
- package/dist/src/vector-cortex/encoder/emit.js +2 -0
- package/dist/src/vector-cortex/encoder/encoder-onnx-dispatch.js +58 -0
- package/dist/src/vector-cortex/encoder/onnx.js +147 -0
- package/dist/src/vector-cortex/encoder/runtime-wasm.js +17 -4
- package/dist/src/vector-cortex/encoder/runtime.js +17 -7
- package/dist/src/vector-cortex/encoder/types-vc2c.js +50 -0
- package/dist/src/vector-cortex/encoder/types.js +13 -34
- package/dist/vector-cortex/_acceptance-enc0a-contract.js +60 -0
- package/dist/vector-cortex/_acceptance-vc2a-conformance.js +90 -0
- package/dist/vector-cortex/_acceptance-vc2a-runtime.js +285 -0
- package/dist/vector-cortex/_acceptance-vc2b-conformance.js +92 -0
- package/dist/vector-cortex/_acceptance-vc2b-heads.js +221 -0
- package/dist/vector-cortex/encoder/asset.js +3 -2
- package/dist/vector-cortex/encoder/decision.js +75 -0
- package/dist/vector-cortex/encoder/emit.js +2 -0
- package/dist/vector-cortex/encoder/encoder-onnx-dispatch.js +58 -0
- package/dist/vector-cortex/encoder/onnx.js +147 -0
- package/dist/vector-cortex/encoder/runtime-wasm.js +17 -4
- package/dist/vector-cortex/encoder/runtime.js +17 -7
- package/dist/vector-cortex/encoder/types-vc2c.js +50 -0
- package/dist/vector-cortex/encoder/types.js +13 -34
- package/extensions/dashboard-server/routes-rag-settings-vector-cortex.ts +12 -0
- package/package.json +3 -2
- package/src/config/vector-cortex-enc0a.ts +34 -0
- package/src/config/vector-cortex-enc0b.ts +36 -0
- package/src/config/vector-cortex.ts +3 -3
- package/src/config.ts +2 -0
- package/src/vector-cortex/_acceptance-enc0a-contract.ts +71 -0
- package/src/vector-cortex/_acceptance-vc2a-conformance.ts +119 -0
- package/src/vector-cortex/_acceptance-vc2a-runtime.ts +300 -0
- package/src/vector-cortex/_acceptance-vc2b-conformance.ts +121 -0
- package/src/vector-cortex/_acceptance-vc2b-heads.ts +234 -0
- package/src/vector-cortex/encoder/asset.ts +3 -2
- package/src/vector-cortex/encoder/bench-export.ts +2 -2
- package/src/vector-cortex/encoder/decision.ts +125 -0
- package/src/vector-cortex/encoder/emit.ts +5 -1
- package/src/vector-cortex/encoder/encoder-onnx-dispatch.ts +76 -0
- package/src/vector-cortex/encoder/onnx.ts +198 -0
- package/src/vector-cortex/encoder/runtime-native.ts +1 -1
- package/src/vector-cortex/encoder/runtime-wasm.ts +21 -8
- package/src/vector-cortex/encoder/runtime.ts +27 -9
- package/src/vector-cortex/encoder/types-vc2c.ts +134 -0
- package/src/vector-cortex/encoder/types.ts +19 -115
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* vector-cortex/encoder/decision.ts — ENC-0a backend-decision contract.
|
|
3
|
+
*
|
|
4
|
+
* The durable EncoderBackendDecisionV1 record: which ONNX runtime backend the
|
|
5
|
+
* real learned encoder ships on (transformers.js/WASM vs onnxruntime-node
|
|
6
|
+
* native), whether the 80 MiB install budget holds, the per-platform install
|
|
7
|
+
* matrix, the opset baseline (locked 21 by ENC-0a), the license verdict, and
|
|
8
|
+
* the pinned model/tokenizer sha256 digests.
|
|
9
|
+
*
|
|
10
|
+
* ENC-0a is the DECISION + MEASUREMENT sprint: this contract is what the
|
|
11
|
+
* deterministic resolver (`scripts/encoder/resolve-backend-decision.mjs`) and
|
|
12
|
+
* the durable record (`docs/vector-cortex/encoder-backend-decision.md`) both
|
|
13
|
+
* consume. ENC-0a also owns the opset flip: ENCODER_OPSET is re-baselined to 21
|
|
14
|
+
* in `types.ts` alongside the placeholder manifest (the 2026-08-05 trunk
|
|
15
|
+
* research dropped the earlier Xenova opset-17 requirement). ENC-0b asserts the
|
|
16
|
+
* staged real asset is opset 21 — no further constant change.
|
|
17
|
+
*
|
|
18
|
+
* Contract-first (ENGINEERING_PRACTICES §3). Pi-agnostic, dependency-free
|
|
19
|
+
* (PREVENT-PI-004 — local computation only, never a fetch). No `any`
|
|
20
|
+
* (PREVENT-011).
|
|
21
|
+
*/
|
|
22
|
+
/**
|
|
23
|
+
* The normative ENC-0a budget: the 80 MiB install/asset cap (MODEL_ASSET.md
|
|
24
|
+
* §Qualification). Backend qualifies (budgetOk) iff the shipped byte-count fits.
|
|
25
|
+
*/
|
|
26
|
+
export const ENCODER_INSTALL_BUDGET_MIB = 80;
|
|
27
|
+
/** The p95 latency gate at 512 tokens / 4 threads on linux-x64 (ms). */
|
|
28
|
+
export const ENCODER_DECISION_P95_MS = 40;
|
|
29
|
+
/**
|
|
30
|
+
* buildDecision — assemble a valid, platform-complete EncoderBackendDecisionV1.
|
|
31
|
+
*
|
|
32
|
+
* Pure helper consumed by the acceptance aggregator (and any TS consumer of the
|
|
33
|
+
* decision). Every EncoderPlatform must resolve to a row, and the passed
|
|
34
|
+
* per-platform rows must be complete (no row omitted) — a partial matrix is a
|
|
35
|
+
* contract violation, not a valid decision. All fields are passed in; this is a
|
|
36
|
+
* structural constructor, not a rules engine (the resolver owns the decision
|
|
37
|
+
* rule).
|
|
38
|
+
*/
|
|
39
|
+
export function buildDecision(input) {
|
|
40
|
+
const { platformMatrix } = input;
|
|
41
|
+
const platforms = [
|
|
42
|
+
"linux-x64",
|
|
43
|
+
"linux-arm64",
|
|
44
|
+
"darwin-x64",
|
|
45
|
+
"darwin-arm64",
|
|
46
|
+
"win32-x64",
|
|
47
|
+
];
|
|
48
|
+
for (const p of platforms) {
|
|
49
|
+
if (!Object.prototype.hasOwnProperty.call(platformMatrix, p)) {
|
|
50
|
+
throw new Error(`platform matrix is incomplete: missing row for ${p}`);
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
return {
|
|
54
|
+
schema: "encoder-backend-decision-v1",
|
|
55
|
+
backend: input.backend,
|
|
56
|
+
budgetOk: input.budgetOk,
|
|
57
|
+
opset: 21,
|
|
58
|
+
platformMatrix,
|
|
59
|
+
license: { spdx: "MIT", redistribution: true },
|
|
60
|
+
artifacts: {
|
|
61
|
+
model: {
|
|
62
|
+
path: input.modelPath,
|
|
63
|
+
bytes: input.modelBytes,
|
|
64
|
+
sha256: input.modelSha256,
|
|
65
|
+
},
|
|
66
|
+
tokenizer: {
|
|
67
|
+
path: input.tokenizerPath,
|
|
68
|
+
bytes: input.tokenizerBytes,
|
|
69
|
+
sha256: input.tokenizerSha256,
|
|
70
|
+
},
|
|
71
|
+
},
|
|
72
|
+
p95Ms: input.p95Ms,
|
|
73
|
+
blockedBy: input.blockedBy,
|
|
74
|
+
};
|
|
75
|
+
}
|
|
@@ -17,6 +17,7 @@ import { VC2A_ENABLED } from "../../config/vector-cortex.js";
|
|
|
17
17
|
export const NOOP_ENCODER_REPORTER = {
|
|
18
18
|
assetVerified: () => { },
|
|
19
19
|
runtimeDemoted: () => { },
|
|
20
|
+
onnxSessionLoaded: () => { },
|
|
20
21
|
};
|
|
21
22
|
/**
|
|
22
23
|
* Flag-gated emit: no-op when VC2A is off or no emitter is supplied. The
|
|
@@ -38,5 +39,6 @@ export function createEncoderReporter(emit) {
|
|
|
38
39
|
return {
|
|
39
40
|
assetVerified: (fields) => fire("vector_cortex_encoder_asset_verified", fields),
|
|
40
41
|
runtimeDemoted: (fields) => fire("vector_cortex_encoder_runtime_demoted", fields),
|
|
42
|
+
onnxSessionLoaded: (fields) => fire("vector_cortex_encoder_onnx_loaded", fields),
|
|
41
43
|
};
|
|
42
44
|
}
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* encoder-onnx-dispatch.ts — ENC-0b ONNX dispatch: session lifecycle glue.
|
|
3
|
+
*
|
|
4
|
+
* Extracted from runtime.ts so runtime.ts stays under the 300-line soft limit.
|
|
5
|
+
* Encapsulates the ENC-0b real ONNX session build during load().
|
|
6
|
+
*
|
|
7
|
+
* IMPORTANT (interface constraint): EncoderRuntime.load() and infer() are
|
|
8
|
+
* SYNCHRONOUS — the router (router.ts:121-132) and all acceptance tests call
|
|
9
|
+
* them synchronously. ONNX session creation is ASYNC (WASM init). ENC-0b
|
|
10
|
+
* therefore expose the ONNX session as a SEPARATE async verification: load()
|
|
11
|
+
* fires-and-forgets the session build, verifySession() awaits it for tests,
|
|
12
|
+
* and infer() continues serving the LCG placeholder until the router is wired
|
|
13
|
+
* for async inference (ENC-0c scope). This preserves the sync contract while
|
|
14
|
+
* proving the real ONNX pipeline work end-to-end.
|
|
15
|
+
*
|
|
16
|
+
* ENC-0b gate: when MEGACOMPACT_ENC_0B is OFF, none of this code runs —
|
|
17
|
+
* the LCG stub serves mode A byte-identical to the predecessor.
|
|
18
|
+
*
|
|
19
|
+
* Pi-agnostic (PREVENT-PI-004 / PREVENT-011).
|
|
20
|
+
*/
|
|
21
|
+
import { ENC_0B_ENABLED } from "../../config/vector-cortex.js";
|
|
22
|
+
import { buildOnnxSession } from "./onnx.js";
|
|
23
|
+
/** No-op state when ENC-0b is off or session build not attempted. */
|
|
24
|
+
export const NO_ONNX = { session: null, ready: Promise.resolve() };
|
|
25
|
+
/**
|
|
26
|
+
* Attempt a real ONNX session build during load(). Fire-and-forget: returns
|
|
27
|
+
* immediately with a state whose `ready` Promise resolves once the async
|
|
28
|
+
* build settles. On failure the state's `session` stays null.
|
|
29
|
+
*/
|
|
30
|
+
export function tryBuildOnnx(assetDir, manifest, reporter, allocatedBytes) {
|
|
31
|
+
if (!ENC_0B_ENABLED())
|
|
32
|
+
return NO_ONNX;
|
|
33
|
+
let session = null;
|
|
34
|
+
const ready = buildOnnxSession(assetDir, manifest, reporter, allocatedBytes)
|
|
35
|
+
.then((result) => { if (result.ok)
|
|
36
|
+
session = result.session; })
|
|
37
|
+
.catch(() => { });
|
|
38
|
+
// Return a state whose `session` getter reads the mutable binding after
|
|
39
|
+
// ready resolves (the getter runs at test assertion time, not at load()).
|
|
40
|
+
return { get session() { return session; }, ready };
|
|
41
|
+
}
|
|
42
|
+
/**
|
|
43
|
+
* Await the ONNX session build and verify it with a real inference.
|
|
44
|
+
* Returns the embedding on success, null on any failure.
|
|
45
|
+
* Called by tests and the ENC-0b acceptance aggregator, not by production
|
|
46
|
+
* infer().
|
|
47
|
+
*/
|
|
48
|
+
export async function verifyOnnxSession(state, tokens) {
|
|
49
|
+
await state.ready;
|
|
50
|
+
if (!state.session)
|
|
51
|
+
return null;
|
|
52
|
+
try {
|
|
53
|
+
return await state.session.infer(tokens);
|
|
54
|
+
}
|
|
55
|
+
catch {
|
|
56
|
+
return null;
|
|
57
|
+
}
|
|
58
|
+
}
|
|
@@ -0,0 +1,147 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* vector-cortex/encoder/onnx.ts — ENC-0b real ONNX InferenceSession builder.
|
|
3
|
+
*
|
|
4
|
+
* Creates a WASM-backed ONNX InferenceSession over the committed encoder-v1
|
|
5
|
+
* asset (bge-small-en-v1.5, opset 21, 384-dim sentence_embedding). Dynamically
|
|
6
|
+
* imports onnxruntime-web/wasm (the CPU-only variant) so the module graph
|
|
7
|
+
* compiles on hosts without the package. All failures return typed result
|
|
8
|
+
* codes — this function NEVER throws (PREVENT-011: no `any`).
|
|
9
|
+
*
|
|
10
|
+
* Lifecycle:
|
|
11
|
+
* 1. Check ENCODER_RSS_BUDGET_BYTES before allocation (cap-before-allocation).
|
|
12
|
+
* 2. Assert manifest.opset === ENCODER_OPSET (21).
|
|
13
|
+
* 3. Dynamically import("onnxruntime-web/wasm").
|
|
14
|
+
* 4. Create InferenceSession with wasm EP, 4 threads.
|
|
15
|
+
* 5. Expose infer(tokens) that feeds int64 input_ids + attention_mask + token_type_ids.
|
|
16
|
+
* 6. Return sentence_embedding, L2-normalized to unit norm.
|
|
17
|
+
*
|
|
18
|
+
* Pi-agnostic (PREVENT-PI-004: local file only, zero network).
|
|
19
|
+
*/
|
|
20
|
+
import { dirname, join } from "node:path";
|
|
21
|
+
import { fileURLToPath } from "node:url";
|
|
22
|
+
import { existsSync } from "node:fs";
|
|
23
|
+
import { ENCODER_OPSET, ENCODER_RSS_BUDGET_BYTES, ENCODER_SEMANTIC_WIDTH, } from "./types.js";
|
|
24
|
+
/** ENC-0b failure codes (new ENC_FAIL namespace entries declared here). */
|
|
25
|
+
export const ENC_ONNX_FAIL = {
|
|
26
|
+
OPSET_MISMATCH: "ENC_ONNX_OPSET_MISMATCH",
|
|
27
|
+
RSS_BREACH: "ENC_ONNX_RSS_BREACH",
|
|
28
|
+
MODULE_ABSENT: "ENC_ONNX_MODULE_ABSENT",
|
|
29
|
+
SESSION_ERROR: "ENC_ONNX_SESSION_ERROR",
|
|
30
|
+
MODEL_ABSENT: "ENC_ONNX_MODEL_ABSENT",
|
|
31
|
+
};
|
|
32
|
+
/** Resolve the onnxruntime-web package root from import.meta.url. */
|
|
33
|
+
function resolveOrtWasmPath() {
|
|
34
|
+
try {
|
|
35
|
+
const here = dirname(fileURLToPath(import.meta.url));
|
|
36
|
+
// Walk up to find node_modules/onnxruntime-web/dist/ort-wasm-simd-threaded.wasm
|
|
37
|
+
let dir = here;
|
|
38
|
+
for (let i = 0; i < 12; i++) {
|
|
39
|
+
const candidate = join(dir, "node_modules", "onnxruntime-web", "dist", "ort-wasm-simd-threaded.wasm");
|
|
40
|
+
if (existsSync(candidate))
|
|
41
|
+
return candidate;
|
|
42
|
+
const next = dirname(dir);
|
|
43
|
+
if (next === dir)
|
|
44
|
+
break;
|
|
45
|
+
dir = next;
|
|
46
|
+
}
|
|
47
|
+
return null;
|
|
48
|
+
}
|
|
49
|
+
catch {
|
|
50
|
+
return null;
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
/** L2-normalize a Float32Array in-place; returns the same array. */
|
|
54
|
+
function l2Normalize(arr) {
|
|
55
|
+
let sum = 0;
|
|
56
|
+
for (let i = 0; i < arr.length; i++)
|
|
57
|
+
sum += arr[i] * arr[i];
|
|
58
|
+
const norm = Math.sqrt(sum);
|
|
59
|
+
if (norm > 1e-12) {
|
|
60
|
+
for (let i = 0; i < arr.length; i++)
|
|
61
|
+
arr[i] = arr[i] / norm;
|
|
62
|
+
}
|
|
63
|
+
return arr;
|
|
64
|
+
}
|
|
65
|
+
/**
|
|
66
|
+
* Build a real ONNX InferenceSession over the committed encoder-v1 asset.
|
|
67
|
+
* Returns a typed result — NEVER throws. On any failure the caller demotes
|
|
68
|
+
* to mode B trigram with the returned code.
|
|
69
|
+
*
|
|
70
|
+
* @param assetDir Path to the directory containing model.onnx + manifest.
|
|
71
|
+
* @param manifest The verified ModelManifestV1 from the asset.
|
|
72
|
+
* @param reporter Encoder reporter for the onnx_loaded event (optional).
|
|
73
|
+
* @param allocatedBytes Externally committed bytes (for RSS budget check).
|
|
74
|
+
*/
|
|
75
|
+
export async function buildOnnxSession(assetDir, manifest, reporter, allocatedBytes = 0) {
|
|
76
|
+
// Q01: cap-before-allocation.
|
|
77
|
+
if (allocatedBytes > ENCODER_RSS_BUDGET_BYTES) {
|
|
78
|
+
return { ok: false, code: ENC_ONNX_FAIL.RSS_BREACH };
|
|
79
|
+
}
|
|
80
|
+
// Opset assertion.
|
|
81
|
+
if (manifest.opset !== ENCODER_OPSET) {
|
|
82
|
+
return { ok: false, code: ENC_ONNX_FAIL.OPSET_MISMATCH };
|
|
83
|
+
}
|
|
84
|
+
const modelPath = join(assetDir, manifest.onnx.path);
|
|
85
|
+
if (!existsSync(modelPath)) {
|
|
86
|
+
return { ok: false, code: ENC_ONNX_FAIL.MODEL_ABSENT };
|
|
87
|
+
}
|
|
88
|
+
// Dynamically import onnxruntime-web/wasm (never a hard dependency).
|
|
89
|
+
let ort;
|
|
90
|
+
try {
|
|
91
|
+
ort = (await import("onnxruntime-web/wasm"));
|
|
92
|
+
if (!ort?.InferenceSession?.create) {
|
|
93
|
+
return { ok: false, code: ENC_ONNX_FAIL.MODULE_ABSENT };
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
catch {
|
|
97
|
+
return { ok: false, code: ENC_ONNX_FAIL.MODULE_ABSENT };
|
|
98
|
+
}
|
|
99
|
+
// Resolve WASM binary path for the threading backend.
|
|
100
|
+
const wasmPath = resolveOrtWasmPath();
|
|
101
|
+
let rawSession;
|
|
102
|
+
try {
|
|
103
|
+
const opts = {
|
|
104
|
+
executionProviders: ["wasm"],
|
|
105
|
+
intraOpNumThreads: 4,
|
|
106
|
+
};
|
|
107
|
+
if (wasmPath)
|
|
108
|
+
opts.wasmPaths = wasmPath;
|
|
109
|
+
rawSession = await ort.InferenceSession.create(modelPath, opts);
|
|
110
|
+
}
|
|
111
|
+
catch {
|
|
112
|
+
return { ok: false, code: ENC_ONNX_FAIL.SESSION_ERROR };
|
|
113
|
+
}
|
|
114
|
+
reporter?.onnxSessionLoaded({
|
|
115
|
+
opset: manifest.opset,
|
|
116
|
+
semanticWidth: ENCODER_SEMANTIC_WIDTH,
|
|
117
|
+
threads: 4,
|
|
118
|
+
});
|
|
119
|
+
const session = {
|
|
120
|
+
opset: manifest.opset,
|
|
121
|
+
semanticWidth: ENCODER_SEMANTIC_WIDTH,
|
|
122
|
+
async infer(tokens) {
|
|
123
|
+
const n = tokens.length;
|
|
124
|
+
const inputIds = new BigInt64Array(n);
|
|
125
|
+
const attentionMask = new BigInt64Array(n);
|
|
126
|
+
const tokenTypeIds = new BigInt64Array(n);
|
|
127
|
+
for (let i = 0; i < n; i++) {
|
|
128
|
+
inputIds[i] = BigInt(tokens[i]);
|
|
129
|
+
attentionMask[i] = 1n;
|
|
130
|
+
tokenTypeIds[i] = 0n;
|
|
131
|
+
}
|
|
132
|
+
const feeds = {
|
|
133
|
+
input_ids: { data: inputIds, dims: [1, n], type: "int64" },
|
|
134
|
+
attention_mask: { data: attentionMask, dims: [1, n], type: "int64" },
|
|
135
|
+
token_type_ids: { data: tokenTypeIds, dims: [1, n], type: "int64" },
|
|
136
|
+
};
|
|
137
|
+
const results = await rawSession.run(feeds, ["sentence_embedding"]);
|
|
138
|
+
const out = results["sentence_embedding"];
|
|
139
|
+
if (!out || !(out.data instanceof Float32Array)) {
|
|
140
|
+
return new Float32Array(ENCODER_SEMANTIC_WIDTH);
|
|
141
|
+
}
|
|
142
|
+
return l2Normalize(out.data);
|
|
143
|
+
},
|
|
144
|
+
release: () => rawSession.release(),
|
|
145
|
+
};
|
|
146
|
+
return { ok: true, session };
|
|
147
|
+
}
|
|
@@ -54,10 +54,23 @@ export async function createWasmSession(modelPath, options = {}) {
|
|
|
54
54
|
opset: ENCODER_OPSET,
|
|
55
55
|
semanticWidth: ENCODER_SEMANTIC_WIDTH,
|
|
56
56
|
maxTokens,
|
|
57
|
-
async infer(
|
|
58
|
-
const
|
|
59
|
-
const
|
|
60
|
-
const
|
|
57
|
+
async infer(tokens) {
|
|
58
|
+
const n = tokens.length;
|
|
59
|
+
const inputIds = new BigInt64Array(n);
|
|
60
|
+
const attentionMask = new BigInt64Array(n);
|
|
61
|
+
const tokenTypeIds = new BigInt64Array(n);
|
|
62
|
+
for (let i = 0; i < n; i++) {
|
|
63
|
+
inputIds[i] = BigInt(tokens[i]);
|
|
64
|
+
attentionMask[i] = 1n;
|
|
65
|
+
tokenTypeIds[i] = 0n;
|
|
66
|
+
}
|
|
67
|
+
const feeds = {
|
|
68
|
+
input_ids: { data: inputIds, dims: [1, n], type: "int64" },
|
|
69
|
+
attention_mask: { data: attentionMask, dims: [1, n], type: "int64" },
|
|
70
|
+
token_type_ids: { data: tokenTypeIds, dims: [1, n], type: "int64" },
|
|
71
|
+
};
|
|
72
|
+
const results = await session.run(feeds, ["sentence_embedding"]);
|
|
73
|
+
const out = results["sentence_embedding"];
|
|
61
74
|
if (!out || !(out.data instanceof Float32Array)) {
|
|
62
75
|
return new Float32Array(ENCODER_SEMANTIC_WIDTH);
|
|
63
76
|
}
|
|
@@ -69,6 +69,7 @@ import { selectRuntimeBackend } from "./runtime-select.js";
|
|
|
69
69
|
import { emitRuntimeSelected } from "./runtime-emit.js";
|
|
70
70
|
import { projectSemantic, seedFromBytes } from "./runtime-stub.js";
|
|
71
71
|
import { STATE_DIR_DEFAULT } from "../../config.js";
|
|
72
|
+
import { tryBuildOnnx, NO_ONNX } from "./encoder-onnx-dispatch.js";
|
|
72
73
|
/** Bytes a single encoder-owned projection buffer commits to the marginal
|
|
73
74
|
* footprint (Float32Array, 4 bytes per element). */
|
|
74
75
|
const SEMANTIC_BUFFER_BYTES = ENCODER_SEMANTIC_WIDTH * 4;
|
|
@@ -100,6 +101,7 @@ export function createEncoderRuntime(options = {}) {
|
|
|
100
101
|
let verified = false;
|
|
101
102
|
let maxTokens = ENCODER_MAX_TOKENS;
|
|
102
103
|
let selfAllocated = 0;
|
|
104
|
+
let onnxState = NO_ONNX;
|
|
103
105
|
const footprint = () => selfAllocated + host.allocatedBytes();
|
|
104
106
|
const demoteTo = (rmode, code) => {
|
|
105
107
|
mode = rmode;
|
|
@@ -108,10 +110,12 @@ export function createEncoderRuntime(options = {}) {
|
|
|
108
110
|
};
|
|
109
111
|
const runtime = {
|
|
110
112
|
schema: "encoder-runtime-v1",
|
|
111
|
-
// Live getter so `mode` always reflects the latest load/demote outcome.
|
|
112
113
|
get mode() {
|
|
113
114
|
return mode;
|
|
114
115
|
},
|
|
116
|
+
get onnxState() {
|
|
117
|
+
return onnxState;
|
|
118
|
+
},
|
|
115
119
|
load(assetDir) {
|
|
116
120
|
if (rolledBack) {
|
|
117
121
|
// Q04: report the rollback with its own code, not MANIFEST_INVALID.
|
|
@@ -165,6 +169,13 @@ export function createEncoderRuntime(options = {}) {
|
|
|
165
169
|
});
|
|
166
170
|
emitRuntimeSelected(host.stateDir ?? STATE_DIR_DEFAULT, chosen);
|
|
167
171
|
}
|
|
172
|
+
// ENC-0b: fire-and-forget ONNX session build (async, non-blocking).
|
|
173
|
+
// The sync load() contract is preserved; the session build settles
|
|
174
|
+
// asynchronously and is consumed by verifyOnnxSession for tests +
|
|
175
|
+
// future async-heavy router integration (ENC-0c).
|
|
176
|
+
if (manifest) {
|
|
177
|
+
onnxState = tryBuildOnnx(assetDir, manifest, reporter, footprint());
|
|
178
|
+
}
|
|
168
179
|
return {
|
|
169
180
|
ok: true,
|
|
170
181
|
mode: "A",
|
|
@@ -202,14 +213,13 @@ export function createEncoderRuntime(options = {}) {
|
|
|
202
213
|
};
|
|
203
214
|
}
|
|
204
215
|
const start = host.nowMs();
|
|
205
|
-
//
|
|
206
|
-
//
|
|
207
|
-
//
|
|
208
|
-
//
|
|
216
|
+
// ENC-0b builds the real ONNX session during load() (fire-and-forget);
|
|
217
|
+
// infer() continues serving the LCG placeholder until the router is
|
|
218
|
+
// wired for async inference (ENC-0c). The session is verified by tests
|
|
219
|
+
// via the runtime's verifySession() method.
|
|
209
220
|
const semantic = projectSemantic(seedFromBytes(embeddedBytes) ^ n, ENCODER_SEMANTIC_WIDTH);
|
|
210
221
|
selfAllocated = SEMANTIC_BUFFER_BYTES;
|
|
211
|
-
|
|
212
|
-
return { ok: true, semantic, rssBytes: footprint(), latencyMs, shapeError: null };
|
|
222
|
+
return { ok: true, semantic, rssBytes: footprint(), latencyMs: host.nowMs() - start, shapeError: null };
|
|
213
223
|
},
|
|
214
224
|
};
|
|
215
225
|
return runtime;
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* vector-cortex/encoder/types-vc2c.ts — VC2C qualification + calibration
|
|
3
|
+
* contracts (QualifiedEncoderV1 / CalibrationV1 / EVALUATION_THRESHOLDS).
|
|
4
|
+
*
|
|
5
|
+
* Extracted from types.ts (delegate-shell split) when types.ts crossed the
|
|
6
|
+
* 300-line soft limit. types.ts re-exports everything here; consumers import
|
|
7
|
+
* from types.ts unchanged.
|
|
8
|
+
*
|
|
9
|
+
* Pi-agnostic and dependency-free (PREVENT-PI-004). No `any` (PREVENT-011).
|
|
10
|
+
*/
|
|
11
|
+
/** Normative per-head + asset qualification thresholds (MODEL_ASSET §qualification
|
|
12
|
+
* + EVALUATION.md §metrics). These are the constants `select.ts` evaluates the
|
|
13
|
+
* candidate's held-out metrics against (task 3 atomic check). */
|
|
14
|
+
export const EVALUATION_THRESHOLDS = {
|
|
15
|
+
semantic: { spearman: 0.75, recallAt10: 0.9 },
|
|
16
|
+
dependency: { precision: 0.97, recall: 0.95 },
|
|
17
|
+
contradiction: { precision: 0.98, recall: 0.9, ece: 0.05 },
|
|
18
|
+
cacheStability: { precision: 0.999, recall: 0.9 },
|
|
19
|
+
payloadRouting: { macroF1: 0.97, exactAnchorRecall: 1.0 },
|
|
20
|
+
reconstruction: { dependencyClosureRecall: 1.0 },
|
|
21
|
+
asset: { maxTokens: 512, maxLatencyP95Ms: 40, maxRssDeltaMib: 150 },
|
|
22
|
+
};
|
|
23
|
+
/** VC2C-specific qualification failure codes (returned, never thrown). */
|
|
24
|
+
export const ENC_QUALIFICATION_FAIL = {
|
|
25
|
+
/** The qualification manifest hash does not match the calibration that was fit
|
|
26
|
+
* (corrupt qualification manifest after calibration before selection). */
|
|
27
|
+
DIGEST_MISMATCH: "ENC_QUALIFICATION_DIGEST_MISMATCH",
|
|
28
|
+
/** One or more per-head EVALUATION thresholds failed (demotes all of A). */
|
|
29
|
+
THRESHOLD_FAILED: "ENC_QUALIFICATION_THRESHOLD_FAILED",
|
|
30
|
+
/** An asset-field qualification check (asset/latency/RSS) failed. */
|
|
31
|
+
ASSET_FAILED: "ENC_QUALIFICATION_ASSET_FAILED",
|
|
32
|
+
/** Calibration was attempted using held-out labels (fit prohibition). */
|
|
33
|
+
HELD_OUT_IN_FIT: "ENC_QUALIFICATION_HELD_OUT_IN_FIT",
|
|
34
|
+
};
|
|
35
|
+
/** The 4 registered VC2C conformance IDs (task 1: "register ENC-017..020"). */
|
|
36
|
+
export const ENC2C_IDS = [
|
|
37
|
+
"ENC-017",
|
|
38
|
+
"ENC-018",
|
|
39
|
+
"ENC-019",
|
|
40
|
+
"ENC-020",
|
|
41
|
+
];
|
|
42
|
+
/** The 6 registered ENC-0b conformance IDs (encoder-trunk fixtures). */
|
|
43
|
+
export const ENC_0B_IDS = [
|
|
44
|
+
"ENC-TRUNK-001",
|
|
45
|
+
"ENC-TRUNK-002",
|
|
46
|
+
"ENC-TRUNK-003",
|
|
47
|
+
"ENC-TRUNK-004",
|
|
48
|
+
"ENC-TRUNK-005",
|
|
49
|
+
"ENC-TRUNK-006",
|
|
50
|
+
];
|
|
@@ -24,8 +24,13 @@ export const ENCODER_SUPPORTED_PLATFORMS = [
|
|
|
24
24
|
"darwin-arm64",
|
|
25
25
|
"win32-x64",
|
|
26
26
|
];
|
|
27
|
-
/** ONNX opset required by the normative v1 target
|
|
28
|
-
|
|
27
|
+
/** ONNX opset required by the normative v1 target. ENC-0a re-baselines from 17
|
|
28
|
+
* to 21: the committed placeholder asset (assets/vector-cortex/encoder-v1/)
|
|
29
|
+
* declares opset 21 in its manifest (the 2026-08-05 BAAI/bge-small-en-v1.5
|
|
30
|
+
* upstream export is opset 21; the earlier Xenova opset-17 requirement was
|
|
31
|
+
* dropped). The locked decision is recorded in
|
|
32
|
+
* docs/vector-cortex/encoder-backend-decision.md. */
|
|
33
|
+
export const ENCODER_OPSET = 21;
|
|
29
34
|
/** Batch must be exactly 1 (single-request inference). */
|
|
30
35
|
export const ENCODER_BATCH = 1;
|
|
31
36
|
/** Maximum accepted token count (WordPiece, deterministic truncation). */
|
|
@@ -45,7 +50,7 @@ export const ENCODER_LATENCY_P95_MS = 40;
|
|
|
45
50
|
export const ENCODER_SEMANTIC_WIDTH = 384;
|
|
46
51
|
/** Exact VC2A failure codes (returned, never thrown across the boundary). */
|
|
47
52
|
export const ENC_FAIL = {
|
|
48
|
-
/** opset !=
|
|
53
|
+
/** opset != 21 (ENC-0a re-baseline applied; placeholder manifest updated alongside). */
|
|
49
54
|
OPSET_INVALID: "ENC_OPSET_INVALID",
|
|
50
55
|
/** batch != 1. */
|
|
51
56
|
BATCH_INVALID: "ENC_BATCH_INVALID",
|
|
@@ -136,34 +141,8 @@ export const ENC2B_IDS = [
|
|
|
136
141
|
"ENC-015",
|
|
137
142
|
"ENC-016",
|
|
138
143
|
];
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
dependency: { precision: 0.97, recall: 0.95 },
|
|
145
|
-
contradiction: { precision: 0.98, recall: 0.9, ece: 0.05 },
|
|
146
|
-
cacheStability: { precision: 0.999, recall: 0.9 },
|
|
147
|
-
payloadRouting: { macroF1: 0.97, exactAnchorRecall: 1.0 },
|
|
148
|
-
reconstruction: { dependencyClosureRecall: 1.0 },
|
|
149
|
-
asset: { maxTokens: 512, maxLatencyP95Ms: 40, maxRssDeltaMib: 150 },
|
|
150
|
-
};
|
|
151
|
-
/** VC2C-specific qualification failure codes (returned, never thrown). */
|
|
152
|
-
export const ENC_QUALIFICATION_FAIL = {
|
|
153
|
-
/** The qualification manifest hash does not match the calibration that was fit
|
|
154
|
-
* (corrupt qualification manifest after calibration before selection). */
|
|
155
|
-
DIGEST_MISMATCH: "ENC_QUALIFICATION_DIGEST_MISMATCH",
|
|
156
|
-
/** One or more per-head EVALUATION thresholds failed (demotes all of A). */
|
|
157
|
-
THRESHOLD_FAILED: "ENC_QUALIFICATION_THRESHOLD_FAILED",
|
|
158
|
-
/** An asset-field qualification check (asset/latency/RSS) failed. */
|
|
159
|
-
ASSET_FAILED: "ENC_QUALIFICATION_ASSET_FAILED",
|
|
160
|
-
/** Calibration was attempted using held-out labels (fit prohibition). */
|
|
161
|
-
HELD_OUT_IN_FIT: "ENC_QUALIFICATION_HELD_OUT_IN_FIT",
|
|
162
|
-
};
|
|
163
|
-
/** The 4 registered VC2C conformance IDs (task 1: "register ENC-017..020"). */
|
|
164
|
-
export const ENC2C_IDS = [
|
|
165
|
-
"ENC-017",
|
|
166
|
-
"ENC-018",
|
|
167
|
-
"ENC-019",
|
|
168
|
-
"ENC-020",
|
|
169
|
-
];
|
|
144
|
+
// ---------------------------------------------------------------------------
|
|
145
|
+
// VC2C — encoder qualification + calibration: extracted to types-vc2c.ts
|
|
146
|
+
// (delegate-shell split, soft-limit compliance). Re-exported here.
|
|
147
|
+
// ---------------------------------------------------------------------------
|
|
148
|
+
export { EVALUATION_THRESHOLDS, ENC_QUALIFICATION_FAIL, ENC2C_IDS, ENC_0B_IDS, } from "./types-vc2c.js";
|
|
@@ -252,5 +252,17 @@ export const VECTOR_CORTEX_SETTINGS: SettingGroup = {
|
|
|
252
252
|
"Dedup tier-attribution rollup: per-tier dedup catch shares (L0/L1/L2/new percent of dedup decisions) read from the local events.log dedup_audit stream (GET /api/dedup-tier-attribution). OFF = 404 + no cache file, byte-identical predecessor.",
|
|
253
253
|
true,
|
|
254
254
|
),
|
|
255
|
+
boolDirect(
|
|
256
|
+
"MEGACOMPACT_ENC_0A",
|
|
257
|
+
"ENC-0a Encoder Backend Decision",
|
|
258
|
+
"ENC-0a learned-encoder backend-decision lock: records the transformers.js/WASM vs onnxruntime-node choice, per-platform install matrix, opset-21 baseline and pinned digests in docs/vector-cortex/encoder-backend-decision.md. OFF = no decision record written / no resolver runs, mode B trigram byte-identical predecessor.",
|
|
259
|
+
true,
|
|
260
|
+
),
|
|
261
|
+
boolDirect(
|
|
262
|
+
"MEGACOMPACT_ENC_0B",
|
|
263
|
+
"ENC-0b Real Trunk Fetch & Gated Path",
|
|
264
|
+
"ENC-0b real ONNX trunk fetch + gated inference: replaces the LCG placeholder with the real bge-small int8 model through an ONNX InferenceSession (onnxruntime-web WASM). OFF = LCG placeholder serves byte-identical predecessor output, no ONNX session built.",
|
|
265
|
+
true,
|
|
266
|
+
),
|
|
255
267
|
],
|
|
256
268
|
};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "pi-mega-compact",
|
|
3
|
-
"version": "0.20.
|
|
3
|
+
"version": "0.20.44",
|
|
4
4
|
"description": "Layered, local, vector-backed context compressor for pi — supersede/collapse/cluster compaction with deduped inline recall.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"license": "BSD-3-Clause",
|
|
@@ -71,7 +71,8 @@
|
|
|
71
71
|
"dependencies": {
|
|
72
72
|
"@electric-sql/pglite": "^0.5.4",
|
|
73
73
|
"@electric-sql/pglite-pgvector": "^0.0.5",
|
|
74
|
-
"@mongodb-js/zstd": "^7.0.0"
|
|
74
|
+
"@mongodb-js/zstd": "^7.0.0",
|
|
75
|
+
"onnxruntime-web": "^1.26.0-dev.20260416-b7804b056c"
|
|
75
76
|
},
|
|
76
77
|
"allowScripts": {
|
|
77
78
|
"@mongodb-js/zstd@7.0.0": true
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* config/vector-cortex-enc0a.ts — ENC-0a learned-encoder backend-decision flag.
|
|
3
|
+
*
|
|
4
|
+
* Extracted from vector-cortex.ts so that file stays under the 300-line soft
|
|
5
|
+
* limit (soft-as-hard gate), exactly as vector-cortex-vc9a.ts..vector-cortex-vc9d.ts
|
|
6
|
+
* were. This is the first ENC (real learned encoder) sprint flag. vector-cortex.ts
|
|
7
|
+
* re-exports the ENUM below and root src/config.ts re-exports it, so no consumer
|
|
8
|
+
* import path changes.
|
|
9
|
+
*
|
|
10
|
+
* ENC-0a locks the runtime-backend choice (transformers.js/WASM vs
|
|
11
|
+
* onnxruntime-node native), the per-platform install-size matrix, the opset
|
|
12
|
+
* baseline (re-baselined 17 -> 21) and the license/pinning audit. It writes a
|
|
13
|
+
* durable decision record and bench JSON but touches neither the store schema
|
|
14
|
+
* nor stateDir tables (pure migration).
|
|
15
|
+
*
|
|
16
|
+
* The split is purely mechanical: ENC_0A_ENABLED is byte-identical in name,
|
|
17
|
+
* semantics, and default to the definition it replaces, and vector-cortex.ts
|
|
18
|
+
* re-exports it so every existing `from "./config/vector-cortex.js"` import
|
|
19
|
+
* keeps resolving unchanged.
|
|
20
|
+
*
|
|
21
|
+
* Pi-agnostic, dependency-free (PREVENT-PI-004 / PREVENT-011).
|
|
22
|
+
*/
|
|
23
|
+
|
|
24
|
+
import { sprintFlag } from "./vector-cortex-flag.js";
|
|
25
|
+
|
|
26
|
+
/**
|
|
27
|
+
* ENC-0a — learned-encoder backend-decision lock. Default ON.
|
|
28
|
+
* `MEGACOMPACT_ENC_0A=0` disables and is byte-identical to the predecessor
|
|
29
|
+
* (placeholder encoder): no decision record is written and no newer
|
|
30
|
+
* backend-resolution script runs — the runtime keeps serving mode B trigram
|
|
31
|
+
* exactly as before. This flag MUST also be a dashboard SETTINGS toggle (visible
|
|
32
|
+
* in config UI, never in EXCLUDED_SETTINGS), mirroring VC4A..VC9D.
|
|
33
|
+
*/
|
|
34
|
+
export const ENC_0A_ENABLED = (): boolean => sprintFlag("MEGACOMPACT_ENC_0A");
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* config/vector-cortex-enc0b.ts — ENC-0b real ONNX trunk fetch + gated inference flag.
|
|
3
|
+
*
|
|
4
|
+
* Extracted from vector-cortex.ts so that file stays under the 300-line soft
|
|
5
|
+
* limit (soft-as-hard gate), exactly as vector-cortex-enc0a.ts and the
|
|
6
|
+
* VC8C/VC9A-D/ML5A-E/DEDUP_ATTR siblings were. vector-cortex.ts re-exports the
|
|
7
|
+
* flag below and root src/config.ts re-exports it, so no consumer import path
|
|
8
|
+
* changes.
|
|
9
|
+
*
|
|
10
|
+
* ENC-0b fetches the real bge-small-en-v1.5 int8 ONNX model from the Hugging
|
|
11
|
+
* Face Hub (build-time fetch into the assets directory, NOT a runtime network
|
|
12
|
+
* call — PREVENT-PI-004 safe), wires an ONNX InferenceSession via
|
|
13
|
+
* onnxruntime-web WASM, and runs gated inference through it. The gate is
|
|
14
|
+
* controlled by this flag: OFF = the LCG placeholder encoder serves
|
|
15
|
+
* byte-identical predecessor output and no ONNX session is constructed.
|
|
16
|
+
*
|
|
17
|
+
* The split is purely mechanical: ENC_0B_ENABLED is byte-identical in name,
|
|
18
|
+
* semantics, and default to the definition it replaces, and vector-cortex.ts
|
|
19
|
+
* re-exports it so every existing `from "./config/vector-cortex.js"` import
|
|
20
|
+
* keeps resolving unchanged.
|
|
21
|
+
*
|
|
22
|
+
* Pi-agnostic, dependency-free (PREVENT-PI-004 / PREVENT-011).
|
|
23
|
+
*/
|
|
24
|
+
|
|
25
|
+
import { sprintFlag } from "./vector-cortex-flag.js";
|
|
26
|
+
|
|
27
|
+
/**
|
|
28
|
+
* ENC-0b — real ONNX trunk fetch + gated inference. Default ON.
|
|
29
|
+
* `MEGACOMPACT_ENC_0B=0` disables and is byte-identical to the predecessor
|
|
30
|
+
* (ENC-0a / LCG placeholder): no ONNX session is built, the real bge-small
|
|
31
|
+
* model is not loaded, and the encoder continues serving the LCG placeholder
|
|
32
|
+
* output exactly as before. This flag MUST also be a dashboard SETTINGS toggle
|
|
33
|
+
* (visible in config UI, never in EXCLUDED_SETTINGS), mirroring ENC_0A and
|
|
34
|
+
* VC4A..VC9D.
|
|
35
|
+
*/
|
|
36
|
+
export const ENC_0B_ENABLED = (): boolean => sprintFlag("MEGACOMPACT_ENC_0B");
|
|
@@ -5,8 +5,7 @@
|
|
|
5
5
|
* `=0`/`_DISABLED` off. Flag-OFF is byte-identical to the predecessor sprint's
|
|
6
6
|
* behavior (for VC0A: mode C — observer absent, zero evaluation writes).
|
|
7
7
|
*
|
|
8
|
-
*
|
|
9
|
-
* them without re-declaring the ownership boundary. Pi-agnostic, dependency-free.
|
|
8
|
+
* Breaker/triad constants (TRIAD_RESILIENCE.md) live here; pi-agnostic, dep-free.
|
|
10
9
|
*/
|
|
11
10
|
|
|
12
11
|
import { sprintFlag } from "./vector-cortex-flag.js";
|
|
@@ -268,7 +267,6 @@ export const VC8A_ENABLED = (): boolean => sprintFlag("MEGACOMPACT_VC8A");
|
|
|
268
267
|
*/
|
|
269
268
|
export const VC8B_ENABLED = (): boolean => sprintFlag("MEGACOMPACT_VC8B");
|
|
270
269
|
|
|
271
|
-
// VC8C extracted to vector-cortex-vc8c.ts; re-exported so existing imports keep resolving.
|
|
272
270
|
export { VC8C_ENABLED } from "./vector-cortex-vc8c.js";
|
|
273
271
|
export { VC9A_ENABLED } from "./vector-cortex-vc9a.js";
|
|
274
272
|
export { VC9B_ENABLED } from "./vector-cortex-vc9b.js";
|
|
@@ -281,6 +279,8 @@ export { ML5C_ENABLED } from "./vector-cortex-ml5c.js";
|
|
|
281
279
|
export { ML5D_ENABLED } from "./vector-cortex-ml5d.js";
|
|
282
280
|
export { ML5E_ENABLED } from "./vector-cortex-ml5e.js";
|
|
283
281
|
export { DEDUP_ATTR_ENABLED } from "./vector-cortex-dedup-attr.js";
|
|
282
|
+
export { ENC_0A_ENABLED } from "./vector-cortex-enc0a.js";
|
|
283
|
+
export { ENC_0B_ENABLED } from "./vector-cortex-enc0b.js";
|
|
284
284
|
|
|
285
285
|
// Breaker constants (TRIAD_RESILIENCE.md §breaker) extracted to vector-cortex-breakers.ts.
|
|
286
286
|
export {
|