chore: remove examples/externalPlugins.js and pluginLoader.ts, update imports to .js

Deleted `examples/externalPlugins.js` and `pluginLoader.ts` as they are no longer used. Updated all `.ts` imports to `.js` across the codebase. Added `MemberOf` to `VerbType` and filtered disabled augmentations in `executeAugmentationPipeline`. Updated documentation to reflect new augmentation registration process. Removed deprecated `allowImportingTsExtensions` from `tsconfig.json`.
This commit is contained in:
David Snelling 2025-05-29 09:52:30 -07:00
parent 7d2b695ea0
commit 203b669203
22 changed files with 1063 additions and 541 deletions

110
README.md
View file

@ -577,88 +577,52 @@ This enum can be used by consumers of the library to identify the different type
Brainy provides an event pipeline that allows registering and executing multiple augmentations of each type. The pipeline supports different execution modes and provides a flexible way to manage augmentations.
#### Using External Augmentation Plugins
### Installing Custom Augmentations
Brainy provides a plugin loader that makes it easy to load and configure augmentation plugins from external npm packages. This allows you to extend Brainy's capabilities with specialized augmentations developed by third parties or maintained in separate packages.
Brainy provides a build-time registration system for installing custom augmentations in your application:
#### Build-Time Registration
For better performance and bundle optimization, you can register augmentations at build time:
```typescript
import {
BrainyData,
configureAndStartPipeline,
createSensePluginConfig,
createConduitPluginConfig,
AugmentationType
} from '@soulcraft/brainy';
// myCustomAugmentation.ts
import { registerAugmentation, AugmentationType } from '@soulcraft/brainy';
// Create a new BrainyData instance
const db = new BrainyData();
await db.init();
// Configure and start the augmentation pipeline with external plugins
// Note: These are example plugin names. You would need to install these packages via npm first.
const result = await configureAndStartPipeline([
// Sense augmentations (will be loaded first)
createSensePluginConfig('@example/text-sense-augmentation', {
language: 'english',
enableNER: true
}),
// Conduit augmentations for two-way synchronization
createConduitPluginConfig('@example/websocket-conduit', {
url: 'wss://example.com/sync',
reconnectInterval: 5000
}),
// Other augmentation types
{
plugin: '@example/memory-augmentation',
config: { storageType: 'persistent' },
type: AugmentationType.MEMORY
}
], {
// Optional: Customize the loading options
useDefaultPipeline: true, // Use the default pipeline instance
initializeAfterLoading: true, // Initialize augmentations after loading
augmentationOrder: [ // Custom order (Sense first, as recommended)
AugmentationType.SENSE,
AugmentationType.CONDUIT,
AugmentationType.MEMORY,
AugmentationType.COGNITION,
AugmentationType.PERCEPTION,
AugmentationType.DIALOG,
AugmentationType.ACTIVATION
]
});
// Get the pipeline instance
const { pipeline } = result;
// Use the pipeline to execute augmentations
const senseResults = await pipeline.executeSensePipeline(
'processRawData',
['This is some example text to process', 'text']
);
// Process the results and insert data into BrainyData
for (const resultPromise of senseResults) {
const result = await resultPromise;
if (result.success) {
// Insert the extracted nouns and verbs into BrainyData according to graphTypes
for (const noun of result.data.nouns) {
await db.add(noun, { type: 'noun' });
}
}
// Create your custom augmentation
class MyCustomAugmentation {
// Implement required methods...
}
// Register it with the registry
export const myAugmentation = registerAugmentation(new MyCustomAugmentation());
```
The plugin loader provides several functions for working with external plugins:
Then configure your build tool (webpack or rollup) to automatically discover and register these augmentations:
- `loadPlugins(plugins, options)`: Loads augmentation plugins from external npm packages
- `configureAndStartPipeline(plugins, options)`: Configures and starts the augmentation pipeline with the specified plugins
- `createSensePluginConfig(plugin, config)`: Creates a plugin configuration for a sense augmentation
- `createConduitPluginConfig(plugin, config)`: Creates a plugin configuration for a conduit augmentation
```javascript
// webpack.config.js
const { createAugmentationRegistryPlugin } = require('@soulcraft/brainy');
module.exports = {
// ... other webpack config
plugins: [
createAugmentationRegistryPlugin({
pattern: /augmentation\.(js|ts)$/,
options: { autoInitialize: true }
})
]
};
```
Benefits of build-time registration:
- Better performance as augmentations are available immediately at startup
- Improved tree-shaking and bundle optimization
- Type safety and better IDE support
- No need for dynamic imports or async loading
For detailed documentation on build-time augmentation registration, see [build-time-augmentations.md](docs/build-time-augmentations.md).
For more details, see the [externalPlugins.js](examples/externalPlugins.js) example.
#### Using the Pipeline Directly

View file

