agent.libx.js 0.93.36 → 0.93.38

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/README.md CHANGED
@@ -117,7 +117,7 @@ agentx --resume <id> "…" # resume a specific session
117
117
  - **Any provider** — set `ANTHROPIC_API_KEY` / `OPENAI_API_KEY` / `GOOGLE_API_KEY` / `GROQ_API_KEY`; choose with `-m provider/model`.
118
118
  - **@-file mentions & headless JSON** — reference files inline in a prompt with `@path` (e.g. `explain @src/Agent.ts`); script with `-p --output-format json` to get one machine-readable result object on stdout (activity stays on stderr).
119
119
  - **Tab-completion** — `Tab` completes `/<command>` names and `@<path>` file/dir references (descends subdirs, dotfiles hidden unless typed) straight from the working tree.
120
- - **Duplex mode** — `agentx --duplex` runs the full standard REPL (slash commands, sessions, postures, rewind, MCP) with the dual-model engine driving turns: a fast voice model (`--voice-model`, default haiku) answers every line instantly and delegates real work to background workers built with the same wiring as a normal run (fs mode, permissions, MCP); worker activity shows as dim chrome and results are re-voiced when ready.
120
+ - **Duplex mode** — `agentx --duplex` runs the full standard REPL (slash commands, sessions, postures, rewind, MCP) with the three-tier engine driving turns: a fast voice model (`--voice-model`, default `groq/openai/gpt-oss-120b`) answers every line instantly and delegates real work to background workers built with the same wiring as a normal run (fs mode, permissions, MCP); worker activity shows as dim chrome and results are re-voiced when ready. Switch any tier live with `/model` (opens a reflex/act/think picker), or the `/voice-model` · `/think-model` shortcuts.
121
121
  - **MCP servers** — declare `mcpServers: { name: { command, args } | { url } }` in config and they're auto-mounted at startup (in parallel, with an optional `mountTimeoutMs` deadline so one slow/dead server never blocks the rest): the client does the JSON-RPC handshake (stdio or HTTP) + `tools/list`, and the discovered tools appear as `mcp__<name>__<tool>` in `/tools` (inspect with `/mcp`). A bad server is logged and skipped, never blocking the agent. For large tool sets, **deferred mode** (`makeMcpToolSearch` / `mountMcpDeferred`) exposes just two bounded tools (`ToolSearch` + `McpCall`) instead of N defs — dodging the provider tool-cap and improving selection accuracy. **`mountMcpCatalog`** goes further: a cached, hash-keyed catalog + lazy connect means a turn that uses no MCP tool opens **zero** connections, and one that uses a tool connects exactly that server — latency scales with tools-used, not servers-configured. A down server is **negative-cached** (`failureCooldownMs`) so it never re-floors a later turn at the deadline. For zero turn-path latency even on a cold process, call **`warmMcpCatalog`** at boot + on a timer (off-turn discovery) and mount with **`{ discover: 'cache-only' }`** — the turn then never synchronously connects: it serves the warmed catalog and discovers any miss in the background.
122
122
 
123
123
  ## 🧬 It improves itself
package/dist/cli.js CHANGED
@@ -9104,6 +9104,47 @@ async function repl(args, ai, cfg, cwd) {
9104
9104
  persistModel(cwd, m);
9105
9105
  err(dim(" model \u2192 " + m + "\n"));
9106
9106
  };
