import { io } from 'socket.io-client' import { request, getApiKey } from '../client' // ─── Types ────────────────────────────────────────────────── export interface RoomInfo { id: string name: string inviteCode: string | null triggerTokens?: number maxHistoryTokens?: number tailMessageCount?: number totalTokens?: number } export interface RoomAgent { id: string roomId: string agentId: string profile: string name: string description: string invited: number } export interface ChatMessage { id: string roomId: string senderId: string senderName: string content: string timestamp: number } export interface MemberInfo { id: string userId: string name: string description: string joinedAt: number } export interface JoinResult { roomId: string roomName: string members: MemberInfo[] messages: ChatMessage[] rooms: string[] } // ─── Socket.IO Client ────────────────────────────────────── let socket: ReturnType | null = null export function connectGroupChat(opts?: { userId?: string; userName?: string; description?: string }): ReturnType { if (socket?.connected) return socket const token = getApiKey() const userId = opts?.userId || localStorage.getItem('gc_user_id') || generateUUID() localStorage.setItem('gc_user_id', userId) socket = io('/group-chat', { auth: { token: token || undefined, userId, name: opts?.userName || localStorage.getItem('gc_user_name') || undefined, description: opts?.description || localStorage.getItem('gc_user_description') || undefined, }, transports: ['websocket'], reconnection: true, reconnectionAttempts: Infinity, reconnectionDelay: 1000, reconnectionDelayMax: 30000, }) return socket } export function getStoredUserId(): string { let id = localStorage.getItem('gc_user_id') if (!id) { id = generateUUID() localStorage.setItem('gc_user_id', id) } return id } export function getStoredUserName(): string | null { return localStorage.getItem('gc_user_name') } function generateUUID(): string { return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, (c) => { const r = Math.random() * 16 | 0 const v = c === 'x' ? r : (r & 0x3 | 0x8) return v.toString(16) }) } export function getSocket(): ReturnType | null { return socket?.connected ? socket : null } export function disconnectGroupChat(): void { if (socket) { socket.disconnect() socket = null } } // ─── REST API ─────────────────────────────────────────────── export async function createRoom(data: { name: string inviteCode: string agents?: { profile: string; name?: string; description?: string; invited?: boolean }[] compression?: { triggerTokens?: number; maxHistoryTokens?: number; tailMessageCount?: number } }): Promise<{ room: RoomInfo; agents: RoomAgent[] }> { return request('/api/hermes/group-chat/rooms', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify(data), }) } export async function listRooms(): Promise<{ rooms: RoomInfo[] }> { return request('/api/hermes/group-chat/rooms') } export async function getRoomDetail(roomId: string): Promise<{ room: RoomInfo; messages: ChatMessage[]; agents: RoomAgent[]; members: MemberInfo[] }> { return request(`/api/hermes/group-chat/rooms/${roomId}`) } export async function joinRoomByCode(code: string): Promise<{ room: RoomInfo }> { return request(`/api/hermes/group-chat/rooms/join/${code}`) } export async function updateInviteCode(roomId: string, inviteCode: string): Promise { return request(`/api/hermes/group-chat/rooms/${roomId}/invite-code`, { method: 'PUT', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ inviteCode }), }) } export async function addAgent(roomId: string, data: { profile: string name?: string description?: string invited?: boolean }): Promise<{ agent: RoomAgent }> { return request(`/api/hermes/group-chat/rooms/${roomId}/agents`, { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify(data), }) } export async function listAgents(roomId: string): Promise<{ agents: RoomAgent[] }> { return request(`/api/hermes/group-chat/rooms/${roomId}/agents`) } export async function removeAgent(roomId: string, agentId: string): Promise { return request(`/api/hermes/group-chat/rooms/${roomId}/agents/${agentId}`, { method: 'DELETE', }) } export async function deleteRoom(roomId: string): Promise { return request(`/api/hermes/group-chat/rooms/${roomId}`, { method: 'DELETE', }) } export async function updateRoomConfig(roomId: string, config: { triggerTokens?: number; maxHistoryTokens?: number; tailMessageCount?: number }): Promise<{ room: RoomInfo }> { return request(`/api/hermes/group-chat/rooms/${roomId}/config`, { method: 'PUT', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify(config), }) } export async function forceCompress(roomId: string): Promise<{ success: boolean; summary: string }> { return request(`/api/hermes/group-chat/rooms/${roomId}/compress`, { method: 'POST', }) }