@ -0,0 +1,213 @@
# Build-Time Augmentation Registration
This document explains how to register custom augmentations at build time using the Brainy library's augmentation
registry system.
## Overview
Brainy provides a system for registering custom augmentations at build time, similar to Angular's pipeline. This allows
you to:
1. Define custom augmentations in your project
2. Register them with the Brainy library during the build process
3. Have them automatically available when your application runs
This approach has several advantages:
- Better performance as augmentations are available immediately at startup
- Improved tree-shaking and bundle optimization
- Type safety and better IDE support
- No need for dynamic imports or async loading
## Creating Custom Augmentations
To create a custom augmentation, you need to implement one of the augmentation interfaces provided by Brainy:
```typescript
// myTextSenseAugmentation.ts
import {
registerAugmentation,
AugmentationType,
BrainyAugmentations
} from 'brainy';
// Define a custom sense augmentation
class MyTextSenseAugmentation implements BrainyAugmentations.ISenseAugmentation {
name = 'MyTextSenseAugmentation';
enabled = true;
type = AugmentationType.SENSE;
// Required IAugmentation methods
async initialize() {
console.log('Initializing MyTextSenseAugmentation');
return true;
}
async shutDown() {
console.log('Shutting down MyTextSenseAugmentation');
return true;
}
getStatus() {
return {
name: this.name,
enabled: this.enabled,
type: this.type,
status: 'ready'
};
}
// ISenseAugmentation methods
async processRawData(rawData, dataType) {
console.log(`Processing ${dataType} data`);
// Your implementation here
return {
success: true,
data: { /* processed data */}
};
}
async listenToFeed(feedUrl, callback) {
console.log(`Listening to feed at ${feedUrl}`);
// Your implementation here
return {
success: true,
data: { /* feed info */}
};
}
}
// Register the augmentation with the registry
// This will make it available to the Brainy library at runtime
export const myTextSenseAugmentation = registerAugmentation(new MyTextSenseAugmentation());
```
## Registering Augmentations
There are two ways to register augmentations:
### 1. Manual Registration
You can manually register augmentations by calling `registerAugmentation()` in your code:
```typescript
import {registerAugmentation} from 'brainy';
import {MyCustomAugmentation} from './myCustomAugmentation';
// Register the augmentation
const myAugmentation = registerAugmentation(new MyCustomAugmentation());
// You can also export it for use elsewhere in your application
export {myAugmentation};
```
### 2. Automatic Registration with Build Tools
For larger projects, you can use build tools like webpack or rollup to automatically discover and register
augmentations:
#### With Webpack
```javascript
// webpack.config.js
const {createAugmentationRegistryPlugin} = require('brainy');
module.exports = {
// ... other webpack config
plugins: [
createAugmentationRegistryPlugin({
// Pattern to match files containing augmentations
pattern: /augmentation\.(js|ts)$/,
options: {
autoInitialize: true,
debug: true
}
})
]
};
```
#### With Rollup
```javascript
// rollup.config.js
import {createAugmentationRegistryRollupPlugin} from 'brainy';
export default {
// ... other rollup config
plugins: [
createAugmentationRegistryRollupPlugin({
pattern: /augmentation\.(js|ts)$/,
options: {
autoInitialize: true,
debug: true
}
})
]
};
```
## Using Registered Augmentations
Once augmentations are registered, they are automatically available to the Brainy library. You can use them through the
augmentation pipeline:
```typescript
import {BrainyData, augmentationPipeline, initializeAugmentationPipeline} from 'brainy';
// Create a new BrainyData instance
const db = new BrainyData();
await db.init();
// Initialize the augmentation pipeline with all registered augmentations
initializeAugmentationPipeline();
// Use the pipeline to execute augmentations
const senseResults = await augmentationPipeline.executeSensePipeline(
'processRawData',
['This is some example text to process', 'text']
);
// Process the results
for (const resultPromise of senseResults) {
const result = await resultPromise;
if (result.success) {
console.log('Processed data:', result.data);
}
}
```
## Best Practices
1. **Naming Convention**: Use a consistent naming convention for your augmentation files, such as ending them with
`augmentation.ts` or `augmentation.js`.
2. **File Organization**: Keep your augmentations organized in a dedicated directory, such as `src/augmentations/`.
3. **Type Safety**: Implement the appropriate interfaces for your augmentations to ensure type safety.
4. **Documentation**: Document your augmentations with JSDoc comments to provide clear usage instructions.
5. **Testing**: Write tests for your augmentations to ensure they work correctly.
## Troubleshooting
If your augmentations are not being registered or are not working as expected, check the following:
1. Make sure your augmentation implements all required methods from the interface.
2. Verify that your augmentation is being registered with `registerAugmentation()`.
3. If using build tools, check that your file naming matches the pattern specified in the plugin configuration.
4. Enable debug logging in the plugin options to see detailed information about the registration process.
5. Check the console for any error messages during initialization.
## Examples
For complete examples, see:
- [Basic Augmentation Registration](../examples/buildTimeRegistration.js)
- [Webpack Configuration](../examples/webpack.config.js)
- [Rollup Configuration](../examples/rollup.config.js)

View file

@ -0,0 +1,184 @@
/**
* Example: Registering Augmentations at Build Time
*
* This example demonstrates how to register custom augmentations at build time
* using the Brainy library's augmentation registry system.
*/
// Import the augmentation registry and types from Brainy
import {
registerAugmentation,
AugmentationType,
BrainyAugmentations
} from '../dist/index.js';
// Define a custom sense augmentation
class CustomTextSenseAugmentation {
constructor() {
this.name = 'CustomTextSenseAugmentation';
this.enabled = true;
this.type = AugmentationType.SENSE;
}
// Required IAugmentation methods
async initialize() {
console.log('Initializing CustomTextSenseAugmentation');
return true;
}
async shutDown() {
console.log('Shutting down CustomTextSenseAugmentation');
return true;
}
getStatus() {
return {
name: this.name,
enabled: this.enabled,
type: this.type,
status: 'ready'
};
}
// ISenseAugmentation methods
async processRawData(rawData, dataType) {
console.log(`Processing ${dataType} data: ${rawData.substring(0, 50)}...`);
// Simple implementation to extract nouns and verbs
const words = rawData.split(' ');
const nouns = words.filter(word => word.length > 4);
const verbs = words.filter(word => word.endsWith('ing'));
return {
success: true,
data: { nouns, verbs }
};
}
async listenToFeed(feedUrl, callback) {
console.log(`Listening to feed at ${feedUrl}`);
// In a real implementation, this would set up a listener
// For this example, we'll just call the callback once
setTimeout(() => {
callback({
success: true,
data: { message: 'Feed update received' }
});
}, 1000);
return {
success: true,
data: { feedId: 'example-feed-1' }
};
}
}
// Define a custom memory augmentation
class CustomMemoryAugmentation {
constructor() {
this.name = 'CustomMemoryAugmentation';
this.enabled = true;
this.type = AugmentationType.MEMORY;
this.storage = new Map();
}
// Required IAugmentation methods
async initialize() {
console.log('Initializing CustomMemoryAugmentation');
return true;
}
async shutDown() {
console.log('Shutting down CustomMemoryAugmentation');
this.storage.clear();
return true;
}
getStatus() {
return {
name: this.name,
enabled: this.enabled,
type: this.type,
status: 'ready',
itemCount: this.storage.size
};
}
// IMemoryAugmentation methods
async storeData(key, data, options = {}) {
console.log(`Storing data with key: ${key}`);
this.storage.set(key, data);
return {
success: true,
data: { key }
};
}
async retrieveData(key, options = {}) {
console.log(`Retrieving data with key: ${key}`);
const data = this.storage.get(key);
return {
success: !!data,
data: data || null,
error: !data ? 'Key not found' : undefined
};
}
async updateData(key, data, options = {}) {
console.log(`Updating data with key: ${key}`);
if (!this.storage.has(key)) {
return {
success: false,
data: null,
error: 'Key not found'
};
}
this.storage.set(key, data);
return {
success: true,
data: { key }
};
}
async deleteData(key, options = {}) {
console.log(`Deleting data with key: ${key}`);
const existed = this.storage.has(key);
this.storage.delete(key);
return {
success: existed,
data: { deleted: existed },
error: !existed ? 'Key not found' : undefined
};
}
async listDataKeys(pattern = '*', options = {}) {
console.log(`Listing data keys with pattern: ${pattern}`);
// Simple implementation that returns all keys
// A real implementation would filter by pattern
const keys = Array.from(this.storage.keys());
return {
success: true,
data: { keys }
};
}
}
// Register the augmentations with the registry
// This will make them available to the Brainy library at runtime
const textSenseAugmentation = registerAugmentation(new CustomTextSenseAugmentation());
const memoryAugmentation = registerAugmentation(new CustomMemoryAugmentation());
console.log('Custom augmentations registered successfully');
// Export the registered augmentations for use in the application
export { textSenseAugmentation, memoryAugmentation };

