agentgui 1.0.799 → 1.0.800

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.
@@ -14,14 +14,38 @@ export function initSpeechManager({ broadcastSync, syncClients, queries }) {
14
14
  _queries = queries;
15
15
  }
16
16
 
17
+ export function isSpeechInstalled() {
18
+ try {
19
+ const r = createRequire(import.meta.url);
20
+ r.resolve('webtalk/speech');
21
+ return true;
22
+ } catch (_) { return false; }
23
+ }
24
+
17
25
  export async function ensurePocketTtsSetup(onProgress) {
18
26
  const r = createRequire(import.meta.url);
19
- const serverTTS = r('webtalk/server-tts');
20
- return serverTTS.ensureInstalled(onProgress);
27
+ try {
28
+ const serverTTS = r('webtalk/server-tts');
29
+ return serverTTS.ensureInstalled(onProgress);
30
+ } catch (err) {
31
+ if (err.code === 'MODULE_NOT_FOUND' || err.code === 'SPEECH_NOT_INSTALLED') return false;
32
+ throw err;
33
+ }
21
34
  }
22
35
 
23
36
  export async function getSpeech() {
24
- if (!speechModule) speechModule = await import('./speech.js');
37
+ if (!speechModule) {
38
+ try {
39
+ speechModule = await import('./speech.js');
40
+ } catch (err) {
41
+ if (err.code === 'MODULE_NOT_FOUND' || err.code === 'SPEECH_NOT_INSTALLED') {
42
+ const e = new Error('speech_not_installed: Install Speech Engine from the Tools tab.');
43
+ e.code = 'SPEECH_NOT_INSTALLED';
44
+ throw e;
45
+ }
46
+ throw err;
47
+ }
48
+ }
25
49
  return speechModule;
26
50
  }
27
51
 
@@ -116,6 +140,10 @@ async function validateAndCleanupModels(modelsDir) {
116
140
  }
117
141
 
