feat: add zero-configuration Brainy service template with augmentation-first architecture

- Implement WebSocket augmentation for real-time communication
- Implement WebRTC augmentation for peer-to-peer connections
- Implement HTTP augmentation as minimal REST fallback
- Add auto-discovery augmentation for data pattern analysis
- Add adaptive storage augmentation for intelligent resource management
- Add environment adapter augmentation for universal compatibility
- Template auto-detects environment (browser, Node.js, serverless, containers)
- Intelligent transport selection (WebRTC → WebSocket → HTTP)
- Automatic storage optimization (memory → filesystem → S3)
- Zero configuration required - just npm start
- Includes intelligent verb scoring by default
- Works in any environment without configuration
- Full documentation and examples included
This commit is contained in:
David Snelling 2025-08-06 18:17:32 -07:00
parent c38c8de10a
commit 768acf66ad
30 changed files with 3548 additions and 0 deletions

View file

@ -0,0 +1,324 @@
import { BrainyData } from '@soulcraft/brainy'
import config from 'config'
import { logger } from '../utils/logger.js'
export class BrainyService {
constructor() {
this.db = null
this.isInitialized = false
}
async initialize() {
if (this.isInitialized) {
return
}
try {
// Build Brainy configuration from app config
const brainyConfig = this.buildBrainyConfig()
// Initialize Brainy database
this.db = new BrainyData(brainyConfig)
await this.db.init()
this.isInitialized = true
logger.info('Brainy database initialized successfully', {
storage: config.get('brainy.storage.type'),
features: config.get('brainy.features')
})
} catch (error) {
logger.error('Failed to initialize Brainy database:', error)
throw error
}
}
buildBrainyConfig() {
const brainyConfig = {}
// Storage configuration
const storageConfig = config.get('brainy.storage')
if (storageConfig.type === 's3' && storageConfig.s3) {
brainyConfig.storage = {
s3Storage: {
bucketName: storageConfig.s3.bucketName,
region: storageConfig.s3.region,
accessKeyId: storageConfig.s3.accessKeyId,
secretAccessKey: storageConfig.s3.secretAccessKey
}
}
} else if (storageConfig.type === 'filesystem') {
brainyConfig.storage = {
forceFileSystemStorage: true
}
} else {
brainyConfig.storage = {
forceMemoryStorage: true
}
}
// Cache configuration
if (config.has('brainy.cache')) {
brainyConfig.cache = config.get('brainy.cache')
}
// Logging configuration
if (config.has('brainy.logging')) {
brainyConfig.logging = config.get('brainy.logging')
}
// Intelligent verb scoring configuration
if (config.get('brainy.features.intelligentVerbScoring')) {
brainyConfig.intelligentVerbScoring = config.get('brainy.intelligentVerbScoring')
}
// Real-time updates
if (config.get('brainy.features.realTimeUpdates')) {
brainyConfig.realtimeUpdates = {
enabled: true,
interval: 30000,
updateStatistics: true,
updateIndex: true
}
}
// Distributed mode
if (config.get('brainy.features.distributedMode')) {
brainyConfig.distributed = true
}
return brainyConfig
}
// Entity operations
async addEntity(data, metadata = {}, options = {}) {
this.ensureInitialized()
try {
const id = await this.db.add(data, metadata, options)
logger.debug('Entity added', { id, metadata: metadata.type || 'unknown' })
return id
} catch (error) {
logger.error('Failed to add entity:', error)
throw error
}
}
async getEntity(id) {
this.ensureInitialized()
try {
const entity = await this.db.get(id)
return entity
} catch (error) {
logger.error(`Failed to get entity ${id}:`, error)
throw error
}
}
async updateEntity(id, data, metadata = {}) {
this.ensureInitialized()
try {
await this.db.update(id, data, metadata)
logger.debug('Entity updated', { id })
return true
} catch (error) {
logger.error(`Failed to update entity ${id}:`, error)
throw error
}
}
async deleteEntity(id) {
this.ensureInitialized()
try {
await this.db.delete(id)
logger.debug('Entity deleted', { id })
return true
} catch (error) {
logger.error(`Failed to delete entity ${id}:`, error)
throw error
}
}
async searchEntities(query, options = {}) {
this.ensureInitialized()
try {
const results = await this.db.search(query, options.limit || 10, {
threshold: options.threshold || 0.7,
includeMetadata: true,
...options
})
logger.debug('Entity search completed', {
query: query.substring(0, 50),
resultCount: results.length
})
return results
} catch (error) {
logger.error('Entity search failed:', error)
throw error
}
}
async listEntities(options = {}) {
this.ensureInitialized()
try {
// Get all entities with pagination if supported
const entities = await this.db.getAllNouns(options)
return entities
} catch (error) {
logger.error('Failed to list entities:', error)
throw error
}
}
// Relationship operations
async addRelationship(sourceId, targetId, type, options = {}) {
this.ensureInitialized()
try {
const relationshipId = await this.db.addVerb(sourceId, targetId, undefined, {
type,
weight: options.weight,
metadata: options.metadata,
autoCreateMissingNouns: options.autoCreateMissingNouns || false
})
logger.debug('Relationship added', {
relationshipId,
sourceId,
targetId,
type
})
return relationshipId
} catch (error) {
logger.error('Failed to add relationship:', error)
throw error
}
}
async getRelationship(id) {
this.ensureInitialized()
try {
const relationship = await this.db.getVerb(id)
return relationship
} catch (error) {
logger.error(`Failed to get relationship ${id}:`, error)
throw error
}
}
async updateRelationship(id, updates) {
this.ensureInitialized()
try {
await this.db.updateVerb(id, updates)
logger.debug('Relationship updated', { id })
return true
} catch (error) {
logger.error(`Failed to update relationship ${id}:`, error)
throw error
}
}
async deleteRelationship(id) {
this.ensureInitialized()
try {
await this.db.deleteVerb(id)
logger.debug('Relationship deleted', { id })
return true
} catch (error) {
logger.error(`Failed to delete relationship ${id}:`, error)
throw error
}
}
async listRelationships(options = {}) {
this.ensureInitialized()
try {
const relationships = await this.db.getVerbs(options)
return relationships
} catch (error) {
logger.error('Failed to list relationships:', error)
throw error
}
}
// Health and metrics
async getHealth() {
if (!this.isInitialized) {
return { status: 'not_initialized' }
}
try {
const stats = await this.db.getStatistics()
return {
status: 'healthy',
database: {
entities: stats.nounCount || 0,
relationships: stats.verbCount || 0,
indexSize: stats.hnswIndexSize || 0
},
features: {
intelligentVerbScoring: config.get('brainy.features.intelligentVerbScoring'),
realTimeUpdates: config.get('brainy.features.realTimeUpdates'),
distributedMode: config.get('brainy.features.distributedMode')
}
}
} catch (error) {
logger.error('Health check failed:', error)
return {
status: 'unhealthy',
error: error.message
}
}
}
async getMetrics() {
this.ensureInitialized()
try {
const stats = await this.db.getStatistics()
return {
database: stats,
performance: {
// Add performance metrics here
uptime: process.uptime(),
memory: process.memoryUsage()
}
}
} catch (error) {
logger.error('Failed to get metrics:', error)
throw error
}
}
// Utility methods
ensureInitialized() {
if (!this.isInitialized) {
throw new Error('BrainyService not initialized')
}
}
async shutdown() {
if (this.db && this.db.cleanup) {
await this.db.cleanup()
}
this.isInitialized = false
logger.info('BrainyService shutdown complete')
}
// Expose the underlying db for advanced operations
getDatabase() {
this.ensureInitialized()
return this.db
}
}

