@livx.cc/agentx 0.99.16 → 0.99.18
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-CvLBalJE.d.ts → Agent-Cn9BxS8h.d.ts} +17 -0
- package/dist/cli.d.ts +1 -1
- package/dist/cli.js +82 -7
- package/dist/cli.js.map +1 -1
- package/dist/index.d.ts +2 -2
- package/dist/index.js +82 -7
- package/dist/index.js.map +1 -1
- package/package.json +2 -2
package/dist/index.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { a as AgentOptions, H as Hooks, h as RunResult, A as Agent } from './Agent-
|
|
2
|
-
export { C as ChatFragment, D as DEFAULT_MUTATING, b as Decision, P as PermissionOptions, c as PermissionPolicy, d as PermissionRule, e as PreToolUseDecision, R as ReasoningEffort, f as RecordingHooks, g as RecordingLifecycle, T as ToolUse, i as ToolUseMeta, j as composeHooks, p as planMode, r as reasoningToChatFragment } from './Agent-
|
|
1
|
+
import { a as AgentOptions, H as Hooks, h as RunResult, A as Agent } from './Agent-Cn9BxS8h.js';
|
|
2
|
+
export { C as ChatFragment, D as DEFAULT_MUTATING, b as Decision, P as PermissionOptions, c as PermissionPolicy, d as PermissionRule, e as PreToolUseDecision, R as ReasoningEffort, f as RecordingHooks, g as RecordingLifecycle, T as ToolUse, i as ToolUseMeta, j as composeHooks, p as planMode, r as reasoningToChatFragment } from './Agent-Cn9BxS8h.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
|
@@ -3181,6 +3181,10 @@ var AgentOptions = class {
|
|
|
3181
3181
|
maxTokens = 2e5;
|
|
3182
3182
|
/** Wall-clock ceiling in ms for the whole run. 0 = unbounded. */
|
|
3183
3183
|
timeoutMs = 12e4;
|
|
3184
|
+
/** Idle-stall watchdog for a SINGLE streamed model request: abort it if no chunk (text OR reasoning)
|
|
3185
|
+
* arrives for this long. The between-steps `timeoutMs` can't preempt an in-flight `chat()`, so a
|
|
3186
|
+
* provider that goes silent mid-stream would otherwise park the loop forever. 0 = off. */
|
|
3187
|
+
stallMs = 6e4;
|
|
3184
3188
|
/** Stop if the identical tool-call batch (name+args) repeats this many times in a row. 0 = off. */
|
|
3185
3189
|
maxRepeats = 3;
|
|
3186
3190
|
/** Cumulative cap on tool calls dispatched across the run. 0 = unbounded. */
|
|
@@ -3383,6 +3387,22 @@ var Agent = class _Agent {
|
|
|
3383
3387
|
clearInjections() {
|
|
3384
3388
|
this.pendingInjections.length = 0;
|
|
3385
3389
|
}
|
|
3390
|
+
/** Pull queued injections that are plain TEXT, removing them, for a runtime that can accept mid-turn
|
|
3391
|
+
* steers over its own channel (claude-code's warm InputQueue via `providerOptions.steer`). Non-text
|
|
3392
|
+
* injections (images) stay queued for the step-boundary `drainInjections()` re-open — the text-only
|
|
3393
|
+
* steer channel can't carry them. Consumed DURING chat(); no overlap with drainInjections() (post-call). */
|
|
3394
|
+
drainPendingSteers() {
|
|
3395
|
+
if (!this.pendingInjections.length) return [];
|
|
3396
|
+
const texts = [];
|
|
3397
|
+
this.pendingInjections = this.pendingInjections.filter((c) => {
|
|
3398
|
+
if (typeof c === "string") {
|
|
3399
|
+
texts.push(c);
|
|
3400
|
+
return false;
|
|
3401
|
+
}
|
|
3402
|
+
return true;
|
|
3403
|
+
});
|
|
3404
|
+
return texts;
|
|
3405
|
+
}
|
|
3386
3406
|
/** Fold any host-injected messages into the transcript as user turns. Returns true if any landed. */
|
|
3387
3407
|
drainInjections() {
|
|
3388
3408
|
if (!this.pendingInjections.length) return false;
|
|
@@ -3587,17 +3607,25 @@ var Agent = class _Agent {
|
|
|
3587
3607
|
return typeof raw === "string" ? raw : raw.text;
|
|
3588
3608
|
}
|
|
3589
3609
|
} : void 0;
|
|
3610
|
+
const claudeSteerPo = o.model.startsWith("claude-code/") ? { steer: () => this.drainPendingSteers() } : void 0;
|
|
3590
3611
|
const reasonOpts = {
|
|
3591
3612
|
...frag,
|
|
3592
3613
|
...o.promptCache ? { promptCache: true } : {},
|
|
3593
|
-
...o.providerOptions || cursorPo ? { providerOptions: { ...frag.providerOptions, ...o.providerOptions, ...cursorPo } } : {}
|
|
3614
|
+
...o.providerOptions || cursorPo || claudeSteerPo ? { providerOptions: { ...frag.providerOptions, ...o.providerOptions, ...cursorPo, ...claudeSteerPo } } : {}
|
|
3594
3615
|
};
|
|
3595
3616
|
try {
|
|
3596
3617
|
for (let attempt = 0; ; attempt++) {
|
|
3597
3618
|
try {
|
|
3598
3619
|
if (useStream) {
|
|
3599
|
-
const
|
|
3600
|
-
|
|
3620
|
+
const stall = this.armStallWatchdog(o.signal, o.stallMs);
|
|
3621
|
+
try {
|
|
3622
|
+
const r = await o.ai.chat({ model: o.model, messages: sent, tools: sentTools, stream: true, signal: stall.signal, ...o.toolChoice ? { toolChoice: o.toolChoice } : {}, ...reasonOpts });
|
|
3623
|
+
res = await this.consumeStream(r, stall.poke);
|
|
3624
|
+
} catch (err) {
|
|
3625
|
+
throw stall.reclassify(err);
|
|
3626
|
+
} finally {
|
|
3627
|
+
stall.clear();
|
|
3628
|
+
}
|
|
3601
3629
|
} else {
|
|
3602
3630
|
const r = await o.ai.chat({ model: o.model, messages: sent, tools: sentTools, stream: false, signal: o.signal, ...o.toolChoice ? { toolChoice: o.toolChoice } : {}, ...reasonOpts });
|
|
3603
3631
|
res = r;
|
|
@@ -3607,16 +3635,21 @@ var Agent = class _Agent {
|
|
|
3607
3635
|
const sc = err?.statusCode;
|
|
3608
3636
|
const serverSide = sc >= 500 || sc === 408 || /Service Unavailable|overloaded|Internal server error|Bad gateway|Gateway time/i.test(String(err?.message ?? ""));
|
|
3609
3637
|
const network = !sc && /ECONNRESET|ECONNREFUSED|ETIMEDOUT|ENOTFOUND|EAI_AGAIN|EPIPE|socket hang up|fetch failed|network|terminated|UND_ERR/i.test(String(err?.message ?? err?.code ?? err));
|
|
3610
|
-
const
|
|
3638
|
+
const stalled = err?.code === "stall";
|
|
3639
|
+
const transient = !o.signal?.aborted && !isAbortError(err) && attempt < 2 && (network || serverSide || stalled);
|
|
3611
3640
|
if (!transient) throw err;
|
|
3612
3641
|
const waitMs = 1e3 * (attempt + 1);
|
|
3613
|
-
log4.warn(
|
|
3614
|
-
o.host?.notify?.({ kind: "retry", message:
|
|
3642
|
+
log4.warn(`${stalled ? "model stall" : "network drop"} mid-step (${err?.message ?? err}) \u2014 retrying in ${waitMs}ms`);
|
|
3643
|
+
o.host?.notify?.({ kind: "retry", message: `${stalled ? "model stalled" : "connection dropped"} \u2014 retrying step (#${attempt + 1})` });
|
|
3615
3644
|
await new Promise((r) => setTimeout(r, waitMs));
|
|
3616
3645
|
}
|
|
3617
3646
|
}
|
|
3618
3647
|
} catch (err) {
|
|
3619
3648
|
if (err?.code === "budget") return kill("budget");
|
|
3649
|
+
if (err?.code === "stall") {
|
|
3650
|
+
log4.warn(`model stalled out after retries: ${err?.message ?? err}`);
|
|
3651
|
+
return kill("timeout");
|
|
3652
|
+
}
|
|
3620
3653
|
if (o.signal?.aborted || isAbortError(err)) return kill("aborted");
|
|
3621
3654
|
const body = err?.body ?? err?.response?.data ?? err?.error;
|
|
3622
3655
|
let bodyStr;
|
|
@@ -3687,12 +3720,54 @@ var Agent = class _Agent {
|
|
|
3687
3720
|
* (`{kind:'text_delta'}`) and fold all chunks back into the single
|
|
3688
3721
|
* ChatResponse the non-stream path would have returned.
|
|
3689
3722
|
*/
|
|
3690
|
-
|
|
3723
|
+
/**
|
|
3724
|
+
* Idle-stall watchdog for one streamed model request. Returns a linked AbortController `signal` to
|
|
3725
|
+
* hand to `chat()`, a `poke()` to reset the idle timer on each chunk, a `reclassify()` that turns a
|
|
3726
|
+
* watchdog-fired abort into an Error{code:'stall'} (leaving a parent/user abort untouched), and a
|
|
3727
|
+
* `clear()` to disarm. Aborts the request if no `poke()` (or completion) happens within `stallMs`.
|
|
3728
|
+
* `stallMs = 0` disables the timer but still links parent-abort → child so cancellation propagates.
|
|
3729
|
+
*/
|
|
3730
|
+
armStallWatchdog(parent, stallMs) {
|
|
3731
|
+
const ac = new AbortController();
|
|
3732
|
+
let fired = false;
|
|
3733
|
+
const onParentAbort = () => ac.abort();
|
|
3734
|
+
if (parent?.aborted) ac.abort();
|
|
3735
|
+
else parent?.addEventListener("abort", onParentAbort, { once: true });
|
|
3736
|
+
let timer;
|
|
3737
|
+
const poke = () => {
|
|
3738
|
+
if (!stallMs) return;
|
|
3739
|
+
if (timer) clearTimeout(timer);
|
|
3740
|
+
timer = setTimeout(() => {
|
|
3741
|
+
fired = true;
|
|
3742
|
+
ac.abort();
|
|
3743
|
+
}, stallMs);
|
|
3744
|
+
};
|
|
3745
|
+
poke();
|
|
3746
|
+
return {
|
|
3747
|
+
signal: ac.signal,
|
|
3748
|
+
poke,
|
|
3749
|
+
clear: () => {
|
|
3750
|
+
if (timer) clearTimeout(timer);
|
|
3751
|
+
parent?.removeEventListener("abort", onParentAbort);
|
|
3752
|
+
},
|
|
3753
|
+
// Distinguish OUR abort (silent provider) from a parent/user cancel, which must stay an abort.
|
|
3754
|
+
reclassify: (err) => {
|
|
3755
|
+
if (fired && !parent?.aborted) {
|
|
3756
|
+
const e = new Error(`model stalled: no stream output for ${stallMs >= 1e3 ? `${Math.round(stallMs / 1e3)}s` : `${stallMs}ms`}`);
|
|
3757
|
+
e.code = "stall";
|
|
3758
|
+
return e;
|
|
3759
|
+
}
|
|
3760
|
+
return err;
|
|
3761
|
+
}
|
|
3762
|
+
};
|
|
3763
|
+
}
|
|
3764
|
+
async consumeStream(stream, poke) {
|
|
3691
3765
|
let content = "";
|
|
3692
3766
|
let finishReason;
|
|
3693
3767
|
let toolCalls;
|
|
3694
3768
|
let usage;
|
|
3695
3769
|
for await (const chunk of stream) {
|
|
3770
|
+
poke?.();
|
|
3696
3771
|
if (this.options.signal?.aborted) break;
|
|
3697
3772
|
if (chunk.reasoningContent) this.options.host.notify({ kind: "thinking_delta", message: chunk.reasoningContent });
|
|
3698
3773
|
if (chunk.toolActivity) {
|