@livx.cc/agentx 0.99.112 → 0.99.114
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 +3 -1
- package/dist/cli.js +137 -28
- package/dist/cli.js.map +1 -1
- package/dist/index.d.ts +17 -4
- package/dist/index.js +104 -14
- package/dist/index.js.map +1 -1
- package/dist/{secondChannel-CJMY5EbL.d.ts → secondChannel-Cl-fIl-F.d.ts} +30 -27
- 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-Cl-fIl-F.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
|
|
|
@@ -140,6 +140,8 @@ interface Args {
|
|
|
140
140
|
help: boolean;
|
|
141
141
|
version: boolean;
|
|
142
142
|
keepAlive?: boolean;
|
|
143
|
+
lean?: boolean;
|
|
144
|
+
voiceGender?: 'female' | 'male';
|
|
143
145
|
duplex: boolean;
|
|
144
146
|
duplexV2?: boolean;
|
|
145
147
|
call?: boolean;
|
package/dist/cli.js
CHANGED
|
@@ -9328,14 +9328,40 @@ var ACK = new Set("yeah yea yes yep yup ya ok okay k right sure true totally exa
|
|
|
9328
9328
|
var LEAD = /* @__PURE__ */ new Set(["and", "so", "um", "uh", "er", "well", "oh"]);
|
|
9329
9329
|
var LEADER = /* @__PURE__ */ new Set(["yeah", "yea", "yes", "yep", "yup", "ok", "okay", "right", "sure", "alright", "mm", "mhm", "hmm", "uh-huh", "totally", "exactly", "true"]);
|
|
9330
9330
|
var PHRASES = ["got it", "i see", "makes sense", "of course", "for sure", "all right", "that's right", "that's true", "thats right", "thats true", "love it", "i know", "me too", "uh huh"];
|
|
9331
|
+
var CONTINUE = /^(?:(?:and|so|oh) )?(?:and|so|really|seriously|then what|and then|go on|keep going|ואז|באמת|נו)$/;
|
|
9332
|
+
var AGREE = new Set("yeah yea yes yep yup right sure true totally exactly definitely absolutely agreed correct indeed \u05DB\u05DF \u05E0\u05DB\u05D5\u05DF \u05D1\u05D3\u05D9\u05D5\u05E7 \u05D1\u05E8\u05D5\u05E8 \u05D1\u05D8\u05D7 \u05D0\u05DB\u05DF \u05DC\u05D2\u05DE\u05E8\u05D9 \u05DE\u05E1\u05DB\u05D9\u05DD \u05DE\u05E1\u05DB\u05D9\u05DE\u05D4 \u05DE\u05DE\u05E9".split(" "));
|
|
9333
|
+
var AGREE_PHRASES = ["of course", "for sure", "that's right", "that's true", "thats right", "thats true", "makes sense", "i agree"];
|
|
9334
|
+
var HE_ACK = new Set("\u05DB\u05DF \u05E0\u05DB\u05D5\u05DF \u05D1\u05D3\u05D9\u05D5\u05E7 \u05D1\u05E8\u05D5\u05E8 \u05D1\u05D8\u05D7 \u05D0\u05DB\u05DF \u05DC\u05D2\u05DE\u05E8\u05D9 \u05DE\u05DE\u05E9 \u05D0\u05D5\u05E7\u05D9\u05D9 \u05D0\u05D5\u05E7\u05D9 \u05E1\u05D1\u05D1\u05D4 \u05D9\u05E4\u05D4 \u05DE\u05E2\u05D5\u05DC\u05D4 \u05D5\u05D5\u05D0\u05D5 \u05D0\u05D4\u05D4 \u05D0\u05D4 \u05D4\u05DE\u05DE \u05DE\u05DE\u05DE".split(" "));
|
|
9335
|
+
function cueKind(text) {
|
|
9336
|
+
const t = norm2(text);
|
|
9337
|
+
if (!t) return null;
|
|
9338
|
+
if (CONTINUE.test(t)) return "continue";
|
|
9339
|
+
let r = t;
|
|
9340
|
+
for (const p of AGREE_PHRASES) if (r.includes(p)) return "agree";
|
|
9341
|
+
r = r.split(/[\s-]+/).filter((w) => !LEAD.has(w)).join(" ");
|
|
9342
|
+
return r.split(" ").some((w) => AGREE.has(w)) ? "agree" : null;
|
|
9343
|
+
}
|
|
9344
|
+
var ASIDES = {
|
|
9345
|
+
en: { agree: ["Oh yeah, definitely.", "Yeah, exactly.", "Right, yeah."], continue: ["Yeah, so\u2026", "So, yeah\u2026"] },
|
|
9346
|
+
he: { agree: ["\u05DB\u05DF, \u05D1\u05D3\u05D9\u05D5\u05E7.", "\u05DB\u05DF, \u05DE\u05DE\u05E9.", "\u05E0\u05DB\u05D5\u05DF, \u05DB\u05DF."], continue: ["\u05DB\u05DF, \u05D0\u05D6\u2026", "\u05D0\u05D6 \u05DB\u05DF\u2026"] }
|
|
9347
|
+
};
|
|
9348
|
+
function overlapAside(text, lang, avoid = "", pick = (n) => Math.floor(Math.random() * n)) {
|
|
9349
|
+
const kind = cueKind(text);
|
|
9350
|
+
const l = new RegExp("\\p{Script=Hebrew}", "u").test(text) ? "he" : /[a-z]/i.test(text) ? "en" : lang;
|
|
9351
|
+
const pool = kind && l ? ASIDES[l]?.[kind] : void 0;
|
|
9352
|
+
if (!pool?.length) return null;
|
|
9353
|
+
const fresh = pool.filter((x) => x !== avoid);
|
|
9354
|
+
return fresh[pick(fresh.length)] ?? null;
|
|
9355
|
+
}
|
|
9331
9356
|
function overlapRule(text) {
|
|
9357
|
+
if (CONTINUE.test(norm2(text))) return "keep";
|
|
9332
9358
|
if (/\?/.test(text)) return "cut";
|
|
9333
9359
|
let t = norm2(text);
|
|
9334
9360
|
if (!t) return void 0;
|
|
9335
9361
|
if (HARD.test(t)) return "cut";
|
|
9336
9362
|
for (const p of PHRASES) t = t.split(p).join(" ");
|
|
9337
9363
|
const words4 = t.split(/[\s-]+/).filter(Boolean);
|
|
9338
|
-
const ack = (w) => ACK.has(w) || /^(?:ha)+h?$|^(?:he)+h?$|^m+(?:hm+)?$|^h?m+$/.test(w);
|
|
9364
|
+
const ack = (w) => ACK.has(w) || HE_ACK.has(w) || /^(?:ha)+h?$|^(?:he)+h?$|^m+(?:hm+)?$|^h?m+$/.test(w);
|
|
9339
9365
|
if (words4.every(ack)) return "keep";
|
|
9340
9366
|
const lead2 = words4.findIndex((w) => !LEAD.has(w));
|
|
9341
9367
|
if (lead2 >= 0 && LEADER.has(words4[lead2]) && words4.slice(lead2).filter((w) => !ack(w) && !LEAD.has(w)).length <= 1) return "keep";
|
|
@@ -10110,6 +10136,9 @@ var KIND_HINT = {
|
|
|
10110
10136
|
bridge: `neutral one-moment cues while the answer is prepared (like "let me see\u2026", "one sec\u2026") \u2014 never the start of a statement or opinion ("the thing is", "well actually", "here's the deal")`,
|
|
10111
10137
|
phatic: 'greetings, thanks and yes/no openers a person starts a turn with (like "hi", "thanks", "how are you")'
|
|
10112
10138
|
};
|
|
10139
|
+
function personaHint(gender) {
|
|
10140
|
+
return gender === "female" ? 'You are a woman: when you refer to yourself, use feminine grammatical forms (e.g. Hebrew "\u05D1\u05D5\u05D3\u05E7\u05EA", not "\u05D1\u05D5\u05D3\u05E7").' : gender === "male" ? 'You are a man: when you refer to yourself, use masculine grammatical forms (e.g. Hebrew "\u05D1\u05D5\u05D3\u05E7", not "\u05D1\u05D5\u05D3\u05E7\u05EA").' : "";
|
|
10141
|
+
}
|
|
10113
10142
|
function fastBankGenerator(ai, model, perKind = 12) {
|
|
10114
10143
|
return async (lang, avoid, signal) => {
|
|
10115
10144
|
const name = languageName(lang);
|
|
@@ -12808,14 +12837,19 @@ init_logging();
|
|
|
12808
12837
|
var log25 = forComponent("Progress");
|
|
12809
12838
|
var HE_RESULT_CLAIM = /(?:^|\s)(?:מצאתי|סיימתי|בוצע|הנה|אין)(?=\s|$|[.,!…])/u;
|
|
12810
12839
|
var TOPICS = [
|
|
12840
|
+
[/toolsearch|^mcp__.*__(list_commands|call_info)$/, null],
|
|
12841
|
+
// tool plumbing — no line (and no generated one)
|
|
12811
12842
|
[/kanban|board|card|\bkb\b|list_cards/, "board"],
|
|
12812
12843
|
[/mail|gmail|inbox/, "mail"],
|
|
12813
12844
|
[/calendar|event|schedule/, "calendar"],
|
|
12814
12845
|
[/memory|recall|remember/, "memory"],
|
|
12815
|
-
[/web_?search|
|
|
12846
|
+
[/web_?search|search_web|google/, "websearch"],
|
|
12847
|
+
[/fetch|read_page|get_page|page_text|navigate|url|history/, "page"],
|
|
12848
|
+
[/click|type|press_key|scroll|screenshot|tab|browser|highlight|point|wait_for|upload/, "browser"],
|
|
12816
12849
|
[/grep|glob|search|find|lookup|quicklook/, "search"],
|
|
12850
|
+
[/^(agent|task)$|subagent|delegate/, "delegate"],
|
|
12817
12851
|
[/edit|write|patch|create|update|save|delete|move/, "write"],
|
|
12818
|
-
[/shell|bash|exec|run|command|terminal/, "run"],
|
|
12852
|
+
[/shell|bash|exec|run|command|terminal|eval/, "run"],
|
|
12819
12853
|
[/read|open|view|cat|look|get|list|ls/, "read"]
|
|
12820
12854
|
];
|
|
12821
12855
|
var PROGRESS_TEMPLATES = {
|
|
@@ -12824,27 +12858,62 @@ var PROGRESS_TEMPLATES = {
|
|
|
12824
12858
|
mail: ["checking the mail\u2026", "going through the inbox\u2026"],
|
|
12825
12859
|
calendar: ["checking the calendar\u2026", "looking at the schedule\u2026"],
|
|
12826
12860
|
memory: ["checking my notes\u2026", "looking back\u2026"],
|
|
12827
|
-
|
|
12861
|
+
websearch: ["searching\u2026", "searching the web\u2026"],
|
|
12862
|
+
page: ["reading the page\u2026", "going through the page\u2026"],
|
|
12863
|
+
browser: ["working in the browser\u2026", "on the page now\u2026"],
|
|
12828
12864
|
search: ["searching\u2026", "still looking\u2026"],
|
|
12865
|
+
delegate: ["working on it\u2026", "still on it\u2026"],
|
|
12829
12866
|
write: ["making the change\u2026", "writing it down\u2026"],
|
|
12830
12867
|
run: ["running it\u2026", "still running\u2026"],
|
|
12831
12868
|
read: ["reading it\u2026", "going through it\u2026"]
|
|
12832
12869
|
},
|
|
12833
12870
|
he: {
|
|
12834
|
-
// plural present: gender-neutral for a voice of either gender
|
|
12835
12871
|
board: ["\u05D1\u05D5\u05D3\u05E7\u05D9\u05DD \u05D1\u05DC\u05D5\u05D7\u2026", "\u05DE\u05E1\u05EA\u05DB\u05DC\u05D9\u05DD \u05E2\u05DC \u05D4\u05DB\u05E8\u05D8\u05D9\u05E1\u05D9\u05DD\u2026"],
|
|
12836
12872
|
mail: ["\u05D1\u05D5\u05D3\u05E7\u05D9\u05DD \u05D0\u05EA \u05D4\u05DE\u05D9\u05D9\u05DC\u2026", "\u05E2\u05D5\u05D1\u05E8\u05D9\u05DD \u05E2\u05DC \u05D4\u05D3\u05D5\u05D0\u05E8\u2026"],
|
|
12837
12873
|
calendar: ["\u05D1\u05D5\u05D3\u05E7\u05D9\u05DD \u05D1\u05D9\u05D5\u05DE\u05DF\u2026", "\u05DE\u05E1\u05EA\u05DB\u05DC\u05D9\u05DD \u05D1\u05DC\u05D5\u05F4\u05D6\u2026"],
|
|
12838
12874
|
memory: ["\u05D1\u05D5\u05D3\u05E7\u05D9\u05DD \u05D1\u05E8\u05E9\u05D9\u05DE\u05D5\u05EA\u2026", "\u05DE\u05D7\u05E4\u05E9\u05D9\u05DD \u05D1\u05D6\u05D9\u05DB\u05E8\u05D5\u05DF\u2026"],
|
|
12839
|
-
|
|
12875
|
+
websearch: ["\u05DE\u05D7\u05E4\u05E9\u05D9\u05DD\u2026", "\u05DE\u05D7\u05E4\u05E9\u05D9\u05DD \u05D1\u05E8\u05E9\u05EA\u2026"],
|
|
12876
|
+
page: ["\u05E7\u05D5\u05E8\u05D0\u05D9\u05DD \u05D0\u05EA \u05D4\u05D3\u05E3\u2026", "\u05E2\u05D5\u05D1\u05E8\u05D9\u05DD \u05E2\u05DC \u05D4\u05D3\u05E3\u2026"],
|
|
12877
|
+
browser: ["\u05E2\u05D5\u05D1\u05D3\u05D9\u05DD \u05D1\u05D3\u05E4\u05D3\u05E4\u05DF\u2026", "\u05E2\u05DC \u05D4\u05D3\u05E3 \u05E2\u05DB\u05E9\u05D9\u05D5\u2026"],
|
|
12840
12878
|
search: ["\u05DE\u05D7\u05E4\u05E9\u05D9\u05DD\u2026", "\u05E2\u05D3\u05D9\u05D9\u05DF \u05DE\u05D7\u05E4\u05E9\u05D9\u05DD\u2026"],
|
|
12879
|
+
delegate: ["\u05E2\u05D5\u05D1\u05D3\u05D9\u05DD \u05E2\u05DC \u05D6\u05D4\u2026", "\u05E2\u05D3\u05D9\u05D9\u05DF \u05E2\u05DC \u05D6\u05D4\u2026"],
|
|
12841
12880
|
write: ["\u05DE\u05D1\u05E6\u05E2\u05D9\u05DD \u05D0\u05EA \u05D4\u05E9\u05D9\u05E0\u05D5\u05D9\u2026", "\u05DB\u05D5\u05EA\u05D1\u05D9\u05DD \u05D0\u05EA \u05D6\u05D4\u2026"],
|
|
12842
12881
|
run: ["\u05DE\u05E8\u05D9\u05E6\u05D9\u05DD\u2026", "\u05E2\u05D3\u05D9\u05D9\u05DF \u05E8\u05E5\u2026"],
|
|
12843
12882
|
read: ["\u05E7\u05D5\u05E8\u05D0\u05D9\u05DD\u2026", "\u05E2\u05D5\u05D1\u05E8\u05D9\u05DD \u05E2\u05DC \u05D6\u05D4\u2026"]
|
|
12883
|
+
},
|
|
12884
|
+
"he-f": {
|
|
12885
|
+
board: ["\u05D1\u05D5\u05D3\u05E7\u05EA \u05D1\u05DC\u05D5\u05D7\u2026", "\u05DE\u05E1\u05EA\u05DB\u05DC\u05EA \u05E2\u05DC \u05D4\u05DB\u05E8\u05D8\u05D9\u05E1\u05D9\u05DD\u2026"],
|
|
12886
|
+
mail: ["\u05D1\u05D5\u05D3\u05E7\u05EA \u05D0\u05EA \u05D4\u05DE\u05D9\u05D9\u05DC\u2026", "\u05E2\u05D5\u05D1\u05E8\u05EA \u05E2\u05DC \u05D4\u05D3\u05D5\u05D0\u05E8\u2026"],
|
|
12887
|
+
calendar: ["\u05D1\u05D5\u05D3\u05E7\u05EA \u05D1\u05D9\u05D5\u05DE\u05DF\u2026", "\u05DE\u05E1\u05EA\u05DB\u05DC\u05EA \u05D1\u05DC\u05D5\u05F4\u05D6\u2026"],
|
|
12888
|
+
memory: ["\u05D1\u05D5\u05D3\u05E7\u05EA \u05D1\u05E8\u05E9\u05D9\u05DE\u05D5\u05EA\u2026", "\u05DE\u05D7\u05E4\u05E9\u05EA \u05D1\u05D6\u05D9\u05DB\u05E8\u05D5\u05DF\u2026"],
|
|
12889
|
+
websearch: ["\u05DE\u05D7\u05E4\u05E9\u05EA\u2026", "\u05DE\u05D7\u05E4\u05E9\u05EA \u05D1\u05E8\u05E9\u05EA\u2026"],
|
|
12890
|
+
page: ["\u05E7\u05D5\u05E8\u05D0\u05EA \u05D0\u05EA \u05D4\u05D3\u05E3\u2026", "\u05E2\u05D5\u05D1\u05E8\u05EA \u05E2\u05DC \u05D4\u05D3\u05E3\u2026"],
|
|
12891
|
+
browser: ["\u05E2\u05D5\u05D1\u05D3\u05EA \u05D1\u05D3\u05E4\u05D3\u05E4\u05DF\u2026", "\u05E2\u05DC \u05D4\u05D3\u05E3 \u05E2\u05DB\u05E9\u05D9\u05D5\u2026"],
|
|
12892
|
+
search: ["\u05DE\u05D7\u05E4\u05E9\u05EA\u2026", "\u05E2\u05D3\u05D9\u05D9\u05DF \u05DE\u05D7\u05E4\u05E9\u05EA\u2026"],
|
|
12893
|
+
delegate: ["\u05E2\u05D5\u05D1\u05D3\u05EA \u05E2\u05DC \u05D6\u05D4\u2026", "\u05E2\u05D3\u05D9\u05D9\u05DF \u05E2\u05DC \u05D6\u05D4\u2026"],
|
|
12894
|
+
write: ["\u05DE\u05D1\u05E6\u05E2\u05EA \u05D0\u05EA \u05D4\u05E9\u05D9\u05E0\u05D5\u05D9\u2026", "\u05DB\u05D5\u05EA\u05D1\u05EA \u05D0\u05EA \u05D6\u05D4\u2026"],
|
|
12895
|
+
run: ["\u05DE\u05E8\u05D9\u05E6\u05D4\u2026", "\u05E2\u05D3\u05D9\u05D9\u05DF \u05E8\u05E5\u2026"],
|
|
12896
|
+
read: ["\u05E7\u05D5\u05E8\u05D0\u05EA\u2026", "\u05E2\u05D5\u05D1\u05E8\u05EA \u05E2\u05DC \u05D6\u05D4\u2026"]
|
|
12897
|
+
},
|
|
12898
|
+
"he-m": {
|
|
12899
|
+
board: ["\u05D1\u05D5\u05D3\u05E7 \u05D1\u05DC\u05D5\u05D7\u2026", "\u05DE\u05E1\u05EA\u05DB\u05DC \u05E2\u05DC \u05D4\u05DB\u05E8\u05D8\u05D9\u05E1\u05D9\u05DD\u2026"],
|
|
12900
|
+
mail: ["\u05D1\u05D5\u05D3\u05E7 \u05D0\u05EA \u05D4\u05DE\u05D9\u05D9\u05DC\u2026", "\u05E2\u05D5\u05D1\u05E8 \u05E2\u05DC \u05D4\u05D3\u05D5\u05D0\u05E8\u2026"],
|
|
12901
|
+
calendar: ["\u05D1\u05D5\u05D3\u05E7 \u05D1\u05D9\u05D5\u05DE\u05DF\u2026", "\u05DE\u05E1\u05EA\u05DB\u05DC \u05D1\u05DC\u05D5\u05F4\u05D6\u2026"],
|
|
12902
|
+
memory: ["\u05D1\u05D5\u05D3\u05E7 \u05D1\u05E8\u05E9\u05D9\u05DE\u05D5\u05EA\u2026", "\u05DE\u05D7\u05E4\u05E9 \u05D1\u05D6\u05D9\u05DB\u05E8\u05D5\u05DF\u2026"],
|
|
12903
|
+
websearch: ["\u05DE\u05D7\u05E4\u05E9\u2026", "\u05DE\u05D7\u05E4\u05E9 \u05D1\u05E8\u05E9\u05EA\u2026"],
|
|
12904
|
+
page: ["\u05E7\u05D5\u05E8\u05D0 \u05D0\u05EA \u05D4\u05D3\u05E3\u2026", "\u05E2\u05D5\u05D1\u05E8 \u05E2\u05DC \u05D4\u05D3\u05E3\u2026"],
|
|
12905
|
+
browser: ["\u05E2\u05D5\u05D1\u05D3 \u05D1\u05D3\u05E4\u05D3\u05E4\u05DF\u2026", "\u05E2\u05DC \u05D4\u05D3\u05E3 \u05E2\u05DB\u05E9\u05D9\u05D5\u2026"],
|
|
12906
|
+
search: ["\u05DE\u05D7\u05E4\u05E9\u2026", "\u05E2\u05D3\u05D9\u05D9\u05DF \u05DE\u05D7\u05E4\u05E9\u2026"],
|
|
12907
|
+
delegate: ["\u05E2\u05D5\u05D1\u05D3 \u05E2\u05DC \u05D6\u05D4\u2026", "\u05E2\u05D3\u05D9\u05D9\u05DF \u05E2\u05DC \u05D6\u05D4\u2026"],
|
|
12908
|
+
write: ["\u05DE\u05D1\u05E6\u05E2 \u05D0\u05EA \u05D4\u05E9\u05D9\u05E0\u05D5\u05D9\u2026", "\u05DB\u05D5\u05EA\u05D1 \u05D0\u05EA \u05D6\u05D4\u2026"],
|
|
12909
|
+
run: ["\u05DE\u05E8\u05D9\u05E5\u2026", "\u05E2\u05D3\u05D9\u05D9\u05DF \u05E8\u05E5\u2026"],
|
|
12910
|
+
read: ["\u05E7\u05D5\u05E8\u05D0\u2026", "\u05E2\u05D5\u05D1\u05E8 \u05E2\u05DC \u05D6\u05D4\u2026"]
|
|
12844
12911
|
}
|
|
12845
12912
|
};
|
|
12846
12913
|
var ProgressOptions = class {
|
|
12847
12914
|
templates = PROGRESS_TEMPLATES;
|
|
12915
|
+
/** The voice's gender: picks the gendered table (`${lang}-f`/`-m`) when one exists. */
|
|
12916
|
+
gender = "";
|
|
12848
12917
|
/** Fast-model fallback for a tool with no template (fastProgressGenerator). Absent → silence. */
|
|
12849
12918
|
generate;
|
|
12850
12919
|
generateBudgetMs = 800;
|
|
@@ -12893,8 +12962,11 @@ var Progress = class {
|
|
|
12893
12962
|
async line(tool, args, lang) {
|
|
12894
12963
|
if (this.streamed) return "";
|
|
12895
12964
|
const name = tool.toLowerCase();
|
|
12896
|
-
const
|
|
12897
|
-
|
|
12965
|
+
const hit = TOPICS.find(([re]) => re.test(name));
|
|
12966
|
+
if (hit && hit[1] === null) return "";
|
|
12967
|
+
const topic = hit?.[1];
|
|
12968
|
+
const g = this.o.gender ? this.o.templates[`${lang}-${this.o.gender[0]}`] : void 0;
|
|
12969
|
+
const pool = topic ? (g ?? this.o.templates[lang])?.[topic] ?? [] : [];
|
|
12898
12970
|
const fresh = pool.find((l2) => !this.said.has(norm3(l2)));
|
|
12899
12971
|
if (fresh) return fresh;
|
|
12900
12972
|
if (!this.o.generate) return "";
|
|
@@ -12915,9 +12987,9 @@ var Progress = class {
|
|
|
12915
12987
|
return l;
|
|
12916
12988
|
}
|
|
12917
12989
|
};
|
|
12918
|
-
function fastProgressGenerator(ai, model) {
|
|
12990
|
+
function fastProgressGenerator(ai, model, gender) {
|
|
12919
12991
|
return async (tool, hint, lang, signal) => {
|
|
12920
|
-
const prompt = `An assistant on a live voice call is running the tool "${tool}"${hint ? ` (about: "${hint}")` : ""}. Write ONE spoken line of 2-5 words, in ${languageName(lang)}, saying what it is doing right now (like "checking the board\u2026"). Never state a result or a finding. Output only the line.`;
|
|
12992
|
+
const prompt = `An assistant on a live voice call is running the tool "${tool}"${hint ? ` (about: "${hint}")` : ""}. Write ONE spoken line of 2-5 words, in ${languageName(lang)}, saying what it is doing right now (like "checking the board\u2026"). Never state a result or a finding. ${personaHint(gender)} Output only the line.`;
|
|
12921
12993
|
const reasoning = /gpt-oss/.test(model) ? { providerOptions: { reasoning_effort: "low" } } : {};
|
|
12922
12994
|
const r = await ai.chat({ model, messages: [{ role: "user", content: prompt }], stream: false, signal, maxTokens: 150, ...reasoning });
|
|
12923
12995
|
return r.content ?? "";
|
|
@@ -13562,14 +13634,14 @@ var KIND_HINT2 = {
|
|
|
13562
13634
|
bridge: 'a neutral one-moment cue while the answer is prepared ("let me see\u2026", "one sec\u2026") \u2014 never the start of a statement or opinion ("the thing is", "well actually")'
|
|
13563
13635
|
};
|
|
13564
13636
|
var REACT_HINT = 'a short reaction to their LAST words instead: feeling ("oh no", "ha, nice", "ugh"), surprise ("wait, really?", "huh"), a light laugh if they joke or laugh ("ha!"), or an echo of their key word ("the deploy?") \u2014 still never asks for an answer or takes the turn; if nothing there deserves a reaction, a plain "mm-hm"';
|
|
13565
|
-
function fastLineGenerator(ai, model) {
|
|
13637
|
+
function fastLineGenerator(ai, model, gender) {
|
|
13566
13638
|
return async (c, signal) => {
|
|
13567
13639
|
const prompt = `You voice the tiny side-sounds of a live spoken conversation. Write ONE line of 1-5 words: ${KIND_HINT2[c.kind]}.
|
|
13568
13640
|
` + (c.react ? `Here the line may be ${REACT_HINT}.
|
|
13569
13641
|
` : "") + `The user just said: "${c.heard}"
|
|
13570
13642
|
The assistant is: ${c.state}.
|
|
13571
13643
|
` + (c.avoid.length ? `Do not reuse any of: ${c.avoid.map((a) => `"${a}"`).join(", ")}.
|
|
13572
|
-
` : "") + `React to their actual words, casually, in ${languageName(c.lang)}. Output only the line.`;
|
|
13644
|
+
` : "") + `React to their actual words, casually, in ${languageName(c.lang)}. ${personaHint(gender)} Output only the line.`;
|
|
13573
13645
|
const reasoning = /gpt-oss/.test(model) ? { providerOptions: { reasoning_effort: "low" } } : {};
|
|
13574
13646
|
const r = await ai.chat({ model, messages: [{ role: "user", content: prompt }], stream: false, signal, maxTokens: 150, ...reasoning });
|
|
13575
13647
|
return r.content ?? "";
|
|
@@ -13607,6 +13679,8 @@ var VoiceCallOptions = class {
|
|
|
13607
13679
|
bankCacheDir;
|
|
13608
13680
|
/** The host STT's language (BCP-47) — the starting language; each turn's own words still decide. */
|
|
13609
13681
|
lang;
|
|
13682
|
+
/** The voice's gender: generated fill/progress lines speak of themselves in it (Hebrew templates too). '' = neutral. */
|
|
13683
|
+
gender = "";
|
|
13610
13684
|
aec = false;
|
|
13611
13685
|
mode = "normal";
|
|
13612
13686
|
gate = {};
|
|
@@ -13616,6 +13690,8 @@ var VoiceCallOptions = class {
|
|
|
13616
13690
|
onMetric = () => {
|
|
13617
13691
|
};
|
|
13618
13692
|
now = () => performance.now();
|
|
13693
|
+
/** An aside (aside()) needs this long since the last one — a cue answered every time sounds scripted. */
|
|
13694
|
+
asideGapMs = 8e3;
|
|
13619
13695
|
};
|
|
13620
13696
|
var VoiceCall = class {
|
|
13621
13697
|
constructor(options) {
|
|
@@ -13628,7 +13704,7 @@ var VoiceCall = class {
|
|
|
13628
13704
|
...ai ? {
|
|
13629
13705
|
banks: new ChannelBanks({ generate: fastBankGenerator(ai, o.fastModel), ...o.bankCacheDir ? { cacheDir: o.bankCacheDir } : {} }),
|
|
13630
13706
|
decide: channelDecide(ai),
|
|
13631
|
-
generate: fastLineGenerator(ai, o.fastModel)
|
|
13707
|
+
generate: fastLineGenerator(ai, o.fastModel, o.gender)
|
|
13632
13708
|
} : {},
|
|
13633
13709
|
mode: o.mode,
|
|
13634
13710
|
aec: o.aec,
|
|
@@ -13642,7 +13718,7 @@ var VoiceCall = class {
|
|
|
13642
13718
|
cancel: () => o.cancel(),
|
|
13643
13719
|
now: o.now
|
|
13644
13720
|
});
|
|
13645
|
-
this.progress = new Progress({ ...ai ? { generate: fastProgressGenerator(ai, o.fastModel) } : {}, now: o.now, ...o.progress });
|
|
13721
|
+
this.progress = new Progress({ ...ai ? { generate: fastProgressGenerator(ai, o.fastModel, o.gender) } : {}, gender: o.gender, now: o.now, ...o.progress });
|
|
13646
13722
|
this.judge = new OverlapJudge({ ...ai ? { model: overlapModelFor(ai) } : {}, now: o.now });
|
|
13647
13723
|
this.gate = new TurnGate({
|
|
13648
13724
|
now: o.now,
|
|
@@ -13659,6 +13735,7 @@ var VoiceCall = class {
|
|
|
13659
13735
|
judge;
|
|
13660
13736
|
cur;
|
|
13661
13737
|
lang = null;
|
|
13738
|
+
lastAside = { text: "", at: -Infinity };
|
|
13662
13739
|
lastAudibleAt = -Infinity;
|
|
13663
13740
|
firstFinalAt = null;
|
|
13664
13741
|
// the first final of the turn being formed (hold/merge)
|
|
@@ -13767,6 +13844,19 @@ var VoiceCall = class {
|
|
|
13767
13844
|
if (d.verdict === "cut") this.barge();
|
|
13768
13845
|
return d.verdict;
|
|
13769
13846
|
}
|
|
13847
|
+
/** The fill channel's spoken aside for an overlap judged 'keep' ("yeah" → "Oh yeah, definitely."): the host plays it
|
|
13848
|
+
* while the reply is held, then resumes the same reply (bod-voice decideOverlap's aside). ≤4 canned words, never a
|
|
13849
|
+
* claim, the cue's language; null = stay quiet (a plain listener cue, too soon after the last, or no line). It is a
|
|
13850
|
+
* fill line: never MAIN history. */
|
|
13851
|
+
aside(text) {
|
|
13852
|
+
const now4 = this.o.now();
|
|
13853
|
+
if (now4 - this.lastAside.at < this.o.asideGapMs) return null;
|
|
13854
|
+
const line = overlapAside(text, this.lang, this.lastAside.text);
|
|
13855
|
+
if (!line) return null;
|
|
13856
|
+
this.lastAside = { text: line, at: now4 };
|
|
13857
|
+
this.o.onMetric({ name: "fill", kind: "aside", text: line, lang: this.lang });
|
|
13858
|
+
return line;
|
|
13859
|
+
}
|
|
13770
13860
|
/** Did the last barge cut OUR fill line `text`? (hosts strip it from the cut reply — it is not MAIN's speech) */
|
|
13771
13861
|
spoke(text) {
|
|
13772
13862
|
return this.fill.spoke(text);
|
|
@@ -14749,7 +14839,7 @@ Reference files in them by their mount path (the left side).`;
|
|
|
14749
14839
|
// turns, amortising the ~2s Agent.create + h2 handshake. Keyed per agentx launch.
|
|
14750
14840
|
...(() => {
|
|
14751
14841
|
const po = providerOptionsFor(o.model, cwd, o.mcpServers, o.hostMcpServers);
|
|
14752
|
-
return po ? { providerOptions: po } : {};
|
|
14842
|
+
return po ? { providerOptions: o.lean && isClaudeCode ? { ...po, settingSources: [] } : po } : {};
|
|
14753
14843
|
})(),
|
|
14754
14844
|
...(() => {
|
|
14755
14845
|
const now4 = /* @__PURE__ */ new Date();
|
|
@@ -14811,12 +14901,11 @@ Windows paths: file tools accept ${cwd} style paths and the same path written ${
|
|
|
14811
14901
|
// Subagent transcript traces, origin-anchored under .agent/traces (disk mode only — sandbox/db modes
|
|
14812
14902
|
// must never write the real disk). Lets an interrupted/failed child leave a readable trail + pointer.
|
|
14813
14903
|
...!virtual ? { traceDir: `${cwd}/.agent/traces` } : {},
|
|
14814
|
-
skillsDir: dots("skills"),
|
|
14815
|
-
commandsDir: dots("commands"),
|
|
14904
|
+
...o.lean ? {} : { skillsDir: dots("skills"), commandsDir: dots("commands") },
|
|
14816
14905
|
memoryDir,
|
|
14817
14906
|
memoryUserDir,
|
|
14818
14907
|
agentsDir: dot("agents"),
|
|
14819
|
-
instructionFiles: o.instructionFiles ?? ["AGENTS.md", "CLAUDE.md"],
|
|
14908
|
+
instructionFiles: o.lean ? false : o.instructionFiles ?? ["AGENTS.md", "CLAUDE.md"],
|
|
14820
14909
|
// Only override the Agent's safety defaults when explicitly configured.
|
|
14821
14910
|
...o.maxTokens != null ? { maxTokens: o.maxTokens } : {},
|
|
14822
14911
|
...o.timeoutMs != null ? { timeoutMs: o.timeoutMs } : {},
|
|
@@ -15355,7 +15444,9 @@ function bindVoiceCall(v, call, live, decideMs = 900) {
|
|
|
15355
15444
|
if (!live() || ev.kind !== "overlap_pause") return;
|
|
15356
15445
|
const heard = String(ev.text ?? "");
|
|
15357
15446
|
void call.overlap(heard).then((verdict) => {
|
|
15358
|
-
if (live())
|
|
15447
|
+
if (!live()) return;
|
|
15448
|
+
if (verdict === "keep") v.decideOverlap("keep_talking", heard, call.aside(heard) ?? void 0);
|
|
15449
|
+
else v.decideOverlap("yield", heard);
|
|
15359
15450
|
});
|
|
15360
15451
|
};
|
|
15361
15452
|
Object.defineProperty(call.fill.options, "aec", { get: () => v.usingAec, set: () => {
|
|
@@ -15457,6 +15548,8 @@ var VoiceIO = class extends VoiceEngine {
|
|
|
15457
15548
|
...o,
|
|
15458
15549
|
stt: o.stt ?? new SonioxSTT({ auth: o.sonioxApiKey, source: duplex ?? new NodeMicSource(), terms: o.sttTerms }),
|
|
15459
15550
|
tts: o.tts ?? new CartesiaTTS({ auth: o.cartesiaApiKey, voiceId: o.cartesiaVoiceId }),
|
|
15551
|
+
asideTts: o.tts ? null : new CartesiaTTS({ auth: o.cartesiaApiKey, voiceId: o.cartesiaVoiceId }),
|
|
15552
|
+
// asides (VoiceCall.aside): a 2nd client — the reply's context may still stream
|
|
15460
15553
|
player: o.player ?? duplex ?? new Player(),
|
|
15461
15554
|
bargeRmsMult: Number(process.env.BARGE_RMS_MULT || o.bargeRmsMult),
|
|
15462
15555
|
bargeRmsFloor: Number(process.env.BARGE_RMS_FLOOR || o.bargeRmsFloor),
|
|
@@ -18725,14 +18818,19 @@ function parseArgs(argv) {
|
|
|
18725
18818
|
} else if (x === "--call") {
|
|
18726
18819
|
a.call = true;
|
|
18727
18820
|
a.duplex = true;
|
|
18728
|
-
} else if (x === "--
|
|
18821
|
+
} else if (x === "--lean") a.lean = true;
|
|
18822
|
+
else if (x === "--keep-alive") a.keepAlive = true;
|
|
18729
18823
|
else if (x === "--channel-only") a.channelOnly = true;
|
|
18730
18824
|
else if (x === "--channel-mode") a.channelMode = parseChannelMode(val(++i, x));
|
|
18731
18825
|
else if (x === "--conversational" || x === "--convo" || x === "--voice") {
|
|
18732
18826
|
a.voice = true;
|
|
18733
18827
|
a.duplex = true;
|
|
18734
18828
|
} else if (x === "--voice-model") a.voiceModel = val(++i, x);
|
|
18735
|
-
else if (x === "--
|
|
18829
|
+
else if (x === "--voice-gender") {
|
|
18830
|
+
const g = val(++i, x);
|
|
18831
|
+
if (g !== "female" && g !== "male") throw new Error("--voice-gender is female or male");
|
|
18832
|
+
a.voiceGender = g;
|
|
18833
|
+
} else if (x === "--think-model") a.thinkModel = val(++i, x);
|
|
18736
18834
|
else if (x === "--no-think") a.thinkModel = false;
|
|
18737
18835
|
else if (x === "--allowedTools" || x === "--allowed-tools") a.allowedTools = val(++i, x).split(",").map((s) => s.trim()).filter(Boolean);
|
|
18738
18836
|
else if (x === "--disallowedTools" || x === "--disallowed-tools") a.disallowedTools = val(++i, x).split(",").map((s) => s.trim()).filter(Boolean);
|
|
@@ -18838,6 +18936,8 @@ Flags:
|
|
|
18838
18936
|
impulsive reactions, human pacing (implies --duplex; aliases: --convo, --voice)
|
|
18839
18937
|
with SONIOX_API_KEY + CARTESIA_API_KEY(+VOICE_ID) set: real voice I/O \u2014 mic in,
|
|
18840
18938
|
spoken replies out (echo-cancelled; speak over it to interrupt)
|
|
18939
|
+
--voice-gender <female|male> with --call/--channel-only: the voice's gender \u2014 fill and progress lines speak of
|
|
18940
|
+
themselves in it (Hebrew and other gendered languages); unset = gender-neutral wording
|
|
18841
18941
|
--voice-model <id> with --duplex: the fast voice model (default groq/openai/gpt-oss-120b)
|
|
18842
18942
|
--think-model <id> with --duplex: the premium deep-reasoning model (default: the newest anthropic Opus)
|
|
18843
18943
|
--no-think with --duplex: disable the Think tier (Act handles everything)
|
|
@@ -18858,6 +18958,9 @@ Flags:
|
|
|
18858
18958
|
results/reminders; note: persistent background) \u2014 never stored as the user's words
|
|
18859
18959
|
with -p: the first {"type":"user","text"} line is the prompt; later ones STEER the running turn
|
|
18860
18960
|
(unconsumed steers come back as the result's \`unsteered\`)
|
|
18961
|
+
--lean a lean prompt (a voice call's turn \u2014 time to first word): no skill, slash-command or
|
|
18962
|
+
AGENTS.md/CLAUDE.md catalogs; claude-code/* runs isolated from settings files (no CLAUDE.md,
|
|
18963
|
+
skills, plugins or settings MCP servers) \u2014 the host's MCP servers (--mcp-config/.agent) stay
|
|
18861
18964
|
--keep-alive with -p --input-format stream-json: stay up after a turn \u2014 each {"type":"user"} line while idle
|
|
18862
18965
|
is the NEXT turn (warm: same session, model connection and MCP servers), one {type:result}
|
|
18863
18966
|
per turn; it boots (and warms a claude-code/* session) before the first line arrives;
|
|
@@ -19639,6 +19742,7 @@ function optsFor(args, ai, cfg = {}, extraTools = []) {
|
|
|
19639
19742
|
// Forwarded to cursor/* delegations for environment parity (chat-model providers ignore it).
|
|
19640
19743
|
// Raw config (pre-OAuth): unresolved-oauth http servers are skipped by the cursor mapper.
|
|
19641
19744
|
mcpServers: cfg.mcpServers,
|
|
19745
|
+
lean: args.lean,
|
|
19642
19746
|
// Gates + powers default-on WebSearchAnthropic. Same precedence as the main client (env wins).
|
|
19643
19747
|
anthropicKey: apiKeysFromEnv().anthropic ?? cfg.apiKeys?.anthropic,
|
|
19644
19748
|
anthropicWebSearch: cfg.anthropicWebSearch
|
|
@@ -20351,7 +20455,8 @@ async function repl(args, ai, cfg, cwd) {
|
|
|
20351
20455
|
ai,
|
|
20352
20456
|
fastModel: args.voiceModel ?? process.env.AGENTX_CHANNEL_MODEL ?? new VoiceCallOptions().fastModel,
|
|
20353
20457
|
mode: args.channelMode,
|
|
20354
|
-
channel: channelOptions(ai, args.voiceModel ?? process.env.AGENTX_CHANNEL_MODEL ?? new VoiceCallOptions().fastModel),
|
|
20458
|
+
channel: channelOptions(ai, args.voiceModel ?? process.env.AGENTX_CHANNEL_MODEL ?? new VoiceCallOptions().fastModel, args.voiceGender),
|
|
20459
|
+
gender: args.voiceGender ?? "",
|
|
20355
20460
|
show: (t, kind) => {
|
|
20356
20461
|
err("\r\x1B[0J" + dim(` \u21B3 ${kind === "progress" ? "\u22EF " : ""}${t}
|
|
20357
20462
|
`));
|
|
@@ -22452,7 +22557,7 @@ var leakDecider = () => voiceDecider();
|
|
|
22452
22557
|
function makeSecondChannel(ai, reflexModel, mode = "normal", opts) {
|
|
22453
22558
|
return new SecondChannel({ ...channelOptions(ai, process.env.AGENTX_CHANNEL_MODEL || reflexModel), mode, ...opts });
|
|
22454
22559
|
}
|
|
22455
|
-
function channelOptions(ai, model) {
|
|
22560
|
+
function channelOptions(ai, model, gender) {
|
|
22456
22561
|
const decider = leakDecider();
|
|
22457
22562
|
const instinct = decider ? new Instinct({ decider }) : void 0;
|
|
22458
22563
|
const planner = new BackchannelPlanner(ai, { model });
|
|
@@ -22460,18 +22565,21 @@ function channelOptions(ai, model) {
|
|
|
22460
22565
|
// Banks in the user's language: generated once per language, cached + topped up across sessions (~/.agent/cache).
|
|
22461
22566
|
banks: new ChannelBanks({ generate: fastBankGenerator(ai, model), cacheDir: join16(homedir10(), ".agent", "cache", "channel-banks") }),
|
|
22462
22567
|
decide: channelDecide(ai, instinct),
|
|
22463
|
-
generate: fastLineGenerator(ai, model),
|
|
22568
|
+
generate: fastLineGenerator(ai, model, gender),
|
|
22464
22569
|
// Anticipated backchannels: on in chatty mode (its preset), else off until the offline replay proves them (tests/voice-bc-anticipate-eval.ts)
|
|
22465
22570
|
plan: (c, s) => planner.plan(c, s),
|
|
22466
22571
|
...process.env.AGENTX_CHANNEL_ANTICIPATE === "1" ? { anticipate: true } : {},
|
|
22467
22572
|
onEvent: (e) => log40.debug(`channel ${e.trigger}: rule=${e.rule} choice=${e.choice ?? "-"} \u2192 ${e.acted}${e.text ? ` "${e.text}"` : ""}${e.cue ? " (planned cue)" : ""} ${e.ms}ms`)
|
|
22468
22573
|
};
|
|
22469
22574
|
}
|
|
22470
|
-
function overlapResponder(ai, mode, out) {
|
|
22575
|
+
function overlapResponder(ai, mode, out, aside) {
|
|
22471
22576
|
const judge = softBarge(mode) ? new OverlapJudge({ model: overlapModelFor(ai) }) : void 0;
|
|
22472
22577
|
return (m) => {
|
|
22473
22578
|
const text = String(m.text ?? "");
|
|
22474
|
-
void (judge ? judge.judge(text) : Promise.resolve({ verdict: "cut", by: "mode", ms: 0 })).then((d) =>
|
|
22579
|
+
void (judge ? judge.judge(text) : Promise.resolve({ verdict: "cut", by: "mode", ms: 0 })).then((d) => {
|
|
22580
|
+
const line = d.verdict === "keep" ? aside?.(text) : null;
|
|
22581
|
+
out({ type: "overlap", ...m.id !== void 0 ? { id: m.id } : {}, verdict: d.verdict, by: d.by, ms: d.ms, ...line ? { aside: line } : {} });
|
|
22582
|
+
});
|
|
22475
22583
|
};
|
|
22476
22584
|
}
|
|
22477
22585
|
async function duplexServe(args, ai, cfg, cwd) {
|
|
@@ -22593,7 +22701,8 @@ async function channelServe(args, ai, cfg) {
|
|
|
22593
22701
|
const call = new VoiceCall({
|
|
22594
22702
|
fastModel: model,
|
|
22595
22703
|
mode: args.channelMode,
|
|
22596
|
-
|
|
22704
|
+
gender: args.voiceGender ?? "",
|
|
22705
|
+
channel: channelOptions(ai, process.env.AGENTX_CHANNEL_MODEL || model, args.voiceGender),
|
|
22597
22706
|
speak: () => true,
|
|
22598
22707
|
// the host plays {type:'channel'} lines (shown via show)
|
|
22599
22708
|
show: (text, kind) => out({ type: "channel", kind, text }),
|
|
@@ -22607,7 +22716,7 @@ async function channelServe(args, ai, cfg) {
|
|
|
22607
22716
|
const overlap2 = overlapResponder(ai, args.channelMode, (o) => {
|
|
22608
22717
|
if (o.verdict === "cut") call.barge();
|
|
22609
22718
|
out(o);
|
|
22610
|
-
});
|
|
22719
|
+
}, (t) => call.aside(t));
|
|
22611
22720
|
out({ type: "ready", model, channelMode: args.channelMode, softBarge: softBarge(args.channelMode), call: true, ...notes.length ? { notes } : {} });
|
|
22612
22721
|
const rl = createInterface({ input: process.stdin });
|
|
22613
22722
|
rl.on("line", (line) => {
|