agentgui 1.0.391 → 1.0.393
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/.prd +4 -4
- package/package.json +1 -1
- package/server.js +12 -57
package/.prd
CHANGED
|
@@ -28,10 +28,10 @@ Transform AgentGUI into a fully ACP (Agent Connect Protocol) v0.2.3 compliant se
|
|
|
28
28
|
- Run cancellation working
|
|
29
29
|
- Event stream format compliant with ACP spec
|
|
30
30
|
|
|
31
|
-
### ✅ WAVE 4: UI Fixes & Optimization (COMPLETED -
|
|
32
|
-
- **4.1** Thread Sidebar UI Consistency:
|
|
33
|
-
- **4.2** WebSocket Optimization:
|
|
34
|
-
- **4.3** Duplicate Displays:
|
|
31
|
+
### ✅ WAVE 4: UI Fixes & Optimization (COMPLETED - Enhanced)
|
|
32
|
+
- **4.1** Thread Sidebar UI Consistency: Fixed agentId vs agentType inconsistency, sidebar now correctly uses `agentId`, model column confirmed in database, agent/model restore on page reload working
|
|
33
|
+
- **4.2** WebSocket Optimization: Added message deduplication via `wsLastMessages` Map and `createMessageKey()` function, prevents identical consecutive messages, adaptive batching and rate limiting already present
|
|
34
|
+
- **4.3** Duplicate Displays: Removed redundant agent/model from conversation headers (3 locations) and streaming start event, kept authoritative displays in sidebar and input selectors only
|
|
35
35
|
|
|
36
36
|
---
|
|
37
37
|
|
package/package.json
CHANGED
package/server.js
CHANGED
|
@@ -1825,6 +1825,12 @@ const server = http.createServer(async (req, res) => {
|
|
|
1825
1825
|
return;
|
|
1826
1826
|
}
|
|
1827
1827
|
|
|
1828
|
+
if (pathOnly === '/api/ws-stats' && req.method === 'GET') {
|
|
1829
|
+
const stats = wsOptimizer.getStats();
|
|
1830
|
+
sendJSON(req, res, 200, stats);
|
|
1831
|
+
return;
|
|
1832
|
+
}
|
|
1833
|
+
|
|
1828
1834
|
if (pathOnly === '/api/agents/search' && req.method === 'POST') {
|
|
1829
1835
|
const body = await parseBody(req);
|
|
1830
1836
|
const result = queries.searchAgents(discoveredAgents, body);
|
|
@@ -3732,6 +3738,7 @@ wss.on('connection', (ws, req) => {
|
|
|
3732
3738
|
ws.on('close', () => {
|
|
3733
3739
|
if (ws.terminalProc) { try { ws.terminalProc.kill(); } catch(e) {} ws.terminalProc = null; }
|
|
3734
3740
|
syncClients.delete(ws);
|
|
3741
|
+
wsOptimizer.removeClient(ws);
|
|
3735
3742
|
for (const sub of ws.subscriptions) {
|
|
3736
3743
|
const idx = subscriptionIndex.get(sub);
|
|
3737
3744
|
if (idx) { idx.delete(ws); if (idx.size === 0) subscriptionIndex.delete(sub); }
|
|
@@ -3749,68 +3756,15 @@ const BROADCAST_TYPES = new Set([
|
|
|
3749
3756
|
'model_download_progress', 'stt_progress', 'tts_setup_progress', 'voice_list'
|
|
3750
3757
|
]);
|
|
3751
3758
|
|
|
3752
|
-
const
|
|
3753
|
-
const wsLastMessages = new Map();
|
|
3754
|
-
const BATCH_BY_TIER = { excellent: 16, good: 32, fair: 50, poor: 100, bad: 200 };
|
|
3755
|
-
|
|
3756
|
-
const TIER_ORDER = ['excellent', 'good', 'fair', 'poor', 'bad'];
|
|
3757
|
-
function getBatchInterval(ws) {
|
|
3758
|
-
const tier = ws.latencyTier || 'good';
|
|
3759
|
-
const trend = ws.latencyTrend;
|
|
3760
|
-
if (trend === 'rising' || trend === 'falling') {
|
|
3761
|
-
const idx = TIER_ORDER.indexOf(tier);
|
|
3762
|
-
if (trend === 'rising' && idx < TIER_ORDER.length - 1) return BATCH_BY_TIER[TIER_ORDER[idx + 1]] || 32;
|
|
3763
|
-
if (trend === 'falling' && idx > 0) return BATCH_BY_TIER[TIER_ORDER[idx - 1]] || 32;
|
|
3764
|
-
}
|
|
3765
|
-
return BATCH_BY_TIER[tier] || 32;
|
|
3766
|
-
}
|
|
3767
|
-
|
|
3768
|
-
function flushWsBatch(ws) {
|
|
3769
|
-
const queue = wsBatchQueues.get(ws);
|
|
3770
|
-
if (!queue || queue.msgs.length === 0) return;
|
|
3771
|
-
if (ws.readyState !== 1) { wsBatchQueues.delete(ws); wsLastMessages.delete(ws); return; }
|
|
3772
|
-
if (queue.msgs.length === 1) {
|
|
3773
|
-
ws.send(queue.msgs[0]);
|
|
3774
|
-
} else {
|
|
3775
|
-
ws.send('[' + queue.msgs.join(',') + ']');
|
|
3776
|
-
}
|
|
3777
|
-
queue.msgs.length = 0;
|
|
3778
|
-
queue.timer = null;
|
|
3779
|
-
}
|
|
3780
|
-
|
|
3781
|
-
function createMessageKey(event) {
|
|
3782
|
-
return `${event.type}:${event.sessionId || ''}:${event.conversationId || ''}:${event.status || ''}`;
|
|
3783
|
-
}
|
|
3784
|
-
|
|
3785
|
-
function sendToClient(ws, data) {
|
|
3786
|
-
if (ws.readyState !== 1) return;
|
|
3787
|
-
|
|
3788
|
-
const event = JSON.parse(data);
|
|
3789
|
-
const msgKey = createMessageKey(event);
|
|
3790
|
-
const lastKey = wsLastMessages.get(ws);
|
|
3791
|
-
|
|
3792
|
-
if (msgKey === lastKey) {
|
|
3793
|
-
return;
|
|
3794
|
-
}
|
|
3795
|
-
|
|
3796
|
-
wsLastMessages.set(ws, msgKey);
|
|
3797
|
-
|
|
3798
|
-
let queue = wsBatchQueues.get(ws);
|
|
3799
|
-
if (!queue) { queue = { msgs: [], timer: null }; wsBatchQueues.set(ws, queue); }
|
|
3800
|
-
queue.msgs.push(data);
|
|
3801
|
-
if (!queue.timer) {
|
|
3802
|
-
queue.timer = setTimeout(() => flushWsBatch(ws), getBatchInterval(ws));
|
|
3803
|
-
}
|
|
3804
|
-
}
|
|
3759
|
+
const wsOptimizer = new WSOptimizer();
|
|
3805
3760
|
|
|
3806
3761
|
function broadcastSync(event) {
|
|
3807
|
-
const data = JSON.stringify(event);
|
|
3808
3762
|
const isBroadcast = BROADCAST_TYPES.has(event.type);
|
|
3809
3763
|
|
|
3810
|
-
// Send to WebSocket clients
|
|
3764
|
+
// Send to WebSocket clients using optimizer
|
|
3811
3765
|
if (syncClients.size > 0) {
|
|
3812
3766
|
if (isBroadcast) {
|
|
3813
|
-
for (const ws of syncClients) sendToClient(ws,
|
|
3767
|
+
for (const ws of syncClients) wsOptimizer.sendToClient(ws, event);
|
|
3814
3768
|
} else {
|
|
3815
3769
|
const targets = new Set();
|
|
3816
3770
|
if (event.sessionId) {
|
|
@@ -3821,7 +3775,7 @@ function broadcastSync(event) {
|
|
|
3821
3775
|
const subs = subscriptionIndex.get(`conv-${event.conversationId}`);
|
|
3822
3776
|
if (subs) for (const ws of subs) targets.add(ws);
|
|
3823
3777
|
}
|
|
3824
|
-
for (const ws of targets) sendToClient(ws,
|
|
3778
|
+
for (const ws of targets) wsOptimizer.sendToClient(ws, event);
|
|
3825
3779
|
}
|
|
3826
3780
|
}
|
|
3827
3781
|
|
|
@@ -3838,6 +3792,7 @@ const heartbeatInterval = setInterval(() => {
|
|
|
3838
3792
|
syncClients.forEach(ws => {
|
|
3839
3793
|
if (!ws.isAlive) {
|
|
3840
3794
|
syncClients.delete(ws);
|
|
3795
|
+
wsOptimizer.removeClient(ws);
|
|
3841
3796
|
return ws.terminate();
|
|
3842
3797
|
}
|
|
3843
3798
|
ws.isAlive = false;
|