View file

@ -0,0 +1,192 @@
import { logger } from '../utils/logger.js'
export class ScoringService {
constructor(brainyService) {
this.brainyService = brainyService
}
async provideFeedback(relationshipId, feedbackData) {
try {
// Get the relationship to extract source, target, and type
const relationship = await this.brainyService.getRelationship(relationshipId)
if (!relationship) {
throw new Error(`Relationship ${relationshipId} not found`)
}
// Provide feedback to the intelligent scoring system
const db = this.brainyService.getDatabase()
await db.provideFeedbackForVerbScoring(
relationship.sourceId,
relationship.targetId,
relationship.type || relationship.verb,
feedbackData.weight,
feedbackData.confidence,
feedbackData.type || 'correction'
)
logger.info('Feedback provided for relationship', {
relationshipId,
feedbackType: feedbackData.type || 'correction',
weight: feedbackData.weight,
confidence: feedbackData.confidence
})
return {
success: true,
message: 'Feedback provided successfully'
}
} catch (error) {
logger.error('Failed to provide feedback:', error)
throw error
}
}
async getStats() {
try {
const db = this.brainyService.getDatabase()
const stats = db.getVerbScoringStats()
if (!stats) {
return {
message: 'Intelligent verb scoring is not enabled or has no data yet',
stats: null
}
}
logger.debug('Retrieved scoring statistics', {
totalRelationships: stats.totalRelationships
})
return {
stats,
timestamp: new Date().toISOString()
}
} catch (error) {
logger.error('Failed to get scoring statistics:', error)
throw error
}
}
async exportLearningData() {
try {
const db = this.brainyService.getDatabase()
const learningData = db.exportVerbScoringLearningData()
if (!learningData) {
return {
message: 'No learning data available for export',
data: null
}
}
logger.info('Learning data exported successfully')
return {
data: learningData,
timestamp: new Date().toISOString(),
format: 'json'
}
} catch (error) {
logger.error('Failed to export learning data:', error)
throw error
}
}
async importLearningData(learningData) {
try {
const db = this.brainyService.getDatabase()
// If data is an object, stringify it
const dataString = typeof learningData === 'string'
? learningData
: JSON.stringify(learningData)
db.importVerbScoringLearningData(dataString)
logger.info('Learning data imported successfully')
return {
success: true,
message: 'Learning data imported successfully'
}
} catch (error) {
logger.error('Failed to import learning data:', error)
throw error
}
}
async clearStats() {
try {
const db = this.brainyService.getDatabase()
// Access the intelligent scoring system directly if available
if (db.intelligentVerbScoring && db.intelligentVerbScoring.enabled) {
db.intelligentVerbScoring.clearStats()
logger.info('Scoring statistics cleared')
return {
success: true,
message: 'Scoring statistics cleared successfully'
}
} else {
return {
success: false,
message: 'Intelligent verb scoring is not enabled'
}
}
} catch (error) {
logger.error('Failed to clear scoring statistics:', error)
throw error
}
}
// Analysis methods
async analyzeRelationshipPattern(sourceType, targetType, relationshipType) {
try {
const stats = await this.getStats()
if (!stats.stats) {
return {
message: 'No data available for pattern analysis'
}
}
// Find patterns for the specific relationship type
const pattern = `${sourceType}-${relationshipType}-${targetType}`
const relevantRelationships = stats.stats.topRelationships.filter(rel =>
rel.relationship.includes(relationshipType)
)
return {
pattern,
relationships: relevantRelationships,
analysis: {
averageWeight: relevantRelationships.reduce((sum, rel) => sum + rel.averageWeight, 0) / relevantRelationships.length || 0,
totalOccurrences: relevantRelationships.reduce((sum, rel) => sum + rel.count, 0),
confidence: relevantRelationships.length > 5 ? 'high' : 'low'
}
}
} catch (error) {
logger.error('Failed to analyze relationship pattern:', error)
throw error
}
}
async getRecommendations(entityId, limit = 10) {
try {
// This would implement recommendation logic based on learned patterns
// For now, return a placeholder
return {
entityId,
recommendations: [],
message: 'Recommendation system not yet implemented',
basedOn: 'intelligent_verb_scoring_patterns'
}
} catch (error) {
logger.error('Failed to get recommendations:', error)
throw error
}
}
}