118
142
  export async function ensureModelsDownloaded() {
143
+ if (!isSpeechInstalled()) {
144
+ console.log('[MODELS] Speech Engine not installed, skipping model download.');
145
+ return false;
146
+ }
119
147
  if (modelDownloadState.downloading) {
120
148
  return new Promise(resolve => { modelDownloadState.waiters.push(resolve); });
121
149
  }
package/lib/speech.js CHANGED
@@ -1,50 +1,67 @@
1
- import { createRequire } from 'module';
2
- const require = createRequire(import.meta.url);
3
- const speech = require('webtalk/speech');
4
-
5
- const ttsMemCache = new Map();
6
- const TTS_CACHE_MAX_BYTES = 10 * 1024 * 1024;
7
- let ttsCacheBytes = 0;
8
-
9
- function ttsCacheKey(text, voiceId) {
10
- return (voiceId || 'default') + ':' + text;
11
- }
12
-
13
- function ttsCacheGet(key) {
14
- return ttsMemCache.get(key) || null;
15
- }
16
-
17
- function ttsCacheSet(key, wav) {
18
- if (ttsMemCache.has(key)) return;
19
- const size = wav ? wav.length : 0;
20
- while (ttsCacheBytes + size > TTS_CACHE_MAX_BYTES && ttsMemCache.size > 0) {
21
- const oldest = ttsMemCache.keys().next().value;
22
- const old = ttsMemCache.get(oldest);
23
- ttsCacheBytes -= old ? old.length : 0;
24
- ttsMemCache.delete(oldest);
25
- }
26
- ttsMemCache.set(key, wav);
27
- ttsCacheBytes += size;
28
- }
29
-
30
- async function synthesizeWithCache(text, voiceId) {
31
- const key = ttsCacheKey(text, voiceId);
32
- const cached = ttsCacheGet(key);
33
- if (cached) return cached;
34
- const wav = await speech.synthesize(text, voiceId);
35
- ttsCacheSet(key, wav);
36
- return wav;
37
- }
38
-
39
- export const transcribe = speech.transcribe;
40
- export const synthesize = synthesizeWithCache;
41
- export const synthesizeStream = speech.synthesizeStream;
42
- export const getSTT = speech.getSTT;
43
- export const getStatus = speech.getStatus;
44
- export const getVoices = speech.getVoices;
45
- export const preloadTTS = speech.preloadTTS;
46
- export { ttsCacheKey, ttsCacheGet, ttsCacheSet };
47
- export const resetSTTError = speech.resetSTTError;
48
- export const clearCorruptedSTTCache = speech.clearCorruptedSTTCache;
49
- export const getSttOptions = speech.getSttOptions;
50
- export const VOICE_DIRS = speech.VOICE_DIRS;
1
+ import { createRequire } from 'module';
2
+
3
+ const _require = createRequire(import.meta.url);
4
+ const ttsMemCache = new Map();
5
+ const TTS_CACHE_MAX_BYTES = 10 * 1024 * 1024;
6
+ let ttsCacheBytes = 0;
7
+ let _speech = null;
8
+
9
+ function loadSpeech() {
10
+ if (_speech) return _speech;
11
+ try {
12
+ _speech = _require('webtalk/speech');
13
+ return _speech;
14
+ } catch (err) {
15
+ const e = new Error('speech_not_installed: Install Speech Engine from the Tools tab.');
16
+ e.code = 'SPEECH_NOT_INSTALLED';
17
+ throw e;
18
+ }
19
+ }
20
+
21
+ export function ttsCacheKey(text, voiceId) {
22
+ return (voiceId || 'default') + ':' + text;
23
+ }
24
+
25
+ export function ttsCacheGet(key) {
26
+ return ttsMemCache.get(key) || null;
27
+ }
28
+
29
+ export function ttsCacheSet(key, wav) {
30
+ if (ttsMemCache.has(key)) return;
31
+ const size = wav ? wav.length : 0;
32
+ while (ttsCacheBytes + size > TTS_CACHE_MAX_BYTES && ttsMemCache.size > 0) {
33
+ const oldest = ttsMemCache.keys().next().value;
34
+ const old = ttsMemCache.get(oldest);
35
+ ttsCacheBytes -= old ? old.length : 0;
36
+ ttsMemCache.delete(oldest);
37
+ }
38
+ ttsMemCache.set(key, wav);
39
+ ttsCacheBytes += size;
40
+ }
41
+
42
+ export async function transcribe(...args) { return loadSpeech().transcribe(...args); }
43
+
44
+ export async function synthesize(text, voiceId) {
45
+ const key = ttsCacheKey(text, voiceId);
46
+ const cached = ttsCacheGet(key);
47
+ if (cached) return cached;
48
+ const wav = await loadSpeech().synthesize(text, voiceId);
49
+ ttsCacheSet(key, wav);
50
+ return wav;
51
+ }
52
+
53
+ export async function synthesizeStream(...args) { return loadSpeech().synthesizeStream(...args); }
54
+ export function getSTT() { return loadSpeech().getSTT(); }
55
+ export function getStatus() {
56
+ try { return loadSpeech().getStatus(); }
57
+ catch (_) { return { sttReady: false, ttsReady: false, sttLoading: false, ttsLoading: false, speechNotInstalled: true }; }
58
+ }
59
+ export function getVoices() {
60
+ try { return loadSpeech().getVoices(); }
61
+ catch (_) { return []; }
62
+ }
63
+ export function preloadTTS() { try { loadSpeech().preloadTTS?.(); } catch (_) {} }
64
+ export function resetSTTError() { try { loadSpeech().resetSTTError?.(); } catch (_) {} }
65
+ export function clearCorruptedSTTCache() { try { return loadSpeech().clearCorruptedSTTCache?.(); } catch (_) {} }
66
+ export function getSttOptions() { try { return loadSpeech().getSttOptions?.(); } catch (_) { return {}; } }
67
+ export const VOICE_DIRS = (() => { try { return loadSpeech().VOICE_DIRS; } catch (_) { return []; } })();
@@ -3,6 +3,7 @@ import { createInstaller } from './tool-spawner.js';
3
3
  import { autoProvision as _autoProvision, startPeriodicUpdateCheck as _startPeriodicUpdateCheck, stopPeriodicUpdateCheck } from './tool-provisioner.js';
4
4
 
5
5
  const TOOLS = [
6
+ { id: 'speech-engine', name: 'Speech Engine', pkg: 'webtalk', category: 'npm-local', description: 'STT/TTS support (Whisper + ONNX)' },
6
7
  { id: 'cli-claude', name: 'Claude Code', pkg: '@anthropic-ai/claude-code', category: 'cli' },
7
8
  { id: 'cli-opencode', name: 'OpenCode', pkg: 'opencode-ai', category: 'cli' },
8
9
  { id: 'cli-gemini', name: 'Gemini CLI', pkg: '@google/gemini-cli', category: 'cli' },
@@ -1,5 +1,7 @@
1
1
  import { spawn } from 'child_process';
2
2
  import os from 'os';
3
+ import path from 'path';
4
+ import { fileURLToPath } from 'url';
3
5
  import { getCliVersion, getInstalledVersion, clearVersionCache, checkToolViaBunx } from './tool-version.js';
4
6
  import * as toolInstallMachine from './tool-install-machine.js';
5
7
 
@@ -73,8 +75,33 @@ const spawnBunxProc = (pkg, onProgress) => new Promise((resolve) => {
73
75
  });
74
76
  });
