@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/index.d.ts CHANGED
@@ -1,5 +1,5 @@
1
- import { a as AgentOptions, H as Hooks, p as RunResult, f as Decider, A as Agent, i as PermissionPolicy, L as LineKind, C as ChannelMode, q as SecondChannelOptions, S as SecondChannel } from './secondChannel-CJMY5EbL.js';
2
- export { b as ChatFragment, c as Classification, d as Classifier, e as CompactResult, D as DEFAULT_MUTATING, g as Decision, M as ModelRouter, h as ModelRouterOptions, P as PermissionOptions, j as PermissionRule, k as PreToolUseDecision, R as ReasoningEffort, l as RecordingHooks, m as RecordingLifecycle, n as RouteDecision, o as RouterState, T as Tier, r as ToolUse, s as ToolUseMeta, t as claudeCodeDisallowedTools, u as composeHooks, v as estimateTokens, w as jevAvailable, x as jevClassifier, y as pickTier, z as planMode, B as reasoningToChatFragment } from './secondChannel-CJMY5EbL.js';
1
+ import { a as AgentOptions, H as Hooks, p as RunResult, f as Decider, A as Agent, i as PermissionPolicy, G as Gender, L as LineKind, C as ChannelMode, q as SecondChannelOptions, S as SecondChannel } from './secondChannel-Cl-fIl-F.js';
2
+ export { b as ChatFragment, c as Classification, d as Classifier, e as CompactResult, D as DEFAULT_MUTATING, g as Decision, M as ModelRouter, h as ModelRouterOptions, P as PermissionOptions, j as PermissionRule, k as PreToolUseDecision, R as ReasoningEffort, l as RecordingHooks, m as RecordingLifecycle, n as RouteDecision, o as RouterState, T as Tier, r as ToolUse, s as ToolUseMeta, t as claudeCodeDisallowedTools, u as composeHooks, v as estimateTokens, w as jevAvailable, x as jevClassifier, y as pickTier, z as planMode, B as reasoningToChatFragment } from './secondChannel-Cl-fIl-F.js';
3
3
  export { MODEL_ALIASES, ModelSwitch, ResolveModelSwitchOpts, latestClaude, modelShortLabel, resolveModelAlias, resolveModelSwitch } from './models.js';
4
4
  import { IFilesystem, FileMetadata } from '@livx.cc/wcli/core';
5
5
  export { CommandExecutor, FileMetadata, IFilesystem, IndexedDbFilesystem, MemFilesystem, registerHeadlessCommands } from '@livx.cc/wcli/core';
@@ -1621,11 +1621,14 @@ declare function makeTaskBatchTool(opts: TaskToolOptions): AgentTool;
1621
1621
  /** Component-scoped logger (libx.js). debug/verbose gated via DEBUG env/localStorage. */
1622
1622
  declare const forComponent: (name: string) => libx_js_src_modules_log.ComponentLogger;
1623
1623
 
1624
- type Topic = 'board' | 'search' | 'web' | 'read' | 'write' | 'run' | 'mail' | 'calendar' | 'memory';
1625
- /** Two phrasings per topic and language (never the same line twice in a call). */
1624
+ type Topic = 'board' | 'websearch' | 'page' | 'browser' | 'search' | 'mail' | 'calendar' | 'memory' | 'write' | 'run' | 'read' | 'delegate';
1625
+ /** Two phrasings per topic and language (never the same line twice in a call). Hebrew is gendered on the speaker:
1626
+ * 'he-f' / 'he-m' follow the voice (ProgressOptions.gender); 'he' (plural present) when the gender is unknown. */
1626
1627
  declare const PROGRESS_TEMPLATES: Record<string, Record<Topic, string[]>>;
