@livx.cc/agentx 0.99.46 → 0.99.47

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.
@@ -427,6 +427,14 @@ declare class Agent {
427
427
  /** The hold is bounded by the transport tool deadline: a host tool that never settles (the helper already gave
428
428
  * up on it) must not disable stall protection for the rest of the request — or this instance. */
429
429
  private hostToolHoldUntil;
430
+ /** Delegated-runtime NATIVE tools (cursor's own shell/mcp/task) seen `running` but not yet `completed`/`error`,
431
+ * id → hold-until. The runtime streams nothing while one runs, so it holds the watchdog like a host tool —
432
+ * bounded by the same tool deadline (`toolHoldMs`) so a lost `completed` event can't disable it. */
433
+ private nativeToolsInFlight;
434
+ private toolHoldMs;
435
+ /** A tool (host or native) already executed in the current step attempt: a stall retry replays the step
436
+ * from the pre-step transcript, which would re-run it — so such a stall is not retried. */
437
+ private toolRanThisAttempt;
430
438
  /** Resets the active request's stall timer; a host tool's completion restarts the model's idle window. */
431
439
  private stallPoke?;
432
440
  /** Advertised tools this run's text claimed to have used while the ledger showed zero calls. */
@@ -533,6 +541,8 @@ declare class Agent {
533
541
  * `stallMs = 0` disables the timer but still links parent-abort → child so cancellation propagates.
534
542
  */
535
543
  private armStallWatchdog;
544
+ /** A host or native delegated tool is running within its deadline — the provider is quiet, not stalled. */
545
+ private toolHoldActive;
536
546
  /** A clean-stop turn that carries no assistant text AND no tool calls (native or delegated) — a
537
547
  * non-result the model produced by going silent. Callers retry it rather than report "done". */
538
548
  private isEmptyStop;
package/dist/cli.d.ts CHANGED
@@ -1,5 +1,5 @@
1
1
  #!/usr/bin/env bun
2
- import { H as Hooks, i as RunResult, R as ReasoningEffort, A as Agent } from './Agent-OcAg2yxA.js';
2
+ import { H as Hooks, i as RunResult, R as ReasoningEffort, A as Agent } from './Agent-BWbQ4Sqp.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, g as MessageContent } from './tools-BqL8Lk4J.js';
5
5
 
package/dist/cli.js CHANGED
@@ -4044,6 +4044,14 @@ var Agent = class _Agent {
4044
4044
  /** The hold is bounded by the transport tool deadline: a host tool that never settles (the helper already gave
4045
4045
  * up on it) must not disable stall protection for the rest of the request — or this instance. */
4046
4046
  hostToolHoldUntil = 0;
4047
+ /** Delegated-runtime NATIVE tools (cursor's own shell/mcp/task) seen `running` but not yet `completed`/`error`,
4048
+ * id → hold-until. The runtime streams nothing while one runs, so it holds the watchdog like a host tool —
4049
+ * bounded by the same tool deadline (`toolHoldMs`) so a lost `completed` event can't disable it. */
4050
+ nativeToolsInFlight = /* @__PURE__ */ new Map();
4051
+ toolHoldMs = 0;
4052
+ /** A tool (host or native) already executed in the current step attempt: a stall retry replays the step
4053
+ * from the pre-step transcript, which would re-run it — so such a stall is not retried. */
4054
+ toolRanThisAttempt = false;
4047
4055
  /** Resets the active request's stall timer; a host tool's completion restarts the model's idle window. */
4048
4056
  stallPoke;
4049
4057
  /** Advertised tools this run's text claimed to have used while the ledger showed zero calls. */
@@ -4374,6 +4382,7 @@ var Agent = class _Agent {
4374
4382
  const hostToolTimeoutMs = o.providerOptions?.toolTimeoutMs;
4375
4383
  const derivedToolTimeoutMs = Math.max(TRANSPORT_TOOL_TIMEOUT_FLOOR_MS, ...this.activeTools.map(transportHeadroomMs));
4376
4384
  const effectiveToolTimeoutMs = typeof hostToolTimeoutMs === "number" ? Math.max(hostToolTimeoutMs, derivedToolTimeoutMs) : derivedToolTimeoutMs;
4385
+ this.toolHoldMs = effectiveToolTimeoutMs;
4377
4386
  if (isCursorWithTools) {
4378
4387
  if (typeof hostToolTimeoutMs === "number" && effectiveToolTimeoutMs !== hostToolTimeoutMs) {
4379
4388
  log6.warn(`providerOptions.toolTimeoutMs=${hostToolTimeoutMs}ms is below what the registered tools need \u2014 RAISED to ${effectiveToolTimeoutMs}ms. ${toolTimeoutViolations(this.activeTools, hostToolTimeoutMs).length} tool(s) could outlive it, and the transport would have destroyed their results. To lower it, lower the tools' own maxDurationMs (e.g. the Shell tool's maxTimeoutMs) instead.`);
@@ -4390,6 +4399,7 @@ var Agent = class _Agent {
4390
4399
  return await this.dispatch(tc);
4391
4400
  } finally {
4392
4401
  this.hostToolsInFlight--;
4402
+ this.toolRanThisAttempt = true;
4393
4403
  this.stallPoke?.();
4394
4404
  }
4395
4405
  }
@@ -4402,6 +4412,8 @@ var Agent = class _Agent {
4402
4412
  };
4403
4413
  try {
4404
4414
  for (let attempt = 0; ; attempt++) {
4415
+ this.nativeToolsInFlight.clear();
4416
+ this.toolRanThisAttempt = false;
4405
4417
  try {
4406
4418
  if (useStream) {
4407
4419
  const stall = this.armStallWatchdog(o.signal, o.stallMs);
@@ -4431,7 +4443,9 @@ var Agent = class _Agent {
4431
4443
  const stalled = err2?.code === "stall";
4432
4444
  const empty = err2?.code === "empty" || err2?.code === "cursor_silent";
4433
4445
  const maxAttempts = empty ? Math.max(o.emptyRetries, 0) : 2;
4434
- const transient = !o.signal?.aborted && !isAbortError(err2) && attempt < maxAttempts && (network || serverSide || stalled || empty);
4446
+ const replaysTool = stalled && this.toolRanThisAttempt;
4447
+ if (replaysTool) log6.warn("model stall after tool(s) already ran this step \u2014 not retrying (a retry would replay them)");
4448
+ const transient = !o.signal?.aborted && !isAbortError(err2) && !replaysTool && attempt < maxAttempts && (network || serverSide || stalled || empty);
4435
4449
  if (!transient) throw err2;
4436
4450
  const waitMs = (empty ? o.emptyRetryBaseMs : 1e3) * (attempt + 1);
4437
4451
  log6.warn(`${empty ? "empty model turn" : stalled ? "model stall" : "network drop"} mid-step (${err2?.message ?? err2}) \u2014 retrying in ${waitMs}ms`);
@@ -4614,7 +4628,7 @@ var Agent = class _Agent {
4614
4628
  if (!stallMs) return;
4615
4629
  if (timer) clearTimeout(timer);
4616
4630
  timer = setTimeout(() => {
4617
- if (this.hostToolsInFlight > 0 && Date.now() < this.hostToolHoldUntil) return poke();
4631
+ if (this.toolHoldActive()) return poke();
4618
4632
  fired = true;
4619
4633
  ac.abort(stallError());
4620
4634
  }, stallMs);
@@ -4634,6 +4648,13 @@ var Agent = class _Agent {
4634
4648
  reclassify: (err2) => stalled() ? stallError() : err2
4635
4649
  };
4636
4650
  }
4651
+ /** A host or native delegated tool is running within its deadline — the provider is quiet, not stalled. */
4652
+ toolHoldActive() {
4653
+ const now4 = Date.now();
4654
+ if (this.hostToolsInFlight > 0 && now4 < this.hostToolHoldUntil) return true;
4655
+ for (const until of this.nativeToolsInFlight.values()) if (now4 < until) return true;
4656
+ return false;
4657
+ }
4637
4658
  /** A clean-stop turn that carries no assistant text AND no tool calls (native or delegated) — a
4638
4659
  * non-result the model produced by going silent. Callers retry it rather than report "done". */
4639
4660
  isEmptyStop(res) {
@@ -4672,6 +4693,12 @@ var Agent = class _Agent {
4672
4693
  if (a.output !== void 0) prev.output = a.output;
4673
4694
  prev.status = a.status;
4674
4695
  }
4696
+ if (a.status === "running") {
4697
+ if (a.id) this.nativeToolsInFlight.set(a.id, Date.now() + this.toolHoldMs);
4698
+ } else {
4699
+ if (a.id) this.nativeToolsInFlight.delete(a.id);
4700
+ this.toolRanThisAttempt = true;
4701
+ }
4675
4702
  sawTool = true;
4676
4703
  this.invokedTools.add(a.name);
4677
4704
  trailing = "";