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 880b8f74e3
commit ee003a9473
30 changed files with 3548 additions and 0 deletions

View file

@ -0,0 +1,174 @@
import { logger } from '../utils/logger.js'
import { ApiError } from '../utils/errors.js'
export const entitiesController = {
async create(req, res, next) {
try {
const { data, metadata = {}, options = {} } = req.body
const { brainyService } = req.app.locals
if (!data) {
throw new ApiError(400, 'Data is required')
}
// Add timestamp and source info to metadata
const enhancedMetadata = {
...metadata,
createdAt: new Date().toISOString(),
source: 'api'
}
const entityId = await brainyService.addEntity(data, enhancedMetadata, options)
res.status(201).json({
success: true,
id: entityId,
data: {
id: entityId,
data,
metadata: enhancedMetadata
}
})
} catch (error) {
next(error)
}
},
async getById(req, res, next) {
try {
const { id } = req.params
const { brainyService } = req.app.locals
const entity = await brainyService.getEntity(id)
if (!entity) {
throw new ApiError(404, `Entity with ID ${id} not found`)
}
res.json({
success: true,
data: entity
})
} catch (error) {
next(error)
}
},
async update(req, res, next) {
try {
const { id } = req.params
const { data, metadata = {} } = req.body
const { brainyService } = req.app.locals
// Check if entity exists
const existingEntity = await brainyService.getEntity(id)
if (!existingEntity) {
throw new ApiError(404, `Entity with ID ${id} not found`)
}
// Add update timestamp
const enhancedMetadata = {
...metadata,
updatedAt: new Date().toISOString()
}
await brainyService.updateEntity(id, data, enhancedMetadata)
res.json({
success: true,
message: 'Entity updated successfully',
id
})
} catch (error) {
next(error)
}
},
async delete(req, res, next) {
try {
const { id } = req.params
const { brainyService } = req.app.locals
// Check if entity exists
const existingEntity = await brainyService.getEntity(id)
if (!existingEntity) {
throw new ApiError(404, `Entity with ID ${id} not found`)
}
await brainyService.deleteEntity(id)
res.json({
success: true,
message: 'Entity deleted successfully',
id
})
} catch (error) {
next(error)
}
},
async search(req, res, next) {
try {
const { query, limit = 10, threshold = 0.7, includeMetadata = true } = req.body
const { brainyService } = req.app.locals
if (!query) {
throw new ApiError(400, 'Query is required')
}
const options = {
limit: Math.min(limit, 100), // Cap at 100 results
threshold,
includeMetadata
}
const results = await brainyService.searchEntities(query, options)
res.json({
success: true,
query,
results: results.map(result => ({
id: result.id,
similarity: result.similarity,
data: result.data,
metadata: result.metadata
})),
count: results.length,
options
})
} catch (error) {
next(error)
}
},
async list(req, res, next) {
try {
const { page = 1, limit = 50, type } = req.query
const { brainyService } = req.app.locals
const options = {
offset: (page - 1) * limit,
limit: Math.min(limit, 100)
}
// Add type filter if specified
if (type) {
options.filter = { type }
}
const entities = await brainyService.listEntities(options)
res.json({
success: true,
data: entities,
pagination: {
page: parseInt(page),
limit: parseInt(limit),
count: entities.length
}
})
} catch (error) {
next(error)
}
}
}

View file

