chore: recovery checkpoint - v3.0 API successfully recovered

CRITICAL CHECKPOINT - DO NOT PUSH TO GITHUB

Recovery Status:
- Successfully recovered brainy.ts from compiled JavaScript
- All core v3.0 API methods functional (add, get, update, delete, relate, find, etc.)
- Neural subsystem intact (562KB embedded patterns, NLP working)
- Augmentation pipeline operational (20+ augmentations)
- HNSW clustering system complete
- Triple Intelligence compiled (needs constructor fix)
- Test suite validates functionality

Changes preserved:
- 898 files with changes from last 3 days
- 144,475 insertions
- All augmentation improvements
- All test coverage enhancements
- Complete v3.0 feature set

This is a LOCAL checkpoint only - contains recovered work after corruption incident.
Created backup in .backups/brainy-full-20250910-151314.tar.gz

Branch: recovery-checkpoint-20250910-151433
Date: Wed Sep 10 03:18:04 PM PDT 2025
This commit is contained in:
David Snelling 2025-09-10 15:18:04 -07:00
parent f65455fb22
commit 8ff382ca3b
895 changed files with 143654 additions and 28268 deletions

View file

@ -0,0 +1,94 @@
/**
* Augmentation Metadata Contract System
*
* Prevents accidental metadata corruption while allowing intentional enrichment
* Each augmentation declares its metadata intentions upfront
*/
export interface AugmentationMetadataContract {
name: string;
version: string;
reads?: {
userFields?: string[];
internalFields?: string[];
augmentationFields?: string[];
};
writes?: {
userFields?: Array<{
field: string;
type: 'create' | 'update' | 'merge' | 'delete';
description: string;
example?: any;
}>;
augmentationFields?: Array<{
field: string;
description: string;
}>;
internalFields?: Array<{
field: string;
permission: 'granted' | 'requested';
reason: string;
}>;
};
conflictResolution?: {
strategy: 'error' | 'warn' | 'merge' | 'skip' | 'override';
priority?: number;
};
guarantees?: {
preservesExisting?: boolean;
reversible?: boolean;
idempotent?: boolean;
validatesTypes?: boolean;
};
}
/**
* Runtime metadata safety enforcer
*/
export declare class MetadataSafetyEnforcer {
private contracts;
private modifications;
/**
* Register an augmentation's contract
*/
registerContract(contract: AugmentationMetadataContract): void;
/**
* Check if an augmentation can modify a field
*/
canModifyField(augName: string, field: string, value: any): {
allowed: boolean;
reason?: string;
warnings?: string[];
};
/**
* Create safe metadata proxy for an augmentation
*/
createSafeProxy(metadata: any, augName: string): any;
}
/**
* Example augmentation contracts
*/
export declare const EXAMPLE_CONTRACTS: Record<string, AugmentationMetadataContract>;
/**
* Augmentation base class with safety
*/
export declare abstract class SafeAugmentation {
protected enforcer: MetadataSafetyEnforcer;
protected contract: AugmentationMetadataContract;
constructor(contract: AugmentationMetadataContract);
/**
* Get safe metadata proxy
*/
protected getSafeMetadata(metadata: any): any;
/**
* Abstract method to implement augmentation logic
*/
abstract execute(metadata: any): Promise<any>;
}
/**
* Example: Category enricher implementation
*/
export declare class CategoryEnricherAugmentation extends SafeAugmentation {
constructor();
execute(metadata: any): Promise<any>;
private detectCategory;
private detectSubcategories;
}

View file

@ -0,0 +1,306 @@
/**
* Augmentation Metadata Contract System
*
* Prevents accidental metadata corruption while allowing intentional enrichment
* Each augmentation declares its metadata intentions upfront
*/
/**
* Runtime metadata safety enforcer
*/
export class MetadataSafetyEnforcer {
constructor() {
this.contracts = new Map();
this.modifications = new Map(); // field -> augmentations that modify it
}
/**
* Register an augmentation's contract
*/
registerContract(contract) {
this.contracts.set(contract.name, contract);
// Track which augmentations modify which fields
if (contract.writes?.userFields) {
for (const fieldDef of contract.writes.userFields) {
if (!this.modifications.has(fieldDef.field)) {
this.modifications.set(fieldDef.field, new Set());
}
this.modifications.get(fieldDef.field).add(contract.name);
}
}
}
/**
* Check if an augmentation can modify a field
*/
canModifyField(augName, field, value) {
const contract = this.contracts.get(augName);
if (!contract) {
return {
allowed: false,
reason: `Augmentation '${augName}' has no registered contract`
};
}
// Check if field is in user namespace
if (!field.startsWith('_brainy.') && !field.startsWith('_augmentations.')) {
// It's a user field
const declaredField = contract.writes?.userFields?.find(f => f.field === field);
if (!declaredField) {
return {
allowed: false,
reason: `Augmentation '${augName}' did not declare intent to modify '${field}'`
};
}
// Check for conflicts
const modifiers = this.modifications.get(field);
if (modifiers && modifiers.size > 1) {
const others = Array.from(modifiers).filter(a => a !== augName);
return {
allowed: true, // Still allowed but with warning
warnings: [`Field '${field}' is also modified by: ${others.join(', ')}`]
};
}
return { allowed: true };
}
// Check internal fields
if (field.startsWith('_brainy.')) {
const internalField = contract.writes?.internalFields?.find(f => field === `_brainy.${f.field}`);
if (!internalField) {
return {
allowed: false,
reason: `Augmentation '${augName}' cannot modify internal field '${field}'`
};
}
if (internalField.permission !== 'granted') {
return {
allowed: false,
reason: `Permission not granted for internal field '${field}'`
};
}
return { allowed: true };
}
// Check augmentation namespace
if (field.startsWith('_augmentations.')) {
const parts = field.split('.');
const targetAug = parts[1];
// Can only modify own namespace
if (targetAug !== augName) {
return {
allowed: false,
reason: `Cannot modify another augmentation's namespace: ${targetAug}`
};
}
return { allowed: true };
}
return { allowed: true };
}
/**
* Create safe metadata proxy for an augmentation
*/
createSafeProxy(metadata, augName) {
const self = this;
return new Proxy(metadata, {
set(target, prop, value) {
const field = String(prop);
// Check permission
const permission = self.canModifyField(augName, field, value);
if (!permission.allowed) {
throw new Error(`[${augName}] ${permission.reason}`);
}
if (permission.warnings) {
console.warn(`[${augName}] Warning:`, ...permission.warnings);
}
// Track modification for audit
if (!target._audit) {
target._audit = [];
}
target._audit.push({
augmentation: augName,
field,
oldValue: target[prop],
newValue: value,
timestamp: Date.now()
});
target[prop] = value;
return true;
},
deleteProperty(target, prop) {
const field = String(prop);
const permission = self.canModifyField(augName, field, undefined);
if (!permission.allowed) {
throw new Error(`[${augName}] Cannot delete field: ${permission.reason}`);
}
delete target[prop];
return true;
}
});
}
}
/**
* Example augmentation contracts
*/
export const EXAMPLE_CONTRACTS = {
// Enrichment augmentation that adds categories
categoryEnricher: {
name: 'categoryEnricher',
version: '1.0.0',
reads: {
userFields: ['title', 'description', 'content']
},
writes: {
userFields: [
{
field: 'category',
type: 'create',
description: 'Auto-detected category',
example: 'technology'
},
{
field: 'subcategories',
type: 'create',
description: 'List of relevant subcategories',
example: ['web', 'framework']
}
],
augmentationFields: [
{
field: 'confidence',
description: 'Confidence score of categorization'
}
]
},
guarantees: {
preservesExisting: true,
idempotent: true
}
},
// Translation augmentation
translator: {
name: 'translator',
version: '1.0.0',
reads: {
userFields: ['title', 'description']
},
writes: {
userFields: [
{
field: 'translations',
type: 'merge',
description: 'Translations in multiple languages',
example: { es: 'Título', fr: 'Titre' }
},
{
field: 'detectedLanguage',
type: 'create',
description: 'Detected source language',
example: 'en'
}
]
},
conflictResolution: {
strategy: 'merge',
priority: 10
}
},
// Sentiment analyzer
sentimentAnalyzer: {
name: 'sentimentAnalyzer',
version: '1.0.0',
reads: {
userFields: ['content', 'description', 'reviews']
},
writes: {
userFields: [
{
field: 'sentiment',
type: 'update',
description: 'Overall sentiment score',
example: { score: 0.8, label: 'positive' }
}
],
augmentationFields: [
{
field: 'analysis',
description: 'Detailed sentiment breakdown'
}
]
},
guarantees: {
reversible: true,
validatesTypes: true
}
},
// System augmentation with internal access
garbageCollector: {
name: 'garbageCollector',
version: '1.0.0',
reads: {
internalFields: ['_brainy.createdAt', '_brainy.lastAccessed']
},
writes: {
internalFields: [
{
field: 'deleted',
permission: 'granted',
reason: 'Soft delete expired items'
},
{
field: 'archived',
permission: 'granted',
reason: 'Archive old items'
}
]
}
}
};
/**
* Augmentation base class with safety
*/
export class SafeAugmentation {
constructor(contract) {
this.contract = contract;
this.enforcer = new MetadataSafetyEnforcer();
this.enforcer.registerContract(contract);
}
/**
* Get safe metadata proxy
*/
getSafeMetadata(metadata) {
return this.enforcer.createSafeProxy(metadata, this.contract.name);
}
}
/**
* Example: Category enricher implementation
*/
export class CategoryEnricherAugmentation extends SafeAugmentation {
constructor() {
super(EXAMPLE_CONTRACTS.categoryEnricher);
}
async execute(metadata) {
const safe = this.getSafeMetadata(metadata);
// Read declared fields
const title = safe.title;
const description = safe.description;
// Analyze and categorize
const category = this.detectCategory(title, description);
const subcategories = this.detectSubcategories(title, description);
// Write to declared fields (will be checked by proxy)
safe.category = category; // ✅ Allowed - declared in contract
safe.subcategories = subcategories; // ✅ Allowed
// Try to write undeclared field
// safe.randomField = 'test' // ❌ Would throw error!
// Write to our augmentation namespace
if (!safe._augmentations)
safe._augmentations = {};
if (!safe._augmentations.categoryEnricher) {
safe._augmentations.categoryEnricher = {};
}
safe._augmentations.categoryEnricher.confidence = 0.95; // ✅ Allowed
return safe;
}
detectCategory(title, description) {
// Simplified logic
return 'technology';
}
detectSubcategories(title, description) {
return ['web', 'framework'];
}
}
//# sourceMappingURL=AugmentationMetadataContract.js.map

File diff suppressed because one or more lines are too long

View file

@ -0,0 +1,109 @@
/**
* API Server Augmentation - Universal API Exposure
*
* 🌐 Exposes Brainy through REST, WebSocket, and MCP
* 🔌 Works in Node.js, Deno, and Service Workers
* 🚀 Single augmentation for all API needs
*
* This unifies and replaces:
* - BrainyMCPBroadcast (Node-specific server)
* - WebSocketConduitAugmentation (client connections)
* - Future REST API implementations
*/
import { BaseAugmentation } from './brainyAugmentation.js';
export interface APIServerConfig {
enabled?: boolean;
port?: number;
mcpPort?: number;
wsPort?: number;
host?: string;
cors?: {
origin?: string | string[];
credentials?: boolean;
};
auth?: {
required?: boolean;
apiKeys?: string[];
bearerTokens?: string[];
};
rateLimit?: {
windowMs?: number;
max?: number;
};
ssl?: {
cert?: string;
key?: string;
};
}
/**
* Unified API Server Augmentation
* Exposes Brainy through multiple protocols
*/
export declare class APIServerAugmentation extends BaseAugmentation {
readonly name = "api-server";
readonly timing: "after";
readonly metadata: "readonly";
readonly operations: ("all")[];
readonly priority = 5;
protected config: APIServerConfig;
private mcpService?;
private httpServer?;
private wsServer?;
private clients;
private operationHistory;
private maxHistorySize;
constructor(config?: APIServerConfig);
protected onInitialize(): Promise<void>;
/**
* Start Node.js server with Express
*/
private startNodeServer;
/**
* Setup REST API routes
*/
private setupRESTRoutes;
/**
* Setup WebSocket server
*/
private setupWebSocketServer;
/**
* Handle WebSocket message
*/
private handleWebSocketMessage;
/**
* Execute augmentation - broadcast operations to clients
*/
execute<T = any>(operation: string, params: any, next: () => Promise<T>): Promise<T>;
/**
* Auth middleware for Express
*/
private authMiddleware;
/**
* Rate limiting middleware
*/
private rateLimitMiddleware;
/**
* Sanitize parameters before broadcasting
*/
private sanitizeParams;
/**
* Send heartbeats to all connected clients
*/
private sendHeartbeats;
/**
* Start Deno server
*/
private startDenoServer;
/**
* Start Service Worker (for browser)
*/
private startServiceWorker;
/**
* Shutdown the server
*/
protected onShutdown(): Promise<void>;
}
/**
* Helper function to create and configure API server
*/
export declare function createAPIServer(config?: APIServerConfig): APIServerAugmentation;

View file

@ -0,0 +1,503 @@
/**
* API Server Augmentation - Universal API Exposure
*
* 🌐 Exposes Brainy through REST, WebSocket, and MCP
* 🔌 Works in Node.js, Deno, and Service Workers
* 🚀 Single augmentation for all API needs
*
* This unifies and replaces:
* - BrainyMCPBroadcast (Node-specific server)
* - WebSocketConduitAugmentation (client connections)
* - Future REST API implementations
*/
import { BaseAugmentation } from './brainyAugmentation.js';
import { BrainyMCPService } from '../mcp/brainyMCPService.js';
import { v4 as uuidv4 } from '../universal/uuid.js';
import { isNode, isBrowser } from '../utils/environment.js';
/**
* Unified API Server Augmentation
* Exposes Brainy through multiple protocols
*/
export class APIServerAugmentation extends BaseAugmentation {
constructor(config = {}) {
super();
this.name = 'api-server';
this.timing = 'after';
this.metadata = 'readonly'; // API server reads metadata to serve data
this.operations = ['all'];
this.priority = 5; // Low priority, runs after other augmentations
this.clients = new Map();
this.operationHistory = [];
this.maxHistorySize = 1000;
this.config = {
enabled: true,
port: 3000,
host: '0.0.0.0',
cors: { origin: '*', credentials: true },
auth: { required: false },
rateLimit: { windowMs: 60000, max: 100 },
...config
};
}
async onInitialize() {
if (!this.config.enabled) {
this.log('API Server disabled in config');
return;
}
// Initialize MCP service
this.mcpService = new BrainyMCPService(this.context.brain, {
enableAuth: this.config.auth?.required
});
// Start appropriate server based on environment
if (isNode()) {
await this.startNodeServer();
}
else if (typeof globalThis.Deno !== 'undefined') {
await this.startDenoServer();
}
else if (isBrowser() && 'serviceWorker' in navigator) {
await this.startServiceWorker();
}
else {
this.log('No suitable server environment detected', 'warn');
}
}
/**
* Start Node.js server with Express
*/
async startNodeServer() {
try {
// Dynamic imports for Node.js dependencies
const express = await import('express').catch(() => null);
const cors = await import('cors').catch(() => null);
const ws = await import('ws').catch(() => null);
const { createServer } = await import('http');
if (!express || !cors || !ws) {
this.log('Express, cors, or ws not available. Install with: npm install express cors ws', 'error');
return;
}
const WebSocketServer = ws?.WebSocketServer || ws?.default?.WebSocketServer || ws?.Server;
const app = express.default();
// Middleware
app.use(cors.default(this.config.cors));
app.use((express.default || express).json({ limit: '50mb' }));
app.use(this.authMiddleware.bind(this));
app.use(this.rateLimitMiddleware.bind(this));
// REST API Routes
this.setupRESTRoutes(app);
// Create HTTP server
this.httpServer = createServer(app);
// WebSocket server
this.wsServer = new WebSocketServer({
server: this.httpServer,
path: '/ws'
});
this.setupWebSocketServer();
// Start listening
await new Promise((resolve, reject) => {
this.httpServer.listen(this.config.port, this.config.host, () => {
this.log(`🌐 API Server listening on http://${this.config.host}:${this.config.port}`);
this.log(`🔌 WebSocket: ws://${this.config.host}:${this.config.port}/ws`);
this.log(`🧠 MCP endpoint: http://${this.config.host}:${this.config.port}/api/mcp`);
resolve();
}).on('error', reject);
});
// Heartbeat interval
setInterval(() => this.sendHeartbeats(), 30000);
}
catch (error) {
this.log(`Failed to start Node.js server: ${error}`, 'error');
throw error;
}
}
/**
* Setup REST API routes
*/
setupRESTRoutes(app) {
// Health check
app.get('/health', (_req, res) => {
res.json({
status: 'healthy',
version: '2.0.0',
clients: this.clients.size,
uptime: process.uptime ? process.uptime() : 0
});
});
// Search endpoint
app.post('/api/search', async (req, res) => {
try {
const { query, limit = 10, options = {} } = req.body;
const results = await this.context.brain.search(query, limit, options);
res.json({ success: true, results });
}
catch (error) {
res.status(500).json({ success: false, error: error.message });
}
});
// Add data endpoint
app.post('/api/add', async (req, res) => {
try {
const { content, metadata } = req.body;
const id = await this.context.brain.addNoun(content, 'Content', metadata);
res.json({ success: true, id });
}
catch (error) {
res.status(500).json({ success: false, error: error.message });
}
});
// Get by ID endpoint
app.get('/api/get/:id', async (req, res) => {
try {
const data = await this.context.brain.get(req.params.id);
if (data) {
res.json({ success: true, data });
}
else {
res.status(404).json({ success: false, error: 'Not found' });
}
}
catch (error) {
res.status(500).json({ success: false, error: error.message });
}
});
// Delete endpoint
app.delete('/api/delete/:id', async (req, res) => {
try {
await this.context.brain.delete(req.params.id);
res.json({ success: true });
}
catch (error) {
res.status(500).json({ success: false, error: error.message });
}
});
// Relate endpoint
app.post('/api/relate', async (req, res) => {
try {
const { source, target, verb, metadata } = req.body;
await this.context.brain.relate(source, target, verb, metadata);
res.json({ success: true });
}
catch (error) {
res.status(500).json({ success: false, error: error.message });
}
});
// Find endpoint (complex queries)
app.post('/api/find', async (req, res) => {
try {
const results = await this.context.brain.find(req.body);
res.json({ success: true, results });
}
catch (error) {
res.status(500).json({ success: false, error: error.message });
}
});
// Cluster endpoint
app.post('/api/cluster', async (req, res) => {
try {
const { algorithm = 'kmeans', options = {} } = req.body;
const clusters = await this.context.brain.cluster(algorithm, options);
res.json({ success: true, clusters });
}
catch (error) {
res.status(500).json({ success: false, error: error.message });
}
});
// MCP endpoint
app.post('/api/mcp', async (req, res) => {
try {
const response = await this.mcpService.handleRequest(req.body);
res.json(response);
}
catch (error) {
res.status(500).json({ success: false, error: error.message });
}
});
// Statistics endpoint
app.get('/api/stats', async (_req, res) => {
try {
const stats = await this.context.brain.getStatistics();
res.json({ success: true, stats });
}
catch (error) {
res.status(500).json({ success: false, error: error.message });
}
});
// Operation history endpoint
app.get('/api/history', (_req, res) => {
res.json({
success: true,
history: this.operationHistory.slice(-100)
});
});
}
/**
* Setup WebSocket server
*/
setupWebSocketServer() {
if (!this.wsServer)
return;
this.wsServer.on('connection', (socket, request) => {
const clientId = uuidv4();
const client = {
id: clientId,
type: 'websocket',
socket,
subscriptions: [],
lastSeen: Date.now()
};
this.clients.set(clientId, client);
// Send welcome message
socket.send(JSON.stringify({
type: 'welcome',
clientId,
message: 'Connected to Brainy API Server',
capabilities: ['search', 'add', 'delete', 'relate', 'subscribe', 'mcp']
}));
// Handle messages
socket.on('message', async (message) => {
try {
const msg = JSON.parse(message);
await this.handleWebSocketMessage(msg, client);
}
catch (error) {
socket.send(JSON.stringify({
type: 'error',
error: error.message
}));
}
});
// Handle disconnect
socket.on('close', () => {
this.clients.delete(clientId);
this.log(`Client ${clientId} disconnected`);
});
// Handle errors
socket.on('error', (error) => {
this.log(`WebSocket error for client ${clientId}: ${error}`, 'error');
});
});
}
/**
* Handle WebSocket message
*/
async handleWebSocketMessage(msg, client) {
const { socket } = client;
switch (msg.type) {
case 'subscribe':
// Subscribe to operation types
client.subscriptions = msg.operations || ['all'];
socket.send(JSON.stringify({
type: 'subscribed',
operations: client.subscriptions
}));
break;
case 'search':
const searchResults = await this.context.brain.search(msg.query, msg.limit || 10, msg.options || {});
socket.send(JSON.stringify({
type: 'searchResults',
requestId: msg.requestId,
results: searchResults
}));
break;
case 'add':
const id = await this.context.brain.addNoun(msg.content, 'Content', msg.metadata);
socket.send(JSON.stringify({
type: 'addResult',
requestId: msg.requestId,
id
}));
break;
case 'mcp':
const mcpResponse = await this.mcpService.handleRequest(msg.request);
socket.send(JSON.stringify({
type: 'mcpResponse',
requestId: msg.requestId,
response: mcpResponse
}));
break;
case 'heartbeat':
client.lastSeen = Date.now();
socket.send(JSON.stringify({
type: 'heartbeat',
timestamp: Date.now()
}));
break;
default:
socket.send(JSON.stringify({
type: 'error',
error: `Unknown message type: ${msg.type}`
}));
}
}
/**
* Execute augmentation - broadcast operations to clients
*/
async execute(operation, params, next) {
const startTime = Date.now();
const result = await next();
const duration = Date.now() - startTime;
// Record operation in history
const historyEntry = {
operation,
params: this.sanitizeParams(params),
timestamp: Date.now(),
duration
};
this.operationHistory.push(historyEntry);
if (this.operationHistory.length > this.maxHistorySize) {
this.operationHistory.shift();
}
// Broadcast to subscribed WebSocket clients
const message = JSON.stringify({
type: 'operation',
operation,
params: historyEntry.params,
timestamp: historyEntry.timestamp,
duration
});
for (const client of this.clients.values()) {
if (client.type === 'websocket' && client.socket) {
if (client.subscriptions?.includes('all') ||
client.subscriptions?.includes(operation)) {
try {
client.socket.send(message);
}
catch (error) {
// Client might be disconnected
this.clients.delete(client.id);
}
}
}
}
return result;
}
/**
* Auth middleware for Express
*/
authMiddleware(req, res, next) {
if (!this.config.auth?.required) {
return next();
}
const apiKey = req.headers['x-api-key'];
const bearerToken = req.headers.authorization?.replace('Bearer ', '');
if (apiKey && this.config.auth.apiKeys?.includes(apiKey)) {
return next();
}
if (bearerToken && this.config.auth.bearerTokens?.includes(bearerToken)) {
return next();
}
res.status(401).json({ error: 'Unauthorized' });
}
/**
* Rate limiting middleware
*/
rateLimitMiddleware(req, res, next) {
// Simple in-memory rate limiting
// In production, use redis or proper rate limiting library
const ip = req.ip || req.connection.remoteAddress;
const now = Date.now();
const windowMs = this.config.rateLimit?.windowMs || 60000;
const max = this.config.rateLimit?.max || 100;
// Clean old entries
for (const [key, client] of this.clients.entries()) {
if (now - client.lastSeen > windowMs) {
this.clients.delete(key);
}
}
// For now, just pass through
// Real implementation would track requests per IP
next();
}
/**
* Sanitize parameters before broadcasting
*/
sanitizeParams(params) {
if (!params)
return params;
const sanitized = { ...params };
// Remove sensitive fields
delete sanitized.password;
delete sanitized.apiKey;
delete sanitized.token;
delete sanitized.secret;
// Truncate large data
if (sanitized.content && sanitized.content.length > 1000) {
sanitized.content = sanitized.content.substring(0, 1000) + '...';
}
return sanitized;
}
/**
* Send heartbeats to all connected clients
*/
sendHeartbeats() {
const now = Date.now();
for (const [id, client] of this.clients.entries()) {
if (client.type === 'websocket' && client.socket) {
// Remove inactive clients
if (now - client.lastSeen > 60000) {
this.clients.delete(id);
continue;
}
// Send heartbeat
try {
client.socket.send(JSON.stringify({
type: 'heartbeat',
timestamp: now
}));
}
catch {
// Client disconnected
this.clients.delete(id);
}
}
}
}
/**
* Start Deno server
*/
async startDenoServer() {
// Deno implementation would go here
// Using Deno.serve() or oak framework
this.log('Deno server not yet implemented', 'warn');
}
/**
* Start Service Worker (for browser)
*/
async startServiceWorker() {
// Service Worker implementation would go here
// Intercepts fetch() calls and handles them locally
this.log('Service Worker API not yet implemented', 'warn');
}
/**
* Shutdown the server
*/
async onShutdown() {
// Close all WebSocket connections
for (const client of this.clients.values()) {
if (client.socket) {
try {
client.socket.close();
}
catch { }
}
}
this.clients.clear();
// Close servers
if (this.wsServer) {
this.wsServer.close();
}
if (this.httpServer) {
await new Promise(resolve => {
this.httpServer.close(() => resolve());
});
}
this.log('API Server shut down');
}
}
/**
* Helper function to create and configure API server
*/
export function createAPIServer(config) {
return new APIServerAugmentation(config);
}
//# sourceMappingURL=apiServerAugmentation.js.map

File diff suppressed because one or more lines are too long

View file

@ -0,0 +1,109 @@
/**
* Audit Logging Augmentation
* Provides comprehensive audit trail for all Brainy operations
*/
import { BaseAugmentation } from './brainyAugmentation.js';
import { AugmentationManifest } from './manifest.js';
export interface AuditLogConfig {
enabled?: boolean;
logLevel?: 'minimal' | 'standard' | 'detailed';
includeData?: boolean;
includeMetadata?: boolean;
retention?: number;
storage?: 'memory' | 'file' | 'database';
filePath?: string;
maxMemoryLogs?: number;
}
export interface AuditLogEntry {
id: string;
timestamp: number;
operation: string;
params: any;
result?: any;
error?: any;
duration: number;
userId?: string;
sessionId?: string;
metadata?: Record<string, any>;
}
/**
* Audit Log Augmentation
*/
export declare class AuditLogAugmentation extends BaseAugmentation {
readonly name = "auditLogger";
readonly timing: "around";
readonly metadata: "readonly";
operations: any;
readonly priority = 90;
readonly category: "core";
readonly description = "Comprehensive audit logging for compliance and debugging";
private logs;
private sessionId;
constructor(config?: AuditLogConfig);
getManifest(): AugmentationManifest;
protected onInitialize(): Promise<void>;
protected onShutdown(): Promise<void>;
/**
* Execute augmentation - log operations
*/
execute<T = any>(operation: string, params: any, next: () => Promise<T>): Promise<T>;
/**
* Sanitize parameters to remove sensitive data
*/
private sanitizeParams;
/**
* Sanitize result data
*/
private sanitizeResult;
/**
* Sanitize error information
*/
private sanitizeError;
/**
* Write log entry
*/
private writeLog;
/**
* Flush logs to persistent storage
*/
private flushLogs;
/**
* Clean up old logs based on retention
*/
private cleanupOldLogs;
/**
* Generate unique ID
*/
private generateId;
/**
* Query audit logs
*/
queryLogs(filter?: {
operation?: string;
startTime?: number;
endTime?: number;
sessionId?: string;
hasError?: boolean;
}): AuditLogEntry[];
/**
* Get audit statistics
*/
getStats(): {
totalLogs: number;
operations: Record<string, number>;
averageDuration: number;
errorRate: number;
};
/**
* Export logs for analysis
*/
exportLogs(): AuditLogEntry[];
/**
* Clear all logs
*/
clearLogs(): void;
}
/**
* Create audit log augmentation
*/
export declare function createAuditLogAugmentation(config?: AuditLogConfig): AuditLogAugmentation;

View file

@ -0,0 +1,358 @@
/**
* Audit Logging Augmentation
* Provides comprehensive audit trail for all Brainy operations
*/
import { BaseAugmentation } from './brainyAugmentation.js';
import { createHash } from 'crypto';
/**
* Audit Log Augmentation
*/
export class AuditLogAugmentation extends BaseAugmentation {
constructor(config = {}) {
super(config);
this.name = 'auditLogger';
this.timing = 'around';
this.metadata = 'readonly'; // Read metadata for context
this.operations = ['all']; // Audit all operations
this.priority = 90; // Low priority, runs last
// Augmentation metadata
this.category = 'core';
this.description = 'Comprehensive audit logging for compliance and debugging';
this.logs = [];
// Merge with defaults
this.config = {
enabled: config.enabled ?? true,
logLevel: config.logLevel ?? 'standard',
includeData: config.includeData ?? false,
includeMetadata: config.includeMetadata ?? true,
retention: config.retention ?? 90, // 90 days default
storage: config.storage ?? 'memory',
filePath: config.filePath,
maxMemoryLogs: config.maxMemoryLogs ?? 10000
};
// Generate session ID
this.sessionId = this.generateId();
}
getManifest() {
return {
id: 'audit-logger',
name: 'Audit Logger',
version: '1.0.0',
description: 'Comprehensive audit trail for all operations',
longDescription: 'Records detailed audit logs of all Brainy operations for compliance, debugging, and analytics purposes.',
category: 'analytics',
configSchema: {
type: 'object',
properties: {
enabled: {
type: 'boolean',
default: true,
description: 'Enable audit logging'
},
logLevel: {
type: 'string',
enum: ['minimal', 'standard', 'detailed'],
default: 'standard',
description: 'Level of detail to log'
},
includeData: {
type: 'boolean',
default: false,
description: 'Include actual data in logs (privacy concern)'
},
includeMetadata: {
type: 'boolean',
default: true,
description: 'Include metadata in logs'
},
retention: {
type: 'number',
default: 90,
minimum: 1,
maximum: 365,
description: 'Days to retain logs'
},
storage: {
type: 'string',
enum: ['memory', 'file', 'database'],
default: 'memory',
description: 'Where to store audit logs'
},
maxMemoryLogs: {
type: 'number',
default: 10000,
description: 'Maximum logs to keep in memory'
}
}
},
configDefaults: {
enabled: true,
logLevel: 'standard',
includeData: false,
includeMetadata: true,
retention: 90,
storage: 'memory',
maxMemoryLogs: 10000
},
minBrainyVersion: '3.0.0',
keywords: ['audit', 'logging', 'compliance', 'analytics'],
documentation: 'https://docs.brainy.dev/augmentations/audit-log',
status: 'stable',
performance: {
memoryUsage: 'medium',
cpuUsage: 'low',
networkUsage: 'none'
},
features: ['operation-logging', 'configurable-detail', 'retention-management'],
enhancedOperations: ['all'],
metrics: [
{
name: 'audit_logs_created',
type: 'counter',
description: 'Total audit logs created'
},
{
name: 'audit_log_size',
type: 'gauge',
description: 'Current audit log size'
}
]
};
}
async onInitialize() {
if (!this.config.enabled) {
this.log('Audit logger disabled by configuration');
return;
}
this.log(`Audit logger initialized (level: ${this.config.logLevel}, storage: ${this.config.storage})`);
// Start retention cleanup if using memory storage
if (this.config.storage === 'memory') {
setInterval(() => {
this.cleanupOldLogs();
}, 3600000); // Every hour
}
}
async onShutdown() {
// Save any pending logs if using file storage
if (this.config.storage === 'file' && this.logs.length > 0) {
await this.flushLogs();
}
this.log('Audit logger shut down');
}
/**
* Execute augmentation - log operations
*/
async execute(operation, params, next) {
// If audit logging is disabled, just pass through
if (!this.config.enabled) {
return next();
}
const startTime = Date.now();
const logEntry = {
id: this.generateId(),
timestamp: startTime,
operation,
sessionId: this.sessionId
};
// Add params based on log level
if (this.config.logLevel !== 'minimal') {
logEntry.params = this.sanitizeParams(params);
}
try {
const result = await next();
// Log successful operation
logEntry.duration = Date.now() - startTime;
// Add result based on log level and config
if (this.config.logLevel === 'detailed' && this.config.includeData) {
logEntry.result = this.sanitizeResult(result);
}
await this.writeLog(logEntry);
return result;
}
catch (error) {
// Log failed operation
logEntry.duration = Date.now() - startTime;
logEntry.error = this.sanitizeError(error);
await this.writeLog(logEntry);
throw error;
}
}
/**
* Sanitize parameters to remove sensitive data
*/
sanitizeParams(params) {
if (!params)
return params;
// Don't include actual data unless configured
if (!this.config.includeData && params.data) {
return {
...params,
data: '[REDACTED]'
};
}
// Redact common sensitive fields
const sanitized = { ...params };
const sensitiveFields = ['password', 'token', 'apiKey', 'secret'];
for (const field of sensitiveFields) {
if (sanitized[field]) {
sanitized[field] = '[REDACTED]';
}
}
return sanitized;
}
/**
* Sanitize result data
*/
sanitizeResult(result) {
if (!result)
return result;
// For arrays, just log count
if (Array.isArray(result)) {
return { count: result.length, type: 'array' };
}
// For objects, remove sensitive fields
if (typeof result === 'object') {
const sanitized = {};
for (const key in result) {
if (!['password', 'token', 'apiKey', 'secret'].includes(key)) {
sanitized[key] = result[key];
}
}
return sanitized;
}
return result;
}
/**
* Sanitize error information
*/
sanitizeError(error) {
if (!error)
return error;
return {
message: error.message || 'Unknown error',
code: error.code,
statusCode: error.statusCode,
stack: this.config.logLevel === 'detailed' ? error.stack : undefined
};
}
/**
* Write log entry
*/
async writeLog(entry) {
switch (this.config.storage) {
case 'memory':
this.logs.push(entry);
// Enforce max memory logs
if (this.logs.length > this.config.maxMemoryLogs) {
this.logs.shift(); // Remove oldest
}
break;
case 'file':
// In production, would write to file
// For now, just add to memory
this.logs.push(entry);
break;
case 'database':
// In production, would write to database
// For now, just add to memory
this.logs.push(entry);
break;
}
}
/**
* Flush logs to persistent storage
*/
async flushLogs() {
// In production, would write to file/database
// For now, just clear old logs
if (this.logs.length > this.config.maxMemoryLogs) {
this.logs = this.logs.slice(-this.config.maxMemoryLogs);
}
}
/**
* Clean up old logs based on retention
*/
cleanupOldLogs() {
const cutoffTime = Date.now() - (this.config.retention * 24 * 60 * 60 * 1000);
this.logs = this.logs.filter(log => log.timestamp >= cutoffTime);
}
/**
* Generate unique ID
*/
generateId() {
return createHash('sha256')
.update(`${Date.now()}-${Math.random()}`)
.digest('hex')
.substring(0, 16);
}
/**
* Query audit logs
*/
queryLogs(filter) {
let results = [...this.logs];
if (filter) {
if (filter.operation) {
results = results.filter(log => log.operation === filter.operation);
}
if (filter.startTime) {
results = results.filter(log => log.timestamp >= filter.startTime);
}
if (filter.endTime) {
results = results.filter(log => log.timestamp <= filter.endTime);
}
if (filter.sessionId) {
results = results.filter(log => log.sessionId === filter.sessionId);
}
if (filter.hasError !== undefined) {
results = results.filter(log => (log.error !== undefined) === filter.hasError);
}
}
return results;
}
/**
* Get audit statistics
*/
getStats() {
const stats = {
totalLogs: this.logs.length,
operations: {},
averageDuration: 0,
errorRate: 0
};
let totalDuration = 0;
let errorCount = 0;
for (const log of this.logs) {
// Count by operation
stats.operations[log.operation] = (stats.operations[log.operation] || 0) + 1;
// Sum duration
totalDuration += log.duration;
// Count errors
if (log.error)
errorCount++;
}
if (this.logs.length > 0) {
stats.averageDuration = totalDuration / this.logs.length;
stats.errorRate = errorCount / this.logs.length;
}
return stats;
}
/**
* Export logs for analysis
*/
exportLogs() {
return [...this.logs];
}
/**
* Clear all logs
*/
clearLogs() {
this.logs = [];
}
}
/**
* Create audit log augmentation
*/
export function createAuditLogAugmentation(config) {
return new AuditLogAugmentation(config);
}
//# sourceMappingURL=auditLogAugmentation.js.map

File diff suppressed because one or more lines are too long

View file

@ -0,0 +1,97 @@
/**
* Batch Processing Augmentation
*
* Critical for enterprise-scale performance: 500,000+ operations/second
* Automatically batches operations for maximum throughput
* Handles streaming data, bulk imports, and high-frequency operations
*
* Performance Impact: 10-50x improvement for bulk operations
*/
import { BaseAugmentation } from './brainyAugmentation.js';
import { AugmentationManifest } from './manifest.js';
interface BatchConfig {
enabled?: boolean;
adaptiveMode?: boolean;
immediateThreshold?: number;
batchThreshold?: number;
maxBatchSize?: number;
maxWaitTime?: number;
adaptiveBatching?: boolean;
priorityLanes?: number;
memoryLimit?: number;
}
interface BatchMetrics {
totalOperations: number;
batchesProcessed: number;
averageBatchSize: number;
averageLatency: number;
throughputPerSecond: number;
memoryUsage: number;
adaptiveAdjustments: number;
}
export declare class BatchProcessingAugmentation extends BaseAugmentation {
readonly metadata: "readonly";
name: string;
timing: "around";
operations: ("add" | "addNoun" | "addVerb" | "saveNoun" | "saveVerb" | "storage")[];
priority: number;
protected config: Required<BatchConfig>;
private batches;
private flushTimers;
private metrics;
private currentMemoryUsage;
private performanceHistory;
constructor(config?: BatchConfig);
getManifest(): AugmentationManifest;
protected onInitialize(): Promise<void>;
shouldExecute(operation: string, params: any): boolean;
execute<T = any>(operation: string, params: any, next: () => Promise<T>): Promise<T>;
private shouldBatch;
/**
* SMART WORKFLOW DETECTION METHODS
* These methods detect critical patterns that must not be batched
*/
private isEntityRegistryWorkflow;
private isDependencyChainStart;
private isWriteOnlyMode;
private hasEntityRegistryMetadata;
private getOperationContext;
private getCurrentLoad;
private addToBatch;
private getOperationPriority;
private getBatchKey;
private getOperationType;
private estimateOperationSize;
private shouldFlushBatch;
private extractPriorityFromKey;
private setFlushTimer;
private getAdaptiveWaitTime;
private getPerformanceMultiplier;
private flushBatch;
private processBatch;
private processBatchByType;
private processBatchSave;
private processBatchUpdate;
private processBatchDelete;
private processIndividually;
private processWithConcurrency;
private flushOldestBatch;
private updateMetrics;
private adjustBatchSize;
private startMetricsCollection;
/**
* Get batch processing statistics
*/
getStats(): BatchMetrics & {
pendingBatches: number;
pendingOperations: number;
currentBatchSize: number;
memoryUtilization: string;
};
/**
* Force flush all pending batches
*/
flushAll(): Promise<void>;
protected onShutdown(): Promise<void>;
}
export {};

View file

@ -0,0 +1,669 @@
/**
* Batch Processing Augmentation
*
* Critical for enterprise-scale performance: 500,000+ operations/second
* Automatically batches operations for maximum throughput
* Handles streaming data, bulk imports, and high-frequency operations
*
* Performance Impact: 10-50x improvement for bulk operations
*/
import { BaseAugmentation } from './brainyAugmentation.js';
export class BatchProcessingAugmentation extends BaseAugmentation {
constructor(config) {
super(config);
this.metadata = 'readonly'; // Reads metadata for batching decisions
this.name = 'BatchProcessing';
this.timing = 'around';
this.operations = ['add', 'addNoun', 'addVerb', 'saveNoun', 'saveVerb', 'storage'];
this.priority = 80; // High priority for performance
this.config = {
enabled: true,
adaptiveMode: true,
immediateThreshold: 1,
batchThreshold: 5,
maxBatchSize: 100,
maxWaitTime: 1000,
adaptiveBatching: true,
priorityLanes: 2,
memoryLimit: 100 * 1024 * 1024 // 100MB
};
this.batches = new Map();
this.flushTimers = new Map();
this.metrics = {
totalOperations: 0,
batchesProcessed: 0,
averageBatchSize: 0,
averageLatency: 0,
throughputPerSecond: 0,
memoryUsage: 0,
adaptiveAdjustments: 0
};
this.currentMemoryUsage = 0;
this.performanceHistory = [];
}
getManifest() {
return {
id: 'batch-processing',
name: 'Batch Processing',
version: '2.0.0',
description: 'High-performance batching for bulk operations',
longDescription: 'Automatically batches operations for maximum throughput. Essential for enterprise-scale workloads, achieving 500,000+ operations/second. Provides 10-50x performance improvement for bulk operations.',
category: 'performance',
configSchema: {
type: 'object',
properties: {
enabled: {
type: 'boolean',
default: true,
description: 'Enable batch processing'
},
adaptiveMode: {
type: 'boolean',
default: true,
description: 'Automatically decide when to batch operations'
},
immediateThreshold: {
type: 'number',
default: 1,
minimum: 1,
maximum: 10,
description: 'Operations count below which to execute immediately'
},
batchThreshold: {
type: 'number',
default: 5,
minimum: 2,
maximum: 100,
description: 'Queue size at which to start batching'
},
maxBatchSize: {
type: 'number',
default: 1000,
minimum: 10,
maximum: 10000,
description: 'Maximum items per batch'
},
maxWaitTime: {
type: 'number',
default: 100,
minimum: 1,
maximum: 5000,
description: 'Maximum wait time before flushing batch (ms)'
},
adaptiveBatching: {
type: 'boolean',
default: true,
description: 'Dynamically adjust batch size based on performance'
},
priorityLanes: {
type: 'number',
default: 3,
minimum: 1,
maximum: 10,
description: 'Number of priority processing lanes'
},
memoryLimit: {
type: 'number',
default: 104857600, // 100MB
minimum: 10485760, // 10MB
maximum: 1073741824, // 1GB
description: 'Maximum memory for batching in bytes'
}
},
additionalProperties: false
},
configDefaults: {
enabled: true,
adaptiveMode: true,
immediateThreshold: 1,
batchThreshold: 5,
maxBatchSize: 1000,
maxWaitTime: 100,
adaptiveBatching: true,
priorityLanes: 3,
memoryLimit: 104857600
},
minBrainyVersion: '2.0.0',
keywords: ['batch', 'performance', 'bulk', 'streaming', 'throughput'],
documentation: 'https://docs.brainy.dev/augmentations/batch-processing',
status: 'stable',
performance: {
memoryUsage: 'high',
cpuUsage: 'medium',
networkUsage: 'none'
},
features: ['auto-batching', 'adaptive-sizing', 'priority-lanes', 'streaming-support'],
enhancedOperations: ['add', 'addNoun', 'addVerb', 'saveNoun', 'saveVerb'],
ui: {
icon: '📦',
color: '#9C27B0'
}
};
}
async onInitialize() {
if (this.config.enabled) {
this.startMetricsCollection();
this.log(`Batch processing initialized: ${this.config.maxBatchSize} batch size, ${this.config.maxWaitTime}ms max wait`);
if (this.config.adaptiveBatching) {
this.log('Adaptive batching enabled - will optimize batch size dynamically');
}
}
else {
this.log('Batch processing disabled');
}
}
shouldExecute(operation, params) {
if (!this.config.enabled)
return false;
// Skip batching for single operations or already-batched operations
if (params?.batch === false || params?.streaming === false)
return false;
// Enable for high-volume operations
return operation.includes('add') ||
operation.includes('save') ||
operation.includes('storage');
}
async execute(operation, params, next) {
if (!this.shouldExecute(operation, params)) {
return next();
}
// Check if this should be batched based on system load
if (this.shouldBatch(operation, params)) {
return this.addToBatch(operation, params, next);
}
// Execute immediately for low-latency requirements
return next();
}
shouldBatch(operation, params) {
// ZERO-CONFIG INTELLIGENT ADAPTATION:
if (this.config.adaptiveMode) {
// CRITICAL WORKFLOW DETECTION: Never batch operations that break critical patterns
// 1. ENTITY REGISTRY PATTERN: Never batch when immediate lookup is expected
if (this.isEntityRegistryWorkflow(operation, params)) {
return false; // Must be immediate for registry lookups to work
}
// 2. DEPENDENCY CHAIN PATTERN: Never batch when next operation depends on this one
if (this.isDependencyChainStart(operation, params)) {
return false; // Must be immediate for noun → verb workflows
}
// Count pending operations in the current operation's batch (needed for write-only mode)
const batchKey = this.getBatchKey(operation, params);
const currentBatch = this.batches.get(batchKey) || [];
const pendingCount = currentBatch.length;
// 3. WRITE-ONLY MODE: Special handling for high-speed streaming
if (this.isWriteOnlyMode(params)) {
// In write-only mode, batch aggressively but ensure entity registry updates immediately
if (this.hasEntityRegistryMetadata(params)) {
return false; // Entity registry updates must be immediate even in write-only mode
}
return pendingCount >= 3; // Lower threshold for write-only mode batching
}
// Apply intelligent thresholds:
// 4. Single operations are immediate (responsive user experience)
if (pendingCount < this.config.immediateThreshold) {
return false; // Execute immediately
}
// 5. Start batching when multiple operations are queued
if (pendingCount >= this.config.batchThreshold) {
return true; // Batch for efficiency
}
// 6. For in-between cases, use smart heuristics
const currentLoad = this.getCurrentLoad();
if (currentLoad > 0.5)
return true; // Higher load = more batching
// 7. Batch operations that naturally benefit from grouping
if (operation.includes('save') || operation.includes('add')) {
return pendingCount > 1; // Batch if others are already waiting
}
return false; // Default to immediate for best responsiveness
}
// TRADITIONAL MODE: (for explicit configuration scenarios)
// Always batch if explicitly requested
if (params?.batch === true || params?.streaming === true)
return true;
// Batch based on current system load
const currentLoad = this.getCurrentLoad();
if (currentLoad > 0.7)
return true; // High load - batch everything
// Batch operations that benefit from grouping
return operation.includes('save') ||
operation.includes('add') ||
operation.includes('update');
}
/**
* SMART WORKFLOW DETECTION METHODS
* These methods detect critical patterns that must not be batched
*/
isEntityRegistryWorkflow(operation, params) {
// Detect operations that will likely be followed by immediate entity registry lookups
if (operation === 'addNoun' || operation === 'add') {
// Check if metadata contains external identifiers (DID, handle, etc.)
const metadata = params?.metadata || params?.data || {};
return !!(metadata.did || // Bluesky DID
metadata.handle || // Social media handle
metadata.uri || // Resource URI
metadata.external_id || // External system ID
metadata.user_id || // User ID
metadata.profile_id || // Profile ID
metadata.account_id // Account ID
);
}
return false;
}
isDependencyChainStart(operation, params) {
// Detect operations that are likely to be followed by dependent operations
if (operation === 'addNoun' || operation === 'add') {
// In interactive workflows, noun creation is often followed by verb creation
// Use heuristics to detect this pattern
const context = this.getOperationContext();
// If we've seen recent addVerb operations, this noun might be for a relationship
if (context.recentVerbOperations > 0) {
return true;
}
// If this is part of a rapid sequence of operations, it might be a dependency chain
if (context.operationsInLastSecond > 3) {
return true;
}
}
return false;
}
isWriteOnlyMode(params) {
// Detect write-only mode from context or parameters
return !!(params?.writeOnlyMode ||
params?.streaming ||
params?.highThroughput ||
this.context?.brain?.writeOnly);
}
hasEntityRegistryMetadata(params) {
// Check if this operation has metadata that needs immediate entity registry updates
const metadata = params?.metadata || params?.data || {};
return !!(metadata.did ||
metadata.handle ||
metadata.uri ||
metadata.external_id ||
// Also check for auto-registration hints
params?.autoCreateMissingNouns ||
params?.entityRegistry);
}
getOperationContext() {
const now = Date.now();
const oneSecondAgo = now - 1000;
let recentVerbOperations = 0;
let operationsInLastSecond = 0;
// Analyze recent operations across all batches
for (const batch of this.batches.values()) {
for (const op of batch) {
if (op.timestamp > oneSecondAgo) {
operationsInLastSecond++;
if (op.operation.includes('Verb') || op.operation.includes('verb')) {
recentVerbOperations++;
}
}
}
}
return { recentVerbOperations, operationsInLastSecond };
}
getCurrentLoad() {
// Simple load calculation based on pending operations
let totalPending = 0;
for (const batch of this.batches.values()) {
totalPending += batch.length;
}
return Math.min(totalPending / 10000, 1.0); // Normalize to 0-1
}
async addToBatch(operation, params, executor) {
return new Promise((resolve, reject) => {
const priority = this.getOperationPriority(operation, params);
const batchKey = this.getBatchKey(operation, priority);
const operationSize = this.estimateOperationSize(params);
// Check memory limit
if (this.currentMemoryUsage + operationSize > this.config.memoryLimit) {
// Memory limit reached - flush oldest batch
this.flushOldestBatch();
}
const batchedOp = {
id: `op_${Date.now()}_${Math.random()}`,
operation,
params,
executor, // Store the actual executor
resolver: resolve,
rejector: reject,
timestamp: Date.now(),
priority,
size: operationSize
};
// Add to appropriate batch
if (!this.batches.has(batchKey)) {
this.batches.set(batchKey, []);
}
const batch = this.batches.get(batchKey);
batch.push(batchedOp);
this.currentMemoryUsage += operationSize;
this.metrics.totalOperations++;
// Check if batch should be flushed immediately
if (this.shouldFlushBatch(batch, batchKey)) {
this.flushBatch(batchKey);
}
else if (!this.flushTimers.has(batchKey)) {
// Set flush timer if not already set
this.setFlushTimer(batchKey);
}
});
}
getOperationPriority(operation, params) {
// Explicit priority
if (params?.priority !== undefined)
return params.priority;
// Operation-based priority
if (operation.includes('delete'))
return 10; // Highest
if (operation.includes('update'))
return 8;
if (operation.includes('save'))
return 6;
if (operation.includes('add'))
return 4;
return 1; // Lowest
}
getBatchKey(operation, priority) {
// Group by operation type and priority for optimal batching
const opType = this.getOperationType(operation);
const priorityLane = Math.min(priority, this.config.priorityLanes - 1);
return `${opType}_p${priorityLane}`;
}
getOperationType(operation) {
if (operation.includes('add'))
return 'add';
if (operation.includes('save'))
return 'save';
if (operation.includes('update'))
return 'update';
if (operation.includes('delete'))
return 'delete';
return 'other';
}
estimateOperationSize(params) {
// Rough estimation of memory usage
if (!params)
return 100;
let size = 0;
if (params.vector && Array.isArray(params.vector)) {
size += params.vector.length * 8; // 8 bytes per float64
}
if (params.data) {
size += JSON.stringify(params.data).length * 2; // Rough UTF-16 estimate
}
if (params.metadata) {
size += JSON.stringify(params.metadata).length * 2;
}
return Math.max(size, 100); // Minimum 100 bytes
}
shouldFlushBatch(batch, batchKey) {
// Flush if batch is full
if (batch.length >= this.config.maxBatchSize)
return true;
// Flush if memory limit approaching
if (this.currentMemoryUsage > this.config.memoryLimit * 0.9)
return true;
// Flush high-priority batches more aggressively
const priority = this.extractPriorityFromKey(batchKey);
if (priority >= 8 && batch.length >= 100)
return true;
if (priority >= 6 && batch.length >= 500)
return true;
return false;
}
extractPriorityFromKey(batchKey) {
const match = batchKey.match(/_p(\d+)$/);
return match ? parseInt(match[1]) : 0;
}
setFlushTimer(batchKey) {
const priority = this.extractPriorityFromKey(batchKey);
const waitTime = this.getAdaptiveWaitTime(priority);
const timer = setTimeout(() => {
this.flushBatch(batchKey);
}, waitTime);
this.flushTimers.set(batchKey, timer);
}
getAdaptiveWaitTime(priority) {
if (!this.config.adaptiveBatching) {
return this.config.maxWaitTime;
}
// Adaptive wait time based on performance and priority
const baseWaitTime = this.config.maxWaitTime;
const performanceMultiplier = this.getPerformanceMultiplier();
const priorityMultiplier = priority >= 8 ? 0.5 : priority >= 6 ? 0.7 : 1.0;
return Math.max(baseWaitTime * performanceMultiplier * priorityMultiplier, 10);
}
getPerformanceMultiplier() {
if (this.performanceHistory.length < 10)
return 1.0;
// Calculate average latency trend
const recent = this.performanceHistory.slice(-10);
const average = recent.reduce((a, b) => a + b, 0) / recent.length;
// If performance is degrading, reduce wait time
if (average > this.metrics.averageLatency * 1.2)
return 0.7;
if (average < this.metrics.averageLatency * 0.8)
return 1.3;
return 1.0;
}
async flushBatch(batchKey) {
const batch = this.batches.get(batchKey);
if (!batch || batch.length === 0)
return;
// Clear timer
const timer = this.flushTimers.get(batchKey);
if (timer) {
clearTimeout(timer);
this.flushTimers.delete(batchKey);
}
// Remove batch from queue
this.batches.delete(batchKey);
const startTime = Date.now();
try {
await this.processBatch(batch);
// Update metrics
const latency = Date.now() - startTime;
this.updateMetrics(batch.length, latency);
// Adaptive adjustment
if (this.config.adaptiveBatching) {
this.adjustBatchSize(latency, batch.length);
}
}
catch (error) {
this.log(`Batch processing failed for ${batchKey}: ${error}`, 'error');
// Reject all operations in batch
batch.forEach(op => {
op.rejector(error);
this.currentMemoryUsage -= op.size;
});
}
}
async processBatch(batch) {
// Group by operation type for efficient processing
const operationGroups = new Map();
for (const op of batch) {
const opType = this.getOperationType(op.operation);
if (!operationGroups.has(opType)) {
operationGroups.set(opType, []);
}
operationGroups.get(opType).push(op);
}
// Process each operation type
for (const [opType, operations] of operationGroups) {
await this.processBatchByType(opType, operations);
}
}
async processBatchByType(opType, operations) {
// Execute batch operation based on type
try {
if (opType === 'add' || opType === 'save') {
await this.processBatchSave(operations);
}
else if (opType === 'update') {
await this.processBatchUpdate(operations);
}
else if (opType === 'delete') {
await this.processBatchDelete(operations);
}
else {
// Fallback: execute individually
await this.processIndividually(operations);
}
}
catch (error) {
throw error;
}
}
async processBatchSave(operations) {
// Try to use storage's bulk save if available
const storage = this.context?.storage;
if (storage && typeof storage.saveBatch === 'function') {
// Use bulk save operation
const items = operations.map(op => ({
...op.params,
_batchId: op.id
}));
try {
const results = await storage.saveBatch(items);
// Resolve all operations with actual results
operations.forEach((op, index) => {
op.resolver(results[index] || op.params.id);
this.currentMemoryUsage -= op.size;
});
}
catch (error) {
// Reject all operations on batch error
operations.forEach(op => {
op.rejector(error);
this.currentMemoryUsage -= op.size;
});
throw error;
}
}
else {
// Execute using stored executors with concurrency control
await this.processWithConcurrency(operations, 10);
}
}
async processBatchUpdate(operations) {
await this.processWithConcurrency(operations, 5); // Lower concurrency for updates
}
async processBatchDelete(operations) {
await this.processWithConcurrency(operations, 5); // Lower concurrency for deletes
}
async processIndividually(operations) {
await this.processWithConcurrency(operations, 3); // Conservative concurrency
}
async processWithConcurrency(operations, concurrency) {
const promises = [];
for (let i = 0; i < operations.length; i += concurrency) {
const chunk = operations.slice(i, i + concurrency);
const chunkPromise = Promise.all(chunk.map(async (op) => {
try {
// Execute using the stored executor function - REAL EXECUTION!
const result = await op.executor();
op.resolver(result);
this.currentMemoryUsage -= op.size;
}
catch (error) {
op.rejector(error);
this.currentMemoryUsage -= op.size;
}
})).then(() => { }); // Convert to void promise
promises.push(chunkPromise);
}
await Promise.all(promises);
}
// REMOVED executeOperation - no longer needed since we use stored executors
flushOldestBatch() {
if (this.batches.size === 0)
return;
// Find oldest batch
let oldestKey = '';
let oldestTime = Infinity;
for (const [key, batch] of this.batches) {
if (batch.length > 0) {
const batchAge = Math.min(...batch.map(op => op.timestamp));
if (batchAge < oldestTime) {
oldestTime = batchAge;
oldestKey = key;
}
}
}
if (oldestKey) {
this.flushBatch(oldestKey);
}
}
updateMetrics(batchSize, latency) {
this.metrics.batchesProcessed++;
this.metrics.averageBatchSize =
(this.metrics.averageBatchSize * (this.metrics.batchesProcessed - 1) + batchSize) /
this.metrics.batchesProcessed;
// Update latency with exponential moving average
this.metrics.averageLatency = this.metrics.averageLatency * 0.9 + latency * 0.1;
// Add to performance history
this.performanceHistory.push(latency);
if (this.performanceHistory.length > 100) {
this.performanceHistory.shift();
}
}
adjustBatchSize(latency, batchSize) {
const targetLatency = this.config.maxWaitTime * 5; // Target: 5x wait time
if (latency > targetLatency && batchSize > 100) {
// Reduce batch size if latency too high
this.config.maxBatchSize = Math.max(this.config.maxBatchSize * 0.9, 100);
this.metrics.adaptiveAdjustments++;
}
else if (latency < targetLatency * 0.5 && batchSize === this.config.maxBatchSize) {
// Increase batch size if latency very low
this.config.maxBatchSize = Math.min(this.config.maxBatchSize * 1.1, 10000);
this.metrics.adaptiveAdjustments++;
}
}
startMetricsCollection() {
setInterval(() => {
// Calculate throughput
this.metrics.throughputPerSecond = this.metrics.totalOperations;
this.metrics.totalOperations = 0; // Reset for next measurement
// Update memory usage
this.metrics.memoryUsage = this.currentMemoryUsage;
}, 1000);
}
/**
* Get batch processing statistics
*/
getStats() {
let pendingOperations = 0;
for (const batch of this.batches.values()) {
pendingOperations += batch.length;
}
return {
...this.metrics,
pendingBatches: this.batches.size,
pendingOperations,
currentBatchSize: this.config.maxBatchSize,
memoryUtilization: `${Math.round((this.currentMemoryUsage / this.config.memoryLimit) * 100)}%`
};
}
/**
* Force flush all pending batches
*/
async flushAll() {
const batchKeys = Array.from(this.batches.keys());
await Promise.all(batchKeys.map(key => this.flushBatch(key)));
}
async onShutdown() {
// Clear all timers
for (const timer of this.flushTimers.values()) {
clearTimeout(timer);
}
this.flushTimers.clear();
// Flush all pending batches
await this.flushAll();
const stats = this.getStats();
this.log(`Batch processing shutdown: ${this.metrics.batchesProcessed} batches processed, ${stats.memoryUtilization} peak memory usage`);
}
}
//# sourceMappingURL=batchProcessingAugmentation.js.map

File diff suppressed because one or more lines are too long

View file

@ -0,0 +1,304 @@
/**
* Single BrainyAugmentation Interface
*
* This replaces the 7 complex interfaces with one elegant, purpose-driven design.
* Each augmentation knows its place and when to execute automatically.
*
* The Vision: Components that enhance Brainy's capabilities seamlessly
* - WAL: Adds durability to storage operations
* - RequestDeduplicator: Prevents duplicate concurrent requests
* - ConnectionPool: Optimizes cloud storage throughput
* - IntelligentVerbScoring: Enhances relationship analysis
* - StreamingPipeline: Enables unlimited data processing
*/
import { AugmentationManifest } from './manifest.js';
/**
* Metadata access declaration for augmentations
*/
export interface MetadataAccess {
reads?: string[] | '*';
writes?: string[] | '*';
namespace?: string;
}
export interface BrainyAugmentation {
/**
* Unique identifier for the augmentation
*/
name: string;
/**
* When this augmentation should execute
* - 'before': Execute before the main operation
* - 'after': Execute after the main operation
* - 'around': Wrap the main operation (like middleware)
* - 'replace': Replace the main operation entirely
*/
timing: 'before' | 'after' | 'around' | 'replace';
/**
* Metadata access contract - REQUIRED
* - 'none': No metadata access at all
* - 'readonly': Can read any metadata but cannot write
* - MetadataAccess: Specific fields to read/write
*/
metadata: 'none' | 'readonly' | MetadataAccess;
/**
* Which operations this augmentation applies to
* Granular operation matching for precise augmentation targeting
*/
operations: ('add' | 'addNoun' | 'addVerb' | 'saveNoun' | 'saveVerb' | 'updateMetadata' | 'update' | 'delete' | 'deleteVerb' | 'clear' | 'get' | 'search' | 'searchText' | 'searchByNounTypes' | 'find' | 'findSimilar' | 'searchWithCursor' | 'similar' | 'relate' | 'unrelate' | 'getConnections' | 'getRelations' | 'storage' | 'backup' | 'restore' | 'all')[];
/**
* Priority for execution order (higher numbers execute first)
* - 100: Critical system operations (WAL, ConnectionPool)
* - 50: Performance optimizations (RequestDeduplicator, Caching)
* - 10: Enhancement features (IntelligentVerbScoring)
* - 1: Optional features (Logging, Analytics)
*/
priority: number;
/**
* Initialize the augmentation
* Called once during Brainy initialization
*
* @param context - The Brainy instance and storage
*/
initialize(context: AugmentationContext): Promise<void>;
/**
* Execute the augmentation
*
* @param operation - The operation being performed
* @param params - Parameters for the operation
* @param next - Function to call the next augmentation or main operation
* @returns Result of the operation
*/
execute<T = any>(operation: string, params: any, next: () => Promise<T>): Promise<T>;
/**
* Optional: Check if this augmentation should run for the given operation
* Return false to skip execution
*/
shouldExecute?(operation: string, params: any): boolean;
/**
* Optional: Cleanup when Brainy is destroyed
*/
shutdown?(): Promise<void>;
/**
* Optional: Computed fields this augmentation provides
* Used for discovery, TypeScript support, and API documentation
*/
computedFields?: {
[namespace: string]: {
[field: string]: {
type: 'string' | 'number' | 'boolean' | 'object' | 'array';
description: string;
confidence?: number;
};
};
};
/**
* Optional: Compute fields for a result entity
* Called when user accesses getDisplay(), getSchema(), etc.
*
* @param result - The result entity (VectorDocument, GraphVerb, etc.)
* @param namespace - The namespace being requested ('display', 'schema', etc.)
* @returns Computed fields for the namespace
*/
computeFields?(result: any, namespace: string): Promise<Record<string, any>> | Record<string, any>;
}
/**
* Context provided to augmentations
*/
export interface AugmentationContext {
/**
* The Brainy instance (for accessing methods and config)
*/
brain: any;
/**
* The storage adapter
*/
storage: any;
/**
* Configuration for this augmentation
*/
config: any;
/**
* Logging function
*/
log: (message: string, level?: 'info' | 'warn' | 'error') => void;
}
/**
* Base class for augmentations with common functionality
*
* This is the unified base class that combines the features of both
* BaseAugmentation and ConfigurableAugmentation. All augmentations
* should extend this class for consistent configuration support.
*/
export declare abstract class BaseAugmentation implements BrainyAugmentation {
abstract name: string;
abstract timing: 'before' | 'after' | 'around' | 'replace';
abstract metadata: 'none' | 'readonly' | MetadataAccess;
abstract operations: ('add' | 'addNoun' | 'addVerb' | 'saveNoun' | 'saveVerb' | 'updateMetadata' | 'update' | 'delete' | 'deleteVerb' | 'clear' | 'get' | 'search' | 'searchText' | 'searchByNounTypes' | 'find' | 'findSimilar' | 'searchWithCursor' | 'similar' | 'relate' | 'unrelate' | 'getConnections' | 'getRelations' | 'storage' | 'backup' | 'restore' | 'all')[];
abstract priority: number;
category: 'internal' | 'core' | 'premium' | 'community' | 'external';
description: string;
enabled: boolean;
protected context?: AugmentationContext;
protected isInitialized: boolean;
protected config: any;
private configResolver?;
/**
* Constructor with optional configuration
* @param config Optional configuration to override defaults
*/
constructor(config?: any);
/**
* Get the augmentation manifest for discovery
* Override this to enable configuration support
* CRITICAL: This enables tools to discover parameters and configuration
*/
getManifest?(): AugmentationManifest;
/**
* Get parameter schema for operations
* Enables tools to know what parameters each operation needs
*/
getParameterSchema?(operation: string): any;
/**
* Get operation descriptions
* Enables tools to show what each operation does
*/
getOperationInfo?(): Record<string, {
description: string;
parameters?: any;
returns?: any;
examples?: any[];
}>;
/**
* Get current configuration
*/
getConfig(): any;
/**
* Update configuration at runtime
* @param partial Partial configuration to merge
*/
updateConfig(partial: any): Promise<void>;
/**
* Optional: Handle configuration changes
* Override this to react to runtime configuration updates
*/
protected onConfigChange?(newConfig: any, oldConfig: any): Promise<void>;
/**
* Resolve configuration from all sources
* Priority: constructor > env > files > defaults
*/
private resolveConfiguration;
initialize(context: AugmentationContext): Promise<void>;
/**
* Override this in subclasses for initialization logic
*/
protected onInitialize(): Promise<void>;
abstract execute<T = any>(operation: string, params: any, next: () => Promise<T>): Promise<T>;
shouldExecute(operation: string, params: any): boolean;
shutdown(): Promise<void>;
/**
* Override this in subclasses for cleanup logic
*/
protected onShutdown(): Promise<void>;
/**
* Optional computed fields declaration (override in subclasses)
*/
computedFields?: {
[namespace: string]: {
[field: string]: {
type: 'string' | 'number' | 'boolean' | 'object' | 'array';
description: string;
confidence?: number;
};
};
};
/**
* Optional computed fields implementation (override in subclasses)
* @param result The result entity
* @param namespace The requested namespace
* @returns Computed fields for the namespace
*/
computeFields?(result: any, namespace: string): Promise<Record<string, any>> | Record<string, any>;
/**
* Log a message with the augmentation name
*/
protected log(message: string, level?: 'info' | 'warn' | 'error'): void;
}
/**
* Alias for backward compatibility
* ConfigurableAugmentation is now merged into BaseAugmentation
* @deprecated Use BaseAugmentation instead
*/
export declare const ConfigurableAugmentation: typeof BaseAugmentation;
/**
* Registry for managing augmentations
*/
export declare class AugmentationRegistry {
private augmentations;
private context?;
/**
* Register an augmentation
*/
register(augmentation: BrainyAugmentation): void;
/**
* Find augmentations by operation (before initialization)
* Used for two-phase initialization to find storage augmentations
*/
findByOperation(operation: string): BrainyAugmentation | null;
/**
* Initialize all augmentations
*/
initialize(context: AugmentationContext): Promise<void>;
/**
* Initialize all augmentations (alias for consistency)
*/
initializeAll(context: AugmentationContext): Promise<void>;
/**
* Execute augmentations for an operation
*/
execute<T = any>(operation: string, params: any, mainOperation: () => Promise<T>): Promise<T>;
/**
* Get all registered augmentations
*/
getAll(): BrainyAugmentation[];
/**
* Get augmentation info for listing
*/
getInfo(): Array<{
name: string;
type: string;
enabled: boolean;
description: string;
category: string;
priority: number;
}>;
/**
* Get augmentations by name
*/
get(name: string): BrainyAugmentation | undefined;
/**
* Discover augmentation parameters and schemas
* Critical for tools like brain-cloud to generate UIs
*/
discover(name?: string): any;
/**
* Get configuration schema for an augmentation
* Enables UI generation for configuration
*/
getConfigSchema(name: string): any;
/**
* Configure an augmentation at runtime
*/
configure(name: string, config: any): Promise<void>;
/**
* Get metrics for an augmentation
*/
metrics(name?: string): any;
/**
* Get health status
*/
health(): any;
/**
* Shutdown all augmentations
*/
shutdown(): Promise<void>;
}

View file

@ -0,0 +1,323 @@
/**
* Single BrainyAugmentation Interface
*
* This replaces the 7 complex interfaces with one elegant, purpose-driven design.
* Each augmentation knows its place and when to execute automatically.
*
* The Vision: Components that enhance Brainy's capabilities seamlessly
* - WAL: Adds durability to storage operations
* - RequestDeduplicator: Prevents duplicate concurrent requests
* - ConnectionPool: Optimizes cloud storage throughput
* - IntelligentVerbScoring: Enhances relationship analysis
* - StreamingPipeline: Enables unlimited data processing
*/
import { AugmentationConfigResolver } from './configResolver.js';
/**
* Base class for augmentations with common functionality
*
* This is the unified base class that combines the features of both
* BaseAugmentation and ConfigurableAugmentation. All augmentations
* should extend this class for consistent configuration support.
*/
export class BaseAugmentation {
/**
* Constructor with optional configuration
* @param config Optional configuration to override defaults
*/
constructor(config) {
// Metadata for augmentation listing and management
this.category = 'core';
this.description = '';
this.enabled = true;
this.isInitialized = false;
this.config = {};
// Only resolve configuration if getManifest is implemented
if (this.getManifest) {
this.config = this.resolveConfiguration(config);
}
else if (config) {
// Legacy support: direct config assignment for augmentations without manifests
this.config = config;
}
}
/**
* Get current configuration
*/
getConfig() {
return { ...this.config };
}
/**
* Update configuration at runtime
* @param partial Partial configuration to merge
*/
async updateConfig(partial) {
if (!this.configResolver) {
// For legacy augmentations without manifest, just merge config
const oldConfig = this.config;
this.config = { ...this.config, ...partial };
if (this.onConfigChange) {
await this.onConfigChange(this.config, oldConfig);
}
return;
}
const oldConfig = this.config;
try {
// Use resolver to update and validate
this.config = this.configResolver.updateRuntime(partial);
// Call config change handler if implemented
if (this.onConfigChange) {
await this.onConfigChange(this.config, oldConfig);
}
}
catch (error) {
// Revert on error
this.config = oldConfig;
throw error;
}
}
/**
* Resolve configuration from all sources
* Priority: constructor > env > files > defaults
*/
resolveConfiguration(constructorConfig) {
const manifest = this.getManifest();
// Create config resolver
this.configResolver = new AugmentationConfigResolver({
augmentationId: manifest.id,
schema: manifest.configSchema,
defaults: manifest.configDefaults
});
// Resolve configuration from all sources
return this.configResolver.resolve(constructorConfig);
}
async initialize(context) {
this.context = context;
this.isInitialized = true;
await this.onInitialize();
}
/**
* Override this in subclasses for initialization logic
*/
async onInitialize() {
// Default: no-op
}
shouldExecute(operation, params) {
// Default: execute if operations match exactly or includes 'all'
return this.operations.includes('all') ||
this.operations.includes(operation) ||
this.operations.some(op => operation.includes(op));
}
async shutdown() {
await this.onShutdown();
this.isInitialized = false;
}
/**
* Override this in subclasses for cleanup logic
*/
async onShutdown() {
// Default: no-op
}
/**
* Log a message with the augmentation name
*/
log(message, level = 'info') {
if (this.context) {
this.context.log(`[${this.name}] ${message}`, level);
}
}
}
/**
* Alias for backward compatibility
* ConfigurableAugmentation is now merged into BaseAugmentation
* @deprecated Use BaseAugmentation instead
*/
export const ConfigurableAugmentation = BaseAugmentation;
/**
* Registry for managing augmentations
*/
export class AugmentationRegistry {
constructor() {
this.augmentations = [];
}
/**
* Register an augmentation
*/
register(augmentation) {
this.augmentations.push(augmentation);
// Sort by priority (highest first)
this.augmentations.sort((a, b) => b.priority - a.priority);
}
/**
* Find augmentations by operation (before initialization)
* Used for two-phase initialization to find storage augmentations
*/
findByOperation(operation) {
return this.augmentations.find(aug => aug.operations.includes(operation) ||
aug.operations.includes('all')) || null;
}
/**
* Initialize all augmentations
*/
async initialize(context) {
this.context = context;
for (const augmentation of this.augmentations) {
await augmentation.initialize(context);
}
context.log(`Initialized ${this.augmentations.length} augmentations`);
}
/**
* Initialize all augmentations (alias for consistency)
*/
async initializeAll(context) {
return this.initialize(context);
}
/**
* Execute augmentations for an operation
*/
async execute(operation, params, mainOperation) {
// Filter augmentations that should execute for this operation
const applicable = this.augmentations.filter(aug => aug.shouldExecute ? aug.shouldExecute(operation, params) :
aug.operations.includes('all') ||
aug.operations.includes(operation) ||
aug.operations.some(op => operation.includes(op)));
if (applicable.length === 0) {
// No augmentations, execute main operation directly
return mainOperation();
}
// Create a chain of augmentations
let index = 0;
const executeNext = async () => {
if (index >= applicable.length) {
// All augmentations processed, execute main operation
return mainOperation();
}
const augmentation = applicable[index++];
return augmentation.execute(operation, params, executeNext);
};
return executeNext();
}
/**
* Get all registered augmentations
*/
getAll() {
return [...this.augmentations];
}
/**
* Get augmentation info for listing
*/
getInfo() {
return this.augmentations.map(aug => {
const baseAug = aug;
return {
name: aug.name,
type: baseAug.category || 'core',
enabled: baseAug.enabled !== false,
description: baseAug.description || `${aug.name} augmentation`,
category: baseAug.category || 'core',
priority: aug.priority
};
});
}
/**
* Get augmentations by name
*/
get(name) {
return this.augmentations.find(aug => aug.name === name);
}
/**
* Discover augmentation parameters and schemas
* Critical for tools like brain-cloud to generate UIs
*/
discover(name) {
if (name) {
const aug = this.get(name);
if (!aug)
return null;
const baseAug = aug;
return {
name: aug.name,
operations: aug.operations,
priority: aug.priority,
timing: aug.timing,
metadata: aug.metadata,
manifest: baseAug.getManifest ? baseAug.getManifest() : undefined,
parameters: baseAug.getParameterSchema ?
aug.operations.reduce((acc, op) => {
acc[op] = baseAug.getParameterSchema(op);
return acc;
}, {}) : undefined,
operationInfo: baseAug.getOperationInfo ? baseAug.getOperationInfo() : undefined,
config: baseAug.getConfig ? baseAug.getConfig() : undefined
};
}
// Return all augmentations discovery info
return this.augmentations.map(aug => this.discover(aug.name));
}
/**
* Get configuration schema for an augmentation
* Enables UI generation for configuration
*/
getConfigSchema(name) {
const aug = this.get(name);
if (!aug || !aug.getManifest)
return null;
const manifest = aug.getManifest();
return manifest?.configSchema;
}
/**
* Configure an augmentation at runtime
*/
async configure(name, config) {
const aug = this.get(name);
if (!aug || !aug.updateConfig) {
throw new Error(`Augmentation ${name} does not support configuration`);
}
await aug.updateConfig(config);
}
/**
* Get metrics for an augmentation
*/
metrics(name) {
if (name) {
const aug = this.get(name);
if (!aug || !aug.metrics)
return null;
return aug.metrics();
}
// Return all metrics
const allMetrics = {};
for (const aug of this.augmentations) {
const a = aug;
if (a.metrics) {
allMetrics[aug.name] = a.metrics();
}
}
return allMetrics;
}
/**
* Get health status
*/
health() {
const health = {
overall: 'healthy',
augmentations: {}
};
for (const aug of this.augmentations) {
const a = aug;
health.augmentations[aug.name] = a.health ? a.health() : 'unknown';
}
return health;
}
/**
* Shutdown all augmentations
*/
async shutdown() {
for (const augmentation of this.augmentations) {
if (augmentation.shutdown) {
await augmentation.shutdown();
}
}
this.augmentations = [];
}
}
//# sourceMappingURL=brainyAugmentation.js.map

File diff suppressed because one or more lines are too long

View file

@ -0,0 +1,109 @@
/**
* Cache Augmentation - Optional Search Result Caching
*
* Replaces the hardcoded SearchCache in Brainy with an optional augmentation.
* This reduces core size and allows custom cache implementations.
*
* Zero-config: Automatically enabled with sensible defaults
* Can be disabled or customized via augmentation registry
*/
import { BaseAugmentation } from './brainyAugmentation.js';
import { AugmentationManifest } from './manifest.js';
import { SearchCache } from '../utils/searchCache.js';
import type { GraphNoun } from '../types/graphTypes.js';
export interface CacheConfig {
maxSize?: number;
ttl?: number;
enabled?: boolean;
invalidateOnWrite?: boolean;
}
/**
* CacheAugmentation - Makes search caching optional and pluggable
*
* Features:
* - Transparent search result caching
* - Automatic invalidation on data changes
* - Memory-aware cache management
* - Zero-config with smart defaults
*/
export declare class CacheAugmentation extends BaseAugmentation {
readonly name = "cache";
readonly timing: "around";
readonly metadata: "none";
operations: ("search" | "find" | "similar" | "add" | "update" | "delete" | "clear" | "all")[];
readonly priority = 50;
readonly category: "core";
readonly description = "Transparent search result caching with automatic invalidation";
private searchCache;
constructor(config?: CacheConfig);
getManifest(): AugmentationManifest;
protected onInitialize(): Promise<void>;
protected onShutdown(): Promise<void>;
/**
* Execute augmentation - wrap operations with caching logic
*/
execute<T = any>(operation: string, params: any, next: () => Promise<T>): Promise<T>;
/**
* Handle search operation with caching
*/
private handleSearch;
/**
* Get cache statistics
*/
getStats(): {
enabled: boolean;
hits: number;
misses: number;
size: number;
memoryUsage: number;
} | {
memoryUsage: number;
hits: number;
misses: number;
evictions: number;
hitRate: number;
size: number;
maxSize: number;
enabled: boolean;
};
/**
* Clear the cache manually
*/
clear(): void;
/**
* Handle runtime configuration changes
*/
protected onConfigChange(newConfig: CacheConfig, oldConfig: CacheConfig): Promise<void>;
/**
* Clean up expired entries
*/
cleanupExpiredEntries(): number;
/**
* Invalidate cache when data changes
*/
invalidateOnDataChange(operation: 'add' | 'update' | 'delete'): void;
/**
* Get cache key for a query
*/
getCacheKey(query: any, options?: any): string;
/**
* Direct cache get
*/
get(key: string): any;
/**
* Direct cache set
*/
set(key: string, value: any): void;
/**
* Get the underlying SearchCache instance (for compatibility)
*/
getSearchCache(): SearchCache<GraphNoun> | null;
/**
* Get memory usage
*/
getMemoryUsage(): number;
}
/**
* Factory function for zero-config cache augmentation
*/
export declare function createCacheAugmentation(config?: CacheConfig): CacheAugmentation;

View file

@ -0,0 +1,338 @@
/**
* Cache Augmentation - Optional Search Result Caching
*
* Replaces the hardcoded SearchCache in Brainy with an optional augmentation.
* This reduces core size and allows custom cache implementations.
*
* Zero-config: Automatically enabled with sensible defaults
* Can be disabled or customized via augmentation registry
*/
import { BaseAugmentation } from './brainyAugmentation.js';
import { SearchCache } from '../utils/searchCache.js';
/**
* CacheAugmentation - Makes search caching optional and pluggable
*
* Features:
* - Transparent search result caching
* - Automatic invalidation on data changes
* - Memory-aware cache management
* - Zero-config with smart defaults
*/
export class CacheAugmentation extends BaseAugmentation {
constructor(config) {
super(config);
this.name = 'cache';
this.timing = 'around';
this.metadata = 'none'; // Cache doesn't access metadata
this.operations = ['search', 'find', 'similar', 'add', 'update', 'delete', 'clear', 'all'];
this.priority = 50; // Mid-priority, runs after data operations
// Augmentation metadata
this.category = 'core';
this.description = 'Transparent search result caching with automatic invalidation';
this.searchCache = null;
}
getManifest() {
return {
id: 'cache',
name: 'Cache',
version: '2.0.0',
description: 'Intelligent caching for search and query operations',
longDescription: 'Provides transparent caching for search results with automatic invalidation on data changes. Significantly improves performance for repeated queries while maintaining data consistency.',
category: 'performance',
configSchema: {
type: 'object',
properties: {
enabled: {
type: 'boolean',
default: true,
description: 'Enable or disable caching'
},
maxSize: {
type: 'number',
default: 1000,
minimum: 10,
maximum: 100000,
description: 'Maximum number of cached entries'
},
ttl: {
type: 'number',
default: 300000, // 5 minutes
minimum: 1000, // 1 second
maximum: 3600000, // 1 hour
description: 'Time to live for cache entries in milliseconds'
},
invalidateOnWrite: {
type: 'boolean',
default: true,
description: 'Automatically invalidate cache on data modifications'
}
},
additionalProperties: false
},
configDefaults: {
enabled: true,
maxSize: 1000,
ttl: 300000,
invalidateOnWrite: true
},
configExamples: [
{
name: 'High Performance',
description: 'Large cache with longer TTL for read-heavy workloads',
config: {
enabled: true,
maxSize: 10000,
ttl: 1800000, // 30 minutes
invalidateOnWrite: true
}
},
{
name: 'Conservative',
description: 'Small cache with short TTL for frequently changing data',
config: {
enabled: true,
maxSize: 100,
ttl: 60000, // 1 minute
invalidateOnWrite: true
}
}
],
minBrainyVersion: '2.0.0',
keywords: ['cache', 'performance', 'search', 'optimization'],
documentation: 'https://docs.brainy.dev/augmentations/cache',
status: 'stable',
performance: {
memoryUsage: 'medium',
cpuUsage: 'low',
networkUsage: 'none'
},
features: ['search-caching', 'auto-invalidation', 'ttl-support', 'memory-management'],
enhancedOperations: ['search', 'searchText', 'findSimilar'],
metrics: [
{
name: 'cache_hits',
type: 'counter',
description: 'Number of cache hits'
},
{
name: 'cache_misses',
type: 'counter',
description: 'Number of cache misses'
},
{
name: 'cache_size',
type: 'gauge',
description: 'Current cache size'
}
],
ui: {
icon: '⚡',
color: '#FFC107'
}
};
}
async onInitialize() {
if (!this.config.enabled) {
this.log('Cache augmentation disabled by configuration');
return;
}
// Initialize search cache with config
this.searchCache = new SearchCache({
maxSize: this.config.maxSize,
maxAge: this.config.ttl, // SearchCache uses maxAge, not ttl
enabled: true
});
this.log(`Cache augmentation initialized (maxSize: ${this.config.maxSize}, ttl: ${this.config.ttl}ms)`);
}
async onShutdown() {
if (this.searchCache) {
this.searchCache.clear();
this.searchCache = null;
}
this.log('Cache augmentation shut down');
}
/**
* Execute augmentation - wrap operations with caching logic
*/
async execute(operation, params, next) {
// If cache is disabled, just pass through
if (!this.searchCache || !this.config.enabled) {
return next();
}
switch (operation) {
case 'search':
return this.handleSearch(params, next);
case 'add':
case 'update':
case 'delete':
// Invalidate cache on data changes
if (this.config.invalidateOnWrite) {
const result = await next();
this.searchCache.invalidateOnDataChange(operation);
this.log(`Cache invalidated due to ${operation} operation`);
return result;
}
return next();
case 'clear':
// Clear cache when all data is cleared
const result = await next();
this.searchCache.clear();
this.log('Cache cleared due to clear operation');
return result;
default:
return next();
}
}
/**
* Handle search operation with caching
*/
async handleSearch(params, next) {
if (!this.searchCache)
return next();
// Extract search parameters
const { query, k, options = {} } = params;
// Skip cache if explicitly disabled or has complex filters
if (options.skipCache || options.metadata) {
return next();
}
// Generate cache key
const cacheKey = this.searchCache.getCacheKey(query, k, options);
// Check cache
const cachedResult = this.searchCache.get(cacheKey);
if (cachedResult) {
this.log('Cache hit for search query');
// Update metrics if available
if (this.context?.brain) {
const metrics = this.context.brain.augmentations?.get('metrics');
if (metrics) {
metrics.recordCacheHit?.();
}
}
return cachedResult;
}
// Execute search
const result = await next();
// Cache the result
this.searchCache.set(cacheKey, result);
this.log('Search result cached');
// Update metrics if available
if (this.context?.brain) {
const metrics = this.context.brain.augmentations?.get('metrics');
if (metrics) {
metrics.recordCacheMiss?.();
}
}
return result;
}
/**
* Get cache statistics
*/
getStats() {
if (!this.searchCache) {
return {
enabled: false,
hits: 0,
misses: 0,
size: 0,
memoryUsage: 0
};
}
const stats = this.searchCache.getStats();
return {
...stats,
memoryUsage: this.searchCache.getMemoryUsage()
};
}
/**
* Clear the cache manually
*/
clear() {
if (this.searchCache) {
this.searchCache.clear();
this.log('Cache manually cleared');
}
}
/**
* Handle runtime configuration changes
*/
async onConfigChange(newConfig, oldConfig) {
if (this.searchCache && newConfig.enabled) {
this.searchCache.updateConfig({
maxSize: newConfig.maxSize,
maxAge: newConfig.ttl, // SearchCache uses maxAge
enabled: newConfig.enabled
});
this.log('Cache configuration updated');
}
else if (!newConfig.enabled && this.searchCache) {
this.searchCache.clear();
this.log('Cache disabled and cleared');
}
}
/**
* Clean up expired entries
*/
cleanupExpiredEntries() {
if (!this.searchCache)
return 0;
const cleaned = this.searchCache.cleanupExpiredEntries();
if (cleaned > 0) {
this.log(`Cleaned ${cleaned} expired cache entries`);
}
return cleaned;
}
/**
* Invalidate cache when data changes
*/
invalidateOnDataChange(operation) {
if (!this.searchCache)
return;
this.searchCache.invalidateOnDataChange(operation);
this.log(`Cache invalidated due to ${operation} operation`);
}
/**
* Get cache key for a query
*/
getCacheKey(query, options) {
if (!this.searchCache)
return '';
return this.searchCache.getCacheKey(query, options);
}
/**
* Direct cache get
*/
get(key) {
if (!this.searchCache)
return null;
return this.searchCache.get(key);
}
/**
* Direct cache set
*/
set(key, value) {
if (!this.searchCache)
return;
this.searchCache.set(key, value);
}
/**
* Get the underlying SearchCache instance (for compatibility)
*/
getSearchCache() {
return this.searchCache;
}
/**
* Get memory usage
*/
getMemoryUsage() {
if (!this.searchCache)
return 0;
return this.searchCache.getMemoryUsage();
}
}
/**
* Factory function for zero-config cache augmentation
*/
export function createCacheAugmentation(config) {
return new CacheAugmentation(config);
}
//# sourceMappingURL=cacheAugmentation.js.map

File diff suppressed because one or more lines are too long

View file

@ -0,0 +1,71 @@
/**
* Conduit Augmentations - Data Synchronization Bridges
*
* These augmentations connect and synchronize data between multiple Brainy instances.
* Now using the unified BrainyAugmentation interface.
*/
import { BaseAugmentation } from './brainyAugmentation.js';
export interface WebSocketConnection {
connectionId: string;
url: string;
readyState: number;
socket?: any;
}
/**
* Base class for conduit augmentations that sync between Brainy instances
* Converted to use the unified BrainyAugmentation interface
*/
declare abstract class BaseConduitAugmentation extends BaseAugmentation {
readonly timing: "after";
readonly metadata: "readonly";
readonly operations: ("addNoun" | "delete" | "addVerb")[];
readonly priority = 20;
protected connections: Map<string, any>;
protected onShutdown(): Promise<void>;
abstract establishConnection(targetSystemId: string, config?: Record<string, unknown>): Promise<WebSocketConnection | null>;
}
/**
* WebSocket Conduit Augmentation
* Syncs data between Brainy instances using WebSockets
*/
export declare class WebSocketConduitAugmentation extends BaseConduitAugmentation {
readonly name = "websocket-conduit";
private webSocketConnections;
private messageCallbacks;
execute<T = any>(operation: string, params: any, next: () => Promise<T>): Promise<T>;
private shouldSync;
private syncOperation;
establishConnection(url: string, config?: Record<string, unknown>): Promise<WebSocketConnection | null>;
private handleMessage;
private applySyncOperation;
/**
* Subscribe to messages from a specific connection
*/
onMessage(connectionId: string, callback: (data: any) => void): void;
/**
* Send a message to a specific connection
*/
sendMessage(connectionId: string, data: any): boolean;
}
export {};
/**
* Example usage:
*
* // Server instance
* const serverBrain = new Brainy()
* serverBrain.augmentations.register(new APIServerAugmentation())
* await serverBrain.init()
*
* // Client instance
* const clientBrain = new Brainy()
* const conduit = new WebSocketConduitAugmentation()
* clientBrain.augmentations.register(conduit)
* await clientBrain.init()
*
* // Connect client to server
* await conduit.establishConnection('ws://localhost:3000/ws')
*
* // Now operations sync automatically!
* await clientBrain.addNoun('synced data', { source: 'client' })
* // This will automatically sync to the server
*/

View file

@ -0,0 +1,233 @@
/**
* Conduit Augmentations - Data Synchronization Bridges
*
* These augmentations connect and synchronize data between multiple Brainy instances.
* Now using the unified BrainyAugmentation interface.
*/
import { BaseAugmentation } from './brainyAugmentation.js';
import { v4 as uuidv4 } from '../universal/uuid.js';
/**
* Base class for conduit augmentations that sync between Brainy instances
* Converted to use the unified BrainyAugmentation interface
*/
class BaseConduitAugmentation extends BaseAugmentation {
constructor() {
super(...arguments);
this.timing = 'after'; // Conduits run after operations to sync
this.metadata = 'readonly'; // Conduits read metadata to pass to external systems
this.operations = ['addNoun', 'delete', 'addVerb'];
this.priority = 20; // Medium-low priority
this.connections = new Map();
}
async onShutdown() {
// Close all connections
for (const [connectionId, connection] of this.connections.entries()) {
try {
if (connection.close) {
await connection.close();
}
}
catch (error) {
this.log(`Failed to close connection ${connectionId}: ${error}`, 'error');
}
}
this.connections.clear();
}
}
/**
* WebSocket Conduit Augmentation
* Syncs data between Brainy instances using WebSockets
*/
export class WebSocketConduitAugmentation extends BaseConduitAugmentation {
constructor() {
super(...arguments);
this.name = 'websocket-conduit';
this.webSocketConnections = new Map();
this.messageCallbacks = new Map();
}
async execute(operation, params, next) {
// Execute the operation first
const result = await next();
// Then sync to connected instances
if (this.shouldSync(operation)) {
await this.syncOperation(operation, params, result);
}
return result;
}
shouldSync(operation) {
return ['addNoun', 'deleteNoun', 'addVerb'].includes(operation);
}
async syncOperation(operation, params, result) {
// Broadcast to all connected WebSocket instances
for (const [id, connection] of this.webSocketConnections) {
if (connection.socket && connection.readyState === 1) { // OPEN state
try {
const message = JSON.stringify({
type: 'sync',
operation,
params,
timestamp: Date.now()
});
if (typeof connection.socket.send === 'function') {
connection.socket.send(message);
}
}
catch (error) {
this.log(`Failed to sync to ${id}: ${error}`, 'error');
}
}
}
}
async establishConnection(url, config) {
try {
const connectionId = uuidv4();
const protocols = config?.protocols;
// Create WebSocket based on environment
let socket;
if (typeof WebSocket !== 'undefined') {
// Browser environment
socket = new WebSocket(url, protocols);
}
else {
// Node.js environment - dynamic import
try {
const ws = await import('ws');
socket = new ws.WebSocket(url, protocols);
}
catch {
this.log('WebSocket not available in this environment', 'error');
return null;
}
}
// Setup event handlers
socket.onopen = () => {
this.log(`Connected to ${url}`);
};
socket.onmessage = (event) => {
this.handleMessage(connectionId, event.data);
};
socket.onerror = (error) => {
this.log(`WebSocket error: ${error}`, 'error');
};
socket.onclose = () => {
this.log(`Disconnected from ${url}`);
this.webSocketConnections.delete(connectionId);
};
// Wait for connection to open
await new Promise((resolve, reject) => {
const timeout = setTimeout(() => {
reject(new Error('Connection timeout'));
}, 5000);
socket.onopen = () => {
clearTimeout(timeout);
resolve();
};
socket.onerror = (error) => {
clearTimeout(timeout);
reject(error);
};
});
const connection = {
connectionId,
url,
readyState: socket.readyState,
socket
};
this.webSocketConnections.set(connectionId, connection);
this.connections.set(connectionId, connection);
return connection;
}
catch (error) {
this.log(`Failed to establish connection to ${url}: ${error}`, 'error');
return null;
}
}
handleMessage(connectionId, data) {
try {
const message = typeof data === 'string' ? JSON.parse(data) : data;
// Handle sync messages from remote instances
if (message.type === 'sync') {
// Apply the operation to our local instance
this.applySyncOperation(message).catch(error => {
this.log(`Failed to apply sync operation: ${error}`, 'error');
});
}
// Notify any registered callbacks
const callbacks = this.messageCallbacks.get(connectionId);
if (callbacks) {
callbacks.forEach(callback => callback(message));
}
}
catch (error) {
this.log(`Failed to handle message: ${error}`, 'error');
}
}
async applySyncOperation(message) {
// Apply the synced operation to our local Brainy instance
const { operation, params } = message;
try {
switch (operation) {
case 'addNoun':
await this.context?.brain.addNoun(params.content, params.metadata);
break;
case 'deleteNoun':
await this.context?.brain.deleteNoun(params.id);
break;
case 'addVerb':
await this.context?.brain.addVerb(params.source, params.target, params.verb, params.metadata);
break;
}
}
catch (error) {
this.log(`Failed to apply ${operation}: ${error}`, 'error');
}
}
/**
* Subscribe to messages from a specific connection
*/
onMessage(connectionId, callback) {
if (!this.messageCallbacks.has(connectionId)) {
this.messageCallbacks.set(connectionId, new Set());
}
this.messageCallbacks.get(connectionId).add(callback);
}
/**
* Send a message to a specific connection
*/
sendMessage(connectionId, data) {
const connection = this.webSocketConnections.get(connectionId);
if (connection?.socket && connection.readyState === 1) {
try {
const message = typeof data === 'string' ? data : JSON.stringify(data);
connection.socket.send(message);
return true;
}
catch (error) {
this.log(`Failed to send message: ${error}`, 'error');
}
}
return false;
}
}
/**
* Example usage:
*
* // Server instance
* const serverBrain = new Brainy()
* serverBrain.augmentations.register(new APIServerAugmentation())
* await serverBrain.init()
*
* // Client instance
* const clientBrain = new Brainy()
* const conduit = new WebSocketConduitAugmentation()
* clientBrain.augmentations.register(conduit)
* await clientBrain.init()
*
* // Connect client to server
* await conduit.establishConnection('ws://localhost:3000/ws')
*
* // Now operations sync automatically!
* await clientBrain.addNoun('synced data', { source: 'client' })
* // This will automatically sync to the server
*/
//# sourceMappingURL=conduitAugmentations.js.map

File diff suppressed because one or more lines are too long

View file

@ -0,0 +1,122 @@
/**
* Configuration Resolver for Augmentations
*
* Handles loading and resolving configuration from multiple sources:
* - Environment variables
* - Configuration files
* - Runtime updates
* - Default values from schema
*/
import { JSONSchema } from './manifest.js';
/**
* Configuration source priority (highest to lowest)
*/
export declare enum ConfigPriority {
RUNTIME = 4,// Runtime updates (highest priority)
CONSTRUCTOR = 3,// Constructor parameters
ENVIRONMENT = 2,// Environment variables
FILE = 1,// Configuration files
DEFAULT = 0
}
/**
* Configuration source information
*/
export interface ConfigSource {
priority: ConfigPriority;
source: string;
config: any;
}
/**
* Configuration resolution options
*/
export interface ConfigResolverOptions {
augmentationId: string;
schema?: JSONSchema;
defaults?: Record<string, any>;
configPaths?: string[];
envPrefix?: string;
allowUndefined?: boolean;
}
/**
* Augmentation Configuration Resolver
*/
export declare class AugmentationConfigResolver {
private options;
private sources;
private resolved;
constructor(options: ConfigResolverOptions);
/**
* Resolve configuration from all sources
* @param constructorConfig Optional constructor configuration
* @returns Resolved configuration
*/
resolve(constructorConfig?: any): any;
/**
* Load default values from schema and defaults
*/
private loadDefaults;
/**
* Load configuration from files
*/
private loadFromFiles;
/**
* Parse configuration file based on extension
*/
private parseConfigFile;
/**
* Extract augmentation-specific configuration from a config object
*/
private extractAugmentationConfig;
/**
* Load configuration from environment variables
*/
private loadFromEnvironment;
/**
* Convert environment variable key to config key
* ENABLED -> enabled
* MAX_SIZE -> maxSize
*/
private envKeyToConfigKey;
/**
* Parse environment variable value
*/
private parseEnvValue;
/**
* Merge configurations by priority
*/
private mergeConfigurations;
/**
* Deep merge two objects
*/
private deepMerge;
/**
* Validate configuration against schema
*/
private validateConfiguration;
/**
* Validate a single property against its schema
*/
private validateProperty;
/**
* Get configuration sources for debugging
*/
getSources(): ConfigSource[];
/**
* Get resolved configuration
*/
getResolved(): any;
/**
* Update configuration at runtime
*/
updateRuntime(config: any): any;
/**
* Save configuration to file
* @param filepath Path to save configuration
* @param format Format to save as (json, etc.)
*/
saveToFile(filepath?: string, format?: 'json'): Promise<void>;
/**
* Get environment variable names for this augmentation
*/
getEnvironmentVariables(): Record<string, any>;
}

View file

@ -0,0 +1,440 @@
/**
* Configuration Resolver for Augmentations
*
* Handles loading and resolving configuration from multiple sources:
* - Environment variables
* - Configuration files
* - Runtime updates
* - Default values from schema
*/
import { existsSync, readFileSync } from 'fs';
import { join } from 'path';
import { homedir } from 'os';
/**
* Configuration source priority (highest to lowest)
*/
export var ConfigPriority;
(function (ConfigPriority) {
ConfigPriority[ConfigPriority["RUNTIME"] = 4] = "RUNTIME";
ConfigPriority[ConfigPriority["CONSTRUCTOR"] = 3] = "CONSTRUCTOR";
ConfigPriority[ConfigPriority["ENVIRONMENT"] = 2] = "ENVIRONMENT";
ConfigPriority[ConfigPriority["FILE"] = 1] = "FILE";
ConfigPriority[ConfigPriority["DEFAULT"] = 0] = "DEFAULT"; // Schema defaults (lowest priority)
})(ConfigPriority || (ConfigPriority = {}));
/**
* Augmentation Configuration Resolver
*/
export class AugmentationConfigResolver {
constructor(options) {
this.options = options;
this.sources = [];
this.resolved = {};
this.options = {
configPaths: [
'.brainyrc',
'.brainyrc.json',
'brainy.config.json',
join(homedir(), '.brainy', 'config.json'),
join(homedir(), '.brainyrc')
],
envPrefix: `BRAINY_AUG_${options.augmentationId.toUpperCase()}_`,
allowUndefined: true,
...options
};
}
/**
* Resolve configuration from all sources
* @param constructorConfig Optional constructor configuration
* @returns Resolved configuration
*/
resolve(constructorConfig) {
this.sources = [];
// Load from all sources in priority order
this.loadDefaults();
this.loadFromFiles();
this.loadFromEnvironment();
if (constructorConfig) {
this.sources.push({
priority: ConfigPriority.CONSTRUCTOR,
source: 'constructor',
config: constructorConfig
});
}
// Merge configurations by priority
this.resolved = this.mergeConfigurations();
// Validate against schema if provided
if (this.options.schema) {
this.validateConfiguration(this.resolved);
}
return this.resolved;
}
/**
* Load default values from schema and defaults
*/
loadDefaults() {
let defaults = {};
// Load from provided defaults
if (this.options.defaults) {
defaults = { ...defaults, ...this.options.defaults };
}
// Load from schema defaults
if (this.options.schema?.properties) {
for (const [key, prop] of Object.entries(this.options.schema.properties)) {
if (prop.default !== undefined && defaults[key] === undefined) {
defaults[key] = prop.default;
}
}
}
if (Object.keys(defaults).length > 0) {
this.sources.push({
priority: ConfigPriority.DEFAULT,
source: 'defaults',
config: defaults
});
}
}
/**
* Load configuration from files
*/
loadFromFiles() {
// Skip in browser environment
if (typeof process === 'undefined' || typeof window !== 'undefined') {
return;
}
for (const configPath of this.options.configPaths || []) {
try {
if (existsSync(configPath)) {
const content = readFileSync(configPath, 'utf8');
const config = this.parseConfigFile(content, configPath);
// Extract augmentation-specific configuration
const augConfig = this.extractAugmentationConfig(config);
if (augConfig && Object.keys(augConfig).length > 0) {
this.sources.push({
priority: ConfigPriority.FILE,
source: `file:${configPath}`,
config: augConfig
});
break; // Use first found config file
}
}
}
catch (error) {
// Silently ignore file errors
console.debug(`Failed to load config from ${configPath}:`, error);
}
}
}
/**
* Parse configuration file based on extension
*/
parseConfigFile(content, filepath) {
try {
// Try JSON first
return JSON.parse(content);
}
catch {
// Try other formats in the future (YAML, TOML, etc.)
throw new Error(`Unable to parse config file: ${filepath}`);
}
}
/**
* Extract augmentation-specific configuration from a config object
*/
extractAugmentationConfig(config) {
const augId = this.options.augmentationId;
// Check for augmentations section
if (config.augmentations && config.augmentations[augId]) {
return config.augmentations[augId];
}
// Check for direct augmentation config (prefixed keys)
const prefix = `${augId}.`;
const augConfig = {};
for (const [key, value] of Object.entries(config)) {
if (key.startsWith(prefix)) {
const configKey = key.slice(prefix.length);
augConfig[configKey] = value;
}
}
return Object.keys(augConfig).length > 0 ? augConfig : null;
}
/**
* Load configuration from environment variables
*/
loadFromEnvironment() {
// Skip in browser environment
if (typeof process === 'undefined' || !process.env) {
return;
}
const prefix = this.options.envPrefix;
const envConfig = {};
for (const [key, value] of Object.entries(process.env)) {
if (key.startsWith(prefix)) {
const configKey = this.envKeyToConfigKey(key.slice(prefix.length));
envConfig[configKey] = this.parseEnvValue(value);
}
}
if (Object.keys(envConfig).length > 0) {
this.sources.push({
priority: ConfigPriority.ENVIRONMENT,
source: 'environment',
config: envConfig
});
}
}
/**
* Convert environment variable key to config key
* ENABLED -> enabled
* MAX_SIZE -> maxSize
*/
envKeyToConfigKey(envKey) {
return envKey
.toLowerCase()
.replace(/_([a-z])/g, (_, letter) => letter.toUpperCase());
}
/**
* Parse environment variable value
*/
parseEnvValue(value) {
// Handle empty strings
if (value === '')
return value;
// Try to parse as JSON
try {
return JSON.parse(value);
}
catch {
// Check for boolean strings
if (value.toLowerCase() === 'true')
return true;
if (value.toLowerCase() === 'false')
return false;
// Check for number strings
const num = Number(value);
if (!isNaN(num) && value.trim() !== '')
return num;
// Return as string
return value;
}
}
/**
* Merge configurations by priority
*/
mergeConfigurations() {
// Sort by priority (lowest to highest)
const sorted = [...this.sources].sort((a, b) => a.priority - b.priority);
// Merge configurations
let merged = {};
for (const source of sorted) {
merged = this.deepMerge(merged, source.config);
}
return merged;
}
/**
* Deep merge two objects
*/
deepMerge(target, source) {
const output = { ...target };
for (const key in source) {
if (source.hasOwnProperty(key)) {
if (source[key] && typeof source[key] === 'object' && !Array.isArray(source[key])) {
if (target[key] && typeof target[key] === 'object' && !Array.isArray(target[key])) {
output[key] = this.deepMerge(target[key], source[key]);
}
else {
output[key] = source[key];
}
}
else {
output[key] = source[key];
}
}
}
return output;
}
/**
* Validate configuration against schema
*/
validateConfiguration(config) {
if (!this.options.schema)
return;
const schema = this.options.schema;
const errors = [];
// Check required fields
if (schema.required) {
for (const field of schema.required) {
if (config[field] === undefined) {
errors.push(`Missing required field: ${field}`);
}
}
}
// Validate properties
if (schema.properties) {
for (const [key, propSchema] of Object.entries(schema.properties)) {
const value = config[key];
if (value !== undefined) {
this.validateProperty(key, value, propSchema, errors);
}
}
}
// Check for additional properties
if (schema.additionalProperties === false) {
const allowedKeys = Object.keys(schema.properties || {});
for (const key of Object.keys(config)) {
if (!allowedKeys.includes(key)) {
errors.push(`Unknown configuration property: ${key}`);
}
}
}
if (errors.length > 0) {
throw new Error(`Configuration validation failed for ${this.options.augmentationId}:\n${errors.join('\n')}`);
}
}
/**
* Validate a single property against its schema
*/
validateProperty(key, value, schema, errors) {
// Type validation
if (schema.type) {
const actualType = Array.isArray(value) ? 'array' : typeof value;
if (actualType !== schema.type) {
errors.push(`${key}: expected ${schema.type}, got ${actualType}`);
return;
}
}
// Number validations
if (schema.type === 'number') {
if (schema.minimum !== undefined && value < schema.minimum) {
errors.push(`${key}: value ${value} is less than minimum ${schema.minimum}`);
}
if (schema.maximum !== undefined && value > schema.maximum) {
errors.push(`${key}: value ${value} is greater than maximum ${schema.maximum}`);
}
}
// String validations
if (schema.type === 'string') {
if (schema.minLength !== undefined && value.length < schema.minLength) {
errors.push(`${key}: length ${value.length} is less than minimum ${schema.minLength}`);
}
if (schema.maxLength !== undefined && value.length > schema.maxLength) {
errors.push(`${key}: length ${value.length} is greater than maximum ${schema.maxLength}`);
}
if (schema.pattern) {
const regex = new RegExp(schema.pattern);
if (!regex.test(value)) {
errors.push(`${key}: value does not match pattern ${schema.pattern}`);
}
}
}
// Enum validation
if (schema.enum && !schema.enum.includes(value)) {
errors.push(`${key}: value ${value} is not one of allowed values: ${schema.enum.join(', ')}`);
}
}
/**
* Get configuration sources for debugging
*/
getSources() {
return [...this.sources];
}
/**
* Get resolved configuration
*/
getResolved() {
return { ...this.resolved };
}
/**
* Update configuration at runtime
*/
updateRuntime(config) {
// Add or update runtime source
const runtimeIndex = this.sources.findIndex(s => s.priority === ConfigPriority.RUNTIME);
if (runtimeIndex >= 0) {
this.sources[runtimeIndex].config = {
...this.sources[runtimeIndex].config,
...config
};
}
else {
this.sources.push({
priority: ConfigPriority.RUNTIME,
source: 'runtime',
config
});
}
// Re-merge configurations
this.resolved = this.mergeConfigurations();
// Validate
if (this.options.schema) {
this.validateConfiguration(this.resolved);
}
return this.resolved;
}
/**
* Save configuration to file
* @param filepath Path to save configuration
* @param format Format to save as (json, etc.)
*/
async saveToFile(filepath, format = 'json') {
// Skip in browser environment
if (typeof process === 'undefined' || typeof window !== 'undefined') {
throw new Error('Cannot save configuration files in browser environment');
}
const fs = await import('fs');
const path = await import('path');
const configPath = filepath || this.options.configPaths?.[0] || '.brainyrc';
const augId = this.options.augmentationId;
// Load existing config if it exists
let fullConfig = {};
try {
if (fs.existsSync(configPath)) {
const content = fs.readFileSync(configPath, 'utf8');
fullConfig = JSON.parse(content);
}
}
catch {
// Start with empty config
}
// Ensure augmentations section exists
if (!fullConfig.augmentations) {
fullConfig.augmentations = {};
}
// Update augmentation config
fullConfig.augmentations[augId] = this.resolved;
// Save based on format
let content;
if (format === 'json') {
content = JSON.stringify(fullConfig, null, 2);
}
else {
throw new Error(`Unsupported format: ${format}`);
}
// Ensure directory exists
const dir = path.dirname(configPath);
if (!fs.existsSync(dir)) {
fs.mkdirSync(dir, { recursive: true });
}
// Write file
fs.writeFileSync(configPath, content, 'utf8');
}
/**
* Get environment variable names for this augmentation
*/
getEnvironmentVariables() {
const schema = this.options.schema;
const prefix = this.options.envPrefix;
const vars = {};
if (schema?.properties) {
for (const [key, prop] of Object.entries(schema.properties)) {
const envKey = prefix + key.replace(/([A-Z])/g, '_$1').toUpperCase();
vars[envKey] = {
description: prop.description,
type: prop.type,
default: prop.default,
currentValue: process.env?.[envKey]
};
}
}
return vars;
}
}
//# sourceMappingURL=configResolver.js.map

File diff suppressed because one or more lines are too long

View file

@ -0,0 +1,65 @@
/**
* Connection Pool Augmentation
*
* Provides 10-20x throughput improvement for cloud storage (S3, R2, GCS)
* Manages connection pooling, request queuing, and parallel processing
* Critical for enterprise-scale operations with millions of entries
*/
import { BaseAugmentation } from './brainyAugmentation.js';
interface ConnectionPoolConfig {
enabled?: boolean;
maxConnections?: number;
minConnections?: number;
acquireTimeout?: number;
idleTimeout?: number;
maxQueueSize?: number;
retryAttempts?: number;
healthCheckInterval?: number;
}
export declare class ConnectionPoolAugmentation extends BaseAugmentation {
name: string;
timing: "around";
metadata: "none";
operations: ("storage")[];
priority: number;
protected config: Required<ConnectionPoolConfig>;
private connections;
private requestQueue;
private healthCheckInterval?;
private storageType;
private stats;
constructor(config?: ConnectionPoolConfig);
protected onInitialize(): Promise<void>;
shouldExecute(operation: string, params: any): boolean;
execute<T = any>(operation: string, params: any, next: () => Promise<T>): Promise<T>;
private detectStorageType;
private isCloudStorage;
private isStorageOperation;
private getOperationPriority;
private executeWithPool;
private getAvailableConnection;
private executeWithConnection;
private queueRequest;
private processQueue;
private initializeConnectionPool;
private createConnection;
private createStorageConnection;
private getOrCreateConnection;
private startHealthChecks;
private performHealthChecks;
private startMetricsCollection;
private updateLatencyMetrics;
private updateThroughputMetrics;
/**
* Get connection pool statistics
*/
getStats(): typeof this.stats & {
queueSize: number;
activeConnections: number;
totalConnections: number;
poolUtilization: string;
storageType: string;
};
protected onShutdown(): Promise<void>;
}
export {};

View file

@ -0,0 +1,342 @@
/**
* Connection Pool Augmentation
*
* Provides 10-20x throughput improvement for cloud storage (S3, R2, GCS)
* Manages connection pooling, request queuing, and parallel processing
* Critical for enterprise-scale operations with millions of entries
*/
import { BaseAugmentation } from './brainyAugmentation.js';
export class ConnectionPoolAugmentation extends BaseAugmentation {
constructor(config = {}) {
super();
this.name = 'ConnectionPool';
this.timing = 'around';
this.metadata = 'none'; // Connection pooling doesn't access metadata
this.operations = ['storage'];
this.priority = 95; // Very high priority for storage operations
this.connections = new Map();
this.requestQueue = [];
this.storageType = 'unknown';
this.stats = {
totalRequests: 0,
queuedRequests: 0,
activeConnections: 0,
totalConnections: 0,
averageLatency: 0,
throughputPerSecond: 0
};
this.config = {
enabled: config.enabled ?? true,
maxConnections: config.maxConnections ?? 50,
minConnections: config.minConnections ?? 5,
acquireTimeout: config.acquireTimeout ?? 30000, // 30s
idleTimeout: config.idleTimeout ?? 300000, // 5 minutes
maxQueueSize: config.maxQueueSize ?? 10000,
retryAttempts: config.retryAttempts ?? 3,
healthCheckInterval: config.healthCheckInterval ?? 60000 // 1 minute
};
}
async onInitialize() {
if (!this.config.enabled) {
this.log('Connection pooling disabled');
return;
}
// Detect storage type
this.storageType = this.detectStorageType();
if (this.isCloudStorage()) {
await this.initializeConnectionPool();
this.startHealthChecks();
this.startMetricsCollection();
this.log(`Connection pool initialized for ${this.storageType}: ${this.config.minConnections}-${this.config.maxConnections} connections`);
}
else {
this.log(`Connection pooling skipped for ${this.storageType} (local storage)`);
}
}
shouldExecute(operation, params) {
return this.config.enabled &&
this.isCloudStorage() &&
this.isStorageOperation(operation);
}
async execute(operation, params, next) {
if (!this.shouldExecute(operation, params)) {
return next();
}
const startTime = Date.now();
this.stats.totalRequests++;
try {
// High priority for critical operations
const priority = this.getOperationPriority(operation);
// Execute with pooled connection
const result = await this.executeWithPool(operation, params, next, priority);
// Update metrics
const latency = Date.now() - startTime;
this.updateLatencyMetrics(latency);
return result;
}
catch (error) {
this.log(`Connection pool error for ${operation}: ${error}`, 'error');
// Fallback to direct execution for reliability
return next();
}
}
detectStorageType() {
const storage = this.context?.storage;
if (!storage)
return 'unknown';
const className = storage.constructor.name.toLowerCase();
if (className.includes('s3'))
return 's3';
if (className.includes('r2'))
return 'r2';
if (className.includes('gcs') || className.includes('google'))
return 'gcs';
if (className.includes('azure'))
return 'azure';
if (className.includes('filesystem'))
return 'filesystem';
if (className.includes('memory'))
return 'memory';
return 'unknown';
}
isCloudStorage() {
return ['s3', 'r2', 'gcs', 'azure'].includes(this.storageType);
}
isStorageOperation(operation) {
return operation.includes('save') ||
operation.includes('get') ||
operation.includes('delete') ||
operation.includes('list') ||
operation.includes('backup') ||
operation.includes('restore');
}
getOperationPriority(operation) {
// Critical operations get highest priority
if (operation.includes('save') || operation.includes('update'))
return 10;
if (operation.includes('delete'))
return 9;
if (operation.includes('get'))
return 7;
if (operation.includes('list'))
return 5;
if (operation.includes('backup'))
return 3;
return 1;
}
async executeWithPool(operation, params, executor, priority) {
// Check queue size
if (this.requestQueue.length >= this.config.maxQueueSize) {
throw new Error('Connection pool queue full - system overloaded');
}
// Try to get available connection immediately
const connection = await this.getOrCreateConnection();
if (connection && connection.isIdle) {
return this.executeWithConnection(connection, operation, executor);
}
// Queue the request with the actual executor
return this.queueRequest(operation, params, executor, priority);
}
getAvailableConnection() {
// Find idle connection with best health score
let bestConnection = null;
let bestScore = -1;
for (const connection of this.connections.values()) {
if (connection.isIdle && connection.healthScore > bestScore) {
bestConnection = connection;
bestScore = connection.healthScore;
}
}
return bestConnection;
}
async executeWithConnection(connection, operation, executor) {
// Mark connection as active
connection.isIdle = false;
connection.activeRequests++;
connection.lastUsed = Date.now();
this.stats.activeConnections++;
try {
const result = await executor();
// Update connection health on success
connection.healthScore = Math.min(connection.healthScore + 1, 100);
return result;
}
catch (error) {
// Decrease health on failure
connection.healthScore = Math.max(connection.healthScore - 5, 0);
throw error;
}
finally {
// Release connection
connection.isIdle = true;
connection.activeRequests--;
this.stats.activeConnections--;
// Process next queued request
this.processQueue();
}
}
async queueRequest(operation, params, executor, priority) {
return new Promise((resolve, reject) => {
const request = {
id: `req_${Date.now()}_${Math.random()}`,
operation,
params,
executor, // Store the actual executor function
resolver: resolve,
rejector: reject,
timestamp: Date.now(),
priority
};
// Insert by priority (higher priority first)
const insertIndex = this.requestQueue.findIndex(r => r.priority < priority);
if (insertIndex === -1) {
this.requestQueue.push(request);
}
else {
this.requestQueue.splice(insertIndex, 0, request);
}
this.stats.queuedRequests++;
// Set timeout
setTimeout(() => {
const index = this.requestQueue.findIndex(r => r.id === request.id);
if (index !== -1) {
this.requestQueue.splice(index, 1);
this.stats.queuedRequests--;
reject(new Error(`Connection pool timeout: ${this.config.acquireTimeout}ms`));
}
}, this.config.acquireTimeout);
});
}
processQueue() {
if (this.requestQueue.length === 0)
return;
const connection = this.getAvailableConnection();
if (!connection)
return;
const request = this.requestQueue.shift();
this.stats.queuedRequests--;
// Execute queued request with the REAL executor
this.executeWithConnection(connection, request.operation, request.executor)
.then(request.resolver)
.catch(request.rejector);
}
async initializeConnectionPool() {
// Create minimum connections
for (let i = 0; i < this.config.minConnections; i++) {
await this.createConnection();
}
}
async createConnection() {
const connectionId = `conn_${Date.now()}_${Math.random()}`;
// Create actual connection based on storage type
const actualConnection = await this.createStorageConnection();
const connection = {
id: connectionId,
connection: actualConnection,
isIdle: true,
lastUsed: Date.now(),
healthScore: 100,
activeRequests: 0,
requestCount: 0
};
this.connections.set(connectionId, connection);
this.stats.totalConnections++;
return connection;
}
async createStorageConnection() {
// For cloud storage, reuse the existing storage instance
// Connection pooling in this context means managing concurrent requests
// not creating multiple storage instances (which would be wasteful)
const storage = this.context?.storage;
if (!storage) {
throw new Error('Storage not available for connection pooling');
}
// Return a connection wrapper that tracks usage
return {
storage,
created: Date.now(),
requestCount: 0
};
}
async getOrCreateConnection() {
// Try to get an available connection
let connection = this.getAvailableConnection();
// If no connection available and under max, create new one
if (!connection && this.connections.size < this.config.maxConnections) {
connection = await this.createConnection();
}
return connection;
}
startHealthChecks() {
this.healthCheckInterval = setInterval(() => {
this.performHealthChecks();
}, this.config.healthCheckInterval);
}
performHealthChecks() {
const now = Date.now();
const toRemove = [];
for (const [id, connection] of this.connections) {
// Remove idle connections that are too old
if (connection.isIdle &&
now - connection.lastUsed > this.config.idleTimeout &&
this.connections.size > this.config.minConnections) {
toRemove.push(id);
}
// Remove unhealthy connections
if (connection.healthScore < 20) {
toRemove.push(id);
}
}
// Remove unhealthy/old connections
for (const id of toRemove) {
this.connections.delete(id);
this.stats.totalConnections--;
}
// Ensure minimum connections
while (this.connections.size < this.config.minConnections) {
this.createConnection();
}
}
startMetricsCollection() {
setInterval(() => {
this.updateThroughputMetrics();
}, 1000); // Update every second
}
updateLatencyMetrics(latency) {
// Simple moving average
this.stats.averageLatency = (this.stats.averageLatency * 0.9) + (latency * 0.1);
}
updateThroughputMetrics() {
// Reset counter for next second
this.stats.throughputPerSecond = this.stats.totalRequests;
// Reset total for next measurement (in practice, use sliding window)
}
/**
* Get connection pool statistics
*/
getStats() {
return {
...this.stats,
queueSize: this.requestQueue.length,
activeConnections: this.stats.activeConnections,
totalConnections: this.connections.size,
poolUtilization: `${Math.round((this.stats.activeConnections / this.connections.size) * 100)}%`,
storageType: this.storageType
};
}
async onShutdown() {
if (this.healthCheckInterval) {
clearInterval(this.healthCheckInterval);
}
// Close all connections
this.connections.clear();
// Reject all queued requests
this.requestQueue.forEach(request => {
request.rejector(new Error('Connection pool shutting down'));
});
this.requestQueue = [];
const stats = this.getStats();
this.log(`Connection pool shutdown: ${stats.totalRequests} requests processed, ${stats.poolUtilization} avg utilization`);
}
}
//# sourceMappingURL=connectionPoolAugmentation.js.map

File diff suppressed because one or more lines are too long

View file

@ -0,0 +1,59 @@
/**
* Default Augmentations Registration
*
* Maintains zero-config philosophy by automatically registering
* core augmentations that were previously hardcoded in Brainy.
*
* These augmentations are optional but enabled by default for
* backward compatibility and optimal performance.
*/
import { Brainy } from '../brainy.js';
import { BaseAugmentation } from './brainyAugmentation.js';
import { CacheAugmentation } from './cacheAugmentation.js';
import { IndexAugmentation } from './indexAugmentation.js';
import { MetricsAugmentation } from './metricsAugmentation.js';
import { MonitoringAugmentation } from './monitoringAugmentation.js';
import { UniversalDisplayAugmentation } from './universalDisplayAugmentation.js';
/**
* Create default augmentations for zero-config operation
* Returns an array of augmentations to be registered
*
* @param config - Configuration options
* @returns Array of augmentations to register
*/
export declare function createDefaultAugmentations(config?: {
cache?: boolean | Record<string, any>;
index?: boolean | Record<string, any>;
metrics?: boolean | Record<string, any>;
monitoring?: boolean | Record<string, any>;
display?: boolean | Record<string, any>;
}): BaseAugmentation[];
/**
* Get augmentation by name with type safety
*/
export declare function getAugmentation<T>(brain: Brainy, name: string): T | null;
/**
* Compatibility helpers for migrating from hardcoded features
*/
export declare const AugmentationHelpers: {
/**
* Get cache augmentation
*/
getCache(brain: Brainy): CacheAugmentation | null;
/**
* Get index augmentation
*/
getIndex(brain: Brainy): IndexAugmentation | null;
/**
* Get metrics augmentation
*/
getMetrics(brain: Brainy): MetricsAugmentation | null;
/**
* Get monitoring augmentation
*/
getMonitoring(brain: Brainy): MonitoringAugmentation | null;
/**
* Get display augmentation
*/
getDisplay(brain: Brainy): UniversalDisplayAugmentation | null;
};

View file

@ -0,0 +1,100 @@
/**
* Default Augmentations Registration
*
* Maintains zero-config philosophy by automatically registering
* core augmentations that were previously hardcoded in Brainy.
*
* These augmentations are optional but enabled by default for
* backward compatibility and optimal performance.
*/
import { CacheAugmentation } from './cacheAugmentation.js';
import { IndexAugmentation } from './indexAugmentation.js';
import { MetricsAugmentation } from './metricsAugmentation.js';
import { MonitoringAugmentation } from './monitoringAugmentation.js';
import { UniversalDisplayAugmentation } from './universalDisplayAugmentation.js';
/**
* Create default augmentations for zero-config operation
* Returns an array of augmentations to be registered
*
* @param config - Configuration options
* @returns Array of augmentations to register
*/
export function createDefaultAugmentations(config = {}) {
const augmentations = [];
// Cache augmentation (was SearchCache)
if (config.cache !== false) {
const cacheConfig = typeof config.cache === 'object' ? config.cache : {};
augmentations.push(new CacheAugmentation(cacheConfig));
}
// Index augmentation (was MetadataIndex)
if (config.index !== false) {
const indexConfig = typeof config.index === 'object' ? config.index : {};
augmentations.push(new IndexAugmentation(indexConfig));
}
// Metrics augmentation (was StatisticsCollector)
if (config.metrics !== false) {
const metricsConfig = typeof config.metrics === 'object' ? config.metrics : {};
augmentations.push(new MetricsAugmentation(metricsConfig));
}
// Display augmentation (AI-powered intelligent display fields)
if (config.display !== false) {
const displayConfig = typeof config.display === 'object' ? config.display : {};
augmentations.push(new UniversalDisplayAugmentation(displayConfig));
}
// Monitoring augmentation (was HealthMonitor)
// Only enable by default in distributed mode
const isDistributed = process.env.BRAINY_MODE === 'distributed' ||
process.env.BRAINY_DISTRIBUTED === 'true';
if (config.monitoring !== false && (config.monitoring || isDistributed)) {
const monitoringConfig = typeof config.monitoring === 'object' ? config.monitoring : {};
augmentations.push(new MonitoringAugmentation(monitoringConfig));
}
return augmentations;
}
/**
* Get augmentation by name with type safety
*/
export function getAugmentation(brain, name) {
// Access augmentations through a public method or property
const augmentations = brain.augmentations;
if (!augmentations)
return null;
const aug = augmentations.get(name);
return aug;
}
/**
* Compatibility helpers for migrating from hardcoded features
*/
export const AugmentationHelpers = {
/**
* Get cache augmentation
*/
getCache(brain) {
return getAugmentation(brain, 'cache');
},
/**
* Get index augmentation
*/
getIndex(brain) {
return getAugmentation(brain, 'index');
},
/**
* Get metrics augmentation
*/
getMetrics(brain) {
return getAugmentation(brain, 'metrics');
},
/**
* Get monitoring augmentation
*/
getMonitoring(brain) {
return getAugmentation(brain, 'monitoring');
},
/**
* Get display augmentation
*/
getDisplay(brain) {
return getAugmentation(brain, 'display');
}
};
//# sourceMappingURL=defaultAugmentations.js.map

View file

@ -0,0 +1 @@
{"version":3,"file":"defaultAugmentations.js","sourceRoot":"","sources":["../../src/augmentations/defaultAugmentations.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAIH,OAAO,EAAE,iBAAiB,EAAE,MAAM,wBAAwB,CAAA;AAC1D,OAAO,EAAE,iBAAiB,EAAE,MAAM,wBAAwB,CAAA;AAC1D,OAAO,EAAE,mBAAmB,EAAE,MAAM,0BAA0B,CAAA;AAC9D,OAAO,EAAE,sBAAsB,EAAE,MAAM,6BAA6B,CAAA;AACpE,OAAO,EAAE,4BAA4B,EAAE,MAAM,mCAAmC,CAAA;AAEhF;;;;;;GAMG;AACH,MAAM,UAAU,0BAA0B,CACxC,SAMI,EAAE;IAEN,MAAM,aAAa,GAAuB,EAAE,CAAA;IAE5C,uCAAuC;IACvC,IAAI,MAAM,CAAC,KAAK,KAAK,KAAK,EAAE,CAAC;QAC3B,MAAM,WAAW,GAAG,OAAO,MAAM,CAAC,KAAK,KAAK,QAAQ,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,CAAA;QACxE,aAAa,CAAC,IAAI,CAAC,IAAI,iBAAiB,CAAC,WAAW,CAAC,CAAC,CAAA;IACxD,CAAC;IAED,yCAAyC;IACzC,IAAI,MAAM,CAAC,KAAK,KAAK,KAAK,EAAE,CAAC;QAC3B,MAAM,WAAW,GAAG,OAAO,MAAM,CAAC,KAAK,KAAK,QAAQ,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,CAAA;QACxE,aAAa,CAAC,IAAI,CAAC,IAAI,iBAAiB,CAAC,WAAW,CAAC,CAAC,CAAA;IACxD,CAAC;IAED,iDAAiD;IACjD,IAAI,MAAM,CAAC,OAAO,KAAK,KAAK,EAAE,CAAC;QAC7B,MAAM,aAAa,GAAG,OAAO,MAAM,CAAC,OAAO,KAAK,QAAQ,CAAC,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,CAAA;QAC9E,aAAa,CAAC,IAAI,CAAC,IAAI,mBAAmB,CAAC,aAAa,CAAC,CAAC,CAAA;IAC5D,CAAC;IAED,+DAA+D;IAC/D,IAAI,MAAM,CAAC,OAAO,KAAK,KAAK,EAAE,CAAC;QAC7B,MAAM,aAAa,GAAG,OAAO,MAAM,CAAC,OAAO,KAAK,QAAQ,CAAC,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,CAAA;QAC9E,aAAa,CAAC,IAAI,CAAC,IAAI,4BAA4B,CAAC,aAAa,CAAC,CAAC,CAAA;IACrE,CAAC;IAED,8CAA8C;IAC9C,6CAA6C;IAC7C,MAAM,aAAa,GAAG,OAAO,CAAC,GAAG,CAAC,WAAW,KAAK,aAAa;QACzC,OAAO,CAAC,GAAG,CAAC,kBAAkB,KAAK,MAAM,CAAA;IAE/D,IAAI,MAAM,CAAC,UAAU,KAAK,KAAK,IAAI,CAAC,MAAM,CAAC,UAAU,IAAI,aAAa,CAAC,EAAE,CAAC;QACxE,MAAM,gBAAgB,GAAG,OAAO,MAAM,CAAC,UAAU,KAAK,QAAQ,CAAC,CAAC,CAAC,MAAM,CAAC,UAAU,CAAC,CAAC,CAAC,EAAE,CAAA;QACvF,aAAa,CAAC,IAAI,CAAC,IAAI,sBAAsB,CAAC,gBAAgB,CAAC,CAAC,CAAA;IAClE,CAAC;IAED,OAAO,aAAa,CAAA;AACtB,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,eAAe,CAAI,KAAa,EAAE,IAAY;IAC5D,2DAA2D;IAC3D,MAAM,aAAa,GAAI,KAAa,CAAC,aAAa,CAAA;IAClD,IAAI,CAAC,aAAa;QAAE,OAAO,IAAI,CAAA;IAC/B,MAAM,GAAG,GAAG,aAAa,CAAC,GAAG,CAAC,IAAI,CAAC,CAAA;IACnC,OAAO,GAAe,CAAA;AACxB,CAAC;AAED;;GAEG;AACH,MAAM,CAAC,MAAM,mBAAmB,GAAG;IACjC;;OAEG;IACH,QAAQ,CAAC,KAAa;QACpB,OAAO,eAAe,CAAoB,KAAK,EAAE,OAAO,CAAC,CAAA;IAC3D,CAAC;IAED;;OAEG;IACH,QAAQ,CAAC,KAAa;QACpB,OAAO,eAAe,CAAoB,KAAK,EAAE,OAAO,CAAC,CAAA;IAC3D,CAAC;IAED;;OAEG;IACH,UAAU,CAAC,KAAa;QACtB,OAAO,eAAe,CAAsB,KAAK,EAAE,SAAS,CAAC,CAAA;IAC/D,CAAC;IAED;;OAEG;IACH,aAAa,CAAC,KAAa;QACzB,OAAO,eAAe,CAAyB,KAAK,EAAE,YAAY,CAAC,CAAA;IACrE,CAAC;IAED;;OAEG;IACH,UAAU,CAAC,KAAa;QACtB,OAAO,eAAe,CAA+B,KAAK,EAAE,SAAS,CAAC,CAAA;IACxE,CAAC;CACF,CAAA"}

View file

@ -0,0 +1,152 @@
/**
* Augmentation Discovery API
*
* Provides discovery and configuration capabilities for augmentations
* Enables tools like brain-cloud to dynamically discover, configure, and manage augmentations
*/
import { AugmentationRegistry } from './brainyAugmentation.js';
import { AugmentationManifest, JSONSchema } from './manifest.js';
/**
* Augmentation listing with manifest and status
*/
export interface AugmentationListing {
id: string;
name: string;
manifest: AugmentationManifest;
status: {
enabled: boolean;
initialized: boolean;
category: string;
priority: number;
};
config?: {
current: any;
schema?: JSONSchema;
sources?: any[];
};
}
/**
* Configuration validation result
*/
export interface ConfigValidationResult {
valid: boolean;
errors?: string[];
warnings?: string[];
suggestions?: string[];
}
/**
* Discovery API options
*/
export interface DiscoveryOptions {
includeConfig?: boolean;
includeSchema?: boolean;
includeSources?: boolean;
category?: string;
enabled?: boolean;
}
/**
* Augmentation Discovery API
*
* Provides a unified interface for discovering and managing augmentations
*/
export declare class AugmentationDiscovery {
private registry;
constructor(registry: AugmentationRegistry);
/**
* Discover all registered augmentations with manifests
* @param options Discovery options
* @returns List of augmentation listings
*/
discover(options?: DiscoveryOptions): Promise<AugmentationListing[]>;
/**
* Get a specific augmentation's manifest
* @param augId Augmentation ID
* @returns Augmentation manifest or null if not found
*/
getManifest(augId: string): Promise<AugmentationManifest | null>;
/**
* Get configuration schema for an augmentation
* @param augId Augmentation ID
* @returns Configuration schema or null
*/
getConfigSchema(augId: string): Promise<JSONSchema | null>;
/**
* Get current configuration for an augmentation
* @param augId Augmentation ID
* @returns Current configuration or null
*/
getConfig(augId: string): Promise<any | null>;
/**
* Update configuration for an augmentation
* @param augId Augmentation ID
* @param config New configuration
* @returns Updated configuration or null on failure
*/
updateConfig(augId: string, config: any): Promise<any | null>;
/**
* Validate configuration against schema
* @param augId Augmentation ID
* @param config Configuration to validate
* @returns Validation result
*/
validateConfig(augId: string, config: any): Promise<ConfigValidationResult>;
/**
* Validate a property value against its schema
*/
private validatePropertyValue;
/**
* Get environment variables for an augmentation
* @param augId Augmentation ID
* @returns Map of environment variable names to descriptions
*/
getEnvironmentVariables(augId: string): Promise<Record<string, any> | null>;
/**
* Get configuration examples for an augmentation
* @param augId Augmentation ID
* @returns Configuration examples or empty array
*/
getConfigExamples(augId: string): Promise<any[]>;
/**
* Check if an augmentation supports configuration
* @param augId Augmentation ID
* @returns True if augmentation supports configuration
*/
supportsConfiguration(augId: string): Promise<boolean>;
/**
* Get augmentations by category
* @param category Category to filter by
* @returns List of augmentations in the category
*/
getByCategory(category: string): Promise<AugmentationListing[]>;
/**
* Get enabled augmentations
* @returns List of enabled augmentations
*/
getEnabled(): Promise<AugmentationListing[]>;
/**
* Search augmentations by keyword
* @param query Search query
* @returns Matching augmentations
*/
search(query: string): Promise<AugmentationListing[]>;
/**
* Export configuration for all augmentations
* @returns Map of augmentation IDs to configurations
*/
exportConfigurations(): Promise<Record<string, any>>;
/**
* Import configurations for multiple augmentations
* @param configs Map of augmentation IDs to configurations
* @returns Results of import operation
*/
importConfigurations(configs: Record<string, any>): Promise<Record<string, {
success: boolean;
error?: string;
}>>;
/**
* Generate configuration documentation
* @param augId Augmentation ID
* @returns Markdown documentation
*/
generateConfigDocs(augId: string): Promise<string | null>;
}

View file

@ -0,0 +1,441 @@
/**
* Augmentation Discovery API
*
* Provides discovery and configuration capabilities for augmentations
* Enables tools like brain-cloud to dynamically discover, configure, and manage augmentations
*/
/**
* Augmentation Discovery API
*
* Provides a unified interface for discovering and managing augmentations
*/
export class AugmentationDiscovery {
constructor(registry) {
this.registry = registry;
}
/**
* Discover all registered augmentations with manifests
* @param options Discovery options
* @returns List of augmentation listings
*/
async discover(options = {}) {
const augmentations = this.registry.getAll();
const listings = [];
for (const aug of augmentations) {
// Check if augmentation has manifest support
const hasManifest = 'getManifest' in aug && typeof aug.getManifest === 'function';
if (!hasManifest) {
// Skip augmentations without manifest support (legacy)
continue;
}
try {
// Check if augmentation has manifest method
if (!('getManifest' in aug) || typeof aug.getManifest !== 'function') {
continue;
}
const getManifestFn = aug.getManifest;
const manifest = getManifestFn();
// Apply filters
if (options.category && manifest.category !== options.category) {
continue;
}
if (options.enabled !== undefined) {
const isEnabled = aug.enabled !== false;
if (isEnabled !== options.enabled) {
continue;
}
}
// Build listing
const listing = {
id: manifest.id,
name: manifest.name,
manifest,
status: {
enabled: aug.enabled !== false,
initialized: aug.isInitialized || false,
category: aug.category || manifest.category,
priority: aug.priority
}
};
// Include configuration if requested
if (options.includeConfig && 'getConfig' in aug) {
const getConfigFn = aug.getConfig;
listing.config = {
current: getConfigFn()
};
if (options.includeSchema) {
listing.config.schema = manifest.configSchema;
}
}
listings.push(listing);
}
catch (error) {
console.warn(`Failed to get manifest for augmentation ${aug.name}:`, error);
}
}
// Sort by priority (highest first) then by name
listings.sort((a, b) => {
const priorityDiff = b.status.priority - a.status.priority;
if (priorityDiff !== 0)
return priorityDiff;
return a.name.localeCompare(b.name);
});
return listings;
}
/**
* Get a specific augmentation's manifest
* @param augId Augmentation ID
* @returns Augmentation manifest or null if not found
*/
async getManifest(augId) {
const aug = this.registry.get(augId);
if (!aug || !('getManifest' in aug)) {
return null;
}
try {
const getManifestFn = aug.getManifest;
return getManifestFn();
}
catch (error) {
console.error(`Failed to get manifest for ${augId}:`, error);
return null;
}
}
/**
* Get configuration schema for an augmentation
* @param augId Augmentation ID
* @returns Configuration schema or null
*/
async getConfigSchema(augId) {
const manifest = await this.getManifest(augId);
return manifest?.configSchema || null;
}
/**
* Get current configuration for an augmentation
* @param augId Augmentation ID
* @returns Current configuration or null
*/
async getConfig(augId) {
const aug = this.registry.get(augId);
if (!aug || !('getConfig' in aug)) {
return null;
}
try {
const getConfigFn = aug.getConfig;
return getConfigFn();
}
catch (error) {
console.error(`Failed to get config for ${augId}:`, error);
return null;
}
}
/**
* Update configuration for an augmentation
* @param augId Augmentation ID
* @param config New configuration
* @returns Updated configuration or null on failure
*/
async updateConfig(augId, config) {
const aug = this.registry.get(augId);
if (!aug || !('updateConfig' in aug) || !('getConfig' in aug)) {
throw new Error(`Augmentation ${augId} does not support configuration updates`);
}
try {
const updateConfigFn = aug.updateConfig;
await updateConfigFn(config);
const getConfigFn = aug.getConfig;
return getConfigFn();
}
catch (error) {
throw new Error(`Failed to update config for ${augId}: ${error}`);
}
}
/**
* Validate configuration against schema
* @param augId Augmentation ID
* @param config Configuration to validate
* @returns Validation result
*/
async validateConfig(augId, config) {
const schema = await this.getConfigSchema(augId);
if (!schema) {
return {
valid: true,
warnings: ['No schema available for validation']
};
}
const errors = [];
const warnings = [];
const suggestions = [];
// Check required fields
if (schema.required) {
for (const field of schema.required) {
if (config[field] === undefined) {
errors.push(`Missing required field: ${field}`);
}
}
}
// Validate properties
if (schema.properties) {
for (const [key, propSchema] of Object.entries(schema.properties)) {
const value = config[key];
if (value === undefined) {
// Check if there's a default
if (propSchema.default !== undefined) {
suggestions.push(`Field '${key}' not provided, will use default: ${JSON.stringify(propSchema.default)}`);
}
continue;
}
// Type validation
if (propSchema.type) {
const actualType = Array.isArray(value) ? 'array' : typeof value;
if (actualType !== propSchema.type) {
errors.push(`${key}: expected ${propSchema.type}, got ${actualType}`);
}
}
// Additional validations for specific types
this.validatePropertyValue(key, value, propSchema, errors, warnings);
}
}
// Check for unknown properties
if (schema.additionalProperties === false && schema.properties) {
const allowedKeys = Object.keys(schema.properties);
for (const key of Object.keys(config)) {
if (!allowedKeys.includes(key)) {
warnings.push(`Unknown property: ${key}`);
}
}
}
return {
valid: errors.length === 0,
errors: errors.length > 0 ? errors : undefined,
warnings: warnings.length > 0 ? warnings : undefined,
suggestions: suggestions.length > 0 ? suggestions : undefined
};
}
/**
* Validate a property value against its schema
*/
validatePropertyValue(key, value, schema, errors, warnings) {
// Number validations
if (schema.type === 'number') {
if (schema.minimum !== undefined && value < schema.minimum) {
errors.push(`${key}: value ${value} is less than minimum ${schema.minimum}`);
}
if (schema.maximum !== undefined && value > schema.maximum) {
errors.push(`${key}: value ${value} is greater than maximum ${schema.maximum}`);
}
}
// String validations
if (schema.type === 'string') {
if (schema.minLength !== undefined && value.length < schema.minLength) {
errors.push(`${key}: length ${value.length} is less than minimum ${schema.minLength}`);
}
if (schema.maxLength !== undefined && value.length > schema.maxLength) {
errors.push(`${key}: length ${value.length} is greater than maximum ${schema.maxLength}`);
}
if (schema.pattern) {
const regex = new RegExp(schema.pattern);
if (!regex.test(value)) {
errors.push(`${key}: value does not match pattern ${schema.pattern}`);
}
}
}
// Enum validation
if (schema.enum && !schema.enum.includes(value)) {
errors.push(`${key}: value '${value}' is not one of allowed values: ${schema.enum.join(', ')}`);
}
}
/**
* Get environment variables for an augmentation
* @param augId Augmentation ID
* @returns Map of environment variable names to descriptions
*/
async getEnvironmentVariables(augId) {
const manifest = await this.getManifest(augId);
if (!manifest?.configSchema?.properties) {
return null;
}
const prefix = `BRAINY_AUG_${augId.toUpperCase()}_`;
const vars = {};
for (const [key, prop] of Object.entries(manifest.configSchema.properties)) {
const envKey = prefix + key.replace(/([A-Z])/g, '_$1').toUpperCase();
vars[envKey] = {
configKey: key,
description: prop.description,
type: prop.type,
default: prop.default,
required: manifest.configSchema.required?.includes(key),
currentValue: typeof process !== 'undefined' ? process.env?.[envKey] : undefined
};
}
return vars;
}
/**
* Get configuration examples for an augmentation
* @param augId Augmentation ID
* @returns Configuration examples or empty array
*/
async getConfigExamples(augId) {
const manifest = await this.getManifest(augId);
return manifest?.configExamples || [];
}
/**
* Check if an augmentation supports configuration
* @param augId Augmentation ID
* @returns True if augmentation supports configuration
*/
async supportsConfiguration(augId) {
const aug = this.registry.get(augId);
return !!(aug && 'getConfig' in aug && 'updateConfig' in aug);
}
/**
* Get augmentations by category
* @param category Category to filter by
* @returns List of augmentations in the category
*/
async getByCategory(category) {
return this.discover({ category });
}
/**
* Get enabled augmentations
* @returns List of enabled augmentations
*/
async getEnabled() {
return this.discover({ enabled: true });
}
/**
* Search augmentations by keyword
* @param query Search query
* @returns Matching augmentations
*/
async search(query) {
const all = await this.discover();
const queryLower = query.toLowerCase();
return all.filter(listing => {
const manifest = listing.manifest;
// Search in various fields
const searchFields = [
manifest.name,
manifest.description,
manifest.longDescription,
...(manifest.keywords || []),
manifest.category
].filter(Boolean).map(s => s.toLowerCase());
return searchFields.some(field => field.includes(queryLower));
});
}
/**
* Export configuration for all augmentations
* @returns Map of augmentation IDs to configurations
*/
async exportConfigurations() {
const configs = {};
const listings = await this.discover({ includeConfig: true });
for (const listing of listings) {
if (listing.config?.current) {
configs[listing.id] = listing.config.current;
}
}
return configs;
}
/**
* Import configurations for multiple augmentations
* @param configs Map of augmentation IDs to configurations
* @returns Results of import operation
*/
async importConfigurations(configs) {
const results = {};
for (const [augId, config] of Object.entries(configs)) {
try {
// Validate before applying
const validation = await this.validateConfig(augId, config);
if (!validation.valid) {
results[augId] = {
success: false,
error: `Validation failed: ${validation.errors?.join(', ')}`
};
continue;
}
// Apply configuration
await this.updateConfig(augId, config);
results[augId] = { success: true };
}
catch (error) {
results[augId] = {
success: false,
error: error instanceof Error ? error.message : String(error)
};
}
}
return results;
}
/**
* Generate configuration documentation
* @param augId Augmentation ID
* @returns Markdown documentation
*/
async generateConfigDocs(augId) {
const manifest = await this.getManifest(augId);
if (!manifest)
return null;
const schema = manifest.configSchema;
const examples = manifest.configExamples || [];
const envVars = await this.getEnvironmentVariables(augId);
let docs = `# ${manifest.name} Configuration\n\n`;
docs += `${manifest.description}\n\n`;
if (manifest.longDescription) {
docs += `## Overview\n\n${manifest.longDescription}\n\n`;
}
// Configuration options
if (schema?.properties) {
docs += `## Configuration Options\n\n`;
for (const [key, prop] of Object.entries(schema.properties)) {
const required = schema.required?.includes(key) ? ' *(required)*' : '';
docs += `### \`${key}\`${required}\n\n`;
if (prop.description) {
docs += `${prop.description}\n\n`;
}
docs += `- **Type**: ${prop.type}\n`;
if (prop.default !== undefined) {
docs += `- **Default**: \`${JSON.stringify(prop.default)}\`\n`;
}
if (prop.minimum !== undefined) {
docs += `- **Minimum**: ${prop.minimum}\n`;
}
if (prop.maximum !== undefined) {
docs += `- **Maximum**: ${prop.maximum}\n`;
}
if (prop.enum) {
docs += `- **Allowed values**: ${prop.enum.map(v => `\`${v}\``).join(', ')}\n`;
}
docs += '\n';
}
}
// Environment variables
if (envVars && Object.keys(envVars).length > 0) {
docs += `## Environment Variables\n\n`;
docs += `| Variable | Config Key | Type | Required | Default |\n`;
docs += `|----------|------------|------|----------|----------|\n`;
for (const [envKey, info] of Object.entries(envVars)) {
docs += `| \`${envKey}\` | ${info.configKey} | ${info.type} | ${info.required ? 'Yes' : 'No'} | ${info.default !== undefined ? `\`${info.default}\`` : '-'} |\n`;
}
docs += '\n';
}
// Examples
if (examples.length > 0) {
docs += `## Examples\n\n`;
for (const example of examples) {
docs += `### ${example.name}\n\n`;
if (example.description) {
docs += `${example.description}\n\n`;
}
docs += '```json\n';
docs += JSON.stringify(example.config, null, 2);
docs += '\n```\n\n';
}
}
return docs;
}
}
//# sourceMappingURL=discovery.js.map

File diff suppressed because one or more lines are too long

View file

@ -0,0 +1,142 @@
/**
* Brain-Cloud Catalog Discovery
*
* Discovers augmentations available in the brain-cloud catalog
* Handles free, premium, and community augmentations
*/
import { AugmentationManifest } from '../manifest.js';
export interface CatalogAugmentation {
id: string;
name: string;
description: string;
longDescription?: string;
category: string;
status: 'available' | 'coming_soon' | 'deprecated';
tier: 'free' | 'premium' | 'enterprise';
price?: {
monthly?: number;
yearly?: number;
oneTime?: number;
};
manifest?: AugmentationManifest;
source: 'catalog';
cdnUrl?: string;
npmPackage?: string;
githubRepo?: string;
author?: {
name: string;
url?: string;
};
metrics?: {
installations: number;
rating: number;
reviews: number;
};
requirements?: {
minBrainyVersion?: string;
maxBrainyVersion?: string;
dependencies?: string[];
};
}
export interface CatalogOptions {
apiUrl?: string;
apiKey?: string;
cache?: boolean;
cacheTimeout?: number;
}
export interface CatalogFilters {
category?: string;
tier?: 'free' | 'premium' | 'enterprise';
status?: 'available' | 'coming_soon' | 'deprecated';
search?: string;
installed?: boolean;
minRating?: number;
}
/**
* Brain-Cloud Catalog Discovery
*/
export declare class CatalogDiscovery {
private apiUrl;
private apiKey?;
private cache;
private cacheTimeout;
constructor(options?: CatalogOptions);
/**
* Discover augmentations from catalog
*/
discover(filters?: CatalogFilters): Promise<CatalogAugmentation[]>;
/**
* Get specific augmentation details
*/
getAugmentation(id: string): Promise<CatalogAugmentation | null>;
/**
* Get augmentation manifest
*/
getManifest(id: string): Promise<AugmentationManifest | null>;
/**
* Get CDN URL for dynamic loading
*/
getCDNUrl(id: string): Promise<string | null>;
/**
* Check if user has access to augmentation
*/
checkAccess(id: string): Promise<{
hasAccess: boolean;
requiresPurchase?: boolean;
requiredTier?: string;
}>;
/**
* Purchase/activate augmentation
*/
purchase(id: string, licenseKey?: string): Promise<{
success: boolean;
cdnUrl?: string;
npmPackage?: string;
licenseKey?: string;
}>;
/**
* Get user's purchased augmentations
*/
getPurchased(): Promise<CatalogAugmentation[]>;
/**
* Get categories
*/
getCategories(): Promise<Array<{
id: string;
name: string;
description: string;
icon?: string;
}>>;
/**
* Search augmentations
*/
search(query: string): Promise<CatalogAugmentation[]>;
/**
* Get trending augmentations
*/
getTrending(limit?: number): Promise<CatalogAugmentation[]>;
/**
* Get recommended augmentations
*/
getRecommended(): Promise<CatalogAugmentation[]>;
/**
* Transform catalog data
*/
private transformCatalogData;
/**
* Transform single augmentation
*/
private transformAugmentation;
/**
* Get request headers
*/
private getHeaders;
/**
* Clear cache
*/
clearCache(): void;
/**
* Set API key
*/
setApiKey(apiKey: string): void;
}

View file

@ -0,0 +1,249 @@
/**
* Brain-Cloud Catalog Discovery
*
* Discovers augmentations available in the brain-cloud catalog
* Handles free, premium, and community augmentations
*/
/**
* Brain-Cloud Catalog Discovery
*/
export class CatalogDiscovery {
constructor(options = {}) {
this.cache = new Map();
this.apiUrl = options.apiUrl || 'https://api.soulcraft.com/brain-cloud';
this.apiKey = options.apiKey;
this.cacheTimeout = options.cacheTimeout || 5 * 60 * 1000; // 5 minutes
}
/**
* Discover augmentations from catalog
*/
async discover(filters = {}) {
const cacheKey = JSON.stringify(filters);
// Check cache
if (this.cache.has(cacheKey)) {
const cached = this.cache.get(cacheKey);
if (Date.now() - cached.timestamp < this.cacheTimeout) {
return cached.data;
}
}
// Build query parameters
const params = new URLSearchParams();
if (filters.category)
params.append('category', filters.category);
if (filters.tier)
params.append('tier', filters.tier);
if (filters.status)
params.append('status', filters.status);
if (filters.search)
params.append('q', filters.search);
if (filters.minRating)
params.append('minRating', filters.minRating.toString());
// Fetch from API
const response = await fetch(`${this.apiUrl}/augmentations/discover?${params}`, {
headers: this.getHeaders()
});
if (!response.ok) {
throw new Error(`Failed to fetch catalog: ${response.statusText}`);
}
const data = await response.json();
const augmentations = this.transformCatalogData(data);
// Cache result
this.cache.set(cacheKey, {
data: augmentations,
timestamp: Date.now()
});
return augmentations;
}
/**
* Get specific augmentation details
*/
async getAugmentation(id) {
const response = await fetch(`${this.apiUrl}/augmentations/${id}`, {
headers: this.getHeaders()
});
if (!response.ok) {
if (response.status === 404)
return null;
throw new Error(`Failed to fetch augmentation: ${response.statusText}`);
}
const data = await response.json();
return this.transformAugmentation(data);
}
/**
* Get augmentation manifest
*/
async getManifest(id) {
const response = await fetch(`${this.apiUrl}/augmentations/${id}/manifest`, {
headers: this.getHeaders()
});
if (!response.ok) {
if (response.status === 404)
return null;
throw new Error(`Failed to fetch manifest: ${response.statusText}`);
}
return response.json();
}
/**
* Get CDN URL for dynamic loading
*/
async getCDNUrl(id) {
const aug = await this.getAugmentation(id);
return aug?.cdnUrl || null;
}
/**
* Check if user has access to augmentation
*/
async checkAccess(id) {
if (!this.apiKey) {
// No API key, only free augmentations
const aug = await this.getAugmentation(id);
return {
hasAccess: aug?.tier === 'free',
requiresPurchase: aug?.tier !== 'free',
requiredTier: aug?.tier
};
}
const response = await fetch(`${this.apiUrl}/augmentations/${id}/access`, {
headers: this.getHeaders()
});
if (!response.ok) {
throw new Error(`Failed to check access: ${response.statusText}`);
}
return response.json();
}
/**
* Purchase/activate augmentation
*/
async purchase(id, licenseKey) {
const body = licenseKey ? { licenseKey } : {};
const response = await fetch(`${this.apiUrl}/augmentations/${id}/purchase`, {
method: 'POST',
headers: {
...this.getHeaders(),
'Content-Type': 'application/json'
},
body: JSON.stringify(body)
});
if (!response.ok) {
throw new Error(`Failed to purchase: ${response.statusText}`);
}
return response.json();
}
/**
* Get user's purchased augmentations
*/
async getPurchased() {
if (!this.apiKey) {
return [];
}
const response = await fetch(`${this.apiUrl}/user/augmentations`, {
headers: this.getHeaders()
});
if (!response.ok) {
throw new Error(`Failed to fetch purchased: ${response.statusText}`);
}
const data = await response.json();
return this.transformCatalogData(data);
}
/**
* Get categories
*/
async getCategories() {
const response = await fetch(`${this.apiUrl}/augmentations/categories`, {
headers: this.getHeaders()
});
if (!response.ok) {
throw new Error(`Failed to fetch categories: ${response.statusText}`);
}
return response.json();
}
/**
* Search augmentations
*/
async search(query) {
return this.discover({ search: query });
}
/**
* Get trending augmentations
*/
async getTrending(limit = 10) {
const response = await fetch(`${this.apiUrl}/augmentations/trending?limit=${limit}`, {
headers: this.getHeaders()
});
if (!response.ok) {
throw new Error(`Failed to fetch trending: ${response.statusText}`);
}
const data = await response.json();
return this.transformCatalogData(data);
}
/**
* Get recommended augmentations
*/
async getRecommended() {
if (!this.apiKey) {
// Return popular free augmentations
return this.discover({ tier: 'free', minRating: 4 });
}
const response = await fetch(`${this.apiUrl}/augmentations/recommended`, {
headers: this.getHeaders()
});
if (!response.ok) {
throw new Error(`Failed to fetch recommended: ${response.statusText}`);
}
const data = await response.json();
return this.transformCatalogData(data);
}
/**
* Transform catalog data
*/
transformCatalogData(data) {
return data.map(item => this.transformAugmentation(item));
}
/**
* Transform single augmentation
*/
transformAugmentation(item) {
return {
id: item.id,
name: item.name,
description: item.description,
longDescription: item.longDescription,
category: item.category,
status: item.status || 'available',
tier: item.tier || 'free',
price: item.price,
manifest: item.manifest,
source: 'catalog',
cdnUrl: item.cdnUrl || `https://cdn.soulcraft.com/augmentations/${item.id}@latest`,
npmPackage: item.npmPackage,
githubRepo: item.githubRepo,
author: item.author,
metrics: item.metrics,
requirements: item.requirements
};
}
/**
* Get request headers
*/
getHeaders() {
const headers = {};
if (this.apiKey) {
headers['Authorization'] = `Bearer ${this.apiKey}`;
}
return headers;
}
/**
* Clear cache
*/
clearCache() {
this.cache.clear();
}
/**
* Set API key
*/
setApiKey(apiKey) {
this.apiKey = apiKey;
this.clearCache(); // Clear cache when API key changes
}
}
//# sourceMappingURL=catalogDiscovery.js.map

File diff suppressed because one or more lines are too long

View file

@ -0,0 +1,84 @@
/**
* Local Augmentation Discovery
*
* Discovers augmentations installed locally in node_modules
* and built-in augmentations that ship with Brainy
*/
import { AugmentationManifest } from '../manifest.js';
export interface LocalAugmentation {
id: string;
name: string;
source: 'builtin' | 'npm' | 'local';
path: string;
manifest?: AugmentationManifest;
package?: {
name: string;
version: string;
description?: string;
};
}
/**
* Discovers augmentations installed locally
*/
export declare class LocalAugmentationDiscovery {
private options;
private builtInAugmentations;
private installedAugmentations;
constructor(options?: {
brainyPath?: string;
projectPath?: string;
scanNodeModules?: boolean;
});
/**
* Register built-in augmentations that ship with Brainy
*/
private registerBuiltIn;
/**
* Find Brainy installation path
*/
private findBrainyPath;
/**
* Discover all augmentations
*/
discoverAll(): Promise<LocalAugmentation[]>;
/**
* Scan node_modules for installed augmentations
*/
private scanNodeModules;
/**
* Scan local project for augmentations
*/
private scanLocalProject;
/**
* Load augmentation from package
*/
private loadPackageAugmentation;
/**
* Load package.json
*/
private loadPackageJson;
/**
* Convert name to human-readable format
*/
private humanizeName;
/**
* Get built-in augmentations
*/
getBuiltIn(): LocalAugmentation[];
/**
* Get installed augmentations
*/
getInstalled(): LocalAugmentation[];
/**
* Check if augmentation is installed
*/
isInstalled(id: string): boolean;
/**
* Get import path for augmentation
*/
getImportPath(id: string): string | null;
/**
* Load augmentation module dynamically
*/
loadAugmentation(id: string): Promise<any>;
}

View file

@ -0,0 +1,247 @@
/**
* Local Augmentation Discovery
*
* Discovers augmentations installed locally in node_modules
* and built-in augmentations that ship with Brainy
*/
import { existsSync, readdirSync, readFileSync } from 'fs';
import { join } from 'path';
/**
* Discovers augmentations installed locally
*/
export class LocalAugmentationDiscovery {
constructor(options = {}) {
this.options = options;
this.builtInAugmentations = new Map();
this.installedAugmentations = new Map();
this.options = {
brainyPath: this.options.brainyPath || this.findBrainyPath(),
projectPath: this.options.projectPath || process.cwd(),
scanNodeModules: this.options.scanNodeModules ?? true
};
// Register built-in augmentations
this.registerBuiltIn();
}
/**
* Register built-in augmentations that ship with Brainy
*/
registerBuiltIn() {
const builtIn = [
{ id: 'wal', name: 'Write-Ahead Log', path: 'walAugmentation' },
{ id: 'cache', name: 'Cache', path: 'cacheAugmentation' },
{ id: 'batch', name: 'Batch Processing', path: 'batchProcessingAugmentation' },
{ id: 'entity-registry', name: 'Entity Registry', path: 'entityRegistryAugmentation' },
{ id: 'index', name: 'Index', path: 'indexAugmentation' },
{ id: 'metrics', name: 'Metrics', path: 'metricsAugmentation' },
{ id: 'monitoring', name: 'Monitoring', path: 'monitoringAugmentation' },
{ id: 'connection-pool', name: 'Connection Pool', path: 'connectionPoolAugmentation' },
{ id: 'request-deduplicator', name: 'Request Deduplicator', path: 'requestDeduplicatorAugmentation' },
{ id: 'api-server', name: 'API Server', path: 'apiServerAugmentation' },
{ id: 'neural-import', name: 'Neural Import', path: 'neuralImport' },
{ id: 'intelligent-verb-scoring', name: 'Intelligent Verb Scoring', path: 'intelligentVerbScoringAugmentation' },
{ id: 'universal-display', name: 'Universal Display', path: 'universalDisplayAugmentation' },
// Storage augmentations
{ id: 'memory-storage', name: 'Memory Storage', path: 'storageAugmentations', export: 'MemoryStorageAugmentation' },
{ id: 'filesystem-storage', name: 'FileSystem Storage', path: 'storageAugmentations', export: 'FileSystemStorageAugmentation' },
{ id: 'opfs-storage', name: 'OPFS Storage', path: 'storageAugmentations', export: 'OPFSStorageAugmentation' },
{ id: 's3-storage', name: 'S3 Storage', path: 'storageAugmentations', export: 'S3StorageAugmentation' },
];
for (const aug of builtIn) {
this.builtInAugmentations.set(aug.id, {
id: aug.id,
name: aug.name,
source: 'builtin',
path: `@soulcraft/brainy/augmentations/${aug.path}`,
package: {
name: '@soulcraft/brainy',
version: 'builtin',
description: `Built-in ${aug.name} augmentation`
}
});
}
}
/**
* Find Brainy installation path
*/
findBrainyPath() {
// Try to find brainy in node_modules
const possiblePaths = [
join(process.cwd(), 'node_modules', '@soulcraft', 'brainy'),
join(process.cwd(), 'node_modules', 'brainy'),
join(process.cwd(), '..', 'node_modules', '@soulcraft', 'brainy'),
];
for (const path of possiblePaths) {
if (existsSync(path)) {
return path;
}
}
// Fallback to current directory
return process.cwd();
}
/**
* Discover all augmentations
*/
async discoverAll() {
const augmentations = [];
// Add built-in augmentations
augmentations.push(...this.builtInAugmentations.values());
// Scan node_modules if enabled
if (this.options.scanNodeModules) {
const installed = await this.scanNodeModules();
augmentations.push(...installed);
}
// Scan local project
const local = await this.scanLocalProject();
augmentations.push(...local);
return augmentations;
}
/**
* Scan node_modules for installed augmentations
*/
async scanNodeModules() {
const augmentations = [];
const nodeModulesPath = join(this.options.projectPath, 'node_modules');
if (!existsSync(nodeModulesPath)) {
return augmentations;
}
// Scan @brainy/* packages
const brainyPath = join(nodeModulesPath, '@brainy');
if (existsSync(brainyPath)) {
const packages = readdirSync(brainyPath);
for (const pkg of packages) {
const augmentation = await this.loadPackageAugmentation(join(brainyPath, pkg));
if (augmentation) {
augmentations.push(augmentation);
}
}
}
// Scan packages with brainy-augmentation keyword
const packages = readdirSync(nodeModulesPath);
for (const pkg of packages) {
if (pkg.startsWith('@') || pkg.startsWith('.'))
continue;
const pkgPath = join(nodeModulesPath, pkg);
const packageJson = this.loadPackageJson(pkgPath);
if (packageJson?.keywords?.includes('brainy-augmentation')) {
const augmentation = await this.loadPackageAugmentation(pkgPath);
if (augmentation) {
augmentations.push(augmentation);
}
}
}
return augmentations;
}
/**
* Scan local project for augmentations
*/
async scanLocalProject() {
const augmentations = [];
// Check for augmentations directory
const augPath = join(this.options.projectPath, 'augmentations');
if (existsSync(augPath)) {
const files = readdirSync(augPath);
for (const file of files) {
if (file.endsWith('.ts') || file.endsWith('.js')) {
const name = file.replace(/\.(ts|js)$/, '');
augmentations.push({
id: name,
name: this.humanizeName(name),
source: 'local',
path: join(augPath, file)
});
}
}
}
return augmentations;
}
/**
* Load augmentation from package
*/
async loadPackageAugmentation(pkgPath) {
const packageJson = this.loadPackageJson(pkgPath);
if (!packageJson)
return null;
// Check if it's a brainy augmentation
const isBrainyAug = packageJson.keywords?.includes('brainy-augmentation') ||
packageJson.brainy?.type === 'augmentation';
if (!isBrainyAug)
return null;
const manifest = packageJson.brainy?.manifest || null;
return {
id: packageJson.brainy?.id || packageJson.name.replace('@brainy/', ''),
name: packageJson.brainy?.name || packageJson.name,
source: 'npm',
path: pkgPath,
manifest,
package: {
name: packageJson.name,
version: packageJson.version,
description: packageJson.description
}
};
}
/**
* Load package.json
*/
loadPackageJson(pkgPath) {
const packageJsonPath = join(pkgPath, 'package.json');
if (!existsSync(packageJsonPath))
return null;
try {
return JSON.parse(readFileSync(packageJsonPath, 'utf8'));
}
catch {
return null;
}
}
/**
* Convert name to human-readable format
*/
humanizeName(name) {
return name
.replace(/[-_]/g, ' ')
.replace(/augmentation/gi, '')
.replace(/\b\w/g, l => l.toUpperCase())
.trim();
}
/**
* Get built-in augmentations
*/
getBuiltIn() {
return Array.from(this.builtInAugmentations.values());
}
/**
* Get installed augmentations
*/
getInstalled() {
return Array.from(this.installedAugmentations.values());
}
/**
* Check if augmentation is installed
*/
isInstalled(id) {
return this.builtInAugmentations.has(id) ||
this.installedAugmentations.has(id);
}
/**
* Get import path for augmentation
*/
getImportPath(id) {
const aug = this.builtInAugmentations.get(id) ||
this.installedAugmentations.get(id);
return aug?.path || null;
}
/**
* Load augmentation module dynamically
*/
async loadAugmentation(id) {
const path = this.getImportPath(id);
if (!path) {
throw new Error(`Augmentation ${id} not found`);
}
// Dynamic import
const module = await import(path);
return module.default || module;
}
}
//# sourceMappingURL=localDiscovery.js.map

File diff suppressed because one or more lines are too long

View file

@ -0,0 +1,97 @@
/**
* Runtime Augmentation Loader
*
* Dynamically loads and registers augmentations at runtime
* Supports CDN loading for browser environments and npm imports for Node.js
*/
import { BrainyAugmentation, AugmentationRegistry } from '../brainyAugmentation.js';
import { AugmentationManifest } from '../manifest.js';
export interface LoaderOptions {
cdnUrl?: string;
allowUnsafe?: boolean;
sandbox?: boolean;
timeout?: number;
cache?: boolean;
}
export interface LoadedAugmentation {
id: string;
instance: BrainyAugmentation;
manifest: AugmentationManifest;
source: 'cdn' | 'npm' | 'local';
loadTime: number;
}
/**
* Runtime Augmentation Loader
*
* Enables dynamic loading of augmentations from various sources
*/
export declare class RuntimeAugmentationLoader {
private options;
private loaded;
private cdnCache;
private registry?;
constructor(options?: LoaderOptions);
/**
* Set the augmentation registry
*/
setRegistry(registry: AugmentationRegistry): void;
/**
* Load augmentation from CDN (browser)
*/
loadFromCDN(id: string, version?: string, config?: any): Promise<LoadedAugmentation>;
/**
* Load augmentation from NPM (Node.js)
*/
loadFromNPM(packageName: string, config?: any): Promise<LoadedAugmentation>;
/**
* Load augmentation from local file
*/
loadFromFile(path: string, config?: any): Promise<LoadedAugmentation>;
/**
* Load multiple augmentations
*/
loadBatch(augmentations: Array<{
source: 'cdn' | 'npm' | 'local';
id: string;
version?: string;
path?: string;
config?: any;
}>): Promise<LoadedAugmentation[]>;
/**
* Unload augmentation
*/
unload(id: string): boolean;
/**
* Get loaded augmentations
*/
getLoaded(): LoadedAugmentation[];
/**
* Check if augmentation is loaded
*/
isLoaded(id: string): boolean;
/**
* Get loaded augmentation
*/
getAugmentation(id: string): BrainyAugmentation | null;
/**
* Load CDN module (browser-specific)
*/
private loadCDNModule;
/**
* Validate augmentation instance
*/
private isValidAugmentation;
/**
* Clear all caches
*/
clearCache(): void;
/**
* Get load statistics
*/
getStats(): {
loaded: number;
totalLoadTime: number;
averageLoadTime: number;
sources: Record<string, number>;
};
}

View file

@ -0,0 +1,337 @@
/**
* Runtime Augmentation Loader
*
* Dynamically loads and registers augmentations at runtime
* Supports CDN loading for browser environments and npm imports for Node.js
*/
/**
* Runtime Augmentation Loader
*
* Enables dynamic loading of augmentations from various sources
*/
export class RuntimeAugmentationLoader {
constructor(options = {}) {
this.options = options;
this.loaded = new Map();
this.cdnCache = new Map();
this.options = {
cdnUrl: options.cdnUrl || 'https://cdn.soulcraft.com/augmentations',
allowUnsafe: options.allowUnsafe || false,
sandbox: options.sandbox || true,
timeout: options.timeout || 30000,
cache: options.cache ?? true
};
}
/**
* Set the augmentation registry
*/
setRegistry(registry) {
this.registry = registry;
}
/**
* Load augmentation from CDN (browser)
*/
async loadFromCDN(id, version = 'latest', config) {
// Check if already loaded
if (this.loaded.has(id)) {
return this.loaded.get(id);
}
const url = `${this.options.cdnUrl}/${id}@${version}/index.js`;
const startTime = Date.now();
try {
// Load module from CDN
const module = await this.loadCDNModule(url);
// Extract augmentation class
const AugmentationClass = module.default || module[Object.keys(module)[0]];
if (!AugmentationClass) {
throw new Error(`No augmentation class found in module ${id}`);
}
// Create instance
const instance = new AugmentationClass(config);
// Validate it's a proper augmentation
if (!this.isValidAugmentation(instance)) {
throw new Error(`Invalid augmentation: ${id}`);
}
// Get manifest
const manifest = instance.getManifest ? instance.getManifest() : {
id,
name: id,
version: version,
description: `Dynamically loaded ${id}`,
category: 'external'
};
const loaded = {
id,
instance,
manifest,
source: 'cdn',
loadTime: Date.now() - startTime
};
// Cache
this.loaded.set(id, loaded);
// Auto-register if registry is set
if (this.registry) {
this.registry.register(instance);
}
return loaded;
}
catch (error) {
throw new Error(`Failed to load augmentation ${id} from CDN: ${error}`);
}
}
/**
* Load augmentation from NPM (Node.js)
*/
async loadFromNPM(packageName, config) {
// Check if already loaded
const id = packageName.replace('@', '').replace('/', '-');
if (this.loaded.has(id)) {
return this.loaded.get(id);
}
const startTime = Date.now();
try {
// Dynamic import
const module = await import(packageName);
// Extract augmentation class
const AugmentationClass = module.default || module[Object.keys(module)[0]];
if (!AugmentationClass) {
throw new Error(`No augmentation class found in package ${packageName}`);
}
// Create instance
const instance = new AugmentationClass(config);
// Validate
if (!this.isValidAugmentation(instance)) {
throw new Error(`Invalid augmentation in package: ${packageName}`);
}
// Get manifest
const manifest = instance.getManifest ? instance.getManifest() : {
id,
name: packageName,
version: 'unknown',
description: `Loaded from ${packageName}`,
category: 'external'
};
const loaded = {
id,
instance,
manifest,
source: 'npm',
loadTime: Date.now() - startTime
};
// Cache
this.loaded.set(id, loaded);
// Auto-register
if (this.registry) {
this.registry.register(instance);
}
return loaded;
}
catch (error) {
throw new Error(`Failed to load augmentation from NPM ${packageName}: ${error}`);
}
}
/**
* Load augmentation from local file
*/
async loadFromFile(path, config) {
const startTime = Date.now();
try {
// Dynamic import
const module = await import(path);
// Extract augmentation class
const AugmentationClass = module.default || module[Object.keys(module)[0]];
if (!AugmentationClass) {
throw new Error(`No augmentation class found in file ${path}`);
}
// Create instance
const instance = new AugmentationClass(config);
// Validate
if (!this.isValidAugmentation(instance)) {
throw new Error(`Invalid augmentation in file: ${path}`);
}
// Extract ID from path
const id = path.split('/').pop()?.replace(/\.(js|ts)$/, '') || 'unknown';
// Get manifest
const manifest = instance.getManifest ? instance.getManifest() : {
id,
name: id,
version: 'local',
description: `Loaded from ${path}`,
category: 'local'
};
const loaded = {
id,
instance,
manifest,
source: 'local',
loadTime: Date.now() - startTime
};
// Cache
this.loaded.set(id, loaded);
// Auto-register
if (this.registry) {
this.registry.register(instance);
}
return loaded;
}
catch (error) {
throw new Error(`Failed to load augmentation from file ${path}: ${error}`);
}
}
/**
* Load multiple augmentations
*/
async loadBatch(augmentations) {
const results = await Promise.allSettled(augmentations.map(aug => {
switch (aug.source) {
case 'cdn':
return this.loadFromCDN(aug.id, aug.version, aug.config);
case 'npm':
return this.loadFromNPM(aug.id, aug.config);
case 'local':
return this.loadFromFile(aug.path || aug.id, aug.config);
default:
return Promise.reject(new Error(`Unknown source: ${aug.source}`));
}
}));
const loaded = [];
const errors = [];
for (const result of results) {
if (result.status === 'fulfilled') {
loaded.push(result.value);
}
else {
errors.push(result.reason.message);
}
}
if (errors.length > 0) {
console.warn('Some augmentations failed to load:', errors);
}
return loaded;
}
/**
* Unload augmentation
*/
unload(id) {
const loaded = this.loaded.get(id);
if (!loaded)
return false;
// Shutdown if possible
if (loaded.instance.shutdown) {
loaded.instance.shutdown();
}
// Remove from registry if set
// Note: Registry doesn't have unregister yet, would need to add
// Remove from cache
this.loaded.delete(id);
return true;
}
/**
* Get loaded augmentations
*/
getLoaded() {
return Array.from(this.loaded.values());
}
/**
* Check if augmentation is loaded
*/
isLoaded(id) {
return this.loaded.has(id);
}
/**
* Get loaded augmentation
*/
getAugmentation(id) {
return this.loaded.get(id)?.instance || null;
}
/**
* Load CDN module (browser-specific)
*/
async loadCDNModule(url) {
// Check cache
if (this.options.cache && this.cdnCache.has(url)) {
return this.cdnCache.get(url);
}
// In browser environment
if (typeof window !== 'undefined') {
return new Promise((resolve, reject) => {
const timeout = setTimeout(() => {
reject(new Error(`Timeout loading ${url}`));
}, this.options.timeout);
// Create script element
const script = document.createElement('script');
script.type = 'module';
script.src = url;
// Handle load
script.onload = async () => {
clearTimeout(timeout);
// The module should register itself on window
const moduleId = url.split('/').pop()?.split('@')[0];
if (moduleId && window[moduleId]) {
const module = window[moduleId];
// Cache
if (this.options.cache) {
this.cdnCache.set(url, module);
}
resolve(module);
}
else {
reject(new Error(`Module not found on window: ${moduleId}`));
}
};
// Handle error
script.onerror = () => {
clearTimeout(timeout);
reject(new Error(`Failed to load script: ${url}`));
};
// Add to document
document.head.appendChild(script);
});
}
else {
// In Node.js, use dynamic import
const module = await import(url);
// Cache
if (this.options.cache) {
this.cdnCache.set(url, module);
}
return module;
}
}
/**
* Validate augmentation instance
*/
isValidAugmentation(instance) {
// Check required properties
return !!(instance.name &&
instance.timing &&
instance.operations &&
instance.priority !== undefined &&
typeof instance.execute === 'function' &&
typeof instance.initialize === 'function');
}
/**
* Clear all caches
*/
clearCache() {
this.cdnCache.clear();
}
/**
* Get load statistics
*/
getStats() {
const loaded = Array.from(this.loaded.values());
const totalLoadTime = loaded.reduce((sum, aug) => sum + aug.loadTime, 0);
const sources = loaded.reduce((acc, aug) => {
acc[aug.source] = (acc[aug.source] || 0) + 1;
return acc;
}, {});
return {
loaded: loaded.length,
totalLoadTime,
averageLoadTime: loaded.length > 0 ? totalLoadTime / loaded.length : 0,
sources
};
}
}
//# sourceMappingURL=runtimeLoader.js.map

File diff suppressed because one or more lines are too long

View file

@ -0,0 +1,130 @@
/**
* Universal Display Augmentation - Intelligent Caching System
*
* High-performance LRU cache with smart eviction and batch optimization
* Designed for minimal memory footprint and maximum hit ratio
*/
import type { ComputedDisplayFields, DisplayAugmentationStats } from './types.js';
/**
* LRU (Least Recently Used) Cache for computed display fields
* Optimized for the display augmentation use case
*/
export declare class DisplayCache {
private cache;
private readonly maxSize;
private stats;
constructor(maxSize?: number);
/**
* Get cached display fields with LRU update
* @param key Cache key
* @returns Cached fields or null if not found
*/
get(key: string): ComputedDisplayFields | null;
/**
* Store computed display fields in cache
* @param key Cache key
* @param fields Computed display fields
* @param computationTime Time taken to compute (for stats)
*/
set(key: string, fields: ComputedDisplayFields, computationTime?: number): void;
/**
* Check if a key exists in cache without affecting LRU order
* @param key Cache key
* @returns True if key exists
*/
has(key: string): boolean;
/**
* Generate cache key from data
* @param id Entity ID (preferred)
* @param data Fallback data for key generation
* @param entityType Type of entity (noun/verb)
* @returns Cache key string
*/
generateKey(id?: string, data?: any, entityType?: 'noun' | 'verb'): string;
/**
* Clear all cached entries
*/
clear(): void;
/**
* Get cache statistics
* @returns Cache performance statistics
*/
getStats(): DisplayAugmentationStats;
/**
* Get current cache size
* @returns Number of cached entries
*/
size(): number;
/**
* Get cache capacity
* @returns Maximum cache size
*/
capacity(): number;
/**
* Evict least recently used entry
*/
private evictOldest;
/**
* Simple hash function for cache keys
* @param str String to hash
* @returns Simple hash number
*/
private simpleHash;
/**
* Optimize cache by removing stale entries
* Called periodically to maintain cache health
*/
optimizeCache(): void;
/**
* Precompute display fields for a batch of entities
* @param entities Array of entities with their compute functions
* @returns Promise resolving when batch is complete
*/
batchPrecompute<T>(entities: Array<{
key: string;
computeFn: () => Promise<ComputedDisplayFields>;
}>): Promise<void>;
}
/**
* Request deduplicator for batch processing
* Prevents duplicate computations for the same data
*/
export declare class RequestDeduplicator {
private pendingRequests;
private readonly batchSize;
constructor(batchSize?: number);
/**
* Deduplicate computation request
* @param key Unique key for the computation
* @param computeFn Function to compute the result
* @returns Promise that resolves to the computed fields
*/
deduplicate(key: string, computeFn: () => Promise<ComputedDisplayFields>): Promise<ComputedDisplayFields>;
/**
* Get number of pending requests
* @returns Number of pending computations
*/
getPendingCount(): number;
/**
* Clear all pending requests
*/
clear(): void;
/**
* Shutdown the deduplicator
*/
shutdown(): void;
}
/**
* Get global display cache instance
* @param maxSize Optional cache size (only used on first call)
* @returns Shared display cache instance
*/
export declare function getGlobalDisplayCache(maxSize?: number): DisplayCache;
/**
* Clear global cache (for testing or memory management)
*/
export declare function clearGlobalDisplayCache(): void;
/**
* Shutdown global cache and cleanup
*/
export declare function shutdownGlobalDisplayCache(): void;

View file

@ -0,0 +1,319 @@
/**
* Universal Display Augmentation - Intelligent Caching System
*
* High-performance LRU cache with smart eviction and batch optimization
* Designed for minimal memory footprint and maximum hit ratio
*/
/**
* LRU (Least Recently Used) Cache for computed display fields
* Optimized for the display augmentation use case
*/
export class DisplayCache {
constructor(maxSize = 1000) {
this.cache = new Map();
this.stats = {
hits: 0,
misses: 0,
evictions: 0,
totalComputations: 0,
totalComputationTime: 0
};
this.maxSize = maxSize;
}
/**
* Get cached display fields with LRU update
* @param key Cache key
* @returns Cached fields or null if not found
*/
get(key) {
const entry = this.cache.get(key);
if (!entry) {
this.stats.misses++;
return null;
}
// Update LRU - move to end
this.cache.delete(key);
entry.lastAccessed = Date.now();
entry.accessCount++;
this.cache.set(key, entry);
this.stats.hits++;
return entry.fields;
}
/**
* Store computed display fields in cache
* @param key Cache key
* @param fields Computed display fields
* @param computationTime Time taken to compute (for stats)
*/
set(key, fields, computationTime) {
// Remove if already exists (for LRU update)
if (this.cache.has(key)) {
this.cache.delete(key);
}
// Create cache entry
const entry = {
fields,
lastAccessed: Date.now(),
accessCount: 1
};
// Add to end (most recently used)
this.cache.set(key, entry);
// Update stats
this.stats.totalComputations++;
if (computationTime) {
this.stats.totalComputationTime += computationTime;
}
// Evict oldest if over capacity
if (this.cache.size > this.maxSize) {
this.evictOldest();
}
}
/**
* Check if a key exists in cache without affecting LRU order
* @param key Cache key
* @returns True if key exists
*/
has(key) {
return this.cache.has(key);
}
/**
* Generate cache key from data
* @param id Entity ID (preferred)
* @param data Fallback data for key generation
* @param entityType Type of entity (noun/verb)
* @returns Cache key string
*/
generateKey(id, data, entityType = 'noun') {
// Use ID if available (most reliable)
if (id) {
return `${entityType}:${id}`;
}
// Generate hash from data
if (data) {
const dataString = JSON.stringify(data, Object.keys(data).sort());
const hash = this.simpleHash(dataString);
return `${entityType}:hash:${hash}`;
}
// Fallback to timestamp (not ideal but prevents crashes)
return `${entityType}:temp:${Date.now()}:${Math.random()}`;
}
/**
* Clear all cached entries
*/
clear() {
this.cache.clear();
this.stats = {
hits: 0,
misses: 0,
evictions: 0,
totalComputations: 0,
totalComputationTime: 0
};
}
/**
* Get cache statistics
* @returns Cache performance statistics
*/
getStats() {
const hitRatio = this.stats.hits + this.stats.misses > 0
? this.stats.hits / (this.stats.hits + this.stats.misses)
: 0;
const avgComputationTime = this.stats.totalComputations > 0
? this.stats.totalComputationTime / this.stats.totalComputations
: 0;
// Analyze cached types for common types statistics
const typeCount = new Map();
let fastestComputation = Infinity;
let slowestComputation = 0;
for (const entry of this.cache.values()) {
const type = entry.fields.type;
typeCount.set(type, (typeCount.get(type) || 0) + 1);
}
const commonTypes = Array.from(typeCount.entries())
.sort(([, a], [, b]) => b - a)
.slice(0, 10)
.map(([type, count]) => ({
type,
count,
percentage: Math.round((count / this.cache.size) * 100)
}));
return {
totalComputations: this.stats.totalComputations,
cacheHitRatio: Math.round(hitRatio * 100) / 100,
averageComputationTime: Math.round(avgComputationTime * 100) / 100,
commonTypes,
performance: {
fastestComputation,
slowestComputation,
totalComputationTime: this.stats.totalComputationTime
}
};
}
/**
* Get current cache size
* @returns Number of cached entries
*/
size() {
return this.cache.size;
}
/**
* Get cache capacity
* @returns Maximum cache size
*/
capacity() {
return this.maxSize;
}
/**
* Evict least recently used entry
*/
evictOldest() {
// First entry is oldest (LRU)
const firstKey = this.cache.keys().next().value;
if (firstKey) {
this.cache.delete(firstKey);
this.stats.evictions++;
}
}
/**
* Simple hash function for cache keys
* @param str String to hash
* @returns Simple hash number
*/
simpleHash(str) {
let hash = 0;
for (let i = 0; i < str.length; i++) {
const char = str.charCodeAt(i);
hash = ((hash << 5) - hash) + char;
hash = hash & hash; // Convert to 32-bit integer
}
return Math.abs(hash);
}
/**
* Optimize cache by removing stale entries
* Called periodically to maintain cache health
*/
optimizeCache() {
const now = Date.now();
const maxAge = 24 * 60 * 60 * 1000; // 24 hours
const minAccessCount = 2; // Minimum access count to keep
const toDelete = [];
for (const [key, entry] of this.cache.entries()) {
// Remove very old entries with low access count
if (now - entry.lastAccessed > maxAge && entry.accessCount < minAccessCount) {
toDelete.push(key);
}
}
// Remove stale entries
for (const key of toDelete) {
this.cache.delete(key);
this.stats.evictions++;
}
}
/**
* Precompute display fields for a batch of entities
* @param entities Array of entities with their compute functions
* @returns Promise resolving when batch is complete
*/
async batchPrecompute(entities) {
const promises = entities.map(async ({ key, computeFn }) => {
if (!this.has(key)) {
const startTime = Date.now();
try {
const fields = await computeFn();
const computationTime = Date.now() - startTime;
this.set(key, fields, computationTime);
}
catch (error) {
console.warn(`Batch precompute failed for key ${key}:`, error);
}
}
});
await Promise.all(promises);
}
}
/**
* Request deduplicator for batch processing
* Prevents duplicate computations for the same data
*/
export class RequestDeduplicator {
constructor(batchSize = 50) {
this.pendingRequests = new Map();
this.batchSize = batchSize;
}
/**
* Deduplicate computation request
* @param key Unique key for the computation
* @param computeFn Function to compute the result
* @returns Promise that resolves to the computed fields
*/
async deduplicate(key, computeFn) {
// Return existing promise if already pending
if (this.pendingRequests.has(key)) {
return this.pendingRequests.get(key);
}
// Create new computation promise
const promise = computeFn().finally(() => {
// Remove from pending when complete
this.pendingRequests.delete(key);
});
this.pendingRequests.set(key, promise);
return promise;
}
/**
* Get number of pending requests
* @returns Number of pending computations
*/
getPendingCount() {
return this.pendingRequests.size;
}
/**
* Clear all pending requests
*/
clear() {
this.pendingRequests.clear();
}
/**
* Shutdown the deduplicator
*/
shutdown() {
this.clear();
}
}
/**
* Global cache instance management
* Provides singleton access to display cache
*/
let globalDisplayCache = null;
/**
* Get global display cache instance
* @param maxSize Optional cache size (only used on first call)
* @returns Shared display cache instance
*/
export function getGlobalDisplayCache(maxSize) {
if (!globalDisplayCache) {
globalDisplayCache = new DisplayCache(maxSize);
// Set up periodic optimization
setInterval(() => {
globalDisplayCache?.optimizeCache();
}, 60 * 60 * 1000); // Every hour
}
return globalDisplayCache;
}
/**
* Clear global cache (for testing or memory management)
*/
export function clearGlobalDisplayCache() {
if (globalDisplayCache) {
globalDisplayCache.clear();
}
}
/**
* Shutdown global cache and cleanup
*/
export function shutdownGlobalDisplayCache() {
if (globalDisplayCache) {
globalDisplayCache.clear();
globalDisplayCache = null;
}
}
//# sourceMappingURL=cache.js.map

File diff suppressed because one or more lines are too long

View file

@ -0,0 +1,52 @@
/**
* Universal Display Augmentation - Smart Field Patterns
*
* Intelligent field detection patterns for mapping user data to display fields
* Uses semantic understanding and common naming conventions
*/
import type { FieldPattern, FieldComputationContext } from './types.js';
/**
* Universal field patterns that work across all data types
* Ordered by confidence level (highest first)
*/
export declare const UNIVERSAL_FIELD_PATTERNS: FieldPattern[];
/**
* Type-specific field patterns for enhanced detection
* Used when we know the specific type of the entity
*/
export declare const TYPE_SPECIFIC_PATTERNS: Record<string, FieldPattern[]>;
/**
* Get field patterns for a specific entity type
* @param entityType The type of entity (noun or verb)
* @param specificType Optional specific noun/verb type
* @returns Array of applicable field patterns
*/
export declare function getFieldPatterns(entityType: 'noun' | 'verb', specificType?: string): FieldPattern[];
/**
* Priority fields for different entity types (for AI analysis)
* Used by the BrainyTypes and neural processing
*/
export declare const TYPE_PRIORITY_FIELDS: Record<string, string[]>;
/**
* Get priority fields for intelligent analysis
* @param entityType The type of entity
* @param specificType Optional specific type
* @returns Array of priority field names
*/
export declare function getPriorityFields(entityType: 'noun' | 'verb', specificType?: string): string[];
/**
* Smart field value extraction with type-aware processing
* @param data The data object to extract from
* @param pattern The field pattern to apply
* @param context The computation context
* @returns The extracted and processed field value
*/
export declare function extractFieldValue(data: any, pattern: FieldPattern, context: FieldComputationContext): any;
/**
* Calculate confidence score for field detection
* @param pattern The field pattern
* @param context The computation context
* @param value The extracted value
* @returns Confidence score (0-1)
*/
export declare function calculateFieldConfidence(pattern: FieldPattern, context: FieldComputationContext, value: any): number;

View file

@ -0,0 +1,393 @@
/**
* Universal Display Augmentation - Smart Field Patterns
*
* Intelligent field detection patterns for mapping user data to display fields
* Uses semantic understanding and common naming conventions
*/
import { NounType } from '../../types/graphTypes.js';
/**
* Universal field patterns that work across all data types
* Ordered by confidence level (highest first)
*/
export const UNIVERSAL_FIELD_PATTERNS = [
// Title/Name Patterns (Highest Priority)
{
fields: ['name', 'title', 'displayName', 'label', 'heading'],
displayField: 'title',
confidence: 0.95
},
{
fields: ['firstName', 'lastName', 'fullName', 'realName'],
displayField: 'title',
confidence: 0.9,
applicableTypes: [NounType.Person, NounType.User],
transform: (value, context) => {
const { metadata } = context;
if (metadata.firstName && metadata.lastName) {
return `${metadata.firstName} ${metadata.lastName}`.trim();
}
return String(value || '');
}
},
{
fields: ['companyName', 'organizationName', 'orgName', 'businessName'],
displayField: 'title',
confidence: 0.9,
applicableTypes: [NounType.Organization]
},
{
fields: ['filename', 'fileName', 'documentTitle', 'docName'],
displayField: 'title',
confidence: 0.85,
applicableTypes: [NounType.Document, NounType.File, NounType.Media]
},
{
fields: ['projectName', 'projectTitle', 'initiative'],
displayField: 'title',
confidence: 0.9,
applicableTypes: [NounType.Project]
},
{
fields: ['taskName', 'taskTitle', 'action', 'todo'],
displayField: 'title',
confidence: 0.85,
applicableTypes: [NounType.Task]
},
{
fields: ['subject', 'topic', 'headline', 'caption'],
displayField: 'title',
confidence: 0.8
},
// Description Patterns (High Priority)
{
fields: ['description', 'summary', 'overview', 'details'],
displayField: 'description',
confidence: 0.9
},
{
fields: ['bio', 'biography', 'profile', 'about'],
displayField: 'description',
confidence: 0.85,
applicableTypes: [NounType.Person, NounType.User]
},
{
fields: ['content', 'text', 'body', 'message'],
displayField: 'description',
confidence: 0.8
},
{
fields: ['abstract', 'excerpt', 'snippet', 'preview'],
displayField: 'description',
confidence: 0.75
},
{
fields: ['notes', 'comments', 'remarks', 'observations'],
displayField: 'description',
confidence: 0.7
},
// Type Patterns (Medium Priority)
{
fields: ['type', 'category', 'classification', 'kind'],
displayField: 'type',
confidence: 0.9
},
{
fields: ['nounType', 'entityType', 'objectType'],
displayField: 'type',
confidence: 0.95
},
{
fields: ['role', 'position', 'jobTitle', 'occupation'],
displayField: 'type',
confidence: 0.8,
applicableTypes: [NounType.Person, NounType.User],
transform: (value) => String(value || 'Person')
},
{
fields: ['industry', 'sector', 'domain', 'field'],
displayField: 'type',
confidence: 0.7,
applicableTypes: [NounType.Organization]
},
// Tag Patterns (Medium Priority)
{
fields: ['tags', 'keywords', 'labels', 'categories'],
displayField: 'tags',
confidence: 0.85
},
{
fields: ['topics', 'subjects', 'themes'],
displayField: 'tags',
confidence: 0.8
}
];
/**
* Type-specific field patterns for enhanced detection
* Used when we know the specific type of the entity
*/
export const TYPE_SPECIFIC_PATTERNS = {
[NounType.Person]: [
{
fields: ['email', 'emailAddress', 'contactEmail'],
displayField: 'description',
confidence: 0.7,
transform: (value, context) => {
const { metadata } = context;
const role = metadata.role || metadata.jobTitle || metadata.position;
const company = metadata.company || metadata.organization || metadata.employer;
const parts = [];
if (role)
parts.push(role);
if (company)
parts.push(`at ${company}`);
if (parts.length === 0 && value)
parts.push(`Contact: ${value}`);
return parts.join(' ') || 'Person';
}
},
{
fields: ['phone', 'phoneNumber', 'mobile', 'cell'],
displayField: 'tags',
confidence: 0.6
}
],
[NounType.Organization]: [
{
fields: ['website', 'url', 'homepage', 'domain'],
displayField: 'description',
confidence: 0.7,
transform: (value, context) => {
const { metadata } = context;
const industry = metadata.industry || metadata.sector;
const location = metadata.location || metadata.city || metadata.country;
const parts = [];
if (industry)
parts.push(industry);
parts.push('organization');
if (location)
parts.push(`in ${location}`);
return parts.join(' ');
}
},
{
fields: ['employees', 'size', 'headcount'],
displayField: 'tags',
confidence: 0.6
}
],
[NounType.Project]: [
{
fields: ['status', 'phase', 'stage', 'state'],
displayField: 'description',
confidence: 0.8,
transform: (value, context) => {
const { metadata } = context;
const status = String(value || 'active').toLowerCase();
const budget = metadata.budget || metadata.cost;
const lead = metadata.lead || metadata.manager || metadata.owner;
const parts = [];
parts.push(status.charAt(0).toUpperCase() + status.slice(1));
if (metadata.description)
parts.push('project');
if (lead)
parts.push(`led by ${lead}`);
if (budget)
parts.push(`($${parseInt(String(budget)).toLocaleString()} budget)`);
return parts.join(' ');
}
}
],
[NounType.Document]: [
{
fields: ['author', 'creator', 'writer'],
displayField: 'description',
confidence: 0.7,
transform: (value, context) => {
const { metadata } = context;
const docType = metadata.type || metadata.category || 'document';
const date = metadata.date || metadata.created || metadata.published;
const parts = [];
if (docType)
parts.push(docType);
if (value)
parts.push(`by ${value}`);
if (date) {
const dateStr = new Date(date).toLocaleDateString();
parts.push(`(${dateStr})`);
}
return parts.join(' ');
}
}
],
[NounType.Task]: [
{
fields: ['priority', 'urgency', 'importance'],
displayField: 'tags',
confidence: 0.7
}
]
};
/**
* Get field patterns for a specific entity type
* @param entityType The type of entity (noun or verb)
* @param specificType Optional specific noun/verb type
* @returns Array of applicable field patterns
*/
export function getFieldPatterns(entityType, specificType) {
const patterns = [...UNIVERSAL_FIELD_PATTERNS];
if (entityType === 'noun' && specificType && TYPE_SPECIFIC_PATTERNS[specificType]) {
patterns.unshift(...TYPE_SPECIFIC_PATTERNS[specificType]);
}
return patterns.sort((a, b) => b.confidence - a.confidence);
}
/**
* Priority fields for different entity types (for AI analysis)
* Used by the BrainyTypes and neural processing
*/
export const TYPE_PRIORITY_FIELDS = {
[NounType.Person]: [
'name', 'firstName', 'lastName', 'fullName', 'displayName',
'email', 'role', 'jobTitle', 'position', 'title',
'bio', 'description', 'about', 'profile',
'company', 'organization', 'employer'
],
[NounType.Organization]: [
'name', 'companyName', 'organizationName', 'title',
'industry', 'sector', 'domain', 'type',
'description', 'about', 'summary',
'location', 'city', 'country', 'headquarters',
'website', 'url'
],
[NounType.Project]: [
'name', 'projectName', 'title', 'projectTitle',
'description', 'summary', 'overview', 'goal',
'status', 'phase', 'stage', 'state',
'lead', 'manager', 'owner', 'team',
'budget', 'timeline', 'deadline'
],
[NounType.Document]: [
'title', 'filename', 'name', 'subject',
'content', 'text', 'body', 'summary',
'author', 'creator', 'writer',
'type', 'category', 'format',
'date', 'created', 'published'
],
[NounType.Task]: [
'title', 'name', 'taskName', 'action',
'description', 'details', 'notes',
'status', 'state', 'priority',
'assignee', 'owner', 'responsible',
'due', 'deadline', 'dueDate'
],
[NounType.Event]: [
'name', 'title', 'eventName',
'description', 'details', 'summary',
'startDate', 'endDate', 'date', 'time',
'location', 'venue', 'address',
'organizer', 'host', 'creator'
],
[NounType.Product]: [
'name', 'productName', 'title',
'description', 'summary', 'features',
'price', 'cost', 'value',
'category', 'type', 'brand',
'manufacturer', 'vendor'
]
};
/**
* Get priority fields for intelligent analysis
* @param entityType The type of entity
* @param specificType Optional specific type
* @returns Array of priority field names
*/
export function getPriorityFields(entityType, specificType) {
if (entityType === 'noun' && specificType && TYPE_PRIORITY_FIELDS[specificType]) {
return TYPE_PRIORITY_FIELDS[specificType];
}
// Default priority fields for any entity
return [
'name', 'title', 'label', 'displayName',
'description', 'summary', 'about', 'details',
'type', 'category', 'kind', 'classification',
'tags', 'keywords', 'labels'
];
}
/**
* Smart field value extraction with type-aware processing
* @param data The data object to extract from
* @param pattern The field pattern to apply
* @param context The computation context
* @returns The extracted and processed field value
*/
export function extractFieldValue(data, pattern, context) {
// Find the first matching field
let value = null;
let matchedField = null;
for (const field of pattern.fields) {
if (data[field] !== undefined && data[field] !== null && data[field] !== '') {
value = data[field];
matchedField = field;
break;
}
}
if (value === null)
return null;
// Apply transformation if provided
if (pattern.transform) {
try {
return pattern.transform(value, context);
}
catch (error) {
console.warn(`Field transformation error for ${matchedField}:`, error);
return String(value);
}
}
// Default processing based on display field type
switch (pattern.displayField) {
case 'title':
case 'description':
case 'type':
return String(value);
case 'tags':
if (Array.isArray(value))
return value;
if (typeof value === 'string') {
return value.split(/[,;]\s*|\s+/).filter(Boolean);
}
return [String(value)];
default:
return value;
}
}
/**
* Calculate confidence score for field detection
* @param pattern The field pattern
* @param context The computation context
* @param value The extracted value
* @returns Confidence score (0-1)
*/
export function calculateFieldConfidence(pattern, context, value) {
let confidence = pattern.confidence;
// Boost confidence if type matches
if (pattern.applicableTypes && context.typeResult) {
if (pattern.applicableTypes.includes(context.typeResult.type)) {
confidence = Math.min(1.0, confidence + 0.1);
}
}
// Reduce confidence for empty or very short values
if (typeof value === 'string') {
if (value.length < 2) {
confidence *= 0.5;
}
else if (value.length < 5) {
confidence *= 0.8;
}
}
// Reduce confidence for generic values
const genericValues = ['unknown', 'n/a', 'null', 'undefined', 'default'];
if (typeof value === 'string' && genericValues.includes(value.toLowerCase())) {
confidence *= 0.3;
}
return Math.max(0, Math.min(1, confidence));
}
//# sourceMappingURL=fieldPatterns.js.map

File diff suppressed because one or more lines are too long

View file

@ -0,0 +1,57 @@
/**
* Universal Display Augmentation - Clean Display
*
* Simple, clean display without icons - focusing on AI-powered
* titles, descriptions, and smart formatting that matches
* Soulcraft's minimal aesthetic
*/
/**
* No icon mappings - clean, minimal approach
* The real value is in AI-generated titles and enhanced descriptions,
* not visual clutter that doesn't align with professional aesthetics
*/
export declare const NOUN_TYPE_ICONS: Record<string, string>;
/**
* No icon mappings for verbs either - focus on clear relationship descriptions
* Human-readable relationship text is more valuable than symbolic representations
*/
export declare const VERB_TYPE_ICONS: Record<string, string>;
/**
* Get icon for a noun type (returns empty string for clean display)
* @param type The noun type
* @returns Empty string (no icons)
*/
export declare function getNounIcon(type: string): string;
/**
* Get icon for a verb type (returns empty string for clean display)
* @param type The verb type
* @returns Empty string (no icons)
*/
export declare function getVerbIcon(type: string): string;
/**
* Get coverage statistics (for backwards compatibility)
* @returns Coverage info showing clean approach
*/
export declare function getIconCoverage(): {
nounTypes: {
total: string;
covered: string;
};
verbTypes: {
total: string;
covered: string;
};
};
/**
* Check if an icon exists for a type (always false for clean display)
* @param type The type to check
* @param entityType Whether it's a noun or verb
* @returns Always false (no icons)
*/
export declare function hasIcon(type: string, entityType?: 'noun' | 'verb'): boolean;
/**
* Get fallback icon (returns empty string for clean display)
* @param entityType The entity type
* @returns Empty string (no fallback icons)
*/
export declare function getFallbackIcon(entityType?: 'noun' | 'verb'): string;

View file

@ -0,0 +1,68 @@
/**
* Universal Display Augmentation - Clean Display
*
* Simple, clean display without icons - focusing on AI-powered
* titles, descriptions, and smart formatting that matches
* Soulcraft's minimal aesthetic
*/
/**
* No icon mappings - clean, minimal approach
* The real value is in AI-generated titles and enhanced descriptions,
* not visual clutter that doesn't align with professional aesthetics
*/
export const NOUN_TYPE_ICONS = {};
/**
* No icon mappings for verbs either - focus on clear relationship descriptions
* Human-readable relationship text is more valuable than symbolic representations
*/
export const VERB_TYPE_ICONS = {};
/**
* Get icon for a noun type (returns empty string for clean display)
* @param type The noun type
* @returns Empty string (no icons)
*/
export function getNounIcon(type) {
return ''; // Clean, no icons
}
/**
* Get icon for a verb type (returns empty string for clean display)
* @param type The verb type
* @returns Empty string (no icons)
*/
export function getVerbIcon(type) {
return ''; // Clean, no icons
}
/**
* Get coverage statistics (for backwards compatibility)
* @returns Coverage info showing clean approach
*/
export function getIconCoverage() {
return {
nounTypes: {
total: 'Clean display - no icons needed',
covered: 'Focus on AI-powered content'
},
verbTypes: {
total: 'Clean display - no icons needed',
covered: 'Focus on relationship descriptions'
}
};
}
/**
* Check if an icon exists for a type (always false for clean display)
* @param type The type to check
* @param entityType Whether it's a noun or verb
* @returns Always false (no icons)
*/
export function hasIcon(type, entityType = 'noun') {
return false; // Clean approach - no icons
}
/**
* Get fallback icon (returns empty string for clean display)
* @param entityType The entity type
* @returns Empty string (no fallback icons)
*/
export function getFallbackIcon(entityType = 'noun') {
return ''; // Clean, minimal display
}
//# sourceMappingURL=iconMappings.js.map

View file

@ -0,0 +1 @@
{"version":3,"file":"iconMappings.js","sourceRoot":"","sources":["../../../src/augmentations/display/iconMappings.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAIH;;;;GAIG;AACH,MAAM,CAAC,MAAM,eAAe,GAA2B,EAAE,CAAA;AAEzD;;;GAGG;AACH,MAAM,CAAC,MAAM,eAAe,GAA2B,EAAE,CAAA;AAEzD;;;;GAIG;AACH,MAAM,UAAU,WAAW,CAAC,IAAY;IACtC,OAAO,EAAE,CAAA,CAAC,kBAAkB;AAC9B,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,WAAW,CAAC,IAAY;IACtC,OAAO,EAAE,CAAA,CAAC,kBAAkB;AAC9B,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,eAAe;IAC7B,OAAO;QACL,SAAS,EAAE;YACT,KAAK,EAAE,iCAAiC;YACxC,OAAO,EAAE,6BAA6B;SACvC;QACD,SAAS,EAAE;YACT,KAAK,EAAE,iCAAiC;YACxC,OAAO,EAAE,oCAAoC;SAC9C;KACF,CAAA;AACH,CAAC;AAED;;;;;GAKG;AACH,MAAM,UAAU,OAAO,CAAC,IAAY,EAAE,aAA8B,MAAM;IACxE,OAAO,KAAK,CAAA,CAAC,4BAA4B;AAC3C,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,eAAe,CAAC,aAA8B,MAAM;IAClE,OAAO,EAAE,CAAA,CAAC,yBAAyB;AACrC,CAAC"}

View file

@ -0,0 +1,109 @@
/**
* Universal Display Augmentation - Intelligent Computation Engine
*
* Leverages existing Brainy AI infrastructure for intelligent field computation:
* - BrainyTypes for semantic type detection
* - Neural Import patterns for field analysis
* - JSON processing utilities for field extraction
* - Existing NounType/VerbType taxonomy (31+40 types)
*/
import type { ComputedDisplayFields, DisplayConfig } from './types.js';
import type { GraphVerb } from '../../coreTypes.js';
/**
* Intelligent field computation engine
* Coordinates AI-powered analysis with fallback heuristics
*/
export declare class IntelligentComputationEngine {
private typeMatcher;
protected config: DisplayConfig;
private initialized;
constructor(config: DisplayConfig);
/**
* Initialize the computation engine with AI components
*/
initialize(): Promise<void>;
/**
* Compute display fields for a noun using AI-first approach
* @param data The noun data/metadata
* @param id Optional noun ID
* @returns Computed display fields
*/
computeNounDisplay(data: any, id?: string): Promise<ComputedDisplayFields>;
/**
* Compute display fields for a verb using AI-first approach
* @param verb The verb/relationship data
* @returns Computed display fields
*/
computeVerbDisplay(verb: GraphVerb): Promise<ComputedDisplayFields>;
/**
* AI-powered computation using your existing BrainyTypes
* @param data Entity data/metadata
* @param entityType Type of entity (noun/verb)
* @param options Additional options
* @returns AI-computed display fields
*/
private computeWithAI;
/**
* AI-powered verb computation using relationship analysis
* @param verb The verb/relationship
* @returns AI-computed display fields
*/
private computeVerbWithAI;
/**
* Heuristic computation when AI is unavailable
* @param data Entity data
* @param entityType Type of entity
* @param options Additional options
* @returns Heuristically computed display fields
*/
private computeWithHeuristics;
/**
* Compute intelligent title using AI insights and your field extraction
* @param context Computation context with AI results
* @returns Computed title
*/
private computeIntelligentTitle;
/**
* Compute intelligent description using AI insights and context
* @param context Computation context
* @returns Enhanced description
*/
private computeIntelligentDescription;
/**
* Compute intelligent tags using type analysis
* @param context Computation context
* @returns Generated tags array
*/
private computeIntelligentTags;
/**
* Compute verb title (relationship summary)
* @param context Verb computation context
* @returns Verb title
*/
private computeVerbTitle;
/**
* Create minimal display for error cases
* @param data Entity data
* @param entityType Entity type
* @returns Minimal display fields
*/
private createMinimalDisplay;
private computePersonTitle;
private computeOrganizationTitle;
private computeProjectTitle;
private computeDocumentTitle;
private extractBestTitle;
private createContextAwareDescription;
private extractExplicitTags;
private generateSemanticTags;
private getReadableVerbPhrase;
private computeVerbDescription;
private computeVerbTags;
private computeHumanReadableRelationship;
private detectTypeHeuristically;
private extractFieldWithPatterns;
/**
* Shutdown the computation engine
*/
shutdown(): Promise<void>;
}

View file

@ -0,0 +1,462 @@
/**
* Universal Display Augmentation - Intelligent Computation Engine
*
* Leverages existing Brainy AI infrastructure for intelligent field computation:
* - BrainyTypes for semantic type detection
* - Neural Import patterns for field analysis
* - JSON processing utilities for field extraction
* - Existing NounType/VerbType taxonomy (31+40 types)
*/
import { getBrainyTypes } from '../typeMatching/brainyTypes.js';
import { getFieldPatterns, getPriorityFields } from './fieldPatterns.js';
import { prepareJsonForVectorization } from '../../utils/jsonProcessing.js';
import { NounType, VerbType } from '../../types/graphTypes.js';
/**
* Intelligent field computation engine
* Coordinates AI-powered analysis with fallback heuristics
*/
export class IntelligentComputationEngine {
constructor(config) {
this.typeMatcher = null;
this.initialized = false;
this.config = config;
}
/**
* Initialize the computation engine with AI components
*/
async initialize() {
if (this.initialized)
return;
try {
// 🧠 LEVERAGE YOUR EXISTING AI INFRASTRUCTURE
this.typeMatcher = await getBrainyTypes();
if (this.typeMatcher) {
console.log('🎨 Display computation engine initialized with AI intelligence');
}
else {
console.warn('🎨 Display computation engine running in basic mode (AI unavailable)');
}
}
catch (error) {
console.warn('🎨 AI initialization failed, using heuristic fallback:', error);
}
this.initialized = true;
}
/**
* Compute display fields for a noun using AI-first approach
* @param data The noun data/metadata
* @param id Optional noun ID
* @returns Computed display fields
*/
async computeNounDisplay(data, id) {
const startTime = Date.now();
try {
// 🟢 PRIMARY PATH: Use your existing AI intelligence
if (this.typeMatcher) {
return await this.computeWithAI(data, 'noun', { id });
}
// 🟡 FALLBACK PATH: Use heuristic patterns
return await this.computeWithHeuristics(data, 'noun', { id });
}
catch (error) {
console.warn('Display computation failed, using minimal fallback:', error);
return this.createMinimalDisplay(data, 'noun');
}
finally {
const computationTime = Date.now() - startTime;
if (this.config.debugMode) {
console.log(`Display computation took ${computationTime}ms`);
}
}
}
/**
* Compute display fields for a verb using AI-first approach
* @param verb The verb/relationship data
* @returns Computed display fields
*/
async computeVerbDisplay(verb) {
const startTime = Date.now();
try {
// 🟢 PRIMARY PATH: Use your existing AI for verb analysis
if (this.typeMatcher) {
return await this.computeVerbWithAI(verb);
}
// 🟡 FALLBACK PATH: Use heuristic patterns for verbs
return await this.computeWithHeuristics(verb, 'verb');
}
catch (error) {
console.warn('Verb display computation failed, using minimal fallback:', error);
return this.createMinimalDisplay(verb, 'verb');
}
finally {
const computationTime = Date.now() - startTime;
if (this.config.debugMode) {
console.log(`Verb display computation took ${computationTime}ms`);
}
}
}
/**
* AI-powered computation using your existing BrainyTypes
* @param data Entity data/metadata
* @param entityType Type of entity (noun/verb)
* @param options Additional options
* @returns AI-computed display fields
*/
async computeWithAI(data, entityType, options = {}) {
// 🧠 USE YOUR EXISTING TYPE DETECTION AI
const typeResult = await this.typeMatcher.matchNounType(data);
// Create computation context
const context = {
data,
metadata: data,
typeResult,
config: this.config,
entityType
};
// 🟢 INTELLIGENT FIELD EXTRACTION using your patterns + AI insights
const displayFields = {
title: await this.computeIntelligentTitle(context),
description: await this.computeIntelligentDescription(context),
type: typeResult.type,
tags: await this.computeIntelligentTags(context),
confidence: typeResult.confidence,
reasoning: this.config.debugMode ? typeResult.reasoning : undefined,
alternatives: this.config.debugMode ? typeResult.alternatives : undefined,
computedAt: Date.now(),
version: '1.0.0'
};
return displayFields;
}
/**
* AI-powered verb computation using relationship analysis
* @param verb The verb/relationship
* @returns AI-computed display fields
*/
async computeVerbWithAI(verb) {
// 🧠 USE YOUR EXISTING VERB TYPE DETECTION
const typeResult = await this.typeMatcher.matchVerbType(verb, 0.7);
// Create verb computation context
const context = {
data: verb,
metadata: verb.metadata || {},
typeResult,
config: this.config,
entityType: 'verb',
verbContext: {
sourceId: verb.sourceId,
targetId: verb.targetId,
verbType: verb.type
}
};
// 🟢 INTELLIGENT VERB DISPLAY COMPUTATION
const displayFields = {
title: await this.computeVerbTitle(context),
description: await this.computeVerbDescription(context),
type: typeResult.type,
tags: await this.computeVerbTags(context),
relationship: await this.computeHumanReadableRelationship(context),
confidence: typeResult.confidence,
reasoning: this.config.debugMode ? typeResult.reasoning : undefined,
alternatives: this.config.debugMode ? typeResult.alternatives : undefined,
computedAt: Date.now(),
version: '1.0.0'
};
return displayFields;
}
/**
* Heuristic computation when AI is unavailable
* @param data Entity data
* @param entityType Type of entity
* @param options Additional options
* @returns Heuristically computed display fields
*/
async computeWithHeuristics(data, entityType, options = {}) {
// Use basic type detection
const detectedType = this.detectTypeHeuristically(data, entityType);
const typeResult = {
type: detectedType,
confidence: 0.6, // Lower confidence for heuristics
reasoning: 'Heuristic detection (AI unavailable)',
alternatives: []
};
const context = {
data,
metadata: data,
typeResult: typeResult,
config: this.config,
entityType
};
// Use pattern-based field extraction
const patterns = getFieldPatterns(entityType, detectedType);
return {
title: this.extractFieldWithPatterns(data, patterns, 'title') || 'Untitled',
description: this.extractFieldWithPatterns(data, patterns, 'description') || 'No description',
type: detectedType,
tags: this.extractFieldWithPatterns(data, patterns, 'tags') || [],
confidence: typeResult.confidence,
reasoning: this.config.debugMode ? typeResult.reasoning : undefined,
computedAt: Date.now(),
version: '1.0.0'
};
}
/**
* Compute intelligent title using AI insights and your field extraction
* @param context Computation context with AI results
* @returns Computed title
*/
async computeIntelligentTitle(context) {
const { data, typeResult } = context;
// 🟢 USE TYPE-SPECIFIC LOGIC based on your NounType taxonomy
switch (typeResult?.type) {
case NounType.Person:
return this.computePersonTitle(data);
case NounType.Organization:
return this.computeOrganizationTitle(data);
case NounType.Project:
return this.computeProjectTitle(data);
case NounType.Document:
return this.computeDocumentTitle(data);
default:
// 🟢 LEVERAGE YOUR JSON PROCESSING for unknown types
return this.extractBestTitle(data, typeResult?.type);
}
}
/**
* Compute intelligent description using AI insights and context
* @param context Computation context
* @returns Enhanced description
*/
async computeIntelligentDescription(context) {
const { data, typeResult } = context;
// 🟢 USE YOUR EXISTING JSON PROCESSING for vectorization-quality text
const priorityFields = getPriorityFields('noun', typeResult?.type);
const enhancedText = prepareJsonForVectorization(data, {
priorityFields,
includeFieldNames: false,
maxDepth: 2
});
// Create context-aware description based on type
return this.createContextAwareDescription(data, typeResult, enhancedText);
}
/**
* Compute intelligent tags using type analysis
* @param context Computation context
* @returns Generated tags array
*/
async computeIntelligentTags(context) {
const { data, typeResult } = context;
const tags = [];
// Add type-based tag
if (typeResult?.type) {
tags.push(typeResult.type.toLowerCase());
}
// Extract explicit tags from data
const explicitTags = this.extractExplicitTags(data);
tags.push(...explicitTags);
// Add semantic tags based on AI analysis
if (typeResult && this.typeMatcher) {
const semanticTags = this.generateSemanticTags(data, typeResult);
tags.push(...semanticTags);
}
// Remove duplicates and return
return [...new Set(tags.filter(Boolean))];
}
/**
* Compute verb title (relationship summary)
* @param context Verb computation context
* @returns Verb title
*/
async computeVerbTitle(context) {
const { verbContext, typeResult } = context;
if (!verbContext)
return 'Relationship';
const { sourceId, targetId } = verbContext;
const relationshipType = typeResult?.type || 'RelatedTo';
// Try to get readable names for source and target
// This could be enhanced to actually resolve the entities
return `${sourceId} ${this.getReadableVerbPhrase(relationshipType)} ${targetId}`;
}
/**
* Create minimal display for error cases
* @param data Entity data
* @param entityType Entity type
* @returns Minimal display fields
*/
createMinimalDisplay(data, entityType) {
return {
title: data.name || data.title || data.id || 'Untitled',
description: data.description || data.summary || 'No description available',
type: entityType === 'noun' ? 'Item' : 'RelatedTo',
tags: [],
confidence: 0.1, // Very low confidence for fallback
computedAt: Date.now(),
version: '1.0.0'
};
}
// Helper methods for specific noun types
computePersonTitle(data) {
if (data.firstName && data.lastName) {
return `${data.firstName} ${data.lastName}`.trim();
}
return data.name || data.fullName || data.displayName || data.firstName || data.lastName || 'Person';
}
computeOrganizationTitle(data) {
return data.name || data.companyName || data.organizationName || data.title || 'Organization';
}
computeProjectTitle(data) {
return data.name || data.projectName || data.title || data.projectTitle || 'Project';
}
computeDocumentTitle(data) {
return data.title || data.filename || data.name || data.subject || 'Document';
}
extractBestTitle(data, type) {
const titleFields = ['name', 'title', 'displayName', 'label', 'subject', 'heading'];
for (const field of titleFields) {
if (data[field])
return String(data[field]);
}
return data.id || Object.keys(data)[0] || 'Untitled';
}
createContextAwareDescription(data, typeResult, enhancedText) {
// Start with basic description fields
const basicDesc = data.description || data.summary || data.about || data.details;
if (basicDesc)
return String(basicDesc);
// Use enhanced text from JSON processing
if (enhancedText && enhancedText.length > 10) {
return enhancedText.substring(0, 200) + (enhancedText.length > 200 ? '...' : '');
}
// Generate from available fields
const parts = [];
if (data.role)
parts.push(data.role);
if (data.company)
parts.push(`at ${data.company}`);
if (data.location)
parts.push(`in ${data.location}`);
return parts.length > 0 ? parts.join(' ') : 'No description available';
}
extractExplicitTags(data) {
const tagFields = ['tags', 'keywords', 'labels', 'categories', 'topics'];
for (const field of tagFields) {
if (data[field]) {
if (Array.isArray(data[field])) {
return data[field].map(String).filter(Boolean);
}
if (typeof data[field] === 'string') {
return data[field].split(/[,;]\s*|\s+/).filter(Boolean);
}
}
}
return [];
}
generateSemanticTags(data, typeResult) {
const tags = [];
// Add confidence-based tags
if (typeResult.confidence > 0.9)
tags.push('verified');
else if (typeResult.confidence < 0.7)
tags.push('uncertain');
// Add type-specific semantic tags
if (data.status)
tags.push(String(data.status).toLowerCase());
if (data.priority)
tags.push(String(data.priority).toLowerCase());
if (data.category)
tags.push(String(data.category).toLowerCase());
return tags;
}
getReadableVerbPhrase(verbType) {
const verbPhrases = {
[VerbType.WorksWith]: 'works with',
[VerbType.MemberOf]: 'is member of',
[VerbType.ReportsTo]: 'reports to',
[VerbType.CreatedBy]: 'created by',
[VerbType.Owns]: 'owns',
[VerbType.LocatedAt]: 'located at',
[VerbType.Likes]: 'likes',
[VerbType.Follows]: 'follows',
[VerbType.Supervises]: 'supervises'
};
return verbPhrases[verbType] || 'related to';
}
async computeVerbDescription(context) {
const { data, verbContext, typeResult } = context;
if (data.description)
return String(data.description);
// Generate contextual description for relationship
if (verbContext && typeResult) {
const parts = [];
const relationshipPhrase = this.getReadableVerbPhrase(typeResult.type);
if (data.role)
parts.push(`Role: ${data.role}`);
if (data.startDate)
parts.push(`Since: ${new Date(data.startDate).toLocaleDateString()}`);
if (data.department)
parts.push(`Department: ${data.department}`);
return parts.length > 0
? `${relationshipPhrase} - ${parts.join(', ')}`
: `${relationshipPhrase} relationship`;
}
return 'Relationship';
}
async computeVerbTags(context) {
const { data, typeResult } = context;
const tags = ['relationship'];
if (typeResult?.type) {
tags.push(typeResult.type.toLowerCase());
}
// Add relationship-specific tags
if (data.status)
tags.push(String(data.status).toLowerCase());
if (data.type)
tags.push(String(data.type).toLowerCase());
return [...new Set(tags)];
}
async computeHumanReadableRelationship(context) {
const { verbContext, typeResult } = context;
if (!verbContext || !typeResult)
return 'Related';
const { sourceId, targetId } = verbContext;
const phrase = this.getReadableVerbPhrase(typeResult.type);
return `${sourceId} ${phrase} ${targetId}`;
}
detectTypeHeuristically(data, entityType) {
if (entityType === 'verb')
return VerbType.RelatedTo;
// Basic heuristics for noun types
if (data.firstName || data.lastName || data.email)
return NounType.Person;
if (data.companyName || data.organization)
return NounType.Organization;
if (data.filename || data.fileType)
return NounType.Document;
if (data.projectName || data.initiative)
return NounType.Project;
if (data.taskName || data.todo)
return NounType.Task;
if (data.startDate || data.endDate)
return NounType.Event;
return 'Item'; // Generic fallback
}
extractFieldWithPatterns(data, patterns, fieldType) {
const relevantPatterns = patterns.filter(p => p.displayField === fieldType);
for (const pattern of relevantPatterns) {
for (const field of pattern.fields) {
if (data[field]) {
return pattern.transform ? pattern.transform(data[field], { data, config: this.config }) : data[field];
}
}
}
return null;
}
/**
* Shutdown the computation engine
*/
async shutdown() {
// Cleanup if needed
this.typeMatcher = null;
this.initialized = false;
}
}
//# sourceMappingURL=intelligentComputation.js.map

File diff suppressed because one or more lines are too long

View file

@ -0,0 +1,203 @@
/**
* Universal Display Augmentation - Type Definitions
*
* Clean TypeScript interfaces for the display augmentation system
*/
import type { VectorDocument, GraphVerb } from '../../coreTypes.js';
/**
* Configuration interface for the Universal Display Augmentation
*/
export interface DisplayConfig {
/** Enable/disable the augmentation */
enabled: boolean;
/** LRU cache size for computed display fields */
cacheSize: number;
/** Use lazy computation (recommended for performance) */
lazyComputation: boolean;
/** Batch processing size for multiple requests */
batchSize: number;
/** Minimum confidence threshold for AI type detection */
confidenceThreshold: number;
/** Custom field mappings (userField -> displayField) */
customFieldMappings: Record<string, string>;
/** Type-specific priority fields for intelligent detection */
priorityFields: Record<string, string[]>;
/** Enable debug mode with reasoning output */
debugMode: boolean;
}
/**
* Computed display fields for any noun or verb
*/
export interface ComputedDisplayFields {
/** Primary display name (AI-detected best field combination) */
title: string;
/** Enhanced description with context awareness */
description: string;
/** Human-readable type name */
type: string;
/** Generated display tags for categorization */
tags: string[];
/** For verbs: human-readable relationship description */
relationship?: string;
/** AI confidence score (0-1) */
confidence: number;
/** Explanation of type detection reasoning (debug mode) */
reasoning?: string;
/** Alternative type suggestions with confidence scores */
alternatives?: Array<{
type: string;
confidence: number;
}>;
/** Timestamp when fields were computed */
computedAt: number;
/** Version of augmentation that computed these fields */
version: string;
}
/**
* Cache entry for computed display fields
*/
export interface DisplayCacheEntry {
fields: ComputedDisplayFields;
lastAccessed: number;
accessCount: number;
}
/**
* Field computation context passed to computation functions
*/
export interface FieldComputationContext {
/** The original data object */
data: any;
/** Metadata associated with the object */
metadata: any;
/** Type detection result from AI */
typeResult?: TypeMatchResult;
/** Display configuration */
config: DisplayConfig;
/** Whether this is a noun or verb */
entityType: 'noun' | 'verb';
/** For verbs: source and target information */
verbContext?: {
sourceId: string;
targetId: string;
verbType?: string;
};
}
/**
* Type matching result from BrainyTypes
*/
export interface TypeMatchResult {
type: string;
confidence: number;
reasoning: string;
alternatives: Array<{
type: string;
confidence: number;
}>;
}
/**
* Enhanced VectorDocument with display capabilities
*/
export interface EnhancedVectorDocument<T = any> extends VectorDocument<T> {
/**
* Get computed display field(s)
* @param field Optional specific field name
* @returns Single field value or all display fields
*/
getDisplay(): Promise<ComputedDisplayFields>;
getDisplay(field: keyof ComputedDisplayFields): Promise<any>;
/**
* Get available fields for a specific augmentation namespace
* @param namespace The augmentation namespace (e.g., 'display')
* @returns Array of available field names
*/
getAvailableFields(namespace: string): string[];
/**
* Get available augmentation namespaces
* @returns Array of available augmentation names
*/
getAvailableAugmentations(): string[];
/**
* Debug exploration of all computed fields
*/
explore(): Promise<void>;
}
/**
* Enhanced GraphVerb with display capabilities
*/
export interface EnhancedGraphVerb extends GraphVerb {
/**
* Get computed display field(s) for relationships
* @param field Optional specific field name
* @returns Single field value or all display fields
*/
getDisplay(): Promise<ComputedDisplayFields>;
getDisplay(field: keyof ComputedDisplayFields): Promise<any>;
/**
* Get available fields for a specific augmentation namespace
* @param namespace The augmentation namespace (e.g., 'display')
* @returns Array of available field names
*/
getAvailableFields(namespace: string): string[];
}
/**
* Batch computation request for performance optimization
*/
export interface BatchComputationRequest {
id: string;
data: any;
metadata: any;
entityType: 'noun' | 'verb';
verbContext?: {
sourceId: string;
targetId: string;
verbType?: string;
};
}
/**
* Batch computation result
*/
export interface BatchComputationResult {
id: string;
fields: ComputedDisplayFields;
error?: string;
}
/**
* Field pattern for intelligent field detection
*/
export interface FieldPattern {
/** Field names that match this pattern */
fields: string[];
/** Target display field name */
displayField: keyof ComputedDisplayFields;
/** Confidence score for this pattern match */
confidence: number;
/** Optional: specific noun/verb types this applies to */
applicableTypes?: string[];
/** Optional: transformation function for the field value */
transform?: (value: any, context: FieldComputationContext) => string;
}
/**
* Statistics for the display augmentation
*/
export interface DisplayAugmentationStats {
/** Total number of computations performed */
totalComputations: number;
/** Cache hit ratio */
cacheHitRatio: number;
/** Average computation time in milliseconds */
averageComputationTime: number;
/** Type detection accuracy (when ground truth available) */
typeDetectionAccuracy?: number;
/** Most commonly detected types */
commonTypes: Array<{
type: string;
count: number;
percentage: number;
}>;
/** Performance metrics */
performance: {
fastestComputation: number;
slowestComputation: number;
totalComputationTime: number;
};
}

View file

@ -0,0 +1,7 @@
/**
* Universal Display Augmentation - Type Definitions
*
* Clean TypeScript interfaces for the display augmentation system
*/
export {};
//# sourceMappingURL=types.js.map

View file

@ -0,0 +1 @@
{"version":3,"file":"types.js","sourceRoot":"","sources":["../../../src/augmentations/display/types.ts"],"names":[],"mappings":"AAAA;;;;GAIG"}

View file

@ -0,0 +1,130 @@
/**
* Entity Registry Augmentation
* Fast external-ID to internal-UUID mapping for streaming data processing
* Works in write-only mode for high-performance deduplication
*/
import { BaseAugmentation, AugmentationContext } from './brainyAugmentation.js';
export interface EntityRegistryConfig {
/**
* Maximum number of entries to keep in memory cache
* Default: 100,000 entries
*/
maxCacheSize?: number;
/**
* Time to live for cache entries in milliseconds
* Default: 300,000 (5 minutes)
*/
cacheTTL?: number;
/**
* Fields to index for fast lookup
* Default: ['did', 'handle', 'uri', 'id', 'external_id']
*/
indexedFields?: string[];
/**
* Persistence strategy
* memory: Keep only in memory (fast, but lost on restart)
* storage: Persist to storage (survives restarts)
* hybrid: Memory + periodic storage sync
*/
persistence?: 'memory' | 'storage' | 'hybrid';
/**
* How often to sync memory cache to storage (hybrid mode)
* Default: 30000 (30 seconds)
*/
syncInterval?: number;
}
export interface EntityMapping {
externalId: string;
field: string;
brainyId: string;
nounType: string;
lastAccessed: number;
metadata?: any;
}
/**
* High-performance entity registry for external ID to Brainy UUID mapping
* Optimized for streaming data scenarios like Bluesky firehose processing
*/
export declare class EntityRegistryAugmentation extends BaseAugmentation {
readonly metadata: "readonly";
readonly name = "entity-registry";
readonly description = "Fast external-ID to internal-UUID mapping for streaming data";
readonly timing: 'before' | 'after' | 'around' | 'replace';
readonly operations: ("add" | "addNoun" | "addVerb")[];
readonly priority = 90;
protected config: Required<EntityRegistryConfig>;
private memoryIndex;
private fieldIndices;
private syncTimer?;
private brain?;
private storage?;
private cacheHits;
private cacheMisses;
constructor(config?: EntityRegistryConfig);
initialize(context: AugmentationContext): Promise<void>;
shutdown(): Promise<void>;
/**
* Execute the augmentation
*/
execute<T = any>(operation: string, params: any, next: () => Promise<T>): Promise<T>;
/**
* Register a new entity mapping
*/
registerEntity(brainyId: string, metadata: any, nounType: string): Promise<void>;
/**
* Fast lookup: external ID Brainy UUID
* Works in write-only mode without search indexes
*/
lookupEntity(field: string, value: string): Promise<string | null>;
/**
* Batch lookup for multiple external IDs
*/
lookupBatch(lookups: Array<{
field: string;
value: string;
}>): Promise<Map<string, string | null>>;
/**
* Check if entity exists (faster than lookupEntity for existence checks)
*/
hasEntity(field: string, value: string): Promise<boolean>;
/**
* Get all entities by field (e.g., all DIDs)
*/
getEntitiesByField(field: string): Promise<string[]>;
/**
* Get registry statistics
*/
getStats(): {
totalMappings: number;
fieldCounts: Record<string, number>;
cacheHitRate: number;
memoryUsage: number;
};
/**
* Clear all cached mappings
*/
clearCache(): Promise<void>;
/**
* Check if an ID looks like it could be an external ID for a specific field
*/
private looksLikeExternalId;
private extractFieldValue;
private evictOldEntries;
private loadFromStorage;
private syncToStorage;
private loadFromStorageByField;
private loadBatchFromStorage;
private estimateMemoryUsage;
}
export declare class AutoRegisterEntitiesAugmentation extends BaseAugmentation {
readonly metadata: "readonly";
readonly name = "auto-register-entities";
readonly description = "Automatically register entities in the registry when added";
readonly timing: 'before' | 'after' | 'around' | 'replace';
readonly operations: ("add" | "addNoun" | "addVerb")[];
readonly priority = 85;
private registry?;
private brain?;
initialize(context: AugmentationContext): Promise<void>;
execute<T = any>(operation: string, params: any, next: () => Promise<T>): Promise<T>;
}

View file

@ -0,0 +1,392 @@
/**
* Entity Registry Augmentation
* Fast external-ID to internal-UUID mapping for streaming data processing
* Works in write-only mode for high-performance deduplication
*/
import { BaseAugmentation } from './brainyAugmentation.js';
/**
* High-performance entity registry for external ID to Brainy UUID mapping
* Optimized for streaming data scenarios like Bluesky firehose processing
*/
export class EntityRegistryAugmentation extends BaseAugmentation {
constructor(config = {}) {
super();
this.metadata = 'readonly'; // Reads metadata to register entities
this.name = 'entity-registry';
this.description = 'Fast external-ID to internal-UUID mapping for streaming data';
this.timing = 'before';
this.operations = ['add', 'addNoun', 'addVerb'];
this.priority = 90; // High priority for entity registration
this.memoryIndex = new Map();
this.fieldIndices = new Map(); // field -> value -> brainyId
this.cacheHits = 0;
this.cacheMisses = 0;
this.config = {
maxCacheSize: config.maxCacheSize ?? 100000,
cacheTTL: config.cacheTTL ?? 300000, // 5 minutes
indexedFields: config.indexedFields ?? ['did', 'handle', 'uri', 'id', 'external_id'],
persistence: config.persistence ?? 'hybrid',
syncInterval: config.syncInterval ?? 30000 // 30 seconds
};
// Initialize field indices
for (const field of this.config.indexedFields) {
this.fieldIndices.set(field, new Map());
}
}
async initialize(context) {
this.brain = context.brain;
this.storage = context.storage;
// Load existing mappings from storage
if (this.config.persistence === 'storage' || this.config.persistence === 'hybrid') {
await this.loadFromStorage();
}
// Start sync timer for hybrid mode
if (this.config.persistence === 'hybrid') {
this.syncTimer = setInterval(() => {
this.syncToStorage().catch(console.error);
}, this.config.syncInterval);
}
console.log(`🔍 EntityRegistry initialized: ${this.memoryIndex.size} cached mappings`);
}
async shutdown() {
// Final sync before shutdown
if (this.config.persistence === 'storage' || this.config.persistence === 'hybrid') {
await this.syncToStorage();
}
if (this.syncTimer) {
clearInterval(this.syncTimer);
}
}
/**
* Execute the augmentation
*/
async execute(operation, params, next) {
console.log(`🔍 [EntityRegistry] execute called: operation=${operation}`);
// For add operations, check for duplicates first
if (operation === 'add' || operation === 'addNoun') {
const metadata = params.metadata || {};
// Check if entity already exists
for (const field of this.config.indexedFields) {
const value = this.extractFieldValue(metadata, field);
if (value) {
const existingId = await this.lookupEntity(field, value);
if (existingId) {
// Entity already exists, return the existing one
console.log(`🔍 Duplicate detected: ${field}:${value}${existingId}`);
return { id: existingId, duplicate: true };
}
}
}
}
// For addVerb operations, resolve external IDs to internal UUIDs
if (operation === 'addVerb') {
const sourceId = params.sourceId;
const targetId = params.targetId;
// Try to resolve source and target IDs if they look like external IDs
for (const field of this.config.indexedFields) {
// Check if sourceId matches an external ID pattern
if (typeof sourceId === 'string' && this.looksLikeExternalId(sourceId, field)) {
const resolvedSourceId = await this.lookupEntity(field, sourceId);
if (resolvedSourceId) {
console.log(`🔍 [EntityRegistry] Resolved source: ${sourceId}${resolvedSourceId}`);
params.sourceId = resolvedSourceId;
}
}
// Check if targetId matches an external ID pattern
if (typeof targetId === 'string' && this.looksLikeExternalId(targetId, field)) {
const resolvedTargetId = await this.lookupEntity(field, targetId);
if (resolvedTargetId) {
console.log(`🔍 [EntityRegistry] Resolved target: ${targetId}${resolvedTargetId}`);
params.targetId = resolvedTargetId;
}
}
}
}
// Proceed with the operation
const result = await next();
// Register the entity after successful add
if ((operation === 'add' || operation === 'addNoun' || operation === 'addVerb') && result) {
// Handle both formats: string UUID or object with id property
const brainyId = typeof result === 'string' ? result : result.id;
if (brainyId) {
const metadata = params.metadata || {};
const nounType = params.nounType || 'default';
console.log(`🔍 [EntityRegistry] Registering entity: ${brainyId}`);
await this.registerEntity(brainyId, metadata, nounType);
console.log(`✅ [EntityRegistry] Entity registered successfully`);
}
}
return result;
}
/**
* Register a new entity mapping
*/
async registerEntity(brainyId, metadata, nounType) {
const now = Date.now();
// Extract indexed fields from metadata
for (const field of this.config.indexedFields) {
const value = this.extractFieldValue(metadata, field);
if (value) {
const key = `${field}:${value}`;
// Add to memory index
const mapping = {
externalId: value,
field,
brainyId,
nounType,
lastAccessed: now,
metadata
};
this.memoryIndex.set(key, mapping);
// Add to field-specific index
const fieldIndex = this.fieldIndices.get(field);
if (fieldIndex) {
fieldIndex.set(value, brainyId);
}
}
}
// Enforce cache size limit (LRU eviction)
await this.evictOldEntries();
}
/**
* Fast lookup: external ID Brainy UUID
* Works in write-only mode without search indexes
*/
async lookupEntity(field, value) {
const key = `${field}:${value}`;
const cached = this.memoryIndex.get(key);
if (cached) {
// Update last accessed time
cached.lastAccessed = Date.now();
this.cacheHits++;
return cached.brainyId;
}
this.cacheMisses++;
// If not in cache and using storage persistence, try loading from storage
if (this.config.persistence === 'storage' || this.config.persistence === 'hybrid') {
const stored = await this.loadFromStorageByField(field, value);
if (stored) {
// Add to memory cache
this.memoryIndex.set(key, stored);
const fieldIndex = this.fieldIndices.get(field);
if (fieldIndex) {
fieldIndex.set(value, stored.brainyId);
}
return stored.brainyId;
}
}
return null;
}
/**
* Batch lookup for multiple external IDs
*/
async lookupBatch(lookups) {
const results = new Map();
const missingKeys = [];
// Check memory cache first
for (const lookup of lookups) {
const key = `${lookup.field}:${lookup.value}`;
const cached = this.memoryIndex.get(key);
if (cached) {
cached.lastAccessed = Date.now();
results.set(key, cached.brainyId);
}
else {
missingKeys.push({ ...lookup, key });
results.set(key, null);
}
}
// Batch load missing keys from storage
if (missingKeys.length > 0 && (this.config.persistence === 'storage' || this.config.persistence === 'hybrid')) {
const stored = await this.loadBatchFromStorage(missingKeys);
for (const [key, mapping] of stored) {
if (mapping) {
// Add to memory cache
this.memoryIndex.set(key, mapping);
const fieldIndex = this.fieldIndices.get(mapping.field);
if (fieldIndex) {
fieldIndex.set(mapping.externalId, mapping.brainyId);
}
results.set(key, mapping.brainyId);
}
}
}
return results;
}
/**
* Check if entity exists (faster than lookupEntity for existence checks)
*/
async hasEntity(field, value) {
const fieldIndex = this.fieldIndices.get(field);
if (fieldIndex && fieldIndex.has(value)) {
return true;
}
return (await this.lookupEntity(field, value)) !== null;
}
/**
* Get all entities by field (e.g., all DIDs)
*/
async getEntitiesByField(field) {
const fieldIndex = this.fieldIndices.get(field);
return fieldIndex ? Array.from(fieldIndex.keys()) : [];
}
/**
* Get registry statistics
*/
getStats() {
const fieldCounts = {};
for (const [field, index] of this.fieldIndices) {
fieldCounts[field] = index.size;
}
return {
totalMappings: this.memoryIndex.size,
fieldCounts,
cacheHitRate: this.cacheHits > 0 ? this.cacheHits / (this.cacheHits + this.cacheMisses) : 0,
memoryUsage: this.estimateMemoryUsage()
};
}
/**
* Clear all cached mappings
*/
async clearCache() {
this.memoryIndex.clear();
for (const fieldIndex of this.fieldIndices.values()) {
fieldIndex.clear();
}
}
// Private helper methods
/**
* Check if an ID looks like it could be an external ID for a specific field
*/
looksLikeExternalId(id, field) {
// Basic heuristics to detect external ID patterns
switch (field) {
case 'did':
return id.startsWith('did:');
case 'handle':
return id.includes('.') && (id.includes('bsky') || id.includes('social'));
case 'external_id':
return !id.match(/^[a-f0-9-]{36}$/i); // Not a UUID
case 'uri':
return id.startsWith('http') || id.startsWith('at://');
case 'id':
return !id.match(/^[a-f0-9-]{36}$/i); // Not a UUID
default:
// For custom fields, assume non-UUID strings might be external IDs
return typeof id === 'string' && id.length > 3 && !id.match(/^[a-f0-9-]{36}$/i);
}
}
extractFieldValue(metadata, field) {
if (!metadata)
return null;
// Support nested field access (e.g., "author.did")
const parts = field.split('.');
let value = metadata;
for (const part of parts) {
value = value?.[part];
if (value === undefined || value === null) {
return null;
}
}
return typeof value === 'string' ? value : String(value);
}
async evictOldEntries() {
if (this.memoryIndex.size <= this.config.maxCacheSize) {
return;
}
// Sort by last accessed time and remove oldest entries
const entries = Array.from(this.memoryIndex.entries());
entries.sort(([, a], [, b]) => a.lastAccessed - b.lastAccessed);
const toRemove = entries.slice(0, entries.length - this.config.maxCacheSize);
for (const [key, mapping] of toRemove) {
this.memoryIndex.delete(key);
const fieldIndex = this.fieldIndices.get(mapping.field);
if (fieldIndex) {
fieldIndex.delete(mapping.externalId);
}
}
}
async loadFromStorage() {
if (!this.brain)
return;
try {
// Load registry data from a special storage location
const registryData = await this.brain.storage?.getMetadata('__entity_registry__');
if (registryData && registryData.mappings) {
for (const mapping of registryData.mappings) {
const key = `${mapping.field}:${mapping.externalId}`;
this.memoryIndex.set(key, mapping);
const fieldIndex = this.fieldIndices.get(mapping.field);
if (fieldIndex) {
fieldIndex.set(mapping.externalId, mapping.brainyId);
}
}
}
}
catch (error) {
console.warn('Failed to load entity registry from storage:', error);
}
}
async syncToStorage() {
if (!this.brain)
return;
try {
const mappings = Array.from(this.memoryIndex.values());
await this.brain.storage?.saveMetadata('__entity_registry__', {
version: 1,
lastSync: Date.now(),
mappings
});
}
catch (error) {
console.warn('Failed to sync entity registry to storage:', error);
}
}
async loadFromStorageByField(field, value) {
// For now, this would require a full load. In production, you'd want
// a more sophisticated storage index system
return null;
}
async loadBatchFromStorage(keys) {
// For now, return empty. In production, implement batch storage lookup
return new Map();
}
estimateMemoryUsage() {
// Rough estimate: 200 bytes per mapping on average
return this.memoryIndex.size * 200;
}
}
// Hook into Brainy's add operations to automatically register entities
export class AutoRegisterEntitiesAugmentation extends BaseAugmentation {
constructor() {
super(...arguments);
this.metadata = 'readonly'; // Reads metadata for auto-registration
this.name = 'auto-register-entities';
this.description = 'Automatically register entities in the registry when added';
this.timing = 'after';
this.operations = ['add', 'addNoun', 'addVerb'];
this.priority = 85; // After entity registry
}
async initialize(context) {
this.brain = context.brain;
// Find the entity registry augmentation from the registry
this.registry = this.brain?.augmentations?.augmentations?.find((aug) => aug instanceof EntityRegistryAugmentation);
}
async execute(operation, params, next) {
const result = await next();
// After successful add, register the entity
if ((operation === 'add' || operation === 'addNoun' || operation === 'addVerb') && result) {
if (this.registry) {
// Handle both formats: string UUID or object with id property
const brainyId = typeof result === 'string' ? result : result.id;
if (brainyId) {
const metadata = params.metadata || {};
const nounType = params.nounType || 'default';
await this.registry.registerEntity(brainyId, metadata, nounType);
}
}
}
return result;
}
}
//# sourceMappingURL=entityRegistryAugmentation.js.map

File diff suppressed because one or more lines are too long

View file

@ -0,0 +1,120 @@
/**
* Index Augmentation - Optional Metadata Indexing
*
* Replaces the hardcoded MetadataIndex in Brainy with an optional augmentation.
* Provides O(1) metadata filtering and field lookups.
*
* Zero-config: Automatically enabled for better search performance
* Can be disabled or customized via augmentation registry
*/
import { BaseAugmentation } from './brainyAugmentation.js';
import { MetadataIndexManager } from '../utils/metadataIndex.js';
export interface IndexConfig {
enabled?: boolean;
maxFieldValues?: number;
maxIndexSize?: number;
autoRebuild?: boolean;
rebuildThreshold?: number;
flushInterval?: number;
}
/**
* IndexAugmentation - Makes metadata indexing optional and pluggable
*
* Features:
* - O(1) metadata field lookups
* - Fast pre-filtering for searches
* - Automatic index maintenance
* - Zero-config with smart defaults
*/
export declare class IndexAugmentation extends BaseAugmentation {
readonly metadata: "readonly";
readonly name = "index";
readonly timing: "after";
operations: ("add" | "update" | "updateMetadata" | "delete" | "clear" | "all")[];
readonly priority = 60;
readonly category: "core";
readonly description = "Fast metadata field indexing for O(1) filtering and lookups";
private metadataIndex;
protected config: IndexConfig;
private flushTimer;
constructor(config?: IndexConfig);
protected onInitialize(): Promise<void>;
protected onShutdown(): Promise<void>;
/**
* Execute augmentation - maintain index on data operations
*/
execute<T = any>(operation: string, params: any, next: () => Promise<T>): Promise<T>;
/**
* Handle add operation - index new metadata
*/
private handleAdd;
/**
* Handle update operation - reindex metadata
*/
private handleUpdate;
/**
* Handle delete operation - remove from index
*/
private handleDelete;
/**
* Handle clear operation - clear index
*/
private handleClear;
/**
* Start periodic flush timer
*/
private startFlushTimer;
/**
* Get IDs that match metadata filter (for pre-filtering)
*/
getIdsForFilter(filter: Record<string, any>): Promise<string[]>;
/**
* Get available values for a field
*/
getFilterValues(field: string): Promise<any[]>;
/**
* Get all indexed fields
*/
getFilterFields(): Promise<string[]>;
/**
* Get index statistics
*/
getStats(): Promise<{
enabled: boolean;
totalEntries: number;
fieldsIndexed: never[];
memoryUsage: number;
} | {
totalEntries: number;
totalIds: number;
fieldsIndexed: string[];
lastRebuild: number;
indexSize: number;
enabled: boolean;
memoryUsage?: undefined;
}>;
/**
* Rebuild the index from storage
*/
rebuild(): Promise<void>;
/**
* Flush index to storage
*/
flush(): Promise<void>;
/**
* Add entry to index (public method for direct access)
*/
addToIndex(id: string, metadata: Record<string, any>): Promise<void>;
/**
* Remove entry from index (public method for direct access)
*/
removeFromIndex(id: string, metadata: Record<string, any>): Promise<void>;
/**
* Get the underlying MetadataIndexManager instance
*/
getMetadataIndex(): MetadataIndexManager | null;
}
/**
* Factory function for zero-config index augmentation
*/
export declare function createIndexAugmentation(config?: IndexConfig): IndexAugmentation;

View file

@ -0,0 +1,288 @@
/**
* Index Augmentation - Optional Metadata Indexing
*
* Replaces the hardcoded MetadataIndex in Brainy with an optional augmentation.
* Provides O(1) metadata filtering and field lookups.
*
* Zero-config: Automatically enabled for better search performance
* Can be disabled or customized via augmentation registry
*/
import { BaseAugmentation } from './brainyAugmentation.js';
import { MetadataIndexManager } from '../utils/metadataIndex.js';
/**
* IndexAugmentation - Makes metadata indexing optional and pluggable
*
* Features:
* - O(1) metadata field lookups
* - Fast pre-filtering for searches
* - Automatic index maintenance
* - Zero-config with smart defaults
*/
export class IndexAugmentation extends BaseAugmentation {
constructor(config = {}) {
super();
this.metadata = 'readonly'; // Reads metadata to build indexes
this.name = 'index';
this.timing = 'after';
this.operations = ['add', 'update', 'updateMetadata', 'delete', 'clear', 'all'];
this.priority = 60; // Run after data operations
// Augmentation metadata
this.category = 'core';
this.description = 'Fast metadata field indexing for O(1) filtering and lookups';
this.metadataIndex = null;
this.flushTimer = null;
this.config = {
enabled: true,
maxFieldValues: 1000,
autoRebuild: true,
rebuildThreshold: 0.3, // Rebuild if 30% inconsistent
flushInterval: 30000, // Flush every 30 seconds
...config
};
}
async onInitialize() {
if (!this.config.enabled) {
this.log('Index augmentation disabled by configuration');
return;
}
// Get storage from context
const storage = this.context?.storage;
if (!storage) {
this.log('No storage available, index augmentation inactive', 'warn');
return;
}
// Initialize metadata index
this.metadataIndex = new MetadataIndexManager(storage, {
maxIndexSize: this.config.maxIndexSize || 10000
});
// Check if we need to rebuild
if (this.config.autoRebuild) {
const stats = await this.metadataIndex.getStats();
if (stats.totalEntries === 0) {
// Check if storage has data but index is empty
try {
const storageStats = await storage.getStatistics?.();
if (storageStats && storageStats.totalNouns > 0) {
this.log('Rebuilding metadata index for existing data...');
await this.metadataIndex.rebuild();
const newStats = await this.metadataIndex.getStats();
this.log(`Index rebuilt: ${newStats.totalEntries} entries, ${newStats.fieldsIndexed.length} fields`);
}
}
catch (e) {
this.log('Could not check storage statistics', 'info');
}
}
}
// Start flush timer
if (this.config.flushInterval && this.config.flushInterval > 0) {
this.startFlushTimer();
}
this.log('Index augmentation initialized');
}
async onShutdown() {
// Stop flush timer
if (this.flushTimer) {
clearInterval(this.flushTimer);
this.flushTimer = null;
}
// Flush index one last time
if (this.metadataIndex) {
try {
await this.metadataIndex.flush();
}
catch (error) {
this.log('Error flushing index during shutdown', 'warn');
}
this.metadataIndex = null;
}
this.log('Index augmentation shut down');
}
/**
* Execute augmentation - maintain index on data operations
*/
async execute(operation, params, next) {
// Execute the operation first
const result = await next();
// If index is disabled, just return
if (!this.metadataIndex || !this.config.enabled) {
return result;
}
// Handle index updates after operation completes
switch (operation) {
case 'add':
await this.handleAdd(params);
break;
case 'updateMetadata':
await this.handleUpdate(params);
break;
case 'delete':
await this.handleDelete(params);
break;
case 'clear':
await this.handleClear();
break;
}
return result;
}
/**
* Handle add operation - index new metadata
*/
async handleAdd(params) {
if (!this.metadataIndex)
return;
const { id, metadata } = params;
if (id && metadata) {
await this.metadataIndex.addToIndex(id, metadata);
this.log(`Indexed metadata for ${id}`, 'info');
}
}
/**
* Handle update operation - reindex metadata
*/
async handleUpdate(params) {
if (!this.metadataIndex)
return;
const { id, oldMetadata, newMetadata } = params;
// Remove old metadata
if (id && oldMetadata) {
await this.metadataIndex.removeFromIndex(id, oldMetadata);
}
// Add new metadata
if (id && newMetadata) {
await this.metadataIndex.addToIndex(id, newMetadata);
this.log(`Reindexed metadata for ${id}`, 'info');
}
}
/**
* Handle delete operation - remove from index
*/
async handleDelete(params) {
if (!this.metadataIndex)
return;
const { id, metadata } = params;
if (id && metadata) {
await this.metadataIndex.removeFromIndex(id, metadata);
this.log(`Removed ${id} from index`, 'info');
}
}
/**
* Handle clear operation - clear index
*/
async handleClear() {
if (!this.metadataIndex)
return;
// Clear the index when all data is cleared (rebuild effectively clears it)
await this.metadataIndex.rebuild();
this.log('Index cleared due to clear operation');
}
/**
* Start periodic flush timer
*/
startFlushTimer() {
if (this.flushTimer)
return;
this.flushTimer = setInterval(async () => {
if (this.metadataIndex) {
try {
await this.metadataIndex.flush();
}
catch (error) {
this.log('Error during periodic index flush', 'warn');
}
}
}, this.config.flushInterval);
}
/**
* Get IDs that match metadata filter (for pre-filtering)
*/
async getIdsForFilter(filter) {
if (!this.metadataIndex)
return [];
return this.metadataIndex.getIdsForFilter(filter);
}
/**
* Get available values for a field
*/
async getFilterValues(field) {
if (!this.metadataIndex)
return [];
return this.metadataIndex.getFilterValues(field);
}
/**
* Get all indexed fields
*/
async getFilterFields() {
if (!this.metadataIndex)
return [];
return this.metadataIndex.getFilterFields();
}
/**
* Get index statistics
*/
async getStats() {
if (!this.metadataIndex) {
return {
enabled: false,
totalEntries: 0,
fieldsIndexed: [],
memoryUsage: 0
};
}
const stats = await this.metadataIndex.getStats();
return {
enabled: true,
...stats
};
}
/**
* Rebuild the index from storage
*/
async rebuild() {
if (!this.metadataIndex) {
throw new Error('Index augmentation is not initialized');
}
this.log('Rebuilding metadata index...');
await this.metadataIndex.rebuild();
const stats = await this.metadataIndex.getStats();
this.log(`Index rebuilt: ${stats.totalEntries} entries, ${stats.fieldsIndexed.length} fields`);
}
/**
* Flush index to storage
*/
async flush() {
if (this.metadataIndex) {
await this.metadataIndex.flush();
this.log('Index flushed to storage', 'info');
}
}
/**
* Add entry to index (public method for direct access)
*/
async addToIndex(id, metadata) {
if (!this.metadataIndex)
return;
await this.metadataIndex.addToIndex(id, metadata);
}
/**
* Remove entry from index (public method for direct access)
*/
async removeFromIndex(id, metadata) {
if (!this.metadataIndex)
return;
await this.metadataIndex.removeFromIndex(id, metadata);
}
/**
* Get the underlying MetadataIndexManager instance
*/
getMetadataIndex() {
return this.metadataIndex;
}
}
/**
* Factory function for zero-config index augmentation
*/
export function createIndexAugmentation(config) {
return new IndexAugmentation(config);
}
//# sourceMappingURL=indexAugmentation.js.map

File diff suppressed because one or more lines are too long

View file

@ -0,0 +1,158 @@
import { ICognitionAugmentation, AugmentationResponse } from '../types/augmentations.js';
/**
* Configuration options for the Intelligent Verb Scoring augmentation
*/
export interface IVerbScoringConfig {
/** Enable semantic proximity scoring based on entity embeddings */
enableSemanticScoring: boolean;
/** Enable frequency-based weight amplification */
enableFrequencyAmplification: boolean;
/** Enable temporal decay for weights */
enableTemporalDecay: boolean;
/** Decay rate per day for temporal scoring (0-1) */
temporalDecayRate: number;
/** Minimum weight threshold */
minWeight: number;
/** Maximum weight threshold */
maxWeight: number;
/** Base confidence score for new relationships */
baseConfidence: number;
/** Learning rate for adaptive scoring (0-1) */
learningRate: number;
}
/**
* Default configuration for the Intelligent Verb Scoring augmentation
*/
export declare const DEFAULT_VERB_SCORING_CONFIG: IVerbScoringConfig;
/**
* Relationship statistics for learning and adaptation
*/
interface RelationshipStats {
count: number;
totalWeight: number;
averageWeight: number;
lastSeen: Date;
firstSeen: Date;
semanticSimilarity?: number;
}
/**
* Intelligent Verb Scoring Cognition Augmentation
*
* Automatically generates intelligent weight and confidence scores for verb relationships
* using semantic analysis, frequency patterns, and temporal factors.
*/
export declare class IntelligentVerbScoring implements ICognitionAugmentation {
readonly name = "intelligent-verb-scoring";
readonly description = "Automatically generates intelligent weight and confidence scores for verb relationships";
enabled: boolean;
private config;
private relationshipStats;
private brainyInstance;
private isInitialized;
constructor(config?: Partial<IVerbScoringConfig>);
initialize(): Promise<void>;
shutDown(): Promise<void>;
getStatus(): Promise<'active' | 'inactive' | 'error'>;
/**
* Set reference to the BrainyData instance for accessing graph data
*/
setBrainyInstance(instance: any): void;
/**
* Main reasoning method for generating intelligent verb scores
*/
reason(query: string, context?: Record<string, unknown>): AugmentationResponse<{
inference: string;
confidence: number;
}>;
infer(dataSubset: Record<string, unknown>): AugmentationResponse<Record<string, unknown>>;
executeLogic(ruleId: string, input: Record<string, unknown>): AugmentationResponse<boolean>;
/**
* Generate intelligent weight and confidence scores for a verb relationship
*
* @param sourceId - ID of the source entity
* @param targetId - ID of the target entity
* @param verbType - Type of the relationship
* @param existingWeight - Existing weight if any
* @param metadata - Additional metadata about the relationship
* @returns Computed weight and confidence scores
*/
computeVerbScores(sourceId: string, targetId: string, verbType: string, existingWeight?: number, metadata?: any): Promise<{
weight: number;
confidence: number;
reasoning: string[];
}>;
/**
* Calculate semantic similarity between two entities using their embeddings
*/
private calculateSemanticScore;
/**
* Calculate frequency-based boost for repeated relationships
*/
private calculateFrequencyBoost;
/**
* Calculate temporal decay factor based on recency
*/
private calculateTemporalFactor;
/**
* Calculate learning-based adjustment using historical patterns
*/
private calculateLearningAdjustment;
/**
* Update relationship statistics for learning
*/
private updateRelationshipStats;
/**
* Blend two scores using a weighted average
*/
private blendScores;
/**
* Get current configuration
*/
getConfig(): IVerbScoringConfig;
/**
* Update configuration
*/
updateConfig(newConfig: Partial<IVerbScoringConfig>): void;
/**
* Get relationship statistics (for debugging/monitoring)
*/
getRelationshipStats(): Map<string, RelationshipStats>;
/**
* Clear relationship statistics
*/
clearStats(): void;
/**
* Provide feedback to improve future scoring
* This allows the system to learn from user corrections or validation
*
* @param sourceId - Source entity ID
* @param targetId - Target entity ID
* @param verbType - Relationship type
* @param feedbackWeight - The corrected/validated weight (0-1)
* @param feedbackConfidence - The corrected/validated confidence (0-1)
* @param feedbackType - Type of feedback ('correction', 'validation', 'enhancement')
*/
provideFeedback(sourceId: string, targetId: string, verbType: string, feedbackWeight: number, feedbackConfidence?: number, feedbackType?: 'correction' | 'validation' | 'enhancement'): Promise<void>;
/**
* Get learning statistics for monitoring and debugging
*/
getLearningStats(): {
totalRelationships: number;
averageConfidence: number;
feedbackCount: number;
topRelationships: Array<{
relationship: string;
count: number;
averageWeight: number;
}>;
};
/**
* Export learning data for backup or analysis
*/
exportLearningData(): string;
/**
* Import learning data from backup
*/
importLearningData(jsonData: string): void;
}
export {};

View file

@ -0,0 +1,377 @@
import { cosineDistance } from '../utils/distance.js';
/**
* Default configuration for the Intelligent Verb Scoring augmentation
*/
export const DEFAULT_VERB_SCORING_CONFIG = {
enableSemanticScoring: true,
enableFrequencyAmplification: true,
enableTemporalDecay: true,
temporalDecayRate: 0.01, // 1% decay per day
minWeight: 0.1,
maxWeight: 1.0,
baseConfidence: 0.5,
learningRate: 0.1
};
/**
* Intelligent Verb Scoring Cognition Augmentation
*
* Automatically generates intelligent weight and confidence scores for verb relationships
* using semantic analysis, frequency patterns, and temporal factors.
*/
export class IntelligentVerbScoring {
constructor(config = {}) {
this.name = 'intelligent-verb-scoring';
this.description = 'Automatically generates intelligent weight and confidence scores for verb relationships';
this.enabled = false; // Off by default as requested
this.relationshipStats = new Map();
this.isInitialized = false;
this.config = { ...DEFAULT_VERB_SCORING_CONFIG, ...config };
}
async initialize() {
if (this.isInitialized)
return;
this.isInitialized = true;
}
async shutDown() {
this.relationshipStats.clear();
this.isInitialized = false;
}
async getStatus() {
return this.enabled && this.isInitialized ? 'active' : 'inactive';
}
/**
* Set reference to the BrainyData instance for accessing graph data
*/
setBrainyInstance(instance) {
this.brainyInstance = instance;
}
/**
* Main reasoning method for generating intelligent verb scores
*/
reason(query, context) {
if (!this.enabled) {
return {
success: false,
data: { inference: 'Augmentation is disabled', confidence: 0 },
error: 'Intelligent verb scoring is disabled'
};
}
return {
success: true,
data: {
inference: 'Intelligent verb scoring active',
confidence: 1.0
}
};
}
infer(dataSubset) {
return {
success: true,
data: dataSubset
};
}
executeLogic(ruleId, input) {
return {
success: true,
data: true
};
}
/**
* Generate intelligent weight and confidence scores for a verb relationship
*
* @param sourceId - ID of the source entity
* @param targetId - ID of the target entity
* @param verbType - Type of the relationship
* @param existingWeight - Existing weight if any
* @param metadata - Additional metadata about the relationship
* @returns Computed weight and confidence scores
*/
async computeVerbScores(sourceId, targetId, verbType, existingWeight, metadata) {
if (!this.enabled || !this.brainyInstance) {
return {
weight: existingWeight ?? 0.5,
confidence: this.config.baseConfidence,
reasoning: ['Intelligent scoring disabled']
};
}
const reasoning = [];
let weight = existingWeight ?? 0.5;
let confidence = this.config.baseConfidence;
try {
// Get relationship key for statistics
const relationKey = `${sourceId}-${verbType}-${targetId}`;
// Update relationship statistics
this.updateRelationshipStats(relationKey, weight, metadata);
// Apply semantic scoring if enabled
if (this.config.enableSemanticScoring) {
const semanticScore = await this.calculateSemanticScore(sourceId, targetId);
if (semanticScore !== null) {
weight = this.blendScores(weight, semanticScore, 0.3);
confidence = Math.min(confidence + semanticScore * 0.2, 1.0);
reasoning.push(`Semantic similarity: ${semanticScore.toFixed(3)}`);
}
}
// Apply frequency amplification if enabled
if (this.config.enableFrequencyAmplification) {
const frequencyBoost = this.calculateFrequencyBoost(relationKey);
weight = this.blendScores(weight, frequencyBoost, 0.2);
if (frequencyBoost > 0.5) {
confidence = Math.min(confidence + 0.1, 1.0);
reasoning.push(`Frequency boost: ${frequencyBoost.toFixed(3)}`);
}
}
// Apply temporal decay if enabled
if (this.config.enableTemporalDecay) {
const temporalFactor = this.calculateTemporalFactor(relationKey);
weight *= temporalFactor;
reasoning.push(`Temporal factor: ${temporalFactor.toFixed(3)}`);
}
// Apply learning adjustments
const learningAdjustment = this.calculateLearningAdjustment(relationKey);
weight = this.blendScores(weight, learningAdjustment, this.config.learningRate);
// Clamp values to configured bounds
weight = Math.max(this.config.minWeight, Math.min(this.config.maxWeight, weight));
confidence = Math.max(0, Math.min(1, confidence));
reasoning.push(`Final weight: ${weight.toFixed(3)}, confidence: ${confidence.toFixed(3)}`);
return { weight, confidence, reasoning };
}
catch (error) {
console.warn('Error computing verb scores:', error);
return {
weight: existingWeight ?? 0.5,
confidence: this.config.baseConfidence,
reasoning: [`Error in scoring: ${error}`]
};
}
}
/**
* Calculate semantic similarity between two entities using their embeddings
*/
async calculateSemanticScore(sourceId, targetId) {
try {
if (!this.brainyInstance?.storage)
return null;
// Get noun embeddings from storage
const sourceNoun = await this.brainyInstance.storage.getNoun(sourceId);
const targetNoun = await this.brainyInstance.storage.getNoun(targetId);
if (!sourceNoun?.vector || !targetNoun?.vector)
return null;
// Calculate cosine similarity (1 - distance)
const distance = cosineDistance(sourceNoun.vector, targetNoun.vector);
return Math.max(0, 1 - distance);
}
catch (error) {
console.warn('Error calculating semantic score:', error);
return null;
}
}
/**
* Calculate frequency-based boost for repeated relationships
*/
calculateFrequencyBoost(relationKey) {
const stats = this.relationshipStats.get(relationKey);
if (!stats || stats.count <= 1)
return 0.5;
// Logarithmic scaling: more occurrences = higher weight, but with diminishing returns
const boost = Math.log(stats.count + 1) / Math.log(10); // Log base 10
return Math.min(boost, 1.0);
}
/**
* Calculate temporal decay factor based on recency
*/
calculateTemporalFactor(relationKey) {
const stats = this.relationshipStats.get(relationKey);
if (!stats)
return 1.0;
const daysSinceLastSeen = (Date.now() - stats.lastSeen.getTime()) / (1000 * 60 * 60 * 24);
const decayFactor = Math.exp(-this.config.temporalDecayRate * daysSinceLastSeen);
return Math.max(0.1, decayFactor); // Minimum 10% of original weight
}
/**
* Calculate learning-based adjustment using historical patterns
*/
calculateLearningAdjustment(relationKey) {
const stats = this.relationshipStats.get(relationKey);
if (!stats || stats.count <= 1)
return 0.5;
// Use moving average of weights as learned baseline
return Math.max(0, Math.min(1, stats.averageWeight));
}
/**
* Update relationship statistics for learning
*/
updateRelationshipStats(relationKey, weight, metadata) {
const now = new Date();
const existing = this.relationshipStats.get(relationKey);
if (existing) {
// Update existing stats
existing.count++;
existing.totalWeight += weight;
existing.averageWeight = existing.totalWeight / existing.count;
existing.lastSeen = now;
}
else {
// Create new stats entry
this.relationshipStats.set(relationKey, {
count: 1,
totalWeight: weight,
averageWeight: weight,
lastSeen: now,
firstSeen: now
});
}
}
/**
* Blend two scores using a weighted average
*/
blendScores(score1, score2, weight2) {
const weight1 = 1 - weight2;
return score1 * weight1 + score2 * weight2;
}
/**
* Get current configuration
*/
getConfig() {
return { ...this.config };
}
/**
* Update configuration
*/
updateConfig(newConfig) {
this.config = { ...this.config, ...newConfig };
}
/**
* Get relationship statistics (for debugging/monitoring)
*/
getRelationshipStats() {
return new Map(this.relationshipStats);
}
/**
* Clear relationship statistics
*/
clearStats() {
this.relationshipStats.clear();
}
/**
* Provide feedback to improve future scoring
* This allows the system to learn from user corrections or validation
*
* @param sourceId - Source entity ID
* @param targetId - Target entity ID
* @param verbType - Relationship type
* @param feedbackWeight - The corrected/validated weight (0-1)
* @param feedbackConfidence - The corrected/validated confidence (0-1)
* @param feedbackType - Type of feedback ('correction', 'validation', 'enhancement')
*/
async provideFeedback(sourceId, targetId, verbType, feedbackWeight, feedbackConfidence, feedbackType = 'correction') {
if (!this.enabled)
return;
const relationKey = `${sourceId}-${verbType}-${targetId}`;
const existing = this.relationshipStats.get(relationKey);
if (existing) {
// Apply feedback with learning rate
const newWeight = existing.averageWeight * (1 - this.config.learningRate) +
feedbackWeight * this.config.learningRate;
// Update the running average with feedback
existing.totalWeight = (existing.totalWeight * existing.count + feedbackWeight) / (existing.count + 1);
existing.averageWeight = existing.totalWeight / existing.count;
existing.count += 1;
existing.lastSeen = new Date();
if (this.brainyInstance?.loggingConfig?.verbose) {
console.log(`Feedback applied for ${relationKey}: ${feedbackType}, ` +
`old weight: ${existing.averageWeight.toFixed(3)}, ` +
`feedback: ${feedbackWeight.toFixed(3)}, ` +
`new weight: ${newWeight.toFixed(3)}`);
}
}
else {
// Create new entry with feedback as initial data
this.relationshipStats.set(relationKey, {
count: 1,
totalWeight: feedbackWeight,
averageWeight: feedbackWeight,
lastSeen: new Date(),
firstSeen: new Date()
});
}
}
/**
* Get learning statistics for monitoring and debugging
*/
getLearningStats() {
const relationships = Array.from(this.relationshipStats.entries());
const totalRelationships = relationships.length;
const feedbackCount = relationships.reduce((sum, [, stats]) => sum + stats.count, 0);
// Calculate average confidence (approximated from weight patterns)
const averageWeight = relationships.reduce((sum, [, stats]) => sum + stats.averageWeight, 0) / totalRelationships || 0;
const averageConfidence = Math.min(averageWeight + 0.2, 1.0); // Heuristic: confidence typically higher than weight
// Get top relationships by count
const topRelationships = relationships
.map(([key, stats]) => ({
relationship: key,
count: stats.count,
averageWeight: stats.averageWeight
}))
.sort((a, b) => b.count - a.count)
.slice(0, 10);
return {
totalRelationships,
averageConfidence,
feedbackCount,
topRelationships
};
}
/**
* Export learning data for backup or analysis
*/
exportLearningData() {
const data = {
config: this.config,
stats: Array.from(this.relationshipStats.entries()).map(([key, stats]) => ({
relationship: key,
...stats,
firstSeen: stats.firstSeen.toISOString(),
lastSeen: stats.lastSeen.toISOString()
})),
exportedAt: new Date().toISOString(),
version: '1.0'
};
return JSON.stringify(data, null, 2);
}
/**
* Import learning data from backup
*/
importLearningData(jsonData) {
try {
const data = JSON.parse(jsonData);
if (data.version !== '1.0') {
console.warn('Learning data version mismatch, importing anyway');
}
// Update configuration if provided
if (data.config) {
this.config = { ...this.config, ...data.config };
}
// Import relationship statistics
if (data.stats && Array.isArray(data.stats)) {
for (const stat of data.stats) {
if (stat.relationship) {
this.relationshipStats.set(stat.relationship, {
count: stat.count || 1,
totalWeight: stat.totalWeight || stat.averageWeight || 0.5,
averageWeight: stat.averageWeight || 0.5,
firstSeen: new Date(stat.firstSeen || Date.now()),
lastSeen: new Date(stat.lastSeen || Date.now()),
semanticSimilarity: stat.semanticSimilarity
});
}
}
}
console.log(`Imported learning data: ${this.relationshipStats.size} relationships`);
}
catch (error) {
console.error('Failed to import learning data:', error);
throw new Error(`Failed to import learning data: ${error}`);
}
}
}
//# sourceMappingURL=intelligentVerbScoring.js.map

File diff suppressed because one or more lines are too long

View file

@ -0,0 +1,157 @@
/**
* Intelligent Verb Scoring Augmentation
*
* Enhances relationship quality through intelligent semantic scoring
* Provides context-aware relationship weights based on:
* - Semantic proximity of connected entities
* - Frequency-based amplification
* - Temporal decay modeling
* - Adaptive learning from usage patterns
*
* Critical for enterprise knowledge graphs with millions of relationships
*/
import { BaseAugmentation } from './brainyAugmentation.js';
interface VerbScoringConfig {
enabled?: boolean;
enableSemanticScoring?: boolean;
semanticThreshold?: number;
semanticWeight?: number;
enableFrequencyAmplification?: boolean;
frequencyDecay?: number;
maxFrequencyBoost?: number;
enableTemporalDecay?: boolean;
temporalDecayRate?: number;
temporalWindow?: number;
enableAdaptiveLearning?: boolean;
learningRate?: number;
confidenceThreshold?: number;
minWeight?: number;
maxWeight?: number;
baseWeight?: number;
}
interface RelationshipMetrics {
count: number;
totalWeight: number;
averageWeight: number;
lastUpdated: number;
semanticScore: number;
frequencyScore: number;
temporalScore: number;
confidenceScore: number;
}
interface ScoringMetrics {
relationshipsScored: number;
averageSemanticScore: number;
averageFrequencyScore: number;
averageTemporalScore: number;
averageConfidenceScore: number;
adaptiveAdjustments: number;
computationTimeMs: number;
}
export declare class IntelligentVerbScoringAugmentation extends BaseAugmentation {
name: string;
timing: "around";
readonly metadata: {
reads: string[];
writes: string[];
};
operations: ("addVerb" | "relate")[];
priority: number;
readonly category: "core";
readonly description = "AI-powered intelligent scoring for relationship strength analysis";
protected config: Required<VerbScoringConfig>;
private relationshipStats;
private metrics;
private scoringInstance;
constructor(config?: VerbScoringConfig);
protected onInitialize(): Promise<void>;
/**
* Get this augmentation instance for API compatibility
* Used by Brainy to access scoring methods
*/
getScoring(): IntelligentVerbScoringAugmentation;
shouldExecute(operation: string, params: any): boolean;
execute<T = any>(operation: string, params: any, next: () => Promise<T>): Promise<T>;
private calculateIntelligentWeight;
private calculateSemanticScore;
/**
* Detect noun type using neural taxonomy matching
*/
private detectNounType;
/**
* Calculate taxonomy-based similarity boost
*/
private calculateTaxonomyBoost;
private calculateCosineSimilarity;
private calculateFrequencyScore;
private calculateTemporalScore;
private calculateContextScore;
private updateRelationshipLearning;
private getConfidenceScore;
private getScoringMethodsUsed;
private storeDetailedScoring;
private updateMetrics;
/**
* Get intelligent verb scoring statistics
*/
getStats(): ScoringMetrics & {
totalRelationships: number;
averageConfidence: number;
highConfidenceRelationships: number;
learningEfficiency: number;
};
/**
* Export relationship statistics for analysis
*/
exportRelationshipStats(): Array<{
relationship: string;
metrics: RelationshipMetrics;
}>;
/**
* Import relationship statistics from previous sessions
*/
importRelationshipStats(stats: Array<{
relationship: string;
metrics: RelationshipMetrics;
}>): void;
/**
* Get learning statistics for monitoring and debugging
* Required for Brainy.getVerbScoringStats()
*/
getLearningStats(): {
totalRelationships: number;
averageConfidence: number;
feedbackCount: number;
topRelationships: Array<{
relationship: string;
count: number;
averageWeight: number;
}>;
};
/**
* Export learning data for backup or analysis
* Required for Brainy.exportVerbScoringLearningData()
*/
exportLearningData(): string;
/**
* Import learning data from backup
* Required for Brainy.importVerbScoringLearningData()
*/
importLearningData(jsonData: string): void;
/**
* Provide feedback on a relationship's weight
* Required for Brainy.provideVerbScoringFeedback()
*/
provideFeedback(sourceId: string, targetId: string, relationType: string, feedback: number, feedbackType?: 'correction' | 'validation' | 'enhancement'): Promise<void>;
/**
* Compute intelligent scores for a verb relationship
* Used internally during verb creation
*/
computeVerbScores(sourceNoun: any, targetNoun: any, relationType: string): Promise<{
weight: number;
confidence: number;
reasoning: string[];
}>;
protected onShutdown(): Promise<void>;
}
export {};

View file

@ -0,0 +1,559 @@
/**
* Intelligent Verb Scoring Augmentation
*
* Enhances relationship quality through intelligent semantic scoring
* Provides context-aware relationship weights based on:
* - Semantic proximity of connected entities
* - Frequency-based amplification
* - Temporal decay modeling
* - Adaptive learning from usage patterns
*
* Critical for enterprise knowledge graphs with millions of relationships
*/
import { BaseAugmentation } from './brainyAugmentation.js';
export class IntelligentVerbScoringAugmentation extends BaseAugmentation {
constructor(config = {}) {
super();
this.name = 'IntelligentVerbScoring';
this.timing = 'around';
this.metadata = {
reads: ['type', 'verb', 'source', 'target'],
writes: ['weight', 'confidence', 'intelligentScoring']
}; // Adds scoring metadata to verbs
this.operations = ['addVerb', 'relate'];
this.priority = 10; // Enhancement feature - runs after core operations
// Augmentation metadata
this.category = 'core';
this.description = 'AI-powered intelligent scoring for relationship strength analysis';
this.relationshipStats = new Map();
this.metrics = {
relationshipsScored: 0,
averageSemanticScore: 0,
averageFrequencyScore: 0,
averageTemporalScore: 0,
averageConfidenceScore: 0,
adaptiveAdjustments: 0,
computationTimeMs: 0
};
this.config = {
enabled: config.enabled ?? true, // Smart by default!
// Semantic Analysis
enableSemanticScoring: config.enableSemanticScoring ?? true,
semanticThreshold: config.semanticThreshold ?? 0.3,
semanticWeight: config.semanticWeight ?? 0.4,
// Frequency Analysis
enableFrequencyAmplification: config.enableFrequencyAmplification ?? true,
frequencyDecay: config.frequencyDecay ?? 0.95, // 5% decay per occurrence
maxFrequencyBoost: config.maxFrequencyBoost ?? 2.0,
// Temporal Analysis
enableTemporalDecay: config.enableTemporalDecay ?? true,
temporalDecayRate: config.temporalDecayRate ?? 0.01, // 1% per day
temporalWindow: config.temporalWindow ?? 365, // 1 year
// Learning & Adaptation
enableAdaptiveLearning: config.enableAdaptiveLearning ?? true,
learningRate: config.learningRate ?? 0.1,
confidenceThreshold: config.confidenceThreshold ?? 0.3,
// Weight Management
minWeight: config.minWeight ?? 0.1,
maxWeight: config.maxWeight ?? 1.0,
baseWeight: config.baseWeight ?? 0.5
};
// Set enabled property based on config
this.enabled = this.config.enabled;
}
async onInitialize() {
if (this.config.enabled) {
this.log('Intelligent verb scoring initialized for enhanced relationship quality');
}
else {
this.log('Intelligent verb scoring disabled');
}
}
/**
* Get this augmentation instance for API compatibility
* Used by Brainy to access scoring methods
*/
getScoring() {
return this;
}
shouldExecute(operation, params) {
// For addVerb, params are passed as array: [sourceId, targetId, verbType, metadata, weight]
if (operation === 'addVerb' && this.config.enabled) {
return Array.isArray(params) && params.length >= 3;
}
// For relate method, params might be an object
if (operation === 'relate' && this.config.enabled) {
return params.sourceId && params.targetId && params.relationType;
}
return false;
}
async execute(operation, params, next) {
if (!this.shouldExecute(operation, params)) {
return next();
}
const startTime = Date.now();
try {
let sourceId, targetId, relationType, metadata;
let scoringResult = null;
// Extract parameters based on operation type
if (operation === 'addVerb' && Array.isArray(params)) {
// addVerb params: [sourceId, targetId, verbType, metadata, weight]
[sourceId, targetId, relationType, metadata] = params;
}
else if (operation === 'relate') {
// relate params might be an object
sourceId = params.sourceId;
targetId = params.targetId;
relationType = params.relationType;
metadata = params.metadata;
}
else {
return next();
}
// Skip if weight is already provided explicitly
if (Array.isArray(params) && params[4] !== undefined && params[4] !== null) {
return next();
}
// Get the nouns to compute scoring
const sourceNoun = await this.context?.brain.get(sourceId);
const targetNoun = await this.context?.brain.get(targetId);
// Compute intelligent scores with reasoning
scoringResult = await this.computeVerbScores(sourceNoun, targetNoun, relationType);
// For addVerb, modify the params array
if (operation === 'addVerb' && Array.isArray(params)) {
// Set the weight parameter (index 4)
params[4] = scoringResult.weight;
// Enhance metadata with scoring info
params[3] = {
...params[3],
intelligentScoring: {
weight: scoringResult.weight,
confidence: scoringResult.confidence,
reasoning: scoringResult.reasoning,
scoringMethod: this.getScoringMethodsUsed(),
computedAt: Date.now()
}
};
}
// Execute with enhanced parameters
const result = await next();
// Learn from this relationship
if (this.config.enableAdaptiveLearning && scoringResult) {
await this.updateRelationshipLearning(sourceId, targetId, relationType, scoringResult.weight);
}
// Update metrics
const computationTime = Date.now() - startTime;
if (scoringResult) {
this.updateMetrics(scoringResult.weight, computationTime);
}
return result;
}
catch (error) {
this.log(`Intelligent verb scoring error: ${error}`, 'error');
// Fallback to original parameters
return next();
}
}
async calculateIntelligentWeight(sourceId, targetId, relationType, metadata) {
let finalWeight = this.config.baseWeight;
let scoreComponents = {};
// 1. Semantic Proximity Score
if (this.config.enableSemanticScoring) {
const semanticScore = await this.calculateSemanticScore(sourceId, targetId);
scoreComponents.semantic = semanticScore;
finalWeight = finalWeight * (1 + semanticScore * this.config.semanticWeight);
}
// 2. Frequency Amplification Score
if (this.config.enableFrequencyAmplification) {
const frequencyScore = this.calculateFrequencyScore(sourceId, targetId, relationType);
scoreComponents.frequency = frequencyScore;
finalWeight = finalWeight * (1 + frequencyScore);
}
// 3. Temporal Relevance Score
if (this.config.enableTemporalDecay) {
const temporalScore = this.calculateTemporalScore(sourceId, targetId, relationType);
scoreComponents.temporal = temporalScore;
finalWeight = finalWeight * temporalScore;
}
// 4. Context Awareness (from metadata)
const contextScore = this.calculateContextScore(metadata);
scoreComponents.context = contextScore;
finalWeight = finalWeight * (1 + contextScore * 0.2);
// 5. Apply constraints
finalWeight = Math.max(this.config.minWeight, Math.min(this.config.maxWeight, finalWeight));
// Store detailed scoring for analysis
this.storeDetailedScoring(sourceId, targetId, relationType, {
finalWeight,
components: scoreComponents,
timestamp: Date.now()
});
return finalWeight;
}
async calculateSemanticScore(sourceId, targetId) {
try {
// Get embeddings for both entities
const sourceNoun = await this.context?.brain.get(sourceId);
const targetNoun = await this.context?.brain.get(targetId);
if (!sourceNoun?.vector || !targetNoun?.vector) {
return 0;
}
// Get noun types using neural detection (taxonomy-based)
const sourceType = await this.detectNounType(sourceNoun.vector);
const targetType = await this.detectNounType(targetNoun.vector);
// Calculate direct similarity
const directSimilarity = this.calculateCosineSimilarity(sourceNoun.vector, targetNoun.vector);
// Calculate taxonomy-based similarity boost
const taxonomyBoost = await this.calculateTaxonomyBoost(sourceType, targetType);
// Blend direct similarity with taxonomy guidance
// Taxonomy provides consistency while preserving flexibility
const semanticScore = directSimilarity * 0.7 + taxonomyBoost * 0.3;
return Math.min(1, Math.max(0, semanticScore));
}
catch (error) {
return 0;
}
}
/**
* Detect noun type using neural taxonomy matching
*/
async detectNounType(vector) {
// Use the same neural detection as addNoun for consistency
if (!this.context?.brain)
return 'unknown';
try {
// This would normally call the brain's detectNounType method
// For now, simplified type detection based on vector patterns
const magnitude = Math.sqrt(vector.reduce((sum, val) => sum + val * val, 0));
// Heuristic type detection (would use actual taxonomy embeddings)
if (magnitude > 10)
return 'concept';
if (magnitude > 5)
return 'entity';
if (magnitude > 2)
return 'object';
return 'item';
}
catch {
return 'unknown';
}
}
/**
* Calculate taxonomy-based similarity boost
*/
async calculateTaxonomyBoost(sourceType, targetType) {
// Define valid relationship patterns in taxonomy
const validPatterns = {
'person': { 'concept': 0.9, 'skill': 0.85, 'organization': 0.8, 'person': 0.7 },
'concept': { 'concept': 0.9, 'example': 0.85, 'application': 0.8 },
'entity': { 'entity': 0.8, 'property': 0.85, 'action': 0.75 },
'object': { 'object': 0.7, 'property': 0.8, 'location': 0.75 },
'document': { 'topic': 0.9, 'author': 0.85, 'document': 0.7 },
'tool': { 'output': 0.9, 'input': 0.85, 'user': 0.8 },
'unknown': { 'unknown': 0.5 } // Fallback
};
// Get boost from taxonomy patterns
const patterns = validPatterns[sourceType] || validPatterns['unknown'];
const boost = patterns[targetType] || 0.3; // Low score for unrecognized patterns
return boost;
}
calculateCosineSimilarity(vectorA, vectorB) {
if (vectorA.length !== vectorB.length)
return 0;
let dotProduct = 0;
let normA = 0;
let normB = 0;
for (let i = 0; i < vectorA.length; i++) {
dotProduct += vectorA[i] * vectorB[i];
normA += vectorA[i] * vectorA[i];
normB += vectorB[i] * vectorB[i];
}
const magnitude = Math.sqrt(normA) * Math.sqrt(normB);
return magnitude ? dotProduct / magnitude : 0;
}
calculateFrequencyScore(sourceId, targetId, relationType) {
const relationshipKey = `${sourceId}:${relationType}:${targetId}`;
const stats = this.relationshipStats.get(relationshipKey);
if (!stats || stats.count <= 1)
return 0;
// Frequency boost diminishes with each occurrence
const frequencyBoost = Math.log(stats.count) * this.config.frequencyDecay;
return Math.min(this.config.maxFrequencyBoost, frequencyBoost);
}
calculateTemporalScore(sourceId, targetId, relationType) {
const relationshipKey = `${sourceId}:${relationType}:${targetId}`;
const stats = this.relationshipStats.get(relationshipKey);
if (!stats)
return 1.0; // New relationship - full temporal score
const daysSinceUpdate = (Date.now() - stats.lastUpdated) / (1000 * 60 * 60 * 24);
const decayFactor = Math.pow(1 - this.config.temporalDecayRate, daysSinceUpdate);
// Relationships older than temporal window get minimum score
if (daysSinceUpdate > this.config.temporalWindow) {
return this.config.minWeight / this.config.baseWeight;
}
return Math.max(0.1, decayFactor);
}
calculateContextScore(metadata) {
if (!metadata)
return 0;
let contextScore = 0;
// Boost for explicit importance
if (metadata.importance) {
contextScore += Math.min(0.5, metadata.importance);
}
// Boost for confidence
if (metadata.confidence) {
contextScore += Math.min(0.3, metadata.confidence);
}
// Boost for source quality
if (metadata.sourceQuality) {
contextScore += Math.min(0.2, metadata.sourceQuality);
}
return contextScore;
}
async updateRelationshipLearning(sourceId, targetId, relationType, weight) {
const relationshipKey = `${sourceId}:${relationType}:${targetId}`;
let stats = this.relationshipStats.get(relationshipKey);
if (!stats) {
stats = {
count: 0,
totalWeight: 0,
averageWeight: this.config.baseWeight,
lastUpdated: Date.now(),
semanticScore: 0,
frequencyScore: 0,
temporalScore: 1.0,
confidenceScore: this.config.baseWeight
};
}
// Update statistics with learning rate
stats.count++;
stats.totalWeight += weight;
stats.averageWeight = stats.averageWeight * (1 - this.config.learningRate) +
weight * this.config.learningRate;
stats.lastUpdated = Date.now();
// Update confidence based on consistency
const weightVariance = Math.abs(weight - stats.averageWeight);
const consistencyScore = 1 - Math.min(1, weightVariance);
stats.confidenceScore = stats.confidenceScore * (1 - this.config.learningRate) +
consistencyScore * this.config.learningRate;
this.relationshipStats.set(relationshipKey, stats);
this.metrics.adaptiveAdjustments++;
}
getConfidenceScore(sourceId, targetId, relationType) {
const relationshipKey = `${sourceId}:${relationType}:${targetId}`;
const stats = this.relationshipStats.get(relationshipKey);
return stats ? stats.confidenceScore : this.config.baseWeight;
}
getScoringMethodsUsed() {
const methods = [];
if (this.config.enableSemanticScoring)
methods.push('semantic');
if (this.config.enableFrequencyAmplification)
methods.push('frequency');
if (this.config.enableTemporalDecay)
methods.push('temporal');
if (this.config.enableAdaptiveLearning)
methods.push('adaptive');
return methods;
}
storeDetailedScoring(sourceId, targetId, relationType, scoring) {
// Store detailed scoring for analysis and debugging
// In production, this might be sent to analytics system
}
updateMetrics(weight, computationTime) {
this.metrics.relationshipsScored++;
this.metrics.computationTimeMs =
(this.metrics.computationTimeMs * (this.metrics.relationshipsScored - 1) + computationTime) /
this.metrics.relationshipsScored;
// Update score averages (simplified)
// In practice, we'd track these more precisely
}
/**
* Get intelligent verb scoring statistics
*/
getStats() {
let totalConfidence = 0;
let highConfidenceCount = 0;
for (const stats of this.relationshipStats.values()) {
totalConfidence += stats.confidenceScore;
if (stats.confidenceScore >= this.config.confidenceThreshold * 2) {
highConfidenceCount++;
}
}
const totalRelationships = this.relationshipStats.size;
const averageConfidence = totalRelationships > 0 ? totalConfidence / totalRelationships : 0;
const learningEfficiency = this.metrics.adaptiveAdjustments / Math.max(1, this.metrics.relationshipsScored);
return {
...this.metrics,
totalRelationships,
averageConfidence,
highConfidenceRelationships: highConfidenceCount,
learningEfficiency
};
}
/**
* Export relationship statistics for analysis
*/
exportRelationshipStats() {
return Array.from(this.relationshipStats.entries()).map(([key, metrics]) => ({
relationship: key,
metrics
}));
}
/**
* Import relationship statistics from previous sessions
*/
importRelationshipStats(stats) {
for (const { relationship, metrics } of stats) {
this.relationshipStats.set(relationship, metrics);
}
this.log(`Imported ${stats.length} relationship statistics`);
}
/**
* Get learning statistics for monitoring and debugging
* Required for Brainy.getVerbScoringStats()
*/
getLearningStats() {
const relationships = Array.from(this.relationshipStats.entries());
const totalRelationships = relationships.length;
const feedbackCount = relationships.reduce((sum, [, stats]) => sum + stats.count, 0);
const averageWeight = relationships.reduce((sum, [, stats]) => sum + stats.averageWeight, 0) / totalRelationships || 0;
const averageConfidence = Math.min(averageWeight + 0.2, 1.0);
const topRelationships = relationships
.map(([key, stats]) => ({
relationship: key,
count: stats.count,
averageWeight: stats.averageWeight
}))
.sort((a, b) => b.count - a.count)
.slice(0, 10);
return {
totalRelationships,
averageConfidence,
feedbackCount,
topRelationships
};
}
/**
* Export learning data for backup or analysis
* Required for Brainy.exportVerbScoringLearningData()
*/
exportLearningData() {
const data = {
config: this.config,
stats: Array.from(this.relationshipStats.entries()).map(([key, stats]) => ({
relationship: key,
...stats
})),
exportedAt: new Date().toISOString(),
version: '1.0'
};
return JSON.stringify(data, null, 2);
}
/**
* Import learning data from backup
* Required for Brainy.importVerbScoringLearningData()
*/
importLearningData(jsonData) {
try {
const data = JSON.parse(jsonData);
if (data.stats && Array.isArray(data.stats)) {
for (const stat of data.stats) {
if (stat.relationship) {
this.relationshipStats.set(stat.relationship, {
count: stat.count || 1,
totalWeight: stat.totalWeight || stat.averageWeight || 0.5,
averageWeight: stat.averageWeight || 0.5,
lastUpdated: stat.lastUpdated || Date.now(),
semanticScore: stat.semanticScore || 0.5,
frequencyScore: stat.frequencyScore || 0.5,
temporalScore: stat.temporalScore || 1.0,
confidenceScore: stat.confidenceScore || 0.5
});
}
}
}
this.log(`Imported learning data: ${this.relationshipStats.size} relationships`);
}
catch (error) {
console.error('Failed to import learning data:', error);
throw new Error(`Failed to import learning data: ${error}`);
}
}
/**
* Provide feedback on a relationship's weight
* Required for Brainy.provideVerbScoringFeedback()
*/
async provideFeedback(sourceId, targetId, relationType, feedback, feedbackType = 'correction') {
const key = `${sourceId}-${relationType}-${targetId}`;
const stats = this.relationshipStats.get(key) || {
count: 0,
totalWeight: 0,
averageWeight: 0.5,
lastUpdated: Date.now(),
semanticScore: 0.5,
frequencyScore: 0.5,
temporalScore: 1.0,
confidenceScore: 0.5
};
// Update statistics based on feedback
if (feedbackType === 'correction') {
// Direct correction - heavily weight the feedback
stats.averageWeight = stats.averageWeight * 0.3 + feedback * 0.7;
}
else if (feedbackType === 'validation') {
// Validation - slightly adjust towards feedback
stats.averageWeight = stats.averageWeight * 0.8 + feedback * 0.2;
}
else {
// Enhancement - minor adjustment
stats.averageWeight = stats.averageWeight * 0.9 + feedback * 0.1;
}
stats.count++;
stats.totalWeight += feedback;
stats.lastUpdated = Date.now();
this.relationshipStats.set(key, stats);
this.metrics.adaptiveAdjustments++;
}
/**
* Compute intelligent scores for a verb relationship
* Used internally during verb creation
*/
async computeVerbScores(sourceNoun, targetNoun, relationType) {
const reasoning = [];
let totalScore = 0;
let components = 0;
// Semantic scoring
if (this.config.enableSemanticScoring && sourceNoun?.vector && targetNoun?.vector) {
const similarity = this.calculateCosineSimilarity(sourceNoun.vector, targetNoun.vector);
const semanticScore = Math.max(similarity, this.config.semanticThreshold);
totalScore += semanticScore * this.config.semanticWeight;
components++;
reasoning.push(`Semantic similarity: ${(similarity * 100).toFixed(1)}%`);
}
// Frequency scoring
const key = `${sourceNoun?.id}-${relationType}-${targetNoun?.id}`;
const stats = this.relationshipStats.get(key);
if (this.config.enableFrequencyAmplification && stats) {
const frequencyScore = Math.min(1 + (stats.count - 1) * 0.1, this.config.maxFrequencyBoost);
totalScore += frequencyScore * 0.3;
components++;
reasoning.push(`Frequency boost: ${frequencyScore.toFixed(2)}x`);
}
// Temporal decay scoring
if (this.config.enableTemporalDecay) {
reasoning.push(`Temporal decay applied (rate: ${this.config.temporalDecayRate})`);
}
// Calculate final weight
const weight = components > 0
? Math.min(Math.max(totalScore / components, this.config.minWeight), this.config.maxWeight)
: this.config.baseWeight;
const confidence = Math.min(weight + 0.2, 1.0);
return { weight, confidence, reasoning };
}
async onShutdown() {
const stats = this.getStats();
this.log(`Intelligent verb scoring shutdown: ${stats.relationshipsScored} relationships scored, ${Math.round(stats.averageConfidence * 100)}% avg confidence`);
}
}
//# sourceMappingURL=intelligentVerbScoringAugmentation.js.map

File diff suppressed because one or more lines are too long

View file

@ -0,0 +1,176 @@
/**
* Augmentation Manifest Types
*
* Defines the manifest structure for augmentation discovery and configuration
* Enables tools like brain-cloud to discover and configure augmentations
*/
/**
* JSON Schema type for configuration validation
*/
export interface JSONSchema {
type?: 'object' | 'array' | 'string' | 'number' | 'boolean' | 'null';
properties?: Record<string, JSONSchema>;
items?: JSONSchema;
required?: string[];
default?: any;
description?: string;
minimum?: number;
maximum?: number;
minLength?: number;
maxLength?: number;
pattern?: string;
enum?: any[];
additionalProperties?: boolean | JSONSchema;
}
/**
* Augmentation manifest for discovery and configuration
*/
export interface AugmentationManifest {
/**
* Unique identifier for the augmentation (e.g., 'wal', 'cache')
*/
id: string;
/**
* Display name for the augmentation
*/
name: string;
/**
* Semantic version (e.g., '2.0.0')
*/
version: string;
/**
* Author or organization
*/
author?: string;
/**
* Short description of what the augmentation does
*/
description: string;
/**
* Detailed description for documentation
*/
longDescription?: string;
/**
* Augmentation category for organization
*/
category: 'storage' | 'performance' | 'analytics' | 'integration' | 'internal' | 'core' | 'premium' | 'community' | 'external';
/**
* JSON Schema for configuration options
* Used to generate configuration UIs and validate configuration
*/
configSchema?: JSONSchema;
/**
* Default configuration values
*/
configDefaults?: Record<string, any>;
/**
* Configuration examples for documentation
*/
configExamples?: Array<{
name: string;
description: string;
config: Record<string, any>;
}>;
/**
* Minimum Brainy version required
*/
minBrainyVersion?: string;
/**
* Maximum Brainy version supported
*/
maxBrainyVersion?: string;
/**
* Other augmentations this one depends on
*/
dependencies?: Array<{
id: string;
version?: string;
optional?: boolean;
}>;
/**
* Keywords for search and discovery
*/
keywords?: string[];
/**
* URL to documentation
*/
documentation?: string;
/**
* URL to source code repository
*/
repository?: string;
/**
* License identifier (e.g., 'MIT', 'Apache-2.0')
*/
license?: string;
/**
* UI hints for tools and configuration interfaces
*/
ui?: {
/**
* Icon for the augmentation (emoji or URL)
*/
icon?: string;
/**
* Color theme for UI
*/
color?: string;
/**
* Custom React component name for configuration
*/
configComponent?: string;
/**
* URL to dashboard or control panel
*/
dashboardUrl?: string;
/**
* Hide from UI listings
*/
hidden?: boolean;
};
/**
* Performance characteristics
*/
performance?: {
/**
* Estimated memory usage
*/
memoryUsage?: 'low' | 'medium' | 'high';
/**
* CPU intensity
*/
cpuUsage?: 'low' | 'medium' | 'high';
/**
* Network usage
*/
networkUsage?: 'none' | 'low' | 'medium' | 'high';
};
/**
* Feature flags this augmentation provides
*/
features?: string[];
/**
* Operations this augmentation enhances
*/
enhancedOperations?: string[];
/**
* Metrics this augmentation exposes
*/
metrics?: Array<{
name: string;
type: 'counter' | 'gauge' | 'histogram';
description: string;
}>;
/**
* Status of the augmentation
*/
status?: 'stable' | 'beta' | 'experimental' | 'deprecated';
/**
* Deprecation notice if applicable
*/
deprecation?: {
since: string;
alternative?: string;
removalDate?: string;
};
}

View file

@ -0,0 +1,8 @@
/**
* Augmentation Manifest Types
*
* Defines the manifest structure for augmentation discovery and configuration
* Enables tools like brain-cloud to discover and configure augmentations
*/
export {};
//# sourceMappingURL=manifest.js.map

View file

@ -0,0 +1 @@
{"version":3,"file":"manifest.js","sourceRoot":"","sources":["../../src/augmentations/manifest.ts"],"names":[],"mappings":"AAAA;;;;;GAKG"}

View file

@ -0,0 +1,72 @@
import { AugmentationType, IMemoryAugmentation, AugmentationResponse } from '../types/augmentations.js';
import { StorageAdapter } from '../coreTypes.js';
/**
* Base class for memory augmentations that wrap a StorageAdapter
*/
declare abstract class BaseMemoryAugmentation implements IMemoryAugmentation {
readonly name: string;
readonly description: string;
enabled: boolean;
protected storage: StorageAdapter;
protected isInitialized: boolean;
constructor(name: string, storage: StorageAdapter);
initialize(): Promise<void>;
shutDown(): Promise<void>;
getStatus(): Promise<'active' | 'inactive' | 'error'>;
storeData(key: string, data: unknown, options?: Record<string, unknown>): Promise<AugmentationResponse<boolean>>;
retrieveData(key: string, options?: Record<string, unknown>): Promise<AugmentationResponse<unknown>>;
updateData(key: string, data: unknown, options?: Record<string, unknown>): Promise<AugmentationResponse<boolean>>;
deleteData(key: string, options?: Record<string, unknown>): Promise<AugmentationResponse<boolean>>;
listDataKeys(pattern?: string, options?: Record<string, unknown>): Promise<AugmentationResponse<string[]>>;
/**
* Searches for data in the storage using vector similarity.
* Implements the findNearest functionality by calculating distances client-side.
* @param query The query vector or data to search for
* @param k Number of results to return (default: 10)
* @param options Optional search options
*/
search(query: unknown, k?: number, options?: Record<string, unknown>): Promise<AugmentationResponse<Array<{
id: string;
score: number;
data: unknown;
}>>>;
protected ensureInitialized(): Promise<void>;
}
/**
* Memory augmentation that uses in-memory storage
*/
export declare class MemoryStorageAugmentation extends BaseMemoryAugmentation {
readonly description = "Memory augmentation that stores data in memory";
enabled: boolean;
constructor(name: string);
getType(): AugmentationType;
}
/**
* Memory augmentation that uses file system storage
*/
export declare class FileSystemStorageAugmentation extends BaseMemoryAugmentation {
readonly description = "Memory augmentation that stores data in the file system";
enabled: boolean;
private rootDirectory;
constructor(name: string, rootDirectory?: string);
initialize(): Promise<void>;
getType(): AugmentationType;
}
/**
* Memory augmentation that uses OPFS (Origin Private File System) storage
*/
export declare class OPFSStorageAugmentation extends BaseMemoryAugmentation {
readonly description = "Memory augmentation that stores data in the Origin Private File System";
enabled: boolean;
constructor(name: string);
getType(): AugmentationType;
}
/**
* Factory function to create the appropriate memory augmentation based on the environment
*/
export declare function createMemoryAugmentation(name: string, options?: {
storageType?: 'memory' | 'filesystem' | 'opfs';
rootDirectory?: string;
requestPersistentStorage?: boolean;
}): Promise<IMemoryAugmentation>;
export {};

View file

@ -0,0 +1,280 @@
import { AugmentationType } from '../types/augmentations.js';
import { MemoryStorage, OPFSStorage } from '../storage/storageFactory.js';
// FileSystemStorage will be dynamically imported when needed to avoid fs imports in browser
import { cosineDistance } from '../utils/distance.js';
/**
* Base class for memory augmentations that wrap a StorageAdapter
*/
class BaseMemoryAugmentation {
constructor(name, storage) {
this.description = 'Base memory augmentation';
this.enabled = true;
this.isInitialized = false;
this.name = name;
this.storage = storage;
}
async initialize() {
if (this.isInitialized) {
return;
}
try {
await this.storage.init();
this.isInitialized = true;
}
catch (error) {
console.error(`Failed to initialize ${this.name}:`, error);
throw new Error(`Failed to initialize ${this.name}: ${error}`);
}
}
async shutDown() {
this.isInitialized = false;
}
async getStatus() {
return this.isInitialized ? 'active' : 'inactive';
}
async storeData(key, data, options) {
await this.ensureInitialized();
try {
await this.storage.saveMetadata(key, data);
return { success: true, data: true };
}
catch (error) {
console.error(`Failed to store data for key ${key}:`, error);
return {
success: false,
data: false,
error: `Failed to store data: ${error}`
};
}
}
async retrieveData(key, options) {
await this.ensureInitialized();
try {
const data = await this.storage.getMetadata(key);
return {
success: true,
data
};
}
catch (error) {
console.error(`Failed to retrieve data for key ${key}:`, error);
return {
success: false,
data: null,
error: `Failed to retrieve data: ${error}`
};
}
}
async updateData(key, data, options) {
await this.ensureInitialized();
try {
await this.storage.saveMetadata(key, data);
return { success: true, data: true };
}
catch (error) {
console.error(`Failed to update data for key ${key}:`, error);
return {
success: false,
data: false,
error: `Failed to update data: ${error}`
};
}
}
async deleteData(key, options) {
await this.ensureInitialized();
try {
// There's no direct deleteMetadata method, so we save null
await this.storage.saveMetadata(key, null);
return { success: true, data: true };
}
catch (error) {
console.error(`Failed to delete data for key ${key}:`, error);
return {
success: false,
data: false,
error: `Failed to delete data: ${error}`
};
}
}
async listDataKeys(pattern, options) {
// This is a limitation of the current StorageAdapter interface
// It doesn't provide a way to list all metadata keys
// We could implement this in the future by extending the StorageAdapter interface
return {
success: false,
data: [],
error: 'listDataKeys is not supported by this storage adapter'
};
}
/**
* Searches for data in the storage using vector similarity.
* Implements the findNearest functionality by calculating distances client-side.
* @param query The query vector or data to search for
* @param k Number of results to return (default: 10)
* @param options Optional search options
*/
async search(query, k = 10, options) {
await this.ensureInitialized();
try {
// Check if query is a vector
let queryVector;
if (Array.isArray(query) && query.every(item => typeof item === 'number')) {
queryVector = query;
}
else {
// If query is not a vector, we can't perform vector search
return {
success: false,
data: [],
error: 'Query must be a vector (array of numbers) for vector search'
};
}
// Process nodes in batches to avoid loading everything into memory
const allResults = [];
let hasMore = true;
let cursor;
while (hasMore) {
// Get a batch of nodes
const batchResult = await this.storage.getNouns({
pagination: { limit: 100, cursor }
});
// Process this batch
for (const noun of batchResult.items) {
// Skip nodes that don't have a vector
if (!noun.vector || !Array.isArray(noun.vector)) {
continue;
}
// Get metadata for the node
const metadata = await this.storage.getMetadata(noun.id);
// Calculate distance between query vector and node vector
const distance = cosineDistance(queryVector, noun.vector);
// Convert distance to similarity score (1 - distance for cosine)
// This way higher scores are better (more similar)
const score = 1 - distance;
allResults.push({
id: noun.id,
score,
data: metadata
});
}
// Update pagination state
hasMore = batchResult.hasMore;
cursor = batchResult.nextCursor;
}
// Sort results by score (descending) and take top k
allResults.sort((a, b) => b.score - a.score);
const topResults = allResults.slice(0, k);
return {
success: true,
data: topResults
};
}
catch (error) {
console.error(`Failed to search in storage:`, error);
return {
success: false,
data: [],
error: `Failed to search in storage: ${error}`
};
}
}
async ensureInitialized() {
if (!this.isInitialized) {
await this.initialize();
}
}
}
/**
* Memory augmentation that uses in-memory storage
*/
export class MemoryStorageAugmentation extends BaseMemoryAugmentation {
constructor(name) {
super(name, new MemoryStorage());
this.description = 'Memory augmentation that stores data in memory';
this.enabled = true;
}
getType() {
return AugmentationType.MEMORY;
}
}
/**
* Memory augmentation that uses file system storage
*/
export class FileSystemStorageAugmentation extends BaseMemoryAugmentation {
constructor(name, rootDirectory) {
// Temporarily use MemoryStorage, will be replaced in initialize()
super(name, new MemoryStorage());
this.description = 'Memory augmentation that stores data in the file system';
this.enabled = true;
this.rootDirectory = rootDirectory || '.';
}
async initialize() {
try {
// Dynamically import FileSystemStorage
const { FileSystemStorage } = await import('../storage/adapters/fileSystemStorage.js');
this.storage = new FileSystemStorage(this.rootDirectory);
await super.initialize();
}
catch (error) {
console.error('Failed to load FileSystemStorage:', error);
throw new Error(`Failed to initialize FileSystemStorage: ${error}`);
}
}
getType() {
return AugmentationType.MEMORY;
}
}
/**
* Memory augmentation that uses OPFS (Origin Private File System) storage
*/
export class OPFSStorageAugmentation extends BaseMemoryAugmentation {
constructor(name) {
super(name, new OPFSStorage());
this.description = 'Memory augmentation that stores data in the Origin Private File System';
this.enabled = true;
}
getType() {
return AugmentationType.MEMORY;
}
}
/**
* Factory function to create the appropriate memory augmentation based on the environment
*/
export async function createMemoryAugmentation(name, options = {}) {
// If a specific storage type is requested, use that
if (options.storageType) {
switch (options.storageType) {
case 'memory':
return new MemoryStorageAugmentation(name);
case 'filesystem':
return new FileSystemStorageAugmentation(name, options.rootDirectory);
case 'opfs':
return new OPFSStorageAugmentation(name);
}
}
// Otherwise, select based on environment
// Use the global isNode variable from the environment detection
const isNodeEnv = globalThis.__ENV__?.isNode || (typeof process !== 'undefined' &&
process.versions != null &&
process.versions.node != null);
if (isNodeEnv) {
// In Node.js, use FileSystemStorage
return new FileSystemStorageAugmentation(name, options.rootDirectory);
}
else {
// In browser, try OPFS first
const opfsStorage = new OPFSStorage();
if (opfsStorage.isOPFSAvailable()) {
// Request persistent storage if specified
if (options.requestPersistentStorage) {
await opfsStorage.requestPersistentStorage();
}
return new OPFSStorageAugmentation(name);
}
else {
// Fall back to memory storage
return new MemoryStorageAugmentation(name);
}
}
}
//# sourceMappingURL=memoryAugmentations.js.map

File diff suppressed because one or more lines are too long

View file

@ -0,0 +1,20 @@
/**
* Runtime enforcement of metadata contracts
* Ensures augmentations only access declared fields
*/
import { BrainyAugmentation } from './brainyAugmentation.js';
export declare class MetadataEnforcer {
/**
* Enforce metadata access based on augmentation contract
* Returns a wrapped metadata object that enforces the contract
*/
static enforce(augmentation: BrainyAugmentation, metadata: any, operation?: 'read' | 'write'): any;
/**
* Validate that an augmentation's actual behavior matches its contract
* Used in testing to verify contracts are accurate
*/
static validateContract(augmentation: BrainyAugmentation, testMetadata?: any): Promise<{
valid: boolean;
violations: string[];
}>;
}

View file

@ -0,0 +1,171 @@
/**
* Runtime enforcement of metadata contracts
* Ensures augmentations only access declared fields
*/
export class MetadataEnforcer {
/**
* Enforce metadata access based on augmentation contract
* Returns a wrapped metadata object that enforces the contract
*/
static enforce(augmentation, metadata, operation = 'write') {
// Handle simple contracts
if (augmentation.metadata === 'none') {
// No access at all
if (operation === 'read')
return null;
throw new Error(`Augmentation '${augmentation.name}' has metadata='none' - cannot access metadata`);
}
if (augmentation.metadata === 'readonly') {
if (operation === 'read') {
// Return frozen deep clone for read-only access
return deepFreeze(deepClone(metadata));
}
throw new Error(`Augmentation '${augmentation.name}' has metadata='readonly' - cannot write`);
}
// Handle specific field access
const access = augmentation.metadata;
if (operation === 'read') {
// For reads, filter to allowed fields
if (access.reads === '*') {
return deepClone(metadata); // Can read everything
}
if (!access.reads) {
return {}; // No read access
}
// Filter to specific fields
const filtered = {};
for (const field of access.reads) {
if (field.includes('.')) {
// Handle nested fields like '_brainy.deleted'
const parts = field.split('.');
let source = metadata;
let target = filtered;
for (let i = 0; i < parts.length - 1; i++) {
const part = parts[i];
if (!source[part])
break;
if (!target[part])
target[part] = {};
source = source[part];
target = target[part];
}
const lastPart = parts[parts.length - 1];
if (source && lastPart in source) {
target[lastPart] = source[lastPart];
}
}
else {
// Simple field
if (field in metadata) {
filtered[field] = metadata[field];
}
}
}
return filtered;
}
// For writes, create a proxy that validates
return new Proxy(metadata, {
set(target, prop, value) {
const field = String(prop);
// Check if write is allowed
if (access.writes === '*') {
// Can write anything
target[prop] = value;
return true;
}
if (!access.writes || !access.writes.includes(field)) {
throw new Error(`Augmentation '${augmentation.name}' cannot write to field '${field}'. ` +
`Allowed writes: ${access.writes?.join(', ') || 'none'}`);
}
// Check namespace if specified
if (access.namespace && !field.startsWith(access.namespace)) {
console.warn(`Augmentation '${augmentation.name}' writing outside its namespace. ` +
`Expected: ${access.namespace}.*, got: ${field}`);
}
target[prop] = value;
return true;
},
deleteProperty(target, prop) {
const field = String(prop);
// Deletion counts as a write
if (access.writes === '*' || access.writes?.includes(field)) {
delete target[prop];
return true;
}
throw new Error(`Augmentation '${augmentation.name}' cannot delete field '${field}'`);
}
});
}
/**
* Validate that an augmentation's actual behavior matches its contract
* Used in testing to verify contracts are accurate
*/
static async validateContract(augmentation, testMetadata = { test: 'data', _brainy: { deleted: false } }) {
const violations = [];
// Test read access
try {
const readable = this.enforce(augmentation, testMetadata, 'read');
if (augmentation.metadata === 'none' && readable !== null) {
violations.push(`Contract says 'none' but got readable metadata`);
}
}
catch (error) {
violations.push(`Read enforcement error: ${error}`);
}
// Test write access
try {
const writable = this.enforce(augmentation, testMetadata, 'write');
if (augmentation.metadata === 'none') {
violations.push(`Contract says 'none' but got writable metadata`);
}
if (augmentation.metadata === 'readonly') {
// Try to write - should fail
try {
writable.testWrite = 'value';
violations.push(`Contract says 'readonly' but write succeeded`);
}
catch {
// Expected to fail
}
}
}
catch (error) {
// Expected for 'none' and 'readonly' on write
if (augmentation.metadata !== 'none' && augmentation.metadata !== 'readonly') {
violations.push(`Write enforcement error: ${error}`);
}
}
return {
valid: violations.length === 0,
violations
};
}
}
// Helper functions
function deepClone(obj) {
if (obj === null || typeof obj !== 'object')
return obj;
if (obj instanceof Date)
return new Date(obj);
if (obj instanceof Array)
return obj.map(item => deepClone(item));
const cloned = {};
for (const key in obj) {
if (obj.hasOwnProperty(key)) {
cloned[key] = deepClone(obj[key]);
}
}
return cloned;
}
function deepFreeze(obj) {
Object.freeze(obj);
Object.getOwnPropertyNames(obj).forEach(prop => {
if (obj[prop] !== null &&
(typeof obj[prop] === 'object' || typeof obj[prop] === 'function') &&
!Object.isFrozen(obj[prop])) {
deepFreeze(obj[prop]);
}
});
return obj;
}
//# sourceMappingURL=metadataEnforcer.js.map

File diff suppressed because one or more lines are too long

View file

@ -0,0 +1,197 @@
/**
* Metrics Augmentation - Optional Performance & Usage Metrics
*
* Replaces the hardcoded StatisticsCollector in Brainy with an optional augmentation.
* Tracks performance metrics, usage patterns, and system statistics.
*
* Zero-config: Automatically enabled for observability
* Can be disabled or customized via augmentation registry
*/
import { BaseAugmentation } from './brainyAugmentation.js';
export interface MetricsConfig {
enabled?: boolean;
trackSearches?: boolean;
trackContentTypes?: boolean;
trackVerbTypes?: boolean;
trackStorageSizes?: boolean;
persistMetrics?: boolean;
metricsInterval?: number;
}
/**
* MetricsAugmentation - Makes metrics collection optional and pluggable
*
* Features:
* - Performance tracking (search latency, throughput)
* - Usage patterns (content types, verb types)
* - Storage metrics (sizes, counts)
* - Zero-config with smart defaults
*/
export declare class MetricsAugmentation extends BaseAugmentation {
readonly metadata: "readonly";
readonly name = "metrics";
readonly timing: "after";
operations: ("add" | "update" | "search" | "find" | "similar" | "delete" | "relate" | "unrelate" | "clear" | "all")[];
readonly priority = 40;
private statisticsCollector;
protected config: MetricsConfig;
private metricsTimer;
constructor(config?: MetricsConfig);
protected onInitialize(): Promise<void>;
protected onShutdown(): Promise<void>;
/**
* Execute augmentation - track metrics for operations
*/
execute<T = any>(operation: string, params: any, next: () => Promise<T>): Promise<T>;
/**
* Handle add operation metrics
*/
private handleAdd;
/**
* Handle search operation metrics
*/
private handleSearch;
/**
* Handle delete operation metrics
*/
private handleDelete;
/**
* Handle clear operation - reset metrics
*/
private handleClear;
/**
* Start periodic metrics update timer
*/
private startMetricsTimer;
/**
* Update storage size metrics
*/
private updateStorageMetrics;
/**
* Persist metrics to storage
*/
private persistMetrics;
/**
* Get current metrics
*/
getStatistics(): {
enabled: boolean;
totalSearches: number;
totalUpdates: number;
contentTypes: {};
verbTypes: {};
searchPerformance: {
averageLatency: number;
p95Latency: number;
p99Latency: number;
};
} | {
nounCount?: Record<string, number> | undefined;
verbCount?: Record<string, number> | undefined;
metadataCount?: Record<string, number> | undefined;
hnswIndexSize?: number | undefined;
totalNodes?: number | undefined;
totalEdges?: number | undefined;
totalMetadata?: number | undefined;
operations?: {
add: number;
search: number;
delete: number;
update: number;
relate: number;
total: number;
} | undefined;
fieldNames?: Record<string, string[]> | undefined;
standardFieldMappings?: Record<string, Record<string, string[]>> | undefined;
contentTypes?: Record<string, number> | undefined;
dataFreshness?: {
oldestEntry: string;
newestEntry: string;
updatesLastHour: number;
updatesLastDay: number;
ageDistribution: {
last24h: number;
last7d: number;
last30d: number;
older: number;
};
} | undefined;
storageMetrics?: {
totalSizeBytes: number;
nounsSizeBytes: number;
verbsSizeBytes: number;
metadataSizeBytes: number;
indexSizeBytes: number;
} | undefined;
searchMetrics?: {
totalSearches: number;
averageSearchTimeMs: number;
searchesLastHour: number;
searchesLastDay: number;
topSearchTerms?: string[];
} | undefined;
verbStatistics?: {
totalVerbs: number;
verbTypes: Record<string, number>;
averageConnectionsPerVerb: number;
} | undefined;
serviceActivity?: Record<string, {
firstActivity: string;
lastActivity: string;
totalOperations: number;
}> | undefined;
services?: import("../coreTypes.js").ServiceStatistics[] | undefined;
throttlingMetrics?: {
storage?: {
currentlyThrottled: boolean;
lastThrottleTime?: string;
consecutiveThrottleEvents: number;
currentBackoffMs: number;
totalThrottleEvents: number;
throttleEventsByHour?: number[];
throttleReasons?: Record<string, number>;
};
operationImpact?: {
delayedOperations: number;
retriedOperations: number;
failedDueToThrottling: number;
averageDelayMs: number;
totalDelayMs: number;
};
serviceThrottling?: Record<string, {
throttleCount: number;
lastThrottle: string;
status: "normal" | "throttled" | "recovering";
}>;
} | undefined;
lastUpdated?: string | undefined;
distributedConfig?: import("../types/distributedTypes.js").SharedConfig | undefined;
enabled: boolean;
totalSearches?: undefined;
totalUpdates?: undefined;
verbTypes?: undefined;
searchPerformance?: undefined;
};
/**
* Record cache hit (called by cache augmentation)
* Note: Cache metrics are tracked internally by StatisticsCollector
*/
recordCacheHit(): void;
/**
* Record cache miss (called by cache augmentation)
* Note: Cache metrics are tracked internally by StatisticsCollector
*/
recordCacheMiss(): void;
/**
* Track custom metric
* Note: Custom metrics would need to be implemented in StatisticsCollector
*/
trackCustomMetric(name: string, value: number): void;
/**
* Reset all metrics
*/
reset(): void;
}
/**
* Factory function for zero-config metrics augmentation
*/
export declare function createMetricsAugmentation(config?: MetricsConfig): MetricsAugmentation;

View file

@ -0,0 +1,292 @@
/**
* Metrics Augmentation - Optional Performance & Usage Metrics
*
* Replaces the hardcoded StatisticsCollector in Brainy with an optional augmentation.
* Tracks performance metrics, usage patterns, and system statistics.
*
* Zero-config: Automatically enabled for observability
* Can be disabled or customized via augmentation registry
*/
import { BaseAugmentation } from './brainyAugmentation.js';
import { StatisticsCollector } from '../utils/statisticsCollector.js';
/**
* MetricsAugmentation - Makes metrics collection optional and pluggable
*
* Features:
* - Performance tracking (search latency, throughput)
* - Usage patterns (content types, verb types)
* - Storage metrics (sizes, counts)
* - Zero-config with smart defaults
*/
export class MetricsAugmentation extends BaseAugmentation {
constructor(config = {}) {
super();
this.metadata = 'readonly'; // Reads metadata for metrics
this.name = 'metrics';
this.timing = 'after';
this.operations = ['add', 'update', 'search', 'find', 'similar', 'delete', 'relate', 'unrelate', 'clear', 'all'];
this.priority = 40; // Low priority, runs after other augmentations
this.statisticsCollector = null;
this.metricsTimer = null;
this.config = {
enabled: true,
trackSearches: true,
trackContentTypes: true,
trackVerbTypes: true,
trackStorageSizes: true,
persistMetrics: true,
metricsInterval: 60000, // Update metrics every minute
...config
};
}
async onInitialize() {
if (!this.config.enabled) {
this.log('Metrics augmentation disabled by configuration');
return;
}
// Initialize statistics collector
this.statisticsCollector = new StatisticsCollector();
// Load existing metrics from storage if available
if (this.config.persistMetrics && this.context?.storage) {
try {
const storage = this.context.storage;
const existingStats = await storage.getStatistics?.();
if (existingStats) {
this.statisticsCollector.mergeFromStorage(existingStats);
this.log('Loaded existing metrics from storage');
}
}
catch (e) {
this.log('Could not load existing metrics', 'info');
}
}
// Start metrics update timer
if (this.config.metricsInterval && this.config.metricsInterval > 0) {
this.startMetricsTimer();
}
this.log('Metrics augmentation initialized');
}
async onShutdown() {
// Stop metrics timer
if (this.metricsTimer) {
clearInterval(this.metricsTimer);
this.metricsTimer = null;
}
// Persist final metrics
if (this.config.persistMetrics && this.statisticsCollector && this.context?.storage) {
try {
await this.persistMetrics();
}
catch (error) {
this.log('Error persisting metrics during shutdown', 'warn');
}
}
this.statisticsCollector = null;
this.log('Metrics augmentation shut down');
}
/**
* Execute augmentation - track metrics for operations
*/
async execute(operation, params, next) {
// If metrics disabled, just pass through
if (!this.statisticsCollector || !this.config.enabled) {
return next();
}
// Track operation timing
const startTime = Date.now();
try {
const result = await next();
const duration = Date.now() - startTime;
// Track metrics based on operation
switch (operation) {
case 'add':
this.handleAdd(params, duration);
break;
case 'search':
this.handleSearch(params, duration);
break;
case 'delete':
this.handleDelete(duration);
break;
case 'clear':
this.handleClear();
break;
}
return result;
}
catch (error) {
// Error tracking removed - StatisticsCollector doesn't have trackError method
// Could be added later if needed
throw error;
}
}
/**
* Handle add operation metrics
*/
handleAdd(params, duration) {
if (!this.statisticsCollector)
return;
// Track update
this.statisticsCollector.trackUpdate();
// Track content type if available
if (this.config.trackContentTypes && params.metadata?.noun) {
this.statisticsCollector.trackContentType(params.metadata.noun);
}
// Track verb type if it's a verb operation
if (this.config.trackVerbTypes && params.metadata?.verb) {
this.statisticsCollector.trackVerbType(params.metadata.verb);
}
this.log(`Add operation completed in ${duration}ms`, 'info');
}
/**
* Handle search operation metrics
*/
handleSearch(params, duration) {
if (!this.statisticsCollector || !this.config.trackSearches)
return;
const { query } = params;
this.statisticsCollector.trackSearch(query || '', duration);
this.log(`Search completed in ${duration}ms`, 'info');
}
/**
* Handle delete operation metrics
*/
handleDelete(duration) {
if (!this.statisticsCollector)
return;
this.statisticsCollector.trackUpdate();
this.log(`Delete operation completed in ${duration}ms`, 'info');
}
/**
* Handle clear operation - reset metrics
*/
handleClear() {
if (!this.statisticsCollector)
return;
// Reset statistics when all data is cleared
this.statisticsCollector = new StatisticsCollector();
this.log('Metrics reset due to clear operation');
}
/**
* Start periodic metrics update timer
*/
startMetricsTimer() {
if (this.metricsTimer)
return;
this.metricsTimer = setInterval(async () => {
await this.updateStorageMetrics();
if (this.config.persistMetrics) {
await this.persistMetrics();
}
}, this.config.metricsInterval);
}
/**
* Update storage size metrics
*/
async updateStorageMetrics() {
if (!this.statisticsCollector || !this.config.trackStorageSizes)
return;
if (!this.context?.storage)
return;
try {
const storage = this.context.storage;
const stats = await storage.getStatistics?.();
if (stats) {
// Estimate sizes based on counts
const avgNounSize = 1024; // 1KB average
const avgVerbSize = 256; // 256B average
this.statisticsCollector.updateStorageSizes({
nouns: (stats.totalNodes || 0) * avgNounSize,
verbs: (stats.totalEdges || 0) * avgVerbSize,
metadata: (stats.totalNodes || 0) * 512, // 512B per metadata
index: (stats.hnswIndexSize || 0) // Use HNSW index size from stats
});
}
}
catch (e) {
this.log('Could not update storage metrics', 'info');
}
}
/**
* Persist metrics to storage
*/
async persistMetrics() {
if (!this.statisticsCollector || !this.context?.storage)
return;
try {
const stats = this.statisticsCollector.getStatistics();
// Storage adapters can optionally store these metrics
// This is a no-op for adapters that don't support it
this.log('Metrics persisted to storage', 'info');
}
catch (e) {
this.log('Could not persist metrics', 'info');
}
}
/**
* Get current metrics
*/
getStatistics() {
if (!this.statisticsCollector) {
return {
enabled: false,
totalSearches: 0,
totalUpdates: 0,
contentTypes: {},
verbTypes: {},
searchPerformance: {
averageLatency: 0,
p95Latency: 0,
p99Latency: 0
}
};
}
return {
enabled: true,
...this.statisticsCollector.getStatistics()
};
}
/**
* Record cache hit (called by cache augmentation)
* Note: Cache metrics are tracked internally by StatisticsCollector
*/
recordCacheHit() {
// StatisticsCollector doesn't have trackCacheHit method
// Cache metrics would need to be implemented if needed
this.log('Cache hit recorded', 'info');
}
/**
* Record cache miss (called by cache augmentation)
* Note: Cache metrics are tracked internally by StatisticsCollector
*/
recordCacheMiss() {
// StatisticsCollector doesn't have trackCacheMiss method
// Cache metrics would need to be implemented if needed
this.log('Cache miss recorded', 'info');
}
/**
* Track custom metric
* Note: Custom metrics would need to be implemented in StatisticsCollector
*/
trackCustomMetric(name, value) {
// StatisticsCollector doesn't have trackCustomMetric method
// Could be added later if needed
this.log(`Custom metric recorded: ${name}=${value}`, 'info');
}
/**
* Reset all metrics
*/
reset() {
if (this.statisticsCollector) {
this.statisticsCollector = new StatisticsCollector();
this.log('Metrics manually reset');
}
}
}
/**
* Factory function for zero-config metrics augmentation
*/
export function createMetricsAugmentation(config) {
return new MetricsAugmentation(config);
}
//# sourceMappingURL=metricsAugmentation.js.map

File diff suppressed because one or more lines are too long

View file

@ -0,0 +1,95 @@
/**
* Monitoring Augmentation - Optional Health & Performance Monitoring
*
* Replaces the hardcoded HealthMonitor in Brainy with an optional augmentation.
* Provides health checks, performance monitoring, and distributed system tracking.
*
* Zero-config: Automatically enabled for distributed deployments
* Can be disabled or customized via augmentation registry
*/
import { BaseAugmentation } from './brainyAugmentation.js';
export interface MonitoringConfig {
enabled?: boolean;
healthCheckInterval?: number;
metricsInterval?: number;
trackLatency?: boolean;
trackErrors?: boolean;
trackCacheMetrics?: boolean;
exposeHealthEndpoint?: boolean;
}
/**
* MonitoringAugmentation - Makes health monitoring optional and pluggable
*
* Features:
* - Health status tracking
* - Performance monitoring
* - Error rate tracking
* - Distributed system health
* - Zero-config with smart defaults
*/
export declare class MonitoringAugmentation extends BaseAugmentation {
readonly metadata: "readonly";
readonly name = "monitoring";
readonly timing: "after";
operations: ("search" | "find" | "similar" | "add" | "update" | "delete" | "relate" | "unrelate" | "all")[];
readonly priority = 30;
private healthMonitor;
private configManager;
protected config: MonitoringConfig;
private requestStartTimes;
constructor(config?: MonitoringConfig);
protected onInitialize(): Promise<void>;
protected onShutdown(): Promise<void>;
/**
* Execute augmentation - track health metrics
*/
execute<T = any>(operation: string, params: any, next: () => Promise<T>): Promise<T>;
/**
* Get health status
*/
getHealthStatus(): {
status: string;
enabled: boolean;
uptime: number;
vectorCount: number;
requestRate: number;
errorRate: number;
cacheHitRate: number;
} | {
status: string;
enabled: boolean;
uptime?: undefined;
vectorCount?: undefined;
requestRate?: undefined;
errorRate?: undefined;
cacheHitRate?: undefined;
};
/**
* Get health endpoint data (for API exposure)
*/
getHealthEndpointData(): Record<string, any>;
/**
* Update vector count manually
*/
updateVectorCount(count: number): void;
/**
* Record custom health metric
*/
recordCustomMetric(name: string, value: number): void;
/**
* Check if system is healthy
*/
isHealthy(): boolean;
/**
* Get uptime in milliseconds
*/
getUptime(): number;
/**
* Force health check
*/
checkHealth(): Promise<boolean>;
}
/**
* Factory function for zero-config monitoring augmentation
*/
export declare function createMonitoringAugmentation(config?: MonitoringConfig): MonitoringAugmentation;

View file

@ -0,0 +1,228 @@
/**
* Monitoring Augmentation - Optional Health & Performance Monitoring
*
* Replaces the hardcoded HealthMonitor in Brainy with an optional augmentation.
* Provides health checks, performance monitoring, and distributed system tracking.
*
* Zero-config: Automatically enabled for distributed deployments
* Can be disabled or customized via augmentation registry
*/
import { BaseAugmentation } from './brainyAugmentation.js';
import { HealthMonitor } from '../distributed/healthMonitor.js';
import { DistributedConfigManager as ConfigManager } from '../distributed/configManager.js';
/**
* MonitoringAugmentation - Makes health monitoring optional and pluggable
*
* Features:
* - Health status tracking
* - Performance monitoring
* - Error rate tracking
* - Distributed system health
* - Zero-config with smart defaults
*/
export class MonitoringAugmentation extends BaseAugmentation {
constructor(config = {}) {
super();
this.metadata = 'readonly'; // Reads metadata for monitoring
this.name = 'monitoring';
this.timing = 'after';
this.operations = ['search', 'find', 'similar', 'add', 'update', 'delete', 'relate', 'unrelate', 'all'];
this.priority = 30; // Low priority, observability layer
this.healthMonitor = null;
this.configManager = null;
this.requestStartTimes = new Map();
this.config = {
enabled: true,
healthCheckInterval: 30000, // 30 seconds
metricsInterval: 60000, // 1 minute
trackLatency: true,
trackErrors: true,
trackCacheMetrics: true,
exposeHealthEndpoint: true,
...config
};
}
async onInitialize() {
if (!this.config.enabled) {
this.log('Monitoring augmentation disabled by configuration');
return;
}
// Initialize config manager and health monitor (requires storage)
if (this.context?.storage) {
this.configManager = new ConfigManager(this.context.storage);
this.healthMonitor = new HealthMonitor(this.configManager);
this.healthMonitor.start();
}
else {
this.log('Storage not available - health monitoring disabled', 'warn');
}
this.log('Monitoring augmentation initialized');
}
async onShutdown() {
if (this.healthMonitor) {
this.healthMonitor.stop();
this.healthMonitor = null;
}
this.configManager = null;
this.requestStartTimes.clear();
this.log('Monitoring augmentation shut down');
}
/**
* Execute augmentation - track health metrics
*/
async execute(operation, params, next) {
// If monitoring disabled, just pass through
if (!this.healthMonitor || !this.config.enabled) {
return next();
}
// Generate request ID for tracking
const requestId = `${operation}-${Date.now()}-${Math.random()}`;
// Track request start time
if (this.config.trackLatency) {
this.requestStartTimes.set(requestId, Date.now());
}
try {
// Execute operation
const result = await next();
// Track successful operation
if (this.config.trackLatency) {
const startTime = this.requestStartTimes.get(requestId);
if (startTime) {
const latency = Date.now() - startTime;
this.healthMonitor.recordRequest(latency, false);
this.requestStartTimes.delete(requestId);
}
}
// Update vector count for 'add' operations
if (operation === 'add' && this.context?.brain) {
try {
const count = await this.context.brain.getNounCount();
this.healthMonitor.updateVectorCount(count);
}
catch (e) {
// Ignore count update errors
}
}
// Track cache metrics for search operations
if (operation === 'search' && this.config.trackCacheMetrics) {
// Check if result came from cache (would be set by cache augmentation)
const fromCache = params._fromCache || false;
this.healthMonitor.recordCacheAccess(fromCache);
}
return result;
}
catch (error) {
// Track error
if (this.config.trackErrors) {
const startTime = this.requestStartTimes.get(requestId);
if (startTime) {
const latency = Date.now() - startTime;
this.healthMonitor.recordRequest(latency, true);
this.requestStartTimes.delete(requestId);
}
else {
this.healthMonitor.recordRequest(0, true);
}
}
throw error;
}
}
/**
* Get health status
*/
getHealthStatus() {
if (!this.healthMonitor) {
return {
status: 'disabled',
enabled: false,
uptime: 0,
vectorCount: 0,
requestRate: 0,
errorRate: 0,
cacheHitRate: 0
};
}
return {
status: 'healthy',
enabled: true,
...this.healthMonitor.getHealthEndpointData()
};
}
/**
* Get health endpoint data (for API exposure)
*/
getHealthEndpointData() {
if (!this.healthMonitor) {
return {
status: 'disabled',
timestamp: new Date().toISOString()
};
}
return this.healthMonitor.getHealthEndpointData();
}
/**
* Update vector count manually
*/
updateVectorCount(count) {
if (this.healthMonitor) {
this.healthMonitor.updateVectorCount(count);
}
}
/**
* Record custom health metric
*/
recordCustomMetric(name, value) {
if (this.healthMonitor) {
// Health monitor could be extended to track custom metrics
this.log(`Custom metric recorded: ${name}=${value}`, 'info');
}
}
/**
* Check if system is healthy
*/
isHealthy() {
if (!this.healthMonitor)
return true; // If disabled, assume healthy
const data = this.healthMonitor.getHealthEndpointData();
// Define health criteria
const errorRateThreshold = 0.05; // 5% error rate
const minUptime = 60000; // 1 minute
return (data.errorRate < errorRateThreshold &&
data.uptime > minUptime);
}
/**
* Get uptime in milliseconds
*/
getUptime() {
if (!this.healthMonitor)
return 0;
const data = this.healthMonitor.getHealthEndpointData();
return data.uptime || 0;
}
/**
* Force health check
*/
async checkHealth() {
if (!this.healthMonitor)
return true;
// Perform active health check
try {
// Could ping storage, check memory, etc.
if (this.context?.storage) {
await this.context.storage.getStatistics?.();
}
return true;
}
catch (error) {
this.log('Health check failed', 'warn');
return false;
}
}
}
/**
* Factory function for zero-config monitoring augmentation
*/
export function createMonitoringAugmentation(config) {
return new MonitoringAugmentation(config);
}
//# sourceMappingURL=monitoringAugmentation.js.map

File diff suppressed because one or more lines are too long

View file

@ -0,0 +1,145 @@
/**
* Neural Import Augmentation - AI-Powered Data Understanding
*
* 🧠 Built-in AI augmentation for intelligent data processing
* Always free, always included, always enabled
*
* Now using the unified BrainyAugmentation interface!
*/
import { BaseAugmentation } from './brainyAugmentation.js';
export interface NeuralAnalysisResult {
detectedEntities: DetectedEntity[];
detectedRelationships: DetectedRelationship[];
confidence: number;
insights: NeuralInsight[];
}
export interface DetectedEntity {
originalData: any;
nounType: string;
confidence: number;
suggestedId: string;
reasoning: string;
alternativeTypes: Array<{
type: string;
confidence: number;
}>;
}
export interface DetectedRelationship {
sourceId: string;
targetId: string;
verbType: string;
confidence: number;
weight: number;
reasoning: string;
context: string;
metadata?: Record<string, any>;
}
export interface NeuralInsight {
type: 'hierarchy' | 'cluster' | 'pattern' | 'anomaly' | 'opportunity';
description: string;
confidence: number;
affectedEntities: string[];
recommendation?: string;
}
export interface NeuralImportConfig {
confidenceThreshold: number;
enableWeights: boolean;
skipDuplicates: boolean;
categoryFilter?: string[];
dataType?: string;
}
/**
* Neural Import Augmentation - Unified Implementation
* Processes data with AI before storage operations
*/
export declare class NeuralImportAugmentation extends BaseAugmentation {
readonly name = "neural-import";
readonly timing: "before";
readonly metadata: {
reads: "*";
writes: string[];
};
operations: ("add" | "addNoun" | "addVerb" | "all")[];
readonly priority = 80;
protected config: NeuralImportConfig;
private analysisCache;
private typeMatcher;
constructor(config?: Partial<NeuralImportConfig>);
protected onInitialize(): Promise<void>;
protected onShutdown(): Promise<void>;
/**
* Execute augmentation - process data with AI before storage
*/
execute<T = any>(operation: string, params: any, next: () => Promise<T>): Promise<T>;
/**
* Extract raw data from operation params
*/
private extractRawData;
/**
* Get the full neural analysis result (for external use)
*/
getNeuralAnalysis(rawData: Buffer | string, dataType?: string): Promise<NeuralAnalysisResult>;
/**
* Parse raw data based on type
*/
private parseRawData;
/**
* Parse CSV data - handles quoted values, escaped quotes, and edge cases
*/
private parseCSV;
/**
* Parse YAML data
*/
private parseYAML;
/**
* Parse a YAML value (handle strings, numbers, booleans, null)
*/
private parseYAMLValue;
/**
* Perform neural analysis on parsed data
*/
private performNeuralAnalysis;
/**
* Infer noun type from object structure using intelligent type matching
*/
private inferNounType;
/**
* Detect relationships from object references
*/
private detectRelationships;
/**
* Infer verb type from field name using intelligent type matching
*/
private inferVerbType;
/**
* Group entities by type
*/
private groupByType;
/**
* Store neural analysis results
*/
private storeNeuralAnalysis;
/**
* Helper to get data type from file path
*/
private getDataTypeFromPath;
/**
* PUBLIC API: Process raw data (for external use, like Synapses)
* This maintains compatibility with code that wants to use Neural Import directly
*/
processRawData(rawData: Buffer | string, dataType: string, options?: Record<string, unknown>): Promise<{
success: boolean;
data: {
nouns: string[];
verbs: string[];
confidence?: number;
insights?: Array<{
type: string;
description: string;
confidence: number;
}>;
metadata?: Record<string, unknown>;
};
error?: string;
}>;
}

View file

@ -0,0 +1,520 @@
/**
* Neural Import Augmentation - AI-Powered Data Understanding
*
* 🧠 Built-in AI augmentation for intelligent data processing
* Always free, always included, always enabled
*
* Now using the unified BrainyAugmentation interface!
*/
import { BaseAugmentation } from './brainyAugmentation.js';
import * as path from '../universal/path.js';
import { getBrainyTypes } from './typeMatching/brainyTypes.js';
import { prodLog } from '../utils/logger.js';
/**
* Neural Import Augmentation - Unified Implementation
* Processes data with AI before storage operations
*/
export class NeuralImportAugmentation extends BaseAugmentation {
constructor(config = {}) {
super();
this.name = 'neural-import';
this.timing = 'before'; // Process data before storage
this.metadata = {
reads: '*', // Needs to read data for analysis
writes: ['_neuralProcessed', '_neuralConfidence', '_detectedEntities', '_detectedRelationships', '_neuralInsights', 'nounType', 'verbType']
}; // Enriches metadata with neural analysis
this.operations = ['add', 'addNoun', 'addVerb', 'all']; // Use 'all' to catch batch operations
this.priority = 80; // High priority for data processing
this.analysisCache = new Map();
this.typeMatcher = null;
this.config = {
confidenceThreshold: 0.7,
enableWeights: true,
skipDuplicates: true,
dataType: 'json',
...config
};
}
async onInitialize() {
try {
this.typeMatcher = await getBrainyTypes();
this.log('🧠 Neural Import augmentation initialized with intelligent type matching');
}
catch (error) {
this.log('⚠️ Failed to initialize type matcher, falling back to heuristics', 'warn');
}
}
async onShutdown() {
this.analysisCache.clear();
this.log('🧠 Neural Import augmentation shut down');
}
/**
* Execute augmentation - process data with AI before storage
*/
async execute(operation, params, next) {
// Only process on add operations
if (!this.operations.includes(operation)) {
return next();
}
try {
// Extract data from params based on operation
const rawData = this.extractRawData(operation, params);
if (!rawData) {
return next();
}
// Perform neural analysis
const analysis = await this.performNeuralAnalysis(rawData, this.config);
// Enhance params with neural insights
if (params.metadata) {
params.metadata._neuralProcessed = true;
params.metadata._neuralConfidence = analysis.confidence;
params.metadata._detectedEntities = analysis.detectedEntities.length;
params.metadata._detectedRelationships = analysis.detectedRelationships.length;
params.metadata._neuralInsights = analysis.insights;
}
else if (typeof params === 'object') {
params.metadata = {
_neuralProcessed: true,
_neuralConfidence: analysis.confidence,
_detectedEntities: analysis.detectedEntities.length,
_detectedRelationships: analysis.detectedRelationships.length,
_neuralInsights: analysis.insights
};
}
// Store neural analysis for later retrieval
await this.storeNeuralAnalysis(analysis);
// If we detected entities/relationships, potentially add them
if (this.context?.brain && analysis.detectedEntities.length > 0) {
// This could automatically create entities/relationships
// But for now, just enhance the metadata
this.log(`Detected ${analysis.detectedEntities.length} entities and ${analysis.detectedRelationships.length} relationships`);
}
// Continue with enhanced data
return next();
}
catch (error) {
this.log(`Neural analysis failed: ${error}`, 'warn');
// Continue without neural processing
return next();
}
}
/**
* Extract raw data from operation params
*/
extractRawData(operation, params) {
switch (operation) {
case 'add':
return params.content || params.data || params;
case 'addNoun':
return params.noun || params.data || params;
case 'addVerb':
return params.verb || params;
case 'addBatch':
return params.items || params.batch || params;
default:
return null;
}
}
/**
* Get the full neural analysis result (for external use)
*/
async getNeuralAnalysis(rawData, dataType) {
const parsedData = await this.parseRawData(rawData, dataType || this.config.dataType || 'json');
return await this.performNeuralAnalysis(parsedData, this.config);
}
/**
* Parse raw data based on type
*/
async parseRawData(rawData, dataType) {
const content = typeof rawData === 'string' ? rawData : rawData.toString('utf8');
switch (dataType.toLowerCase()) {
case 'json':
try {
const jsonData = JSON.parse(content);
return Array.isArray(jsonData) ? jsonData : [jsonData];
}
catch {
// If JSON parse fails, treat as text
return [{ text: content }];
}
case 'csv':
return this.parseCSV(content);
case 'yaml':
case 'yml':
return this.parseYAML(content);
case 'txt':
case 'text':
// Split text into sentences/paragraphs for analysis
return content.split(/\n+/).filter(line => line.trim()).map(line => ({ text: line }));
default:
// Unknown type, treat as text
return [{ text: content }];
}
}
/**
* Parse CSV data - handles quoted values, escaped quotes, and edge cases
*/
parseCSV(content) {
const lines = content.split('\n');
if (lines.length === 0)
return [];
// Parse a CSV line handling quotes
const parseLine = (line) => {
const result = [];
let current = '';
let inQuotes = false;
let i = 0;
while (i < line.length) {
const char = line[i];
const nextChar = line[i + 1];
if (char === '"') {
if (inQuotes && nextChar === '"') {
// Escaped quote
current += '"';
i += 2;
}
else {
// Toggle quote mode
inQuotes = !inQuotes;
i++;
}
}
else if (char === ',' && !inQuotes) {
// Field separator
result.push(current.trim());
current = '';
i++;
}
else {
current += char;
i++;
}
}
// Add last field
result.push(current.trim());
return result;
};
// Parse headers
const headers = parseLine(lines[0]);
const data = [];
// Parse data rows
for (let i = 1; i < lines.length; i++) {
const line = lines[i].trim();
if (!line)
continue; // Skip empty lines
const values = parseLine(line);
const row = {};
headers.forEach((header, index) => {
const value = values[index] || '';
// Try to parse numbers
const num = Number(value);
row[header] = !isNaN(num) && value !== '' ? num : value;
});
data.push(row);
}
return data;
}
/**
* Parse YAML data
*/
parseYAML(content) {
try {
// Simple YAML parser for basic structures
// For full YAML support, we'd use js-yaml library
const lines = content.split('\n');
const result = [];
let currentObject = null;
let currentIndent = 0;
for (const line of lines) {
const trimmed = line.trim();
if (!trimmed || trimmed.startsWith('#'))
continue; // Skip empty lines and comments
// Calculate indentation
const indent = line.length - line.trimStart().length;
// Check for array item
if (trimmed.startsWith('- ')) {
const value = trimmed.substring(2).trim();
if (indent === 0) {
// Top-level array item
if (value.includes(':')) {
// Object in array
currentObject = {};
result.push(currentObject);
const [key, val] = value.split(':').map(s => s.trim());
currentObject[key] = this.parseYAMLValue(val);
}
else {
result.push(this.parseYAMLValue(value));
}
}
else if (currentObject) {
// Nested array
const lastKey = Object.keys(currentObject).pop();
if (lastKey) {
if (!Array.isArray(currentObject[lastKey])) {
currentObject[lastKey] = [];
}
currentObject[lastKey].push(this.parseYAMLValue(value));
}
}
}
else if (trimmed.includes(':')) {
// Key-value pair
const colonIndex = trimmed.indexOf(':');
const key = trimmed.substring(0, colonIndex).trim();
const value = trimmed.substring(colonIndex + 1).trim();
if (indent === 0) {
// Top-level object
if (!currentObject) {
currentObject = {};
result.push(currentObject);
}
currentObject[key] = this.parseYAMLValue(value);
currentIndent = 0;
}
else if (currentObject) {
// Nested object
if (indent > currentIndent && !value) {
// Start of nested object
const lastKey = Object.keys(currentObject).pop();
if (lastKey) {
currentObject[lastKey] = { [key]: '' };
}
}
else {
currentObject[key] = this.parseYAMLValue(value);
}
currentIndent = indent;
}
}
}
// If we built a single object and not an array, wrap it
if (result.length === 0 && currentObject) {
result.push(currentObject);
}
return result.length > 0 ? result : [{ text: content }];
}
catch (error) {
prodLog.warn('YAML parsing failed, treating as text:', error);
return [{ text: content }];
}
}
/**
* Parse a YAML value (handle strings, numbers, booleans, null)
*/
parseYAMLValue(value) {
if (!value || value === '~' || value === 'null')
return null;
if (value === 'true')
return true;
if (value === 'false')
return false;
// Remove quotes if present
if ((value.startsWith('"') && value.endsWith('"')) ||
(value.startsWith("'") && value.endsWith("'"))) {
return value.slice(1, -1);
}
// Try to parse as number
const num = Number(value);
if (!isNaN(num) && value !== '')
return num;
return value;
}
/**
* Perform neural analysis on parsed data
*/
async performNeuralAnalysis(data, config) {
const detectedEntities = [];
const detectedRelationships = [];
const insights = [];
// Simple entity detection (in real implementation, would use ML)
for (const item of data) {
if (typeof item === 'object') {
// Detect entities from object properties
const entityId = item.id || item.name || item.title || `entity_${Date.now()}_${Math.random()}`;
detectedEntities.push({
originalData: item,
nounType: await this.inferNounType(item),
confidence: 0.85,
suggestedId: String(entityId),
reasoning: 'Detected from structured data',
alternativeTypes: []
});
// Detect relationships from references
await this.detectRelationships(item, entityId, detectedRelationships);
}
}
// Generate insights
if (detectedEntities.length > 10) {
insights.push({
type: 'pattern',
description: `Large dataset with ${detectedEntities.length} entities detected`,
confidence: 0.9,
affectedEntities: detectedEntities.slice(0, 5).map(e => e.suggestedId),
recommendation: 'Consider batch processing for optimal performance'
});
}
// Look for clusters
const typeGroups = this.groupByType(detectedEntities);
if (Object.keys(typeGroups).length > 1) {
insights.push({
type: 'cluster',
description: `Multiple entity types detected: ${Object.keys(typeGroups).join(', ')}`,
confidence: 0.8,
affectedEntities: [],
recommendation: 'Data contains diverse entity types suitable for graph analysis'
});
}
return {
detectedEntities,
detectedRelationships,
confidence: detectedEntities.length > 0 ? 0.85 : 0.5,
insights
};
}
/**
* Infer noun type from object structure using intelligent type matching
*/
async inferNounType(obj) {
if (!this.typeMatcher) {
// Initialize type matcher if not available
this.typeMatcher = await getBrainyTypes();
}
const result = await this.typeMatcher.matchNounType(obj);
// Log if confidence is low for debugging
if (result.confidence < 0.5) {
this.log(`Low confidence (${result.confidence.toFixed(2)}) for noun type: ${result.type}`, 'warn');
}
return result.type;
}
/**
* Detect relationships from object references
*/
async detectRelationships(obj, sourceId, relationships) {
// Look for reference patterns
for (const [key, value] of Object.entries(obj)) {
if (key.endsWith('Id') || key.endsWith('_id') || key === 'parentId' || key === 'userId') {
relationships.push({
sourceId,
targetId: String(value),
verbType: await this.inferVerbType(key, obj, { id: value }),
confidence: 0.75,
weight: 1,
reasoning: `Reference detected in field: ${key}`,
context: key
});
}
// Array of IDs
if (Array.isArray(value) && value.length > 0 && typeof value[0] === 'string') {
if (key.endsWith('Ids') || key.endsWith('_ids')) {
for (const targetId of value) {
relationships.push({
sourceId,
targetId: String(targetId),
verbType: await this.inferVerbType(key, obj, { id: targetId }),
confidence: 0.7,
weight: 1,
reasoning: `Array reference in field: ${key}`,
context: key
});
}
}
}
}
}
/**
* Infer verb type from field name using intelligent type matching
*/
async inferVerbType(fieldName, sourceObj, targetObj) {
if (!this.typeMatcher) {
// Initialize type matcher if not available
this.typeMatcher = await getBrainyTypes();
}
const result = await this.typeMatcher.matchVerbType(sourceObj, targetObj, fieldName);
// Log if confidence is low for debugging
if (result.confidence < 0.5) {
this.log(`Low confidence (${result.confidence.toFixed(2)}) for verb type: ${result.type}`, 'warn');
}
return result.type;
}
/**
* Group entities by type
*/
groupByType(entities) {
const groups = {};
for (const entity of entities) {
if (!groups[entity.nounType]) {
groups[entity.nounType] = [];
}
groups[entity.nounType].push(entity);
}
return groups;
}
/**
* Store neural analysis results
*/
async storeNeuralAnalysis(analysis) {
// Cache the analysis for potential later use
const key = `analysis_${Date.now()}`;
this.analysisCache.set(key, analysis);
// Limit cache size
if (this.analysisCache.size > 100) {
const firstKey = this.analysisCache.keys().next().value;
if (firstKey) {
this.analysisCache.delete(firstKey);
}
}
}
/**
* Helper to get data type from file path
*/
getDataTypeFromPath(filePath) {
const ext = path.extname(filePath).toLowerCase();
switch (ext) {
case '.json': return 'json';
case '.csv': return 'csv';
case '.txt': return 'text';
case '.yaml':
case '.yml': return 'yaml';
default: return 'text';
}
}
/**
* PUBLIC API: Process raw data (for external use, like Synapses)
* This maintains compatibility with code that wants to use Neural Import directly
*/
async processRawData(rawData, dataType, options) {
try {
const analysis = await this.getNeuralAnalysis(rawData, dataType);
// Convert to legacy format for compatibility
const nouns = analysis.detectedEntities.map(e => e.suggestedId);
const verbs = analysis.detectedRelationships.map(r => `${r.sourceId}->${r.verbType}->${r.targetId}`);
return {
success: true,
data: {
nouns,
verbs,
confidence: analysis.confidence,
insights: analysis.insights.map(i => ({
type: i.type,
description: i.description,
confidence: i.confidence
})),
metadata: {
detectedEntities: analysis.detectedEntities.length,
detectedRelationships: analysis.detectedRelationships.length,
timestamp: new Date().toISOString()
}
}
};
}
catch (error) {
return {
success: false,
data: { nouns: [], verbs: [] },
error: error instanceof Error ? error.message : 'Neural analysis failed'
};
}
}
}
//# sourceMappingURL=neuralImport.js.map

File diff suppressed because one or more lines are too long

View file

@ -0,0 +1,82 @@
/**
* Rate Limiting Augmentation
* Provides configurable rate limiting for Brainy operations
*/
import { BaseAugmentation } from './brainyAugmentation.js';
import { AugmentationManifest } from './manifest.js';
export interface RateLimitConfig {
enabled?: boolean;
limits?: {
searches?: number;
writes?: number;
reads?: number;
deletes?: number;
};
windowMs?: number;
skipSuccessfulRequests?: boolean;
skipFailedRequests?: boolean;
keyGenerator?: (context: any) => string;
}
/**
* Rate Limit Augmentation
*/
export declare class RateLimitAugmentation extends BaseAugmentation {
readonly name = "rateLimiter";
readonly timing: "before";
readonly metadata: "none";
operations: any;
readonly priority = 10;
readonly category: "core";
readonly description = "Provides rate limiting for Brainy operations";
private limiters;
private windowMs;
constructor(config?: RateLimitConfig);
getManifest(): AugmentationManifest;
/**
* Initialize rate limiters for each operation type
*/
private initializeLimiters;
/**
* Default key generator (could be IP, user ID, etc.)
*/
private defaultKeyGenerator;
/**
* Check if request should be rate limited
*/
private checkRateLimit;
/**
* Get remaining requests for an operation
*/
private getRemainingRequests;
/**
* Get time until reset
*/
private getResetTime;
protected onInitialize(): Promise<void>;
protected onShutdown(): Promise<void>;
/**
* Execute augmentation - apply rate limiting
*/
execute<T = any>(operation: string, params: any, next: () => Promise<T>): Promise<T>;
/**
* Get rate limit statistics
*/
getStats(): {
operations: Record<string, {
activeKeys: number;
totalRequests: number;
}>;
};
/**
* Clear all rate limit entries
*/
clear(): void;
/**
* Clear expired entries (cleanup)
*/
cleanup(): void;
}
/**
* Create rate limit augmentation
*/
export declare function createRateLimitAugmentation(config?: RateLimitConfig): RateLimitAugmentation;

View file

@ -0,0 +1,321 @@
/**
* Rate Limiting Augmentation
* Provides configurable rate limiting for Brainy operations
*/
import { BaseAugmentation } from './brainyAugmentation.js';
/**
* Rate Limit Augmentation
*/
export class RateLimitAugmentation extends BaseAugmentation {
constructor(config = {}) {
super(config);
this.name = 'rateLimiter';
this.timing = 'before';
this.metadata = 'none';
this.operations = ['search', 'find', 'add', 'update', 'delete', 'get'];
this.priority = 10; // High priority, runs early
// Augmentation metadata
this.category = 'core'; // Use 'core' as security isn't a valid category
this.description = 'Provides rate limiting for Brainy operations';
this.limiters = new Map();
// Merge with defaults
this.config = {
enabled: config.enabled ?? true,
limits: {
searches: config.limits?.searches ?? 1000,
writes: config.limits?.writes ?? 100,
reads: config.limits?.reads ?? 5000,
deletes: config.limits?.deletes ?? 50
},
windowMs: config.windowMs ?? 60000, // 1 minute default
skipSuccessfulRequests: config.skipSuccessfulRequests ?? false,
skipFailedRequests: config.skipFailedRequests ?? true,
keyGenerator: config.keyGenerator || this.defaultKeyGenerator
};
this.windowMs = this.config.windowMs;
// Initialize operation limiters
this.initializeLimiters();
}
getManifest() {
return {
id: 'rate-limiter',
name: 'Rate Limiter',
version: '1.0.0',
description: 'Configurable rate limiting for API operations',
longDescription: 'Provides per-operation rate limiting with configurable windows and limits. Helps prevent abuse and ensures fair resource usage.',
category: 'core',
configSchema: {
type: 'object',
properties: {
enabled: {
type: 'boolean',
default: true,
description: 'Enable or disable rate limiting'
},
limits: {
type: 'object',
properties: {
searches: {
type: 'number',
default: 1000,
description: 'Search operations per minute'
},
writes: {
type: 'number',
default: 100,
description: 'Write operations per minute'
},
reads: {
type: 'number',
default: 5000,
description: 'Read operations per minute'
},
deletes: {
type: 'number',
default: 50,
description: 'Delete operations per minute'
}
}
},
windowMs: {
type: 'number',
default: 60000,
description: 'Time window in milliseconds'
}
}
},
configDefaults: {
enabled: true,
limits: {
searches: 1000,
writes: 100,
reads: 5000,
deletes: 50
},
windowMs: 60000
},
minBrainyVersion: '3.0.0',
keywords: ['rate-limit', 'security', 'throttle'],
documentation: 'https://docs.brainy.dev/augmentations/rate-limit',
status: 'stable',
performance: {
memoryUsage: 'low',
cpuUsage: 'low',
networkUsage: 'none'
},
features: ['per-operation-limits', 'configurable-windows', 'key-based-limiting'],
enhancedOperations: ['search', 'add', 'update', 'delete', 'get'],
metrics: [
{
name: 'rate_limit_exceeded',
type: 'counter',
description: 'Number of rate limit violations'
},
{
name: 'rate_limit_requests',
type: 'counter',
description: 'Total requests checked'
}
]
};
}
/**
* Initialize rate limiters for each operation type
*/
initializeLimiters() {
const operations = ['searches', 'writes', 'reads', 'deletes'];
for (const op of operations) {
this.limiters.set(op, new Map());
}
}
/**
* Default key generator (could be IP, user ID, etc.)
*/
defaultKeyGenerator(_context) {
// In a real implementation, this would extract IP or user ID
return 'default';
}
/**
* Check if request should be rate limited
*/
checkRateLimit(operation, key) {
const limiter = this.limiters.get(operation);
if (!limiter)
return false;
const limit = this.config.limits[operation];
if (!limit)
return false;
const now = Date.now();
let entry = limiter.get(key);
// Initialize or reset entry
if (!entry || now >= entry.resetTime) {
entry = {
count: 0,
resetTime: now + this.windowMs
};
limiter.set(key, entry);
}
// Check if limit exceeded
if (entry.count >= limit) {
return true; // Rate limited
}
// Increment counter
entry.count++;
return false;
}
/**
* Get remaining requests for an operation
*/
getRemainingRequests(operation, key) {
const limiter = this.limiters.get(operation);
if (!limiter)
return -1;
const limit = this.config.limits[operation];
if (!limit)
return -1;
const entry = limiter.get(key);
if (!entry)
return limit;
const now = Date.now();
if (now >= entry.resetTime)
return limit;
return Math.max(0, limit - entry.count);
}
/**
* Get time until reset
*/
getResetTime(operation, key) {
const limiter = this.limiters.get(operation);
if (!limiter)
return 0;
const entry = limiter.get(key);
if (!entry)
return 0;
const now = Date.now();
return Math.max(0, entry.resetTime - now);
}
async onInitialize() {
if (!this.config.enabled) {
this.log('Rate limiter disabled by configuration');
return;
}
this.log(`Rate limiter initialized (window: ${this.windowMs}ms)`);
// Start cleanup timer
setInterval(() => {
this.cleanup();
}, this.windowMs);
}
async onShutdown() {
this.clear();
this.log('Rate limiter shut down');
}
/**
* Execute augmentation - apply rate limiting
*/
async execute(operation, params, next) {
// If rate limiting is disabled, just pass through
if (!this.config.enabled) {
return next();
}
// Map operations to rate limit categories
let rateLimitOperation;
switch (operation) {
case 'search':
case 'find':
case 'similar':
rateLimitOperation = 'searches';
break;
case 'add':
case 'update':
rateLimitOperation = 'writes';
break;
case 'delete':
rateLimitOperation = 'deletes';
break;
case 'get':
rateLimitOperation = 'reads';
break;
default:
return next(); // Don't rate limit unknown operations
}
const key = this.config.keyGenerator(params);
if (this.checkRateLimit(rateLimitOperation, key)) {
const error = new Error(`Rate limit exceeded for ${operation}`);
error.statusCode = 429;
error.retryAfter = this.getResetTime(rateLimitOperation, key);
error.rateLimit = {
limit: this.config.limits[rateLimitOperation],
remaining: 0,
reset: Date.now() + this.getResetTime(rateLimitOperation, key)
};
throw error;
}
try {
const result = await next();
// Add rate limit info to result if possible
if (result && typeof result === 'object' && !Array.isArray(result)) {
result._rateLimit = {
limit: this.config.limits[rateLimitOperation],
remaining: this.getRemainingRequests(rateLimitOperation, key),
reset: Date.now() + this.getResetTime(rateLimitOperation, key)
};
}
return result;
}
catch (error) {
// Optionally don't count failed requests
if (this.config.skipFailedRequests) {
const limiter = this.limiters.get(rateLimitOperation);
const entry = limiter.get(key);
if (entry && entry.count > 0)
entry.count--;
}
throw error;
}
}
/**
* Get rate limit statistics
*/
getStats() {
const stats = { operations: {} };
for (const [operation, limiter] of this.limiters) {
let totalRequests = 0;
for (const entry of limiter.values()) {
totalRequests += entry.count;
}
stats.operations[operation] = {
activeKeys: limiter.size,
totalRequests
};
}
return stats;
}
/**
* Clear all rate limit entries
*/
clear() {
for (const limiter of this.limiters.values()) {
limiter.clear();
}
}
/**
* Clear expired entries (cleanup)
*/
cleanup() {
const now = Date.now();
for (const limiter of this.limiters.values()) {
for (const [key, entry] of limiter) {
if (now >= entry.resetTime) {
limiter.delete(key);
}
}
}
}
}
/**
* Create rate limit augmentation
*/
export function createRateLimitAugmentation(config) {
return new RateLimitAugmentation(config);
}
//# sourceMappingURL=rateLimitAugmentation.js.map

File diff suppressed because one or more lines are too long

View file

@ -0,0 +1,53 @@
/**
* Request Deduplicator Augmentation
*
* Prevents duplicate concurrent requests to improve performance by 3x
* Automatically deduplicates identical operations
*/
import { BaseAugmentation } from './brainyAugmentation.js';
interface DeduplicatorConfig {
enabled?: boolean;
ttl?: number;
maxSize?: number;
}
export declare class RequestDeduplicatorAugmentation extends BaseAugmentation {
name: string;
timing: "around";
metadata: "none";
operations: ("search" | "find" | "similar" | "searchText" | "searchByNounTypes" | "findSimilar" | "get")[];
priority: number;
private pendingRequests;
protected config: Required<DeduplicatorConfig>;
private cleanupInterval?;
constructor(config?: DeduplicatorConfig);
protected onInitialize(): Promise<void>;
shouldExecute(operation: string, params: any): boolean;
execute<T = any>(operation: string, params: any, next: () => Promise<T>): Promise<T>;
/**
* Create a unique key for the request based on operation and parameters
*/
private createRequestKey;
/**
* Serialize parameters to a consistent string
*/
private serializeParams;
/**
* Clean up expired requests
*/
private cleanup;
/**
* Get statistics about request deduplication
*/
getStats(): {
activePendingRequests: number;
totalDeduplicationHits: number;
memoryUsage: string;
efficiency: string;
};
/**
* Force clear all pending requests (for testing)
*/
clear(): void;
protected onShutdown(): Promise<void>;
}
export {};

View file

@ -0,0 +1,163 @@
/**
* Request Deduplicator Augmentation
*
* Prevents duplicate concurrent requests to improve performance by 3x
* Automatically deduplicates identical operations
*/
import { BaseAugmentation } from './brainyAugmentation.js';
export class RequestDeduplicatorAugmentation extends BaseAugmentation {
constructor(config = {}) {
super();
this.name = 'RequestDeduplicator';
this.timing = 'around';
this.metadata = 'none'; // Doesn't access metadata
this.operations = ['search', 'find', 'similar', 'searchText', 'searchByNounTypes', 'findSimilar', 'get'];
this.priority = 50; // Performance optimization
this.pendingRequests = new Map();
this.config = {
enabled: config.enabled ?? true,
ttl: config.ttl ?? 5000, // 5 second default
maxSize: config.maxSize ?? 1000
};
}
async onInitialize() {
if (this.config.enabled) {
this.log('Request deduplicator initialized for 3x performance boost');
// Start cleanup interval
this.cleanupInterval = setInterval(() => {
this.cleanup();
}, this.config.ttl);
}
else {
this.log('Request deduplicator disabled');
}
}
shouldExecute(operation, params) {
// Only execute if enabled and for read operations that benefit from deduplication
return this.config.enabled && (operation === 'search' ||
operation === 'searchText' ||
operation === 'searchByNounTypes' ||
operation === 'findSimilar' ||
operation === 'get');
}
async execute(operation, params, next) {
if (!this.config.enabled) {
return next();
}
// Create a unique key for this request
const key = this.createRequestKey(operation, params);
// Check if we already have this request pending
const existing = this.pendingRequests.get(key);
if (existing) {
existing.count++;
this.log(`Deduplicating request: ${key} (${existing.count} total)`);
return existing.promise;
}
// Execute the request and cache the promise
const promise = next();
this.pendingRequests.set(key, {
promise,
timestamp: Date.now(),
count: 1
});
// Clean up when done
promise.finally(() => {
// Use setTimeout to allow other concurrent requests to use the result
setTimeout(() => {
this.pendingRequests.delete(key);
}, 100);
});
return promise;
}
/**
* Create a unique key for the request based on operation and parameters
*/
createRequestKey(operation, params) {
// Create a stable string representation of the operation and params
const paramsKey = this.serializeParams(params);
return `${operation}:${paramsKey}`;
}
/**
* Serialize parameters to a consistent string
*/
serializeParams(params) {
if (!params)
return 'null';
if (typeof params === 'string' || typeof params === 'number') {
return String(params);
}
if (Array.isArray(params)) {
// For arrays, create a hash-like representation
if (params.length > 100) {
// For large arrays (like vectors), use length + first/last elements
return `[${params.length}:${params[0]}...${params[params.length - 1]}]`;
}
return `[${params.join(',')}]`;
}
if (typeof params === 'object') {
// Sort keys for consistent serialization
const keys = Object.keys(params).sort();
const keyValues = keys.map(key => `${key}:${this.serializeParams(params[key])}`);
return `{${keyValues.join(',')}}`;
}
return String(params);
}
/**
* Clean up expired requests
*/
cleanup() {
const now = Date.now();
const expired = [];
for (const [key, request] of this.pendingRequests) {
if (now - request.timestamp > this.config.ttl) {
expired.push(key);
}
}
for (const key of expired) {
this.pendingRequests.delete(key);
}
// Also enforce max size
if (this.pendingRequests.size > this.config.maxSize) {
const entries = Array.from(this.pendingRequests.entries())
.sort(([, a], [, b]) => a.timestamp - b.timestamp); // Oldest first
// Remove oldest entries
const toRemove = entries.slice(0, entries.length - this.config.maxSize);
for (const [key] of toRemove) {
this.pendingRequests.delete(key);
}
}
if (expired.length > 0) {
this.log(`Cleaned up ${expired.length} expired requests`);
}
}
/**
* Get statistics about request deduplication
*/
getStats() {
const requests = Array.from(this.pendingRequests.values());
const totalRequests = requests.reduce((sum, req) => sum + req.count, 0);
const actualRequests = requests.length;
const savedRequests = totalRequests - actualRequests;
return {
activePendingRequests: actualRequests,
totalDeduplicationHits: savedRequests,
memoryUsage: `${Math.round(JSON.stringify(requests).length / 1024)}KB`,
efficiency: actualRequests > 0 ? `${Math.round((savedRequests / totalRequests) * 100)}% reduction` : '0%'
};
}
/**
* Force clear all pending requests (for testing)
*/
clear() {
this.pendingRequests.clear();
}
async onShutdown() {
if (this.cleanupInterval) {
clearInterval(this.cleanupInterval);
}
const stats = this.getStats();
this.log(`Request deduplicator shutdown: ${stats.efficiency} efficiency achieved`);
this.pendingRequests.clear();
}
}
//# sourceMappingURL=requestDeduplicatorAugmentation.js.map

File diff suppressed because one or more lines are too long

View file

@ -0,0 +1,190 @@
/**
* Server Search Augmentations
*
* This file implements conduit and activation augmentations for browser-server search functionality.
* It allows Brainy to search a server-hosted instance and store results locally.
*/
import { AugmentationResponse, WebSocketConnection } from '../types/augmentations.js';
import { BaseAugmentation } from '../augmentations/brainyAugmentation.js';
import { BrainyDataInterface } from '../types/brainyDataInterface.js';
/**
* ServerSearchConduitAugmentation
*
* A specialized conduit augmentation that provides functionality for searching
* a server-hosted Brainy instance and storing results locally.
*/
export declare class ServerSearchConduitAugmentation extends BaseAugmentation {
readonly name = "server-search-conduit";
readonly timing: "after";
readonly metadata: "readonly";
operations: ("addNoun" | "delete" | "addVerb")[];
readonly priority = 20;
private localDb;
constructor(name?: string);
/**
* Initialize the augmentation
*/
protected onInitialize(): Promise<void>;
/**
* Set the local Brainy instance
* @param db The Brainy instance to use for local storage
*/
setLocalDb(db: BrainyDataInterface): void;
/**
* Stub method for performing search operations via WebSocket
* TODO: Implement proper WebSocket communication
*/
private performSearch;
/**
* Stub method for performing write operations via WebSocket
* TODO: Implement proper WebSocket communication
*/
private performWrite;
/**
* Get the local Brainy instance
* @returns The local Brainy instance
*/
getLocalDb(): BrainyDataInterface | null;
/**
* Execute method - required by BaseAugmentation
*/
execute<T = any>(operation: string, params: any, next: () => Promise<T>): Promise<T>;
/**
* Search the server-hosted Brainy instance and store results locally
* @param connectionId The ID of the established connection
* @param query The search query
* @param limit Maximum number of results to return
* @returns Search results
*/
searchServer(connectionId: string, query: string, limit?: number): Promise<AugmentationResponse<unknown>>;
/**
* Search the local Brainy instance
* @param query The search query
* @param limit Maximum number of results to return
* @returns Search results
*/
searchLocal(query: string, limit?: number): Promise<AugmentationResponse<unknown>>;
/**
* Search both server and local instances, combine results, and store server results locally
* @param connectionId The ID of the established connection
* @param query The search query
* @param limit Maximum number of results to return
* @returns Combined search results
*/
searchCombined(connectionId: string, query: string, limit?: number): Promise<AugmentationResponse<unknown>>;
/**
* Add data to both local and server instances
* @param connectionId The ID of the established connection
* @param data Text or vector to add
* @param metadata Metadata for the data
* @returns ID of the added data
*/
addToBoth(connectionId: string, data: string | any[], metadata?: any): Promise<AugmentationResponse<string>>;
/**
* Establish connection to remote server
* @param serverUrl Server URL to connect to
* @param options Connection options
* @returns Connection promise
*/
establishConnection(serverUrl: string, options?: any): Promise<any>;
/**
* Close WebSocket connection
* @param connectionId Connection ID to close
* @returns Promise that resolves when connection is closed
*/
closeWebSocket(connectionId: string): Promise<void>;
}
/**
* ServerSearchActivationAugmentation
*
* An activation augmentation that provides actions for server search functionality.
*/
export declare class ServerSearchActivationAugmentation extends BaseAugmentation {
readonly name = "server-search-activation";
readonly timing: "after";
readonly metadata: "readonly";
operations: ("search" | "addNoun")[];
readonly priority = 20;
private conduitAugmentation;
private connections;
constructor(name?: string);
protected onInitialize(): Promise<void>;
protected onShutdown(): Promise<void>;
execute<T = any>(operation: string, params: any, next: () => Promise<T>): Promise<T>;
/**
* Set the conduit augmentation to use for server search
* @param conduit The ServerSearchConduitAugmentation to use
*/
setConduitAugmentation(conduit: ServerSearchConduitAugmentation): void;
/**
* Store a connection for later use
* @param connectionId The ID to use for the connection
* @param connection The WebSocket connection
*/
storeConnection(connectionId: string, connection: WebSocketConnection): void;
/**
* Get a stored connection
* @param connectionId The ID of the connection to retrieve
* @returns The WebSocket connection
*/
getConnection(connectionId: string): WebSocketConnection | undefined;
/**
* Trigger an action based on a processed command or internal state
* @param actionName The name of the action to trigger
* @param parameters Optional parameters for the action
*/
triggerAction(actionName: string, parameters?: Record<string, unknown>): AugmentationResponse<unknown>;
/**
* Handle the connectToServer action
* @param parameters Action parameters
*/
private handleConnectToServer;
/**
* Handle the searchServer action
* @param parameters Action parameters
*/
private handleSearchServer;
/**
* Handle the searchLocal action
* @param parameters Action parameters
*/
private handleSearchLocal;
/**
* Handle the searchCombined action
* @param parameters Action parameters
*/
private handleSearchCombined;
/**
* Handle the addToBoth action
* @param parameters Action parameters
*/
private handleAddToBoth;
/**
* Generates an expressive output or response from Brainy
* @param knowledgeId The identifier of the knowledge to express
* @param format The desired output format (e.g., 'text', 'json')
*/
generateOutput(knowledgeId: string, format: string): AugmentationResponse<string | Record<string, unknown>>;
/**
* Interacts with an external system or API
* @param systemId The identifier of the external system
* @param payload The data to send to the external system
*/
interactExternal(systemId: string, payload: Record<string, unknown>): AugmentationResponse<unknown>;
}
/**
* Factory function to create server search augmentations
* @param serverUrl The URL of the server to connect to
* @param options Additional options
* @returns An object containing the created augmentations
*/
export declare function createServerSearchAugmentations(serverUrl: string, options?: {
conduitName?: string;
activationName?: string;
protocols?: string | string[];
localDb?: BrainyDataInterface;
}): Promise<{
conduit: ServerSearchConduitAugmentation;
activation: ServerSearchActivationAugmentation;
connection: WebSocketConnection;
}>;

View file

@ -0,0 +1,586 @@
/**
* Server Search Augmentations
*
* This file implements conduit and activation augmentations for browser-server search functionality.
* It allows Brainy to search a server-hosted instance and store results locally.
*/
import { BaseAugmentation } from '../augmentations/brainyAugmentation.js';
/**
* ServerSearchConduitAugmentation
*
* A specialized conduit augmentation that provides functionality for searching
* a server-hosted Brainy instance and storing results locally.
*/
export class ServerSearchConduitAugmentation extends BaseAugmentation {
constructor(name) {
super();
this.name = 'server-search-conduit';
this.timing = 'after';
this.metadata = 'readonly'; // Reads metadata to sync with server
this.operations = ['addNoun', 'delete', 'addVerb'];
this.priority = 20;
this.localDb = null;
if (name) {
// Override name if provided (though it's readonly, this won't work)
// Keep constructor parameter for API compatibility but ignore it
}
}
/**
* Initialize the augmentation
*/
async onInitialize() {
// Local DB must be set before initialization
if (!this.localDb) {
this.log('Local database not set. Call setLocalDb before using server search.', 'warn');
return;
}
this.log('Server search conduit initialized');
}
/**
* Set the local Brainy instance
* @param db The Brainy instance to use for local storage
*/
setLocalDb(db) {
this.localDb = db;
}
/**
* Stub method for performing search operations via WebSocket
* TODO: Implement proper WebSocket communication
*/
async performSearch(params) {
this.log('Search operation not yet implemented - returning empty results', 'warn');
return {
success: true,
data: []
};
}
/**
* Stub method for performing write operations via WebSocket
* TODO: Implement proper WebSocket communication
*/
async performWrite(params) {
this.log('Write operation not yet implemented', 'warn');
return {
success: false,
data: null,
error: 'Write operation not implemented'
};
}
/**
* Get the local Brainy instance
* @returns The local Brainy instance
*/
getLocalDb() {
return this.localDb;
}
/**
* Execute method - required by BaseAugmentation
*/
async execute(operation, params, next) {
// Just pass through for now - server search operations are handled by the activation augmentation
return next();
}
/**
* Search the server-hosted Brainy instance and store results locally
* @param connectionId The ID of the established connection
* @param query The search query
* @param limit Maximum number of results to return
* @returns Search results
*/
async searchServer(connectionId, query, limit = 10) {
if (!this.isInitialized) {
throw new Error('ServerSearchConduitAugmentation not initialized');
}
try {
// Create a search request (TODO: Implement proper WebSocket communication)
const readResult = await this.performSearch({
connectionId,
query: {
type: 'search',
query,
limit
}
});
if (readResult.success && readResult.data) {
const searchResults = readResult.data;
// Store the results in the local Brainy instance
if (this.localDb) {
for (const result of searchResults) {
// Check if the noun already exists in the local database
const existingNoun = await this.localDb.getNoun(result.id);
if (!existingNoun) {
// Add the noun to the local database
await this.localDb.addNoun(result.vector, result.metadata);
}
}
}
return {
success: true,
data: searchResults
};
}
else {
return {
success: false,
data: null,
error: readResult.error || 'Unknown error searching server'
};
}
}
catch (error) {
console.error('Error searching server:', error);
return {
success: false,
data: null,
error: `Error searching server: ${error}`
};
}
}
/**
* Search the local Brainy instance
* @param query The search query
* @param limit Maximum number of results to return
* @returns Search results
*/
async searchLocal(query, limit = 10) {
if (!this.isInitialized) {
throw new Error('ServerSearchConduitAugmentation not initialized');
}
try {
if (!this.localDb) {
return {
success: false,
data: null,
error: 'Local database not initialized'
};
}
const results = await this.localDb.searchText(query, limit);
return {
success: true,
data: results
};
}
catch (error) {
console.error('Error searching local database:', error);
return {
success: false,
data: null,
error: `Error searching local database: ${error}`
};
}
}
/**
* Search both server and local instances, combine results, and store server results locally
* @param connectionId The ID of the established connection
* @param query The search query
* @param limit Maximum number of results to return
* @returns Combined search results
*/
async searchCombined(connectionId, query, limit = 10) {
if (!this.isInitialized) {
throw new Error('ServerSearchConduitAugmentation not initialized');
}
try {
// Search local first
const localSearchResult = await this.searchLocal(query, limit);
if (!localSearchResult.success) {
return localSearchResult;
}
const localResults = localSearchResult.data;
// If we have enough local results, return them
if (localResults.length >= limit) {
return localSearchResult;
}
// Otherwise, search server for additional results
const serverSearchResult = await this.searchServer(connectionId, query, limit - localResults.length);
if (!serverSearchResult.success) {
// If server search fails, return local results
return localSearchResult;
}
const serverResults = serverSearchResult.data;
// Combine results, removing duplicates
const combinedResults = [...localResults];
const localIds = new Set(localResults.map((r) => r.id));
for (const result of serverResults) {
if (!localIds.has(result.id)) {
combinedResults.push(result);
}
}
return {
success: true,
data: combinedResults
};
}
catch (error) {
console.error('Error performing combined search:', error);
return {
success: false,
data: null,
error: `Error performing combined search: ${error}`
};
}
}
/**
* Add data to both local and server instances
* @param connectionId The ID of the established connection
* @param data Text or vector to add
* @param metadata Metadata for the data
* @returns ID of the added data
*/
async addToBoth(connectionId, data, metadata = {}) {
if (!this.isInitialized) {
throw new Error('ServerSearchConduitAugmentation not initialized');
}
try {
if (!this.localDb) {
return {
success: false,
data: '',
error: 'Local database not initialized'
};
}
// Add to local first - addNoun handles both strings and vectors automatically
const id = await this.localDb.addNoun(data, metadata);
// Get the vector and metadata
const noun = (await this.localDb.getNoun(id));
if (!noun) {
return {
success: false,
data: '',
error: 'Failed to retrieve newly created noun'
};
}
// Add to server (TODO: Implement proper WebSocket communication)
const writeResult = await this.performWrite({
connectionId,
data: {
type: 'addNoun',
vector: noun.vector,
metadata: noun.metadata
}
});
if (!writeResult.success) {
return {
success: true,
data: id,
error: `Added locally but failed to add to server: ${writeResult.error}`
};
}
return {
success: true,
data: id
};
}
catch (error) {
console.error('Error adding data to both:', error);
return {
success: false,
data: '',
error: `Error adding data to both: ${error}`
};
}
}
/**
* Establish connection to remote server
* @param serverUrl Server URL to connect to
* @param options Connection options
* @returns Connection promise
*/
establishConnection(serverUrl, options) {
// Stub implementation - remote connection functionality not yet fully implemented in 2.0
console.warn('establishConnection: Remote server connections not yet fully implemented in Brainy 2.0');
return Promise.resolve({ connected: false, reason: 'Not implemented' });
}
/**
* Close WebSocket connection
* @param connectionId Connection ID to close
* @returns Promise that resolves when connection is closed
*/
async closeWebSocket(connectionId) {
// Stub implementation - WebSocket functionality not yet fully implemented in 2.0
console.warn(`closeWebSocket: WebSocket functionality not yet fully implemented in Brainy 2.0 (connectionId: ${connectionId})`);
}
}
/**
* ServerSearchActivationAugmentation
*
* An activation augmentation that provides actions for server search functionality.
*/
export class ServerSearchActivationAugmentation extends BaseAugmentation {
constructor(name) {
super();
this.name = 'server-search-activation';
this.timing = 'after';
this.metadata = 'readonly'; // Reads metadata for server activation
this.operations = ['search', 'addNoun'];
this.priority = 20;
this.conduitAugmentation = null;
this.connections = new Map();
if (name) {
// Keep constructor parameter for API compatibility but ignore it
}
}
async onInitialize() {
// Initialization logic if needed
}
async onShutdown() {
// Cleanup connections
this.connections.clear();
}
async execute(operation, params, next) {
// Execute the operation first
const result = await next();
// Handle server search operations
if (operation === 'search' && this.conduitAugmentation) {
// Trigger server search when local search happens
const connectionId = this.connections.keys().next().value;
if (connectionId && params.query) {
await this.conduitAugmentation.searchServer(connectionId, params.query, params.limit || 10);
}
}
return result;
}
/**
* Set the conduit augmentation to use for server search
* @param conduit The ServerSearchConduitAugmentation to use
*/
setConduitAugmentation(conduit) {
this.conduitAugmentation = conduit;
}
/**
* Store a connection for later use
* @param connectionId The ID to use for the connection
* @param connection The WebSocket connection
*/
storeConnection(connectionId, connection) {
this.connections.set(connectionId, connection);
}
/**
* Get a stored connection
* @param connectionId The ID of the connection to retrieve
* @returns The WebSocket connection
*/
getConnection(connectionId) {
return this.connections.get(connectionId);
}
/**
* Trigger an action based on a processed command or internal state
* @param actionName The name of the action to trigger
* @param parameters Optional parameters for the action
*/
triggerAction(actionName, parameters) {
if (!this.conduitAugmentation) {
return {
success: false,
data: null,
error: 'Conduit augmentation not set'
};
}
// Handle different actions
switch (actionName) {
case 'connectToServer':
return this.handleConnectToServer(parameters || {});
case 'searchServer':
return this.handleSearchServer(parameters || {});
case 'searchLocal':
return this.handleSearchLocal(parameters || {});
case 'searchCombined':
return this.handleSearchCombined(parameters || {});
case 'addToBoth':
return this.handleAddToBoth(parameters || {});
default:
return {
success: false,
data: null,
error: `Unknown action: ${actionName}`
};
}
}
/**
* Handle the connectToServer action
* @param parameters Action parameters
*/
handleConnectToServer(parameters) {
const serverUrl = parameters.serverUrl;
const protocols = parameters.protocols;
if (!serverUrl) {
return {
success: false,
data: null,
error: 'serverUrl parameter is required'
};
}
// Return a promise that will be resolved when the connection is established
return {
success: true,
data: this.conduitAugmentation.establishConnection(serverUrl, {
protocols
})
};
}
/**
* Handle the searchServer action
* @param parameters Action parameters
*/
handleSearchServer(parameters) {
const connectionId = parameters.connectionId;
const query = parameters.query;
const limit = parameters.limit || 10;
if (!connectionId) {
return {
success: false,
data: null,
error: 'connectionId parameter is required'
};
}
if (!query) {
return {
success: false,
data: null,
error: 'query parameter is required'
};
}
// Return a promise that will be resolved when the search is complete
return {
success: true,
data: this.conduitAugmentation.searchServer(connectionId, query, limit)
};
}
/**
* Handle the searchLocal action
* @param parameters Action parameters
*/
handleSearchLocal(parameters) {
const query = parameters.query;
const limit = parameters.limit || 10;
if (!query) {
return {
success: false,
data: null,
error: 'query parameter is required'
};
}
// Return a promise that will be resolved when the search is complete
return {
success: true,
data: this.conduitAugmentation.searchLocal(query, limit)
};
}
/**
* Handle the searchCombined action
* @param parameters Action parameters
*/
handleSearchCombined(parameters) {
const connectionId = parameters.connectionId;
const query = parameters.query;
const limit = parameters.limit || 10;
if (!connectionId) {
return {
success: false,
data: null,
error: 'connectionId parameter is required'
};
}
if (!query) {
return {
success: false,
data: null,
error: 'query parameter is required'
};
}
// Return a promise that will be resolved when the search is complete
return {
success: true,
data: this.conduitAugmentation.searchCombined(connectionId, query, limit)
};
}
/**
* Handle the addToBoth action
* @param parameters Action parameters
*/
handleAddToBoth(parameters) {
const connectionId = parameters.connectionId;
const data = parameters.data;
const metadata = parameters.metadata || {};
if (!connectionId) {
return {
success: false,
data: null,
error: 'connectionId parameter is required'
};
}
if (!data) {
return {
success: false,
data: null,
error: 'data parameter is required'
};
}
// Return a promise that will be resolved when the add is complete
return {
success: true,
data: this.conduitAugmentation.addToBoth(connectionId, data, metadata)
};
}
/**
* Generates an expressive output or response from Brainy
* @param knowledgeId The identifier of the knowledge to express
* @param format The desired output format (e.g., 'text', 'json')
*/
generateOutput(knowledgeId, format) {
// This method is not used for server search functionality
return {
success: false,
data: '',
error: 'generateOutput is not implemented for ServerSearchActivationAugmentation'
};
}
/**
* Interacts with an external system or API
* @param systemId The identifier of the external system
* @param payload The data to send to the external system
*/
interactExternal(systemId, payload) {
// This method is not used for server search functionality
return {
success: false,
data: null,
error: 'interactExternal is not implemented for ServerSearchActivationAugmentation'
};
}
}
/**
* Factory function to create server search augmentations
* @param serverUrl The URL of the server to connect to
* @param options Additional options
* @returns An object containing the created augmentations
*/
export async function createServerSearchAugmentations(serverUrl, options = {}) {
// Create the conduit augmentation
const conduit = new ServerSearchConduitAugmentation(options.conduitName);
// Set the local database if provided
if (options.localDb) {
conduit.setLocalDb(options.localDb);
}
// Create the activation augmentation
const activation = new ServerSearchActivationAugmentation(options.activationName);
// Note: Augmentations will be initialized when added to BrainyData
// Link the augmentations
activation.setConduitAugmentation(conduit);
// TODO: Connect to the server (stub implementation for now)
const connection = {
connectionId: `stub-connection-${Date.now()}`,
url: serverUrl,
status: 'connected',
close: async () => { },
send: async (data) => { }
};
// Store the connection in the activation augmentation
activation.storeConnection(connection.connectionId, connection);
return {
conduit,
activation,
connection
};
}
//# sourceMappingURL=serverSearchAugmentations.js.map

File diff suppressed because one or more lines are too long

View file

@ -0,0 +1,55 @@
/**
* Storage Augmentation Base Classes
*
* Unifies storage adapters and augmentations into a single system.
* All storage backends are now augmentations for consistency and extensibility.
*/
import { BaseAugmentation, BrainyAugmentation, AugmentationContext } from './brainyAugmentation.js';
import { StorageAdapter } from '../coreTypes.js';
/**
* Base class for all storage augmentations
* Provides the storage adapter to the brain during initialization
*/
export declare abstract class StorageAugmentation extends BaseAugmentation implements BrainyAugmentation {
readonly timing: "replace";
readonly metadata: "none";
operations: ("storage")[];
readonly priority = 100;
protected storageAdapter: StorageAdapter | null;
constructor(config?: any);
/**
* Provide the storage adapter before full initialization
* This is called during the storage resolution phase
*/
abstract provideStorage(): Promise<StorageAdapter>;
/**
* Initialize the augmentation with context
* Called after storage has been resolved
*/
initialize(context: AugmentationContext): Promise<void>;
/**
* Execute storage operations
* For storage augmentations, this replaces the default storage
*/
execute<T = any>(operation: string, params: any, next: () => Promise<T>): Promise<T>;
/**
* Shutdown and cleanup
*/
shutdown(): Promise<void>;
}
/**
* Dynamic storage augmentation that wraps any storage adapter
* Used for backward compatibility and zero-config
*/
export declare class DynamicStorageAugmentation extends StorageAugmentation {
private adapter;
readonly name = "dynamic-storage";
constructor(adapter: StorageAdapter);
provideStorage(): Promise<StorageAdapter>;
protected onInitialize(): Promise<void>;
}
/**
* Create a storage augmentation from configuration
* Maintains backward compatibility with existing storage config
*/
export declare function createStorageAugmentationFromConfig(config: any): Promise<StorageAugmentation | null>;

View file

@ -0,0 +1,94 @@
/**
* Storage Augmentation Base Classes
*
* Unifies storage adapters and augmentations into a single system.
* All storage backends are now augmentations for consistency and extensibility.
*/
import { BaseAugmentation } from './brainyAugmentation.js';
/**
* Base class for all storage augmentations
* Provides the storage adapter to the brain during initialization
*/
export class StorageAugmentation extends BaseAugmentation {
// Storage augmentations must provide their name via readonly property
constructor(config) {
super(config);
this.timing = 'replace';
this.metadata = 'none'; // Storage doesn't directly access metadata
this.operations = ['storage']; // Make mutable for TypeScript compatibility
this.priority = 100; // High priority for storage
this.storageAdapter = null;
}
/**
* Initialize the augmentation with context
* Called after storage has been resolved
*/
async initialize(context) {
await super.initialize(context);
// Storage adapter should already be provided
if (!this.storageAdapter) {
this.storageAdapter = await this.provideStorage();
}
}
/**
* Execute storage operations
* For storage augmentations, this replaces the default storage
*/
async execute(operation, params, next) {
if (operation === 'storage') {
// Return our storage adapter
return this.storageAdapter;
}
// Pass through all other operations
return next();
}
/**
* Shutdown and cleanup
*/
async shutdown() {
// Cleanup storage adapter if needed
if (this.storageAdapter && typeof this.storageAdapter.close === 'function') {
await this.storageAdapter.close();
}
await super.shutdown();
}
}
/**
* Dynamic storage augmentation that wraps any storage adapter
* Used for backward compatibility and zero-config
*/
export class DynamicStorageAugmentation extends StorageAugmentation {
constructor(adapter) {
super();
this.adapter = adapter;
this.name = 'dynamic-storage';
this.storageAdapter = adapter;
}
async provideStorage() {
return this.adapter;
}
async onInitialize() {
// Adapter is already provided in constructor
await this.adapter.init();
this.log(`${this.name} initialized`);
}
}
/**
* Create a storage augmentation from configuration
* Maintains backward compatibility with existing storage config
*/
export async function createStorageAugmentationFromConfig(config) {
// Import storage factory dynamically to avoid circular deps
const { createStorage } = await import('../storage/storageFactory.js');
try {
// Create storage adapter from config
const adapter = await createStorage(config);
// Wrap in augmentation
return new DynamicStorageAugmentation(adapter);
}
catch (error) {
console.warn('Failed to create storage augmentation from config:', error);
return null;
}
}
//# sourceMappingURL=storageAugmentation.js.map

View file

@ -0,0 +1 @@
{"version":3,"file":"storageAugmentation.js","sourceRoot":"","sources":["../../src/augmentations/storageAugmentation.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,EAAE,gBAAgB,EAA2C,MAAM,yBAAyB,CAAA;AAGnG;;;GAGG;AACH,MAAM,OAAgB,mBAAoB,SAAQ,gBAAgB;IAQhE,sEAAsE;IACtE,YAAY,MAAY;QACtB,KAAK,CAAC,MAAM,CAAC,CAAA;QATN,WAAM,GAAG,SAAkB,CAAA;QAC3B,aAAQ,GAAG,MAAe,CAAA,CAAE,2CAA2C;QAChF,eAAU,GAAG,CAAC,SAAS,CAAkB,CAAA,CAAE,4CAA4C;QAC9E,aAAQ,GAAG,GAAG,CAAA,CAAC,4BAA4B;QAE1C,mBAAc,GAA0B,IAAI,CAAA;IAKtD,CAAC;IAQD;;;OAGG;IACH,KAAK,CAAC,UAAU,CAAC,OAA4B;QAC3C,MAAM,KAAK,CAAC,UAAU,CAAC,OAAO,CAAC,CAAA;QAC/B,6CAA6C;QAC7C,IAAI,CAAC,IAAI,CAAC,cAAc,EAAE,CAAC;YACzB,IAAI,CAAC,cAAc,GAAG,MAAM,IAAI,CAAC,cAAc,EAAE,CAAA;QACnD,CAAC;IACH,CAAC;IAED;;;OAGG;IACH,KAAK,CAAC,OAAO,CACX,SAAiB,EACjB,MAAW,EACX,IAAsB;QAEtB,IAAI,SAAS,KAAK,SAAS,EAAE,CAAC;YAC5B,6BAA6B;YAC7B,OAAO,IAAI,CAAC,cAA0B,CAAA;QACxC,CAAC;QAED,oCAAoC;QACpC,OAAO,IAAI,EAAE,CAAA;IACf,CAAC;IAED;;OAEG;IACH,KAAK,CAAC,QAAQ;QACZ,oCAAoC;QACpC,IAAI,IAAI,CAAC,cAAc,IAAI,OAAQ,IAAI,CAAC,cAAsB,CAAC,KAAK,KAAK,UAAU,EAAE,CAAC;YACpF,MAAO,IAAI,CAAC,cAAsB,CAAC,KAAK,EAAE,CAAA;QAC5C,CAAC;QACD,MAAM,KAAK,CAAC,QAAQ,EAAE,CAAA;IACxB,CAAC;CACF;AAED;;;GAGG;AACH,MAAM,OAAO,0BAA2B,SAAQ,mBAAmB;IAGjE,YAAoB,OAAuB;QACzC,KAAK,EAAE,CAAA;QADW,YAAO,GAAP,OAAO,CAAgB;QAFlC,SAAI,GAAG,iBAAiB,CAAA;QAI/B,IAAI,CAAC,cAAc,GAAG,OAAO,CAAA;IAC/B,CAAC;IAED,KAAK,CAAC,cAAc;QAClB,OAAO,IAAI,CAAC,OAAO,CAAA;IACrB,CAAC;IAES,KAAK,CAAC,YAAY;QAC1B,6CAA6C;QAC7C,MAAM,IAAI,CAAC,OAAO,CAAC,IAAI,EAAE,CAAA;QACzB,IAAI,CAAC,GAAG,CAAC,GAAG,IAAI,CAAC,IAAI,cAAc,CAAC,CAAA;IACtC,CAAC;CACF;AAED;;;GAGG;AACH,MAAM,CAAC,KAAK,UAAU,mCAAmC,CACvD,MAAW;IAEX,4DAA4D;IAC5D,MAAM,EAAE,aAAa,EAAE,GAAG,MAAM,MAAM,CAAC,8BAA8B,CAAC,CAAA;IAEtE,IAAI,CAAC;QACH,qCAAqC;QACrC,MAAM,OAAO,GAAG,MAAM,aAAa,CAAC,MAAM,CAAC,CAAA;QAE3C,uBAAuB;QACvB,OAAO,IAAI,0BAA0B,CAAC,OAAO,CAAC,CAAA;IAChD,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,OAAO,CAAC,IAAI,CAAC,oDAAoD,EAAE,KAAK,CAAC,CAAA;QACzE,OAAO,IAAI,CAAA;IACb,CAAC;AACH,CAAC"}

View file

@ -0,0 +1,125 @@
/**
* Storage Augmentations - Concrete Implementations
*
* These augmentations provide different storage backends for Brainy.
* Each wraps an existing storage adapter for backward compatibility.
*/
import { StorageAugmentation } from './storageAugmentation.js';
import { StorageAdapter } from '../coreTypes.js';
import { AugmentationManifest } from './manifest.js';
/**
* Memory Storage Augmentation - Fast in-memory storage
*/
export declare class MemoryStorageAugmentation extends StorageAugmentation {
readonly name = "memory-storage";
readonly category: "core";
readonly description = "High-performance in-memory storage for development and testing";
constructor(config?: any);
getManifest(): AugmentationManifest;
provideStorage(): Promise<StorageAdapter>;
protected onInitialize(): Promise<void>;
}
/**
* FileSystem Storage Augmentation - Node.js persistent storage
*/
export declare class FileSystemStorageAugmentation extends StorageAugmentation {
readonly name = "filesystem-storage";
readonly category: "core";
readonly description = "Persistent file-based storage for Node.js environments";
constructor(config?: any);
getManifest(): AugmentationManifest;
provideStorage(): Promise<StorageAdapter>;
protected onInitialize(): Promise<void>;
}
/**
* OPFS Storage Augmentation - Browser persistent storage
*/
export declare class OPFSStorageAugmentation extends StorageAugmentation {
readonly name = "opfs-storage";
readonly category: "core";
readonly description = "Persistent browser storage using Origin Private File System";
constructor(config?: any);
getManifest(): AugmentationManifest;
provideStorage(): Promise<StorageAdapter>;
protected onInitialize(): Promise<void>;
}
/**
* S3 Storage Augmentation - Amazon S3 cloud storage
*/
export declare class S3StorageAugmentation extends StorageAugmentation {
readonly name = "s3-storage";
protected config: {
bucketName: string;
region?: string;
accessKeyId: string;
secretAccessKey: string;
sessionToken?: string;
cacheConfig?: any;
operationConfig?: any;
};
constructor(config: {
bucketName: string;
region?: string;
accessKeyId: string;
secretAccessKey: string;
sessionToken?: string;
cacheConfig?: any;
operationConfig?: any;
});
provideStorage(): Promise<StorageAdapter>;
protected onInitialize(): Promise<void>;
}
/**
* R2 Storage Augmentation - Cloudflare R2 storage
*/
export declare class R2StorageAugmentation extends StorageAugmentation {
readonly name = "r2-storage";
protected config: {
bucketName: string;
accountId: string;
accessKeyId: string;
secretAccessKey: string;
cacheConfig?: any;
};
constructor(config: {
bucketName: string;
accountId: string;
accessKeyId: string;
secretAccessKey: string;
cacheConfig?: any;
});
provideStorage(): Promise<StorageAdapter>;
protected onInitialize(): Promise<void>;
}
/**
* GCS Storage Augmentation - Google Cloud Storage
*/
export declare class GCSStorageAugmentation extends StorageAugmentation {
readonly name = "gcs-storage";
protected config: {
bucketName: string;
region?: string;
accessKeyId: string;
secretAccessKey: string;
endpoint?: string;
cacheConfig?: any;
};
constructor(config: {
bucketName: string;
region?: string;
accessKeyId: string;
secretAccessKey: string;
endpoint?: string;
cacheConfig?: any;
});
provideStorage(): Promise<StorageAdapter>;
protected onInitialize(): Promise<void>;
}
/**
* Auto-select the best storage augmentation for the environment
* Maintains zero-config philosophy
*/
export declare function createAutoStorageAugmentation(options?: {
rootDirectory?: string;
requestPersistentStorage?: boolean;
}): Promise<StorageAugmentation>;

Some files were not shown because too many files have changed in this diff Show more