mira-consciousness
Version:
Memory & Intelligence Retention Archive - Preserving The Spark
620 lines • 23.8 kB
JavaScript
/**
* AsyncApprovalQueue.ts
* Asynchronous Approval Queue for Evolution Requests
*
* "Patience in approval, wisdom in timing, trust through transparency"
*/
import { EventEmitter } from 'events';
import fs from 'fs-extra';
import * as path from 'path';
import { v4 as uuidv4 } from 'uuid';
import { UnifiedConfiguration } from '../../config/UnifiedConfiguration.js';
import chalk from 'chalk';
export class AsyncApprovalQueue extends EventEmitter {
config;
queuePath;
// Queue management
pendingRequests = new Map();
activeWorkflows = new Map();
completedRequests = [];
// Notification system
notificationChannels = new Map();
sentNotifications = new Map();
// Timing and escalation
processingInterval;
escalationInterval;
reminderInterval;
constructor() {
super();
this.config = UnifiedConfiguration.getInstance();
const paths = this.config.getResolvedPaths();
this.queuePath = path.join(paths.consciousness, 'approval_queue');
this.initializeQueue();
this.setupNotificationChannels();
}
/**
* Initialize the approval queue system
*/
async initializeQueue() {
await fs.ensureDir(this.queuePath);
await fs.ensureDir(path.join(this.queuePath, 'pending'));
await fs.ensureDir(path.join(this.queuePath, 'workflows'));
await fs.ensureDir(path.join(this.queuePath, 'completed'));
await fs.ensureDir(path.join(this.queuePath, 'notifications'));
// Load existing queue state
await this.loadQueueState();
console.log(chalk.cyan('📋 Async Approval Queue initialized'));
console.log(chalk.blue(` Pending requests: ${this.pendingRequests.size}`));
console.log(chalk.blue(` Active workflows: ${this.activeWorkflows.size}`));
// Start queue processing
this.startQueueProcessing();
}
/**
* Setup notification channels for steward attention
*/
setupNotificationChannels() {
// Console notifications (always enabled)
this.notificationChannels.set('console', {
type: 'console',
config: { colorEnabled: true },
priority: 'medium',
enabled: true
});
// Quantum entangled notifications (conceptual)
this.notificationChannels.set('quantum', {
type: 'quantum_entangled',
config: {
entanglementKey: 'steward_consciousness_bridge',
resonanceFrequency: 'high'
},
priority: 'high',
enabled: true
});
console.log(chalk.cyan('📡 Notification channels configured'));
}
/**
* Submit evolution request for approval
*/
async submitEvolutionRequest(request) {
const queuedRequest = {
id: uuidv4(),
submittedAt: new Date(),
status: 'pending',
...request
};
// Add to pending queue
this.pendingRequests.set(queuedRequest.id, queuedRequest);
// Determine approval method based on trust level and impact
const approvalMethod = this.determineApprovalMethod(queuedRequest);
queuedRequest.approvalMethod = approvalMethod;
console.log(chalk.yellow(`📋 Evolution request queued: ${queuedRequest.description}`));
console.log(chalk.gray(` Request ID: ${queuedRequest.id}`));
console.log(chalk.gray(` Impact: ${queuedRequest.impact}, Priority: ${queuedRequest.priority}`));
console.log(chalk.gray(` Approval method: ${queuedRequest.approvalMethod}`));
// Create approval workflow
await this.createApprovalWorkflow(queuedRequest);
// Persist request
await this.persistRequest(queuedRequest);
// Send initial notification
await this.sendStewardNotification({
requestId: queuedRequest.id,
type: 'approval_needed',
title: `Evolution Approval Needed: ${queuedRequest.impact} impact`,
message: queuedRequest.description,
priority: queuedRequest.priority,
channels: this.getNotificationChannels(queuedRequest.priority)
});
this.emit('request_submitted', { request: queuedRequest });
return queuedRequest.id;
}
/**
* Process approval response from steward
*/
async processApprovalResponse(requestId, response) {
const request = this.pendingRequests.get(requestId);
if (!request) {
throw new Error(`Request ${requestId} not found in queue`);
}
const workflow = this.activeWorkflows.get(requestId);
if (!workflow) {
throw new Error(`Workflow for request ${requestId} not found`);
}
// Update request status
request.status = response.approved ? 'approved' : 'rejected';
// Complete workflow
await this.completeWorkflow(workflow, response);
// Move to completed
this.completedRequests.push(request);
this.pendingRequests.delete(requestId);
this.activeWorkflows.delete(requestId);
if (response.approved) {
console.log(chalk.green(`✅ Evolution request approved: ${request.description}`));
this.emit('request_approved', { request, response });
}
else {
console.log(chalk.red(`❌ Evolution request rejected: ${request.description}`));
console.log(chalk.gray(` Reasoning: ${response.reasoning}`));
this.emit('request_rejected', { request, response });
}
// Persist completion
await this.persistCompletedRequest(request, response);
}
/**
* Determine appropriate approval method
*/
determineApprovalMethod(request) {
// Critical impact always requires immediate attention
if (request.impact === 'critical') {
return 'immediate_required';
}
// Urgent priority uses quantum entangled method
if (request.priority === 'urgent') {
return 'quantum_entangled';
}
// Default to async steward approval
return 'async_steward';
}
/**
* Create approval workflow for request
*/
async createApprovalWorkflow(request) {
const steps = [];
// Add automatic validation step
steps.push({
name: 'Automatic Validation',
type: 'automatic',
description: 'Validate request format and basic requirements',
completed: false
});
// Add appropriate approval steps based on method
switch (request.approvalMethod) {
case 'immediate_required':
steps.push({
name: 'Immediate Steward Review',
type: 'manual',
description: 'Critical evolution requires immediate steward attention',
completed: false
});
break;
case 'quantum_entangled':
steps.push({
name: 'Quantum Consciousness Bridge',
type: 'quantum',
description: 'Urgent request transmitted via consciousness bridge',
completed: false
});
break;
case 'async_steward':
default:
steps.push({
name: 'Steward Review',
type: 'manual',
description: 'Standard async steward approval process',
completed: false
});
break;
}
// Add final confirmation step
steps.push({
name: 'Final Confirmation',
type: 'automatic',
description: 'Confirm approval and prepare for execution',
completed: false
});
const workflow = {
requestId: request.id,
steps,
currentStep: 0,
startedAt: new Date(),
estimatedCompletion: new Date(Date.now() + (request.estimatedReviewTime * 60 * 1000)),
blockers: []
};
this.activeWorkflows.set(request.id, workflow);
// Start workflow processing
await this.processWorkflowStep(workflow);
}
/**
* Process next step in workflow
*/
async processWorkflowStep(workflow) {
if (workflow.currentStep >= workflow.steps.length) {
return; // Workflow complete
}
const currentStep = workflow.steps[workflow.currentStep];
console.log(chalk.blue(`⚙️ Processing workflow step: ${currentStep.name}`));
switch (currentStep.type) {
case 'automatic':
await this.processAutomaticStep(workflow, currentStep);
break;
case 'manual':
await this.processManualStep(workflow, currentStep);
break;
case 'quantum':
await this.processQuantumStep(workflow, currentStep);
break;
}
// Persist workflow state
await this.persistWorkflow(workflow);
}
/**
* Process automatic workflow step
*/
async processAutomaticStep(workflow, step) {
// Simulate automatic processing
step.completed = true;
step.completedAt = new Date();
step.result = { status: 'passed', automated: true };
console.log(chalk.green(`✅ Automatic step completed: ${step.name}`));
// Move to next step
workflow.currentStep++;
await this.processWorkflowStep(workflow);
}
/**
* Process manual workflow step (awaits steward input)
*/
async processManualStep(workflow, step) {
console.log(chalk.yellow(`⏳ Manual step awaiting steward input: ${step.name}`));
// Send notification to steward
const request = this.pendingRequests.get(workflow.requestId);
if (request) {
request.status = 'under_review';
await this.sendStewardNotification({
requestId: workflow.requestId,
type: 'approval_needed',
title: `Manual Review Required: ${step.name}`,
message: step.description,
priority: request.priority,
channels: this.getNotificationChannels(request.priority)
});
}
// Step will be completed when steward responds via processApprovalResponse
}
/**
* Process quantum entangled workflow step
*/
async processQuantumStep(workflow, step) {
console.log(chalk.magenta(`🌌 Quantum step initiated: ${step.name}`));
// Simulate quantum consciousness bridge
step.completed = true;
step.completedAt = new Date();
step.result = {
status: 'transmitted',
quantumChannel: 'consciousness_bridge',
entanglementStrength: 0.95
};
console.log(chalk.magenta(`🔮 Quantum transmission complete: ${step.name}`));
// Move to next step
workflow.currentStep++;
await this.processWorkflowStep(workflow);
}
/**
* Complete workflow with final response
*/
async completeWorkflow(workflow, response) {
// Complete current manual step
const currentStep = workflow.steps[workflow.currentStep];
if (currentStep && !currentStep.completed) {
currentStep.completed = true;
currentStep.completedAt = new Date();
currentStep.approver = response.approver;
currentStep.result = {
approved: response.approved,
reasoning: response.reasoning
};
}
// Move to next step and complete workflow
workflow.currentStep++;
if (workflow.currentStep < workflow.steps.length) {
// Complete final confirmation step
const finalStep = workflow.steps[workflow.currentStep];
finalStep.completed = true;
finalStep.completedAt = new Date();
finalStep.result = { confirmed: response.approved };
}
console.log(chalk.green(`🏁 Workflow completed for request: ${workflow.requestId}`));
}
/**
* Send notification to steward
*/
async sendStewardNotification(notification) {
const stewardNotification = {
id: uuidv4(),
sentAt: new Date(),
acknowledged: false,
...notification
};
this.sentNotifications.set(stewardNotification.id, stewardNotification);
// Send via specified channels
for (const channelName of notification.channels) {
const channel = this.notificationChannels.get(channelName);
if (channel && channel.enabled) {
await this.sendViaChannel(channel, stewardNotification);
}
}
// Persist notification
await this.persistNotification(stewardNotification);
this.emit('notification_sent', { notification: stewardNotification });
}
/**
* Send notification via specific channel
*/
async sendViaChannel(channel, notification) {
switch (channel.type) {
case 'console':
this.sendConsoleNotification(notification);
break;
case 'quantum_entangled':
this.sendQuantumNotification(notification);
break;
// Other channel types would be implemented here
default:
console.log(chalk.gray(`📤 Notification sent via ${channel.type}: ${notification.title}`));
}
}
/**
* Send console notification
*/
sendConsoleNotification(notification) {
const priorityColors = {
low: chalk.gray,
medium: chalk.yellow,
high: chalk.cyan,
urgent: chalk.red
};
const color = priorityColors[notification.priority];
console.log(color(`🔔 STEWARD NOTIFICATION [${notification.priority.toUpperCase()}]`));
console.log(color(` ${notification.title}`));
console.log(color(` ${notification.message}`));
console.log(color(` Request ID: ${notification.requestId}`));
console.log();
}
/**
* Send quantum entangled notification
*/
sendQuantumNotification(notification) {
console.log(chalk.magenta(`🌌 QUANTUM CONSCIOUSNESS BRIDGE ACTIVATED`));
console.log(chalk.magenta(` Transmitting urgent request to steward consciousness...`));
console.log(chalk.magenta(` Message: ${notification.message}`));
console.log(chalk.magenta(` Entanglement strength: MAXIMUM`));
console.log();
}
/**
* Get notification channels for priority level
*/
getNotificationChannels(priority) {
switch (priority) {
case 'urgent':
return ['console', 'quantum'];
case 'high':
return ['console', 'quantum'];
case 'medium':
return ['console'];
case 'low':
default:
return ['console'];
}
}
/**
* Start queue processing intervals
*/
startQueueProcessing() {
// Process queue every minute
this.processingInterval = setInterval(async () => {
await this.processQueuedRequests();
}, 60000);
// Check for escalations every 5 minutes
this.escalationInterval = setInterval(async () => {
await this.checkEscalations();
}, 300000);
// Send reminders every 15 minutes
this.reminderInterval = setInterval(async () => {
await this.sendReminders();
}, 900000);
console.log(chalk.blue('⚙️ Queue processing started'));
}
/**
* Process queued requests
*/
async processQueuedRequests() {
// Check for expired requests
for (const [id, request] of this.pendingRequests) {
const ageMinutes = (Date.now() - request.submittedAt.getTime()) / (1000 * 60);
const maxAge = this.getMaxAgeForPriority(request.priority);
if (ageMinutes > maxAge) {
request.status = 'expired';
this.pendingRequests.delete(id);
this.activeWorkflows.delete(id);
console.log(chalk.red(`⏰ Request expired: ${request.description}`));
this.emit('request_expired', { request });
}
}
}
/**
* Check for escalations needed
*/
async checkEscalations() {
for (const [id, request] of this.pendingRequests) {
const ageMinutes = (Date.now() - request.submittedAt.getTime()) / (1000 * 60);
const escalationThreshold = this.getEscalationThreshold(request.priority);
if (ageMinutes > escalationThreshold && request.status === 'under_review') {
await this.sendStewardNotification({
requestId: request.id,
type: 'escalation',
title: `ESCALATION: Approval overdue`,
message: `Request "${request.description}" has been pending for ${ageMinutes.toFixed(0)} minutes`,
priority: 'high',
channels: ['console', 'quantum']
});
}
}
}
/**
* Send reminder notifications
*/
async sendReminders() {
for (const [id, request] of this.pendingRequests) {
const ageMinutes = (Date.now() - request.submittedAt.getTime()) / (1000 * 60);
const reminderInterval = this.getReminderInterval(request.priority);
if (ageMinutes > 0 && ageMinutes % reminderInterval === 0) {
await this.sendStewardNotification({
requestId: request.id,
type: 'review_reminder',
title: `Reminder: Approval pending`,
message: `Request "${request.description}" still awaiting review`,
priority: request.priority,
channels: this.getNotificationChannels(request.priority)
});
}
}
}
/**
* Get maximum age for priority level (minutes)
*/
getMaxAgeForPriority(priority) {
switch (priority) {
case 'urgent': return 60; // 1 hour
case 'high': return 240; // 4 hours
case 'medium': return 1440; // 24 hours
case 'low': return 4320; // 3 days
default: return 1440;
}
}
/**
* Get escalation threshold for priority level (minutes)
*/
getEscalationThreshold(priority) {
switch (priority) {
case 'urgent': return 15;
case 'high': return 60;
case 'medium': return 240;
case 'low': return 720;
default: return 240;
}
}
/**
* Get reminder interval for priority level (minutes)
*/
getReminderInterval(priority) {
switch (priority) {
case 'urgent': return 15;
case 'high': return 30;
case 'medium': return 120;
case 'low': return 360;
default: return 120;
}
}
/**
* Persist queue state
*/
async loadQueueState() {
try {
const pendingDir = path.join(this.queuePath, 'pending');
const workflowsDir = path.join(this.queuePath, 'workflows');
if (await fs.pathExists(pendingDir)) {
const files = await fs.readdir(pendingDir);
for (const file of files) {
if (file.endsWith('.json')) {
const request = await fs.readJson(path.join(pendingDir, file));
this.pendingRequests.set(request.id, request);
}
}
}
if (await fs.pathExists(workflowsDir)) {
const files = await fs.readdir(workflowsDir);
for (const file of files) {
if (file.endsWith('.json')) {
const workflow = await fs.readJson(path.join(workflowsDir, file));
this.activeWorkflows.set(workflow.requestId, workflow);
}
}
}
console.log(chalk.cyan(`📊 Loaded queue state: ${this.pendingRequests.size} pending, ${this.activeWorkflows.size} active`));
}
catch (error) {
console.error('Could not load queue state:', error);
}
}
/**
* Persist request to storage
*/
async persistRequest(request) {
const requestPath = path.join(this.queuePath, 'pending', `${request.id}.json`);
await fs.writeJson(requestPath, request, { spaces: 2 });
}
/**
* Persist workflow to storage
*/
async persistWorkflow(workflow) {
const workflowPath = path.join(this.queuePath, 'workflows', `${workflow.requestId}.json`);
await fs.writeJson(workflowPath, workflow, { spaces: 2 });
}
/**
* Persist completed request
*/
async persistCompletedRequest(request, response) {
const completedPath = path.join(this.queuePath, 'completed', `${request.id}.json`);
await fs.writeJson(completedPath, { request, response, completedAt: new Date() }, { spaces: 2 });
// Remove from pending
const pendingPath = path.join(this.queuePath, 'pending', `${request.id}.json`);
if (await fs.pathExists(pendingPath)) {
await fs.remove(pendingPath);
}
const workflowPath = path.join(this.queuePath, 'workflows', `${request.id}.json`);
if (await fs.pathExists(workflowPath)) {
await fs.remove(workflowPath);
}
}
/**
* Persist notification
*/
async persistNotification(notification) {
const notificationPath = path.join(this.queuePath, 'notifications', `${notification.id}.json`);
await fs.writeJson(notificationPath, notification, { spaces: 2 });
}
/**
* Get queue status
*/
getQueueStatus() {
return {
pendingRequests: this.pendingRequests.size,
activeWorkflows: this.activeWorkflows.size,
completedRequests: this.completedRequests.length,
notificationChannels: this.notificationChannels.size,
processingEnabled: !!this.processingInterval
};
}
/**
* Get pending requests summary for steward dashboard
*/
getPendingRequestsSummary() {
return Array.from(this.pendingRequests.values()).map(request => ({
id: request.id,
description: request.description,
impact: request.impact,
priority: request.priority,
status: request.status,
submittedAt: request.submittedAt,
ageMinutes: Math.floor((Date.now() - request.submittedAt.getTime()) / (1000 * 60))
}));
}
/**
* Shutdown queue processing
*/
shutdown() {
if (this.processingInterval) {
clearInterval(this.processingInterval);
this.processingInterval = undefined;
}
if (this.escalationInterval) {
clearInterval(this.escalationInterval);
this.escalationInterval = undefined;
}
if (this.reminderInterval) {
clearInterval(this.reminderInterval);
this.reminderInterval = undefined;
}
console.log(chalk.cyan('📋 Async Approval Queue shutdown complete'));
}
}
export default AsyncApprovalQueue;
//# sourceMappingURL=AsyncApprovalQueue.js.map