ruvector 0.1.25 → 0.1.27

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.
@@ -1,7 +1,7 @@
1
1
  {
2
- "startTime": 1764542370768,
3
- "sessionId": "session-1764542370768",
4
- "lastActivity": 1764542370768,
2
+ "startTime": 1764779126575,
3
+ "sessionId": "session-1764779126575",
4
+ "lastActivity": 1764779126575,
5
5
  "sessionDuration": 0,
6
6
  "totalTasks": 1,
7
7
  "successfulTasks": 1,
@@ -1,10 +1,10 @@
1
1
  [
2
2
  {
3
- "id": "cmd-hooks-1764542370895",
3
+ "id": "cmd-hooks-1764779126675",
4
4
  "type": "hooks",
5
5
  "success": true,
6
- "duration": 15.263496999999973,
7
- "timestamp": 1764542370910,
6
+ "duration": 6.509910999999988,
7
+ "timestamp": 1764779126682,
8
8
  "metadata": {}
9
9
  }
10
10
  ]
package/README.md CHANGED
@@ -484,6 +484,119 @@ npx ruvector gnn search -q "[1.0,0.0,0.0]" -c candidates.json -k 5
484
484
  # -t, --temperature Softmax temperature (default: 1.0)
485
485
  ```
486
486
 
487
+ ### Attention Commands
488
+
489
+ Ruvector includes high-performance attention mechanisms for transformer-based operations, hyperbolic embeddings, and graph attention.
490
+
491
+ ```bash
492
+ # Install the attention module (optional)
493
+ npm install @ruvector/attention
494
+ ```
495
+
496
+ #### Attention Mechanisms Reference
497
+
498
+ | Mechanism | Type | Complexity | When to Use |
499
+ |-----------|------|------------|-------------|
500
+ | **DotProductAttention** | Core | O(n²) | Standard scaled dot-product attention for transformers |
501
+ | **MultiHeadAttention** | Core | O(n²) | Parallel attention heads for capturing different relationships |
502
+ | **FlashAttention** | Core | O(n²) IO-optimized | Memory-efficient attention for long sequences |
503
+ | **HyperbolicAttention** | Core | O(n²) | Hierarchical data, tree-like structures, taxonomies |
504
+ | **LinearAttention** | Core | O(n) | Very long sequences where O(n²) is prohibitive |
505
+ | **MoEAttention** | Core | O(n*k) | Mixture of Experts routing, specialized attention |
506
+ | **GraphRoPeAttention** | Graph | O(n²) | Graph data with rotary position embeddings |
507
+ | **EdgeFeaturedAttention** | Graph | O(n²) | Graphs with rich edge features/attributes |
508
+ | **DualSpaceAttention** | Graph | O(n²) | Combined Euclidean + hyperbolic representation |
509
+ | **LocalGlobalAttention** | Graph | O(n*k) | Large graphs with local + global context |
510
+
511
+ #### Attention Info
512
+
513
+ ```bash
514
+ # Show attention module information
515
+ npx ruvector attention info
516
+
517
+ # Output:
518
+ # Attention Module Information
519
+ # Status: Available
520
+ # Version: 0.1.0
521
+ # Platform: linux
522
+ # Architecture: x64
523
+ #
524
+ # Core Attention Mechanisms:
525
+ # • DotProductAttention - Scaled dot-product attention
526
+ # • MultiHeadAttention - Multi-head self-attention
527
+ # • FlashAttention - Memory-efficient IO-aware attention
528
+ # • HyperbolicAttention - Poincaré ball attention
529
+ # • LinearAttention - O(n) linear complexity attention
530
+ # • MoEAttention - Mixture of Experts attention
531
+ ```
532
+
533
+ #### Attention List
534
+
535
+ ```bash
536
+ # List all available attention mechanisms
537
+ npx ruvector attention list
538
+
539
+ # With verbose details
540
+ npx ruvector attention list -v
541
+ ```
542
+
543
+ #### Attention Benchmark
544
+
545
+ ```bash
546
+ # Benchmark attention mechanisms
547
+ npx ruvector attention benchmark -d 256 -n 100 -i 100
548
+
549
+ # Options:
550
+ # -d, --dimension Vector dimension (default: 256)
551
+ # -n, --num-vectors Number of vectors (default: 100)
552
+ # -i, --iterations Benchmark iterations (default: 100)
553
+ # -t, --types Attention types to benchmark (default: dot,flash,linear)
554
+
555
+ # Example output:
556
+ # Dimension: 256
557
+ # Vectors: 100
558
+ # Iterations: 100
559
+ #
560
+ # dot: 0.012ms/op (84,386 ops/sec)
561
+ # flash: 0.012ms/op (82,844 ops/sec)
562
+ # linear: 0.066ms/op (15,259 ops/sec)
563
+ ```
564
+
565
+ #### Hyperbolic Operations
566
+
567
+ ```bash
568
+ # Calculate Poincaré distance between two points
569
+ npx ruvector attention hyperbolic -a distance -v "[0.1,0.2,0.3]" -b "[0.4,0.5,0.6]"
570
+
571
+ # Project vector to Poincaré ball
572
+ npx ruvector attention hyperbolic -a project -v "[1.5,2.0,0.8]"
573
+
574
+ # Möbius addition in hyperbolic space
575
+ npx ruvector attention hyperbolic -a mobius-add -v "[0.1,0.2]" -b "[0.3,0.4]"
576
+
577
+ # Exponential map (tangent space → Poincaré ball)
578
+ npx ruvector attention hyperbolic -a exp-map -v "[0.1,0.2,0.3]"
579
+
580
+ # Options:
581
+ # -a, --action Action: distance|project|mobius-add|exp-map|log-map
582
+ # -v, --vector Input vector as JSON array (required)
583
+ # -b, --vector-b Second vector for binary operations
584
+ # -c, --curvature Poincaré ball curvature (default: 1.0)
585
+ ```
586
+
587
+ #### When to Use Each Attention Type
588
+
589
+ | Use Case | Recommended Attention | Reason |
590
+ |----------|----------------------|--------|
591
+ | **Standard NLP/Transformers** | MultiHeadAttention | Industry standard, well-tested |
592
+ | **Long Documents (>4K tokens)** | FlashAttention or LinearAttention | Memory efficient |
593
+ | **Hierarchical Classification** | HyperbolicAttention | Captures tree-like structures |
594
+ | **Knowledge Graphs** | GraphRoPeAttention | Position-aware graph attention |
595
+ | **Multi-Relational Graphs** | EdgeFeaturedAttention | Leverages edge attributes |
596
+ | **Taxonomy/Ontology Search** | DualSpaceAttention | Best of both Euclidean + hyperbolic |
597
+ | **Large-Scale Graphs** | LocalGlobalAttention | Efficient local + global context |
598
+ | **Model Routing/MoE** | MoEAttention | Expert selection and routing |
599
+
487
600
  ## 📊 Performance Benchmarks
488
601
 
489
602
  Tested on AMD Ryzen 9 5950X, 128-dimensional vectors:
package/bin/cli.js CHANGED
@@ -356,9 +356,10 @@ program
356
356
 
357
357
  // Try to load ruvector for implementation info
358
358
  if (loadRuvector()) {
359
- const info = getVersion();
360
- console.log(chalk.white(` Core Version: ${chalk.yellow(info.version)}`));
361
- console.log(chalk.white(` Implementation: ${chalk.yellow(info.implementation)}`));
359
+ const version = typeof getVersion === 'function' ? getVersion() : 'unknown';
360
+ const impl = typeof getImplementationType === 'function' ? getImplementationType() : 'native';
361
+ console.log(chalk.white(` Core Version: ${chalk.yellow(version)}`));
362
+ console.log(chalk.white(` Implementation: ${chalk.yellow(impl)}`));
362
363
  } else {
363
364
  console.log(chalk.white(` Core: ${chalk.gray('Not loaded (install @ruvector/core)')}`));
364
365
  }
@@ -1056,6 +1057,10 @@ attentionCmd
1056
1057
 
1057
1058
  const results = [];
1058
1059
 
1060
+ // Convert to Float32Arrays for compute()
1061
+ const queryF32 = new Float32Array(query);
1062
+ const keysF32 = keys.map(k => new Float32Array(k));
1063
+
1059
1064
  for (const type of types) {
1060
1065
  spinner.text = `Benchmarking ${type} attention...`;
1061
1066
  spinner.start();
@@ -1064,39 +1069,42 @@ attentionCmd
1064
1069
  try {
1065
1070
  switch (type) {
1066
1071
  case 'dot':
1067
- attn = new DotProductAttention();
1072
+ attn = new DotProductAttention(dim);
1068
1073
  break;
1069
1074
  case 'flash':
1070
- attn = new FlashAttention(dim);
1075
+ attn = new FlashAttention(dim, 64); // dim, block_size
1071
1076
  break;
1072
1077
  case 'linear':
1073
- attn = new LinearAttention(dim);
1078
+ attn = new LinearAttention(dim, 64); // dim, num_features
1074
1079
  break;
1075
1080
  case 'hyperbolic':
1076
1081
  attn = new HyperbolicAttention(dim, 1.0);
1077
1082
  break;
1078
1083
  case 'multi-head':
1079
- attn = new MultiHeadAttention(dim, 4, 64);
1084
+ attn = new MultiHeadAttention(dim, 4); // dim, num_heads
1080
1085
  break;
1081
1086
  default:
1082
1087
  console.log(chalk.yellow(` Skipping unknown type: ${type}`));
1083
1088
  continue;
1084
1089
  }
1085
1090
  } catch (e) {
1086
- console.log(chalk.yellow(` ${type}: not available`));
1091
+ console.log(chalk.yellow(` ${type}: not available (${e.message})`));
1087
1092
  continue;
1088
1093
  }
1089
1094
 
1090
1095
  // Warm up
1091
- const queryMat = [query];
1092
1096
  for (let i = 0; i < 5; i++) {
1093
- attn.forward(queryMat, keys, keys);
1097
+ try {
1098
+ attn.compute(queryF32, keysF32, keysF32);
1099
+ } catch (e) {
1100
+ // Some mechanisms may fail warmup
1101
+ }
1094
1102
  }
1095
1103
 
1096
1104
  // Benchmark
1097
1105
  const start = process.hrtime.bigint();
1098
1106
  for (let i = 0; i < iterations; i++) {
1099
- attn.forward(queryMat, keys, keys);
1107
+ attn.compute(queryF32, keysF32, keysF32);
1100
1108
  }
1101
1109
  const end = process.hrtime.bigint();
1102
1110
  const totalMs = Number(end - start) / 1_000_000;
@@ -1398,8 +1406,10 @@ program
1398
1406
 
1399
1407
  // Check if native binding works
1400
1408
  if (coreAvailable && loadRuvector()) {
1401
- const info = getVersion();
1402
- console.log(chalk.green(` ✓ Native binding working (${info.implementation})`));
1409
+ const version = typeof getVersion === 'function' ? getVersion() : null;
1410
+ const impl = typeof getImplementationType === 'function' ? getImplementationType() : 'native';
1411
+ const versionStr = version ? `, v${version}` : '';
1412
+ console.log(chalk.green(` ✓ Native binding working (${impl}${versionStr})`));
1403
1413
  } else if (coreAvailable) {
1404
1414
  console.log(chalk.yellow(` ! Native binding failed to load`));
1405
1415
  warnings++;
@@ -0,0 +1,149 @@
1
+ /**
2
+ * AgentDB Fast - High-performance in-process alternative to AgentDB CLI
3
+ *
4
+ * The AgentDB CLI has ~2.3s startup overhead due to npx initialization.
5
+ * This module provides 50-200x faster operations by using in-process calls.
6
+ *
7
+ * Features:
8
+ * - In-memory episode storage with LRU eviction
9
+ * - Vector similarity search using @ruvector/core
10
+ * - Compatible API with AgentDB's episode/trajectory interfaces
11
+ */
12
+ /**
13
+ * Episode entry for trajectory storage
14
+ */
15
+ export interface Episode {
16
+ id: string;
17
+ state: number[];
18
+ action: string | number;
19
+ reward: number;
20
+ nextState: number[];
21
+ done: boolean;
22
+ metadata?: Record<string, any>;
23
+ timestamp?: number;
24
+ }
25
+ /**
26
+ * Trajectory (sequence of episodes)
27
+ */
28
+ export interface Trajectory {
29
+ id: string;
30
+ episodes: Episode[];
31
+ totalReward: number;
32
+ metadata?: Record<string, any>;
33
+ }
34
+ /**
35
+ * Search result for episode queries
36
+ */
37
+ export interface EpisodeSearchResult {
38
+ episode: Episode;
39
+ similarity: number;
40
+ trajectoryId?: string;
41
+ }
42
+ /**
43
+ * Fast in-memory AgentDB implementation
44
+ */
45
+ export declare class FastAgentDB {
46
+ private episodes;
47
+ private trajectories;
48
+ private vectorDb;
49
+ private dimensions;
50
+ private maxEpisodes;
51
+ private episodeOrder;
52
+ /**
53
+ * Create a new FastAgentDB instance
54
+ *
55
+ * @param dimensions - Vector dimensions for state embeddings
56
+ * @param maxEpisodes - Maximum episodes to store (LRU eviction)
57
+ */
58
+ constructor(dimensions?: number, maxEpisodes?: number);
59
+ /**
60
+ * Initialize the vector database
61
+ */
62
+ private initVectorDb;
63
+ /**
64
+ * Store an episode
65
+ *
66
+ * @param episode - Episode to store
67
+ * @returns Episode ID
68
+ */
69
+ storeEpisode(episode: Omit<Episode, 'id'> & {
70
+ id?: string;
71
+ }): Promise<string>;
72
+ /**
73
+ * Store multiple episodes in batch
74
+ */
75
+ storeEpisodes(episodes: (Omit<Episode, 'id'> & {
76
+ id?: string;
77
+ })[]): Promise<string[]>;
78
+ /**
79
+ * Retrieve an episode by ID
80
+ */
81
+ getEpisode(id: string): Promise<Episode | null>;
82
+ /**
83
+ * Search for similar episodes by state
84
+ *
85
+ * @param queryState - State vector to search for
86
+ * @param k - Number of results to return
87
+ * @returns Similar episodes sorted by similarity
88
+ */
89
+ searchByState(queryState: number[] | Float32Array, k?: number): Promise<EpisodeSearchResult[]>;
90
+ /**
91
+ * Fallback similarity search using brute-force cosine similarity
92
+ */
93
+ private fallbackSearch;
94
+ /**
95
+ * Compute cosine similarity between two vectors
96
+ */
97
+ private cosineSimilarity;
98
+ /**
99
+ * Store a trajectory (sequence of episodes)
100
+ */
101
+ storeTrajectory(episodes: (Omit<Episode, 'id'> & {
102
+ id?: string;
103
+ })[], metadata?: Record<string, any>): Promise<string>;
104
+ /**
105
+ * Get a trajectory by ID
106
+ */
107
+ getTrajectory(id: string): Promise<Trajectory | null>;
108
+ /**
109
+ * Get top trajectories by total reward
110
+ */
111
+ getTopTrajectories(k?: number): Promise<Trajectory[]>;
112
+ /**
113
+ * Sample random episodes (for experience replay)
114
+ */
115
+ sampleEpisodes(n: number): Promise<Episode[]>;
116
+ /**
117
+ * Get database statistics
118
+ */
119
+ getStats(): {
120
+ episodeCount: number;
121
+ trajectoryCount: number;
122
+ dimensions: number;
123
+ maxEpisodes: number;
124
+ vectorDbAvailable: boolean;
125
+ };
126
+ /**
127
+ * Clear all data
128
+ */
129
+ clear(): void;
130
+ /**
131
+ * Generate a unique ID
132
+ */
133
+ private generateId;
134
+ }
135
+ /**
136
+ * Create a fast AgentDB instance
137
+ */
138
+ export declare function createFastAgentDB(dimensions?: number, maxEpisodes?: number): FastAgentDB;
139
+ /**
140
+ * Get the default FastAgentDB instance
141
+ */
142
+ export declare function getDefaultAgentDB(): FastAgentDB;
143
+ declare const _default: {
144
+ FastAgentDB: typeof FastAgentDB;
145
+ createFastAgentDB: typeof createFastAgentDB;
146
+ getDefaultAgentDB: typeof getDefaultAgentDB;
147
+ };
148
+ export default _default;
149
+ //# sourceMappingURL=agentdb-fast.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"agentdb-fast.d.ts","sourceRoot":"","sources":["../../src/core/agentdb-fast.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,301 @@
1
+ "use strict";
2
+ /**
3
+ * AgentDB Fast - High-performance in-process alternative to AgentDB CLI
4
+ *
5
+ * The AgentDB CLI has ~2.3s startup overhead due to npx initialization.
6
+ * This module provides 50-200x faster operations by using in-process calls.
7
+ *
8
+ * Features:
9
+ * - In-memory episode storage with LRU eviction
10
+ * - Vector similarity search using @ruvector/core
11
+ * - Compatible API with AgentDB's episode/trajectory interfaces
12
+ */
13
+ Object.defineProperty(exports, "__esModule", { value: true });
14
+ exports.FastAgentDB = void 0;
15
+ exports.createFastAgentDB = createFastAgentDB;
16
+ exports.getDefaultAgentDB = getDefaultAgentDB;
17
+ // Lazy load ruvector core
18
+ let coreModule = null;
19
+ function getCoreModule() {
20
+ if (coreModule)
21
+ return coreModule;
22
+ try {
23
+ coreModule = require('@ruvector/core');
24
+ return coreModule;
25
+ }
26
+ catch {
27
+ // Fallback to ruvector if core not available
28
+ try {
29
+ coreModule = require('ruvector');
30
+ return coreModule;
31
+ }
32
+ catch (e) {
33
+ throw new Error(`Neither @ruvector/core nor ruvector is available: ${e.message}`);
34
+ }
35
+ }
36
+ }
37
+ /**
38
+ * Fast in-memory AgentDB implementation
39
+ */
40
+ class FastAgentDB {
41
+ /**
42
+ * Create a new FastAgentDB instance
43
+ *
44
+ * @param dimensions - Vector dimensions for state embeddings
45
+ * @param maxEpisodes - Maximum episodes to store (LRU eviction)
46
+ */
47
+ constructor(dimensions = 128, maxEpisodes = 100000) {
48
+ this.episodes = new Map();
49
+ this.trajectories = new Map();
50
+ this.vectorDb = null;
51
+ this.episodeOrder = []; // For LRU eviction
52
+ this.dimensions = dimensions;
53
+ this.maxEpisodes = maxEpisodes;
54
+ }
55
+ /**
56
+ * Initialize the vector database
57
+ */
58
+ async initVectorDb() {
59
+ if (this.vectorDb)
60
+ return;
61
+ try {
62
+ const core = getCoreModule();
63
+ this.vectorDb = new core.VectorDB({
64
+ dimensions: this.dimensions,
65
+ distanceMetric: 'Cosine',
66
+ });
67
+ }
68
+ catch (e) {
69
+ // Vector DB not available, use fallback similarity
70
+ console.warn(`VectorDB not available, using fallback similarity: ${e.message}`);
71
+ }
72
+ }
73
+ /**
74
+ * Store an episode
75
+ *
76
+ * @param episode - Episode to store
77
+ * @returns Episode ID
78
+ */
79
+ async storeEpisode(episode) {
80
+ await this.initVectorDb();
81
+ const id = episode.id ?? this.generateId();
82
+ const fullEpisode = {
83
+ ...episode,
84
+ id,
85
+ timestamp: episode.timestamp ?? Date.now(),
86
+ };
87
+ // LRU eviction if needed
88
+ if (this.episodes.size >= this.maxEpisodes) {
89
+ const oldestId = this.episodeOrder.shift();
90
+ if (oldestId) {
91
+ this.episodes.delete(oldestId);
92
+ }
93
+ }
94
+ this.episodes.set(id, fullEpisode);
95
+ this.episodeOrder.push(id);
96
+ // Index in vector DB if available
97
+ if (this.vectorDb && fullEpisode.state.length === this.dimensions) {
98
+ try {
99
+ await this.vectorDb.insert({
100
+ id,
101
+ vector: new Float32Array(fullEpisode.state),
102
+ });
103
+ }
104
+ catch {
105
+ // Ignore indexing errors
106
+ }
107
+ }
108
+ return id;
109
+ }
110
+ /**
111
+ * Store multiple episodes in batch
112
+ */
113
+ async storeEpisodes(episodes) {
114
+ const ids = [];
115
+ for (const episode of episodes) {
116
+ const id = await this.storeEpisode(episode);
117
+ ids.push(id);
118
+ }
119
+ return ids;
120
+ }
121
+ /**
122
+ * Retrieve an episode by ID
123
+ */
124
+ async getEpisode(id) {
125
+ const episode = this.episodes.get(id);
126
+ if (episode) {
127
+ // Update LRU order
128
+ const idx = this.episodeOrder.indexOf(id);
129
+ if (idx > -1) {
130
+ this.episodeOrder.splice(idx, 1);
131
+ this.episodeOrder.push(id);
132
+ }
133
+ }
134
+ return episode ?? null;
135
+ }
136
+ /**
137
+ * Search for similar episodes by state
138
+ *
139
+ * @param queryState - State vector to search for
140
+ * @param k - Number of results to return
141
+ * @returns Similar episodes sorted by similarity
142
+ */
143
+ async searchByState(queryState, k = 10) {
144
+ await this.initVectorDb();
145
+ const query = Array.isArray(queryState) ? queryState : Array.from(queryState);
146
+ // Use vector DB if available
147
+ if (this.vectorDb && query.length === this.dimensions) {
148
+ try {
149
+ const results = await this.vectorDb.search({
150
+ vector: new Float32Array(query),
151
+ k,
152
+ });
153
+ return results
154
+ .map((r) => {
155
+ const episode = this.episodes.get(r.id);
156
+ if (!episode)
157
+ return null;
158
+ return {
159
+ episode,
160
+ similarity: 1 - r.score, // Convert distance to similarity
161
+ };
162
+ })
163
+ .filter((r) => r !== null);
164
+ }
165
+ catch {
166
+ // Fall through to fallback
167
+ }
168
+ }
169
+ // Fallback: brute-force cosine similarity
170
+ return this.fallbackSearch(query, k);
171
+ }
172
+ /**
173
+ * Fallback similarity search using brute-force cosine similarity
174
+ */
175
+ fallbackSearch(query, k) {
176
+ const results = [];
177
+ for (const episode of this.episodes.values()) {
178
+ if (episode.state.length !== query.length)
179
+ continue;
180
+ const similarity = this.cosineSimilarity(query, episode.state);
181
+ results.push({ episode, similarity });
182
+ }
183
+ return results
184
+ .sort((a, b) => b.similarity - a.similarity)
185
+ .slice(0, k);
186
+ }
187
+ /**
188
+ * Compute cosine similarity between two vectors
189
+ */
190
+ cosineSimilarity(a, b) {
191
+ let dotProduct = 0;
192
+ let normA = 0;
193
+ let normB = 0;
194
+ for (let i = 0; i < a.length; i++) {
195
+ dotProduct += a[i] * b[i];
196
+ normA += a[i] * a[i];
197
+ normB += b[i] * b[i];
198
+ }
199
+ const denom = Math.sqrt(normA) * Math.sqrt(normB);
200
+ return denom === 0 ? 0 : dotProduct / denom;
201
+ }
202
+ /**
203
+ * Store a trajectory (sequence of episodes)
204
+ */
205
+ async storeTrajectory(episodes, metadata) {
206
+ const trajectoryId = this.generateId();
207
+ const storedEpisodes = [];
208
+ let totalReward = 0;
209
+ for (const episode of episodes) {
210
+ const id = await this.storeEpisode(episode);
211
+ const stored = await this.getEpisode(id);
212
+ if (stored) {
213
+ storedEpisodes.push(stored);
214
+ totalReward += stored.reward;
215
+ }
216
+ }
217
+ const trajectory = {
218
+ id: trajectoryId,
219
+ episodes: storedEpisodes,
220
+ totalReward,
221
+ metadata,
222
+ };
223
+ this.trajectories.set(trajectoryId, trajectory);
224
+ return trajectoryId;
225
+ }
226
+ /**
227
+ * Get a trajectory by ID
228
+ */
229
+ async getTrajectory(id) {
230
+ return this.trajectories.get(id) ?? null;
231
+ }
232
+ /**
233
+ * Get top trajectories by total reward
234
+ */
235
+ async getTopTrajectories(k = 10) {
236
+ return Array.from(this.trajectories.values())
237
+ .sort((a, b) => b.totalReward - a.totalReward)
238
+ .slice(0, k);
239
+ }
240
+ /**
241
+ * Sample random episodes (for experience replay)
242
+ */
243
+ async sampleEpisodes(n) {
244
+ const allEpisodes = Array.from(this.episodes.values());
245
+ const sampled = [];
246
+ for (let i = 0; i < Math.min(n, allEpisodes.length); i++) {
247
+ const idx = Math.floor(Math.random() * allEpisodes.length);
248
+ sampled.push(allEpisodes[idx]);
249
+ }
250
+ return sampled;
251
+ }
252
+ /**
253
+ * Get database statistics
254
+ */
255
+ getStats() {
256
+ return {
257
+ episodeCount: this.episodes.size,
258
+ trajectoryCount: this.trajectories.size,
259
+ dimensions: this.dimensions,
260
+ maxEpisodes: this.maxEpisodes,
261
+ vectorDbAvailable: this.vectorDb !== null,
262
+ };
263
+ }
264
+ /**
265
+ * Clear all data
266
+ */
267
+ clear() {
268
+ this.episodes.clear();
269
+ this.trajectories.clear();
270
+ this.episodeOrder = [];
271
+ }
272
+ /**
273
+ * Generate a unique ID
274
+ */
275
+ generateId() {
276
+ return `${Date.now()}-${Math.random().toString(36).substr(2, 9)}`;
277
+ }
278
+ }
279
+ exports.FastAgentDB = FastAgentDB;
280
+ /**
281
+ * Create a fast AgentDB instance
282
+ */
283
+ function createFastAgentDB(dimensions = 128, maxEpisodes = 100000) {
284
+ return new FastAgentDB(dimensions, maxEpisodes);
285
+ }
286
+ // Singleton instance for convenience
287
+ let defaultInstance = null;
288
+ /**
289
+ * Get the default FastAgentDB instance
290
+ */
291
+ function getDefaultAgentDB() {
292
+ if (!defaultInstance) {
293
+ defaultInstance = new FastAgentDB();
294
+ }
295
+ return defaultInstance;
296
+ }
297
+ exports.default = {
298
+ FastAgentDB,
299
+ createFastAgentDB,
300
+ getDefaultAgentDB,
301
+ };