@zaly/agent 0.0.3

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.
Files changed (77) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +50 -0
  3. package/dist/agent-BaD2kax9.mjs +68 -0
  4. package/dist/agent-BaD2kax9.mjs.map +1 -0
  5. package/dist/agent-GDLdDc2w.mjs +902 -0
  6. package/dist/agent-GDLdDc2w.mjs.map +1 -0
  7. package/dist/bash-QNMTQ1PD.mjs +142 -0
  8. package/dist/bash-QNMTQ1PD.mjs.map +1 -0
  9. package/dist/compactions-3AjPqjeZ.mjs +190 -0
  10. package/dist/compactions-3AjPqjeZ.mjs.map +1 -0
  11. package/dist/edit-Qxl4w1C2.mjs +170 -0
  12. package/dist/edit-Qxl4w1C2.mjs.map +1 -0
  13. package/dist/env-UUFv5Mye.mjs +30 -0
  14. package/dist/env-UUFv5Mye.mjs.map +1 -0
  15. package/dist/fetch-D8cmmA3E.mjs +111 -0
  16. package/dist/fetch-D8cmmA3E.mjs.map +1 -0
  17. package/dist/find-Bah9SKWX.mjs +87 -0
  18. package/dist/find-Bah9SKWX.mjs.map +1 -0
  19. package/dist/grep-B2Ax7ewy.mjs +244 -0
  20. package/dist/grep-B2Ax7ewy.mjs.map +1 -0
  21. package/dist/index-node-esm-D6YQRKEz.mjs +1537 -0
  22. package/dist/index-node-esm-D6YQRKEz.mjs.map +1 -0
  23. package/dist/index.d.mts +1605 -0
  24. package/dist/index.d.mts.map +1 -0
  25. package/dist/index.mjs +948 -0
  26. package/dist/index.mjs.map +1 -0
  27. package/dist/jsonl-Dw_VBp46.mjs +134 -0
  28. package/dist/jsonl-Dw_VBp46.mjs.map +1 -0
  29. package/dist/manager-D-lWBTHG.mjs +271 -0
  30. package/dist/manager-D-lWBTHG.mjs.map +1 -0
  31. package/dist/markdown-Bv4J8cg3.mjs +53 -0
  32. package/dist/markdown-Bv4J8cg3.mjs.map +1 -0
  33. package/dist/masker-Bv9KjkDF.mjs +396 -0
  34. package/dist/masker-Bv9KjkDF.mjs.map +1 -0
  35. package/dist/model-_3ZA2xqm.mjs +27 -0
  36. package/dist/model-_3ZA2xqm.mjs.map +1 -0
  37. package/dist/notify-DpG_m9iP.mjs +96 -0
  38. package/dist/notify-DpG_m9iP.mjs.map +1 -0
  39. package/dist/read-Djsx2NZl.mjs +205 -0
  40. package/dist/read-Djsx2NZl.mjs.map +1 -0
  41. package/dist/registry-CFmR5G3J.mjs +564 -0
  42. package/dist/registry-CFmR5G3J.mjs.map +1 -0
  43. package/dist/search-CRw247ES.mjs +121 -0
  44. package/dist/search-CRw247ES.mjs.map +1 -0
  45. package/dist/session/claude.d.mts +59 -0
  46. package/dist/session/claude.d.mts.map +1 -0
  47. package/dist/session/claude.mjs +455 -0
  48. package/dist/session/claude.mjs.map +1 -0
  49. package/dist/session-CUUdWFC5.mjs +450 -0
  50. package/dist/session-CUUdWFC5.mjs.map +1 -0
  51. package/dist/session-Ds5nJz5A.d.mts +346 -0
  52. package/dist/session-Ds5nJz5A.d.mts.map +1 -0
  53. package/dist/session.d.mts +37 -0
  54. package/dist/session.d.mts.map +1 -0
  55. package/dist/session.mjs +106 -0
  56. package/dist/session.mjs.map +1 -0
  57. package/dist/subagent-baqzjRMc.mjs +136 -0
  58. package/dist/subagent-baqzjRMc.mjs.map +1 -0
  59. package/dist/swarm-BJ3gQA1Z.mjs +194 -0
  60. package/dist/swarm-BJ3gQA1Z.mjs.map +1 -0
  61. package/dist/swarm-BuFx_xeY.mjs +109 -0
  62. package/dist/swarm-BuFx_xeY.mjs.map +1 -0
  63. package/dist/tasks-D8rARHZ1.mjs +65 -0
  64. package/dist/tasks-D8rARHZ1.mjs.map +1 -0
  65. package/dist/tasks-WmC270X2.mjs +615 -0
  66. package/dist/tasks-WmC270X2.mjs.map +1 -0
  67. package/dist/tools-DW1dbcCz.mjs +695 -0
  68. package/dist/tools-DW1dbcCz.mjs.map +1 -0
  69. package/dist/truncate-BSMXgiXj.mjs +102 -0
  70. package/dist/truncate-BSMXgiXj.mjs.map +1 -0
  71. package/dist/uuid-ByXP5SO5.mjs +59 -0
  72. package/dist/uuid-ByXP5SO5.mjs.map +1 -0
  73. package/dist/wakeup-BYqTnfSp.mjs +29 -0
  74. package/dist/wakeup-BYqTnfSp.mjs.map +1 -0
  75. package/dist/write-D3L-92vj.mjs +89 -0
  76. package/dist/write-D3L-92vj.mjs.map +1 -0
  77. package/package.json +63 -0