9107
+ const applyReflexModel = (id) => {
9108
+ const m = resolveModelOrNewest(id);
9109
+ dx.options.reflexModel = m;
9110
+ dx.voice.options.model = m;
9111
+ err(green(` \u2713 reflex model \u2192 ${m}
9112
+ `));
9113
+ };
9114
+ const applyThinkModel = (id) => {
9115
+ const m = resolveModelOrNewest(id);
9116
+ dx.setThinkModel(m);
9117
+ err(green(` \u2713 think model \u2192 ${m}
9118
+ `));
9119
+ };
9120
+ const pickModelByTier = async () => {
9121
+ const thinkLabel = dx.options.thinkModel === false ? "off" : String(dx.options.thinkModel);
9122
+ const tier = await selectMenu(process.stderr, { title: "Set model for which tier?", items: [
9123
+ { label: "Reflex (voice)", value: "reflex", desc: dx.options.reflexModel },
9124
+ { label: "Act (worker)", value: "act", desc: work.model },
9125
+ { label: "Think", value: "think", desc: thinkLabel }
9126
+ ] });
9127
+ if (!tier) return;
9128
+ if (tier === "think") {
9129
+ const sub = await selectMenu(process.stderr, { title: "Think tier", items: [
9130
+ { label: "Choose a model\u2026", value: "__pick__", desc: thinkLabel === "off" ? "currently off" : `current: ${thinkLabel}` },
9131
+ { label: "Disable Think tier", value: "__off__" }
9132
+ ] });
9133
+ if (!sub) return;
9134
+ if (sub === "__off__") {
9135
+ dx.setThinkModel(false);
9136
+ err(green(" \u2713 think tier disabled\n"));
9137
+ return;
9138
+ }
9139
+ const picked2 = await pickModel(dx.options.thinkModel === false ? "anthropic/claude-opus-4-6" : String(dx.options.thinkModel));
9140
+ if (picked2) applyThinkModel(picked2);
9141
+ return;
9142
+ }
9143
+ const picked = await pickModel(tier === "reflex" ? dx.options.reflexModel : work.model);
9144
+ if (!picked) return;
9145
+ if (tier === "reflex") applyReflexModel(picked);
9146
+ else setModel(picked);
9147
+ };
9107
9148
  const addWorkTools = (ts) => {
9108
9149
  if (duplex) work.tools = [...work.tools ?? [], ...ts];
9109
9150
  else agent.addTools(ts);
@@ -9480,15 +9521,19 @@ ${extra}` : body);
9480
9521
  }
9481
9522
  },
9482
9523
  model: {
9483
- desc: "switch model \u2014 /model <id>, or /model alone for an interactive picker (duplex: the worker model)",
9524
+ desc: "switch model \u2014 /model <id> (duplex: the worker), or /model alone for a picker (duplex: pick a tier first)",
9484
9525
  run: async (a) => {
9485
9526
  if (a[0]) {
9486
9527
  setModel(a[0]);
9487
9528
  return;
9488
9529
  }
9530
+ if (duplex) {
9531
+ await pickModelByTier();
9532
+ return;
9533
+ }
9489
9534
  const picked = await pickModel(work.model);
9490
9535
  if (picked) setModel(picked);
9491
- else err(dim(" " + (duplex ? `reflex ${dx.options.reflexModel} \xB7 act ${work.model}${dx.options.thinkModel !== false ? ` \xB7 think ${dx.options.thinkModel}` : ""}` : work.model) + "\n"));
9536
+ else err(dim(" " + work.model + "\n"));
9492
9537
  }
9493
9538
  },
9494
9539
  ...duplex ? { workers: {
@@ -9515,19 +9560,12 @@ ${extra}` : body);
9515
9560
  }, "voice-model": {
9516
9561
  desc: "switch the reflex (voice) model \u2014 /voice-model <id>, or alone for a picker",
9517
9562
  run: async (a) => {
9518
- const apply = (id) => {
9519
- const m = resolveModelOrNewest(id);
9520
- dx.options.reflexModel = m;
9521
- dx.voice.options.model = m;
9522
- err(green(` \u2713 reflex model \u2192 ${m}
9523
- `));
9524
- };
9525
9563
  if (a[0]) {
9526
- apply(a[0]);
9564
+ applyReflexModel(a[0]);
9527
9565
  return;
9528
9566
  }
9529
9567
  const picked = await pickModel(dx.options.reflexModel);
9530
- if (picked) apply(picked);
9568
+ if (picked) applyReflexModel(picked);
9531
9569
  else err(dim(` reflex ${dx.options.reflexModel}
9532
9570
  `));
9533
9571
  }
@@ -9540,19 +9578,13 @@ ${extra}` : body);
9540
9578
  `));
9541
9579
  return;
9542
9580
  }
9543
- const apply = (id) => {
9544
- const m = resolveModelOrNewest(id);
9545
- dx.setThinkModel(m);
9546
- err(green(` \u2713 think model \u2192 ${m}
9547
- `));
9548
- };
9549
9581
  if (a[0]) {
9550
- apply(a[0]);
9582
+ applyThinkModel(a[0]);
9551
9583
  return;
9552
9584
  }
9553
9585
  const current = dx.options.thinkModel === false ? void 0 : dx.options.thinkModel;
9554
9586
  const picked = await pickModel(current ?? "anthropic/claude-opus-4-6");
9555
- if (picked) apply(picked);
9587
+ if (picked) applyThinkModel(picked);
9556
9588
  else err(dim(` think ${dx.options.thinkModel === false ? "off" : dx.options.thinkModel}
9557
9589
  `));
9558
9590
  }