This repository has been archived on 2026-09-03. You can view files and clone it, but you cannot make any changes to it's state, such as pushing and creating new issues, pull requests or comments.
open-brainy/src/augmentations/discovery.ts
David Snelling 0996c72468 feat: Brainy 3.0 - Production-ready Triple Intelligence database
Major improvements and simplifications:
- Simplified to Q8-only model precision (99% accuracy, 75% smaller)
- Removed WAL augmentation (not needed with modern filesystems)
- Eliminated all fake/stub code - 100% production-ready
- Added comprehensive cloud deployment support (Docker, K8s, AWS, GCP)
- Enhanced distributed system capabilities
- Improved Triple Intelligence find() implementation
- Added streaming pipeline for large-scale operations
- Comprehensive test coverage with new test suites

Breaking changes:
- Renamed BrainyData to Brainy (simpler, cleaner)
- Removed FP32 model option (Q8 provides 99% accuracy)
- Removed deprecated augmentations

Performance improvements:
- 10x faster initialization with Q8-only
- Reduced memory footprint by 75%
- Better scaling for millions of items

Co-Authored-By: Recovery checkpoint system
2025-09-11 16:23:32 -07:00

560 lines
No EOL
16 KiB
TypeScript

/**
* 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'
import { AugmentationConfigResolver } from './configResolver.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 class AugmentationDiscovery {
constructor(private registry: AugmentationRegistry) {}
/**
* Discover all registered augmentations with manifests
* @param options Discovery options
* @returns List of augmentation listings
*/
async discover(options: DiscoveryOptions = {}): Promise<AugmentationListing[]> {
const augmentations = this.registry.getAll()
const listings: AugmentationListing[] = []
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 as Function
const manifest = getManifestFn()
// Apply filters
if (options.category && manifest.category !== options.category) {
continue
}
if (options.enabled !== undefined) {
const isEnabled = (aug as any).enabled !== false
if (isEnabled !== options.enabled) {
continue
}
}
// Build listing
const listing: AugmentationListing = {
id: manifest.id,
name: manifest.name,
manifest,
status: {
enabled: (aug as any).enabled !== false,
initialized: (aug as any).isInitialized || false,
category: (aug as any).category || manifest.category,
priority: aug.priority
}
}
// Include configuration if requested
if (options.includeConfig && 'getConfig' in aug) {
const getConfigFn = aug.getConfig as Function
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: string): Promise<AugmentationManifest | null> {
const aug = this.registry.get(augId)
if (!aug || !('getManifest' in aug)) {
return null
}
try {
const getManifestFn = aug.getManifest as Function
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: string): Promise<JSONSchema | null> {
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: string): Promise<any | null> {
const aug = this.registry.get(augId)
if (!aug || !('getConfig' in aug)) {
return null
}
try {
const getConfigFn = aug.getConfig as Function
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: string, config: any): Promise<any | null> {
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 as Function
await updateConfigFn(config)
const getConfigFn = aug.getConfig as Function
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: string, config: any): Promise<ConfigValidationResult> {
const schema = await this.getConfigSchema(augId)
if (!schema) {
return {
valid: true,
warnings: ['No schema available for validation']
}
}
const errors: string[] = []
const warnings: string[] = []
const suggestions: string[] = []
// 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
*/
private validatePropertyValue(
key: string,
value: any,
schema: JSONSchema,
errors: string[],
warnings: string[]
): void {
// 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: string): Promise<Record<string, any> | null> {
const manifest = await this.getManifest(augId)
if (!manifest?.configSchema?.properties) {
return null
}
const prefix = `BRAINY_AUG_${augId.toUpperCase()}_`
const vars: Record<string, any> = {}
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: string): Promise<any[]> {
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: string): Promise<boolean> {
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: string): Promise<AugmentationListing[]> {
return this.discover({ category })
}
/**
* Get enabled augmentations
* @returns List of enabled augmentations
*/
async getEnabled(): Promise<AugmentationListing[]> {
return this.discover({ enabled: true })
}
/**
* Search augmentations by keyword
* @param query Search query
* @returns Matching augmentations
*/
async search(query: string): Promise<AugmentationListing[]> {
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(): Promise<Record<string, any>> {
const configs: Record<string, any> = {}
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: Record<string, any>): Promise<Record<string, { success: boolean; error?: string }>> {
const results: Record<string, { success: boolean; error?: string }> = {}
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: string): Promise<string | null> {
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
}
}