@@ -0,0 +1,1605 @@
1
+ import { p as SessionOptions, t as Session } from "./session-Ds5nJz5A.mjs";
2
+ import { Emitter, Envelope, MaybeGetter } from "@zaly/shared";
3
+ import { BaseCollection } from "@zaly/shared/collection";
4
+ import { AnyKey } from "@zaly/shared/registry";
5
+ import { AiError, AnyPart, AnyType, AssistantMessage, CollectOptions, Content, FinishReason, Message, MetaOf, MetaPart, Model, ParamsOf, ReasoningEffort, Role, StreamEvent, StreamOptions, TokenCount as TokenCount$1, Tool, ToolCallPart, ToolContext, ToolResult, ToolResultPart, Usage } from "@zaly/ai";
6
+ import { Logger } from "@zaly/shared/logger";
7
+ import { ArgsOpts, ArgsResult } from "@zaly/shared/args";
8
+ //#region src/events.d.ts
9
+ /** Status of an agent session — at most one transition per moment.
10
+ * `paused` covers both explicit pause and post-error states; the
11
+ * `lastError` field on the session disambiguates. */
12
+ type AgentStatus = "idle" | "streaming" | "running-tools" | "compacting" | "paused";
13
+ /** Reason the loop stopped this turn. Distinct from the provider's
14
+ * `finishReason` (which describes why one round-trip ended). */
15
+ type AgentStopKind = "natural" | "max-steps" | "token-budget" | "loop-detected" | "max-tool-errors" | "context-overflow" | "paused" | "aborted" | "error";
16
+ /** Outcome kind of a single step (one provider round-trip + tool batch).
17
+ * Returned from `step()` so custom drivers can interleave their own
18
+ * logic between steps. */
19
+ type StepKind = "natural" | "tool-calls" | "context-overflow" | "error";
20
+ type AgentStop = {
21
+ kind: AgentStopKind;
22
+ reason?: string;
23
+ error?: Error;
24
+ };
25
+ /** Events emitted by an `Agent` as the loop runs. Listeners fire
26
+ * synchronously; a throw inside a listener is caught and routed to
27
+ * `onEmitError` so the loop keeps running.
28
+ *
29
+ * Conversation-shape events (new message committed, head moved, …)
30
+ * live on the `Session`, not here — subscribe via `agent.session.on(…)`. */
31
+ type AgentEvents = {
32
+ status: {
33
+ status: AgentStatus;
34
+ };
35
+ start: {};
36
+ "stream-event": {
37
+ event: StreamEvent;
38
+ };
39
+ "tool-call": {
40
+ call: ToolCallPart;
41
+ };
42
+ "tool-calls": {
43
+ calls: ToolCallPart[];
44
+ };
45
+ "tool-result": {
46
+ call: ToolCallPart;
47
+ result: ToolResult;
48
+ };
49
+ "step-start": {
50
+ step: number;
51
+ };
52
+ "step-end": {
53
+ step: number;
54
+ outcome: StepKind;
55
+ };
56
+ "turn-start": {
57
+ turn: number;
58
+ };
59
+ "turn-end": {
60
+ turn: number;
61
+ outcome: AgentStopKind;
62
+ reason?: string;
63
+ };
64
+ stop: AgentStop & {
65
+ usage: TokenCount$1;
66
+ status: AgentStatus;
67
+ };
68
+ context: {
69
+ prompt: string[];
70
+ tools: Tool[];
71
+ messages: Message[];
72
+ };
73
+ pending: {
74
+ messages: Message[];
75
+ };
76
+ };
77
+ //#endregion
78
+ //#region src/masker.d.ts
79
+ /** Top-level masking config. */
80
+ type MaskerOptions = {
81
+ enabled?: boolean;
82
+ /** Don't mask tool-result parts whose original content is shorter
83
+ * than this (estimated tokens). Skips tiny "ok"-style success
84
+ * messages where the stub would be larger than the original.
85
+ * Doesn't apply to attachments (always worth masking). */
86
+ minTokens?: number;
87
+ /** How many turns to keep in the tail of the conversation, regardless
88
+ * of score. Defaults to 20. */
89
+ keepTurns?: number;
90
+ /** How far above the target ratio to trigger a new masking pass.
91
+ * Defaults to 0.25 (25%). */
92
+ delta?: number;
93
+ /** Target ratio of used/limit tokens to reach by masking. Defaults to 0.5 (50%). */
94
+ target?: number;
95
+ };
96
+ type MaskOpts = {
97
+ force?: boolean;
98
+ limit?: number;
99
+ ratio?: number;
100
+ tools?: Tool[];
101
+ prompt?: string[];
102
+ };
103
+ /** In-place mask projection for the request stream.
104
+ *
105
+ * The masker replaces low-value parts with stable stubs to keep the
106
+ * projected request within budget. A scoring pass ranks maskable parts
107
+ * by recency, repeated-use shadowing, and per-policy weights; the budget
108
+ * pass masks from lowest score upward until the target is reached or no
109
+ * useful candidates remain.
110
+ *
111
+ * Masking intentionally happens rarely because it changes historical
112
+ * bytes and busts prefix cache. The first pass after startup/session
113
+ * reset always rebuilds the projection. Later passes use a hysteresis
114
+ * threshold: mask toward `target`, then trigger again at roughly
115
+ * `actual + delta`. If the target cannot be reached, the next threshold
116
+ * rises automatically to avoid repeated no-op cache busts.
117
+ */
118
+ declare class Masker {
119
+ #private;
120
+ constructor(agent: Agent, opts?: MaybeGetter<MaskerOptions>);
121
+ get enabled(): boolean;
122
+ reset(): void;
123
+ get stats(): Map<Role, Record<string, number>>;
124
+ /** Number of messages with at least one masked part. */
125
+ get masked(): number;
126
+ isMasked(msgId: string, partIdx?: number): boolean;
127
+ /** Apply masks and return the projected message array.
128
+ *
129
+ * Always rebuild once after startup/session reset: `pressure.ratio`
130
+ * may describe a previously masked projection, while this instance has
131
+ * no mask decisions yet. After that, rebuild only when projected
132
+ * pressure crosses the hysteresis threshold. */
133
+ mask(messages: readonly Message[], opts?: MaskOpts): Promise<Message[]>;
134
+ }
135
+ //#endregion
136
+ //#region src/permissions/types.d.ts
137
+ /**
138
+ * Core permission primitives.
139
+ *
140
+ * - `Rule<T>` is the policy unit — pattern + verdict, scoped to a kind
141
+ * of resource (`bash`, `read`, `write`, …).
142
+ * - `PermissionHandler<T>` is the validator for one or more scopes; the
143
+ * manager dispatches `validate()` to the right handler.
144
+ * - `PermissionContext<T>` is what the handler sees on each call:
145
+ * the matched `scope`, the rules pre-filtered to that scope, plus any
146
+ * shared data (e.g. workspace directories) that the manager exposes
147
+ * to all handlers.
148
+ *
149
+ * Scopes are open strings — built-ins are `bash | read | write | fetch`,
150
+ * but plugins register their own. `PermissionHandler<"a" | "b">` lets
151
+ * one impl handle multiple related scopes (e.g. `FileHandler` for both
152
+ * `read` and `write`, sharing workspace state via the context).
153
+ */
154
+ type Verdict = "allow" | "deny" | "ask";
155
+ type Rule<T extends string = string> = {
156
+ scope: T;
157
+ pattern: string;
158
+ policy: Verdict;
159
+ };
160
+ /** A handler-proposed action the user can promote (the matching pattern
161
+ * / containing path that *would* have allowed the input). The handler
162
+ * describes "what would have matched"; the UI picks the polarity
163
+ * ("allow once", "allow always", "deny always") and writes the rule
164
+ * back through the appropriate manager API.
165
+ *
166
+ * - `kind: "rule"` → suggests adding a `Rule<scope>` with this pattern.
167
+ * - `kind: "workspace"` → suggests adding a workspace directory; only
168
+ * handlers operating over paths emit this.
169
+ */
170
+ type Suggestion = {
171
+ kind: "rule";
172
+ scope: string;
173
+ pattern: string;
174
+ description?: string;
175
+ } | {
176
+ kind: "workspace";
177
+ path: string;
178
+ description?: string;
179
+ };
180
+ type CheckResult = {
181
+ verdict: "allow";
182
+ } | {
183
+ verdict: "deny";
184
+ reason: string;
185
+ /** Optional hints for the prompt UI. Each suggestion describes a
186
+ * pattern/path that would have matched the input; the UI offers
187
+ * polarity buttons ("allow once" / "allow always" / "deny always")
188
+ * and applies the user's choice via the manager. */
189
+ suggestions?: Suggestion[];
190
+ } | {
191
+ verdict: "ask";
192
+ reason: string;
193
+ ask: string;
194
+ suggestions?: Suggestion[];
195
+ };
196
+ interface PermissionContext<T extends string> {
197
+ /** The matched scope. Useful when a handler covers multiple scopes
198
+ * (e.g. `FileHandler` for `"read" | "write"`) and wants to branch. */
199
+ scope: T;
200
+ /** Rules pre-filtered to `scope` by the manager. */
201
+ rules: readonly Rule<T>[];
202
+ /** Workspace directories shared across handlers — file scopes use
203
+ * these as containment roots; bash uses them for cwd-aware checks.
204
+ * All paths are absolute and pre-normalized. The session cwd is
205
+ * always included as the first entry. */
206
+ workspaces: readonly string[];
207
+ /** Session cwd — absolute, pinned at manager construction. Use this
208
+ * to resolve relative paths in `input`; never read `process.cwd()`
209
+ * directly from a handler. */
210
+ cwd: string;
211
+ /** Re-enter the manager to validate a different scope. Used by
212
+ * composite handlers — e.g. the bash handler delegates `<` redirects
213
+ * and inferred file paths to `ctx.validate("read", path)` rather
214
+ * than carrying file-rule logic itself. */
215
+ validate: (scope: string, input: string) => CheckResult;
216
+ }
217
+ interface PermissionHandler<T extends string> {
218
+ validate(input: string, ctx: PermissionContext<T>): CheckResult;
219
+ }
220
+ //#endregion
221
+ //#region src/permissions/presets.d.ts
222
+ /**
223
+ * Permission presets — verdict-keyed pattern lists in the same shape
224
+ * `parseRules` accepts. The TUI exposes these as `--preset strict`,
225
+ * `--preset readonly`, etc.; the manager resolves the chosen preset to
226
+ * the structured `Rule<string>[]` at construction.
227
+ *
228
+ * Pattern grammar:
229
+ * "bash(ls:*)" → bash command pattern
230
+ * "read(/src/**)" → workspace-relative gitignore pattern
231
+ * "read(*)" → matches every read in any workspace
232
+ * "bash" → bare scope, equivalent to `bash(*)` (match any cmd)
233
+ *
234
+ * Scope names are exact matches against the tool name they gate
235
+ * (snake_case). Underscored scopes work too (`task_stop`, `task_poll`).
236
+ */
237
+ type PermissionPresetName = "strict" | "readonly" | "permissive" | "yolo";
238
+ interface PermissionPreset {
239
+ description: string;
240
+ rules: Partial<Record<Verdict, string[]>>;
241
+ }
242
+ //#endregion
243
+ //#region src/permissions/manager.d.ts
244
+ type PermissionOptions = {
245
+ /** Session cwd — anchor for resolving relative paths and the default
246
+ * spawn cwd for bash subprocesses. Pinned at construction; the agent
247
+ * never mutates `process.cwd()`, and there's no `cd` tool. Defaults
248
+ * to `process.cwd()`. */
249
+ cwd?: string;
250
+ /** Named preset — supplies a baseline rule set. Explicit `rules` win
251
+ * over preset rules on conflict (first-match-wins resolution; user
252
+ * rules are listed before preset rules at construction). */
253
+ preset?: PermissionPresetName;
254
+ rules?: Rule[] | Partial<Record<Verdict, string[] | undefined>>;
255
+ /** Initial workspace list. `cwd` is auto-added so the user doesn't
256
+ * have to repeat it. Pass paths absolute (or relative — they'll be
257
+ * resolved against `cwd`). */
258
+ workspaces?: readonly string[];
259
+ };
260
+ /**
261
+ * Owns per-session permission state and dispatches `validate(scope, input)`
262
+ * to the registered handler for `scope`. Handlers receive rules
263
+ * pre-filtered to their scope plus the shared workspace list.
264
+ *
265
+ * Mutators (`addWorkspace`, `addRule`, …) are how the prompt UI promotes
266
+ * an `ask` verdict — once the user picks "allow `Bash(git push:*)` for
267
+ * this session", the TUI calls `manager.addRule(...)` and subsequent
268
+ * `validate()` calls pick it up via the filter.
269
+ */
270
+ declare class PermissionManager {
271
+ #private;
272
+ readonly cwd: string;
273
+ constructor(opts?: PermissionOptions);
274
+ get workspaces(): readonly string[];
275
+ addWorkspace(path: string): void;
276
+ removeWorkspace(path: string): void;
277
+ get rules(): readonly Rule[];
278
+ /** Rules whose scope has no registered handler — surfaces config
279
+ * errors (typos, unknown scopes, malformed pattern strings). The TUI
280
+ * can render these as a startup warning. */
281
+ get invalidRules(): readonly Rule[];
282
+ addRule(rule: Rule): void;
283
+ validate(scope: string, input: string): CheckResult;
284
+ }
285
+ //#endregion
286
+ //#region src/skills.d.ts
287
+ type SkillMeta = {
288
+ name: string;
289
+ mtime: number;
290
+ desc: string;
291
+ path: string;
292
+ unchanged?: boolean;
293
+ };
294
+ type SkillTool = Tool<{
295
+ name: string;
296
+ }, unknown, SkillMeta>;
297
+ /**
298
+ * Agent Skills support — discovery, catalog, and the activation tool.
299
+ *
300
+ * Locations scanned (subdirectories containing `SKILL.md`):
301
+ * - `${cwd}/.agent/skills/` — project
302
+ * - `${homedir()}/.agent/skills/` — user (cross-project)
303
+ *
304
+ * Project shadows user on name collision.
305
+ *
306
+ * Progressive disclosure (per the Agent Skills spec):
307
+ * - Catalog (name + description) lives in the tool's schema /
308
+ * description. The model sees this from the start.
309
+ * - Body of the SKILL.md is loaded only when the tool is invoked.
310
+ * - References (files under the skill's directory) are *enumerated*
311
+ * at activation, not read — the model reads them via the `read`
312
+ * tool when its instructions call for it.
313
+ *
314
+ * Lifecycle:
315
+ * - Construct with `new Skills({ cwd })` — no I/O yet.
316
+ * - Call `await skills.load()` to populate the catalog. Idempotent;
317
+ * re-call to pick up newly installed skills (`/reload-plugins`).
318
+ * - `skills.tool` returns the current activation tool, or undefined
319
+ * when the catalog is empty. Lazily built; invalidated on reload.
320
+ */
321
+ interface SkillEntry {
322
+ name: string;
323
+ desc: string;
324
+ mtime: number;
325
+ body: string;
326
+ /** Absolute path to the SKILL.md file. */
327
+ path: string;
328
+ /** Absolute path to the skill's base directory (parent of SKILL.md).
329
+ * Used as the workspace anchor for permissions and as the root for
330
+ * resolving references. */
331
+ dir: string;
332
+ }
333
+ interface SkillsOptions {
334
+ /** SKILL.md paths, sorted from highest to lowest precedence. */
335
+ paths?: string[];
336
+ }
337
+ declare class Skills {
338
+ #private;
339
+ readonly catalog: Map<string, SkillEntry>;
340
+ protected constructor(opts?: SkillsOptions);
341
+ static load(opts?: SkillsOptions): Promise<Skills>;
342
+ /** (Re)scan project + user `.agent/skills/` directories. Wipes the
343
+ * current catalog and the cached tool, then repopulates. Safe to
344
+ * call mid-session — agent uses `this.tool` per-step so the next
345
+ * request after reload picks up the change. */
346
+ reload(): Promise<this>;
347
+ /** Skill base directories — pass each to `agent.permissions.addWorkspace`
348
+ * so the model can read bundled `references/` files without tripping
349
+ * permission asks. */
350
+ get dirs(): readonly string[];
351
+ /** The activation tool. Returns `undefined` when the catalog is empty
352
+ * (the agent then omits skills entirely from the model's tool list,
353
+ * per the spec). Lazily built on first access; invalidated by
354
+ * `load()`. */
355
+ get tool(): Tool | undefined;
356
+ isActivated(skill: SkillEntry, ctx: ToolContext<SkillMeta>): Promise<boolean>;
357
+ activate(name: string, agent: Agent): Promise<{
358
+ call: import("@zaly/ai").ToolCallPart<string, {
359
+ name: string;
360
+ }>;
361
+ result: import("@zaly/ai").ToolResult<SkillMeta>;
362
+ messages: [import("@zaly/ai").Message<"system">, import("@zaly/ai").Message<"assistant">, import("@zaly/ai").Message<"tool">];
363
+ } | undefined>;
364
+ }
365
+ //#endregion
366
+ //#region src/swarm.d.ts
367
+ /** A registered agent in the swarm — a node in the agent tree. The
368
+ * `name` IS the id: agents address each other by name, so there's no
369
+ * point in maintaining a separate uuid the model would have to
370
+ * remember. Collisions get an auto-suffix (`reviewer`, `reviewer-2`,
371
+ * `reviewer-3`, …) resolved at `attach` time; reading `entry.name`
372
+ * after attach tells the caller which suffix landed. The parent
373
+ * relationship lives on `agent.parent` — single source of truth. */
374
+ interface SwarmEntry {
375
+ /** Unique identity within the swarm. Same string as `name` (kept as
376
+ * a separate field for code that wants to be explicit about "this
377
+ * is the lookup key vs. the displayable name"). */
378
+ id: string;
379
+ /** Resolved name (with collision suffix if needed). What other
380
+ * agents type when addressing this one. */
381
+ name: string;
382
+ desc: string;
383
+ agent: Agent;
384
+ /** Wallclock at registration. */
385
+ startedAt: number;
386
+ }
387
+ /** Options for spawning a new subagent via `Swarm.spawn`. */
388
+ interface SpawnOptions {
389
+ /** Human-readable identity for inter-agent addressing — e.g.
390
+ * `"reviewer"`, `"researcher"`. Other agents reference the spawned
391
+ * agent by this name in `<agent>` meta tags. */
392
+ name: string;
393
+ /** What this agent is doing (one short line). Surfaced in
394
+ * `task_list` / `<agent>` headers so the orchestrator can keep
395
+ * track of who's working on what. */
396
+ desc: string;
397
+ /** System prompt for the child. Spelled out from scratch — the child
398
+ * does NOT inherit the parent's prompt. */
399
+ prompt: string;
400
+ /** Initial task for the child. When set, the swarm sends it as the
401
+ * child's first user message right after spawn. Omit to spawn an
402
+ * agent that idles waiting for the first `send`. */
403
+ task?: string;
404
+ }
405
+ /**
406
+ * Tree of cooperating agents. One `Swarm` instance per agent tree —
407
+ * the orchestrator (root), every subagent it spawns, every subagent
408
+ * THEY spawn, all live in the same swarm and address each other by
409
+ * `name`.
410
+ *
411
+ * Responsibilities:
412
+ * - Register / look up agents in the tree.
413
+ * - Spawn subagents under a parent (delegates inheritance to
414
+ * `parent.child(...)`; the swarm just records the metadata and
415
+ * routes the initial task message).
416
+ * - Route messages between agents (`send(from, to, content)`
417
+ * injects a `<agent>` system message into the receiver carrying
418
+ * the sender's identity).
419
+ * - Tear-down (`stop(id)` aborts the agent and removes the entry).
420
+ *
421
+ * Not yet wired into `Tasks` or the tool catalog — that lands as a
422
+ * follow-up. This module is the data structure + lifecycle.
423
+ */
424
+ declare class Swarm {
425
+ #private;
426
+ /** Look up an entry by id. */
427
+ get(id: string): SwarmEntry | undefined;
428
+ /** Reverse lookup: find an entry by Agent instance. Returns
429
+ * `undefined` for agents that haven't been registered. */
430
+ find(agent: Agent): SwarmEntry | undefined;
431
+ /** All registered entries (root + every subagent). */
432
+ get entries(): readonly SwarmEntry[];
433
+ /** Direct children of the given agent (one level only). Walks the
434
+ * agent-side parent pointer (`agent.parent`) so the swarm stays
435
+ * free of duplicate parent state. */
436
+ children(parent: Agent): SwarmEntry[];
437
+ /** Register an existing Agent in the swarm. Use this to label the
438
+ * root (the orchestrator that wasn't spawned by `spawn`) with a
439
+ * name + description so other swarm members can address it.
440
+ *
441
+ * The `name` doubles as the entry's id — the swarm resolves
442
+ * collisions by auto-suffixing (`reviewer`, `reviewer-2`, ...).
443
+ * Read the returned `entry.name` to find the actual assigned
444
+ * identity if you care which suffix landed.
445
+ *
446
+ * Idempotent on the same `Agent` instance: re-attaching returns
447
+ * the existing entry, ignoring the new opts. To re-name an agent,
448
+ * `stop()` first then re-attach.
449
+ *
450
+ * Reserved: `name` of `"user"` and the empty string both throw —
451
+ * the former conflicts with the human-sender identity in `<agent>`
452
+ * meta; the latter is a programming error. */
453
+ attach(agent: Agent, opts: {
454
+ name: string;
455
+ desc: string;
456
+ }): SwarmEntry;
457
+ /** Spawn a new subagent under `parent`. Inheritance (cwd, model,
458
+ * permissions, effective tools) is delegated to `parent.child(...)`;
459
+ * the swarm then attaches the child and (optionally) seeds it with
460
+ * `opts.task` as its first user message. */
461
+ spawn(parent: Agent, opts: SpawnOptions): Promise<SwarmEntry>;
462
+ /** Send a message from one agent to another. The receiver gets a
463
+ * message tagged `<agent>` with sender metadata (`name` + `id`) so
464
+ * it can parse who's speaking and respond by addressing them back.
465
+ *
466
+ * Role:
467
+ * - `role: "user"` when the sender is the receiver's parent (or
468
+ * the literal `"user"`) — from the receiver's perspective the
469
+ * sender IS its user.
470
+ * - `role: "system"` otherwise (child → parent reports, sibling
471
+ * messages, unregistered senders). */
472
+ send(from: Agent | "user", to: Agent, content: string): void;
473
+ /** Stop a registered subagent. Aborts its in-flight run and removes
474
+ * the entry. The `Agent` itself is NOT disposed — call
475
+ * `agent.dispose()` separately if you need its resources released. */
476
+ stop(id: string): void;
477
+ /** Stop every registered agent in the swarm. */
478
+ stopAll(): void;
479
+ }
480
+ //#endregion
481
+ //#region src/ctx.d.ts
482
+ type AgentContextOptions = Omit<AgentOptions, "session"> & {
483
+ session: Session;
484
+ };
485
+ type AgentContextEvents = {
486
+ model: {
487
+ model?: Model;
488
+ prev?: Model;
489
+ };
490
+ reasoning: {
491
+ effort: ReasoningEffort;
492
+ prev?: ReasoningEffort;
493
+ };
494
+ session: {
495
+ session: Session;
496
+ prev?: Session;
497
+ };
498
+ cwd: {
499
+ cwd: string;
500
+ prev?: string;
501
+ };
502
+ skills: {
503
+ skills?: Skills;
504
+ };
505
+ };
506
+ declare class AgentContext extends Emitter<AgentContextEvents> {
507
+ #private;
508
+ constructor(opts: AgentContextOptions);
509
+ private start;
510
+ attach(agent: Agent): void;
511
+ get messages(): readonly import("@zaly/ai").Message[];
512
+ get status(): AgentStatus | undefined;
513
+ get opts(): AgentOptions;
514
+ get cwd(): string;
515
+ set cwd(c: string);
516
+ get signal(): AbortSignal | undefined;
517
+ get agent(): Agent;
518
+ get reasoning(): ReasoningEffort;
519
+ set reasoning(r: ReasoningEffort);
520
+ get session(): Session;
521
+ useSession(s: Session): Promise<void>;
522
+ get model(): Model | undefined;
523
+ set model(m: Model | undefined);
524
+ set tools(tools: Tool[]);
525
+ get tools(): Tool[];
526
+ get prompt(): string[];
527
+ set prompt(p: string[]);
528
+ swarm(): Promise<Swarm>;
529
+ set skills(s: Skills | undefined);
530
+ get skills(): Skills | undefined;
531
+ private notifier;
532
+ masker(): Promise<Masker | undefined>;
533
+ permissions(): Promise<PermissionManager>;
534
+ }
535
+ declare function createAgentContext(opts: AgentOptions): Promise<AgentContext>;
536
+ declare function createAgent(opts: AgentOptions): Promise<Agent>;
537
+ //#endregion
538
+ //#region src/tasks.d.ts
539
+ /** Status of a task. `pending` = queued behind a dependency, not yet
540
+ * started. `running` = work in progress (a Streamable is being polled).
541
+ * `done` = result captured, no longer mutating. */
542
+ type TaskStatus = "pending" | "running" | "done";
543
+ /** Public projection of a registered task. Status-discriminated so the
544
+ * fields visible at any moment are exactly the ones that make sense
545
+ * for that lifecycle stage:
546
+ *
547
+ * - `running`: `elapsedMs` since start; `hasNewOutput` when the
548
+ * streamable signals that `task_poll` would yield bytes.
549
+ * - `pending`: queued behind another task (`waitingFor`); `elapsedMs`
550
+ * counts time-since-registration.
551
+ * - `done`: settled. Carries `durationMs` and the captured `result`.
552
+ *
553
+ * This is the only public task type — the registry exposes it via
554
+ * `running()` / `finished()` / `get()`, events carry it (`task-done`
555
+ * is narrowed to `status: "done"` so listeners get `result` typed
556
+ * without checks), and `task_list` JSON-stringifies it directly. */
557
+ type TaskInfo = {
558
+ id: string;
559
+ type: string;
560
+ desc: string;
561
+ } & ({
562
+ status: "running";
563
+ elapsedMs: number;
564
+ hasNewOutput?: boolean;
565
+ } | {
566
+ status: "pending";
567
+ waitingFor: string;
568
+ elapsedMs: number;
569
+ } | {
570
+ status: "done";
571
+ durationMs: number;
572
+ result: ToolResult;
573
+ });
574
+ /** A `TaskInfo` known to be in the `done` state. `task-done` event
575
+ * payloads use this so listeners get `result` and `durationMs` typed
576
+ * without manual narrowing. */
577
+ type DoneTaskInfo = Extract<TaskInfo, {
578
+ status: "done";
579
+ }>;
580
+ /** Events emitted by a `Tasks` instance. `task-done` only fires for
581
+ * completions that happen *outside* an in-flight `run()` round —
582
+ * round-internal completions are folded into the `run()` return value
583
+ * instead. `heartbeat` fires periodically (when `heartbeatMs` is set
584
+ * and at least one task is active), giving the agent a hook to keep
585
+ * the model engaged on long-running work. */
586
+ type TasksEvents = {
587
+ "task-added": {
588
+ task: TaskInfo;
589
+ };
590
+ "task-removed": {
591
+ task: TaskInfo;
592
+ };
593
+ "task-done": {
594
+ task: DoneTaskInfo;
595
+ };
596
+ heartbeat: {
597
+ running: readonly TaskInfo[];
598
+ };
599
+ };
600
+ /** Augment ToolMeta so tools and consumers can read freshness/state info
601
+ * off `ToolResultPart.meta.task`. The registry stamps this on every
602
+ * result it produces so the model can correlate placeholders to their
603
+ * eventual completion. */
604
+ interface TaskMeta {
605
+ task?: {
606
+ id: string;
607
+ status: TaskStatus;
608
+ type: string;
609
+ desc: string;
610
+ dependsOn?: string;
611
+ durationMs?: number;
612
+ };
613
+ }
614
+ /**
615
+ * Tool registry + execution machinery + long-running task bookkeeping.
616
+ * One Tasks instance per Agent. Owns the tool list (the agent delegates
617
+ * `agent.tools` to it) and runs every assistant tool batch through
618
+ * `run()`, which:
619
+ *
620
+ * - validates each call's params,
621
+ * - dispatches to the named tool (sync results land immediately),
622
+ * - races `Streamable` returns against a grace window,
623
+ * - chains `parallel: false` calls behind their predecessors,
624
+ * - returns `ToolResultPart[]` 1:1 with the assistant's calls,
625
+ * surfacing partial results / placeholders for anything still running
626
+ * when the grace expires.
627
+ *
628
+ * Completions during a round are folded into the returned parts and do
629
+ * NOT fire `task-done`. Completions afterward fire normally — the agent
630
+ * listens and injects a system message into the next step.
631
+ */
632
+ declare class Tasks extends Emitter<TasksEvents> {
633
+ #private;
634
+ graceMs: number;
635
+ get heartbeatMs(): number | undefined;
636
+ set heartbeatMs(value: number | undefined);
637
+ /** Snapshot of every active task (pending or running). */
638
+ running(): readonly TaskInfo[];
639
+ /** Snapshot of every task that has completed. Drops are by `remove()`
640
+ * or implicit retention; this list grows unless the caller prunes. */
641
+ finished(): readonly DoneTaskInfo[];
642
+ /** Look up a task by id. Useful for `task_stop` / `task_poll`. */
643
+ get(id: string): TaskInfo | undefined;
644
+ /** Snapshot of every task in the registry — running, pending, and done. */
645
+ info(): readonly TaskInfo[];
646
+ tools(): Promise<readonly Tool[]>;
647
+ set $tools(tools: (() => Promise<readonly Tool[]>) | Tool[]);
648
+ /** Non-consuming check: does the underlying streamable have output
649
+ * the model hasn't seen since the last `poll()`? Returns false for
650
+ * tasks without a streamable, completed tasks, or streamables that
651
+ * don't implement the optional `hasNew` hook (no signal to give).
652
+ * Used by heartbeats to flag tasks worth polling. */
653
+ hasNewOutput(id: string): boolean;
654
+ /** Poll a task's streamable for incremental output without changing
655
+ * its lifecycle state. Advances the streamable's cursor — the next
656
+ * call returns only what arrived since *this* one. Returns the same
657
+ * `ToolResult` shape the original tool produces (parts + meta).
658
+ * Errors when the task is unknown, already done, or has no streamable
659
+ * (the latter is the case for plain-Promise tools — there's no
660
+ * partial state to read). */
661
+ pollOutput(id: string): ToolResult & {
662
+ running: boolean;
663
+ };
664
+ /** Drop a task from the registry — does not abort. Caller is
665
+ * responsible for `abort()`-ing if the task is still running. */
666
+ remove(id: string): boolean;
667
+ /** Mark a task done with a final result. Fires `task-done` UNLESS the
668
+ * task is currently owned by an in-flight `run()` round — in that
669
+ * case the round folds the completion into its returned parts and
670
+ * the event is suppressed. Starts any pending dependents. */
671
+ done(id: string, result: ToolResult): void;
672
+ /** Abort a running task. Calls the streamable's `abort()` if present;
673
+ * pending tasks transition straight to `done` with a cancelled
674
+ * result. Idempotent. */
675
+ abort(id: string, reason?: string): void;
676
+ /** Abort every active task. Used on agent dispose. Awaits each
677
+ * task's `donePromise` so the registry is fully drained before
678
+ * resolving — so callers can rely on no pending I/O after `dispose`. */
679
+ killAll(): Promise<void>;
680
+ /**
681
+ * Execute a batch of assistant tool calls. Returns ToolResultPart[]
682
+ * mapped 1:1 with `calls`. Sync completions land in the result array
683
+ * immediately; long-running ones return a placeholder and the eventual
684
+ * completion fires `task-done` post-round (the agent injects a system
685
+ * message in response).
686
+ *
687
+ * The `messages` snapshot is what tools see on `ctx.messages` — pass
688
+ * the conversation up to (and including) the assistant message that
689
+ * produced these calls, so freshness checks can scan back through
690
+ * prior tool results.
691
+ */
692
+ run(calls: readonly ToolCallPart[], ctx: ToolContext, opts?: {
693
+ onResult?: (call: ToolCallPart, result: ToolResultPart, idx: number) => void;
694
+ }): Promise<ToolResultPart[]>;
695
+ }
696
+ /** Render an array of `TaskInfo` as a `<tasks>` MetaPart for the model
697
+ * (heartbeat pulses and `task_list`). Each task lands as one line of
698
+ * JSON. The `result` field on done tasks is stripped — listing should
699
+ * give an inventory, not historical output (the result was already
700
+ * injected as a system message at task-done time, and re-shipping it
701
+ * on every heartbeat / list call would be a token bomb). */
702
+ declare function taskInfoPart(info: readonly TaskInfo[]): MetaPart;
703
+ /** Build an `inject`-ready system message for a finished task. */
704
+ declare function taskCompletionMessage(task: DoneTaskInfo): Message<"system">;
705
+ //#endregion
706
+ //#region src/utils/usage.d.ts
707
+ /** Sum two Usages. Optional fields are only present in the result
708
+ * when at least one input had them set, so callers can tell "no
709
+ * reasoning happened this turn" apart from "0 reasoning tokens." */
710
+ declare function addUsage(a: Usage, b: Usage): Usage;
711
+ declare class TokenUsage implements Usage {
712
+ #private;
713
+ constructor(messages?: readonly Message[]);
714
+ get cost(): Usage;
715
+ get input(): number;
716
+ get output(): number;
717
+ get cacheRead(): number;
718
+ get cacheWrite(): number;
719
+ get reasoning(): number;
720
+ add(count: Usage): void;
721
+ resetLast(): void;
722
+ get last(): Usage;
723
+ get total(): Usage;
724
+ get contextSize(): number;
725
+ }
726
+ //#endregion
727
+ //#region src/agent.d.ts
728
+ /**
729
+ * Long-lived agent — drives the multi-turn loop, owns the run-time
730
+ * status / queues, and delegates conversation state to a `Session`.
731
+ *
732
+ * Typical interactive use:
733
+ *
734
+ * ```ts
735
+ * const agent = await Agent.load({ model, tools })
736
+ * agent.session.on("node", (e) => render(e))
737
+ * agent.send({ role: "user", content: "hi" }) // auto-runs
738
+ * // …user types again later…
739
+ * agent.send({ role: "user", content: "follow-up" }) // queues if running
740
+ * ```
741
+ *
742
+ * Headless / one-shot use is just a thin wrapper on top — see
743
+ * `runAgent` in the test helpers.
744
+ */
745
+ declare class Agent extends Emitter<AgentEvents> {
746
+ #private;
747
+ /** Nesting depth — see `AgentOptions.depth`. Read-only; subagents pass
748
+ * `parent.depth + 1` when constructing their child. */
749
+ readonly depth: number;
750
+ /** Cap on `depth` — see `AgentOptions.maxDepth`. */
751
+ readonly maxDepth: number;
752
+ /** Synchronous, low-level constructor. Prefer `Agent.load(opts)` —
753
+ * it runs the same construction *plus* any async setup (resolving
754
+ * `session: SessionOptions` to a built `Session`, skills discovery,
755
+ * future warm-ups). The constructor is `protected` so test doubles /
756
+ * subclasses can still call `super(init)` directly; they're
757
+ * responsible for providing a pre-built `Session` on `init.session`. */
758
+ constructor(ctx: AgentContext);
759
+ reset(): Promise<void>;
760
+ /** Spawn a child agent that inherits this agent's runtime defaults —
761
+ * cwd, model, permissions, full effective tool list (user tools +
762
+ * the loaded skill tool), `depth + 1`, and `maxDepth`. Pass
763
+ * `overrides` to specialize: typical ones are `prompt` (the child
764
+ * has its own role), `session` (the child writes to its own JSONL),
765
+ * and `tools` (curated subset).
766
+ *
767
+ * Used by the `subagent` tool for delegation; equally useful for
768
+ * ad-hoc parallel-agent patterns (multiple children working on
769
+ * pieces of a task in parallel).
770
+ *
771
+ * Depth cap: when the child would be at `maxDepth`, the `subagent`
772
+ * tool is filtered out of its inherited tool list so recursion
773
+ * bottoms out cleanly. The model just doesn't see the tool — no
774
+ * error path. */
775
+ child(overrides?: Partial<AgentOptions>): Promise<Agent>;
776
+ /** Active conversation — delegates to the underlying `Session`. */
777
+ get messages(): readonly Message[];
778
+ get status(): AgentStatus;
779
+ get cwd(): string;
780
+ get model(): Model | undefined;
781
+ get session(): Session;
782
+ get signal(): AbortSignal | undefined;
783
+ /** Token usage from the most recent step's response. Drives
784
+ * `contextSize` and any "this turn used N tokens" UI. */
785
+ get usage(): TokenUsage;
786
+ /** Cumulative token usage across every step in the current run.
787
+ * Useful for billing-style displays. */
788
+ get totalUsage(): TokenCount$1;
789
+ /** Logical size of the current conversation in tokens — what the
790
+ * next request will send as input. Equals the last step's
791
+ * `input + output` (since the model's reply becomes part of the
792
+ * next prompt). Returns 0 before any step has run. */
793
+ get contextSize(): number;
794
+ get pressure(): ContextPressure;
795
+ get lastStop(): AgentStop | undefined;
796
+ get steps(): number;
797
+ get parent(): Agent | undefined;
798
+ get tools(): Tool<unknown, unknown, object>[];
799
+ get prompt(): string[];
800
+ get ctx(): AgentContext;
801
+ /** Long-running task registry — exposed for the TUI / introspection
802
+ * tools (`task_list`, etc.). Mutating directly is a foot-gun;
803
+ * prefer the agent's higher-level surface. */
804
+ get tasks(): Tasks;
805
+ /** Append a message and (re)start the loop. The user spoke; the agent
806
+ * responds. If a loop is currently running, the message lands on the
807
+ * follow-up queue and is processed after the current turn naturally
808
+ * stops. Otherwise the loop starts immediately. */
809
+ send(message?: Message | Message[], opts?: {
810
+ mode?: SendMode;
811
+ run?: boolean;
812
+ }): void;
813
+ useTool<T extends Tool = Tool>(name: T["name"], params: ParamsOf<T>, msg: string, opts?: {
814
+ hidden?: boolean;
815
+ }): Promise<{
816
+ call: ToolCallPart<T["name"], ParamsOf<T>>;
817
+ result: ToolResult<MetaOf<T>>;
818
+ messages: [Message<"system">, Message<"assistant">, Message<"tool">];
819
+ }>;
820
+ notify(type: string, data: Content | Record<string, unknown>): void;
821
+ /** Schedule a one-shot wake-up at `delayMs` from now. The agent will
822
+ * receive a system message at that time IF nothing else has woken
823
+ * the loop in the meantime — task-done injects, heartbeats, and user
824
+ * messages all auto-cancel pending wakeups (their job was to ensure
825
+ * the agent gets a turn; if it's already getting one, the timer is
826
+ * redundant).
827
+ *
828
+ * Cancelled wakeups don't silently disappear — their `hint`s, if any,
829
+ * are folded into a system message that lands in the next step
830
+ * alongside whatever woke the loop. The model sees the hints with a
831
+ * `status="cancelled"` marker so it knows the timer didn't fire.
832
+ *
833
+ * Returns the wakeup id (mostly for telemetry / TUI display — the
834
+ * model can't usefully cancel it later, since by the time it has a
835
+ * turn to call cancel, the wakeup has either fired or been cancelled
836
+ * for it). */
837
+ scheduleWakeup(opts: {
838
+ delayMs: number;
839
+ hint?: string;
840
+ }): string;
841
+ /** Drive steps until the agent goes idle (no queued messages and
842
+ * the model stopped naturally) or hits a non-recoverable stop.
843
+ * Doubles as a resume from `paused` — drains queued messages and
844
+ * picks the loop back up. If a run is already in flight, returns
845
+ * the existing promise. */
846
+ run(): Promise<AgentStopKind>;
847
+ /** Run exactly one step. Useful for tests and custom drivers
848
+ * that want to interleave logic between steps. */
849
+ step(): Promise<StepResult>;
850
+ compact(): Promise<void>;
851
+ /** Resolve when the agent is in a quiescent state — `idle` or
852
+ * `paused`. If a run is currently in flight (or was just kicked off
853
+ * synchronously by `send` / `inject` / a wakeup), waits for it to
854
+ * settle before returning the final status. If no run is in flight,
855
+ * resolves immediately with the current status.
856
+ *
857
+ * Use this in REPL-style drivers to await the loop without racing
858
+ * with internally-triggered runs (the wakeup timer, heartbeat, or
859
+ * task-completion injects all spawn `void this.run()` independently
860
+ * of caller-driven `await agent.run()`). The `#running` promise is
861
+ * set synchronously inside `run()` before any await point, so this
862
+ * catches every kicked-off cycle including the one `send` just fired.
863
+ *
864
+ * Errors from the loop are swallowed — callers read `agent.lastError`
865
+ * / `agent.lastStopReason` for diagnostics. The point of `waitIdle`
866
+ * is just to know "the loop is no longer driving." */
867
+ waitIdle(timeout?: number): Promise<AgentStatus>;
868
+ /** Stop the loop with a custom reason.
869
+ * When `abort: true` (the default), also trigger the abort signal so any
870
+ * in-flight stream or tool calls can react to the stop.
871
+ * When `abort: false`, the agent still stops immediately, but any active
872
+ * stream or tool calls are left to run to completion */
873
+ stop(opts?: {
874
+ abort?: boolean;
875
+ reason?: string;
876
+ }): void;
877
+ start(): Promise<void>;
878
+ get started(): boolean;
879
+ /** Tear down session-scoped resources. Called on agent disposal — the
880
+ * agent doesn't auto-dispose today, so callers (TUI on quit, headless
881
+ * runner on completion) should invoke this explicitly. */
882
+ dispose(): Promise<void>;
883
+ }
884
+ //#endregion
885
+ //#region src/compaction/utils.d.ts
886
+ type ToolStat = {
887
+ count: number;
888
+ score: number;
889
+ /** Turns ago at the most recent occurrence (0 = current/last turn).
890
+ * Use with `lastTs` to give the agent both an "in-experience" recency
891
+ * signal and a wall-clock staleness signal. */
892
+ lastTurn: number;
893
+ /** Wall-clock ms timestamp of the most recent occurrence. `0` if no
894
+ * occurrence carried a timestamp. */
895
+ lastTs: number;
896
+ };
897
+ /** Per-file activity tally produced by `extractFiles`. Each entry is a
898
+ * path that the agent touched, with per-kind counts and a frecency
899
+ * `score` that downweights older touches and weights writes/edits
900
+ * more than reads. Sort the top-N by `score` to surface the active
901
+ * working set; `reads` / `writes` / `edits` give the per-kind detail
902
+ * for display. */
903
+ type FileUsage = ToolStat & {
904
+ path: string;
905
+ reads: number;
906
+ writes: number;
907
+ edits: number;
908
+ };
909
+ /** Per-command activity tally produced by `extractBashCommands`. `count`
910
+ * is raw invocations; `score` is the same number but exp-decay-weighted
911
+ * by turn distance from the end of the conversation, so recently-used
912
+ * commands rank above old hot ones. */
913
+ type BashUsage = ToolStat & {
914
+ command: string;
915
+ };
916
+ type ToolStatOptions = {
917
+ minCount?: number;
918
+ minScore?: number;
919
+ limit?: number;
920
+ sort?: "score" | "count" | "key";
921
+ };
922
+ /** Walk assistant tool-calls for `read` / `write` / `edit` and tally
923
+ * per-path activity with frecency-weighted scoring. Returns the top-N
924
+ * by score. Each entry carries the per-kind breakdown so the
925
+ * summarizer can describe the *kind* of activity ("heavily edited",
926
+ * "read once, then written", "iteratively refined").
927
+ *
928
+ * Paths are canonicalized via the cwd recorded on each call's session
929
+ * node — relative paths are resolved against the cwd that was active
930
+ * when the call ran, and `~` is expanded. Calls under different cwds
931
+ * that target the same file thus collapse into one bucket. */
932
+ declare function extractFileUsage(messages: readonly Message[], opts?: ToolStatOptions): FileUsage[];
933
+ /** Walk assistant tool-calls for `bash`, parse each command line, and
934
+ * tally per-command frecency. Plumbing commands (cat, head, grep, awk,
935
+ * sed, …) are filtered out — they dominate raw counts but carry no
936
+ * operational signal a summarizer would describe. Returns the top-N
937
+ * by frecency `score`. */
938
+ declare function extractBashUsage(messages: readonly Message[], opts?: ToolStatOptions): BashUsage[];
939
+ /** Flatten a list of messages into a single tagged transcript. */
940
+ declare function extractConversation(messages: readonly Message[], opts?: {
941
+ maxToolResultLen?: number;
942
+ }): string;
943
+ declare function messageTail(messages: readonly Message[], opts: {
944
+ keepTokens?: number;
945
+ }): Message[];
946
+ declare function formatBashUsage(commands: BashUsage[]): string;
947
+ declare function formatFileUsage(files: FileUsage[]): string;
948
+ //#endregion
949
+ //#region src/compaction/compactions.d.ts
950
+ type CompactionOptions = {
951
+ enabled: boolean;
952
+ threshold?: number;
953
+ /** Existing messages up to this many tokens will be preserved in the context */
954
+ keepTokens: number;
955
+ maxToolResultLen: number;
956
+ summaryTokens: number;
957
+ bash: ToolStatOptions;
958
+ files: ToolStatOptions;
959
+ signal?: AbortSignal;
960
+ reasoning?: ReasoningEffort;
961
+ trigger?: "manual" | "auto";
962
+ };
963
+ //#endregion
964
+ //#region src/notify.d.ts
965
+ type NotifyOptions = {
966
+ idle?: number;
967
+ periodic?: number;
968
+ };
969
+ //#endregion
970
+ //#region src/permissions/handlers/registry.d.ts
971
+ type HandlerLoader = () => PermissionHandler<string>;
972
+ declare const builtin$2: {
973
+ readonly bash: () => PermissionHandler<"bash">;
974
+ readonly read: () => PermissionHandler<"read" | "write">;
975
+ readonly tool: () => PermissionHandler<"tool">;
976
+ readonly write: () => PermissionHandler<"read" | "write">;
977
+ };
978
+ /** Open registry of permission scopes — declaration-merge to add your
979
+ * own. The keys give `ctx.need("…", input)` typed autocomplete and
980
+ * catch typos at compile time. The value carries the *input* type for
981
+ * that scope (almost always `string` — files take paths, bash takes
982
+ * commands, the generic `tool` scope takes the tool name).
983
+ *
984
+ * Built-ins:
985
+ * - `bash` → command string
986
+ * - `read` → absolute path
987
+ * - `write` → absolute path
988
+ * - `tool` → tool name (or richer `name:arg` shape per tool)
989
+ *
990
+ * Add your own scope:
991
+ *
992
+ * ```ts
993
+ * declare module "@zaly/agent" {
994
+ * interface PermissionScopes {
995
+ * fetch: string // expects a domain (or "*" for any)
996
+ * }
997
+ * }
998
+ * ```
999
+ *
1000
+ * Then `ctx.need("fetch", domain)` is typed end-to-end. You still need
1001
+ * to register a runtime handler via `handlerRegistry.register("fetch", …)`
1002
+ * — this interface is only the type-side declaration.
1003
+ */
1004
+ interface PermissionScopes {
1005
+ bash: string;
1006
+ read: string;
1007
+ tool: string;
1008
+ write: string;
1009
+ }
1010
+ type BuiltinScope = keyof typeof builtin$2;
1011
+ type PermissionScope = keyof PermissionScopes;
1012
+ type AnyScope = PermissionScope | (string & {});
1013
+ declare const handlerRegistry: import("@zaly/shared/registry").Registry<HandlerLoader, {
1014
+ readonly bash: () => PermissionHandler<"bash">;
1015
+ readonly read: () => PermissionHandler<"read" | "write">;
1016
+ readonly tool: () => PermissionHandler<"tool">;
1017
+ readonly write: () => PermissionHandler<"read" | "write">;
1018
+ }>;
1019
+ //#endregion
1020
+ //#region src/stop.d.ts
1021
+ /** Caps + heuristics that can end a run early. Wired into the
1022
+ * `AgentSession` loop via a single `detect()` call after each step. */
1023
+ interface StopOptions {
1024
+ /** Hard ceiling on provider round-trips per `run()`. Default: 50. */
1025
+ maxSteps?: number;
1026
+ /** Cumulative token cap across the whole `run()`
1027
+ * (`totalUsage.input + totalUsage.output`). */
1028
+ tokenBudget?: number;
1029
+ /** Bail after this many consecutive failing tool calls. A successful
1030
+ * tool result resets the streak. */
1031
+ maxToolErrors?: number;
1032
+ /** Same `(name, params)` appearing N times in a row → loop. Catches
1033
+ * the most common failure mode: re-calling `read_file` with the same
1034
+ * path expecting different output. Default 3. */
1035
+ loopConsecutive?: number;
1036
+ /** Bounded window for duplicate detection. Default 10. */
1037
+ loopWindow?: number;
1038
+ /** Within the window, this many duplicates of one call → loop.
1039
+ * Catches alternation patterns (`A B A B …`) the consecutive arm
1040
+ * alone won't see. Default 4. */
1041
+ loopWindowRepeats?: number;
1042
+ }
1043
+ /**
1044
+ * Subscribes to an `AgentEvent` stream, accumulates the bookkeeping
1045
+ * the loop needs to make stop-or-continue decisions, and exposes a
1046
+ * single `detect()` to consult after each step.
1047
+ *
1048
+ * Lives outside `AgentSession` so concerns separate cleanly:
1049
+ * - the session owns conversation, queues, status, and loop control;
1050
+ * - the policy owns counters and the rules that act on them.
1051
+ *
1052
+ * Wire it up via `attach(session)` (returns an unsubscribe), or feed
1053
+ * events manually with `handle(event)` for custom drivers.
1054
+ */
1055
+ declare class StopPolicy {
1056
+ #private;
1057
+ constructor(opts?: StopOptions);
1058
+ /** Token usage from the most recent step's response. */
1059
+ get usage(): TokenCount$1;
1060
+ /** Cumulative token usage across every step in the current run. */
1061
+ get totalUsage(): TokenCount$1;
1062
+ get steps(): number;
1063
+ get consecutiveErrors(): number;
1064
+ /** Tool-call history fed to the loop detector. Read-only. */
1065
+ get calls(): readonly ToolCallPart[];
1066
+ /** Subscribe to an emitter. To detach later, register the listener
1067
+ * yourself and pass the same fn to `emitter.off(fn)`:
1068
+ *
1069
+ * const handler = (e) => policy.handle(e)
1070
+ * emitter.all(handler)
1071
+ * // later:
1072
+ * emitter.off(handler) */
1073
+ attach(emitter: Emitter<AgentEvents>): void;
1074
+ /** Feed a single event into the policy. Public so custom drivers
1075
+ * can drive it without going through `attach`. */
1076
+ handle(event: Envelope<AgentEvents>): void;
1077
+ /** Reset per-run counters. Token totals (`usage` / `totalUsage`)
1078
+ * persist unless `keepUsage: false` is passed — billing-style
1079
+ * displays usually want them sticky across resets. */
1080
+ reset(opts?: {
1081
+ keepUsage?: boolean;
1082
+ }): void;
1083
+ /** Decide whether the loop should stop. Returns the stop reason or
1084
+ * `undefined` to continue. Order matters — `loop-detected` wins
1085
+ * over `max-tool-errors` if both fire, since a model in a tight
1086
+ * loop is the more pressing thing to surface. */
1087
+ detect(): AgentStopKind | undefined;
1088
+ }
1089
+ //#endregion
1090
+ //#region src/types.d.ts
1091
+ type SendMode = "inject" | "append";
1092
+ declare module "@zaly/ai" {
1093
+ interface ToolContext {
1094
+ /** Reference to the running agent — surfaced for tools that need to
1095
+ * schedule future inject-style work (`wakeup`, future
1096
+ * notifications). Only populated when invoked through an `Agent`;
1097
+ * one-shot harnesses leave it undefined. */
1098
+ agent?: Agent;
1099
+ /** Override the default `bash` command used by the `bash` tool. */
1100
+ bash?: string[];
1101
+ /** Data directory for tools to read/write durable files. */
1102
+ sessionDir?: string;
1103
+ /** Permissions registry — manager.validate(scope, input) for tools
1104
+ * that gate themselves. */
1105
+ perms?: PermissionManager;
1106
+ /** Long-running task registry. Tools that need to introspect (the
1107
+ * task management tools) read it; ordinary tools can stay
1108
+ * Tasks-unaware and return a `Streamable` instead. */
1109
+ tasks?: Tasks;
1110
+ messages?: readonly Message[];
1111
+ /** Swarm registry — populated when the running agent was
1112
+ * constructed with one (or inherited it from its parent). Tools
1113
+ * that spawn or message subagents (`agent_spawn`, `agent_send`)
1114
+ * read this. Absent on standalone agents and on test contexts
1115
+ * that build a `ToolContext` by hand. */
1116
+ swarm?: () => Promise<Swarm>;
1117
+ /** Async permission check tools call before doing work. Resolves on
1118
+ * `allow`, throws a `AiError(PERMISSION_DENIED)` on `deny`. For
1119
+ * `ask` verdicts, the agent invokes `AgentOptions.allow` (when
1120
+ * configured); if that returns `true` we resolve, otherwise we
1121
+ * throw. Absent on contexts without an Agent (eval / direct
1122
+ * `runTool`) — tools should treat a missing `need` as "no
1123
+ * permission system, allow."
1124
+ *
1125
+ * Two layers of gating exist:
1126
+ * - `Tasks` auto-checks `tool` scope with the tool name on every
1127
+ * dispatch (so `tool(bash)` rules globally gate by name).
1128
+ * - Tools may opt into richer per-input checks via specialized
1129
+ * scopes (`bash(args.command)`, `read(path)`, …).
1130
+ *
1131
+ * Scope names autocomplete from the `PermissionScopes` interface;
1132
+ * add your own via declaration merging. */
1133
+ need?: <S extends PermissionScope>(scope: S, input: PermissionScopes[S]) => Promise<void>;
1134
+ isMasked?: (msgId: string, partIdx?: number) => boolean;
1135
+ }
1136
+ }
1137
+ /** Information passed to `AgentOptions.allow` when an `ask` verdict
1138
+ * needs interactive resolution. Carry-everything shape so the harness
1139
+ * can render a useful prompt: which scope, which input, why the
1140
+ * manager paused, and what rule (if added) would have allowed it. */
1141
+ interface PermissionRequest {
1142
+ ask: string;
1143
+ scope: string;
1144
+ input: string;
1145
+ reason: string;
1146
+ suggestions?: Suggestion[];
1147
+ }
1148
+ /** Resolved-options shape handed to `Agent`'s protected constructor.
1149
+ * Identical to `AgentOptions` except `session` is the *built* `Session`
1150
+ * instance (constructed for you by `Agent.load`). Subclasses that call
1151
+ * `super(init)` directly need to provide their own pre-built session. */
1152
+ interface AgentInit extends Omit<AgentOptions, "session" | "skills" | "cwd" | "tools" | "prompt"> {
1153
+ cwd: string;
1154
+ session: Session;
1155
+ skills?: Skills;
1156
+ tools?: Tool[];
1157
+ prompt?: string[];
1158
+ }
1159
+ /** Snapshot of context-window pressure. Computed by `agent.pressure`
1160
+ * from the most recent step's usage and the model's declared context
1161
+ * limit. Consumers (notifier, masker) escalate behavior on `level`
1162
+ * rises and reset on `level === 0` (e.g. after compaction). */
1163
+ interface ContextPressure {
1164
+ /** Cumulative tokens occupying the context window — uncached input
1165
+ * + cached reads + cached writes + output. */
1166
+ used: number;
1167
+ /** Model's declared context limit (`model.spec.limit.context`). */
1168
+ limit: number;
1169
+ /** `used / limit`. Useful for fine-grained displays; downstream
1170
+ * triggers should typically branch on `level` instead. */
1171
+ ratio: number;
1172
+ /** Discrete escalation level: `0` below the lowest threshold, `1`
1173
+ * past 75%, `2` past 85%, `3` past 95%. Hysteresis-friendly —
1174
+ * consumers track the highest level reached and only reset on `0`. */
1175
+ level: number;
1176
+ }
1177
+ /** Outcome of a single step (one provider round-trip + tool batch).
1178
+ * Returned from `step()` so custom drivers can interleave their own
1179
+ * logic between steps. */
1180
+ type StepResult = {
1181
+ kind: StepKind;
1182
+ message?: AssistantMessage;
1183
+ toolMessage?: Message<"tool">;
1184
+ finishReason: FinishReason;
1185
+ usage: TokenCount$1;
1186
+ error?: Error;
1187
+ };
1188
+ type TurnResult = {
1189
+ kind: AgentStopKind;
1190
+ reason?: unknown;
1191
+ };
1192
+ /** Options for constructing an `Agent`. */
1193
+ interface AgentOptions extends CollectOptions {
1194
+ model?: Model;
1195
+ /** Logger used for top-level agent error boundaries. */
1196
+ logger?: Logger;
1197
+ /** Session for the conversation.
1198
+ * When omitted, a fresh in-memory Session is created. Either way,
1199
+ * `messages` (if any) are appended to it. */
1200
+ session?: Session | SessionOptions;
1201
+ /** Initial working directory for the agent and its tools.
1202
+ * Defaults to the process's current directory at load time.
1203
+ */
1204
+ cwd?: string;
1205
+ /** Tools the model may call. Kernel-owned: the agent both passes
1206
+ * these to the provider on every step and dispatches calls against
1207
+ * them. Mutable post-construction via `agent.tools = …`. */
1208
+ tools?: Tool[];
1209
+ /** Stop-policy knobs — `maxSteps`, `tokenBudget`, `maxToolErrors`,
1210
+ * loop-detection tuning. Grouped under one key to keep the agent's
1211
+ * top-level surface focused. Omit to use defaults (see `StopPolicy`). */
1212
+ stop?: StopOptions;
1213
+ /** Either `PermissionOptions` (construct a fresh manager) or an
1214
+ * existing `PermissionManager` instance to reuse — used by subagents
1215
+ * to share the parent's workspaces + rules without copying. */
1216
+ permissions?: Omit<PermissionOptions, "cwd"> | PermissionManager;
1217
+ /** Per-call passthrough knobs (`temperature`, `toolChoice`,
1218
+ * `reasoning`, `responseFormat`, …). The agent owns `model`,
1219
+ * `messages`, `prompt`, and `tools` — those have dedicated
1220
+ * top-level fields here. */
1221
+ request?: StreamOptions;
1222
+ /** Initial messages appended to the session at construction. Useful
1223
+ * for seeding a fresh conversation or for prepending fixed context
1224
+ * to an existing session. */
1225
+ messages?: Message[];
1226
+ /** Durable system prompt — passed to every step's request and
1227
+ * routed by adapters to each provider's dedicated system slot. Use
1228
+ * this for "behave like X" instructions that don't change across
1229
+ * the session. For mid-conversation steering, `send()` a
1230
+ * `role: "system"` message instead. Mutable via `agent.prompt = …`. */
1231
+ prompt?: string[];
1232
+ /** Model's declared context window — enables silent-overflow detection. */
1233
+ contextLimit?: number;
1234
+ /** Nesting depth of this agent. `0` = top-level (user-facing).
1235
+ * Subagents bump this by 1 each time they spawn. The `subagent` tool
1236
+ * consults this to decide whether to expose itself to the spawned
1237
+ * child — at depth `maxDepth`, the child gets the parent's tool list
1238
+ * *without* the subagent tool, so recursion bottoms out cleanly.
1239
+ * Defaults to `0`. */
1240
+ depth?: number;
1241
+ /** Maximum allowed agent depth. Subagents at depth `< maxDepth` may
1242
+ * spawn further subagents; at depth `>= maxDepth`, the subagent tool
1243
+ * is filtered out of their tool list (no error — the model just
1244
+ * doesn't see it). Defaults to `2`, giving root → child → grandchild.
1245
+ * Top-level only — children inherit this from the parent at spawn
1246
+ * time. */
1247
+ maxDepth?: number;
1248
+ /** Enable the built-in `skill` tool (Agent Skills support). When
1249
+ * `true` (default), the agent constructs a `Skills` instance, scans
1250
+ * `${cwd}/.agent/skills/` and `~/.agent/skills/` on `skills.load()`,
1251
+ * and exposes the activation tool to the model. Set `false` to skip
1252
+ * skills entirely (no `skills` getter, no scanning, no tool). */
1253
+ skills?: Skills;
1254
+ /** Optional `Swarm` registry. When set, this agent participates in a
1255
+ * multi-agent swarm — children spawned via `agent.child()` inherit
1256
+ * the same swarm, and tools like `agent_spawn` / `agent_send`
1257
+ * become functional via `ctx.swarm`. The swarm is shared by every
1258
+ * agent in the tree; only the root needs to be configured with one.
1259
+ * Children inherit it automatically. */
1260
+ swarm?: Swarm;
1261
+ /** Heartbeat interval (ms) for the Tasks registry. While at least one
1262
+ * task is pending or running, the agent injects a `<heartbeat>` system
1263
+ * message at this cadence so the model sees what's still going and
1264
+ * the loop stays alive. Leave undefined to disable. Tune for the
1265
+ * workload — interactive sessions often want 30s; batch / autonomous
1266
+ * runs may want 5m. */
1267
+ heartbeatMs?: number;
1268
+ /** Runtime notifications: `session-started` / `session-resumed`,
1269
+ * `time` / `new-day` / `user-returned`, `model-changed`,
1270
+ * `context-pressure`. Defaults to enabled with sensible thresholds.
1271
+ *
1272
+ * Pass `false` to disable entirely (tests usually want this — the
1273
+ * injected messages would otherwise show up in conversation
1274
+ * expectations); pass a `NotifyOptions` object to tune thresholds
1275
+ * while keeping the notifier active. */
1276
+ notify?: boolean | NotifyOptions;
1277
+ /** Tool-result masking. When enabled, the agent rewrites older
1278
+ * re-callable tool results (`read`, `fetch`, …) to compact stubs on
1279
+ * the way to the provider, freeing context without touching the
1280
+ * session DAG. Once a message is stamped, the stamp is durable for
1281
+ * the agent's lifetime — see `Masker` for the cache-stability rules.
1282
+ *
1283
+ * Default off. Pass `true` to enable, or a `MaskOptions` object to
1284
+ * tune `tools` / `keepRecent`. */
1285
+ mask?: MaybeGetter<MaskerOptions>;
1286
+ /** Resolver for `ask` permission verdicts. The agent invokes this
1287
+ * with the scope / input / reason / suggestions; resolve `true` to
1288
+ * allow the call, `false` to deny. Absent → ask defaults to deny.
1289
+ *
1290
+ * Hook a TUI prompt here, or return `true` unconditionally for
1291
+ * unattended runs that should treat ask as allow (yolo-but-richer). */
1292
+ allow?: (req: PermissionRequest) => Promise<boolean>;
1293
+ compaction?: MaybeGetter<Partial<CompactionOptions>>;
1294
+ /** Override the default `bash` command used by the `bash` tool. */
1295
+ bash?: string[];
1296
+ loadModel?: (id: string) => Promise<Model>;
1297
+ }
1298
+ //#endregion
1299
+ //#region src/prompt/registry.d.ts
1300
+ interface PromptCtx {
1301
+ model: Model;
1302
+ cwd: string;
1303
+ }
1304
+ type PromptLoader = (ctx: PromptCtx) => Promise<string>;
1305
+ type Prompt<T extends string | PromptLoader = string | PromptLoader> = {
1306
+ name: string;
1307
+ text: T;
1308
+ };
1309
+ declare const builtin$1: {
1310
+ readonly "AGENTS.md": (ctx: PromptCtx) => Promise<string>;
1311
+ readonly "MEMORY.md": (ctx: PromptCtx) => Promise<string>;
1312
+ readonly agent: () => Promise<string>;
1313
+ readonly env: (ctx: PromptCtx) => Promise<string>;
1314
+ readonly model: (ctx: PromptCtx) => Promise<string>;
1315
+ };
1316
+ type BuiltinPrompt = keyof typeof builtin$1;
1317
+ type AnyPrompt = BuiltinPrompt | (string & {});
1318
+ declare const promptRegistry: import("@zaly/shared/registry").Registry<PromptLoader, {
1319
+ readonly "AGENTS.md": (ctx: PromptCtx) => Promise<string>;
1320
+ readonly "MEMORY.md": (ctx: PromptCtx) => Promise<string>;
1321
+ readonly agent: () => Promise<string>;
1322
+ readonly env: (ctx: PromptCtx) => Promise<string>;
1323
+ readonly model: (ctx: PromptCtx) => Promise<string>;
1324
+ }>;
1325
+ declare class PromptCollection extends BaseCollection<AnyPrompt[], Prompt[], Prompt> {
1326
+ list(): Prompt[];
1327
+ render(ctx: PromptCtx & {
1328
+ prompts?: string[];
1329
+ }): Promise<Prompt<string>[]>;
1330
+ }
1331
+ declare function promptCollection(): Promise<PromptCollection>;
1332
+ //#endregion
1333
+ //#region src/tools/registry.d.ts
1334
+ /** Per-load context handed to every tool factory. Lets factories
1335
+ * customise the tool — typically schema descriptions — based on the
1336
+ * agent's model and working directory. Tools that don't care about
1337
+ * init just ignore the arg. */
1338
+ interface ToolInit {
1339
+ model: Model;
1340
+ cwd: string;
1341
+ }
1342
+ type ToolLoader = () => Promise<Tool>;
1343
+ type BuiltinTool = keyof typeof builtin;
1344
+ type AnyTool = AnyKey<BuiltinTool>;
1345
+ declare const builtin: {
1346
+ readonly agent_send: () => Promise<Tool<unknown, unknown, object>>;
1347
+ readonly agent_spawn: () => Promise<Tool<unknown, unknown, object>>;
1348
+ readonly bash: () => Promise<Tool<unknown, unknown, object>>;
1349
+ readonly edit: () => Promise<Tool<unknown, unknown, object>>;
1350
+ readonly fetch: () => Promise<Tool<unknown, unknown, object>>;
1351
+ readonly find: () => Promise<Tool<unknown, unknown, object>>;
1352
+ readonly grep: () => Promise<Tool<unknown, unknown, object>>;
1353
+ readonly read: () => Promise<Tool<unknown, unknown, object>>;
1354
+ readonly search: () => Promise<Tool<unknown, unknown, object>>;
1355
+ readonly subagent: () => Promise<Tool<unknown, unknown, object>>;
1356
+ readonly task_list: () => Promise<Tool<unknown, unknown, object>>;
1357
+ readonly task_poll: () => Promise<Tool<unknown, unknown, object>>;
1358
+ readonly task_stop: () => Promise<Tool<unknown, unknown, object>>;
1359
+ readonly wakeup: () => Promise<Tool<unknown, unknown, object>>;
1360
+ readonly write: () => Promise<Tool<unknown, unknown, object>>;
1361
+ };
1362
+ declare const toolRegistry: import("@zaly/shared/registry").Registry<ToolLoader, {
1363
+ readonly agent_send: () => Promise<Tool<unknown, unknown, object>>;
1364
+ readonly agent_spawn: () => Promise<Tool<unknown, unknown, object>>;
1365
+ readonly bash: () => Promise<Tool<unknown, unknown, object>>;
1366
+ readonly edit: () => Promise<Tool<unknown, unknown, object>>;
1367
+ readonly fetch: () => Promise<Tool<unknown, unknown, object>>;
1368
+ readonly find: () => Promise<Tool<unknown, unknown, object>>;
1369
+ readonly grep: () => Promise<Tool<unknown, unknown, object>>;
1370
+ readonly read: () => Promise<Tool<unknown, unknown, object>>;
1371
+ readonly search: () => Promise<Tool<unknown, unknown, object>>;
1372
+ readonly subagent: () => Promise<Tool<unknown, unknown, object>>;
1373
+ readonly task_list: () => Promise<Tool<unknown, unknown, object>>;
1374
+ readonly task_poll: () => Promise<Tool<unknown, unknown, object>>;
1375
+ readonly task_stop: () => Promise<Tool<unknown, unknown, object>>;
1376
+ readonly wakeup: () => Promise<Tool<unknown, unknown, object>>;
1377
+ readonly write: () => Promise<Tool<unknown, unknown, object>>;
1378
+ }>;
1379
+ declare class ToolCollection extends BaseCollection<AnyTool[], AnyTool[], Tool> {
1380
+ list(): AnyTool[];
1381
+ load(tools?: AnyTool[]): Promise<Tool[]>;
1382
+ }
1383
+ declare function toolCollection(): Promise<ToolCollection>;
1384
+ //#endregion
1385
+ //#region src/tools/bash.d.ts
1386
+ type BashTool = typeof bashTool;
1387
+ declare const bashTool: import("@zaly/ai").Tool<{
1388
+ command: string;
1389
+ description?: string | undefined;
1390
+ max_lines?: number | undefined;
1391
+ timeout?: number | undefined;
1392
+ }, unknown, object>;
1393
+ //#endregion
1394
+ //#region src/tools/read.d.ts
1395
+ type ReadTool = typeof readTool;
1396
+ type FileMeta = {
1397
+ path: string;
1398
+ mtime: number;
1399
+ kind: "read" | "write" | "edit";
1400
+ /** True when the result reflects the whole-file content — set by
1401
+ * un-sliced `read` and by `write` (which always replaces the
1402
+ * full file). Used by the masker to know whether this result
1403
+ * subsumes earlier reads of the same path. `edit` never sets it
1404
+ * because the result is patch-relative. */
1405
+ full?: boolean;
1406
+ unchanged?: boolean;
1407
+ };
1408
+ type ReadToolMeta = FileMeta & {
1409
+ offset: number;
1410
+ limit: number;
1411
+ };
1412
+ /** Build the `read` tool with model-aware schema description. The
1413
+ * attachment-shape blurb is included only when the loaded model
1414
+ * actually accepts the relevant modality — text-only models see a
1415
+ * description that promises only text output, so they don't reach
1416
+ * for the tool expecting images they can't process. */
1417
+ declare const readTool: import("@zaly/ai").Tool<{
1418
+ path: string;
1419
+ offset?: number | undefined;
1420
+ limit?: number | undefined;
1421
+ }, unknown, ReadToolMeta>;
1422
+ //#endregion
1423
+ //#region src/tools/edit.d.ts
1424
+ type EditTool = typeof editTool;
1425
+ type EditToolMeta = FileMeta & {
1426
+ /** File content before any edit was applied. */
1427
+ original: string;
1428
+ /** File content after all edits were applied — exactly what's now on disk. */
1429
+ content: string;
1430
+ };
1431
+ /**
1432
+ * Apply one or more exact-text replacements to a file.
1433
+ *
1434
+ * Semantics:
1435
+ * - All `oldText` matches are resolved against the *original* file
1436
+ * content. Edits are not applied sequentially — so edit #1's
1437
+ * `newText` cannot accidentally produce a match for edit #2's
1438
+ * `oldText`.
1439
+ * - Each `oldText` must occur exactly once in the file (uniqueness
1440
+ * forces the model to disambiguate via context rather than guessing).
1441
+ * - Edits must not overlap. Nearby changes should be combined into a
1442
+ * single edit covering the surrounding block.
1443
+ * - The file is rewritten atomically: either every edit applies
1444
+ * cleanly or none do.
1445
+ *
1446
+ * Use `read` first to inspect the file. Keep `oldText` minimal but
1447
+ * uniquely identifying. For full-file rewrites, use `write` instead.
1448
+ */
1449
+ declare const editTool: import("@zaly/ai").Tool<{
1450
+ path: string;
1451
+ oldText: string;
1452
+ newText: string;
1453
+ edits?: {
1454
+ oldText: string;
1455
+ newText: string;
1456
+ }[] | undefined;
1457
+ }, unknown, EditToolMeta>;
1458
+ //#endregion
1459
+ //#region src/tools/find.d.ts
1460
+ type FindTool = typeof findTool;
1461
+ type FindToolMeta = {
1462
+ cwd: string;
1463
+ glob: string | string[];
1464
+ matches: number;
1465
+ truncated: boolean;
1466
+ };
1467
+ declare const findTool: import("@zaly/ai").Tool<{
1468
+ glob?: string | string[] | undefined;
1469
+ cwd?: string | undefined;
1470
+ paths?: string[] | undefined;
1471
+ type?: "any" | "dir" | "file" | undefined;
1472
+ exclude?: string[] | undefined;
1473
+ hidden?: boolean | undefined;
1474
+ ignore?: boolean | undefined;
1475
+ follow?: boolean | undefined;
1476
+ limit?: number | undefined;
1477
+ }, unknown, FindToolMeta>;
1478
+ //#endregion
1479
+ //#region src/tools/grep.d.ts
1480
+ type GrepTool = typeof grepTool;
1481
+ type GrepToolMeta = {
1482
+ cwd: string;
1483
+ pattern: string;
1484
+ truncated: boolean;
1485
+ cmd: string[];
1486
+ };
1487
+ declare const grepTool: import("@zaly/ai").Tool<{
1488
+ pattern: string;
1489
+ cwd?: string | undefined;
1490
+ paths?: string[] | undefined;
1491
+ glob?: string[] | undefined;
1492
+ exclude?: string[] | undefined;
1493
+ file_type?: string[] | undefined;
1494
+ fixed_strings?: boolean | undefined;
1495
+ case_sensitive?: boolean | undefined;
1496
+ hidden?: boolean | undefined;
1497
+ ignore?: boolean | undefined;
1498
+ follow?: boolean | undefined;
1499
+ context?: number | undefined;
1500
+ limit?: number | undefined;
1501
+ }, unknown, GrepToolMeta>;
1502
+ //#endregion
1503
+ //#region src/tools/write.d.ts
1504
+ type WriteTool = typeof writeTool;
1505
+ type WriteToolMeta = FileMeta & {
1506
+ /** File content before the write. Undefined for new files. The
1507
+ * post-write content is recoverable from the original call's
1508
+ * `params.content`, so we don't redundantly stash it on meta. */
1509
+ original?: string;
1510
+ };
1511
+ /**
1512
+ * Write a file to disk. Overwrites if the file exists; creates parent
1513
+ * directories as needed.
1514
+ *
1515
+ * Content is written *verbatim* in everything but line endings. The
1516
+ * model always emits LF; this tool detects the existing file's
1517
+ * line-ending style (or the platform default for new files via
1518
+ * `detectEol`) and re-applies it on write so a CRLF file stays CRLF
1519
+ * after an LF-from-the-model overwrite. No trailing-newline injection,
1520
+ * no whitespace stripping.
1521
+ *
1522
+ * Freshness: when the target file already exists, the model must have
1523
+ * read it in this session and the on-disk mtime must be unchanged
1524
+ * since that read. Otherwise the tool refuses with `FILE_NOT_FRESH` —
1525
+ * "read this file before overwriting it." New files (path doesn't
1526
+ * exist) bypass this check; nothing to be fresh against.
1527
+ *
1528
+ * Returns a small acknowledgement (`{ ok, bytes, lines }`) rather than
1529
+ * echoing the content back — the model already has it. `bytes` reflects
1530
+ * the on-disk byte count, including any extra bytes from CRLF expansion.
1531
+ */
1532
+ declare const writeTool: import("@zaly/ai").Tool<{
1533
+ path: string;
1534
+ content: string;
1535
+ }, unknown, WriteToolMeta>;
1536
+ //#endregion
1537
+ //#region src/utils/uuid.d.ts
1538
+ /**
1539
+ * RFC 9562 UUIDv7 — timestamp-prefixed (48-bit ms since epoch),
1540
+ * monotonic within a millisecond via a 32-bit sequence counter,
1541
+ * random tail otherwise. Sortable lexicographically by creation time,
1542
+ * which is handy for debugging ("show me the latest few records by
1543
+ * uuid") and for any future DB index.
1544
+ *
1545
+ * Hand-rolled to keep `@zaly/agent` dep-free. Same algorithm as the
1546
+ * `uuid` package's v7 implementation, just without the buffer/offset
1547
+ * ceremony — we only ever want the canonical string form.
1548
+ */
1549
+ declare function uuidv7(): string;
1550
+ declare function isUuidv7(s: string): boolean;
1551
+ declare function isUuidv7Like(s: string): boolean;
1552
+ //#endregion
1553
+ //#region src/commands.d.ts
1554
+ type Command = {
1555
+ name: string;
1556
+ body: string;
1557
+ path: string;
1558
+ description?: string;
1559
+ args: ArgsOpts;
1560
+ };
1561
+ interface CommandsOptions {
1562
+ /** cmd.md paths, sorted from highest to lowest precedence. */
1563
+ paths?: string[];
1564
+ logger?: Logger;
1565
+ /** Bash execution of commands:
1566
+ * - `true`: Use the system default bash shell.
1567
+ * - `false`: Disable bash execution.
1568
+ * - `string[]`: Use a custom bash shell with the provided arguments. */
1569
+ bash?: boolean | string[];
1570
+ /** When `false`, template expressions are disabled and only simple variable interpolation is allowed. */
1571
+ expr?: boolean;
1572
+ }
1573
+ declare class Commands {
1574
+ #private;
1575
+ readonly catalog: Map<string, Command>;
1576
+ constructor(opts?: CommandsOptions);
1577
+ load(): Promise<this>;
1578
+ add(path: string): Promise<void>;
1579
+ get(name: string): Command | undefined;
1580
+ format(input: string | ArgsResult, cmd: Command): Promise<string>;
1581
+ }
1582
+ //#endregion
1583
+ //#region src/context/tokens.d.ts
1584
+ type TokenCount = {
1585
+ type: AnyType | Message["role"] | "prompt" | "tool-schema" | "system-prompt";
1586
+ kind?: string;
1587
+ tokens: number;
1588
+ children?: TokenCount[];
1589
+ };
1590
+ type TokenStats = {
1591
+ key: string;
1592
+ tokens: number;
1593
+ count: number;
1594
+ children?: Map<string, TokenStats>;
1595
+ };
1596
+ declare function estimatePart(p: AnyPart): TokenCount;
1597
+ declare function tokenStats(msgs: readonly Message[], opts?: {
1598
+ prompt?: (string | Prompt<string>)[];
1599
+ tools?: Tool[];
1600
+ expand?: (c: TokenCount) => boolean;
1601
+ }): TokenStats;
1602
+ declare function formatTokenStats(s: TokenStats, indent?: number): string;
1603
+ //#endregion
1604
+ export { type Agent, type AgentContext, type AgentContextEvents, type AgentEvents, type AgentInit, type AgentOptions, type AgentStatus, type AgentStop, type AgentStopKind, AnyPrompt, type AnyScope, AnyTool, type BashTool, BashUsage, BuiltinPrompt, type BuiltinScope, BuiltinTool, type CheckResult, Command, Commands, CommandsOptions, type ContextPressure, type DoneTaskInfo, type EditTool, type EditToolMeta, FileUsage, type FindTool, type FindToolMeta, type GrepTool, type GrepToolMeta, type PermissionContext, type PermissionHandler, type PermissionManager, type PermissionOptions, type PermissionPreset, type PermissionPresetName, type PermissionRequest, type PermissionScope, type PermissionScopes, Prompt, type PromptCollection, PromptCtx, PromptLoader, type ReadTool, type ReadToolMeta, type Rule, type SendMode, SkillEntry, SkillMeta, SkillTool, Skills, SkillsOptions, type StepKind, type StepResult, type StopOptions, type StopPolicy, type Suggestion, type TaskInfo, type TaskMeta, type TaskStatus, type Tasks, type TasksEvents, TokenCount, TokenStats, type TokenUsage, type ToolCollection, ToolInit, ToolLoader, ToolStat, ToolStatOptions, type TurnResult, type Verdict, type WriteTool, type WriteToolMeta, type addUsage, createAgent, type createAgentContext, estimatePart, extractBashUsage, extractConversation, extractFileUsage, formatBashUsage, formatFileUsage, formatTokenStats, handlerRegistry, isUuidv7, isUuidv7Like, messageTail, promptCollection, promptRegistry, type taskCompletionMessage, type taskInfoPart, tokenStats, toolCollection, toolRegistry, uuidv7 };
1605
+ //# sourceMappingURL=index.d.mts.map