agentgui 1.0.775 → 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.775",
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
@@ -86,7 +86,6 @@ function buildSystemPrompt(agentId, model, subAgent) {
86
86
  }
87
87
  if (model) parts.push(`Model: ${model}.`);
88
88
  if (subAgent) parts.push(`Subagent: ${subAgent}.`);
89
- parts.push('Be concise. Minimize unnecessary tool calls. Read files before editing. Prefer targeted searches over broad exploration.');
90
89
  return parts.join(' ');
91
90
  }
92
91
 
@@ -144,10 +143,13 @@ function cleanupExecution(conversationId, broadcastCompletion = false) {
144
143
  const __dirname = path.dirname(fileURLToPath(import.meta.url));
145
144
  const rootDir = process.env.PORTABLE_EXE_DIR || __dirname;
146
145
  const PORT = process.env.PORT || 3000;
147
- const BASE_URL = (process.env.BASE_URL || '/gm').replace(/\/+$/, '');
146
+ const BASE_URL = (process.env.BASE_URL || '/gm').replace(/\/+/g, '/').replace(/\/+$/, '');
148
147
  const watch = process.argv.includes('--no-watch') ? false : (process.argv.includes('--watch') || process.env.HOT_RELOAD !== 'false');
149
148
 
150
- 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
+ })();
151
153
  const staticDir = path.join(rootDir, 'static');
152
154
  if (!fs.existsSync(staticDir)) fs.mkdirSync(staticDir, { recursive: true });
153
155
 
@@ -655,7 +657,7 @@ const server = http.createServer(async (req, res) => {
655
657
  sendJSON(req, res, 200, { message: userMessage, session, streamId: session.id });
656
658
 
657
659
  processMessageWithStreaming(conversationId, userMessage.id, session.id, prompt, agentId, model, subAgent)
658
- .catch(err => debugLog(`[stream] Uncaught error: ${err.message}`));
660
+ .catch(err => debugLog(`[stream] Uncaught error: ${err.stack || err.message}`));
659
661
  return;
660
662
  }
661
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);