diff --git a/README.md b/README.md index c24722a..801838b 100644 --- a/README.md +++ b/README.md @@ -153,6 +153,43 @@ const intent = await llm.query('analyze the data'); // Returns: { confidence: 0.9, action: 'analysis' } ``` +## Nested Manifolds + +### NestedManifoldRegion + +A `NestedManifoldRegion` allows embedding a `WorkflowFunctionManifold` inside a region. This enables creating hierarchical workflows where regions themselves contain sub-workflows. + +```javascript +import { + WorkflowFunctionManifold, + NestedManifoldRegion, + ManifoldRegion, + WorkflowOperator, + DummyLlmService, +} from 'workflow-function-manifold'; + +// Sub-workflow +const nestedLlm = new DummyLlmService(); +const nestedManifold = new WorkflowFunctionManifold(nestedLlm); + +const nestedOperator = new WorkflowOperator('nestedOperation', async state => { + return { ...state, nested: true }; +}); + +const nestedRegion = new ManifoldRegion('nestedRegion', [nestedOperator]); +nestedManifold.addRegion(nestedRegion); + +// Main workflow +const mainLlm = new DummyLlmService(); +const mainManifold = new WorkflowFunctionManifold(mainLlm); + +const nestedManifoldRegion = new NestedManifoldRegion('nestedManifoldRegion', nestedManifold); +mainManifold.addRegion(nestedManifoldRegion); + +await mainManifold.navigate('perform nested operation'); +await mainManifold.executeWorkflow('perform nested operation'); +``` + ## Complete Example Here's a full example demonstrating a three-stage workflow: @@ -241,6 +278,10 @@ console.log(manifold.state); // Final state after all operations - `async execute(state: any): Promise` +### NestedManifoldRegion +- Extends `ManifoldRegion` and embeds a `WorkflowFunctionManifold`. + + ## State Management The workflow maintains state across operations. Each operator can access and diff --git a/bin.js b/bin.js index 5258611..cdcc9f6 100755 --- a/bin.js +++ b/bin.js @@ -5,59 +5,95 @@ import { ManifoldRegion, WorkflowFunctionManifold, WorkflowOperator, + NestedManifoldRegion, } from './lib.js'; -async function demonstrateManifold() { - // Initialize services and manifold - const llm = new DummyLlmService(); - const manifold = new WorkflowFunctionManifold(llm); +async function demonstrateNestedManifold() { + console.log('\nšŸš€ Starting Nested Manifold Demonstration\n'); - // Create operators - const dataAnalysisOp = new WorkflowOperator('analysis', async state => { - console.log('Performing data analysis...'); + console.log('šŸ“¦ Creating Secondary Manifold...'); + const nestedLlm = new DummyLlmService(); + const nestedManifold = new WorkflowFunctionManifold(nestedLlm); + + const validateOp = new WorkflowOperator('validation', async state => { + console.log(' āœ“ Validating data structure'); + return { ...state, validated: true }; + }); + + const cleanOp = new WorkflowOperator('cleaning', async state => { + console.log(' āœ“ Cleaning data'); + return { ...state, cleaned: true }; + }); + + const validateRegion = new ManifoldRegion('validation', [validateOp]); + const cleanRegion = new ManifoldRegion('cleaning', [cleanOp]); + + // Set up nested manifold regions + validateRegion.connectTo(cleanRegion); + nestedManifold.addRegion(validateRegion); + nestedManifold.addRegion(cleanRegion); + + console.log('šŸ“¦ Creating Primary Manifold...'); + const mainLlm = new DummyLlmService(); + const mainManifold = new WorkflowFunctionManifold(mainLlm); + + const analysisOp = new WorkflowOperator('analysis', async state => { + console.log(' āœ“ Performing data analysis'); return { ...state, analyzed: true }; }); - const dataProcessingOp = new WorkflowOperator('processing', async state => { - console.log('Processing data...'); - return { ...state, processed: true }; - }); - - const dataTransformOp = new WorkflowOperator('transformation', async state => { - console.log('Transforming data...'); + const transformOp = new WorkflowOperator('transformation', async state => { + console.log(' āœ“ Transforming results'); return { ...state, transformed: true }; }); - // Create regions - const analysisRegion = new ManifoldRegion('analysis', [dataAnalysisOp]); - const processingRegion = new ManifoldRegion('processing', [dataProcessingOp]); - const transformationRegion = new ManifoldRegion('transformation', [dataTransformOp]); + // Set up main manifold regions + const nestedPreprocessRegion = new NestedManifoldRegion('preprocessing', nestedManifold); + const analysisRegion = new ManifoldRegion('analysis', [analysisOp]); + const transformRegion = new ManifoldRegion('transformation', [transformOp]); - // Connect regions - analysisRegion.connectTo(processingRegion); - processingRegion.connectTo(transformationRegion); + nestedPreprocessRegion.connectTo(analysisRegion); + analysisRegion.connectTo(transformRegion); - // Add regions to manifold - manifold.addRegion(analysisRegion); - manifold.addRegion(processingRegion); - manifold.addRegion(transformationRegion); + mainManifold.addRegion(nestedPreprocessRegion); + mainManifold.addRegion(analysisRegion); + mainManifold.addRegion(transformRegion); - // Demonstrate workflow execution - console.log('Starting workflow demonstration...'); + console.log('\nšŸ”„ Executing Workflow...\n'); - const prompts = ['analyze the data', 'process the results', 'transform the output']; + const prompts = [ + { text: 'validate the input', description: 'Nested: Data Validation' }, + { text: 'clean the data', description: 'Nested: Data Cleaning' }, + { text: 'analyze the results', description: 'Main: Data Analysis' }, + { text: 'transform the output', description: 'Main: Data Transformation' }, + ]; - for (const prompt of prompts) { - console.log(`\nExecuting prompt: "${prompt}"`); - await manifold.navigate(prompt); - const executed = await manifold.executeWorkflow(prompt); - console.log('Current state:', manifold.state); - console.log(`Current region: ${manifold.currentRegion.name}`); - console.log(`Operation executed: ${executed}`); + for (const { text, description } of prompts) { + console.log(`šŸ“ Step: ${description}\n Prompt: "${text}"`); + + try { + // First try to navigate + const navigated = await mainManifold.navigate(text); + if (navigated) { + console.log(' ↪ Navigation successful'); + } + + // Then execute the workflow + const executed = await mainManifold.executeWorkflow(text); + if (executed) { + console.log(' āœ… Execution complete\n'); + } else { + console.log(' āŒ Execution failed - No matching operator found\n'); + } + } catch (error) { + console.error(` āŒ Error: ${error.message}\n`); + } } + + console.log('šŸŽ‰ Workflow Demonstration Complete!\n'); } -// Run the demonstration -demonstrateManifold().catch(console.error); - -export {}; +demonstrateNestedManifold().catch(error => { + console.error('āŒ Fatal Error:', error); + process.exit(1); +}); \ No newline at end of file diff --git a/lib.js b/lib.js index 6032e8e..7b590a4 100644 --- a/lib.js +++ b/lib.js @@ -1,105 +1,75 @@ -// Simulated LLM Service -/** - * Simulates a Large Language Model (LLM) service for intent detection. - */ export class DummyLlmService { - /** - * Queries the simulated LLM with a prompt. - * @param {string} prompt - The input prompt to query the LLM. - * @returns {Promise<{confidence: number, action: string}>} - The detected intent with confidence and action. - */ async query(prompt) { const intents = { analyze: { confidence: 0.9, action: 'analysis' }, process: { confidence: 0.8, action: 'processing' }, transform: { confidence: 0.7, action: 'transformation' }, + validate: { confidence: 0.85, action: 'validation' }, + clean: { confidence: 0.85, action: 'cleaning' }, }; - const matchedIntent = Object.entries(intents).find(([key]) => - prompt.toLowerCase().includes(key), + prompt.toLowerCase().includes(key) ); - return matchedIntent ? matchedIntent[1] : { confidence: 0.1, action: 'unknown' }; } } -// Interface for workflow operators -/** - * Represents a workflow operator responsible for performing a specific operation. - */ export class WorkflowOperator { - /** - * Creates an instance of WorkflowOperator. - * @param {string} name - The name of the operator. - * @param {function(object): Promise} operation - The operation function executed by the operator. - */ constructor(name, operation) { this.name = name; this.operation = operation; } - /** - * Executes the operator's operation with the given state. - * @param {object} state - The current state to be processed. - * @returns {Promise} - The updated state after the operation. - */ async execute(state) { return await this.operation(state); } } -// Interface for manifold regions -/** - * Represents a region within the manifold, containing workflow operators. - */ export class ManifoldRegion { - /** - * Creates an instance of ManifoldRegion. - * @param {string} name - The name of the region. - * @param {WorkflowOperator[]} [operators=[]] - The operators available in this region. - */ constructor(name, operators = []) { this.name = name; this.operators = operators; this.adjacentRegions = new Set(); } - /** - * Adds an operator to the region. - * @param {WorkflowOperator} operator - The operator to be added. - */ addOperator(operator) { this.operators.push(operator); } - /** - * Establishes a connection to another region. - * @param {ManifoldRegion} region - The region to connect to. - */ connectTo(region) { this.adjacentRegions.add(region); region.adjacentRegions.add(this); } - /** - * Retrieves valid operators for the given state. - * @param {object} _state - The current state. - * @returns {Promise} - The list of valid operators. - */ async getValidOperators(_state) { return this.operators; } } -// Main manifold implementation -/** - * Represents the workflow function manifold managing regions and state transitions. - */ +export class NestedManifoldRegion extends ManifoldRegion { + constructor(name, nestedManifold) { + super(name); + this.nestedManifold = nestedManifold; + } + + async getValidOperators(state) { + if (!this.nestedManifold.currentRegion) { + return []; + } + return await this.nestedManifold.currentRegion.getValidOperators(state); + } + + async navigate(prompt) { + return await this.nestedManifold.navigate(prompt); + } + + async executeWorkflow(prompt) { + const result = await this.nestedManifold.executeWorkflow(prompt); + return result; + } +} + export class WorkflowFunctionManifold { - /** - * Creates an instance of WorkflowFunctionManifold. - * @param {DummyLlmService} llmService - The LLM service used for intent detection. - */ constructor(llmService) { this.llmService = llmService; this.regions = new Map(); @@ -107,10 +77,6 @@ export class WorkflowFunctionManifold { this.state = {}; } - /** - * Adds a region to the manifold. - * @param {ManifoldRegion} region - The region to be added. - */ addRegion(region) { this.regions.set(region.name, region); if (!this.currentRegion) { @@ -118,52 +84,61 @@ export class WorkflowFunctionManifold { } } - /** - * Navigates to the next region based on the provided prompt. - * @param {string} prompt - The input prompt for intent matching. - * @returns {Promise} - Whether navigation was successful. - */ async navigate(prompt) { try { - const intent = await this.llmService.query(prompt); + // If current region is nested, try to navigate within it first + if (this.currentRegion instanceof NestedManifoldRegion) { + const nestedNavigated = await this.currentRegion.navigate(prompt); + if (nestedNavigated) { + return true; + } + } + const intent = await this.llmService.query(prompt); + if (intent.confidence <= 0.5) { + return false; + } + + // Try to find matching region const nextRegion = Array.from(this.currentRegion.adjacentRegions).find(region => - region.name.toLowerCase().includes(intent.action), + region.name.toLowerCase().includes(intent.action) ); - if (nextRegion && intent.confidence > 0.5) { + if (nextRegion) { this.currentRegion = nextRegion; return true; } - console.warn(`No valid region found for prompt: "${prompt}"`); + return false; } catch (error) { - console.error(`Error during navigation for prompt "${prompt}":`, error); + console.error('Navigation error:', error); return false; } } - /** - * Executes the workflow based on the current region and provided prompt. - * @param {string} prompt - The input prompt for intent matching. - * @returns {Promise} - Whether the workflow execution was successful. - */ async executeWorkflow(prompt) { try { - const operators = await this.currentRegion.getValidOperators(this.state); + if (this.currentRegion instanceof NestedManifoldRegion) { + const nestedResult = await this.currentRegion.executeWorkflow(prompt); + return nestedResult; + } + const intent = await this.llmService.query(prompt); + const operators = await this.currentRegion.getValidOperators(this.state); - const matchedOperator = operators.find(op => op.name.toLowerCase().includes(intent.action)); + const matchedOperator = operators.find(op => + op.name.toLowerCase().includes(intent.action) + ); - if (matchedOperator) { + if (matchedOperator && intent.confidence > 0.5) { this.state = await matchedOperator.execute(this.state); return true; } - console.warn(`No matching operator found for intent: ${intent.action}`); + return false; } catch (error) { - console.error(`Error during workflow execution for prompt "${prompt}":`, error); + console.error('Execution error:', error); return false; } } -} +} \ No newline at end of file diff --git a/package.json b/package.json index 0598e6d..b135aed 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,7 @@ { "name": "workflow-function-manifold", "version": "1.0.2", + "type": "module", "description": "for building dynamic, LLM-driven workflows using a region-based execution model", "main": "index.js", "bin": {