@livx.cc/agentx 0.99.41 → 0.99.43
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/{Agent-DydgLoT-.d.ts → Agent-f4um2q8E.d.ts} +3 -1
- package/dist/cli.d.ts +1 -1
- package/dist/cli.js +72 -14
- package/dist/cli.js.map +1 -1
- package/dist/index.d.ts +2 -2
- package/dist/index.js +72 -14
- 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.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { a as AgentOptions, H as Hooks, i as RunResult, A as Agent } from './Agent-
|
|
2
|
-
export { C as ChatFragment, b as CompactResult, D as DEFAULT_MUTATING, c as Decision, P as PermissionOptions, d as PermissionPolicy, e as PermissionRule, f as PreToolUseDecision, R as ReasoningEffort, g as RecordingHooks, h as RecordingLifecycle, T as ToolUse, j as ToolUseMeta, k as composeHooks, l as estimateTokens, p as planMode, r as reasoningToChatFragment } from './Agent-
|
|
1
|
+
import { a as AgentOptions, H as Hooks, i as RunResult, A as Agent } from './Agent-f4um2q8E.js';
|
|
2
|
+
export { C as ChatFragment, b as CompactResult, D as DEFAULT_MUTATING, c as Decision, P as PermissionOptions, d as PermissionPolicy, e as PermissionRule, f as PreToolUseDecision, R as ReasoningEffort, g as RecordingHooks, h as RecordingLifecycle, T as ToolUse, j as ToolUseMeta, k as composeHooks, l as estimateTokens, p as planMode, r as reasoningToChatFragment } from './Agent-f4um2q8E.js';
|
|
3
3
|
export { MODEL_ALIASES, ModelSwitch, ResolveModelSwitchOpts, modelShortLabel, resolveModelAlias, resolveModelSwitch } from './models.js';
|
|
4
4
|
import { IFilesystem, FileMetadata } from '@livx.cc/wcli/core';
|
|
5
5
|
export { CommandExecutor, FileMetadata, IFilesystem, IndexedDbFilesystem, MemFilesystem, registerHeadlessCommands } from '@livx.cc/wcli/core';
|
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;
|
|
@@ -3793,7 +3849,9 @@ var AgentOptions = class {
|
|
|
3793
3849
|
/** Retry budget for an EMPTY/silent-turn (a delegated-runtime wedge: cursor's warm helper spins then
|
|
3794
3850
|
* returns a content-less end, surfaced as `code:'empty'`/`code:'cursor_silent'`). Tuned WIDER than the
|
|
3795
3851
|
* network-drop budget (fixed 2) because clearing a wedge needs several reap+respawn cycles — each retry
|
|
3796
|
-
* hits a FRESH cursor session (the adapter evicts the wedged warm helper on the silent-end
|
|
3852
|
+
* hits a FRESH cursor session (the adapter evicts the wedged warm helper on the silent-end; a stall-watchdog
|
|
3853
|
+
* cancel is NOT this class — it is classified `stall`, and the watchdog's coded abort reason is what tells
|
|
3854
|
+
* the adapter to evict on that path too). Still bounded:
|
|
3797
3855
|
* after exhaustion the turn surfaces `finishReason:'empty'` (non-zero exit), never infinite, never silent.
|
|
3798
3856
|
* Env: AGENTX_EMPTY_RETRIES. */
|
|
3799
3857
|
emptyRetries = envInt("AGENTX_EMPTY_RETRIES", 4);
|
|
@@ -4312,6 +4370,7 @@ var Agent = class _Agent {
|
|
|
4312
4370
|
try {
|
|
4313
4371
|
const r = await o.ai.chat({ model: o.model, messages: sent, tools: sentTools, stream: true, signal: stall.signal, ...o.toolChoice ? { toolChoice: o.toolChoice } : {}, ...reasonOpts });
|
|
4314
4372
|
res = await this.consumeStream(r, stall.poke);
|
|
4373
|
+
if (stall.stalled()) throw stall.reclassify(void 0);
|
|
4315
4374
|
} catch (err) {
|
|
4316
4375
|
throw stall.reclassify(err);
|
|
4317
4376
|
} finally {
|
|
@@ -4346,7 +4405,7 @@ var Agent = class _Agent {
|
|
|
4346
4405
|
if (err?.code === "budget") return kill("budget");
|
|
4347
4406
|
if (err?.code === "stall") {
|
|
4348
4407
|
log6.warn(`model stalled out after retries: ${err?.message ?? err}`);
|
|
4349
|
-
return kill("timeout");
|
|
4408
|
+
return { ...kill("timeout"), error: err };
|
|
4350
4409
|
}
|
|
4351
4410
|
if (o.signal?.aborted || isAbortError(err)) return kill("aborted");
|
|
4352
4411
|
if (err?.code === "empty" || err?.code === "cursor_silent") {
|
|
@@ -4494,31 +4553,30 @@ var Agent = class _Agent {
|
|
|
4494
4553
|
if (parent?.aborted) ac.abort();
|
|
4495
4554
|
else parent?.addEventListener("abort", onParentAbort, { once: true });
|
|
4496
4555
|
let timer;
|
|
4556
|
+
const stallError = () => {
|
|
4557
|
+
const e = new Error(`model stalled: no stream output for ${stallMs >= 1e3 ? `${Math.round(stallMs / 1e3)}s` : `${stallMs}ms`}`);
|
|
4558
|
+
e.code = "stall";
|
|
4559
|
+
return e;
|
|
4560
|
+
};
|
|
4497
4561
|
const poke = () => {
|
|
4498
4562
|
if (!stallMs) return;
|
|
4499
4563
|
if (timer) clearTimeout(timer);
|
|
4500
4564
|
timer = setTimeout(() => {
|
|
4501
4565
|
fired = true;
|
|
4502
|
-
ac.abort();
|
|
4566
|
+
ac.abort(stallError());
|
|
4503
4567
|
}, stallMs);
|
|
4504
4568
|
};
|
|
4505
4569
|
poke();
|
|
4570
|
+
const stalled = () => fired && !parent?.aborted;
|
|
4506
4571
|
return {
|
|
4507
4572
|
signal: ac.signal,
|
|
4508
4573
|
poke,
|
|
4574
|
+
stalled,
|
|
4509
4575
|
clear: () => {
|
|
4510
4576
|
if (timer) clearTimeout(timer);
|
|
4511
4577
|
parent?.removeEventListener("abort", onParentAbort);
|
|
4512
4578
|
},
|
|
4513
|
-
|
|
4514
|
-
reclassify: (err) => {
|
|
4515
|
-
if (fired && !parent?.aborted) {
|
|
4516
|
-
const e = new Error(`model stalled: no stream output for ${stallMs >= 1e3 ? `${Math.round(stallMs / 1e3)}s` : `${stallMs}ms`}`);
|
|
4517
|
-
e.code = "stall";
|
|
4518
|
-
return e;
|
|
4519
|
-
}
|
|
4520
|
-
return err;
|
|
4521
|
-
}
|
|
4579
|
+
reclassify: (err) => stalled() ? stallError() : err
|
|
4522
4580
|
};
|
|
4523
4581
|
}
|
|
4524
4582
|
/** A clean-stop turn that carries no assistant text AND no tool calls (native or delegated) — a
|