UNPKG

blax

Version:

Blax - HMS-Powered Multi-Agent Platform with Government Agency Analysis, Deep Research, and Enterprise-Ready Deployment. No local LLM keys required.

214 lines 7.28 kB
import WebSocket from 'ws'; import { EventEmitter } from 'events'; import { eventBus } from '../../core/eventBus.js'; import { blaxConfig } from '../../config/blax.js'; export class HubAdapter extends EventEmitter { ws; config; connected = false; reconnectAttempts = 0; maxReconnectAttempts = 5; heartbeatTimer; constructor(config) { super(); this.config = { url: blaxConfig.api.hubUrl, reconnect: true, heartbeatInterval: 30000, ...config }; } async connect() { if (this.connected) { return; } return new Promise((resolve, reject) => { try { const headers = {}; if (this.config.auth) { if (this.config.auth.type === 'jwt') { headers['Authorization'] = `Bearer ${this.config.auth.token}`; } else if (this.config.auth.type === 'apikey') { headers['X-API-Key'] = this.config.auth.token; } } this.ws = new WebSocket(this.config.url, { headers }); this.ws.on('open', () => { this.connected = true; this.reconnectAttempts = 0; this.startHeartbeat(); this.emit('connected'); eventBus.publish({ type: 'hub.connected', timestamp: Date.now(), source: 'tlnt', data: { url: this.config.url } }); resolve(); }); this.ws.on('message', (data) => { try { const event = JSON.parse(data.toString()); this.handleHubEvent(event); } catch (error) { console.error('Failed to parse hub message:', error); } }); this.ws.on('close', (code, reason) => { this.connected = false; this.stopHeartbeat(); this.emit('disconnected', { code, reason: reason.toString() }); eventBus.publish({ type: 'hub.disconnected', timestamp: Date.now(), source: 'tlnt', data: { code, reason: reason.toString() } }); if (this.config.reconnect && this.reconnectAttempts < this.maxReconnectAttempts) { this.scheduleReconnect(); } }); this.ws.on('error', (error) => { this.emit('error', error); if (!this.connected) { reject(error); } }); setTimeout(() => { if (!this.connected) { reject(new Error('Connection timeout')); } }, 10000); } catch (error) { reject(error); } }); } disconnect() { if (this.ws) { this.ws.close(); this.ws = undefined; } this.connected = false; this.stopHeartbeat(); } async listAgents() { return this.sendRequest('agents.list', {}); } async listDeals() { return this.sendRequest('deals.list', {}); } async createDeal(deal) { return this.sendRequest('deals.create', deal); } async submitAction(agentId, action, data) { return this.sendRequest('agents.action', { agentId, action, data }); } async getAgentLogs(agentId, options = {}) { return this.sendRequest('agents.logs', { agentId, ...options }); } async sendRequest(method, params) { if (!this.connected || !this.ws) { throw new Error('Not connected to hub'); } return new Promise((resolve, reject) => { const requestId = this.generateRequestId(); const message = { id: requestId, method, params }; const timeout = setTimeout(() => { reject(new Error('Request timeout')); }, 30000); const handleResponse = (event) => { try { const response = JSON.parse(event.data?.toString() || event.toString()); if (response.id === requestId) { clearTimeout(timeout); this.ws?.removeEventListener('message', handleResponse); if (response.error) { reject(new Error(response.error.message || 'Hub request failed')); } else { resolve(response.result); } } } catch (error) { // Ignore parse errors for non-response messages } }; this.ws.addEventListener('message', handleResponse); this.ws.send(JSON.stringify(message)); }); } handleHubEvent(event) { this.emit('hubEvent', event); eventBus.publish(event); switch (event.type) { case 'agent.started': case 'agent.stopped': case 'agent.error': this.emit('agentEvent', event); break; case 'deal.created': case 'deal.updated': case 'deal.completed': this.emit('dealEvent', event); break; case 'metric.recorded': this.emit('metricEvent', event); break; } } startHeartbeat() { if (this.heartbeatTimer) { clearInterval(this.heartbeatTimer); } this.heartbeatTimer = setInterval(() => { if (this.connected && this.ws) { this.ws.ping(); } }, this.config.heartbeatInterval); } stopHeartbeat() { if (this.heartbeatTimer) { clearInterval(this.heartbeatTimer); this.heartbeatTimer = undefined; } } scheduleReconnect() { this.reconnectAttempts++; const delay = Math.min(1000 * Math.pow(2, this.reconnectAttempts), 30000); setTimeout(() => { this.connect().catch(() => { // Reconnection failed, will try again if attempts remain }); }, delay); } generateRequestId() { return `req_${Date.now()}_${Math.random().toString(36).substring(2)}`; } isConnected() { return this.connected; } getConnectionStatus() { return { connected: this.connected, url: this.config.url, reconnectAttempts: this.reconnectAttempts }; } } //# sourceMappingURL=hubAdapter.js.map