jay-code
Version:
Streamlined AI CLI orchestration engine with mathematical rigor and enterprise-grade reliability
605 lines (510 loc) • 15.3 kB
JavaScript
/**
* SwarmMemory - MCP-specific memory persistence extending SharedMemory
* Provides swarm-specific features like agent coordination, task tracking, and neural patterns
*
* @module swarm-memory
*/
import { SharedMemory } from './shared-memory.js';
import path from 'path';
/**
* Swarm-specific namespaces
*/
const SWARM_NAMESPACES = {
AGENTS: 'swarm:agents',
TASKS: 'swarm:tasks',
COMMUNICATIONS: 'swarm:communications',
CONSENSUS: 'swarm:consensus',
PATTERNS: 'swarm:patterns',
METRICS: 'swarm:metrics',
COORDINATION: 'swarm:coordination',
};
/**
* SwarmMemory class - Extends SharedMemory with MCP features
*/
export class SwarmMemory extends SharedMemory {
constructor(options = {}) {
// Default to .swarm directory for MCP
super({
directory: options.directory || '.swarm',
filename: options.filename || 'swarm-memory.db',
...options,
});
this.swarmId = options.swarmId || 'default';
this.mcpMode = options.mcpMode !== false;
// Additional swarm-specific caches
this.agentCache = new Map();
this.taskCache = new Map();
this.patternCache = new Map();
}
/**
* Initialize with swarm-specific setup
*/
async initialize() {
await super.initialize();
// Initialize swarm-specific namespaces
await this._initializeSwarmNamespaces();
// Load active agents and tasks into cache
await this._loadSwarmState();
this.emit('swarm:initialized', { swarmId: this.swarmId });
}
/**
* Store agent information
*/
async storeAgent(agentId, agentData) {
const key = `agent:${agentId}`;
const enrichedData = {
...agentData,
swarmId: this.swarmId,
lastUpdated: new Date().toISOString(),
};
await this.store(key, enrichedData, {
namespace: SWARM_NAMESPACES.AGENTS,
tags: ['agent', agentData.type, agentData.status],
metadata: {
swarmId: this.swarmId,
agentType: agentData.type,
},
});
// Update agent cache
this.agentCache.set(agentId, enrichedData);
this.emit('swarm:agentStored', { agentId, type: agentData.type });
return { agentId, stored: true };
}
/**
* Retrieve agent information
*/
async getAgent(agentId) {
// Check cache first
if (this.agentCache.has(agentId)) {
return this.agentCache.get(agentId);
}
const key = `agent:${agentId}`;
const agent = await this.retrieve(key, SWARM_NAMESPACES.AGENTS);
if (agent) {
this.agentCache.set(agentId, agent);
}
return agent;
}
/**
* List all agents in swarm
*/
async listAgents(filter = {}) {
const agents = await this.list(SWARM_NAMESPACES.AGENTS, {
limit: filter.limit || 100,
});
return agents
.map((entry) => entry.value)
.filter((agent) => {
if (filter.type && agent.type !== filter.type) return false;
if (filter.status && agent.status !== filter.status) return false;
if (filter.swarmId && agent.swarmId !== filter.swarmId) return false;
return true;
});
}
/**
* Store task information
*/
async storeTask(taskId, taskData) {
const key = `task:${taskId}`;
const enrichedData = {
...taskData,
swarmId: this.swarmId,
createdAt: taskData.createdAt || new Date().toISOString(),
updatedAt: new Date().toISOString(),
};
await this.store(key, enrichedData, {
namespace: SWARM_NAMESPACES.TASKS,
tags: ['task', taskData.status, taskData.priority],
metadata: {
swarmId: this.swarmId,
assignedAgents: taskData.assignedAgents || [],
},
});
// Update task cache
this.taskCache.set(taskId, enrichedData);
this.emit('swarm:taskStored', { taskId, status: taskData.status });
return { taskId, stored: true };
}
/**
* Update task status
*/
async updateTaskStatus(taskId, status, result = null) {
const task = await this.getTask(taskId);
if (!task) {
throw new Error(`Task ${taskId} not found`);
}
task.status = status;
task.updatedAt = new Date().toISOString();
if (result) {
task.result = result;
}
if (status === 'completed') {
task.completedAt = new Date().toISOString();
}
await this.storeTask(taskId, task);
this.emit('swarm:taskStatusUpdated', { taskId, status });
return { taskId, status, updated: true };
}
/**
* Get task information
*/
async getTask(taskId) {
// Check cache first
if (this.taskCache.has(taskId)) {
return this.taskCache.get(taskId);
}
const key = `task:${taskId}`;
const task = await this.retrieve(key, SWARM_NAMESPACES.TASKS);
if (task) {
this.taskCache.set(taskId, task);
}
return task;
}
/**
* Store inter-agent communication
*/
async storeCommunication(fromAgent, toAgent, message) {
const commId = `comm:${Date.now()}-${Math.random().toString(36).substr(2, 9)}`;
const communication = {
id: commId,
fromAgent,
toAgent,
message,
swarmId: this.swarmId,
timestamp: new Date().toISOString(),
};
await this.store(commId, communication, {
namespace: SWARM_NAMESPACES.COMMUNICATIONS,
ttl: 86400, // 24 hours
tags: ['communication', message.type],
metadata: {
fromAgent,
toAgent,
messageType: message.type,
},
});
this.emit('swarm:communication', { fromAgent, toAgent, type: message.type });
return { id: commId, stored: true };
}
/**
* Store consensus decision
*/
async storeConsensus(consensusId, decision) {
const key = `consensus:${consensusId}`;
const consensusData = {
...decision,
swarmId: this.swarmId,
timestamp: new Date().toISOString(),
};
await this.store(key, consensusData, {
namespace: SWARM_NAMESPACES.CONSENSUS,
tags: ['consensus', decision.status],
metadata: {
swarmId: this.swarmId,
taskId: decision.taskId,
threshold: decision.threshold,
},
});
this.emit('swarm:consensus', { consensusId, status: decision.status });
return { consensusId, stored: true };
}
/**
* Store neural pattern
*/
async storePattern(patternId, pattern) {
const key = `pattern:${patternId}`;
const patternData = {
...pattern,
swarmId: this.swarmId,
createdAt: new Date().toISOString(),
usageCount: 0,
successRate: 0,
};
await this.store(key, patternData, {
namespace: SWARM_NAMESPACES.PATTERNS,
tags: ['pattern', pattern.type],
metadata: {
swarmId: this.swarmId,
patternType: pattern.type,
confidence: pattern.confidence || 0,
},
});
// Cache frequently used patterns
if (pattern.type === 'coordination' || pattern.type === 'optimization') {
this.patternCache.set(patternId, patternData);
}
this.emit('swarm:patternStored', { patternId, type: pattern.type });
return { patternId, stored: true };
}
/**
* Update pattern usage and success metrics
*/
async updatePatternMetrics(patternId, success = true) {
const pattern = await this.getPattern(patternId);
if (!pattern) {
throw new Error(`Pattern ${patternId} not found`);
}
pattern.usageCount++;
pattern.lastUsedAt = new Date().toISOString();
// Update success rate with exponential moving average
const alpha = 0.1; // Smoothing factor
const currentSuccess = success ? 1 : 0;
pattern.successRate = alpha * currentSuccess + (1 - alpha) * (pattern.successRate || 0);
await this.storePattern(patternId, pattern);
return { patternId, usageCount: pattern.usageCount, successRate: pattern.successRate };
}
/**
* Get pattern
*/
async getPattern(patternId) {
// Check cache first
if (this.patternCache.has(patternId)) {
return this.patternCache.get(patternId);
}
const key = `pattern:${patternId}`;
return await this.retrieve(key, SWARM_NAMESPACES.PATTERNS);
}
/**
* Find best patterns for a given context
*/
async findBestPatterns(context, limit = 5) {
const patterns = await this.search({
namespace: SWARM_NAMESPACES.PATTERNS,
tags: context.tags,
limit: 100,
});
// Score patterns based on success rate and relevance
const scored = patterns.map((entry) => {
const pattern = entry.value;
const score =
pattern.successRate * 0.7 +
(pattern.confidence || 0) * 0.2 +
(pattern.usageCount > 0 ? 0.1 : 0);
return { ...pattern, score };
});
// Sort by score and return top patterns
return scored.sort((a, b) => b.score - a.score).slice(0, limit);
}
/**
* Store coordination state
*/
async storeCoordination(key, state) {
await this.store(key, state, {
namespace: SWARM_NAMESPACES.COORDINATION,
ttl: 3600, // 1 hour
metadata: {
swarmId: this.swarmId,
timestamp: new Date().toISOString(),
},
});
return { key, stored: true };
}
/**
* Get coordination state
*/
async getCoordination(key) {
return await this.retrieve(key, SWARM_NAMESPACES.COORDINATION);
}
/**
* Store performance metrics
*/
async storeMetrics(metricsId, metrics) {
const key = `metrics:${metricsId}`;
await this.store(key, metrics, {
namespace: SWARM_NAMESPACES.METRICS,
ttl: 86400 * 7, // 7 days
tags: ['metrics', metrics.type],
metadata: {
swarmId: this.swarmId,
agentId: metrics.agentId,
timestamp: new Date().toISOString(),
},
});
this.emit('swarm:metricsStored', { metricsId, type: metrics.type });
return { metricsId, stored: true };
}
/**
* Get swarm statistics
*/
async getSwarmStats() {
const baseStats = await this.getStats();
// Add swarm-specific stats
const agentCount = await this._countNamespace(SWARM_NAMESPACES.AGENTS);
const taskCount = await this._countNamespace(SWARM_NAMESPACES.TASKS);
const patternCount = await this._countNamespace(SWARM_NAMESPACES.PATTERNS);
// Get active agents
const activeAgents = Array.from(this.agentCache.values()).filter(
(agent) => agent.status === 'active' || agent.status === 'busy',
).length;
// Get task statistics
const tasks = Array.from(this.taskCache.values());
const taskStats = {
total: tasks.length,
pending: tasks.filter((t) => t.status === 'pending').length,
inProgress: tasks.filter((t) => t.status === 'in_progress').length,
completed: tasks.filter((t) => t.status === 'completed').length,
failed: tasks.filter((t) => t.status === 'failed').length,
};
return {
...baseStats,
swarm: {
swarmId: this.swarmId,
agents: {
total: agentCount,
active: activeAgents,
cached: this.agentCache.size,
},
tasks: taskStats,
patterns: {
total: patternCount,
cached: this.patternCache.size,
},
namespaces: Object.values(SWARM_NAMESPACES),
},
};
}
/**
* Clean up old swarm data
*/
async cleanupSwarmData(options = {}) {
const {
maxAge = 86400 * 7, // 7 days
keepPatterns = true,
keepConsensus = true,
} = options;
const cutoffTime = Date.now() - maxAge * 1000;
let cleaned = 0;
// Clean old communications
const comms = await this.list(SWARM_NAMESPACES.COMMUNICATIONS);
for (const comm of comms) {
if (new Date(comm.value.timestamp).getTime() < cutoffTime) {
await this.delete(comm.key, SWARM_NAMESPACES.COMMUNICATIONS);
cleaned++;
}
}
// Clean completed tasks
const tasks = await this.list(SWARM_NAMESPACES.TASKS);
for (const task of tasks) {
if (
task.value.status === 'completed' &&
new Date(task.value.completedAt).getTime() < cutoffTime
) {
await this.delete(task.key, SWARM_NAMESPACES.TASKS);
this.taskCache.delete(task.value.id);
cleaned++;
}
}
// Clean old metrics
const metrics = await this.list(SWARM_NAMESPACES.METRICS);
for (const metric of metrics) {
if (new Date(metric.createdAt).getTime() < cutoffTime) {
await this.delete(metric.key, SWARM_NAMESPACES.METRICS);
cleaned++;
}
}
this.emit('swarm:cleanup', { cleaned, maxAge });
return { cleaned };
}
/**
* Export swarm state
*/
async exportSwarmState() {
const agents = await this.listAgents();
const tasks = Array.from(this.taskCache.values());
const patterns = await this.list(SWARM_NAMESPACES.PATTERNS);
return {
swarmId: this.swarmId,
exportedAt: new Date().toISOString(),
agents: agents,
tasks: tasks,
patterns: patterns.map((p) => p.value),
statistics: await this.getSwarmStats(),
};
}
/**
* Import swarm state
*/
async importSwarmState(state) {
let imported = {
agents: 0,
tasks: 0,
patterns: 0,
};
// Import agents
if (state.agents) {
for (const agent of state.agents) {
await this.storeAgent(agent.id, agent);
imported.agents++;
}
}
// Import tasks
if (state.tasks) {
for (const task of state.tasks) {
await this.storeTask(task.id, task);
imported.tasks++;
}
}
// Import patterns
if (state.patterns) {
for (const pattern of state.patterns) {
await this.storePattern(pattern.id, pattern);
imported.patterns++;
}
}
this.emit('swarm:imported', imported);
return imported;
}
/**
* Private helper methods
*/
async _initializeSwarmNamespaces() {
// Create swarm metadata
await this.store(
'swarm:metadata',
{
swarmId: this.swarmId,
createdAt: new Date().toISOString(),
version: '1.0.0',
namespaces: Object.values(SWARM_NAMESPACES),
},
{
namespace: 'swarm:system',
},
);
}
async _loadSwarmState() {
// Load active agents
const agents = await this.list(SWARM_NAMESPACES.AGENTS, { limit: 100 });
for (const entry of agents) {
if (entry.value.status === 'active' || entry.value.status === 'busy') {
this.agentCache.set(entry.value.id, entry.value);
}
}
// Load in-progress tasks
const tasks = await this.search({
namespace: SWARM_NAMESPACES.TASKS,
tags: ['in_progress'],
limit: 100,
});
for (const entry of tasks) {
this.taskCache.set(entry.value.id, entry.value);
}
// Load high-confidence patterns
const patterns = await this.list(SWARM_NAMESPACES.PATTERNS, { limit: 50 });
for (const entry of patterns) {
if (entry.value.confidence > 0.7 || entry.value.successRate > 0.8) {
this.patternCache.set(entry.value.id, entry.value);
}
}
}
async _countNamespace(namespace) {
const stats = await this.getStats();
return stats.namespaces[namespace]?.count || 0;
}
}
// Export factory function for easy creation
export function createSwarmMemory(options = {}) {
return new SwarmMemory(options);
}
// Export for backwards compatibility
export default SwarmMemory;