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.
- package/.claude-flow/metrics/performance.json +3 -3
- package/.claude-flow/metrics/task-metrics.json +3 -3
- package/README.md +113 -0
- package/bin/cli.js +23 -13
- package/dist/core/agentdb-fast.d.ts +149 -0
- package/dist/core/agentdb-fast.d.ts.map +1 -0
- package/dist/core/agentdb-fast.js +301 -0
- package/dist/core/attention-fallbacks.d.ts +221 -0
- package/dist/core/attention-fallbacks.d.ts.map +1 -0
- package/dist/core/attention-fallbacks.js +361 -0
- package/dist/core/gnn-wrapper.d.ts +124 -0
- package/dist/core/gnn-wrapper.d.ts.map +1 -0
- package/dist/core/gnn-wrapper.js +192 -0
- package/dist/core/index.d.ts +15 -0
- package/dist/core/index.d.ts.map +1 -0
- package/dist/core/index.js +39 -0
- package/dist/core/sona-wrapper.d.ts +215 -0
- package/dist/core/sona-wrapper.d.ts.map +1 -0
- package/dist/core/sona-wrapper.js +258 -0
- package/dist/index.d.ts +5 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +6 -0
- package/dist/services/embedding-service.d.ts +136 -0
- package/dist/services/embedding-service.d.ts.map +1 -0
- package/dist/services/embedding-service.js +294 -0
- package/dist/services/index.d.ts +6 -0
- package/dist/services/index.d.ts.map +1 -0
- package/dist/services/index.js +26 -0
- package/package.json +10 -4
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
|
-
"startTime":
|
|
3
|
-
"sessionId": "session-
|
|
4
|
-
"lastActivity":
|
|
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-
|
|
3
|
+
"id": "cmd-hooks-1764779126675",
|
|
4
4
|
"type": "hooks",
|
|
5
5
|
"success": true,
|
|
6
|
-
"duration":
|
|
7
|
-
"timestamp":
|
|
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
|
|
360
|
-
|
|
361
|
-
console.log(chalk.white(`
|
|
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,
|
|
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
|
-
|
|
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.
|
|
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
|
|
1402
|
-
|
|
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
|
+
};
|