@livx.cc/agentx 0.99.93 → 0.99.95

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
@@ -27,6 +27,13 @@ interface SessionMeta {
27
27
  costEstimated?: boolean;
28
28
  /** Per-turn forensic log: timing, outcome, usage, and provider error per turn — for investigating a reported issue. */
29
29
  events?: TurnEvent[];
30
+ /** claude-code/*: Claude Code's own session for this transcript — resumed while the transcript is still the `n`
31
+ * messages it last saw, so the history is a cached prefix rather than a re-sent flattened prompt. */
32
+ cc?: {
33
+ id: string;
34
+ n: number;
35
+ model: string;
36
+ };
30
37
  }
31
38
  /** One turn's diagnostics, captured for offline forensics (mirrors what the footer prints, but persisted). */
32
39
  interface TurnEvent {
package/dist/cli.js CHANGED
@@ -5105,7 +5105,8 @@ var Agent = class _Agent {
5105
5105
  // a child obeys the parent's allow/deny rules (else Task is a one-call bypass)
5106
5106
  tools: [...o.tools, ...this.injectedTools],
5107
5107
  systemPrompt: o.systemPrompt,
5108
- providerOptionsFor: o.providerOptionsFor ?? ((m) => modelProvider(m) === modelProvider(o.model) ? o.providerOptions : void 0)
5108
+ // A child never resumes the parent's own claude-code session (the host's `resume` link is the parent's).
5109
+ providerOptionsFor: o.providerOptionsFor ?? ((m) => modelProvider(m) === modelProvider(o.model) && o.providerOptions ? { ...o.providerOptions, resume: void 0, onClaudeCodeSession: void 0 } : void 0)
5109
5110
  };
5110
5111
  tools = [...tools, makeTaskTool(taskOpts), makeTaskBatchTool(taskOpts)];
5111
5112
  }
@@ -10307,6 +10308,37 @@ ${nowLine()}. Anchor every relative or time-sensitive reference \u2014 "today",
10307
10308
  }
10308
10309
  if (this.silentTurn && res?.finishReason === "error" && refusedCall(res.error)) this.emitHost({ kind: "text_delta", message: fallback ?? _DuplexAgent.FALLBACK_ERROR });
10309
10310
  else if (this.silentTurn) await this.ackIfSilent(fallback);
