@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/index.d.ts
CHANGED
|
@@ -1119,6 +1119,12 @@ declare class DuplexAgentOptions {
|
|
|
1119
1119
|
/** User-scope memory dir for global facts (type=user/feedback). Forwarded to Remember's routing. */
|
|
1120
1120
|
memoryUserDir?: string;
|
|
1121
1121
|
}
|
|
1122
|
+
/** The host side of a user line: `context` = volatile per-line rules (they stay in force for later reflex calls — results,
|
|
1123
|
+
* reminders — until the next line replaces them); `note` = persistent background, stored fenced in that turn. */
|
|
1124
|
+
type HostInfo = {
|
|
1125
|
+
context?: string;
|
|
1126
|
+
note?: string;
|
|
1127
|
+
};
|
|
1122
1128
|
declare const VOICE_SYSTEM_PROMPT: string;
|
|
1123
1129
|
/**
|
|
1124
1130
|
* The duplex orchestrator. `send()` enqueues a user turn on the reflex agent; `Act`/`Think`
|
|
@@ -1280,6 +1286,8 @@ declare class DuplexAgent {
|
|
|
1280
1286
|
* stored turn keeps only what the user said, so later turns, briefs and the saved session never carry it. A block, not a
|
|
1281
1287
|
* mid-transcript system message: the Anthropic/Google adapters keep only the leading system message. */
|
|
1282
1288
|
private sendWithContext;
|
|
1289
|
+
/** The last line's host context (call rules, browser context): every reflex call runs under it, not only the user's line. */
|
|
1290
|
+
private lastContext?;
|
|
1283
1291
|
/** The turn SAID it is on it ("got it — checking…") but called no tool and nothing is running: a promise nothing
|
|
1284
1292
|
* keeps — the user waits on silence (live Para #798: a follow-up while the reflex believed a finished task still ran). */
|
|
1285
1293
|
private get hollowPromise();
|
|
@@ -1346,8 +1354,7 @@ declare class DuplexAgent {
|
|
|
1346
1354
|
id?: string;
|
|
1347
1355
|
replaces?: string;
|
|
1348
1356
|
followUp?: string | Record<string, string>;
|
|
1349
|
-
|
|
1350
|
-
}): Promise<RunResult>;
|
|
1357
|
+
} & HostInfo): Promise<RunResult>;
|
|
1351
1358
|
/** Host-named user turns (send opts.id), so a later send can replace one. Bounded; a replace that arrives
|
|
1352
1359
|
* BEFORE its target (the host's dispatch hops can reorder) leaves a pre-superseded record behind. */
|
|
1353
1360
|
private userTurns;
|
package/dist/index.js
CHANGED
|
@@ -10183,6 +10183,14 @@ ${context.trim()}
|
|
|
10183
10183
|
</host_context>
|
|
10184
10184
|
(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.)
|
|
10185
10185
|
|
|
10186
|
+
`;
|
|
10187
|
+
}
|
|
10188
|
+
function hostNoteBlock(note) {
|
|
10189
|
+
return `<host_note>
|
|
10190
|
+
${note.trim()}
|
|
10191
|
+
</host_note>
|
|
10192
|
+
(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.)
|
|
10193
|
+
|
|
10186
10194
|
`;
|
|
10187
10195
|
}
|
|
10188
10196
|
function nowLine() {
|
|
@@ -10678,9 +10686,9 @@ ${nowLine()}. Anchor every relative or time-sensitive reference \u2014 "today",
|
|
|
10678
10686
|
/** One reflex model call for a turn; a turn rejected for load (rateLimited) that has not spoken or dispatched yet is rolled
|
|
10679
10687
|
* back and re-run once on `reflexFallbackModel` — a re-prompt of the same model (the dead-air nudge) only hits the
|
|
10680
10688
|
* same limit and ends in "could you say that again?". */
|
|
10681
|
-
async reflexSend(content,
|
|
10682
|
-
const base = this.voice.transcript.length;
|
|
10683
|
-
const res = await this.sendWithContext(content, context);
|
|
10689
|
+
async reflexSend(content, note) {
|
|
10690
|
+
const base = this.voice.transcript.length, context = this.lastContext;
|
|
10691
|
+
const res = await this.sendWithContext(content, context, note);
|
|
10684
10692
|
const fb = this.options.reflexFallbackModel, model = this.voice.options.model;
|
|
10685
10693
|
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;
|
|
10686
10694
|
log24.warn(`reflex ${model} rate-limited \u2014 re-running the turn on ${fb}`);
|
|
@@ -10688,7 +10696,7 @@ ${nowLine()}. Anchor every relative or time-sensitive reference \u2014 "today",
|
|
|
10688
10696
|
this.voice.transcript.length = base;
|
|
10689
10697
|
this.voice.options.model = fb;
|
|
10690
10698
|
try {
|
|
10691
|
-
return await this.sendWithContext(content, context);
|
|
10699
|
+
return await this.sendWithContext(content, context, note);
|
|
10692
10700
|
} finally {
|
|
10693
10701
|
this.voice.options.model = model;
|
|
10694
10702
|
}
|
|
@@ -10697,16 +10705,18 @@ ${nowLine()}. Anchor every relative or time-sensitive reference \u2014 "today",
|
|
|
10697
10705
|
* inside the user turn it read as the user's own words (live #938: "repeat everything I said" recited the call rules). The
|
|
10698
10706
|
* stored turn keeps only what the user said, so later turns, briefs and the saved session never carry it. A block, not a
|
|
10699
10707
|
* mid-transcript system message: the Anthropic/Google adapters keep only the leading system message. */
|
|
10700
|
-
async sendWithContext(content, context) {
|
|
10701
|
-
if (
|
|
10702
|
-
const base = this.voice.transcript.length;
|
|
10708
|
+
async sendWithContext(content, context, note) {
|
|
10709
|
+
if (typeof content !== "string" || !context?.trim() && !note?.trim()) return this.voice.send(content);
|
|
10710
|
+
const stored = (note?.trim() ? hostNoteBlock(note) : "") + content, base = this.voice.transcript.length;
|
|
10703
10711
|
try {
|
|
10704
|
-
return await this.voice.send(hostContextBlock(context) +
|
|
10712
|
+
return await this.voice.send((context?.trim() ? hostContextBlock(context) : "") + stored);
|
|
10705
10713
|
} finally {
|
|
10706
10714
|
const m = this.voice.transcript.slice(base).find((x) => x.role === "user");
|
|
10707
|
-
if (m) m.content =
|
|
10715
|
+
if (m) m.content = stored;
|
|
10708
10716
|
}
|
|
10709
10717
|
}
|
|
10718
|
+
/** The last line's host context (call rules, browser context): every reflex call runs under it, not only the user's line. */
|
|
10719
|
+
lastContext;
|
|
10710
10720
|
/** The turn SAID it is on it ("got it — checking…") but called no tool and nothing is running: a promise nothing
|
|
10711
10721
|
* keeps — the user waits on silence (live Para #798: a follow-up while the reflex believed a finished task still ran). */
|
|
10712
10722
|
get hollowPromise() {
|
|
@@ -10728,7 +10738,7 @@ ${nowLine()}. Anchor every relative or time-sensitive reference \u2014 "today",
|
|
|
10728
10738
|
this.stepMarks = [];
|
|
10729
10739
|
this.dropJudge();
|
|
10730
10740
|
try {
|
|
10731
|
-
await this.
|
|
10741
|
+
await this.sendWithContext(reminder, this.lastContext);
|
|
10732
10742
|
} catch (e) {
|
|
10733
10743
|
log24.warn(`follow-through nudge failed: ${e instanceof Error ? e.message : e}`);
|
|
10734
10744
|
} finally {
|
|
@@ -10871,7 +10881,7 @@ ${nowLine()}. Anchor every relative or time-sensitive reference \u2014 "today",
|
|
|
10871
10881
|
if (this.dispatchAt >= 0) this.dispatchAt = 0;
|
|
10872
10882
|
this.nudging = true;
|
|
10873
10883
|
try {
|
|
10874
|
-
await this.
|
|
10884
|
+
await this.sendWithContext(reminder, this.lastContext);
|
|
10875
10885
|
} catch (e) {
|
|
10876
10886
|
log24.warn(`ack nudge failed: ${e instanceof Error ? e.message : e}`);
|
|
10877
10887
|
} finally {
|
|
@@ -10910,7 +10920,7 @@ ${nowLine()}. Anchor every relative or time-sensitive reference \u2014 "today",
|
|
|
10910
10920
|
* second Act). The host gets `turn_replace` {id, replaces, rolledBack, followed?}: only a rollback drops the replaced
|
|
10911
10921
|
* line; `followed` = the kept turn whose follow-up ran (absent: the merged text ran). */
|
|
10912
10922
|
send(content, opts) {
|
|
10913
|
-
const ctx = opts
|
|
10923
|
+
const ctx = opts && (opts.context !== void 0 || opts.note !== void 0) ? { context: opts.context, note: opts.note } : void 0;
|
|
10914
10924
|
this.clearHoldResume();
|
|
10915
10925
|
this.holdResumed = false;
|
|
10916
10926
|
if (opts?.replaces) this.replaceTurn(opts.replaces);
|
|
@@ -11022,12 +11032,17 @@ ${nowLine()}. Anchor every relative or time-sensitive reference \u2014 "today",
|
|
|
11022
11032
|
return { text: "", steps: 0, finishReason: "stop", messages: [] };
|
|
11023
11033
|
});
|
|
11024
11034
|
}
|
|
11025
|
-
sendTurn(content, keepParked = false, rec, ext,
|
|
11035
|
+
sendTurn(content, keepParked = false, rec, ext, host) {
|
|
11026
11036
|
const spec = this.spec;
|
|
11027
11037
|
if (spec?.state === "pending") {
|
|
11028
11038
|
if (typeof content === "string" && speculationConfirms(spec.text, content)) {
|
|
11029
11039
|
spec.state = "confirmed";
|
|
11030
11040
|
spec.finalText = content;
|
|
11041
|
+
if (host?.context !== void 0) this.lastContext = host.context;
|
|
11042
|
+
if (host?.note?.trim()) {
|
|
11043
|
+
const m = [...this.voice.transcript].reverse().find((x) => x.role === "user" && x.content === spec.text);
|
|
11044
|
+
if (m) m.content = hostNoteBlock(host.note) + spec.text;
|
|
11045
|
+
}
|
|
11031
11046
|
if (rec) {
|
|
11032
11047
|
spec.rec = rec;
|
|
11033
11048
|
rec.ctl.signal.addEventListener("abort", () => spec.ctl.abort(), { once: true });
|
|
@@ -11074,8 +11089,9 @@ ${nowLine()}. Anchor every relative or time-sensitive reference \u2014 "today",
|
|
|
11074
11089
|
}
|
|
11075
11090
|
if (typeof content === "string") content += spellingNote(content);
|
|
11076
11091
|
let res;
|
|
11092
|
+
if (host?.context !== void 0) this.lastContext = host.context;
|
|
11077
11093
|
try {
|
|
11078
|
-
res = await this.reflexSend(content,
|
|
11094
|
+
res = await this.reflexSend(content, host?.note);
|
|
11079
11095
|
} finally {
|
|
11080
11096
|
if (signal) {
|
|
11081
11097
|
this.voice.options.signal = ext;
|
|
@@ -11124,7 +11140,7 @@ ${nowLine()}. Anchor every relative or time-sensitive reference \u2014 "today",
|
|
|
11124
11140
|
this.voice.options.signal = spec.ctl.signal;
|
|
11125
11141
|
let res;
|
|
11126
11142
|
try {
|
|
11127
|
-
res = await this.
|
|
11143
|
+
res = await this.sendWithContext(spec.text, this.lastContext);
|
|
11128
11144
|
} catch (e) {
|
|
11129
11145
|
log24.warn(`speculative turn failed: ${e instanceof Error ? e.message : e}`);
|
|
11130
11146
|
} finally {
|
|
@@ -11403,7 +11419,7 @@ Update: ${brief}`;
|
|
|
11403
11419
|
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");
|
|
11404
11420
|
}
|
|
11405
11421
|
buildBrief(brief, tier = "act", deliver = true) {
|
|
11406
|
-
const recent = this.recentExcerpt();
|
|
11422
|
+
const recent = this.recentExcerpt(), host = this.lastContext?.trim();
|
|
11407
11423
|
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." : "";
|
|
11408
11424
|
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." : "") : "";
|
|
11409
11425
|
return `${nowLine()}.
|
|
@@ -11411,7 +11427,10 @@ Update: ${brief}`;
|
|
|
11411
11427
|
` + (recent ? `${brief}
|
|
11412
11428
|
|
|
11413
11429
|
## Recent conversation (for context)
|
|
11414
|
-
${recent}` : brief) +
|
|
11430
|
+
${recent}` : brief) + (host ? `
|
|
11431
|
+
|
|
11432
|
+
## The app's context for this line (not the user's words)
|
|
11433
|
+
${host}` : "") + verify + deliverContract;
|
|
11415
11434
|
}
|
|
11416
11435
|
/** Spawn a detached worker for task `id`; its settlement notifies + enqueues the re-voice turn. */
|
|
11417
11436
|
spawnWorker(id, label, briefText, tier, brief, followUp) {
|