agentgui 1.0.776 → 1.0.777

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.
@@ -65,7 +65,8 @@ export const modelDownloadState = {
65
65
  error: null,
66
66
  complete: false,
67
67
  startTime: null,
68
- downloadMetrics: new Map()
68
+ downloadMetrics: new Map(),
69
+ waiters: []
69
70
  };
70
71
 
71
72
  export function broadcastModelProgress(progress) {
@@ -116,8 +117,7 @@ async function validateAndCleanupModels(modelsDir) {
116
117
 
117
118
  export async function ensureModelsDownloaded() {
118
119
  if (modelDownloadState.downloading) {
119
- while (modelDownloadState.downloading) { await new Promise(r => setTimeout(r, 100)); }
120
- return modelDownloadState.complete;
120
+ return new Promise(resolve => { modelDownloadState.waiters.push(resolve); });
121
121
  }
122
122
  modelDownloadState.downloading = true;
123
123
  modelDownloadState.error = null;
@@ -147,6 +147,9 @@ export async function ensureModelsDownloaded() {
147
147
  return false;
148
148
  } finally {
149
149
  modelDownloadState.downloading = false;
150
+ const result = modelDownloadState.complete;
151
+ for (const resolve of modelDownloadState.waiters) resolve(result);
152
+ modelDownloadState.waiters = [];
150
153
  }
151
154
  }
152
155
 
@@ -100,9 +100,11 @@ export function createInstaller(getTool, statusCache, checkToolStatusAsync) {
100
100
  toolInstallMachine.send(toolId, { type: 'INSTALL_COMPLETE', version: fresh.version });
101
101
  return fresh;
102
102
  }
103
+ clearVersionCache();
103
104
  toolInstallMachine.send(toolId, { type: 'FAILED', error: result.error });
104
105
  return result;
105
106
  } catch (err) {
107
+ clearVersionCache();
106
108
  toolInstallMachine.send(toolId, { type: 'FAILED', error: err.message });
107
109
  return { success: false, error: err.message };
108
110
  }
@@ -122,9 +124,11 @@ export function createInstaller(getTool, statusCache, checkToolStatusAsync) {
122
124
  toolInstallMachine.send(toolId, { type: 'UPDATE_COMPLETE', version: fresh.version });
123
125
  return fresh;
124
126
  }
127
+ clearVersionCache();
125
128
  toolInstallMachine.send(toolId, { type: 'FAILED', error: result.error });
126
129
  return result;
127
130
  } catch (err) {
131
+ clearVersionCache();
128
132
  toolInstallMachine.send(toolId, { type: 'FAILED', error: err.message });
129
133
  return { success: false, error: err.message };
130
134
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "agentgui",
3
- "version": "1.0.776",
3
+ "version": "1.0.777",
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
@@ -143,10 +143,13 @@ function cleanupExecution(conversationId, broadcastCompletion = false) {
143
143
  const __dirname = path.dirname(fileURLToPath(import.meta.url));
144
144
  const rootDir = process.env.PORTABLE_EXE_DIR || __dirname;
145
145
  const PORT = process.env.PORT || 3000;
146
- const BASE_URL = (process.env.BASE_URL || '/gm').replace(/\/+$/, '');
146
+ const BASE_URL = (process.env.BASE_URL || '/gm').replace(/\/+/g, '/').replace(/\/+$/, '');
147
147
  const watch = process.argv.includes('--no-watch') ? false : (process.argv.includes('--watch') || process.env.HOT_RELOAD !== 'false');
148
148
 
149
- const STARTUP_CWD = process.env.STARTUP_CWD || process.cwd();
149
+ const STARTUP_CWD = (() => {
150
+ const cwd = process.env.STARTUP_CWD || process.cwd();
151
+ try { fs.accessSync(cwd, fs.constants.R_OK); return cwd; } catch { console.warn(`[server] STARTUP_CWD "${cwd}" not accessible, falling back to ${process.cwd()}`); return process.cwd(); }
152
+ })();
150
153
  const staticDir = path.join(rootDir, 'static');
151
154
  if (!fs.existsSync(staticDir)) fs.mkdirSync(staticDir, { recursive: true });
152
155
 
@@ -654,7 +657,7 @@ const server = http.createServer(async (req, res) => {
654
657
  sendJSON(req, res, 200, { message: userMessage, session, streamId: session.id });
655
658
 
656
659
  processMessageWithStreaming(conversationId, userMessage.id, session.id, prompt, agentId, model, subAgent)
657
- .catch(err => debugLog(`[stream] Uncaught error: ${err.message}`));
660
+ .catch(err => debugLog(`[stream] Uncaught error: ${err.stack || err.message}`));
658
661
  return;
659
662
  }
660
663
 
@@ -94,7 +94,7 @@ class AgentGUIClient {
94
94
  this._debug = typeof localStorage !== 'undefined' && localStorage.getItem('debug') === '1';
95
95
  }
96
96
 
97
- _dbg(...args) { if (this._debug) this._dbg(...args); }
97
+ _dbg(...args) { if (this._debug) console.log('[AgentGUI]', ...args); }
98
98
 
99
99
  /**
100
100
  * Initialize the client
@@ -57,8 +57,9 @@
57
57
 
58
58
  function _doSpeak(text) {
59
59
  audioChunkQueue = [];
60
- var cached = ttsAudioCache.get(selectedVoiceId + ':' + text);
61
- if (cached) { audioChunkQueue.push(cached); playNextChunk(); return; }
60
+ var cacheKey = selectedVoiceId + ':' + text;
61
+ var cached = ttsAudioCache.get(cacheKey);
62
+ if (cached) { ttsAudioCache.delete(cacheKey); ttsAudioCache.set(cacheKey, cached); audioChunkQueue.push(cached); playNextChunk(); return; }
62
63
  function stream() {
63
64
  if (!streamingSupported) { nonStream(text); return; }
64
65
  fetch(BASE + '/api/tts-stream', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ text: text, voiceId: selectedVoiceId }) })
@@ -71,6 +72,7 @@
71
72
  buf = cat(buf, res.value);
72
73
  while (buf.length >= 4) {
73
74
  var len = new DataView(buf.buffer, buf.byteOffset, 4).getUint32(0, false);
75
+ if (len > 10 * 1024 * 1024) { buf = new Uint8Array(0); if (api()) api().send({ type: 'PLAYBACK_ERROR' }); return; }
74
76
  if (buf.length < 4 + len) break;
75
77
  audioChunkQueue.push(new Blob([buf.slice(4, 4 + len)], { type: 'audio/wav' }));
76
78
  buf = buf.slice(4 + len);