@soulcraft/cor 3.0.0-rc.1
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 +16 -0
- package/README.md +328 -0
- package/dist/aggregation/NativeAggregationEngine.d.ts +118 -0
- package/dist/aggregation/NativeAggregationEngine.js +186 -0
- package/dist/cli.d.ts +12 -0
- package/dist/cli.js +236 -0
- package/dist/graph/GraphAccelerationAdapter.d.ts +153 -0
- package/dist/graph/GraphAccelerationAdapter.js +326 -0
- package/dist/graph/NativeGraphAdjacencyIndex.d.ts +286 -0
- package/dist/graph/NativeGraphAdjacencyIndex.js +944 -0
- package/dist/hnsw/AdaptiveDiskAnnModeSelector.d.ts +187 -0
- package/dist/hnsw/AdaptiveDiskAnnModeSelector.js +313 -0
- package/dist/hnsw/NativeDiskAnnWrapper.d.ts +489 -0
- package/dist/hnsw/NativeDiskAnnWrapper.js +1456 -0
- package/dist/index.d.ts +28 -0
- package/dist/index.js +29 -0
- package/dist/legacyLayoutGuard.d.ts +93 -0
- package/dist/legacyLayoutGuard.js +237 -0
- package/dist/license/constants.d.ts +30 -0
- package/dist/license/constants.js +30 -0
- package/dist/license/onlineValidator.d.ts +43 -0
- package/dist/license/onlineValidator.js +225 -0
- package/dist/license/types.d.ts +39 -0
- package/dist/license/types.js +5 -0
- package/dist/license.d.ts +64 -0
- package/dist/license.js +165 -0
- package/dist/migration/MigrationCoordinator.d.ts +171 -0
- package/dist/migration/MigrationCoordinator.js +249 -0
- package/dist/migration/indexEpochGuard.d.ts +163 -0
- package/dist/migration/indexEpochGuard.js +202 -0
- package/dist/native/NativeEmbeddingEngine.d.ts +79 -0
- package/dist/native/NativeEmbeddingEngine.js +318 -0
- package/dist/native/NativeRoaringBitmap32.d.ts +114 -0
- package/dist/native/NativeRoaringBitmap32.js +221 -0
- package/dist/native/ffi.d.ts +20 -0
- package/dist/native/ffi.js +48 -0
- package/dist/native/idMapperTestSupport.d.ts +67 -0
- package/dist/native/idMapperTestSupport.js +112 -0
- package/dist/native/index.d.ts +49 -0
- package/dist/native/index.js +87 -0
- package/dist/native/napi.d.ts +21 -0
- package/dist/native/napi.js +88 -0
- package/dist/native/types.d.ts +1298 -0
- package/dist/native/types.js +16 -0
- package/dist/plugin.d.ts +50 -0
- package/dist/plugin.js +388 -0
- package/dist/providerContracts.d.ts +277 -0
- package/dist/providerContracts.js +38 -0
- package/dist/resource/OsMemoryProbe.d.ts +175 -0
- package/dist/resource/OsMemoryProbe.js +206 -0
- package/dist/resource/ResourceManager.d.ts +491 -0
- package/dist/resource/ResourceManager.js +960 -0
- package/dist/utils/ColumnManifest.d.ts +97 -0
- package/dist/utils/ColumnManifest.js +129 -0
- package/dist/utils/NativeColumnStore.d.ts +284 -0
- package/dist/utils/NativeColumnStore.js +685 -0
- package/dist/utils/NativeMetadataIndex.d.ts +882 -0
- package/dist/utils/NativeMetadataIndex.js +2631 -0
- package/dist/utils/NativeUnifiedCache.d.ts +87 -0
- package/dist/utils/NativeUnifiedCache.js +273 -0
- package/dist/utils/binaryIdMapperFactory.d.ts +59 -0
- package/dist/utils/binaryIdMapperFactory.js +94 -0
- package/dist/utils/collation.d.ts +30 -0
- package/dist/utils/collation.js +40 -0
- package/dist/utils/columnStoreTypes.d.ts +161 -0
- package/dist/utils/columnStoreTypes.js +29 -0
- package/dist/utils/nativeBinaryEntityIdMapper.d.ts +211 -0
- package/dist/utils/nativeBinaryEntityIdMapper.js +381 -0
- package/dist/utils/nativeEntityIdMapper.d.ts +111 -0
- package/dist/utils/nativeEntityIdMapper.js +170 -0
- package/docs/ADR-002-diskann-100-percent-rust.md +294 -0
- package/docs/ADR-003-semantic-time-travel.md +100 -0
- package/docs/aggregation.md +251 -0
- package/docs/comparison.md +162 -0
- package/docs/deployment-limits.md +87 -0
- package/docs/diskann.md +184 -0
- package/docs/migration-3.0.md +396 -0
- package/docs/performance-budget.md +274 -0
- package/docs/performance.md +117 -0
- package/docs/scaling.md +439 -0
- package/docs/snapshot-safety.md +246 -0
- package/docs/u64-id-space.md +214 -0
- package/docs/verification-report.md +670 -0
- package/native/brainy-native.node +0 -0
- package/native/index.d.ts +3916 -0
- package/package.json +92 -0
- package/scripts/migrate-cortex-2x-to-3x.mjs +970 -0
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Shared types for the native module integration.
|
|
3
|
+
*
|
|
4
|
+
* These types are used by both the napi-rs and bun:ffi loaders.
|
|
5
|
+
* Ported from src/embeddings/wasm/types.ts — keeps the same API surface.
|
|
6
|
+
*/
|
|
7
|
+
/**
|
|
8
|
+
* Model constants for all-MiniLM-L6-v2
|
|
9
|
+
*/
|
|
10
|
+
export const MODEL_CONSTANTS = {
|
|
11
|
+
HIDDEN_SIZE: 384,
|
|
12
|
+
MAX_SEQUENCE_LENGTH: 256,
|
|
13
|
+
VOCAB_SIZE: 30522,
|
|
14
|
+
MODEL_NAME: 'all-MiniLM-L6-v2',
|
|
15
|
+
};
|
|
16
|
+
//# sourceMappingURL=types.js.map
|
package/dist/plugin.d.ts
ADDED
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @module plugin
|
|
3
|
+
* @description `@soulcraft/cor` Brainy plugin entry point.
|
|
4
|
+
*
|
|
5
|
+
* Implements the `BrainyPlugin` interface to register every native
|
|
6
|
+
* provider cor 3.0 ships. Brainy auto-detects this plugin during
|
|
7
|
+
* `init()` via dynamic import.
|
|
8
|
+
*
|
|
9
|
+
* ## Tier gating
|
|
10
|
+
*
|
|
11
|
+
* - **Free tier (no license key)**: nothing registered — brainy runs
|
|
12
|
+
* on its pure-JS defaults with zero acceleration.
|
|
13
|
+
* - **Pro / Enterprise / Internal**: every compute provider below
|
|
14
|
+
* wired in. Cor is a pure 1:1 accelerator — it registers ONLY
|
|
15
|
+
* the providers brainy currently looks up; native capabilities
|
|
16
|
+
* that don't yet have a brainy hook stay dormant in the cdylib.
|
|
17
|
+
*
|
|
18
|
+
* ## Cor 3.0 surface (Piece F, 2026-06-09)
|
|
19
|
+
*
|
|
20
|
+
* | Provider | Implementation |
|
|
21
|
+
* |-------------------|---------------------------------------------|
|
|
22
|
+
* | `distance` | SIMD-accelerated cosine |
|
|
23
|
+
* | `distance:sq8` | SQ8 quantized cosine (uint8) |
|
|
24
|
+
* | `distance:sq4` | SQ4 quantized cosine (packed nibbles) |
|
|
25
|
+
* | `graph:compression` | delta-varint connection codec |
|
|
26
|
+
* | `hnsw` | **Adaptive DiskANN** (`NativeDiskAnnWrapper`) — the vector index. The provider key is brainy's historical name; cor's implementation is DiskANN |
|
|
27
|
+
* | `diskann` | Same `NativeDiskAnnWrapper` under brainy's explicit DiskANN key (for callers that set `config.index.type='diskann'`) |
|
|
28
|
+
* | `cache` | Native eviction engine (`NativeUnifiedCacheWrapper`) |
|
|
29
|
+
* | `metadataIndex` | Native LSM-backed metadata index + column store |
|
|
30
|
+
* | `graphIndex` | Native graph adjacency (u64-keyed LSM trees) |
|
|
31
|
+
* | `embeddings` | Candle ML (CPU/CUDA/Metal) |
|
|
32
|
+
* | `embedBatch` | Single-forward-pass batch embeddings |
|
|
33
|
+
* | `entityIdMapper` | mmap binary mapper or JSON fallback |
|
|
34
|
+
* | `roaring` | CRoaring bindings (Roaring32 + Roaring64) |
|
|
35
|
+
* | `msgpack` | Native encode/decode |
|
|
36
|
+
* | `aggregation` | Rust-accelerated incremental aggregation |
|
|
37
|
+
* | `sort:topK` | `O(N log K)` bounded-heap ranking |
|
|
38
|
+
*
|
|
39
|
+
* The legacy native HNSW implementation (cortex 2.x) and its
|
|
40
|
+
* companion mmap vector store + BVEC reader were removed in
|
|
41
|
+
* Piece F. **Adaptive DiskANN** covers the same workload range
|
|
42
|
+
* with a single code path (in-memory / hybrid / on-disk modes
|
|
43
|
+
* selected at brain-open time from observed memory).
|
|
44
|
+
*/
|
|
45
|
+
import type { BrainyPlugin } from '@soulcraft/brainy/plugin';
|
|
46
|
+
declare const corPlugin: BrainyPlugin & {
|
|
47
|
+
brainyRange?: string;
|
|
48
|
+
};
|
|
49
|
+
export default corPlugin;
|
|
50
|
+
//# sourceMappingURL=plugin.d.ts.map
|
package/dist/plugin.js
ADDED
|
@@ -0,0 +1,388 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @module plugin
|
|
3
|
+
* @description `@soulcraft/cor` Brainy plugin entry point.
|
|
4
|
+
*
|
|
5
|
+
* Implements the `BrainyPlugin` interface to register every native
|
|
6
|
+
* provider cor 3.0 ships. Brainy auto-detects this plugin during
|
|
7
|
+
* `init()` via dynamic import.
|
|
8
|
+
*
|
|
9
|
+
* ## Tier gating
|
|
10
|
+
*
|
|
11
|
+
* - **Free tier (no license key)**: nothing registered — brainy runs
|
|
12
|
+
* on its pure-JS defaults with zero acceleration.
|
|
13
|
+
* - **Pro / Enterprise / Internal**: every compute provider below
|
|
14
|
+
* wired in. Cor is a pure 1:1 accelerator — it registers ONLY
|
|
15
|
+
* the providers brainy currently looks up; native capabilities
|
|
16
|
+
* that don't yet have a brainy hook stay dormant in the cdylib.
|
|
17
|
+
*
|
|
18
|
+
* ## Cor 3.0 surface (Piece F, 2026-06-09)
|
|
19
|
+
*
|
|
20
|
+
* | Provider | Implementation |
|
|
21
|
+
* |-------------------|---------------------------------------------|
|
|
22
|
+
* | `distance` | SIMD-accelerated cosine |
|
|
23
|
+
* | `distance:sq8` | SQ8 quantized cosine (uint8) |
|
|
24
|
+
* | `distance:sq4` | SQ4 quantized cosine (packed nibbles) |
|
|
25
|
+
* | `graph:compression` | delta-varint connection codec |
|
|
26
|
+
* | `hnsw` | **Adaptive DiskANN** (`NativeDiskAnnWrapper`) — the vector index. The provider key is brainy's historical name; cor's implementation is DiskANN |
|
|
27
|
+
* | `diskann` | Same `NativeDiskAnnWrapper` under brainy's explicit DiskANN key (for callers that set `config.index.type='diskann'`) |
|
|
28
|
+
* | `cache` | Native eviction engine (`NativeUnifiedCacheWrapper`) |
|
|
29
|
+
* | `metadataIndex` | Native LSM-backed metadata index + column store |
|
|
30
|
+
* | `graphIndex` | Native graph adjacency (u64-keyed LSM trees) |
|
|
31
|
+
* | `embeddings` | Candle ML (CPU/CUDA/Metal) |
|
|
32
|
+
* | `embedBatch` | Single-forward-pass batch embeddings |
|
|
33
|
+
* | `entityIdMapper` | mmap binary mapper or JSON fallback |
|
|
34
|
+
* | `roaring` | CRoaring bindings (Roaring32 + Roaring64) |
|
|
35
|
+
* | `msgpack` | Native encode/decode |
|
|
36
|
+
* | `aggregation` | Rust-accelerated incremental aggregation |
|
|
37
|
+
* | `sort:topK` | `O(N log K)` bounded-heap ranking |
|
|
38
|
+
*
|
|
39
|
+
* The legacy native HNSW implementation (cortex 2.x) and its
|
|
40
|
+
* companion mmap vector store + BVEC reader were removed in
|
|
41
|
+
* Piece F. **Adaptive DiskANN** covers the same workload range
|
|
42
|
+
* with a single code path (in-memory / hybrid / on-disk modes
|
|
43
|
+
* selected at brain-open time from observed memory).
|
|
44
|
+
*/
|
|
45
|
+
import { loadNativeModule, isNativeAvailable } from './native/index.js';
|
|
46
|
+
import { validateLicense, readLicenseToken, readConfig, isShortCode } from './license.js';
|
|
47
|
+
import { MigrationCoordinator } from './migration/MigrationCoordinator.js';
|
|
48
|
+
const PRICING_URL = 'https://soulcraft.com/pricing?focus=pro';
|
|
49
|
+
// `brainyRange` engages brainy 8.0's version-coupling gate (handoff LV.3): a
|
|
50
|
+
// brainy outside this range fails loud at init() instead of silently dropping to
|
|
51
|
+
// the JS engine. Typed via intersection until the devDependency moves to brainy
|
|
52
|
+
// 8.0 (whose `BrainyPlugin` declares the field); brainy reads the runtime
|
|
53
|
+
// property regardless of cor's compile-time type. `'vector'` provider key is
|
|
54
|
+
// registered below (the other half of the gate's contract).
|
|
55
|
+
const corPlugin = {
|
|
56
|
+
name: '@soulcraft/cor',
|
|
57
|
+
brainyRange: '>=8.0.0 <9.0.0',
|
|
58
|
+
async activate(context) {
|
|
59
|
+
// **Safety guard — Cor 3.0 production default.** Refuse to start if
|
|
60
|
+
// the storage root still contains cortex 2.x on-disk artifacts. The
|
|
61
|
+
// check is *deferred to the storage-receiving provider factories
|
|
62
|
+
// below*: brainy 8.0's `activate(context)` does not expose the
|
|
63
|
+
// brain's storage here (the context carries only `registerProvider`
|
|
64
|
+
// + `version`), so scanning it now would inspect `undefined` and
|
|
65
|
+
// silently pass — defeating the safety net. `guardLegacyLayoutOnce`
|
|
66
|
+
// is called at the top of the metadataIndex / graphIndex /
|
|
67
|
+
// entityIdMapper factories, which DO receive the real storage, and
|
|
68
|
+
// fires before any native engine opens files under the root. A loud
|
|
69
|
+
// "service won't start" failure is recoverable; letting cor 3.0
|
|
70
|
+
// auto-engagement run alongside 2.x remnants produces a
|
|
71
|
+
// half-migrated state that's harder to undo. Bypass via env
|
|
72
|
+
// `COR_LEGACY_LAYOUT_GUARD=skip` (used by the migration script).
|
|
73
|
+
const { guardLegacyLayoutOnce } = await import('./legacyLayoutGuard.js');
|
|
74
|
+
// **Piece 19 storage simplification.** Cor does not register
|
|
75
|
+
// a `storage:filesystem` provider — brainy's built-in
|
|
76
|
+
// `FileSystemStorage` (which since 7.25.0 ships the binary-blob
|
|
77
|
+
// primitives + multi-process locking cor used to layer on
|
|
78
|
+
// top) is the canonical storage adapter. That keeps the
|
|
79
|
+
// boundary between brainy and cor razor-sharp:
|
|
80
|
+
//
|
|
81
|
+
// - **Brainy** = data + filesystem storage + JS default
|
|
82
|
+
// implementations of every operation (MIT open source).
|
|
83
|
+
// - **Cor** = drop-in fast replacements for every compute
|
|
84
|
+
// hot path (proprietary, license-gated).
|
|
85
|
+
//
|
|
86
|
+
// Cor's compute providers (Adaptive DiskANN, metadata index,
|
|
87
|
+
// graph adjacency, embeddings, etc.) all require local file
|
|
88
|
+
// paths via `storage.getBinaryBlobPath` — i.e. filesystem
|
|
89
|
+
// storage. On a cloud adapter the compute providers fail at
|
|
90
|
+
// init with a clear error rather than silently degrading.
|
|
91
|
+
// Brainy continues to work unaccelerated on any adapter.
|
|
92
|
+
// Gate: native module must be available for compute acceleration
|
|
93
|
+
if (!isNativeAvailable()) {
|
|
94
|
+
return true;
|
|
95
|
+
}
|
|
96
|
+
// Gate: license tier determines compute access
|
|
97
|
+
const license = await validateLicense();
|
|
98
|
+
let useOfflineGrace = false;
|
|
99
|
+
if (license.tier === 'free') {
|
|
100
|
+
if (license.error) {
|
|
101
|
+
// 'native module unavailable' — defensive; isNativeAvailable() already gated above
|
|
102
|
+
console.warn(`[cor] ${license.error}`);
|
|
103
|
+
return true;
|
|
104
|
+
}
|
|
105
|
+
// Distinguish "no key configured" from "short code exchange failed at runtime".
|
|
106
|
+
// The CLI now writes JWTs directly (sc_cor_...), so short codes in .soulcraft.json
|
|
107
|
+
// only appear in old or manually-written files. Exchange at runtime is a fallback path.
|
|
108
|
+
//
|
|
109
|
+
// Resolve the RAW license value with the same env-then-file precedence
|
|
110
|
+
// readLicenseToken() uses (env var COR_LICENSE_KEY / legacy CORTEX_LICENSE_KEY
|
|
111
|
+
// wins over .soulcraft.json). We can't reuse readLicenseToken() directly here
|
|
112
|
+
// because it exchanges short codes into JWTs (or returns null on a failed
|
|
113
|
+
// exchange), erasing the short-code shape this branch needs to test. Reading
|
|
114
|
+
// the file alone would drop offline grace for an env-supplied short code on a
|
|
115
|
+
// network blip — the exact gap this fixes.
|
|
116
|
+
const envValue = (process.env.COR_LICENSE_KEY ?? process.env.CORTEX_LICENSE_KEY)?.trim();
|
|
117
|
+
let licenseValue;
|
|
118
|
+
if (envValue) {
|
|
119
|
+
licenseValue = envValue;
|
|
120
|
+
}
|
|
121
|
+
else {
|
|
122
|
+
const config = await readConfig();
|
|
123
|
+
// Dual-read during the cortex→cor rename: new `cor` key, legacy `cortex`.
|
|
124
|
+
licenseValue = config.cor ?? config.cortex;
|
|
125
|
+
}
|
|
126
|
+
if (!licenseValue) {
|
|
127
|
+
return true; // No license configured — free tier, no warning
|
|
128
|
+
}
|
|
129
|
+
if (isShortCode(licenseValue)) {
|
|
130
|
+
// Exchange failed. Check heartbeat cache: if the license was previously active,
|
|
131
|
+
// grant offline grace so a transient network issue doesn't break production.
|
|
132
|
+
const { readHeartbeatCache } = await import('./license/onlineValidator.js');
|
|
133
|
+
const cached = await readHeartbeatCache();
|
|
134
|
+
if (cached?.status === 'active') {
|
|
135
|
+
const lastCheck = new Date(cached.lastCheck).toLocaleDateString();
|
|
136
|
+
console.warn(`[cor] License server unreachable — offline mode (last verified: ${lastCheck}). ` +
|
|
137
|
+
`Ensure soulcraft.com is accessible for periodic renewal.`);
|
|
138
|
+
useOfflineGrace = true;
|
|
139
|
+
}
|
|
140
|
+
else {
|
|
141
|
+
console.warn(`[cor] License exchange failed — cannot verify activation code with soulcraft.com.\n` +
|
|
142
|
+
`[cor] Native compute acceleration disabled.\n` +
|
|
143
|
+
`[cor] Re-run: npx @soulcraft/cor activate <code> (on a machine with internet access)`);
|
|
144
|
+
return true;
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
else {
|
|
148
|
+
return true; // JWT present but resolved to free — valid state, no warning
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
if (!useOfflineGrace) {
|
|
152
|
+
// Invalid key (bad signature, wrong product, expired, etc.)
|
|
153
|
+
if (!license.valid) {
|
|
154
|
+
if (license.error) {
|
|
155
|
+
console.warn(`[cor] ${license.error}. ` +
|
|
156
|
+
`Get a valid license at ${PRICING_URL}`);
|
|
157
|
+
}
|
|
158
|
+
return true;
|
|
159
|
+
}
|
|
160
|
+
// Check cached heartbeat state BEFORE registering compute providers.
|
|
161
|
+
// This catches an expired grace period from a previous run without a network call.
|
|
162
|
+
const { readHeartbeatCache, isGracePeriodExpired } = await import('./license/onlineValidator.js');
|
|
163
|
+
const cachedState = await readHeartbeatCache();
|
|
164
|
+
if (cachedState?.gracePeriodStart && isGracePeriodExpired(cachedState.gracePeriodStart)) {
|
|
165
|
+
console.warn('[cor] License lapsed. Compute acceleration disabled. Renew at soulcraft.com/account');
|
|
166
|
+
return true;
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
// Pro / Enterprise / Internal: register ALL native compute providers
|
|
170
|
+
const native = loadNativeModule();
|
|
171
|
+
// Distance: SIMD-accelerated cosine.
|
|
172
|
+
context.registerProvider('distance', native.cosineDistance);
|
|
173
|
+
// Quantized distance: SQ8 cosine on uint8 arrays (no
|
|
174
|
+
// dequantization). Used by brainy's SQ8 rerank path.
|
|
175
|
+
context.registerProvider('distance:sq8', native.cosineDistanceSq8);
|
|
176
|
+
// Quantized distance: SQ4 cosine on packed nibbles (2 values
|
|
177
|
+
// per byte). Used by brainy 7.28.0+ when
|
|
178
|
+
// `config.hnsw.quantization.bits === 4`. Byte-for-byte
|
|
179
|
+
// identical to brainy's pure-JS `distanceSQ4Js`;
|
|
180
|
+
// cross-language parity is asserted by brainy's test suite.
|
|
181
|
+
context.registerProvider('distance:sq4', native.cosineDistanceSq4);
|
|
182
|
+
// Graph connection compression: delta-varint encoded
|
|
183
|
+
// connection lists. Brainy uses this on the JS HNSW path it
|
|
184
|
+
// still owns for the standalone open-core deployment shape;
|
|
185
|
+
// cor provides the native codec.
|
|
186
|
+
context.registerProvider('graph:compression', {
|
|
187
|
+
encode: native.encodeConnections,
|
|
188
|
+
decode: native.decodeConnections,
|
|
189
|
+
});
|
|
190
|
+
// Metadata index: Native Rust query/mutation engine.
|
|
191
|
+
// Imported + captured BEFORE the vector factory so the DiskANN
|
|
192
|
+
// wrapper's lazy mapperResolver can close over `metadataIndexInstance`
|
|
193
|
+
// (the canonical entity-id mapper). The capture is also handed to the
|
|
194
|
+
// graphIndex factory below — the SAME mapper brainy resolves verb
|
|
195
|
+
// endpoints through at write time (`metadataIndex.getIdMapper().getOrAssign`);
|
|
196
|
+
// restored edges (#68) and DiskANN slot↔int resolution (#72) MUST use
|
|
197
|
+
// THIS one mapper. The resolver is lazy, so factory-call order between
|
|
198
|
+
// the providers doesn't matter.
|
|
199
|
+
const { MetadataIndexManager: NativeMetadataIndex } = await import('./utils/NativeMetadataIndex.js');
|
|
200
|
+
let metadataIndexInstance;
|
|
201
|
+
// **Adaptive DiskANN** — the sole vector index in cor 3.0.
|
|
202
|
+
// Registered against brainy 8.0's canonical `'vector'` provider
|
|
203
|
+
// key (algorithm-neutral; matches `VectorIndexProvider`). The
|
|
204
|
+
// wrapper self-selects operating mode (in-memory / hybrid /
|
|
205
|
+
// on-disk) from observed memory pressure per Piece I — no
|
|
206
|
+
// user-tunable algorithm choice. #72: the wrapper resolves slot↔uuid
|
|
207
|
+
// through the off-heap mmap slotmaps + the canonical mapper, so it is
|
|
208
|
+
// wired with the SAME lazy `getIdMapper()` resolver as the graph index.
|
|
209
|
+
const { NativeDiskAnnWrapper } = await import('./hnsw/NativeDiskAnnWrapper.js');
|
|
210
|
+
let vectorInstance;
|
|
211
|
+
const diskAnnFactory = (config, distanceFn, options) => {
|
|
212
|
+
// Capture the constructed wrapper so the #18 migration coordinator can reach
|
|
213
|
+
// the vector provider (brainy calls this factory once for the 'vector' key).
|
|
214
|
+
vectorInstance = new NativeDiskAnnWrapper(config, distanceFn, {
|
|
215
|
+
...options,
|
|
216
|
+
mapperResolver: () => metadataIndexInstance?.getIdMapper(),
|
|
217
|
+
migrationCoordinator: getMigrationCoordinator,
|
|
218
|
+
});
|
|
219
|
+
return vectorInstance;
|
|
220
|
+
};
|
|
221
|
+
context.registerProvider('vector', diskAnnFactory);
|
|
222
|
+
// Cache: Native Rust eviction engine with JS data storage
|
|
223
|
+
const { NativeUnifiedCacheWrapper } = await import('./utils/NativeUnifiedCache.js');
|
|
224
|
+
context.registerProvider('cache', new NativeUnifiedCacheWrapper());
|
|
225
|
+
context.registerProvider('metadataIndex', (storage) => {
|
|
226
|
+
guardLegacyLayoutOnce(storage);
|
|
227
|
+
// The metadata index owns the #18 migration trigger: on a large stale brain
|
|
228
|
+
// its init() calls coordinator.start(). Create/resolve the one coordinator for
|
|
229
|
+
// this brain here (the context has no storage; the factories do).
|
|
230
|
+
ensureMigrationCoordinator(storage);
|
|
231
|
+
metadataIndexInstance = new NativeMetadataIndex(storage, {}, getMigrationCoordinator);
|
|
232
|
+
return metadataIndexInstance;
|
|
233
|
+
});
|
|
234
|
+
// Graph adjacency: Native 4 LSM-trees with verb tracking
|
|
235
|
+
const { GraphAdjacencyIndex: NativeGraphAdjacencyIndex } = await import('./graph/NativeGraphAdjacencyIndex.js');
|
|
236
|
+
// **Phase B graph acceleration (ADR-006) — self-wire.** brainy 8.0's
|
|
237
|
+
// `activate(context)` has no storage and its provider factories are
|
|
238
|
+
// called with storage only (not the constructed graphIndex), while the
|
|
239
|
+
// `graphAcceleration` value is feature-detected RAW (the factory is
|
|
240
|
+
// never invoked). So we register the adapter here, bound to a resolver
|
|
241
|
+
// the graphIndex factory fills once it builds the native engine — the
|
|
242
|
+
// adapter wraps that SAME native handle (never a second index). Until
|
|
243
|
+
// the engine is built + loaded, the adapter reports `isInitialized:
|
|
244
|
+
// false` and brainy keeps serving graph ops from TS.
|
|
245
|
+
let graphEngine;
|
|
246
|
+
// **#18 migration lock (coordinator).** One per brain, created on the first
|
|
247
|
+
// storage-receiving factory call (memoized) and shared by all three derived-
|
|
248
|
+
// index providers via the SAME lazy `() => migrationCoordinator` getter so
|
|
249
|
+
// factory-call order doesn't matter. It drives the blocking 7.x→8.0 upgrade
|
|
250
|
+
// (rebuild all 3 indexes from canonical under a lock brainy holds reads+writes
|
|
251
|
+
// behind) and answers the feature-detected isMigrating / migrationStatus
|
|
252
|
+
// methods each provider delegates to it.
|
|
253
|
+
let migrationCoordinator;
|
|
254
|
+
const getMigrationCoordinator = () => migrationCoordinator;
|
|
255
|
+
const ensureMigrationCoordinator = (storage) => {
|
|
256
|
+
if (!migrationCoordinator) {
|
|
257
|
+
migrationCoordinator = new MigrationCoordinator(storage, {
|
|
258
|
+
metadata: () => metadataIndexInstance,
|
|
259
|
+
vector: () => vectorInstance,
|
|
260
|
+
graph: () => graphEngine,
|
|
261
|
+
});
|
|
262
|
+
}
|
|
263
|
+
return migrationCoordinator;
|
|
264
|
+
};
|
|
265
|
+
context.registerProvider('graphIndex', (storage) => {
|
|
266
|
+
guardLegacyLayoutOnce(storage);
|
|
267
|
+
ensureMigrationCoordinator(storage);
|
|
268
|
+
// Pass a lazy resolver to the metadata index's entity-id mapper so
|
|
269
|
+
// graphIndex.rebuild() (restore path, #68) resolves verb endpoints
|
|
270
|
+
// through the SAME mapper brainy assigns ints with at write time.
|
|
271
|
+
graphEngine = new NativeGraphAdjacencyIndex(storage, {}, () => metadataIndexInstance?.getIdMapper(), getMigrationCoordinator);
|
|
272
|
+
return graphEngine;
|
|
273
|
+
});
|
|
274
|
+
const { GraphAccelerationAdapter } = await import('./graph/GraphAccelerationAdapter.js');
|
|
275
|
+
context.registerProvider('graphAcceleration', new GraphAccelerationAdapter(() => graphEngine));
|
|
276
|
+
// Embeddings: Candle ML native engine — initialized eagerly so the 88MB model
|
|
277
|
+
// is loaded at startup, not lazily on first embed call. This eliminates the
|
|
278
|
+
// ~883ms delay on the first embedding request (e.g. during onboarding seeding).
|
|
279
|
+
const { NativeEmbeddingEngine } = await import('./native/NativeEmbeddingEngine.js');
|
|
280
|
+
const engine = NativeEmbeddingEngine.getInstance();
|
|
281
|
+
if (!engine.isInitialized()) {
|
|
282
|
+
await engine.initialize();
|
|
283
|
+
}
|
|
284
|
+
context.registerProvider('embeddings', async (text) => {
|
|
285
|
+
if (Array.isArray(text)) {
|
|
286
|
+
return engine.embedBatch(text);
|
|
287
|
+
}
|
|
288
|
+
return engine.embed(text);
|
|
289
|
+
});
|
|
290
|
+
// Batch embeddings: single Rust forward pass for multiple texts
|
|
291
|
+
context.registerProvider('embedBatch', async (texts) => {
|
|
292
|
+
return engine.embedBatch(texts);
|
|
293
|
+
});
|
|
294
|
+
// Entity ID mapper: dispatch on storage capability.
|
|
295
|
+
//
|
|
296
|
+
// • Filesystem-backed storage (exposes `getBinaryBlobPath`) →
|
|
297
|
+
// the cor 3.0 mmap-backed binary mapper (billion-scale,
|
|
298
|
+
// constant-RAM, crash-safe).
|
|
299
|
+
// • Cloud / non-path storage → the JSON-persisted mapper.
|
|
300
|
+
//
|
|
301
|
+
// Both implement the same brainy `EntityIdMapperProvider` contract;
|
|
302
|
+
// the choice is transparent to brainy.
|
|
303
|
+
//
|
|
304
|
+
// This is a single dispatch, not a fallback chain. Either the
|
|
305
|
+
// storage has a local path (binary) or it does not (JSON). A
|
|
306
|
+
// failure constructing the binary mapper on a path-capable storage
|
|
307
|
+
// is a real bug and surfaces as an init error rather than silently
|
|
308
|
+
// degrading to JSON (which would mask corruption / config issues
|
|
309
|
+
// and quietly break the billion-scale guarantee for that node).
|
|
310
|
+
const { NativeEntityIdMapperWrapper } = await import('./utils/nativeEntityIdMapper.js');
|
|
311
|
+
const { NativeBinaryEntityIdMapperWrapper } = await import('./utils/nativeBinaryEntityIdMapper.js');
|
|
312
|
+
context.registerProvider('entityIdMapper', (storage) => {
|
|
313
|
+
guardLegacyLayoutOnce(storage);
|
|
314
|
+
if (typeof storage?.getBinaryBlobPath === 'function') {
|
|
315
|
+
return new NativeBinaryEntityIdMapperWrapper({ storage });
|
|
316
|
+
}
|
|
317
|
+
return new NativeEntityIdMapperWrapper({ storage });
|
|
318
|
+
});
|
|
319
|
+
// Roaring bitmaps: CRoaring bindings (binary-compatible with roaring-wasm)
|
|
320
|
+
const { RoaringBitmap32 } = await import('./native/NativeRoaringBitmap32.js');
|
|
321
|
+
context.registerProvider('roaring', RoaringBitmap32);
|
|
322
|
+
// Msgpack: Native encode/decode
|
|
323
|
+
context.registerProvider('msgpack', {
|
|
324
|
+
encode: native.msgpackEncode,
|
|
325
|
+
decode: native.msgpackDecode
|
|
326
|
+
});
|
|
327
|
+
// Aggregation: Rust-accelerated incremental aggregation.
|
|
328
|
+
// Precise MIN/MAX + exact percentile/distinctCount
|
|
329
|
+
// (value-multiset, never stale after deletes), HAVING,
|
|
330
|
+
// array-unnest groupBy, Rayon parallel rebuild. Registering
|
|
331
|
+
// the `'aggregation'` provider makes brainy's `AggregationIndex`
|
|
332
|
+
// delegate all metric computation to Rust.
|
|
333
|
+
const { NativeAggregationProvider } = await import('./aggregation/NativeAggregationEngine.js');
|
|
334
|
+
context.registerProvider('aggregation', new NativeAggregationProvider());
|
|
335
|
+
// Top-K result ranking: `O(N log K)` bounded-heap selection.
|
|
336
|
+
// Returns the indices of the best K scores in ranked order
|
|
337
|
+
// so brainy can rank a large candidate set (e.g. a 1M-result
|
|
338
|
+
// search with `limit=10`) without an `O(N log N)` full sort.
|
|
339
|
+
context.registerProvider('sort:topK', native.sortTopKScores);
|
|
340
|
+
// Resource Manager: adaptive memory budgeting for multi-instance deployments.
|
|
341
|
+
// Tracks active brainy instances, observes system resources (RAM, cgroups),
|
|
342
|
+
// and dynamically adjusts cache sizing. Zero-config — auto-detects VM size.
|
|
343
|
+
const { ResourceManager } = await import('./resource/ResourceManager.js');
|
|
344
|
+
const { getGlobalCache } = await import('@soulcraft/brainy/internals');
|
|
345
|
+
const resourceManager = ResourceManager.getInstance();
|
|
346
|
+
// Connect ResourceManager → UnifiedCache: when instance count changes,
|
|
347
|
+
// ResourceManager recalculates the cache budget and resizes dynamically.
|
|
348
|
+
const globalCache = getGlobalCache();
|
|
349
|
+
if (typeof globalCache.setMaxSize === 'function') {
|
|
350
|
+
resourceManager.setCacheResizeCallback((newSize) => {
|
|
351
|
+
globalCache.setMaxSize(newSize);
|
|
352
|
+
});
|
|
353
|
+
}
|
|
354
|
+
// ResourceManager runs internally (adaptive cache sizing, wired above) — it is
|
|
355
|
+
// not registered as a provider since brainy has no consumer for it.
|
|
356
|
+
resourceManager.startRebalancing();
|
|
357
|
+
// Background heartbeat with forceCheck — always checks Portal on startup.
|
|
358
|
+
// Updates the cache so the next startup sees current subscription state.
|
|
359
|
+
// Runs after providers are registered (non-blocking for the user).
|
|
360
|
+
// Skipped in offline grace mode — we have no JWT to send.
|
|
361
|
+
if (!useOfflineGrace) {
|
|
362
|
+
const token = await readLicenseToken();
|
|
363
|
+
if (token) {
|
|
364
|
+
import('./license/onlineValidator.js')
|
|
365
|
+
.then(({ performHeartbeat }) => performHeartbeat(token, { forceCheck: true }))
|
|
366
|
+
.then(result => {
|
|
367
|
+
if (result.degrade) {
|
|
368
|
+
const msg = result.warning ?? 'License lapsed. Compute acceleration disabled. Renew at soulcraft.com/account';
|
|
369
|
+
console.warn(`[cor] ${msg}`);
|
|
370
|
+
}
|
|
371
|
+
else if (result.warning) {
|
|
372
|
+
console.warn(`[cor] ${result.warning}`);
|
|
373
|
+
}
|
|
374
|
+
})
|
|
375
|
+
.catch(() => {
|
|
376
|
+
// Silently ignore heartbeat errors
|
|
377
|
+
});
|
|
378
|
+
}
|
|
379
|
+
}
|
|
380
|
+
return true;
|
|
381
|
+
},
|
|
382
|
+
async deactivate() {
|
|
383
|
+
// Native resources are cleaned up by the Rust drop() mechanism
|
|
384
|
+
// when the process exits. No explicit cleanup needed.
|
|
385
|
+
}
|
|
386
|
+
};
|
|
387
|
+
export default corPlugin;
|
|
388
|
+
//# sourceMappingURL=plugin.js.map
|