tasq/node_modules/agentic-flow/dist/mcp/fastmcp/tools/hooks/pre-edit.js

121 lines
4.8 KiB
JavaScript

/**
* Pre-Edit Hook - Context retrieval and agent routing before file edit
* Latency target: <20ms
*
* NOW WITH RUVECTOR INTELLIGENCE:
* - Trajectory tracking for learning from edit sequences
* - HNSW-powered similar file retrieval
* - SONA pattern matching for agent selection
*/
import { z } from 'zod';
import * as path from 'path';
import { loadIntelligence, getAgentForFile, simpleEmbed, cosineSimilarity } from './shared.js';
import { beginTaskTrajectory, findSimilarPatterns } from './intelligence-bridge.js';
// Store active trajectory IDs for continuation in post-edit
const activeEditTrajectories = new Map();
// Export for post-edit to access
export { activeEditTrajectories };
export const hookPreEditTool = {
name: 'hook_pre_edit',
description: 'Pre-edit intelligence: retrieve context, suggest agent, find related files',
parameters: z.object({
filePath: z.string().describe('Path to file being edited'),
task: z.string().optional().describe('Optional task description')
}),
execute: async ({ filePath, task }, { onProgress }) => {
const startTime = Date.now();
const intel = loadIntelligence();
const ext = path.extname(filePath);
const dir = path.dirname(filePath);
// START TRAJECTORY TRACKING (RuVector Intelligence)
let trajectoryId = null;
let intelligenceEnabled = false;
let similarPatterns = [];
try {
// Begin trajectory for this edit
const taskDesc = task || `Edit ${path.basename(filePath)}`;
const trajectoryResult = await beginTaskTrajectory(taskDesc, getAgentForFile(filePath));
if (trajectoryResult.success && trajectoryResult.trajectoryId >= 0) {
trajectoryId = trajectoryResult.trajectoryId;
activeEditTrajectories.set(filePath, trajectoryId);
intelligenceEnabled = true;
}
// Find similar past edits using HNSW (150x faster)
similarPatterns = await findSimilarPatterns(taskDesc, 3);
}
catch (error) {
// Continue without trajectory if intelligence not available
console.debug('[PreEdit] Intelligence not available:', error);
}
// 1. Determine suggested agent from patterns
const state = `edit:${ext}`;
let suggestedAgent = getAgentForFile(filePath);
let confidence = 0.5;
// Check learned patterns
if (intel.patterns[state]) {
const agents = intel.patterns[state];
let bestAgent = suggestedAgent;
let bestScore = 0;
for (const [agent, score] of Object.entries(agents)) {
if (score > bestScore) {
bestScore = score;
bestAgent = agent;
}
}
if (bestScore > 0) {
suggestedAgent = bestAgent;
confidence = Math.min(0.9, 0.5 + bestScore / 10);
}
}
// Check directory patterns
if (intel.dirPatterns[dir]) {
suggestedAgent = intel.dirPatterns[dir];
confidence = Math.max(confidence, 0.6);
}
// 2. Find related files from co-edit sequences
const relatedFiles = [];
if (intel.sequences[filePath]) {
relatedFiles.push(...intel.sequences[filePath]
.sort((a, b) => b.score - a.score)
.slice(0, 5));
}
// 3. Retrieve relevant memories
const memories = [];
if (task && intel.memories.length > 0) {
const taskEmbed = simpleEmbed(task);
for (const mem of intel.memories) {
if (mem.embedding) {
const score = cosineSimilarity(taskEmbed, mem.embedding);
if (score > 0.3) {
memories.push({ content: mem.content.slice(0, 200), score });
}
}
}
memories.sort((a, b) => b.score - a.score);
memories.splice(3); // Keep top 3
}
// 4. Check for relevant error patterns
const errorHints = [];
for (const ep of intel.errorPatterns) {
if (ep.context.includes(ext) || ep.context.includes(path.basename(filePath))) {
errorHints.push(ep.resolution);
}
}
const latency = Date.now() - startTime;
return {
success: true,
suggestedAgent,
confidence,
relatedFiles,
memories,
errorHints: errorHints.slice(0, 2),
// RuVector Intelligence additions
trajectoryId,
intelligenceEnabled,
similarPatterns: similarPatterns.slice(0, 3),
latencyMs: latency,
timestamp: new Date().toISOString()
};
}
};
//# sourceMappingURL=pre-edit.js.map