@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 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-CJMY5EbL.js';
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|websearch|fetch|browse|url|page|tab|browser/, "web"],
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
- web: ["reading the page\u2026", "looking it up online\u2026"],
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
- web: ["\u05E7\u05D5\u05E8\u05D0\u05D9\u05DD \u05D0\u05EA \u05D4\u05D3\u05E3\u2026", "\u05DE\u05D7\u05E4\u05E9\u05D9\u05DD \u05D1\u05E8\u05E9\u05EA\u2026"],
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 topic = TOPICS.find(([re]) => re.test(name))?.[1];
12897
- const pool = topic ? this.o.templates[lang]?.[topic] ?? [] : [];
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()) v.decideOverlap(verdict === "keep" ? "keep_talking" : "yield", heard);
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 === "--keep-alive") a.keepAlive = true;
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 === "--think-model") a.thinkModel = val(++i, 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) => out({ type: "overlap", ...m.id !== void 0 ? { id: m.id } : {}, verdict: d.verdict, by: d.by, ms: d.ms }));
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
- channel: channelOptions(ai, process.env.AGENTX_CHANNEL_MODEL || model),
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) => {