agentic-flow 2.0.1-alpha.2 → 2.0.1-alpha.20
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/CHANGELOG.md +352 -0
- package/dist/.tsbuildinfo +1 -1
- package/dist/agentdb/controllers/EmbeddingService.d.ts +37 -0
- package/dist/agentdb/controllers/EmbeddingService.d.ts.map +1 -0
- package/dist/agentdb/controllers/EmbeddingService.js +1 -0
- package/dist/agentdb/controllers/EmbeddingService.js.map +1 -0
- package/dist/billing/mcp/tools.d.ts.map +1 -1
- package/dist/billing/mcp/tools.js +2 -0
- package/dist/billing/mcp/tools.js.map +1 -1
- package/dist/cli/commands/hooks.d.ts +18 -0
- package/dist/cli/commands/hooks.d.ts.map +1 -0
- package/dist/cli/commands/hooks.js +755 -0
- package/dist/cli/commands/hooks.js.map +1 -0
- package/dist/cli-proxy.d.ts +1 -1
- package/dist/cli-proxy.d.ts.map +1 -1
- package/dist/cli-proxy.js +28 -1
- package/dist/cli-proxy.js.map +1 -1
- package/dist/core/agentdb-fast.js +3 -3
- package/dist/core/agentdb-fast.js.map +1 -1
- package/dist/core/agentdb-wrapper-enhanced.d.ts.map +1 -1
- package/dist/core/agentdb-wrapper-enhanced.js +32 -17
- package/dist/core/agentdb-wrapper-enhanced.js.map +1 -1
- package/dist/core/attention-native.d.ts +1 -0
- package/dist/core/attention-native.d.ts.map +1 -1
- package/dist/core/attention-native.js +6 -1
- package/dist/core/attention-native.js.map +1 -1
- package/dist/federation/integrations/supabase-adapter-debug.js +3 -3
- package/dist/federation/integrations/supabase-adapter-debug.js.map +1 -1
- package/dist/intelligence/EmbeddingCache.d.ts +112 -0
- package/dist/intelligence/EmbeddingCache.d.ts.map +1 -0
- package/dist/intelligence/EmbeddingCache.js +624 -0
- package/dist/intelligence/EmbeddingCache.js.map +1 -0
- package/dist/intelligence/EmbeddingService.d.ts +380 -0
- package/dist/intelligence/EmbeddingService.d.ts.map +1 -0
- package/dist/intelligence/EmbeddingService.js +1484 -0
- package/dist/intelligence/EmbeddingService.js.map +1 -0
- package/dist/intelligence/IntelligenceStore.d.ts +168 -0
- package/dist/intelligence/IntelligenceStore.d.ts.map +1 -0
- package/dist/intelligence/IntelligenceStore.js +364 -0
- package/dist/intelligence/IntelligenceStore.js.map +1 -0
- package/dist/intelligence/RuVectorIntelligence.d.ts +362 -0
- package/dist/intelligence/RuVectorIntelligence.d.ts.map +1 -0
- package/dist/intelligence/RuVectorIntelligence.js +853 -0
- package/dist/intelligence/RuVectorIntelligence.js.map +1 -0
- package/dist/intelligence/embedding-benchmark.d.ts +7 -0
- package/dist/intelligence/embedding-benchmark.d.ts.map +1 -0
- package/dist/intelligence/embedding-benchmark.js +155 -0
- package/dist/intelligence/embedding-benchmark.js.map +1 -0
- package/dist/intelligence/index.d.ts +14 -0
- package/dist/intelligence/index.d.ts.map +1 -0
- package/dist/intelligence/index.js +14 -0
- package/dist/intelligence/index.js.map +1 -0
- package/dist/llm/RuvLLMOrchestrator.d.ts +184 -0
- package/dist/llm/RuvLLMOrchestrator.d.ts.map +1 -0
- package/dist/llm/RuvLLMOrchestrator.js +442 -0
- package/dist/llm/RuvLLMOrchestrator.js.map +1 -0
- package/dist/llm/index.d.ts +9 -0
- package/dist/llm/index.d.ts.map +1 -0
- package/dist/llm/index.js +8 -0
- package/dist/llm/index.js.map +1 -0
- package/dist/mcp/claudeFlowSdkServer.d.ts.map +1 -1
- package/dist/mcp/claudeFlowSdkServer.js +86 -21
- package/dist/mcp/claudeFlowSdkServer.js.map +1 -1
- package/dist/mcp/fastmcp/servers/hooks-server.d.ts +15 -0
- package/dist/mcp/fastmcp/servers/hooks-server.d.ts.map +1 -0
- package/dist/mcp/fastmcp/servers/hooks-server.js +63 -0
- package/dist/mcp/fastmcp/servers/hooks-server.js.map +1 -0
- package/dist/mcp/fastmcp/tools/hooks/benchmark.d.ts +20 -0
- package/dist/mcp/fastmcp/tools/hooks/benchmark.d.ts.map +1 -0
- package/dist/mcp/fastmcp/tools/hooks/benchmark.js +110 -0
- package/dist/mcp/fastmcp/tools/hooks/benchmark.js.map +1 -0
- package/dist/mcp/fastmcp/tools/hooks/build-agents.d.ts +7 -0
- package/dist/mcp/fastmcp/tools/hooks/build-agents.d.ts.map +1 -0
- package/dist/mcp/fastmcp/tools/hooks/build-agents.js +276 -0
- package/dist/mcp/fastmcp/tools/hooks/build-agents.js.map +1 -0
- package/dist/mcp/fastmcp/tools/hooks/explain.d.ts +6 -0
- package/dist/mcp/fastmcp/tools/hooks/explain.d.ts.map +1 -0
- package/dist/mcp/fastmcp/tools/hooks/explain.js +164 -0
- package/dist/mcp/fastmcp/tools/hooks/explain.js.map +1 -0
- package/dist/mcp/fastmcp/tools/hooks/index.d.ts +28 -0
- package/dist/mcp/fastmcp/tools/hooks/index.d.ts.map +1 -0
- package/dist/mcp/fastmcp/tools/hooks/index.js +59 -0
- package/dist/mcp/fastmcp/tools/hooks/index.js.map +1 -0
- package/dist/mcp/fastmcp/tools/hooks/intelligence-bridge.d.ts +307 -0
- package/dist/mcp/fastmcp/tools/hooks/intelligence-bridge.d.ts.map +1 -0
- package/dist/mcp/fastmcp/tools/hooks/intelligence-bridge.js +714 -0
- package/dist/mcp/fastmcp/tools/hooks/intelligence-bridge.js.map +1 -0
- package/dist/mcp/fastmcp/tools/hooks/intelligence-tools.d.ts +58 -0
- package/dist/mcp/fastmcp/tools/hooks/intelligence-tools.d.ts.map +1 -0
- package/dist/mcp/fastmcp/tools/hooks/intelligence-tools.js +425 -0
- package/dist/mcp/fastmcp/tools/hooks/intelligence-tools.js.map +1 -0
- package/dist/mcp/fastmcp/tools/hooks/metrics.d.ts +6 -0
- package/dist/mcp/fastmcp/tools/hooks/metrics.d.ts.map +1 -0
- package/dist/mcp/fastmcp/tools/hooks/metrics.js +137 -0
- package/dist/mcp/fastmcp/tools/hooks/metrics.js.map +1 -0
- package/dist/mcp/fastmcp/tools/hooks/post-command.d.ts +7 -0
- package/dist/mcp/fastmcp/tools/hooks/post-command.d.ts.map +1 -0
- package/dist/mcp/fastmcp/tools/hooks/post-command.js +91 -0
- package/dist/mcp/fastmcp/tools/hooks/post-command.js.map +1 -0
- package/dist/mcp/fastmcp/tools/hooks/post-edit.d.ts +12 -0
- package/dist/mcp/fastmcp/tools/hooks/post-edit.d.ts.map +1 -0
- package/dist/mcp/fastmcp/tools/hooks/post-edit.js +146 -0
- package/dist/mcp/fastmcp/tools/hooks/post-edit.js.map +1 -0
- package/dist/mcp/fastmcp/tools/hooks/pre-command.d.ts +7 -0
- package/dist/mcp/fastmcp/tools/hooks/pre-command.d.ts.map +1 -0
- package/dist/mcp/fastmcp/tools/hooks/pre-command.js +70 -0
- package/dist/mcp/fastmcp/tools/hooks/pre-command.js.map +1 -0
- package/dist/mcp/fastmcp/tools/hooks/pre-edit.d.ts +14 -0
- package/dist/mcp/fastmcp/tools/hooks/pre-edit.d.ts.map +1 -0
- package/dist/mcp/fastmcp/tools/hooks/pre-edit.js +121 -0
- package/dist/mcp/fastmcp/tools/hooks/pre-edit.js.map +1 -0
- package/dist/mcp/fastmcp/tools/hooks/pretrain.d.ts +7 -0
- package/dist/mcp/fastmcp/tools/hooks/pretrain.d.ts.map +1 -0
- package/dist/mcp/fastmcp/tools/hooks/pretrain.js +171 -0
- package/dist/mcp/fastmcp/tools/hooks/pretrain.js.map +1 -0
- package/dist/mcp/fastmcp/tools/hooks/route.d.ts +12 -0
- package/dist/mcp/fastmcp/tools/hooks/route.d.ts.map +1 -0
- package/dist/mcp/fastmcp/tools/hooks/route.js +267 -0
- package/dist/mcp/fastmcp/tools/hooks/route.js.map +1 -0
- package/dist/mcp/fastmcp/tools/hooks/shared.d.ts +46 -0
- package/dist/mcp/fastmcp/tools/hooks/shared.d.ts.map +1 -0
- package/dist/mcp/fastmcp/tools/hooks/shared.js +159 -0
- package/dist/mcp/fastmcp/tools/hooks/shared.js.map +1 -0
- package/dist/mcp/fastmcp/tools/hooks/transfer.d.ts +7 -0
- package/dist/mcp/fastmcp/tools/hooks/transfer.d.ts.map +1 -0
- package/dist/mcp/fastmcp/tools/hooks/transfer.js +151 -0
- package/dist/mcp/fastmcp/tools/hooks/transfer.js.map +1 -0
- package/dist/mcp/tools/agent-booster-tools.d.ts +10 -1
- package/dist/mcp/tools/agent-booster-tools.d.ts.map +1 -1
- package/dist/mcp/tools/agent-booster-tools.js.map +1 -1
- package/dist/mcp/tools/sona-tools.d.ts.map +1 -1
- package/dist/mcp/tools/sona-tools.js +15 -3
- package/dist/mcp/tools/sona-tools.js.map +1 -1
- package/dist/memory/SharedMemoryPool.d.ts +16 -3
- package/dist/memory/SharedMemoryPool.d.ts.map +1 -1
- package/dist/memory/SharedMemoryPool.js +33 -1
- package/dist/memory/SharedMemoryPool.js.map +1 -1
- package/dist/middleware/auth.middleware.d.ts +114 -0
- package/dist/middleware/auth.middleware.d.ts.map +1 -0
- package/dist/middleware/auth.middleware.js +222 -0
- package/dist/middleware/auth.middleware.js.map +1 -0
- package/dist/optimizations/agent-booster-migration.d.ts.map +1 -1
- package/dist/optimizations/agent-booster-migration.js.map +1 -1
- package/dist/proxy/anthropic-to-gemini.d.ts.map +1 -1
- package/dist/proxy/anthropic-to-gemini.js.map +1 -1
- package/dist/proxy/anthropic-to-openrouter.d.ts.map +1 -1
- package/dist/proxy/anthropic-to-openrouter.js.map +1 -1
- package/dist/proxy/anthropic-to-requesty.d.ts.map +1 -1
- package/dist/proxy/anthropic-to-requesty.js.map +1 -1
- package/dist/proxy/quic-proxy.d.ts +0 -1
- package/dist/proxy/quic-proxy.d.ts.map +1 -1
- package/dist/proxy/quic-proxy.js +2 -1
- package/dist/proxy/quic-proxy.js.map +1 -1
- package/dist/reasoningbank/AdvancedMemory.d.ts.map +1 -1
- package/dist/reasoningbank/AdvancedMemory.js +12 -1
- package/dist/reasoningbank/AdvancedMemory.js.map +1 -1
- package/dist/reasoningbank/HybridBackend.d.ts +9 -0
- package/dist/reasoningbank/HybridBackend.d.ts.map +1 -1
- package/dist/reasoningbank/HybridBackend.js +48 -4
- package/dist/reasoningbank/HybridBackend.js.map +1 -1
- package/dist/reasoningbank/backend-selector.d.ts +1 -1
- package/dist/reasoningbank/backend-selector.d.ts.map +1 -1
- package/dist/reasoningbank/backend-selector.js.map +1 -1
- package/dist/reasoningbank/index-new.d.ts +0 -6
- package/dist/reasoningbank/index-new.d.ts.map +1 -1
- package/dist/reasoningbank/index-new.js +9 -7
- package/dist/reasoningbank/index-new.js.map +1 -1
- package/dist/reasoningbank/index.d.ts +1 -6
- package/dist/reasoningbank/index.d.ts.map +1 -1
- package/dist/reasoningbank/index.js +10 -7
- package/dist/reasoningbank/index.js.map +1 -1
- package/dist/router/providers/onnx-local.d.ts.map +1 -1
- package/dist/router/providers/onnx-local.js +3 -1
- package/dist/router/providers/onnx-local.js.map +1 -1
- package/dist/routing/CircuitBreakerRouter.d.ts +187 -0
- package/dist/routing/CircuitBreakerRouter.d.ts.map +1 -0
- package/dist/routing/CircuitBreakerRouter.js +460 -0
- package/dist/routing/CircuitBreakerRouter.js.map +1 -0
- package/dist/routing/SemanticRouter.d.ts +164 -0
- package/dist/routing/SemanticRouter.d.ts.map +1 -0
- package/dist/routing/SemanticRouter.js +291 -0
- package/dist/routing/SemanticRouter.js.map +1 -0
- package/dist/routing/index.d.ts +12 -0
- package/dist/routing/index.d.ts.map +1 -0
- package/dist/routing/index.js +10 -0
- package/dist/routing/index.js.map +1 -0
- package/dist/services/embedding-service.d.ts.map +1 -1
- package/dist/services/embedding-service.js +5 -2
- package/dist/services/embedding-service.js.map +1 -1
- package/dist/services/sona-agent-training.js +1 -1
- package/dist/services/sona-agent-training.js.map +1 -1
- package/dist/services/sona-agentdb-integration.d.ts.map +1 -1
- package/dist/services/sona-agentdb-integration.js +10 -5
- package/dist/services/sona-agentdb-integration.js.map +1 -1
- package/dist/services/sona-service.d.ts +6 -6
- package/dist/services/sona-service.d.ts.map +1 -1
- package/dist/services/sona-service.js +3 -1
- package/dist/services/sona-service.js.map +1 -1
- package/dist/utils/agentdb-runtime-patch.d.ts +1 -0
- package/dist/utils/agentdb-runtime-patch.d.ts.map +1 -1
- package/dist/utils/agentdb-runtime-patch.js +97 -2
- package/dist/utils/agentdb-runtime-patch.js.map +1 -1
- package/dist/utils/audit-logger.d.ts +115 -0
- package/dist/utils/audit-logger.d.ts.map +1 -0
- package/dist/utils/audit-logger.js +228 -0
- package/dist/utils/audit-logger.js.map +1 -0
- package/dist/utils/cli.d.ts +1 -1
- package/dist/utils/cli.d.ts.map +1 -1
- package/dist/utils/cli.js +5 -0
- package/dist/utils/cli.js.map +1 -1
- package/dist/utils/input-validator.d.ts +116 -0
- package/dist/utils/input-validator.d.ts.map +1 -0
- package/dist/utils/input-validator.js +299 -0
- package/dist/utils/input-validator.js.map +1 -0
- package/dist/utils/rate-limiter.js +2 -2
- package/dist/utils/rate-limiter.js.map +1 -1
- package/package.json +14 -3
- package/scripts/postinstall.js +72 -0
|
@@ -0,0 +1,624 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* EmbeddingCache - Persistent cache for embeddings
|
|
3
|
+
*
|
|
4
|
+
* Makes ONNX embeddings practical by caching across sessions:
|
|
5
|
+
* - First embed: ~400ms (ONNX inference)
|
|
6
|
+
* - Cached embed: ~0.1ms (SQLite lookup) or ~0.01ms (in-memory fallback)
|
|
7
|
+
*
|
|
8
|
+
* Storage: ~/.agentic-flow/embedding-cache.db (if SQLite available)
|
|
9
|
+
*
|
|
10
|
+
* Windows Compatibility:
|
|
11
|
+
* - Falls back to in-memory cache if better-sqlite3 compilation fails
|
|
12
|
+
* - No native module compilation required for basic functionality
|
|
13
|
+
*/
|
|
14
|
+
import { existsSync, mkdirSync, statSync, readFileSync, writeFileSync } from 'fs';
|
|
15
|
+
import { join } from 'path';
|
|
16
|
+
import { homedir } from 'os';
|
|
17
|
+
import { createHash } from 'crypto';
|
|
18
|
+
// Default config
|
|
19
|
+
const DEFAULT_CONFIG = {
|
|
20
|
+
maxEntries: 10000,
|
|
21
|
+
maxAgeDays: 30,
|
|
22
|
+
dbPath: join(homedir(), '.agentic-flow', 'embedding-cache.db'),
|
|
23
|
+
dimension: 384,
|
|
24
|
+
forceMemory: false,
|
|
25
|
+
};
|
|
26
|
+
// Check if better-sqlite3 is available (native, fastest)
|
|
27
|
+
let BetterSqlite3 = null;
|
|
28
|
+
let nativeSqliteAvailable = false;
|
|
29
|
+
// Check if sql.js is available (WASM, cross-platform)
|
|
30
|
+
let SqlJs = null;
|
|
31
|
+
let wasmSqliteAvailable = false;
|
|
32
|
+
try {
|
|
33
|
+
// Try native SQLite first (fastest)
|
|
34
|
+
BetterSqlite3 = require('better-sqlite3');
|
|
35
|
+
nativeSqliteAvailable = true;
|
|
36
|
+
}
|
|
37
|
+
catch {
|
|
38
|
+
// Native not available, try WASM fallback
|
|
39
|
+
try {
|
|
40
|
+
SqlJs = require('sql.js');
|
|
41
|
+
wasmSqliteAvailable = true;
|
|
42
|
+
}
|
|
43
|
+
catch {
|
|
44
|
+
// Neither available, will use memory cache
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
const sqliteAvailable = nativeSqliteAvailable || wasmSqliteAvailable;
|
|
48
|
+
/**
|
|
49
|
+
* In-memory cache fallback for Windows compatibility
|
|
50
|
+
*/
|
|
51
|
+
class MemoryCache {
|
|
52
|
+
cache = new Map();
|
|
53
|
+
maxEntries;
|
|
54
|
+
hits = 0;
|
|
55
|
+
misses = 0;
|
|
56
|
+
constructor(maxEntries = 10000) {
|
|
57
|
+
this.maxEntries = maxEntries;
|
|
58
|
+
}
|
|
59
|
+
get(hash) {
|
|
60
|
+
const entry = this.cache.get(hash);
|
|
61
|
+
if (entry) {
|
|
62
|
+
entry.hits++;
|
|
63
|
+
entry.accessed = Date.now();
|
|
64
|
+
this.hits++;
|
|
65
|
+
return { embedding: entry.embedding, dimension: entry.embedding.length };
|
|
66
|
+
}
|
|
67
|
+
this.misses++;
|
|
68
|
+
return null;
|
|
69
|
+
}
|
|
70
|
+
set(hash, text, embedding, model) {
|
|
71
|
+
const now = Date.now();
|
|
72
|
+
this.cache.set(hash, {
|
|
73
|
+
embedding,
|
|
74
|
+
model,
|
|
75
|
+
hits: 1,
|
|
76
|
+
created: now,
|
|
77
|
+
accessed: now,
|
|
78
|
+
});
|
|
79
|
+
// Evict if over limit
|
|
80
|
+
if (this.cache.size > this.maxEntries) {
|
|
81
|
+
this.evictLRU(Math.ceil(this.maxEntries * 0.1));
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
has(hash) {
|
|
85
|
+
return this.cache.has(hash);
|
|
86
|
+
}
|
|
87
|
+
evictLRU(count) {
|
|
88
|
+
const entries = Array.from(this.cache.entries())
|
|
89
|
+
.sort((a, b) => a[1].accessed - b[1].accessed)
|
|
90
|
+
.slice(0, count);
|
|
91
|
+
for (const [key] of entries) {
|
|
92
|
+
this.cache.delete(key);
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
clear() {
|
|
96
|
+
this.cache.clear();
|
|
97
|
+
this.hits = 0;
|
|
98
|
+
this.misses = 0;
|
|
99
|
+
}
|
|
100
|
+
getStats() {
|
|
101
|
+
const entries = Array.from(this.cache.values());
|
|
102
|
+
const oldest = entries.length > 0 ? Math.min(...entries.map(e => e.created)) : 0;
|
|
103
|
+
const newest = entries.length > 0 ? Math.max(...entries.map(e => e.created)) : 0;
|
|
104
|
+
return {
|
|
105
|
+
totalEntries: this.cache.size,
|
|
106
|
+
hits: this.hits,
|
|
107
|
+
misses: this.misses,
|
|
108
|
+
hitRate: this.hits + this.misses > 0 ? this.hits / (this.hits + this.misses) : 0,
|
|
109
|
+
dbSizeBytes: this.cache.size * 384 * 4, // Approximate
|
|
110
|
+
oldestEntry: oldest,
|
|
111
|
+
newestEntry: newest,
|
|
112
|
+
backend: 'memory',
|
|
113
|
+
};
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
/**
|
|
117
|
+
* WASM SQLite cache (sql.js) - Cross-platform with persistence
|
|
118
|
+
* Works on Windows without native compilation
|
|
119
|
+
*/
|
|
120
|
+
class WasmSqliteCache {
|
|
121
|
+
db = null;
|
|
122
|
+
config;
|
|
123
|
+
hits = 0;
|
|
124
|
+
misses = 0;
|
|
125
|
+
dirty = false;
|
|
126
|
+
saveTimeout = null;
|
|
127
|
+
constructor(config) {
|
|
128
|
+
this.config = config;
|
|
129
|
+
}
|
|
130
|
+
async init() {
|
|
131
|
+
if (this.db)
|
|
132
|
+
return;
|
|
133
|
+
// Ensure directory exists
|
|
134
|
+
const dir = join(homedir(), '.agentic-flow');
|
|
135
|
+
if (!existsSync(dir)) {
|
|
136
|
+
mkdirSync(dir, { recursive: true });
|
|
137
|
+
}
|
|
138
|
+
// Initialize sql.js
|
|
139
|
+
const SQL = await SqlJs();
|
|
140
|
+
// Load existing database or create new
|
|
141
|
+
const dbPath = this.config.dbPath.replace('.db', '-wasm.db');
|
|
142
|
+
try {
|
|
143
|
+
if (existsSync(dbPath)) {
|
|
144
|
+
const buffer = readFileSync(dbPath);
|
|
145
|
+
this.db = new SQL.Database(buffer);
|
|
146
|
+
}
|
|
147
|
+
else {
|
|
148
|
+
this.db = new SQL.Database();
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
catch {
|
|
152
|
+
this.db = new SQL.Database();
|
|
153
|
+
}
|
|
154
|
+
this.initSchema();
|
|
155
|
+
this.cleanupOldEntries();
|
|
156
|
+
}
|
|
157
|
+
initSchema() {
|
|
158
|
+
this.db.run(`
|
|
159
|
+
CREATE TABLE IF NOT EXISTS embeddings (
|
|
160
|
+
hash TEXT PRIMARY KEY,
|
|
161
|
+
text TEXT NOT NULL,
|
|
162
|
+
embedding BLOB NOT NULL,
|
|
163
|
+
dimension INTEGER NOT NULL,
|
|
164
|
+
model TEXT NOT NULL,
|
|
165
|
+
hits INTEGER DEFAULT 1,
|
|
166
|
+
created_at INTEGER NOT NULL,
|
|
167
|
+
last_accessed INTEGER NOT NULL
|
|
168
|
+
)
|
|
169
|
+
`);
|
|
170
|
+
this.db.run(`CREATE INDEX IF NOT EXISTS idx_last_accessed ON embeddings(last_accessed)`);
|
|
171
|
+
this.db.run(`CREATE INDEX IF NOT EXISTS idx_created_at ON embeddings(created_at)`);
|
|
172
|
+
}
|
|
173
|
+
save() {
|
|
174
|
+
// Debounce saves
|
|
175
|
+
if (this.saveTimeout)
|
|
176
|
+
return;
|
|
177
|
+
this.saveTimeout = setTimeout(() => {
|
|
178
|
+
try {
|
|
179
|
+
const data = this.db.export();
|
|
180
|
+
const buffer = Buffer.from(data);
|
|
181
|
+
const dbPath = this.config.dbPath.replace('.db', '-wasm.db');
|
|
182
|
+
writeFileSync(dbPath, buffer);
|
|
183
|
+
this.dirty = false;
|
|
184
|
+
}
|
|
185
|
+
catch (err) {
|
|
186
|
+
console.warn('[WasmSqliteCache] Save failed:', err);
|
|
187
|
+
}
|
|
188
|
+
this.saveTimeout = null;
|
|
189
|
+
}, 1000);
|
|
190
|
+
}
|
|
191
|
+
get(hash) {
|
|
192
|
+
if (!this.db)
|
|
193
|
+
return null;
|
|
194
|
+
const stmt = this.db.prepare(`SELECT embedding, dimension FROM embeddings WHERE hash = ?`);
|
|
195
|
+
stmt.bind([hash]);
|
|
196
|
+
if (stmt.step()) {
|
|
197
|
+
const row = stmt.getAsObject();
|
|
198
|
+
stmt.free();
|
|
199
|
+
this.hits++;
|
|
200
|
+
this.db.run(`UPDATE embeddings SET hits = hits + 1, last_accessed = ? WHERE hash = ?`, [Date.now(), hash]);
|
|
201
|
+
this.dirty = true;
|
|
202
|
+
this.save();
|
|
203
|
+
// Convert Uint8Array to Float32Array
|
|
204
|
+
const uint8 = row.embedding;
|
|
205
|
+
const float32 = new Float32Array(uint8.buffer, uint8.byteOffset, row.dimension);
|
|
206
|
+
return { embedding: float32, dimension: row.dimension };
|
|
207
|
+
}
|
|
208
|
+
stmt.free();
|
|
209
|
+
this.misses++;
|
|
210
|
+
return null;
|
|
211
|
+
}
|
|
212
|
+
set(hash, text, embedding, model) {
|
|
213
|
+
if (!this.db)
|
|
214
|
+
return;
|
|
215
|
+
const now = Date.now();
|
|
216
|
+
const buffer = new Uint8Array(embedding.buffer, embedding.byteOffset, embedding.byteLength);
|
|
217
|
+
this.db.run(`INSERT OR REPLACE INTO embeddings (hash, text, embedding, dimension, model, hits, created_at, last_accessed)
|
|
218
|
+
VALUES (?, ?, ?, ?, ?, 1, ?, ?)`, [hash, text, buffer, embedding.length, model, now, now]);
|
|
219
|
+
this.dirty = true;
|
|
220
|
+
this.maybeEvict();
|
|
221
|
+
this.save();
|
|
222
|
+
}
|
|
223
|
+
has(hash) {
|
|
224
|
+
if (!this.db)
|
|
225
|
+
return false;
|
|
226
|
+
const stmt = this.db.prepare(`SELECT 1 FROM embeddings WHERE hash = ? LIMIT 1`);
|
|
227
|
+
stmt.bind([hash]);
|
|
228
|
+
const found = stmt.step();
|
|
229
|
+
stmt.free();
|
|
230
|
+
return found;
|
|
231
|
+
}
|
|
232
|
+
maybeEvict() {
|
|
233
|
+
const countStmt = this.db.prepare(`SELECT COUNT(*) as count FROM embeddings`);
|
|
234
|
+
countStmt.step();
|
|
235
|
+
const count = countStmt.getAsObject().count;
|
|
236
|
+
countStmt.free();
|
|
237
|
+
if (count > this.config.maxEntries) {
|
|
238
|
+
const toEvict = Math.ceil(this.config.maxEntries * 0.1);
|
|
239
|
+
this.db.run(`DELETE FROM embeddings WHERE hash IN (
|
|
240
|
+
SELECT hash FROM embeddings ORDER BY last_accessed ASC LIMIT ?
|
|
241
|
+
)`, [toEvict]);
|
|
242
|
+
}
|
|
243
|
+
}
|
|
244
|
+
cleanupOldEntries() {
|
|
245
|
+
const cutoff = Date.now() - (this.config.maxAgeDays * 24 * 60 * 60 * 1000);
|
|
246
|
+
this.db.run(`DELETE FROM embeddings WHERE created_at < ?`, [cutoff]);
|
|
247
|
+
}
|
|
248
|
+
clear() {
|
|
249
|
+
if (this.db) {
|
|
250
|
+
this.db.run('DELETE FROM embeddings');
|
|
251
|
+
this.hits = 0;
|
|
252
|
+
this.misses = 0;
|
|
253
|
+
this.save();
|
|
254
|
+
}
|
|
255
|
+
}
|
|
256
|
+
close() {
|
|
257
|
+
if (this.saveTimeout) {
|
|
258
|
+
clearTimeout(this.saveTimeout);
|
|
259
|
+
// Force save
|
|
260
|
+
try {
|
|
261
|
+
const data = this.db.export();
|
|
262
|
+
const buffer = Buffer.from(data);
|
|
263
|
+
const dbPath = this.config.dbPath.replace('.db', '-wasm.db');
|
|
264
|
+
writeFileSync(dbPath, buffer);
|
|
265
|
+
}
|
|
266
|
+
catch { }
|
|
267
|
+
}
|
|
268
|
+
if (this.db) {
|
|
269
|
+
this.db.close();
|
|
270
|
+
this.db = null;
|
|
271
|
+
}
|
|
272
|
+
}
|
|
273
|
+
getStats() {
|
|
274
|
+
if (!this.db) {
|
|
275
|
+
return {
|
|
276
|
+
totalEntries: 0,
|
|
277
|
+
hits: this.hits,
|
|
278
|
+
misses: this.misses,
|
|
279
|
+
hitRate: 0,
|
|
280
|
+
dbSizeBytes: 0,
|
|
281
|
+
oldestEntry: 0,
|
|
282
|
+
newestEntry: 0,
|
|
283
|
+
backend: 'memory',
|
|
284
|
+
};
|
|
285
|
+
}
|
|
286
|
+
const countStmt = this.db.prepare(`SELECT COUNT(*) as count FROM embeddings`);
|
|
287
|
+
countStmt.step();
|
|
288
|
+
const count = countStmt.getAsObject().count;
|
|
289
|
+
countStmt.free();
|
|
290
|
+
const oldestStmt = this.db.prepare(`SELECT MIN(created_at) as oldest FROM embeddings`);
|
|
291
|
+
oldestStmt.step();
|
|
292
|
+
const oldest = oldestStmt.getAsObject().oldest || 0;
|
|
293
|
+
oldestStmt.free();
|
|
294
|
+
const newestStmt = this.db.prepare(`SELECT MAX(created_at) as newest FROM embeddings`);
|
|
295
|
+
newestStmt.step();
|
|
296
|
+
const newest = newestStmt.getAsObject().newest || 0;
|
|
297
|
+
newestStmt.free();
|
|
298
|
+
let dbSizeBytes = 0;
|
|
299
|
+
try {
|
|
300
|
+
const dbPath = this.config.dbPath.replace('.db', '-wasm.db');
|
|
301
|
+
const stats = statSync(dbPath);
|
|
302
|
+
dbSizeBytes = stats.size;
|
|
303
|
+
}
|
|
304
|
+
catch { }
|
|
305
|
+
return {
|
|
306
|
+
totalEntries: count,
|
|
307
|
+
hits: this.hits,
|
|
308
|
+
misses: this.misses,
|
|
309
|
+
hitRate: this.hits + this.misses > 0 ? this.hits / (this.hits + this.misses) : 0,
|
|
310
|
+
dbSizeBytes,
|
|
311
|
+
oldestEntry: oldest,
|
|
312
|
+
newestEntry: newest,
|
|
313
|
+
backend: 'file',
|
|
314
|
+
};
|
|
315
|
+
}
|
|
316
|
+
}
|
|
317
|
+
/**
|
|
318
|
+
* Native SQLite cache (better-sqlite3) - Fastest option
|
|
319
|
+
*/
|
|
320
|
+
class SqliteCache {
|
|
321
|
+
db;
|
|
322
|
+
config;
|
|
323
|
+
hits = 0;
|
|
324
|
+
misses = 0;
|
|
325
|
+
// Prepared statements for performance
|
|
326
|
+
stmtGet;
|
|
327
|
+
stmtInsert;
|
|
328
|
+
stmtUpdateHits;
|
|
329
|
+
stmtCount;
|
|
330
|
+
stmtEvictOld;
|
|
331
|
+
stmtEvictLRU;
|
|
332
|
+
stmtHas;
|
|
333
|
+
constructor(config) {
|
|
334
|
+
this.config = config;
|
|
335
|
+
// Ensure directory exists
|
|
336
|
+
const dir = join(homedir(), '.agentic-flow');
|
|
337
|
+
if (!existsSync(dir)) {
|
|
338
|
+
mkdirSync(dir, { recursive: true });
|
|
339
|
+
}
|
|
340
|
+
// Open database with WAL mode for better concurrency
|
|
341
|
+
this.db = new BetterSqlite3(this.config.dbPath);
|
|
342
|
+
this.db.pragma('journal_mode = WAL');
|
|
343
|
+
this.db.pragma('synchronous = NORMAL');
|
|
344
|
+
this.db.pragma('cache_size = 10000');
|
|
345
|
+
this.initSchema();
|
|
346
|
+
this.prepareStatements();
|
|
347
|
+
this.cleanupOldEntries();
|
|
348
|
+
}
|
|
349
|
+
initSchema() {
|
|
350
|
+
this.db.exec(`
|
|
351
|
+
CREATE TABLE IF NOT EXISTS embeddings (
|
|
352
|
+
hash TEXT PRIMARY KEY,
|
|
353
|
+
text TEXT NOT NULL,
|
|
354
|
+
embedding BLOB NOT NULL,
|
|
355
|
+
dimension INTEGER NOT NULL,
|
|
356
|
+
model TEXT NOT NULL,
|
|
357
|
+
hits INTEGER DEFAULT 1,
|
|
358
|
+
created_at INTEGER NOT NULL,
|
|
359
|
+
last_accessed INTEGER NOT NULL
|
|
360
|
+
);
|
|
361
|
+
|
|
362
|
+
CREATE INDEX IF NOT EXISTS idx_last_accessed ON embeddings(last_accessed);
|
|
363
|
+
CREATE INDEX IF NOT EXISTS idx_created_at ON embeddings(created_at);
|
|
364
|
+
CREATE INDEX IF NOT EXISTS idx_model ON embeddings(model);
|
|
365
|
+
`);
|
|
366
|
+
}
|
|
367
|
+
prepareStatements() {
|
|
368
|
+
this.stmtGet = this.db.prepare(`
|
|
369
|
+
SELECT embedding, dimension FROM embeddings WHERE hash = ?
|
|
370
|
+
`);
|
|
371
|
+
this.stmtInsert = this.db.prepare(`
|
|
372
|
+
INSERT OR REPLACE INTO embeddings (hash, text, embedding, dimension, model, hits, created_at, last_accessed)
|
|
373
|
+
VALUES (?, ?, ?, ?, ?, 1, ?, ?)
|
|
374
|
+
`);
|
|
375
|
+
this.stmtUpdateHits = this.db.prepare(`
|
|
376
|
+
UPDATE embeddings SET hits = hits + 1, last_accessed = ? WHERE hash = ?
|
|
377
|
+
`);
|
|
378
|
+
this.stmtCount = this.db.prepare(`SELECT COUNT(*) as count FROM embeddings`);
|
|
379
|
+
this.stmtEvictOld = this.db.prepare(`
|
|
380
|
+
DELETE FROM embeddings WHERE created_at < ?
|
|
381
|
+
`);
|
|
382
|
+
this.stmtEvictLRU = this.db.prepare(`
|
|
383
|
+
DELETE FROM embeddings WHERE hash IN (
|
|
384
|
+
SELECT hash FROM embeddings ORDER BY last_accessed ASC LIMIT ?
|
|
385
|
+
)
|
|
386
|
+
`);
|
|
387
|
+
this.stmtHas = this.db.prepare(`SELECT 1 FROM embeddings WHERE hash = ? LIMIT 1`);
|
|
388
|
+
}
|
|
389
|
+
get(hash) {
|
|
390
|
+
const row = this.stmtGet.get(hash);
|
|
391
|
+
if (row) {
|
|
392
|
+
this.hits++;
|
|
393
|
+
this.stmtUpdateHits.run(Date.now(), hash);
|
|
394
|
+
return {
|
|
395
|
+
embedding: new Float32Array(row.embedding.buffer, row.embedding.byteOffset, row.dimension),
|
|
396
|
+
dimension: row.dimension,
|
|
397
|
+
};
|
|
398
|
+
}
|
|
399
|
+
this.misses++;
|
|
400
|
+
return null;
|
|
401
|
+
}
|
|
402
|
+
set(hash, text, embedding, model) {
|
|
403
|
+
const now = Date.now();
|
|
404
|
+
const buffer = Buffer.from(embedding.buffer, embedding.byteOffset, embedding.byteLength);
|
|
405
|
+
this.stmtInsert.run(hash, text, buffer, embedding.length, model, now, now);
|
|
406
|
+
this.maybeEvict();
|
|
407
|
+
}
|
|
408
|
+
has(hash) {
|
|
409
|
+
return this.stmtHas.get(hash) !== undefined;
|
|
410
|
+
}
|
|
411
|
+
maybeEvict() {
|
|
412
|
+
const count = this.stmtCount.get().count;
|
|
413
|
+
if (count > this.config.maxEntries) {
|
|
414
|
+
const toEvict = Math.ceil(this.config.maxEntries * 0.1);
|
|
415
|
+
this.stmtEvictLRU.run(toEvict);
|
|
416
|
+
}
|
|
417
|
+
}
|
|
418
|
+
cleanupOldEntries() {
|
|
419
|
+
const cutoff = Date.now() - (this.config.maxAgeDays * 24 * 60 * 60 * 1000);
|
|
420
|
+
this.stmtEvictOld.run(cutoff);
|
|
421
|
+
}
|
|
422
|
+
clear() {
|
|
423
|
+
this.db.exec('DELETE FROM embeddings');
|
|
424
|
+
this.hits = 0;
|
|
425
|
+
this.misses = 0;
|
|
426
|
+
}
|
|
427
|
+
vacuum() {
|
|
428
|
+
this.db.exec('VACUUM');
|
|
429
|
+
}
|
|
430
|
+
close() {
|
|
431
|
+
this.db.close();
|
|
432
|
+
}
|
|
433
|
+
getStats() {
|
|
434
|
+
const count = this.stmtCount.get().count;
|
|
435
|
+
const oldest = this.db.prepare(`SELECT MIN(created_at) as oldest FROM embeddings`).get();
|
|
436
|
+
const newest = this.db.prepare(`SELECT MAX(created_at) as newest FROM embeddings`).get();
|
|
437
|
+
let dbSizeBytes = 0;
|
|
438
|
+
try {
|
|
439
|
+
const stats = statSync(this.config.dbPath);
|
|
440
|
+
dbSizeBytes = stats.size;
|
|
441
|
+
}
|
|
442
|
+
catch { }
|
|
443
|
+
return {
|
|
444
|
+
totalEntries: count,
|
|
445
|
+
hits: this.hits,
|
|
446
|
+
misses: this.misses,
|
|
447
|
+
hitRate: this.hits + this.misses > 0 ? this.hits / (this.hits + this.misses) : 0,
|
|
448
|
+
dbSizeBytes,
|
|
449
|
+
oldestEntry: oldest.oldest || 0,
|
|
450
|
+
newestEntry: newest.newest || 0,
|
|
451
|
+
backend: 'sqlite',
|
|
452
|
+
};
|
|
453
|
+
}
|
|
454
|
+
}
|
|
455
|
+
/**
|
|
456
|
+
* EmbeddingCache - Auto-selects best available backend
|
|
457
|
+
*
|
|
458
|
+
* Backend priority:
|
|
459
|
+
* 1. Native SQLite (better-sqlite3) - Fastest, 9000x speedup
|
|
460
|
+
* 2. WASM SQLite (sql.js) - Cross-platform with persistence
|
|
461
|
+
* 3. Memory cache - Fallback, no persistence
|
|
462
|
+
*/
|
|
463
|
+
export class EmbeddingCache {
|
|
464
|
+
backend;
|
|
465
|
+
config;
|
|
466
|
+
wasmInitPromise = null;
|
|
467
|
+
constructor(config = {}) {
|
|
468
|
+
this.config = { ...DEFAULT_CONFIG, ...config };
|
|
469
|
+
// Try native SQLite first (fastest)
|
|
470
|
+
if (nativeSqliteAvailable && !this.config.forceMemory) {
|
|
471
|
+
try {
|
|
472
|
+
this.backend = new SqliteCache(this.config);
|
|
473
|
+
return;
|
|
474
|
+
}
|
|
475
|
+
catch (err) {
|
|
476
|
+
console.warn('[EmbeddingCache] Native SQLite failed, trying WASM fallback');
|
|
477
|
+
}
|
|
478
|
+
}
|
|
479
|
+
// Try WASM SQLite second (cross-platform with persistence)
|
|
480
|
+
if (wasmSqliteAvailable && !this.config.forceMemory) {
|
|
481
|
+
this.backend = new WasmSqliteCache(this.config);
|
|
482
|
+
this.wasmInitPromise = this.backend.init().catch(err => {
|
|
483
|
+
console.warn('[EmbeddingCache] WASM SQLite init failed, using memory cache');
|
|
484
|
+
this.backend = new MemoryCache(this.config.maxEntries);
|
|
485
|
+
});
|
|
486
|
+
return;
|
|
487
|
+
}
|
|
488
|
+
// Fallback to memory cache
|
|
489
|
+
this.backend = new MemoryCache(this.config.maxEntries);
|
|
490
|
+
}
|
|
491
|
+
/**
|
|
492
|
+
* Ensure WASM backend is initialized (if using)
|
|
493
|
+
*/
|
|
494
|
+
async ensureInit() {
|
|
495
|
+
if (this.wasmInitPromise) {
|
|
496
|
+
await this.wasmInitPromise;
|
|
497
|
+
}
|
|
498
|
+
}
|
|
499
|
+
/**
|
|
500
|
+
* Generate hash key for text + model combination
|
|
501
|
+
*/
|
|
502
|
+
hashKey(text, model = 'default') {
|
|
503
|
+
return createHash('sha256').update(`${model}:${text}`).digest('hex').slice(0, 32);
|
|
504
|
+
}
|
|
505
|
+
/**
|
|
506
|
+
* Get embedding from cache
|
|
507
|
+
*/
|
|
508
|
+
get(text, model = 'default') {
|
|
509
|
+
const hash = this.hashKey(text, model);
|
|
510
|
+
const result = this.backend.get(hash);
|
|
511
|
+
return result ? result.embedding : null;
|
|
512
|
+
}
|
|
513
|
+
/**
|
|
514
|
+
* Store embedding in cache
|
|
515
|
+
*/
|
|
516
|
+
set(text, embedding, model = 'default') {
|
|
517
|
+
const hash = this.hashKey(text, model);
|
|
518
|
+
if (this.backend instanceof SqliteCache) {
|
|
519
|
+
this.backend.set(hash, text, embedding, model);
|
|
520
|
+
}
|
|
521
|
+
else {
|
|
522
|
+
this.backend.set(hash, text, embedding, model);
|
|
523
|
+
}
|
|
524
|
+
}
|
|
525
|
+
/**
|
|
526
|
+
* Check if text is cached
|
|
527
|
+
*/
|
|
528
|
+
has(text, model = 'default') {
|
|
529
|
+
const hash = this.hashKey(text, model);
|
|
530
|
+
return this.backend.has(hash);
|
|
531
|
+
}
|
|
532
|
+
/**
|
|
533
|
+
* Get multiple embeddings at once
|
|
534
|
+
*/
|
|
535
|
+
getMany(texts, model = 'default') {
|
|
536
|
+
const result = new Map();
|
|
537
|
+
for (const text of texts) {
|
|
538
|
+
const embedding = this.get(text, model);
|
|
539
|
+
if (embedding) {
|
|
540
|
+
result.set(text, embedding);
|
|
541
|
+
}
|
|
542
|
+
}
|
|
543
|
+
return result;
|
|
544
|
+
}
|
|
545
|
+
/**
|
|
546
|
+
* Store multiple embeddings at once
|
|
547
|
+
*/
|
|
548
|
+
setMany(entries, model = 'default') {
|
|
549
|
+
for (const { text, embedding } of entries) {
|
|
550
|
+
this.set(text, embedding, model);
|
|
551
|
+
}
|
|
552
|
+
}
|
|
553
|
+
/**
|
|
554
|
+
* Get cache statistics
|
|
555
|
+
*/
|
|
556
|
+
getStats() {
|
|
557
|
+
return this.backend.getStats();
|
|
558
|
+
}
|
|
559
|
+
/**
|
|
560
|
+
* Clear all cached embeddings
|
|
561
|
+
*/
|
|
562
|
+
clear() {
|
|
563
|
+
this.backend.clear();
|
|
564
|
+
}
|
|
565
|
+
/**
|
|
566
|
+
* Vacuum database (SQLite only)
|
|
567
|
+
*/
|
|
568
|
+
vacuum() {
|
|
569
|
+
if (this.backend instanceof SqliteCache) {
|
|
570
|
+
this.backend.vacuum();
|
|
571
|
+
}
|
|
572
|
+
}
|
|
573
|
+
/**
|
|
574
|
+
* Close database connection
|
|
575
|
+
*/
|
|
576
|
+
close() {
|
|
577
|
+
if (this.backend instanceof SqliteCache || this.backend instanceof WasmSqliteCache) {
|
|
578
|
+
this.backend.close();
|
|
579
|
+
}
|
|
580
|
+
}
|
|
581
|
+
/**
|
|
582
|
+
* Check if using SQLite backend (native or WASM)
|
|
583
|
+
*/
|
|
584
|
+
isSqliteBackend() {
|
|
585
|
+
return this.backend instanceof SqliteCache || this.backend instanceof WasmSqliteCache;
|
|
586
|
+
}
|
|
587
|
+
/**
|
|
588
|
+
* Get backend type
|
|
589
|
+
*/
|
|
590
|
+
getBackendType() {
|
|
591
|
+
if (this.backend instanceof SqliteCache)
|
|
592
|
+
return 'native';
|
|
593
|
+
if (this.backend instanceof WasmSqliteCache)
|
|
594
|
+
return 'wasm';
|
|
595
|
+
return 'memory';
|
|
596
|
+
}
|
|
597
|
+
}
|
|
598
|
+
// Singleton instance
|
|
599
|
+
let cacheInstance = null;
|
|
600
|
+
/**
|
|
601
|
+
* Get the singleton embedding cache
|
|
602
|
+
*/
|
|
603
|
+
export function getEmbeddingCache(config) {
|
|
604
|
+
if (!cacheInstance) {
|
|
605
|
+
cacheInstance = new EmbeddingCache(config);
|
|
606
|
+
}
|
|
607
|
+
return cacheInstance;
|
|
608
|
+
}
|
|
609
|
+
/**
|
|
610
|
+
* Reset the cache singleton (for testing)
|
|
611
|
+
*/
|
|
612
|
+
export function resetEmbeddingCache() {
|
|
613
|
+
if (cacheInstance) {
|
|
614
|
+
cacheInstance.close();
|
|
615
|
+
cacheInstance = null;
|
|
616
|
+
}
|
|
617
|
+
}
|
|
618
|
+
/**
|
|
619
|
+
* Check if SQLite is available
|
|
620
|
+
*/
|
|
621
|
+
export function isSqliteAvailable() {
|
|
622
|
+
return sqliteAvailable;
|
|
623
|
+
}
|
|
624
|
+
//# sourceMappingURL=EmbeddingCache.js.map
|