@livx.cc/agentx 0.94.38

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.
@@ -0,0 +1,1319 @@
1
+ import { a as AgentOptions, H as Hooks, h as RunResult, A as Agent } from './Agent-1DRfsYaK.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-1DRfsYaK.js';
3
+ import { IFilesystem, FileMetadata } from '@livx.cc/wcli/core';
4
+ export { CommandExecutor, FileMetadata, IFilesystem, IndexedDbFilesystem, MemFilesystem, registerHeadlessCommands } from '@livx.cc/wcli/core';
5
+ import { BodDB } from '@bod.ee/db';
6
+ import { A as AgentTool, C as ChatLike, a as ChatOptions, b as ChatResponse, h as ToolCall, H as HostBridge, U as UserQuestion, e as MessageContent } from './tools-DtpN8Agv.js';
7
+ export { c as ContentPart, d as HostEvent, M as Message, R as Role, S as SandboxJobRegistry, f as StreamChunk, T as TodoItem, g as Tool, i as ToolContext, j as bashTool, k as contentText, l as defaultTools, m as editTool, n as exitSessionTool, o as imagePart, p as makeContext, q as makeJobTools, r as readTool, t as toWireTools, s as todoWriteTool, u as toolRegistry, v as toolsByName } from './tools-DtpN8Agv.js';
8
+ export { M as McpCall, a as McpImage, b as McpRoute, c as McpRouteResolver, d as McpToolResult, e as McpToolSearchOptions, f as McpToolSpec, g as MountedMcpLike, h as buildMcpCatalog, m as makeLazyMcpToolSearch, i as makeMcpToolSearch, j as makeMcpToolSearchFromMounted, k as mcpToolToAgentTool, l as mcpToolsToAgentTools } from './mcp-CnzmQ8JE.js';
9
+ import * as libx_js_src_modules_log from 'libx.js/src/modules/log';
10
+ export { log } from 'libx.js/src/modules/log';
11
+
12
+ /**
13
+ * Real-disk backend implementing wcli's IFilesystem, rooted at `baseDir`.
14
+ * The VFS path space ('/...') maps under baseDir, so the same agent/tools/commands
15
+ * run unchanged against disk or memory — complete mem↔disk interchangeability.
16
+ * Semantics mirror MemFilesystem (throws on missing parent / existing dir / etc.).
17
+ */
18
+ declare class NodeDiskFilesystem implements IFilesystem {
19
+ private baseDir;
20
+ private cwd;
21
+ private opts;
22
+ constructor(baseDir: string, opts?: {
23
+ denySymlinks?: boolean;
24
+ });
25
+ /** Ensure the root dir exists. */
26
+ init(): Promise<void>;
27
+ private real;
28
+ private verified;
29
+ private static VERIFY_TTL_MS;
30
+ /** Throw if any existing component of `real` is a symlink (escape vector). */
31
+ private assertNoSymlink;
32
+ resolvePath(path: string, cwd?: string): string;
33
+ getCwd(): string;
34
+ setCwd(path: string): void;
35
+ readFile(path: string): Promise<string>;
36
+ /** Read raw bytes (for binary files like images). Not on the base IFilesystem (which is utf8-only) — an
37
+ * optional capability the Read tool duck-types to return image blocks. Same symlink/jail guards as readFile. */
38
+ readFileBytes(path: string): Promise<Uint8Array>;
39
+ writeFile(path: string, content: string): Promise<void>;
40
+ deleteFile(path: string): Promise<void>;
41
+ readDir(path: string): Promise<string[]>;
42
+ createDir(path: string): Promise<void>;
43
+ exists(path: string): Promise<boolean>;
44
+ stat(path: string): Promise<FileMetadata>;
45
+ isDirectory(path: string): Promise<boolean>;
46
+ isFile(path: string): Promise<boolean>;
47
+ }
48
+
49
+ /**
50
+ * Database-backed `IFilesystem` over bod-db's VFS — the normalization thesis realized: the agent
51
+ * operates on a file tree that lives in a database, yet the same tools/commands run unchanged
52
+ * (semantics mirror MemFilesystem/NodeDiskFilesystem: throw on missing parent / existing dir /
53
+ * non-empty dir / missing file). bod-db's VFS is path-based and async, so the adapter is thin.
54
+ *
55
+ * Construct with no args for an in-memory DB (great for tests), or pass a configured `BodDB`
56
+ * (with VFS enabled) backed by real/cloud storage for persistence. Call `close()` when done to
57
+ * release the DB's timers (the in-memory default uses `sweepInterval: 0`, so there's nothing to sweep).
58
+ */
59
+ declare class BodDbFilesystem implements IFilesystem {
60
+ private cwd;
61
+ private db;
62
+ private vfs;
63
+ private owns;
64
+ constructor(db?: BodDB);
65
+ /** Release the underlying DB's timers/handles. Closes only a DB we created (a passed-in DB is the caller's). */
66
+ close(): void;
67
+ resolvePath(path: string, cwd?: string): string;
68
+ getCwd(): string;
69
+ setCwd(path: string): void;
70
+ /** Parent dir of an absolute VFS path ('/a/b.txt' -> '/a'; '/a' -> '/'). */
71
+ private parentOf;
72
+ /** Throw (matching the other backends) unless the parent directory exists. Root is always a dir. */
73
+ private assertParentDir;
74
+ readFile(path: string): Promise<string>;
75
+ writeFile(path: string, content: string): Promise<void>;
76
+ deleteFile(path: string): Promise<void>;
77
+ readDir(path: string): Promise<string[]>;
78
+ createDir(path: string): Promise<void>;
79
+ exists(path: string): Promise<boolean>;
80
+ stat(path: string): Promise<FileMetadata>;
81
+ isDirectory(path: string): Promise<boolean>;
82
+ isFile(path: string): Promise<boolean>;
83
+ }
84
+
85
+ /**
86
+ * Containment boundary A — a policy decorator over ANY IFilesystem.
87
+ *
88
+ * The agent only ever sees an IFilesystem, so what it can touch is exactly what we
89
+ * mount. This jail:
90
+ * - hides + blocks `deny` paths entirely (secrets: .env, keys, .git, …) — invisible
91
+ * to read/stat/exists/readDir, unwritable;
92
+ * - makes `readonly` paths readable but unwritable (the "constitution": pinned
93
+ * grader/suite/criteria the self-evolve agent must never edit);
94
+ * - optionally `confineTo` a set of subtrees (anything outside is denied);
95
+ * - normalizes paths first, so `..` traversal (`/src/../.env`) is caught after resolution;
96
+ * - reports every violation via `onViolation` (audit trail / circuit-breaker hook).
97
+ *
98
+ * Crucial limitation: this guards what the AGENT'S TOOLS touch. It does NOT contain
99
+ * code executed against the real disk at eval time (the grader imports agent-written
100
+ * code) — that is boundary B (a sandboxed subprocess). See mind/08-self-evolve.md.
101
+ */
102
+ declare class JailedFilesystem implements IFilesystem {
103
+ private inner;
104
+ options: JailOptions;
105
+ private denyRe;
106
+ private roRe;
107
+ private confineRe?;
108
+ constructor(inner: IFilesystem, options?: Partial<JailOptions>);
109
+ private abs;
110
+ /** Throw if reading `path` is not permitted (denied or out of confinement). */
111
+ private guardRead;
112
+ /** Throw if writing/deleting `path` is not permitted (denied, readonly, or out of confinement). */
113
+ private guardWrite;
114
+ private violate;
115
+ /** Fire the audit hook without throwing (for boolean probes that must still return false). */
116
+ private note;
117
+ /** Is `abs` (already-resolved) visible? If not, fire the audit hook (op given) and return false. */
118
+ private visible;
119
+ readFile(path: string): Promise<string>;
120
+ /** Forward the optional binary-read capability (if the inner fs has it), jailed like readFile. */
121
+ readFileBytes(path: string): Promise<Uint8Array>;
122
+ writeFile(path: string, content: string): Promise<void>;
123
+ deleteFile(path: string): Promise<void>;
124
+ createDir(path: string): Promise<void>;
125
+ stat(path: string): Promise<FileMetadata>;
126
+ exists(path: string): Promise<boolean>;
127
+ isDirectory(path: string): Promise<boolean>;
128
+ isFile(path: string): Promise<boolean>;
129
+ /** List a directory, filtering out entries the policy hides. */
130
+ readDir(path: string): Promise<string[]>;
131
+ resolvePath(path: string, cwd?: string): string;
132
+ getCwd(): string;
133
+ /** Guard cwd too: the jail must never be able to "stand" on a denied/out-of-confine dir. */
134
+ setCwd(path: string): void;
135
+ }
136
+ /** Default denylist: secrets and VCS internals that must never be read or written.
137
+ * Patterns are matched case-insensitively (so /.ENV is covered too). */
138
+ declare const DEFAULT_DENY: string[];
139
+ declare class JailOptions {
140
+ /** Globs that are invisible and unwritable (secrets). */
141
+ deny: string[];
142
+ /** Globs readable but not writable/deletable (the pinned constitution). */
143
+ readonly: string[];
144
+ /** If set, only paths matching these globs are accessible at all. */
145
+ confineTo?: string[];
146
+ /** Audit hook fired on every blocked operation (drives the circuit breaker). */
147
+ onViolation?: (v: {
148
+ op: string;
149
+ path: string;
150
+ rule: string;
151
+ }) => void;
152
+ }
153
+
154
+ declare class OverlayFilesystem implements IFilesystem {
155
+ private base;
156
+ private st;
157
+ private snapshots;
158
+ private seq;
159
+ constructor(base: IFilesystem);
160
+ resolvePath(path: string, cwd?: string): string;
161
+ getCwd(): string;
162
+ setCwd(path: string): void;
163
+ private abs;
164
+ private parent;
165
+ private name;
166
+ readFile(path: string): Promise<string>;
167
+ exists(path: string): Promise<boolean>;
168
+ isFile(path: string): Promise<boolean>;
169
+ isDirectory(path: string): Promise<boolean>;
170
+ stat(path: string): Promise<FileMetadata>;
171
+ /** Merge base entries (minus tombstones) with overlay-created children of `path`. */
172
+ readDir(path: string): Promise<string[]>;
173
+ writeFile(path: string, content: string): Promise<void>;
174
+ createDir(path: string): Promise<void>;
175
+ deleteFile(path: string): Promise<void>;
176
+ private clone;
177
+ /** Capture the current overlay; returns a token to `rollback(token)` to. */
178
+ snapshot(label?: string): string;
179
+ /** Discard all changes since the named snapshot (or the most recent if omitted). */
180
+ rollback(token?: string): void;
181
+ /** Paths changed vs the base since this overlay was created (added = not in base, modified = was). */
182
+ diff(): Promise<{
183
+ added: string[];
184
+ modified: string[];
185
+ deleted: string[];
186
+ }>;
187
+ /** Flush the overlay into the base (writes, mkdirs, deletes), then clear the overlay. */
188
+ commit(): Promise<void>;
189
+ }
190
+ /** `Checkpoint` tool — snapshot the VFS before a risky multi-step change. */
191
+ declare const checkpointTool: AgentTool;
192
+ /** `Rollback` tool — undo all VFS changes since a Checkpoint. */
193
+ declare const rollbackTool: AgentTool;
194
+ declare const checkpointTools: () => AgentTool[];
195
+
196
+ interface Mount {
197
+ prefix: string;
198
+ fs: IFilesystem;
199
+ }
200
+ declare class MountFilesystem implements IFilesystem {
201
+ private root;
202
+ private mounts;
203
+ constructor(root: IFilesystem, mounts?: Mount[]);
204
+ resolvePath(path: string, cwd?: string): string;
205
+ getCwd(): string;
206
+ setCwd(path: string): void;
207
+ private abs;
208
+ /** Route an absolute VFS path to a backend + its path within that backend. */
209
+ private route;
210
+ /** Is `abs` strictly ABOVE a mount point (a synthesized dir the root may not have)? */
211
+ private isMountAncestor;
212
+ /** Immediate child segment names of `abs` that come from mounts (for readDir merge). */
213
+ private mountChildrenOf;
214
+ readFile(path: string): Promise<string>;
215
+ writeFile(path: string, content: string): Promise<void>;
216
+ deleteFile(path: string): Promise<void>;
217
+ createDir(path: string): Promise<void>;
218
+ exists(path: string): Promise<boolean>;
219
+ isDirectory(path: string): Promise<boolean>;
220
+ isFile(path: string): Promise<boolean>;
221
+ stat(path: string): Promise<FileMetadata>;
222
+ readDir(path: string): Promise<string[]>;
223
+ }
224
+
225
+ /**
226
+ * Speculative parallel attempts — a primitive uniquely cheap on a SWAPPABLE VFS.
227
+ *
228
+ * Fork the workspace into N copy-on-write overlays of the same `base`, run an attempt in
229
+ * each (independently — writes stay in each overlay, the base is untouched), score them,
230
+ * then COMMIT the best overlay into the base and DISCARD the losers (they leave no trace).
231
+ * Use it to race several approaches/seeds for a flaky or multi-path task and keep only the
232
+ * winner — something agents on a real, non-forkable filesystem can't do without copying the
233
+ * whole tree. Pairs naturally with subagents (each attempt is a child Agent over its overlay).
234
+ *
235
+ * `score` returns a higher-is-better number, or null to disqualify (e.g. failed grading).
236
+ */
237
+ interface Attempt<R> {
238
+ index: number;
239
+ fs: OverlayFilesystem;
240
+ result: R;
241
+ score: number | null;
242
+ }
243
+ declare function raceAttempts<R>(base: IFilesystem, n: number, run: (fs: IFilesystem, index: number) => Promise<R>, score: (a: {
244
+ fs: OverlayFilesystem;
245
+ result: R;
246
+ index: number;
247
+ }) => Promise<number | null> | number | null): Promise<{
248
+ winner: Attempt<R> | null;
249
+ attempts: Attempt<R>[];
250
+ }>;
251
+
252
+ /**
253
+ * Tool synthesis — compile a NEW agent tool from a spec the model authored. The unbounded
254
+ * frontier of self-evolution: the agent invents its own capabilities.
255
+ *
256
+ * SAFETY (this is the load-bearing part). A synthesized tool's `code` is arbitrary JS that
257
+ * runs IN-PROCESS over the agent's filesystem, so before compiling we statically REJECT a
258
+ * denylist of escape vectors (process/require/import/eval/Function/constructor/__proto__/
259
+ * globalThis/Bun/fetch/network/timers/WebAssembly/infinite-loops/…). A compiled tool sees
260
+ * ONLY its `args` and `ctx` (whose fs is the JailedFilesystem — boundary A); combined with
261
+ * the Agent's timeout/tool-call kill-switches this is defensible. Residual risk remains for
262
+ * a determined denylist bypass, so synthesized tools are OPT-IN and should additionally be
263
+ * self-tested in the sandbox (boundary B) before being trusted in a live loop. See mind/08.
264
+ */
265
+ interface ToolSpec {
266
+ name: string;
267
+ description: string;
268
+ parameters: object;
269
+ /** body of `async (args, ctx) => { … return <string> }` — may use args + ctx.fs ONLY. */
270
+ code: string;
271
+ }
272
+ /** Static safety gate. Returns the matched escape vectors (empty = code is allowed). */
273
+ declare function validateToolCode(code: string): {
274
+ ok: boolean;
275
+ violations: string[];
276
+ };
277
+ /**
278
+ * Compile a spec into an AgentTool — THROWS if the code fails the static safety gate.
279
+ * The body runs as `async (args, ctx) => { <code> }`; only `args` and `ctx` are in scope.
280
+ */
281
+ declare function compileSynthesizedTool(spec: ToolSpec): AgentTool;
282
+
283
+ /**
284
+ * Deterministic test/dev double for an ai.libx.js AIClient. Plays a scripted
285
+ * queue of ChatResponses (tool_calls then a final answer). Records each
286
+ * ChatOptions it saw so tests can assert tools were advertised and tool
287
+ * results were threaded back. No network, no API key.
288
+ */
289
+ declare class FakeAIClient implements ChatLike {
290
+ seen: ChatOptions[];
291
+ private script;
292
+ constructor(script: ChatResponse[]);
293
+ chat(options: ChatOptions): Promise<ChatResponse>;
294
+ }
295
+ /** Build a tool_call block (arguments JSON-stringified, matching the wire format). */
296
+ declare const toolCall: (id: string, name: string, args: object) => ToolCall;
297
+
298
+ /**
299
+ * In-process scheduler — timers that fire prompts into the agent loop while the session is alive.
300
+ * Three trigger modes: one-off ({at}), interval ({everyMs}), cron ({cron}).
301
+ * The scheduler never calls `turn()` itself — it invokes an IoC `fire` callback with due jobs,
302
+ * keeping it testable and host-agnostic. Persistence is the host's responsibility (serialize jobs
303
+ * into the session and re-arm on resume).
304
+ *
305
+ * Survives --resume (host reloads); does NOT survive process exit (no daemon, no launchd).
306
+ */
307
+ type TriggerOneOff = {
308
+ at: number;
309
+ };
310
+ type TriggerInterval = {
311
+ everyMs: number;
312
+ };
313
+ type TriggerCron = {
314
+ cron: string;
315
+ };
316
+ type Trigger = TriggerOneOff | TriggerInterval | TriggerCron;
317
+ type ScheduledJobStatus = 'active' | 'done';
318
+ interface ScheduledJob {
319
+ id: string;
320
+ prompt: string;
321
+ trigger: Trigger;
322
+ status: ScheduledJobStatus;
323
+ created: number;
324
+ lastRun?: number;
325
+ runs: number;
326
+ /** Optional label for display (e.g. footer, /schedule list). */
327
+ label?: string;
328
+ }
329
+ /** Serializable snapshot for session persistence (same shape — kept as an alias for clarity at call sites). */
330
+ type ScheduledJobSnapshot = ScheduledJob;
331
+ interface SchedulerOptions {
332
+ /** Called when a job is due. Must not throw — the scheduler logs errors and continues. */
333
+ fire: (job: ScheduledJob) => Promise<void> | void;
334
+ /** Monotonic clock override for testing (default: Date.now). */
335
+ now?: () => number;
336
+ /** Tick interval in ms (default: 15_000 — 15s). */
337
+ tickMs?: number;
338
+ /** If true, suppress the setInterval (for unit tests that call tick() manually). */
339
+ manual?: boolean;
340
+ }
341
+ interface CronFields {
342
+ minute: number[];
343
+ hour: number[];
344
+ dom: number[];
345
+ month: number[];
346
+ dow: number[];
347
+ }
348
+ declare function parseCron(expr: string): CronFields;
349
+ declare function cronMatches(fields: CronFields, date: Date): boolean;
350
+ /** Next occurrence of `cron` after `after` (epoch ms). Returns epoch ms, or null if >366 days out (guard). */
351
+ declare function nextCronAfter(cron: string, after: number): number | null;
352
+ declare class Scheduler {
353
+ private jobs;
354
+ private seq;
355
+ private timer;
356
+ private firing;
357
+ private readonly fire;
358
+ private readonly now;
359
+ private readonly tickMs;
360
+ constructor(opts: SchedulerOptions);
361
+ /** Start the tick timer. Idempotent. */
362
+ start(): void;
363
+ /** Stop the tick timer. Does not clear jobs. */
364
+ stop(): void;
365
+ /** Add a scheduled job. Returns the job id. */
366
+ add(opts: {
367
+ prompt: string;
368
+ trigger: Trigger;
369
+ label?: string;
370
+ }): string;
371
+ /** Cancel a job. Returns false if not found. */
372
+ cancel(id: string): boolean;
373
+ get(id: string): ScheduledJob | undefined;
374
+ list(): ScheduledJob[];
375
+ active(): ScheduledJob[];
376
+ /** Compute when a job next fires (epoch ms), or null if done/unknown. */
377
+ nextFire(job: ScheduledJob): number | null;
378
+ /** Check all active jobs and fire any that are due. Reentrant-safe. */
379
+ tick(): Promise<void>;
380
+ /** Export all jobs for session persistence. */
381
+ snapshot(): ScheduledJobSnapshot[];
382
+ /** Restore jobs from a snapshot (e.g. on --resume). Clears existing jobs first. */
383
+ restore(snapshots: ScheduledJobSnapshot[]): void;
384
+ /** Number of active jobs. */
385
+ get size(): number;
386
+ destroy(): void;
387
+ }
388
+
389
+ /** Narrow seam to an OS-level scheduler backend (jobs that survive quit/reboot). Node hosts wire
390
+ * the CLI's `OsScheduler` (launchd/cron/at); absent => everything stays in-process. Edge-safe:
391
+ * this module only sees the interface. */
392
+ interface OsBackend {
393
+ sessionId: string;
394
+ cwd: string;
395
+ /** 'os' when the trigger should outlive the session (per hint/heuristic). */
396
+ route(trigger: Trigger, backendHint?: string): 'session' | 'os';
397
+ /** Register with the OS. Returns a mechanism description (e.g. 'launchd:…'). Throws on failure. */
398
+ schedule(spec: {
399
+ id: string;
400
+ prompt: string;
401
+ sessionId: string;
402
+ cwd: string;
403
+ trigger: Trigger;
404
+ label?: string;
405
+ }): string;
406
+ cancel(id: string): boolean;
407
+ list(): Array<{
408
+ id: string;
409
+ label?: string;
410
+ mechanism: string;
411
+ trigger: Trigger;
412
+ }>;
413
+ }
414
+ declare function makeScheduleTools(scheduler: Scheduler, os?: OsBackend): AgentTool[];
415
+
416
+ /** Sandbox mode: an in-memory VFS — the real disk is never read or written. Edge/browser/test/dry-run. */
417
+ declare function sandboxAgentOptions(opts?: Partial<AgentOptions>): Partial<AgentOptions>;
418
+ /** Disk mode (the default): operate on the real filesystem, jailed to cwd (secrets hidden by DEFAULT_DENY).
419
+ * Omitting `fs` lets the Agent lazily resolve the jailed disk — this preset just makes the intent explicit
420
+ * (and is where you'd thread overrides). Pass an explicit `fs` to use a different backend. */
421
+ declare function diskAgentOptions(opts?: Partial<AgentOptions>): Partial<AgentOptions>;
422
+ /** Full mode: disk + a real `/bin/sh` tool (run installed binaries — git, bun, node, …) plus its
423
+ * background-job companions. NODE-ONLY: the real-shell module is dynamic-imported so this file stays
424
+ * edge-safe to import. `cwd` defaults to `process.cwd()`; secret env is scrubbed from spawned children. */
425
+ declare function fullAgentOptions(opts?: Partial<AgentOptions> & {
426
+ cwd?: string;
427
+ }): Promise<Partial<AgentOptions>>;
428
+
429
+ /** List paths matching a glob, sorted — the structured alternative to `find`. */
430
+ declare const globTool: AgentTool;
431
+ /** Search file contents by regex, returning typed `path:line:text` hits with optional context. */
432
+ declare const grepTool: AgentTool;
433
+ /**
434
+ * Compact map of a VFS — code signatures and/or doc outlines. Edge-safe (pure IFilesystem walk).
435
+ * `mode`: "code" (default) = top-level signatures; "docs" = heading outlines; "all" = both.
436
+ */
437
+ declare function repoIndex(fs: IFilesystem, glob?: string, mode?: 'code' | 'docs' | 'all', signal?: AbortSignal): Promise<string>;
438
+ /** Compact map of the codebase or document workspace — orient in ONE call, not many. */
439
+ declare const repoMapTool: AgentTool;
440
+ /** Create or overwrite a file, creating parent directories as needed (mkdir -p). */
441
+ declare const writeTool: AgentTool;
442
+ /** Apply an ordered list of exact-substring edits to one file in a single call. */
443
+ declare const multiEditTool: AgentTool;
444
+ /**
445
+ * Cross-file batch edit — the multi-file refactor primitive. One call edits MANY files:
446
+ * each entry with an `old_string` replaces that exact, UNIQUE substring (read fresh + verified,
447
+ * so NO prior Read is needed — locate the sites with Grep, whose output is the text to match);
448
+ * each entry WITHOUT `old_string` writes `new_string` as the whole file (creates it + parent dirs).
449
+ * Validate-all-before-write → atomic across files. Collapses "Grep + N×(Read+Edit)" into "Grep + ApplyEdits".
450
+ */
451
+ declare const applyEditsTool: AgentTool;
452
+ /** mkdir -p over the VFS (idempotent, top-down). */
453
+ declare function mkdirp(fs: IFilesystem, dir: string): Promise<void>;
454
+
455
+ /** Strip HTML to readable text — dependency-free: drop script/style/comments, block tags → newlines, decode common entities. */
456
+ declare function htmlToText(html: string): string;
457
+ interface WebFetchOptions {
458
+ /** Override the global fetch (tests inject a mock; edge runtimes can supply their own). */
459
+ fetch?: typeof globalThis.fetch;
460
+ maxBytes?: number;
461
+ maxChars?: number;
462
+ timeoutMs?: number;
463
+ /** Allow fetching private/loopback/link-local hosts (default false — blocks basic SSRF). */
464
+ allowPrivateHosts?: boolean;
465
+ }
466
+ /** Build a WebFetch tool. */
467
+ declare function makeWebFetchTool(options?: WebFetchOptions): AgentTool;
468
+ interface WebSearchOptions {
469
+ fetch?: typeof globalThis.fetch;
470
+ /** Provider: 'auto' (default) uses Tavily if an API key is present, else keyless DuckDuckGo. */
471
+ provider?: 'auto' | 'tavily' | 'duckduckgo';
472
+ /** API key for Tavily (default: process.env.TAVILY_API_KEY). */
473
+ apiKey?: string;
474
+ /** Tavily endpoint override. */
475
+ endpoint?: string;
476
+ maxResults?: number;
477
+ timeoutMs?: number;
478
+ }
479
+ interface SearchHit {
480
+ title: string;
481
+ url: string;
482
+ snippet: string;
483
+ }
484
+ /** Decode a DuckDuckGo HTML result href: results are `//duckduckgo.com/l/?uddg=<encoded-target>` redirects. */
485
+ declare function decodeDdgUrl(href: string): string;
486
+ /** Parse DuckDuckGo's HTML results page into hits (title/url/snippet) — dependency-free, zips anchors to snippets in order. */
487
+ declare function parseDdgHtml(html: string, max: number): SearchHit[];
488
+ /**
489
+ * Build a WebSearch tool. Keyless by default (DuckDuckGo HTML) so it works in any deployment with
490
+ * no setup; auto-upgrades to Tavily (better, agent-oriented results) when TAVILY_API_KEY is present.
491
+ */
492
+ declare function makeWebSearchTool(options?: WebSearchOptions): AgentTool;
493
+ /** Default instances (registered in the tool registry; opt-in by name). */
494
+ declare const webFetchTool: AgentTool;
495
+ declare const webSearchTool: AgentTool;
496
+
497
+ /**
498
+ * Scratch — keep large tool/subagent outputs OUT of the main context, but queryable AS FILES.
499
+ *
500
+ * Pattern: many-tool / many-subagent engines bloat context with raw outputs (search results, big
501
+ * file reads, subagent reports) that are mostly noise once a gist is taken. Here, a tool wrapped with
502
+ * `Scratch.capture` writes any oversized result to an ephemeral scratch filesystem (a real VFS) and
503
+ * returns a compact stub (path + preview) to context. To recover a buried detail later you do NOT
504
+ * re-bloat context — you peek with the FILE tools already on hand:
505
+ * • Grep/Glob/Read over the scratch dir — returns matching lines, not the blob (a free, light peek).
506
+ * • Ask({question, over?}) — a CHEAP child agent over the scratch FS that greps/reads and returns
507
+ * just the answer; its reasoning tokens never touch the caller's context.
508
+ * Two-tier division of labour: cheap RETRIEVE/EXTRACT, strong caller SYNTHESIZE.
509
+ *
510
+ * The scratch FS is injected (IoC): pass a MemFilesystem for ephemeral, or a disk-backed one under the
511
+ * session dir to persist across resume (CC's lesson: the filesystem is the durable store). Segregated
512
+ * module — zero Agent-core changes.
513
+ */
514
+
515
+ /** Default scratch dir (a path in the injected scratch FS). */
516
+ declare const SCRATCH_DIR = "/scratch";
517
+ interface ScratchOptions {
518
+ /** Min result length (chars) to capture; smaller results pass through untouched. Default 1500. */
519
+ threshold?: number;
520
+ /** Dir within the scratch FS to write captures. Default SCRATCH_DIR. */
521
+ dir?: string;
522
+ /** Chars of the captured output to preview in the stub. Default 320. */
523
+ previewChars?: number;
524
+ }
525
+ /**
526
+ * Owns an (injected) scratch filesystem + a capture counter. `capture(tool)` wraps a tool so its
527
+ * oversized string results spill to a scratch file and are replaced in context with a stub.
528
+ */
529
+ declare class Scratch {
530
+ fs: IFilesystem;
531
+ options: Required<ScratchOptions>;
532
+ private seq;
533
+ private dirReady?;
534
+ constructor(fs: IFilesystem, options?: ScratchOptions);
535
+ /** Number of captures so far. */
536
+ get count(): number;
537
+ /** Wrap a tool: oversized STRING results spill to a scratch file; everything else passes through. */
538
+ capture(tool: AgentTool): AgentTool;
539
+ /** Wrap many tools at once. */
540
+ captureAll(tools: AgentTool[]): AgentTool[];
541
+ /**
542
+ * Spill an oversized tool result to a scratch file and return PAGE 1 + a recoverable, paginated stub.
543
+ * Drop-in for `Agent.capToolResult`: the agent sees usable content immediately and knows how to get
544
+ * the rest (refine the query, Read the file in pages with offset/limit, or Ask to extract specifics).
545
+ * Lossless — unlike a plain crop, the full output stays available on the scratch FS.
546
+ */
547
+ spill(full: string, info: {
548
+ tool: string;
549
+ args: any;
550
+ }, pageBytes?: number): Promise<string>;
551
+ }
552
+ interface AskOptions {
553
+ /** The scratch filesystem to peek into (dedicated VFS holding only scratch files). */
554
+ fs: IFilesystem;
555
+ ai: ChatLike;
556
+ /** Model for the peek — intentionally a CHEAP model; the caller synthesizes. */
557
+ model: string;
558
+ /** Step budget for the peek child (default 6). */
559
+ maxSteps?: number;
560
+ /** Scratch dir to search when `over` is omitted. Default SCRATCH_DIR. */
561
+ dir?: string;
562
+ }
563
+ /**
564
+ * `Ask` — peek into the scratch FS to answer a question WITHOUT loading raw data into the caller's
565
+ * context. Spawns a cheap child agent (Read/Grep/Glob over scratch) that greps/reads and returns just
566
+ * the answer. Pass `over` (a path) for a targeted peek, or omit to grep-discover.
567
+ */
568
+ declare function makeAskTool(o: AskOptions): AgentTool;
569
+
570
+ /**
571
+ * `AskUserQuestion` tool — lets the model pose a structured choice to a human.
572
+ * Delegates to `ctx.host.ask`. Registered only when a HostBridge is provided
573
+ * (autonomous runs don't see it), so it never dead-ends a headless agent.
574
+ */
575
+ declare const askUserQuestionTool: AgentTool;
576
+ /** Deterministic HostBridge for tests/dev: scripts answers + records what was asked. */
577
+ declare class ScriptedHostBridge implements HostBridge {
578
+ private answers;
579
+ private confirmDefault;
580
+ asked: UserQuestion[];
581
+ confirms: string[];
582
+ events: Array<{
583
+ kind: string;
584
+ message: string;
585
+ data?: unknown;
586
+ }>;
587
+ constructor(answers?: string[], confirmDefault?: boolean);
588
+ ask(q: UserQuestion): Promise<string>;
589
+ confirm(prompt: string): Promise<boolean>;
590
+ notify(event: {
591
+ kind: string;
592
+ message: string;
593
+ data?: unknown;
594
+ }): void;
595
+ }
596
+ /** Node CLI HostBridge: prompts on stdin. (node-only host adapter; not edge-safe by design.) */
597
+ declare class ConsoleHostBridge implements HostBridge {
598
+ ask(q: UserQuestion): Promise<string>;
599
+ confirm(prompt: string): Promise<boolean>;
600
+ notify(event: {
601
+ kind: string;
602
+ message: string;
603
+ }): void;
604
+ }
605
+
606
+ interface CommandInfo {
607
+ name: string;
608
+ description: string;
609
+ path: string;
610
+ }
611
+ /**
612
+ * Resolves a name in the *other* half of the merged slash namespace (CC parity: `/x` is one
613
+ * namespace whether `x` is a `commands/x.md` or a `skills/x/SKILL.md`). On a miss in its own
614
+ * registry, a tool calls this to find the sibling and learn how to expand it. Injected by the
615
+ * caller (Agent.prepare) so commands.ts and skills.ts stay mutually decoupled (no circular import).
616
+ */
617
+ type SiblingResolver = (name: string) => Promise<{
618
+ path: string;
619
+ stripFrontmatter: boolean;
620
+ } | undefined>;
621
+ /**
622
+ * Expand a command template's argument placeholders:
623
+ * - `$ARGUMENTS` → all args (every occurrence)
624
+ * - `$1`…`$9` → positional args (whitespace-split; missing → empty)
625
+ * If the body has neither placeholder, `args` is appended as a trailing block (back-compat).
626
+ */
627
+ declare function expandTemplate(body: string, args: string): string;
628
+ /**
629
+ * Read a slash entry's file and return its expanded text: arg placeholders filled, then `@file`
630
+ * refs embedded. `stripFrontmatter` drops the YAML head (commands feed only their body); skills
631
+ * feed the whole SKILL.md (frontmatter is part of the instructions). Shared by commands + skills
632
+ * so both halves of the merged namespace expand identically (CC parity).
633
+ */
634
+ declare function expandEntry(fs: IFilesystem, path: string, args: string, opts?: {
635
+ stripFrontmatter?: boolean;
636
+ }): Promise<string>;
637
+ /** Read a command file and return its expanded body: arg placeholders filled, then `@file` refs embedded. */
638
+ declare function expandCommand(fs: IFilesystem, cmd: CommandInfo, args: string): Promise<string>;
639
+ /**
640
+ * Discover slash commands under `dir` (each `<dir>/<name>.md`) and produce:
641
+ * - `catalog`: a names+descriptions block for the system prompt,
642
+ * - `tool`: a `SlashCommand` tool that returns a command's expanded template body.
643
+ *
644
+ * Commands are reusable prompt templates (like Claude Code slash commands) — just
645
+ * VFS files. The template body is returned (user args appended, and `$ARGUMENTS`
646
+ * substituted if present) so the model can act on it. Mirrors loadSkills.
647
+ */
648
+ /** Scan `dir`(s) for `<dir>/<name>.md` command templates (first dir wins on duplicate names). */
649
+ declare function scanCommands(fs: IFilesystem, dir: string | string[]): Promise<CommandInfo[]>;
650
+ declare function loadCommands(fs: IFilesystem, dir: string | string[], opts?: {
651
+ relevanceHint?: string;
652
+ max?: number;
653
+ sibling?: SiblingResolver;
654
+ }): Promise<{
655
+ commands: CommandInfo[];
656
+ catalog: string;
657
+ tool?: AgentTool;
658
+ }>;
659
+
660
+ interface SkillInfo {
661
+ name: string;
662
+ description: string;
663
+ path: string;
664
+ }
665
+ /**
666
+ * Discover skills under `dir` (each `<dir>/<id>/SKILL.md`) and produce:
667
+ * - `catalog`: a names+descriptions block for the system prompt,
668
+ * - `tool`: a `Skill` tool that returns a skill's full SKILL.md (progressive disclosure).
669
+ *
670
+ * Skills are just VFS files — the Read tool already gives progressive disclosure; this
671
+ * adds the catalog + a convenience tool. (Executable skills can be `bash`-exec'd: wcli
672
+ * runs JS files from the VFS as commands.)
673
+ */
674
+ /** Scan `dir`(s) for `<dir>/<id>/SKILL.md` entries (first dir wins on duplicate ids). */
675
+ declare function scanSkills(fs: IFilesystem, dir: string | string[]): Promise<SkillInfo[]>;
676
+ declare function loadSkills(fs: IFilesystem, dir: string | string[], opts?: {
677
+ relevanceHint?: string;
678
+ max?: number;
679
+ sibling?: SiblingResolver;
680
+ }): Promise<{
681
+ skills: SkillInfo[];
682
+ catalog: string;
683
+ tool?: AgentTool;
684
+ }>;
685
+
686
+ /**
687
+ * Lexical relevance — no deps, deterministic, edge-safe. Ranks catalog entries (skills,
688
+ * commands, memories, docs) by a task hint so a LARGE catalog doesn't dump every entry into
689
+ * the prompt. TF-IDF weighted: rare terms in the corpus score higher than common ones.
690
+ */
691
+ /** Lowercased alphanumeric tokens of length ≥ 3, minus a few stopwords. */
692
+ declare function tokenize(s: string): Set<string>;
693
+ /** Build IDF weights from a corpus of texts. Rare terms get higher weight. */
694
+ declare function idfWeights(corpus: string[]): Map<string, number>;
695
+ /** TF-IDF weighted relevance score. Without IDF, falls back to flat token overlap (backward-compatible). */
696
+ declare function relevanceScore(text: string, queryTokens: Set<string>, idf?: Map<string, number>): number;
697
+ /**
698
+ * Split `items` into the `k` most relevant to `query` (by TF-IDF overlap with `text(item)`)
699
+ * and the rest, preserving each item's original order within its group. Returns everything in
700
+ * `kept` (empty `rest`) when `items.length <= k` or `query` is blank — so it's a no-op for
701
+ * small lists. When `corpus` is provided, builds IDF weights for better ranking.
702
+ */
703
+ declare function topByRelevance<T>(items: T[], query: string, text: (x: T) => string, k: number, corpus?: string[]): {
704
+ kept: T[];
705
+ rest: T[];
706
+ };
707
+
708
+ /** Behavioral guidance injected alongside the memory index — adapted from CC's battle-tuned prose, for our tool-based workflow. */
709
+ declare const MEMORY_PROMPT: string;
710
+ /** Voice-specific memory guidance — shorter, spoken-interaction tuned. */
711
+ declare const VOICE_MEMORY_PROMPT: string;
712
+ /**
713
+ * Load memory for injection at run start (the recall step), with progressive disclosure:
714
+ * - `index`: the compact `<dir>/MEMORY.md` index, injected into the system prompt — cheap,
715
+ * always-hot. Each line points at a fact file the agent can pull on demand.
716
+ * - `tools`: `Recall` (load one fact body on demand — keeps facts COLD until needed) and
717
+ * `Remember` (persist a durable fact + index pointer mid-run — the WRITE half that closes
718
+ * the learning loop: what the agent learns now steers future sessions).
719
+ *
720
+ * Persistence is the BACKEND's job, for free: NodeDiskFilesystem → disk,
721
+ * IndexedDbFilesystem → browser, (planned) BodDbFilesystem → database. The same
722
+ * memory mechanism therefore works in node, a browser tab, or on edge.
723
+ */
724
+ interface LoadMemoryOpts {
725
+ relevanceHint?: string;
726
+ max?: number;
727
+ /** Max Remember calls per session (default 25). Prevents runaway memory writes. */
728
+ maxWritesPerSession?: number;
729
+ /** Called after each successful memory write (auditing, UI indicators). */
730
+ onMemorySaved?: (slug: string, type?: string) => void;
731
+ /** User-scope dir for global memories (type=user/feedback). If set, Remember routes by type:
732
+ * user/feedback → userDir (global, survives across projects), project/reference → writeDir. */
733
+ userDir?: string;
734
+ }
735
+ declare function loadMemory(fs: IFilesystem, dir: string | string[], opts?: LoadMemoryOpts): Promise<{
736
+ index: string;
737
+ tools: AgentTool[];
738
+ }>;
739
+ /** Slugify free text into a safe kebab filename stem (no separators, bounded). */
740
+ declare function slugify(s: string, fallback?: string): string;
741
+ /**
742
+ * Persist a durable fact: write `<dir>/<slug>.md` and ensure a one-line pointer exists in
743
+ * `<dir>/MEMORY.md` (created if missing). Idempotent on the index (won't duplicate a pointer).
744
+ * This is the shared write path behind the `Remember` tool and automatic lesson capture.
745
+ */
746
+ declare function writeFact(fs: IFilesystem, dir: string, slug: string, body: string, opts?: {
747
+ type?: string;
748
+ description?: string;
749
+ }): Promise<void>;
750
+
751
+ /**
752
+ * Automatic mistake → lesson → steer loop. Closes the within-run learning gap: the agent
753
+ * reacting to an error string is transient, but a RECURRING failure is a signal worth keeping.
754
+ * This hook watches tool results for known failure patterns; once the SAME pattern recurs
755
+ * `minRepeats` times in a run, it persists a corrective lesson to memory (deduped) — so the
756
+ * NEXT session's `loadMemory` injects it as steering. Deterministic, edge-safe, no LLM call.
757
+ *
758
+ * Writes immediately on crossing the threshold (not on a clean stop), so a loop/budget kill —
759
+ * exactly the runs that wasted effort — still leaves a lesson behind.
760
+ */
761
+ interface LessonOptions {
762
+ fs: IFilesystem;
763
+ /** Memory dir to persist lessons into (same dir loadMemory reads). */
764
+ dir: string;
765
+ /** How many times a pattern must recur before it's worth remembering. */
766
+ minRepeats: number;
767
+ }
768
+ declare class LessonOptionsDefaults implements Partial<LessonOptions> {
769
+ minRepeats: number;
770
+ }
771
+ /**
772
+ * Build a Hooks object that auto-captures recurring failures as memory lessons.
773
+ * Compose it with the host's own hooks via `composeHooks`.
774
+ */
775
+ declare function lessonCapture(options: LessonOptions): Hooks;
776
+
777
+ /**
778
+ * One-shot LLM reflection on a finished run. The deterministic `lessonCapture` hook only
779
+ * knows OUR pre-mapped failure patterns; reflection catches NOVEL mistakes — it reads a digest
780
+ * of what the run actually did and, if there's a durable lesson, persists it to memory so the
781
+ * next session is steered. Costs exactly ONE model call, so it's meant for runs that went badly
782
+ * (loop / budget / max_steps), not every run. Opt-in. Returns the slug written, or null.
783
+ */
784
+ interface ReflectOptions {
785
+ ai: ChatLike;
786
+ model: string;
787
+ /** Filesystem + memory dir to persist the lesson into (same dir loadMemory reads). */
788
+ fs: IFilesystem;
789
+ dir: string;
790
+ /** The finished run to reflect on. */
791
+ result: RunResult;
792
+ /** Bound the reflection prompt (chars of run digest). */
793
+ maxDigestChars?: number;
794
+ }
795
+ declare function reflectOnRun(o: ReflectOptions): Promise<string | null>;
796
+
797
+ /**
798
+ * Walk the VFS directory tree from `/` down, collecting instruction files
799
+ * (AGENT.md, AGENTS.md, CLAUDE.md, .claude/<name>) at each level.
800
+ * Merges all found files general-first → specific-last (mirrors Claude Code's
801
+ * hierarchical CLAUDE.md discovery). First matching filename per directory wins
802
+ * (no duplicates from the same level). Edge-portable: works over any IFilesystem.
803
+ */
804
+ declare function loadInstructions(fs: IFilesystem, names?: string[]): Promise<string>;
805
+
806
+ /**
807
+ * DuplexAgent — voice-optimized three-tier conversational engine, composed on top of `Agent`.
808
+ *
809
+ * Three cognitive tiers (like a human brain):
810
+ * REFLEX — fast voice agent (streams instant replies, owns THE transcript, the only voice the
811
+ * user hears). Handles simple questions, routes complex work to Act or Think.
812
+ * ACT — standard worker (Sonnet-class). Full tools, file access, shell. The hands.
813
+ * THINK — premium reasoning (Opus-class). Deep analysis, architecture, hard problems. The brain.
814
+ *
815
+ * Workers are spawned per escalation via `Act`/`Think` tools. Results are pushed back as
816
+ * `[task <id> completed] …` events and re-voiced by the reflex — push, not poll.
817
+ *
818
+ * Host events (via the open HostEvent union): the voice agent's standard `text_delta` stream,
819
+ * plus `task_started` / `task_progress` / `task_done` / `task_error` / `task_cancelled`.
820
+ */
821
+
822
+ type DuplexTaskStatus = 'running' | 'done' | 'error' | 'cancelled';
823
+ interface TaskRecord {
824
+ id: string;
825
+ label: string;
826
+ status: DuplexTaskStatus;
827
+ controller: AbortController;
828
+ /** Settles when the worker finished AND its completion was processed. Never rejects. */
829
+ promise: Promise<void>;
830
+ /** Rolling activity tail (tool calls + last-result previews, capped) — feeds task inspection UIs. */
831
+ tail: string[];
832
+ /** Final report text (or error message) once the task settled. */
833
+ result?: string;
834
+ }
835
+ type WorkerTier = 'act' | 'think';
836
+ declare class DuplexAgentOptions {
837
+ /** Any ai.libx.js AIClient — shared by all tiers (routed by model). */
838
+ ai: ChatLike;
839
+ /** The WORKER's filesystem (act + think). If omitted the worker keeps Agent's jailed-disk-at-cwd default. */
840
+ fs?: IFilesystem;
841
+ reflexModel: string;
842
+ actModel: string;
843
+ /** Premium reasoning model. Set to `false` to disable the Think tier entirely. */
844
+ thinkModel: string | false;
845
+ /** Per-worker providerOptions, derived from the worker's actual model at spawn time (IoC — keeps duplex
846
+ * provider-agnostic). Workers override the reflex/main model, so provider-specific options (e.g. cursor's
847
+ * cwd/cursorSession) must be recomputed for the worker's model, never inherited from the main template —
848
+ * leaking cursor options to an anthropic worker is a hard 400. Returns undefined → no providerOptions. */
849
+ providerOptionsFor?: (model: string) => Record<string, unknown> | undefined;
850
+ /** Escape hatches merged over the derived per-agent options. */
851
+ reflexOptions?: Partial<AgentOptions>;
852
+ actOptions?: Partial<AgentOptions>;
853
+ thinkOptions?: Partial<AgentOptions>;
854
+ /** Fresh-context check on each successful Act task: a NEW agent (no self-confirmation bias) re-reads
855
+ * the file state against the brief and fixes any gap before the result is re-voiced. Bounded to one
856
+ * pass; ~2x Act cost so default OFF. The self-verify FOOTER (same context) was measured ineffective —
857
+ * this is the structural fix (see mind/10). Think tasks are pure reasoning, never checked. */
858
+ verifyActTasks: boolean;
859
+ /** Receives the voice text_delta stream + task lifecycle events. */
860
+ host?: HostBridge;
861
+ /** How many recent transcript messages are rendered into a worker's brief. */
862
+ excerptTurns: number;
863
+ /** Voice register: 'neutral' = clean spoken style; 'conversational' = human-like — fillers,
864
+ * backchannels, impulsive first reactions before content (mimics real duplex conversation). */
865
+ voiceStyle: 'neutral' | 'conversational';
866
+ /** Awaited BEFORE a worker spawns — open a per-task checkpoint frame, audit, etc.
867
+ * (post-spawn would race the worker's first edits). */
868
+ onTaskStart?: (id: string, label: string) => void | Promise<void>;
869
+ /** Re-voice throttled worker progress asides ('[task t1 progress] …') so long tasks aren't dead
870
+ * air. Off by default — each update costs a voice turn (LLM call + speech). */
871
+ progressUpdates: boolean;
872
+ /** Min ms between progress re-voices per task. */
873
+ progressIntervalMs: number;
874
+ /** Relay worker questions (AskUserQuestion + permission asks via parkQuestion) through the VOICE:
875
+ * the question re-voices as '[task <id> asks] …', the user answers conversationally, and the
876
+ * voice model resolves it with the AnswerTask tool. Off → host.ask passthrough (text menus). */
877
+ askRelay: boolean;
878
+ /** Parked questions auto-resolve empty after this long (callers map '' to deny/best-judgment). */
879
+ askTimeoutMs: number;
880
+ /** Max retained task records: oldest SETTLED tasks (and their activity tails) are evicted past this,
881
+ * bounding memory over a long-lived session. Running tasks are never evicted. */
882
+ maxTaskRecords: number;
883
+ /** Host overrides for QuickLook lookups (keyed by `what`). The engine's defaults go through the
884
+ * (possibly jailed) fs — e.g. `.git/**` is deny-listed, so the CLI supplies 'branch' itself. */
885
+ quickLook?: Record<string, (path?: string) => string | Promise<string>>;
886
+ /** Memory directory/directories on the WORKER fs. If set, the voice agent gets Remember + Recall
887
+ * tools directly (no delegation needed) and implicit capture guidance. */
888
+ memoryDir?: string | string[];
889
+ /** User-scope memory dir for global facts (type=user/feedback). Forwarded to Remember's routing. */
890
+ memoryUserDir?: string;
891
+ }
892
+ declare const VOICE_SYSTEM_PROMPT: string;
893
+ /**
894
+ * The duplex orchestrator. `send()` enqueues a user turn on the reflex agent; `Act`/`Think`
895
+ * spawn detached workers whose completions enqueue re-voice turns. A promise-chain
896
+ * mutex serializes all voice turns so streams never interleave, and completions that
897
+ * pile up while the voice is busy are coalesced into a single re-voice turn.
898
+ */
899
+ declare class DuplexAgent {
900
+ options: DuplexAgentOptions;
901
+ readonly voice: Agent;
902
+ readonly tasks: Map<string, TaskRecord>;
903
+ private queue;
904
+ private seq;
905
+ private pendingEvents;
906
+ private flushQueued;
907
+ /** Per-voice-turn guards (reset by resetTurn at each turn's start). The reflex is a weak model:
908
+ * left unguarded it polls TaskStatus after a dispatch and/or dispatches silently (dead air).
909
+ * Like CC's Task tool, a dispatch is "said my piece, now wait for the push" — these enforce that. */
910
+ private turnDispatched;
911
+ private turnBriefs;
912
+ private spokeThisTurn;
913
+ private nudging;
914
+ private reflexBuf;
915
+ private reflexForwarded;
916
+ private fabricationCut;
917
+ /** Parked worker questions awaiting a (voice-relayed) user answer, keyed by ask id. */
918
+ readonly pendingAsks: Map<string, {
919
+ question: string;
920
+ resolve: (answer: string) => void;
921
+ }>;
922
+ /** Lazily resolved memory tools (async loadMemory runs in initMemory). */
923
+ private memoryReady;
924
+ constructor(options?: Partial<DuplexAgentOptions>);
925
+ /** Resolve memory tools + inject index into voice system prompt (once). */
926
+ private initMemory;
927
+ /** Clear the per-turn guards. Called at the head of every voice turn (user send + re-voice flush). */
928
+ private resetTurn;
929
+ /** preToolUse guard on the reflex: once it has dispatched this turn, a dispatch is "said my piece,
930
+ * now wait for the push" (CC's Task model). Block the temptations — TaskStatus polling and identical
931
+ * re-dispatch — so the only remaining move is to voice a short ack and end. A genuinely NEW Act is
932
+ * still allowed (parallel independent work). During a re-ack pass, block every tool. */
933
+ private dispatchGuard;
934
+ /** True when the just-finished turn dispatched a task but voiced nothing — dead air to repair.
935
+ * Requires a host: without one there's no stream to detect speech on (and no one to speak to). */
936
+ private get silentDispatch();
937
+ /** A dispatch with no spoken text is dead air. Re-prompt the reflex ONCE so the LLM itself voices a
938
+ * short ack (no template). If it STILL says nothing, fall back to a minimal line so silence never ships. */
939
+ private ackIfSilent;
940
+ /** One user turn: the voice agent streams the reply (and may Act/Think). Serialized with re-voice turns. */
941
+ send(content: MessageContent): Promise<RunResult>;
942
+ /** Cancel a running background task — shared by the CancelTask tool and the CLI /tasks picker. */
943
+ cancelTask(id: string): string;
944
+ /** Resolve when all queued voice turns AND all in-flight worker tasks have settled (tests, graceful shutdown). */
945
+ idle(): Promise<void>;
946
+ /** Promise-chain mutex: turns run strictly one at a time; a failed turn doesn't poison the chain. */
947
+ private enqueue;
948
+ private notify;
949
+ /** Queue a `[task …]` event for re-voicing. Events arriving while the voice is busy coalesce into ONE turn. */
950
+ private queueRevoice;
951
+ /** The worker's brief: the Act/Think args + a STATIC text snapshot of the recent conversation.
952
+ * Act briefs get a self-verify footer — the worker's report is trusted without review, so it
953
+ * must check its own work before reporting (nearly free under prompt caching; measured honest:
954
+ * it does NOT fix one-shot logic bugs — see mind/10). Think tasks are pure reasoning — no footer. */
955
+ private buildBrief;
956
+ /** Spawn a detached worker for task `id`; its settlement notifies + enqueues the re-voice turn. */
957
+ private spawnWorker;
958
+ /** Fresh-context check of a successful Act task: a NEW agent (same model/fs/tools, but NO shared
959
+ * conversation context) re-reads the file state against the brief and fixes any gap. The fix lands
960
+ * on the shared fs automatically (workers write fs directly, no overlay), so grading sees the
961
+ * corrected state. Bounded to ONE pass. Off unless `verifyActTasks`; never runs for think/failed/
962
+ * cancelled tasks. Usage is merged so /cost reflects the real (worker + checker) spend. */
963
+ private maybeVerify;
964
+ /** Throttled per-task progress: worker tool calls → at most one progress re-voice per interval.
965
+ * Two sources, one throttle: completed steps (post) and a heartbeat for a SINGLE long tool call
966
+ * (pre records the in-flight call; a self-cleaning timer narrates "still inside Bash — 70s").
967
+ * Completion supersedes: nothing is emitted once the task has settled. */
968
+ private progressReporter;
969
+ /** Park a question under `askId` (a task id, or any unique key for permission asks): re-voices
970
+ * '[task <id> asks] …' and resolves with the user's answer via AnswerTask — or '' on timeout/
971
+ * task settle (callers map '' to deny / best-judgment). Workers never block forever. */
972
+ parkQuestion(askId: string, question: string): Promise<string>;
973
+ /** Resolve any question a settling/cancelled task left parked (its answer can no longer matter). */
974
+ private dropAsk;
975
+ private onWorkerSettled;
976
+ private onWorkerFailed;
977
+ private failTask;
978
+ /** Live-switch the think tier: `false` disables (removes the Think tool from the voice agent),
979
+ * a model id enables (adds the tool if missing). The system-prompt THINK_SLOT text is frozen at
980
+ * construction — the tool's own description carries the routing guidance, so a live enable works;
981
+ * dispatch()'s think→act fallback covers any straggler calls after a live disable. */
982
+ setThinkModel(model: string | false): void;
983
+ /** User/programmatic spawn: the CLI's /act and /think commands. Returns the task id. */
984
+ dispatch(brief: string, tier?: WorkerTier, label?: string): Promise<string>;
985
+ private actTool;
986
+ private thinkTool;
987
+ private taskStatusTool;
988
+ /** Sub-100ms read-only lookups the voice may do itself — everything else stays Act-only.
989
+ * fs-only (no shell; the engine is VFS-abstracted): time, git branch (.git/HEAD read), ls, file
990
+ * head. Output is hard-capped so a lookup can never bloat the skinny voice context. */
991
+ private quickLookTool;
992
+ private answerTaskTool;
993
+ private holdTool;
994
+ private cancelTaskTool;
995
+ }
996
+
997
+ /**
998
+ * Typed subagents — named child-agent definitions from `<dir>/<name>.md`, each with a
999
+ * description, an optional model + tool allowlist (frontmatter), and a system prompt (the
1000
+ * body). The `Task` tool's `agentType` selects one, so a delegated sub-task runs with its
1001
+ * own persona, model, and scoped tools — the Claude-Code `.claude/agents` model.
1002
+ * VFS-backed (edge-portable), mirroring loadSkills / loadCommands.
1003
+ */
1004
+ interface AgentDef {
1005
+ name: string;
1006
+ description: string;
1007
+ /** The .md body — used as the child's system prompt (overrides the default). */
1008
+ systemPrompt?: string;
1009
+ /** Optional model override for this subagent type. */
1010
+ model?: string;
1011
+ /** Optional tool-name allowlist (scopes the child's tools). */
1012
+ tools?: string[];
1013
+ }
1014
+ /** Discover subagent definitions under `dir` and a catalog block for the system prompt. */
1015
+ declare function loadAgents(fs: IFilesystem, dir: string): Promise<{
1016
+ agents: AgentDef[];
1017
+ catalog: string;
1018
+ }>;
1019
+
1020
+ interface TaskToolOptions {
1021
+ /** The same ai.libx.js client the parent uses — the child shares it. */
1022
+ ai: ChatLike;
1023
+ model: string;
1024
+ /** The filesystem the child operates over (jail/scope it before passing, if desired). */
1025
+ fs: IFilesystem;
1026
+ /** Step budget for the child run (independent of the parent's). */
1027
+ maxSteps?: number;
1028
+ /** Recursion depth of the child this tool would spawn (0 = first level). */
1029
+ depth?: number;
1030
+ /** Hard ceiling on nesting — beyond this the tool refuses to spawn. */
1031
+ maxDepth?: number;
1032
+ /** Named subagent types selectable via the `agentType` param (persona + model + scoped tools). */
1033
+ agents?: AgentDef[];
1034
+ /** Max children running concurrently in a `TaskBatch` (default 4). */
1035
+ maxParallel?: number;
1036
+ /** Parent hooks — `onSubagentStop` fires with each child's summary when it finishes. */
1037
+ hooks?: Hooks;
1038
+ }
1039
+ /**
1040
+ * `Task` tool — spawn a CHILD agent over the same VFS with its own step budget,
1041
+ * returning only its final summary to the parent. Use to fan out a self-contained
1042
+ * sub-task (search, refactor a subtree) without polluting the parent's context.
1043
+ * @returns the child's final text, or an error string if the depth limit is reached.
1044
+ */
1045
+ declare function makeTaskTool(opts: TaskToolOptions): AgentTool;
1046
+ /**
1047
+ * `TaskBatch` tool — fan out several self-contained sub-tasks to child agents that run
1048
+ * **concurrently** (bounded pool), returning all their summaries together. Each child runs over its
1049
+ * OWN `OverlayFilesystem` (write-isolated from siblings), and successful children's edits are
1050
+ * committed **in array order** afterward — so concurrent writes resolve deterministically
1051
+ * (last index wins) instead of racing. Use to parallelize independent work (review N files, search M
1052
+ * subtrees, scoped refactors). For a single sub-task, use `Task`.
1053
+ */
1054
+ declare function makeTaskBatchTool(opts: TaskToolOptions): AgentTool;
1055
+
1056
+ /** Component-scoped logger (libx.js). debug/verbose gated via DEBUG env/localStorage. */
1057
+ declare const forComponent: (name: string) => libx_js_src_modules_log.ComponentLogger;
1058
+
1059
+ /**
1060
+ * Portable voice I/O contracts — zero platform imports. The engine, STT and TTS clients in this
1061
+ * directory run anywhere with a `WebSocket` global (Bun, Node, browser); platform backends
1062
+ * (mic capture, audio playback) plug in through these seams.
1063
+ */
1064
+ type VoiceState = 'idle' | 'listening' | 'thinking' | 'speaking';
1065
+ /** STT input sample format — sources MUST deliver this (downsample/convert in the adapter). */
1066
+ declare const STT_SAMPLE_RATE = 16000;
1067
+ /** Playback format the TTS requests and sinks must play. */
1068
+ declare const TTS_SAMPLE_RATE = 44100;
1069
+ /** A microphone (or any PCM) source. Emits s16le mono 16kHz chunks.
1070
+ * Node: mic-aec/ffmpeg child process. Web: getUserMedia({ echoCancellation: true }) + worklet. */
1071
+ interface AudioSource {
1072
+ /** `aec` = the source is echo-cancelled (assistant's own TTS never reaches the chunks) —
1073
+ * selects the engine's trivial barge-in path vs the heuristic echo tier. */
1074
+ readonly aec: boolean;
1075
+ start(onChunk: (pcm: Uint8Array) => void): void | Promise<void>;
1076
+ stop(): void;
1077
+ }
1078
+ /** An audio playback sink for s16le mono 44.1kHz PCM.
1079
+ * Node: per-turn ffplay. Web: AudioContext/worklet ring buffer. */
1080
+ interface AudioSink {
1081
+ /** start a new spoken turn (may recycle or recreate the underlying player) */
1082
+ markTurn(): void;
1083
+ write(pcm: Uint8Array): void;
1084
+ /** estimated ms until queued audio finishes playing */
1085
+ drainMs(): number;
1086
+ /** ms of audio actually played this turn */
1087
+ playedMs(): number;
1088
+ /** stop playback NOW (barge-in primitive) */
1089
+ kill(): void;
1090
+ /** optional exact-sample pause/resume — enables the overlap trail-off tier (web: AudioContext
1091
+ * suspend/resume; CLI AEC helper: control frames). Sinks without it degrade to interrupt-only
1092
+ * turn-taking. Nothing is lost across a pause; playedMs/drainMs must exclude paused time. */
1093
+ pause?(): void;
1094
+ resume?(): void;
1095
+ }
1096
+ /** Static key (server/CLI) or an async getter (browser: fetch a short-lived token from YOUR
1097
+ * backend). Getters are invoked on EVERY (re)connect — temp tokens expire, so a reconnect
1098
+ * must re-mint, never reuse the boot-time token. */
1099
+ type AuthProvider = string | (() => string | Promise<string>);
1100
+ declare function resolveAuth(auth: AuthProvider): Promise<string>;
1101
+
1102
+ /** Structural contracts (satisfied by SonioxSTT/CartesiaTTS or test fakes). */
1103
+ interface SttLike {
1104
+ usingAec: boolean;
1105
+ onPartial: (text: string) => void;
1106
+ onUtterance: (text: string, endpointAt: number) => void;
1107
+ onLevel: (rms: number) => void;
1108
+ start(): Promise<void> | void;
1109
+ reset(): void;
1110
+ stop(): void;
1111
+ }
1112
+ interface TtsLike {
1113
+ onAudio: (chunk: Uint8Array) => void;
1114
+ onDone: () => void;
1115
+ connect(): Promise<void> | void;
1116
+ newContext(): string;
1117
+ speak(text: string, cont: boolean): void;
1118
+ end(): void;
1119
+ cancel(): void;
1120
+ close(): void;
1121
+ }
1122
+ declare class VoiceEngineOptions {
1123
+ stt: SttLike;
1124
+ tts: TtsLike;
1125
+ player: AudioSink;
1126
+ /** a final utterance arrived (endpoint) — host dispatches it as a turn */
1127
+ onUtterance: (text: string) => void;
1128
+ /** live partial transcript while listening (host renders the 🎤 line) */
1129
+ onPartial: (text: string) => void;
1130
+ onState: (s: VoiceState) => void;
1131
+ /** user spoke/acted over playback — host aborts the in-flight turn (called AFTER audio is killed).
1132
+ * phase: 'speaking' = cut mid-speech (real interruption); 'drain' = in the final audio tail
1133
+ * (normal turn-taking — hosts shouldn't alarm). */
1134
+ onBargeIn: (phase: 'speaking' | 'drain') => void;
1135
+ /** spoken micro-ack on utterance endpoint (masks LLM TTFT); '' disables */
1136
+ ackPhrase: string;
1137
+ /** Endpoint merge window (ms): hold an endpointed utterance briefly — if speech resumes (spelled
1138
+ * letters, mid-thought pauses), the next utterance MERGES instead of dispatching a truncated one
1139
+ * ("E-L-Y." / "A."). Costs this much latency per turn; 0 disables. */
1140
+ utteranceMergeMs: number;
1141
+ /** Extended merge window (ms) for utterances that look incomplete (trailing conjunction/filler).
1142
+ * Gives the user time to finish their thought without triggering a model call. */
1143
+ incompleteMergeMs: number;
1144
+ /** Filler phrase spoken when holding for an incomplete utterance ('' disables). */
1145
+ holdFiller: string;
1146
+ /** Called when the engine holds an incomplete utterance (host can render a visual cue). */
1147
+ onHold: () => void;
1148
+ /** heuristic (non-AEC) energy barge-in tuning */
1149
+ bargeRmsMult: number;
1150
+ bargeRmsFloor: number;
1151
+ /** Overlap turn-taking (AEC tier, needs player.pause/resume) — human phone-call model, driven by
1152
+ * the STT ITSELF (a trained speech classifier) instead of energy thresholds (energy could not
1153
+ * separate residue bursts from speech in every room — hiccup whack-a-mole): partial text while
1154
+ * speaking → PAUSE (exact-sample hold); partial grows into dominant-novel ≥2 words → cede
1155
+ * (interrupt; the LLM re-enters); partial stalls/endpoints without ceding (backchannel by
1156
+ * DURATION, not vocabulary) → resume + drop. false disables. */
1157
+ overlapPause: boolean;
1158
+ /** no new partial activity for this long while paused → resume, drop the interjection */
1159
+ overlapResumeMs: number;
1160
+ /** A genuine barge over a LONG reply is defeated by the dominant-novel gate: Meet echoes our own
1161
+ * speech back, so the partial is mostly our words + a few of hers → never "dominant novel" → it
1162
+ * resumes (replaying old audio — the audible "completes the buffer" blip) instead of ceding.
1163
+ * Mechanism-based discriminator: a re-PAUSE this soon after a resume = a persistent human, not an
1164
+ * echo blip (which pauses once and stalls). Cede on the re-pause regardless of the novel gate. */
1165
+ overlapRepauseCedeMs: number;
1166
+ }
1167
+ declare class VoiceEngine {
1168
+ options: VoiceEngineOptions;
1169
+ state: VoiceState;
1170
+ protected stt: SttLike;
1171
+ protected tts: TtsLike;
1172
+ protected player: AudioSink;
1173
+ private speaking;
1174
+ private ctxOpen;
1175
+ private interrupted;
1176
+ private spokeDeltas;
1177
+ private drainTimer;
1178
+ private echoWords;
1179
+ private prevReply;
1180
+ private reply;
1181
+ private echoUntil;
1182
+ private baseline;
1183
+ private hot;
1184
+ private suspectUntil;
1185
+ private ackAt;
1186
+ private pendingUtt;
1187
+ private pendingTimer;
1188
+ private lastInterrupted;
1189
+ private pausedAt;
1190
+ private lastResumeAt;
1191
+ private lastOverlapPartial;
1192
+ private resumeTimer;
1193
+ private turnStartAt;
1194
+ constructor(options?: Partial<VoiceEngineOptions>);
1195
+ start(): Promise<void>;
1196
+ get usingAec(): boolean;
1197
+ private idleWaiters;
1198
+ private setState;
1199
+ /** Resolve when the engine is no longer speaking (immediate if already idle). */
1200
+ awaitIdle(): Promise<void>;
1201
+ /** open a spoken turn (idempotent — safe from both onUtterance and first-delta paths).
1202
+ * `ack` speaks the configured micro-ack as the context opener (utterance path only —
1203
+ * masks LLM TTFT; re-voice turns begun by their first delta skip it). */
1204
+ beginSpeech(ack?: boolean): void;
1205
+ speakDelta(text: string): void;
1206
+ /** close the spoken turn (idempotent); stays audible until ALL audio arrived AND playback drains */
1207
+ endSpeech(): void;
1208
+ /** text of the reply cut by the last barge-in — consumed by the host to tell the model what
1209
+ * the user did NOT hear. Cleared on read. */
1210
+ takeInterruptedReply(): {
1211
+ full: string;
1212
+ heard: string;
1213
+ } | null;
1214
+ /** Speak a short filler phrase without starting a model turn (stays in listening mode after). */
1215
+ speakFiller(text: string): void;
1216
+ /** barge-in: stop audio NOW, cancel generation, reset for the user's utterance */
1217
+ interrupt(): void;
1218
+ stop(): void;
1219
+ private words;
1220
+ private novelWords;
1221
+ private echoActive;
1222
+ /** Genuine user speech vs our own bleed (AEC tier): novel words must DOMINATE, not merely exist.
1223
+ * Degraded AEC + an STT mis-hearing manufactures a single novel word out of pure echo (a name or
1224
+ * rare word in our own reply comes back transcribed slightly differently — 1 novel / N words).
1225
+ * A real interjection is mostly novel ("stop", "wait what") — short utterances pass on ratio,
1226
+ * longer ones on count. */
1227
+ private genuine;
1228
+ private handlePartial;
1229
+ private static readonly TRAIL_RE;
1230
+ /** The utterance sounds like the user paused mid-thought (trailing conjunction/filler/comma). */
1231
+ private looksIncomplete;
1232
+ private handleUtterance;
1233
+ private flushUtterance;
1234
+ private get overlapCapable();
1235
+ private armResume;
1236
+ private resetOverlap;
1237
+ /** energy two-stage barge-in (heuristic tier only): spike over echo baseline → pause + confirm via STT */
1238
+ private gatePassTimes;
1239
+ private handleLevel;
1240
+ }
1241
+
1242
+ declare class SonioxSTTOptions {
1243
+ auth: AuthProvider;
1244
+ source: AudioSource;
1245
+ model: string;
1246
+ languageHints: string[];
1247
+ /** Client-side endpoint: finalized text + no new tokens for this long = utterance (don't wait for
1248
+ * Soniox's semantic <end>, which adds 0.5-1.5s — the difference between ping-pong and lag). */
1249
+ silenceEndpointMs: number;
1250
+ }
1251
+ declare class SonioxSTT {
1252
+ options: SonioxSTTOptions;
1253
+ private ws;
1254
+ private stopped;
1255
+ private sourceStarted;
1256
+ onPartial: (text: string) => void;
1257
+ onUtterance: (text: string, endpointAt: number) => void;
1258
+ /** mic energy (RMS) per chunk — drives the energy-based heuristic barge-in tier */
1259
+ onLevel: (rms: number) => void;
1260
+ private finalText;
1261
+ private partialText;
1262
+ private lastChangeAt;
1263
+ private lastCombined;
1264
+ private endpointTimer;
1265
+ private firstTokenAt;
1266
+ constructor(options?: Partial<SonioxSTTOptions>);
1267
+ get usingAec(): boolean;
1268
+ private connectWs;
1269
+ start(): Promise<void>;
1270
+ private handle;
1271
+ reset(): void;
1272
+ stop(): void;
1273
+ }
1274
+
1275
+ declare class CartesiaTTSOptions {
1276
+ auth: AuthProvider;
1277
+ voiceId: string;
1278
+ model: string;
1279
+ /** 'apiKey' (server/CLI) → `api_key=` URL param; 'token' (browser, BE-minted) → `access_token=`. */
1280
+ authMode: 'apiKey' | 'token';
1281
+ }
1282
+ declare class CartesiaTTS {
1283
+ options: CartesiaTTSOptions;
1284
+ private ws;
1285
+ private ctxSeq;
1286
+ ctxId: string;
1287
+ onAudio: (chunk: Uint8Array) => void;
1288
+ onDone: () => void;
1289
+ firstAudioAt: number;
1290
+ /** Circuit breaker: consecutive error count + down flag. */
1291
+ private consecutiveErrors;
1292
+ private consecutiveOk;
1293
+ private down;
1294
+ private downAt;
1295
+ private probeTimer;
1296
+ private static readonly CB_THRESHOLD;
1297
+ private static readonly CB_RECOVER_OK;
1298
+ private static readonly CB_PROBE_MS;
1299
+ constructor(options?: Partial<CartesiaTTSOptions>);
1300
+ private closed;
1301
+ private connecting;
1302
+ connect(): Promise<void>;
1303
+ private doConnect;
1304
+ /** Close the breaker only after CB_RECOVER_OK consecutive good frames, so a single straggler chunk
1305
+ * after a 503 burst doesn't flap open→recover in <1s. A sub-2s down-window is a transient blip → debug. */
1306
+ private markRecovered;
1307
+ /** Ensure the WS is open before sending — reconnects if idle-closed. */
1308
+ private ensureConnected;
1309
+ newContext(): string;
1310
+ private frame;
1311
+ speak(text: string, cont: boolean): void;
1312
+ end(): void;
1313
+ cancel(): void;
1314
+ private startProbe;
1315
+ private stopProbe;
1316
+ close(): void;
1317
+ }
1318
+
1319
+ export { Agent, type AgentDef, AgentOptions, AgentTool, type AskOptions, type Attempt, type AudioSink, type AudioSource, type AuthProvider, BodDbFilesystem, CartesiaTTS, CartesiaTTSOptions, ChatLike, ChatOptions, ChatResponse, type CommandInfo, ConsoleHostBridge, DEFAULT_DENY, DuplexAgent, DuplexAgentOptions, type DuplexTaskStatus, FakeAIClient, Hooks, HostBridge, JailOptions, JailedFilesystem, type LessonOptions, LessonOptionsDefaults, type LoadMemoryOpts, MEMORY_PROMPT, MessageContent, type Mount, MountFilesystem, NodeDiskFilesystem, OverlayFilesystem, type ReflectOptions, RunResult, SCRATCH_DIR, STT_SAMPLE_RATE, type ScheduledJob, type ScheduledJobSnapshot, Scheduler, type SchedulerOptions, Scratch, type ScratchOptions, ScriptedHostBridge, type SiblingResolver, type SkillInfo, SonioxSTT, SonioxSTTOptions, type SttLike, TTS_SAMPLE_RATE, type TaskRecord, type TaskToolOptions, ToolCall, type ToolSpec, type Trigger, type TriggerCron, type TriggerInterval, type TriggerOneOff, type TtsLike, UserQuestion, VOICE_MEMORY_PROMPT, VOICE_SYSTEM_PROMPT, VoiceEngine, VoiceEngineOptions, type VoiceState, type WebFetchOptions, type WebSearchOptions, type WorkerTier, applyEditsTool, askUserQuestionTool, checkpointTool, checkpointTools, compileSynthesizedTool, cronMatches, decodeDdgUrl, diskAgentOptions, expandCommand, expandEntry, expandTemplate, forComponent, fullAgentOptions, globTool, grepTool, htmlToText, idfWeights, lessonCapture, loadAgents, loadCommands, loadInstructions, loadMemory, loadSkills, makeAskTool, makeScheduleTools, makeTaskBatchTool, makeTaskTool, makeWebFetchTool, makeWebSearchTool, mkdirp, multiEditTool, nextCronAfter, parseCron, parseDdgHtml, raceAttempts, reflectOnRun, relevanceScore, repoIndex, repoMapTool, resolveAuth, rollbackTool, sandboxAgentOptions, scanCommands, scanSkills, slugify, tokenize, toolCall, topByRelevance, validateToolCode, webFetchTool, webSearchTool, writeFact, writeTool };