moflo 4.8.21 → 4.8.23
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/agents/browser/browser-agent.yaml +182 -182
- package/.claude/agents/core/coder.md +265 -265
- package/.claude/agents/core/planner.md +167 -167
- package/.claude/agents/core/researcher.md +189 -189
- package/.claude/agents/core/reviewer.md +325 -325
- package/.claude/agents/core/tester.md +318 -318
- package/.claude/agents/database-specialist.yaml +21 -21
- package/.claude/agents/dual-mode/codex-coordinator.md +224 -224
- package/.claude/agents/dual-mode/codex-worker.md +211 -211
- package/.claude/agents/dual-mode/dual-orchestrator.md +291 -291
- package/.claude/agents/github/code-review-swarm.md +537 -537
- package/.claude/agents/github/github-modes.md +172 -172
- package/.claude/agents/github/issue-tracker.md +318 -318
- package/.claude/agents/github/multi-repo-swarm.md +552 -552
- package/.claude/agents/github/pr-manager.md +190 -190
- package/.claude/agents/github/project-board-sync.md +508 -508
- package/.claude/agents/github/release-manager.md +366 -366
- package/.claude/agents/github/release-swarm.md +582 -582
- package/.claude/agents/github/repo-architect.md +397 -397
- package/.claude/agents/github/swarm-issue.md +572 -572
- package/.claude/agents/github/swarm-pr.md +427 -427
- package/.claude/agents/github/sync-coordinator.md +451 -451
- package/.claude/agents/github/workflow-automation.md +634 -634
- package/.claude/agents/goal/code-goal-planner.md +445 -445
- package/.claude/agents/hive-mind/collective-intelligence-coordinator.md +129 -129
- package/.claude/agents/hive-mind/queen-coordinator.md +202 -202
- package/.claude/agents/hive-mind/scout-explorer.md +241 -241
- package/.claude/agents/hive-mind/swarm-memory-manager.md +192 -192
- package/.claude/agents/hive-mind/worker-specialist.md +216 -216
- package/.claude/agents/index.yaml +17 -17
- package/.claude/agents/neural/safla-neural.md +73 -73
- package/.claude/agents/project-coordinator.yaml +15 -15
- package/.claude/agents/python-specialist.yaml +21 -21
- package/.claude/agents/reasoning/goal-planner.md +72 -72
- package/.claude/agents/security-auditor.yaml +20 -20
- package/.claude/agents/swarm/adaptive-coordinator.md +395 -395
- package/.claude/agents/swarm/hierarchical-coordinator.md +326 -326
- package/.claude/agents/swarm/mesh-coordinator.md +391 -391
- package/.claude/agents/templates/migration-plan.md +745 -745
- package/.claude/agents/typescript-specialist.yaml +21 -21
- package/.claude/checkpoints/1767754460.json +8 -8
- package/.claude/commands/agents/agent-spawning.md +28 -28
- package/.claude/commands/github/github-modes.md +146 -146
- package/.claude/commands/github/github-swarm.md +121 -121
- package/.claude/commands/github/issue-tracker.md +291 -291
- package/.claude/commands/github/pr-manager.md +169 -169
- package/.claude/commands/github/release-manager.md +337 -337
- package/.claude/commands/github/repo-architect.md +366 -366
- package/.claude/commands/github/sync-coordinator.md +300 -300
- package/.claude/commands/memory/neural.md +47 -47
- package/.claude/commands/sparc/analyzer.md +51 -51
- package/.claude/commands/sparc/architect.md +53 -53
- package/.claude/commands/sparc/ask.md +97 -97
- package/.claude/commands/sparc/batch-executor.md +54 -54
- package/.claude/commands/sparc/code.md +89 -89
- package/.claude/commands/sparc/coder.md +54 -54
- package/.claude/commands/sparc/debug.md +83 -83
- package/.claude/commands/sparc/debugger.md +54 -54
- package/.claude/commands/sparc/designer.md +53 -53
- package/.claude/commands/sparc/devops.md +109 -109
- package/.claude/commands/sparc/docs-writer.md +80 -80
- package/.claude/commands/sparc/documenter.md +54 -54
- package/.claude/commands/sparc/innovator.md +54 -54
- package/.claude/commands/sparc/integration.md +83 -83
- package/.claude/commands/sparc/mcp.md +117 -117
- package/.claude/commands/sparc/memory-manager.md +54 -54
- package/.claude/commands/sparc/optimizer.md +54 -54
- package/.claude/commands/sparc/orchestrator.md +131 -131
- package/.claude/commands/sparc/post-deployment-monitoring-mode.md +83 -83
- package/.claude/commands/sparc/refinement-optimization-mode.md +83 -83
- package/.claude/commands/sparc/researcher.md +54 -54
- package/.claude/commands/sparc/reviewer.md +54 -54
- package/.claude/commands/sparc/security-review.md +80 -80
- package/.claude/commands/sparc/sparc-modes.md +174 -174
- package/.claude/commands/sparc/sparc.md +111 -111
- package/.claude/commands/sparc/spec-pseudocode.md +80 -80
- package/.claude/commands/sparc/supabase-admin.md +348 -348
- package/.claude/commands/sparc/swarm-coordinator.md +54 -54
- package/.claude/commands/sparc/tdd.md +54 -54
- package/.claude/commands/sparc/tester.md +54 -54
- package/.claude/commands/sparc/tutorial.md +79 -79
- package/.claude/commands/sparc/workflow-manager.md +54 -54
- package/.claude/commands/sparc.md +166 -166
- package/.claude/commands/swarm/analysis.md +95 -95
- package/.claude/commands/swarm/development.md +96 -96
- package/.claude/commands/swarm/examples.md +168 -168
- package/.claude/commands/swarm/maintenance.md +102 -102
- package/.claude/commands/swarm/optimization.md +117 -117
- package/.claude/commands/swarm/research.md +136 -136
- package/.claude/commands/swarm/testing.md +131 -131
- package/.claude/commands/workflows/development.md +77 -77
- package/.claude/commands/workflows/research.md +62 -62
- package/.claude/guidance/moflo-bootstrap.md +126 -126
- package/.claude/guidance/shipped/agent-bootstrap.md +126 -126
- package/.claude/guidance/shipped/guidance-memory-strategy.md +262 -262
- package/.claude/guidance/shipped/memory-strategy.md +204 -204
- package/.claude/guidance/shipped/moflo.md +668 -653
- package/.claude/guidance/shipped/task-swarm-integration.md +441 -441
- package/.claude/helpers/intelligence.cjs +207 -207
- package/.claude/helpers/statusline.cjs +851 -851
- package/.claude/settings.local.json +18 -0
- package/.claude/skills/fl/SKILL.md +583 -583
- package/.claude/skills/flo/SKILL.md +583 -583
- package/.claude/skills/github-code-review/SKILL.md +1140 -1140
- package/.claude/skills/github-multi-repo/SKILL.md +874 -874
- package/.claude/skills/github-project-management/SKILL.md +1277 -1277
- package/.claude/skills/github-release-management/SKILL.md +1081 -1081
- package/.claude/skills/github-workflow-automation/SKILL.md +1065 -1065
- package/.claude/skills/hive-mind-advanced/SKILL.md +712 -712
- package/.claude/skills/hooks-automation/SKILL.md +1201 -1201
- package/.claude/skills/performance-analysis/SKILL.md +563 -563
- package/.claude/skills/sparc-methodology/SKILL.md +1115 -1115
- package/.claude/skills/swarm-advanced/SKILL.md +973 -973
- package/.claude/workflow-state.json +4 -4
- package/LICENSE +21 -21
- package/README.md +698 -685
- package/bin/cli.js +0 -0
- package/bin/gate-hook.mjs +50 -50
- package/bin/gate.cjs +138 -138
- package/bin/generate-code-map.mjs +775 -775
- package/bin/hook-handler.cjs +83 -83
- package/bin/hooks.mjs +656 -656
- package/bin/index-guidance.mjs +892 -892
- package/bin/index-tests.mjs +709 -709
- package/bin/lib/process-manager.mjs +243 -243
- package/bin/lib/registry-cleanup.cjs +41 -41
- package/bin/prompt-hook.mjs +72 -72
- package/bin/semantic-search.mjs +472 -472
- package/bin/session-start-launcher.mjs +238 -238
- package/bin/setup-project.mjs +250 -250
- package/package.json +123 -123
- package/src/@claude-flow/cli/README.md +452 -452
- package/src/@claude-flow/cli/bin/cli.js +180 -180
- package/src/@claude-flow/cli/bin/preinstall.cjs +2 -2
- package/src/@claude-flow/cli/dist/src/commands/completions.js +409 -409
- package/src/@claude-flow/cli/dist/src/commands/doctor.js +18 -2
- package/src/@claude-flow/cli/dist/src/commands/embeddings.js +25 -25
- package/src/@claude-flow/cli/dist/src/commands/github.js +61 -61
- package/src/@claude-flow/cli/dist/src/commands/hive-mind.js +90 -90
- package/src/@claude-flow/cli/dist/src/commands/hooks.js +9 -9
- package/src/@claude-flow/cli/dist/src/commands/init.js +3 -8
- package/src/@claude-flow/cli/dist/src/commands/ruvector/import.js +14 -14
- package/src/@claude-flow/cli/dist/src/commands/ruvector/setup.js +624 -624
- package/src/@claude-flow/cli/dist/src/config/moflo-config.d.ts +3 -0
- package/src/@claude-flow/cli/dist/src/config/moflo-config.js +101 -91
- package/src/@claude-flow/cli/dist/src/index.d.ts +5 -0
- package/src/@claude-flow/cli/dist/src/index.js +44 -0
- package/src/@claude-flow/cli/dist/src/init/claudemd-generator.d.ts +29 -29
- package/src/@claude-flow/cli/dist/src/init/claudemd-generator.js +43 -43
- package/src/@claude-flow/cli/dist/src/init/executor.js +453 -453
- package/src/@claude-flow/cli/dist/src/init/helpers-generator.js +482 -482
- package/src/@claude-flow/cli/dist/src/init/moflo-init.d.ts +30 -30
- package/src/@claude-flow/cli/dist/src/init/moflo-init.js +140 -140
- package/src/@claude-flow/cli/dist/src/init/statusline-generator.js +876 -876
- package/src/@claude-flow/cli/dist/src/memory/memory-initializer.js +371 -371
- package/src/@claude-flow/cli/dist/src/runtime/headless.js +28 -28
- package/src/@claude-flow/cli/dist/src/services/container-worker-pool.d.ts +197 -0
- package/src/@claude-flow/cli/dist/src/services/container-worker-pool.js +584 -0
- package/src/@claude-flow/cli/dist/src/services/daemon-lock.d.ts +14 -0
- package/src/@claude-flow/cli/dist/src/services/daemon-lock.js +1 -1
- package/src/@claude-flow/cli/dist/src/services/headless-worker-executor.js +84 -84
- package/src/@claude-flow/cli/package.json +1 -1
- package/src/@claude-flow/guidance/README.md +1195 -1195
- package/src/@claude-flow/guidance/package.json +198 -198
- package/src/@claude-flow/memory/README.md +587 -587
- package/src/@claude-flow/memory/dist/agentdb-backend.js +26 -26
- package/src/@claude-flow/memory/dist/auto-memory-bridge.test.js +27 -27
- package/src/@claude-flow/memory/dist/hybrid-backend.d.ts +245 -0
- package/src/@claude-flow/memory/dist/hybrid-backend.js +569 -0
- package/src/@claude-flow/memory/dist/hybrid-backend.test.d.ts +8 -0
- package/src/@claude-flow/memory/dist/hybrid-backend.test.js +320 -0
- package/src/@claude-flow/memory/dist/sqlite-backend.d.ts +121 -0
- package/src/@claude-flow/memory/dist/sqlite-backend.js +572 -0
- package/src/@claude-flow/memory/dist/sqljs-backend.js +26 -26
- package/src/@claude-flow/memory/package.json +44 -44
- package/src/@claude-flow/shared/README.md +323 -323
- package/src/@claude-flow/shared/dist/events/event-store.js +31 -31
- package/src/README.md +493 -493
|
@@ -0,0 +1,569 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* HybridBackend - Combines SQLite (structured queries) + AgentDB (vector search)
|
|
3
|
+
*
|
|
4
|
+
* Per ADR-009: "HybridBackend (SQLite + AgentDB) as default"
|
|
5
|
+
* - SQLite for: Structured queries, ACID transactions, exact matches
|
|
6
|
+
* - AgentDB for: Semantic search, vector similarity, RAG
|
|
7
|
+
*
|
|
8
|
+
* @module v3/memory/hybrid-backend
|
|
9
|
+
*/
|
|
10
|
+
import { EventEmitter } from 'node:events';
|
|
11
|
+
import { SQLiteBackend } from './sqlite-backend.js';
|
|
12
|
+
import { AgentDBBackend } from './agentdb-backend.js';
|
|
13
|
+
/**
|
|
14
|
+
* Default configuration
|
|
15
|
+
*/
|
|
16
|
+
const DEFAULT_CONFIG = {
|
|
17
|
+
sqlite: {},
|
|
18
|
+
agentdb: {},
|
|
19
|
+
defaultNamespace: 'default',
|
|
20
|
+
embeddingGenerator: undefined,
|
|
21
|
+
routingStrategy: 'auto',
|
|
22
|
+
dualWrite: true,
|
|
23
|
+
semanticThreshold: 0.7,
|
|
24
|
+
hybridMaxResults: 100,
|
|
25
|
+
};
|
|
26
|
+
/**
|
|
27
|
+
* HybridBackend Implementation
|
|
28
|
+
*
|
|
29
|
+
* Intelligently routes queries between SQLite and AgentDB:
|
|
30
|
+
* - Exact matches, prefix queries → SQLite
|
|
31
|
+
* - Semantic search, similarity → AgentDB
|
|
32
|
+
* - Complex hybrid queries → Both backends with intelligent merging
|
|
33
|
+
*/
|
|
34
|
+
export class HybridBackend extends EventEmitter {
|
|
35
|
+
sqlite;
|
|
36
|
+
agentdb;
|
|
37
|
+
config;
|
|
38
|
+
initialized = false;
|
|
39
|
+
// Performance tracking
|
|
40
|
+
stats = {
|
|
41
|
+
sqliteQueries: 0,
|
|
42
|
+
agentdbQueries: 0,
|
|
43
|
+
hybridQueries: 0,
|
|
44
|
+
totalQueryTime: 0,
|
|
45
|
+
};
|
|
46
|
+
constructor(config = {}) {
|
|
47
|
+
super();
|
|
48
|
+
this.config = { ...DEFAULT_CONFIG, ...config };
|
|
49
|
+
// Initialize SQLite backend
|
|
50
|
+
this.sqlite = new SQLiteBackend({
|
|
51
|
+
...this.config.sqlite,
|
|
52
|
+
defaultNamespace: this.config.defaultNamespace,
|
|
53
|
+
embeddingGenerator: this.config.embeddingGenerator,
|
|
54
|
+
});
|
|
55
|
+
// Initialize AgentDB backend
|
|
56
|
+
this.agentdb = new AgentDBBackend({
|
|
57
|
+
...this.config.agentdb,
|
|
58
|
+
namespace: this.config.defaultNamespace,
|
|
59
|
+
embeddingGenerator: this.config.embeddingGenerator,
|
|
60
|
+
});
|
|
61
|
+
// Forward events from both backends
|
|
62
|
+
this.sqlite.on('entry:stored', (data) => this.emit('sqlite:stored', data));
|
|
63
|
+
this.sqlite.on('entry:updated', (data) => this.emit('sqlite:updated', data));
|
|
64
|
+
this.sqlite.on('entry:deleted', (data) => this.emit('sqlite:deleted', data));
|
|
65
|
+
this.agentdb.on('entry:stored', (data) => this.emit('agentdb:stored', data));
|
|
66
|
+
this.agentdb.on('entry:updated', (data) => this.emit('agentdb:updated', data));
|
|
67
|
+
this.agentdb.on('entry:deleted', (data) => this.emit('agentdb:deleted', data));
|
|
68
|
+
this.agentdb.on('cache:hit', (data) => this.emit('cache:hit', data));
|
|
69
|
+
this.agentdb.on('cache:miss', (data) => this.emit('cache:miss', data));
|
|
70
|
+
}
|
|
71
|
+
/**
|
|
72
|
+
* Initialize both backends
|
|
73
|
+
*/
|
|
74
|
+
async initialize() {
|
|
75
|
+
if (this.initialized)
|
|
76
|
+
return;
|
|
77
|
+
await Promise.all([this.sqlite.initialize(), this.agentdb.initialize()]);
|
|
78
|
+
this.initialized = true;
|
|
79
|
+
this.emit('initialized');
|
|
80
|
+
}
|
|
81
|
+
/**
|
|
82
|
+
* Shutdown both backends
|
|
83
|
+
*/
|
|
84
|
+
async shutdown() {
|
|
85
|
+
if (!this.initialized)
|
|
86
|
+
return;
|
|
87
|
+
await Promise.all([this.sqlite.shutdown(), this.agentdb.shutdown()]);
|
|
88
|
+
this.initialized = false;
|
|
89
|
+
this.emit('shutdown');
|
|
90
|
+
}
|
|
91
|
+
/**
|
|
92
|
+
* Store in both backends (dual-write for consistency)
|
|
93
|
+
*/
|
|
94
|
+
async store(entry) {
|
|
95
|
+
if (this.config.dualWrite) {
|
|
96
|
+
// Write to both backends in parallel
|
|
97
|
+
await Promise.all([this.sqlite.store(entry), this.agentdb.store(entry)]);
|
|
98
|
+
}
|
|
99
|
+
else {
|
|
100
|
+
// Write to primary backend only (AgentDB has vector search)
|
|
101
|
+
await this.agentdb.store(entry);
|
|
102
|
+
}
|
|
103
|
+
this.emit('entry:stored', { id: entry.id });
|
|
104
|
+
}
|
|
105
|
+
/**
|
|
106
|
+
* Get from AgentDB (has caching enabled)
|
|
107
|
+
*/
|
|
108
|
+
async get(id) {
|
|
109
|
+
return this.agentdb.get(id);
|
|
110
|
+
}
|
|
111
|
+
/**
|
|
112
|
+
* Get by key (SQLite optimized for exact matches)
|
|
113
|
+
*/
|
|
114
|
+
async getByKey(namespace, key) {
|
|
115
|
+
return this.sqlite.getByKey(namespace, key);
|
|
116
|
+
}
|
|
117
|
+
/**
|
|
118
|
+
* Update in both backends
|
|
119
|
+
*/
|
|
120
|
+
async update(id, update) {
|
|
121
|
+
if (this.config.dualWrite) {
|
|
122
|
+
// Update both backends
|
|
123
|
+
const [sqliteResult, agentdbResult] = await Promise.all([
|
|
124
|
+
this.sqlite.update(id, update),
|
|
125
|
+
this.agentdb.update(id, update),
|
|
126
|
+
]);
|
|
127
|
+
return agentdbResult || sqliteResult;
|
|
128
|
+
}
|
|
129
|
+
else {
|
|
130
|
+
return this.agentdb.update(id, update);
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
/**
|
|
134
|
+
* Delete from both backends
|
|
135
|
+
*/
|
|
136
|
+
async delete(id) {
|
|
137
|
+
if (this.config.dualWrite) {
|
|
138
|
+
const [sqliteResult, agentdbResult] = await Promise.all([
|
|
139
|
+
this.sqlite.delete(id),
|
|
140
|
+
this.agentdb.delete(id),
|
|
141
|
+
]);
|
|
142
|
+
return sqliteResult || agentdbResult;
|
|
143
|
+
}
|
|
144
|
+
else {
|
|
145
|
+
return this.agentdb.delete(id);
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
/**
|
|
149
|
+
* Query routing - semantic goes to AgentDB, structured to SQLite
|
|
150
|
+
*/
|
|
151
|
+
async query(query) {
|
|
152
|
+
const startTime = performance.now();
|
|
153
|
+
let results;
|
|
154
|
+
// Route based on query type
|
|
155
|
+
switch (query.type) {
|
|
156
|
+
case 'exact':
|
|
157
|
+
// SQLite optimized for exact matches
|
|
158
|
+
this.stats.sqliteQueries++;
|
|
159
|
+
results = await this.sqlite.query(query);
|
|
160
|
+
break;
|
|
161
|
+
case 'prefix':
|
|
162
|
+
// SQLite optimized for prefix queries
|
|
163
|
+
this.stats.sqliteQueries++;
|
|
164
|
+
results = await this.sqlite.query(query);
|
|
165
|
+
break;
|
|
166
|
+
case 'tag':
|
|
167
|
+
// Both can handle tags, use SQLite for structured filtering
|
|
168
|
+
this.stats.sqliteQueries++;
|
|
169
|
+
results = await this.sqlite.query(query);
|
|
170
|
+
break;
|
|
171
|
+
case 'semantic':
|
|
172
|
+
// AgentDB optimized for semantic search
|
|
173
|
+
this.stats.agentdbQueries++;
|
|
174
|
+
results = await this.agentdb.query(query);
|
|
175
|
+
break;
|
|
176
|
+
case 'hybrid':
|
|
177
|
+
// Use hybrid query combining both backends
|
|
178
|
+
this.stats.hybridQueries++;
|
|
179
|
+
results = await this.queryHybridInternal(query);
|
|
180
|
+
break;
|
|
181
|
+
default:
|
|
182
|
+
// Auto-routing based on query properties
|
|
183
|
+
results = await this.autoRoute(query);
|
|
184
|
+
}
|
|
185
|
+
const duration = performance.now() - startTime;
|
|
186
|
+
this.stats.totalQueryTime += duration;
|
|
187
|
+
this.emit('query:completed', { type: query.type, duration, count: results.length });
|
|
188
|
+
return results;
|
|
189
|
+
}
|
|
190
|
+
/**
|
|
191
|
+
* Structured queries (SQL)
|
|
192
|
+
* Routes to SQLite for optimal performance
|
|
193
|
+
*/
|
|
194
|
+
async queryStructured(query) {
|
|
195
|
+
this.stats.sqliteQueries++;
|
|
196
|
+
const memoryQuery = {
|
|
197
|
+
type: query.key ? 'exact' : query.keyPrefix ? 'prefix' : 'hybrid',
|
|
198
|
+
key: query.key,
|
|
199
|
+
keyPrefix: query.keyPrefix,
|
|
200
|
+
namespace: query.namespace,
|
|
201
|
+
ownerId: query.ownerId,
|
|
202
|
+
memoryType: query.type,
|
|
203
|
+
createdAfter: query.createdAfter,
|
|
204
|
+
createdBefore: query.createdBefore,
|
|
205
|
+
updatedAfter: query.updatedAfter,
|
|
206
|
+
updatedBefore: query.updatedBefore,
|
|
207
|
+
limit: query.limit || 100,
|
|
208
|
+
offset: query.offset || 0,
|
|
209
|
+
};
|
|
210
|
+
return this.sqlite.query(memoryQuery);
|
|
211
|
+
}
|
|
212
|
+
/**
|
|
213
|
+
* Semantic queries (vector)
|
|
214
|
+
* Routes to AgentDB for HNSW-based vector search
|
|
215
|
+
*/
|
|
216
|
+
async querySemantic(query) {
|
|
217
|
+
this.stats.agentdbQueries++;
|
|
218
|
+
let embedding = query.embedding;
|
|
219
|
+
// Generate embedding if content provided
|
|
220
|
+
if (!embedding && query.content && this.config.embeddingGenerator) {
|
|
221
|
+
embedding = await this.config.embeddingGenerator(query.content);
|
|
222
|
+
}
|
|
223
|
+
if (!embedding) {
|
|
224
|
+
throw new Error('SemanticQuery requires either content or embedding');
|
|
225
|
+
}
|
|
226
|
+
const searchResults = await this.agentdb.search(embedding, {
|
|
227
|
+
k: (query.k || 10) * 2, // Over-fetch to account for post-filtering
|
|
228
|
+
threshold: query.threshold || this.config.semanticThreshold,
|
|
229
|
+
filters: query.filters,
|
|
230
|
+
});
|
|
231
|
+
let entries = searchResults.map((r) => r.entry);
|
|
232
|
+
// Apply tag/namespace/type filters that AgentDB may not enforce
|
|
233
|
+
if (query.filters) {
|
|
234
|
+
const f = query.filters;
|
|
235
|
+
if (f.tags && Array.isArray(f.tags)) {
|
|
236
|
+
const requiredTags = f.tags;
|
|
237
|
+
entries = entries.filter((e) => requiredTags.every((t) => e.tags.includes(t)));
|
|
238
|
+
}
|
|
239
|
+
if (f.namespace && typeof f.namespace === 'string') {
|
|
240
|
+
entries = entries.filter((e) => e.namespace === f.namespace);
|
|
241
|
+
}
|
|
242
|
+
if (f.type && typeof f.type === 'string' && f.type !== 'semantic') {
|
|
243
|
+
entries = entries.filter((e) => e.type === f.type);
|
|
244
|
+
}
|
|
245
|
+
}
|
|
246
|
+
return entries.slice(0, query.k || 10);
|
|
247
|
+
}
|
|
248
|
+
/**
|
|
249
|
+
* Hybrid queries (combine both)
|
|
250
|
+
* Intelligently merges results from both backends
|
|
251
|
+
*/
|
|
252
|
+
async queryHybrid(query) {
|
|
253
|
+
this.stats.hybridQueries++;
|
|
254
|
+
const strategy = query.combineStrategy || 'semantic-first';
|
|
255
|
+
const weights = query.weights || { semantic: 0.7, structured: 0.3 };
|
|
256
|
+
// Execute both queries in parallel
|
|
257
|
+
const [semanticResults, structuredResults] = await Promise.all([
|
|
258
|
+
this.querySemantic(query.semantic),
|
|
259
|
+
query.structured ? this.queryStructured(query.structured) : Promise.resolve([]),
|
|
260
|
+
]);
|
|
261
|
+
// Combine results based on strategy
|
|
262
|
+
switch (strategy) {
|
|
263
|
+
case 'union':
|
|
264
|
+
return this.combineUnion(semanticResults, structuredResults);
|
|
265
|
+
case 'intersection':
|
|
266
|
+
return this.combineIntersection(semanticResults, structuredResults);
|
|
267
|
+
case 'semantic-first':
|
|
268
|
+
return this.combineSemanticFirst(semanticResults, structuredResults);
|
|
269
|
+
case 'structured-first':
|
|
270
|
+
return this.combineStructuredFirst(semanticResults, structuredResults);
|
|
271
|
+
default:
|
|
272
|
+
return this.combineUnion(semanticResults, structuredResults);
|
|
273
|
+
}
|
|
274
|
+
}
|
|
275
|
+
/**
|
|
276
|
+
* Semantic vector search (routes to AgentDB)
|
|
277
|
+
*/
|
|
278
|
+
async search(embedding, options) {
|
|
279
|
+
this.stats.agentdbQueries++;
|
|
280
|
+
return this.agentdb.search(embedding, options);
|
|
281
|
+
}
|
|
282
|
+
/**
|
|
283
|
+
* Bulk insert to both backends
|
|
284
|
+
*/
|
|
285
|
+
async bulkInsert(entries) {
|
|
286
|
+
if (this.config.dualWrite) {
|
|
287
|
+
await Promise.all([this.sqlite.bulkInsert(entries), this.agentdb.bulkInsert(entries)]);
|
|
288
|
+
}
|
|
289
|
+
else {
|
|
290
|
+
await this.agentdb.bulkInsert(entries);
|
|
291
|
+
}
|
|
292
|
+
}
|
|
293
|
+
/**
|
|
294
|
+
* Bulk delete from both backends
|
|
295
|
+
*/
|
|
296
|
+
async bulkDelete(ids) {
|
|
297
|
+
if (this.config.dualWrite) {
|
|
298
|
+
const [sqliteCount, agentdbCount] = await Promise.all([
|
|
299
|
+
this.sqlite.bulkDelete(ids),
|
|
300
|
+
this.agentdb.bulkDelete(ids),
|
|
301
|
+
]);
|
|
302
|
+
return Math.max(sqliteCount, agentdbCount);
|
|
303
|
+
}
|
|
304
|
+
else {
|
|
305
|
+
return this.agentdb.bulkDelete(ids);
|
|
306
|
+
}
|
|
307
|
+
}
|
|
308
|
+
/**
|
|
309
|
+
* Count entries (use SQLite for efficiency)
|
|
310
|
+
*/
|
|
311
|
+
async count(namespace) {
|
|
312
|
+
return this.sqlite.count(namespace);
|
|
313
|
+
}
|
|
314
|
+
/**
|
|
315
|
+
* List namespaces (use SQLite)
|
|
316
|
+
*/
|
|
317
|
+
async listNamespaces() {
|
|
318
|
+
return this.sqlite.listNamespaces();
|
|
319
|
+
}
|
|
320
|
+
/**
|
|
321
|
+
* Clear namespace in both backends
|
|
322
|
+
*/
|
|
323
|
+
async clearNamespace(namespace) {
|
|
324
|
+
if (this.config.dualWrite) {
|
|
325
|
+
const [sqliteCount, agentdbCount] = await Promise.all([
|
|
326
|
+
this.sqlite.clearNamespace(namespace),
|
|
327
|
+
this.agentdb.clearNamespace(namespace),
|
|
328
|
+
]);
|
|
329
|
+
return Math.max(sqliteCount, agentdbCount);
|
|
330
|
+
}
|
|
331
|
+
else {
|
|
332
|
+
return this.agentdb.clearNamespace(namespace);
|
|
333
|
+
}
|
|
334
|
+
}
|
|
335
|
+
/**
|
|
336
|
+
* Get combined statistics from both backends
|
|
337
|
+
*/
|
|
338
|
+
async getStats() {
|
|
339
|
+
const [sqliteStats, agentdbStats] = await Promise.all([
|
|
340
|
+
this.sqlite.getStats(),
|
|
341
|
+
this.agentdb.getStats(),
|
|
342
|
+
]);
|
|
343
|
+
return {
|
|
344
|
+
totalEntries: Math.max(sqliteStats.totalEntries, agentdbStats.totalEntries),
|
|
345
|
+
entriesByNamespace: agentdbStats.entriesByNamespace,
|
|
346
|
+
entriesByType: agentdbStats.entriesByType,
|
|
347
|
+
memoryUsage: sqliteStats.memoryUsage + agentdbStats.memoryUsage,
|
|
348
|
+
hnswStats: agentdbStats.hnswStats ?? {
|
|
349
|
+
vectorCount: agentdbStats.totalEntries,
|
|
350
|
+
memoryUsage: 0,
|
|
351
|
+
avgSearchTime: agentdbStats.avgSearchTime,
|
|
352
|
+
buildTime: 0,
|
|
353
|
+
compressionRatio: 1.0,
|
|
354
|
+
},
|
|
355
|
+
cacheStats: agentdbStats.cacheStats ?? {
|
|
356
|
+
hitRate: 0,
|
|
357
|
+
size: 0,
|
|
358
|
+
maxSize: 1000,
|
|
359
|
+
},
|
|
360
|
+
avgQueryTime: this.stats.hybridQueries + this.stats.sqliteQueries + this.stats.agentdbQueries > 0
|
|
361
|
+
? this.stats.totalQueryTime /
|
|
362
|
+
(this.stats.hybridQueries + this.stats.sqliteQueries + this.stats.agentdbQueries)
|
|
363
|
+
: 0,
|
|
364
|
+
avgSearchTime: agentdbStats.avgSearchTime,
|
|
365
|
+
};
|
|
366
|
+
}
|
|
367
|
+
/**
|
|
368
|
+
* Health check for both backends
|
|
369
|
+
*/
|
|
370
|
+
async healthCheck() {
|
|
371
|
+
const [sqliteHealth, agentdbHealth] = await Promise.all([
|
|
372
|
+
this.sqlite.healthCheck(),
|
|
373
|
+
this.agentdb.healthCheck(),
|
|
374
|
+
]);
|
|
375
|
+
const allIssues = [...sqliteHealth.issues, ...agentdbHealth.issues];
|
|
376
|
+
const allRecommendations = [
|
|
377
|
+
...sqliteHealth.recommendations,
|
|
378
|
+
...agentdbHealth.recommendations,
|
|
379
|
+
];
|
|
380
|
+
// Determine overall status
|
|
381
|
+
let status = 'healthy';
|
|
382
|
+
if (sqliteHealth.status === 'unhealthy' ||
|
|
383
|
+
agentdbHealth.status === 'unhealthy') {
|
|
384
|
+
status = 'unhealthy';
|
|
385
|
+
}
|
|
386
|
+
else if (sqliteHealth.status === 'degraded' ||
|
|
387
|
+
agentdbHealth.status === 'degraded') {
|
|
388
|
+
status = 'degraded';
|
|
389
|
+
}
|
|
390
|
+
return {
|
|
391
|
+
status,
|
|
392
|
+
components: {
|
|
393
|
+
storage: sqliteHealth.components.storage,
|
|
394
|
+
index: agentdbHealth.components.index,
|
|
395
|
+
cache: agentdbHealth.components.cache,
|
|
396
|
+
},
|
|
397
|
+
timestamp: Date.now(),
|
|
398
|
+
issues: allIssues,
|
|
399
|
+
recommendations: allRecommendations,
|
|
400
|
+
};
|
|
401
|
+
}
|
|
402
|
+
// ===== Private Methods =====
|
|
403
|
+
/**
|
|
404
|
+
* Auto-route queries based on properties
|
|
405
|
+
*/
|
|
406
|
+
async autoRoute(query) {
|
|
407
|
+
// If has embedding or content, use semantic search (AgentDB)
|
|
408
|
+
const hasEmbeddingGenerator = typeof this.config.embeddingGenerator === 'function';
|
|
409
|
+
if (query.embedding || (query.content && hasEmbeddingGenerator)) {
|
|
410
|
+
this.stats.agentdbQueries++;
|
|
411
|
+
return this.agentdb.query(query);
|
|
412
|
+
}
|
|
413
|
+
// If has exact key or prefix, use structured search (SQLite)
|
|
414
|
+
if (query.key || query.keyPrefix) {
|
|
415
|
+
this.stats.sqliteQueries++;
|
|
416
|
+
return this.sqlite.query(query);
|
|
417
|
+
}
|
|
418
|
+
// For other filters, use routing strategy
|
|
419
|
+
switch (this.config.routingStrategy) {
|
|
420
|
+
case 'sqlite-first':
|
|
421
|
+
this.stats.sqliteQueries++;
|
|
422
|
+
return this.sqlite.query(query);
|
|
423
|
+
case 'agentdb-first':
|
|
424
|
+
this.stats.agentdbQueries++;
|
|
425
|
+
return this.agentdb.query(query);
|
|
426
|
+
case 'auto':
|
|
427
|
+
default:
|
|
428
|
+
// Default to AgentDB (has caching)
|
|
429
|
+
this.stats.agentdbQueries++;
|
|
430
|
+
return this.agentdb.query(query);
|
|
431
|
+
}
|
|
432
|
+
}
|
|
433
|
+
/**
|
|
434
|
+
* Internal hybrid query implementation
|
|
435
|
+
*/
|
|
436
|
+
async queryHybridInternal(query) {
|
|
437
|
+
// If semantic component exists, use hybrid
|
|
438
|
+
if (query.embedding || query.content) {
|
|
439
|
+
const semanticQuery = {
|
|
440
|
+
content: query.content,
|
|
441
|
+
embedding: query.embedding,
|
|
442
|
+
k: query.limit || 10,
|
|
443
|
+
threshold: query.threshold,
|
|
444
|
+
filters: query,
|
|
445
|
+
};
|
|
446
|
+
const structuredQuery = {
|
|
447
|
+
namespace: query.namespace,
|
|
448
|
+
key: query.key,
|
|
449
|
+
keyPrefix: query.keyPrefix,
|
|
450
|
+
ownerId: query.ownerId,
|
|
451
|
+
type: query.memoryType,
|
|
452
|
+
createdAfter: query.createdAfter,
|
|
453
|
+
createdBefore: query.createdBefore,
|
|
454
|
+
updatedAfter: query.updatedAfter,
|
|
455
|
+
updatedBefore: query.updatedBefore,
|
|
456
|
+
limit: query.limit,
|
|
457
|
+
offset: query.offset,
|
|
458
|
+
};
|
|
459
|
+
return this.queryHybrid({
|
|
460
|
+
semantic: semanticQuery,
|
|
461
|
+
structured: structuredQuery,
|
|
462
|
+
combineStrategy: 'semantic-first',
|
|
463
|
+
});
|
|
464
|
+
}
|
|
465
|
+
// Otherwise, route to structured
|
|
466
|
+
return this.autoRoute(query);
|
|
467
|
+
}
|
|
468
|
+
/**
|
|
469
|
+
* Combine results using union (all unique results)
|
|
470
|
+
*/
|
|
471
|
+
combineUnion(semanticResults, structuredResults) {
|
|
472
|
+
const seen = new Set();
|
|
473
|
+
const combined = [];
|
|
474
|
+
for (const entry of [...semanticResults, ...structuredResults]) {
|
|
475
|
+
if (!seen.has(entry.id)) {
|
|
476
|
+
seen.add(entry.id);
|
|
477
|
+
combined.push(entry);
|
|
478
|
+
}
|
|
479
|
+
}
|
|
480
|
+
return combined;
|
|
481
|
+
}
|
|
482
|
+
/**
|
|
483
|
+
* Combine results using intersection (only common results)
|
|
484
|
+
*/
|
|
485
|
+
combineIntersection(semanticResults, structuredResults) {
|
|
486
|
+
const semanticIds = new Set(semanticResults.map((e) => e.id));
|
|
487
|
+
return structuredResults.filter((e) => semanticIds.has(e.id));
|
|
488
|
+
}
|
|
489
|
+
/**
|
|
490
|
+
* Semantic-first: Prefer semantic results, add structured if not present
|
|
491
|
+
*/
|
|
492
|
+
combineSemanticFirst(semanticResults, structuredResults) {
|
|
493
|
+
const semanticIds = new Set(semanticResults.map((e) => e.id));
|
|
494
|
+
const additional = structuredResults.filter((e) => !semanticIds.has(e.id));
|
|
495
|
+
return [...semanticResults, ...additional];
|
|
496
|
+
}
|
|
497
|
+
/**
|
|
498
|
+
* Structured-first: Prefer structured results, add semantic if not present
|
|
499
|
+
*/
|
|
500
|
+
combineStructuredFirst(semanticResults, structuredResults) {
|
|
501
|
+
const structuredIds = new Set(structuredResults.map((e) => e.id));
|
|
502
|
+
const additional = semanticResults.filter((e) => !structuredIds.has(e.id));
|
|
503
|
+
return [...structuredResults, ...additional];
|
|
504
|
+
}
|
|
505
|
+
// ===== Proxy Methods for AgentDB v3 Controllers (ADR-053 #1212) =====
|
|
506
|
+
/**
|
|
507
|
+
* Record feedback for a memory entry.
|
|
508
|
+
* Delegates to AgentDB's recordFeedback when available.
|
|
509
|
+
* Gracefully degrades to a no-op when AgentDB is unavailable.
|
|
510
|
+
*/
|
|
511
|
+
async recordFeedback(entryId, feedback) {
|
|
512
|
+
const agentdbInstance = this.agentdb.getAgentDB?.();
|
|
513
|
+
if (agentdbInstance && typeof agentdbInstance.recordFeedback === 'function') {
|
|
514
|
+
try {
|
|
515
|
+
await agentdbInstance.recordFeedback(entryId, feedback);
|
|
516
|
+
this.emit('feedback:recorded', { entryId, score: feedback.score });
|
|
517
|
+
return true;
|
|
518
|
+
}
|
|
519
|
+
catch {
|
|
520
|
+
// AgentDB feedback recording failed — degrade silently
|
|
521
|
+
}
|
|
522
|
+
}
|
|
523
|
+
return false;
|
|
524
|
+
}
|
|
525
|
+
/**
|
|
526
|
+
* Verify a witness chain for a memory entry.
|
|
527
|
+
* Delegates to AgentDB's verifyWitnessChain when available.
|
|
528
|
+
*/
|
|
529
|
+
async verifyWitnessChain(entryId) {
|
|
530
|
+
const agentdbInstance = this.agentdb.getAgentDB?.();
|
|
531
|
+
if (agentdbInstance && typeof agentdbInstance.verifyWitnessChain === 'function') {
|
|
532
|
+
try {
|
|
533
|
+
return await agentdbInstance.verifyWitnessChain(entryId);
|
|
534
|
+
}
|
|
535
|
+
catch {
|
|
536
|
+
// Verification failed — return degraded result
|
|
537
|
+
}
|
|
538
|
+
}
|
|
539
|
+
return { valid: false, chainLength: 0, errors: ['AgentDB not available'] };
|
|
540
|
+
}
|
|
541
|
+
/**
|
|
542
|
+
* Get the witness chain for a memory entry.
|
|
543
|
+
* Delegates to AgentDB's getWitnessChain when available.
|
|
544
|
+
*/
|
|
545
|
+
async getWitnessChain(entryId) {
|
|
546
|
+
const agentdbInstance = this.agentdb.getAgentDB?.();
|
|
547
|
+
if (agentdbInstance && typeof agentdbInstance.getWitnessChain === 'function') {
|
|
548
|
+
try {
|
|
549
|
+
return await agentdbInstance.getWitnessChain(entryId);
|
|
550
|
+
}
|
|
551
|
+
catch {
|
|
552
|
+
// Chain retrieval failed
|
|
553
|
+
}
|
|
554
|
+
}
|
|
555
|
+
return [];
|
|
556
|
+
}
|
|
557
|
+
// ===== Backend Access =====
|
|
558
|
+
/**
|
|
559
|
+
* Get underlying backends for advanced operations
|
|
560
|
+
*/
|
|
561
|
+
getSQLiteBackend() {
|
|
562
|
+
return this.sqlite;
|
|
563
|
+
}
|
|
564
|
+
getAgentDBBackend() {
|
|
565
|
+
return this.agentdb;
|
|
566
|
+
}
|
|
567
|
+
}
|
|
568
|
+
export default HybridBackend;
|
|
569
|
+
//# sourceMappingURL=hybrid-backend.js.map
|