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.
Files changed (2) hide show
  1. package/dist/index.js +196 -63
  2. 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 execAsync2 = (cmd, opts = {}) => new Promise((res, rej) => {
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 execAsync2("npm root -g", { timeout: 5e3 });
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 execAsync2("npm view open-agents-nexus version 2>/dev/null", { timeout: 8e3 });
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 execAsync2(`npm install open-agents-nexus@${latestRaw} --save 2>&1`, {
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 execAsync2("npm install open-agents-nexus@latest 2>&1", {
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 execAsync2("npm install -g open-agents-nexus@latest 2>&1", { timeout: 12e4 });
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 execAsync2("npm root -g", { timeout: 5e3 });
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: execFile7 } = await import("node:child_process");
25044
+ const { execFile: execFile8 } = await import("node:child_process");
25045
25045
  const { promisify: promisify7 } = await import("node:util");
25046
- const execFileAsync6 = promisify7(execFile7);
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
- execSync27(`python3 -m venv${ssp} "${venvDir}"`, { timeout: 6e4, stdio: "pipe" });
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
- execSync27("curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- -y", { timeout: 12e4, stdio: "pipe" });
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
- execSync27(`"${pip}" install --quiet maturin`, { timeout: 6e4, stdio: "pipe" });
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
- execSync27(`git clone https://github.com/NVIDIA/personaplex.git "${repoDir}"`, { timeout: 12e4, stdio: "pipe" });
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
- execSync27(`${rustEnv} "${pip}" install --quiet --no-binary sphn sphn`, { timeout: 3e5, stdio: "pipe", shell: "/bin/bash" });
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
- execSync27(`"${pip}" install --quiet "${join54(repoDir, "moshi")}/."`, { timeout: 3e5, stdio: "pipe" });
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
- execSync27(`"${pip}" install --quiet torch torchaudio websockets soundfile huggingface_hub`, { timeout: 3e5, stdio: "pipe" });
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
- execSync27(`"${pip}" install --quiet bitsandbytes`, { timeout: 12e4, stdio: "pipe" });
41532
+ await execAsync(`"${pip}" install --quiet bitsandbytes`, { timeout: 12e4, stdio: "pipe" });
41509
41533
  } catch {
41510
41534
  }
41511
41535
  }
41512
41536
  try {
41513
- execSync27(`"${pip}" install --quiet pyloudnorm noisereduce torchaudio`, { timeout: 12e4, stdio: "pipe" });
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 = execSync27(dlCmd, {
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 and tokenizer...");
41532
- try {
41533
- const hasToken = !!(process.env["HF_TOKEN"] || process.env["HUGGING_FACE_HUB_TOKEN"]);
41534
- if (hasToken) {
41535
- execSync27(`"${python}" -c "from huggingface_hub import hf_hub_download; hf_hub_download('nvidia/personaplex-7b-v1', 'tokenizer_spm_32k_3.model'); hf_hub_download('nvidia/personaplex-7b-v1', 'tokenizer-e351c8d8-checkpoint125.safetensors')"`, {
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
- log("Codec + tokenizer downloaded.");
41540
- } else {
41541
- log("Note: Mimi codec needs HF_TOKEN on first run (set HF_TOKEN env var).");
41542
- log("Weights themselves are public \u2014 no token needed for the model.");
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
- execSync27(`"${python}" -c "from huggingface_hub import hf_hub_download; hf_hub_download('${nf4.repo}', '${nf4.file}', token=False)"`, {
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 execAsync("free -b 2>/dev/null || sysctl -n hw.memsize 2>/dev/null", { timeout: 5e3 });
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 execAsync("nvidia-smi --query-gpu=memory.total,name --format=csv,noheader,nounits 2>/dev/null", { timeout: 5e3 });
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 execAsync(`ollama create ${customName} -f ${modelfilePath}`, {
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 execAsync, QWEN_VARIANTS, _toolSupportCache, _cloudflaredInstallPromise;
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
- execAsync = promisify6(exec2);
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
- renderInfo(`GPU: ${caps.gpuName} (${caps.vramGB.toFixed(0)}GB VRAM) \u2014 PersonaPlex compatible \u2713`);
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("Installing PersonaPlex-7B (~14GB download)...");
49485
- const ok = await installPersonaPlex2((msg2) => renderInfo(msg2));
49486
- if (!ok) {
49487
- renderError("PersonaPlex installation failed.");
49488
- return "handled";
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
- const url = await startPersonaPlexDaemon2((msg2) => renderInfo(msg2));
49496
- if (url) {
49497
- renderInfo(`PersonaPlex ready at ${url}`);
49498
- renderInfo("Use /call to start a full-duplex voice session with PersonaPlex.");
49499
- } else {
49500
- renderError("PersonaPlex daemon failed to start.");
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
- await handleVoiceList(ctx);
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
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "open-agents-ai",
3
- "version": "0.185.32",
3
+ "version": "0.185.34",
4
4
  "description": "AI coding agent powered by open-source models (Ollama/vLLM) — interactive TUI with agentic tool-calling loop",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",