moflo 4.5.0 → 4.6.1
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/package.json +1 -1
- package/src/@claude-flow/cli/dist/src/commands/appliance.js +12 -12
- package/src/@claude-flow/cli/dist/src/commands/benchmark.js +2 -2
- package/src/@claude-flow/cli/dist/src/commands/claims.js +1 -1
- package/src/@claude-flow/cli/dist/src/commands/config.js +1 -1
- package/src/@claude-flow/cli/dist/src/commands/daemon.js +25 -3
- package/src/@claude-flow/cli/dist/src/commands/deployment.js +1 -1
- package/src/@claude-flow/cli/dist/src/commands/doctor.js +23 -6
- package/src/@claude-flow/cli/dist/src/commands/embeddings.js +1 -1
- package/src/@claude-flow/cli/dist/src/commands/hooks.js +1 -1
- package/src/@claude-flow/cli/dist/src/commands/init.js +14 -12
- package/src/@claude-flow/cli/dist/src/commands/neural.js +1 -1
- package/src/@claude-flow/cli/dist/src/commands/orc.d.ts +2 -2
- package/src/@claude-flow/cli/dist/src/commands/orc.js +12 -12
- package/src/@claude-flow/cli/dist/src/commands/performance.js +1 -1
- package/src/@claude-flow/cli/dist/src/commands/plugins.js +1 -1
- package/src/@claude-flow/cli/dist/src/commands/providers.js +1 -1
- package/src/@claude-flow/cli/dist/src/commands/security.js +1 -1
- package/src/@claude-flow/cli/dist/src/commands/start.js +11 -11
- package/src/@claude-flow/cli/dist/src/commands/status.js +3 -3
- package/src/@claude-flow/cli/dist/src/commands/transfer-store.js +1 -1
- package/src/@claude-flow/cli/dist/src/config/moflo-config.d.ts +30 -0
- package/src/@claude-flow/cli/dist/src/config/moflo-config.js +103 -7
- package/src/@claude-flow/cli/dist/src/index.d.ts +1 -1
- package/src/@claude-flow/cli/dist/src/index.js +3 -3
- package/src/@claude-flow/cli/dist/src/init/claudemd-generator.js +1 -1
- package/src/@claude-flow/cli/dist/src/init/executor.js +485 -472
- package/src/@claude-flow/cli/dist/src/init/helpers-generator.js +640 -640
- package/src/@claude-flow/cli/dist/src/init/moflo-init.js +530 -66
- package/src/@claude-flow/cli/dist/src/init/settings-generator.js +7 -12
- package/src/@claude-flow/cli/dist/src/init/statusline-generator.d.ts +1 -1
- package/src/@claude-flow/cli/dist/src/init/statusline-generator.js +784 -784
- package/src/@claude-flow/cli/dist/src/mcp-tools/agentdb-tools.js +12 -12
- package/src/@claude-flow/cli/dist/src/mcp-tools/hooks-tools.js +122 -66
- package/src/@claude-flow/cli/dist/src/memory/intelligence.js +5 -1
- package/src/@claude-flow/cli/dist/src/memory/memory-initializer.d.ts +1 -1
- package/src/@claude-flow/cli/dist/src/memory/memory-initializer.js +371 -371
- package/src/@claude-flow/cli/dist/src/parser.d.ts +10 -0
- package/src/@claude-flow/cli/dist/src/parser.js +49 -3
- package/src/@claude-flow/cli/dist/src/plugins/store/discovery.js +1 -1
- package/src/@claude-flow/cli/dist/src/runtime/headless.js +30 -30
- package/src/@claude-flow/cli/dist/src/services/claim-service.js +1 -1
- package/src/@claude-flow/cli/dist/src/services/ruvector-training.js +11 -5
- package/src/@claude-flow/cli/dist/src/services/workflow-gate.d.ts +13 -3
- package/src/@claude-flow/cli/dist/src/services/workflow-gate.js +73 -5
- package/src/@claude-flow/cli/dist/src/types.d.ts +1 -1
- package/src/@claude-flow/cli/dist/src/types.js +1 -1
|
@@ -81,7 +81,7 @@ export const agentdbControllers = {
|
|
|
81
81
|
const bridge = await getBridge();
|
|
82
82
|
const controllers = await bridge.bridgeListControllers();
|
|
83
83
|
if (!controllers)
|
|
84
|
-
return { available: false, controllers: [], error: '
|
|
84
|
+
return { available: false, controllers: [], error: 'AgentDB bridge not available — @claude-flow/memory not installed or missing controller-registry. Use memory_store/memory_search tools instead.' };
|
|
85
85
|
return {
|
|
86
86
|
available: true,
|
|
87
87
|
controllers,
|
|
@@ -118,7 +118,7 @@ export const agentdbPatternStore = {
|
|
|
118
118
|
type: validateString(params.type, 'type', 200) ?? 'general',
|
|
119
119
|
confidence: validateScore(params.confidence, 0.8),
|
|
120
120
|
});
|
|
121
|
-
return result ?? { success: false, error: '
|
|
121
|
+
return result ?? { success: false, error: 'AgentDB bridge not available. Use memory_store/memory_search instead.' };
|
|
122
122
|
}
|
|
123
123
|
catch (error) {
|
|
124
124
|
return { success: false, error: sanitizeError(error) };
|
|
@@ -182,7 +182,7 @@ export const agentdbFeedback = {
|
|
|
182
182
|
quality: validateScore(params.quality, 0.85),
|
|
183
183
|
agent: validateString(params.agent, 'agent', 200) ?? undefined,
|
|
184
184
|
});
|
|
185
|
-
return result ?? { success: false, error: '
|
|
185
|
+
return result ?? { success: false, error: 'AgentDB bridge not available. Use memory_store/memory_search instead.' };
|
|
186
186
|
}
|
|
187
187
|
catch (error) {
|
|
188
188
|
return { success: false, error: sanitizeError(error) };
|
|
@@ -221,7 +221,7 @@ export const agentdbCausalEdge = {
|
|
|
221
221
|
relation,
|
|
222
222
|
weight: typeof params.weight === 'number' ? validateScore(params.weight, 0.5) : undefined,
|
|
223
223
|
});
|
|
224
|
-
return result ?? { success: false, error: '
|
|
224
|
+
return result ?? { success: false, error: 'AgentDB bridge not available. Use memory_store/memory_search instead.' };
|
|
225
225
|
}
|
|
226
226
|
catch (error) {
|
|
227
227
|
return { success: false, error: sanitizeError(error) };
|
|
@@ -279,7 +279,7 @@ export const agentdbSessionStart = {
|
|
|
279
279
|
sessionId,
|
|
280
280
|
context: validateString(params.context, 'context', 10_000) ?? undefined,
|
|
281
281
|
});
|
|
282
|
-
return result ?? { success: false, error: '
|
|
282
|
+
return result ?? { success: false, error: 'AgentDB bridge not available. Use memory_store/memory_search instead.' };
|
|
283
283
|
}
|
|
284
284
|
catch (error) {
|
|
285
285
|
return { success: false, error: sanitizeError(error) };
|
|
@@ -310,7 +310,7 @@ export const agentdbSessionEnd = {
|
|
|
310
310
|
summary: validateString(params.summary, 'summary', 50_000) ?? undefined,
|
|
311
311
|
tasksCompleted: validatePositiveInt(params.tasksCompleted, 0, 10_000),
|
|
312
312
|
});
|
|
313
|
-
return result ?? { success: false, error: '
|
|
313
|
+
return result ?? { success: false, error: 'AgentDB bridge not available. Use memory_store/memory_search instead.' };
|
|
314
314
|
}
|
|
315
315
|
catch (error) {
|
|
316
316
|
return { success: false, error: sanitizeError(error) };
|
|
@@ -349,7 +349,7 @@ export const agentdbHierarchicalStore = {
|
|
|
349
349
|
}
|
|
350
350
|
const bridge = await getBridge();
|
|
351
351
|
const result = await bridge.bridgeHierarchicalStore({ key, value, tier });
|
|
352
|
-
return result ?? { success: false, error: '
|
|
352
|
+
return result ?? { success: false, error: 'AgentDB bridge not available. Use memory_store/memory_search instead.' };
|
|
353
353
|
}
|
|
354
354
|
catch (error) {
|
|
355
355
|
return { success: false, error: sanitizeError(error) };
|
|
@@ -384,7 +384,7 @@ export const agentdbHierarchicalRecall = {
|
|
|
384
384
|
tier: tier ?? undefined,
|
|
385
385
|
topK: validatePositiveInt(params.topK, 5, MAX_TOP_K),
|
|
386
386
|
});
|
|
387
|
-
return result ?? { results: [], error: '
|
|
387
|
+
return result ?? { results: [], error: 'AgentDB bridge not available. Use memory_search instead.' };
|
|
388
388
|
}
|
|
389
389
|
catch (error) {
|
|
390
390
|
return { results: [], error: sanitizeError(error) };
|
|
@@ -409,7 +409,7 @@ export const agentdbConsolidate = {
|
|
|
409
409
|
minAge: typeof params.minAge === 'number' ? Math.max(0, params.minAge) : undefined,
|
|
410
410
|
maxEntries: validatePositiveInt(params.maxEntries, 1000, 10_000),
|
|
411
411
|
});
|
|
412
|
-
return result ?? { success: false, error: '
|
|
412
|
+
return result ?? { success: false, error: 'AgentDB bridge not available. Use memory_store/memory_search instead.' };
|
|
413
413
|
}
|
|
414
414
|
catch (error) {
|
|
415
415
|
return { success: false, error: sanitizeError(error) };
|
|
@@ -475,7 +475,7 @@ export const agentdbBatch = {
|
|
|
475
475
|
operation,
|
|
476
476
|
entries: validatedEntries,
|
|
477
477
|
});
|
|
478
|
-
return result ?? { success: false, error: '
|
|
478
|
+
return result ?? { success: false, error: 'AgentDB bridge not available. Use memory_store/memory_search instead.' };
|
|
479
479
|
}
|
|
480
480
|
catch (error) {
|
|
481
481
|
return { success: false, error: sanitizeError(error) };
|
|
@@ -504,7 +504,7 @@ export const agentdbContextSynthesize = {
|
|
|
504
504
|
query,
|
|
505
505
|
maxEntries: validatePositiveInt(params.maxEntries, 10, MAX_TOP_K),
|
|
506
506
|
});
|
|
507
|
-
return result ?? { success: false, error: '
|
|
507
|
+
return result ?? { success: false, error: 'AgentDB bridge not available. Use memory_store/memory_search instead.' };
|
|
508
508
|
}
|
|
509
509
|
catch (error) {
|
|
510
510
|
return { success: false, error: sanitizeError(error) };
|
|
@@ -529,7 +529,7 @@ export const agentdbSemanticRoute = {
|
|
|
529
529
|
return { route: null, error: 'input is required (non-empty string, max 10KB)' };
|
|
530
530
|
const bridge = await getBridge();
|
|
531
531
|
const result = await bridge.bridgeSemanticRoute({ input });
|
|
532
|
-
return result ?? { route: null, error: '
|
|
532
|
+
return result ?? { route: null, error: 'AgentDB bridge not available. Use hooks route instead.' };
|
|
533
533
|
}
|
|
534
534
|
catch (error) {
|
|
535
535
|
return { route: null, error: sanitizeError(error) };
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
* Provides intelligent hooks functionality via MCP protocol
|
|
4
4
|
*/
|
|
5
5
|
import { mkdirSync, writeFileSync, existsSync, readFileSync, statSync } from 'fs';
|
|
6
|
-
import { join, resolve } from 'path';
|
|
6
|
+
import { dirname, join, resolve } from 'path';
|
|
7
7
|
// Real vector search functions - lazy loaded to avoid circular imports
|
|
8
8
|
let searchEntriesFn = null;
|
|
9
9
|
async function getRealSearchFunction() {
|
|
@@ -121,6 +121,81 @@ function generateSimpleEmbedding(text, dimension = 384) {
|
|
|
121
121
|
}
|
|
122
122
|
return embedding;
|
|
123
123
|
}
|
|
124
|
+
// ── Runtime routing outcome persistence ──────────────────────────────
|
|
125
|
+
// Closes the learning loop: post-task records outcomes → route loads them.
|
|
126
|
+
const ROUTING_OUTCOMES_PATH = join(resolve('.'), '.claude-flow/routing-outcomes.json');
|
|
127
|
+
const ROUTING_STOPWORDS = new Set([
|
|
128
|
+
'the', 'a', 'an', 'is', 'are', 'was', 'were', 'be', 'been', 'being', 'have', 'has', 'had',
|
|
129
|
+
'do', 'does', 'did', 'will', 'would', 'could', 'should', 'may', 'might', 'shall', 'can',
|
|
130
|
+
'to', 'of', 'in', 'for', 'on', 'with', 'at', 'by', 'from', 'as', 'into', 'through', 'during',
|
|
131
|
+
'before', 'after', 'above', 'below', 'between', 'under', 'again', 'further', 'then', 'once',
|
|
132
|
+
'it', 'its', 'this', 'that', 'these', 'those', 'i', 'me', 'my', 'we', 'our', 'you', 'your',
|
|
133
|
+
'he', 'she', 'they', 'them', 'and', 'but', 'or', 'nor', 'not', 'no', 'so', 'if', 'when', 'than',
|
|
134
|
+
'very', 'just', 'also', 'only', 'both', 'each', 'all', 'any', 'few', 'more', 'most', 'other',
|
|
135
|
+
'some', 'such', 'same', 'new', 'now', 'here', 'there', 'where', 'how', 'what', 'which', 'who',
|
|
136
|
+
]);
|
|
137
|
+
function extractKeywords(text) {
|
|
138
|
+
if (!text)
|
|
139
|
+
return [];
|
|
140
|
+
return text.toLowerCase()
|
|
141
|
+
.replace(/[^a-z0-9\s-]/g, ' ')
|
|
142
|
+
.split(/\s+/)
|
|
143
|
+
.filter(w => w.length > 2 && !ROUTING_STOPWORDS.has(w));
|
|
144
|
+
}
|
|
145
|
+
function loadRoutingOutcomes() {
|
|
146
|
+
try {
|
|
147
|
+
if (existsSync(ROUTING_OUTCOMES_PATH)) {
|
|
148
|
+
const data = JSON.parse(readFileSync(ROUTING_OUTCOMES_PATH, 'utf-8'));
|
|
149
|
+
return data.outcomes || [];
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
catch { /* corrupt file, start fresh */ }
|
|
153
|
+
return [];
|
|
154
|
+
}
|
|
155
|
+
function saveRoutingOutcomes(outcomes) {
|
|
156
|
+
try {
|
|
157
|
+
const dir = dirname(ROUTING_OUTCOMES_PATH);
|
|
158
|
+
if (!existsSync(dir))
|
|
159
|
+
mkdirSync(dir, { recursive: true });
|
|
160
|
+
// Cap at 500 entries to bound file size
|
|
161
|
+
const capped = outcomes.slice(-500);
|
|
162
|
+
writeFileSync(ROUTING_OUTCOMES_PATH, JSON.stringify({ outcomes: capped }, null, 2));
|
|
163
|
+
}
|
|
164
|
+
catch { /* non-critical */ }
|
|
165
|
+
}
|
|
166
|
+
/**
|
|
167
|
+
* Build learned patterns from past routing outcomes.
|
|
168
|
+
* Called by hooks_route to incorporate runtime learning into routing decisions.
|
|
169
|
+
*/
|
|
170
|
+
function learnedPatternsFromOutcomes() {
|
|
171
|
+
const outcomes = loadRoutingOutcomes();
|
|
172
|
+
if (outcomes.length === 0)
|
|
173
|
+
return {};
|
|
174
|
+
// Group successful outcomes by agent
|
|
175
|
+
const agentKeywords = new Map();
|
|
176
|
+
for (const o of outcomes) {
|
|
177
|
+
if (!o.success || o.quality < 0.5)
|
|
178
|
+
continue;
|
|
179
|
+
if (!agentKeywords.has(o.agent))
|
|
180
|
+
agentKeywords.set(o.agent, new Map());
|
|
181
|
+
const kwMap = agentKeywords.get(o.agent);
|
|
182
|
+
for (const kw of o.keywords) {
|
|
183
|
+
kwMap.set(kw, (kwMap.get(kw) || 0) + 1);
|
|
184
|
+
}
|
|
185
|
+
}
|
|
186
|
+
const learned = {};
|
|
187
|
+
for (const [agent, kwMap] of agentKeywords) {
|
|
188
|
+
// Take top-10 most frequent keywords for this agent
|
|
189
|
+
const sorted = [...kwMap.entries()].sort((a, b) => b[1] - a[1]).slice(0, 10);
|
|
190
|
+
if (sorted.length >= 2) { // Need at least 2 keywords for a meaningful pattern
|
|
191
|
+
learned[`learned-${agent}`] = {
|
|
192
|
+
keywords: sorted.map(([kw]) => kw),
|
|
193
|
+
agents: [agent],
|
|
194
|
+
};
|
|
195
|
+
}
|
|
196
|
+
}
|
|
197
|
+
return learned;
|
|
198
|
+
}
|
|
124
199
|
// Task patterns used by both native and pure-JS routers
|
|
125
200
|
const TASK_PATTERNS = {
|
|
126
201
|
'security-task': {
|
|
@@ -176,50 +251,8 @@ const TASK_PATTERNS = {
|
|
|
176
251
|
* Load learned routing patterns from persisted file.
|
|
177
252
|
* These are outcomes from previous task executions stored by hooksPostTask.
|
|
178
253
|
*/
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
try {
|
|
182
|
-
const fullPath = join(process.cwd(), ROUTING_OUTCOMES_PATH);
|
|
183
|
-
if (!existsSync(fullPath))
|
|
184
|
-
return [];
|
|
185
|
-
const data = JSON.parse(readFileSync(fullPath, 'utf-8'));
|
|
186
|
-
return Array.isArray(data) ? data : [];
|
|
187
|
-
}
|
|
188
|
-
catch {
|
|
189
|
-
return [];
|
|
190
|
-
}
|
|
191
|
-
}
|
|
192
|
-
function saveRoutingOutcome(task, agentType, confidence) {
|
|
193
|
-
try {
|
|
194
|
-
const fullPath = join(process.cwd(), ROUTING_OUTCOMES_PATH);
|
|
195
|
-
const dir = resolve(fullPath, '..');
|
|
196
|
-
if (!existsSync(dir))
|
|
197
|
-
mkdirSync(dir, { recursive: true });
|
|
198
|
-
const existing = loadRoutingOutcomes();
|
|
199
|
-
// Extract keywords for pattern matching
|
|
200
|
-
const keywords = task.toLowerCase()
|
|
201
|
-
.replace(/[^a-z0-9\s]/g, ' ')
|
|
202
|
-
.split(/\s+/)
|
|
203
|
-
.filter(w => w.length > 3)
|
|
204
|
-
.slice(0, 5);
|
|
205
|
-
if (keywords.length > 0) {
|
|
206
|
-
existing.push({
|
|
207
|
-
pattern: `learned-${agentType}`,
|
|
208
|
-
agentType,
|
|
209
|
-
confidence,
|
|
210
|
-
keywords,
|
|
211
|
-
task: task.slice(0, 200),
|
|
212
|
-
timestamp: new Date().toISOString(),
|
|
213
|
-
});
|
|
214
|
-
// Keep last 500 outcomes
|
|
215
|
-
const trimmed = existing.slice(-500);
|
|
216
|
-
writeFileSync(fullPath, JSON.stringify(trimmed, null, 2));
|
|
217
|
-
}
|
|
218
|
-
}
|
|
219
|
-
catch {
|
|
220
|
-
// Silently fail — routing outcome persistence is best-effort
|
|
221
|
-
}
|
|
222
|
-
}
|
|
254
|
+
// Old loadRoutingOutcomes/saveRoutingOutcome removed — replaced by
|
|
255
|
+
// RoutingOutcome-based persistence at top of file (upstream adcfe6fad).
|
|
223
256
|
/**
|
|
224
257
|
* Get the semantic router with environment detection.
|
|
225
258
|
* Tries native VectorDb first (HNSW, 16k routes/s), falls back to pure JS (47k routes/s cosine).
|
|
@@ -255,13 +288,11 @@ async function getSemanticRouter() {
|
|
|
255
288
|
}
|
|
256
289
|
}
|
|
257
290
|
// Also load learned patterns from previous task executions
|
|
258
|
-
const
|
|
259
|
-
for (const
|
|
260
|
-
|
|
261
|
-
const kws = lp.keywords || [lp.pattern];
|
|
262
|
-
for (const kw of kws) {
|
|
291
|
+
const learned = learnedPatternsFromOutcomes();
|
|
292
|
+
for (const [patternName, { keywords }] of Object.entries(learned)) {
|
|
293
|
+
for (const kw of keywords) {
|
|
263
294
|
const embedding = generateSimpleEmbedding(kw);
|
|
264
|
-
const entryKey =
|
|
295
|
+
const entryKey = `${patternName}:${kw}`;
|
|
265
296
|
db.insert(entryKey, embedding);
|
|
266
297
|
TASK_PATTERN_EMBEDDINGS.set(entryKey, embedding);
|
|
267
298
|
}
|
|
@@ -289,13 +320,12 @@ async function getSemanticRouter() {
|
|
|
289
320
|
});
|
|
290
321
|
}
|
|
291
322
|
// Also load learned patterns from previous task executions
|
|
292
|
-
const
|
|
293
|
-
for (const
|
|
294
|
-
const
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
TASK_PATTERN_EMBEDDINGS.set(`learned-${lp.agentType}:${kw}`, embeddings[i]);
|
|
323
|
+
const learned = learnedPatternsFromOutcomes();
|
|
324
|
+
for (const [patternName, { keywords, agents }] of Object.entries(learned)) {
|
|
325
|
+
const embeddings = keywords.map(kw => generateSimpleEmbedding(kw));
|
|
326
|
+
semanticRouter.addIntentWithEmbeddings(patternName, embeddings, { agents, keywords });
|
|
327
|
+
keywords.forEach((kw, i) => {
|
|
328
|
+
TASK_PATTERN_EMBEDDINGS.set(`${patternName}:${kw}`, embeddings[i]);
|
|
299
329
|
});
|
|
300
330
|
}
|
|
301
331
|
routerBackend = 'pure-js';
|
|
@@ -1054,18 +1084,43 @@ export const hooksPostTask = {
|
|
|
1054
1084
|
// Non-fatal
|
|
1055
1085
|
}
|
|
1056
1086
|
// Persist routing outcome for future learned pattern matching
|
|
1057
|
-
|
|
1058
|
-
|
|
1087
|
+
// Persist routing outcome for runtime learning (file-based, always reliable)
|
|
1088
|
+
const taskText = params.task || '';
|
|
1089
|
+
const outcomeKeywords = extractKeywords(taskText);
|
|
1090
|
+
let outcomePersisted = false;
|
|
1091
|
+
if (taskText && agent && agent.length <= 100 && /^[a-zA-Z0-9_-]+$/.test(agent)) {
|
|
1059
1092
|
try {
|
|
1060
|
-
|
|
1061
|
-
|
|
1093
|
+
const outcomes = loadRoutingOutcomes();
|
|
1094
|
+
outcomes.push({
|
|
1095
|
+
task: taskText,
|
|
1096
|
+
agent,
|
|
1097
|
+
success,
|
|
1098
|
+
quality,
|
|
1099
|
+
keywords: outcomeKeywords,
|
|
1100
|
+
timestamp: new Date().toISOString(),
|
|
1101
|
+
});
|
|
1102
|
+
saveRoutingOutcomes(outcomes);
|
|
1103
|
+
outcomePersisted = true;
|
|
1062
1104
|
// Sync learning metrics for dashboard
|
|
1063
1105
|
const { getAgentRouter } = await import('../services/agent-router.js');
|
|
1064
1106
|
getAgentRouter().syncLearningMetrics();
|
|
1065
1107
|
}
|
|
1066
|
-
catch {
|
|
1067
|
-
|
|
1108
|
+
catch { /* non-critical */ }
|
|
1109
|
+
}
|
|
1110
|
+
// Optionally store in memory DB for cross-session vector retrieval
|
|
1111
|
+
if (params.storeDecisions && taskText && agent) {
|
|
1112
|
+
try {
|
|
1113
|
+
const storeFn = await getRealStoreFunction();
|
|
1114
|
+
if (storeFn) {
|
|
1115
|
+
await storeFn({
|
|
1116
|
+
key: `routing-decision:${taskId}`,
|
|
1117
|
+
namespace: 'patterns',
|
|
1118
|
+
value: JSON.stringify({ task: taskText, agent, success, quality, keywords: outcomeKeywords }),
|
|
1119
|
+
tags: ['routing-decision'],
|
|
1120
|
+
});
|
|
1121
|
+
}
|
|
1068
1122
|
}
|
|
1123
|
+
catch { /* non-critical */ }
|
|
1069
1124
|
}
|
|
1070
1125
|
const duration = Date.now() - startTime;
|
|
1071
1126
|
return {
|
|
@@ -1077,6 +1132,7 @@ export const hooksPostTask = {
|
|
|
1077
1132
|
newPatterns: success ? 1 : 0,
|
|
1078
1133
|
trajectoryId: `traj-${Date.now()}`,
|
|
1079
1134
|
controller: feedbackResult?.controller || 'none',
|
|
1135
|
+
outcomePersisted,
|
|
1080
1136
|
},
|
|
1081
1137
|
quality,
|
|
1082
1138
|
feedback: feedbackResult ? {
|
|
@@ -1085,9 +1141,9 @@ export const hooksPostTask = {
|
|
|
1085
1141
|
updates: feedbackResult.updated,
|
|
1086
1142
|
} : { recorded: false, controller: 'unavailable', updates: 0 },
|
|
1087
1143
|
routingOutcome: {
|
|
1088
|
-
saved:
|
|
1144
|
+
saved: outcomePersisted,
|
|
1089
1145
|
agent: agent || null,
|
|
1090
|
-
task:
|
|
1146
|
+
task: taskText || null,
|
|
1091
1147
|
},
|
|
1092
1148
|
timestamp: new Date().toISOString(),
|
|
1093
1149
|
};
|
|
@@ -545,9 +545,13 @@ export async function findSimilarPatterns(query, options) {
|
|
|
545
545
|
const queryResult = await generateEmbedding(query);
|
|
546
546
|
queryEmbedding = queryResult.embedding;
|
|
547
547
|
}
|
|
548
|
+
// Hash-fallback embeddings (128-dim) produce lower cosine similarities
|
|
549
|
+
// than ONNX/transformer embeddings, so use a lower default threshold
|
|
550
|
+
const isHashFallback = queryEmbedding.length === 128;
|
|
551
|
+
const defaultThreshold = isHashFallback ? 0.1 : 0.5;
|
|
548
552
|
const results = reasoningBank.findSimilar(queryEmbedding, {
|
|
549
553
|
k: options?.k ?? 5,
|
|
550
|
-
threshold: options?.threshold ??
|
|
554
|
+
threshold: options?.threshold ?? defaultThreshold,
|
|
551
555
|
type: options?.type
|
|
552
556
|
});
|
|
553
557
|
return results.map((r) => ({
|
|
@@ -12,7 +12,7 @@
|
|
|
12
12
|
* Enhanced schema with pattern confidence, temporal decay, versioning
|
|
13
13
|
* Vector embeddings enabled for semantic search
|
|
14
14
|
*/
|
|
15
|
-
export declare const MEMORY_SCHEMA_V3 = "\n--
|
|
15
|
+
export declare const MEMORY_SCHEMA_V3 = "\n-- MoFlo Memory Database\n-- Version: 3.0.0\n-- Features: Pattern learning, vector embeddings, temporal decay, migration tracking\n\nPRAGMA journal_mode = WAL;\nPRAGMA synchronous = NORMAL;\nPRAGMA foreign_keys = ON;\n\n-- ============================================\n-- CORE MEMORY TABLES\n-- ============================================\n\n-- Memory entries (main storage)\nCREATE TABLE IF NOT EXISTS memory_entries (\n id TEXT PRIMARY KEY,\n key TEXT NOT NULL,\n namespace TEXT DEFAULT 'default',\n content TEXT NOT NULL,\n type TEXT DEFAULT 'semantic' CHECK(type IN ('semantic', 'episodic', 'procedural', 'working', 'pattern')),\n\n -- Vector embedding for semantic search (stored as JSON array)\n embedding TEXT,\n embedding_model TEXT DEFAULT 'local',\n embedding_dimensions INTEGER,\n\n -- Metadata\n tags TEXT, -- JSON array\n metadata TEXT, -- JSON object\n owner_id TEXT,\n\n -- Timestamps\n created_at INTEGER NOT NULL DEFAULT (strftime('%s', 'now') * 1000),\n updated_at INTEGER NOT NULL DEFAULT (strftime('%s', 'now') * 1000),\n expires_at INTEGER,\n last_accessed_at INTEGER,\n\n -- Access tracking for hot/cold detection\n access_count INTEGER DEFAULT 0,\n\n -- Status\n status TEXT DEFAULT 'active' CHECK(status IN ('active', 'archived', 'deleted')),\n\n UNIQUE(namespace, key)\n);\n\n-- Indexes for memory entries\nCREATE INDEX IF NOT EXISTS idx_memory_namespace ON memory_entries(namespace);\nCREATE INDEX IF NOT EXISTS idx_memory_key ON memory_entries(key);\nCREATE INDEX IF NOT EXISTS idx_memory_type ON memory_entries(type);\nCREATE INDEX IF NOT EXISTS idx_memory_status ON memory_entries(status);\nCREATE INDEX IF NOT EXISTS idx_memory_created ON memory_entries(created_at);\nCREATE INDEX IF NOT EXISTS idx_memory_accessed ON memory_entries(last_accessed_at);\nCREATE INDEX IF NOT EXISTS idx_memory_owner ON memory_entries(owner_id);\n\n-- ============================================\n-- PATTERN LEARNING TABLES\n-- ============================================\n\n-- Learned patterns with confidence scoring and versioning\nCREATE TABLE IF NOT EXISTS patterns (\n id TEXT PRIMARY KEY,\n\n -- Pattern identification\n name TEXT NOT NULL,\n pattern_type TEXT NOT NULL CHECK(pattern_type IN (\n 'task-routing', 'error-recovery', 'optimization', 'learning',\n 'coordination', 'prediction', 'code-pattern', 'workflow'\n )),\n\n -- Pattern definition\n condition TEXT NOT NULL, -- Regex or semantic match\n action TEXT NOT NULL, -- What to do when pattern matches\n description TEXT,\n\n -- Confidence scoring (0.0 - 1.0)\n confidence REAL DEFAULT 0.5,\n success_count INTEGER DEFAULT 0,\n failure_count INTEGER DEFAULT 0,\n\n -- Temporal decay\n decay_rate REAL DEFAULT 0.01, -- How fast confidence decays\n half_life_days INTEGER DEFAULT 30, -- Days until confidence halves without use\n\n -- Vector embedding for semantic pattern matching\n embedding TEXT,\n embedding_dimensions INTEGER,\n\n -- Versioning\n version INTEGER DEFAULT 1,\n parent_id TEXT REFERENCES patterns(id),\n\n -- Metadata\n tags TEXT, -- JSON array\n metadata TEXT, -- JSON object\n source TEXT, -- Where the pattern was learned from\n\n -- Timestamps\n created_at INTEGER NOT NULL DEFAULT (strftime('%s', 'now') * 1000),\n updated_at INTEGER NOT NULL DEFAULT (strftime('%s', 'now') * 1000),\n last_matched_at INTEGER,\n last_success_at INTEGER,\n last_failure_at INTEGER,\n\n -- Status\n status TEXT DEFAULT 'active' CHECK(status IN ('active', 'archived', 'deprecated', 'experimental'))\n);\n\n-- Indexes for patterns\nCREATE INDEX IF NOT EXISTS idx_patterns_type ON patterns(pattern_type);\nCREATE INDEX IF NOT EXISTS idx_patterns_confidence ON patterns(confidence DESC);\nCREATE INDEX IF NOT EXISTS idx_patterns_status ON patterns(status);\nCREATE INDEX IF NOT EXISTS idx_patterns_last_matched ON patterns(last_matched_at);\n\n-- Pattern evolution history (for versioning)\nCREATE TABLE IF NOT EXISTS pattern_history (\n id INTEGER PRIMARY KEY AUTOINCREMENT,\n pattern_id TEXT NOT NULL REFERENCES patterns(id),\n version INTEGER NOT NULL,\n\n -- Snapshot of pattern state\n confidence REAL,\n success_count INTEGER,\n failure_count INTEGER,\n condition TEXT,\n action TEXT,\n\n -- What changed\n change_type TEXT CHECK(change_type IN ('created', 'updated', 'success', 'failure', 'decay', 'merged', 'split')),\n change_reason TEXT,\n\n created_at INTEGER NOT NULL DEFAULT (strftime('%s', 'now') * 1000)\n);\n\nCREATE INDEX IF NOT EXISTS idx_pattern_history_pattern ON pattern_history(pattern_id);\n\n-- ============================================\n-- LEARNING & TRAJECTORY TABLES\n-- ============================================\n\n-- Learning trajectories (SONA integration)\nCREATE TABLE IF NOT EXISTS trajectories (\n id TEXT PRIMARY KEY,\n session_id TEXT,\n\n -- Trajectory state\n status TEXT DEFAULT 'active' CHECK(status IN ('active', 'completed', 'failed', 'abandoned')),\n verdict TEXT CHECK(verdict IN ('success', 'failure', 'partial', NULL)),\n\n -- Context\n task TEXT,\n context TEXT, -- JSON object\n\n -- Metrics\n total_steps INTEGER DEFAULT 0,\n total_reward REAL DEFAULT 0,\n\n -- Timestamps\n started_at INTEGER NOT NULL DEFAULT (strftime('%s', 'now') * 1000),\n ended_at INTEGER,\n\n -- Reference to extracted pattern (if any)\n extracted_pattern_id TEXT REFERENCES patterns(id)\n);\n\n-- Trajectory steps\nCREATE TABLE IF NOT EXISTS trajectory_steps (\n id INTEGER PRIMARY KEY AUTOINCREMENT,\n trajectory_id TEXT NOT NULL REFERENCES trajectories(id),\n step_number INTEGER NOT NULL,\n\n -- Step data\n action TEXT NOT NULL,\n observation TEXT,\n reward REAL DEFAULT 0,\n\n -- Metadata\n metadata TEXT, -- JSON object\n\n created_at INTEGER NOT NULL DEFAULT (strftime('%s', 'now') * 1000)\n);\n\nCREATE INDEX IF NOT EXISTS idx_steps_trajectory ON trajectory_steps(trajectory_id);\n\n-- ============================================\n-- MIGRATION STATE TRACKING\n-- ============================================\n\n-- Migration state (for resume capability)\nCREATE TABLE IF NOT EXISTS migration_state (\n id TEXT PRIMARY KEY,\n migration_type TEXT NOT NULL, -- 'v2-to-v3', 'pattern', 'memory', etc.\n\n -- Progress tracking\n status TEXT DEFAULT 'pending' CHECK(status IN ('pending', 'in_progress', 'completed', 'failed', 'rolled_back')),\n total_items INTEGER DEFAULT 0,\n processed_items INTEGER DEFAULT 0,\n failed_items INTEGER DEFAULT 0,\n skipped_items INTEGER DEFAULT 0,\n\n -- Current position (for resume)\n current_batch INTEGER DEFAULT 0,\n last_processed_id TEXT,\n\n -- Source/destination info\n source_path TEXT,\n source_type TEXT,\n destination_path TEXT,\n\n -- Backup info\n backup_path TEXT,\n backup_created_at INTEGER,\n\n -- Error tracking\n last_error TEXT,\n errors TEXT, -- JSON array of errors\n\n -- Timestamps\n started_at INTEGER,\n completed_at INTEGER,\n created_at INTEGER NOT NULL DEFAULT (strftime('%s', 'now') * 1000),\n updated_at INTEGER NOT NULL DEFAULT (strftime('%s', 'now') * 1000)\n);\n\n-- ============================================\n-- SESSION MANAGEMENT\n-- ============================================\n\n-- Sessions for context persistence\nCREATE TABLE IF NOT EXISTS sessions (\n id TEXT PRIMARY KEY,\n\n -- Session state\n state TEXT NOT NULL, -- JSON object with full session state\n status TEXT DEFAULT 'active' CHECK(status IN ('active', 'paused', 'completed', 'expired')),\n\n -- Context\n project_path TEXT,\n branch TEXT,\n\n -- Metrics\n tasks_completed INTEGER DEFAULT 0,\n patterns_learned INTEGER DEFAULT 0,\n\n -- Timestamps\n created_at INTEGER NOT NULL DEFAULT (strftime('%s', 'now') * 1000),\n updated_at INTEGER NOT NULL DEFAULT (strftime('%s', 'now') * 1000),\n expires_at INTEGER\n);\n\n-- ============================================\n-- VECTOR INDEX METADATA (for HNSW)\n-- ============================================\n\n-- Track HNSW index state\nCREATE TABLE IF NOT EXISTS vector_indexes (\n id TEXT PRIMARY KEY,\n name TEXT NOT NULL UNIQUE,\n\n -- Index configuration\n dimensions INTEGER NOT NULL,\n metric TEXT DEFAULT 'cosine' CHECK(metric IN ('cosine', 'euclidean', 'dot')),\n\n -- HNSW parameters\n hnsw_m INTEGER DEFAULT 16,\n hnsw_ef_construction INTEGER DEFAULT 200,\n hnsw_ef_search INTEGER DEFAULT 100,\n\n -- Quantization\n quantization_type TEXT CHECK(quantization_type IN ('none', 'scalar', 'product')),\n quantization_bits INTEGER DEFAULT 8,\n\n -- Statistics\n total_vectors INTEGER DEFAULT 0,\n last_rebuild_at INTEGER,\n\n created_at INTEGER NOT NULL DEFAULT (strftime('%s', 'now') * 1000),\n updated_at INTEGER NOT NULL DEFAULT (strftime('%s', 'now') * 1000)\n);\n\n-- ============================================\n-- SYSTEM METADATA\n-- ============================================\n\nCREATE TABLE IF NOT EXISTS metadata (\n key TEXT PRIMARY KEY,\n value TEXT NOT NULL,\n updated_at INTEGER DEFAULT (strftime('%s', 'now') * 1000)\n);\n";
|
|
16
16
|
interface HNSWEntry {
|
|
17
17
|
id: string;
|
|
18
18
|
key: string;
|