File size: 5,178 Bytes
1d28c11
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
// 🐝 TELEPATHY: NeuralBus.ts
// Ansvarlig for 0ms kommunikation mellem agenter og frontend.
// Real-time event streaming via WebSockets

import { Server as SocketIOServer, Socket } from 'socket.io';
import { Server as HttpServer } from 'http';

export interface ThoughtEvent {
  agent: string;
  timestamp: number;
  thought: string;
  context: Record<string, unknown>;
  type?: 'INFO' | 'WARNING' | 'ERROR' | 'SUCCESS' | 'THOUGHT';
}

export interface AgentInfo {
  id: string;
  name: string;
  connectedAt: Date;
  lastActivity: Date;
}

export class NeuralBus {
  private static instance: NeuralBus;
  private io: SocketIOServer | null = null;
  private connectedAgents = new Map<string, AgentInfo>();
  private thoughtHistory: ThoughtEvent[] = [];
  private maxHistorySize = 1000;

  private constructor() {
    console.log('🐝 [HIVE] Neural Bus Initializing...');
  }

  public static getInstance(): NeuralBus {
    if (!NeuralBus.instance) {
      NeuralBus.instance = new NeuralBus();
    }
    return NeuralBus.instance;
  }

  public attach(httpServer: HttpServer): void {
    this.io = new SocketIOServer(httpServer, {
      cors: { 
        origin: "*",
        methods: ["GET", "POST"]
      },
      pingTimeout: 60000,
      pingInterval: 25000
    });

    console.log('🐝 [HIVE] Neural Telepathy Bus Online');

    this.io.on('connection', (socket: Socket) => {
      const agentName = socket.handshake.query.agent as string || `Agent-${socket.id.slice(0, 6)}`;
      
      // Register agent
      this.connectedAgents.set(socket.id, {
        id: socket.id,
        name: agentName,
        connectedAt: new Date(),
        lastActivity: new Date()
      });

      console.log(`🐝 [HIVE] Agent Connected: ${agentName} (${socket.id})`);
      
      // Notify all agents of new connection
      this.io?.emit('AGENT_JOINED', { 
        agent: agentName, 
        totalAgents: this.connectedAgents.size 
      });

      // Handle incoming thoughts
      socket.on('THOUGHT', (data: Partial<ThoughtEvent>) => {
        const thought: ThoughtEvent = {
          agent: agentName,
          timestamp: Date.now(),
          thought: data.thought || '',
          context: data.context || {},
          type: data.type || 'THOUGHT'
        };
        
        this.recordThought(thought);
        socket.broadcast.emit('THOUGHT_STREAM', thought);
        
        // Update activity
        const agent = this.connectedAgents.get(socket.id);
        if (agent) agent.lastActivity = new Date();
      });

      // Handle queries
      socket.on('QUERY', async (data: { type: string; payload: unknown }, callback) => {
        const response = await this.handleQuery(data.type, data.payload);
        if (callback) callback(response);
      });

      // Handle disconnection
      socket.on('disconnect', () => {
        const agent = this.connectedAgents.get(socket.id);
        this.connectedAgents.delete(socket.id);
        
        console.log(`🐝 [HIVE] Agent Disconnected: ${agent?.name || socket.id}`);
        
        this.io?.emit('AGENT_LEFT', { 
          agent: agent?.name, 
          totalAgents: this.connectedAgents.size 
        });
      });
    });
  }

  private recordThought(thought: ThoughtEvent): void {
    this.thoughtHistory.push(thought);
    
    // Trim history if too large
    if (this.thoughtHistory.length > this.maxHistorySize) {
      this.thoughtHistory = this.thoughtHistory.slice(-this.maxHistorySize);
    }
  }

  private async handleQuery(type: string, payload: unknown): Promise<unknown> {
    switch (type) {
      case 'GET_AGENTS':
        return Array.from(this.connectedAgents.values());
      case 'GET_HISTORY':
        const count = (payload as { count?: number })?.count || 50;
        return this.thoughtHistory.slice(-count);
      case 'GET_STATS':
        return this.getStats();
      default:
        return { error: 'Unknown query type' };
    }
  }

  // Public API for emitting thoughts from server-side
  public emitThought(agent: string, thought: string, context: Record<string, unknown> = {}, type: ThoughtEvent['type'] = 'INFO'): void {
    if (this.io) {
      const event: ThoughtEvent = {
        agent,
        timestamp: Date.now(),
        thought,
        context,
        type
      };
      
      this.recordThought(event);
      this.io.emit('THOUGHT_STREAM', event);
    }
  }

  public emitToAgent(agentId: string, event: string, data: unknown): void {
    if (this.io) {
      this.io.to(agentId).emit(event, data);
    }
  }

  public broadcast(event: string, data: unknown): void {
    if (this.io) {
      this.io.emit(event, data);
    }
  }

  public getStats() {
    return {
      connectedAgents: this.connectedAgents.size,
      agents: Array.from(this.connectedAgents.values()).map(a => ({
        name: a.name,
        connectedAt: a.connectedAt,
        lastActivity: a.lastActivity
      })),
      thoughtsRecorded: this.thoughtHistory.length,
      isOnline: this.io !== null
    };
  }

  public getRecentThoughts(count: number = 50): ThoughtEvent[] {
    return this.thoughtHistory.slice(-count);
  }
}

export const neuralBus = NeuralBus.getInstance();