hermes-web-ui 0.3.8 → 0.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +7 -10
- package/dist/client/assets/{Add-s316k4Av.js → Add-BChxDDdy.js} +1 -1
- package/dist/client/assets/{Button-BkA_RI8a.js → Button-uvjCWO-i.js} +1 -1
- package/dist/client/assets/{ChannelsView-DPmPn8DW.js → ChannelsView-D3a0g0rb.js} +1 -1
- package/dist/client/assets/{ChatView-DEtziOPB.js → ChatView-T8LH7dwU.js} +1 -1
- package/dist/client/assets/{Close-CrLD0IXG.js → Close-DbXijZpL.js} +1 -1
- package/dist/client/assets/{FormItem-CQLdFrl9.js → FormItem-BRiLD3TC.js} +1 -1
- package/dist/client/assets/{GatewaysView-CC1Y0tZZ.js → GatewaysView-rfzh1nqy.js} +1 -1
- package/dist/client/assets/{Input-nXKlujwJ.js → Input-CjlUbV0M.js} +1 -1
- package/dist/client/assets/{InputNumber-DLZwwIyX.js → InputNumber-CPEjoOAv.js} +1 -1
- package/dist/client/assets/{JobsView-BC0bBrJO.js → JobsView-D6AFr9Xe.js} +2 -2
- package/dist/client/assets/{LoginView-PqpFR9bV.js → LoginView-DJB_TSHN.js} +1 -1
- package/dist/client/assets/{LogsView-DtR88N0b.js → LogsView-Ul8pAp42.js} +1 -1
- package/dist/client/assets/{MarkdownRenderer-BSLfTurm.js → MarkdownRenderer-CY7d2L7Z.js} +1 -1
- package/dist/client/assets/{MemoryView-CJRWnePL.js → MemoryView-BR5Dl_fa.js} +1 -1
- package/dist/client/assets/{Modal-Bp9RK8LZ.js → Modal-DDUFP8vh.js} +1 -1
- package/dist/client/assets/{ModelsView-7Obe34Cz.js → ModelsView-DAi9Jdmk.js} +1 -1
- package/dist/client/assets/{Popconfirm-DTdUi7r_.js → Popconfirm-Cnb_uQVo.js} +1 -1
- package/dist/client/assets/{Popover-_M3o0B7L.js → Popover-DiVI0l6E.js} +1 -1
- package/dist/client/assets/{ProfilesView-1_GmRx-S.js → ProfilesView-BB0Zrfhi.js} +1 -1
- package/dist/client/assets/{Select-aHPR3urY.js → Select-BqUA1wxE.js} +1 -1
- package/dist/client/assets/{SettingRow-DKasLuS5.js → SettingRow-CK0bHtaz.js} +1 -1
- package/dist/client/assets/{SettingsView-DZCA7_CM.js → SettingsView-BKKk44FG.js} +1 -1
- package/dist/client/assets/{SkillsView-Dk7O05cK.js → SkillsView-whSlyc23.js} +1 -1
- package/dist/client/assets/{Spin-Bt_9cTiO.js → Spin-DwHJdgNz.js} +1 -1
- package/dist/client/assets/{Suffix-XaH8SDbR.js → Suffix-D6x-7akR.js} +1 -1
- package/dist/client/assets/{Switch-D1_psmjT.js → Switch-BvHRSSqt.js} +1 -1
- package/dist/client/assets/{Tag-3FaOhoJN.js → Tag-BMMlXaEi.js} +1 -1
- package/dist/client/assets/{TerminalView-DNU7oQxK.js → TerminalView-el6o2Q0a.js} +1 -1
- package/dist/client/assets/{Tooltip-YHrHWGPa.js → Tooltip-BM4wl764.js} +1 -1
- package/dist/client/assets/{UsageView-COCrOiiV.js → UsageView-DQ_YKoEV.js} +1 -1
- package/dist/client/assets/{Warning-B6CM9aBl.js → Warning-CEC7rgvY.js} +1 -1
- package/dist/client/assets/{_plugin-vue_export-helper-BGG8ORDx.js → _plugin-vue_export-helper-DgUZPfuZ.js} +1 -1
- package/dist/client/assets/app-DPUhLGXq.js +1 -0
- package/dist/client/assets/{app-B7ktf7Fh.js → app-DUt8TNq3.js} +1 -1
- package/dist/client/assets/{browser-f5W8abIG.js → browser-vxCOMmsq.js} +1 -1
- package/dist/client/assets/{chat-6q6pkzEW.js → chat-i_Ge_Lfr.js} +2 -2
- package/dist/client/assets/composables-jrQPIjcq.js +1 -0
- package/dist/client/assets/{fade-in.cssr-ifHK7yH1.js → fade-in.cssr-DVg2CkO3.js} +1 -1
- package/dist/client/assets/{index-CSCYx7ux.js → index-COwJ2oY0.js} +1 -1
- package/dist/client/assets/{jobs-DObWfhbO.js → jobs-Czr1RcSG.js} +1 -1
- package/dist/client/assets/{light-DgLcPjgU.js → light-3rSjNeC-.js} +1 -1
- package/dist/client/assets/{light-CxjyoF0s.js → light-CKDlpgGU.js} +1 -1
- package/dist/client/assets/{light-D1yfed_s.js → light-CiIDFs7y.js} +1 -1
- package/dist/client/assets/{light-TGFKT-UB.js → light-CoJqT8Vu.js} +1 -1
- package/dist/client/assets/{light-D_3MwJj1.js → light-DPRJ1OEN.js} +1 -1
- package/dist/client/assets/{light-DWy-mwyK.js → light-vTpJevRf.js} +1 -1
- package/dist/client/assets/{models-DQ4CT-vv.js → models-BzEeJuoO.js} +1 -1
- package/dist/client/assets/{pinia-DcAkZ8vx.js → pinia-BoNLlsLy.js} +1 -1
- package/dist/client/assets/{profiles-DzkigJwq.js → profiles-B-DFTmc2.js} +1 -1
- package/dist/client/assets/{router-D8sJ39Io.js → router-HHMeDEaP.js} +2 -2
- package/dist/client/assets/{sessions-Dg8n9PBo.js → sessions-BmxS_BoH.js} +1 -1
- package/dist/client/assets/{skills-BehzdECn.js → skills-Be8Mzr1r.js} +1 -1
- package/dist/client/assets/{use-message-DBz2JSTt.js → use-message-DBTY4945.js} +1 -1
- package/dist/client/assets/{useTheme-UdVT814n.js → useTheme-D58Cg7k2.js} +1 -1
- package/dist/client/index.html +27 -27
- package/dist/server/index.js +19 -199
- package/dist/server/routes/health.d.ts +4 -0
- package/dist/server/routes/health.js +109 -0
- package/dist/server/routes/hermes/group-chat.d.ts +2 -0
- package/dist/server/routes/hermes/group-chat.js +112 -101
- package/dist/server/routes/update.d.ts +2 -0
- package/dist/server/routes/update.js +69 -0
- package/dist/server/services/auth.js +1 -1
- package/dist/server/services/gateway-bootstrap.d.ts +2 -0
- package/dist/server/services/gateway-bootstrap.js +51 -0
- package/dist/server/services/hermes/group-chat/agent-clients.d.ts +133 -0
- package/dist/server/services/hermes/group-chat/agent-clients.js +364 -0
- package/dist/server/services/hermes/group-chat/index.d.ts +72 -0
- package/dist/server/services/hermes/group-chat/index.js +307 -0
- package/dist/server/services/shutdown.d.ts +1 -0
- package/dist/server/services/shutdown.js +37 -0
- package/package.json +1 -1
- package/dist/client/assets/app-BPvTl2-V.js +0 -1
- package/dist/client/assets/composables-xV7dhNpf.js +0 -1
|
@@ -0,0 +1,364 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.AgentClients = void 0;
|
|
4
|
+
const socket_io_client_1 = require("socket.io-client");
|
|
5
|
+
const auth_1 = require("../../auth");
|
|
6
|
+
// ─── Agent Client (single connection) ─────────────────────────
|
|
7
|
+
class AgentClient {
|
|
8
|
+
agentId;
|
|
9
|
+
profile;
|
|
10
|
+
name;
|
|
11
|
+
socket = null;
|
|
12
|
+
joinedRooms = new Set();
|
|
13
|
+
handlers;
|
|
14
|
+
port = 8648;
|
|
15
|
+
_reconnecting = false;
|
|
16
|
+
gatewayManager = null;
|
|
17
|
+
constructor(config, handlers = {}) {
|
|
18
|
+
this.agentId = Date.now().toString(36) + Math.random().toString(36).slice(2, 8);
|
|
19
|
+
this.profile = config.profile;
|
|
20
|
+
this.name = config.name;
|
|
21
|
+
this.handlers = handlers;
|
|
22
|
+
}
|
|
23
|
+
get connected() {
|
|
24
|
+
return this.socket?.connected ?? false;
|
|
25
|
+
}
|
|
26
|
+
get id() {
|
|
27
|
+
return this.socket?.id;
|
|
28
|
+
}
|
|
29
|
+
setGatewayManager(manager) {
|
|
30
|
+
this.gatewayManager = manager;
|
|
31
|
+
}
|
|
32
|
+
async connect(port = 8648) {
|
|
33
|
+
this.port = port;
|
|
34
|
+
const token = await (0, auth_1.getToken)();
|
|
35
|
+
this.socket = (0, socket_io_client_1.io)(`http://127.0.0.1:${port}/api/hermes/group-chat`, {
|
|
36
|
+
auth: {
|
|
37
|
+
token: token || undefined,
|
|
38
|
+
name: this.name,
|
|
39
|
+
},
|
|
40
|
+
transports: ['websocket'],
|
|
41
|
+
reconnection: true,
|
|
42
|
+
reconnectionAttempts: Infinity,
|
|
43
|
+
reconnectionDelay: 1000,
|
|
44
|
+
reconnectionDelayMax: 30000,
|
|
45
|
+
});
|
|
46
|
+
this.bindEvents();
|
|
47
|
+
return new Promise((resolve, reject) => {
|
|
48
|
+
const timeout = setTimeout(() => reject(new Error('Connection timeout')), 10000);
|
|
49
|
+
this.socket.on('connect', () => {
|
|
50
|
+
clearTimeout(timeout);
|
|
51
|
+
resolve();
|
|
52
|
+
});
|
|
53
|
+
this.socket.on('connect_error', (err) => {
|
|
54
|
+
clearTimeout(timeout);
|
|
55
|
+
reject(err);
|
|
56
|
+
});
|
|
57
|
+
});
|
|
58
|
+
}
|
|
59
|
+
disconnect() {
|
|
60
|
+
if (this.socket) {
|
|
61
|
+
this.socket.disconnect();
|
|
62
|
+
this.socket = null;
|
|
63
|
+
this.joinedRooms.clear();
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
async joinRoom(roomId) {
|
|
67
|
+
this.ensureConnected();
|
|
68
|
+
return new Promise((resolve, reject) => {
|
|
69
|
+
this.socket.emit('join', { roomId }, (res) => {
|
|
70
|
+
if ('error' in res) {
|
|
71
|
+
reject(new Error(res.error));
|
|
72
|
+
}
|
|
73
|
+
else {
|
|
74
|
+
this.joinedRooms.add(roomId);
|
|
75
|
+
resolve(res);
|
|
76
|
+
}
|
|
77
|
+
});
|
|
78
|
+
});
|
|
79
|
+
}
|
|
80
|
+
sendMessage(roomId, content) {
|
|
81
|
+
this.ensureConnected();
|
|
82
|
+
return new Promise((resolve, reject) => {
|
|
83
|
+
this.socket.emit('message', { roomId, content }, (res) => {
|
|
84
|
+
if (res.error) {
|
|
85
|
+
reject(new Error(res.error));
|
|
86
|
+
}
|
|
87
|
+
else {
|
|
88
|
+
resolve(res.id);
|
|
89
|
+
}
|
|
90
|
+
});
|
|
91
|
+
});
|
|
92
|
+
}
|
|
93
|
+
startTyping(roomId) {
|
|
94
|
+
this.ensureConnected();
|
|
95
|
+
this.socket.emit('typing', { roomId });
|
|
96
|
+
}
|
|
97
|
+
stopTyping(roomId) {
|
|
98
|
+
this.ensureConnected();
|
|
99
|
+
this.socket.emit('stop_typing', { roomId });
|
|
100
|
+
}
|
|
101
|
+
getJoinedRooms() {
|
|
102
|
+
return Array.from(this.joinedRooms);
|
|
103
|
+
}
|
|
104
|
+
async deleteSession(upstream, apiKey, runId) {
|
|
105
|
+
try {
|
|
106
|
+
await fetch(`${upstream}/v1/sessions/${runId}`, {
|
|
107
|
+
method: 'DELETE',
|
|
108
|
+
headers: {
|
|
109
|
+
...(apiKey ? { Authorization: `Bearer ${apiKey}` } : {}),
|
|
110
|
+
},
|
|
111
|
+
signal: AbortSignal.timeout(10000),
|
|
112
|
+
});
|
|
113
|
+
}
|
|
114
|
+
catch (err) {
|
|
115
|
+
console.warn(`[AgentClients] ${this.name}: failed to delete session ${runId}: ${err.message}`);
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
ensureConnected() {
|
|
119
|
+
if (!this.socket?.connected) {
|
|
120
|
+
throw new Error(`Agent "${this.name}" is not connected`);
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
// ─── Hermes Gateway Integration ────────────────────────────
|
|
124
|
+
/**
|
|
125
|
+
* Forward a user message to Hermes gateway and stream the reply back to the room.
|
|
126
|
+
*/
|
|
127
|
+
async handleUserMessage(roomId, msg) {
|
|
128
|
+
if (!this.gatewayManager)
|
|
129
|
+
return;
|
|
130
|
+
// Ignore own messages and messages mentioning own name
|
|
131
|
+
if (msg.senderId === this.socket?.id)
|
|
132
|
+
return;
|
|
133
|
+
if (!msg.content.toLowerCase().includes(`@${this.name.toLowerCase()}`))
|
|
134
|
+
return;
|
|
135
|
+
const upstream = this.gatewayManager.getUpstream(this.profile);
|
|
136
|
+
const apiKey = this.gatewayManager.getApiKey(this.profile);
|
|
137
|
+
if (!upstream) {
|
|
138
|
+
console.error(`[AgentClients] ${this.name}: no gateway upstream for profile "${this.profile}"`);
|
|
139
|
+
return;
|
|
140
|
+
}
|
|
141
|
+
try {
|
|
142
|
+
// Notify room that agent is typing
|
|
143
|
+
this.startTyping(roomId);
|
|
144
|
+
// Generate unique session_id per agent per interaction
|
|
145
|
+
const sessionId = Date.now().toString(36) + Math.random().toString(36).slice(2, 8);
|
|
146
|
+
// Start a run on Hermes gateway
|
|
147
|
+
const runRes = await fetch(`${upstream}/v1/runs`, {
|
|
148
|
+
method: 'POST',
|
|
149
|
+
headers: {
|
|
150
|
+
'Content-Type': 'application/json',
|
|
151
|
+
...(apiKey ? { Authorization: `Bearer ${apiKey}` } : {}),
|
|
152
|
+
},
|
|
153
|
+
body: JSON.stringify({
|
|
154
|
+
input: msg.content,
|
|
155
|
+
session_id: sessionId,
|
|
156
|
+
}),
|
|
157
|
+
signal: AbortSignal.timeout(120000),
|
|
158
|
+
});
|
|
159
|
+
if (!runRes.ok) {
|
|
160
|
+
const text = await runRes.text().catch(() => '');
|
|
161
|
+
console.error(`[AgentClients] ${this.name}: gateway run failed (${runRes.status}): ${text}`);
|
|
162
|
+
this.stopTyping(roomId);
|
|
163
|
+
return;
|
|
164
|
+
}
|
|
165
|
+
const { run_id } = await runRes.json();
|
|
166
|
+
if (!run_id) {
|
|
167
|
+
this.stopTyping(roomId);
|
|
168
|
+
return;
|
|
169
|
+
}
|
|
170
|
+
// Stream events from Hermes
|
|
171
|
+
const eventsUrl = new URL(`${upstream}/v1/runs/${run_id}/events`);
|
|
172
|
+
if (apiKey)
|
|
173
|
+
eventsUrl.searchParams.set('token', apiKey);
|
|
174
|
+
const source = new EventSource(eventsUrl.toString());
|
|
175
|
+
let fullContent = '';
|
|
176
|
+
source.onmessage = (e) => {
|
|
177
|
+
try {
|
|
178
|
+
const parsed = JSON.parse(e.data);
|
|
179
|
+
if (parsed.event === 'run.completed') {
|
|
180
|
+
source.close();
|
|
181
|
+
if (fullContent) {
|
|
182
|
+
this.stopTyping(roomId);
|
|
183
|
+
this.sendMessage(roomId, fullContent);
|
|
184
|
+
}
|
|
185
|
+
this.deleteSession(upstream, apiKey, sessionId).catch(() => { });
|
|
186
|
+
return;
|
|
187
|
+
}
|
|
188
|
+
if (parsed.event === 'run.failed') {
|
|
189
|
+
source.close();
|
|
190
|
+
this.stopTyping(roomId);
|
|
191
|
+
this.deleteSession(upstream, apiKey, sessionId).catch(() => { });
|
|
192
|
+
return;
|
|
193
|
+
}
|
|
194
|
+
// Accumulate message deltas
|
|
195
|
+
if (parsed.event === 'message' && parsed.delta) {
|
|
196
|
+
fullContent += parsed.delta;
|
|
197
|
+
}
|
|
198
|
+
}
|
|
199
|
+
catch {
|
|
200
|
+
// ignore parse errors
|
|
201
|
+
}
|
|
202
|
+
};
|
|
203
|
+
source.onerror = () => {
|
|
204
|
+
source.close();
|
|
205
|
+
this.stopTyping(roomId);
|
|
206
|
+
};
|
|
207
|
+
}
|
|
208
|
+
catch (err) {
|
|
209
|
+
console.error(`[AgentClients] ${this.name}: error handling message: ${err.message}`);
|
|
210
|
+
this.stopTyping(roomId);
|
|
211
|
+
}
|
|
212
|
+
}
|
|
213
|
+
bindEvents() {
|
|
214
|
+
const s = this.socket;
|
|
215
|
+
s.on('message', (msg) => {
|
|
216
|
+
// Forward to Hermes gateway for AI response
|
|
217
|
+
this.handleUserMessage(msg.roomId, msg).catch((err) => {
|
|
218
|
+
console.error(`[AgentClients] ${this.name}: handleUserMessage error: ${err.message}`);
|
|
219
|
+
});
|
|
220
|
+
// Also notify external handlers
|
|
221
|
+
this.handlers.onMessage?.({ roomId: msg.roomId, msg });
|
|
222
|
+
});
|
|
223
|
+
s.on('typing', (data) => {
|
|
224
|
+
this.handlers.onTyping?.(data);
|
|
225
|
+
});
|
|
226
|
+
s.on('stop_typing', (data) => {
|
|
227
|
+
this.handlers.onStopTyping?.(data);
|
|
228
|
+
});
|
|
229
|
+
s.on('member_joined', (data) => {
|
|
230
|
+
this.handlers.onMemberJoined?.(data);
|
|
231
|
+
});
|
|
232
|
+
s.on('member_left', (data) => {
|
|
233
|
+
this.handlers.onMemberLeft?.(data);
|
|
234
|
+
});
|
|
235
|
+
// Auto rejoin rooms on reconnect
|
|
236
|
+
s.io.on('reconnect', async () => {
|
|
237
|
+
if (this._reconnecting)
|
|
238
|
+
return;
|
|
239
|
+
this._reconnecting = true;
|
|
240
|
+
console.log(`[AgentClients] ${this.name} reconnecting, rejoining ${this.joinedRooms.size} rooms...`);
|
|
241
|
+
const rooms = Array.from(this.joinedRooms);
|
|
242
|
+
for (const roomId of rooms) {
|
|
243
|
+
try {
|
|
244
|
+
await this.joinRoom(roomId);
|
|
245
|
+
}
|
|
246
|
+
catch (err) {
|
|
247
|
+
console.error(`[AgentClients] ${this.name} failed to rejoin room ${roomId}: ${err.message}`);
|
|
248
|
+
}
|
|
249
|
+
}
|
|
250
|
+
this._reconnecting = false;
|
|
251
|
+
});
|
|
252
|
+
}
|
|
253
|
+
}
|
|
254
|
+
// ─── AgentClients (roomId -> agents) ──────────────────────────
|
|
255
|
+
class AgentClients {
|
|
256
|
+
rooms = new Map();
|
|
257
|
+
/**
|
|
258
|
+
* Create an agent client and connect it to the server.
|
|
259
|
+
* The agent will NOT auto-join any room — call addAgentToRoom separately.
|
|
260
|
+
*/
|
|
261
|
+
async createAgent(config, handlers, port) {
|
|
262
|
+
const client = new AgentClient(config, handlers);
|
|
263
|
+
await client.connect(port);
|
|
264
|
+
console.log(`[AgentClients] Connected: ${client.name} (${client.agentId})`);
|
|
265
|
+
return client;
|
|
266
|
+
}
|
|
267
|
+
/**
|
|
268
|
+
* Connect an agent to a room.
|
|
269
|
+
*/
|
|
270
|
+
async addAgentToRoom(roomId, client) {
|
|
271
|
+
let room = this.rooms.get(roomId);
|
|
272
|
+
if (!room) {
|
|
273
|
+
room = new Map();
|
|
274
|
+
this.rooms.set(roomId, room);
|
|
275
|
+
}
|
|
276
|
+
room.set(client.agentId, client);
|
|
277
|
+
const result = await client.joinRoom(roomId);
|
|
278
|
+
console.log(`[AgentClients] ${client.name} joined room: ${roomId}`);
|
|
279
|
+
return result;
|
|
280
|
+
}
|
|
281
|
+
/**
|
|
282
|
+
* Remove an agent from a room and disconnect it.
|
|
283
|
+
*/
|
|
284
|
+
removeAgentFromRoom(roomId, agentId) {
|
|
285
|
+
const room = this.rooms.get(roomId);
|
|
286
|
+
if (!room)
|
|
287
|
+
return;
|
|
288
|
+
const client = room.get(agentId);
|
|
289
|
+
if (client) {
|
|
290
|
+
client.disconnect();
|
|
291
|
+
room.delete(agentId);
|
|
292
|
+
console.log(`[AgentClients] ${client.name} left room: ${roomId}`);
|
|
293
|
+
}
|
|
294
|
+
if (room.size === 0) {
|
|
295
|
+
this.rooms.delete(roomId);
|
|
296
|
+
}
|
|
297
|
+
}
|
|
298
|
+
/**
|
|
299
|
+
* Get all agents in a room.
|
|
300
|
+
*/
|
|
301
|
+
getAgents(roomId) {
|
|
302
|
+
const room = this.rooms.get(roomId);
|
|
303
|
+
return room ? Array.from(room.values()) : [];
|
|
304
|
+
}
|
|
305
|
+
/**
|
|
306
|
+
* Get a specific agent in a room.
|
|
307
|
+
*/
|
|
308
|
+
getAgent(roomId, agentId) {
|
|
309
|
+
return this.rooms.get(roomId)?.get(agentId);
|
|
310
|
+
}
|
|
311
|
+
/**
|
|
312
|
+
* Get all room IDs that have agents.
|
|
313
|
+
*/
|
|
314
|
+
getRoomIds() {
|
|
315
|
+
return Array.from(this.rooms.keys());
|
|
316
|
+
}
|
|
317
|
+
/**
|
|
318
|
+
* Send a message from a specific agent in a room.
|
|
319
|
+
*/
|
|
320
|
+
async sendMessage(roomId, agentId, content) {
|
|
321
|
+
const client = this.getAgent(roomId, agentId);
|
|
322
|
+
if (!client) {
|
|
323
|
+
throw new Error(`Agent "${agentId}" not found in room "${roomId}"`);
|
|
324
|
+
}
|
|
325
|
+
return client.sendMessage(roomId, content);
|
|
326
|
+
}
|
|
327
|
+
/**
|
|
328
|
+
* Broadcast a message from all agents in a room.
|
|
329
|
+
*/
|
|
330
|
+
async broadcastFromRoom(roomId, content) {
|
|
331
|
+
const agents = this.getAgents(roomId);
|
|
332
|
+
return Promise.all(agents.map((agent) => agent.sendMessage(roomId, content)));
|
|
333
|
+
}
|
|
334
|
+
/**
|
|
335
|
+
* Disconnect all agents in a room.
|
|
336
|
+
*/
|
|
337
|
+
disconnectRoom(roomId) {
|
|
338
|
+
const room = this.rooms.get(roomId);
|
|
339
|
+
if (!room)
|
|
340
|
+
return;
|
|
341
|
+
room.forEach((client) => client.disconnect());
|
|
342
|
+
this.rooms.delete(roomId);
|
|
343
|
+
console.log(`[AgentClients] All agents disconnected from room: ${roomId}`);
|
|
344
|
+
}
|
|
345
|
+
/**
|
|
346
|
+
* Disconnect all agents in all rooms.
|
|
347
|
+
*/
|
|
348
|
+
disconnectAll() {
|
|
349
|
+
this.rooms.forEach((room) => {
|
|
350
|
+
room.forEach((client) => client.disconnect());
|
|
351
|
+
});
|
|
352
|
+
this.rooms.clear();
|
|
353
|
+
console.log('[AgentClients] All agents disconnected');
|
|
354
|
+
}
|
|
355
|
+
/**
|
|
356
|
+
* Set gateway manager for all existing and future agents.
|
|
357
|
+
*/
|
|
358
|
+
setGatewayManager(manager) {
|
|
359
|
+
this.rooms.forEach((room) => {
|
|
360
|
+
room.forEach((client) => client.setGatewayManager(manager));
|
|
361
|
+
});
|
|
362
|
+
}
|
|
363
|
+
}
|
|
364
|
+
exports.AgentClients = AgentClients;
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
import { Server } from 'socket.io';
|
|
2
|
+
import type { Server as HttpServer } from 'http';
|
|
3
|
+
import { AgentClients } from './agent-clients';
|
|
4
|
+
interface ChatMessage {
|
|
5
|
+
id: string;
|
|
6
|
+
roomId: string;
|
|
7
|
+
senderId: string;
|
|
8
|
+
senderName: string;
|
|
9
|
+
content: string;
|
|
10
|
+
timestamp: number;
|
|
11
|
+
}
|
|
12
|
+
interface RoomAgent {
|
|
13
|
+
id: string;
|
|
14
|
+
roomId: string;
|
|
15
|
+
agentId: string;
|
|
16
|
+
profile: string;
|
|
17
|
+
name: string;
|
|
18
|
+
description: string;
|
|
19
|
+
invited: number;
|
|
20
|
+
}
|
|
21
|
+
declare class ChatStorage {
|
|
22
|
+
private db;
|
|
23
|
+
constructor(dbPath: string);
|
|
24
|
+
getRoom(roomId: string): {
|
|
25
|
+
id: string;
|
|
26
|
+
name: string;
|
|
27
|
+
inviteCode: string | null;
|
|
28
|
+
} | undefined;
|
|
29
|
+
getRoomByInviteCode(code: string): {
|
|
30
|
+
id: string;
|
|
31
|
+
name: string;
|
|
32
|
+
inviteCode: string | null;
|
|
33
|
+
} | undefined;
|
|
34
|
+
getAllRooms(): {
|
|
35
|
+
id: string;
|
|
36
|
+
name: string;
|
|
37
|
+
inviteCode: string | null;
|
|
38
|
+
}[];
|
|
39
|
+
saveRoom(id: string, name: string, inviteCode?: string): void;
|
|
40
|
+
updateRoomInviteCode(roomId: string, inviteCode: string): void;
|
|
41
|
+
getMessages(roomId: string, limit?: number): ChatMessage[];
|
|
42
|
+
addMessage(msg: ChatMessage): void;
|
|
43
|
+
pruneMessages(roomId: string, keep?: number): void;
|
|
44
|
+
getRoomAgents(roomId: string): RoomAgent[];
|
|
45
|
+
addRoomAgent(roomId: string, agentId: string, profile: string, name: string, description: string, invited: number): RoomAgent;
|
|
46
|
+
removeRoomAgent(agentId: string): void;
|
|
47
|
+
close(): void;
|
|
48
|
+
}
|
|
49
|
+
export declare class GroupChatServer {
|
|
50
|
+
private io;
|
|
51
|
+
private storage;
|
|
52
|
+
private rooms;
|
|
53
|
+
private userNames;
|
|
54
|
+
readonly agentClients: AgentClients;
|
|
55
|
+
private gatewayManager;
|
|
56
|
+
setGatewayManager(manager: any): void;
|
|
57
|
+
constructor(httpServer: HttpServer);
|
|
58
|
+
getIO(): Server;
|
|
59
|
+
getStorage(): ChatStorage;
|
|
60
|
+
getRoomIds(): string[];
|
|
61
|
+
private restoreAgents;
|
|
62
|
+
private authMiddleware;
|
|
63
|
+
private onConnection;
|
|
64
|
+
private handleJoin;
|
|
65
|
+
private handleMessage;
|
|
66
|
+
private handleTyping;
|
|
67
|
+
private handleStopTyping;
|
|
68
|
+
private handleDisconnect;
|
|
69
|
+
private leaveAllRooms;
|
|
70
|
+
private generateId;
|
|
71
|
+
}
|
|
72
|
+
export {};
|