433 lines
12 KiB
TypeScript
433 lines
12 KiB
TypeScript
/**
|
|
* SONA Integration for V3 Neural Module
|
|
*
|
|
* Wraps @ruvector/sona package for V3 usage with:
|
|
* - Trajectory tracking and verdict judgment
|
|
* - Pattern extraction and memory distillation
|
|
* - Sub-0.05ms learning performance target
|
|
* - Clean TypeScript API with proper types
|
|
*
|
|
* @module sona-integration
|
|
*/
|
|
|
|
import { SonaEngine, type JsSonaConfig, type JsLearnedPattern } from '@ruvector/sona';
|
|
import type {
|
|
Trajectory,
|
|
TrajectoryStep,
|
|
TrajectoryVerdict,
|
|
DistilledMemory,
|
|
SONAMode,
|
|
SONAModeConfig,
|
|
} from './types.js';
|
|
|
|
// =============================================================================
|
|
// Types
|
|
// =============================================================================
|
|
|
|
/**
|
|
* Context for SONA learning adaptation
|
|
*/
|
|
export interface Context {
|
|
/** Task domain */
|
|
domain: 'code' | 'creative' | 'reasoning' | 'chat' | 'math' | 'general';
|
|
/** Current query embedding */
|
|
queryEmbedding: Float32Array;
|
|
/** Additional context metadata */
|
|
metadata?: Record<string, unknown>;
|
|
}
|
|
|
|
/**
|
|
* Adapted behavior result from SONA
|
|
*/
|
|
export interface AdaptedBehavior {
|
|
/** Transformed query embedding after micro-LoRA */
|
|
transformedQuery: Float32Array;
|
|
/** Similar learned patterns */
|
|
patterns: JsLearnedPattern[];
|
|
/** Suggested route/model */
|
|
suggestedRoute?: string;
|
|
/** Confidence score */
|
|
confidence: number;
|
|
}
|
|
|
|
/**
|
|
* SONA engine statistics
|
|
*/
|
|
export interface SONAStats {
|
|
/** Total trajectories recorded */
|
|
totalTrajectories: number;
|
|
/** Patterns learned */
|
|
patternsLearned: number;
|
|
/** Average quality */
|
|
avgQuality: number;
|
|
/** Last learning time (ms) */
|
|
lastLearningMs: number;
|
|
/** Engine enabled state */
|
|
enabled: boolean;
|
|
}
|
|
|
|
// =============================================================================
|
|
// Mode Configuration Mapping
|
|
// =============================================================================
|
|
|
|
/**
|
|
* Convert V3 SONA mode to @ruvector/sona config
|
|
*/
|
|
function modeToConfig(mode: SONAMode, modeConfig: SONAModeConfig): JsSonaConfig {
|
|
const baseConfig: JsSonaConfig = {
|
|
hiddenDim: 768, // Standard transformer dimension
|
|
embeddingDim: 768,
|
|
microLoraRank: modeConfig.loraRank <= 2 ? modeConfig.loraRank : 1,
|
|
baseLoraRank: modeConfig.loraRank,
|
|
microLoraLr: modeConfig.learningRate,
|
|
baseLoraLr: modeConfig.learningRate * 0.1,
|
|
ewcLambda: modeConfig.ewcLambda,
|
|
patternClusters: modeConfig.patternClusters,
|
|
trajectoryCapacity: modeConfig.trajectoryCapacity,
|
|
qualityThreshold: modeConfig.qualityThreshold,
|
|
enableSimd: true,
|
|
};
|
|
|
|
// Mode-specific adjustments
|
|
switch (mode) {
|
|
case 'real-time':
|
|
return {
|
|
...baseConfig,
|
|
microLoraRank: 1,
|
|
backgroundIntervalMs: 60000, // 1 minute
|
|
};
|
|
case 'edge':
|
|
return {
|
|
...baseConfig,
|
|
hiddenDim: 384, // Smaller for edge devices
|
|
embeddingDim: 384,
|
|
microLoraRank: 1,
|
|
patternClusters: 25,
|
|
backgroundIntervalMs: 300000, // 5 minutes
|
|
};
|
|
case 'research':
|
|
return {
|
|
...baseConfig,
|
|
baseLoraRank: 16,
|
|
backgroundIntervalMs: 3600000, // 1 hour
|
|
};
|
|
case 'batch':
|
|
return {
|
|
...baseConfig,
|
|
backgroundIntervalMs: 7200000, // 2 hours
|
|
};
|
|
case 'balanced':
|
|
default:
|
|
return {
|
|
...baseConfig,
|
|
backgroundIntervalMs: 1800000, // 30 minutes
|
|
};
|
|
}
|
|
}
|
|
|
|
// =============================================================================
|
|
// SONA Learning Engine
|
|
// =============================================================================
|
|
|
|
/**
|
|
* SONA Learning Engine - wraps @ruvector/sona for V3 usage
|
|
*
|
|
* Performance targets:
|
|
* - learn(): <0.05ms
|
|
* - adapt(): <0.1ms
|
|
* - Full learning cycle: <10ms
|
|
*/
|
|
export class SONALearningEngine {
|
|
private engine: SonaEngine;
|
|
private trajectoryMap: Map<string, number> = new Map();
|
|
private adaptationTimeMs: number = 0;
|
|
private learningTimeMs: number = 0;
|
|
private mode: SONAMode;
|
|
private modeConfig: SONAModeConfig;
|
|
|
|
constructor(mode: SONAMode, modeConfig: SONAModeConfig) {
|
|
this.mode = mode;
|
|
this.modeConfig = modeConfig;
|
|
const config = modeToConfig(mode, modeConfig);
|
|
this.engine = SonaEngine.withConfig(config);
|
|
}
|
|
|
|
/**
|
|
* Learn from a trajectory
|
|
*
|
|
* Performance target: <0.05ms
|
|
*
|
|
* @param trajectory - Trajectory to learn from
|
|
*/
|
|
async learn(trajectory: Trajectory): Promise<void> {
|
|
const startTime = performance.now();
|
|
|
|
try {
|
|
// Begin trajectory recording
|
|
const queryEmbedding = this.trajectoryToQueryEmbedding(trajectory);
|
|
const trajectoryId = this.engine.beginTrajectory(
|
|
Array.from(queryEmbedding)
|
|
);
|
|
|
|
// Add trajectory steps
|
|
for (const step of trajectory.steps) {
|
|
const activations = this.stateToActivations(step.stateBefore);
|
|
const attentionWeights = this.stateToAttentionWeights(step.stateAfter);
|
|
|
|
this.engine.addTrajectoryStep(
|
|
trajectoryId,
|
|
Array.from(activations),
|
|
Array.from(attentionWeights),
|
|
step.reward
|
|
);
|
|
}
|
|
|
|
// Set context if available
|
|
if (trajectory.domain) {
|
|
this.engine.addTrajectoryContext(trajectoryId, trajectory.domain);
|
|
}
|
|
|
|
// Complete trajectory with quality score
|
|
const quality = this.calculateQuality(trajectory);
|
|
this.engine.endTrajectory(trajectoryId, quality);
|
|
|
|
// Flush instant updates
|
|
this.engine.flush();
|
|
|
|
this.learningTimeMs = performance.now() - startTime;
|
|
} catch (error) {
|
|
throw new Error(`SONA learning failed: ${error}`);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Adapt behavior based on context
|
|
*
|
|
* @param context - Current context for adaptation
|
|
* @returns Adapted behavior with transformed embeddings
|
|
*/
|
|
async adapt(context: Context): Promise<AdaptedBehavior> {
|
|
const startTime = performance.now();
|
|
|
|
try {
|
|
// Apply micro-LoRA transformation
|
|
const transformedQuery = this.engine.applyMicroLora(
|
|
Array.from(context.queryEmbedding)
|
|
);
|
|
|
|
// Find similar patterns
|
|
const patterns = this.engine.findPatterns(
|
|
Array.from(context.queryEmbedding),
|
|
5
|
|
);
|
|
|
|
// Determine suggested route from patterns
|
|
const suggestedRoute = this.inferRoute(patterns, context);
|
|
const confidence = patterns.length > 0 ? patterns[0].avgQuality : 0.5;
|
|
|
|
this.adaptationTimeMs = performance.now() - startTime;
|
|
|
|
return {
|
|
transformedQuery: new Float32Array(transformedQuery),
|
|
patterns,
|
|
suggestedRoute,
|
|
confidence,
|
|
};
|
|
} catch (error) {
|
|
throw new Error(`SONA adaptation failed: ${error}`);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Get last adaptation time
|
|
*
|
|
* @returns Adaptation time in milliseconds
|
|
*/
|
|
getAdaptationTime(): number {
|
|
return this.adaptationTimeMs;
|
|
}
|
|
|
|
/**
|
|
* Get last learning time
|
|
*
|
|
* @returns Learning time in milliseconds
|
|
*/
|
|
getLearningTime(): number {
|
|
return this.learningTimeMs;
|
|
}
|
|
|
|
/**
|
|
* Reset learning state
|
|
*/
|
|
resetLearning(): void {
|
|
// Create a new engine with the same config
|
|
const config = modeToConfig(this.mode, this.modeConfig);
|
|
this.engine = SonaEngine.withConfig(config);
|
|
this.trajectoryMap.clear();
|
|
this.adaptationTimeMs = 0;
|
|
this.learningTimeMs = 0;
|
|
}
|
|
|
|
/**
|
|
* Force immediate learning cycle
|
|
*
|
|
* @returns Status message
|
|
*/
|
|
forceLearning(): string {
|
|
return this.engine.forceLearn();
|
|
}
|
|
|
|
/**
|
|
* Tick background learning (call periodically)
|
|
*
|
|
* @returns Status message if learning occurred
|
|
*/
|
|
tick(): string | null {
|
|
return this.engine.tick();
|
|
}
|
|
|
|
/**
|
|
* Get engine statistics
|
|
*
|
|
* @returns SONA engine statistics
|
|
*/
|
|
getStats(): SONAStats {
|
|
const statsJson = this.engine.getStats();
|
|
const stats = JSON.parse(statsJson);
|
|
|
|
return {
|
|
totalTrajectories: stats.total_trajectories || 0,
|
|
patternsLearned: stats.patterns_learned || 0,
|
|
avgQuality: stats.avg_quality || 0,
|
|
lastLearningMs: this.learningTimeMs,
|
|
enabled: this.engine.isEnabled(),
|
|
};
|
|
}
|
|
|
|
/**
|
|
* Enable or disable the engine
|
|
*
|
|
* @param enabled - Whether to enable the engine
|
|
*/
|
|
setEnabled(enabled: boolean): void {
|
|
this.engine.setEnabled(enabled);
|
|
}
|
|
|
|
/**
|
|
* Check if engine is enabled
|
|
*
|
|
* @returns Whether the engine is enabled
|
|
*/
|
|
isEnabled(): boolean {
|
|
return this.engine.isEnabled();
|
|
}
|
|
|
|
/**
|
|
* Find learned patterns similar to query
|
|
*
|
|
* @param queryEmbedding - Query embedding
|
|
* @param k - Number of patterns to return
|
|
* @returns Learned patterns
|
|
*/
|
|
findPatterns(queryEmbedding: Float32Array, k: number = 5): JsLearnedPattern[] {
|
|
return this.engine.findPatterns(Array.from(queryEmbedding), k);
|
|
}
|
|
|
|
// =============================================================================
|
|
// Private Helpers
|
|
// =============================================================================
|
|
|
|
/**
|
|
* Convert trajectory to query embedding
|
|
*/
|
|
private trajectoryToQueryEmbedding(trajectory: Trajectory): Float32Array {
|
|
// Use the first step's state as query
|
|
if (trajectory.steps.length > 0) {
|
|
return trajectory.steps[0].stateBefore;
|
|
}
|
|
// Fallback to zero embedding
|
|
return new Float32Array(768);
|
|
}
|
|
|
|
/**
|
|
* Convert state embedding to activations
|
|
*/
|
|
private stateToActivations(state: Float32Array): Float32Array {
|
|
// For now, use state directly as activations
|
|
// In a real implementation, this would extract layer activations
|
|
return state;
|
|
}
|
|
|
|
/**
|
|
* Convert state embedding to attention weights
|
|
*/
|
|
private stateToAttentionWeights(state: Float32Array): Float32Array {
|
|
// For now, use normalized state as attention weights
|
|
// In a real implementation, this would extract attention patterns
|
|
const sum = state.reduce((acc, val) => acc + Math.abs(val), 0);
|
|
if (sum === 0) return state;
|
|
|
|
const weights = new Float32Array(state.length);
|
|
for (let i = 0; i < state.length; i++) {
|
|
weights[i] = Math.abs(state[i]) / sum;
|
|
}
|
|
return weights;
|
|
}
|
|
|
|
/**
|
|
* Calculate quality score for trajectory
|
|
*/
|
|
private calculateQuality(trajectory: Trajectory): number {
|
|
if (trajectory.qualityScore !== undefined) {
|
|
return trajectory.qualityScore;
|
|
}
|
|
|
|
// Calculate from steps
|
|
if (trajectory.steps.length === 0) return 0.5;
|
|
|
|
const avgReward = trajectory.steps.reduce((sum, step) => sum + step.reward, 0) /
|
|
trajectory.steps.length;
|
|
|
|
// Normalize to [0, 1]
|
|
return Math.max(0, Math.min(1, (avgReward + 1) / 2));
|
|
}
|
|
|
|
/**
|
|
* Infer suggested route from patterns and context
|
|
*/
|
|
private inferRoute(patterns: JsLearnedPattern[], context: Context): string | undefined {
|
|
if (patterns.length === 0) return undefined;
|
|
|
|
// Use the highest quality pattern's type as route
|
|
const bestPattern = patterns.reduce((best, pattern) =>
|
|
pattern.avgQuality > best.avgQuality ? pattern : best
|
|
);
|
|
|
|
return bestPattern.patternType || `${context.domain}-default`;
|
|
}
|
|
}
|
|
|
|
// =============================================================================
|
|
// Factory Functions
|
|
// =============================================================================
|
|
|
|
/**
|
|
* Create a SONA learning engine
|
|
*
|
|
* @param mode - SONA learning mode
|
|
* @param modeConfig - Mode configuration
|
|
* @returns SONA learning engine instance
|
|
*/
|
|
export function createSONALearningEngine(
|
|
mode: SONAMode,
|
|
modeConfig: SONAModeConfig
|
|
): SONALearningEngine {
|
|
return new SONALearningEngine(mode, modeConfig);
|
|
}
|
|
|
|
// =============================================================================
|
|
// Exports
|
|
// =============================================================================
|
|
|
|
export type { JsLearnedPattern, JsSonaConfig };
|