View file

@ -1,158 +0,0 @@
/**
* Example: Using External Augmentation Plugins with Brainy
*
* This example demonstrates how to load and configure external augmentation plugins
* with the Brainy library. It shows how to use the plugin loader to integrate
* externally installed augmentation plugins into the Brainy system.
*/
import {
BrainyData,
configureAndStartPipeline,
createSensePluginConfig,
createConduitPluginConfig,
AugmentationType
} from '../dist/index.js';
// Create a new BrainyData instance
const db = new BrainyData();
await db.init();
console.log('BrainyData initialized successfully');
// Configure and start the augmentation pipeline with external plugins
// Note: These are example plugin names. You would need to install these packages via npm first.
const result = await configureAndStartPipeline([
// Sense augmentations (will be loaded first)
createSensePluginConfig('@example/text-sense-augmentation', {
language: 'english',
enableNER: true
}),
createSensePluginConfig('@example/image-sense-augmentation', {
modelSize: 'medium',
detectObjects: true
}),
// Conduit augmentations for two-way synchronization
createConduitPluginConfig('@example/websocket-conduit', {
url: 'wss://example.com/sync',
reconnectInterval: 5000
}),
createConduitPluginConfig('@example/webrtc-conduit', {
iceServers: [{ urls: 'stun:stun.example.com:19302' }],
peerConfig: { reliable: true }
}),
// Other augmentation types
{
plugin: '@example/memory-augmentation',
config: { storageType: 'persistent' },
type: AugmentationType.MEMORY
}
], {
// Optional: Customize the loading options
useDefaultPipeline: true, // Use the default pipeline instance
initializeAfterLoading: true, // Initialize augmentations after loading
augmentationOrder: [ // Custom order (Sense first, as recommended)
AugmentationType.SENSE,
AugmentationType.CONDUIT,
AugmentationType.MEMORY,
AugmentationType.COGNITION,
AugmentationType.PERCEPTION,
AugmentationType.DIALOG,
AugmentationType.ACTIVATION
]
});
// Check for any errors during loading
if (result.errors.length > 0) {
console.error('Errors occurred while loading plugins:');
result.errors.forEach(error => console.error(` - ${error.message}`));
} else {
console.log('All plugins loaded successfully');
}
// Get the pipeline instance
const { pipeline } = result;
// Get all loaded augmentations by type
console.log('Loaded augmentations:');
for (const [type, augmentations] of result.augmentations.entries()) {
if (augmentations.length > 0) {
console.log(`${type}: ${augmentations.map(a => a.name).join(', ')}`);
}
}
// Example: Using a sense augmentation to process raw data
try {
const senseResults = await pipeline.executeSensePipeline(
'processRawData',
['This is some example text to process', 'text']
);
// Process the results
for (const resultPromise of senseResults) {
const result = await resultPromise;
if (result.success) {
console.log('Processed data:', result.data);
// Insert the extracted nouns and verbs into BrainyData according to graphTypes
for (const noun of result.data.nouns) {
await db.add(noun, { type: 'noun' });
}
for (const verb of result.data.verbs) {
await db.add(verb, { type: 'verb' });
}
} else {
console.error('Error processing data:', result.error);
}
}
} catch (error) {
console.error('Error executing sense pipeline:', error);
}
// Example: Using a conduit augmentation for two-way synchronization
try {
// Establish a connection
const connectionResults = await pipeline.executeConduitPipeline(
'establishConnection',
['external-system', { apiKey: 'your-api-key' }]
);
// Process the results
for (const resultPromise of connectionResults) {
const result = await resultPromise;
if (result.success) {
console.log('Connection established:', result.data);
// Read data from the external system
const readResults = await pipeline.executeConduitPipeline(
'readData',
[{ query: 'get-latest-data' }]
);
// Process the read results
for (const readResultPromise of readResults) {
const readResult = await readResultPromise;
if (readResult.success) {
console.log('Data read from external system:', readResult.data);
// Write data to the external system
await pipeline.executeConduitPipeline(
'writeData',
[{ updatedData: 'example' }]
);
}
}
} else {
console.error('Error establishing connection:', result.error);
}
}
} catch (error) {
console.error('Error executing conduit pipeline:', error);
}
// Shut down the pipeline when done
await pipeline.shutDown();
console.log('Pipeline shut down successfully');