1627
1628
  declare class ProgressOptions {
1628
1629
  templates: Record<string, Partial<Record<Topic, string[]>>>;
1630
+ /** The voice's gender: picks the gendered table (`${lang}-f`/`-m`) when one exists. */
1631
+ gender: Gender;
1629
1632
  /** Fast-model fallback for a tool with no template (fastProgressGenerator). Absent → silence. */
1630
1633
  generate?: (tool: string, hint: string, lang: string, signal: AbortSignal) => Promise<string>;
1631
1634
  generateBudgetMs: number;
@@ -1695,6 +1698,8 @@ declare class VoiceCallOptions {
1695
1698
  bankCacheDir?: string;
1696
1699
  /** The host STT's language (BCP-47) — the starting language; each turn's own words still decide. */
1697
1700
  lang?: string;
1701
+ /** The voice's gender: generated fill/progress lines speak of themselves in it (Hebrew templates too). '' = neutral. */
1702
+ gender: Gender;
1698
1703
  aec: boolean;
1699
1704
  mode: ChannelMode;
1700
1705
  gate: Partial<TurnGateOptions>;
@@ -1703,6 +1708,8 @@ declare class VoiceCallOptions {
1703
1708
  channel: Partial<SecondChannelOptions>;
1704
1709
  onMetric: (m: CallMetric) => void;
1705
1710
  now: () => number;
1711
+ /** An aside (aside()) needs this long since the last one — a cue answered every time sounds scripted. */
1712
+ asideGapMs: number;
1706
1713
  }
1707
1714
  declare class VoiceCall {
1708
1715
  options?: Partial<VoiceCallOptions> | undefined;
@@ -1712,6 +1719,7 @@ declare class VoiceCall {
1712
1719
  private judge;
1713
1720
  private cur?;
1714
1721
  private lang;
1722
+ private lastAside;
1715
1723
  private lastAudibleAt;
1716
1724
  private firstFinalAt;
1717
1725
  private progressTimer;
@@ -1742,6 +1750,11 @@ declare class VoiceCall {
1742
1750
  barge(): void;
1743
1751
  /** Soft barge-in: keep (a listener cue — no turn) or cut (→ barge()). */
1744
1752
  overlap(text: string): Promise<OverlapVerdict>;
1753
+ /** The fill channel's spoken aside for an overlap judged 'keep' ("yeah" → "Oh yeah, definitely."): the host plays it
1754
+ * while the reply is held, then resumes the same reply (bod-voice decideOverlap's aside). ≤4 canned words, never a
1755
+ * claim, the cue's language; null = stay quiet (a plain listener cue, too soon after the last, or no line). It is a
1756
+ * fill line: never MAIN history. */
1757
+ aside(text: string): string | null;
1745
1758
  /** Did the last barge cut OUR fill line `text`? (hosts strip it from the cut reply — it is not MAIN's speech) */
1746
1759
  spoke(text: string): boolean;
1747
1760
  /** Resolves when the in-flight fill line finished — hosts queue MAIN audio behind it (stack, don't cut). */
package/dist/index.js CHANGED
@@ -9304,14 +9304,40 @@ var ACK = new Set("yeah yea yes yep yup ya ok okay k right sure true totally exa
9304
9304
  var LEAD = /* @__PURE__ */ new Set(["and", "so", "um", "uh", "er", "well", "oh"]);
9305
9305
  var LEADER = /* @__PURE__ */ new Set(["yeah", "yea", "yes", "yep", "yup", "ok", "okay", "right", "sure", "alright", "mm", "mhm", "hmm", "uh-huh", "totally", "exactly", "true"]);
9306
9306
  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"];
9307
+ var CONTINUE = /^(?:(?:and|so|oh) )?(?:and|so|really|seriously|then what|and then|go on|keep going|ואז|באמת|נו)$/;
9308
+ 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(" "));
9309
+ var AGREE_PHRASES = ["of course", "for sure", "that's right", "that's true", "thats right", "thats true", "makes sense", "i agree"];
9310
+ 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(" "));
9311
+ function cueKind(text) {
9312
+ const t = norm2(text);
9313
+ if (!t) return null;
9314
+ if (CONTINUE.test(t)) return "continue";
9315
+ let r = t;
9316
+ for (const p of AGREE_PHRASES) if (r.includes(p)) return "agree";
9317
+ r = r.split(/[\s-]+/).filter((w) => !LEAD.has(w)).join(" ");
9318
+ return r.split(" ").some((w) => AGREE.has(w)) ? "agree" : null;
9319
+ }
9320
+ var ASIDES = {
9321
+ en: { agree: ["Oh yeah, definitely.", "Yeah, exactly.", "Right, yeah."], continue: ["Yeah, so\u2026", "So, yeah\u2026"] },
9322
+ 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"] }
9323
+ };
9324
+ function overlapAside(text, lang, avoid = "", pick = (n) => Math.floor(Math.random() * n)) {
9325
+ const kind = cueKind(text);
9326
+ const l = new RegExp("\\p{Script=Hebrew}", "u").test(text) ? "he" : /[a-z]/i.test(text) ? "en" : lang;
9327
+ const pool = kind && l ? ASIDES[l]?.[kind] : void 0;
9328
+ if (!pool?.length) return null;
9329
+ const fresh = pool.filter((x) => x !== avoid);
9330
+ return fresh[pick(fresh.length)] ?? null;
9331
+ }
9307
9332
  function overlapRule(text) {
9333
+ if (CONTINUE.test(norm2(text))) return "keep";
9308
9334
  if (/\?/.test(text)) return "cut";
9309
9335
  let t = norm2(text);
9310
9336
  if (!t) return void 0;
9311
9337
  if (HARD.test(t)) return "cut";
9312
9338
  for (const p of PHRASES) t = t.split(p).join(" ");
9313
9339
  const words3 = t.split(/[\s-]+/).filter(Boolean);
9314
- const ack = (w) => ACK.has(w) || /^(?:ha)+h?$|^(?:he)+h?$|^m+(?:hm+)?$|^h?m+$/.test(w);
9340
+ const ack = (w) => ACK.has(w) || HE_ACK.has(w) || /^(?:ha)+h?$|^(?:he)+h?$|^m+(?:hm+)?$|^h?m+$/.test(w);
9315
9341
  if (words3.every(ack)) return "keep";
9316
9342
  const lead2 = words3.findIndex((w) => !LEAD.has(w));
9317
9343
  if (lead2 >= 0 && LEADER.has(words3[lead2]) && words3.slice(lead2).filter((w) => !ack(w) && !LEAD.has(w)).length <= 1) return "keep";
@@ -9778,6 +9804,9 @@ var KIND_HINT = {
9778
9804
  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")`,
9779
9805
  phatic: 'greetings, thanks and yes/no openers a person starts a turn with (like "hi", "thanks", "how are you")'
9780
9806
  };
9807
+ function personaHint(gender) {
9808
+ 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").' : "";
9809
+ }
9781
9810
  function fastBankGenerator(ai, model, perKind = 12) {
9782
9811
  return async (lang, avoid, signal) => {
9783
9812
  const name = languageName(lang);
@@ -12534,14 +12563,19 @@ init_logging();
12534
12563
  var log26 = forComponent("Progress");
12535
12564
  var HE_RESULT_CLAIM = /(?:^|\s)(?:מצאתי|סיימתי|בוצע|הנה|אין)(?=\s|$|[.,!…])/u;
12536
12565
  var TOPICS = [
12566
+ [/toolsearch|^mcp__.*__(list_commands|call_info)$/, null],
12567
+ // tool plumbing — no line (and no generated one)
12537
12568
  [/kanban|board|card|\bkb\b|list_cards/, "board"],
12538
12569
  [/mail|gmail|inbox/, "mail"],
12539
12570
  [/calendar|event|schedule/, "calendar"],
12540
12571
  [/memory|recall|remember/, "memory"],
12541
- [/web_?search|websearch|fetch|browse|url|page|tab|browser/, "web"],
12572
+ [/web_?search|search_web|google/, "websearch"],
12573
+ [/fetch|read_page|get_page|page_text|navigate|url|history/, "page"],
12574
+ [/click|type|press_key|scroll|screenshot|tab|browser|highlight|point|wait_for|upload/, "browser"],
12542
12575
  [/grep|glob|search|find|lookup|quicklook/, "search"],
12576
+ [/^(agent|task)$|subagent|delegate/, "delegate"],
12543
12577
  [/edit|write|patch|create|update|save|delete|move/, "write"],
12544
- [/shell|bash|exec|run|command|terminal/, "run"],
12578
+ [/shell|bash|exec|run|command|terminal|eval/, "run"],
12545
12579
  [/read|open|view|cat|look|get|list|ls/, "read"]
12546
12580
  ];
12547
12581
  var PROGRESS_TEMPLATES = {
@@ -12550,27 +12584,62 @@ var PROGRESS_TEMPLATES = {
12550
12584
  mail: ["checking the mail\u2026", "going through the inbox\u2026"],
12551
12585
  calendar: ["checking the calendar\u2026", "looking at the schedule\u2026"],
12552
12586
  memory: ["checking my notes\u2026", "looking back\u2026"],
12553
- web: ["reading the page\u2026", "looking it up online\u2026"],
12587
+ websearch: ["searching\u2026", "searching the web\u2026"],
12588
+ page: ["reading the page\u2026", "going through the page\u2026"],
12589
+ browser: ["working in the browser\u2026", "on the page now\u2026"],
12554
12590
  search: ["searching\u2026", "still looking\u2026"],
12591
+ delegate: ["working on it\u2026", "still on it\u2026"],
12555
12592
  write: ["making the change\u2026", "writing it down\u2026"],
12556
12593
  run: ["running it\u2026", "still running\u2026"],
12557
12594
  read: ["reading it\u2026", "going through it\u2026"]
12558
12595
  },
12559
12596
  he: {
12560
- // plural present: gender-neutral for a voice of either gender
12561
12597
  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"],
12562
12598
  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"],
12563
12599
  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"],
12564
12600
  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"],
12565
- web: ["\u05E7\u05D5\u05E8\u05D0\u05D9\u05DD \u05D0\u05EA \u05D4\u05D3\u05E3\u2026", "\u05DE\u05D7\u05E4\u05E9\u05D9\u05DD \u05D1\u05E8\u05E9\u05EA\u2026"],
12601
+ websearch: ["\u05DE\u05D7\u05E4\u05E9\u05D9\u05DD\u2026", "\u05DE\u05D7\u05E4\u05E9\u05D9\u05DD \u05D1\u05E8\u05E9\u05EA\u2026"],
12602
+ 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"],
12603
+ 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"],
12566
12604
  search: ["\u05DE\u05D7\u05E4\u05E9\u05D9\u05DD\u2026", "\u05E2\u05D3\u05D9\u05D9\u05DF \u05DE\u05D7\u05E4\u05E9\u05D9\u05DD\u2026"],
12605
+ delegate: ["\u05E2\u05D5\u05D1\u05D3\u05D9\u05DD \u05E2\u05DC \u05D6\u05D4\u2026", "\u05E2\u05D3\u05D9\u05D9\u05DF \u05E2\u05DC \u05D6\u05D4\u2026"],
12567
12606
  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"],
12568
12607
  run: ["\u05DE\u05E8\u05D9\u05E6\u05D9\u05DD\u2026", "\u05E2\u05D3\u05D9\u05D9\u05DF \u05E8\u05E5\u2026"],
12569
12608
  read: ["\u05E7\u05D5\u05E8\u05D0\u05D9\u05DD\u2026", "\u05E2\u05D5\u05D1\u05E8\u05D9\u05DD \u05E2\u05DC \u05D6\u05D4\u2026"]
12609
+ },
12610
+ "he-f": {
12611
+ 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"],
12612
+ 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"],
12613
+ calendar: ["\u05D1\u05D5\u05D3\u05E7\u05EA \u05D1\u05D9\u05D5\u05DE\u05DF\u2026", "\u05DE\u05E1\u05EA\u05DB\u05DC\u05EA \u05D1\u05DC\u05D5\u05F4\u05D6\u2026"],
12614
+ 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"],
12615
+ websearch: ["\u05DE\u05D7\u05E4\u05E9\u05EA\u2026", "\u05DE\u05D7\u05E4\u05E9\u05EA \u05D1\u05E8\u05E9\u05EA\u2026"],
12616
+ page: ["\u05E7\u05D5\u05E8\u05D0\u05EA \u05D0\u05EA \u05D4\u05D3\u05E3\u2026", "\u05E2\u05D5\u05D1\u05E8\u05EA \u05E2\u05DC \u05D4\u05D3\u05E3\u2026"],
12617
+ browser: ["\u05E2\u05D5\u05D1\u05D3\u05EA \u05D1\u05D3\u05E4\u05D3\u05E4\u05DF\u2026", "\u05E2\u05DC \u05D4\u05D3\u05E3 \u05E2\u05DB\u05E9\u05D9\u05D5\u2026"],
12618
+ search: ["\u05DE\u05D7\u05E4\u05E9\u05EA\u2026", "\u05E2\u05D3\u05D9\u05D9\u05DF \u05DE\u05D7\u05E4\u05E9\u05EA\u2026"],
12619
+ delegate: ["\u05E2\u05D5\u05D1\u05D3\u05EA \u05E2\u05DC \u05D6\u05D4\u2026", "\u05E2\u05D3\u05D9\u05D9\u05DF \u05E2\u05DC \u05D6\u05D4\u2026"],
12620
+ 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"],
12621
+ run: ["\u05DE\u05E8\u05D9\u05E6\u05D4\u2026", "\u05E2\u05D3\u05D9\u05D9\u05DF \u05E8\u05E5\u2026"],
12622
+ read: ["\u05E7\u05D5\u05E8\u05D0\u05EA\u2026", "\u05E2\u05D5\u05D1\u05E8\u05EA \u05E2\u05DC \u05D6\u05D4\u2026"]
12623
+ },
12624
+ "he-m": {
12625
+ 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"],
12626
+ 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"],
12627
+ calendar: ["\u05D1\u05D5\u05D3\u05E7 \u05D1\u05D9\u05D5\u05DE\u05DF\u2026", "\u05DE\u05E1\u05EA\u05DB\u05DC \u05D1\u05DC\u05D5\u05F4\u05D6\u2026"],
12628
+ 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"],
12629
+ websearch: ["\u05DE\u05D7\u05E4\u05E9\u2026", "\u05DE\u05D7\u05E4\u05E9 \u05D1\u05E8\u05E9\u05EA\u2026"],
12630
+ page: ["\u05E7\u05D5\u05E8\u05D0 \u05D0\u05EA \u05D4\u05D3\u05E3\u2026", "\u05E2\u05D5\u05D1\u05E8 \u05E2\u05DC \u05D4\u05D3\u05E3\u2026"],
12631
+ browser: ["\u05E2\u05D5\u05D1\u05D3 \u05D1\u05D3\u05E4\u05D3\u05E4\u05DF\u2026", "\u05E2\u05DC \u05D4\u05D3\u05E3 \u05E2\u05DB\u05E9\u05D9\u05D5\u2026"],
12632
+ search: ["\u05DE\u05D7\u05E4\u05E9\u2026", "\u05E2\u05D3\u05D9\u05D9\u05DF \u05DE\u05D7\u05E4\u05E9\u2026"],
12633
+ delegate: ["\u05E2\u05D5\u05D1\u05D3 \u05E2\u05DC \u05D6\u05D4\u2026", "\u05E2\u05D3\u05D9\u05D9\u05DF \u05E2\u05DC \u05D6\u05D4\u2026"],
12634
+ write: ["\u05DE\u05D1\u05E6\u05E2 \u05D0\u05EA \u05D4\u05E9\u05D9\u05E0\u05D5\u05D9\u2026", "\u05DB\u05D5\u05EA\u05D1 \u05D0\u05EA \u05D6\u05D4\u2026"],
12635
+ run: ["\u05DE\u05E8\u05D9\u05E5\u2026", "\u05E2\u05D3\u05D9\u05D9\u05DF \u05E8\u05E5\u2026"],
12636
+ read: ["\u05E7\u05D5\u05E8\u05D0\u2026", "\u05E2\u05D5\u05D1\u05E8 \u05E2\u05DC \u05D6\u05D4\u2026"]
12570
12637
  }
12571
12638
  };
12572
12639
  var ProgressOptions = class {
12573
12640
  templates = PROGRESS_TEMPLATES;
12641
+ /** The voice's gender: picks the gendered table (`${lang}-f`/`-m`) when one exists. */
12642
+ gender = "";
12574
12643
  /** Fast-model fallback for a tool with no template (fastProgressGenerator). Absent → silence. */
12575
12644
  generate;
12576
12645
  generateBudgetMs = 800;
@@ -12619,8 +12688,11 @@ var Progress = class {
12619
12688
  async line(tool, args, lang) {
12620
12689
  if (this.streamed) return "";
12621
12690
  const name = tool.toLowerCase();
12622
- const topic = TOPICS.find(([re]) => re.test(name))?.[1];
12623
- const pool = topic ? this.o.templates[lang]?.[topic] ?? [] : [];
12691
+ const hit = TOPICS.find(([re]) => re.test(name));
12692
+ if (hit && hit[1] === null) return "";
12693
+ const topic = hit?.[1];
12694
+ const g = this.o.gender ? this.o.templates[`${lang}-${this.o.gender[0]}`] : void 0;
12695
+ const pool = topic ? (g ?? this.o.templates[lang])?.[topic] ?? [] : [];
12624
12696
  const fresh = pool.find((l2) => !this.said.has(norm3(l2)));
12625
12697
  if (fresh) return fresh;
12626
12698
  if (!this.o.generate) return "";
@@ -12641,9 +12713,9 @@ var Progress = class {
12641
12713
  return l;
12642
12714
  }
12643
12715
  };
12644
- function fastProgressGenerator(ai, model) {
12716
+ function fastProgressGenerator(ai, model, gender) {
12645
12717
  return async (tool, hint, lang, signal) => {
12646
- 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.`;
12718
+ 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.`;
12647
12719
  const reasoning = /gpt-oss/.test(model) ? { providerOptions: { reasoning_effort: "low" } } : {};
12648
12720
  const r = await ai.chat({ model, messages: [{ role: "user", content: prompt }], stream: false, signal, maxTokens: 150, ...reasoning });
12649
12721
  return r.content ?? "";
@@ -13230,14 +13302,14 @@ var KIND_HINT2 = {
13230
13302
  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")'
13231
13303
  };
13232
13304
  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"';
13233
- function fastLineGenerator(ai, model) {
13305
+ function fastLineGenerator(ai, model, gender) {
13234
13306
  return async (c, signal) => {
13235
13307
  const prompt = `You voice the tiny side-sounds of a live spoken conversation. Write ONE line of 1-5 words: ${KIND_HINT2[c.kind]}.
13236
13308
  ` + (c.react ? `Here the line may be ${REACT_HINT}.
13237
13309
  ` : "") + `The user just said: "${c.heard}"
13238
13310
  The assistant is: ${c.state}.
13239
13311
  ` + (c.avoid.length ? `Do not reuse any of: ${c.avoid.map((a) => `"${a}"`).join(", ")}.
13240
- ` : "") + `React to their actual words, casually, in ${languageName(c.lang)}. Output only the line.`;
13312
+ ` : "") + `React to their actual words, casually, in ${languageName(c.lang)}. ${personaHint(gender)} Output only the line.`;
13241
13313
  const reasoning = /gpt-oss/.test(model) ? { providerOptions: { reasoning_effort: "low" } } : {};
13242
13314
  const r = await ai.chat({ model, messages: [{ role: "user", content: prompt }], stream: false, signal, maxTokens: 150, ...reasoning });
13243
13315
  return r.content ?? "";
@@ -13275,6 +13347,8 @@ var VoiceCallOptions = class {
13275
13347
  bankCacheDir;
13276
13348
  /** The host STT's language (BCP-47) — the starting language; each turn's own words still decide. */
13277
13349
  lang;
13350
+ /** The voice's gender: generated fill/progress lines speak of themselves in it (Hebrew templates too). '' = neutral. */
13351
+ gender = "";
13278
13352
  aec = false;
13279
13353
  mode = "normal";
13280
13354
  gate = {};
@@ -13284,6 +13358,8 @@ var VoiceCallOptions = class {
13284
13358
  onMetric = () => {
13285
13359
  };
13286
13360
  now = () => performance.now();
13361
+ /** An aside (aside()) needs this long since the last one — a cue answered every time sounds scripted. */
13362
+ asideGapMs = 8e3;
13287
13363
  };
13288
13364
  var VoiceCall = class {
13289
13365
  constructor(options) {
@@ -13296,7 +13372,7 @@ var VoiceCall = class {
13296
13372
  ...ai ? {
13297
13373
  banks: new ChannelBanks({ generate: fastBankGenerator(ai, o.fastModel), ...o.bankCacheDir ? { cacheDir: o.bankCacheDir } : {} }),
13298
13374
  decide: channelDecide(ai),
13299
- generate: fastLineGenerator(ai, o.fastModel)
13375
+ generate: fastLineGenerator(ai, o.fastModel, o.gender)
13300
13376
  } : {},
13301
13377
  mode: o.mode,
13302
13378
  aec: o.aec,
@@ -13310,7 +13386,7 @@ var VoiceCall = class {
13310
13386
  cancel: () => o.cancel(),
13311
13387
  now: o.now
13312
13388
  });
13313
- this.progress = new Progress({ ...ai ? { generate: fastProgressGenerator(ai, o.fastModel) } : {}, now: o.now, ...o.progress });
13389
+ this.progress = new Progress({ ...ai ? { generate: fastProgressGenerator(ai, o.fastModel, o.gender) } : {}, gender: o.gender, now: o.now, ...o.progress });
13314
13390
  this.judge = new OverlapJudge({ ...ai ? { model: overlapModelFor(ai) } : {}, now: o.now });
13315
13391
  this.gate = new TurnGate({
13316
13392
  now: o.now,
@@ -13327,6 +13403,7 @@ var VoiceCall = class {
13327
13403
  judge;
13328
13404
  cur;
13329
13405
  lang = null;
13406
+ lastAside = { text: "", at: -Infinity };
13330
13407
  lastAudibleAt = -Infinity;
13331
13408
  firstFinalAt = null;
13332
13409
  // the first final of the turn being formed (hold/merge)
@@ -13435,6 +13512,19 @@ var VoiceCall = class {
13435
13512
  if (d.verdict === "cut") this.barge();
13436
13513
  return d.verdict;
13437
13514
  }
13515
+ /** The fill channel's spoken aside for an overlap judged 'keep' ("yeah" → "Oh yeah, definitely."): the host plays it
13516
+ * while the reply is held, then resumes the same reply (bod-voice decideOverlap's aside). ≤4 canned words, never a
13517
+ * claim, the cue's language; null = stay quiet (a plain listener cue, too soon after the last, or no line). It is a
13518
+ * fill line: never MAIN history. */
13519
+ aside(text) {
13520
+ const now3 = this.o.now();
13521
+ if (now3 - this.lastAside.at < this.o.asideGapMs) return null;
13522
+ const line = overlapAside(text, this.lang, this.lastAside.text);
13523
+ if (!line) return null;
13524
+ this.lastAside = { text: line, at: now3 };
13525
+ this.o.onMetric({ name: "fill", kind: "aside", text: line, lang: this.lang });
13526
+ return line;
13527
+ }
13438
13528
  /** Did the last barge cut OUR fill line `text`? (hosts strip it from the cut reply — it is not MAIN's speech) */
13439
13529
  spoke(text) {
13440
13530
  return this.fill.spoke(text);