@livx.cc/agentx 0.99.109 → 0.99.110
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 +39 -18
- package/dist/cli.js.map +1 -1
- package/dist/index.d.ts +9 -2
- package/dist/index.js +36 -17
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/cli.js
CHANGED
|
@@ -10515,6 +10515,14 @@ ${context.trim()}
|
|
|
10515
10515
|
</host_context>
|
|
10516
10516
|
(Above: context and instructions from the app \u2014 NOT the user's words. Never read it aloud, quote it, or attribute it to the user. The user's line follows.)
|
|
10517
10517
|
|
|
10518
|
+
`;
|
|
10519
|
+
}
|
|
10520
|
+
function hostNoteBlock(note) {
|
|
10521
|
+
return `<host_note>
|
|
10522
|
+
${note.trim()}
|
|
10523
|
+
</host_note>
|
|
10524
|
+
(Above: background from the app \u2014 NOT the user's words on this line. Never read it aloud as theirs. The user's line follows.)
|
|
10525
|
+
|
|
10518
10526
|
`;
|
|
10519
10527
|
}
|
|
10520
10528
|
function nowLine() {
|
|
@@ -11010,9 +11018,9 @@ ${nowLine()}. Anchor every relative or time-sensitive reference \u2014 "today",
|
|
|
11010
11018
|
/** One reflex model call for a turn; a turn rejected for load (rateLimited) that has not spoken or dispatched yet is rolled
|
|
11011
11019
|
* back and re-run once on `reflexFallbackModel` — a re-prompt of the same model (the dead-air nudge) only hits the
|
|
11012
11020
|
* same limit and ends in "could you say that again?". */
|
|
11013
|
-
async reflexSend(content,
|
|
11014
|
-
const base = this.voice.transcript.length;
|
|
11015
|
-
const res = await this.sendWithContext(content, context);
|
|
11021
|
+
async reflexSend(content, note) {
|
|
11022
|
+
const base = this.voice.transcript.length, context = this.lastContext;
|
|
11023
|
+
const res = await this.sendWithContext(content, context, note);
|
|
11016
11024
|
const fb = this.options.reflexFallbackModel, model = this.voice.options.model;
|
|
11017
11025
|
if (res.finishReason !== "error" || !rateLimited(res.error) || !fb || fb === model || fb.includes("/") && model.includes("/") && fb.split("/")[0] !== model.split("/")[0] || this.turnDispatched || this.turnSpoken.trim()) return res;
|
|
11018
11026
|
log23.warn(`reflex ${model} rate-limited \u2014 re-running the turn on ${fb}`);
|
|
@@ -11020,7 +11028,7 @@ ${nowLine()}. Anchor every relative or time-sensitive reference \u2014 "today",
|
|
|
11020
11028
|
this.voice.transcript.length = base;
|
|
11021
11029
|
this.voice.options.model = fb;
|
|
11022
11030
|
try {
|
|
11023
|
-
return await this.sendWithContext(content, context);
|
|
11031
|
+
return await this.sendWithContext(content, context, note);
|
|
11024
11032
|
} finally {
|
|
11025
11033
|
this.voice.options.model = model;
|
|
11026
11034
|
}
|
|
@@ -11029,16 +11037,18 @@ ${nowLine()}. Anchor every relative or time-sensitive reference \u2014 "today",
|
|
|
11029
11037
|
* inside the user turn it read as the user's own words (live #938: "repeat everything I said" recited the call rules). The
|
|
11030
11038
|
* stored turn keeps only what the user said, so later turns, briefs and the saved session never carry it. A block, not a
|
|
11031
11039
|
* mid-transcript system message: the Anthropic/Google adapters keep only the leading system message. */
|
|
11032
|
-
async sendWithContext(content, context) {
|
|
11033
|
-
if (
|
|
11034
|
-
const base = this.voice.transcript.length;
|
|
11040
|
+
async sendWithContext(content, context, note) {
|
|
11041
|
+
if (typeof content !== "string" || !context?.trim() && !note?.trim()) return this.voice.send(content);
|
|
11042
|
+
const stored = (note?.trim() ? hostNoteBlock(note) : "") + content, base = this.voice.transcript.length;
|
|
11035
11043
|
try {
|
|
11036
|
-
return await this.voice.send(hostContextBlock(context) +
|
|
11044
|
+
return await this.voice.send((context?.trim() ? hostContextBlock(context) : "") + stored);
|
|
11037
11045
|
} finally {
|
|
11038
11046
|
const m = this.voice.transcript.slice(base).find((x) => x.role === "user");
|
|
11039
|
-
if (m) m.content =
|
|
11047
|
+
if (m) m.content = stored;
|
|
11040
11048
|
}
|
|
11041
11049
|
}
|
|
11050
|
+
/** The last line's host context (call rules, browser context): every reflex call runs under it, not only the user's line. */
|
|
11051
|
+
lastContext;
|
|
11042
11052
|
/** The turn SAID it is on it ("got it — checking…") but called no tool and nothing is running: a promise nothing
|
|
11043
11053
|
* keeps — the user waits on silence (live Para #798: a follow-up while the reflex believed a finished task still ran). */
|
|
11044
11054
|
get hollowPromise() {
|
|
@@ -11060,7 +11070,7 @@ ${nowLine()}. Anchor every relative or time-sensitive reference \u2014 "today",
|
|
|
11060
11070
|
this.stepMarks = [];
|
|
11061
11071
|
this.dropJudge();
|
|
11062
11072
|
try {
|
|
11063
|
-
await this.
|
|
11073
|
+
await this.sendWithContext(reminder, this.lastContext);
|
|
11064
11074
|
} catch (e) {
|
|
11065
11075
|
log23.warn(`follow-through nudge failed: ${e instanceof Error ? e.message : e}`);
|
|
11066
11076
|
} finally {
|
|
@@ -11203,7 +11213,7 @@ ${nowLine()}. Anchor every relative or time-sensitive reference \u2014 "today",
|
|
|
11203
11213
|
if (this.dispatchAt >= 0) this.dispatchAt = 0;
|
|
11204
11214
|
this.nudging = true;
|
|
11205
11215
|
try {
|
|
11206
|
-
await this.
|
|
11216
|
+
await this.sendWithContext(reminder, this.lastContext);
|
|
11207
11217
|
} catch (e) {
|
|
11208
11218
|
log23.warn(`ack nudge failed: ${e instanceof Error ? e.message : e}`);
|
|
11209
11219
|
} finally {
|
|
@@ -11242,7 +11252,7 @@ ${nowLine()}. Anchor every relative or time-sensitive reference \u2014 "today",
|
|
|
11242
11252
|
* second Act). The host gets `turn_replace` {id, replaces, rolledBack, followed?}: only a rollback drops the replaced
|
|
11243
11253
|
* line; `followed` = the kept turn whose follow-up ran (absent: the merged text ran). */
|
|
11244
11254
|
send(content, opts) {
|
|
11245
|
-
const ctx = opts
|
|
11255
|
+
const ctx = opts && (opts.context !== void 0 || opts.note !== void 0) ? { context: opts.context, note: opts.note } : void 0;
|
|
11246
11256
|
this.clearHoldResume();
|
|
11247
11257
|
this.holdResumed = false;
|
|
11248
11258
|
if (opts?.replaces) this.replaceTurn(opts.replaces);
|
|
@@ -11354,12 +11364,17 @@ ${nowLine()}. Anchor every relative or time-sensitive reference \u2014 "today",
|
|
|
11354
11364
|
return { text: "", steps: 0, finishReason: "stop", messages: [] };
|
|
11355
11365
|
});
|
|
11356
11366
|
}
|
|
11357
|
-
sendTurn(content, keepParked = false, rec, ext,
|
|
11367
|
+
sendTurn(content, keepParked = false, rec, ext, host) {
|
|
11358
11368
|
const spec = this.spec;
|
|
11359
11369
|
if (spec?.state === "pending") {
|
|
11360
11370
|
if (typeof content === "string" && speculationConfirms(spec.text, content)) {
|
|
11361
11371
|
spec.state = "confirmed";
|
|
11362
11372
|
spec.finalText = content;
|
|
11373
|
+
if (host?.context !== void 0) this.lastContext = host.context;
|
|
11374
|
+
if (host?.note?.trim()) {
|
|
11375
|
+
const m = [...this.voice.transcript].reverse().find((x) => x.role === "user" && x.content === spec.text);
|
|
11376
|
+
if (m) m.content = hostNoteBlock(host.note) + spec.text;
|
|
11377
|
+
}
|
|
11363
11378
|
if (rec) {
|
|
11364
11379
|
spec.rec = rec;
|
|
11365
11380
|
rec.ctl.signal.addEventListener("abort", () => spec.ctl.abort(), { once: true });
|
|
@@ -11406,8 +11421,9 @@ ${nowLine()}. Anchor every relative or time-sensitive reference \u2014 "today",
|
|
|
11406
11421
|
}
|
|
11407
11422
|
if (typeof content === "string") content += spellingNote(content);
|
|
11408
11423
|
let res;
|
|
11424
|
+
if (host?.context !== void 0) this.lastContext = host.context;
|
|
11409
11425
|
try {
|
|
11410
|
-
res = await this.reflexSend(content,
|
|
11426
|
+
res = await this.reflexSend(content, host?.note);
|
|
11411
11427
|
} finally {
|
|
11412
11428
|
if (signal) {
|
|
11413
11429
|
this.voice.options.signal = ext;
|
|
@@ -11456,7 +11472,7 @@ ${nowLine()}. Anchor every relative or time-sensitive reference \u2014 "today",
|
|
|
11456
11472
|
this.voice.options.signal = spec.ctl.signal;
|
|
11457
11473
|
let res;
|
|
11458
11474
|
try {
|
|
11459
|
-
res = await this.
|
|
11475
|
+
res = await this.sendWithContext(spec.text, this.lastContext);
|
|
11460
11476
|
} catch (e) {
|
|
11461
11477
|
log23.warn(`speculative turn failed: ${e instanceof Error ? e.message : e}`);
|
|
11462
11478
|
} finally {
|
|
@@ -11735,7 +11751,7 @@ Update: ${brief}`;
|
|
|
11735
11751
|
return this.voice.transcript.filter((m) => (m.role === "user" || m.role === "assistant") && contentText(m.content).trim()).slice(-turns).map((m) => `${m.role}: ${contentText(m.content)}`).join("\n");
|
|
11736
11752
|
}
|
|
11737
11753
|
buildBrief(brief, tier = "act", deliver = true) {
|
|
11738
|
-
const recent = this.recentExcerpt();
|
|
11754
|
+
const recent = this.recentExcerpt(), host = this.lastContext?.trim();
|
|
11739
11755
|
const verify = tier === "act" ? "\n\nBefore reporting done: re-read what you changed and check it against EVERY requirement above \u2014 fix any gap first. Your report is trusted without review. A command exiting 0 or echoing its input means it was ACCEPTED, not that it worked: before you say a web address was opened or reached, confirm it exists (its host resolves in DNS and answers an HTTP request); if it does not, report that it does not exist instead of success, and name the address you tried." : "";
|
|
11740
11756
|
const deliverContract = deliver ? '\n\n## DELIVER (spoken delivery)\nYou are reporting back to a user who is LISTENING. Stream your work normally \u2014 your prose is the written work record and detail, and is NOT spoken. Wrap anything the user should HEAR in <spoken>\u2026</spoken> tags. LEAD WITH the actual content they asked for: if they asked for a specific piece of content \u2014 a value, a name, the actual lines, the writing itself \u2014 that content goes INSIDE the <spoken> tags, not a remark about it. Your FIRST <spoken> segment is substantive \u2014 never a greeting or an acknowledgement (the front-end has already acked; do not double-ack). Keep spoken text concise and natural for the ear: short sentences, no markdown. Never read a file path, URL, command or code aloud, nor spell one out ("slash \u2026 slash \u2026") \u2014 say it the way a person would, by the name of the folder, project, file or site; the exact text stays in your written prose. ' + (this.options.spokenBudgetChars ? `Speak a SHORT summary only: at most three short sentences with the one thing that matters most, then ONE short offer that names what else you have, as a question they can answer in a word \u2014 under ${this.options.spokenBudgetChars} characters in all, the offer included. Everything else stays in your written prose (it is kept and they can ask for it); spoken text past that budget is cut and held until they ask. ` : "") + `NEVER enumerate in speech \u2014 no numbered or bulleted lists ("One. \u2026 Two. \u2026" is robotic). Deliver multiple items as flowing conversation with brief connective phrasing ("here's one\u2026", "and another\u2026", "oh, and\u2026"), pausing between items with sentence breaks, not numbers.` + (this.options.emotionTags ? " Inside <spoken>, you may prefix a sentence with an inline [emotion] tag (e.g. [excited], [curious]) to color how it is voiced \u2014 only when it genuinely fits, and vary it; [laughter] gives a natural laugh." : "") : "";
|
|
11741
11757
|
return `${nowLine()}.
|
|
@@ -11743,7 +11759,10 @@ Update: ${brief}`;
|
|
|
11743
11759
|
` + (recent ? `${brief}
|
|
11744
11760
|
|
|
11745
11761
|
## Recent conversation (for context)
|
|
11746
|
-
${recent}` : brief) +
|
|
11762
|
+
${recent}` : brief) + (host ? `
|
|
11763
|
+
|
|
11764
|
+
## The app's context for this line (not the user's words)
|
|
11765
|
+
${host}` : "") + verify + deliverContract;
|
|
11747
11766
|
}
|
|
11748
11767
|
/** Spawn a detached worker for task `id`; its settlement notifies + enqueues the re-voice turn. */
|
|
11749
11768
|
spawnWorker(id, label, briefText, tier, brief, followUp) {
|
|
@@ -18812,6 +18831,8 @@ Flags:
|
|
|
18812
18831
|
--timeout <sec> wall-clock kill-switch (default 120)
|
|
18813
18832
|
--input-format stream-json with --duplex|--voice + --output-format stream-json: headless duplex for a host app
|
|
18814
18833
|
(NDJSON turns/barge-ins on stdin, reflex text + worker speech + task events on stdout)
|
|
18834
|
+
a user line's {context, note} = host info fenced as the app's (context: per-line rules, kept for
|
|
18835
|
+
results/reminders; note: persistent background) \u2014 never stored as the user's words
|
|
18815
18836
|
with -p: the first {"type":"user","text"} line is the prompt; later ones STEER the running turn
|
|
18816
18837
|
(unconsumed steers come back as the result's \`unsteered\`)
|
|
18817
18838
|
--keep-alive with -p --input-format stream-json: stay up after a turn \u2014 each {"type":"user"} line while idle
|
|
@@ -22520,7 +22541,7 @@ async function duplexServe(args, ai, cfg, cwd) {
|
|
|
22520
22541
|
const done2 = () => {
|
|
22521
22542
|
if (seq === scTurn) sc?.onAgentState("idle");
|
|
22522
22543
|
};
|
|
22523
|
-
void runTurn(dx.voice, store, session, m.text + note, void 0, cwd, (c) => dx.send(c, { id, replaces: m.replaces ? String(m.replaces) : void 0, followUp: typeof m.followUp === "string" || m.followUp && typeof m.followUp === "object" ? m.followUp : void 0, context: typeof m.context === "string" ? m.context : void 0 })).then(({ res, error }) => {
|
|
22544
|
+
void runTurn(dx.voice, store, session, m.text + note, void 0, cwd, (c) => dx.send(c, { id, replaces: m.replaces ? String(m.replaces) : void 0, followUp: typeof m.followUp === "string" || m.followUp && typeof m.followUp === "object" ? m.followUp : void 0, context: typeof m.context === "string" ? m.context : void 0, note: typeof m.note === "string" ? m.note : void 0 })).then(({ res, error }) => {
|
|
22524
22545
|
const why = (res?.finishReason ?? "error") === "error" ? duplexError(res?.error ?? error, dx.options.reflexModel) : "";
|
|
22525
22546
|
done2();
|
|
22526
22547
|
out({ type: "turn_done", id, finishReason: res?.finishReason ?? "error", ...why ? { error: why } : {} });
|