@livx.cc/agentx 0.99.19 → 0.99.20

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
@@ -150,6 +150,7 @@ declare function makeHost(format?: 'text' | 'json' | 'stream-json', opts?: {
150
150
  stream?: boolean;
151
151
  }): HostBridge & {
152
152
  flushText: () => void;
153
+ takeToolCount: () => number;
153
154
  };
154
155
  /** Hooks that render tool activity to stderr: a preToolUse header, and for edits a colorized diff.
155
156
  * `opts.background` marks the agent as a BACKGROUND one (duplex workers): its chrome lands async on
package/dist/cli.js CHANGED
@@ -10160,19 +10160,112 @@ function renderMdLine(line, inFence, p, cols = 80, fenceLang) {
10160
10160
  function renderMdBlock(text, p, cols = 80) {
10161
10161
  let inFence = false, fenceLang;
10162
10162
  const out = [];
10163
+ let table = [];
10164
+ const flush = () => {
10165
+ if (table.length) {
10166
+ out.push(...renderTableLines(table, p, cols));
10167
+ table = [];
10168
+ }
10169
+ };
10163
10170
  for (const line of text.split("\n")) {
10171
+ if (!inFence && isTableRow(line)) {
10172
+ table.push(line);
10173
+ continue;
10174
+ }
10175
+ flush();
10164
10176
  const r = renderMdLine(line, inFence, p, cols, fenceLang);
10165
10177
  inFence = r.inFence;
10166
10178
  fenceLang = r.fenceLang;
10167
10179
  out.push(r.inFence || /^\s*```/.test(line) ? r.out : wrapAnsi(r.out, cols, hangIndent(line)));
10168
10180
  }
10181
+ flush();
10169
10182
  return out.join("\n");
10170
10183
  }
10184
+ var T_PAD = " ";
10185
+ var T_GAP = 3;
10186
+ var SGR_CLOSES = {
10187
+ "0": /./,
10188
+ "22": /^[12]$/,
10189
+ "23": /^3$/,
10190
+ "24": /^4$/,
10191
+ "27": /^7$/,
10192
+ "29": /^9$/,
10193
+ "39": /^(3[0-7]|9[0-7])$/,
10194
+ "49": /^(4[0-7]|10[0-7])$/
10195
+ };
10196
+ function wrapCell(styled, w) {
10197
+ const segs = wrapAnsi(styled, w).split("\r\n");
10198
+ if (segs.length < 2 || !styled.includes("\x1B")) return segs;
10199
+ const tok = new RegExp(ANSI_TOKEN.source, "g");
10200
+ let open = [];
10201
+ return segs.map((seg) => {
10202
+ const prefix = open.join("");
10203
+ for (const m of seg.match(tok) ?? []) {
10204
+ const code = /^\x1b\[([0-9;]*)m$/.exec(m)?.[1];
10205
+ if (code === void 0) continue;
10206
+ const closes = SGR_CLOSES[code || "0"];
10207
+ if (closes) open = open.filter((o) => !closes.test(/^\x1b\[([0-9;]*)m$/.exec(o)[1]));
10208
+ else open.push(m);
10209
+ }
10210
+ return prefix + seg + (open.length ? "\x1B[0m" : "");
10211
+ });
10212
+ }
10213
+ var T_MINCOL = 2;
10214
+ function fitWidths(natural, avail) {
10215
+ const total = natural.reduce((a, b) => a + b, 0);
10216
+ if (total <= avail || !natural.length) return natural;
10217
+ const room = Math.max(T_MINCOL * natural.length, avail);
10218
+ let cap = 1;
10219
+ for (let c = 1; c <= Math.max(...natural); c++) {
10220
+ if (natural.reduce((a, w2) => a + Math.min(w2, c), 0) <= room) cap = c;
10221
+ else break;
10222
+ }
10223
+ const w = natural.map((n) => Math.min(n, cap));
10224
+ let left = room - w.reduce((a, b) => a + b, 0);
10225
+ for (let i = 0; i < w.length && left > 0; i++) {
10226
+ const take = Math.min(left, natural[i] - w[i]);
10227
+ w[i] += take;
10228
+ left -= take;
10229
+ }
10230
+ return w;
10231
+ }
10232
+ function renderTableLines(rows, p, cols = 80) {
10233
+ const sepIdx = rows.findIndex((r, i) => i > 0 && r.includes("-") && /^\s*\|[\s:|-]+\|\s*$/.test(r));
10234
+ if (sepIdx < 0) return rows.map((r) => renderMdLine(r, false, p, cols).out);
10235
+ const cells = (r) => r.trim().replace(/^\||\|$/g, "").split("|").map((c) => c.trim());
10236
+ const data = rows.filter((_, i) => i !== sepIdx).map(cells);
10237
+ const ncol = Math.max(...data.map((r) => r.length));
10238
+ const natural = Array.from({ length: ncol }, (_, i) => Math.max(...data.map((r) => displayText(r[i] ?? "").length)));
10239
+ const widths = fitWidths(natural, cols - T_PAD.length - T_GAP * (ncol - 1));
10240
+ const grid = data.map((row, ri) => widths.map((w, ci) => {
10241
+ const c = row[ci] ?? "";
10242
+ const styled = ri === 0 ? p.bold(displayText(vis(c))) : mdInline(vis(c), p);
10243
+ return wrapCell(styled, w);
10244
+ }));
10245
+ const airy = grid.slice(1).some((row) => row.some((c) => c.length > 1));
10246
+ const out = [];
10247
+ grid.forEach((col, ri) => {
10248
+ const header = ri === 0;
10249
+ if (airy && ri > 1) out.push("");
10250
+ const height = Math.max(...col.map((c) => c.length));
10251
+ for (let li = 0; li < height; li++) {
10252
+ out.push((T_PAD + widths.map((w, ci) => {
10253
+ const seg = col[ci][li] ?? "";
10254
+ return seg + " ".repeat(Math.max(0, w - visWidth(seg)));
10255
+ }).join(" ".repeat(T_GAP))).replace(/\s+$/, ""));
10256
+ }
10257
+ if (header) out.push(T_PAD + p.dim("\u2500".repeat(widths.reduce((a, b) => a + b, 0) + T_GAP * (ncol - 1))));
10258
+ });
10259
+ return out;
10260
+ }
10171
10261
  function isTableRow(line) {
10172
10262
  return /^\s*\|.*\|\s*$/.test(line);
10173
10263
  }
10174
10264
  var ANSI_TOKEN = /\x1b\[[0-9;]*m|\x1b\]8;;[^\x07\x1b]*(?:\x07|\x1b\\)/;
10175
10265
  var WRAP_TOKENS = new RegExp(`${ANSI_TOKEN.source}|[ \\t]+|[^\\s\\x1b]+`, "g");
10266
+ function visWidth(s) {
10267
+ return s.replace(new RegExp(ANSI_TOKEN.source, "g"), "").length;
10268
+ }
10176
10269
  function wrapAnsi(s, cols, indent = "") {
10177
10270
  if (cols <= 1 || s.replace(new RegExp(ANSI_TOKEN.source, "g"), "").length <= cols) return s;
10178
10271
  if (indent.length >= cols) indent = "";
@@ -10239,29 +10332,11 @@ var MarkdownStream = class {
10239
10332
  this.cols = Math.max(1, cols);
10240
10333
  if (this.buf) this.lineRows = Math.max(1, Math.ceil(this.buf.length / this.cols));
10241
10334
  }
10242
- /** Render the held table block as aligned columns and reset the buffer. If the block lacks a `|---|`
10243
- * separator row it isn't a real table — emit the rows verbatim (rendered as normal lines) instead. */
10335
+ /** Render the held table block as aligned columns (shared with renderMdBlock) and reset the buffer. */
10244
10336
  flushTable() {
10245
10337
  const rows = this.tableBuf;
10246
10338
  this.tableBuf = [];
10247
- const sepIdx = rows.findIndex((r, i) => i > 0 && r.includes("-") && /^\s*\|[\s:|-]+\|\s*$/.test(r));
10248
- if (sepIdx < 0) return rows.map((r) => renderMdLine(r, false, this.p, this.cols).out + "\r\n").join("");
10249
- const cells = (r) => r.trim().replace(/^\||\|$/g, "").split("|").map((c) => c.trim());
10250
- const data = rows.filter((_, i) => i !== sepIdx).map(cells);
10251
- const ncol = Math.max(...data.map((r) => r.length));
10252
- const widths = Array.from({ length: ncol }, (_, i) => Math.max(...data.map((r) => displayText(r[i] ?? "").length)));
10253
- const out = [];
10254
- data.forEach((row, ri) => {
10255
- const header = ri === 0;
10256
- const line = " " + widths.map((w, ci) => {
10257
- const c = row[ci] ?? "";
10258
- const styled = header ? this.p.bold(displayText(vis(c))) : mdInline(vis(c), this.p);
10259
- return styled + " ".repeat(Math.max(0, w - displayText(c).length));
10260
- }).join(" ").replace(/\s+$/, "");
10261
- out.push(line);
10262
- if (header) out.push(" " + this.p.dim("\u2500".repeat(widths.reduce((a, b) => a + b, 0) + 3 * (ncol - 1))));
10263
- });
10264
- return out.map((l) => l + "\r\n").join("");
10339
+ return renderTableLines(rows, this.p, this.cols).map((l) => l + "\r\n").join("");
10265
10340
  }