@ -0,0 +1,130 @@
import { logger } from '../utils/logger.js'
export const healthController = {
async check(req, res, next) {
try {
const { brainyService } = req.app.locals
// Get Brainy health status
const brainyHealth = await brainyService.getHealth()
// Overall system health
const health = {
status: brainyHealth.status === 'healthy' ? 'healthy' : 'unhealthy',
timestamp: new Date().toISOString(),
version: process.env.npm_package_version || '1.0.0',
environment: process.env.NODE_ENV || 'development',
uptime: Math.floor(process.uptime()),
services: {
brainy: brainyHealth
},
system: {
memory: {
used: Math.round(process.memoryUsage().heapUsed / 1024 / 1024),
total: Math.round(process.memoryUsage().heapTotal / 1024 / 1024),
external: Math.round(process.memoryUsage().external / 1024 / 1024)
},
cpu: process.cpuUsage()
}
}
const statusCode = health.status === 'healthy' ? 200 : 503
res.status(statusCode).json(health)
} catch (error) {
logger.error('Health check failed:', error)
res.status(503).json({
status: 'unhealthy',
timestamp: new Date().toISOString(),
error: error.message,
services: {
brainy: { status: 'error', error: error.message }
}
})
}
},
async readiness(req, res, next) {
try {
const { brainyService } = req.app.locals
// Check if services are ready
const brainyHealth = await brainyService.getHealth()
const isReady = brainyHealth.status === 'healthy'
const readiness = {
ready: isReady,
timestamp: new Date().toISOString(),
checks: {
brainy: {
ready: brainyHealth.status === 'healthy',
details: brainyHealth
}
}
}
const statusCode = readiness.ready ? 200 : 503
res.status(statusCode).json(readiness)
} catch (error) {
logger.error('Readiness check failed:', error)
res.status(503).json({
ready: false,
timestamp: new Date().toISOString(),
error: error.message
})
}
},
async liveness(req, res, next) {
try {
// Simple liveness check - just verify the process is running
res.status(200).json({
alive: true,
timestamp: new Date().toISOString(),
pid: process.pid,
uptime: Math.floor(process.uptime())
})
} catch (error) {
logger.error('Liveness check failed:', error)
res.status(503).json({
alive: false,
timestamp: new Date().toISOString(),
error: error.message
})
}
},
async metrics(req, res, next) {
try {
const { brainyService } = req.app.locals
// Get detailed metrics
const brainyMetrics = await brainyService.getMetrics()
const metrics = {
timestamp: new Date().toISOString(),
brainy: brainyMetrics.database,
system: {
...brainyMetrics.performance,
process: {
pid: process.pid,
version: process.version,
platform: process.platform,
arch: process.arch,
env: process.env.NODE_ENV || 'development'
}
}
}
res.json({
success: true,
data: metrics
})
} catch (error) {
next(error)
}
}
}

View file

@ -0,0 +1,167 @@
import { logger } from '../utils/logger.js'
import { ApiError } from '../utils/errors.js'
export const relationshipsController = {
async create(req, res, next) {
try {
const { sourceId, targetId, type, weight, metadata = {}, autoCreateMissingNouns = false } = req.body
const { brainyService } = req.app.locals
if (!sourceId || !targetId || !type) {
throw new ApiError(400, 'sourceId, targetId, and type are required')
}
// Add timestamp and source info to metadata
const enhancedMetadata = {
...metadata,
createdAt: new Date().toISOString(),
source: 'api'
}
const options = {
weight,
metadata: enhancedMetadata,
autoCreateMissingNouns
}
const relationshipId = await brainyService.addRelationship(sourceId, targetId, type, options)
// Get the created relationship to return full details
const relationship = await brainyService.getRelationship(relationshipId)
res.status(201).json({
success: true,
id: relationshipId,
data: {
id: relationshipId,
sourceId,
targetId,
type,
weight: relationship?.metadata?.weight,
confidence: relationship?.metadata?.confidence,
intelligentScoring: relationship?.metadata?.intelligentScoring,
metadata: enhancedMetadata
}
})
} catch (error) {
next(error)
}
},
async getById(req, res, next) {
try {
const { id } = req.params
const { brainyService } = req.app.locals
const relationship = await brainyService.getRelationship(id)
if (!relationship) {
throw new ApiError(404, `Relationship with ID ${id} not found`)
}
res.json({
success: true,
data: relationship
})
} catch (error) {
next(error)
}
},
async update(req, res, next) {
try {
const { id } = req.params
const { weight, metadata = {} } = req.body
const { brainyService } = req.app.locals
// Check if relationship exists
const existingRelationship = await brainyService.getRelationship(id)
if (!existingRelationship) {
throw new ApiError(404, `Relationship with ID ${id} not found`)
}
// Prepare updates
const updates = {}
if (weight !== undefined) updates.weight = weight
if (Object.keys(metadata).length > 0) {
updates.metadata = {
...metadata,
updatedAt: new Date().toISOString()
}
}
await brainyService.updateRelationship(id, updates)
res.json({
success: true,
message: 'Relationship updated successfully',
id
})
} catch (error) {
next(error)
}
},
async delete(req, res, next) {
try {
const { id } = req.params
const { brainyService } = req.app.locals
// Check if relationship exists
const existingRelationship = await brainyService.getRelationship(id)
if (!existingRelationship) {
throw new ApiError(404, `Relationship with ID ${id} not found`)
}
await brainyService.deleteRelationship(id)
res.json({
success: true,
message: 'Relationship deleted successfully',
id
})
} catch (error) {
next(error)
}
},
async list(req, res, next) {
try {
const { page = 1, limit = 50, sourceId, targetId, type } = req.query
const { brainyService } = req.app.locals
const options = {
pagination: {
offset: (page - 1) * limit,
limit: Math.min(limit, 100)
}
}
// Add filters if specified
const filter = {}
if (sourceId) filter.sourceId = sourceId
if (targetId) filter.targetId = targetId
if (type) filter.verbType = type
if (Object.keys(filter).length > 0) {
options.filter = filter
}
const result = await brainyService.listRelationships(options)
res.json({
success: true,
data: result.items || result,
pagination: {
page: parseInt(page),
limit: parseInt(limit),
count: result.items ? result.items.length : result.length,
hasMore: result.hasMore || false,
totalCount: result.totalCount
}
})
} catch (error) {
next(error)
}
}
}

