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
658 lines
21 KiB
TypeScript
658 lines
21 KiB
TypeScript
/**
|
|
* ReasoningBank Integration Plugin
|
|
*
|
|
* Stores successful reasoning trajectories and retrieves them for similar problems.
|
|
* Uses @ruvector/wasm for vector storage with HNSW indexing (<1ms search).
|
|
*
|
|
* Features:
|
|
* - Store reasoning chains with embeddings
|
|
* - Retrieve similar past reasoning for new problems
|
|
* - Learn from successful/failed outcomes
|
|
* - Verdict judgment for quality scoring
|
|
* - Memory distillation for pattern extraction
|
|
*
|
|
* @example
|
|
* ```typescript
|
|
* import { reasoningBankPlugin } from '@claude-flow/plugins/examples/ruvector-plugins';
|
|
* await getDefaultRegistry().register(reasoningBankPlugin);
|
|
* ```
|
|
*/
|
|
|
|
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 ReasoningTrajectory {
|
|
id: string;
|
|
problem: string;
|
|
problemEmbedding?: Float32Array;
|
|
steps: ReasoningStep[];
|
|
outcome: 'success' | 'failure' | 'partial';
|
|
score: number;
|
|
metadata: {
|
|
taskType: string;
|
|
duration: number;
|
|
tokensUsed: number;
|
|
model?: string;
|
|
timestamp: Date;
|
|
};
|
|
}
|
|
|
|
export interface ReasoningStep {
|
|
thought: string;
|
|
action: string;
|
|
observation: string;
|
|
confidence: number;
|
|
}
|
|
|
|
export interface RetrievalResult {
|
|
trajectory: ReasoningTrajectory;
|
|
similarity: number;
|
|
applicability: number;
|
|
}
|
|
|
|
export interface VerdictJudgment {
|
|
trajectoryId: string;
|
|
verdict: 'accept' | 'reject' | 'revise';
|
|
score: number;
|
|
feedback: string;
|
|
improvements?: string[];
|
|
}
|
|
|
|
// ============================================================================
|
|
// ReasoningBank Core
|
|
// ============================================================================
|
|
|
|
export class ReasoningBank {
|
|
private vectorDb: IVectorDB | null = null;
|
|
private trajectories = new Map<string, ReasoningTrajectory>();
|
|
private dimensions: number;
|
|
private nextId = 1;
|
|
private initPromise: Promise<void> | null = null;
|
|
|
|
constructor(dimensions: number = 1536) {
|
|
this.dimensions = dimensions;
|
|
}
|
|
|
|
/**
|
|
* Initialize the vector database.
|
|
*/
|
|
async initialize(): Promise<void> {
|
|
if (this.vectorDb) return;
|
|
if (this.initPromise) return this.initPromise;
|
|
|
|
this.initPromise = (async () => {
|
|
this.vectorDb = await createVectorDB(this.dimensions);
|
|
})();
|
|
|
|
return this.initPromise;
|
|
}
|
|
|
|
private async ensureInitialized(): Promise<IVectorDB> {
|
|
await this.initialize();
|
|
return this.vectorDb!;
|
|
}
|
|
|
|
/**
|
|
* Store a reasoning trajectory.
|
|
*/
|
|
async store(trajectory: Omit<ReasoningTrajectory, 'id'>): Promise<string> {
|
|
const db = await this.ensureInitialized();
|
|
const id = `reasoning-${this.nextId++}`;
|
|
|
|
// Validate inputs
|
|
const safeProblem = Security.validateString(trajectory.problem, { maxLength: 10000 });
|
|
|
|
// Generate embedding from problem + steps
|
|
const embedding = trajectory.problemEmbedding ?? this.generateEmbedding(safeProblem);
|
|
|
|
const fullTrajectory: ReasoningTrajectory = {
|
|
...trajectory,
|
|
id,
|
|
problem: safeProblem,
|
|
problemEmbedding: embedding,
|
|
};
|
|
|
|
// Store in vector DB with HNSW indexing
|
|
db.insert(embedding, id, {
|
|
problem: safeProblem,
|
|
outcome: trajectory.outcome,
|
|
score: trajectory.score,
|
|
taskType: trajectory.metadata.taskType,
|
|
stepsCount: trajectory.steps.length,
|
|
timestamp: trajectory.metadata.timestamp.toISOString(),
|
|
});
|
|
|
|
// Store full trajectory
|
|
this.trajectories.set(id, fullTrajectory);
|
|
|
|
return id;
|
|
}
|
|
|
|
/**
|
|
* Retrieve similar reasoning trajectories (<1ms with HNSW).
|
|
*/
|
|
async retrieve(
|
|
problem: string,
|
|
options?: {
|
|
k?: number;
|
|
minScore?: number;
|
|
taskType?: string;
|
|
outcomeFilter?: 'success' | 'failure' | 'partial';
|
|
}
|
|
): Promise<RetrievalResult[]> {
|
|
const db = await this.ensureInitialized();
|
|
const k = options?.k ?? 5;
|
|
const minScore = options?.minScore ?? 0.5;
|
|
|
|
const safeProblem = Security.validateString(problem, { maxLength: 10000 });
|
|
const queryEmbedding = this.generateEmbedding(safeProblem);
|
|
|
|
// HNSW search - sub-millisecond for 10K+ vectors
|
|
const searchResults = db.search(queryEmbedding, k * 2);
|
|
|
|
const results: RetrievalResult[] = [];
|
|
|
|
for (const result of searchResults) {
|
|
if (result.score < minScore) continue;
|
|
|
|
const trajectory = this.trajectories.get(result.id);
|
|
if (!trajectory) continue;
|
|
|
|
// Apply filters
|
|
if (options?.taskType && trajectory.metadata.taskType !== options.taskType) continue;
|
|
if (options?.outcomeFilter && trajectory.outcome !== options.outcomeFilter) continue;
|
|
|
|
// Calculate applicability based on task type match and recency
|
|
const applicability = this.calculateApplicability(trajectory, safeProblem, options?.taskType);
|
|
|
|
results.push({
|
|
trajectory,
|
|
similarity: result.score,
|
|
applicability,
|
|
});
|
|
|
|
if (results.length >= k) break;
|
|
}
|
|
|
|
return results.sort((a, b) => (b.similarity * b.applicability) - (a.similarity * a.applicability));
|
|
}
|
|
|
|
/**
|
|
* Judge a trajectory and update its score.
|
|
*/
|
|
async judge(judgment: VerdictJudgment): Promise<void> {
|
|
const trajectory = this.trajectories.get(judgment.trajectoryId);
|
|
if (!trajectory) {
|
|
throw new Error(`Trajectory ${judgment.trajectoryId} not found`);
|
|
}
|
|
|
|
const db = await this.ensureInitialized();
|
|
|
|
// Update score based on verdict
|
|
const scoreAdjustment = {
|
|
accept: 0.1,
|
|
reject: -0.2,
|
|
revise: -0.05,
|
|
}[judgment.verdict];
|
|
|
|
trajectory.score = Math.max(0, Math.min(1, trajectory.score + scoreAdjustment));
|
|
|
|
// If rejected with low score, remove from index
|
|
if (judgment.verdict === 'reject' && trajectory.score < 0.2) {
|
|
db.delete(trajectory.id);
|
|
this.trajectories.delete(trajectory.id);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Distill patterns from successful trajectories.
|
|
*/
|
|
async distill(taskType?: string): Promise<{
|
|
patterns: string[];
|
|
commonSteps: string[];
|
|
avgSteps: number;
|
|
successRate: number;
|
|
}> {
|
|
const trajectories = Array.from(this.trajectories.values())
|
|
.filter(t => (!taskType || t.metadata.taskType === taskType) && t.score > 0.6);
|
|
|
|
if (trajectories.length === 0) {
|
|
return { patterns: [], commonSteps: [], avgSteps: 0, successRate: 0 };
|
|
}
|
|
|
|
const actionCounts = new Map<string, number>();
|
|
let totalSteps = 0;
|
|
let successCount = 0;
|
|
|
|
for (const t of trajectories) {
|
|
totalSteps += t.steps.length;
|
|
if (t.outcome === 'success') successCount++;
|
|
|
|
for (const step of t.steps) {
|
|
const count = actionCounts.get(step.action) ?? 0;
|
|
actionCounts.set(step.action, count + 1);
|
|
}
|
|
}
|
|
|
|
const commonSteps = Array.from(actionCounts.entries())
|
|
.sort((a, b) => b[1] - a[1])
|
|
.slice(0, 10)
|
|
.map(([action]) => action);
|
|
|
|
const patterns = this.extractPatterns(trajectories);
|
|
|
|
return {
|
|
patterns,
|
|
commonSteps,
|
|
avgSteps: totalSteps / trajectories.length,
|
|
successRate: successCount / trajectories.length,
|
|
};
|
|
}
|
|
|
|
/**
|
|
* Get statistics about stored trajectories.
|
|
*/
|
|
getStats(): {
|
|
total: number;
|
|
byOutcome: Record<string, number>;
|
|
byTaskType: Record<string, number>;
|
|
avgScore: number;
|
|
} {
|
|
const trajectories = Array.from(this.trajectories.values());
|
|
|
|
const byOutcome: Record<string, number> = { success: 0, failure: 0, partial: 0 };
|
|
const byTaskType: Record<string, number> = {};
|
|
let totalScore = 0;
|
|
|
|
for (const t of trajectories) {
|
|
byOutcome[t.outcome]++;
|
|
byTaskType[t.metadata.taskType] = (byTaskType[t.metadata.taskType] ?? 0) + 1;
|
|
totalScore += t.score;
|
|
}
|
|
|
|
return {
|
|
total: trajectories.length,
|
|
byOutcome,
|
|
byTaskType,
|
|
avgScore: trajectories.length > 0 ? totalScore / trajectories.length : 0,
|
|
};
|
|
}
|
|
|
|
// =========================================================================
|
|
// Private Helpers
|
|
// =========================================================================
|
|
|
|
/**
|
|
* External embedding provider (optional - set via setEmbeddingProvider)
|
|
* When set, uses @claude-flow/embeddings for high-quality embeddings
|
|
*/
|
|
private embeddingProvider: ((text: string) => Promise<Float32Array>) | null = null;
|
|
|
|
/**
|
|
* Set external embedding provider from @claude-flow/embeddings
|
|
*
|
|
* @example
|
|
* ```typescript
|
|
* import { createEmbeddingService } from '@claude-flow/embeddings';
|
|
* const embeddings = createEmbeddingService({ provider: 'transformers' });
|
|
* await embeddings.initialize();
|
|
* bank.setEmbeddingProvider(async (text) => {
|
|
* const result = await embeddings.embed(text);
|
|
* return result.embedding;
|
|
* });
|
|
* ```
|
|
*/
|
|
setEmbeddingProvider(provider: (text: string) => Promise<Float32Array>): void {
|
|
this.embeddingProvider = provider;
|
|
}
|
|
|
|
/**
|
|
* Generate embedding using external provider or fallback to hash-based
|
|
* Performance: <100ms with external provider, <1ms with hash fallback
|
|
*/
|
|
private generateEmbedding(text: string): Float32Array {
|
|
// Use synchronous hash-based fallback for immediate returns
|
|
// Async embeddings are handled by generateEmbeddingAsync
|
|
return this.generateHashEmbedding(text);
|
|
}
|
|
|
|
/**
|
|
* Generate embedding asynchronously using external provider if available
|
|
*/
|
|
async generateEmbeddingAsync(text: string): Promise<Float32Array> {
|
|
if (this.embeddingProvider) {
|
|
try {
|
|
return await this.embeddingProvider(text);
|
|
} catch (error) {
|
|
// Fallback to hash-based if provider fails
|
|
console.warn('[ReasoningBank] Embedding provider failed, using fallback:', error);
|
|
}
|
|
}
|
|
return this.generateHashEmbedding(text);
|
|
}
|
|
|
|
/**
|
|
* Hash-based embedding fallback (fast but low quality)
|
|
* Used when @claude-flow/embeddings is not configured
|
|
*/
|
|
private generateHashEmbedding(text: string): Float32Array {
|
|
const embedding = new Float32Array(this.dimensions);
|
|
let hash = 0;
|
|
|
|
for (let i = 0; i < text.length; i++) {
|
|
hash = ((hash << 5) - hash) + text.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;
|
|
}
|
|
|
|
// L2 Normalize
|
|
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;
|
|
}
|
|
|
|
private calculateApplicability(
|
|
trajectory: ReasoningTrajectory,
|
|
_problem: string,
|
|
taskType?: string
|
|
): number {
|
|
let score = trajectory.score;
|
|
|
|
if (taskType && trajectory.metadata.taskType === taskType) {
|
|
score *= 1.2;
|
|
}
|
|
|
|
if (trajectory.outcome === 'success') {
|
|
score *= 1.1;
|
|
}
|
|
|
|
const age = Date.now() - trajectory.metadata.timestamp.getTime();
|
|
const daysSinceCreation = age / (1000 * 60 * 60 * 24);
|
|
if (daysSinceCreation > 7) {
|
|
score *= Math.exp(-0.05 * (daysSinceCreation - 7));
|
|
}
|
|
|
|
return Math.min(1, score);
|
|
}
|
|
|
|
private extractPatterns(trajectories: ReasoningTrajectory[]): string[] {
|
|
const patterns: string[] = [];
|
|
const sequences = new Map<string, number>();
|
|
|
|
for (const t of trajectories) {
|
|
for (let i = 0; i < t.steps.length - 1; i++) {
|
|
const seq = `${t.steps[i].action} → ${t.steps[i + 1].action}`;
|
|
sequences.set(seq, (sequences.get(seq) ?? 0) + 1);
|
|
}
|
|
}
|
|
|
|
for (const [seq, count] of sequences) {
|
|
if (count >= 2) {
|
|
patterns.push(`Common sequence: ${seq} (${count} occurrences)`);
|
|
}
|
|
}
|
|
|
|
return patterns.slice(0, 5);
|
|
}
|
|
}
|
|
|
|
// ============================================================================
|
|
// Plugin Definition
|
|
// ============================================================================
|
|
|
|
let reasoningBankInstance: ReasoningBank | null = null;
|
|
|
|
async function getReasoningBank(): Promise<ReasoningBank> {
|
|
if (!reasoningBankInstance) {
|
|
reasoningBankInstance = new ReasoningBank(1536);
|
|
await reasoningBankInstance.initialize();
|
|
}
|
|
return reasoningBankInstance;
|
|
}
|
|
|
|
export const reasoningBankPlugin = new PluginBuilder('reasoning-bank', '1.0.0')
|
|
.withDescription('Store and retrieve reasoning trajectories using @ruvector/wasm HNSW indexing')
|
|
.withAuthor('Claude Flow Team')
|
|
.withTags(['reasoning', 'memory', 'learning', 'ruvector', 'hnsw'])
|
|
.withMCPTools([
|
|
new MCPToolBuilder('reasoning-store')
|
|
.withDescription('Store a reasoning trajectory for future retrieval')
|
|
.addStringParam('problem', 'The problem that was solved', { required: true })
|
|
.addStringParam('steps', 'JSON array of reasoning steps', { required: true })
|
|
.addStringParam('outcome', 'Outcome: success, failure, or partial', {
|
|
required: true,
|
|
enum: ['success', 'failure', 'partial'],
|
|
})
|
|
.addNumberParam('score', 'Quality score 0-1', { default: 0.7, minimum: 0, maximum: 1 })
|
|
.addStringParam('taskType', 'Type of task (coding, research, planning, etc.)', { required: true })
|
|
.withHandler(async (params) => {
|
|
try {
|
|
const steps = JSON.parse(params.steps as string) as ReasoningStep[];
|
|
const rb = await getReasoningBank();
|
|
|
|
const id = await rb.store({
|
|
problem: params.problem as string,
|
|
steps,
|
|
outcome: params.outcome as 'success' | 'failure' | 'partial',
|
|
score: params.score as number,
|
|
metadata: {
|
|
taskType: params.taskType as string,
|
|
duration: 0,
|
|
tokensUsed: 0,
|
|
timestamp: new Date(),
|
|
},
|
|
});
|
|
|
|
return {
|
|
content: [{
|
|
type: 'text',
|
|
text: `✅ Stored reasoning trajectory: ${id}\n` +
|
|
`Problem: ${(params.problem as string).substring(0, 100)}...\n` +
|
|
`Steps: ${steps.length}\n` +
|
|
`Outcome: ${params.outcome}\n` +
|
|
`Score: ${params.score}`,
|
|
}],
|
|
};
|
|
} catch (error) {
|
|
return {
|
|
content: [{ type: 'text', text: `❌ Error: ${error instanceof Error ? error.message : String(error)}` }],
|
|
isError: true,
|
|
};
|
|
}
|
|
})
|
|
.build(),
|
|
|
|
new MCPToolBuilder('reasoning-retrieve')
|
|
.withDescription('Retrieve similar reasoning trajectories (<1ms with HNSW)')
|
|
.addStringParam('problem', 'The problem to find similar reasoning for', { required: true })
|
|
.addNumberParam('k', 'Number of results', { default: 5 })
|
|
.addNumberParam('minScore', 'Minimum similarity score', { default: 0.5 })
|
|
.addStringParam('taskType', 'Filter by task type')
|
|
.addStringParam('outcomeFilter', 'Filter by outcome', { enum: ['success', 'failure', 'partial'] })
|
|
.withHandler(async (params) => {
|
|
try {
|
|
const rb = await getReasoningBank();
|
|
const results = await rb.retrieve(params.problem as string, {
|
|
k: params.k as number,
|
|
minScore: params.minScore as number,
|
|
taskType: params.taskType as string | undefined,
|
|
outcomeFilter: params.outcomeFilter as 'success' | 'failure' | 'partial' | undefined,
|
|
});
|
|
|
|
if (results.length === 0) {
|
|
return { content: [{ type: 'text', text: '📭 No similar reasoning found.' }] };
|
|
}
|
|
|
|
const output = results.map((r, i) =>
|
|
`**${i + 1}. ${r.trajectory.id}** (similarity: ${(r.similarity * 100).toFixed(1)}%)\n` +
|
|
` Problem: ${r.trajectory.problem.substring(0, 80)}...\n` +
|
|
` Outcome: ${r.trajectory.outcome} | Steps: ${r.trajectory.steps.length}\n` +
|
|
` Actions: ${r.trajectory.steps.map(s => s.action).join(' → ')}`
|
|
).join('\n\n');
|
|
|
|
return {
|
|
content: [{ type: 'text', text: `📚 **Found ${results.length} similar trajectories:**\n\n${output}` }],
|
|
};
|
|
} catch (error) {
|
|
return {
|
|
content: [{ type: 'text', text: `❌ Error: ${error instanceof Error ? error.message : String(error)}` }],
|
|
isError: true,
|
|
};
|
|
}
|
|
})
|
|
.build(),
|
|
|
|
new MCPToolBuilder('reasoning-judge')
|
|
.withDescription('Judge a reasoning trajectory and update its score')
|
|
.addStringParam('trajectoryId', 'ID of the trajectory to judge', { required: true })
|
|
.addStringParam('verdict', 'Verdict: accept, reject, or revise', {
|
|
required: true,
|
|
enum: ['accept', 'reject', 'revise'],
|
|
})
|
|
.addStringParam('feedback', 'Feedback about the trajectory')
|
|
.withHandler(async (params) => {
|
|
try {
|
|
const rb = await getReasoningBank();
|
|
await rb.judge({
|
|
trajectoryId: params.trajectoryId as string,
|
|
verdict: params.verdict as 'accept' | 'reject' | 'revise',
|
|
score: params.verdict === 'accept' ? 0.1 : params.verdict === 'reject' ? -0.2 : -0.05,
|
|
feedback: (params.feedback as string) ?? '',
|
|
});
|
|
|
|
return {
|
|
content: [{
|
|
type: 'text',
|
|
text: `⚖️ Judged trajectory ${params.trajectoryId}: ${params.verdict}`,
|
|
}],
|
|
};
|
|
} catch (error) {
|
|
return {
|
|
content: [{ type: 'text', text: `❌ Error: ${error instanceof Error ? error.message : String(error)}` }],
|
|
isError: true,
|
|
};
|
|
}
|
|
})
|
|
.build(),
|
|
|
|
new MCPToolBuilder('reasoning-distill')
|
|
.withDescription('Extract common patterns from successful reasoning trajectories')
|
|
.addStringParam('taskType', 'Filter by task type (optional)')
|
|
.withHandler(async (params) => {
|
|
try {
|
|
const rb = await getReasoningBank();
|
|
const distilled = await rb.distill(params.taskType as string | undefined);
|
|
|
|
return {
|
|
content: [{
|
|
type: 'text',
|
|
text: `🧬 **Distilled Patterns${params.taskType ? ` for ${params.taskType}` : ''}:**\n\n` +
|
|
`**Success Rate:** ${(distilled.successRate * 100).toFixed(1)}%\n` +
|
|
`**Average Steps:** ${distilled.avgSteps.toFixed(1)}\n\n` +
|
|
`**Common Actions:**\n${distilled.commonSteps.map((s, i) => `${i + 1}. ${s}`).join('\n')}\n\n` +
|
|
`**Patterns:**\n${distilled.patterns.map((p, i) => `${i + 1}. ${p}`).join('\n') || 'None found yet'}`,
|
|
}],
|
|
};
|
|
} catch (error) {
|
|
return {
|
|
content: [{ type: 'text', text: `❌ Error: ${error instanceof Error ? error.message : String(error)}` }],
|
|
isError: true,
|
|
};
|
|
}
|
|
})
|
|
.build(),
|
|
|
|
new MCPToolBuilder('reasoning-stats')
|
|
.withDescription('Get statistics about stored reasoning trajectories')
|
|
.withHandler(async () => {
|
|
const rb = await getReasoningBank();
|
|
const stats = rb.getStats();
|
|
|
|
return {
|
|
content: [{
|
|
type: 'text',
|
|
text: `📊 **ReasoningBank Statistics:**\n\n` +
|
|
`**Total Trajectories:** ${stats.total}\n` +
|
|
`**Backend:** @ruvector/wasm HNSW\n\n` +
|
|
`**By Outcome:**\n` +
|
|
` ✅ Success: ${stats.byOutcome.success}\n` +
|
|
` ❌ Failure: ${stats.byOutcome.failure}\n` +
|
|
` ⚠️ Partial: ${stats.byOutcome.partial}\n\n` +
|
|
`**By Task Type:**\n${Object.entries(stats.byTaskType).map(([type, count]) => ` • ${type}: ${count}`).join('\n') || ' None'}\n\n` +
|
|
`**Average Score:** ${(stats.avgScore * 100).toFixed(1)}%`,
|
|
}],
|
|
};
|
|
})
|
|
.build(),
|
|
])
|
|
.withHooks([
|
|
new HookBuilder(HookEvent.PostTaskComplete)
|
|
.withName('reasoning-auto-store')
|
|
.withDescription('Automatically store successful task reasoning')
|
|
.withPriority(HookPriority.Low)
|
|
.when((ctx) => {
|
|
const data = ctx.data as { success?: boolean; reasoning?: unknown[] } | undefined;
|
|
return data?.success === true && Array.isArray(data?.reasoning) && data.reasoning.length > 0;
|
|
})
|
|
.handle(async (ctx) => {
|
|
const data = ctx.data as { problem?: string; reasoning?: ReasoningStep[]; taskType?: string };
|
|
if (!data.problem || !data.reasoning) return { success: true };
|
|
|
|
try {
|
|
const rb = await getReasoningBank();
|
|
await rb.store({
|
|
problem: data.problem,
|
|
steps: data.reasoning,
|
|
outcome: 'success',
|
|
score: 0.8,
|
|
metadata: {
|
|
taskType: data.taskType ?? 'general',
|
|
duration: 0,
|
|
tokensUsed: 0,
|
|
timestamp: new Date(),
|
|
},
|
|
});
|
|
} catch {
|
|
// Silent fail for auto-store
|
|
}
|
|
|
|
return { success: true };
|
|
})
|
|
.build(),
|
|
])
|
|
.onInitialize(async (ctx) => {
|
|
ctx.logger.info('ReasoningBank plugin initializing with @ruvector/wasm...');
|
|
await getReasoningBank();
|
|
ctx.logger.info('ReasoningBank ready - HNSW indexing enabled');
|
|
})
|
|
.build();
|
|
|
|
export default reasoningBankPlugin;
|