10266
10341
  feed(text) {
10267
10342
  this.buf += text;
@@ -12158,8 +12233,17 @@ function makeHost(format = "text", opts) {
12158
12233
  }
12159
12234
  };
12160
12235
  const activitySeen = /* @__PURE__ */ new Set();
12236
+ const turnActivityIds = /* @__PURE__ */ new Set();
12237
+ let anonActivityCount = 0;
12161
12238
  return {
12162
12239
  flushText,
12240
+ /** Read + reset this turn's self-executing-backend tool tally (see turnActivityIds). */
12241
+ takeToolCount: () => {
12242
+ const n = turnActivityIds.size + anonActivityCount;
12243
+ turnActivityIds.clear();
12244
+ anonActivityCount = 0;
12245
+ return n;
12246
+ },
12163
12247
  notify(e) {
12164
12248
  if (e.kind === "turn_start") {
12165
12249
  activitySeen.clear();
@@ -12192,6 +12276,8 @@ function makeHost(format = "text", opts) {
12192
12276
  }
12193
12277
  if (e.kind === "tool_activity") {
12194
12278
  const a = e;
12279
+ if (a.id) turnActivityIds.add(a.id);
12280
+ else if (a.status === "running") anonActivityCount++;
12195
12281
  flushLookupGroup();
12196
12282
  closeReasonLine();
12197
12283
  flushText();
@@ -12890,6 +12976,7 @@ async function runTurn(agent, store, session, task, cp, cwd = process.cwd(), sen
12890
12976
  spinner.turnStart = t0;
12891
12977
  spinner.start(sendFn ? "voice\u2026" : void 0);
12892
12978
  const msgsBefore = agent.transcript.length;
12979
+ agent.options.host?.takeToolCount?.();
12893
12980
  const host = agent.options.host;
12894
12981
  const origNotify = host?.notify?.bind(host);
12895
12982
  if (host && origNotify) host.notify = (e) => {
@@ -12931,7 +13018,7 @@ async function runTurn(agent, store, session, task, cp, cwd = process.cwd(), sen
12931
13018
  const m = res.usageEstimated ? "~" : "";
12932
13019
  const tok = res.usage?.totalTokens ? `${m}${(res.usage.totalTokens / 1e3).toFixed(1)}k tok \xB7 ${cost > 0 ? m + fmtUsd(cost) + " \xB7 " : ""}` : "";
12933
13020
  const lastUser = res.messages.map((m2) => m2.role).lastIndexOf("user");
12934
- const tools = res.messages.slice(lastUser).filter((m2) => m2.role === "tool").length;
13021
+ const tools = res.messages.slice(lastUser).filter((m2) => m2.role === "tool").length + (agent.options.host?.takeToolCount?.() ?? 0);
12935
13022
  const ok = res.finishReason === "stop";
12936
13023
  const shortId = session.meta.id.replace(/^\d{8}-/, "");
12937
13024
  const didWork = agent.transcript.slice(msgsBefore).some((m2) => m2.role === "assistant" || m2.role === "tool");