75
77
 
78
+ const spawnNpmLocalInstall = (pkg, onProgress) => new Promise((resolve) => {
79
+ const cmd = isWindows ? 'npm.cmd' : 'npm';
80
+ let completed = false, stderr = '', stdout = '';
81
+ let proc;
82
+ const rootDir = path.dirname(path.dirname(fileURLToPath(import.meta.url)));
83
+ try {
84
+ proc = spawn(cmd, ['install', '--save', pkg], { stdio: ['pipe', 'pipe', 'pipe'], timeout: 300000, shell: isWindows, windowsHide: true, cwd: rootDir });
85
+ } catch (err) {
86
+ return resolve({ success: false, error: `Failed to spawn npm install: ${err.message}` });
87
+ }
88
+ if (!proc) return resolve({ success: false, error: 'Failed to spawn npm process' });
89
+ const timer = setTimeout(() => { if (!completed) { completed = true; try { proc.kill('SIGKILL'); } catch (_) {} resolve({ success: false, error: 'Timeout (5min)' }); } }, 300000);
90
+ const onData = (d) => { if (onProgress) onProgress({ type: 'progress', data: d.toString() }); };
91
+ if (proc.stdout) proc.stdout.on('data', (d) => { stdout += d.toString(); onData(d); });
92
+ if (proc.stderr) proc.stderr.on('data', (d) => { stderr += d.toString(); onData(d); });
93
+ proc.on('close', (code) => {
94
+ clearTimeout(timer);
95
+ if (completed) return;
96
+ completed = true;
97
+ resolve(code === 0 ? { success: true, error: null, pkg } : { success: false, error: (stdout + stderr).substring(0, 1000) || 'Failed' });
98
+ });
99
+ proc.on('error', (err) => { clearTimeout(timer); if (!completed) { completed = true; resolve({ success: false, error: err.message }); } });
100
+ });
101
+
76
102
  function spawnForTool(tool, onProgress) {
77
103
  const pkg = tool.installPkg || tool.pkg;
104
+ if (tool.category === 'npm-local') return spawnNpmLocalInstall(pkg, onProgress);
78
105
  return tool.category === 'cli' ? spawnNpmInstall(pkg, onProgress) : spawnBunxProc(pkg, onProgress);
79
106
  }
80
107
 
@@ -216,11 +216,26 @@ export function clearVersionCache() {
216
216
  versionCache.clear();
217
217
  }
218
218
 
