@livx.cc/agentx 0.99.106 → 0.99.108
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 +2 -1
- package/dist/cli.js +65 -8
- package/dist/cli.js.map +1 -1
- package/dist/index.d.ts +2 -2
- package/dist/index.js +27 -1
- package/dist/index.js.map +1 -1
- package/dist/{secondChannel-BYW5qPAJ.d.ts → secondChannel-3IPP3Qgh.d.ts} +6 -0
- package/package.json +1 -1
package/dist/cli.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
#!/usr/bin/env bun
|
|
2
|
-
import { o as RouterState, H as Hooks, p as RunResult, R as ReasoningEffort, C as ChannelMode, A as Agent } from './secondChannel-
|
|
2
|
+
import { o as RouterState, H as Hooks, p as RunResult, R as ReasoningEffort, C as ChannelMode, A as Agent } from './secondChannel-3IPP3Qgh.js';
|
|
3
3
|
import { IFilesystem } from '@livx.cc/wcli/core';
|
|
4
4
|
import { M as Message, U as UserQuestion, H as HostBridge, c as ContentPart, o as MessageContent } from './tools-DZHZIyxh.js';
|
|
5
5
|
|
|
@@ -139,6 +139,7 @@ interface Args {
|
|
|
139
139
|
reasoning?: ReasoningEffort;
|
|
140
140
|
help: boolean;
|
|
141
141
|
version: boolean;
|
|
142
|
+
keepAlive?: boolean;
|
|
142
143
|
duplex: boolean;
|
|
143
144
|
duplexV2?: boolean;
|
|
144
145
|
call?: boolean;
|
package/dist/cli.js
CHANGED
|
@@ -13022,6 +13022,9 @@ var SecondChannelOptions = class {
|
|
|
13022
13022
|
/** A bridge waits this long after the user's turn is dispatched, and plays only if channel-1 has said nothing yet
|
|
13023
13023
|
* (a fast reply/ack needs no bridge — one before it reads as the agent starting a different sentence). 0 = at once. */
|
|
13024
13024
|
bridgeDelayMs = 1200;
|
|
13025
|
+
/** Duplex v3 (§3 first sound): a bridge skips the decider (the veto stays for backchannels/fillers) and speaks a
|
|
13026
|
+
* canned line at once; a generated one is started at dispatch and used only if it already landed. */
|
|
13027
|
+
instantBridge = false;
|
|
13025
13028
|
/** No new interim for this long → a pause (hosts may also call onPause). */
|
|
13026
13029
|
fillerPauseMs = 700;
|
|
13027
13030
|
fillerMinWords = 4;
|
|
@@ -13093,6 +13096,8 @@ var SecondChannel = class {
|
|
|
13093
13096
|
// the line the last barge actually cut (spoke())
|
|
13094
13097
|
bridged = false;
|
|
13095
13098
|
// one bridge per main turn
|
|
13099
|
+
bridgeDraft = null;
|
|
13100
|
+
// a bridge generated ahead, used only if ready in time
|
|
13096
13101
|
recent = [];
|
|
13097
13102
|
picks = /* @__PURE__ */ new Map();
|
|
13098
13103
|
inflight = null;
|
|
@@ -13228,6 +13233,7 @@ var SecondChannel = class {
|
|
|
13228
13233
|
if (this[k]) clearTimeout(this[k]);
|
|
13229
13234
|
this[k] = null;
|
|
13230
13235
|
}
|
|
13236
|
+
if (this.o.instantBridge) this.prefetchBridge();
|
|
13231
13237
|
const wait = Math.max(this.o.bridgeDelayMs, this.o.minGapMs - (this.o.now() - this.lastAt));
|
|
13232
13238
|
if (wait > 0) this.bridgeTimer = setTimeout(() => {
|
|
13233
13239
|
this.bridgeTimer = null;
|
|
@@ -13360,7 +13366,7 @@ var SecondChannel = class {
|
|
|
13360
13366
|
try {
|
|
13361
13367
|
let kind = rule;
|
|
13362
13368
|
let choice;
|
|
13363
|
-
if (this.o.decide && !cue) {
|
|
13369
|
+
if (this.o.decide && !cue && !(rule === "bridge" && this.o.instantBridge)) {
|
|
13364
13370
|
const ac = new AbortController();
|
|
13365
13371
|
const d = await withBudget(this.o.decide(this.tail(), { ...this.state(pauseMs), rule }, ac.signal), this.o.decisionBudgetMs, "channel decision", ac);
|
|
13366
13372
|
choice = d?.choice;
|
|
@@ -13394,7 +13400,24 @@ var SecondChannel = class {
|
|
|
13394
13400
|
call_ms: Math.round(now4 - this.startedAt)
|
|
13395
13401
|
};
|
|
13396
13402
|
}
|
|
13403
|
+
/** Start writing this turn's bridge now, so it may be ready by bridgeDelayMs. The bridge never waits for it. */
|
|
13404
|
+
prefetchBridge() {
|
|
13405
|
+
this.bridgeDraft = null;
|
|
13406
|
+
if (!this.o.generate || !this.o.generateFor.includes("bridge") || !this.lang || !this.heard) return;
|
|
13407
|
+
const gen = this.gen, ac = new AbortController();
|
|
13408
|
+
const ctx = { kind: "bridge", heard: this.tail(), state: this.main, avoid: [...this.recent], lang: this.lang };
|
|
13409
|
+
void withBudget(this.o.generate(ctx, ac.signal), Math.max(this.o.generateBudgetMs, this.o.bridgeDelayMs), "bridge generate", ac).then((raw) => {
|
|
13410
|
+
const text = cleanLine(raw ?? "", ctx.lang);
|
|
13411
|
+
if (text && gen === this.gen) this.bridgeDraft = { gen, text };
|
|
13412
|
+
}).catch((e) => log27.debug(`bridge prefetch failed: ${e?.message ?? e}`));
|
|
13413
|
+
}
|
|
13397
13414
|
async line(kind, react = true) {
|
|
13415
|
+
if (kind === "bridge" && this.o.instantBridge) {
|
|
13416
|
+
const d = this.bridgeDraft?.gen === this.gen ? this.bridgeDraft.text : "";
|
|
13417
|
+
this.bridgeDraft = null;
|
|
13418
|
+
if (d && !this.recent.some((r) => norm3(r) === norm3(d))) return d;
|
|
13419
|
+
return this.pick(kind);
|
|
13420
|
+
}
|
|
13398
13421
|
if (this.o.generate && this.o.generateFor.includes(kind) && (kind !== "backchannel" || react)) {
|
|
13399
13422
|
const ac = new AbortController();
|
|
13400
13423
|
const ctx = { kind, heard: this.tail(), state: this.main, avoid: [...this.recent], lang: this.lang, ...kind === "backchannel" && this.o.reactionGapMs ? { react: true } : {} };
|
|
@@ -13544,6 +13567,9 @@ var VoiceCall = class {
|
|
|
13544
13567
|
} : {},
|
|
13545
13568
|
mode: o.mode,
|
|
13546
13569
|
aec: o.aec,
|
|
13570
|
+
bridgeDelayMs: 700,
|
|
13571
|
+
instantBridge: true,
|
|
13572
|
+
// v3 §3: first sound <1.2s p50 — a bridge at 700ms if MAIN is still silent, no veto, no wait
|
|
13547
13573
|
...this.lang ? { lang: this.lang } : {},
|
|
13548
13574
|
...o.channel,
|
|
13549
13575
|
speak: (text, kind) => this.say(text, kind),
|
|
@@ -18634,7 +18660,8 @@ function parseArgs(argv) {
|
|
|
18634
18660
|
} else if (x === "--call") {
|
|
18635
18661
|
a.call = true;
|
|
18636
18662
|
a.duplex = true;
|
|
18637
|
-
} else if (x === "--
|
|
18663
|
+
} else if (x === "--keep-alive") a.keepAlive = true;
|
|
18664
|
+
else if (x === "--channel-only") a.channelOnly = true;
|
|
18638
18665
|
else if (x === "--channel-mode") a.channelMode = parseChannelMode(val(++i, x));
|
|
18639
18666
|
else if (x === "--conversational" || x === "--convo" || x === "--voice") {
|
|
18640
18667
|
a.voice = true;
|
|
@@ -18676,6 +18703,7 @@ function parseArgs(argv) {
|
|
|
18676
18703
|
if (a.worktree && (a.vfs || a.boddb)) throw new Error("--worktree is a real-disk concept \u2014 incompatible with --vfs/--boddb");
|
|
18677
18704
|
if (a.duplex && (a.task || a.print)) throw new Error("--duplex is interactive-only (a conversational mode) \u2014 drop the task/-p");
|
|
18678
18705
|
if (a.inputFormat && (!a.duplex && !a.print && !a.channelOnly || a.outputFormat !== "stream-json")) throw new Error("--input-format stream-json needs --output-format stream-json and --duplex (or --voice), --channel-only or -p");
|
|
18706
|
+
if (a.keepAlive && (!a.print || !a.inputFormat)) throw new Error("--keep-alive needs -p --input-format stream-json --output-format stream-json");
|
|
18679
18707
|
if (a.channelOnly && !a.inputFormat) throw new Error("--channel-only needs --input-format stream-json --output-format stream-json");
|
|
18680
18708
|
if (a.duplex && a.plan) throw new Error("--plan is not supported in --duplex (workers are non-interactive; a plan could never be approved)");
|
|
18681
18709
|
if (a.voiceSystemPrompt && !a.duplex) throw new Error("--voice-system-prompt only applies with --duplex");
|
|
@@ -18763,6 +18791,9 @@ Flags:
|
|
|
18763
18791
|
(NDJSON turns/barge-ins on stdin, reflex text + worker speech + task events on stdout)
|
|
18764
18792
|
with -p: the first {"type":"user","text"} line is the prompt; later ones STEER the running turn
|
|
18765
18793
|
(unconsumed steers come back as the result's \`unsteered\`)
|
|
18794
|
+
--keep-alive with -p --input-format stream-json: stay up after a turn \u2014 each {"type":"user"} line while idle
|
|
18795
|
+
is the NEXT turn (warm: same session, model connection and MCP servers), one {type:result}
|
|
18796
|
+
per turn; {"type":"abort"} stops the running turn; stdin EOF exits
|
|
18766
18797
|
--output-format <f> headless output: text (default) | json (one result object) | stream-json (NDJSON events: {type:text|thinking}\u2026 then {type:result})
|
|
18767
18798
|
-v, --version print version and exit
|
|
18768
18799
|
-h, --help
|
|
@@ -22527,9 +22558,9 @@ async function channelServe(args, ai, cfg) {
|
|
|
22527
22558
|
await new Promise((r) => rl.on("close", () => r()));
|
|
22528
22559
|
call.end();
|
|
22529
22560
|
}
|
|
22530
|
-
function readStdinSteers() {
|
|
22561
|
+
function readStdinSteers(keepAlive = false) {
|
|
22531
22562
|
const early = [];
|
|
22532
|
-
let sink, got;
|
|
22563
|
+
let sink, got, closed = false;
|
|
22533
22564
|
const first = new Promise((res) => {
|
|
22534
22565
|
got = res;
|
|
22535
22566
|
});
|
|
@@ -22541,6 +22572,10 @@ function readStdinSteers() {
|
|
|
22541
22572
|
} catch {
|
|
22542
22573
|
return;
|
|
22543
22574
|
}
|
|
22575
|
+
if (keepAlive && m?.type === "abort") {
|
|
22576
|
+
activeTurn?.abort();
|
|
22577
|
+
return;
|
|
22578
|
+
}
|
|
22544
22579
|
if (m?.type !== "user" || typeof m.text !== "string" || !m.text.trim()) return;
|
|
22545
22580
|
if (got) {
|
|
22546
22581
|
got(m.text);
|
|
@@ -22548,11 +22583,21 @@ function readStdinSteers() {
|
|
|
22548
22583
|
} else if (sink) sink(m.text);
|
|
22549
22584
|
else early.push(m.text);
|
|
22550
22585
|
});
|
|
22551
|
-
rl.on("close", () =>
|
|
22586
|
+
rl.on("close", () => {
|
|
22587
|
+
closed = true;
|
|
22588
|
+
got?.("");
|
|
22589
|
+
got = void 0;
|
|
22590
|
+
});
|
|
22591
|
+
const next = () => {
|
|
22592
|
+
sink = void 0;
|
|
22593
|
+
return early.length ? Promise.resolve(early.shift()) : closed ? Promise.resolve("") : new Promise((res) => {
|
|
22594
|
+
got = res;
|
|
22595
|
+
});
|
|
22596
|
+
};
|
|
22552
22597
|
return { first, steer: (to) => {
|
|
22553
22598
|
sink = to;
|
|
22554
22599
|
early.splice(0).forEach(to);
|
|
22555
|
-
} };
|
|
22600
|
+
}, next };
|
|
22556
22601
|
}
|
|
22557
22602
|
function readAllStdin() {
|
|
22558
22603
|
return new Promise((res) => {
|
|
@@ -22587,7 +22632,7 @@ async function main() {
|
|
|
22587
22632
|
process.exit(installUpdate() ? 0 : 1);
|
|
22588
22633
|
}
|
|
22589
22634
|
if (args.debug) process.env.DEBUG ||= "*";
|
|
22590
|
-
const steers = args.print && args.inputFormat && !args.task ? readStdinSteers() : void 0;
|
|
22635
|
+
const steers = args.print && args.inputFormat && !args.task ? readStdinSteers(args.keepAlive) : void 0;
|
|
22591
22636
|
if (steers) args.task = (await steers.first).trim();
|
|
22592
22637
|
else if (args.print && !args.task && !process.stdin.isTTY) args.task = (await readAllStdin()).trim();
|
|
22593
22638
|
if (args.print && !args.task) {
|
|
@@ -22680,7 +22725,19 @@ async function main() {
|
|
|
22680
22725
|
const session = startSession(args, store, agent, cwd);
|
|
22681
22726
|
process.once("SIGINT", () => activeTurn?.abort());
|
|
22682
22727
|
steers?.steer((text) => agent.inject(text));
|
|
22683
|
-
const
|
|
22728
|
+
const turn = (task) => runTurn(agent, store, session, task, void 0, cwd, autoRouteSend(args, agent, () => session, (m) => providerOptionsFor(m, cwd, cfg.mcpServers, mounted.map((x) => x.name))));
|
|
22729
|
+
if (args.keepAlive && steers) {
|
|
22730
|
+
for (let task = args.task; task.trim(); task = (await steers.next()).trim()) {
|
|
22731
|
+
steers.steer((text) => agent.inject(text));
|
|
22732
|
+
const { res: res2 } = await turn(task);
|
|
22733
|
+
const left = agent.drainPendingSteers();
|
|
22734
|
+
process.stdout.write(JSON.stringify({ type: "result", ...res2 ? jsonResult(res2, session) : { ok: false, finishReason: "error", sessionId: session.meta.id }, ...left.length ? { unsteered: left } : {} }) + "\n");
|
|
22735
|
+
}
|
|
22736
|
+
await closeMcp(mounted);
|
|
22737
|
+
worktreeCleanup?.();
|
|
22738
|
+
process.exit(0);
|
|
22739
|
+
}
|
|
22740
|
+
const { ok, res } = await turn(args.task);
|
|
22684
22741
|
if (cfg.reflectOnFailure && !ok && res?.finishReason !== "needs_input" && res && agent.options.memoryDir) {
|
|
22685
22742
|
const _fsBase = agent.options.fs.getCwd() === "/" ? "" : agent.options.fs.getCwd();
|
|
22686
22743
|
const slug2 = await reflectOnRun({ ai, model: agent.options.model, fs: agent.options.fs, dir: primaryMemDir(agent.options.memoryDir, `${_fsBase}/.agent/memory`), result: res });
|