23f7624596
ADR-166 MCP Bridge Security Lock / Static-source security lock (push) Failing after 0s
ADR-166 MCP Bridge Security Lock / Compose default binds loopback + Mongo has auth (push) Failing after 2s
CodeQL Advanced / Analyze (rust) (push) Failing after 0s
ADR-166 MCP Bridge Security Lock / plugin-agent-federation bindHost default (push) Failing after 1s
ADR-166 MCP Bridge Security Lock / Runtime behavior — 401 + terminal gate + fail-closed (push) Failing after 4s
business-pods-smoke / smoke (push) Failing after 1s
all-plugins-smoke / smoke-all (push) Failing after 2s
CI/CD Pipeline / Security & Code Quality (push) Failing after 1s
CI/CD Pipeline / Test Suite (ubuntu-latest) (push) Failing after 1s
CI/CD Pipeline / Build & Package (macos-latest) (push) Has been skipped
CI/CD Pipeline / Build & Package (ubuntu-latest) (push) Has been skipped
CI/CD Pipeline / Build & Package (windows-latest) (push) Has been skipped
CI/CD Pipeline / Documentation & Examples (push) Failing after 1s
Clone Tracker (14-day rolling) / Snapshot clones for ruflo ecosystem (push) Failing after 1s
CodeQL Advanced / Analyze (actions) (push) Failing after 1s
CodeQL Advanced / Analyze (javascript-typescript) (push) Failing after 1s
federation-peer-rust / stable-noop (push) Failing after 1s
metaharness-ci / score (push) Failing after 1s
metaharness-ci / router-compat (push) Failing after 0s
metaharness-ci / similarity-tests (push) Failing after 0s
no-agentbbs-smoke / smoke-without-agentbbs (push) Failing after 1s
V3 CI/CD Pipeline / Build V3 (windows-latest) (push) Has been skipped
codex-integration-audit / Codex integration audit (push) Failing after 1s
helpers-manifest-guard / guard (push) Failing after 1s
🔗 Cross-Agent Integration Tests / 🤝 Agent Coordination Tests (push) Has been skipped
🔗 Cross-Agent Integration Tests / 🧠 Memory Sharing Integration (push) Has been skipped
🔗 Cross-Agent Integration Tests / 🛡️ Fault Tolerance Tests (push) Has been skipped
🔗 Cross-Agent Integration Tests / ⚡ Performance Integration Tests (push) Has been skipped
metaharness-ci / mcp-scan (push) Failing after 1s
metaharness-ci / eject-dryrun (push) Failing after 1s
metaharness-ci / metaharness-real-data (push) Failing after 0s
no-cli-optdep-bloat-2561 / guard (push) Failing after 1s
no-metaharness-smoke / smoke-without-metaharness (push) Failing after 1s
no-phantom-agentic-flow-subpath / guard (push) Failing after 1s
🔄 Automated Rollback Manager / 🚨 Failure Detection (push) Failing after 1s
V3 CI/CD Pipeline / Plugin hooks smoke / ubuntu-latest / Node 22 (push) Failing after 1s
V3 CI/CD Pipeline / ruflo-graph-intelligence build + test smoke (#2044, ADR-123) (push) Failing after 1s
CVE Audit Gate / Audit root (critical-blocking) (push) Failing after 2s
cost-tracker-smoke / smoke (push) Failing after 3s
oia-audit-weekly / audit (push) Failing after 2s
ruflo-agent-smoke / ruflo-agent structural smoke (push) Failing after 1s
📊 Status Badges Update / 📊 Update Status Badges (push) Failing after 1s
V3 CI/CD Pipeline / Static regression guards (#2267 YAML + (push) Failing after 1s
V3 CI/CD Pipeline / Test V3 Packages (push) Failing after 0s
V3 CI/CD Pipeline / agent_execute provider routing smoke (#2042) (push) Failing after 0s
CVE Audit Gate / Audit v3 (critical-blocking) (push) Failing after 1s
federation-peer-rust / stable-native (push) Failing after 2s
🔗 Cross-Agent Integration Tests / 🚀 Integration Test Setup (push) Failing after 2s
neural-trader-smoke / runtime-smoke (push) Failing after 1s
V3 CI/CD Pipeline / Build V3 (macos-latest) (push) Has been skipped
V3 CI/CD Pipeline / Build V3 (ubuntu-latest) (push) Has been skipped
V3 CI/CD Pipeline / Type Check V3 (push) Failing after 1s
V3 CI/CD Pipeline / Smoke (no better-sqlite3) / ubuntu-latest / Node 24 (push) Failing after 1s
V3 CI/CD Pipeline / Smoke (no better-sqlite3) / ubuntu-latest / Node 22 (push) Failing after 2s
V3 CI/CD Pipeline / browser rvf create flag smoke (#2015) (push) Failing after 0s
V3 CI/CD Pipeline / Dependency review (#2046) (push) Has been skipped
V3 CI/CD Pipeline / Supply-chain audit (#2046) (push) Failing after 0s
V3 CI/CD Pipeline / witness marker drift smoke (#2021) (push) Failing after 1s
V3 CI/CD Pipeline / neural-trader portfolio CG smoke (#2068, ADR-126 Phase 3) (push) Failing after 1s
V3 CI/CD Pipeline / neural-trader backtest signing smoke (#2068, ADR-126 Phase 4) (push) Failing after 1s
V3 CI/CD Pipeline / kg-extract type-import classification smoke (#2049) (push) Failing after 0s
V3 CI/CD Pipeline / witness verify precondition smoke (#1880) (push) Failing after 2s
V3 CI/CD Pipeline / neural-trader pipeline risk-gate smoke (#2068, ADR-126 Phase 5) (push) Failing after 0s
V3 CI/CD Pipeline / neural-trader feature attribution smoke (#2068, ADR-126 Phase 6) (push) Failing after 0s
V3 CI/CD Pipeline / plugin-registry signature verification smoke (#1922, CWE-347) (push) Failing after 4s
V3 CI/CD Pipeline / memory stats legacy-DB smoke (#2120) (push) Failing after 4s
V3 CI/CD Pipeline / github deprecated actions smoke (#2089, ADR-127 Phase 3) (push) Failing after 1s
V3 CI/CD Pipeline / graph query + pathfinder smoke (ADR-130 P2+P5) (push) Has been skipped
V3 CI/CD Pipeline / graph trajectory hooks smoke (ADR-130 P3) (push) Has been skipped
V3 CI/CD Pipeline / graph plugin adapter smoke (ADR-130 P4) (push) Has been skipped
V3 CI/CD Pipeline / graph benchmark (ADR-130 P6) (push) Has been skipped
V3 CI/CD Pipeline / statusline generator delegation smoke (#2195) (push) Failing after 1s
V3 CI/CD Pipeline / wizard init regression guard (#2206 (push) Failing after 1s
V3 CI/CD Pipeline / memory no-stray-db smoke (ADR-125 P7) (push) Failing after 1s
V3 CI/CD Pipeline / github-safe injection smoke (#2089, ADR-127 Phase 1) (push) Failing after 1s
V3 CI/CD Pipeline / github actions pin smoke (#2089, ADR-127 Phase 1) (push) Failing after 1s
V3 CI/CD Pipeline / github attribution opt-in smoke (#2089, ADR-127 Phase 4) (push) Failing after 1s
V3 CI/CD Pipeline / pre-bash hook safety smoke (#2017) (push) Failing after 1s
V3 CI/CD Pipeline / Memory import smoke / ubuntu-latest (push) Failing after 0s
V3 CI/CD Pipeline / MCP protocol smoke / ubuntu-latest (push) Failing after 2s
V3 CI/CD Pipeline / ruvllm WASM auto-init smoke (#2086) (push) Failing after 4s
V3 CI/CD Pipeline / MCP paired-tool round-trip smoke (#1889) (push) Failing after 1s
V3 CI/CD Pipeline / Plugin package install-safety (#1902/#1903/#1904) (push) Failing after 1s
V3 CI/CD Pipeline / Tool description discoverability (ADR-112) (push) Failing after 3s
V3 CI/CD Pipeline / CLI npx-install smoke (#1147 / (22) (push) Failing after 1s
V3 CI/CD Pipeline / CLI npx-install smoke (#1147 / (24) (push) Failing after 1s
V3 CI/CD Pipeline / Windows hook shim smoke (#2132) / ubuntu-latest (push) Failing after 2s
V3 CI/CD Pipeline / Windows hook execution smoke (#2132) / ubuntu-latest (push) Failing after 1s
V3 CI/CD Pipeline / Windows init hooks smoke (#2132) / ubuntu-latest (push) Failing after 1s
V3 CI/CD Pipeline / Vector-index dimension audit (#1947) (push) Failing after 0s
V3 CI/CD Pipeline / Hook-command install safety (#1921) (push) Failing after 1s
V3 CI/CD Pipeline / ToolOutputGuardrail smoke (ADR-131, (push) Failing after 1s
V3 CI/CD Pipeline / init-bundle invariants smoke (#2095, ADR-128 Phase 5) (push) Failing after 1s
V3 CI/CD Pipeline / wasm provider bridge smoke (ADR-129 P1) (push) Failing after 2s
V3 CI/CD Pipeline / wasm gallery CRUD smoke (ADR-129 P3) (push) Failing after 1s
V3 CI/CD Pipeline / wasm plugin bridge smoke (ADR-129 P4) (push) Failing after 0s
V3 CI/CD Pipeline / wasm compose smoke (ADR-129 P2) (push) Failing after 4s
V3 CI/CD Pipeline / graph schema smoke (ADR-130 P1) (push) Failing after 0s
Validate Marketplace / validate (push) Failing after 1s
🔍 Verification Pipeline / 🚀 Setup Verification (push) Failing after 1s
🔍 Verification Pipeline / 🛡️ Security Verification (push) Has been skipped
🔍 Verification Pipeline / 📝 Code Quality (push) Has been skipped
🔍 Verification Pipeline / 🧪 Test Verification (${{ matrix.os }}, Node ${{ matrix.node }}) (push) Has been skipped
🔍 Verification Pipeline / 🏗️ Build Verification (push) Has been skipped
🔍 Verification Pipeline / 📚 Documentation Verification (push) Has been skipped
CVE Audit Gate / High-severity report (warn only) (push) Has been cancelled
🔄 Automated Rollback Manager / 🔄 Execute Rollback (push) Has been cancelled
🔄 Automated Rollback Manager / ✅ Post-Rollback Verification (push) Has been cancelled
🔄 Automated Rollback Manager / 📊 Rollback Monitoring (push) Has been cancelled
V3 CI/CD Pipeline / Windows init hooks smoke (#2132) / windows-latest (push) Has been cancelled
V3 CI/CD Pipeline / Windows hook execution smoke (#2132) / macos-latest (push) Has been cancelled
V3 CI/CD Pipeline / Windows hook execution smoke (#2132) / windows-latest (push) Has been cancelled
🔄 Automated Rollback Manager / ⏳ Manual Rollback Approval (push) Has been cancelled
V3 CI/CD Pipeline / MCP protocol smoke / macos-latest (push) Has been cancelled
V3 CI/CD Pipeline / Memory import smoke / macos-latest (push) Has been cancelled
V3 CI/CD Pipeline / Windows hook shim smoke (#2132) / macos-latest (push) Has been cancelled
V3 CI/CD Pipeline / Windows hook shim smoke (#2132) / windows-latest (push) Has been cancelled
V3 CI/CD Pipeline / Windows init hooks smoke (#2132) / macos-latest (push) Has been cancelled
V3 CI/CD Pipeline / Witness verify (signed manifest) / macos-latest (push) Has been cancelled
V3 CI/CD Pipeline / Witness verify (signed manifest) / ubuntu-latest (push) Has been cancelled
V3 CI/CD Pipeline / Witness verify (signed manifest) / windows-latest (push) Has been cancelled
V3 CI/CD Pipeline / Publish to npm (alpha) (push) Has been cancelled
V3 CI/CD Pipeline / Smoke (no better-sqlite3) / macos-latest / Node 22 (push) Has been cancelled
V3 CI/CD Pipeline / Plugin hooks smoke / macos-latest / Node 22 (push) Has been cancelled
CI/CD Pipeline / Deploy & Release (push) Has been cancelled
CI/CD Pipeline / CI Status (push) Has been cancelled
🔗 Cross-Agent Integration Tests / 📊 Integration Test Report (push) Has been cancelled
🔄 Automated Rollback Manager / 🔍 Pre-Rollback Validation (push) Has been cancelled
🔍 Verification Pipeline / ⚡ Performance Verification (push) Has been cancelled
🔍 Verification Pipeline / 📊 Verification Report (push) Has been cancelled
355 lines
14 KiB
TypeScript
355 lines
14 KiB
TypeScript
/**
|
|
* Intent Router Plugin
|
|
*
|
|
* Smart query → agent/tool mapping using @ruvector/wasm semantic matching.
|
|
* Routes user intents to optimal handlers with confidence scoring.
|
|
*
|
|
* Features:
|
|
* - Semantic intent classification (<1ms)
|
|
* - Multi-label routing (can route to multiple handlers)
|
|
* - Confidence-based fallback
|
|
* - Intent history for optimization
|
|
* - Dynamic route learning
|
|
*
|
|
* @example
|
|
* ```typescript
|
|
* import { intentRouterPlugin } from '@claude-flow/plugins/examples/ruvector-plugins';
|
|
* await getDefaultRegistry().register(intentRouterPlugin);
|
|
* ```
|
|
*/
|
|
|
|
import {
|
|
PluginBuilder,
|
|
MCPToolBuilder,
|
|
HookBuilder,
|
|
HookEvent,
|
|
HookPriority,
|
|
Security,
|
|
} from '../../src/index.js';
|
|
|
|
// Import shared vector utilities (consolidated from all plugins)
|
|
import {
|
|
IVectorDB,
|
|
createVectorDB,
|
|
generateHashEmbedding,
|
|
} from './shared/vector-utils.js';
|
|
|
|
// ============================================================================
|
|
// Types
|
|
// ============================================================================
|
|
|
|
export interface Intent {
|
|
id: string;
|
|
pattern: string;
|
|
category: string;
|
|
handlers: IntentHandler[];
|
|
priority: number;
|
|
examples: string[];
|
|
embedding?: Float32Array;
|
|
metadata: {
|
|
createdAt: Date;
|
|
updatedAt: Date;
|
|
usageCount: number;
|
|
successRate: number;
|
|
};
|
|
}
|
|
|
|
export interface IntentHandler {
|
|
type: 'agent' | 'tool' | 'workflow' | 'skill';
|
|
name: string;
|
|
config?: Record<string, unknown>;
|
|
weight: number;
|
|
}
|
|
|
|
export interface RouteResult {
|
|
intent: Intent;
|
|
confidence: number;
|
|
handlers: Array<IntentHandler & { score: number }>;
|
|
alternatives: Array<{ intent: Intent; confidence: number }>;
|
|
}
|
|
|
|
export interface RouterConfig {
|
|
minConfidence: number;
|
|
maxAlternatives: number;
|
|
enableLearning: boolean;
|
|
defaultHandler?: IntentHandler;
|
|
}
|
|
|
|
// ============================================================================
|
|
// Intent Router Core
|
|
// ============================================================================
|
|
|
|
export class IntentRouter {
|
|
private vectorDb: IVectorDB | null = null;
|
|
private intents = new Map<string, Intent>();
|
|
private routeHistory: Array<{ query: string; intentId: string; success: boolean; timestamp: Date }> = [];
|
|
private config: RouterConfig;
|
|
private dimensions = 768;
|
|
private nextId = 1;
|
|
private initPromise: Promise<void> | null = null;
|
|
|
|
constructor(config?: Partial<RouterConfig>) {
|
|
this.config = {
|
|
minConfidence: 0.4,
|
|
maxAlternatives: 3,
|
|
enableLearning: true,
|
|
...config,
|
|
};
|
|
}
|
|
|
|
async initialize(): Promise<void> {
|
|
if (this.vectorDb) return;
|
|
if (this.initPromise) return this.initPromise;
|
|
|
|
this.initPromise = (async () => {
|
|
this.vectorDb = await createVectorDB(this.dimensions);
|
|
await this.initializeDefaultIntents();
|
|
})();
|
|
|
|
return this.initPromise;
|
|
}
|
|
|
|
private async ensureInitialized(): Promise<IVectorDB> {
|
|
await this.initialize();
|
|
return this.vectorDb!;
|
|
}
|
|
|
|
/**
|
|
* Register a new intent pattern.
|
|
*/
|
|
async registerIntent(
|
|
pattern: string,
|
|
category: string,
|
|
handlers: IntentHandler[],
|
|
options?: { priority?: number; examples?: string[] }
|
|
): Promise<Intent> {
|
|
const db = await this.ensureInitialized();
|
|
|
|
const safePattern = Security.validateString(pattern, { maxLength: 500 });
|
|
const safeCategory = Security.validateString(category, { maxLength: 100 });
|
|
|
|
const id = `intent-${this.nextId++}`;
|
|
const examples = options?.examples ?? [];
|
|
const allText = [safePattern, ...examples].join(' ');
|
|
const embedding = this.generateEmbedding(allText);
|
|
|
|
const intent: Intent = {
|
|
id,
|
|
pattern: safePattern,
|
|
category: safeCategory,
|
|
handlers,
|
|
priority: options?.priority ?? 0,
|
|
examples,
|
|
embedding,
|
|
metadata: { createdAt: new Date(), updatedAt: new Date(), usageCount: 0, successRate: 1.0 },
|
|
};
|
|
|
|
db.insert(embedding, id, { pattern: safePattern, category: safeCategory, priority: intent.priority });
|
|
this.intents.set(id, intent);
|
|
return intent;
|
|
}
|
|
|
|
/**
|
|
* Route a query to the best matching intent handlers (<1ms).
|
|
*/
|
|
async route(query: string): Promise<RouteResult> {
|
|
const db = await this.ensureInitialized();
|
|
|
|
const safeQuery = Security.validateString(query, { maxLength: 1000 });
|
|
const queryEmbedding = this.generateEmbedding(safeQuery);
|
|
const searchResults = db.search(queryEmbedding, this.config.maxAlternatives + 1);
|
|
|
|
if (searchResults.length === 0 || searchResults[0].score < this.config.minConfidence) {
|
|
if (this.config.defaultHandler) {
|
|
const fallbackIntent: Intent = {
|
|
id: 'fallback', pattern: 'default', category: 'general',
|
|
handlers: [this.config.defaultHandler], priority: -1, examples: [],
|
|
metadata: { createdAt: new Date(), updatedAt: new Date(), usageCount: 0, successRate: 0 },
|
|
};
|
|
return { intent: fallbackIntent, confidence: 0, handlers: [{ ...this.config.defaultHandler, score: 0 }], alternatives: [] };
|
|
}
|
|
throw new Error('No matching intent found');
|
|
}
|
|
|
|
const bestMatch = searchResults[0];
|
|
const intent = this.intents.get(bestMatch.id)!;
|
|
|
|
intent.metadata.usageCount++;
|
|
intent.metadata.updatedAt = new Date();
|
|
|
|
if (this.config.enableLearning) {
|
|
this.routeHistory.push({ query: safeQuery, intentId: intent.id, success: true, timestamp: new Date() });
|
|
if (this.routeHistory.length > 1000) this.routeHistory = this.routeHistory.slice(-500);
|
|
}
|
|
|
|
const scoredHandlers = intent.handlers.map(h => ({ ...h, score: h.weight * bestMatch.score })).sort((a, b) => b.score - a.score);
|
|
const alternatives = searchResults.slice(1, this.config.maxAlternatives + 1)
|
|
.filter(r => r.score >= this.config.minConfidence * 0.7)
|
|
.map(r => ({ intent: this.intents.get(r.id)!, confidence: r.score }))
|
|
.filter(a => a.intent);
|
|
|
|
return { intent, confidence: bestMatch.score, handlers: scoredHandlers, alternatives };
|
|
}
|
|
|
|
/**
|
|
* Provide feedback on a routing decision.
|
|
*/
|
|
async feedback(intentId: string, success: boolean): Promise<void> {
|
|
const intent = this.intents.get(intentId);
|
|
if (!intent) return;
|
|
|
|
const alpha = 0.1;
|
|
intent.metadata.successRate = alpha * (success ? 1 : 0) + (1 - alpha) * intent.metadata.successRate;
|
|
|
|
const lastRoute = this.routeHistory.find(r => r.intentId === intentId);
|
|
if (lastRoute) lastRoute.success = success;
|
|
}
|
|
|
|
/**
|
|
* Get router statistics.
|
|
*/
|
|
getStats(): {
|
|
totalIntents: number;
|
|
byCategory: Record<string, number>;
|
|
topIntents: Array<{ id: string; pattern: string; usageCount: number; successRate: number }>;
|
|
recentRoutes: number;
|
|
} {
|
|
const byCategory: Record<string, number> = {};
|
|
for (const intent of this.intents.values()) {
|
|
byCategory[intent.category] = (byCategory[intent.category] ?? 0) + 1;
|
|
}
|
|
|
|
const topIntents = Array.from(this.intents.values())
|
|
.sort((a, b) => b.metadata.usageCount - a.metadata.usageCount)
|
|
.slice(0, 5)
|
|
.map(i => ({ id: i.id, pattern: i.pattern, usageCount: i.metadata.usageCount, successRate: i.metadata.successRate }));
|
|
|
|
return { totalIntents: this.intents.size, byCategory, topIntents, recentRoutes: this.routeHistory.length };
|
|
}
|
|
|
|
listIntents(): Intent[] {
|
|
return Array.from(this.intents.values()).sort((a, b) => b.priority - a.priority);
|
|
}
|
|
|
|
// =========================================================================
|
|
// Private Helpers
|
|
// =========================================================================
|
|
|
|
private async initializeDefaultIntents(): Promise<void> {
|
|
const defaults: Array<{ pattern: string; category: string; handlers: IntentHandler[]; priority: number; examples: string[] }> = [
|
|
{ pattern: 'write code implement function', category: 'coding', handlers: [{ type: 'agent', name: 'coder', weight: 1.0 }], priority: 10, examples: ['create a function', 'implement feature'] },
|
|
{ pattern: 'review code analyze quality', category: 'coding', handlers: [{ type: 'agent', name: 'reviewer', weight: 1.0 }], priority: 10, examples: ['review my code', 'check for bugs'] },
|
|
{ pattern: 'test write unit test', category: 'testing', handlers: [{ type: 'agent', name: 'tester', weight: 1.0 }], priority: 10, examples: ['write tests', 'add unit tests'] },
|
|
{ pattern: 'search find research', category: 'research', handlers: [{ type: 'agent', name: 'researcher', weight: 1.0 }, { type: 'tool', name: 'WebSearch', weight: 0.8 }], priority: 8, examples: ['look up', 'research topic'] },
|
|
{ pattern: 'plan design architecture', category: 'planning', handlers: [{ type: 'agent', name: 'planner', weight: 1.0 }], priority: 8, examples: ['plan implementation', 'design system'] },
|
|
{ pattern: 'read file open', category: 'files', handlers: [{ type: 'tool', name: 'Read', weight: 1.0 }], priority: 5, examples: ['show me file', 'read content'] },
|
|
{ pattern: 'edit modify change', category: 'files', handlers: [{ type: 'tool', name: 'Edit', weight: 1.0 }], priority: 5, examples: ['change this', 'update file'] },
|
|
{ pattern: 'search grep find', category: 'files', handlers: [{ type: 'tool', name: 'Grep', weight: 1.0 }, { type: 'tool', name: 'Glob', weight: 0.8 }], priority: 5, examples: ['find in files', 'search codebase'] },
|
|
{ pattern: 'commit git save', category: 'git', handlers: [{ type: 'skill', name: 'commit', weight: 1.0 }], priority: 7, examples: ['commit changes', 'save to git'] },
|
|
{ pattern: 'swarm coordinate agents', category: 'swarm', handlers: [{ type: 'agent', name: 'hierarchical-coordinator', weight: 1.0 }], priority: 9, examples: ['run swarm', 'coordinate agents'] },
|
|
];
|
|
|
|
for (const def of defaults) {
|
|
await this.registerIntent(def.pattern, def.category, def.handlers, { priority: def.priority, examples: def.examples });
|
|
}
|
|
}
|
|
|
|
private generateEmbedding(text: string): Float32Array {
|
|
const embedding = new Float32Array(this.dimensions);
|
|
const normalized = text.toLowerCase();
|
|
let hash = 0;
|
|
for (let i = 0; i < normalized.length; i++) { hash = ((hash << 5) - hash) + normalized.charCodeAt(i); hash = hash & hash; }
|
|
for (let i = 0; i < this.dimensions; i++) { embedding[i] = Math.sin(hash * (i + 1) * 0.001) * 0.5 + 0.5; }
|
|
let norm = 0;
|
|
for (let i = 0; i < this.dimensions; i++) norm += embedding[i] * embedding[i];
|
|
norm = Math.sqrt(norm);
|
|
for (let i = 0; i < this.dimensions; i++) embedding[i] /= norm;
|
|
return embedding;
|
|
}
|
|
}
|
|
|
|
// ============================================================================
|
|
// Plugin Definition
|
|
// ============================================================================
|
|
|
|
let routerInstance: IntentRouter | null = null;
|
|
|
|
async function getRouter(): Promise<IntentRouter> {
|
|
if (!routerInstance) {
|
|
routerInstance = new IntentRouter({ defaultHandler: { type: 'agent', name: 'general-purpose', weight: 0.5 } });
|
|
await routerInstance.initialize();
|
|
}
|
|
return routerInstance;
|
|
}
|
|
|
|
export const intentRouterPlugin = new PluginBuilder('intent-router', '1.0.0')
|
|
.withDescription('Smart intent → handler routing using @ruvector/wasm HNSW (<1ms)')
|
|
.withAuthor('Claude Flow Team')
|
|
.withTags(['routing', 'intent', 'semantic', 'ruvector', 'hnsw'])
|
|
.withMCPTools([
|
|
new MCPToolBuilder('intent-route')
|
|
.withDescription('Route a query to best handlers (<1ms)')
|
|
.addStringParam('query', 'User query or intent', { required: true })
|
|
.withHandler(async (params) => {
|
|
try {
|
|
const router = await getRouter();
|
|
const result = await router.route(params.query as string);
|
|
const handlersOutput = result.handlers.map((h, i) => ` ${i + 1}. [${h.type}] ${h.name} (${(h.score * 100).toFixed(0)}%)`).join('\n');
|
|
return { content: [{ type: 'text', text: `🎯 **${result.intent.pattern}** (${(result.confidence * 100).toFixed(0)}%)\n\n**Handlers:**\n${handlersOutput}` }] };
|
|
} catch (error) {
|
|
return { content: [{ type: 'text', text: `❌ Error: ${error instanceof Error ? error.message : String(error)}` }], isError: true };
|
|
}
|
|
})
|
|
.build(),
|
|
|
|
new MCPToolBuilder('intent-register')
|
|
.withDescription('Register a new intent')
|
|
.addStringParam('pattern', 'Intent pattern', { required: true })
|
|
.addStringParam('category', 'Category', { required: true })
|
|
.addStringParam('handlers', 'JSON handlers [{type, name, weight}]', { required: true })
|
|
.withHandler(async (params) => {
|
|
try {
|
|
const router = await getRouter();
|
|
const handlers = JSON.parse(params.handlers as string) as IntentHandler[];
|
|
const intent = await router.registerIntent(params.pattern as string, params.category as string, handlers);
|
|
return { content: [{ type: 'text', text: `✅ Registered: ${intent.id}` }] };
|
|
} catch (error) {
|
|
return { content: [{ type: 'text', text: `❌ Error: ${error instanceof Error ? error.message : String(error)}` }], isError: true };
|
|
}
|
|
})
|
|
.build(),
|
|
|
|
new MCPToolBuilder('intent-stats')
|
|
.withDescription('Get router statistics')
|
|
.withHandler(async () => {
|
|
const router = await getRouter();
|
|
const stats = router.getStats();
|
|
return { content: [{ type: 'text', text: `📊 **Intent Router:**\n\n**Intents:** ${stats.totalIntents}\n**Routes:** ${stats.recentRoutes}\n**Backend:** @ruvector/wasm HNSW` }] };
|
|
})
|
|
.build(),
|
|
])
|
|
.withHooks([
|
|
new HookBuilder(HookEvent.PreTaskExecute)
|
|
.withName('intent-auto-route')
|
|
.withDescription('Auto-route tasks')
|
|
.withPriority(HookPriority.High)
|
|
.when((ctx) => (ctx.data as { autoRoute?: boolean; query?: string } | undefined)?.autoRoute === true)
|
|
.handle(async (ctx) => {
|
|
const data = ctx.data as { query: string };
|
|
try {
|
|
const router = await getRouter();
|
|
const result = await router.route(data.query);
|
|
return { success: true, data: { ...data, routedIntent: result.intent.id, routedHandlers: result.handlers }, modified: true };
|
|
} catch { return { success: true }; }
|
|
})
|
|
.build(),
|
|
])
|
|
.onInitialize(async (ctx) => {
|
|
ctx.logger.info('Intent Router initializing with @ruvector/wasm...');
|
|
const router = await getRouter();
|
|
ctx.logger.info(`Intent Router ready - ${router.listIntents().length} intents, HNSW enabled`);
|
|
})
|
|
.build();
|
|
|
|
export default intentRouterPlugin;
|