@livx.cc/agentx 0.96.15 → 0.96.16
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-DRe91tAy.d.ts → Agent-DdhD1pGw.d.ts} +15 -0
- package/dist/cli.d.ts +1 -1
- package/dist/cli.js +62 -17
- package/dist/cli.js.map +1 -1
- package/dist/index.d.ts +13 -2
- package/dist/index.js +52 -2
- package/dist/index.js.map +1 -1
- package/dist/native/mic-aec.swift +13 -0
- package/package.json +1 -1
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-DdhD1pGw.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-DdhD1pGw.js';
|
|
3
3
|
import { IFilesystem, FileMetadata } from '@livx.cc/wcli/core';
|
|
4
4
|
export { CommandExecutor, FileMetadata, IFilesystem, IndexedDbFilesystem, MemFilesystem, registerHeadlessCommands } from '@livx.cc/wcli/core';
|
|
5
5
|
import { BodDB } from '@bod.ee/db';
|
|
@@ -1166,6 +1166,8 @@ interface SttLike {
|
|
|
1166
1166
|
onPartial: (text: string) => void;
|
|
1167
1167
|
onUtterance: (text: string, endpointAt: number) => void;
|
|
1168
1168
|
onLevel: (rms: number) => void;
|
|
1169
|
+
/** Optional: unrecoverable capture failure (e.g. mic produced no audio) — host tears voice down. */
|
|
1170
|
+
onFatal?: (message: string) => void;
|
|
1169
1171
|
start(): Promise<void> | void;
|
|
1170
1172
|
reset(): void;
|
|
1171
1173
|
stop(): void;
|
|
@@ -1326,6 +1328,9 @@ declare class SonioxSTTOptions {
|
|
|
1326
1328
|
/** Client-side endpoint: finalized text + no new tokens for this long = utterance (don't wait for
|
|
1327
1329
|
* Soniox's semantic <end>, which adds 0.5-1.5s — the difference between ping-pong and lag). */
|
|
1328
1330
|
silenceEndpointMs: number;
|
|
1331
|
+
/** No-audio watchdog: if the mic source stops delivering chunks for this long, capture is dead →
|
|
1332
|
+
* fire onFatal + stop (else Soniox idle-timeouts and reconnect-loops forever). 0 = disable. */
|
|
1333
|
+
noAudioTimeoutMs: number;
|
|
1329
1334
|
}
|
|
1330
1335
|
declare class SonioxSTT {
|
|
1331
1336
|
options: SonioxSTTOptions;
|
|
@@ -1336,6 +1341,12 @@ declare class SonioxSTT {
|
|
|
1336
1341
|
onUtterance: (text: string, endpointAt: number) => void;
|
|
1337
1342
|
/** mic energy (RMS) per chunk — drives the energy-based heuristic barge-in tier */
|
|
1338
1343
|
onLevel: (rms: number) => void;
|
|
1344
|
+
/** Unrecoverable: the mic source stopped delivering audio (Soniox starves → idle-timeout reconnect
|
|
1345
|
+
* loop). The host tears voice down instead of spinning forever. */
|
|
1346
|
+
onFatal: (message: string) => void;
|
|
1347
|
+
private lastChunkAt;
|
|
1348
|
+
private startedChunksAt;
|
|
1349
|
+
private noAudioTimer;
|
|
1339
1350
|
private finalText;
|
|
1340
1351
|
private partialText;
|
|
1341
1352
|
private lastChangeAt;
|
package/dist/index.js
CHANGED
|
@@ -3103,6 +3103,9 @@ function reasoningToChatFragment(model, effort) {
|
|
|
3103
3103
|
|
|
3104
3104
|
// src/Agent.ts
|
|
3105
3105
|
var log4 = forComponent("Agent");
|
|
3106
|
+
function isBrowserTool(name) {
|
|
3107
|
+
return name.startsWith("mcp__") && /browser/i.test(name.slice(5).split("__")[0]);
|
|
3108
|
+
}
|
|
3106
3109
|
function isAbortError(err) {
|
|
3107
3110
|
const e = err;
|
|
3108
3111
|
const blob = `${e?.message ?? ""} ${e?.name ?? ""} ${e?.code ?? ""} ${e?.cause?.name ?? ""}`;
|
|
@@ -3150,6 +3153,17 @@ var AgentOptions = class {
|
|
|
3150
3153
|
* and returns the (cropped) string to put in context — e.g. spill to scratch and return a recoverable,
|
|
3151
3154
|
* paginated stub. Called only when a result exceeds `maxToolResultBytes`. */
|
|
3152
3155
|
capToolResult;
|
|
3156
|
+
/** Browser-run adaptive trimming. Browser MCP tools (`mcp__*browser*`) return huge per-call results
|
|
3157
|
+
* (full DOM text + screenshots) that accumulate per step and blow the cumulative `maxTokens` budget
|
|
3158
|
+
* kill-switch mid-browse. The fix attacks PER-STEP TOKEN GROWTH, and engages ONLY once a browser tool
|
|
3159
|
+
* is ACTUALLY invoked (not on mere config presence — so normal coding is untouched):
|
|
3160
|
+
* - `resultBytes`: tighter `maxToolResultBytes` applied to BROWSER tool results (each oversized DOM is
|
|
3161
|
+
* cropped/spilled to a small stub → small fresh-token tail per step).
|
|
3162
|
+
* - `keepOutputs`: keep only the most-recent N tool-result bodies verbatim ONCE a browser tool has run
|
|
3163
|
+
* (older huge DOMs collapse to one-line stubs → small cached prefix → small 0.1×cacheRead/step).
|
|
3164
|
+
* Explicit `keepToolOutputs`/`maxToolResultBytes` are NOT overridden below their browser values — the
|
|
3165
|
+
* tighter of (user, browser) wins, never loosening a user's cap. Unset = off (no adaptive behavior). */
|
|
3166
|
+
browserTrim;
|
|
3153
3167
|
/** VFS dir(s) of skills (`<dir>/<id>/SKILL.md`). If set: inject a catalog + add the `Skill` tool. Multiple dirs are merged (first wins on name collisions). */
|
|
3154
3168
|
skillsDir;
|
|
3155
3169
|
/** VFS dir(s) of slash-command templates (`<dir>/<name>.md`). If set: inject a catalog + add the `SlashCommand` tool. Multiple dirs are merged (first wins). */
|
|
@@ -3234,6 +3248,8 @@ var Agent = class _Agent {
|
|
|
3234
3248
|
// session-start lifecycle hook fires once per conversation
|
|
3235
3249
|
parkedMs = 0;
|
|
3236
3250
|
// cumulative time blocked on the HUMAN (permission/plan prompts) — excluded from the timeout
|
|
3251
|
+
browserActive = false;
|
|
3252
|
+
// flips true once a browser MCP tool is actually invoked → adaptive trimming engages (browserTrim)
|
|
3237
3253
|
/** Time a human-blocking await (a permission/plan prompt) and bank it in `parkedMs` so idle prompt
|
|
3238
3254
|
* time never trips the wall-clock kill-switch. The agent did no work while parked on the user. */
|
|
3239
3255
|
async park(p) {
|
|
@@ -3642,7 +3658,11 @@ var Agent = class _Agent {
|
|
|
3642
3658
|
}
|
|
3643
3659
|
if (!threw) result = await this.maybeAutoTest(tc.function.name, result);
|
|
3644
3660
|
if (images?.length && !result) result = `[${images.length} image${images.length > 1 ? "s" : ""} attached]`;
|
|
3645
|
-
const
|
|
3661
|
+
const browser = isBrowserTool(tc.function.name);
|
|
3662
|
+
if (browser && this.options.browserTrim) this.browserActive = true;
|
|
3663
|
+
const browserBytes = browser ? this.options.browserTrim?.resultBytes : void 0;
|
|
3664
|
+
const baseCap = this.options.maxToolResultBytes ?? 0;
|
|
3665
|
+
const cap = browserBytes ? baseCap > 0 ? Math.min(baseCap, browserBytes) : browserBytes : baseCap;
|
|
3646
3666
|
if (!threw && cap > 0 && result.length > cap) {
|
|
3647
3667
|
const info = { tool: tc.function.name, args };
|
|
3648
3668
|
result = this.options.capToolResult ? await this.options.capToolResult(result, info) : cropResult(result, cap);
|
|
@@ -3686,7 +3706,9 @@ ${out}`;
|
|
|
3686
3706
|
let out = null;
|
|
3687
3707
|
if (o.compaction?.maxMessages && m.length > o.compaction.maxMessages) out = compact(m, o.compaction.maxMessages);
|
|
3688
3708
|
else if (o.maxContextMessages && m.length > o.maxContextMessages) out = dropOldest(m, o.maxContextMessages);
|
|
3689
|
-
|
|
3709
|
+
const browserKeep = this.browserActive ? o.browserTrim?.keepOutputs : void 0;
|
|
3710
|
+
const keep = browserKeep != null ? o.keepToolOutputs ? Math.min(o.keepToolOutputs, browserKeep) : browserKeep : o.keepToolOutputs;
|
|
3711
|
+
if (keep) out = stubOldToolResults(out ?? m, keep);
|
|
3690
3712
|
if (o.maxContextTokens) {
|
|
3691
3713
|
const pre = (out ?? m).length;
|
|
3692
3714
|
out = fitTokenBudget(out ?? m, o.maxContextTokens);
|
|
@@ -6042,6 +6064,9 @@ var SonioxSTTOptions = class {
|
|
|
6042
6064
|
/** Client-side endpoint: finalized text + no new tokens for this long = utterance (don't wait for
|
|
6043
6065
|
* Soniox's semantic <end>, which adds 0.5-1.5s — the difference between ping-pong and lag). */
|
|
6044
6066
|
silenceEndpointMs = 500;
|
|
6067
|
+
/** No-audio watchdog: if the mic source stops delivering chunks for this long, capture is dead →
|
|
6068
|
+
* fire onFatal + stop (else Soniox idle-timeouts and reconnect-loops forever). 0 = disable. */
|
|
6069
|
+
noAudioTimeoutMs = 1e4;
|
|
6045
6070
|
};
|
|
6046
6071
|
var SonioxSTT = class {
|
|
6047
6072
|
options;
|
|
@@ -6055,6 +6080,15 @@ var SonioxSTT = class {
|
|
|
6055
6080
|
/** mic energy (RMS) per chunk — drives the energy-based heuristic barge-in tier */
|
|
6056
6081
|
onLevel = () => {
|
|
6057
6082
|
};
|
|
6083
|
+
/** Unrecoverable: the mic source stopped delivering audio (Soniox starves → idle-timeout reconnect
|
|
6084
|
+
* loop). The host tears voice down instead of spinning forever. */
|
|
6085
|
+
onFatal = () => {
|
|
6086
|
+
};
|
|
6087
|
+
lastChunkAt = 0;
|
|
6088
|
+
// timestamp of the most recent mic chunk (0 = none yet)
|
|
6089
|
+
startedChunksAt = 0;
|
|
6090
|
+
// when capture started (grace before the first chunk)
|
|
6091
|
+
noAudioTimer = null;
|
|
6058
6092
|
finalText = "";
|
|
6059
6093
|
partialText = "";
|
|
6060
6094
|
lastChangeAt = 0;
|
|
@@ -6106,7 +6140,22 @@ var SonioxSTT = class {
|
|
|
6106
6140
|
this.onUtterance(combined, now2());
|
|
6107
6141
|
}, 120);
|
|
6108
6142
|
this.endpointTimer.unref?.();
|
|
6143
|
+
this.startedChunksAt = now2();
|
|
6144
|
+
const noAudioMs = this.options.noAudioTimeoutMs;
|
|
6145
|
+
if (noAudioMs > 0) {
|
|
6146
|
+
this.noAudioTimer = setInterval(() => {
|
|
6147
|
+
if (this.stopped) return;
|
|
6148
|
+
const ref = this.lastChunkAt || this.startedChunksAt;
|
|
6149
|
+
if (now2() - ref > noAudioMs) {
|
|
6150
|
+
log11.error(`stt: no mic audio for >${Math.round(noAudioMs / 1e3)}s \u2014 capture device stopped delivering`);
|
|
6151
|
+
this.onFatal("microphone stopped delivering audio (try a different input device, e.g. AirPods, or check System Settings \u2192 Sound \u2192 Input)");
|
|
6152
|
+
this.stop();
|
|
6153
|
+
}
|
|
6154
|
+
}, Math.max(250, Math.min(2e3, noAudioMs / 4)));
|
|
6155
|
+
this.noAudioTimer.unref?.();
|
|
6156
|
+
}
|
|
6109
6157
|
await this.options.source.start((chunk) => {
|
|
6158
|
+
this.lastChunkAt = now2();
|
|
6110
6159
|
let sum = 0;
|
|
6111
6160
|
const view = new DataView(chunk.buffer, chunk.byteOffset, chunk.byteLength);
|
|
6112
6161
|
for (let i = 0; i + 1 < chunk.byteLength; i += 2) {
|
|
@@ -6148,6 +6197,7 @@ var SonioxSTT = class {
|
|
|
6148
6197
|
stop() {
|
|
6149
6198
|
this.stopped = true;
|
|
6150
6199
|
if (this.endpointTimer) clearInterval(this.endpointTimer);
|
|
6200
|
+
if (this.noAudioTimer) clearInterval(this.noAudioTimer);
|
|
6151
6201
|
this.options.source?.stop();
|
|
6152
6202
|
if (this.ws) this.ws.onclose = null;
|
|
6153
6203
|
this.ws?.close();
|