/** * Gateway Server * Central server for managing channels and message routing */ import { getChannelManager } from '../channels'; import { BaseChannel } from '../channels/base'; import { getMessageBus } from '../bus'; import { getSessionManager } from '../session'; import { initializeHeartbeat } from '../heartbeat'; import { AgentLoop } from '../agent/loop'; import { logger } from '../utils/logger'; import { getConfig } from '../config'; import { ChannelMessage } from '../types'; export class GatewayServer { private channelManager: ReturnType; private messageBus: ReturnType; private heartbeat: ReturnType | null; private isRunning: boolean; constructor() { this.channelManager = getChannelManager(); this.messageBus = getMessageBus(); this.heartbeat = null; this.isRunning = false; } /** * Register an external channel for message routing */ registerChannel(channel: BaseChannel): void { this.channelManager.registerChannel(channel); logger.info(`Channel registered: ${channel.getChannelType()}`); } /** * Initialize the gateway */ async initialize(): Promise { logger.info('Initializing gateway server...'); void getSessionManager(); logger.info('Session manager initialized'); const config = getConfig(); this.messageBus.subscribeAll(async (message: ChannelMessage) => { await this.handleMessage(message); }); if (config.agents?.defaults?.systemPrompt) { this.heartbeat = initializeHeartbeat({ enabled: false, interval: 60000, onBeat: async () => logger.debug('Heartbeat tick'), }); } logger.info('Gateway initialized'); } async start(): Promise { if (this.isRunning) { logger.warn('Gateway is already running'); return; } await this.initialize(); await this.channelManager.startAll(); if (this.heartbeat) { this.heartbeat.start(); } this.isRunning = true; logger.info('Gateway server started successfully'); } async stop(): Promise { if (!this.isRunning) { logger.warn('Gateway is not running'); return; } logger.info('Stopping gateway server...'); if (this.heartbeat) { this.heartbeat.stop(); } await this.channelManager.stopAll(); this.messageBus.clear(); this.isRunning = false; logger.info('Gateway server stopped'); } private async handleMessage(message: ChannelMessage): Promise { logger.info(`Handling message from ${message.channelType} (user: ${message.userId})`); try { const sessionManager = await getSessionManager(); await sessionManager.getOrCreateSession( message.sessionId, message.userId, message.channelType ); const config = getConfig(); const agentLoop = new AgentLoop(message.sessionId, config); const result = await agentLoop.processMessage(message.content); await this.channelManager.sendMessage( message.channelType, message.userId, result.content, message.metadata ); logger.info(`Response sent to ${message.userId} via ${message.channelType}`); } catch (error) { logger.error('Error handling message', error); try { await this.channelManager.sendMessage( message.channelType, message.userId, 'Sorry, I encountered an error processing your message. Please try again.', message.metadata ); } catch (sendError) { logger.error('Failed to send error message', sendError); } } } getStatus(): { running: boolean; channels: Record; heartbeat: unknown; } { return { running: this.isRunning, channels: this.channelManager.getAllChannelStatuses(), heartbeat: this.heartbeat ? this.heartbeat.getStatus() : null, }; } } let gateway: GatewayServer | null = null; export function getGateway(): GatewayServer { if (!gateway) { gateway = new GatewayServer(); } return gateway; }