agentgui 1.0.218 → 1.0.219

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/lib/speech.js CHANGED
@@ -4,7 +4,6 @@ import path from 'path';
4
4
  import os from 'os';
5
5
  import http from 'http';
6
6
  import { fileURLToPath } from 'url';
7
- import { patchWebtalkForWindows } from './webtalk-patch.js';
8
7
 
9
8
  const require = createRequire(import.meta.url);
10
9
  const __dirname = path.dirname(fileURLToPath(import.meta.url));
@@ -13,8 +12,6 @@ const ROOT = path.dirname(__dirname);
13
12
  const serverSTT = require('webtalk/server-stt');
14
13
  const serverTTS = require('webtalk/server-tts');
15
14
 
16
- patchWebtalkForWindows(serverTTS);
17
-
18
15
  const EXTRA_VOICE_DIRS = [path.join(ROOT, 'voices')];
19
16
 
20
17
  const POCKET_TTS_VOICES = [
@@ -124,14 +121,7 @@ function getStatus() {
124
121
  function preloadTTS() {
125
122
  const defaultVoice = serverTTS.findVoiceFile('custom_cleetus', EXTRA_VOICE_DIRS) || '/config/voices/cleetus.wav';
126
123
  const voicePath = fs.existsSync(defaultVoice) ? defaultVoice : null;
127
- const options = {
128
- binaryPaths: [
129
- path.join(os.homedir(), '.gmgui', 'pocket-venv', 'Scripts', 'pocket-tts.exe'),
130
- path.join(os.homedir(), '.gmgui', 'pocket-venv', 'bin', 'pocket-tts.exe'),
131
- path.join(os.homedir(), '.gmgui', 'pocket-venv', 'bin', 'pocket-tts'),
132
- ]
133
- };
134
- serverTTS.start(voicePath, options).then(ok => {
124
+ serverTTS.start(voicePath, {}).then(ok => {
135
125
  if (ok) console.log('[TTS] pocket-tts sidecar started');
136
126
  else console.log('[TTS] pocket-tts failed to start');
137
127
  }).catch(err => {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "agentgui",
3
- "version": "1.0.218",
3
+ "version": "1.0.219",
4
4
  "description": "Multi-agent ACP client with real-time communication",
5
5
  "type": "module",
6
6
  "main": "server.js",
package/server.js CHANGED
@@ -11,44 +11,17 @@ import { createRequire } from 'module';
11
11
  import { OAuth2Client } from 'google-auth-library';
12
12
  import { queries } from './database.js';
13
13
  import { runClaudeWithStreaming } from './lib/claude-runner.js';
14
- import { isSetup, install, detectPython } from './lib/windows-pocket-tts-setup.js';
15
14
  let speechModule = null;
16
15
  async function getSpeech() {
17
16
  if (!speechModule) speechModule = await import('./lib/speech.js');
18
17
  return speechModule;
19
18
  }
20
19
 
21
- const pocketTtsSetupState = { attempted: false, ready: false, error: null, inProgress: false };
22
-
23
20
  async function ensurePocketTtsSetup(onProgress) {
24
- if (pocketTtsSetupState.attempted) {
25
- return pocketTtsSetupState.ready;
26
- }
27
-
28
- if (pocketTtsSetupState.inProgress) {
29
- let waited = 0;
30
- const MAX_WAIT = 600000;
31
- while (pocketTtsSetupState.inProgress && waited < MAX_WAIT) {
32
- await new Promise(r => setTimeout(r, 100));
33
- waited += 100;
34
- }
35
- return pocketTtsSetupState.ready;
36
- }
37
-
38
- pocketTtsSetupState.inProgress = true;
39
-
40
- if (onProgress) onProgress({ step: 'detecting-python', status: 'in-progress', message: 'Detecting Python installation' });
41
-
42
- const result = await install((msg) => {
43
- if (onProgress) onProgress(msg);
44
- });
45
-
46
- pocketTtsSetupState.attempted = true;
47
- pocketTtsSetupState.ready = result.success;
48
- pocketTtsSetupState.error = result.error || null;
49
- pocketTtsSetupState.inProgress = false;
50
-
51
- return pocketTtsSetupState.ready;
21
+ const { createRequire: cr } = await import('module');
22
+ const r = cr(import.meta.url);
23
+ const serverTTS = r('webtalk/server-tts');
24
+ return serverTTS.ensureInstalled(onProgress);
52
25
  }
53
26
 
54
27
  function eagerTTS(text, conversationId, sessionId) {
@@ -1446,12 +1419,12 @@ const server = http.createServer(async (req, res) => {
1446
1419
  return;
1447
1420
  }
1448
1421
 
1449
- if (!pocketTtsSetupState.attempted && process.platform === 'win32') {
1422
+ if (process.platform === 'win32') {
1450
1423
  const setupOk = await ensurePocketTtsSetup((msg) => {
1451
1424
  broadcastSync({ type: 'tts_setup_progress', ...msg });
1452
1425
  });
1453
1426
  if (!setupOk) {
1454
- sendJSON(req, res, 503, { error: pocketTtsSetupState.error || 'pocket-tts setup failed', retryable: false });
1427
+ sendJSON(req, res, 503, { error: 'pocket-tts setup failed', retryable: false });
1455
1428
  return;
1456
1429
  }
1457
1430
 
@@ -1524,26 +1497,18 @@ const server = http.createServer(async (req, res) => {
1524
1497
  try {
1525
1498
  const { getStatus } = await getSpeech();
1526
1499
  const baseStatus = getStatus();
1527
- const pythonDetect = detectPython();
1528
- const statusWithSetup = {
1500
+ const r = createRequire(import.meta.url);
1501
+ const serverTTS = r('webtalk/server-tts');
1502
+ const pyInfo = serverTTS.detectPython();
1503
+ sendJSON(req, res, 200, {
1529
1504
  ...baseStatus,
1530
- pythonDetected: pythonDetect.found,
1531
- pythonVersion: pythonDetect.version,
1532
- pocketTtsSetup: {
1533
- ready: pocketTtsSetupState.ready,
1534
- attempted: pocketTtsSetupState.attempted,
1535
- error: pocketTtsSetupState.error,
1536
- },
1537
- setupMessage: pocketTtsSetupState.error || (pocketTtsSetupState.ready ? 'pocket-tts ready' : 'Will setup on first TTS request'),
1538
- };
1539
- sendJSON(req, res, 200, statusWithSetup);
1505
+ pythonDetected: pyInfo.found,
1506
+ pythonVersion: pyInfo.version || null,
1507
+ setupMessage: baseStatus.ttsReady ? 'pocket-tts ready' : 'Will setup on first TTS request',
1508
+ });
1540
1509
  } catch (err) {
1541
- const pythonDetect = detectPython();
1542
1510
  sendJSON(req, res, 200, {
1543
1511
  sttReady: false, ttsReady: false, sttLoading: false, ttsLoading: false,
1544
- pythonDetected: pythonDetect.found,
1545
- pythonVersion: pythonDetect.version,
1546
- pocketTtsSetup: { ready: false, attempted: false, error: null },
1547
1512
  setupMessage: 'Will setup on first TTS request',
1548
1513
  });
1549
1514
  }
@@ -1,33 +0,0 @@
1
- import fs from 'fs';
2
- import path from 'path';
3
- import os from 'os';
4
-
5
- export function patchWebtalkForWindows(serverTTS) {
6
- if (process.platform !== 'win32') return;
7
-
8
- const venvDir = path.join(os.homedir(), '.gmgui', 'pocket-venv');
9
-
10
- // Check if pocket-tts exists at Windows paths
11
- const windowsBinaries = [
12
- path.join(venvDir, 'Scripts', 'pocket-tts.exe'),
13
- path.join(venvDir, 'bin', 'pocket-tts.exe'),
14
- path.join(venvDir, 'bin', 'pocket-tts'),
15
- ];
16
-
17
- const found = windowsBinaries.find(p => fs.existsSync(p));
18
-
19
- if (found) {
20
- // Patch the start function to use the correct binary
21
- const originalStart = serverTTS.start;
22
-
23
- serverTTS.start = function(voicePath, options) {
24
- if (!options) options = {};
25
- if (!options.binaryPaths) options.binaryPaths = [];
26
-
27
- // Ensure Windows paths are first
28
- options.binaryPaths = [...windowsBinaries, ...options.binaryPaths];
29
-
30
- return originalStart.call(this, voicePath, options);
31
- };
32
- }
33
- }
@@ -1,215 +0,0 @@
1
- import { execSync, spawnSync } from 'child_process';
2
- import fs from 'fs';
3
- import path from 'path';
4
- import os from 'os';
5
-
6
- const PYTHON_VERSION_MIN = [3, 9];
7
- const VENV_DIR = path.join(os.homedir(), '.gmgui', 'pocket-venv');
8
- const isWin = process.platform === 'win32';
9
- const EXECUTABLE_NAME = isWin ? 'pocket-tts.exe' : 'pocket-tts';
10
-
11
- const CONFIG = {
12
- PIP_TIMEOUT: 120000,
13
- VENV_CREATION_TIMEOUT: 30000,
14
- MAX_RETRIES: 3,
15
- RETRY_DELAY_MS: 1000,
16
- RETRY_BACKOFF_MULTIPLIER: 2,
17
- };
18
-
19
- function getPocketTtsPath() {
20
- if (isWin) {
21
- return path.join(VENV_DIR, 'Scripts', EXECUTABLE_NAME);
22
- }
23
- return path.join(VENV_DIR, 'bin', EXECUTABLE_NAME);
24
- }
25
-
26
- function detectPython() {
27
- try {
28
- const versionOutput = execSync('python --version', { encoding: 'utf-8', timeout: 10000 }).trim();
29
- const match = versionOutput.match(/(\d+)\.(\d+)/);
30
- if (!match) return { found: false, version: null, error: 'Could not parse version' };
31
-
32
- const major = parseInt(match[1], 10);
33
- const minor = parseInt(match[2], 10);
34
- const versionOk = major > PYTHON_VERSION_MIN[0] || (major === PYTHON_VERSION_MIN[0] && minor >= PYTHON_VERSION_MIN[1]);
35
-
36
- if (!versionOk) {
37
- return { found: true, version: `${major}.${minor}`, error: `Python ${major}.${minor} found but ${PYTHON_VERSION_MIN[0]}.${PYTHON_VERSION_MIN[1]}+ required` };
38
- }
39
-
40
- return { found: true, version: `${major}.${minor}`, error: null };
41
- } catch (e) {
42
- return { found: false, version: null, error: 'Python not found in PATH' };
43
- }
44
- }
45
-
46
- function isSetup() {
47
- const exePath = getPocketTtsPath();
48
- return fs.existsSync(exePath);
49
- }
50
-
51
- function cleanupPartialInstall() {
52
- try {
53
- if (fs.existsSync(VENV_DIR)) {
54
- fs.rmSync(VENV_DIR, { recursive: true, force: true });
55
- return true;
56
- }
57
- } catch (e) {
58
- console.error(`Failed to cleanup partial install: ${e.message}`);
59
- }
60
- return false;
61
- }
62
-
63
- function verifyInstallation() {
64
- const exePath = getPocketTtsPath();
65
- if (!fs.existsSync(exePath)) {
66
- return { valid: false, error: `Binary not found at ${exePath}` };
67
- }
68
-
69
- try {
70
- const result = spawnSync(exePath, ['--help'], { encoding: 'utf-8', timeout: 10000, stdio: 'pipe' });
71
- if (result.status === 0 || (result.stdout && result.stdout.includes('pocket-tts'))) {
72
- return { valid: true, version: 'installed' };
73
- }
74
- if (result.stderr && result.stderr.includes('pocket-tts')) {
75
- return { valid: true, version: 'installed' };
76
- }
77
- return { valid: true, version: 'binary-exists' };
78
- } catch (e) {
79
- return { valid: false, error: `Binary exists but failed verification: ${e.message}` };
80
- }
81
- }
82
-
83
- async function executeWithRetry(fn, stepName, maxRetries = CONFIG.MAX_RETRIES) {
84
- let lastError = null;
85
- let delayMs = CONFIG.RETRY_DELAY_MS;
86
-
87
- for (let attempt = 1; attempt <= maxRetries; attempt++) {
88
- try {
89
- return await fn(attempt);
90
- } catch (e) {
91
- lastError = e;
92
- if (attempt < maxRetries) {
93
- console.log(`Attempt ${attempt}/${maxRetries} failed for ${stepName}, retrying in ${delayMs}ms`);
94
- await new Promise(r => setTimeout(r, delayMs));
95
- delayMs *= CONFIG.RETRY_BACKOFF_MULTIPLIER;
96
- }
97
- }
98
- }
99
-
100
- const msg = `${stepName} failed after ${maxRetries} attempts: ${lastError.message || lastError}`;
101
- throw new Error(msg);
102
- }
103
-
104
- async function install(onProgress) {
105
- const pythonDetect = detectPython();
106
-
107
- if (!pythonDetect.found) {
108
- const msg = pythonDetect.error || 'Python not found';
109
- if (onProgress) onProgress({ step: 'detecting-python', status: 'error', message: msg });
110
- return { success: false, error: msg };
111
- }
112
-
113
- if (pythonDetect.error) {
114
- if (onProgress) onProgress({ step: 'detecting-python', status: 'error', message: pythonDetect.error });
115
- return { success: false, error: pythonDetect.error };
116
- }
117
-
118
- if (onProgress) onProgress({ step: 'detecting-python', status: 'success', message: `Found Python ${pythonDetect.version}` });
119
-
120
- if (isSetup()) {
121
- const verify = verifyInstallation();
122
- if (verify.valid) {
123
- if (onProgress) onProgress({ step: 'verifying', status: 'success', message: 'pocket-tts already installed' });
124
- return { success: true };
125
- }
126
- }
127
-
128
- if (onProgress) onProgress({ step: 'creating-venv', status: 'in-progress', message: `Creating virtual environment at ${VENV_DIR}` });
129
-
130
- try {
131
- await executeWithRetry(async (attempt) => {
132
- return execSync(`python -m venv "${VENV_DIR}"`, {
133
- encoding: 'utf-8',
134
- stdio: 'pipe',
135
- timeout: CONFIG.VENV_CREATION_TIMEOUT,
136
- });
137
- }, 'venv creation', 2);
138
-
139
- if (onProgress) onProgress({ step: 'creating-venv', status: 'success', message: 'Virtual environment created' });
140
- } catch (e) {
141
- const msg = `Failed to create venv: ${e.message || e}`;
142
- if (onProgress) onProgress({ step: 'creating-venv', status: 'error', message: msg });
143
- cleanupPartialInstall();
144
- return { success: false, error: msg };
145
- }
146
-
147
- if (onProgress) onProgress({ step: 'installing', status: 'in-progress', message: 'Installing pocket-tts via pip (this may take 2-5 minutes on slow connections)' });
148
-
149
- try {
150
- await executeWithRetry(async (attempt) => {
151
- if (attempt > 1 && onProgress) {
152
- onProgress({ step: 'installing', status: 'in-progress', message: `Installing pocket-tts (attempt ${attempt}/${CONFIG.MAX_RETRIES})` });
153
- }
154
-
155
- const pipCmd = isWin
156
- ? `"${path.join(VENV_DIR, 'Scripts', 'pip')}" install --no-cache-dir pocket-tts`
157
- : `"${path.join(VENV_DIR, 'bin', 'pip')}" install --no-cache-dir pocket-tts`;
158
-
159
- return execSync(pipCmd, {
160
- encoding: 'utf-8',
161
- stdio: 'pipe',
162
- timeout: CONFIG.PIP_TIMEOUT,
163
- env: { ...process.env, PIP_DEFAULT_TIMEOUT: '120' },
164
- });
165
- }, 'pip install', CONFIG.MAX_RETRIES);
166
-
167
- if (onProgress) onProgress({ step: 'installing', status: 'success', message: 'pocket-tts installed successfully' });
168
- } catch (e) {
169
- const msg = `Failed to install pocket-tts: ${e.message || e}`;
170
- if (onProgress) onProgress({ step: 'installing', status: 'error', message: msg });
171
- cleanupPartialInstall();
172
- return { success: false, error: msg };
173
- }
174
-
175
- if (onProgress) onProgress({ step: 'verifying', status: 'in-progress', message: 'Verifying installation' });
176
-
177
- const verify = verifyInstallation();
178
- if (!verify.valid) {
179
- const msg = verify.error || 'Installation verification failed';
180
- if (onProgress) onProgress({ step: 'verifying', status: 'error', message: msg });
181
- cleanupPartialInstall();
182
- return { success: false, error: msg };
183
- }
184
-
185
- const exePath = getPocketTtsPath();
186
- const binDir = path.join(VENV_DIR, 'bin');
187
- const binExePath = path.join(binDir, 'pocket-tts');
188
-
189
- if (isWin) {
190
- try {
191
- fs.mkdirSync(binDir, { recursive: true });
192
- } catch (e) {}
193
-
194
- const exeWithExt = path.join(binDir, 'pocket-tts.exe');
195
- if (fs.existsSync(exePath) && !fs.existsSync(exeWithExt)) {
196
- try {
197
- fs.copyFileSync(exePath, exeWithExt);
198
- } catch (e) {}
199
- }
200
-
201
- const batchFile = path.join(binDir, 'pocket-tts.bat');
202
- if (!fs.existsSync(batchFile) && fs.existsSync(exeWithExt)) {
203
- try {
204
- const batchContent = `@echo off\nsetlocal enabledelayedexpansion\nset PYTHONUNBUFFERED=1\nset HF_HUB_DISABLE_SYMLINKS_WARNING=1\n"${exeWithExt}" %*\n`;
205
- fs.writeFileSync(batchFile, batchContent, 'utf-8');
206
- } catch (e) {}
207
- }
208
- }
209
-
210
- if (onProgress) onProgress({ step: 'verifying', status: 'success', message: `pocket-tts ready (${verify.version})` });
211
-
212
- return { success: true };
213
- }
214
-
215
- export { detectPython, isSetup, install, getPocketTtsPath, VENV_DIR, CONFIG, cleanupPartialInstall, verifyInstallation };