10311
+ else if (this.hollowPromise) await this.followThrough();
10312
+ }
10313
+ /** The turn SAID it is on it ("got it — checking…") but called no tool and nothing is running: a promise nothing
10314
+ * keeps — the user waits on silence (live Para #798: a follow-up while the reflex believed a finished task still ran). */
10315
+ get hollowPromise() {
10316
+ if (!this.options.host || this.turnDispatched || this.leakHit || this.fabricationCut) return false;
10317
+ if (this.voice.transcript.slice(this.turnBase).some((m) => m.tool_calls?.length)) return false;
10318
+ if ([...this.tasks.values()].some((t) => t.status === "running")) return false;
10319
+ return _DuplexAgent.PROMISE_RE.test(this.turnSpoken);
10320
+ }
10321
+ static PROMISE_RE = /\b(?:checking|looking (?:into|it up)|let me (?:check|look|see|find|pull)|i(?:'ll| will) (?:check|look|find|pull)|on it|one (?:moment|sec(?:ond)?))\b/i;
10322
+ static FOLLOW_THROUGH = "[reminder] You told the user you are checking, but no task is running and you called no tool. Keep that promise now: if a finished task result above already answers it, give that answer; otherwise call Act with a clear brief. Do not acknowledge again.";
10323
+ /** Re-prompt the reflex ONCE, tools allowed, to keep its hollow promise; the reminder never stays in the transcript. */
10324
+ async followThrough() {
10325
+ const base = this.voice.transcript.length, reminder = _DuplexAgent.FOLLOW_THROUGH;
10326
+ this.notify("diag", "hollow_promise", { text: this.turnSpoken.trim().slice(0, 80) });
10327
+ this.turnSpoken = "";
10328
+ this.reflexBuf = "";
10329
+ this.reflexForwarded = 0;
10330
+ this.stepMarks = [];
10331
+ this.dropJudge();
10332
+ try {
10333
+ await this.voice.send(reminder);
10334
+ } catch (e) {
10335
+ log21.warn(`follow-through nudge failed: ${e instanceof Error ? e.message : e}`);
10336
+ } finally {
10337
+ const i = this.voice.transcript.findIndex((m, k) => k >= base && m.role === "user" && m.content === reminder);
10338
+ if (i >= 0) this.voice.transcript.splice(i, 1);
10339
+ await this.drainReflex();
10340
+ this.scrubLeakFromTranscript();
10341
+ }
10310
10342
  }
10311
10343
  /** Rewrite the UNFORWARDED reflex text: drop complete stage-direction parentheticals (STAGE_DIRECTION_RE) and spoken
10312
10344
  * junk (scrubSpokenJunk). Only the unforwarded region is touched — already-spoken audio can't be unsent, and
@@ -14045,10 +14077,11 @@ var SecondChannel = class {
14045
14077
  if (this[k]) clearTimeout(this[k]);
14046
14078
  this[k] = null;
14047
14079
  }
14048
- if (this.o.bridgeDelayMs > 0) this.bridgeTimer = setTimeout(() => {
14080
+ const wait = Math.max(this.o.bridgeDelayMs, this.o.minGapMs - (this.o.now() - this.lastAt));
14081
+ if (wait > 0) this.bridgeTimer = setTimeout(() => {
14049
14082
  this.bridgeTimer = null;
14050
14083
  void this.consider("working");
14051
- }, this.o.bridgeDelayMs);
14084
+ }, wait);
14052
14085
  else void this.consider("working");
14053
14086
  }
14054
14087
  }
@@ -14132,7 +14165,8 @@ var SecondChannel = class {
14132
14165
  if (this.o.decide) {
14133
14166
  const d = await withBudget(this.o.decide(this.tail(), this.state(pauseMs)), this.o.decisionBudgetMs, "channel decision");
14134
14167
  choice = d?.choice;
14135
- if (choice && choice in CHANNEL_ACTIONS) kind = choice;
14168
+ if (choice && choice in CHANNEL_ACTIONS && (choice === "silence" || this.allowed(choice))) kind = choice;
14169
+ else if (choice && choice in CHANNEL_ACTIONS) log30.debug(`decider chose ${choice} for a ${rule} moment \u2014 the rule stands`);
14136
14170
  }
14137
14171
  if (kind === "silence") return ev({ choice, acted: "silence" });
14138
14172
  if (stale()) return ev({ choice, kind, acted: "stale" });
@@ -18455,6 +18489,7 @@ async function runTurn(agent, store, session, task, cp, cwd = process.cwd(), sen
18455
18489
  }
18456
18490
  return origNotify(e);
18457
18491
  };
18492
+ const ccRecord = bindClaudeCodeSession(agent, session);
18458
18493
  try {
18459
18494
  res = await (sendFn ? sendFn(content) : agent.send(content));
18460
18495
  } catch (e) {
@@ -18506,6 +18541,7 @@ async function runTurn(agent, store, session, task, cp, cwd = process.cwd(), sen
18506
18541
  const ev = { ts: t0, durationMs: Date.now() - t0, model: agent.options.model, finishReason: res.finishReason, steps: res.steps, tools, tokens: res.usage?.totalTokens, costUsd: cost, estimated: res.usageEstimated };
18507
18542
  if (res.finishReason === "error" && res.error) ev.error = errInfo(res.error);
18508
18543
  (session.meta.events ??= []).push(ev);
18544
+ ccRecord?.(ok);
18509
18545
  if (!session.meta.title) {
18510
18546
  session.meta.title = titleOf(agent.transcript);
18511
18547
  if (session.meta.title) setTermTitle(`agentx \xB7 ${session.meta.title}`);
@@ -18518,6 +18554,19 @@ async function runTurn(agent, store, session, task, cp, cwd = process.cwd(), sen
18518
18554
  }
18519
18555
  return { ok, res };
18520
18556
  }
18557
+ function bindClaudeCodeSession(agent, session) {
18558
+ const po = agent.options.providerOptions;
18559
+ if (!po?.claudeCodeSession) return void 0;
18560
+ const cc = session.meta.cc, model = agent.options.model;
18561
+ let id;
18562
+ const resume = cc && cc.model === model && cc.n === agent.transcript.length ? cc.id : void 0;
18563
+ agent.options.providerOptions = { ...po, resume, onClaudeCodeSession: (s) => {
18564
+ id = s;
18565
+ } };
18566
+ return (ok) => {
18567
+ session.meta.cc = ok && id ? { id, n: agent.transcript.length, model } : void 0;
18568
+ };
18569
+ }
18521
18570
  var remintSessionImages = (data, store, cwd) => remintImageRefs(data.messages, [join16(store.dir, `${data.meta.id}.images`), cwd]);
18522
18571
  function startSession(args, store, agent, cwd) {
18523
18572
  if (args.resume || args.cont) {