open-agents-ai 0.187.277 → 0.187.280
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/dist/index.js +177 -25
- package/dist/launcher.cjs +74 -10
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -264717,12 +264717,12 @@ var init_taskNormalizer = __esm({
|
|
|
264717
264717
|
// packages/orchestrator/dist/dispatcher.js
|
|
264718
264718
|
function estimateComplexity(task) {
|
|
264719
264719
|
const text = `${task.goal} ${task.constraints.join(" ")} ${task.successCriteria.join(" ")}`;
|
|
264720
|
-
const
|
|
264720
|
+
const wordCount2 = text.split(/\s+/).length;
|
|
264721
264721
|
if (task.urgency === "critical")
|
|
264722
264722
|
return "high";
|
|
264723
|
-
if (
|
|
264723
|
+
if (wordCount2 > 150 || task.successCriteria.length > 5)
|
|
264724
264724
|
return "high";
|
|
264725
|
-
if (
|
|
264725
|
+
if (wordCount2 > 60 || task.successCriteria.length > 2)
|
|
264726
264726
|
return "medium";
|
|
264727
264727
|
return "low";
|
|
264728
264728
|
}
|
|
@@ -265643,8 +265643,8 @@ function classifyQuery(query) {
|
|
|
265643
265643
|
return "error";
|
|
265644
265644
|
if (/^[A-Za-z_$][A-Za-z0-9_$]*$/.test(trimmed))
|
|
265645
265645
|
return "symbol";
|
|
265646
|
-
const
|
|
265647
|
-
if (
|
|
265646
|
+
const wordCount2 = trimmed.split(/\s+/).length;
|
|
265647
|
+
if (wordCount2 <= 3)
|
|
265648
265648
|
return "short";
|
|
265649
265649
|
return "long";
|
|
265650
265650
|
}
|
|
@@ -270703,10 +270703,10 @@ Integrate this guidance into your current approach. Continue working on the task
|
|
|
270703
270703
|
const turnTier = this.options.modelTier ?? "large";
|
|
270704
270704
|
if (turn === 0 && (turnTier === "small" || turnTier === "medium")) {
|
|
270705
270705
|
const goal = this._taskState.goal || "";
|
|
270706
|
-
const
|
|
270706
|
+
const wordCount2 = goal.split(/\s+/).length;
|
|
270707
270707
|
const hasMultipleActions = /\band\b.*\band\b|then.*then|also.*also/i.test(goal);
|
|
270708
270708
|
const hasMultipleFiles = /files?.*files?|\.ts.*\.ts|create.*write|modify.*create/i.test(goal);
|
|
270709
|
-
const isComplex =
|
|
270709
|
+
const isComplex = wordCount2 > 40 || hasMultipleActions || hasMultipleFiles;
|
|
270710
270710
|
if (isComplex) {
|
|
270711
270711
|
messages2.push({
|
|
270712
270712
|
role: "user",
|
|
@@ -294676,6 +294676,8 @@ var init_voice = __esm({
|
|
|
294676
294676
|
currentPlayback = null;
|
|
294677
294677
|
speakQueue = [];
|
|
294678
294678
|
speaking = false;
|
|
294679
|
+
drainPromise = null;
|
|
294680
|
+
drainResolve = null;
|
|
294679
294681
|
phonemizeFn = null;
|
|
294680
294682
|
/** True when current model uses MLX Audio backend */
|
|
294681
294683
|
mlxActive = false;
|
|
@@ -294992,6 +294994,15 @@ var init_voice = __esm({
|
|
|
294992
294994
|
const speedFactor = emotion ? emotionToSpeedFactor(emotion, this.starkMode, this.autistMode) : 1;
|
|
294993
294995
|
this.enqueueSpeech(text, 0.55, 1 + pitchBias, speedFactor, 0.15);
|
|
294994
294996
|
}
|
|
294997
|
+
/** Wait until the speak queue is fully drained (all audio played). */
|
|
294998
|
+
async waitUntilIdle() {
|
|
294999
|
+
if (!this.speaking && this.speakQueue.length === 0) return;
|
|
295000
|
+
if (this.drainPromise) {
|
|
295001
|
+
await this.drainPromise;
|
|
295002
|
+
} else {
|
|
295003
|
+
await this.sleep(100);
|
|
295004
|
+
}
|
|
295005
|
+
}
|
|
294995
295006
|
enqueueSpeech(text, volume, pitchFactor, speedFactor = 1, stereoDelayMs = 0.6) {
|
|
294996
295007
|
if (!this.enabled || !this.ready) return;
|
|
294997
295008
|
text = sanitizeForTTS(text);
|
|
@@ -295190,6 +295201,11 @@ var init_voice = __esm({
|
|
|
295190
295201
|
*/
|
|
295191
295202
|
async drainQueue() {
|
|
295192
295203
|
this.speaking = true;
|
|
295204
|
+
if (!this.drainPromise) {
|
|
295205
|
+
this.drainPromise = new Promise((resolve40) => {
|
|
295206
|
+
this.drainResolve = resolve40;
|
|
295207
|
+
});
|
|
295208
|
+
}
|
|
295193
295209
|
let isFirst = true;
|
|
295194
295210
|
let prefetchedWav = null;
|
|
295195
295211
|
while (this.speakQueue.length > 0) {
|
|
@@ -295241,6 +295257,14 @@ var init_voice = __esm({
|
|
|
295241
295257
|
}
|
|
295242
295258
|
}
|
|
295243
295259
|
this.speaking = false;
|
|
295260
|
+
if (this.drainResolve) {
|
|
295261
|
+
try {
|
|
295262
|
+
this.drainResolve();
|
|
295263
|
+
} catch {
|
|
295264
|
+
}
|
|
295265
|
+
}
|
|
295266
|
+
this.drainResolve = null;
|
|
295267
|
+
this.drainPromise = null;
|
|
295244
295268
|
}
|
|
295245
295269
|
sleep(ms) {
|
|
295246
295270
|
return new Promise((resolve40) => setTimeout(resolve40, ms));
|
|
@@ -328218,15 +328242,62 @@ __export(voicechat_exports, {
|
|
|
328218
328242
|
VoiceChatSession: () => VoiceChatSession
|
|
328219
328243
|
});
|
|
328220
328244
|
import { EventEmitter as EventEmitter10 } from "node:events";
|
|
328221
|
-
|
|
328245
|
+
function clamp01(x) {
|
|
328246
|
+
return x < 0 ? 0 : x > 1 ? 1 : x;
|
|
328247
|
+
}
|
|
328248
|
+
function alnumRatio(s2) {
|
|
328249
|
+
if (!s2) return 0;
|
|
328250
|
+
const al = (s2.match(/[\p{L}\p{N}]/gu) || []).length;
|
|
328251
|
+
return al / s2.length;
|
|
328252
|
+
}
|
|
328253
|
+
function wordCount(s2) {
|
|
328254
|
+
const words = s2.trim().match(/[\p{L}\p{N}][\p{L}\p{N}'’_-]*/gu);
|
|
328255
|
+
return words ? words.length : 0;
|
|
328256
|
+
}
|
|
328257
|
+
function repeatingCharPenalty(s2) {
|
|
328258
|
+
let maxRun = 1, cur = 1;
|
|
328259
|
+
for (let i2 = 1; i2 < s2.length; i2++) {
|
|
328260
|
+
if (s2[i2] === s2[i2 - 1]) cur++;
|
|
328261
|
+
else {
|
|
328262
|
+
if (cur > maxRun) maxRun = cur;
|
|
328263
|
+
cur = 1;
|
|
328264
|
+
}
|
|
328265
|
+
}
|
|
328266
|
+
if (cur > maxRun) maxRun = cur;
|
|
328267
|
+
return Math.min(1, Math.max(0, (maxRun - 3) / 10));
|
|
328268
|
+
}
|
|
328269
|
+
function computeSignalFromText(text, confidence) {
|
|
328270
|
+
const t2 = text.trim();
|
|
328271
|
+
if (!t2) return 0;
|
|
328272
|
+
if (NOISE_ONLY_RE.test(t2)) return 0.05;
|
|
328273
|
+
const len = t2.length;
|
|
328274
|
+
const wc = wordCount(t2);
|
|
328275
|
+
const alpha = alnumRatio(t2);
|
|
328276
|
+
let score = 0;
|
|
328277
|
+
if (wc >= 6 && alpha >= 0.6) score = 0.85;
|
|
328278
|
+
else if (wc >= 3 && alpha >= 0.5) score = 0.7;
|
|
328279
|
+
else if (wc >= 2 && alpha >= 0.4) score = 0.5;
|
|
328280
|
+
else if (wc >= 1 && alpha >= 0.3 && len >= 4) score = 0.35;
|
|
328281
|
+
else score = 0.15;
|
|
328282
|
+
score -= repeatingCharPenalty(t2) * 0.4;
|
|
328283
|
+
if (typeof confidence === "number" && !Number.isNaN(confidence)) {
|
|
328284
|
+
score = 0.7 * score + 0.3 * clamp01(confidence);
|
|
328285
|
+
}
|
|
328286
|
+
return clamp01(score);
|
|
328287
|
+
}
|
|
328288
|
+
function truncateForLog(s2, n2) {
|
|
328289
|
+
return s2.length <= n2 ? s2 : s2.slice(0, n2 - 1) + "…";
|
|
328290
|
+
}
|
|
328291
|
+
var VAD_SILENCE_MS, MAX_SEGMENT_MS, MAX_CONTEXT_TURNS, SYSTEM_PROMPT2, MIN_SIGNAL_SCORE, NOISE_ONLY_RE, VoiceChatSession;
|
|
328222
328292
|
var init_voicechat = __esm({
|
|
328223
328293
|
"packages/cli/src/tui/voicechat.ts"() {
|
|
328224
328294
|
"use strict";
|
|
328225
|
-
VAD_SILENCE_MS =
|
|
328295
|
+
VAD_SILENCE_MS = 2e3;
|
|
328226
328296
|
MAX_SEGMENT_MS = 6500;
|
|
328227
|
-
SUMMARY_INJECTION_INTERVAL = 4;
|
|
328228
328297
|
MAX_CONTEXT_TURNS = 20;
|
|
328229
328298
|
SYSTEM_PROMPT2 = `You are a voice assistant having a live spoken conversation. Keep responses extremely brief — 1-2 sentences max. You're speaking aloud, not writing. Be conversational, direct, and helpful. Don't use markdown, bullet points, or formatting — just natural speech. If you don't know something, say so briefly. Do not over-think — respond quickly and concisely.`;
|
|
328299
|
+
MIN_SIGNAL_SCORE = 0.4;
|
|
328300
|
+
NOISE_ONLY_RE = /^(?:[.·…\s,;:!?\-–—_()\[\]{}"'`]+|(?:uh|um|erm|hmm|mm+|uhh+|umm+)[\s.!?]*)+$/i;
|
|
328230
328301
|
VoiceChatSession = class extends EventEmitter10 {
|
|
328231
328302
|
voice;
|
|
328232
328303
|
listen;
|
|
@@ -328245,6 +328316,7 @@ var init_voicechat = __esm({
|
|
|
328245
328316
|
captureStartTime = 0;
|
|
328246
328317
|
silenceTimer = null;
|
|
328247
328318
|
maxSegmentTimer = null;
|
|
328319
|
+
lastSignalScore = null;
|
|
328248
328320
|
// Abort control for inference
|
|
328249
328321
|
abortController = null;
|
|
328250
328322
|
// Callbacks
|
|
@@ -328256,6 +328328,7 @@ var init_voicechat = __esm({
|
|
|
328256
328328
|
// Bound handlers for cleanup
|
|
328257
328329
|
_onTranscript = null;
|
|
328258
328330
|
_onError = null;
|
|
328331
|
+
_retryMicTimer = null;
|
|
328259
328332
|
constructor(opts) {
|
|
328260
328333
|
super();
|
|
328261
328334
|
this.voice = opts.voice;
|
|
@@ -328307,20 +328380,37 @@ var init_voicechat = __esm({
|
|
|
328307
328380
|
this._onTranscript = (...args) => {
|
|
328308
328381
|
let text;
|
|
328309
328382
|
let isFinal;
|
|
328383
|
+
let snr;
|
|
328384
|
+
let confidence;
|
|
328310
328385
|
if (typeof args[0] === "object" && args[0] !== null) {
|
|
328311
328386
|
const evt = args[0];
|
|
328312
328387
|
text = evt.text ?? "";
|
|
328313
328388
|
isFinal = evt.isFinal ?? false;
|
|
328389
|
+
snr = evt.snr;
|
|
328390
|
+
confidence = evt.confidence;
|
|
328314
328391
|
} else {
|
|
328315
328392
|
text = String(args[0] ?? "");
|
|
328316
328393
|
isFinal = Boolean(args[1]);
|
|
328317
328394
|
}
|
|
328318
328395
|
if (!text.trim()) return;
|
|
328319
|
-
this.handleTranscript(text.trim(), isFinal);
|
|
328396
|
+
this.handleTranscript(text.trim(), isFinal, snr, confidence);
|
|
328320
328397
|
};
|
|
328321
328398
|
this._onError = (err) => {
|
|
328322
328399
|
const msg = err instanceof Error ? err.message : String(err);
|
|
328323
328400
|
this.onStatus(`ASR error (voicechat continues without mic): ${msg.slice(0, 80)}`);
|
|
328401
|
+
if (this.active && !this._retryMicTimer) {
|
|
328402
|
+
this._retryMicTimer = setTimeout(async () => {
|
|
328403
|
+
this._retryMicTimer = null;
|
|
328404
|
+
if (!this.active) return;
|
|
328405
|
+
try {
|
|
328406
|
+
await this.listen.stop().catch(() => {
|
|
328407
|
+
});
|
|
328408
|
+
await this.listen.start();
|
|
328409
|
+
this.onStatus("Mic auto-recovered — LISTENING");
|
|
328410
|
+
} catch {
|
|
328411
|
+
}
|
|
328412
|
+
}, 1e3);
|
|
328413
|
+
}
|
|
328324
328414
|
};
|
|
328325
328415
|
this.listen.on("transcript", this._onTranscript);
|
|
328326
328416
|
this.listen.on("error", this._onError);
|
|
@@ -328372,7 +328462,7 @@ var init_voicechat = __esm({
|
|
|
328372
328462
|
// ---------------------------------------------------------------------------
|
|
328373
328463
|
// Transcript handling — VAD-style segment capture (Voryn pattern)
|
|
328374
328464
|
// ---------------------------------------------------------------------------
|
|
328375
|
-
handleTranscript(text, isFinal) {
|
|
328465
|
+
handleTranscript(text, isFinal, snr, confidence) {
|
|
328376
328466
|
if (!this.active) return;
|
|
328377
328467
|
if (this._state !== "LISTENING" && this._state !== "CAPTURING") {
|
|
328378
328468
|
return;
|
|
@@ -328388,6 +328478,8 @@ var init_voicechat = __esm({
|
|
|
328388
328478
|
}, MAX_SEGMENT_MS);
|
|
328389
328479
|
}
|
|
328390
328480
|
this.captureBuffer = text;
|
|
328481
|
+
this.lastSignalScore = typeof snr === "number" && !Number.isNaN(snr) ? clamp01(snr) : computeSignalFromText(text, confidence);
|
|
328482
|
+
this.emit("snr", { score: this.lastSignalScore });
|
|
328391
328483
|
this.onPartialTranscript(text);
|
|
328392
328484
|
if (this.silenceTimer) clearTimeout(this.silenceTimer);
|
|
328393
328485
|
if (isFinal) {
|
|
@@ -328418,10 +328510,25 @@ var init_voicechat = __esm({
|
|
|
328418
328510
|
this.setState("LISTENING");
|
|
328419
328511
|
return;
|
|
328420
328512
|
}
|
|
328513
|
+
const score = this.lastSignalScore ?? computeSignalFromText(text);
|
|
328514
|
+
if (score < MIN_SIGNAL_SCORE || NOISE_ONLY_RE.test(text)) {
|
|
328515
|
+
this.onStatus(`Ignoring low-signal utterance (SNR:${score.toFixed(2)}): ${truncateForLog(text, 48)}`);
|
|
328516
|
+
this.emit("snrFiltered", { score, text });
|
|
328517
|
+
this.setState("LISTENING");
|
|
328518
|
+
this.captureBuffer = "";
|
|
328519
|
+
this.lastSignalScore = null;
|
|
328520
|
+
return;
|
|
328521
|
+
}
|
|
328421
328522
|
this.setState("TRANSCRIBING");
|
|
328422
328523
|
this.onUserSpeech(text);
|
|
328423
328524
|
this.context.push({ role: "user", content: text });
|
|
328424
328525
|
this.turnCount++;
|
|
328526
|
+
if (this.runner) {
|
|
328527
|
+
try {
|
|
328528
|
+
this.runner.injectUserMessage(`[VOICECHAT] ${text}`);
|
|
328529
|
+
} catch {
|
|
328530
|
+
}
|
|
328531
|
+
}
|
|
328425
328532
|
while (this.context.length > MAX_CONTEXT_TURNS + 1) {
|
|
328426
328533
|
this.context.splice(1, 1);
|
|
328427
328534
|
}
|
|
@@ -328443,11 +328550,18 @@ var init_voicechat = __esm({
|
|
|
328443
328550
|
this.setState("SPEAKING");
|
|
328444
328551
|
this.onAgentSpeech(response.trim());
|
|
328445
328552
|
this.voice.speak(response.trim());
|
|
328446
|
-
if (this.runner
|
|
328553
|
+
if (this.runner) {
|
|
328447
328554
|
this.injectSummary();
|
|
328448
328555
|
}
|
|
328449
|
-
|
|
328450
|
-
|
|
328556
|
+
if (typeof this.voice.waitUntilIdle === "function") {
|
|
328557
|
+
try {
|
|
328558
|
+
await this.voice.waitUntilIdle();
|
|
328559
|
+
} catch {
|
|
328560
|
+
}
|
|
328561
|
+
} else {
|
|
328562
|
+
const estimatedMs = Math.max(1500, response.length / 5 * (6e4 / 150));
|
|
328563
|
+
await new Promise((r2) => setTimeout(r2, estimatedMs));
|
|
328564
|
+
}
|
|
328451
328565
|
}
|
|
328452
328566
|
} catch (err) {
|
|
328453
328567
|
if (!this.active) return;
|
|
@@ -328570,13 +328684,19 @@ var init_voicechat = __esm({
|
|
|
328570
328684
|
// ---------------------------------------------------------------------------
|
|
328571
328685
|
injectSummary() {
|
|
328572
328686
|
if (!this.runner) return;
|
|
328573
|
-
const recentTurns = this.context.filter((t2) => t2.role !== "system").slice(-
|
|
328687
|
+
const recentTurns = this.context.filter((t2) => t2.role !== "system").slice(-8).map((t2) => `${t2.role === "user" ? "User" : "Assistant"}: ${t2.content}`).join("\n");
|
|
328574
328688
|
this.runner.injectUserMessage(
|
|
328575
|
-
`[VOICECHAT SUMMARY]
|
|
328689
|
+
`[VOICECHAT SUMMARY] Parallel voice liaison update (for awareness only). Continue your current task; do not respond to this directly.
|
|
328576
328690
|
|
|
328577
328691
|
${recentTurns}`
|
|
328578
328692
|
);
|
|
328579
328693
|
}
|
|
328694
|
+
/** Enqueue narration from main agent events into the voice channel */
|
|
328695
|
+
enqueueAgentNarration(text, subordinate = true) {
|
|
328696
|
+
if (!text || !this.active) return;
|
|
328697
|
+
if (subordinate) this.voice.speakSubordinate(text);
|
|
328698
|
+
else this.voice.speak(text);
|
|
328699
|
+
}
|
|
328580
328700
|
};
|
|
328581
328701
|
}
|
|
328582
328702
|
});
|
|
@@ -330156,6 +330276,17 @@ ${entry.fullContent}`
|
|
|
330156
330276
|
}
|
|
330157
330277
|
});
|
|
330158
330278
|
}
|
|
330279
|
+
if (voice?.enabled && voice.voiceMode === "voicechat" && _voiceChatSession?.isActive && event.toolName === "task_complete") {
|
|
330280
|
+
const emoStateFinal = emotionEngine?.getState();
|
|
330281
|
+
const emoCtxFinal = emoStateFinal ? { valence: emoStateFinal.valence, arousal: emoStateFinal.arousal, label: emoStateFinal.label, emoji: emoStateFinal.emoji } : void 0;
|
|
330282
|
+
const desc = describeTaskComplete(String(event.content ?? ""), true, vLevel);
|
|
330283
|
+
if (desc) {
|
|
330284
|
+
try {
|
|
330285
|
+
_voiceChatSession.enqueueAgentNarration(desc, false);
|
|
330286
|
+
} catch {
|
|
330287
|
+
}
|
|
330288
|
+
}
|
|
330289
|
+
}
|
|
330159
330290
|
break;
|
|
330160
330291
|
}
|
|
330161
330292
|
case "model_response":
|
|
@@ -330237,6 +330368,15 @@ ${entry.fullContent}`
|
|
|
330237
330368
|
voice.speak(chatText);
|
|
330238
330369
|
voice._spokenStreamText = true;
|
|
330239
330370
|
}
|
|
330371
|
+
} else if (voice?.enabled && voice.voiceMode === "voicechat" && (streamTextBuffer || event.content)) {
|
|
330372
|
+
const chatText = (streamTextBuffer || event.content || "").trim();
|
|
330373
|
+
streamTextBuffer = "";
|
|
330374
|
+
if (chatText.length > 10 && _voiceChatSession?.isActive) {
|
|
330375
|
+
try {
|
|
330376
|
+
_voiceChatSession.enqueueAgentNarration(chatText, false);
|
|
330377
|
+
} catch {
|
|
330378
|
+
}
|
|
330379
|
+
}
|
|
330240
330380
|
}
|
|
330241
330381
|
break;
|
|
330242
330382
|
}
|
|
@@ -331274,7 +331414,7 @@ ${opts.systemPromptAddition}` : `Working directory: ${repoRoot}`;
|
|
|
331274
331414
|
autoUpdateTimer.unref();
|
|
331275
331415
|
const voiceEngine = new VoiceEngine();
|
|
331276
331416
|
let voiceSession = null;
|
|
331277
|
-
let
|
|
331417
|
+
let _voiceChatSession2 = null;
|
|
331278
331418
|
let tunnelGateway = null;
|
|
331279
331419
|
let p2pGateway = null;
|
|
331280
331420
|
let peerMesh = null;
|
|
@@ -332963,7 +333103,7 @@ Respond concisely and safely. Remember: you are talking to the general public.`;
|
|
|
332963
333103
|
},
|
|
332964
333104
|
// --- /voicechat: Voryn-style state machine voice conversation ---
|
|
332965
333105
|
async voiceChatStart() {
|
|
332966
|
-
if (
|
|
333106
|
+
if (_voiceChatSession2?.isActive) return;
|
|
332967
333107
|
if (!voiceEngine.enabled || !voiceEngine.ready) {
|
|
332968
333108
|
writeContent(() => renderInfo2("Auto-enabling voice for voice chat..."));
|
|
332969
333109
|
const voiceMsg = await voiceEngine.toggle();
|
|
@@ -332980,7 +333120,7 @@ Respond concisely and safely. Remember: you are talking to the general public.`;
|
|
|
332980
333120
|
}
|
|
332981
333121
|
}
|
|
332982
333122
|
};
|
|
332983
|
-
|
|
333123
|
+
_voiceChatSession2 = new VoiceChatSession2({
|
|
332984
333124
|
voice: voiceEngine,
|
|
332985
333125
|
listen: listenEng,
|
|
332986
333126
|
backendUrl: currentConfig.backendUrl,
|
|
@@ -333005,16 +333145,28 @@ Respond concisely and safely. Remember: you are talking to the general public.`;
|
|
|
333005
333145
|
writeContent(() => renderInfo2(`\x1B[38;5;243m[voicechat] ${state}\x1B[0m`));
|
|
333006
333146
|
}
|
|
333007
333147
|
});
|
|
333008
|
-
|
|
333148
|
+
_voiceChatSession2.on("snr", (e2) => {
|
|
333149
|
+
const s2 = typeof e2?.score === "number" ? Math.max(0, Math.min(1, e2.score)) : null;
|
|
333150
|
+
if (s2 !== null) {
|
|
333151
|
+
writeContent(() => {
|
|
333152
|
+
process.stdout.write(`\r\x1B[2K\x1B[38;5;243m [hearing] (snr:${s2.toFixed(2)})\x1B[0m`);
|
|
333153
|
+
});
|
|
333154
|
+
}
|
|
333155
|
+
});
|
|
333156
|
+
_voiceChatSession2.on("snrFiltered", (e2) => {
|
|
333157
|
+
const s2 = typeof e2?.score === "number" ? e2.score.toFixed(2) : "?";
|
|
333158
|
+
writeContent(() => renderInfo2(`\x1B[38;5;243m[voicechat]\x1B[0m dropped low-signal utterance (SNR:${s2})`));
|
|
333159
|
+
});
|
|
333160
|
+
await _voiceChatSession2.start();
|
|
333009
333161
|
},
|
|
333010
333162
|
async voiceChatStop() {
|
|
333011
|
-
if (
|
|
333012
|
-
await
|
|
333013
|
-
|
|
333163
|
+
if (_voiceChatSession2?.isActive) {
|
|
333164
|
+
await _voiceChatSession2.stop();
|
|
333165
|
+
_voiceChatSession2 = null;
|
|
333014
333166
|
}
|
|
333015
333167
|
},
|
|
333016
333168
|
isVoiceChatActive() {
|
|
333017
|
-
return
|
|
333169
|
+
return _voiceChatSession2?.isActive ?? false;
|
|
333018
333170
|
},
|
|
333019
333171
|
async exposeStart(kindOrUrl, authKey, transport, fullAccess, passthrough, loadbalance) {
|
|
333020
333172
|
const knownKinds = ["ollama", "vllm", "llvm", "passthrough"];
|
package/dist/launcher.cjs
CHANGED
|
@@ -1,14 +1,78 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
//
|
|
3
|
-
//
|
|
4
|
-
|
|
2
|
+
// Robust launcher for open-agents CLI.
|
|
3
|
+
// - Runs the ESM entry as a child process
|
|
4
|
+
// - On exit code 120 (update), resets terminal and restarts child
|
|
5
|
+
// - Prevents raw-mode/mouse-tracking bleedthrough on restart or crash
|
|
6
|
+
|
|
7
|
+
const { spawn, spawnSync } = require('node:child_process');
|
|
8
|
+
const { resolve } = require('node:path');
|
|
9
|
+
|
|
10
|
+
function resetTerminal() {
|
|
11
|
+
try { if (process.stdin.isTTY && typeof process.stdin.setRawMode === 'function') process.stdin.setRawMode(false); } catch {}
|
|
12
|
+
// Disable mouse tracking, bracketed paste, show cursor, reset attrs, exit alt screen if active
|
|
13
|
+
const ESC = '\x1B';
|
|
5
14
|
try {
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
15
|
+
process.stdout.write(
|
|
16
|
+
ESC + '[?25h' + // show cursor
|
|
17
|
+
ESC + '[?1000l' + // X10 mouse off
|
|
18
|
+
ESC + '[?1002l' + // button-event mouse off
|
|
19
|
+
ESC + '[?1003l' + // any-event mouse off
|
|
20
|
+
ESC + '[?1006l' + // SGR mouse off
|
|
21
|
+
ESC + '[?1015l' + // urxvt mouse off
|
|
22
|
+
ESC + '[?2004l' + // bracketed paste off
|
|
23
|
+
ESC + '[?1049l' + // exit alt screen
|
|
24
|
+
ESC + '[0m' // reset attributes
|
|
25
|
+
);
|
|
26
|
+
} catch {}
|
|
27
|
+
// stty sane (POSIX)
|
|
28
|
+
if (process.platform !== 'win32' && process.stdin.isTTY) {
|
|
29
|
+
try { spawnSync('stty', ['sane'], { stdio: 'inherit' }); } catch {}
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
function runChild() {
|
|
34
|
+
const entry = resolve(__dirname, 'index.js');
|
|
35
|
+
const args = [entry, ...process.argv.slice(2)];
|
|
36
|
+
const child = spawn(process.execPath, args, {
|
|
37
|
+
stdio: 'inherit',
|
|
38
|
+
env: process.env,
|
|
39
|
+
});
|
|
40
|
+
return child;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
(async () => {
|
|
44
|
+
let restarts = 0;
|
|
45
|
+
const MAX_RESTARTS = 3;
|
|
46
|
+
let child = runChild();
|
|
47
|
+
|
|
48
|
+
const forward = (sig) => {
|
|
49
|
+
try { child && child.kill(sig); } catch {}
|
|
50
|
+
};
|
|
51
|
+
process.on('SIGINT', () => forward('SIGINT'));
|
|
52
|
+
process.on('SIGTERM', () => forward('SIGTERM'));
|
|
53
|
+
|
|
54
|
+
function attach(childProc) {
|
|
55
|
+
childProc.on('exit', (code, signal) => {
|
|
56
|
+
if (signal) {
|
|
57
|
+
resetTerminal();
|
|
58
|
+
process.kill(process.pid, signal);
|
|
59
|
+
return;
|
|
60
|
+
}
|
|
61
|
+
if (code === 120 && restarts < MAX_RESTARTS) {
|
|
62
|
+
// Update-triggered restart
|
|
63
|
+
resetTerminal();
|
|
64
|
+
restarts += 1;
|
|
65
|
+
setTimeout(() => {
|
|
66
|
+
child = runChild();
|
|
67
|
+
attach(child);
|
|
68
|
+
}, 300);
|
|
69
|
+
return;
|
|
70
|
+
}
|
|
71
|
+
// Normal exit or too many restarts
|
|
72
|
+
resetTerminal();
|
|
73
|
+
process.exit(typeof code === 'number' ? code : 0);
|
|
74
|
+
});
|
|
13
75
|
}
|
|
76
|
+
|
|
77
|
+
attach(child);
|
|
14
78
|
})();
|
package/package.json
CHANGED