View file

@ -0,0 +1,195 @@
import { logger } from '../utils/logger.js'
import { ApiError } from '../utils/errors.js'
export const scoringController = {
async provideFeedback(req, res, next) {
try {
const { id } = req.params
const { weight, confidence, type = 'correction' } = req.body
const { scoringService } = req.app.locals
if (!scoringService) {
throw new ApiError(400, 'Intelligent verb scoring is not enabled')
}
if (weight === undefined) {
throw new ApiError(400, 'Weight is required for feedback')
}
if (weight < 0 || weight > 1) {
throw new ApiError(400, 'Weight must be between 0 and 1')
}
if (confidence !== undefined && (confidence < 0 || confidence > 1)) {
throw new ApiError(400, 'Confidence must be between 0 and 1')
}
const feedbackData = {
weight,
confidence,
type
}
const result = await scoringService.provideFeedback(id, feedbackData)
res.json({
success: true,
message: result.message,
feedback: {
relationshipId: id,
weight,
confidence,
type,
timestamp: new Date().toISOString()
}
})
} catch (error) {
next(error)
}
},
async getStats(req, res, next) {
try {
const { scoringService } = req.app.locals
if (!scoringService) {
throw new ApiError(400, 'Intelligent verb scoring is not enabled')
}
const stats = await scoringService.getStats()
res.json({
success: true,
data: stats
})
} catch (error) {
next(error)
}
},
async exportLearningData(req, res, next) {
try {
const { scoringService } = req.app.locals
if (!scoringService) {
throw new ApiError(400, 'Intelligent verb scoring is not enabled')
}
const result = await scoringService.exportLearningData()
if (!result.data) {
return res.json({
success: true,
message: result.message
})
}
// Set appropriate headers for download
res.setHeader('Content-Type', 'application/json')
res.setHeader('Content-Disposition', 'attachment; filename="brainy-learning-data.json"')
res.json({
success: true,
data: result.data,
timestamp: result.timestamp,
format: result.format
})
} catch (error) {
next(error)
}
},
async importLearningData(req, res, next) {
try {
const { data } = req.body
const { scoringService } = req.app.locals
if (!scoringService) {
throw new ApiError(400, 'Intelligent verb scoring is not enabled')
}
if (!data) {
throw new ApiError(400, 'Learning data is required')
}
const result = await scoringService.importLearningData(data)
res.json({
success: true,
message: result.message,
timestamp: new Date().toISOString()
})
} catch (error) {
next(error)
}
},
async clearStats(req, res, next) {
try {
const { scoringService } = req.app.locals
if (!scoringService) {
throw new ApiError(400, 'Intelligent verb scoring is not enabled')
}
const result = await scoringService.clearStats()
res.json({
success: result.success,
message: result.message,
timestamp: new Date().toISOString()
})
} catch (error) {
next(error)
}
},
async analyzePattern(req, res, next) {
try {
const { sourceType, targetType, relationshipType } = req.body
const { scoringService } = req.app.locals
if (!scoringService) {
throw new ApiError(400, 'Intelligent verb scoring is not enabled')
}
if (!sourceType || !targetType || !relationshipType) {
throw new ApiError(400, 'sourceType, targetType, and relationshipType are required')
}
const analysis = await scoringService.analyzeRelationshipPattern(
sourceType,
targetType,
relationshipType
)
res.json({
success: true,
data: analysis
})
} catch (error) {
next(error)
}
},
async getRecommendations(req, res, next) {
try {
const { entityId } = req.params
const { limit = 10 } = req.query
const { scoringService } = req.app.locals
if (!scoringService) {
throw new ApiError(400, 'Intelligent verb scoring is not enabled')
}
const recommendations = await scoringService.getRecommendations(entityId, parseInt(limit))
res.json({
success: true,
data: recommendations
})
} catch (error) {
next(error)
}
}
}