@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.
- package/LICENSE +21 -0
- package/README.md +50 -0
- package/dist/agent-BaD2kax9.mjs +68 -0
- package/dist/agent-BaD2kax9.mjs.map +1 -0
- package/dist/agent-GDLdDc2w.mjs +902 -0
- package/dist/agent-GDLdDc2w.mjs.map +1 -0
- package/dist/bash-QNMTQ1PD.mjs +142 -0
- package/dist/bash-QNMTQ1PD.mjs.map +1 -0
- package/dist/compactions-3AjPqjeZ.mjs +190 -0
- package/dist/compactions-3AjPqjeZ.mjs.map +1 -0
- package/dist/edit-Qxl4w1C2.mjs +170 -0
- package/dist/edit-Qxl4w1C2.mjs.map +1 -0
- package/dist/env-UUFv5Mye.mjs +30 -0
- package/dist/env-UUFv5Mye.mjs.map +1 -0
- package/dist/fetch-D8cmmA3E.mjs +111 -0
- package/dist/fetch-D8cmmA3E.mjs.map +1 -0
- package/dist/find-Bah9SKWX.mjs +87 -0
- package/dist/find-Bah9SKWX.mjs.map +1 -0
- package/dist/grep-B2Ax7ewy.mjs +244 -0
- package/dist/grep-B2Ax7ewy.mjs.map +1 -0
- package/dist/index-node-esm-D6YQRKEz.mjs +1537 -0
- package/dist/index-node-esm-D6YQRKEz.mjs.map +1 -0
- package/dist/index.d.mts +1605 -0
- package/dist/index.d.mts.map +1 -0
- package/dist/index.mjs +948 -0
- package/dist/index.mjs.map +1 -0
- package/dist/jsonl-Dw_VBp46.mjs +134 -0
- package/dist/jsonl-Dw_VBp46.mjs.map +1 -0
- package/dist/manager-D-lWBTHG.mjs +271 -0
- package/dist/manager-D-lWBTHG.mjs.map +1 -0
- package/dist/markdown-Bv4J8cg3.mjs +53 -0
- package/dist/markdown-Bv4J8cg3.mjs.map +1 -0
- package/dist/masker-Bv9KjkDF.mjs +396 -0
- package/dist/masker-Bv9KjkDF.mjs.map +1 -0
- package/dist/model-_3ZA2xqm.mjs +27 -0
- package/dist/model-_3ZA2xqm.mjs.map +1 -0
- package/dist/notify-DpG_m9iP.mjs +96 -0
- package/dist/notify-DpG_m9iP.mjs.map +1 -0
- package/dist/read-Djsx2NZl.mjs +205 -0
- package/dist/read-Djsx2NZl.mjs.map +1 -0
- package/dist/registry-CFmR5G3J.mjs +564 -0
- package/dist/registry-CFmR5G3J.mjs.map +1 -0
- package/dist/search-CRw247ES.mjs +121 -0
- package/dist/search-CRw247ES.mjs.map +1 -0
- package/dist/session/claude.d.mts +59 -0
- package/dist/session/claude.d.mts.map +1 -0
- package/dist/session/claude.mjs +455 -0
- package/dist/session/claude.mjs.map +1 -0
- package/dist/session-CUUdWFC5.mjs +450 -0
- package/dist/session-CUUdWFC5.mjs.map +1 -0
- package/dist/session-Ds5nJz5A.d.mts +346 -0
- package/dist/session-Ds5nJz5A.d.mts.map +1 -0
- package/dist/session.d.mts +37 -0
- package/dist/session.d.mts.map +1 -0
- package/dist/session.mjs +106 -0
- package/dist/session.mjs.map +1 -0
- package/dist/subagent-baqzjRMc.mjs +136 -0
- package/dist/subagent-baqzjRMc.mjs.map +1 -0
- package/dist/swarm-BJ3gQA1Z.mjs +194 -0
- package/dist/swarm-BJ3gQA1Z.mjs.map +1 -0
- package/dist/swarm-BuFx_xeY.mjs +109 -0
- package/dist/swarm-BuFx_xeY.mjs.map +1 -0
- package/dist/tasks-D8rARHZ1.mjs +65 -0
- package/dist/tasks-D8rARHZ1.mjs.map +1 -0
- package/dist/tasks-WmC270X2.mjs +615 -0
- package/dist/tasks-WmC270X2.mjs.map +1 -0
- package/dist/tools-DW1dbcCz.mjs +695 -0
- package/dist/tools-DW1dbcCz.mjs.map +1 -0
- package/dist/truncate-BSMXgiXj.mjs +102 -0
- package/dist/truncate-BSMXgiXj.mjs.map +1 -0
- package/dist/uuid-ByXP5SO5.mjs +59 -0
- package/dist/uuid-ByXP5SO5.mjs.map +1 -0
- package/dist/wakeup-BYqTnfSp.mjs +29 -0
- package/dist/wakeup-BYqTnfSp.mjs.map +1 -0
- package/dist/write-D3L-92vj.mjs +89 -0
- package/dist/write-D3L-92vj.mjs.map +1 -0
- package/package.json +63 -0
package/dist/index.d.mts
ADDED
|
@@ -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
|