agentgui 1.0.793 → 1.0.795

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.
Files changed (2) hide show
  1. package/package.json +1 -1
  2. package/server.js +22 -21
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "agentgui",
3
- "version": "1.0.793",
3
+ "version": "1.0.795",
4
4
  "description": "Multi-agent ACP client with real-time communication",
5
5
  "type": "module",
6
6
  "main": "electron/main.js",
package/server.js CHANGED
@@ -8,6 +8,7 @@ import { WebSocketServer } from 'ws';
8
8
  import { execSync, spawn } from 'child_process';
9
9
  import { LRUCache } from 'lru-cache';
10
10
  import { createRequire } from 'module';
11
+ import crypto from 'crypto';
11
12
  const PKG_VERSION = JSON.parse(fs.readFileSync(new URL('./package.json', import.meta.url), 'utf8')).version;
12
13
  import express from 'express';
13
14
  import Busboy from 'busboy';
@@ -59,20 +60,7 @@ process.on('unhandledRejection', (reason, promise) => {
59
60
  if (reason instanceof Error) console.error(reason.stack);
60
61
  });
61
62
 
62
- function gracefulShutdown(signal) {
63
- console.log(`[SIGNAL] ${signal} received - graceful shutdown`);
64
- try { pm2Manager.disconnect(); } catch (_) {}
65
- if (jsonlWatcher) try { jsonlWatcher.stop(); } catch (_) {}
66
- for (const [convId, entry] of activeExecutions) {
67
- try { if (entry.pid) process.kill(entry.pid, 'SIGTERM'); } catch (_) {}
68
- }
69
- stopACPTools().catch(() => {}).finally(() => {
70
- try { wss.close(() => server.close(() => process.exit(0))); } catch (_) { process.exit(0); }
71
- setTimeout(() => process.exit(1), 5000);
72
- });
73
- }
74
- process.on('SIGINT', () => gracefulShutdown('SIGINT'));
75
- process.on('SIGTERM', () => gracefulShutdown('SIGTERM'));
63
+ // Signal handlers registered after server initialization (see bottom of file)
76
64
  process.on('SIGHUP', () => { console.log('[SIGNAL] SIGHUP received (ignored - uncrashable)'); });
77
65
  process.on('beforeExit', (code) => { console.log('[PROCESS] beforeExit with code:', code); });
78
66
  process.on('exit', (code) => { console.log('[PROCESS] exit with code:', code); });
@@ -469,7 +457,7 @@ const server = http.createServer(async (req, res) => {
469
457
  try {
470
458
  const _decoded = Buffer.from(_auth.slice(6), 'base64').toString('utf8');
471
459
  const _ci = _decoded.indexOf(':');
472
- if (_ci !== -1) _ok = _decoded.slice(_ci + 1) === _pwd;
460
+ if (_ci !== -1) { const _p = _decoded.slice(_ci + 1); try { _ok = _p.length === _pwd.length && crypto.timingSafeEqual(Buffer.from(_p), Buffer.from(_pwd)); } catch { _ok = false; } }
473
461
  } catch (_) {}
474
462
  }
475
463
  if (!_ok) {
@@ -1966,10 +1954,21 @@ async function processMessageWithStreaming(conversationId, messageId, sessionId,
1966
1954
  }
1967
1955
 
1968
1956
  // Set flag to stop processing and trigger retry
1969
- rateLimitState.set(conversationId, {
1970
- retryAt: Date.now() + (retryAfterSec * 1000),
1971
- cooldownMs: retryAfterSec * 1000,
1972
- retryCount: 0,
1957
+ const existingRetryCount = rateLimitState.get(conversationId)?.retryCount || 0;
1958
+ if (existingRetryCount >= 3) {
1959
+ debugLog(`[rate-limit] Conv ${conversationId} stream rate limit hit ${existingRetryCount + 1} times, giving up`);
1960
+ batcher.drain();
1961
+ activeExecutions.delete(conversationId);
1962
+ queries.setIsStreaming(conversationId, false);
1963
+ const errorMessage = queries.createMessage(conversationId, 'assistant', `Error: Rate limit exceeded after ${existingRetryCount + 1} attempts. Please try again later.`);
1964
+ broadcastSync({ type: 'message_created', conversationId, message: errorMessage, timestamp: Date.now() });
1965
+ broadcastSync({ type: 'streaming_complete', sessionId, conversationId, interrupted: true, timestamp: Date.now() });
1966
+ return;
1967
+ }
1968
+ rateLimitState.set(conversationId, {
1969
+ retryAt: Date.now() + (retryAfterSec * 1000),
1970
+ cooldownMs: retryAfterSec * 1000,
1971
+ retryCount: existingRetryCount + 1,
1973
1972
  isStreamDetected: true
1974
1973
  });
1975
1974
 
@@ -2543,7 +2542,7 @@ wss.on('connection', (ws, req) => {
2543
2542
 
2544
2543
  const BROADCAST_TYPES = new Set([
2545
2544
  'message_created', 'conversation_created', 'conversation_updated',
2546
- 'conversations_updated', 'conversation_deleted', 'all_conversations_deleted', 'queue_status', 'queue_updated',
2545
+ 'conversations_updated', 'conversation_deleted', 'all_conversations_deleted', 'queue_status', 'queue_updated', 'queue_item_dequeued',
2547
2546
  'rate_limit_hit', 'rate_limit_clear',
2548
2547
  'script_started', 'script_stopped', 'script_output',
2549
2548
  'model_download_progress', 'stt_progress', 'tts_setup_progress', 'voice_list',
@@ -2938,10 +2937,12 @@ function killActiveExecutions() {
2938
2937
 
2939
2938
  process.on('SIGTERM', () => {
2940
2939
  console.log('[SIGNAL] SIGTERM received - graceful shutdown');
2941
- if (!watch) killActiveExecutions();
2940
+ killActiveExecutions();
2941
+ if (jsonlWatcher) try { jsonlWatcher.stop(); } catch (_) {}
2942
2942
  try { pm2Manager.disconnect(); } catch (_) {}
2943
2943
  stopACPTools().catch(() => {}).finally(() => {
2944
2944
  try { wss.close(() => server.close(() => process.exit(0))); } catch (_) { process.exit(0); }
2945
+ setTimeout(() => process.exit(1), 5000);
2945
2946
  });
2946
2947
  });
2947
2948