@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
|
@@ -186,6 +186,8 @@ interface RunResult {
|
|
|
186
186
|
* Answer it and resume the session to continue. */
|
|
187
187
|
finishReason: 'stop' | 'max_steps' | 'budget' | 'timeout' | 'loop' | 'max_tool_calls' | 'aborted' | 'error' | 'needs_input' | 'empty';
|
|
188
188
|
messages: Message[];
|
|
189
|
+
/** The provider's own finish reason for the final model call (e.g. 'stop', 'end_turn', 'length'), when it gave one. */
|
|
190
|
+
providerFinishReason?: string;
|
|
189
191
|
/** The parked question — present iff `finishReason === 'needs_input'`. */
|
|
190
192
|
question?: UserQuestion;
|
|
191
193
|
/** Accumulated token usage across all turns (non-stream path). With prompt caching,
|
|
@@ -352,6 +354,10 @@ declare class AgentOptions {
|
|
|
352
354
|
* not prose: a named tool with zero invocations is provable. On detection the loop nudges ONCE for a real
|
|
353
355
|
* call, and records the names in `RunResult.fabricatedToolClaims` either way. */
|
|
354
356
|
catchFabricatedToolUse: boolean;
|
|
357
|
+
/** An empty model turn (no text, no tools) that ends the loop after work is re-prompted ONCE, then finishes
|
|
358
|
+
* as `finishReason:'empty'` (a failure) instead of a phantom 'stop'. Off for layers that deliberately
|
|
359
|
+
* allow a silent turn and repair it themselves (the duplex voice reflex). */
|
|
360
|
+
failEmptyTurns: boolean;
|
|
355
361
|
/** Fold the dropped middle of an over-long transcript into a synthetic summary (edge-safe, no LLM). Off => drop-oldest. */
|
|
356
362
|
compaction?: {
|
|
357
363
|
maxMessages: number;
|
|
@@ -415,6 +421,22 @@ declare class Agent {
|
|
|
415
421
|
/** Per-run ground truth: every tool name actually INVOKED this run (native dispatch + delegated
|
|
416
422
|
* runtime activity). The ledger that makes a fabricated tool claim provable. Reset per run. */
|
|
417
423
|
private invokedTools;
|
|
424
|
+
/** Delegated-runtime HOST tools currently executing (cursor toolExecutor). While > 0 the provider is
|
|
425
|
+
* not silent — it is waiting on US — so the idle-stall watchdog must not fire (see armStallWatchdog). */
|
|
426
|
+
private hostToolsInFlight;
|
|
427
|
+
/** The hold is bounded by the transport tool deadline: a host tool that never settles (the helper already gave
|
|
428
|
+
* up on it) must not disable stall protection for the rest of the request — or this instance. */
|
|
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;
|
|
438
|
+
/** Resets the active request's stall timer; a host tool's completion restarts the model's idle window. */
|
|
439
|
+
private stallPoke?;
|
|
418
440
|
/** Advertised tools this run's text claimed to have used while the ledger showed zero calls. */
|
|
419
441
|
private fabricatedClaims;
|
|
420
442
|
private activeHooks?;
|
|
@@ -519,6 +541,8 @@ declare class Agent {
|
|
|
519
541
|
* `stallMs = 0` disables the timer but still links parent-abort → child so cancellation propagates.
|
|
520
542
|
*/
|
|
521
543
|
private armStallWatchdog;
|
|
544
|
+
/** A host or native delegated tool is running within its deadline — the provider is quiet, not stalled. */
|
|
545
|
+
private toolHoldActive;
|
|
522
546
|
/** A clean-stop turn that carries no assistant text AND no tool calls (native or delegated) — a
|
|
523
547
|
* non-result the model produced by going silent. Callers retry it rather than report "done". */
|
|
524
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-
|
|
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
|
|
|
@@ -277,8 +277,6 @@ declare function expandMentions(fs: IFilesystem, line: string): Promise<{
|
|
|
277
277
|
declare function jsonResult(res: RunResult, session: SessionData): {
|
|
278
278
|
error?: any;
|
|
279
279
|
question?: UserQuestion | undefined;
|
|
280
|
-
ok: boolean;
|
|
281
|
-
finishReason: "error" | "budget" | "stop" | "max_steps" | "timeout" | "loop" | "max_tool_calls" | "aborted" | "needs_input" | "empty";
|
|
282
280
|
text: string;
|
|
283
281
|
steps: number;
|
|
284
282
|
tools: number;
|
|
@@ -290,6 +288,9 @@ declare function jsonResult(res: RunResult, session: SessionData): {
|
|
|
290
288
|
cacheReadTokens?: number;
|
|
291
289
|
} | undefined;
|
|
292
290
|
sessionId: string;
|
|
291
|
+
providerFinishReason?: string | undefined;
|
|
292
|
+
ok: boolean;
|
|
293
|
+
finishReason: "error" | "budget" | "stop" | "max_steps" | "timeout" | "loop" | "max_tool_calls" | "aborted" | "needs_input" | "empty";
|
|
293
294
|
};
|
|
294
295
|
/**
|
|
295
296
|
* Read one logical input, supporting `\`-continuation for multi-line prompts: a line ending in
|
package/dist/cli.js
CHANGED
|
@@ -3961,6 +3961,10 @@ var AgentOptions = class {
|
|
|
3961
3961
|
* not prose: a named tool with zero invocations is provable. On detection the loop nudges ONCE for a real
|
|
3962
3962
|
* call, and records the names in `RunResult.fabricatedToolClaims` either way. */
|
|
3963
3963
|
catchFabricatedToolUse = true;
|
|
3964
|
+
/** An empty model turn (no text, no tools) that ends the loop after work is re-prompted ONCE, then finishes
|
|
3965
|
+
* as `finishReason:'empty'` (a failure) instead of a phantom 'stop'. Off for layers that deliberately
|
|
3966
|
+
* allow a silent turn and repair it themselves (the duplex voice reflex). */
|
|
3967
|
+
failEmptyTurns = true;
|
|
3964
3968
|
/** Fold the dropped middle of an over-long transcript into a synthetic summary (edge-safe, no LLM). Off => drop-oldest. */
|
|
3965
3969
|
compaction;
|
|
3966
3970
|
/** Add `Checkpoint`/`Rollback` tools (requires the fs to be an OverlayFilesystem). */
|
|
@@ -4034,6 +4038,22 @@ var Agent = class _Agent {
|
|
|
4034
4038
|
/** Per-run ground truth: every tool name actually INVOKED this run (native dispatch + delegated
|
|
4035
4039
|
* runtime activity). The ledger that makes a fabricated tool claim provable. Reset per run. */
|
|
4036
4040
|
invokedTools = /* @__PURE__ */ new Set();
|
|
4041
|
+
/** Delegated-runtime HOST tools currently executing (cursor toolExecutor). While > 0 the provider is
|
|
4042
|
+
* not silent — it is waiting on US — so the idle-stall watchdog must not fire (see armStallWatchdog). */
|
|
4043
|
+
hostToolsInFlight = 0;
|
|
4044
|
+
/** The hold is bounded by the transport tool deadline: a host tool that never settles (the helper already gave
|
|
4045
|
+
* up on it) must not disable stall protection for the rest of the request — or this instance. */
|
|
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;
|
|
4055
|
+
/** Resets the active request's stall timer; a host tool's completion restarts the model's idle window. */
|
|
4056
|
+
stallPoke;
|
|
4037
4057
|
/** Advertised tools this run's text claimed to have used while the ledger showed zero calls. */
|
|
4038
4058
|
fabricatedClaims = /* @__PURE__ */ new Set();
|
|
4039
4059
|
activeHooks;
|
|
@@ -4336,6 +4356,7 @@ var Agent = class _Agent {
|
|
|
4336
4356
|
let toolCallsTotal = 0;
|
|
4337
4357
|
let lastFp = "";
|
|
4338
4358
|
let repeats = 0;
|
|
4359
|
+
let emptyNudged = false;
|
|
4339
4360
|
let closureNudged = false;
|
|
4340
4361
|
let lastProgressAt = start;
|
|
4341
4362
|
const kill = (finishReason) => {
|
|
@@ -4344,12 +4365,13 @@ var Agent = class _Agent {
|
|
|
4344
4365
|
const claims = this.survivingClaims();
|
|
4345
4366
|
return { text: lastAssistantText(this.transcript), steps, finishReason, messages: this.transcript, usage, usageEstimated, ...claims.length ? { fabricatedToolClaims: claims } : {} };
|
|
4346
4367
|
};
|
|
4368
|
+
const overBudget = () => !!o.maxTokens && usage.totalTokens - 0.9 * usage.cacheReadTokens >= o.maxTokens;
|
|
4369
|
+
const canNudge = () => steps < o.maxSteps && !overBudget();
|
|
4347
4370
|
while (true) {
|
|
4348
4371
|
if (o.signal?.aborted) return kill("aborted");
|
|
4349
4372
|
if (steps >= o.maxSteps) return kill("max_steps");
|
|
4350
4373
|
if (o.timeoutMs && Date.now() - lastProgressAt - this.parkedMs >= o.timeoutMs) return kill("timeout");
|
|
4351
|
-
|
|
4352
|
-
if (o.maxTokens && budgetTokens >= o.maxTokens) return kill("budget");
|
|
4374
|
+
if (overBudget()) return kill("budget");
|
|
4353
4375
|
steps++;
|
|
4354
4376
|
this.options.host?.notify?.({ kind: "turn_start", message: `step ${steps}` });
|
|
4355
4377
|
let res;
|
|
@@ -4360,6 +4382,7 @@ var Agent = class _Agent {
|
|
|
4360
4382
|
const hostToolTimeoutMs = o.providerOptions?.toolTimeoutMs;
|
|
4361
4383
|
const derivedToolTimeoutMs = Math.max(TRANSPORT_TOOL_TIMEOUT_FLOOR_MS, ...this.activeTools.map(transportHeadroomMs));
|
|
4362
4384
|
const effectiveToolTimeoutMs = typeof hostToolTimeoutMs === "number" ? Math.max(hostToolTimeoutMs, derivedToolTimeoutMs) : derivedToolTimeoutMs;
|
|
4385
|
+
this.toolHoldMs = effectiveToolTimeoutMs;
|
|
4363
4386
|
if (isCursorWithTools) {
|
|
4364
4387
|
if (typeof hostToolTimeoutMs === "number" && effectiveToolTimeoutMs !== hostToolTimeoutMs) {
|
|
4365
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.`);
|
|
@@ -4370,7 +4393,15 @@ var Agent = class _Agent {
|
|
|
4370
4393
|
toolTimeoutMs: effectiveToolTimeoutMs,
|
|
4371
4394
|
toolExecutor: async (name, args) => {
|
|
4372
4395
|
const tc = { id: `cursor-${Date.now()}`, type: "function", function: { name, arguments: JSON.stringify(args) } };
|
|
4373
|
-
|
|
4396
|
+
this.hostToolsInFlight++;
|
|
4397
|
+
this.hostToolHoldUntil = Math.max(this.hostToolHoldUntil, Date.now() + effectiveToolTimeoutMs);
|
|
4398
|
+
try {
|
|
4399
|
+
return await this.dispatch(tc);
|
|
4400
|
+
} finally {
|
|
4401
|
+
this.hostToolsInFlight--;
|
|
4402
|
+
this.toolRanThisAttempt = true;
|
|
4403
|
+
this.stallPoke?.();
|
|
4404
|
+
}
|
|
4374
4405
|
}
|
|
4375
4406
|
} : void 0;
|
|
4376
4407
|
const claudeSteerPo = o.model.startsWith("claude-code/") ? { steer: () => this.drainPendingSteers() } : void 0;
|
|
@@ -4381,6 +4412,8 @@ var Agent = class _Agent {
|
|
|
4381
4412
|
};
|
|
4382
4413
|
try {
|
|
4383
4414
|
for (let attempt = 0; ; attempt++) {
|
|
4415
|
+
this.nativeToolsInFlight.clear();
|
|
4416
|
+
this.toolRanThisAttempt = false;
|
|
4384
4417
|
try {
|
|
4385
4418
|
if (useStream) {
|
|
4386
4419
|
const stall = this.armStallWatchdog(o.signal, o.stallMs);
|
|
@@ -4410,7 +4443,9 @@ var Agent = class _Agent {
|
|
|
4410
4443
|
const stalled = err2?.code === "stall";
|
|
4411
4444
|
const empty = err2?.code === "empty" || err2?.code === "cursor_silent";
|
|
4412
4445
|
const maxAttempts = empty ? Math.max(o.emptyRetries, 0) : 2;
|
|
4413
|
-
const
|
|
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);
|
|
4414
4449
|
if (!transient) throw err2;
|
|
4415
4450
|
const waitMs = (empty ? o.emptyRetryBaseMs : 1e3) * (attempt + 1);
|
|
4416
4451
|
log6.warn(`${empty ? "empty model turn" : stalled ? "model stall" : "network drop"} mid-step (${err2?.message ?? err2}) \u2014 retrying in ${waitMs}ms`);
|
|
@@ -4491,9 +4526,22 @@ var Agent = class _Agent {
|
|
|
4491
4526
|
}
|
|
4492
4527
|
if (toolCalls.length === 0) {
|
|
4493
4528
|
if (this.drainInjections()) continue;
|
|
4529
|
+
if (emptyTurn && o.failEmptyTurns) {
|
|
4530
|
+
if (!emptyNudged && canNudge()) {
|
|
4531
|
+
emptyNudged = true;
|
|
4532
|
+
log6.warn(`empty model turn after tool work (step ${steps}, provider finishReason=${res.finishReason ?? "n/a"}) \u2014 nudging once`);
|
|
4533
|
+
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." });
|
|
4534
|
+
continue;
|
|
4535
|
+
}
|
|
4536
|
+
log6.warn(`model returned empty turns after tool work \u2014 surfacing as failed`);
|
|
4537
|
+
const e = new Error("empty_response: model returned an empty turn (no text, no tools) after a re-prompt");
|
|
4538
|
+
e.code = "empty";
|
|
4539
|
+
return { text: "", steps, finishReason: "empty", ...res.finishReason ? { providerFinishReason: res.finishReason } : {}, messages: this.transcript, usage, usageEstimated, error: e };
|
|
4540
|
+
}
|
|
4494
4541
|
const fabricated = o.catchFabricatedToolUse && !closureNudged ? this.fabricatedToolNames(contentText(res.content ?? "")) : [];
|
|
4495
4542
|
for (const n of fabricated) this.fabricatedClaims.add(n);
|
|
4496
|
-
if (fabricated.length &&
|
|
4543
|
+
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`);
|
|
4544
|
+
if (fabricated.length && canNudge()) {
|
|
4497
4545
|
closureNudged = true;
|
|
4498
4546
|
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`);
|
|
4499
4547
|
this.transcript.push({
|
|
@@ -4502,7 +4550,7 @@ var Agent = class _Agent {
|
|
|
4502
4550
|
});
|
|
4503
4551
|
continue;
|
|
4504
4552
|
}
|
|
4505
|
-
if (o.closeDelegatedTurns && res.endedWithoutClosing && !closureNudged &&
|
|
4553
|
+
if (o.closeDelegatedTurns && res.endedWithoutClosing && !closureNudged && canNudge()) {
|
|
4506
4554
|
closureNudged = true;
|
|
4507
4555
|
log6.verbose("delegated turn went silent after a tool \u2014 nudging a closing answer");
|
|
4508
4556
|
this.transcript.push({
|
|
@@ -4516,7 +4564,7 @@ var Agent = class _Agent {
|
|
|
4516
4564
|
this.releaseStaleImages();
|
|
4517
4565
|
await this.activeHooks?.onStop?.(res.content ?? "");
|
|
4518
4566
|
const claims = this.survivingClaims();
|
|
4519
|
-
return { text: res.content ?? "", steps, finishReason: "stop", messages: this.transcript, usage, usageEstimated, ...claims.length ? { fabricatedToolClaims: claims } : {} };
|
|
4567
|
+
return { text: res.content ?? "", steps, finishReason: "stop", ...res.finishReason ? { providerFinishReason: res.finishReason } : {}, messages: this.transcript, usage, usageEstimated, ...claims.length ? { fabricatedToolClaims: claims } : {} };
|
|
4520
4568
|
}
|
|
4521
4569
|
const fp = toolCalls.map((tc) => tc.function.name + ":" + (tc.function.arguments ?? "")).join("|");
|
|
4522
4570
|
repeats = fp === lastFp ? repeats + 1 : 1;
|
|
@@ -4580,10 +4628,12 @@ var Agent = class _Agent {
|
|
|
4580
4628
|
if (!stallMs) return;
|
|
4581
4629
|
if (timer) clearTimeout(timer);
|
|
4582
4630
|
timer = setTimeout(() => {
|
|
4631
|
+
if (this.toolHoldActive()) return poke();
|
|
4583
4632
|
fired = true;
|
|
4584
4633
|
ac.abort(stallError());
|
|
4585
4634
|
}, stallMs);
|
|
4586
4635
|
};
|
|
4636
|
+
this.stallPoke = poke;
|
|
4587
4637
|
poke();
|
|
4588
4638
|
const stalled = () => fired && !parent?.aborted;
|
|
4589
4639
|
return {
|
|
@@ -4592,11 +4642,19 @@ var Agent = class _Agent {
|
|
|
4592
4642
|
stalled,
|
|
4593
4643
|
clear: () => {
|
|
4594
4644
|
if (timer) clearTimeout(timer);
|
|
4645
|
+
if (this.stallPoke === poke) this.stallPoke = void 0;
|
|
4595
4646
|
parent?.removeEventListener("abort", onParentAbort);
|
|
4596
4647
|
},
|
|
4597
4648
|
reclassify: (err2) => stalled() ? stallError() : err2
|
|
4598
4649
|
};
|
|
4599
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
|
+
}
|
|
4600
4658
|
/** A clean-stop turn that carries no assistant text AND no tool calls (native or delegated) — a
|
|
4601
4659
|
* non-result the model produced by going silent. Callers retry it rather than report "done". */
|
|
4602
4660
|
isEmptyStop(res) {
|
|
@@ -4635,6 +4693,12 @@ var Agent = class _Agent {
|
|
|
4635
4693
|
if (a.output !== void 0) prev.output = a.output;
|
|
4636
4694
|
prev.status = a.status;
|
|
4637
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
|
+
}
|
|
4638
4702
|
sawTool = true;
|
|
4639
4703
|
this.invokedTools.add(a.name);
|
|
4640
4704
|
trailing = "";
|
|
@@ -4687,8 +4751,9 @@ var Agent = class _Agent {
|
|
|
4687
4751
|
*/
|
|
4688
4752
|
fabricatedToolNames(text) {
|
|
4689
4753
|
const out = [];
|
|
4754
|
+
const invoked = new Set([...this.invokedTools].map(toolKey));
|
|
4690
4755
|
for (const t of this.activeTools) {
|
|
4691
|
-
if (
|
|
4756
|
+
if (invoked.has(toolKey(t.name))) continue;
|
|
4692
4757
|
if (t.name.length < 4 || !/[_\-A-Z]/.test(t.name)) continue;
|
|
4693
4758
|
const re = new RegExp(`(?:^|[^\\w])${t.name.replace(/[.*+?^${}()|[\]\\]/g, "\\$&")}(?:[^\\w]|$)`);
|
|
4694
4759
|
if (re.test(text)) out.push(t.name);
|
|
@@ -4701,7 +4766,8 @@ var Agent = class _Agent {
|
|
|
4701
4766
|
* call that demonstrably ran. See `RunResult.fabricatedToolClaims`. */
|
|
4702
4767
|
survivingClaims() {
|
|
4703
4768
|
if (!this.fabricatedClaims.size) return [];
|
|
4704
|
-
|
|
4769
|
+
const invoked = new Set([...this.invokedTools].map(toolKey));
|
|
4770
|
+
return [...this.fabricatedClaims].filter((n) => !invoked.has(toolKey(n)));
|
|
4705
4771
|
}
|
|
4706
4772
|
async dispatch(tc) {
|
|
4707
4773
|
this.invokedTools.add(tc.function.name);
|
|
@@ -5089,6 +5155,11 @@ function lastAssistantText(messages) {
|
|
|
5089
5155
|
}
|
|
5090
5156
|
return "";
|
|
5091
5157
|
}
|
|
5158
|
+
var TOOL_ALIASES = { bash: "shell" };
|
|
5159
|
+
function toolKey(name) {
|
|
5160
|
+
const k = name.toLowerCase();
|
|
5161
|
+
return TOOL_ALIASES[k] ?? k;
|
|
5162
|
+
}
|
|
5092
5163
|
|
|
5093
5164
|
// src/index.ts
|
|
5094
5165
|
init_NodeDiskFilesystem();
|
|
@@ -7772,6 +7843,8 @@ ${nowLine()}. Anchor every relative or time-sensitive reference \u2014 "today",
|
|
|
7772
7843
|
instructionFiles: false,
|
|
7773
7844
|
maxSteps: 8,
|
|
7774
7845
|
timeoutMs: 3e4,
|
|
7846
|
+
failEmptyTurns: false,
|
|
7847
|
+
// a silent reflex turn after a dispatch is legitimate — the voice layer repairs it
|
|
7775
7848
|
...o.reflexOptions,
|
|
7776
7849
|
tools,
|
|
7777
7850
|
// Composed AFTER the spread so the dispatch guard can't be dropped by reflexOptions.
|
|
@@ -14071,6 +14144,7 @@ function jsonResult(res, session) {
|
|
|
14071
14144
|
return {
|
|
14072
14145
|
ok: res.finishReason === "stop",
|
|
14073
14146
|
finishReason: res.finishReason,
|
|
14147
|
+
...res.providerFinishReason ? { providerFinishReason: res.providerFinishReason } : {},
|
|
14074
14148
|
text: res.text,
|
|
14075
14149
|
steps: res.steps,
|
|
14076
14150
|
tools: res.messages.slice(lastUser).filter((m) => m.role === "tool").length,
|
|
@@ -14078,7 +14152,7 @@ function jsonResult(res, session) {
|
|
|
14078
14152
|
sessionId: session.meta.id,
|
|
14079
14153
|
// The parked question, machine-readable — the caller answers it and resumes `sessionId`.
|
|
14080
14154
|
...res.finishReason === "needs_input" && res.question ? { question: res.question } : {},
|
|
14081
|
-
...res.finishReason === "error" && res.error ? { error: res.error?.message ?? String(res.error) } : {}
|
|
14155
|
+
...(res.finishReason === "error" || res.finishReason === "empty") && res.error ? { error: res.error?.message ?? String(res.error) } : {}
|
|
14082
14156
|
};
|
|
14083
14157
|
}
|
|
14084
14158
|
async function readMultiline(readLine) {
|