@livx.cc/agentx 0.99.24 → 0.99.26
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.d.ts +1 -0
- package/dist/cli.js +63 -11
- package/dist/cli.js.map +1 -1
- package/dist/index.d.ts +25 -5
- package/dist/index.js +33 -8
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/cli.d.ts
CHANGED
|
@@ -144,6 +144,7 @@ interface Args {
|
|
|
144
144
|
worktree?: string;
|
|
145
145
|
updateCheck?: boolean;
|
|
146
146
|
update?: boolean;
|
|
147
|
+
listModels?: boolean;
|
|
147
148
|
}
|
|
148
149
|
declare function parseArgs(argv: string[]): Args;
|
|
149
150
|
declare function makeHost(format?: 'text' | 'json' | 'stream-json', opts?: {
|
package/dist/cli.js
CHANGED
|
@@ -6649,6 +6649,9 @@ var DuplexAgent = class _DuplexAgent {
|
|
|
6649
6649
|
tasks = /* @__PURE__ */ new Map();
|
|
6650
6650
|
queue = Promise.resolve();
|
|
6651
6651
|
seq = 0;
|
|
6652
|
+
/** Monotonic user-turn counter (bumped once per SUBSTANTIVE turn). Stamped onto each task at dispatch
|
|
6653
|
+
* (TaskRecord.createdTurn) so parking can tell a prior-topic task from the current turn's fresh one. */
|
|
6654
|
+
turn = 0;
|
|
6652
6655
|
pendingEvents = [];
|
|
6653
6656
|
/** Spoken text of parked deliveries that have SETTLED, awaiting a trivial-barge resume decision on the
|
|
6654
6657
|
* next turn (a substantive turn clears it — the result stays in the transcript, recoverable by asking). */
|
|
@@ -6942,6 +6945,7 @@ ${nowLine()}. Anchor every relative or time-sensitive reference \u2014 "today",
|
|
|
6942
6945
|
return this.enqueue(async () => {
|
|
6943
6946
|
await this.initMemory();
|
|
6944
6947
|
this.resetTurn();
|
|
6948
|
+
this.turn++;
|
|
6945
6949
|
this.awaitTrivialRedeliver = false;
|
|
6946
6950
|
this.parkedRedeliver = [];
|
|
6947
6951
|
this.suppressParkedResume = true;
|
|
@@ -7040,15 +7044,21 @@ ${nowLine()}. Anchor every relative or time-sensitive reference \u2014 "today",
|
|
|
7040
7044
|
rec.controller.abort();
|
|
7041
7045
|
return `Task ${rec.id} (${rec.label}) cancelled.`;
|
|
7042
7046
|
}
|
|
7043
|
-
/** Barge-in
|
|
7044
|
-
*
|
|
7045
|
-
*
|
|
7046
|
-
*
|
|
7047
|
-
|
|
7048
|
-
|
|
7047
|
+
/** Barge-in (or a dispatch-driven supersede): suppress running tasks' remaining SPOKEN delivery so a
|
|
7048
|
+
* superseded topic never talks over the new one (the debt-after-jokes regression). Tasks keep running and
|
|
7049
|
+
* still fold their result into the transcript — recoverable, just not spoken. Returns parked ids (logging).
|
|
7050
|
+
* Does NOT cancel. Two callers, two shapes:
|
|
7051
|
+
* - BARGE (default): the user interrupted AUDIO. Park EVERY running task (including this turn's) — the
|
|
7052
|
+
* worker they cut off must stop, whatever turn launched it — and re-arm trivial-barge auto-resume so a
|
|
7053
|
+
* following "go on" can bring the parked delivery back.
|
|
7054
|
+
* - SUPERSEDE (`priorTurnsOnly`, `reenableResume:false`, from dispatch()): a new dispatch redirected to
|
|
7055
|
+
* fresh work. Park only PRIOR-turn tasks so parallel siblings dispatched in the SAME turn don't silence
|
|
7056
|
+
* each other, and keep them suppressed (the user moved on — don't resurface on a stray "go on"). */
|
|
7057
|
+
parkInFlightDeliveries(reenableResume = true, priorTurnsOnly = false) {
|
|
7058
|
+
if (reenableResume) this.suppressParkedResume = false;
|
|
7049
7059
|
const parked = [];
|
|
7050
7060
|
for (const rec of this.tasks.values())
|
|
7051
|
-
if (rec.status === "running" && !rec.deliveryParked) {
|
|
7061
|
+
if (rec.status === "running" && !rec.deliveryParked && (!priorTurnsOnly || rec.createdTurn < this.turn)) {
|
|
7052
7062
|
rec.deliveryParked = true;
|
|
7053
7063
|
parked.push(rec.id);
|
|
7054
7064
|
}
|
|
@@ -7234,7 +7244,7 @@ ${recent}` : brief) + verify + deliverContract;
|
|
|
7234
7244
|
flushSpoken();
|
|
7235
7245
|
return res;
|
|
7236
7246
|
}).then((res) => this.maybeVerify(id, brief, res, tier, agentOpts, askBridge)).then((res) => this.onWorkerSettled(id, res)).catch((err2) => this.onWorkerFailed(id, err2));
|
|
7237
|
-
this.tasks.set(id, { id, label, status: "running", controller, promise, tail, brief, followUp, splitter });
|
|
7247
|
+
this.tasks.set(id, { id, label, status: "running", controller, promise, tail, brief, followUp, splitter, createdTurn: this.turn });
|
|
7238
7248
|
if (this.tasks.size > this.options.maxTaskRecords)
|
|
7239
7249
|
for (const [tid, rec] of this.tasks) {
|
|
7240
7250
|
if (this.tasks.size <= this.options.maxTaskRecords) break;
|
|
@@ -7408,6 +7418,7 @@ Another agent just implemented the above. Independently check the CURRENT state
|
|
|
7408
7418
|
toolCalls: res.messages.filter((m) => m.role === "tool").length
|
|
7409
7419
|
});
|
|
7410
7420
|
if (incomplete) {
|
|
7421
|
+
if (this.foldIfSuperseded(rec, res.text)) return;
|
|
7411
7422
|
return this.queueRevoice(this.integrationPrompt(rec, "incomplete", res.text, res.finishReason), true);
|
|
7412
7423
|
}
|
|
7413
7424
|
const tail = rec.splitter?.flush();
|
|
@@ -7429,12 +7440,25 @@ Another agent just implemented the above. Independently check the CURRENT state
|
|
|
7429
7440
|
onWorkerFailed(id, err2) {
|
|
7430
7441
|
this.failTask(this.tasks.get(id), err2 instanceof Error ? err2.message : String(err2));
|
|
7431
7442
|
}
|
|
7443
|
+
/** A delivery the user has SUPERSEDED — parked AND moved on (suppressParkedResume, set by a redirect) —
|
|
7444
|
+
* must not hijack the voice when it settles late (partial or failed): that would talk over the new topic
|
|
7445
|
+
* and, worse, auto-escalate work the user already abandoned. Fold a recoverable note into the transcript
|
|
7446
|
+
* instead (the reflex can surface it if asked) and report true so the caller skips queueRevoice. A merely
|
|
7447
|
+
* barge-parked task (suppressParkedResume false — a "go on" may still resume it) is NOT superseded: it
|
|
7448
|
+
* keeps the normal surfacing path so a failure the user still cares about is not swallowed. */
|
|
7449
|
+
foldIfSuperseded(rec, note) {
|
|
7450
|
+
if (!(rec.deliveryParked && this.suppressParkedResume)) return false;
|
|
7451
|
+
if (note.trim()) this.voice.transcript.push({ role: "assistant", content: note });
|
|
7452
|
+
log12.verbose(`task ${rec.id} settled but superseded (${rec.status}) \u2014 folded into transcript, not voiced`);
|
|
7453
|
+
return true;
|
|
7454
|
+
}
|
|
7432
7455
|
failTask(rec, msg) {
|
|
7433
7456
|
this.dropAsk(rec.id);
|
|
7434
7457
|
rec.status = "error";
|
|
7435
7458
|
rec.result = msg;
|
|
7436
7459
|
log12.warn(`task ${rec.id} failed: ${msg}`);
|
|
7437
7460
|
this.notify("task_error", `task ${rec.id} (${rec.label}) failed: ${msg}`);
|
|
7461
|
+
if (this.foldIfSuperseded(rec, `The "${rec.label}" task failed: ${msg}`)) return;
|
|
7438
7462
|
this.queueRevoice(this.integrationPrompt(rec, "error", msg, "error"), true);
|
|
7439
7463
|
}
|
|
7440
7464
|
// --- voice tools (closures over this instance) ---
|
|
@@ -7455,6 +7479,7 @@ Another agent just implemented the above. Independently check the CURRENT state
|
|
|
7455
7479
|
async dispatch(brief, tier = "act", label, followUp = false) {
|
|
7456
7480
|
if (tier === "think" && this.options.thinkModel === false) tier = "act";
|
|
7457
7481
|
if (followUp) this.autoEscalations++;
|
|
7482
|
+
this.parkInFlightDeliveries(false, true);
|
|
7458
7483
|
const id = `t${++this.seq}`;
|
|
7459
7484
|
const lbl = label ?? tier;
|
|
7460
7485
|
await this.options.onTaskStart?.(id, lbl);
|
|
@@ -12075,8 +12100,13 @@ function parseArgs(argv) {
|
|
|
12075
12100
|
const x = argv[i];
|
|
12076
12101
|
if (x === "-h" || x === "--help") a.help = true;
|
|
12077
12102
|
else if (x === "-v" || x === "--version") a.version = true;
|
|
12078
|
-
else if (x === "-m" || x === "--model")
|
|
12079
|
-
|
|
12103
|
+
else if (x === "-m" || x === "--model") {
|
|
12104
|
+
const nxt = argv[i + 1];
|
|
12105
|
+
if (nxt === void 0 || nxt.startsWith("-") || nxt === "list" || nxt === "ls" || nxt === "?") {
|
|
12106
|
+
a.listModels = true;
|
|
12107
|
+
if (nxt === "list" || nxt === "ls" || nxt === "?") i++;
|
|
12108
|
+
} else a.model = argv[++i];
|
|
12109
|
+
} else if (x === "-C" || x === "--cwd") a.cwd = val(++i, x);
|
|
12080
12110
|
else if (x === "-p" || x === "--print") {
|
|
12081
12111
|
const nxt = argv[i + 1];
|
|
12082
12112
|
if (nxt !== void 0 && !nxt.startsWith("-")) a.task = argv[++i];
|
|
@@ -12149,7 +12179,7 @@ var HELP = `agentx \u2014 agent runtime CLI
|
|
|
12149
12179
|
agentx -c "<task>" continue the most recent session
|
|
12150
12180
|
|
|
12151
12181
|
Flags:
|
|
12152
|
-
-m, --model <id> model (default anthropic/claude-sonnet-4-6)
|
|
12182
|
+
-m, --model <id> model (default anthropic/claude-sonnet-4-6); bare -m or -m list = list all models
|
|
12153
12183
|
-C, --cwd <dir> working dir / project root (default .)
|
|
12154
12184
|
-c, --continue resume the most recent session in this dir
|
|
12155
12185
|
-r, --resume [id] resume a session \u2014 with an id, or bare for an interactive picker
|
|
@@ -12229,6 +12259,24 @@ REPL paste: large/multi-line pastes collapse to a [Pasted text +N lines] preview
|
|
|
12229
12259
|
function newestModel() {
|
|
12230
12260
|
return listModels().slice().sort((a, b) => (getModelInfo(b)?.releaseDate ?? "").localeCompare(getModelInfo(a)?.releaseDate ?? ""))[0] ?? "";
|
|
12231
12261
|
}
|
|
12262
|
+
function printModels() {
|
|
12263
|
+
const byProvider = /* @__PURE__ */ new Map();
|
|
12264
|
+
for (const id of listModels()) {
|
|
12265
|
+
const provider = getProviderFromModel(id) ?? "other";
|
|
12266
|
+
if (!byProvider.has(provider)) byProvider.set(provider, []);
|
|
12267
|
+
byProvider.get(provider).push(id);
|
|
12268
|
+
}
|
|
12269
|
+
for (const [provider, ids] of Array.from(byProvider.entries()).sort((a, b) => a[0].localeCompare(b[0]))) {
|
|
12270
|
+
console.log(`
|
|
12271
|
+
${provider}`);
|
|
12272
|
+
ids.sort((a, b) => (getModelInfo(b)?.releaseDate ?? "").localeCompare(getModelInfo(a)?.releaseDate ?? ""));
|
|
12273
|
+
for (const id of ids) {
|
|
12274
|
+
const info = getModelInfo(id);
|
|
12275
|
+
const meta = [info?.displayName, info?.releaseDate].filter(Boolean).join(" \xB7 ");
|
|
12276
|
+
console.log(` ${id}${meta ? ` (${meta})` : ""}`);
|
|
12277
|
+
}
|
|
12278
|
+
}
|
|
12279
|
+
}
|
|
12232
12280
|
function resolveModelOrNewest(model) {
|
|
12233
12281
|
const want = model ?? new AgentOptions().model;
|
|
12234
12282
|
const resolved = resolveModel(want);
|
|
@@ -15492,6 +15540,10 @@ async function main() {
|
|
|
15492
15540
|
console.log(HELP);
|
|
15493
15541
|
return;
|
|
15494
15542
|
}
|
|
15543
|
+
if (args.listModels) {
|
|
15544
|
+
printModels();
|
|
15545
|
+
return;
|
|
15546
|
+
}
|
|
15495
15547
|
if (args.update) {
|
|
15496
15548
|
const msg = await checkForUpdate(VERSION).catch(() => null);
|
|
15497
15549
|
if (!msg) {
|