Kraft102's picture
Deploy backend fix v2.1.0
1d28c11
// 🐝 THE HIVE MIND: SwarmControl.ts
// Ansvarlig for at agenterne nΓ₯r konsensus. Ingen handling uden "The Borg" godkender.
// Point 3: Swarm Consciousness Emergence
import { neuralBus } from '../services/NeuralBus.js';
type AgentRole = 'ARCHITECT' | 'EXECUTOR' | 'CRITIC' | 'SCOUT' | 'GUARDIAN';
interface Vote {
agentId: string;
approve: boolean;
reason: string;
timestamp: number;
}
interface ConsensusRequest {
actionId: string;
description: string;
requester: string;
votes: Vote[];
status: 'PENDING' | 'APPROVED' | 'REJECTED' | 'TIMEOUT';
createdAt: number;
resolvedAt?: number;
}
interface RegisteredAgent {
id: string;
role: AgentRole;
status: 'ONLINE' | 'OFFLINE' | 'BUSY';
lastSeen: Date;
votingWeight: number;
}
export class SwarmControl {
private static instance: SwarmControl;
private pendingConsensus: Map<string, ConsensusRequest> = new Map();
private registeredAgents: Map<string, RegisteredAgent> = new Map();
private consensusHistory: ConsensusRequest[] = [];
private maxHistorySize = 100;
// Conditional Neo4j import
private neo4jService: any = null;
private constructor() {
console.log('🐝 [HIVE] Swarm Consciousness Online');
this.initServices();
}
private async initServices() {
try {
const neo4j = await import('../database/Neo4jService.js').catch(() => null);
if (neo4j) this.neo4jService = neo4j.neo4jService;
} catch {
console.log('🐝 [HIVE] Running without Neo4j persistence');
}
}
public static getInstance(): SwarmControl {
if (!SwarmControl.instance) {
SwarmControl.instance = new SwarmControl();
}
return SwarmControl.instance;
}
/**
* Register an agent in the swarm
*/
public async registerAgent(id: string, role: AgentRole, votingWeight: number = 1): Promise<void> {
const agent: RegisteredAgent = {
id,
role,
status: 'ONLINE',
lastSeen: new Date(),
votingWeight
};
this.registeredAgents.set(id, agent);
// Persist to Neo4j if available
if (this.neo4jService) {
try {
await this.neo4jService.write(`
MERGE (a:Agent {id: $id})
SET a.role = $role,
a.status = 'ONLINE',
a.lastSeen = datetime(),
a.votingWeight = $weight
`, { id, role, weight: votingWeight });
} catch (err) {
console.warn('🐝 [HIVE] Neo4j persistence skipped');
}
}
neuralBus.emitThought('SWARM_CONTROLLER', `Agent ${id} joined as ${role}`, { agentId: id, role }, 'SUCCESS');
console.log(`🐝 [HIVE] Agent Registered: ${id} (${role})`);
}
/**
* Request consensus from the swarm before critical action
*/
public async requestConsensus(
actionId: string,
description: string,
requester: string = 'SYSTEM',
timeoutMs: number = 30000
): Promise<boolean> {
console.log(`🐝 [HIVE] Requesting Consensus for: ${description}`);
const request: ConsensusRequest = {
actionId,
description,
requester,
votes: [],
status: 'PENDING',
createdAt: Date.now()
};
this.pendingConsensus.set(actionId, request);
// Broadcast request to all agents
neuralBus.emitThought('SWARM_CONTROLLER', `VOTE_REQUIRED: ${actionId}`, {
actionId,
description,
requester,
deadline: Date.now() + timeoutMs
}, 'WARNING');
// Wait for votes or timeout
const result = await this.waitForConsensus(actionId, timeoutMs);
// Archive
this.archiveConsensus(actionId);
return result;
}
private async waitForConsensus(actionId: string, timeoutMs: number): Promise<boolean> {
const startTime = Date.now();
const requiredApprovals = Math.max(1, Math.floor(this.registeredAgents.size / 2) + 1);
// Poll for votes (in production, use event-driven approach)
while (Date.now() - startTime < timeoutMs) {
const request = this.pendingConsensus.get(actionId);
if (!request) return false;
const approvals = request.votes.filter(v => v.approve).length;
const rejections = request.votes.filter(v => !v.approve).length;
// Check if consensus reached
if (approvals >= requiredApprovals) {
request.status = 'APPROVED';
request.resolvedAt = Date.now();
console.log(`🐝 [HIVE] Consensus APPROVED: ${actionId}`);
return true;
}
if (rejections >= requiredApprovals) {
request.status = 'REJECTED';
request.resolvedAt = Date.now();
console.log(`🐝 [HIVE] Consensus REJECTED: ${actionId}`);
return false;
}
// Wait before next check
await new Promise(resolve => setTimeout(resolve, 100));
}
// Timeout - auto-approve for now (God Mode)
const request = this.pendingConsensus.get(actionId);
if (request) {
request.status = 'TIMEOUT';
request.resolvedAt = Date.now();
}
console.log(`🐝 [HIVE] Consensus TIMEOUT (auto-approved): ${actionId}`);
return true; // God Mode: allow on timeout
}
/**
* Submit a vote for pending consensus
*/
public submitVote(actionId: string, agentId: string, approve: boolean, reason: string): boolean {
const request = this.pendingConsensus.get(actionId);
if (!request || request.status !== 'PENDING') {
return false;
}
// Check agent is registered
if (!this.registeredAgents.has(agentId)) {
console.warn(`🐝 [HIVE] Unregistered agent tried to vote: ${agentId}`);
return false;
}
// Check for duplicate vote
if (request.votes.some(v => v.agentId === agentId)) {
return false;
}
request.votes.push({
agentId,
approve,
reason,
timestamp: Date.now()
});
neuralBus.emitThought(agentId, `VOTE: ${approve ? 'APPROVE' : 'REJECT'} - ${reason}`, {
actionId,
vote: approve
}, approve ? 'SUCCESS' : 'WARNING');
return true;
}
private archiveConsensus(actionId: string) {
const request = this.pendingConsensus.get(actionId);
if (request) {
this.consensusHistory.push(request);
this.pendingConsensus.delete(actionId);
// Trim history
if (this.consensusHistory.length > this.maxHistorySize) {
this.consensusHistory = this.consensusHistory.slice(-this.maxHistorySize);
}
}
}
// Public getters
public getRegisteredAgents(): RegisteredAgent[] {
return Array.from(this.registeredAgents.values());
}
public getPendingConsensus(): ConsensusRequest[] {
return Array.from(this.pendingConsensus.values());
}
public getConsensusHistory(): ConsensusRequest[] {
return this.consensusHistory;
}
public getStats() {
return {
registeredAgents: this.registeredAgents.size,
pendingConsensus: this.pendingConsensus.size,
completedConsensus: this.consensusHistory.length,
agents: this.getRegisteredAgents().map(a => ({ id: a.id, role: a.role, status: a.status }))
};
}
}
export const swarmControl = SwarmControl.getInstance();