@livx.cc/agentx 0.99.45 → 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.
- package/dist/{Agent-Bzs57-iD.d.ts → Agent-BWbQ4Sqp.d.ts} +24 -0
- package/dist/cli.d.ts +4 -3
- package/dist/cli.js +84 -10
- package/dist/cli.js.map +1 -1
- package/dist/index.d.ts +2 -2
- package/dist/index.js +82 -9
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { a as AgentOptions, H as Hooks, i as RunResult, A as Agent } from './Agent-
|
|
2
|
-
export { C as ChatFragment, b as CompactResult, D as DEFAULT_MUTATING, c as Decision, P as PermissionOptions, d as PermissionPolicy, e as PermissionRule, f as PreToolUseDecision, R as ReasoningEffort, g as RecordingHooks, h as RecordingLifecycle, T as ToolUse, j as ToolUseMeta, k as composeHooks, l as estimateTokens, p as planMode, r as reasoningToChatFragment } from './Agent-
|
|
1
|
+
import { a as AgentOptions, H as Hooks, i as RunResult, A as Agent } from './Agent-BWbQ4Sqp.js';
|
|
2
|
+
export { C as ChatFragment, b as CompactResult, D as DEFAULT_MUTATING, c as Decision, P as PermissionOptions, d as PermissionPolicy, e as PermissionRule, f as PreToolUseDecision, R as ReasoningEffort, g as RecordingHooks, h as RecordingLifecycle, T as ToolUse, j as ToolUseMeta, k as composeHooks, l as estimateTokens, p as planMode, r as reasoningToChatFragment } from './Agent-BWbQ4Sqp.js';
|
|
3
3
|
export { MODEL_ALIASES, ModelSwitch, ResolveModelSwitchOpts, 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';
|
package/dist/index.js
CHANGED
|
@@ -3947,6 +3947,10 @@ var AgentOptions = class {
|
|
|
3947
3947
|
* not prose: a named tool with zero invocations is provable. On detection the loop nudges ONCE for a real
|
|
3948
3948
|
* call, and records the names in `RunResult.fabricatedToolClaims` either way. */
|
|
3949
3949
|
catchFabricatedToolUse = true;
|
|
3950
|
+
/** An empty model turn (no text, no tools) that ends the loop after work is re-prompted ONCE, then finishes
|
|
3951
|
+
* as `finishReason:'empty'` (a failure) instead of a phantom 'stop'. Off for layers that deliberately
|
|
3952
|
+
* allow a silent turn and repair it themselves (the duplex voice reflex). */
|
|
3953
|
+
failEmptyTurns = true;
|
|
3950
3954
|
/** Fold the dropped middle of an over-long transcript into a synthetic summary (edge-safe, no LLM). Off => drop-oldest. */
|
|
3951
3955
|
compaction;
|
|
3952
3956
|
/** Add `Checkpoint`/`Rollback` tools (requires the fs to be an OverlayFilesystem). */
|
|
@@ -4020,6 +4024,22 @@ var Agent = class _Agent {
|
|
|
4020
4024
|
/** Per-run ground truth: every tool name actually INVOKED this run (native dispatch + delegated
|
|
4021
4025
|
* runtime activity). The ledger that makes a fabricated tool claim provable. Reset per run. */
|
|
4022
4026
|
invokedTools = /* @__PURE__ */ new Set();
|
|
4027
|
+
/** Delegated-runtime HOST tools currently executing (cursor toolExecutor). While > 0 the provider is
|
|
4028
|
+
* not silent — it is waiting on US — so the idle-stall watchdog must not fire (see armStallWatchdog). */
|
|
4029
|
+
hostToolsInFlight = 0;
|
|
4030
|
+
/** The hold is bounded by the transport tool deadline: a host tool that never settles (the helper already gave
|
|
4031
|
+
* up on it) must not disable stall protection for the rest of the request — or this instance. */
|
|
4032
|
+
hostToolHoldUntil = 0;
|
|
4033
|
+
/** Delegated-runtime NATIVE tools (cursor's own shell/mcp/task) seen `running` but not yet `completed`/`error`,
|
|
4034
|
+
* id → hold-until. The runtime streams nothing while one runs, so it holds the watchdog like a host tool —
|
|
4035
|
+
* bounded by the same tool deadline (`toolHoldMs`) so a lost `completed` event can't disable it. */
|
|
4036
|
+
nativeToolsInFlight = /* @__PURE__ */ new Map();
|
|
4037
|
+
toolHoldMs = 0;
|
|
4038
|
+
/** A tool (host or native) already executed in the current step attempt: a stall retry replays the step
|
|
4039
|
+
* from the pre-step transcript, which would re-run it — so such a stall is not retried. */
|
|
4040
|
+
toolRanThisAttempt = false;
|
|
4041
|
+
/** Resets the active request's stall timer; a host tool's completion restarts the model's idle window. */
|
|
4042
|
+
stallPoke;
|
|
4023
4043
|
/** Advertised tools this run's text claimed to have used while the ledger showed zero calls. */
|
|
4024
4044
|
fabricatedClaims = /* @__PURE__ */ new Set();
|
|
4025
4045
|
activeHooks;
|
|
@@ -4322,6 +4342,7 @@ var Agent = class _Agent {
|
|
|
4322
4342
|
let toolCallsTotal = 0;
|
|
4323
4343
|
let lastFp = "";
|
|
4324
4344
|
let repeats = 0;
|
|
4345
|
+
let emptyNudged = false;
|
|
4325
4346
|
let closureNudged = false;
|
|
4326
4347
|
let lastProgressAt = start;
|
|
4327
4348
|
const kill = (finishReason) => {
|
|
@@ -4330,12 +4351,13 @@ var Agent = class _Agent {
|
|
|
4330
4351
|
const claims = this.survivingClaims();
|
|
4331
4352
|
return { text: lastAssistantText(this.transcript), steps, finishReason, messages: this.transcript, usage, usageEstimated, ...claims.length ? { fabricatedToolClaims: claims } : {} };
|
|
4332
4353
|
};
|
|
4354
|
+
const overBudget = () => !!o.maxTokens && usage.totalTokens - 0.9 * usage.cacheReadTokens >= o.maxTokens;
|
|
4355
|
+
const canNudge = () => steps < o.maxSteps && !overBudget();
|
|
4333
4356
|
while (true) {
|
|
4334
4357
|
if (o.signal?.aborted) return kill("aborted");
|
|
4335
4358
|
if (steps >= o.maxSteps) return kill("max_steps");
|
|
4336
4359
|
if (o.timeoutMs && Date.now() - lastProgressAt - this.parkedMs >= o.timeoutMs) return kill("timeout");
|
|
4337
|
-
|
|
4338
|
-
if (o.maxTokens && budgetTokens >= o.maxTokens) return kill("budget");
|
|
4360
|
+
if (overBudget()) return kill("budget");
|
|
4339
4361
|
steps++;
|
|
4340
4362
|
this.options.host?.notify?.({ kind: "turn_start", message: `step ${steps}` });
|
|
4341
4363
|
let res;
|
|
@@ -4346,6 +4368,7 @@ var Agent = class _Agent {
|
|
|
4346
4368
|
const hostToolTimeoutMs = o.providerOptions?.toolTimeoutMs;
|
|
4347
4369
|
const derivedToolTimeoutMs = Math.max(TRANSPORT_TOOL_TIMEOUT_FLOOR_MS, ...this.activeTools.map(transportHeadroomMs));
|
|
4348
4370
|
const effectiveToolTimeoutMs = typeof hostToolTimeoutMs === "number" ? Math.max(hostToolTimeoutMs, derivedToolTimeoutMs) : derivedToolTimeoutMs;
|
|
4371
|
+
this.toolHoldMs = effectiveToolTimeoutMs;
|
|
4349
4372
|
if (isCursorWithTools) {
|
|
4350
4373
|
if (typeof hostToolTimeoutMs === "number" && effectiveToolTimeoutMs !== hostToolTimeoutMs) {
|
|
4351
4374
|
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.`);
|
|
@@ -4356,7 +4379,15 @@ var Agent = class _Agent {
|
|
|
4356
4379
|
toolTimeoutMs: effectiveToolTimeoutMs,
|
|
4357
4380
|
toolExecutor: async (name, args) => {
|
|
4358
4381
|
const tc = { id: `cursor-${Date.now()}`, type: "function", function: { name, arguments: JSON.stringify(args) } };
|
|
4359
|
-
|
|
4382
|
+
this.hostToolsInFlight++;
|
|
4383
|
+
this.hostToolHoldUntil = Math.max(this.hostToolHoldUntil, Date.now() + effectiveToolTimeoutMs);
|
|
4384
|
+
try {
|
|
4385
|
+
return await this.dispatch(tc);
|
|
4386
|
+
} finally {
|
|
4387
|
+
this.hostToolsInFlight--;
|
|
4388
|
+
this.toolRanThisAttempt = true;
|
|
4389
|
+
this.stallPoke?.();
|
|
4390
|
+
}
|
|
4360
4391
|
}
|
|
4361
4392
|
} : void 0;
|
|
4362
4393
|
const claudeSteerPo = o.model.startsWith("claude-code/") ? { steer: () => this.drainPendingSteers() } : void 0;
|
|
@@ -4367,6 +4398,8 @@ var Agent = class _Agent {
|
|
|
4367
4398
|
};
|
|
4368
4399
|
try {
|
|
4369
4400
|
for (let attempt = 0; ; attempt++) {
|
|
4401
|
+
this.nativeToolsInFlight.clear();
|
|
4402
|
+
this.toolRanThisAttempt = false;
|
|
4370
4403
|
try {
|
|
4371
4404
|
if (useStream) {
|
|
4372
4405
|
const stall = this.armStallWatchdog(o.signal, o.stallMs);
|
|
@@ -4396,7 +4429,9 @@ var Agent = class _Agent {
|
|
|
4396
4429
|
const stalled = err?.code === "stall";
|
|
4397
4430
|
const empty = err?.code === "empty" || err?.code === "cursor_silent";
|
|
4398
4431
|
const maxAttempts = empty ? Math.max(o.emptyRetries, 0) : 2;
|
|
4399
|
-
const
|
|
4432
|
+
const replaysTool = stalled && this.toolRanThisAttempt;
|
|
4433
|
+
if (replaysTool) log6.warn("model stall after tool(s) already ran this step \u2014 not retrying (a retry would replay them)");
|
|
4434
|
+
const transient = !o.signal?.aborted && !isAbortError(err) && !replaysTool && attempt < maxAttempts && (network || serverSide || stalled || empty);
|
|
4400
4435
|
if (!transient) throw err;
|
|
4401
4436
|
const waitMs = (empty ? o.emptyRetryBaseMs : 1e3) * (attempt + 1);
|
|
4402
4437
|
log6.warn(`${empty ? "empty model turn" : stalled ? "model stall" : "network drop"} mid-step (${err?.message ?? err}) \u2014 retrying in ${waitMs}ms`);
|
|
@@ -4477,9 +4512,22 @@ var Agent = class _Agent {
|
|
|
4477
4512
|
}
|
|
4478
4513
|
if (toolCalls.length === 0) {
|
|
4479
4514
|
if (this.drainInjections()) continue;
|
|
4515
|
+
if (emptyTurn && o.failEmptyTurns) {
|
|
4516
|
+
if (!emptyNudged && canNudge()) {
|
|
4517
|
+
emptyNudged = true;
|
|
4518
|
+
log6.warn(`empty model turn after tool work (step ${steps}, provider finishReason=${res.finishReason ?? "n/a"}) \u2014 nudging once`);
|
|
4519
|
+
this.transcript.push({ role: "user", content: "Continue \u2014 you returned nothing. Answer the user now using the tool results above, or keep working if you are not done." });
|
|
4520
|
+
continue;
|
|
4521
|
+
}
|
|
4522
|
+
log6.warn(`model returned empty turns after tool work \u2014 surfacing as failed`);
|
|
4523
|
+
const e = new Error("empty_response: model returned an empty turn (no text, no tools) after a re-prompt");
|
|
4524
|
+
e.code = "empty";
|
|
4525
|
+
return { text: "", steps, finishReason: "empty", ...res.finishReason ? { providerFinishReason: res.finishReason } : {}, messages: this.transcript, usage, usageEstimated, error: e };
|
|
4526
|
+
}
|
|
4480
4527
|
const fabricated = o.catchFabricatedToolUse && !closureNudged ? this.fabricatedToolNames(contentText(res.content ?? "")) : [];
|
|
4481
4528
|
for (const n of fabricated) this.fabricatedClaims.add(n);
|
|
4482
|
-
if (fabricated.length &&
|
|
4529
|
+
if (fabricated.length && !canNudge()) log6.warn(`fabricated tool use: text names ${fabricated.join(", ")} but no step/budget left to demand the call \u2014 finishing with the existing answer`);
|
|
4530
|
+
if (fabricated.length && canNudge()) {
|
|
4483
4531
|
closureNudged = true;
|
|
4484
4532
|
log6.warn(`fabricated tool use: text names ${fabricated.join(", ")} but the run invoked ${this.invokedTools.size ? [...this.invokedTools].join(", ") : "nothing"} \u2014 demanding the real call`);
|
|
4485
4533
|
this.transcript.push({
|
|
@@ -4488,7 +4536,7 @@ var Agent = class _Agent {
|
|
|
4488
4536
|
});
|
|
4489
4537
|
continue;
|
|
4490
4538
|
}
|
|
4491
|
-
if (o.closeDelegatedTurns && res.endedWithoutClosing && !closureNudged &&
|
|
4539
|
+
if (o.closeDelegatedTurns && res.endedWithoutClosing && !closureNudged && canNudge()) {
|
|
4492
4540
|
closureNudged = true;
|
|
4493
4541
|
log6.verbose("delegated turn went silent after a tool \u2014 nudging a closing answer");
|
|
4494
4542
|
this.transcript.push({
|
|
@@ -4502,7 +4550,7 @@ var Agent = class _Agent {
|
|
|
4502
4550
|
this.releaseStaleImages();
|
|
4503
4551
|
await this.activeHooks?.onStop?.(res.content ?? "");
|
|
4504
4552
|
const claims = this.survivingClaims();
|
|
4505
|
-
return { text: res.content ?? "", steps, finishReason: "stop", messages: this.transcript, usage, usageEstimated, ...claims.length ? { fabricatedToolClaims: claims } : {} };
|
|
4553
|
+
return { text: res.content ?? "", steps, finishReason: "stop", ...res.finishReason ? { providerFinishReason: res.finishReason } : {}, messages: this.transcript, usage, usageEstimated, ...claims.length ? { fabricatedToolClaims: claims } : {} };
|
|
4506
4554
|
}
|
|
4507
4555
|
const fp = toolCalls.map((tc) => tc.function.name + ":" + (tc.function.arguments ?? "")).join("|");
|
|
4508
4556
|
repeats = fp === lastFp ? repeats + 1 : 1;
|
|
@@ -4566,10 +4614,12 @@ var Agent = class _Agent {
|
|
|
4566
4614
|
if (!stallMs) return;
|
|
4567
4615
|
if (timer) clearTimeout(timer);
|
|
4568
4616
|
timer = setTimeout(() => {
|
|
4617
|
+
if (this.toolHoldActive()) return poke();
|
|
4569
4618
|
fired = true;
|
|
4570
4619
|
ac.abort(stallError());
|
|
4571
4620
|
}, stallMs);
|
|
4572
4621
|
};
|
|
4622
|
+
this.stallPoke = poke;
|
|
4573
4623
|
poke();
|
|
4574
4624
|
const stalled = () => fired && !parent?.aborted;
|
|
4575
4625
|
return {
|
|
@@ -4578,11 +4628,19 @@ var Agent = class _Agent {
|
|
|
4578
4628
|
stalled,
|
|
4579
4629
|
clear: () => {
|
|
4580
4630
|
if (timer) clearTimeout(timer);
|
|
4631
|
+
if (this.stallPoke === poke) this.stallPoke = void 0;
|
|
4581
4632
|
parent?.removeEventListener("abort", onParentAbort);
|
|
4582
4633
|
},
|
|
4583
4634
|
reclassify: (err) => stalled() ? stallError() : err
|
|
4584
4635
|
};
|
|
4585
4636
|
}
|
|
4637
|
+
/** A host or native delegated tool is running within its deadline — the provider is quiet, not stalled. */
|
|
4638
|
+
toolHoldActive() {
|
|
4639
|
+
const now3 = Date.now();
|
|
4640
|
+
if (this.hostToolsInFlight > 0 && now3 < this.hostToolHoldUntil) return true;
|
|
4641
|
+
for (const until of this.nativeToolsInFlight.values()) if (now3 < until) return true;
|
|
4642
|
+
return false;
|
|
4643
|
+
}
|
|
4586
4644
|
/** A clean-stop turn that carries no assistant text AND no tool calls (native or delegated) — a
|
|
4587
4645
|
* non-result the model produced by going silent. Callers retry it rather than report "done". */
|
|
4588
4646
|
isEmptyStop(res) {
|
|
@@ -4621,6 +4679,12 @@ var Agent = class _Agent {
|
|
|
4621
4679
|
if (a.output !== void 0) prev.output = a.output;
|
|
4622
4680
|
prev.status = a.status;
|
|
4623
4681
|
}
|
|
4682
|
+
if (a.status === "running") {
|
|
4683
|
+
if (a.id) this.nativeToolsInFlight.set(a.id, Date.now() + this.toolHoldMs);
|
|
4684
|
+
} else {
|
|
4685
|
+
if (a.id) this.nativeToolsInFlight.delete(a.id);
|
|
4686
|
+
this.toolRanThisAttempt = true;
|
|
4687
|
+
}
|
|
4624
4688
|
sawTool = true;
|
|
4625
4689
|
this.invokedTools.add(a.name);
|
|
4626
4690
|
trailing = "";
|
|
@@ -4673,8 +4737,9 @@ var Agent = class _Agent {
|
|
|
4673
4737
|
*/
|
|
4674
4738
|
fabricatedToolNames(text) {
|
|
4675
4739
|
const out = [];
|
|
4740
|
+
const invoked = new Set([...this.invokedTools].map(toolKey));
|
|
4676
4741
|
for (const t of this.activeTools) {
|
|
4677
|
-
if (
|
|
4742
|
+
if (invoked.has(toolKey(t.name))) continue;
|
|
4678
4743
|
if (t.name.length < 4 || !/[_\-A-Z]/.test(t.name)) continue;
|
|
4679
4744
|
const re = new RegExp(`(?:^|[^\\w])${t.name.replace(/[.*+?^${}()|[\]\\]/g, "\\$&")}(?:[^\\w]|$)`);
|
|
4680
4745
|
if (re.test(text)) out.push(t.name);
|
|
@@ -4687,7 +4752,8 @@ var Agent = class _Agent {
|
|
|
4687
4752
|
* call that demonstrably ran. See `RunResult.fabricatedToolClaims`. */
|
|
4688
4753
|
survivingClaims() {
|
|
4689
4754
|
if (!this.fabricatedClaims.size) return [];
|
|
4690
|
-
|
|
4755
|
+
const invoked = new Set([...this.invokedTools].map(toolKey));
|
|
4756
|
+
return [...this.fabricatedClaims].filter((n) => !invoked.has(toolKey(n)));
|
|
4691
4757
|
}
|
|
4692
4758
|
async dispatch(tc) {
|
|
4693
4759
|
this.invokedTools.add(tc.function.name);
|
|
@@ -5075,6 +5141,11 @@ function lastAssistantText(messages) {
|
|
|
5075
5141
|
}
|
|
5076
5142
|
return "";
|
|
5077
5143
|
}
|
|
5144
|
+
var TOOL_ALIASES = { bash: "shell" };
|
|
5145
|
+
function toolKey(name) {
|
|
5146
|
+
const k = name.toLowerCase();
|
|
5147
|
+
return TOOL_ALIASES[k] ?? k;
|
|
5148
|
+
}
|
|
5078
5149
|
|
|
5079
5150
|
// src/index.ts
|
|
5080
5151
|
init_NodeDiskFilesystem();
|
|
@@ -7843,6 +7914,8 @@ ${nowLine()}. Anchor every relative or time-sensitive reference \u2014 "today",
|
|
|
7843
7914
|
instructionFiles: false,
|
|
7844
7915
|
maxSteps: 8,
|
|
7845
7916
|
timeoutMs: 3e4,
|
|
7917
|
+
failEmptyTurns: false,
|
|
7918
|
+
// a silent reflex turn after a dispatch is legitimate — the voice layer repairs it
|
|
7846
7919
|
...o.reflexOptions,
|
|
7847
7920
|
tools,
|
|
7848
7921
|
// Composed AFTER the spread so the dispatch guard can't be dropped by reflexOptions.
|