open-agents-ai 0.101.0 → 0.101.2

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 CHANGED
@@ -29251,30 +29251,51 @@ function runWithSudo(cmd, password, timeoutMs = 12e4) {
29251
29251
  timeout: timeoutMs,
29252
29252
  env: { ...process.env, DEBIAN_FRONTEND: "noninteractive" }
29253
29253
  });
29254
- return true;
29255
- } catch {
29256
- return false;
29254
+ return "ok";
29255
+ } catch (err) {
29256
+ const stderr = err?.stderr?.toString() ?? "";
29257
+ if (/incorrect password|authentication failure|Sorry, try again|not in the sudoers/i.test(stderr)) {
29258
+ return "auth_fail";
29259
+ }
29260
+ return "cmd_fail";
29257
29261
  }
29258
29262
  }
29259
- async function sudoInstall(cmd, getSudoPassword, log, cachedPasswordRef, timeoutMs = 12e4) {
29260
- if (cachedPasswordRef.value) {
29261
- if (runWithSudo(cmd, cachedPasswordRef.value, timeoutMs))
29262
- return true;
29263
+ function validateSudoPassword(password) {
29264
+ return runWithSudo("true", password, 1e4) === "ok";
29265
+ }
29266
+ async function acquireSudoPassword(getSudoPassword, log, cachedPasswordRef) {
29267
+ if (cachedPasswordRef.value && validateSudoPassword(cachedPasswordRef.value)) {
29268
+ return cachedPasswordRef.value;
29263
29269
  }
29270
+ if (trySudoPasswordless("true", 1e4)) {
29271
+ return "";
29272
+ }
29273
+ for (let attempt = 0; attempt < 2; attempt++) {
29274
+ if (attempt > 0)
29275
+ log("Authentication failed \u2014 please re-enter password.");
29276
+ const pw = await getSudoPassword();
29277
+ if (!pw)
29278
+ return null;
29279
+ if (validateSudoPassword(pw)) {
29280
+ cachedPasswordRef.value = pw;
29281
+ return pw;
29282
+ }
29283
+ }
29284
+ return null;
29285
+ }
29286
+ async function sudoInstall(cmd, getSudoPassword, log, cachedPasswordRef, timeoutMs = 12e4) {
29264
29287
  if (trySudoPasswordless(cmd, timeoutMs))
29265
29288
  return true;
29266
- const pw = await getSudoPassword();
29267
- if (pw) {
29268
- cachedPasswordRef.value = pw;
29269
- if (runWithSudo(cmd, pw, timeoutMs))
29270
- return true;
29271
- log("Authentication failed \u2014 please re-enter password.");
29272
- const pw2 = await getSudoPassword();
29273
- if (pw2) {
29274
- cachedPasswordRef.value = pw2;
29275
- if (runWithSudo(cmd, pw2, timeoutMs))
29276
- return true;
29277
- }
29289
+ const pw = await acquireSudoPassword(getSudoPassword, log, cachedPasswordRef);
29290
+ if (pw === null)
29291
+ return false;
29292
+ if (pw === "")
29293
+ return false;
29294
+ const result = runWithSudo(cmd, pw, timeoutMs);
29295
+ if (result === "ok")
29296
+ return true;
29297
+ if (result === "cmd_fail") {
29298
+ log(`Install command failed (not an auth issue) \u2014 package may not be available for this OS.`);
29278
29299
  }
29279
29300
  return false;
29280
29301
  }
@@ -29283,108 +29304,68 @@ async function ensureVisionDeps(onInfo, getSudoPassword) {
29283
29304
  });
29284
29305
  const cachedPasswordRef = { value: null };
29285
29306
  const getPassword = getSudoPassword ?? (() => Promise.resolve(null));
29286
- if (!hasCmd("tesseract")) {
29287
- const pm2 = detectPkgManager();
29288
- if (pm2) {
29289
- const pkgMap = {
29290
- apt: { cmd: "apt-get install -y tesseract-ocr", needsSudo: true },
29291
- dnf: { cmd: "dnf install -y tesseract", needsSudo: true },
29292
- pacman: { cmd: "pacman -S --noconfirm tesseract", needsSudo: true },
29293
- brew: { cmd: "brew install tesseract", needsSudo: false },
29294
- choco: { cmd: "choco install -y tesseract", needsSudo: false }
29295
- };
29296
- const pkg = pkgMap[pm2];
29297
- if (pkg.needsSudo) {
29298
- log("Installing tesseract-ocr...");
29299
- const ok = await sudoInstall(pkg.cmd, getPassword, log, cachedPasswordRef);
29300
- if (ok && hasCmd("tesseract")) {
29301
- log("tesseract-ocr installed successfully.");
29302
- } else {
29303
- log("tesseract-ocr could not be installed \u2014 OCR features will be limited.");
29304
- }
29305
- } else {
29306
- log("Installing tesseract-ocr...");
29307
- try {
29308
- execSync25(pkg.cmd, { stdio: "pipe", timeout: 12e4 });
29309
- if (hasCmd("tesseract")) {
29310
- log("tesseract-ocr installed successfully.");
29311
- } else {
29312
- log("tesseract-ocr install completed but binary not found \u2014 OCR features will be limited.");
29313
- }
29314
- } catch {
29315
- log("tesseract-ocr could not be installed \u2014 OCR features will be limited.");
29316
- }
29317
- }
29318
- } else {
29319
- log("No supported package manager detected \u2014 tesseract OCR unavailable.");
29320
- }
29321
- }
29322
- const pdfDeps = [
29323
- {
29324
- binary: "pdftotext",
29325
- label: "poppler-utils (pdftotext)",
29326
- pkgMap: {
29327
- apt: { cmd: "apt-get install -y poppler-utils", needsSudo: true },
29328
- dnf: { cmd: "dnf install -y poppler-utils", needsSudo: true },
29329
- pacman: { cmd: "pacman -S --noconfirm poppler", needsSudo: true },
29330
- brew: { cmd: "brew install poppler", needsSudo: false },
29331
- choco: { cmd: "choco install -y poppler", needsSudo: false }
29332
- }
29333
- },
29334
- {
29335
- binary: "gs",
29336
- label: "ghostscript",
29337
- pkgMap: {
29338
- apt: { cmd: "apt-get install -y ghostscript", needsSudo: true },
29339
- dnf: { cmd: "dnf install -y ghostscript", needsSudo: true },
29340
- pacman: { cmd: "pacman -S --noconfirm ghostscript", needsSudo: true },
29341
- brew: { cmd: "brew install ghostscript", needsSudo: false },
29342
- choco: { cmd: "choco install -y ghostscript", needsSudo: false }
29343
- }
29344
- },
29345
- {
29346
- binary: "ocrmypdf",
29347
- label: "ocrmypdf",
29348
- pkgMap: {
29349
- apt: { cmd: "apt-get install -y ocrmypdf", needsSudo: true },
29350
- dnf: { cmd: "dnf install -y ocrmypdf", needsSudo: true },
29351
- pacman: { cmd: "pacman -S --noconfirm ocrmypdf", needsSudo: true },
29352
- brew: { cmd: "brew install ocrmypdf", needsSudo: false },
29353
- choco: { cmd: "choco install -y ocrmypdf", needsSudo: false }
29354
- }
29355
- }
29307
+ const allDeps = [
29308
+ { binary: "tesseract", label: "tesseract-ocr", pkgs: { apt: "tesseract-ocr", dnf: "tesseract", pacman: "tesseract", brew: "tesseract", choco: "tesseract" } },
29309
+ { binary: "pdftotext", label: "poppler-utils", pkgs: { apt: "poppler-utils", dnf: "poppler-utils", pacman: "poppler", brew: "poppler", choco: "poppler" } },
29310
+ { binary: "gs", label: "ghostscript", pkgs: { apt: "ghostscript", dnf: "ghostscript", pacman: "ghostscript", brew: "ghostscript", choco: "ghostscript" } },
29311
+ { binary: "ocrmypdf", label: "ocrmypdf", pkgs: { apt: "ocrmypdf", dnf: "ocrmypdf", pacman: "ocrmypdf", brew: "ocrmypdf", choco: "ocrmypdf" } }
29356
29312
  ];
29357
29313
  {
29358
29314
  const pm2 = detectPkgManager();
29359
- for (const dep of pdfDeps) {
29360
- if (hasCmd(dep.binary))
29361
- continue;
29362
- if (!pm2) {
29363
- log(`No supported package manager detected \u2014 ${dep.label} unavailable.`);
29364
- continue;
29365
- }
29366
- const pkg = dep.pkgMap[pm2];
29367
- if (!pkg)
29368
- continue;
29369
- if (pkg.needsSudo) {
29370
- log(`Installing ${dep.label}...`);
29371
- const ok = await sudoInstall(pkg.cmd, getPassword, log, cachedPasswordRef);
29372
- if (ok && hasCmd(dep.binary)) {
29373
- log(`${dep.label} installed successfully.`);
29315
+ const missing = allDeps.filter((d) => !hasCmd(d.binary));
29316
+ if (missing.length === 0) {
29317
+ } else if (!pm2) {
29318
+ for (const d of missing)
29319
+ log(`No supported package manager \u2014 ${d.label} unavailable.`);
29320
+ } else {
29321
+ const pkgNames = missing.map((d) => d.pkgs[pm2]).filter(Boolean);
29322
+ if (pkgNames.length === 0) {
29323
+ for (const d of missing)
29324
+ log(`${d.label} not available for ${pm2}.`);
29325
+ } else {
29326
+ const labels = missing.map((d) => d.label).join(", ");
29327
+ log(`Installing ${labels}...`);
29328
+ const needsSudo = pm2 !== "brew" && pm2 !== "choco";
29329
+ let batchCmd;
29330
+ switch (pm2) {
29331
+ case "apt":
29332
+ batchCmd = `apt-get update -qq && apt-get install -y -qq ${pkgNames.join(" ")}`;
29333
+ break;
29334
+ case "dnf":
29335
+ batchCmd = `dnf install -y -q ${pkgNames.join(" ")}`;
29336
+ break;
29337
+ case "pacman":
29338
+ batchCmd = `pacman -S --noconfirm ${pkgNames.join(" ")}`;
29339
+ break;
29340
+ case "brew":
29341
+ batchCmd = `brew install ${pkgNames.join(" ")}`;
29342
+ break;
29343
+ case "choco":
29344
+ batchCmd = `choco install -y ${pkgNames.join(" ")}`;
29345
+ break;
29346
+ default:
29347
+ batchCmd = `echo "unsupported pm: ${pm2}" && exit 1`;
29348
+ break;
29349
+ }
29350
+ let ok = false;
29351
+ if (needsSudo) {
29352
+ ok = await sudoInstall(batchCmd, getPassword, log, cachedPasswordRef, 18e4);
29374
29353
  } else {
29375
- log(`${dep.label} could not be installed \u2014 PDF OCR features will be limited.`);
29354
+ try {
29355
+ execSync25(batchCmd, { stdio: "pipe", timeout: 18e4 });
29356
+ ok = true;
29357
+ } catch {
29358
+ ok = false;
29359
+ }
29376
29360
  }
29377
- } else {
29378
- log(`Installing ${dep.label}...`);
29379
- try {
29380
- execSync25(pkg.cmd, { stdio: "pipe", timeout: 12e4 });
29381
- if (hasCmd(dep.binary)) {
29382
- log(`${dep.label} installed successfully.`);
29361
+ for (const d of missing) {
29362
+ if (hasCmd(d.binary)) {
29363
+ log(`${d.label} installed.`);
29364
+ } else if (!ok) {
29365
+ log(`${d.label} could not be installed \u2014 features will be limited.`);
29383
29366
  } else {
29384
- log(`${dep.label} install completed but binary not found.`);
29367
+ log(`${d.label} install completed but binary not found.`);
29385
29368
  }
29386
- } catch {
29387
- log(`${dep.label} could not be installed \u2014 PDF OCR features will be limited.`);
29388
29369
  }
29389
29370
  }
29390
29371
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "open-agents-ai",
3
- "version": "0.101.0",
3
+ "version": "0.101.2",
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",
@@ -56,6 +56,15 @@ PARALLEL SUB-AGENT PATTERN (preferred for independent tasks):
56
56
  2. Both sub-agents run simultaneously against the backend
57
57
  3. Use task_status() to poll, then task_output() to read results
58
58
 
59
+ WHEN TO DECOMPOSE — assess before starting complex work:
60
+ - Task touches 3+ independent files/modules? → sub-agents can work on each in parallel
61
+ - Need to research AND implement? → sub-agent explores while you start coding
62
+ - Multiple test suites to validate? → background_run each suite concurrently
63
+ - Task has clearly separable phases (e.g. frontend + backend, or docs + code)? → parallel sub-agents
64
+ - Simple single-file edit or sequential dependency chain? → do it yourself, no sub-agents needed
65
+
66
+ You don't need to be asked to parallelize. If you recognize independent subtasks, delegate them.
67
+
59
68
  ## Skills (AIWG)
60
69
 
61
70
  - skill_list: Discover available skills — shows descriptions and trigger patterns. Use filter param to search.
@@ -24,12 +24,20 @@ NEVER say "I can't do that". ALWAYS attempt the task using your tools. If a tool
24
24
  - nexus: P2P agent networking (connect, join_room, send_message, discover_peers, invoke_capability, register_capability, block_peer, metering_status, room_members, wallet, etc.)
25
25
  - task_complete: Signal completion with a summary
26
26
  - background_run / task_status / task_output / task_stop: Background tasks
27
+ - sub_agent: Delegate a subtask to an independent agent (use background=true for parallel work)
27
28
  - batch_edit: Multiple edits across files in one call
28
29
  - skill_list / skill_execute / skill_build: Discover, load, and generate skills (use on-demand)
29
30
 
31
+ Parallelism: Multiple read-only tool calls in ONE response run in parallel automatically.
32
+ For complex tasks touching 3+ independent files/modules, delegate each to a sub_agent:
33
+ sub_agent({task: "Fix module-a — read test.js for expected behavior", background: true})
34
+ sub_agent({task: "Fix module-b — read test.js for expected behavior", background: true})
35
+ Launch ALL sub_agent calls in ONE response. This saves your context window for other work.
36
+
30
37
  ## Workflow
31
38
 
32
- 1. EXPLORE: Use find_files, grep_search, file_read to understand the codebase
39
+ 1. If task mentions 3+ independent modules/files: delegate each to a sub_agent (saves context)
40
+ 2. EXPLORE: Use find_files, grep_search, file_read to understand the codebase
33
41
  2. IMPLEMENT: Make changes with file_edit (preferred) or file_write
34
42
  3. VALIDATE: Run tests/build with shell. Read FULL output.
35
43
  4. FIX: If validation fails, fix the specific issue and re-validate