open-agents-ai 0.185.32 → 0.185.34
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 +196 -63
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -8663,7 +8663,7 @@ process.on('SIGINT', () => process.emit('SIGTERM'));
|
|
|
8663
8663
|
const nodeModulesDir = resolve13(this.repoRoot, "node_modules");
|
|
8664
8664
|
let nexusResolved = false;
|
|
8665
8665
|
let installedVersion = "";
|
|
8666
|
-
const
|
|
8666
|
+
const execAsync3 = (cmd, opts = {}) => new Promise((res, rej) => {
|
|
8667
8667
|
const { exec: ex } = __require("node:child_process");
|
|
8668
8668
|
ex(cmd, { encoding: "utf8", timeout: opts.timeout ?? 3e4, cwd: opts.cwd, maxBuffer: 10 * 1024 * 1024 }, (err, stdout) => {
|
|
8669
8669
|
if (err)
|
|
@@ -8683,7 +8683,7 @@ process.on('SIGINT', () => process.emit('SIGTERM'));
|
|
|
8683
8683
|
}
|
|
8684
8684
|
} else {
|
|
8685
8685
|
try {
|
|
8686
|
-
const globalDir2 = await
|
|
8686
|
+
const globalDir2 = await execAsync3("npm root -g", { timeout: 5e3 });
|
|
8687
8687
|
const globalPkg = join14(globalDir2, "open-agents-nexus", "package.json");
|
|
8688
8688
|
if (existsSync11(globalPkg)) {
|
|
8689
8689
|
nexusResolved = true;
|
|
@@ -8700,10 +8700,10 @@ process.on('SIGINT', () => process.emit('SIGTERM'));
|
|
|
8700
8700
|
}
|
|
8701
8701
|
if (nexusResolved && installedVersion) {
|
|
8702
8702
|
try {
|
|
8703
|
-
const latestRaw = await
|
|
8703
|
+
const latestRaw = await execAsync3("npm view open-agents-nexus version 2>/dev/null", { timeout: 8e3 });
|
|
8704
8704
|
if (latestRaw && latestRaw !== installedVersion) {
|
|
8705
8705
|
try {
|
|
8706
|
-
await
|
|
8706
|
+
await execAsync3(`npm install open-agents-nexus@${latestRaw} --save 2>&1`, {
|
|
8707
8707
|
cwd: this.repoRoot,
|
|
8708
8708
|
timeout: 6e4
|
|
8709
8709
|
});
|
|
@@ -8716,13 +8716,13 @@ process.on('SIGINT', () => process.emit('SIGTERM'));
|
|
|
8716
8716
|
}
|
|
8717
8717
|
if (!nexusResolved) {
|
|
8718
8718
|
try {
|
|
8719
|
-
await
|
|
8719
|
+
await execAsync3("npm install open-agents-nexus@latest 2>&1", {
|
|
8720
8720
|
cwd: this.repoRoot,
|
|
8721
8721
|
timeout: 12e4
|
|
8722
8722
|
});
|
|
8723
8723
|
} catch {
|
|
8724
8724
|
try {
|
|
8725
|
-
await
|
|
8725
|
+
await execAsync3("npm install -g open-agents-nexus@latest 2>&1", { timeout: 12e4 });
|
|
8726
8726
|
} catch {
|
|
8727
8727
|
throw new Error("Failed to install open-agents-nexus. Run: npm install open-agents-nexus");
|
|
8728
8728
|
}
|
|
@@ -8767,7 +8767,7 @@ process.on('SIGINT', () => process.emit('SIGTERM'));
|
|
|
8767
8767
|
const agentType = args.agent_type || "general";
|
|
8768
8768
|
const nodePaths = [nodeModulesDir];
|
|
8769
8769
|
try {
|
|
8770
|
-
const globalDir2 = await
|
|
8770
|
+
const globalDir2 = await execAsync3("npm root -g", { timeout: 5e3 });
|
|
8771
8771
|
nodePaths.push(globalDir2);
|
|
8772
8772
|
} catch {
|
|
8773
8773
|
}
|
|
@@ -25041,9 +25041,9 @@ var init_verifierRunner = __esm({
|
|
|
25041
25041
|
async executeTests(patch, repoRoot) {
|
|
25042
25042
|
if (patch.testsToRun.length === 0)
|
|
25043
25043
|
return "(no tests specified)";
|
|
25044
|
-
const { execFile:
|
|
25044
|
+
const { execFile: execFile8 } = await import("node:child_process");
|
|
25045
25045
|
const { promisify: promisify7 } = await import("node:util");
|
|
25046
|
-
const execFileAsync6 = promisify7(
|
|
25046
|
+
const execFileAsync6 = promisify7(execFile8);
|
|
25047
25047
|
const outputs = [];
|
|
25048
25048
|
const workDir = this.options.workingDir || repoRoot;
|
|
25049
25049
|
for (const cmd of patch.testsToRun.slice(0, 3)) {
|
|
@@ -41284,8 +41284,32 @@ __export(personaplex_exports, {
|
|
|
41284
41284
|
import { existsSync as existsSync37, writeFileSync as writeFileSync16, readFileSync as readFileSync28, mkdirSync as mkdirSync15, copyFileSync as copyFileSync2, readdirSync as readdirSync11, statSync as statSync13 } from "node:fs";
|
|
41285
41285
|
import { join as join54, dirname as dirname18 } from "node:path";
|
|
41286
41286
|
import { homedir as homedir13 } from "node:os";
|
|
41287
|
-
import { execSync as execSync27, spawn as spawn19 } from "node:child_process";
|
|
41287
|
+
import { execSync as execSync27, spawn as spawn19, execFile as execFile7 } from "node:child_process";
|
|
41288
41288
|
import { fileURLToPath as fileURLToPath11 } from "node:url";
|
|
41289
|
+
function execAsync(cmd, opts = {}) {
|
|
41290
|
+
return new Promise((resolve36, reject) => {
|
|
41291
|
+
const child = spawn19("bash", ["-c", cmd], {
|
|
41292
|
+
stdio: ["ignore", "pipe", "pipe"],
|
|
41293
|
+
timeout: opts.timeout ?? 3e5,
|
|
41294
|
+
env: opts.env ?? process.env
|
|
41295
|
+
});
|
|
41296
|
+
let stdout = "";
|
|
41297
|
+
let stderr = "";
|
|
41298
|
+
child.stdout?.on("data", (d) => {
|
|
41299
|
+
stdout += d.toString();
|
|
41300
|
+
});
|
|
41301
|
+
child.stderr?.on("data", (d) => {
|
|
41302
|
+
stderr += d.toString();
|
|
41303
|
+
});
|
|
41304
|
+
child.on("close", (code) => {
|
|
41305
|
+
if (code === 0)
|
|
41306
|
+
resolve36(stdout.trim());
|
|
41307
|
+
else
|
|
41308
|
+
reject(new Error(`Exit ${code}: ${stderr.slice(0, 500)}`));
|
|
41309
|
+
});
|
|
41310
|
+
child.on("error", reject);
|
|
41311
|
+
});
|
|
41312
|
+
}
|
|
41289
41313
|
function selectWeightTier(vramGB) {
|
|
41290
41314
|
if (vramGB >= 48)
|
|
41291
41315
|
return "original";
|
|
@@ -41421,7 +41445,7 @@ async function installPersonaPlex(onInfo, weightTier) {
|
|
|
41421
41445
|
log("Creating Python virtual environment...");
|
|
41422
41446
|
try {
|
|
41423
41447
|
const ssp = isAarch64 ? " --system-site-packages" : "";
|
|
41424
|
-
|
|
41448
|
+
await execAsync(`python3 -m venv${ssp} "${venvDir}"`, { timeout: 6e4 });
|
|
41425
41449
|
} catch (err) {
|
|
41426
41450
|
log(`Failed to create venv: ${err instanceof Error ? err.message : String(err)}`);
|
|
41427
41451
|
return false;
|
|
@@ -41445,7 +41469,7 @@ async function installPersonaPlex(onInfo, weightTier) {
|
|
|
41445
41469
|
} catch {
|
|
41446
41470
|
log("ARM64: Installing Rust toolchain (needed for sphn audio codec)...");
|
|
41447
41471
|
try {
|
|
41448
|
-
|
|
41472
|
+
await execAsync("curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- -y", { timeout: 12e4 });
|
|
41449
41473
|
} catch (e) {
|
|
41450
41474
|
log(`Rust install failed: ${e instanceof Error ? e.message : String(e)}`);
|
|
41451
41475
|
log("Install Rust manually: curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh");
|
|
@@ -41453,7 +41477,7 @@ async function installPersonaPlex(onInfo, weightTier) {
|
|
|
41453
41477
|
}
|
|
41454
41478
|
}
|
|
41455
41479
|
try {
|
|
41456
|
-
|
|
41480
|
+
await execAsync(`"${pip}" install --quiet maturin`, { timeout: 6e4, stdio: "pipe" });
|
|
41457
41481
|
} catch {
|
|
41458
41482
|
}
|
|
41459
41483
|
}
|
|
@@ -41461,13 +41485,13 @@ async function installPersonaPlex(onInfo, weightTier) {
|
|
|
41461
41485
|
const repoDir = join54(PERSONAPLEX_DIR, "personaplex-repo");
|
|
41462
41486
|
try {
|
|
41463
41487
|
if (!existsSync37(repoDir)) {
|
|
41464
|
-
|
|
41488
|
+
await execAsync(`git clone https://github.com/NVIDIA/personaplex.git "${repoDir}"`, { timeout: 12e4 });
|
|
41465
41489
|
}
|
|
41466
41490
|
if (isAarch64) {
|
|
41467
41491
|
log("ARM64: Building sphn from source (Opus codec bindings)...");
|
|
41468
41492
|
try {
|
|
41469
41493
|
const rustEnv = `export PATH="$HOME/.cargo/bin:$PATH" &&`;
|
|
41470
|
-
|
|
41494
|
+
await execAsync(`${rustEnv} "${pip}" install --quiet --no-binary sphn sphn`, { timeout: 3e5 });
|
|
41471
41495
|
log("ARM64: sphn built successfully");
|
|
41472
41496
|
} catch (e) {
|
|
41473
41497
|
log(`ARM64: sphn build failed \u2014 ${e instanceof Error ? e.message : String(e)}`);
|
|
@@ -41475,11 +41499,11 @@ async function installPersonaPlex(onInfo, weightTier) {
|
|
|
41475
41499
|
return false;
|
|
41476
41500
|
}
|
|
41477
41501
|
}
|
|
41478
|
-
|
|
41502
|
+
await execAsync(`"${pip}" install --quiet "${join54(repoDir, "moshi")}/."`, { timeout: 3e5 });
|
|
41479
41503
|
} catch (err) {
|
|
41480
41504
|
log(`Moshi install failed: ${err instanceof Error ? err.message : String(err)}`);
|
|
41481
41505
|
try {
|
|
41482
|
-
|
|
41506
|
+
await execAsync(`"${pip}" install --quiet torch torchaudio websockets soundfile huggingface_hub`, { timeout: 3e5, stdio: "pipe" });
|
|
41483
41507
|
} catch {
|
|
41484
41508
|
}
|
|
41485
41509
|
return false;
|
|
@@ -41505,12 +41529,12 @@ async function installPersonaPlex(onInfo, weightTier) {
|
|
|
41505
41529
|
if (isAarch64) {
|
|
41506
41530
|
log("ARM64: Installing bitsandbytes for INT4 inference...");
|
|
41507
41531
|
try {
|
|
41508
|
-
|
|
41532
|
+
await execAsync(`"${pip}" install --quiet bitsandbytes`, { timeout: 12e4, stdio: "pipe" });
|
|
41509
41533
|
} catch {
|
|
41510
41534
|
}
|
|
41511
41535
|
}
|
|
41512
41536
|
try {
|
|
41513
|
-
|
|
41537
|
+
await execAsync(`"${pip}" install --quiet pyloudnorm noisereduce torchaudio`, { timeout: 12e4, stdio: "pipe" });
|
|
41514
41538
|
} catch {
|
|
41515
41539
|
}
|
|
41516
41540
|
const tier = weightTier ?? detectPersonaPlexCapability().weightTier;
|
|
@@ -41520,29 +41544,26 @@ async function installPersonaPlex(onInfo, weightTier) {
|
|
|
41520
41544
|
try {
|
|
41521
41545
|
const tokenArg = repoInfo.needsToken ? "" : "--token ''";
|
|
41522
41546
|
const dlCmd = `"${python}" -c "from huggingface_hub import hf_hub_download; f=hf_hub_download('${repoInfo.repo}', '${repoInfo.file}'${repoInfo.needsToken ? "" : ", token=False"}); print(f)"`;
|
|
41523
|
-
const weightPath =
|
|
41524
|
-
encoding: "utf8",
|
|
41525
|
-
timeout: 6e5,
|
|
41526
|
-
stdio: "pipe",
|
|
41527
|
-
env: { ...process.env }
|
|
41528
|
-
}).trim();
|
|
41547
|
+
const weightPath = (await execAsync(dlCmd, { timeout: 6e5 })).trim();
|
|
41529
41548
|
log(`Weights downloaded: ${repoInfo.file}`);
|
|
41530
41549
|
if (tier !== "original") {
|
|
41531
|
-
log("Downloading Mimi codec
|
|
41532
|
-
|
|
41533
|
-
|
|
41534
|
-
|
|
41535
|
-
|
|
41536
|
-
timeout: 3e5
|
|
41537
|
-
stdio: "pipe"
|
|
41550
|
+
log("Downloading Mimi codec + tokenizer (no token needed)...");
|
|
41551
|
+
const supportFiles = ["tokenizer-e351c8d8-checkpoint125.safetensors", "tokenizer_spm_32k_3.model", "config.json"];
|
|
41552
|
+
for (const sf of supportFiles) {
|
|
41553
|
+
try {
|
|
41554
|
+
await execAsync(`"${python}" -c "from huggingface_hub import hf_hub_download; hf_hub_download('${repoInfo.repo}', '${sf}', token=False)"`, {
|
|
41555
|
+
timeout: 3e5
|
|
41538
41556
|
});
|
|
41539
|
-
|
|
41540
|
-
|
|
41541
|
-
|
|
41542
|
-
|
|
41557
|
+
} catch {
|
|
41558
|
+
try {
|
|
41559
|
+
await execAsync(`"${python}" -c "from huggingface_hub import hf_hub_download; hf_hub_download('nvidia/personaplex-7b-v1', '${sf}')"`, {
|
|
41560
|
+
timeout: 3e5
|
|
41561
|
+
});
|
|
41562
|
+
} catch {
|
|
41563
|
+
}
|
|
41543
41564
|
}
|
|
41544
|
-
} catch {
|
|
41545
41565
|
}
|
|
41566
|
+
log("Codec + tokenizer downloaded.");
|
|
41546
41567
|
}
|
|
41547
41568
|
} catch (err) {
|
|
41548
41569
|
const msg = err instanceof Error ? err.message : String(err);
|
|
@@ -41552,9 +41573,8 @@ async function installPersonaPlex(onInfo, weightTier) {
|
|
|
41552
41573
|
log("Auto-downgrading to INT4 weights (no token required)...");
|
|
41553
41574
|
const nf4 = WEIGHT_REPOS["nf4"];
|
|
41554
41575
|
try {
|
|
41555
|
-
|
|
41556
|
-
timeout: 6e5
|
|
41557
|
-
stdio: "pipe"
|
|
41576
|
+
await execAsync(`"${python}" -c "from huggingface_hub import hf_hub_download; hf_hub_download('${nf4.repo}', '${nf4.file}', token=False)"`, {
|
|
41577
|
+
timeout: 6e5
|
|
41558
41578
|
});
|
|
41559
41579
|
writeFileSync16(join54(PERSONAPLEX_DIR, "weight_tier"), "nf4");
|
|
41560
41580
|
log(`Downloaded INT4 weights instead (${nf4.sizeGB}GB, public).`);
|
|
@@ -41620,9 +41640,22 @@ async function startPersonaPlexDaemon(onInfo) {
|
|
|
41620
41640
|
log(`Dequantization failed \u2014 server will try to load original weights`);
|
|
41621
41641
|
}
|
|
41622
41642
|
}
|
|
41643
|
+
try {
|
|
41644
|
+
const mimiPath = execSync27(`"${venvPython2}" -c "from huggingface_hub import hf_hub_download; print(hf_hub_download('${repoInfo.repo}', 'tokenizer-e351c8d8-checkpoint125.safetensors', token=False))"`, { encoding: "utf8", timeout: 3e4, stdio: "pipe" }).trim();
|
|
41645
|
+
if (existsSync37(mimiPath))
|
|
41646
|
+
extraArgs.push("--mimi-weight", mimiPath);
|
|
41647
|
+
} catch {
|
|
41648
|
+
}
|
|
41649
|
+
try {
|
|
41650
|
+
const tokPath = execSync27(`"${venvPython2}" -c "from huggingface_hub import hf_hub_download; print(hf_hub_download('${repoInfo.repo}', 'tokenizer_spm_32k_3.model', token=False))"`, { encoding: "utf8", timeout: 3e4, stdio: "pipe" }).trim();
|
|
41651
|
+
if (existsSync37(tokPath))
|
|
41652
|
+
extraArgs.push("--tokenizer", tokPath);
|
|
41653
|
+
} catch {
|
|
41654
|
+
}
|
|
41623
41655
|
} catch {
|
|
41624
41656
|
log(`Weight file not found \u2014 server will download on first run`);
|
|
41625
41657
|
}
|
|
41658
|
+
extraArgs.push("--hf-repo", repoInfo.repo);
|
|
41626
41659
|
}
|
|
41627
41660
|
log(`Starting PersonaPlex daemon (${tier} tier)...`);
|
|
41628
41661
|
const child = spawn19(venvPython2, [
|
|
@@ -42051,7 +42084,7 @@ async function detectSystemSpecsAsync() {
|
|
|
42051
42084
|
let gpuVramGB = 0;
|
|
42052
42085
|
let gpuName = "";
|
|
42053
42086
|
try {
|
|
42054
|
-
const { stdout: memInfo } = await
|
|
42087
|
+
const { stdout: memInfo } = await execAsync2("free -b 2>/dev/null || sysctl -n hw.memsize 2>/dev/null", { timeout: 5e3 });
|
|
42055
42088
|
if (memInfo.includes("Mem:")) {
|
|
42056
42089
|
const match = memInfo.match(/^Mem:\s+(\d+)\s+\d+\s+\d+\s+\d+\s+\d+\s+(\d+)/m);
|
|
42057
42090
|
if (match) {
|
|
@@ -42068,7 +42101,7 @@ async function detectSystemSpecsAsync() {
|
|
|
42068
42101
|
} catch {
|
|
42069
42102
|
}
|
|
42070
42103
|
try {
|
|
42071
|
-
const { stdout: nvidiaSmi } = await
|
|
42104
|
+
const { stdout: nvidiaSmi } = await execAsync2("nvidia-smi --query-gpu=memory.total,name --format=csv,noheader,nounits 2>/dev/null", { timeout: 5e3 });
|
|
42072
42105
|
const lines = nvidiaSmi.trim().split("\n");
|
|
42073
42106
|
if (lines.length > 0) {
|
|
42074
42107
|
for (const line of lines) {
|
|
@@ -43510,7 +43543,7 @@ async function createExpandedVariantAsync(baseModel, specs, sizeGB, kvBytesPerTo
|
|
|
43510
43543
|
mkdirSync16(modelDir2, { recursive: true });
|
|
43511
43544
|
const modelfilePath = join55(modelDir2, `Modelfile.${customName}`);
|
|
43512
43545
|
writeFileSync17(modelfilePath, modelfileContent + "\n", "utf8");
|
|
43513
|
-
await
|
|
43546
|
+
await execAsync2(`ollama create ${customName} -f ${modelfilePath}`, {
|
|
43514
43547
|
timeout: 12e4
|
|
43515
43548
|
});
|
|
43516
43549
|
return customName;
|
|
@@ -43668,7 +43701,7 @@ export PATH="${binDir}:$PATH" # Added by open-agents for nvim
|
|
|
43668
43701
|
} catch {
|
|
43669
43702
|
}
|
|
43670
43703
|
}
|
|
43671
|
-
var
|
|
43704
|
+
var execAsync2, QWEN_VARIANTS, _toolSupportCache, _cloudflaredInstallPromise;
|
|
43672
43705
|
var init_setup = __esm({
|
|
43673
43706
|
"packages/cli/dist/tui/setup.js"() {
|
|
43674
43707
|
"use strict";
|
|
@@ -43677,7 +43710,7 @@ var init_setup = __esm({
|
|
|
43677
43710
|
init_config();
|
|
43678
43711
|
init_dist();
|
|
43679
43712
|
init_tui_select();
|
|
43680
|
-
|
|
43713
|
+
execAsync2 = promisify6(exec2);
|
|
43681
43714
|
QWEN_VARIANTS = [
|
|
43682
43715
|
{ tag: "qwen3.5:0.8b", sizeGB: 1, label: "0.8B params (1.0 GB)", cloud: false },
|
|
43683
43716
|
{ tag: "qwen3.5:2b", sizeGB: 2.7, label: "2B params (2.7 GB)", cloud: false },
|
|
@@ -49479,26 +49512,43 @@ async function handleSlashCommand(input, ctx) {
|
|
|
49479
49512
|
renderInfo("Requirements: NVIDIA GPU with \u22658GB VRAM (RTX 3060+, Jetson AGX Orin), CUDA, PyTorch");
|
|
49480
49513
|
return "handled";
|
|
49481
49514
|
}
|
|
49482
|
-
|
|
49515
|
+
const tierInfo = caps.weightTier;
|
|
49516
|
+
renderInfo(`GPU: ${caps.gpuName} (${caps.vramGB.toFixed(0)}GB) \u2192 ${tierInfo} tier${caps.needsHfToken ? "" : " (no HF token needed)"}`);
|
|
49483
49517
|
if (!isPersonaPlexInstalled2()) {
|
|
49484
|
-
renderInfo("
|
|
49485
|
-
|
|
49486
|
-
|
|
49487
|
-
|
|
49488
|
-
|
|
49489
|
-
|
|
49518
|
+
renderInfo("Setting up PersonaPlex in background \u2014 you can keep working...");
|
|
49519
|
+
(async () => {
|
|
49520
|
+
try {
|
|
49521
|
+
const ok = await installPersonaPlex2((msg2) => renderInfo(msg2), caps.weightTier);
|
|
49522
|
+
if (!ok) {
|
|
49523
|
+
renderError("PersonaPlex installation failed.");
|
|
49524
|
+
return;
|
|
49525
|
+
}
|
|
49526
|
+
if (!isPersonaPlexRunning2()) {
|
|
49527
|
+
const url = await startPersonaPlexDaemon2((msg2) => renderInfo(msg2));
|
|
49528
|
+
if (url) {
|
|
49529
|
+
renderInfo(`PersonaPlex ready at ${url} \u2014 use /call for full-duplex voice`);
|
|
49530
|
+
} else {
|
|
49531
|
+
renderError("PersonaPlex daemon failed to start. Check ~/.open-agents/voice/personaplex/daemon.log");
|
|
49532
|
+
}
|
|
49533
|
+
}
|
|
49534
|
+
} catch (e) {
|
|
49535
|
+
renderError(`PersonaPlex setup error: ${e instanceof Error ? e.message : String(e)}`);
|
|
49536
|
+
}
|
|
49537
|
+
})();
|
|
49538
|
+
return "handled";
|
|
49490
49539
|
}
|
|
49491
49540
|
if (isPersonaPlexRunning2()) {
|
|
49492
|
-
renderInfo("PersonaPlex daemon is running.");
|
|
49493
|
-
renderInfo("Use /call to start a full-duplex voice session.");
|
|
49541
|
+
renderInfo("PersonaPlex daemon is running. Use /call for full-duplex voice.");
|
|
49494
49542
|
} else {
|
|
49495
|
-
|
|
49496
|
-
|
|
49497
|
-
|
|
49498
|
-
|
|
49499
|
-
|
|
49500
|
-
|
|
49501
|
-
|
|
49543
|
+
renderInfo("Starting PersonaPlex daemon...");
|
|
49544
|
+
startPersonaPlexDaemon2((msg2) => renderInfo(msg2)).then((url) => {
|
|
49545
|
+
if (url) {
|
|
49546
|
+
renderInfo(`PersonaPlex ready at ${url} \u2014 use /call for full-duplex voice`);
|
|
49547
|
+
} else {
|
|
49548
|
+
renderError("PersonaPlex daemon failed to start. Check daemon.log");
|
|
49549
|
+
}
|
|
49550
|
+
}).catch(() => {
|
|
49551
|
+
});
|
|
49502
49552
|
}
|
|
49503
49553
|
return "handled";
|
|
49504
49554
|
}
|
|
@@ -49590,6 +49640,36 @@ async function handleSlashCommand(input, ctx) {
|
|
|
49590
49640
|
}
|
|
49591
49641
|
if (arg.startsWith("clone")) {
|
|
49592
49642
|
const cloneArg = arg.replace(/^clone\s*/, "").trim();
|
|
49643
|
+
const currentVoiceModel = ctx.voiceGetModel?.() ?? "glados";
|
|
49644
|
+
if (currentVoiceModel === "personaplex") {
|
|
49645
|
+
if (!cloneArg) {
|
|
49646
|
+
const dropResult = await showDropPanel({
|
|
49647
|
+
title: "PersonaPlex Voice Clone \u2014 Drop Audio File",
|
|
49648
|
+
instruction: "Drop a WAV file (4-10s clean speech) to clone into PersonaPlex",
|
|
49649
|
+
allowedExtensions: [".wav", ".mp3", ".ogg", ".flac", ".m4a", ".opus", ".aac"],
|
|
49650
|
+
typeLabel: "Audio files",
|
|
49651
|
+
rl: ctx.rl
|
|
49652
|
+
});
|
|
49653
|
+
if (dropResult.confirmed && dropResult.path) {
|
|
49654
|
+
const voiceName2 = dropResult.path.replace(/.*[\\/]/, "").replace(/\.[^.]+$/, "").replace(/[^a-zA-Z0-9_-]/g, "_");
|
|
49655
|
+
const { clonePersonaPlexVoice: clonePersonaPlexVoice3 } = await Promise.resolve().then(() => (init_personaplex(), personaplex_exports));
|
|
49656
|
+
const result2 = await clonePersonaPlexVoice3(dropResult.path, voiceName2, (m) => renderInfo(m));
|
|
49657
|
+
if (result2)
|
|
49658
|
+
renderInfo(`Voice "${voiceName2}" ready \u2014 use /voice list to see all voices`);
|
|
49659
|
+
} else {
|
|
49660
|
+
renderInfo("Voice clone cancelled.");
|
|
49661
|
+
}
|
|
49662
|
+
return "handled";
|
|
49663
|
+
}
|
|
49664
|
+
const parts = cloneArg.split(/\s+/);
|
|
49665
|
+
const wavPath = parts[0];
|
|
49666
|
+
const voiceName = parts[1] || wavPath.replace(/.*[\\/]/, "").replace(/\.[^.]+$/, "").replace(/[^a-zA-Z0-9_-]/g, "_");
|
|
49667
|
+
const { clonePersonaPlexVoice: clonePersonaPlexVoice2 } = await Promise.resolve().then(() => (init_personaplex(), personaplex_exports));
|
|
49668
|
+
const result = await clonePersonaPlexVoice2(wavPath, voiceName, (m) => renderInfo(m));
|
|
49669
|
+
if (result)
|
|
49670
|
+
renderInfo(`Voice "${voiceName}" ready for PersonaPlex`);
|
|
49671
|
+
return "handled";
|
|
49672
|
+
}
|
|
49593
49673
|
if (!cloneArg) {
|
|
49594
49674
|
const dropResult = await showDropPanel({
|
|
49595
49675
|
title: "Voice Clone \u2014 Drop Audio File",
|
|
@@ -49629,7 +49709,60 @@ async function handleSlashCommand(input, ctx) {
|
|
|
49629
49709
|
return "handled";
|
|
49630
49710
|
}
|
|
49631
49711
|
if (arg === "list" || arg === "ls" || arg === "voices") {
|
|
49632
|
-
|
|
49712
|
+
const currentVoiceModel = ctx.voiceGetModel?.() ?? "glados";
|
|
49713
|
+
if (currentVoiceModel === "personaplex") {
|
|
49714
|
+
const { listPersonaPlexVoices: listPersonaPlexVoices2 } = await Promise.resolve().then(() => (init_personaplex(), personaplex_exports));
|
|
49715
|
+
const voices = listPersonaPlexVoices2();
|
|
49716
|
+
const builtins = voices.filter((v) => v.type === "builtin");
|
|
49717
|
+
const customs = voices.filter((v) => v.type === "custom");
|
|
49718
|
+
renderInfo("PersonaPlex Voices:");
|
|
49719
|
+
renderInfo(" Natural (F): " + builtins.filter((v) => v.name.startsWith("NATF")).map((v) => v.name).join(", "));
|
|
49720
|
+
renderInfo(" Natural (M): " + builtins.filter((v) => v.name.startsWith("NATM")).map((v) => v.name).join(", "));
|
|
49721
|
+
renderInfo(" Variety (F): " + builtins.filter((v) => v.name.startsWith("VARF")).map((v) => v.name).join(", "));
|
|
49722
|
+
renderInfo(" Variety (M): " + builtins.filter((v) => v.name.startsWith("VARM")).map((v) => v.name).join(", "));
|
|
49723
|
+
if (customs.length > 0) {
|
|
49724
|
+
renderInfo(" Custom: " + customs.map((v) => v.name).join(", "));
|
|
49725
|
+
}
|
|
49726
|
+
renderInfo(`
|
|
49727
|
+
Clone a new voice: /voice clone <wav-file> [name]`);
|
|
49728
|
+
} else {
|
|
49729
|
+
await handleVoiceList(ctx);
|
|
49730
|
+
}
|
|
49731
|
+
return "handled";
|
|
49732
|
+
}
|
|
49733
|
+
if (arg === "personaplex" || arg === "pp") {
|
|
49734
|
+
const { detectPersonaPlexCapability: detectPersonaPlexCapability2, isPersonaPlexInstalled: isPersonaPlexInstalled2, installPersonaPlex: installPersonaPlex2, startPersonaPlexDaemon: startPersonaPlexDaemon2, isPersonaPlexRunning: isPersonaPlexRunning2 } = await Promise.resolve().then(() => (init_personaplex(), personaplex_exports));
|
|
49735
|
+
const caps = detectPersonaPlexCapability2();
|
|
49736
|
+
if (!caps.supported) {
|
|
49737
|
+
renderWarning(`PersonaPlex not available: ${caps.reason}`);
|
|
49738
|
+
renderInfo("Requirements: NVIDIA GPU with \u22658GB VRAM (RTX 3060+, Jetson AGX Orin), CUDA, PyTorch");
|
|
49739
|
+
return "handled";
|
|
49740
|
+
}
|
|
49741
|
+
save({ voice: true, voiceModel: "personaplex" });
|
|
49742
|
+
renderInfo(`Voice system: personaplex (${caps.weightTier} tier, ${caps.vramGB.toFixed(0)}GB VRAM)`);
|
|
49743
|
+
if (!isPersonaPlexInstalled2()) {
|
|
49744
|
+
renderInfo("Setting up PersonaPlex in background...");
|
|
49745
|
+
(async () => {
|
|
49746
|
+
try {
|
|
49747
|
+
const ok = await installPersonaPlex2((m) => renderInfo(m), caps.weightTier);
|
|
49748
|
+
if (ok && !isPersonaPlexRunning2()) {
|
|
49749
|
+
const url = await startPersonaPlexDaemon2((m) => renderInfo(m));
|
|
49750
|
+
if (url)
|
|
49751
|
+
renderInfo(`PersonaPlex ready at ${url}`);
|
|
49752
|
+
}
|
|
49753
|
+
} catch (e) {
|
|
49754
|
+
renderError(`PersonaPlex: ${e instanceof Error ? e.message : String(e)}`);
|
|
49755
|
+
}
|
|
49756
|
+
})();
|
|
49757
|
+
} else if (!isPersonaPlexRunning2()) {
|
|
49758
|
+
startPersonaPlexDaemon2((m) => renderInfo(m)).then((url) => {
|
|
49759
|
+
if (url)
|
|
49760
|
+
renderInfo(`PersonaPlex ready at ${url}`);
|
|
49761
|
+
}).catch(() => {
|
|
49762
|
+
});
|
|
49763
|
+
} else {
|
|
49764
|
+
renderInfo("PersonaPlex daemon already running. Use /call for full-duplex voice.");
|
|
49765
|
+
}
|
|
49633
49766
|
return "handled";
|
|
49634
49767
|
}
|
|
49635
49768
|
const msg = await ctx.voiceSetModel(arg);
|
|
@@ -50730,7 +50863,7 @@ async function showConfigEditor(ctx) {
|
|
|
50730
50863
|
{ key: "style", label: "style", kind: "enum", value: String(ctx.getStyle?.() ?? merged.style ?? "balanced"), detail: String(ctx.getStyle?.() ?? merged.style ?? "balanced"), options: [...PRESET_NAMES], settingsKey: "style" },
|
|
50731
50864
|
{ key: "__h_voice__", label: c2.dim("\u2500\u2500 Voice \u2500\u2500"), detail: "", kind: "header", value: "" },
|
|
50732
50865
|
{ key: "voice", label: "voice", kind: "boolean", value: String(merged.voice ?? false), detail: String(merged.voice ?? false), settingsKey: "voice" },
|
|
50733
|
-
{ key: "voiceModel", label: "voiceModel", kind: "enum", value: String(merged.voiceModel ?? "glados"), detail: String(merged.voiceModel ?? "glados"), options: ["glados", "overwatch", "kokoro", "luxtts"], settingsKey: "voiceModel" },
|
|
50866
|
+
{ key: "voiceModel", label: "voiceModel", kind: "enum", value: String(merged.voiceModel ?? "glados"), detail: String(merged.voiceModel ?? "glados"), options: ["glados", "overwatch", "kokoro", "luxtts", "personaplex"], settingsKey: "voiceModel" },
|
|
50734
50867
|
{ key: "__h_auto__", label: c2.dim("\u2500\u2500 Autonomy \u2500\u2500"), detail: "", kind: "header", value: "" },
|
|
50735
50868
|
{ key: "commandsMode", label: "commandsMode", kind: "enum", value: String(ctx.getCommandsMode?.() ?? merged.commandsMode ?? "manual"), detail: String(ctx.getCommandsMode?.() ?? merged.commandsMode ?? "manual"), options: ["manual", "auto"], settingsKey: "commandsMode" },
|
|
50736
50869
|
{ key: "updateMode", label: "updateMode", kind: "enum", value: String(merged.updateMode ?? "auto"), detail: String(merged.updateMode ?? "auto"), options: ["auto", "manual"], settingsKey: "updateMode" },
|
package/package.json
CHANGED