@livx.cc/agentx 0.99.108 → 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 +59 -15
- package/dist/cli.js.map +1 -1
- package/dist/index.d.ts +14 -1
- package/dist/index.js +56 -14
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/cli.js
CHANGED
|
@@ -10509,6 +10509,22 @@ function nameScore(want, have) {
|
|
|
10509
10509
|
var RESERVED_EVENT_MARKER = /\[task\b[^\]\n]*\b(?:completed|failed|progress|asks)\b/i;
|
|
10510
10510
|
var RESERVED_EVENT_OPENER = /\[\s*task\b/i;
|
|
10511
10511
|
var STAGE_DIRECTION_RE = /^\(\s*(?:(?:waiting|checking|searching|thinking|processing|loading|working|fetching|looking)\b[^)]*|[^)]*(?:\.\.\.|…)\s*)\)$/i;
|
|
10512
|
+
function hostContextBlock(context) {
|
|
10513
|
+
return `<host_context>
|
|
10514
|
+
${context.trim()}
|
|
10515
|
+
</host_context>
|
|
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
|
+
|
|
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
|
+
|
|
10526
|
+
`;
|
|
10527
|
+
}
|
|
10512
10528
|
function nowLine() {
|
|
10513
10529
|
return `Current date and time: ${(/* @__PURE__ */ new Date()).toLocaleString("en-US", { weekday: "long", year: "numeric", month: "long", day: "numeric", hour: "numeric", minute: "2-digit", timeZoneName: "short" })}`;
|
|
10514
10530
|
}
|
|
@@ -11002,9 +11018,9 @@ ${nowLine()}. Anchor every relative or time-sensitive reference \u2014 "today",
|
|
|
11002
11018
|
/** One reflex model call for a turn; a turn rejected for load (rateLimited) that has not spoken or dispatched yet is rolled
|
|
11003
11019
|
* back and re-run once on `reflexFallbackModel` — a re-prompt of the same model (the dead-air nudge) only hits the
|
|
11004
11020
|
* same limit and ends in "could you say that again?". */
|
|
11005
|
-
async reflexSend(content) {
|
|
11006
|
-
const base = this.voice.transcript.length;
|
|
11007
|
-
const res = await this.
|
|
11021
|
+
async reflexSend(content, note) {
|
|
11022
|
+
const base = this.voice.transcript.length, context = this.lastContext;
|
|
11023
|
+
const res = await this.sendWithContext(content, context, note);
|
|
11008
11024
|
const fb = this.options.reflexFallbackModel, model = this.voice.options.model;
|
|
11009
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;
|
|
11010
11026
|
log23.warn(`reflex ${model} rate-limited \u2014 re-running the turn on ${fb}`);
|
|
@@ -11012,11 +11028,27 @@ ${nowLine()}. Anchor every relative or time-sensitive reference \u2014 "today",
|
|
|
11012
11028
|
this.voice.transcript.length = base;
|
|
11013
11029
|
this.voice.options.model = fb;
|
|
11014
11030
|
try {
|
|
11015
|
-
return await this.
|
|
11031
|
+
return await this.sendWithContext(content, context, note);
|
|
11016
11032
|
} finally {
|
|
11017
11033
|
this.voice.options.model = model;
|
|
11018
11034
|
}
|
|
11019
11035
|
}
|
|
11036
|
+
/** The host's per-line context (call rules, browser context, earlier conversation) rides THIS call only, fenced as the app's —
|
|
11037
|
+
* inside the user turn it read as the user's own words (live #938: "repeat everything I said" recited the call rules). The
|
|
11038
|
+
* stored turn keeps only what the user said, so later turns, briefs and the saved session never carry it. A block, not a
|
|
11039
|
+
* mid-transcript system message: the Anthropic/Google adapters keep only the leading system message. */
|
|
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;
|
|
11043
|
+
try {
|
|
11044
|
+
return await this.voice.send((context?.trim() ? hostContextBlock(context) : "") + stored);
|
|
11045
|
+
} finally {
|
|
11046
|
+
const m = this.voice.transcript.slice(base).find((x) => x.role === "user");
|
|
11047
|
+
if (m) m.content = stored;
|
|
11048
|
+
}
|
|
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;
|
|
11020
11052
|
/** The turn SAID it is on it ("got it — checking…") but called no tool and nothing is running: a promise nothing
|
|
11021
11053
|
* keeps — the user waits on silence (live Para #798: a follow-up while the reflex believed a finished task still ran). */
|
|
11022
11054
|
get hollowPromise() {
|
|
@@ -11038,7 +11070,7 @@ ${nowLine()}. Anchor every relative or time-sensitive reference \u2014 "today",
|
|
|
11038
11070
|
this.stepMarks = [];
|
|
11039
11071
|
this.dropJudge();
|
|
11040
11072
|
try {
|
|
11041
|
-
await this.
|
|
11073
|
+
await this.sendWithContext(reminder, this.lastContext);
|
|
11042
11074
|
} catch (e) {
|
|
11043
11075
|
log23.warn(`follow-through nudge failed: ${e instanceof Error ? e.message : e}`);
|
|
11044
11076
|
} finally {
|
|
@@ -11181,7 +11213,7 @@ ${nowLine()}. Anchor every relative or time-sensitive reference \u2014 "today",
|
|
|
11181
11213
|
if (this.dispatchAt >= 0) this.dispatchAt = 0;
|
|
11182
11214
|
this.nudging = true;
|
|
11183
11215
|
try {
|
|
11184
|
-
await this.
|
|
11216
|
+
await this.sendWithContext(reminder, this.lastContext);
|
|
11185
11217
|
} catch (e) {
|
|
11186
11218
|
log23.warn(`ack nudge failed: ${e instanceof Error ? e.message : e}`);
|
|
11187
11219
|
} finally {
|
|
@@ -11220,6 +11252,7 @@ ${nowLine()}. Anchor every relative or time-sensitive reference \u2014 "today",
|
|
|
11220
11252
|
* second Act). The host gets `turn_replace` {id, replaces, rolledBack, followed?}: only a rollback drops the replaced
|
|
11221
11253
|
* line; `followed` = the kept turn whose follow-up ran (absent: the merged text ran). */
|
|
11222
11254
|
send(content, opts) {
|
|
11255
|
+
const ctx = opts && (opts.context !== void 0 || opts.note !== void 0) ? { context: opts.context, note: opts.note } : void 0;
|
|
11223
11256
|
this.clearHoldResume();
|
|
11224
11257
|
this.holdResumed = false;
|
|
11225
11258
|
if (opts?.replaces) this.replaceTurn(opts.replaces);
|
|
@@ -11245,7 +11278,7 @@ ${nowLine()}. Anchor every relative or time-sensitive reference \u2014 "today",
|
|
|
11245
11278
|
if (intent === "resume" && !reflexCut) return this.resumeParked();
|
|
11246
11279
|
if (intent === "aside" || intent === "resume") {
|
|
11247
11280
|
const told = intent === "aside" ? [...this.parkedRedeliver] : [];
|
|
11248
|
-
return this.sendTurn(intent === "aside" ? content + this.asideNote(told) : content, true, rec, ext).then(async (r) => {
|
|
11281
|
+
return this.sendTurn(intent === "aside" ? content + this.asideNote(told) : content, true, rec, ext, ctx).then(async (r) => {
|
|
11249
11282
|
if (r.finishReason === "aborted" || this.heldThisTurn) return r;
|
|
11250
11283
|
const missed = unsaidClauses(told.map((p) => p.text), this.turnSpoken, this.options.decider);
|
|
11251
11284
|
const turn = this.turn;
|
|
@@ -11260,10 +11293,10 @@ ${nowLine()}. Anchor every relative or time-sensitive reference \u2014 "today",
|
|
|
11260
11293
|
return r;
|
|
11261
11294
|
});
|
|
11262
11295
|
}
|
|
11263
|
-
return this.sendTurn(content, false, rec, ext);
|
|
11296
|
+
return this.sendTurn(content, false, rec, ext, ctx);
|
|
11264
11297
|
});
|
|
11265
11298
|
}
|
|
11266
|
-
return this.sendTurn(typeof content === "string" ? content + this.acceptNote(content) : content, false, rec, ext);
|
|
11299
|
+
return this.sendTurn(typeof content === "string" ? content + this.acceptNote(content) : content, false, rec, ext, ctx);
|
|
11267
11300
|
}
|
|
11268
11301
|
/** Host-named user turns (send opts.id), so a later send can replace one. Bounded; a replace that arrives
|
|
11269
11302
|
* BEFORE its target (the host's dispatch hops can reorder) leaves a pre-superseded record behind. */
|
|
@@ -11331,12 +11364,17 @@ ${nowLine()}. Anchor every relative or time-sensitive reference \u2014 "today",
|
|
|
11331
11364
|
return { text: "", steps: 0, finishReason: "stop", messages: [] };
|
|
11332
11365
|
});
|
|
11333
11366
|
}
|
|
11334
|
-
sendTurn(content, keepParked = false, rec, ext) {
|
|
11367
|
+
sendTurn(content, keepParked = false, rec, ext, host) {
|
|
11335
11368
|
const spec = this.spec;
|
|
11336
11369
|
if (spec?.state === "pending") {
|
|
11337
11370
|
if (typeof content === "string" && speculationConfirms(spec.text, content)) {
|
|
11338
11371
|
spec.state = "confirmed";
|
|
11339
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
|
+
}
|
|
11340
11378
|
if (rec) {
|
|
11341
11379
|
spec.rec = rec;
|
|
11342
11380
|
rec.ctl.signal.addEventListener("abort", () => spec.ctl.abort(), { once: true });
|
|
@@ -11383,8 +11421,9 @@ ${nowLine()}. Anchor every relative or time-sensitive reference \u2014 "today",
|
|
|
11383
11421
|
}
|
|
11384
11422
|
if (typeof content === "string") content += spellingNote(content);
|
|
11385
11423
|
let res;
|
|
11424
|
+
if (host?.context !== void 0) this.lastContext = host.context;
|
|
11386
11425
|
try {
|
|
11387
|
-
res = await this.reflexSend(content);
|
|
11426
|
+
res = await this.reflexSend(content, host?.note);
|
|
11388
11427
|
} finally {
|
|
11389
11428
|
if (signal) {
|
|
11390
11429
|
this.voice.options.signal = ext;
|
|
@@ -11433,7 +11472,7 @@ ${nowLine()}. Anchor every relative or time-sensitive reference \u2014 "today",
|
|
|
11433
11472
|
this.voice.options.signal = spec.ctl.signal;
|
|
11434
11473
|
let res;
|
|
11435
11474
|
try {
|
|
11436
|
-
res = await this.
|
|
11475
|
+
res = await this.sendWithContext(spec.text, this.lastContext);
|
|
11437
11476
|
} catch (e) {
|
|
11438
11477
|
log23.warn(`speculative turn failed: ${e instanceof Error ? e.message : e}`);
|
|
11439
11478
|
} finally {
|
|
@@ -11712,7 +11751,7 @@ Update: ${brief}`;
|
|
|
11712
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");
|
|
11713
11752
|
}
|
|
11714
11753
|
buildBrief(brief, tier = "act", deliver = true) {
|
|
11715
|
-
const recent = this.recentExcerpt();
|
|
11754
|
+
const recent = this.recentExcerpt(), host = this.lastContext?.trim();
|
|
11716
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." : "";
|
|
11717
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." : "") : "";
|
|
11718
11757
|
return `${nowLine()}.
|
|
@@ -11720,7 +11759,10 @@ Update: ${brief}`;
|
|
|
11720
11759
|
` + (recent ? `${brief}
|
|
11721
11760
|
|
|
11722
11761
|
## Recent conversation (for context)
|
|
11723
|
-
${recent}` : brief) +
|
|
11762
|
+
${recent}` : brief) + (host ? `
|
|
11763
|
+
|
|
11764
|
+
## The app's context for this line (not the user's words)
|
|
11765
|
+
${host}` : "") + verify + deliverContract;
|
|
11724
11766
|
}
|
|
11725
11767
|
/** Spawn a detached worker for task `id`; its settlement notifies + enqueues the re-voice turn. */
|
|
11726
11768
|
spawnWorker(id, label, briefText, tier, brief, followUp) {
|
|
@@ -18789,6 +18831,8 @@ Flags:
|
|
|
18789
18831
|
--timeout <sec> wall-clock kill-switch (default 120)
|
|
18790
18832
|
--input-format stream-json with --duplex|--voice + --output-format stream-json: headless duplex for a host app
|
|
18791
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
|
|
18792
18836
|
with -p: the first {"type":"user","text"} line is the prompt; later ones STEER the running turn
|
|
18793
18837
|
(unconsumed steers come back as the result's \`unsteered\`)
|
|
18794
18838
|
--keep-alive with -p --input-format stream-json: stay up after a turn \u2014 each {"type":"user"} line while idle
|
|
@@ -22497,7 +22541,7 @@ async function duplexServe(args, ai, cfg, cwd) {
|
|
|
22497
22541
|
const done2 = () => {
|
|
22498
22542
|
if (seq === scTurn) sc?.onAgentState("idle");
|
|
22499
22543
|
};
|
|
22500
|
-
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 })).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 }) => {
|
|
22501
22545
|
const why = (res?.finishReason ?? "error") === "error" ? duplexError(res?.error ?? error, dx.options.reflexModel) : "";
|
|
22502
22546
|
done2();
|
|
22503
22547
|
out({ type: "turn_done", id, finishReason: res?.finishReason ?? "error", ...why ? { error: why } : {} });
|