agentic-qe 3.7.21 → 3.8.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.claude/helpers/brain-checkpoint.cjs +4 -1
- package/.claude/helpers/statusline-v3.cjs +3 -1
- package/.claude/skills/skills-manifest.json +1 -1
- package/CHANGELOG.md +45 -0
- package/README.md +2 -14
- package/assets/helpers/statusline-v3.cjs +3 -1
- package/dist/cli/brain-commands.js +6 -10
- package/dist/cli/bundle.js +7441 -4327
- package/dist/cli/commands/audit.d.ts +43 -0
- package/dist/cli/commands/audit.js +125 -0
- package/dist/cli/commands/hooks.js +29 -6
- package/dist/cli/commands/init.js +1 -73
- package/dist/cli/commands/learning.js +270 -13
- package/dist/cli/commands/ruvector-commands.d.ts +15 -0
- package/dist/cli/commands/ruvector-commands.js +271 -0
- package/dist/cli/handlers/init-handler.d.ts +0 -1
- package/dist/cli/handlers/init-handler.js +0 -6
- package/dist/cli/index.js +4 -2
- package/dist/context/sources/defect-source.js +2 -2
- package/dist/context/sources/memory-source.js +2 -2
- package/dist/context/sources/requirements-source.js +2 -2
- package/dist/coordination/behavior-tree/decorators.d.ts +108 -0
- package/dist/coordination/behavior-tree/decorators.js +251 -0
- package/dist/coordination/behavior-tree/index.d.ts +12 -0
- package/dist/coordination/behavior-tree/index.js +15 -0
- package/dist/coordination/behavior-tree/nodes.d.ts +165 -0
- package/dist/coordination/behavior-tree/nodes.js +338 -0
- package/dist/coordination/behavior-tree/qe-trees.d.ts +105 -0
- package/dist/coordination/behavior-tree/qe-trees.js +181 -0
- package/dist/coordination/coherence-action-gate.d.ts +284 -0
- package/dist/coordination/coherence-action-gate.js +512 -0
- package/dist/coordination/index.d.ts +4 -0
- package/dist/coordination/index.js +8 -0
- package/dist/coordination/reasoning-qec.d.ts +315 -0
- package/dist/coordination/reasoning-qec.js +585 -0
- package/dist/coordination/task-executor.d.ts +16 -0
- package/dist/coordination/task-executor.js +99 -0
- package/dist/coordination/workflow-orchestrator.d.ts +29 -0
- package/dist/coordination/workflow-orchestrator.js +42 -0
- package/dist/domains/visual-accessibility/cnn-visual-regression.d.ts +135 -0
- package/dist/domains/visual-accessibility/cnn-visual-regression.js +327 -0
- package/dist/domains/visual-accessibility/index.d.ts +1 -0
- package/dist/domains/visual-accessibility/index.js +4 -0
- package/dist/governance/coherence-validator.d.ts +112 -0
- package/dist/governance/coherence-validator.js +180 -0
- package/dist/governance/index.d.ts +1 -0
- package/dist/governance/index.js +2 -0
- package/dist/governance/witness-chain.d.ts +311 -0
- package/dist/governance/witness-chain.js +509 -0
- package/dist/init/index.d.ts +0 -2
- package/dist/init/index.js +0 -1
- package/dist/init/init-wizard-steps.d.ts +10 -0
- package/dist/init/init-wizard-steps.js +87 -1
- package/dist/init/init-wizard.d.ts +1 -9
- package/dist/init/init-wizard.js +3 -69
- package/dist/init/orchestrator.js +0 -1
- package/dist/init/phases/01-detection.js +0 -27
- package/dist/init/phases/07-hooks.js +6 -4
- package/dist/init/phases/phase-interface.d.ts +0 -1
- package/dist/init/settings-merge.js +1 -1
- package/dist/integrations/browser/qe-dashboard/clustering.d.ts +48 -0
- package/dist/integrations/browser/qe-dashboard/clustering.js +183 -0
- package/dist/integrations/browser/qe-dashboard/index.d.ts +12 -0
- package/dist/integrations/browser/qe-dashboard/index.js +15 -0
- package/dist/integrations/browser/qe-dashboard/pattern-explorer.d.ts +165 -0
- package/dist/integrations/browser/qe-dashboard/pattern-explorer.js +260 -0
- package/dist/integrations/browser/qe-dashboard/wasm-vector-store.d.ts +144 -0
- package/dist/integrations/browser/qe-dashboard/wasm-vector-store.js +277 -0
- package/dist/integrations/ruvector/cognitive-container-codec.d.ts +51 -0
- package/dist/integrations/ruvector/cognitive-container-codec.js +180 -0
- package/dist/integrations/ruvector/cognitive-container.d.ts +125 -0
- package/dist/integrations/ruvector/cognitive-container.js +306 -0
- package/dist/integrations/ruvector/coherence-gate.d.ts +309 -0
- package/dist/integrations/ruvector/coherence-gate.js +631 -0
- package/dist/integrations/ruvector/compressed-hnsw-integration.d.ts +176 -0
- package/dist/integrations/ruvector/compressed-hnsw-integration.js +301 -0
- package/dist/integrations/ruvector/dither-adapter.d.ts +122 -0
- package/dist/integrations/ruvector/dither-adapter.js +295 -0
- package/dist/integrations/ruvector/domain-transfer.d.ts +129 -0
- package/dist/integrations/ruvector/domain-transfer.js +220 -0
- package/dist/integrations/ruvector/feature-flags.d.ts +214 -2
- package/dist/integrations/ruvector/feature-flags.js +167 -2
- package/dist/integrations/ruvector/filter-adapter.d.ts +71 -0
- package/dist/integrations/ruvector/filter-adapter.js +285 -0
- package/dist/integrations/ruvector/gnn-wrapper.d.ts +20 -0
- package/dist/integrations/ruvector/gnn-wrapper.js +40 -0
- package/dist/integrations/ruvector/hnsw-health-monitor.d.ts +237 -0
- package/dist/integrations/ruvector/hnsw-health-monitor.js +394 -0
- package/dist/integrations/ruvector/index.d.ts +8 -2
- package/dist/integrations/ruvector/index.js +18 -2
- package/dist/integrations/ruvector/interfaces.d.ts +40 -0
- package/dist/integrations/ruvector/sona-persistence.d.ts +54 -0
- package/dist/integrations/ruvector/sona-persistence.js +162 -0
- package/dist/integrations/ruvector/sona-three-loop.d.ts +392 -0
- package/dist/integrations/ruvector/sona-three-loop.js +814 -0
- package/dist/integrations/ruvector/sona-wrapper.d.ts +97 -0
- package/dist/integrations/ruvector/sona-wrapper.js +147 -3
- package/dist/integrations/ruvector/spectral-math.d.ts +101 -0
- package/dist/integrations/ruvector/spectral-math.js +254 -0
- package/dist/integrations/ruvector/temporal-compression.d.ts +163 -0
- package/dist/integrations/ruvector/temporal-compression.js +318 -0
- package/dist/integrations/ruvector/thompson-sampler.d.ts +61 -0
- package/dist/integrations/ruvector/thompson-sampler.js +118 -0
- package/dist/integrations/ruvector/transfer-coherence-stub.d.ts +80 -0
- package/dist/integrations/ruvector/transfer-coherence-stub.js +63 -0
- package/dist/integrations/ruvector/transfer-verification.d.ts +119 -0
- package/dist/integrations/ruvector/transfer-verification.js +115 -0
- package/dist/kernel/hnsw-adapter.d.ts +52 -1
- package/dist/kernel/hnsw-adapter.js +139 -4
- package/dist/kernel/hnsw-index-provider.d.ts +5 -0
- package/dist/kernel/native-hnsw-backend.d.ts +110 -0
- package/dist/kernel/native-hnsw-backend.js +408 -0
- package/dist/kernel/unified-memory.js +5 -6
- package/dist/learning/aqe-learning-engine.d.ts +2 -0
- package/dist/learning/aqe-learning-engine.js +65 -0
- package/dist/learning/experience-capture-middleware.js +20 -0
- package/dist/learning/experience-capture.d.ts +10 -0
- package/dist/learning/experience-capture.js +34 -0
- package/dist/learning/index.d.ts +2 -2
- package/dist/learning/index.js +4 -4
- package/dist/learning/metrics-tracker.d.ts +11 -0
- package/dist/learning/metrics-tracker.js +29 -13
- package/dist/learning/pattern-lifecycle.d.ts +30 -1
- package/dist/learning/pattern-lifecycle.js +92 -20
- package/dist/learning/pattern-store.d.ts +8 -0
- package/dist/learning/pattern-store.js +8 -2
- package/dist/learning/qe-unified-memory.js +1 -28
- package/dist/learning/regret-tracker.d.ts +201 -0
- package/dist/learning/regret-tracker.js +361 -0
- package/dist/mcp/bundle.js +5915 -474
- package/dist/routing/index.d.ts +4 -2
- package/dist/routing/index.js +3 -1
- package/dist/routing/neural-tiny-dancer-router.d.ts +268 -0
- package/dist/routing/neural-tiny-dancer-router.js +514 -0
- package/dist/routing/queen-integration.js +5 -5
- package/dist/routing/routing-config.d.ts +6 -0
- package/dist/routing/routing-config.js +1 -0
- package/dist/routing/simple-neural-router.d.ts +76 -0
- package/dist/routing/simple-neural-router.js +202 -0
- package/dist/routing/tiny-dancer-router.d.ts +20 -1
- package/dist/routing/tiny-dancer-router.js +21 -2
- package/dist/test-scheduling/dag-attention-scheduler.d.ts +81 -0
- package/dist/test-scheduling/dag-attention-scheduler.js +358 -0
- package/dist/test-scheduling/dag-attention-types.d.ts +81 -0
- package/dist/test-scheduling/dag-attention-types.js +10 -0
- package/dist/test-scheduling/index.d.ts +1 -0
- package/dist/test-scheduling/index.js +4 -0
- package/dist/test-scheduling/pipeline.d.ts +8 -0
- package/dist/test-scheduling/pipeline.js +28 -0
- package/package.json +6 -2
- package/dist/cli/commands/migrate.d.ts +0 -9
- package/dist/cli/commands/migrate.js +0 -566
- package/dist/init/init-wizard-migration.d.ts +0 -52
- package/dist/init/init-wizard-migration.js +0 -345
- package/dist/init/migration/config-migrator.d.ts +0 -31
- package/dist/init/migration/config-migrator.js +0 -149
- package/dist/init/migration/data-migrator.d.ts +0 -72
- package/dist/init/migration/data-migrator.js +0 -232
- package/dist/init/migration/detector.d.ts +0 -44
- package/dist/init/migration/detector.js +0 -105
- package/dist/init/migration/index.d.ts +0 -8
- package/dist/init/migration/index.js +0 -8
- package/dist/learning/v2-to-v3-migration.d.ts +0 -86
- package/dist/learning/v2-to-v3-migration.js +0 -529
|
@@ -0,0 +1,176 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Compressed HNSW Integration
|
|
3
|
+
* ADR-085: Temporal Tensor Pattern Compression + HNSW Backend
|
|
4
|
+
*
|
|
5
|
+
* Wraps an IHnswIndexProvider to transparently handle compressed vectors.
|
|
6
|
+
* On add(), the original vector is passed to the underlying HNSW index for
|
|
7
|
+
* accurate search, while a compressed copy is stored for memory savings.
|
|
8
|
+
* On search(), results come from the HNSW index normally.
|
|
9
|
+
*
|
|
10
|
+
* The compressIndex() method bulk-compresses cold/warm vectors, and
|
|
11
|
+
* getMemoryStats() reports the savings achieved.
|
|
12
|
+
*
|
|
13
|
+
* Activation is controlled by the `useTemporalCompression` feature flag.
|
|
14
|
+
*
|
|
15
|
+
* @module integrations/ruvector/compressed-hnsw-integration
|
|
16
|
+
*/
|
|
17
|
+
import type { IHnswIndexProvider, SearchResult } from '../../kernel/hnsw-index-provider.js';
|
|
18
|
+
import type { CompressionTier } from './temporal-compression.js';
|
|
19
|
+
import { TemporalCompressionService } from './temporal-compression.js';
|
|
20
|
+
/**
|
|
21
|
+
* Memory statistics for the compressed HNSW index.
|
|
22
|
+
*/
|
|
23
|
+
export interface CompressedHnswMemoryStats {
|
|
24
|
+
/** Total vectors in the index */
|
|
25
|
+
totalVectors: number;
|
|
26
|
+
/** Vectors that are still uncompressed */
|
|
27
|
+
uncompressedCount: number;
|
|
28
|
+
/** Vectors that have been compressed */
|
|
29
|
+
compressedCount: number;
|
|
30
|
+
/** Breakdown of compressed vectors by tier */
|
|
31
|
+
compressedByTier: Record<CompressionTier, number>;
|
|
32
|
+
/** Total bytes used by original (uncompressed) vectors */
|
|
33
|
+
originalBytes: number;
|
|
34
|
+
/** Total bytes used by compressed vectors (effective) */
|
|
35
|
+
compressedBytes: number;
|
|
36
|
+
/** Total bytes saved through compression */
|
|
37
|
+
bytesSaved: number;
|
|
38
|
+
/** Savings as a percentage (0-100) */
|
|
39
|
+
savingsPercent: number;
|
|
40
|
+
/** Whether temporal compression is enabled via feature flag */
|
|
41
|
+
compressionEnabled: boolean;
|
|
42
|
+
}
|
|
43
|
+
/**
|
|
44
|
+
* Wrapper around IHnswIndexProvider that transparently manages compressed
|
|
45
|
+
* vector storage alongside the HNSW index.
|
|
46
|
+
*
|
|
47
|
+
* The HNSW index always receives full-precision vectors for accurate search.
|
|
48
|
+
* Compression is a separate memory-optimization layer that stores compact
|
|
49
|
+
* representations of vectors that can be decompressed on demand.
|
|
50
|
+
*
|
|
51
|
+
* Usage:
|
|
52
|
+
* ```typescript
|
|
53
|
+
* const baseIndex = new ProgressiveHnswBackend({ dimensions: 384 });
|
|
54
|
+
* const compressed = new CompressedHnswIntegration(baseIndex);
|
|
55
|
+
*
|
|
56
|
+
* compressed.add(1, embedding, { domain: 'auth' });
|
|
57
|
+
* const results = compressed.search(queryEmbedding, 10);
|
|
58
|
+
*
|
|
59
|
+
* // Compress cold vectors to save memory
|
|
60
|
+
* const stats = compressed.compressIndex();
|
|
61
|
+
* console.log(`Compressed ${stats.compressedCount} vectors`);
|
|
62
|
+
* ```
|
|
63
|
+
*/
|
|
64
|
+
export declare class CompressedHnswIntegration implements IHnswIndexProvider {
|
|
65
|
+
private readonly backend;
|
|
66
|
+
private readonly compressionService;
|
|
67
|
+
private readonly vectorEntries;
|
|
68
|
+
/**
|
|
69
|
+
* Create a CompressedHnswIntegration.
|
|
70
|
+
*
|
|
71
|
+
* @param backend - The underlying HNSW index provider to delegate to
|
|
72
|
+
* @param compressionService - Optional compression service (defaults to new instance)
|
|
73
|
+
*/
|
|
74
|
+
constructor(backend: IHnswIndexProvider, compressionService?: TemporalCompressionService);
|
|
75
|
+
/**
|
|
76
|
+
* Add a vector to the index.
|
|
77
|
+
*
|
|
78
|
+
* The full-precision vector is passed to the HNSW backend for search.
|
|
79
|
+
* A copy is stored locally for potential future compression.
|
|
80
|
+
* If temporal compression is enabled, the vector is also compressed
|
|
81
|
+
* immediately and the compressed form is stored.
|
|
82
|
+
*/
|
|
83
|
+
add(id: number, vector: Float32Array, metadata?: Record<string, unknown>): void;
|
|
84
|
+
/**
|
|
85
|
+
* Search for the k nearest neighbors.
|
|
86
|
+
*
|
|
87
|
+
* Delegates entirely to the HNSW backend which holds full-precision
|
|
88
|
+
* vectors. Updates access timestamps for returned results so they
|
|
89
|
+
* stay in the hot tier.
|
|
90
|
+
*/
|
|
91
|
+
search(query: Float32Array, k: number): SearchResult[];
|
|
92
|
+
/**
|
|
93
|
+
* Remove a vector from the index.
|
|
94
|
+
*/
|
|
95
|
+
remove(id: number): boolean;
|
|
96
|
+
/**
|
|
97
|
+
* Get the number of vectors in the index.
|
|
98
|
+
*/
|
|
99
|
+
size(): number;
|
|
100
|
+
/**
|
|
101
|
+
* Get the configured vector dimensions.
|
|
102
|
+
*/
|
|
103
|
+
dimensions(): number;
|
|
104
|
+
/**
|
|
105
|
+
* Get estimated recall. Delegates to the underlying backend.
|
|
106
|
+
*/
|
|
107
|
+
recall(): number;
|
|
108
|
+
/**
|
|
109
|
+
* Compress vectors in the index based on their access tier.
|
|
110
|
+
*
|
|
111
|
+
* Iterates over all stored vectors and compresses those classified as
|
|
112
|
+
* warm or cold. Hot vectors are left uncompressed for maximum fidelity.
|
|
113
|
+
* After compression, the original float32 data for warm/cold vectors
|
|
114
|
+
* is released to free memory (the HNSW backend still holds its own copy
|
|
115
|
+
* for search operations).
|
|
116
|
+
*
|
|
117
|
+
* @param options - Optional configuration
|
|
118
|
+
* @param options.compressHot - If true, also compress hot-tier vectors (default: false)
|
|
119
|
+
* @returns Statistics about the compression operation
|
|
120
|
+
*/
|
|
121
|
+
compressIndex(options?: {
|
|
122
|
+
compressHot?: boolean;
|
|
123
|
+
}): CompressedHnswBulkResult;
|
|
124
|
+
/**
|
|
125
|
+
* Decompress and retrieve the vector for a given ID.
|
|
126
|
+
*
|
|
127
|
+
* Returns the original vector if still available, otherwise
|
|
128
|
+
* decompresses from the stored compressed form.
|
|
129
|
+
*
|
|
130
|
+
* @param id - The vector ID
|
|
131
|
+
* @returns The decompressed Float32Array, or null if not found
|
|
132
|
+
*/
|
|
133
|
+
getVector(id: number): Float32Array | null;
|
|
134
|
+
/**
|
|
135
|
+
* Get the compression tier for a specific vector.
|
|
136
|
+
*
|
|
137
|
+
* @param id - The vector ID
|
|
138
|
+
* @returns The tier, or null if not found or not compressed
|
|
139
|
+
*/
|
|
140
|
+
getVectorTier(id: number): CompressionTier | null;
|
|
141
|
+
/**
|
|
142
|
+
* Update the last-accessed timestamp for a vector.
|
|
143
|
+
* This affects which tier it falls into during the next compressIndex() call.
|
|
144
|
+
*
|
|
145
|
+
* @param id - The vector ID
|
|
146
|
+
* @param accessDate - The access date (defaults to now)
|
|
147
|
+
*/
|
|
148
|
+
touchVector(id: number, accessDate?: Date): void;
|
|
149
|
+
/**
|
|
150
|
+
* Get memory usage statistics for the compressed index.
|
|
151
|
+
*/
|
|
152
|
+
getMemoryStats(): CompressedHnswMemoryStats;
|
|
153
|
+
/**
|
|
154
|
+
* Get the underlying HNSW backend.
|
|
155
|
+
* Useful for accessing backend-specific methods (e.g., NativeHnswBackend.getMetrics()).
|
|
156
|
+
*/
|
|
157
|
+
getBackend(): IHnswIndexProvider;
|
|
158
|
+
/**
|
|
159
|
+
* Get the compression service instance.
|
|
160
|
+
*/
|
|
161
|
+
getCompressionService(): TemporalCompressionService;
|
|
162
|
+
}
|
|
163
|
+
/**
|
|
164
|
+
* Result of a bulk compression operation via compressIndex().
|
|
165
|
+
*/
|
|
166
|
+
export interface CompressedHnswBulkResult {
|
|
167
|
+
/** Number of vectors compressed in this operation */
|
|
168
|
+
compressedCount: number;
|
|
169
|
+
/** Number of vectors skipped (already compressed or hot) */
|
|
170
|
+
skippedCount: number;
|
|
171
|
+
/** Bytes freed by releasing original vectors */
|
|
172
|
+
bytesFreed: number;
|
|
173
|
+
/** Breakdown of newly compressed vectors by tier */
|
|
174
|
+
byTier: Record<CompressionTier, number>;
|
|
175
|
+
}
|
|
176
|
+
//# sourceMappingURL=compressed-hnsw-integration.d.ts.map
|
|
@@ -0,0 +1,301 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Compressed HNSW Integration
|
|
3
|
+
* ADR-085: Temporal Tensor Pattern Compression + HNSW Backend
|
|
4
|
+
*
|
|
5
|
+
* Wraps an IHnswIndexProvider to transparently handle compressed vectors.
|
|
6
|
+
* On add(), the original vector is passed to the underlying HNSW index for
|
|
7
|
+
* accurate search, while a compressed copy is stored for memory savings.
|
|
8
|
+
* On search(), results come from the HNSW index normally.
|
|
9
|
+
*
|
|
10
|
+
* The compressIndex() method bulk-compresses cold/warm vectors, and
|
|
11
|
+
* getMemoryStats() reports the savings achieved.
|
|
12
|
+
*
|
|
13
|
+
* Activation is controlled by the `useTemporalCompression` feature flag.
|
|
14
|
+
*
|
|
15
|
+
* @module integrations/ruvector/compressed-hnsw-integration
|
|
16
|
+
*/
|
|
17
|
+
import { createTemporalCompressionService, } from './temporal-compression.js';
|
|
18
|
+
import { isTemporalCompressionEnabled } from './feature-flags.js';
|
|
19
|
+
import { LoggerFactory } from '../../logging/index.js';
|
|
20
|
+
const logger = LoggerFactory.create('compressed-hnsw');
|
|
21
|
+
// ============================================================================
|
|
22
|
+
// CompressedHnswIntegration
|
|
23
|
+
// ============================================================================
|
|
24
|
+
/**
|
|
25
|
+
* Wrapper around IHnswIndexProvider that transparently manages compressed
|
|
26
|
+
* vector storage alongside the HNSW index.
|
|
27
|
+
*
|
|
28
|
+
* The HNSW index always receives full-precision vectors for accurate search.
|
|
29
|
+
* Compression is a separate memory-optimization layer that stores compact
|
|
30
|
+
* representations of vectors that can be decompressed on demand.
|
|
31
|
+
*
|
|
32
|
+
* Usage:
|
|
33
|
+
* ```typescript
|
|
34
|
+
* const baseIndex = new ProgressiveHnswBackend({ dimensions: 384 });
|
|
35
|
+
* const compressed = new CompressedHnswIntegration(baseIndex);
|
|
36
|
+
*
|
|
37
|
+
* compressed.add(1, embedding, { domain: 'auth' });
|
|
38
|
+
* const results = compressed.search(queryEmbedding, 10);
|
|
39
|
+
*
|
|
40
|
+
* // Compress cold vectors to save memory
|
|
41
|
+
* const stats = compressed.compressIndex();
|
|
42
|
+
* console.log(`Compressed ${stats.compressedCount} vectors`);
|
|
43
|
+
* ```
|
|
44
|
+
*/
|
|
45
|
+
export class CompressedHnswIntegration {
|
|
46
|
+
backend;
|
|
47
|
+
compressionService;
|
|
48
|
+
vectorEntries = new Map();
|
|
49
|
+
/**
|
|
50
|
+
* Create a CompressedHnswIntegration.
|
|
51
|
+
*
|
|
52
|
+
* @param backend - The underlying HNSW index provider to delegate to
|
|
53
|
+
* @param compressionService - Optional compression service (defaults to new instance)
|
|
54
|
+
*/
|
|
55
|
+
constructor(backend, compressionService) {
|
|
56
|
+
this.backend = backend;
|
|
57
|
+
this.compressionService = compressionService ?? createTemporalCompressionService();
|
|
58
|
+
}
|
|
59
|
+
// ==========================================================================
|
|
60
|
+
// IHnswIndexProvider Implementation
|
|
61
|
+
// ==========================================================================
|
|
62
|
+
/**
|
|
63
|
+
* Add a vector to the index.
|
|
64
|
+
*
|
|
65
|
+
* The full-precision vector is passed to the HNSW backend for search.
|
|
66
|
+
* A copy is stored locally for potential future compression.
|
|
67
|
+
* If temporal compression is enabled, the vector is also compressed
|
|
68
|
+
* immediately and the compressed form is stored.
|
|
69
|
+
*/
|
|
70
|
+
add(id, vector, metadata) {
|
|
71
|
+
// Always delegate the full-precision vector to the HNSW backend
|
|
72
|
+
this.backend.add(id, vector, metadata);
|
|
73
|
+
const now = new Date();
|
|
74
|
+
const entry = {
|
|
75
|
+
original: new Float32Array(vector),
|
|
76
|
+
compressed: null,
|
|
77
|
+
tier: null,
|
|
78
|
+
lastAccessedAt: now,
|
|
79
|
+
};
|
|
80
|
+
// If compression is enabled, compress immediately but keep the original
|
|
81
|
+
// in the HNSW index for accurate search
|
|
82
|
+
if (isTemporalCompressionEnabled()) {
|
|
83
|
+
const tier = this.compressionService.classifyTier(now);
|
|
84
|
+
entry.compressed = this.compressionService.compress(vector, tier);
|
|
85
|
+
entry.tier = tier;
|
|
86
|
+
}
|
|
87
|
+
this.vectorEntries.set(id, entry);
|
|
88
|
+
}
|
|
89
|
+
/**
|
|
90
|
+
* Search for the k nearest neighbors.
|
|
91
|
+
*
|
|
92
|
+
* Delegates entirely to the HNSW backend which holds full-precision
|
|
93
|
+
* vectors. Updates access timestamps for returned results so they
|
|
94
|
+
* stay in the hot tier.
|
|
95
|
+
*/
|
|
96
|
+
search(query, k) {
|
|
97
|
+
const results = this.backend.search(query, k);
|
|
98
|
+
// Update last-accessed timestamps for returned results
|
|
99
|
+
const now = new Date();
|
|
100
|
+
for (const result of results) {
|
|
101
|
+
const entry = this.vectorEntries.get(result.id);
|
|
102
|
+
if (entry) {
|
|
103
|
+
entry.lastAccessedAt = now;
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
return results;
|
|
107
|
+
}
|
|
108
|
+
/**
|
|
109
|
+
* Remove a vector from the index.
|
|
110
|
+
*/
|
|
111
|
+
remove(id) {
|
|
112
|
+
this.vectorEntries.delete(id);
|
|
113
|
+
return this.backend.remove(id);
|
|
114
|
+
}
|
|
115
|
+
/**
|
|
116
|
+
* Get the number of vectors in the index.
|
|
117
|
+
*/
|
|
118
|
+
size() {
|
|
119
|
+
return this.backend.size();
|
|
120
|
+
}
|
|
121
|
+
/**
|
|
122
|
+
* Get the configured vector dimensions.
|
|
123
|
+
*/
|
|
124
|
+
dimensions() {
|
|
125
|
+
return this.backend.dimensions();
|
|
126
|
+
}
|
|
127
|
+
/**
|
|
128
|
+
* Get estimated recall. Delegates to the underlying backend.
|
|
129
|
+
*/
|
|
130
|
+
recall() {
|
|
131
|
+
return this.backend.recall();
|
|
132
|
+
}
|
|
133
|
+
// ==========================================================================
|
|
134
|
+
// Compression Operations
|
|
135
|
+
// ==========================================================================
|
|
136
|
+
/**
|
|
137
|
+
* Compress vectors in the index based on their access tier.
|
|
138
|
+
*
|
|
139
|
+
* Iterates over all stored vectors and compresses those classified as
|
|
140
|
+
* warm or cold. Hot vectors are left uncompressed for maximum fidelity.
|
|
141
|
+
* After compression, the original float32 data for warm/cold vectors
|
|
142
|
+
* is released to free memory (the HNSW backend still holds its own copy
|
|
143
|
+
* for search operations).
|
|
144
|
+
*
|
|
145
|
+
* @param options - Optional configuration
|
|
146
|
+
* @param options.compressHot - If true, also compress hot-tier vectors (default: false)
|
|
147
|
+
* @returns Statistics about the compression operation
|
|
148
|
+
*/
|
|
149
|
+
compressIndex(options) {
|
|
150
|
+
const compressHot = options?.compressHot ?? false;
|
|
151
|
+
let compressedCount = 0;
|
|
152
|
+
let skippedCount = 0;
|
|
153
|
+
let bytesFreed = 0;
|
|
154
|
+
const byTier = { hot: 0, warm: 0, cold: 0 };
|
|
155
|
+
for (const [id, entry] of this.vectorEntries) {
|
|
156
|
+
const tier = this.compressionService.classifyTier(entry.lastAccessedAt);
|
|
157
|
+
// Skip hot vectors unless explicitly requested
|
|
158
|
+
if (tier === 'hot' && !compressHot) {
|
|
159
|
+
skippedCount++;
|
|
160
|
+
continue;
|
|
161
|
+
}
|
|
162
|
+
// Skip if already compressed at the same or more aggressive tier
|
|
163
|
+
if (entry.compressed && entry.tier === tier) {
|
|
164
|
+
skippedCount++;
|
|
165
|
+
continue;
|
|
166
|
+
}
|
|
167
|
+
// Need the original vector to compress. If we already freed it,
|
|
168
|
+
// we cannot re-compress (the HNSW backend doesn't expose vectors).
|
|
169
|
+
if (!entry.original) {
|
|
170
|
+
// If we have an existing compressed form at a less aggressive tier,
|
|
171
|
+
// we could decompress and recompress, but that adds error.
|
|
172
|
+
// For now, skip.
|
|
173
|
+
skippedCount++;
|
|
174
|
+
continue;
|
|
175
|
+
}
|
|
176
|
+
const compressed = this.compressionService.compress(entry.original, tier);
|
|
177
|
+
const originalSize = entry.original.byteLength;
|
|
178
|
+
entry.compressed = compressed;
|
|
179
|
+
entry.tier = tier;
|
|
180
|
+
// For warm and cold tiers, release the original to save memory.
|
|
181
|
+
// The HNSW backend still holds its own copy for search.
|
|
182
|
+
if (tier !== 'hot') {
|
|
183
|
+
entry.original = null;
|
|
184
|
+
bytesFreed += originalSize;
|
|
185
|
+
}
|
|
186
|
+
compressedCount++;
|
|
187
|
+
byTier[tier]++;
|
|
188
|
+
}
|
|
189
|
+
logger.debug(`compressIndex: compressed=${compressedCount}, skipped=${skippedCount}, freed=${bytesFreed} bytes`);
|
|
190
|
+
return {
|
|
191
|
+
compressedCount,
|
|
192
|
+
skippedCount,
|
|
193
|
+
bytesFreed,
|
|
194
|
+
byTier,
|
|
195
|
+
};
|
|
196
|
+
}
|
|
197
|
+
/**
|
|
198
|
+
* Decompress and retrieve the vector for a given ID.
|
|
199
|
+
*
|
|
200
|
+
* Returns the original vector if still available, otherwise
|
|
201
|
+
* decompresses from the stored compressed form.
|
|
202
|
+
*
|
|
203
|
+
* @param id - The vector ID
|
|
204
|
+
* @returns The decompressed Float32Array, or null if not found
|
|
205
|
+
*/
|
|
206
|
+
getVector(id) {
|
|
207
|
+
const entry = this.vectorEntries.get(id);
|
|
208
|
+
if (!entry)
|
|
209
|
+
return null;
|
|
210
|
+
// Return original if still available
|
|
211
|
+
if (entry.original)
|
|
212
|
+
return entry.original;
|
|
213
|
+
// Decompress from compressed form
|
|
214
|
+
if (entry.compressed) {
|
|
215
|
+
return this.compressionService.decompress(entry.compressed);
|
|
216
|
+
}
|
|
217
|
+
return null;
|
|
218
|
+
}
|
|
219
|
+
/**
|
|
220
|
+
* Get the compression tier for a specific vector.
|
|
221
|
+
*
|
|
222
|
+
* @param id - The vector ID
|
|
223
|
+
* @returns The tier, or null if not found or not compressed
|
|
224
|
+
*/
|
|
225
|
+
getVectorTier(id) {
|
|
226
|
+
const entry = this.vectorEntries.get(id);
|
|
227
|
+
return entry?.tier ?? null;
|
|
228
|
+
}
|
|
229
|
+
/**
|
|
230
|
+
* Update the last-accessed timestamp for a vector.
|
|
231
|
+
* This affects which tier it falls into during the next compressIndex() call.
|
|
232
|
+
*
|
|
233
|
+
* @param id - The vector ID
|
|
234
|
+
* @param accessDate - The access date (defaults to now)
|
|
235
|
+
*/
|
|
236
|
+
touchVector(id, accessDate) {
|
|
237
|
+
const entry = this.vectorEntries.get(id);
|
|
238
|
+
if (entry) {
|
|
239
|
+
entry.lastAccessedAt = accessDate ?? new Date();
|
|
240
|
+
}
|
|
241
|
+
}
|
|
242
|
+
// ==========================================================================
|
|
243
|
+
// Memory Statistics
|
|
244
|
+
// ==========================================================================
|
|
245
|
+
/**
|
|
246
|
+
* Get memory usage statistics for the compressed index.
|
|
247
|
+
*/
|
|
248
|
+
getMemoryStats() {
|
|
249
|
+
let uncompressedCount = 0;
|
|
250
|
+
let compressedCount = 0;
|
|
251
|
+
let originalBytes = 0;
|
|
252
|
+
let compressedBytes = 0;
|
|
253
|
+
const compressedByTier = { hot: 0, warm: 0, cold: 0 };
|
|
254
|
+
for (const entry of this.vectorEntries.values()) {
|
|
255
|
+
if (entry.compressed && entry.tier) {
|
|
256
|
+
compressedCount++;
|
|
257
|
+
compressedByTier[entry.tier]++;
|
|
258
|
+
compressedBytes += entry.compressed.compressedByteSize;
|
|
259
|
+
originalBytes += entry.compressed.originalByteSize;
|
|
260
|
+
}
|
|
261
|
+
else if (entry.original) {
|
|
262
|
+
uncompressedCount++;
|
|
263
|
+
const byteSize = entry.original.byteLength;
|
|
264
|
+
originalBytes += byteSize;
|
|
265
|
+
compressedBytes += byteSize; // Not compressed, so same size
|
|
266
|
+
}
|
|
267
|
+
}
|
|
268
|
+
const bytesSaved = originalBytes - compressedBytes;
|
|
269
|
+
const savingsPercent = originalBytes > 0
|
|
270
|
+
? (bytesSaved / originalBytes) * 100
|
|
271
|
+
: 0;
|
|
272
|
+
return {
|
|
273
|
+
totalVectors: this.vectorEntries.size,
|
|
274
|
+
uncompressedCount,
|
|
275
|
+
compressedCount,
|
|
276
|
+
compressedByTier,
|
|
277
|
+
originalBytes,
|
|
278
|
+
compressedBytes,
|
|
279
|
+
bytesSaved,
|
|
280
|
+
savingsPercent,
|
|
281
|
+
compressionEnabled: isTemporalCompressionEnabled(),
|
|
282
|
+
};
|
|
283
|
+
}
|
|
284
|
+
// ==========================================================================
|
|
285
|
+
// Accessors
|
|
286
|
+
// ==========================================================================
|
|
287
|
+
/**
|
|
288
|
+
* Get the underlying HNSW backend.
|
|
289
|
+
* Useful for accessing backend-specific methods (e.g., NativeHnswBackend.getMetrics()).
|
|
290
|
+
*/
|
|
291
|
+
getBackend() {
|
|
292
|
+
return this.backend;
|
|
293
|
+
}
|
|
294
|
+
/**
|
|
295
|
+
* Get the compression service instance.
|
|
296
|
+
*/
|
|
297
|
+
getCompressionService() {
|
|
298
|
+
return this.compressionService;
|
|
299
|
+
}
|
|
300
|
+
}
|
|
301
|
+
//# sourceMappingURL=compressed-hnsw-integration.js.map
|
|
@@ -0,0 +1,122 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Deterministic Dithering Adapter for Cross-Platform Reproducibility
|
|
3
|
+
*
|
|
4
|
+
* Provides golden-ratio quasi-random dithering for embedding quantization.
|
|
5
|
+
* Ensures identical quantization results across x86, ARM, and WASM platforms
|
|
6
|
+
* by using only deterministic integer and float arithmetic.
|
|
7
|
+
*
|
|
8
|
+
* The golden ratio sequence produces a low-discrepancy quasi-random sequence
|
|
9
|
+
* that distributes quantization error more evenly than truncation alone,
|
|
10
|
+
* improving reconstruction quality at low bit depths.
|
|
11
|
+
*
|
|
12
|
+
* @module integrations/ruvector/dither-adapter
|
|
13
|
+
*/
|
|
14
|
+
/**
|
|
15
|
+
* Result of applying dithered quantization to a vector
|
|
16
|
+
*/
|
|
17
|
+
export interface DitheredResult {
|
|
18
|
+
/** Quantized values as integers in [0, 2^bitDepth - 1] */
|
|
19
|
+
quantized: Int32Array;
|
|
20
|
+
/** Dequantized (reconstructed) float values */
|
|
21
|
+
dequantized: Float32Array;
|
|
22
|
+
/** Bit depth used for quantization */
|
|
23
|
+
bitDepth: number;
|
|
24
|
+
/** Seed used for dither generation */
|
|
25
|
+
seed: number;
|
|
26
|
+
/** Step size (quantization interval width) */
|
|
27
|
+
stepSize: number;
|
|
28
|
+
/** Min value of the original vector (used for dequantization) */
|
|
29
|
+
minValue: number;
|
|
30
|
+
/** Max value of the original vector (used for dequantization) */
|
|
31
|
+
maxValue: number;
|
|
32
|
+
}
|
|
33
|
+
/**
|
|
34
|
+
* Options for the dither adapter
|
|
35
|
+
*/
|
|
36
|
+
export interface DitherOptions {
|
|
37
|
+
/** Bit depth for quantization (1-32, typical: 3, 5, 7, 8) */
|
|
38
|
+
bitDepth: number;
|
|
39
|
+
/** Seed for the dither sequence (default: 0) */
|
|
40
|
+
seed?: number;
|
|
41
|
+
}
|
|
42
|
+
/**
|
|
43
|
+
* Check if a native dither module is available.
|
|
44
|
+
* Always returns false — the TypeScript implementation is production-ready.
|
|
45
|
+
*/
|
|
46
|
+
export declare function isNativeDitherAvailable(): boolean;
|
|
47
|
+
/**
|
|
48
|
+
* Create a deterministic quasi-random dither sequence using the golden ratio.
|
|
49
|
+
*
|
|
50
|
+
* The sequence d_n = frac((seed + (n+1) * phi)) produces values uniformly
|
|
51
|
+
* distributed in [0, 1) with low discrepancy (no clumping). This is a
|
|
52
|
+
* Weyl sequence / additive recurrence, which is deterministic and
|
|
53
|
+
* platform-independent since it uses only standard IEEE 754 arithmetic.
|
|
54
|
+
*
|
|
55
|
+
* @param length - Number of dither values to generate
|
|
56
|
+
* @param seed - Starting offset for the sequence (default: 0)
|
|
57
|
+
* @returns Float32Array of dither values in [0, 1)
|
|
58
|
+
*/
|
|
59
|
+
export declare function createDitherSequence(length: number, seed?: number): Float32Array;
|
|
60
|
+
/**
|
|
61
|
+
* Apply deterministic dithered quantization to a float vector.
|
|
62
|
+
*
|
|
63
|
+
* The algorithm:
|
|
64
|
+
* 1. Compute the range [min, max] of the input vector.
|
|
65
|
+
* 2. Compute step_size = range / (2^bitDepth - 1).
|
|
66
|
+
* 3. Generate a golden-ratio dither sequence of the same length.
|
|
67
|
+
* 4. For each element: quantized[i] = clamp(round((value[i] - min) / stepSize + (dither[i] - 0.5)), 0, maxLevel)
|
|
68
|
+
* 5. Dequantize: dequantized[i] = quantized[i] * stepSize + min
|
|
69
|
+
*
|
|
70
|
+
* The dither offset (dither[i] - 0.5) centers the dither noise around zero,
|
|
71
|
+
* which reduces systematic bias compared to truncation-only quantization.
|
|
72
|
+
*
|
|
73
|
+
* @param vector - Input float vector to quantize
|
|
74
|
+
* @param bitDepth - Number of bits for quantization (1-32)
|
|
75
|
+
* @param seed - Seed for dither sequence reproducibility (default: 0)
|
|
76
|
+
* @returns DitheredResult with quantized and reconstructed values
|
|
77
|
+
*/
|
|
78
|
+
export declare function applyDither(vector: Float32Array, bitDepth: number, seed?: number): DitheredResult;
|
|
79
|
+
/**
|
|
80
|
+
* Apply naive (non-dithered) quantization for comparison purposes.
|
|
81
|
+
*
|
|
82
|
+
* Uses simple rounding without dither noise. This tends to produce
|
|
83
|
+
* systematic quantization artifacts, especially at low bit depths.
|
|
84
|
+
*
|
|
85
|
+
* @param vector - Input float vector to quantize
|
|
86
|
+
* @param bitDepth - Number of bits for quantization (1-32)
|
|
87
|
+
* @returns DitheredResult with quantized and reconstructed values (seed = -1 to indicate no dither)
|
|
88
|
+
*/
|
|
89
|
+
export declare function applyNaiveQuantization(vector: Float32Array, bitDepth: number): DitheredResult;
|
|
90
|
+
/**
|
|
91
|
+
* Verify that dithered quantization is deterministic for the given input.
|
|
92
|
+
*
|
|
93
|
+
* Runs the quantization twice with the same parameters and compares results.
|
|
94
|
+
* This guards against any non-determinism from floating point ordering,
|
|
95
|
+
* platform differences, or hidden state.
|
|
96
|
+
*
|
|
97
|
+
* @param vector - Input float vector to test
|
|
98
|
+
* @param bitDepth - Number of bits for quantization
|
|
99
|
+
* @returns true if both runs produce identical quantized values
|
|
100
|
+
*/
|
|
101
|
+
export declare function verifyDeterminism(vector: Float32Array, bitDepth: number): boolean;
|
|
102
|
+
/**
|
|
103
|
+
* Compute mean squared error between original and reconstructed vectors.
|
|
104
|
+
*
|
|
105
|
+
* @param original - Original float vector
|
|
106
|
+
* @param reconstructed - Reconstructed (dequantized) float vector
|
|
107
|
+
* @returns Mean squared error
|
|
108
|
+
*/
|
|
109
|
+
export declare function computeMSE(original: Float32Array, reconstructed: Float32Array): number;
|
|
110
|
+
/**
|
|
111
|
+
* Compute signal-to-noise ratio (SNR) in decibels.
|
|
112
|
+
*
|
|
113
|
+
* SNR = 10 * log10(signal_power / noise_power)
|
|
114
|
+
*
|
|
115
|
+
* Higher SNR means better reconstruction quality.
|
|
116
|
+
*
|
|
117
|
+
* @param original - Original float vector
|
|
118
|
+
* @param reconstructed - Reconstructed (dequantized) float vector
|
|
119
|
+
* @returns SNR in dB, or Infinity if reconstruction is perfect
|
|
120
|
+
*/
|
|
121
|
+
export declare function computeSNR(original: Float32Array, reconstructed: Float32Array): number;
|
|
122
|
+
//# sourceMappingURL=dither-adapter.d.ts.map
|