58
examples/rollup.config.js Normal file
View file

@ -0,0 +1,58 @@
/**
* Example rollup configuration for using the Brainy augmentation registry
*
* This example shows how to configure rollup to automatically discover and register
* augmentations at build time.
*/
import resolve from '@rollup/plugin-node-resolve';
import commonjs from '@rollup/plugin-commonjs';
import typescript from '@rollup/plugin-typescript';
import { createAugmentationRegistryRollupPlugin } from '../dist/index.js';
export default {
// Entry point for the application
input: 'src/index.js',
// Output configuration
output: {
file: 'dist/bundle.js',
format: 'esm',
sourcemap: true
},
// Plugins
plugins: [
// Resolve node modules
resolve(),
// Convert CommonJS modules to ES6
commonjs(),
// Process TypeScript files
typescript(),
// Augmentation Registry Plugin
// This plugin will automatically discover and register augmentations
// from files that match the specified pattern
createAugmentationRegistryRollupPlugin({
// Pattern to match files containing augmentations
// This will match any file ending with 'augmentation.js' or 'augmentation.ts'
pattern: /augmentation\.(js|ts)$/,
// Options for the loader
options: {
// Automatically initialize augmentations after loading
autoInitialize: true,
// Log debug information during loading
debug: true
}
})
],
// External dependencies that should not be bundled
external: [
'brainy'
]
};

View file

@ -0,0 +1,81 @@
/**
* Example webpack configuration for using the Brainy augmentation registry
*
* This example shows how to configure webpack to automatically discover and register
* augmentations at build time.
*/
const path = require('path');
const { createAugmentationRegistryPlugin } = require('../dist/index.js');
module.exports = {
// Entry point for the application
entry: './src/index.js',
// Output configuration
output: {
path: path.resolve(__dirname, 'dist'),
filename: 'bundle.js',
},
// Module rules for processing different file types
module: {
rules: [
// Process JavaScript files with babel
{
test: /\.js$/,
exclude: /node_modules/,
use: {
loader: 'babel-loader',
options: {
presets: ['@babel/preset-env']
}
}
},
// Process TypeScript files
{
test: /\.ts$/,
exclude: /node_modules/,
use: {
loader: 'ts-loader'
}
}
]
},
// Resolve file extensions
resolve: {
extensions: ['.js', '.ts']
},
// Plugins
plugins: [
// Augmentation Registry Plugin
// This plugin will automatically discover and register augmentations
// from files that match the specified pattern
createAugmentationRegistryPlugin({
// Pattern to match files containing augmentations
// This will match any file ending with 'augmentation.js' or 'augmentation.ts'
pattern: /augmentation\.(js|ts)$/,
// Options for the loader
options: {
// Automatically initialize augmentations after loading
autoInitialize: true,
// Log debug information during loading
debug: true
}
})
],
// Development server configuration
devServer: {
static: {
directory: path.join(__dirname, 'public'),
},
compress: true,
port: 9000,
}
};

View file