219
+ const ROOT_DIR = path.dirname(new URL(import.meta.url).pathname).replace(/\/lib$/, '');
220
+
221
+ export function checkNpmLocalInstalled(pkg) {
222
+ return fs.existsSync(path.join(ROOT_DIR, 'node_modules', pkg, 'package.json'));
223
+ }
224
+
225
+ export function getNpmLocalVersion(pkg) {
226
+ try {
227
+ const p = path.join(ROOT_DIR, 'node_modules', pkg, 'package.json');
228
+ if (fs.existsSync(p)) return JSON.parse(fs.readFileSync(p, 'utf8')).version;
229
+ } catch (_) {}
230
+ return null;
231
+ }
232
+
219
233
  export async function checkToolViaBunx(pkg, pluginId = null, category = 'plugin', frameWork = null, skipPublishedVersion = false, tools = []) {
220
234
  try {
235
+ const isNpmLocal = category === 'npm-local';
221
236
  const isCli = category === 'cli';
222
- const installed = isCli ? checkCliInstalled(pkg) : checkToolInstalled(pluginId || pkg, frameWork);
223
- const installedVersion = isCli ? getCliVersion(pkg) : getInstalledVersion(pkg, pluginId, frameWork, tools);
237
+ const installed = isNpmLocal ? checkNpmLocalInstalled(pkg) : isCli ? checkCliInstalled(pkg) : checkToolInstalled(pluginId || pkg, frameWork);
238
+ const installedVersion = isNpmLocal ? getNpmLocalVersion(pkg) : isCli ? getCliVersion(pkg) : getInstalledVersion(pkg, pluginId, frameWork, tools);
224
239
  let publishedVersion = null;
225
240
  if (!skipPublishedVersion) {
226
241
  publishedVersion = await fetchPublishedVersion(pkg);
@@ -230,9 +245,10 @@ export async function checkToolViaBunx(pkg, pluginId = null, category = 'plugin'
230
245
  return { installed, isUpToDate, upgradeNeeded: needsUpdate, output: 'version-check', installedVersion, publishedVersion };
231
246
  } catch (err) {
232
247
  console.log(`[tool-manager] Error checking ${pkg}:`, err.message);
248
+ const isNpmLocal = category === 'npm-local';
233
249
  const isCli = category === 'cli';
234
- const installed = isCli ? checkCliInstalled(pkg) : checkToolInstalled(pluginId || pkg, frameWork);
235
- const installedVersion = isCli ? getCliVersion(pkg) : getInstalledVersion(pkg, pluginId, frameWork, tools);
250
+ const installed = isNpmLocal ? checkNpmLocalInstalled(pkg) : isCli ? checkCliInstalled(pkg) : checkToolInstalled(pluginId || pkg, frameWork);
251
+ const installedVersion = isNpmLocal ? getNpmLocalVersion(pkg) : isCli ? getCliVersion(pkg) : getInstalledVersion(pkg, pluginId, frameWork, tools);
236
252
  return { installed, isUpToDate: false, upgradeNeeded: false, output: '', installedVersion, publishedVersion: null };
237
253
  }
238
254
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "agentgui",
3
- "version": "1.0.799",
3
+ "version": "1.0.800",
4
4
  "description": "Multi-agent ACP client with real-time communication",
5
5
  "type": "module",
6
6
  "main": "electron/main.js",
@@ -24,11 +24,6 @@
24
24
  },
25
25
  "dependencies": {
26
26
  "@agentclientprotocol/sdk": "^0.4.1",
27
- "@anthropic-ai/claude-code": "^2.1.37",
28
- "@google/gemini-cli": "latest",
29
- "@huggingface/transformers": "^3.8.1",
30
- "@kilocode/cli": "latest",
31
- "audio-decode": "^2.2.3",
32
27
  "better-sqlite3": "^12.6.2",
33
28
  "busboy": "^1.6.0",
34
29
  "execa": "^9.6.1",
@@ -38,13 +33,9 @@
38
33
  "google-auth-library": "^10.5.0",
39
34
  "lru-cache": "^11.2.7",
40
35
  "msgpackr": "^1.11.8",
41
- "onnxruntime-node": "1.21.0",
42
- "opencode-ai": "^1.2.15",
43
36
  "p-retry": "^7.1.1",
44
37
  "pm2": "^5.4.3",
45
- "puppeteer-core": "^24.37.5",
46
38
  "webjsx": "^0.0.73",
47
- "webtalk": "^1.0.31",
48
39
  "ws": "^8.14.2",
49
40
  "xstate": "^5.28.0",
50
41
  "zod": "^4.3.6"
@@ -52,12 +43,6 @@
52
43
  "optionalDependencies": {
53
44
  "node-pty": "^1.0.0"
54
45
  },
55
- "overrides": {
56
- "onnxruntime-web": "npm:empty-npm-package@1.0.0",
57
- "sharp": "npm:empty-npm-package@1.0.0",
58
- "onnxruntime-common": "1.21.0",
59
- "onnxruntime-node": "1.21.0"
60
- },
61
46
  "devDependencies": {
62
47
  "electron": "^35.0.0"
63
48
  }