UNPKG

@graphteon/juricode

Version:

We are forging the future with lines of digital steel

147 lines 5.5 kB
import { io } from 'socket.io-client'; import OpenHands from './open-hands'; import { getConfig } from '../utils/config'; export class WSClient { constructor(baseUrl) { this.baseUrl = baseUrl; this.socket = null; this.messageHandlers = []; this.errorHandlers = []; this.stateHandlers = []; this.connectHandlers = []; this.lastEventId = -1; const config = getConfig(); this.baseUrl = baseUrl || config.websocketUrl || config.baseUrl; } async connect(conversationId) { if (this.socket) { this.socket.close(); } this.lastEventId = -1; try { const conversation = await OpenHands.getConversation(conversationId); if (conversation) { OpenHands.setCurrentConversation(conversation); } } catch (error) { console.warn('Could not set current conversation:', error); } const headers = OpenHands.getConversationHeaders(); const authHeaders = {}; if (headers.get('X-Session-API-Key')) { authHeaders['X-Session-API-Key'] = headers.get('X-Session-API-Key'); } const socketUrl = (this.baseUrl || 'http://localhost:13000').replace(/\/api$/, ''); this.socket = io(socketUrl, { transports: ['websocket', 'polling'], query: { latest_event_id: this.lastEventId, conversation_id: conversationId }, extraHeaders: authHeaders, timeout: 10000, forceNew: true }); this.socket.on('connect', () => { console.log(`✅ WebSocket connected to ${socketUrl}`); this.connectHandlers.forEach(handler => handler()); }); this.socket.on('oh_event', (event) => { const eventId = parseInt(event.id); if (!isNaN(eventId)) { this.lastEventId = eventId; } if (event.type === 'message' || (event.action === 'message' && (event.source === 'user' || event.source === 'agent'))) { const formattedEvent = { ...event, type: 'message', message: event.message || event.args?.content || '' }; this.messageHandlers.forEach(handler => handler(formattedEvent)); } else if (event.type === 'status' && event.status === 'error') { const error = new Error(event.message || 'Unknown error'); this.errorHandlers.forEach(handler => handler(error)); } else if (event.observation === 'agent_state_changed') { const state = event.extras?.agent_state; if (state) { console.log(`🔄 Agent state changed: ${state}`); this.stateHandlers.forEach(handler => handler(state)); } } else if (event.source === 'agent') { let message = ''; if (event.args?.thought) { message = event.args.thought; } else if (event.action === 'run' && event.args?.command) { message = `Running command: ${event.args.command}`; } else if (event.observation === 'run' && event.content) { message = event.message; if (event.content && event.content.trim()) { message += '\n\n```\n' + event.content + '\n```'; } } else if (event.message || event.content || event.args?.content) { message = event.message || event.content || event.args?.content || ''; } if (message) { const formattedEvent = { ...event, type: 'message', message }; this.messageHandlers.forEach(handler => handler(formattedEvent)); } } }); this.socket.on('connect_error', (error) => { console.log(`❌ WebSocket connection error: ${error.message}`); console.log(` Attempted URL: ${socketUrl}`); this.errorHandlers.forEach(handler => handler(error)); }); this.socket.on('disconnect', () => { setTimeout(() => { if (this.socket) { this.socket.connect(); } }, 1000); }); } onConnect(handler) { this.connectHandlers.push(handler); } onMessage(handler) { this.messageHandlers.push(handler); } onError(handler) { this.errorHandlers.push(handler); } onStateChange(handler) { this.stateHandlers.push(handler); } send(message) { if (!this.socket) { throw new Error('WebSocket is not connected'); } this.socket.emit('oh_action', { action: 'message', args: { content: message, image_urls: [], timestamp: new Date().toISOString() } }); } disconnect() { if (this.socket) { this.socket.disconnect(); this.socket = null; } } } //# sourceMappingURL=ws-client.js.map