@ -524,7 +524,10 @@ export class AugmentationPipeline {
data: R
error?: string
}>[]> {
if (augmentations.length === 0) {
// Filter out disabled augmentations
const enabledAugmentations = augmentations.filter(aug => aug.enabled !== false)
if (enabledAugmentations.length === 0) {
return []
}
@ -571,11 +574,11 @@ export class AugmentationPipeline {
switch (options.mode) {
case ExecutionMode.PARALLEL:
// Execute all augmentations in parallel
return augmentations.map(executeMethod)
return enabledAugmentations.map(executeMethod)
case ExecutionMode.FIRST_SUCCESS:
// Execute augmentations sequentially until one succeeds
for (const augmentation of augmentations) {
for (const augmentation of enabledAugmentations) {
const resultPromise = executeMethod(augmentation)
const result = await resultPromise
if (result.success) {
@ -586,7 +589,7 @@ export class AugmentationPipeline {
case ExecutionMode.FIRST_RESULT:
// Execute augmentations sequentially until one returns a result
for (const augmentation of augmentations) {
for (const augmentation of enabledAugmentations) {
const resultPromise = executeMethod(augmentation)
const result = await resultPromise
if (result.success && result.data) {
@ -603,7 +606,7 @@ export class AugmentationPipeline {
data: R
error?: string
}>[] = []
for (const augmentation of augmentations) {
for (const augmentation of enabledAugmentations) {
const resultPromise = executeMethod(augmentation)
results.push(resultPromise)

102
src/augmentationRegistry.ts Normal file
View file

@ -0,0 +1,102 @@
/**
* Augmentation Registry
*
* This module provides a registry for augmentations that are loaded at build time.
* It replaces the dynamic loading mechanism in pluginLoader.ts.
*/
import { AugmentationPipeline, augmentationPipeline } from './augmentationPipeline.js'
import { AugmentationType, IAugmentation } from './types/augmentations.js'
/**
* Registry of all available augmentations
*/
export const availableAugmentations: IAugmentation[] = []
/**
* Registers an augmentation with the registry
*
* @param augmentation The augmentation to register
* @returns The augmentation that was registered
*/
export function registerAugmentation<T extends IAugmentation>(augmentation: T): T {
// Set enabled to true by default if not specified
if (augmentation.enabled === undefined) {
augmentation.enabled = true
}
// Add to the registry
availableAugmentations.push(augmentation)
return augmentation
}
/**
* Initializes the augmentation pipeline with all registered augmentations
*
* @param pipeline Optional custom pipeline to use instead of the default
* @returns The pipeline that was initialized
*/
export function initializeAugmentationPipeline(
pipeline: AugmentationPipeline = augmentationPipeline
): AugmentationPipeline {
// Register all augmentations with the pipeline
for (const augmentation of availableAugmentations) {
if (augmentation.enabled) {
pipeline.register(augmentation)
}
}
return pipeline
}
/**
* Enables or disables an augmentation by name
*
* @param name The name of the augmentation to enable/disable
* @param enabled Whether to enable or disable the augmentation
* @returns True if the augmentation was found and updated, false otherwise
*/
export function setAugmentationEnabled(name: string, enabled: boolean): boolean {
const augmentation = availableAugmentations.find(aug => aug.name === name)
if (augmentation) {
augmentation.enabled = enabled
return true
}
return false
}
/**
* Gets all augmentations of a specific type
*
* @param type The type of augmentation to get
* @returns An array of all augmentations of the specified type
*/
export function getAugmentationsByType(type: AugmentationType): IAugmentation[] {
return availableAugmentations.filter(aug => {
// Check if the augmentation is of the specified type
// This is a simplified check and may need to be updated based on how types are determined
switch (type) {
case AugmentationType.SENSE:
return 'processRawData' in aug && 'listenToFeed' in aug
case AugmentationType.CONDUIT:
return 'establishConnection' in aug && 'readData' in aug && 'writeData' in aug
case AugmentationType.COGNITION:
return 'reason' in aug && 'infer' in aug && 'executeLogic' in aug
case AugmentationType.MEMORY:
return 'storeData' in aug && 'retrieveData' in aug && 'updateData' in aug
case AugmentationType.PERCEPTION:
return 'interpret' in aug && 'organize' in aug && 'generateVisualization' in aug
case AugmentationType.DIALOG:
return 'processUserInput' in aug && 'generateResponse' in aug && 'manageContext' in aug
case AugmentationType.ACTIVATION:
return 'triggerAction' in aug && 'generateOutput' in aug && 'interactExternal' in aug
case AugmentationType.WEBSOCKET:
return 'connectWebSocket' in aug && 'sendWebSocketMessage' in aug && 'onWebSocketMessage' in aug
default:
return false
}
})
}

View file

@ -0,0 +1,291 @@
/**
* Augmentation Registry Loader
*
* This module provides functionality for loading augmentation registrations
* at build time. It's designed to be used with build tools like webpack or rollup
* to automatically discover and register augmentations.
*/
import { IAugmentation } from './types/augmentations.js'
import { registerAugmentation } from './augmentationRegistry.js'
/**
* Options for the augmentation registry loader
*/
export interface AugmentationRegistryLoaderOptions {
/**
* Whether to automatically initialize the augmentations after loading
* @default false
*/
autoInitialize?: boolean;
/**
* Whether to log debug information during loading
* @default false
*/
debug?: boolean;
}
/**
* Default options for the augmentation registry loader
*/
const DEFAULT_OPTIONS: AugmentationRegistryLoaderOptions = {
autoInitialize: false,
debug: false
}
/**
* Result of loading augmentations
*/
export interface AugmentationLoadResult {
/**
* The augmentations that were loaded
*/
augmentations: IAugmentation[];
/**
* Any errors that occurred during loading
*/
errors: Error[];
}
/**
* Loads augmentations from the specified modules
*
* This function is designed to be used with build tools like webpack or rollup
* to automatically discover and register augmentations.
*
* @param modules An object containing modules with augmentations to register
* @param options Options for the loader
* @returns A promise that resolves with the result of loading the augmentations
*
* @example
* ```typescript
* // webpack.config.js
* const { AugmentationRegistryPlugin } = require('brainy/dist/webpack');
*
* module.exports = {
* // ... other webpack config
* plugins: [
* new AugmentationRegistryPlugin({
* // Pattern to match files containing augmentations
* pattern: /augmentation\.js$/,
* // Options for the loader
* options: {
* autoInitialize: true,
* debug: true
* }
* })
* ]
* };
* ```
*/
export async function loadAugmentationsFromModules(
modules: Record<string, any>,
options: AugmentationRegistryLoaderOptions = {}
): Promise<AugmentationLoadResult> {
const opts = { ...DEFAULT_OPTIONS, ...options }
const result: AugmentationLoadResult = {
augmentations: [],
errors: []
}
if (opts.debug) {
console.log(`[AugmentationRegistryLoader] Loading augmentations from ${Object.keys(modules).length} modules`)
}
// Process each module
for (const [modulePath, module] of Object.entries(modules)) {
try {
if (opts.debug) {
console.log(`[AugmentationRegistryLoader] Processing module: ${modulePath}`)
}
// Extract augmentations from the module
const augmentations = extractAugmentationsFromModule(module)
if (augmentations.length === 0) {
if (opts.debug) {
console.log(`[AugmentationRegistryLoader] No augmentations found in module: ${modulePath}`)
}
continue
}
// Register each augmentation
for (const augmentation of augmentations) {
try {
const registered = registerAugmentation(augmentation)
result.augmentations.push(registered)
if (opts.debug) {
console.log(`[AugmentationRegistryLoader] Registered augmentation: ${registered.name}`)
}
} catch (error) {
const err = error instanceof Error ? error : new Error(String(error))
result.errors.push(err)
if (opts.debug) {
console.error(`[AugmentationRegistryLoader] Failed to register augmentation: ${err.message}`)
}
}
}
} catch (error) {
const err = error instanceof Error ? error : new Error(String(error))
result.errors.push(err)
if (opts.debug) {
console.error(`[AugmentationRegistryLoader] Error processing module ${modulePath}: ${err.message}`)
}
}
}
if (opts.debug) {
console.log(`[AugmentationRegistryLoader] Loaded ${result.augmentations.length} augmentations with ${result.errors.length} errors`)
}
return result
}
/**
* Extracts augmentations from a module
*
* @param module The module to extract augmentations from
* @returns An array of augmentations found in the module
*/
function extractAugmentationsFromModule(module: any): IAugmentation[] {
const augmentations: IAugmentation[] = []
// If the module itself is an augmentation, add it
if (isAugmentation(module)) {
augmentations.push(module)
}
// Check for exported augmentations
if (module && typeof module === 'object') {
for (const key of Object.keys(module)) {
const exported = module[key]
// Skip non-objects and null
if (!exported || typeof exported !== 'object') {
continue
}
// If the exported value is an augmentation, add it
if (isAugmentation(exported)) {
augmentations.push(exported)
}
// If the exported value is an array of augmentations, add them
if (Array.isArray(exported) && exported.every(isAugmentation)) {
augmentations.push(...exported)
}
}
}
return augmentations
}
/**
* Checks if an object is an augmentation
*
* @param obj The object to check
* @returns True if the object is an augmentation
*/
function isAugmentation(obj: any): obj is IAugmentation {
return (
obj &&
typeof obj === 'object' &&
typeof obj.name === 'string' &&
typeof obj.initialize === 'function' &&
typeof obj.shutDown === 'function' &&
typeof obj.getStatus === 'function'
)
}
/**
* Creates a webpack plugin for automatically loading augmentations
*
* @param options Options for the plugin
* @returns A webpack plugin
*
* @example
* ```typescript
* // webpack.config.js
* const { createAugmentationRegistryPlugin } = require('brainy/dist/webpack');
*
* module.exports = {
* // ... other webpack config
* plugins: [
* createAugmentationRegistryPlugin({
* pattern: /augmentation\.js$/,
* options: {
* autoInitialize: true,
* debug: true
* }
* })
* ]
* };
* ```
*/
export function createAugmentationRegistryPlugin(options: {
/**
* Pattern to match files containing augmentations
*/
pattern: RegExp;
/**
* Options for the loader
*/
options?: AugmentationRegistryLoaderOptions;
}) {
// This is just a placeholder - the actual implementation would depend on the build tool
return {
name: 'AugmentationRegistryPlugin',
pattern: options.pattern,
options: options.options || {}
}
}
/**
* Creates a rollup plugin for automatically loading augmentations
*
* @param options Options for the plugin
* @returns A rollup plugin
*
* @example
* ```typescript
* // rollup.config.js
* import { createAugmentationRegistryRollupPlugin } from 'brainy/dist/rollup';
*
* export default {
* // ... other rollup config
* plugins: [
* createAugmentationRegistryRollupPlugin({
* pattern: /augmentation\.js$/,
* options: {
* autoInitialize: true,
* debug: true
* }
* })
* ]
* };
* ```
*/
export function createAugmentationRegistryRollupPlugin(options: {
/**
* Pattern to match files containing augmentations
*/
pattern: RegExp;
/**
* Options for the loader
*/
options?: AugmentationRegistryLoaderOptions;
}) {
// This is just a placeholder - the actual implementation would depend on the build tool
return {
name: 'augmentation-registry-rollup-plugin',
pattern: options.pattern,
options: options.options || {}
}
}

View file

@ -4,8 +4,8 @@
*/
import { v4 as uuidv4 } from 'uuid'
import { HNSWIndex } from './hnsw/hnswIndex.ts'
import { createStorage } from './storage/opfsStorage.ts'
import { HNSWIndex } from './hnsw/hnswIndex.js'
import { createStorage } from './storage/opfsStorage.js'
import {
DistanceFunction,
Edge,
@ -15,8 +15,8 @@ import {
StorageAdapter,
Vector,
VectorDocument
} from './coreTypes.ts'
import { cosineDistance, defaultEmbeddingFunction, euclideanDistance } from './utils/index.ts'
} from './coreTypes.js'
import { cosineDistance, defaultEmbeddingFunction, euclideanDistance } from './utils/index.js'
export interface BrainyDataConfig {
/**

View file

@ -2,7 +2,7 @@
* Basic usage example for the Soulcraft Brainy database
*/
import { BrainyData } from '../brainyData.ts'
import { BrainyData } from '../brainyData.js'
// Example data - word embeddings
const wordEmbeddings = {

View file

@ -3,8 +3,8 @@
* Based on the paper: "Efficient and robust approximate nearest neighbor search using Hierarchical Navigable Small World graphs"
*/
import { DistanceFunction, HNSWConfig, HNSWNode, Vector, VectorDocument } from '../coreTypes.ts'
import { euclideanDistance } from '../utils/index.ts'
import { DistanceFunction, HNSWConfig, HNSWNode, Vector, VectorDocument } from '../coreTypes.js'
import { euclideanDistance } from '../utils/index.js'
// Default HNSW parameters
const DEFAULT_CONFIG: HNSWConfig = {

View file

@ -4,22 +4,24 @@
*/
// Export main BrainyData class and related types
import { BrainyData, BrainyDataConfig } from './brainyData.ts'
import { BrainyData, BrainyDataConfig } from './brainyData.js'
export { BrainyData }
export type { BrainyDataConfig }
// Export distance functions for convenience
import {
euclideanDistance,
cosineDistance,
manhattanDistance,
dotProductDistance
} from './utils/index.ts'
export {
euclideanDistance,
cosineDistance,
manhattanDistance,
dotProductDistance
import {
euclideanDistance,
cosineDistance,
manhattanDistance,
dotProductDistance
} from './utils/index.js'
export {
euclideanDistance,
cosineDistance,
manhattanDistance,
dotProductDistance
}
// Export embedding functionality
@ -30,7 +32,8 @@ import {
createTensorFlowEmbeddingFunction,
createSimpleEmbeddingFunction,
defaultEmbeddingFunction
} from './utils/embedding.ts'
} from './utils/embedding.js'
export {
SimpleEmbedding,
UniversalSentenceEncoder,
@ -41,15 +44,16 @@ export {
}
// Export storage adapters
import {
OPFSStorage,
MemoryStorage,
createStorage
} from './storage/opfsStorage.ts'
export {
OPFSStorage,
MemoryStorage,
createStorage
import {
OPFSStorage,
MemoryStorage,
createStorage
} from './storage/opfsStorage.js'
export {
OPFSStorage,
MemoryStorage,
createStorage
}
// Export augmentation pipeline
@ -58,7 +62,8 @@ import {
augmentationPipeline,
ExecutionMode,
PipelineOptions
} from './augmentationPipeline.ts'
} from './augmentationPipeline.js'
export {
AugmentationPipeline,
augmentationPipeline,
@ -66,30 +71,45 @@ export {
}
export type { PipelineOptions }
// Export plugin loader
// Export augmentation registry for build-time loading
import {
loadPlugins,
configureAndStartPipeline,
createSensePluginConfig,
createConduitPluginConfig
} from './pluginLoader.ts'
import type {
PluginLoaderOptions,
PluginConfig,
PluginLoadResult
} from './pluginLoader.ts'
availableAugmentations,
registerAugmentation,
initializeAugmentationPipeline,
setAugmentationEnabled,
getAugmentationsByType
} from './augmentationRegistry.js'
export {
loadPlugins,
configureAndStartPipeline,
createSensePluginConfig,
createConduitPluginConfig
availableAugmentations,
registerAugmentation,
initializeAugmentationPipeline,
setAugmentationEnabled,
getAugmentationsByType
}
// Export augmentation registry loader for build tools
import {
loadAugmentationsFromModules,
createAugmentationRegistryPlugin,
createAugmentationRegistryRollupPlugin
} from './augmentationRegistryLoader.js'
import type {
AugmentationRegistryLoaderOptions,
AugmentationLoadResult
} from './augmentationRegistryLoader.js'
export {
loadAugmentationsFromModules,
createAugmentationRegistryPlugin,
createAugmentationRegistryRollupPlugin
}
export type {
PluginLoaderOptions,
PluginConfig,
PluginLoadResult
AugmentationRegistryLoaderOptions,
AugmentationLoadResult
}
// Export types
import type {
Vector,
@ -102,7 +122,8 @@ import type {
Edge,
HNSWConfig,
StorageAdapter
} from './coreTypes.ts'
} from './coreTypes.js'
export type {
Vector,
VectorDocument,
@ -128,8 +149,9 @@ import type {
IPerceptionAugmentation,
IDialogAugmentation,
IActivationAugmentation
} from './types/augmentations.ts'
import { AugmentationType, BrainyAugmentations } from './types/augmentations.ts'
} from './types/augmentations.js'
import { AugmentationType, BrainyAugmentations } from './types/augmentations.js'
export type {
IAugmentation,
AugmentationResponse,
@ -156,7 +178,7 @@ export type {
IWebSocketDialogAugmentation,
IWebSocketConduitAugmentation,
IWebSocketMemoryAugmentation
} from './types/augmentations.ts'
} from './types/augmentations.js'
// Export graph types
import type {
@ -169,8 +191,9 @@ import type {
Event,
Concept,
Content
} from './types/graphTypes.ts'
import { NounType, VerbType } from './types/graphTypes.ts'
} from './types/graphTypes.js'
import { NounType, VerbType } from './types/graphTypes.js'
export type {
GraphNoun,
GraphVerb,

View file

@ -1,241 +0,0 @@
/**
* Plugin Loader for Brainy Augmentations
*
* This module provides functionality for loading and configuring augmentation plugins
* from external npm packages. It allows consumers of the library to easily integrate
* externally installed augmentation plugins into the Brainy system.
*/
import { AugmentationPipeline, augmentationPipeline, ExecutionMode } from './augmentationPipeline.js';
import { AugmentationType, IAugmentation, ISenseAugmentation, IConduitAugmentation } from './types/augmentations.js';
/**
* Configuration options for loading plugins
*/
export interface PluginLoaderOptions {
/**
* Whether to use the default augmentation pipeline instance
* If false, a new pipeline instance will be created
* @default true
*/
useDefaultPipeline?: boolean;
/**
* Whether to initialize the augmentations after loading
* @default true
*/
initializeAfterLoading?: boolean;
/**
* Order of augmentation types to load
* By default, sense augmentations are loaded first
* @default [AugmentationType.SENSE, AugmentationType.CONDUIT, ...]
*/
augmentationOrder?: AugmentationType[];
}
/**
* Default options for the plugin loader
*/
const DEFAULT_OPTIONS: PluginLoaderOptions = {
useDefaultPipeline: true,
initializeAfterLoading: true,
augmentationOrder: [
AugmentationType.SENSE,
AugmentationType.CONDUIT,
AugmentationType.COGNITION,
AugmentationType.MEMORY,
AugmentationType.PERCEPTION,
AugmentationType.DIALOG,
AugmentationType.ACTIVATION,
AugmentationType.WEBSOCKET
]
};
/**
* Plugin configuration for a specific augmentation
*/
export interface PluginConfig {
/**
* The plugin module name or path
* This can be an npm package name or a relative path
*/
plugin: string;
/**
* Optional configuration to pass to the plugin
*/
config?: Record<string, any>;
/**
* Optional type of the augmentation
* If not provided, it will be determined automatically
*/
type?: AugmentationType;
}
/**
* Result of loading plugins
*/
export interface PluginLoadResult {
/**
* The augmentation pipeline instance
*/
pipeline: AugmentationPipeline;
/**
* Map of loaded augmentations by type
*/
augmentations: Map<AugmentationType, IAugmentation[]>;
/**
* Any errors that occurred during loading
*/
errors: Error[];
}
/**
* Loads augmentation plugins from external npm packages
*
* @param plugins Array of plugin configurations
* @param options Options for loading plugins
* @returns Promise that resolves to the plugin load result
*/
export async function loadPlugins(
plugins: PluginConfig[],
options: PluginLoaderOptions = {}
): Promise<PluginLoadResult> {
// Merge options with defaults
const opts = { ...DEFAULT_OPTIONS, ...options };
// Use the default pipeline or create a new one
const pipeline = opts.useDefaultPipeline ? augmentationPipeline : new AugmentationPipeline();
// Track loaded augmentations by type
const loadedAugmentations = new Map<AugmentationType, IAugmentation[]>();
const errors: Error[] = [];
// Group plugins by type according to the specified order
const pluginsByType = new Map<AugmentationType, PluginConfig[]>();
// Initialize the map with empty arrays for each type
for (const type of opts.augmentationOrder!) {
pluginsByType.set(type, []);
loadedAugmentations.set(type, []);
}
// Group plugins by type
for (const pluginConfig of plugins) {
const type = pluginConfig.type || AugmentationType.SENSE; // Default to SENSE if not specified
const typePlugins = pluginsByType.get(type) || [];
typePlugins.push(pluginConfig);
pluginsByType.set(type, typePlugins);
}
// Load plugins in the specified order
for (const type of opts.augmentationOrder!) {
const typePlugins = pluginsByType.get(type) || [];
for (const pluginConfig of typePlugins) {
try {
// Import the plugin module
const pluginModule = await import(pluginConfig.plugin);
// Get the default export or the named export that matches the plugin name
const PluginClass = pluginModule.default || pluginModule[pluginConfig.plugin.split('/').pop()!];
if (!PluginClass) {
throw new Error(`Could not find a valid export in plugin ${pluginConfig.plugin}`);
}
// Instantiate the plugin with the provided configuration
const plugin = new PluginClass(pluginConfig.config);
// Register the plugin with the pipeline
pipeline.register(plugin);
// Add to the loaded augmentations map
const typeAugmentations = loadedAugmentations.get(type) || [];
typeAugmentations.push(plugin);
loadedAugmentations.set(type, typeAugmentations);
} catch (error) {
const err = error instanceof Error ? error : new Error(String(error));
errors.push(err);
console.error(`Error loading plugin ${pluginConfig.plugin}:`, err);
}
}
}
// Initialize the augmentations if requested
if (opts.initializeAfterLoading) {
try {
await pipeline.initialize();
} catch (error) {
const err = error instanceof Error ? error : new Error(String(error));
errors.push(err);
console.error('Error initializing augmentations:', err);
}
}
return {
pipeline,
augmentations: loadedAugmentations,
errors
};
}
/**
* Configures and starts the augmentation pipeline with the specified plugins
*
* @param plugins Array of plugin configurations
* @param options Options for loading plugins
* @returns Promise that resolves to the plugin load result
*/
export async function configureAndStartPipeline(
plugins: PluginConfig[],
options: PluginLoaderOptions = {}
): Promise<PluginLoadResult> {
// Load the plugins
const result = await loadPlugins(plugins, {
...options,
initializeAfterLoading: true
});
return result;
}
/**
* Creates a plugin configuration for a sense augmentation
*
* @param plugin The plugin module name or path
* @param config Optional configuration to pass to the plugin
* @returns Plugin configuration
*/
export function createSensePluginConfig(
plugin: string,
config?: Record<string, any>
): PluginConfig {
return {
plugin,
config,
type: AugmentationType.SENSE
};
}
/**
* Creates a plugin configuration for a conduit augmentation
*
* @param plugin The plugin module name or path
* @param config Optional configuration to pass to the plugin
* @returns Plugin configuration
*/
export function createConduitPluginConfig(
plugin: string,
config?: Record<string, any>
): PluginConfig {
return {
plugin,
config,
type: AugmentationType.CONDUIT
};
}

View file

@ -1,4 +1,4 @@
import { Edge, HNSWNode, StorageAdapter } from '../coreTypes.ts'
import { Edge, HNSWNode, StorageAdapter } from '../coreTypes.js'
// We'll dynamically import Node.js built-in modules
let fs: any

View file

@ -3,7 +3,7 @@
* Provides persistent storage for the vector database using the Origin Private File System API
*/
import { Edge, HNSWNode, StorageAdapter } from '../coreTypes.ts'
import { Edge, HNSWNode, StorageAdapter } from '../coreTypes.js'
// Directory and file names
const ROOT_DIR = 'opfs-vector-db'
@ -902,7 +902,7 @@ export async function createStorage(options: {
if (isNode) {
// In Node.js, use FileSystemStorage first, then fall back to memory
try {
const fileSystemModule = await import('./fileSystemStorage.ts')
const fileSystemModule = await import('./fileSystemStorage.js')
return new fileSystemModule.FileSystemStorage()
} catch (error) {
console.warn('Failed to load FileSystemStorage, falling back to in-memory storage:', error)
@ -928,7 +928,7 @@ export async function createStorage(options: {
try {
// Try to load FileSystemStorage for browser environments
// Note: This will likely fail as FileSystemStorage is designed for Node.js
const fileSystemModule = await import('./fileSystemStorage.ts')
const fileSystemModule = await import('./fileSystemStorage.js')
return new fileSystemModule.FileSystemStorage()
} catch (error) {
console.warn('FileSystem storage is not available, falling back to in-memory storage')

View file

@ -35,6 +35,8 @@ export interface IAugmentation {
readonly name: string
/** A human-readable description of the augmentation's purpose */
readonly description: string
/** Whether this augmentation is enabled */
enabled: boolean
/**
* Initializes the augmentation. This method is called when Brainy starts up.

View file

@ -124,6 +124,7 @@ export const VerbType = {
Controls: 'controls', // Indicates control or ownership
Created: 'created', // Indicates creation or authorship
Earned: 'earned', // Indicates achievement or acquisition
Owns: 'owns' // Indicates ownership
Owns: 'owns', // Indicates ownership
MemberOf: 'memberOf' // Indicates membership or affiliation
} as const
export type VerbType = (typeof VerbType)[keyof typeof VerbType]

View file

@ -2,7 +2,7 @@
* Distance functions for vector similarity calculations
*/
import { DistanceFunction, Vector } from '../coreTypes.ts'
import { DistanceFunction, Vector } from '../coreTypes.js'
/**
* Calculates the Euclidean distance between two vectors

View file

@ -2,7 +2,7 @@
* Embedding functions for converting data to vectors
*/
import { EmbeddingFunction, EmbeddingModel, Vector } from '../coreTypes.ts'
import { EmbeddingFunction, EmbeddingModel, Vector } from '../coreTypes.js'
/**
* Simple character-based embedding function

View file

@ -1,2 +1,2 @@
export * from './distance.ts'
export * from './embedding.ts'
export * from './distance.js'
export * from './embedding.js'

View file

@ -14,7 +14,6 @@
],
"skipLibCheck": true,
"forceConsistentCasingInFileNames": true,
"allowImportingTsExtensions": true,
"noEmit": false,
"preserveConstEnums": true,
"sourceMap": true