Add support for nested manifolds
Introduced the `NestedManifoldRegion` class to enable embedding of `WorkflowFunctionManifold` inside regions, allowing hierarchical workflows. Updated `bin.js` to demonstrate the new functionality and adjusted `lib.js` for nested region navigation and execution logic. Updated `package.json` to specify "type": "module" for ES module support.
This commit is contained in:
41
README.md
41
README.md
@@ -153,6 +153,43 @@ const intent = await llm.query('analyze the data');
|
|||||||
// Returns: { confidence: 0.9, action: 'analysis' }
|
// 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
|
## Complete Example
|
||||||
|
|
||||||
Here's a full example demonstrating a three-stage workflow:
|
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<any>`
|
- `async execute(state: any): Promise<any>`
|
||||||
|
|
||||||
|
### NestedManifoldRegion
|
||||||
|
- Extends `ManifoldRegion` and embeds a `WorkflowFunctionManifold`.
|
||||||
|
|
||||||
|
|
||||||
## State Management
|
## State Management
|
||||||
|
|
||||||
The workflow maintains state across operations. Each operator can access and
|
The workflow maintains state across operations. Each operator can access and
|
||||||
|
114
bin.js
114
bin.js
@@ -5,59 +5,95 @@ import {
|
|||||||
ManifoldRegion,
|
ManifoldRegion,
|
||||||
WorkflowFunctionManifold,
|
WorkflowFunctionManifold,
|
||||||
WorkflowOperator,
|
WorkflowOperator,
|
||||||
|
NestedManifoldRegion,
|
||||||
} from './lib.js';
|
} from './lib.js';
|
||||||
|
|
||||||
async function demonstrateManifold() {
|
async function demonstrateNestedManifold() {
|
||||||
// Initialize services and manifold
|
console.log('\n🚀 Starting Nested Manifold Demonstration\n');
|
||||||
const llm = new DummyLlmService();
|
|
||||||
const manifold = new WorkflowFunctionManifold(llm);
|
|
||||||
|
|
||||||
// Create operators
|
console.log('📦 Creating Secondary Manifold...');
|
||||||
const dataAnalysisOp = new WorkflowOperator('analysis', async state => {
|
const nestedLlm = new DummyLlmService();
|
||||||
console.log('Performing data analysis...');
|
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 };
|
return { ...state, analyzed: true };
|
||||||
});
|
});
|
||||||
|
|
||||||
const dataProcessingOp = new WorkflowOperator('processing', async state => {
|
const transformOp = new WorkflowOperator('transformation', async state => {
|
||||||
console.log('Processing data...');
|
console.log(' ✓ Transforming results');
|
||||||
return { ...state, processed: true };
|
|
||||||
});
|
|
||||||
|
|
||||||
const dataTransformOp = new WorkflowOperator('transformation', async state => {
|
|
||||||
console.log('Transforming data...');
|
|
||||||
return { ...state, transformed: true };
|
return { ...state, transformed: true };
|
||||||
});
|
});
|
||||||
|
|
||||||
// Create regions
|
// Set up main manifold regions
|
||||||
const analysisRegion = new ManifoldRegion('analysis', [dataAnalysisOp]);
|
const nestedPreprocessRegion = new NestedManifoldRegion('preprocessing', nestedManifold);
|
||||||
const processingRegion = new ManifoldRegion('processing', [dataProcessingOp]);
|
const analysisRegion = new ManifoldRegion('analysis', [analysisOp]);
|
||||||
const transformationRegion = new ManifoldRegion('transformation', [dataTransformOp]);
|
const transformRegion = new ManifoldRegion('transformation', [transformOp]);
|
||||||
|
|
||||||
// Connect regions
|
nestedPreprocessRegion.connectTo(analysisRegion);
|
||||||
analysisRegion.connectTo(processingRegion);
|
analysisRegion.connectTo(transformRegion);
|
||||||
processingRegion.connectTo(transformationRegion);
|
|
||||||
|
|
||||||
// Add regions to manifold
|
mainManifold.addRegion(nestedPreprocessRegion);
|
||||||
manifold.addRegion(analysisRegion);
|
mainManifold.addRegion(analysisRegion);
|
||||||
manifold.addRegion(processingRegion);
|
mainManifold.addRegion(transformRegion);
|
||||||
manifold.addRegion(transformationRegion);
|
|
||||||
|
|
||||||
// Demonstrate workflow execution
|
console.log('\n🔄 Executing Workflow...\n');
|
||||||
console.log('Starting workflow demonstration...');
|
|
||||||
|
|
||||||
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) {
|
for (const { text, description } of prompts) {
|
||||||
console.log(`\nExecuting prompt: "${prompt}"`);
|
console.log(`📍 Step: ${description}\n Prompt: "${text}"`);
|
||||||
await manifold.navigate(prompt);
|
|
||||||
const executed = await manifold.executeWorkflow(prompt);
|
try {
|
||||||
console.log('Current state:', manifold.state);
|
// First try to navigate
|
||||||
console.log(`Current region: ${manifold.currentRegion.name}`);
|
const navigated = await mainManifold.navigate(text);
|
||||||
console.log(`Operation executed: ${executed}`);
|
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
|
demonstrateNestedManifold().catch(error => {
|
||||||
demonstrateManifold().catch(console.error);
|
console.error('❌ Fatal Error:', error);
|
||||||
|
process.exit(1);
|
||||||
export {};
|
});
|
135
lib.js
135
lib.js
@@ -1,105 +1,75 @@
|
|||||||
// Simulated LLM Service
|
|
||||||
/**
|
|
||||||
* Simulates a Large Language Model (LLM) service for intent detection.
|
|
||||||
*/
|
|
||||||
export class DummyLlmService {
|
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) {
|
async query(prompt) {
|
||||||
const intents = {
|
const intents = {
|
||||||
analyze: { confidence: 0.9, action: 'analysis' },
|
analyze: { confidence: 0.9, action: 'analysis' },
|
||||||
process: { confidence: 0.8, action: 'processing' },
|
process: { confidence: 0.8, action: 'processing' },
|
||||||
transform: { confidence: 0.7, action: 'transformation' },
|
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]) =>
|
const matchedIntent = Object.entries(intents).find(([key]) =>
|
||||||
prompt.toLowerCase().includes(key),
|
prompt.toLowerCase().includes(key)
|
||||||
);
|
);
|
||||||
|
|
||||||
return matchedIntent ? matchedIntent[1] : { confidence: 0.1, action: 'unknown' };
|
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 {
|
export class WorkflowOperator {
|
||||||
/**
|
|
||||||
* Creates an instance of WorkflowOperator.
|
|
||||||
* @param {string} name - The name of the operator.
|
|
||||||
* @param {function(object): Promise<object>} operation - The operation function executed by the operator.
|
|
||||||
*/
|
|
||||||
constructor(name, operation) {
|
constructor(name, operation) {
|
||||||
this.name = name;
|
this.name = name;
|
||||||
this.operation = operation;
|
this.operation = operation;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Executes the operator's operation with the given state.
|
|
||||||
* @param {object} state - The current state to be processed.
|
|
||||||
* @returns {Promise<object>} - The updated state after the operation.
|
|
||||||
*/
|
|
||||||
async execute(state) {
|
async execute(state) {
|
||||||
return await this.operation(state);
|
return await this.operation(state);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Interface for manifold regions
|
|
||||||
/**
|
|
||||||
* Represents a region within the manifold, containing workflow operators.
|
|
||||||
*/
|
|
||||||
export class ManifoldRegion {
|
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 = []) {
|
constructor(name, operators = []) {
|
||||||
this.name = name;
|
this.name = name;
|
||||||
this.operators = operators;
|
this.operators = operators;
|
||||||
this.adjacentRegions = new Set();
|
this.adjacentRegions = new Set();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Adds an operator to the region.
|
|
||||||
* @param {WorkflowOperator} operator - The operator to be added.
|
|
||||||
*/
|
|
||||||
addOperator(operator) {
|
addOperator(operator) {
|
||||||
this.operators.push(operator);
|
this.operators.push(operator);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Establishes a connection to another region.
|
|
||||||
* @param {ManifoldRegion} region - The region to connect to.
|
|
||||||
*/
|
|
||||||
connectTo(region) {
|
connectTo(region) {
|
||||||
this.adjacentRegions.add(region);
|
this.adjacentRegions.add(region);
|
||||||
region.adjacentRegions.add(this);
|
region.adjacentRegions.add(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Retrieves valid operators for the given state.
|
|
||||||
* @param {object} _state - The current state.
|
|
||||||
* @returns {Promise<WorkflowOperator[]>} - The list of valid operators.
|
|
||||||
*/
|
|
||||||
async getValidOperators(_state) {
|
async getValidOperators(_state) {
|
||||||
return this.operators;
|
return this.operators;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Main manifold implementation
|
export class NestedManifoldRegion extends ManifoldRegion {
|
||||||
/**
|
constructor(name, nestedManifold) {
|
||||||
* Represents the workflow function manifold managing regions and state transitions.
|
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 {
|
export class WorkflowFunctionManifold {
|
||||||
/**
|
|
||||||
* Creates an instance of WorkflowFunctionManifold.
|
|
||||||
* @param {DummyLlmService} llmService - The LLM service used for intent detection.
|
|
||||||
*/
|
|
||||||
constructor(llmService) {
|
constructor(llmService) {
|
||||||
this.llmService = llmService;
|
this.llmService = llmService;
|
||||||
this.regions = new Map();
|
this.regions = new Map();
|
||||||
@@ -107,10 +77,6 @@ export class WorkflowFunctionManifold {
|
|||||||
this.state = {};
|
this.state = {};
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Adds a region to the manifold.
|
|
||||||
* @param {ManifoldRegion} region - The region to be added.
|
|
||||||
*/
|
|
||||||
addRegion(region) {
|
addRegion(region) {
|
||||||
this.regions.set(region.name, region);
|
this.regions.set(region.name, region);
|
||||||
if (!this.currentRegion) {
|
if (!this.currentRegion) {
|
||||||
@@ -118,51 +84,60 @@ export class WorkflowFunctionManifold {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Navigates to the next region based on the provided prompt.
|
|
||||||
* @param {string} prompt - The input prompt for intent matching.
|
|
||||||
* @returns {Promise<boolean>} - Whether navigation was successful.
|
|
||||||
*/
|
|
||||||
async navigate(prompt) {
|
async navigate(prompt) {
|
||||||
try {
|
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 =>
|
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;
|
this.currentRegion = nextRegion;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
console.warn(`No valid region found for prompt: "${prompt}"`);
|
|
||||||
return false;
|
return false;
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error(`Error during navigation for prompt "${prompt}":`, error);
|
console.error('Navigation error:', error);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Executes the workflow based on the current region and provided prompt.
|
|
||||||
* @param {string} prompt - The input prompt for intent matching.
|
|
||||||
* @returns {Promise<boolean>} - Whether the workflow execution was successful.
|
|
||||||
*/
|
|
||||||
async executeWorkflow(prompt) {
|
async executeWorkflow(prompt) {
|
||||||
try {
|
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 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);
|
this.state = await matchedOperator.execute(this.state);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
console.warn(`No matching operator found for intent: ${intent.action}`);
|
|
||||||
return false;
|
return false;
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error(`Error during workflow execution for prompt "${prompt}":`, error);
|
console.error('Execution error:', error);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -1,6 +1,7 @@
|
|||||||
{
|
{
|
||||||
"name": "workflow-function-manifold",
|
"name": "workflow-function-manifold",
|
||||||
"version": "1.0.2",
|
"version": "1.0.2",
|
||||||
|
"type": "module",
|
||||||
"description": "for building dynamic, LLM-driven workflows using a region-based execution model",
|
"description": "for building dynamic, LLM-driven workflows using a region-based execution model",
|
||||||
"main": "index.js",
|
"main": "index.js",
|
||||||
"bin": {
|
"bin": {
|
||||||
|
Reference in New Issue
Block a user