@livx.cc/agentx 0.99.41 → 0.99.42
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/cli.js +58 -2
- package/dist/cli.js.map +1 -1
- package/dist/index.js +58 -2
- package/dist/index.js.map +1 -1
- package/dist/tools.shell.d.ts +8 -0
- package/dist/tools.shell.js +58 -2
- package/dist/tools.shell.js.map +1 -1
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -2015,7 +2015,7 @@ function makeRealShellTool(options) {
|
|
|
2015
2015
|
return { ...this, description: rebound.description, run: rebound.run, withCwd: rebound.withCwd };
|
|
2016
2016
|
},
|
|
2017
2017
|
get description() {
|
|
2018
|
-
return
|
|
2018
|
+
return "Run a shell command via /bin/sh in the working directory. Executes any installed binary \u2014 ls, cat, grep, git, bun, node, curl, scripts, etc. Returns combined stdout+stderr; non-zero exits are prefixed `[exit N]`. Runs non-interactively with no terminal (stdin is /dev/null): commands that prompt for input fail fast rather than hang \u2014 for privileged actions use a non-interactive flag (e.g. `sudo -n`), or ask the user to run the command themselves. " + (options.registry?.adopt ? `A command still running after ${defaultTimeoutMs}ms is NOT killed \u2014 it is handed to a background job and you get its id, so you can keep checking on it (\`[still running]\`). Pass \`timeoutMs\` (max ${maxTimeoutMs}) to wait longer in the foreground, and always bound network commands yourself (e.g. \`curl -m 10\`). ` : `Each command is killed after ${defaultTimeoutMs}ms (result \`[exit 124]\` with whatever output it produced) \u2014 pass \`timeoutMs\` (max ${maxTimeoutMs}) for a legitimately slower command, and always bound network commands yourself (e.g. \`curl -m 10\`). `) + backgroundDoc();
|
|
2019
2019
|
},
|
|
2020
2020
|
// Declared so transports above the agent loop can size their own deadline with headroom (see AgentTool.maxDurationMs).
|
|
2021
2021
|
maxDurationMs: maxTimeoutMs,
|
|
@@ -2054,9 +2054,12 @@ function makeRealShellTool(options) {
|
|
|
2054
2054
|
else ctx.signal.addEventListener("abort", onAbort, { once: true });
|
|
2055
2055
|
}
|
|
2056
2056
|
let timedOut = false;
|
|
2057
|
-
|
|
2057
|
+
let onDeadline = () => {
|
|
2058
2058
|
timedOut = true;
|
|
2059
2059
|
ctl.abort();
|
|
2060
|
+
};
|
|
2061
|
+
const timer = setTimeout(() => {
|
|
2062
|
+
onDeadline();
|
|
2060
2063
|
}, timeoutMs);
|
|
2061
2064
|
let pend = "";
|
|
2062
2065
|
let flushTimer = null;
|
|
@@ -2087,6 +2090,18 @@ function makeRealShellTool(options) {
|
|
|
2087
2090
|
}
|
|
2088
2091
|
if (ctl.signal.aborted) killGroup(proc, "SIGKILL");
|
|
2089
2092
|
else ctl.signal.addEventListener("abort", () => killGroup(proc, "SIGKILL"), { once: true });
|
|
2093
|
+
const registry = options.registry;
|
|
2094
|
+
if (registry?.adopt) {
|
|
2095
|
+
onDeadline = () => {
|
|
2096
|
+
timedOut = true;
|
|
2097
|
+
if (settled) return;
|
|
2098
|
+
flushEmit(ctx);
|
|
2099
|
+
proc.stdout?.off?.("data", collect);
|
|
2100
|
+
proc.stderr?.off?.("data", collect);
|
|
2101
|
+
const id = registry.adopt(cmd, proc, out);
|
|
2102
|
+
finish(handoffFor(timeoutMs, id, clean(out), !!registry.notifiesOnExit));
|
|
2103
|
+
};
|
|
2104
|
+
}
|
|
2090
2105
|
const collect = (chunk) => {
|
|
2091
2106
|
const s = typeof chunk === "string" ? chunk : chunk?.toString?.("utf8") ?? "";
|
|
2092
2107
|
out += s;
|
|
@@ -2119,6 +2134,12 @@ function makeRealShellTool(options) {
|
|
|
2119
2134
|
}
|
|
2120
2135
|
};
|
|
2121
2136
|
}
|
|
2137
|
+
function handoffFor(timeoutMs, id, body, notifies) {
|
|
2138
|
+
const head = `[still running] exceeded ${timeoutMs}ms, so it was handed to background job ${id} \u2014 NOT killed, it is still going. Check on it with ShellOutput({id:"${id}"}) / ShellStatus({id:"${id}"}), stop it with ShellKill({id:"${id}"}). ` + (notifies ? "Its completion will be reported to you, so you may continue with other work meanwhile." : "Nothing will tell you when it finishes \u2014 poll it yourself before you rely on its result.");
|
|
2139
|
+
return body ? `${head}
|
|
2140
|
+
Output so far:
|
|
2141
|
+
${body}` : head;
|
|
2142
|
+
}
|
|
2122
2143
|
function reasonFor(timedOut, timeoutMs, body) {
|
|
2123
2144
|
const head = timedOut ? `[exit 124] timed out after ${timeoutMs}ms (killed). Re-running this command unchanged will time out again. Either re-run it with background:true (returns a job id immediately; poll with ShellOutput/ShellStatus, stop with ShellKill) or narrow it so it can finish \u2014 bound it, scope it, or ask for less.` : "[exit 130] cancelled (killed)";
|
|
2124
2145
|
return body ? `${head}
|
|
@@ -2258,6 +2279,41 @@ var init_tools_shell = __esm({
|
|
|
2258
2279
|
list() {
|
|
2259
2280
|
return [...this.jobs].map(([id, j]) => ({ id, command: j.command, status: j.status }));
|
|
2260
2281
|
}
|
|
2282
|
+
/**
|
|
2283
|
+
* Take over an ALREADY-RUNNING child as a background job. A foreground command that outruns its
|
|
2284
|
+
* timeout is not necessarily a hung command — killing it throws away work that was nearly done and,
|
|
2285
|
+
* worse, a launcher that spawned its own detached worker leaves that worker running with nothing
|
|
2286
|
+
* tracking it. Adopting hands the model a handle instead: the command keeps going, its completion
|
|
2287
|
+
* is reported like any other job, and `seed` carries the output produced before the handoff.
|
|
2288
|
+
*/
|
|
2289
|
+
adopt(command, proc, seed = "") {
|
|
2290
|
+
const id = `job-${++this.seq}`;
|
|
2291
|
+
const max = this.cfg.maxBuffer ?? 256 * 1024;
|
|
2292
|
+
const job = { command, buf: seed.slice(-max), status: "running", proc };
|
|
2293
|
+
const append = (chunk) => {
|
|
2294
|
+
const s = typeof chunk === "string" ? chunk : chunk?.toString?.("utf8") ?? "";
|
|
2295
|
+
job.buf = (job.buf + s).slice(-max);
|
|
2296
|
+
};
|
|
2297
|
+
proc.stdout?.on("data", append);
|
|
2298
|
+
proc.stderr?.on("data", append);
|
|
2299
|
+
proc.on("error", (err) => {
|
|
2300
|
+
if (job.status === "running") {
|
|
2301
|
+
job.status = "error";
|
|
2302
|
+
append(`
|
|
2303
|
+
[error] ${err?.message ?? err}`);
|
|
2304
|
+
this.notifyExit(id, job);
|
|
2305
|
+
}
|
|
2306
|
+
});
|
|
2307
|
+
proc.on("close", (code) => {
|
|
2308
|
+
if (job.status === "running") {
|
|
2309
|
+
job.status = "exited";
|
|
2310
|
+
job.exitCode = code ?? void 0;
|
|
2311
|
+
this.notifyExit(id, job);
|
|
2312
|
+
}
|
|
2313
|
+
});
|
|
2314
|
+
this.jobs.set(id, job);
|
|
2315
|
+
return id;
|
|
2316
|
+
}
|
|
2261
2317
|
kill(id) {
|
|
2262
2318
|
const j = this.jobs.get(id);
|
|
2263
2319
|
if (!j) return false;
|