agentgui 1.0.218 → 1.0.220

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.220",
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
 
@@ -1465,11 +1438,6 @@ const server = http.createServer(async (req, res) => {
1465
1438
  }
1466
1439
 
1467
1440
  const speech = await getSpeech();
1468
- const status = speech.getStatus();
1469
- if (status.ttsError) {
1470
- sendJSON(req, res, 503, { error: status.ttsError, retryable: false });
1471
- return;
1472
- }
1473
1441
  const wavBuffer = await speech.synthesize(text, voiceId);
1474
1442
  res.writeHead(200, { 'Content-Type': 'audio/wav', 'Content-Length': wavBuffer.length });
1475
1443
  res.end(wavBuffer);
@@ -1492,11 +1460,6 @@ const server = http.createServer(async (req, res) => {
1492
1460
  return;
1493
1461
  }
1494
1462
  const speech = await getSpeech();
1495
- const status = speech.getStatus();
1496
- if (status.ttsError) {
1497
- sendJSON(req, res, 503, { error: status.ttsError, retryable: false });
1498
- return;
1499
- }
1500
1463
  res.writeHead(200, {
1501
1464
  'Content-Type': 'application/octet-stream',
1502
1465
  'Transfer-Encoding': 'chunked',
@@ -1524,26 +1487,18 @@ const server = http.createServer(async (req, res) => {
1524
1487
  try {
1525
1488
  const { getStatus } = await getSpeech();
1526
1489
  const baseStatus = getStatus();
1527
- const pythonDetect = detectPython();
1528
- const statusWithSetup = {
1490
+ const r = createRequire(import.meta.url);
1491
+ const serverTTS = r('webtalk/server-tts');
1492
+ const pyInfo = serverTTS.detectPython();
1493
+ sendJSON(req, res, 200, {
1529
1494
  ...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);
1495
+ pythonDetected: pyInfo.found,
1496
+ pythonVersion: pyInfo.version || null,
1497
+ setupMessage: baseStatus.ttsReady ? 'pocket-tts ready' : 'Will setup on first TTS request',
1498
+ });
1540
1499
  } catch (err) {
1541
- const pythonDetect = detectPython();
1542
1500
  sendJSON(req, res, 200, {
1543
1501
  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
1502
  setupMessage: 'Will setup on first TTS request',
1548
1503
  });
1549
1504
  }
@@ -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 };