@orkestrel/agent 0.0.20 → 0.0.21

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.
@@ -1,29 +1,31 @@
1
- import { BudgetInterface } from '@orkestrel/budget';
2
- import { ControllerInterface } from '@orkestrel/workflow';
3
- import { DriverInterface } from '@orkestrel/database';
4
- import { EmitterErrorHandler } from '@orkestrel/emitter';
5
- import { EmitterHooks } from '@orkestrel/emitter';
6
- import { EmitterInterface } from '@orkestrel/emitter';
7
- import { FileInterface } from '@orkestrel/workspace';
8
- import { JSONValue } from '@orkestrel/contract';
9
- import { QueueContext } from '@orkestrel/queue';
10
- import { QueueInterface } from '@orkestrel/queue';
11
- import { QueueStoreInterface } from '@orkestrel/queue';
12
- import { RunnerInterface } from '@orkestrel/workflow';
13
- import { SchedulerInterface } from '@orkestrel/workflow';
14
- import { TableInterface } from '@orkestrel/database';
15
- import { TokenUsage } from '@orkestrel/budget';
16
- import { ToolCall } from '@orkestrel/tool';
17
- import { ToolDefinition } from '@orkestrel/tool';
18
- import { ToolInterface } from '@orkestrel/tool';
19
- import { ToolManagerInterface } from '@orkestrel/tool';
20
- import { ToolResult } from '@orkestrel/tool';
21
- import { WorkspaceManagerInterface } from '@orkestrel/workspace';
1
+ import type { BudgetInterface } from '@orkestrel/budget';
2
+ import type { ControllerInterface } from '@orkestrel/workflow';
3
+ import type { DriverInterface } from '@orkestrel/database';
4
+ import type { EmitterErrorHandler } from '@orkestrel/emitter';
5
+ import type { EmitterHooks } from '@orkestrel/emitter';
6
+ import type { EmitterInterface } from '@orkestrel/emitter';
7
+ import type { FileInterface } from '@orkestrel/workspace';
8
+ import type { JSONValue } from '@orkestrel/contract';
9
+ import type { QueueContext } from '@orkestrel/queue';
10
+ import type { QueueInterface } from '@orkestrel/queue';
11
+ import type { QueueStoreInterface } from '@orkestrel/queue';
12
+ import type { RunnerInterface } from '@orkestrel/workflow';
13
+ import type { SchedulerInterface } from '@orkestrel/workflow';
14
+ import type { TableInterface } from '@orkestrel/database';
15
+ import type { TokenUsage } from '@orkestrel/budget';
16
+ import type { ToolCall } from '@orkestrel/tool';
17
+ import type { ToolDefinition } from '@orkestrel/tool';
18
+ import type { ToolInterface } from '@orkestrel/tool';
19
+ import type { ToolManagerInterface } from '@orkestrel/tool';
20
+ import type { ToolResult } from '@orkestrel/tool';
21
+ import type { WorkspaceManagerInterface } from '@orkestrel/workspace';
22
22
 
23
23
  /**
24
24
  * Composes a {@link ProviderInterface}, an {@link AgentContext}, and a
25
- * {@link ToolManagerInterface} into a bounded context → provider → tools → repeat
26
- * turn, exposed as both a one-shot `generate` and a live `stream`.
25
+ * {@link ToolManagerInterface} into a bounded context → provider → tools → repeat turn, exposed
26
+ * as both a one-shot `generate` and a live `stream` that share one private run — bounded by the
27
+ * run `signal`, the `timeout`, and the `budget` folded through `AbortSignal.any`, paced by
28
+ * `scheduler`, with tool iteration capped at `limit`.
27
29
  *
28
30
  * @remarks
29
31
  * - **One loop, two faces.** A single private async generator (`#run`) drives the
@@ -40,15 +42,15 @@ import { WorkspaceManagerInterface } from '@orkestrel/workspace';
40
42
  * assistant message and stop.
41
43
  * - **Bounded.** Each run arms one cancel through `createAbort({ signal: AbortSignal.any([
42
44
  * …]) })` folding the external `signal`, the `timeout` deadline, and the `budget`
43
- * signal; `abort()` fires it. Any trip stops the loop and commits a PARTIAL result
44
- * (the `result` promise RESOLVES, never rejects, on a cancel) — only a genuine
45
+ * signal; `abort()` fires it. Any trip stops the loop and commits a partial result
46
+ * (the `result` promise resolves, never rejects, on a cancel) — only a genuine
45
47
  * provider / tool error rejects.
46
48
  * - **Paced + capped.** The `scheduler` (when given) `yield`s between turns; tool
47
49
  * iteration is capped at `limit`.
48
- * - **Two observation surfaces.** The PULL {@link AgentChunk} stream carries per-token
49
- * deltas (+ usage/tool chunks); the PUSH {@link emitter} ({@link AgentEventMap}) carries
50
+ * - **Two observation surfaces.** The pull {@link AgentChunk} stream carries per-token
51
+ * deltas (+ usage/tool chunks); the push {@link emitter} ({@link AgentEventMap}) carries
50
52
  * lifecycle + usage/tool/deny moments for fire-and-forget observers. Every event is
51
- * emitted directly, AFTER the relevant state transition / settle; the emitter isolates a
53
+ * emitted directly, after the relevant state transition / settle; the emitter isolates a
52
54
  * listener throw and routes it to its `error` handler (the `error` option), so a buggy
53
55
  * observer can never escape into / reorder / corrupt the settle-once loop — observation is
54
56
  * purely a side-channel.
@@ -74,15 +76,15 @@ export declare class Agent implements AgentInterface {
74
76
 
75
77
  /**
76
78
  * Represents a streamed step of an agent turn — the union the loop yields as it runs, discriminated
77
- * by the `category` of step it carries.
79
+ * by the `category` of step it carries, and the pull surface beside the push {@link AgentEventMap}.
78
80
  *
79
81
  * @remarks
80
82
  * - `token` — a content delta the provider streamed (the `'content'`
81
83
  * {@link ProviderDelta}s a {@link ProviderInterface}'s `stream` yields), re-surfaced for
82
- * live rendering of the assistant ANSWER.
84
+ * live rendering of the assistant answer.
83
85
  * - `think` — a reasoning delta the provider streamed (the `'thinking'`
84
86
  * {@link ProviderDelta}s, the daemon's native `message.thinking` channel), surfaced so a
85
- * consumer can stream the model's reasoning LIVE into a collapsible; NEVER answer content
87
+ * consumer can stream the model's reasoning live into a collapsible; never answer content
86
88
  * (it is never fed into the accumulated `content`).
87
89
  * - `tool` — a {@link ToolCall} the loop dispatched paired with its {@link ToolResult},
88
90
  * emitted once the tool ran (so a consumer sees what was called and what came back).
@@ -107,58 +109,59 @@ export declare type AgentChunk = {
107
109
  /**
108
110
  * Assembles a provider request from the richer turn context — the optional system prompt, the
109
111
  * observable context managers (instructions / workspaces), the
110
- * {@link ConversationManagerInterface} message source (whose active conversation IS `messages`),
111
- * the {@link ToolManagerInterface} registry, and an active {@link ScopeInterface} changed through
112
- * {@link AgentContextInterface.apply}.
112
+ * {@link ConversationManagerInterface} message source whose active conversation is `messages`, the
113
+ * {@link ToolManagerInterface} registry, and an active {@link ScopeInterface} changed through
114
+ * {@link AgentContextInterface.apply}. `build()` folds the scoped managers and the active
115
+ * workspace into one system block, then the conversation, and never reads `tools`.
113
116
  *
114
117
  * @remarks
115
118
  * - **Composition.** `system` is the optional system prompt; `instructions` / `tools` /
116
119
  * `workspaces` / `conversations` are the registries passed in `options` (bring your own), or
117
- * fresh empty ones when omitted (so `workspaces` is ALWAYS present); `messages` is the ACTIVE
118
- * conversation's live tail (ALWAYS defined — see below). `scope` is the active filter —
120
+ * fresh empty ones when omitted (so `workspaces` is always present); `messages` is the active
121
+ * conversation's live tail (always defined — see the following item). `scope` is the active filter —
119
122
  * `undefined` (the default) ⇒ no filtering; change it through `apply(scope)`. The structural
120
123
  * `workspaces` / `conversations` registries are fixed at construction; switch their active
121
124
  * members through their own `switch(id)` methods.
122
- * - **The message source — the conversation registry's ACTIVE conversation.** `conversations` is a
123
- * {@link ConversationManagerInterface}; the context ENSURES it always has an active conversation
124
- * (at construction it `add`s a default when the manager has none), so the DYNAMIC `messages`
125
- * getter — `this.#conversations.active` — is ALWAYS defined. `messages` returns the active
126
- * conversation ITSELF (it owns the live tail + the message verbs directly, satisfying
125
+ * - **The message source — the conversation registry's active conversation.** `conversations` is a
126
+ * {@link ConversationManagerInterface}; the context ensures it always has an active conversation
127
+ * (at construction it `add`s a default when the manager has none), so the dynamic `messages`
128
+ * getter — `this.#conversations.active` — is always defined. `messages` returns the active
129
+ * conversation itself (it owns the live tail + the message verbs directly, satisfying
127
130
  * {@link MessageManagerInterface} structurally — the same reference, no duplication), and
128
131
  * `build()` folds that conversation's `view()` (its per-section summaries + live tail) as the
129
- * AUTHORITATIVE message inclusion — the scope does NOT filter the conversation (it owns inclusion
132
+ * authoritative message inclusion — the scope does not filter the conversation (it owns inclusion
130
133
  * through compaction; scope filters only instructions / tools / workspace files). Because `messages`
131
- * is read dynamically, an agent SWITCHES the active
132
- * conversation BETWEEN runs (`conversations.switch(id)`) to serve MANY threads (the real
134
+ * is read dynamically, an agent switches the active
135
+ * conversation between runs (`conversations.switch(id)`) to serve many threads (the real
133
136
  * multi-conversation pattern); switch between runs, not during a run, and use separate agents
134
137
  * for concurrent threads.
135
138
  * - **`build(format?)` — the scoped assembly + the format cascade.** It folds, in order,
136
- * the system prompt then the scope-filtered instructions → the ACTIVE workspace's text files
139
+ * the system prompt then the scope-filtered instructions → the active workspace's text files
137
140
  * (each as a block: the section's resolved `open` text, each item's resolved rendering, then
138
- * any resolved `close` text) into ONE leading `system` message (prepended only when at least
139
- * one part exists), then appends the ACTIVE conversation's `view()` (the conversation owns
140
- * message inclusion through compaction — the scope does NOT filter the conversation). Each
141
+ * any resolved `close` text) into one leading `system` message (prepended only when at least
142
+ * one part exists), then appends the active conversation's `view()` (the conversation owns
143
+ * message inclusion through compaction — the scope does not filter the conversation). Each
141
144
  * `open` / item / `close`
142
- * resolves INDEPENDENTLY, MOST-SPECIFIC-FIRST — `build()`'s optional `format` (a provider's
143
- * per-section default) is the PROVIDER level: `open` = manager-options-override > provider >
145
+ * resolves independently, most-specific-first — `build()`'s optional `format` (a provider's
146
+ * per-section default) is the provider level: `open` = manager-options-override > provider >
144
147
  * built-in; per item = item-override > manager-options-override > provider > built-in; `close` =
145
- * manager-options-override > provider (NO built-in ⇒ no closing line when unset) (see
146
- * {@link AgentContextInterface.build}). Passing NO `format` (and with no overrides / no per-item
148
+ * manager-options-override > provider (no built-in ⇒ no closing line when unset) (see
149
+ * {@link AgentContextInterface.build}). Passing no `format` (and with no overrides / no per-item
147
150
  * override) reproduces the built-in framing byte-for-byte (each section is its built-in header +
148
151
  * items, no closing line). The active workspace's scoped-in image files' `base64` payload is attached to
149
- * the LAST user message (a vision provider reads images off a user turn); when no user message
152
+ * the last user message (a vision provider reads images off a user turn); when no user message
150
153
  * exists the attachment is skipped. Built fresh each call (recomputed, never cached), so it
151
154
  * always reflects the current managers / messages / scope / active workspace; it never mutates a
152
155
  * manager or the stored messages.
153
- * - **The ACTIVE workspace, rendered BY CARRIER — the SOLE document/image context.**
156
+ * - **The active workspace, rendered by carrier — the sole document/image context.**
154
157
  * `workspaces.active` (when set) has its {@link import('@orkestrel/workspace').FileInterface}s scope-filtered by `scope.files`,
155
- * then split: TEXT files fold into a dedicated `## Workspace` system section (fenced reference
156
- * blocks — placed right after the instructions section), and IMAGE files' `base64` payload attaches
157
- * to the last user message. ACTIVE-ONLY — never the other registered workspaces; with no active
158
- * workspace nothing renders for workspaces. `build()` OWNS this render (a `Workspace` /
158
+ * then split: text files fold into a dedicated `## Workspace` system section (fenced reference
159
+ * blocks — placed right after the instructions section), and image files' `base64` payload attaches
160
+ * to the last user message. Active-only — never the other registered workspaces; with no active
161
+ * workspace nothing renders for workspaces. `build()` owns this render (a `Workspace` /
159
162
  * `WorkspaceManager` stays file-focused).
160
163
  * - **Tools are structural, not in the prompt.** The registry is advertised to the provider
161
- * through `tools.definitions()` (scope-filtered by the loop), NEVER serialized into the
164
+ * through `tools.definitions()` (scope-filtered by the loop), never serialized into the
162
165
  * message array — so `build()`'s output carries no tool content, scoped or not.
163
166
  * - **Event-free context; observable managers.** The context itself owns no Emitter; the
164
167
  * context managers each carry their own (the push observation surface).
@@ -194,12 +197,12 @@ export declare class AgentContext implements AgentContextInterface {
194
197
  * (`instructions` / `workspaces` / `conversations`), `messages` (the active
195
198
  * conversation's live tail, satisfying {@link MessageManagerInterface}), and the current `scope`
196
199
  * (the active {@link ScopeInterface} filter, or `undefined` for no filtering). `build()` folds the
197
- * scoped instructions into ONE leading `system` message (under the manager's `open`,
198
- * each item through its `render`) — PLUS the ACTIVE workspace's scope-filtered text files
199
- * (rendered as fenced reference blocks) — and appends the ACTIVE conversation's `view()`, attaching
200
- * the active workspace's scope-filtered image files' `base64` payload to the LAST user message. The
201
- * active workspace is the SOLE document/image context. Tools are advertised to the provider
202
- * STRUCTURALLY (through `tools.definitions()`, scope-filtered by the loop), NOT serialized into
200
+ * scoped instructions into one leading `system` message (under the manager's `open`,
201
+ * each item through its `render`) — plus the active workspace's scope-filtered text files
202
+ * (rendered as fenced reference blocks) — and appends the active conversation's `view()`, attaching
203
+ * the active workspace's scope-filtered image files' `base64` payload to the last user message. The
204
+ * active workspace is the sole document/image context. Tools are advertised to the provider
205
+ * structurally (through `tools.definitions()`, scope-filtered by the loop), not serialized into
203
206
  * the prompt, so they never appear in `build()`'s output. The context managers are observable
204
207
  * (their own `emitter`s); the context itself is event-free.
205
208
  */
@@ -207,32 +210,32 @@ export declare interface AgentContextInterface {
207
210
  readonly system: string | undefined;
208
211
  readonly instructions: InstructionManagerInterface;
209
212
  /**
210
- * Holds the {@link WorkspaceManagerInterface} whose ACTIVE workspace `build()` renders by carrier —
213
+ * Holds the {@link WorkspaceManagerInterface} whose active workspace `build()` renders by carrier —
211
214
  * its text files folded into the system block (fenced reference blocks) and its image files'
212
- * `base64` payload attached to the LAST user message. The active workspace is the SOLE
213
- * document/image context. ALWAYS present (a fresh empty manager when none was supplied).
214
- * `build()` reads its `active` (and the active workspace's `files()`) FRESH each call. With NO
215
+ * `base64` payload attached to the last user message. The active workspace is the sole
216
+ * document/image context. Always present (a fresh empty manager when none was supplied).
217
+ * `build()` reads its `active` (and the active workspace's `files()`) fresh each call. With no
215
218
  * active workspace, nothing is rendered for workspaces. Active-only — never the other registered
216
219
  * workspaces.
217
220
  */
218
221
  readonly workspaces: WorkspaceManagerInterface;
219
222
  /**
220
- * Holds the active conversation's LIVE tail — the agent's message source, ALWAYS defined (the
223
+ * Holds the active conversation's live tail — the agent's message source, always defined (the
221
224
  * {@link conversations} registry always has an active conversation; a default is added at
222
- * construction). It IS the active {@link ConversationInterface} itself (which satisfies
225
+ * construction). It is the active {@link ConversationInterface} itself (which satisfies
223
226
  * {@link MessageManagerInterface} structurally), so appends through `messages` route to the
224
227
  * active conversation's tail and `build()` folds its `view()`. Computed dynamically (it follows
225
- * `conversations.switch(id)`), the SAME reference the active conversation exposes — no
228
+ * `conversations.switch(id)`), the same reference the active conversation exposes — no
226
229
  * duplication.
227
230
  */
228
231
  readonly messages: MessageManagerInterface;
229
232
  /**
230
- * Holds the {@link ConversationManagerInterface} the message source flows from — `messages` IS its
231
- * ACTIVE conversation's live tail and `build()` folds that conversation's `view()`. ALWAYS holds
233
+ * Holds the {@link ConversationManagerInterface} the message source flows from — `messages` is its
234
+ * active conversation's live tail and `build()` folds that conversation's `view()`. Always holds
232
235
  * an active conversation (a default is added at construction when none was supplied), so
233
236
  * `messages` is always defined. Switch the active conversation through
234
- * `conversations.switch(id)` — so one agent can serve MANY conversations (set the active one per
235
- * request). Switch BETWEEN runs, not during one; for CONCURRENT threads use separate agents.
237
+ * `conversations.switch(id)` — so one agent can serve many conversations (set the active one per
238
+ * request). Switch between runs, not during one; for concurrent threads use separate agents.
236
239
  */
237
240
  readonly conversations: ConversationManagerInterface;
238
241
  /**
@@ -243,7 +246,8 @@ export declare interface AgentContextInterface {
243
246
  /** Holds the active scope applied at `build()` time + the loop's tool-advertise step (`undefined` ⇒ no filtering). */
244
247
  readonly scope: ScopeInterface | undefined;
245
248
  /**
246
- * Applies the active per-turn scope filter. Passing `undefined` removes filtering.
249
+ * Applies the given scope as the active per-turn filter; passing `undefined` explicitly
250
+ * removes filtering.
247
251
  *
248
252
  * @param scope - The scope to apply, or `undefined` to remove the active filter
249
253
  *
@@ -255,51 +259,57 @@ export declare interface AgentContextInterface {
255
259
  */
256
260
  apply(scope: ScopeInterface | undefined): void;
257
261
  /**
258
- * Builds the provider input for the next turn: a leading `system` message folding the prompt
259
- * + the scoped instructions + the ACTIVE workspace's scoped-in TEXT files (rendered as
260
- * fenced reference blocks), then the ACTIVE conversation's `view()` (with the active workspace's
261
- * scoped-in IMAGE files' `base64` payload attached to the last user message). Tools are advertised
262
- * structurally, not in the prompt. Built fresh on each call.
262
+ * Builds the provider input for the next turn: a leading `system` message folding the
263
+ * prompt, the scope-filtered instructions (each section's header and each item's rendering
264
+ * resolved through the format cascade), and the active workspace's scope-filtered
265
+ * (`scope.files`) text files as fenced reference blocks in a `## Workspace` section, then
266
+ * the active conversation's `view()`, with the active workspace's image files' `base64`
267
+ * payload attached to the last user message. Takes an optional `format` — typically
268
+ * `provider.format`, the provider level of the cascade — and omitting it with no overrides
269
+ * set renders each section on its manager's built-in framing. The `system` message is
270
+ * prepended only when some part of it exists, the workspace render covers the active
271
+ * workspace alone, tools are advertised structurally rather than in the prompt, and the
272
+ * input is built fresh on each call.
263
273
  *
264
274
  * @remarks
265
- * **The active workspace (rendered by carrier) — the SOLE document/image context.** When
275
+ * **The active workspace (rendered by carrier) — the sole document/image context.** When
266
276
  * `workspaces.active` is set, its
267
277
  * {@link import('@orkestrel/workspace').WorkspaceInterface.files} are filtered by
268
278
  * `scope.files` (a three-way allow-list; `undefined` ⇒ all active files), then split by
269
- * carrier: TEXT files ({@link import('@orkestrel/workspace').isText}) render into a dedicated
279
+ * carrier: text files ({@link import('@orkestrel/workspace').isText}) render into a dedicated
270
280
  * `## Workspace` section in the system block — each a fenced
271
281
  * `` File: <path>\n```<language>\n<text>\n``` `` block — placed immediately after the instructions
272
282
  * section; binary files whose MIME starts with `image/` have their `base64` payload
273
- * attached to the LAST user message (a vision provider reads images off a user turn).
274
- * ACTIVE-ONLY — never the other registered workspaces; with NO active workspace nothing is
283
+ * attached to the last user message (a vision provider reads images off a user turn).
284
+ * Active-only — never the other registered workspaces; with no active workspace nothing is
275
285
  * rendered for workspaces.
276
286
  *
277
287
  * **The format cascade.** Each manager section frames as `[open, ...items.map(render), close]`
278
288
  * (empty / absent slots dropped, the survivors `\n\n`-joined). The `open` (the section's
279
289
  * leading text), each item's `render`, and the `close` (the section's trailing text)
280
- * resolve INDEPENDENTLY, MOST-SPECIFIC-FIRST, from a {@link ContextSectionFormat} at each
290
+ * resolve independently, most-specific-first, from a {@link ContextSectionFormat} at each
281
291
  * level — an item override, a manager-options override, the provider `format` default,
282
292
  * and the manager's built-in. For the `instructions` section kind `K`, manager
283
293
  * `M`, and the supplied `format` `F`:
284
294
  * - **open** = `M.format?.open ?? F?.[K]?.open ?? M.open` — that is,
285
295
  * **manager-options override > provider default > built-in** (the leading text has no
286
- * per-item level). The manager ENCAPSULATES the `[options-override → built-in]` half:
296
+ * per-item level). The manager encapsulates the `[options-override → built-in]` half:
287
297
  * `M.open` already returns the options override's `open` when one is set, else
288
- * the built-in header — so `build()` only layers the provider default BETWEEN them.
298
+ * the built-in header — so `build()` only layers the provider default between them.
289
299
  * - **item** `I` = `I.override ?? M.format?.render?.(I) ?? F?.[K]?.render?.(I) ?? M.render(I)`
290
300
  * — that is, **item override > manager-options override > provider default > built-in**.
291
301
  * Again `M.render(I)` already returns the options override when set, else the
292
- * built-in, so `build()` layers the per-item `I.override` ON TOP and the provider
293
- * default BETWEEN.
302
+ * built-in, so `build()` layers the per-item `I.override` on top and the provider
303
+ * default between.
294
304
  * - **close** = `M.format?.close ?? F?.[K]?.close` — that is, **manager-options
295
- * override > provider default**, with NO built-in floor (the trailing text has no
305
+ * override > provider default**, with no built-in floor (the trailing text has no
296
306
  * per-item level): unset at both levels ⇒ `undefined` ⇒ no closing line. Paired with
297
- * `open`, it lets a level WRAP the group (`open: '<instructions>'` … `close: '</instructions>'`).
307
+ * `open`, it lets a level wrap the group (`open: '<instructions>'` … `close: '</instructions>'`).
298
308
  *
299
- * Passing NO `format` (the default) leaves the provider-default level empty, so the
300
- * output is BYTE-FOR-BYTE the managers' built-in framing — every section is its
309
+ * Passing no `format` (the default) leaves the provider-default level empty, so the
310
+ * output is byte-for-byte the managers' built-in framing — every section is its
301
311
  * built-in header + items, with no closing line (the regression contract). Scope
302
- * filtering runs BEFORE formatting (unchanged); the workspace image-data attachment to the
312
+ * filtering runs before formatting (unchanged); the workspace image-data attachment to the
303
313
  * last user message is unchanged.
304
314
  *
305
315
  * @param format - The provider's optional {@link ContextFormat} default
@@ -312,7 +322,10 @@ export declare interface AgentContextInterface {
312
322
  }
313
323
 
314
324
  /**
315
- * Configures `createAgentContext` — the richer context's configuration.
325
+ * Configures `createAgentContext` — the optional system prompt plus the pre-built managers to
326
+ * reuse: an `instructions` registry, a `workspaces` registry (the only document channel), a
327
+ * `conversations` registry (the message source), a `tools` registry (the loop's advertise and
328
+ * dispatch surface), and an initial `scope`.
316
329
  *
317
330
  * @remarks
318
331
  * `system` is the optional system prompt prepended to the turn's input. `instructions` /
@@ -322,10 +335,10 @@ export declare interface AgentContextInterface {
322
335
  * initial active filter applied at `build()` time (and at the loop's tool-advertise step); it
323
336
  * defaults to `undefined` — no filtering — and can be changed through the context's `apply`
324
337
  * method afterwards. `conversations` is the structural {@link ConversationManagerInterface} the
325
- * context's message source flows from: `messages` IS the manager's ACTIVE conversation's live tail
338
+ * context's message source flows from: `messages` is the manager's active conversation's live tail
326
339
  * and `build()` folds that conversation's `view()` (section summaries + live). When omitted, a fresh
327
340
  * {@link ConversationManagerInterface} is created and a default conversation is added (so
328
- * `messages` is ALWAYS defined). All default to a context with no system prompt, empty registries,
341
+ * `messages` is always defined). All default to a context with no system prompt, empty registries,
329
342
  * no scope, and a fresh conversation registry holding one default conversation.
330
343
  */
331
344
  export declare interface AgentContextOptions {
@@ -339,21 +352,21 @@ export declare interface AgentContextOptions {
339
352
  readonly instructions?: InstructionManagerInterface;
340
353
  /**
341
354
  * Reuses a pre-built {@link WorkspaceManagerInterface}; a fresh empty one is created when
342
- * omitted (so `context.workspaces` is ALWAYS present). `build()` renders the ACTIVE workspace's
355
+ * omitted (so `context.workspaces` is always present). `build()` renders the active workspace's
343
356
  * files by carrier — text files into the system block (fenced), image files attached to the last
344
357
  * user message. The registry is structural; change its active workspace through
345
- * `workspaces.switch(id)`. The active workspace is the SOLE document/image context.
358
+ * `workspaces.switch(id)`. The active workspace is the sole document/image context.
346
359
  */
347
360
  readonly workspaces?: WorkspaceManagerInterface;
348
361
  /** Sets the initial active scope (the build-time filter); `undefined` ⇒ no filtering. */
349
362
  readonly scope?: ScopeInterface;
350
363
  /**
351
364
  * Reuses a pre-built {@link ConversationManagerInterface} as the message source; a fresh
352
- * empty one is created when omitted. The context ENSURES an active conversation at construction
353
- * (it `add`s a default when the manager has none), so `messages` — the manager's ACTIVE
354
- * conversation's LIVE tail — is ALWAYS defined. `build()` folds the active conversation's
355
- * `view()` (the per-section summaries + the live tail) as its AUTHORITATIVE message inclusion —
356
- * the scope does NOT filter the conversation (it owns inclusion through compaction; scope filters
365
+ * empty one is created when omitted. The context ensures an active conversation at construction
366
+ * (it `add`s a default when the manager has none), so `messages` — the manager's active
367
+ * conversation's live tail — is always defined. `build()` folds the active conversation's
368
+ * `view()` (the per-section summaries + the live tail) as its authoritative message inclusion —
369
+ * the scope does not filter the conversation (it owns inclusion through compaction; scope filters
357
370
  * only instructions / tools / workspace files). The registry is structural; change its active
358
371
  * conversation through the manager's `switch(id)`.
359
372
  */
@@ -361,13 +374,16 @@ export declare interface AgentContextOptions {
361
374
  }
362
375
 
363
376
  /**
364
- * Reports a concurrent run that would corrupt SHARED per-agent accounting, or a rehydration
377
+ * Reports a concurrent run that would corrupt shared per-agent accounting, or a rehydration
365
378
  * name absent from its registry pool — thrown synchronously by an {@link AgentInterface}'s
366
- * `stream()` and by an {@link AgentRegistryInterface}'s accessors, carrying a machine-readable
367
- * `code`.
379
+ * `stream()` (and so by `generate()`, which calls it) and by an
380
+ * {@link AgentRegistryInterface}'s accessors, carrying the machine-readable `code`
381
+ * `'CONCURRENCY' | 'REGISTRY'`. Synchronous means a fire-and-forget
382
+ * `agent.generate().catch(…)` never catches it: `await` the call inside `try`/`catch`, or wrap
383
+ * the call expression itself.
368
384
  *
369
385
  * @remarks
370
- * `'CONCURRENCY'` reports a run already in flight on the same agent, PLUS a construction-level
386
+ * `'CONCURRENCY'` reports a run already in flight on the same agent, plus a construction-level
371
387
  * `window` (a shared context budget) or a construction-level `budget` with no per-run override
372
388
  * (a shared cost budget) — a second concurrent `stream()` would race its charges against the
373
389
  * same shared instance, corrupting the accounting. Use separate agents, or per-run `budget`
@@ -382,26 +398,26 @@ export declare class AgentError extends Error {
382
398
  }
383
399
 
384
400
  /**
385
- * Maps the push observation surface of an {@link AgentInterface} — the
386
- * lifecycle + usage/tool moments a fire-and-forget observer (logging, metrics,
387
- * tracing) subscribes to, ALONGSIDE the pull {@link AgentChunk} stream.
401
+ * Maps the push observation surface of an {@link AgentInterface} — the lifecycle, usage, and tool
402
+ * moments a fire-and-forget observer (logging, metrics, tracing) subscribes to, beside the pull
403
+ * {@link AgentChunk} stream.
388
404
  *
389
405
  * @remarks
390
- * Push vs. pull: the Emitter carries the loop's LIFECYCLE moments (a run begins /
406
+ * Push vs. pull: the Emitter carries the loop's lifecycle moments (a run begins /
391
407
  * each turn / a settle / a cancel) plus usage and dispatched-tool events — the things
392
408
  * the chunk stream can't express (a `deny` never reaches the stream) or that a
393
- * fire-and-forget observer wants without draining the stream. PER-TOKEN deltas stay
394
- * EXCLUSIVELY the {@link AgentChunk} stream's job (the pull surface) — there is
395
- * deliberately NO `token` event here. Subscribe through `agent.emitter.on(...)`.
409
+ * fire-and-forget observer wants without draining the stream. Per-token deltas stay
410
+ * exclusively the {@link AgentChunk} stream's job (the pull surface) — there is
411
+ * deliberately no `token` event here. Subscribe through `agent.emitter.on(...)`.
396
412
  *
397
413
  * Observation is side-effect-free on the loop: listener isolation is the emitter's
398
- * — every event is emitted directly and a listener throw is routed to the emitter's OWN
414
+ * — every event is emitted directly and a listener throw is routed to the emitter's own
399
415
  * `error` handler (the `error` option), never onto this domain map and never into the
400
416
  * settle-once / wake-park engine — so a buggy observer can never reorder, throw into, or
401
417
  * corrupt the run.
402
418
  *
403
- * A cancelled run emits `abort` (the cancel signal) AND then `finish` (the settled
404
- * PARTIAL result) — so an observer sees both that the run was cancelled and the partial
419
+ * A cancelled run emits `abort` (the cancel signal) and then `finish` (the settled
420
+ * partial result) — so an observer sees both that the run was cancelled and the partial
405
421
  * outcome it committed; a genuine error emits `error` instead of `finish`.
406
422
  *
407
423
  * Declared as a `type` alias (not `interface extends EventMap` — `EventMap` is a
@@ -418,9 +434,9 @@ export declare type AgentEventMap = {
418
434
  readonly tool: readonly [call: ToolCall, result: ToolResult];
419
435
  /** Reports a turn's {@link TokenUsage} — emitted after a usage-bearing provider call. */
420
436
  readonly usage: readonly [usage: TokenUsage];
421
- /** Reports a call the authority DENIED — the call + the optional reason (NOT in the chunk stream). */
437
+ /** Reports a call the authority denied — the call + the optional reason (not in the chunk stream). */
422
438
  readonly deny: readonly [call: ToolCall, reason: string | undefined];
423
- /** Reports the run settled successfully (a natural finish OR a cancel's partial) — the {@link AgentResult}. */
439
+ /** Reports the run settled successfully (a natural finish or a cancel's partial) — the {@link AgentResult}. */
424
440
  readonly finish: readonly [result: AgentResult];
425
441
  /** Reports the run settled with a genuine (non-cancel) error — the thrown value (always `unknown`). */
426
442
  readonly error: readonly [error: unknown];
@@ -429,20 +445,20 @@ export declare type AgentEventMap = {
429
445
  /**
430
446
  * Reports the loop exhausting its `limit` while still holding unresolved tool intent (the model
431
447
  * requested tools on the very last allowed turn) — the turn count reached. Distinct from
432
- * `abort`: exhaustion is NOT a cancel (no external signal / timeout / budget tripped), so
433
- * this fires INSTEAD of `abort`, still followed by `finish` carrying the partial result.
448
+ * `abort`: exhaustion is not a cancel (no external signal / timeout / budget tripped), so
449
+ * this fires instead of `abort`, still followed by `finish` carrying the partial result.
434
450
  */
435
451
  readonly exhaust: readonly [turns: number];
436
452
  /**
437
- * Reports AUTOMATIC compaction's summarizer THROWING — a NON-FATAL warn channel (the run continues; see
453
+ * Reports automatic compaction's summarizer throwing — a non-fatal warn channel (the run continues; see
438
454
  * {@link AgentOptions.window}). When the loop's between-turns / pre-first-turn auto-compaction
439
- * (`conversation.compact()`) rejects, the run does NOT crash: the loop skips compaction that
455
+ * (`conversation.compact()`) rejects, the run does not crash: the loop skips compaction that
440
456
  * turn and surfaces the caught error here so the failure is observable, never silently lost.
441
- * The run still SETTLES through the other events — `finish` for the lenient default, and
457
+ * The run still settles through the other events — `finish` for the lenient default, and
442
458
  * `error` when {@link AgentOptions.strict} rethrows the same caught value — so `fault` reports
443
- * the best-effort optimization that failed and never the run's own outcome. A MANUAL
444
- * `conversation.compact()` still propagates its own error; only the agent's AUTO path is
445
- * resilient. A DOMAIN event (the emitter isolates a listener throw separately, routing it to
459
+ * the best-effort optimization that failed and never the run's own outcome. A manual
460
+ * `conversation.compact()` still propagates its own error; only the agent's auto path is
461
+ * resilient. A domain event (the emitter isolates a listener throw separately, routing it to
446
462
  * its `error` handler).
447
463
  */
448
464
  readonly fault: readonly [error: unknown];
@@ -453,7 +469,7 @@ export declare type AgentEventMap = {
453
469
  * {@link ToolManagerInterface} into a bounded context → provider → tools → repeat turn.
454
470
  *
455
471
  * @remarks
456
- * - **One loop, two faces.** `generate` and `stream` share ONE private run, so they
472
+ * - **One loop, two faces.** `generate` and `stream` share one private run, so they
457
473
  * can never diverge: `generate` drains the same stream `stream` exposes, then
458
474
  * resolves its settled {@link AgentResult}.
459
475
  * - **Bounded.** Each turn arms a single cancel folded from the external `signal`, the
@@ -461,11 +477,11 @@ export declare type AgentEventMap = {
461
477
  * or `abort()` — stops the loop and settles the result `partial: true`.
462
478
  * - **Paced + capped.** The `scheduler` (when given) yields between turns; tool
463
479
  * iteration is capped at `limit` so the loop always terminates.
464
- * - **Two observation surfaces.** PULL: the {@link AgentChunk} stream (`stream().events`)
465
- * carries per-token answer deltas, per-think reasoning deltas, and usage/tool chunks for a live consumer. PUSH: the
480
+ * - **Two observation surfaces.** Pull: the {@link AgentChunk} stream (`stream().events`)
481
+ * carries per-token answer deltas, per-think reasoning deltas, and usage/tool chunks for a live consumer. Push: the
466
482
  * {@link emitter} ({@link AgentEventMap}) carries lifecycle + usage/tool/deny moments
467
483
  * for fire-and-forget observers — the emitter isolates a listener throw and routes it to
468
- * its `error` handler (the `error` option), so a buggy observer can NEVER corrupt the
484
+ * its `error` handler (the `error` option), so a buggy observer can never corrupt the
469
485
  * loop. Per-token / per-thinking deltas are the stream's job exclusively; there is no
470
486
  * `token` or `think` event.
471
487
  * - **Per-run overrides.** Both faces accept an optional {@link AgentRunOptions} bag whose
@@ -477,14 +493,14 @@ export declare interface AgentInterface {
477
493
  readonly status: AgentStatus;
478
494
  readonly context: AgentContextInterface;
479
495
  /**
480
- * Runs the turn to completion, discarding the live chunks — drains the shared
481
- * stream and resolves the settled outcome.
496
+ * Runs the turn to completion, discarding the live chunks — drains the shared stream and
497
+ * resolves the settled {@link AgentResult} (`partial: true` when cancelled).
482
498
  *
483
499
  * @remarks
484
500
  * A concurrent run on a shared accounting agent throws an
485
501
  * {@link import('./errors.js').AgentError} (`code: 'CONCURRENCY'`) — and it throws
486
- * SYNCHRONOUSLY, before any `Promise` is returned. A fire-and-forget
487
- * `agent.generate().catch(...)` therefore will NOT catch it (the throw happens on the call
502
+ * synchronously, before any `Promise` is returned. A fire-and-forget
503
+ * `agent.generate().catch(...)` therefore will not catch it (the throw happens on the call
488
504
  * itself, ahead of the `.catch` ever attaching) — `await` the call (inside a `try`/`catch`)
489
505
  * or wrap the call expression itself in `try`/`catch`.
490
506
  *
@@ -495,11 +511,12 @@ export declare interface AgentInterface {
495
511
  generate(options?: AgentRunOptions): Promise<AgentResult>;
496
512
  /**
497
513
  * Runs the turn as a live stream — iterate `events` for {@link AgentChunk}s and
498
- * `await result` for the settled outcome.
514
+ * `await result` for the settled outcome; `result` resolves partial on a cancel and rejects
515
+ * on a genuine error.
499
516
  *
500
517
  * @remarks
501
518
  * Like `generate()`, a concurrent run on a shared accounting agent throws an
502
- * {@link import('./errors.js').AgentError} (`code: 'CONCURRENCY'`) SYNCHRONOUSLY — before the
519
+ * {@link import('./errors.js').AgentError} (`code: 'CONCURRENCY'`) synchronously — before the
503
520
  * {@link AgentStreamInterface} handle is even returned, so it cannot be caught by chaining
504
521
  * off the (never-produced) handle; wrap the call itself in `try`/`catch`.
505
522
  *
@@ -520,13 +537,13 @@ export declare interface AgentInterface {
520
537
  /**
521
538
  * Reports an {@link AgentInterface} run that ended {@link AgentResult.partial} under a
522
539
  * `partial` policy of `false` (the default) — thrown by an agent-job handler (a
523
- * `createAgentQueue` / `createAgentRunner` job), carrying the partial
524
- * {@link AgentResult} so the failure stays inspectable.
540
+ * `createAgentQueue` / `createAgentRunner` job), carrying the partial {@link AgentResult} so
541
+ * the failure stays inspectable, and the machine-readable `code` `'PARTIAL'`.
525
542
  *
526
543
  * @remarks
527
544
  * A partial result means the agent was cancelled (an external `signal` abort, a queue /
528
545
  * runner abort threaded in, a `timeout` deadline, or an exhausted token `budget`) rather
529
- * than finishing naturally. For a durable JOB that is a failure by default: throwing this
546
+ * than finishing naturally. For a durable job that is a failure by default: throwing this
530
547
  * lets the Queue's retries re-run the job and a Runner's fail-fast abort its siblings.
531
548
  * Set `partial: true` (see `AgentQueueOptions` / `AgentRunnerOptions`) to treat a
532
549
  * partial as success instead, in which case this is never thrown. Narrow a caught value
@@ -543,11 +560,11 @@ export declare class AgentJobError extends Error {
543
560
  }
544
561
 
545
562
  /**
546
- * Represents a JSON-serializable agent job — the descriptor a durable queue / runner runs. Its
547
- * non-serializable pieces (the provider, tools, authority, scheduler) are referenced by
548
- * NAME and resolved to live objects through an {@link AgentRegistryInterface} at handler
549
- * time; its data fields (the seed `messages`, `system`, `limit`, `timeout`, and a token
550
- * `budget` ceiling) carry directly.
563
+ * Represents a JSON-serializable agent job — the descriptor a durable queue or runner runs. Its
564
+ * non-serializable pieces (the provider, tools, authority, scheduler) are referenced by name and
565
+ * resolved to live objects through an {@link AgentRegistryInterface} at handler time, while its
566
+ * data fields (the seed `messages`, `system`, `limit`, `timeout`, and a token `budget` ceiling)
567
+ * carry directly.
551
568
  *
552
569
  * @remarks
553
570
  * Because every field is JSON-serializable, a job survives a crash through the Queue's
@@ -581,7 +598,7 @@ export declare interface AgentJobInput {
581
598
  /**
582
599
  * Lists the sub-agent jobs this job fans out — each a nested {@link AgentJobInput} (so the whole
583
600
  * tree stays serializable). On a `createAgentRunner`, the handler `controller.spawn`s
584
- * each child through the same bounded queue BEFORE running this (parent) job, so the
601
+ * each child through the same bounded queue before running this (parent) job, so the
585
602
  * children run as sibling sub-agents and their results join the run after the declared
586
603
  * jobs (in spawn order). Ignored by `createAgentQueue` (a queue has no fan-out).
587
604
  */
@@ -589,7 +606,11 @@ export declare interface AgentJobInput {
589
606
  }
590
607
 
591
608
  /**
592
- * Configures `createAgent` — bounds and pacing for the agent loop.
609
+ * Configures `createAgent` — the loop's bounds and pacing, the reserved `on` hooks, the
610
+ * construction-time context wiring (`instructions` / `workspaces` / `scope`), the `conversations`
611
+ * registry that is the message source, the context `window` budget that opts into automatic
612
+ * compaction of the active conversation, and the `strict` switch that aborts the run on an
613
+ * automatic-compaction summarizer failure instead of the lenient default.
593
614
  *
594
615
  * @remarks
595
616
  * - `system` — an optional system prompt prepended to the turn (seeds the context).
@@ -609,16 +630,16 @@ export declare interface AgentJobInput {
609
630
  * - `signal` — an optional external `AbortSignal` whose abort cancels the turn (a
610
631
  * partial result).
611
632
  * - `conversations` — an optional {@link ConversationManagerInterface} forwarded to the agent's
612
- * context as the message source (so `context.messages` is its ACTIVE conversation's live tail);
633
+ * context as the message source (so `context.messages` is its active conversation's live tail);
613
634
  * omitted ⇒ a fresh registry holding one default conversation. Auto-compaction (`window`) folds
614
- * the ACTIVE conversation when it is summarizable.
615
- * - `window` — an optional CONTEXT {@link BudgetInterface} for AUTOMATIC conversation
616
- * compaction: when set, the loop measures the CURRENT FULL prompt against this budget each turn
635
+ * the active conversation when it is summarizable.
636
+ * - `window` — an optional context {@link BudgetInterface} for automatic conversation
637
+ * compaction: when set, the loop measures the current full prompt against this budget each turn
617
638
  * (its `consumer` is a token estimator, its `max` the context window) and, when the prompt
618
- * reaches the window AND the active conversation is summarizable, COMPACTS the active
639
+ * reaches the window and the active conversation is summarizable, compacts the active
619
640
  * conversation + continues on the rebuilt smaller view — compact-and-continue, distinct from
620
641
  * `budget`'s hard abort. Omitted ⇒ no auto-compaction.
621
- * - `strict` — when `true`, a summarizer failure during AUTOMATIC compaction ABORTS the run
642
+ * - `strict` — when `true`, a summarizer failure during automatic compaction aborts the run
622
643
  * (rethrown after the `fault` event, propagating through `#run` to a genuine `error`
623
644
  * settle) instead of skipping compaction and continuing over-window. Defaults to `false`
624
645
  * (lenient — the prior, byte-for-byte behavior).
@@ -663,27 +684,27 @@ export declare interface AgentOptions {
663
684
  */
664
685
  readonly authority?: AuthorityInterface;
665
686
  /**
666
- * Holds an optional {@link ConversationManagerInterface} that becomes the agent context's MESSAGE
667
- * SOURCE — forwarded to the {@link AgentContextInterface} the agent builds, so
668
- * `agent.context.messages` IS its ACTIVE conversation's live tail and `build()` folds that
687
+ * Holds an optional {@link ConversationManagerInterface} that becomes the agent context's message
688
+ * source — forwarded to the {@link AgentContextInterface} the agent builds, so
689
+ * `agent.context.messages` is its active conversation's live tail and `build()` folds that
669
690
  * conversation's `view()` (the per-section summaries + the live tail). Omitted ⇒ a fresh
670
- * registry holding one default conversation. With `window` set, AUTOMATIC compaction folds the
671
- * ACTIVE conversation between turns (when it is summarizable).
691
+ * registry holding one default conversation. With `window` set, automatic compaction folds the
692
+ * active conversation between turns (when it is summarizable).
672
693
  */
673
694
  readonly conversations?: ConversationManagerInterface;
674
695
  /**
675
- * Holds an optional CONTEXT {@link BudgetInterface} for AUTOMATIC compaction. Its `consumer` is a
696
+ * Holds an optional context {@link BudgetInterface} for automatic compaction. Its `consumer` is a
676
697
  * token estimator (for example the exported {@link import('./helpers.js').estimateMessages}) and
677
- * its `max` is the context window. When set, the loop measures the CURRENT FULL prompt (the
678
- * next provider request) against this budget each turn; when that prompt reaches the window AND
698
+ * its `max` is the context window. When set, the loop measures the current full prompt (the
699
+ * next provider request) against this budget each turn; when that prompt reaches the window and
679
700
  * the active conversation is summarizable, it **compacts the active conversation + continues on
680
701
  * the rebuilt smaller view** (compact-and-continue) — the same consume-to-a-ceiling primitive
681
702
  * as the cost `budget`, but compaction is the ceiling action instead of abort. Omit to disable.
682
703
  */
683
704
  readonly window?: BudgetInterface<readonly Message[]>;
684
705
  /**
685
- * If `true`, a summarizer failure during AUTOMATIC compaction ABORTS the run — the
686
- * `fault` event still fires, then the caught error is RETHROWN so the run settles
706
+ * If `true`, a summarizer failure during automatic compaction aborts the run — the
707
+ * `fault` event still fires, then the caught error is rethrown so the run settles
687
708
  * `error` instead of continuing over-window. Defaults to `false` (lenient — the run
688
709
  * continues over-window, byte-for-byte the prior behavior).
689
710
  */
@@ -698,9 +719,9 @@ export declare interface AgentOptions {
698
719
  * - `registry` — the {@link AgentRegistryInterface} the handler rehydrates each job
699
720
  * through (required).
700
721
  * - `partial` — the partial policy. A partial {@link AgentResult} (a job committed
701
- * early from an abort / budget / timeout) is by DEFAULT a FAILURE: the handler THROWS
722
+ * early from an abort / budget / timeout) is by default a failure: the handler throws
702
723
  * an {@link import('./errors.js').AgentJobError}, so the Queue's retries (and a
703
- * Runner's fail-fast) engage. Set `true` to treat a partial as SUCCESS instead — the
724
+ * Runner's fail-fast) engage. Set `true` to treat a partial as success instead — the
704
725
  * handler resolves the partial result rather than throwing.
705
726
  * - `concurrency` / `retries` / `timeout` / `store` — passed straight to the backing
706
727
  * `QueueInterface` (see `QueueOptions`): bounded concurrency, the retry budget, the
@@ -708,7 +729,7 @@ export declare interface AgentOptions {
708
729
  */
709
730
  export declare interface AgentQueueOptions {
710
731
  readonly registry: AgentRegistryInterface;
711
- /** If `true`, a partial `AgentResult` resolves as success; if `false` (the default), it THROWS and retries engage. */
732
+ /** If `true`, a partial `AgentResult` resolves as success; if `false` (the default), it throws and retries engage. */
712
733
  readonly partial?: boolean;
713
734
  readonly concurrency?: number;
714
735
  readonly retries?: number;
@@ -717,9 +738,10 @@ export declare interface AgentQueueOptions {
717
738
  }
718
739
 
719
740
  /**
720
- * Makes a durable, JSON-serializable {@link AgentJobInput} runnable — holds the named
721
- * pools of live, non-serializable pieces (providers, tools, authorities, schedulers) and
722
- * rehydrates a seeded, signal-wired {@link Agent} from a job's names + data.
741
+ * Makes a durable, JSON-serializable {@link AgentJobInput} runnable — holds the named pools of
742
+ * live, non-serializable pieces (providers, tools, authorities, schedulers), throws on a name
743
+ * absent from its pool, and `build`s a seeded, signal-wired {@link Agent} from a job's names and
744
+ * data.
723
745
  *
724
746
  * @remarks
725
747
  * - **Why it exists.** An `AgentJobInput` is serializable so it can survive a crash in a
@@ -728,9 +750,9 @@ export declare interface AgentQueueOptions {
728
750
  * construct it once with the live pools, then a queue / runner handler calls `build`
729
751
  * on each (possibly restored) job to get a ready agent.
730
752
  * - **Accessors throw on a miss.** `provider` / `tool` / `authority` / `scheduler` resolve a
731
- * name against their pool and THROW an {@link AgentError} carrying `code: 'REGISTRY'` and
753
+ * name against their pool and throw an {@link AgentError} carrying `code: 'REGISTRY'` and
732
754
  * the message `unknown <category>: <name>` when it is absent — an unknown name in a
733
- * rehydrated job is a programmer / config error that must fail LOUDLY at build time, never
755
+ * rehydrated job is a programmer / config error that must fail loudly at build time, never
734
756
  * silently resolve to `undefined` and run an agent missing a dependency.
735
757
  * - **`build` rehydrates.** Resolve the job's `provider`; assemble a fresh
736
758
  * {@link ToolManager} from the `tools` names; rebuild the token `budget` from its
@@ -767,7 +789,7 @@ export declare class AgentRegistry implements AgentRegistryInterface {
767
789
  *
768
790
  * @remarks
769
791
  * - **Accessors throw on a miss.** `provider` / `tool` / `authority` / `scheduler` look one
770
- * up by name and THROW an {@link AgentError} carrying `code: 'REGISTRY'` and the message
792
+ * up by name and throw an {@link AgentError} carrying `code: 'REGISTRY'` and the message
771
793
  * `unknown <category>: <name>` when the name is unregistered — an unknown name in a
772
794
  * rehydrated job must fail loudly, never silently resolve to `undefined`, so a
773
795
  * misconfigured job surfaces at once rather than running with a missing dependency.
@@ -780,7 +802,8 @@ export declare class AgentRegistry implements AgentRegistryInterface {
780
802
  */
781
803
  export declare interface AgentRegistryInterface {
782
804
  /**
783
- * Resolves a registered {@link ProviderInterface} by name.
805
+ * Resolves a registered {@link ProviderInterface} by name — throws `unknown provider: <name>` when
806
+ * absent.
784
807
  *
785
808
  * @param name - The provider's registry key
786
809
  * @returns The live provider
@@ -788,7 +811,8 @@ export declare interface AgentRegistryInterface {
788
811
  */
789
812
  provider(name: string): ProviderInterface;
790
813
  /**
791
- * Resolves a registered {@link ToolInterface} by name.
814
+ * Resolves a registered {@link ToolInterface} by name — throws `unknown tool: <name>` when
815
+ * absent.
792
816
  *
793
817
  * @param name - The tool's registry key
794
818
  * @returns The live tool
@@ -796,7 +820,8 @@ export declare interface AgentRegistryInterface {
796
820
  */
797
821
  tool(name: string): ToolInterface;
798
822
  /**
799
- * Resolves a registered {@link AuthorityInterface} by name.
823
+ * Resolves a registered {@link AuthorityInterface} by name — throws `unknown authority: <name>` when
824
+ * absent.
800
825
  *
801
826
  * @param name - The authority's registry key
802
827
  * @returns The live authority
@@ -804,7 +829,8 @@ export declare interface AgentRegistryInterface {
804
829
  */
805
830
  authority(name: string): AuthorityInterface;
806
831
  /**
807
- * Resolves a registered {@link SchedulerInterface} by name.
832
+ * Resolves a registered {@link SchedulerInterface} by name — throws `unknown scheduler: <name>` when
833
+ * absent.
808
834
  *
809
835
  * @param name - The scheduler's registry key
810
836
  * @returns The live scheduler
@@ -812,8 +838,9 @@ export declare interface AgentRegistryInterface {
812
838
  */
813
839
  scheduler(name: string): SchedulerInterface;
814
840
  /**
815
- * Rehydrates a live, seeded {@link AgentInterface} from a serializable job — resolving
816
- * its names, rebuilding its budget, seeding its conversation, and wiring `signal`.
841
+ * Rehydrates a live, seeded {@link AgentInterface} from a serializable {@link AgentJobInput}
842
+ * — resolving its names, rebuilding its token budget, seeding its conversation, and wiring
843
+ * `signal`; a name absent from its pool throws.
817
844
  *
818
845
  * @param input - The serializable {@link AgentJobInput} to rehydrate
819
846
  * @param signal - An optional cancel threaded into the agent (a queue / runner abort)
@@ -824,20 +851,21 @@ export declare interface AgentRegistryInterface {
824
851
  }
825
852
 
826
853
  /**
827
- * Configures `createAgentRegistry` — the named pools of live, non-serializable pieces
828
- * a {@link AgentJobInput}'s names resolve against.
854
+ * Configures `createAgentRegistry` — the named pools of live, non-serializable pieces an {@link
855
+ * AgentJobInput}'s names resolve against, plus the optional durable `store` every built agent's
856
+ * conversation manager shares.
829
857
  *
830
858
  * @remarks
831
859
  * `providers` is required (a job always names a provider); `tools` / `authorities` /
832
860
  * `schedulers` are optional pools, each an entity-keyed record mapping a registry
833
861
  * name to its live object. A name absent from its pool throws when resolved (see
834
862
  * {@link AgentRegistryInterface}). `store` is the durable {@link ConversationStoreInterface}
835
- * every agent this registry builds carries: each built agent gets its OWN store-backed
836
- * {@link ConversationManagerInterface} over THIS shared store — a fresh conversation id per
863
+ * every agent this registry builds carries: each built agent gets its own store-backed
864
+ * {@link ConversationManagerInterface} over this shared store — a fresh conversation id per
837
865
  * build (minted by the seeded `add`), so concurrent builds never collide, and the store
838
866
  * accumulates one snapshot per built agent that later calls `save`. Persistence
839
867
  * stays caller-triggered (`open` / `save`) — `build` never hydrates, so `build` stays
840
- * SYNCHRONOUS. Omitted ⇒ every built agent gets a registry-only manager, byte-identical
868
+ * synchronous. Omitted ⇒ every built agent gets a registry-only manager, byte-identical
841
869
  * to today.
842
870
  */
843
871
  export declare interface AgentRegistryOptions {
@@ -857,13 +885,13 @@ export declare interface AgentRegistryOptions {
857
885
  * `partial` is `true` when the turn was committed early from a cancel — an external
858
886
  * `signal` abort, the turn's own `abort()`, a `timeout` deadline, or an exhausted
859
887
  * `budget` — in which case `content` is whatever had accumulated when the cancel
860
- * landed. `partial` is ALSO `true` when the loop exhausted its `limit` while still
888
+ * landed. `partial` is also `true` when the loop exhausted its `limit` while still
861
889
  * holding unresolved tool intent (the model requested tools on the very last allowed
862
890
  * turn) — a distinct, non-cancel cause covered by {@link RunOutcome.exhausted} (see
863
891
  * the `exhaust` {@link AgentEventMap} event). It is `false` for a turn that ran to a
864
892
  * natural finish (including a `limit: 0` run, which never enters the loop). `usage` is
865
893
  * present only when at least one provider call reported usage — an aborted run's `usage`
866
- * INCLUDES the cancelled turn's tokens when the provider reports partial usage on the
894
+ * includes the cancelled turn's tokens when the provider reports partial usage on the
867
895
  * abort (folded in exactly like a completed turn's); a provider that cannot observe
868
896
  * usage mid-stream (for example a daemon whose final counts never arrive before the cancel)
869
897
  * reports none for that turn, and none is fabricated. `thinking` is present
@@ -881,8 +909,11 @@ export declare interface AgentResult {
881
909
  }
882
910
 
883
911
  /**
884
- * Projects an unknown value onto the canonical JSON representation of an
885
- * {@link AgentResult}.
912
+ * Projects an unknown value onto a fresh, exact `JSONValue` representation of an
913
+ * {@link AgentResult} — capturing each structural field once through a total boundary,
914
+ * accepting conforming accessors and inherited properties, preserving finite negative and
915
+ * fractional usage counts, dropping extras, and resolving `undefined` for a malformed field, a
916
+ * non-finite usage number, a throwing getter, or a hostile or revoked proxy.
886
917
  *
887
918
  * @remarks
888
919
  * This is a total hostile-boundary projection. Each structural field is captured once
@@ -912,7 +943,7 @@ export declare function agentResultToJSON(value: unknown): JSONValue | undefined
912
943
  *
913
944
  * @remarks
914
945
  * Identical partial policy to {@link AgentQueueOptions} (`partial` — a partial
915
- * `AgentResult` THROWS by default so the run's fail-fast engages, `true` resolves it as
946
+ * `AgentResult` throws by default so the run's fail-fast engages, `true` resolves it as
916
947
  * success). `concurrency` / `retries` / `timeout` pass straight to the backing
917
948
  * `RunnerInterface` (see `RunnerOptions`). The runner enables sub-agent fan-out: a
918
949
  * parent job's handler can `controller.spawn(childJob)` to launch a child agent job
@@ -920,7 +951,7 @@ export declare function agentResultToJSON(value: unknown): JSONValue | undefined
920
951
  */
921
952
  export declare interface AgentRunnerOptions {
922
953
  readonly registry: AgentRegistryInterface;
923
- /** If `true`, a partial `AgentResult` resolves as success; if `false` (the default), it THROWS and fail-fast engages. */
954
+ /** If `true`, a partial `AgentResult` resolves as success; if `false` (the default), it throws and fail-fast engages. */
924
955
  readonly partial?: boolean;
925
956
  readonly concurrency?: number;
926
957
  readonly retries?: number;
@@ -929,14 +960,15 @@ export declare interface AgentRunnerOptions {
929
960
 
930
961
  /**
931
962
  * Carries the per-run override bag an {@link AgentInterface}'s `generate` / `stream` accepts — each
932
- * member overrides the matching {@link AgentOptions} value for ONE run.
963
+ * member overrides the matching {@link AgentOptions} value for one run, where `think` and `schema`
964
+ * forward to the provider call and `signal` composes with the constructed one.
933
965
  *
934
966
  * @remarks
935
967
  * Every member is optional and resolved independently, so an omitted member leaves the
936
968
  * agent's constructed value in force and a caller that passes no options runs exactly the
937
969
  * agent it configured. `think` / `schema` ride through to the provider as
938
970
  * {@link ProviderStreamOptions}; `limit` / `timeout` / `budget` replace their construction
939
- * defaults for this run only; `signal` COMPOSES with the constructed `signal` (both fold into
971
+ * defaults for this run only; `signal` composes with the constructed `signal` (both fold into
940
972
  * the run's bound abort) rather than replacing it. Nothing here mutates the agent — the next
941
973
  * run reads the construction defaults again.
942
974
  */
@@ -956,23 +988,23 @@ export declare interface AgentRunOptions {
956
988
  */
957
989
  readonly schema?: Readonly<Record<string, unknown>>;
958
990
  /**
959
- * Overrides {@link AgentOptions.limit} for THIS run only — the max tool-iteration turns
991
+ * Overrides {@link AgentOptions.limit} for this run only — the max tool-iteration turns
960
992
  * before the loop stops. Omitted ⇒ the agent's constructed `limit` applies.
961
993
  */
962
994
  readonly limit?: number;
963
995
  /**
964
- * Overrides {@link AgentOptions.timeout} for THIS run only — a wall-clock deadline (ms)
996
+ * Overrides {@link AgentOptions.timeout} for this run only — a wall-clock deadline (ms)
965
997
  * whose abort commits a partial result. Omitted ⇒ the agent's constructed `timeout` applies.
966
998
  */
967
999
  readonly timeout?: number;
968
1000
  /**
969
- * Overrides {@link AgentOptions.budget} for THIS run only — a token cost bound whose abort
1001
+ * Overrides {@link AgentOptions.budget} for this run only — a token cost bound whose abort
970
1002
  * commits a partial result; `start()`ed for this run exactly as the constructed budget is.
971
1003
  * Omitted ⇒ the agent's constructed `budget` applies.
972
1004
  */
973
1005
  readonly budget?: BudgetInterface<TokenUsage>;
974
1006
  /**
975
- * Carries an additional per-run external cancel, COMPOSED with {@link AgentOptions.signal} (both
1007
+ * Carries an additional per-run external cancel, composed with {@link AgentOptions.signal} (both
976
1008
  * fold into the run's bound abort through `AbortSignal.any` — neither is dropped). Omitted ⇒
977
1009
  * only the agent's constructed `signal` (if any) applies.
978
1010
  */
@@ -994,10 +1026,11 @@ export declare type AgentStreamInterface = StreamInterface<AgentChunk, AgentResu
994
1026
 
995
1027
  /**
996
1028
  * Assembles the settled {@link AgentResult} from a run's {@link RunOutcome} — `thinking` and
997
- * `usage` are carried only when the run surfaced them.
1029
+ * `usage` are carried only when the run surfaced them, and the loop-internal `exhausted` flag is
1030
+ * left out.
998
1031
  *
999
1032
  * @remarks
1000
- * Pure and total. An absent optional is OMITTED rather than stored as `undefined` (the
1033
+ * Pure and total. An absent optional is omitted rather than stored as `undefined` (the
1001
1034
  * present-when-given convention the message store follows), so a settled result JSON
1002
1035
  * round-trips without an explicit `undefined` field. `exhausted` is loop bookkeeping and does
1003
1036
  * not reach the public result — the `exhaust` event carries it instead.
@@ -1014,11 +1047,11 @@ export declare type AgentStreamInterface = StreamInterface<AgentChunk, AgentResu
1014
1047
  export declare function assembleResult(outcome: RunOutcome): AgentResult;
1015
1048
 
1016
1049
  /**
1017
- * Copies a message with image data merged onto its `images` — the message's own images
1018
- * first, then the attached data.
1050
+ * Copies a message with image data merged onto its `images` — the message's own images first,
1051
+ * then the attached data, carrying `calls` only when present and never mutating the original.
1019
1052
  *
1020
1053
  * @remarks
1021
- * Pure and total: the original message is NEVER mutated. `calls` is carried only when the
1054
+ * Pure and total: the original message is never mutated. `calls` is carried only when the
1022
1055
  * source message has one (kept omitted otherwise, mirroring the store's present-when-given
1023
1056
  * convention).
1024
1057
  *
@@ -1035,13 +1068,14 @@ export declare function assembleResult(outcome: RunOutcome): AgentResult;
1035
1068
  export declare function attachImages(message: Message, data: readonly string[]): Message;
1036
1069
 
1037
1070
  /**
1038
- * Attaches image data to a conversation's LAST user message — the turn a vision provider
1039
- * reads images off.
1071
+ * Attaches image data to a conversation's last user message — the turn a vision provider reads
1072
+ * images off — as a new array with that one message replaced by its carrying copy, and unchanged
1073
+ * when there is no data or no user turn.
1040
1074
  *
1041
1075
  * @remarks
1042
- * Pure and total: the conversation and its messages are NEVER mutated, and the returned array
1076
+ * Pure and total: the conversation and its messages are never mutated, and the returned array
1043
1077
  * replaces exactly the one target message with the copy {@link attachImages} builds. Empty
1044
- * data returns the conversation unchanged; a conversation with NO user message returns it
1078
+ * data returns the conversation unchanged; a conversation with no user message returns it
1045
1079
  * unchanged too (there is nowhere to attach, and the images already rode the system block).
1046
1080
  *
1047
1081
  * @param conversation - The messages to attach into (left unchanged)
@@ -1057,18 +1091,20 @@ export declare function attachImages(message: Message, data: readonly string[]):
1057
1091
  export declare function attachUserImages(conversation: readonly Message[], data: readonly string[]): readonly Message[];
1058
1092
 
1059
1093
  /**
1060
- * Gates the agent loop's tool calls — the synchronous policy consulted before each call
1061
- * runs, turning one {@link AuthorityContext} into an {@link AuthorityDecision}.
1094
+ * Gates the agent loop's tool calls — the synchronous policy consulted before each call runs,
1095
+ * turning one {@link AuthorityContext} into an {@link AuthorityDecision} by walking the ordered
1096
+ * rules first-match-wins and falling back to a configurable default, which allows an unmatched
1097
+ * call unless its `fallback` denies.
1062
1098
  *
1063
1099
  * @remarks
1064
1100
  * - **Ordered, first-match-wins.** `evaluate` walks the configured rules in order and
1065
- * returns the FIRST whose `match(context)` is true as
1066
- * `{ zone, allowed: rule.allowed ?? true, reason }` — a matched rule ALLOWS by
1067
- * default and DENIES only when its `allowed` is explicitly `false`.
1101
+ * returns the first whose `match(context)` is true as
1102
+ * `{ zone, allowed: rule.allowed ?? true, reason }` — a matched rule allows by
1103
+ * default and denies only when its `allowed` is explicitly `false`.
1068
1104
  * - **Fallback.** When no rule matches, `evaluate` returns the configured `fallback`.
1069
1105
  * It defaults to `{ zone: DEFAULT_AUTHORITY_ZONE, allowed: true }` (allow-unmatched),
1070
- * so a rules list of denials behaves as a DENYLIST. To make the gate deny-by-default
1071
- * (an ALLOWLIST — only matched rules that allow get through), pass an `allowed: false`
1106
+ * so a rules list of denials behaves as a denylist. To make the gate deny-by-default
1107
+ * (an allowlist — only matched rules that allow get through), pass an `allowed: false`
1072
1108
  * `fallback`.
1073
1109
  * - **Consulted before each tool call.** The agent loop calls `evaluate({ call })` for
1074
1110
  * every {@link import('@orkestrel/tool').ToolCall} the model emits; a denied call is fed
@@ -1133,7 +1169,8 @@ export declare interface AuthorityDecision {
1133
1169
  */
1134
1170
  export declare interface AuthorityInterface {
1135
1171
  /**
1136
- * Evaluates one tool call against the ordered rules.
1172
+ * Evaluates one tool call against the ordered rules — returns the first matching rule's
1173
+ * verdict, which allows unless `allowed: false`, or the fallback when none match.
1137
1174
  *
1138
1175
  * @param context - The call under consideration (see {@link AuthorityContext})
1139
1176
  * @returns The first matching rule's verdict, or the fallback when none match
@@ -1146,7 +1183,7 @@ export declare interface AuthorityInterface {
1146
1183
  *
1147
1184
  * @remarks
1148
1185
  * `rules` are evaluated in order, first match wins (see {@link AuthorityRule}).
1149
- * `fallback` is the {@link AuthorityDecision} returned when NO rule matches; it
1186
+ * `fallback` is the {@link AuthorityDecision} returned when no rule matches; it
1150
1187
  * defaults to `{ zone: DEFAULT_AUTHORITY_ZONE, allowed: true }` (allow-unmatched — a
1151
1188
  * rules list of denials acts as a denylist). Set `fallback` to an `allowed: false`
1152
1189
  * decision to flip the gate to deny-by-default (an allowlist — only matched rules
@@ -1161,8 +1198,8 @@ export declare interface AuthorityOptions {
1161
1198
  * Represents one ordered policy rule an {@link AuthorityInterface} evaluates.
1162
1199
  *
1163
1200
  * @remarks
1164
- * The FIRST rule whose `match` returns true decides; if none match, the authority's
1165
- * `fallback` decides. A matched rule ALLOWS by default and DENIES only when its
1201
+ * The first rule whose `match` returns true decides; if none match, the authority's
1202
+ * `fallback` decides. A matched rule allows by default and denies only when its
1166
1203
  * `allowed` is explicitly `false`. `zone` classifies the matched call; `reason` is the
1167
1204
  * optional explanation carried into the {@link AuthorityDecision} (and, on a denial,
1168
1205
  * into the denial {@link ToolResult}).
@@ -1175,13 +1212,13 @@ export declare interface AuthorityRule {
1175
1212
  }
1176
1213
 
1177
1214
  /**
1178
- * Builds the FRAMED recap message for one compacted section — the same role and stable `id`
1179
- * as {@link buildSummaryMessage}, with the content prefixed by
1180
- * {@link import('./constants.js').CONVERSATION_RECAP_PREFIX}.
1215
+ * Builds the framed recap message for one compacted section — the same role and stable `id` as
1216
+ * {@link buildSummaryMessage}, with the content prefixed by {@link
1217
+ * import('./constants.js').CONVERSATION_RECAP_PREFIX}.
1181
1218
  *
1182
1219
  * @remarks
1183
- * Pure and total. The prefix is what makes a small model read the message as a CONDENSED
1184
- * RECAP of earlier turns rather than a literal assistant turn to echo or answer from. It is a
1220
+ * Pure and total. The prefix is what makes a small model read the message as a condensed
1221
+ * recap of earlier turns rather than a literal assistant turn to echo or answer from. It is a
1185
1222
  * fixed handful of tokens, so a conversation's `view()` stays lean however many sections it
1186
1223
  * carries.
1187
1224
  *
@@ -1197,12 +1234,12 @@ export declare interface AuthorityRule {
1197
1234
  export declare function buildRecapMessage(section: Section): Message;
1198
1235
 
1199
1236
  /**
1200
- * Builds the RAW synthetic summary message for one compacted section — role `'assistant'`,
1201
- * the section's stable `id`, its `summary` VERBATIM as content.
1237
+ * Builds the raw synthetic summary message for one compacted section — role `'assistant'`, the
1238
+ * section's stable `id`, and its `summary` verbatim as content.
1202
1239
  *
1203
1240
  * @remarks
1204
1241
  * Pure and total. This is the unframed form the rollup regeneration digests (a
1205
- * summary-of-summaries over the section summaries); the recap LABEL is a `view()`
1242
+ * summary-of-summaries over the section summaries); the recap label is a `view()`
1206
1243
  * presentation concern kept out of what the summarizer re-reads — see
1207
1244
  * {@link buildRecapMessage}.
1208
1245
  *
@@ -1218,10 +1255,11 @@ export declare function buildRecapMessage(section: Section): Message;
1218
1255
  export declare function buildSummaryMessage(section: Section): Message;
1219
1256
 
1220
1257
  /**
1221
- * Buffers chunks in a minimal unbounded async channel — the eager pump WRITES them in
1222
- * (`push`) and ends it (`close` / `fail`) regardless of consumption; a consumer READS them back
1223
- * live through the `drain` async-iterator. Decoupling write from read is what lets a
1224
- * producer make progress without a consumer pulling.
1258
+ * Buffers chunks in a minimal unbounded async channel — the eager pump writes them in (`push`)
1259
+ * and ends it (`close` / `fail`) regardless of consumption, while a consumer reads them back live
1260
+ * through the `drain` async-iterator. Decoupling write from read is what lets a producer make
1261
+ * progress without a consumer pulling, and it is why an agent's `result` settles whether or not
1262
+ * its `events` are drained.
1225
1263
  *
1226
1264
  * @remarks
1227
1265
  * The standard resolver-swap: a waiting `drain` parks on `#wake` (a void resolver);
@@ -1250,24 +1288,25 @@ export declare class Channel<T> implements ChannelInterface<T> {
1250
1288
  }
1251
1289
 
1252
1290
  /**
1253
- * Buffers values in an unbounded async channel — a producer WRITES them in (`push`) and
1254
- * ends it (`close` / `fail`) regardless of consumption, while a consumer READS them back
1255
- * live through `drain`.
1291
+ * Buffers values in an unbounded async channel — a producer writes them in (`push`) and ends it
1292
+ * (`close` / `fail`) regardless of consumption, while a consumer reads them back live through
1293
+ * `drain`.
1256
1294
  *
1257
1295
  * @remarks
1258
1296
  * Decoupling the write from the read is what lets a producer make progress with nobody
1259
1297
  * pulling: an agent's eager pump writes each {@link AgentChunk} into one, so the run's
1260
1298
  * `result` settles whether or not `events` is ever drained. A waiting `drain` parks on a
1261
1299
  * resolver the next `push` / `close` / `fail` fires, so a value pushed at a parked reader is
1262
- * delivered rather than dropped. Buffered values are always yielded BEFORE the end is
1263
- * reported, so a `close` arriving alongside the last values still delivers them. The FIRST
1300
+ * delivered rather than dropped. Buffered values are always yielded before the end is
1301
+ * reported, so a `close` arriving alongside the last values still delivers them. The first
1264
1302
  * failure wins — a later `close` / `fail` cannot override a recorded error. Event-free.
1265
1303
  *
1266
1304
  * @typeParam T - The value type the channel carries
1267
1305
  */
1268
1306
  export declare interface ChannelInterface<T> {
1269
1307
  /**
1270
- * Writes one value — buffered, then handed to a parked consumer.
1308
+ * Writes one value — buffered, then handed to a parked consumer; a value pushed at an
1309
+ * already-parked reader is delivered, never dropped.
1271
1310
  *
1272
1311
  * @param value - The value to enqueue
1273
1312
  */
@@ -1275,13 +1314,14 @@ export declare interface ChannelInterface<T> {
1275
1314
  /** Ends the channel normally — a draining consumer returns once the buffer is empty. */
1276
1315
  close(): void;
1277
1316
  /**
1278
- * Ends the channel with a failure — a draining consumer throws it once the buffer is empty.
1317
+ * Ends the channel with a failure — a draining consumer throws it once the buffer is empty;
1318
+ * the first failure wins.
1279
1319
  *
1280
1320
  * @param error - The failure to surface (the first one recorded wins)
1281
1321
  */
1282
1322
  fail(error: unknown): void;
1283
1323
  /**
1284
- * Reads the values back live, in write order.
1324
+ * Reads the values back live, in write order — returning on `close` and throwing on `fail`.
1285
1325
  *
1286
1326
  * @returns A generator yielding each pushed value, returning on `close` and throwing on `fail`
1287
1327
  */
@@ -1289,11 +1329,11 @@ export declare interface ChannelInterface<T> {
1289
1329
  }
1290
1330
 
1291
1331
  /**
1292
- * Collects the `base64` payload of the IMAGE files in a workspace file list — the data an
1293
- * agent context attaches to the last user message.
1332
+ * Collects the `base64` payload of the image files in a workspace file list — the data an agent
1333
+ * context attaches to the last user message.
1294
1334
  *
1295
1335
  * @remarks
1296
- * Pure and total. `isBinary` NARROWS the tagless content to its binary arm (a total guard,
1336
+ * Pure and total. `isBinary` narrows the tagless content to its binary arm (a total guard,
1297
1337
  * never an assertion), then the MIME prefix gates it to an image, so a text file and a non-image
1298
1338
  * binary (a PDF) are both skipped. Order follows the file list.
1299
1339
  *
@@ -1309,14 +1349,15 @@ export declare interface ChannelInterface<T> {
1309
1349
  export declare function collectImageData(files: readonly FileInterface[]): readonly string[];
1310
1350
 
1311
1351
  /**
1312
- * Configures one {@link ConversationInterface.compact} call — overrides for ONE fold.
1352
+ * Configures one {@link ConversationInterface.compact} call — the retained-tail size, the
1353
+ * `sections` cap, or both, overridden for one fold.
1313
1354
  *
1314
1355
  * @remarks
1315
- * `keep` overrides the conversation's configured retained-tail size for THIS compaction only
1356
+ * `keep` overrides the conversation's configured retained-tail size for this compaction only
1316
1357
  * (the older `count - keep` live messages fold; when `count <= keep` nothing folds and
1317
1358
  * `compact()` is a no-op returning `undefined`). Omitted ⇒ the conversation's own `keep`
1318
1359
  * (its option, or `DEFAULT_CONVERSATION_KEEP`) applies. `sections` overrides the conversation's
1319
- * configured `sections` cap for THIS compaction only — after the new section is pushed, an
1360
+ * configured `sections` cap for this compaction only — after the new section is pushed, an
1320
1361
  * overflow past `sections` folds the oldest sections into one merged section. Omitted ⇒ the
1321
1362
  * conversation's own `sections` cap (or unlimited) applies.
1322
1363
  */
@@ -1328,17 +1369,17 @@ export declare interface CompactOptions {
1328
1369
  }
1329
1370
 
1330
1371
  /**
1331
- * Holds a provider's OPTIONAL context-framing default, keyed by section kind — the framing a
1332
- * model prefers (for example XML tags against Markdown headers), declared by a
1333
- * {@link ProviderInterface} that opts in.
1372
+ * Holds a provider's optional context-framing default, keyed by section kind — the framing a model
1373
+ * prefers (for example XML tags against Markdown headers), declared by a {@link ProviderInterface}
1374
+ * that opts in.
1334
1375
  *
1335
1376
  * @remarks
1336
1377
  * Each key is a {@link ContextSectionFormat} for one of the observable context sections
1337
1378
  * (the `instructions` section), so a provider can frame each section independently — and any
1338
- * it omits falls through to that manager's built-in default. It is the PROVIDER-DEFAULT
1339
- * level of the {@link import('./AgentContext.js').AgentContext} build cascade: it BEATS a
1340
- * manager's built-in default but is BEATEN by a manager-options override and by a per-item
1341
- * override (see {@link AgentContextInterface.build}). It references the ABSTRACT core
1379
+ * it omits falls through to that manager's built-in default. It is the provider-default
1380
+ * level of the {@link import('./AgentContext.js').AgentContext} build cascade: it beats a
1381
+ * manager's built-in default but is beaten by a manager-options override and by a per-item
1382
+ * override (see {@link AgentContextInterface.build}). It references the abstract core
1342
1383
  * item interface ({@link InstructionInterface}), so a provider opting in imports it from
1343
1384
  * `@orkestrel/agent` — the type is provider-agnostic, with no backend coupling. Omitting it
1344
1385
  * entirely (the default for an agnostic provider) leaves every section on its manager's
@@ -1356,17 +1397,17 @@ export declare interface ContextFormat {
1356
1397
  * line rendered once after the items.
1357
1398
  *
1358
1399
  * @remarks
1359
- * `open`, `render`, and `close` are OPTIONAL and resolved INDEPENDENTLY (so an override may set only
1400
+ * `open`, `render`, and `close` are optional and resolved independently (so an override may set only
1360
1401
  * the top, only the per-item rendering, only the bottom, or any mix). A section assembles
1361
1402
  * as `[open, ...items.map(render), close]` with empty / absent slots dropped, the survivors
1362
- * blank-line (`\n\n`) joined — so `open` + `close` together let a developer WRAP the whole
1403
+ * blank-line (`\n\n`) joined — so `open` + `close` together let a developer wrap the whole
1363
1404
  * group (for example `open: '<instructions>'` … `close: '</instructions>'`). `open` is the
1364
1405
  * section's leading text (the header, or a group's opening tag); `render` turns one section
1365
1406
  * item (an {@link InstructionInterface}) into its prompt text; `close` is the trailing text.
1366
1407
  * `open` and `render` cascade through the
1367
1408
  * built-in floor (`open` ⇒ the manager's built-in header, `render` ⇒ the manager's built-in
1368
- * rendering); `close` has NO built-in, so an unset `close` yields no closing line.
1369
- * It is the unit BOTH a provider's {@link ContextFormat} (a per-section-kind
1409
+ * rendering); `close` has no built-in, so an unset `close` yields no closing line.
1410
+ * It is the unit both a provider's {@link ContextFormat} (a per-section-kind
1370
1411
  * default) and a manager's `Options` carry — see {@link AgentContextInterface.build} for
1371
1412
  * the full precedence.
1372
1413
  *
@@ -1374,7 +1415,7 @@ export declare interface ContextFormat {
1374
1415
  */
1375
1416
  export declare interface ContextSectionFormat<T> {
1376
1417
  /**
1377
- * Holds text rendered ONCE before the section's items — the section header or a group's
1418
+ * Holds text rendered once before the section's items — the section header or a group's
1378
1419
  * opening wrapper, for example `'<instructions>'`; omitted ⇒ the next cascade level decides
1379
1420
  * (defaulting to the built-in header).
1380
1421
  */
@@ -1382,25 +1423,25 @@ export declare interface ContextSectionFormat<T> {
1382
1423
  /** Overrides one item's rendering; omitted ⇒ the next cascade level decides. */
1383
1424
  readonly render?: (item: T) => string;
1384
1425
  /**
1385
- * Holds text rendered ONCE after the section's items — a group's closing wrapper, for
1426
+ * Holds text rendered once after the section's items — a group's closing wrapper, for
1386
1427
  * example `'</instructions>'`; omitted ⇒ no closing line (there is no built-in close).
1387
1428
  */
1388
1429
  readonly close?: string;
1389
1430
  }
1390
1431
 
1391
1432
  /**
1392
- * Exposes the manager surface one context section's format cascade reads — its built-in
1393
- * `open` / `render`, plus the raw options override the cascade layers a provider
1394
- * default beneath.
1433
+ * Exposes the manager surface one context section's format cascade reads — its built-in `open` /
1434
+ * `render`, plus the raw options override the cascade layers a provider default beneath; {@link
1435
+ * InstructionManagerInterface} satisfies it structurally.
1395
1436
  *
1396
1437
  * @remarks
1397
1438
  * The narrow contract the cascade resolvers
1398
1439
  * ({@link import('./helpers.js').resolveOpen} / {@link import('./helpers.js').resolveClose} /
1399
- * {@link import('./helpers.js').resolveItem}) take, so they stay independent of WHICH manager
1440
+ * {@link import('./helpers.js').resolveItem}) take, so they stay independent of which manager
1400
1441
  * supplies the section: an {@link InstructionManagerInterface} satisfies it structurally.
1401
1442
  * `open` and `render` already encapsulate `[options-override → built-in]` (so a manager
1402
1443
  * used standalone renders correctly), and `format` exposes the raw override so `build()` can
1403
- * interleave the provider default BENEATH it.
1444
+ * interleave the provider default beneath it.
1404
1445
  *
1405
1446
  * @typeParam T - The section item this source renders
1406
1447
  */
@@ -1409,41 +1450,45 @@ export declare interface ContextSectionSourceInterface<T> {
1409
1450
  readonly open: string;
1410
1451
  /** Holds the raw manager-options override, or `undefined` when none was supplied. */
1411
1452
  readonly format: ContextSectionFormat<T> | undefined;
1412
- /** Renders one item (already resolved against the manager-options override). */
1453
+ /**
1454
+ * Renders one section item, already resolved against the manager-options override and
1455
+ * otherwise on the built-in rendering.
1456
+ */
1413
1457
  render(item: T): string;
1414
1458
  }
1415
1459
 
1416
1460
  /**
1417
- * Represents a conversation — a live uncompacted tail of messages it OWNS DIRECTLY ABOVE a
1418
- * flat message store, plus compacted, summarized {@link Section}s and a regenerated rollup
1419
- * `summary`, with on-demand `rehydrate` and substring `search`, driven by a provider-agnostic
1420
- * {@link ConversationSummaryHandler} seam (so `core` never imports a provider).
1461
+ * Represents a conversation — a live uncompacted tail of messages it owns directly above a flat
1462
+ * message store, plus compacted, summarized {@link Section}s, a regenerated rollup `summary`, and
1463
+ * a `summarizable` flag, with on-demand `rehydrate` and substring `search`, driven by a
1464
+ * provider-agnostic {@link ConversationSummaryHandler} seam so `core` never imports a provider.
1465
+ * Observable through its own `emitter`.
1421
1466
  *
1422
1467
  * @remarks
1423
- * - **Live tail + sections.** The conversation OWNS its live tail DIRECTLY — `#messages` is an
1468
+ * - **Live tail + sections.** The conversation owns its live tail directly — `#messages` is an
1424
1469
  * insertion-ordered `Map` of immutable {@link Message}s keyed by their minted id
1425
- * (the SAME store mechanics a flat manager had, folded in: `add` / `message` / `messages` /
1470
+ * (the same store mechanics a flat manager had, folded in: `add` / `message` / `messages` /
1426
1471
  * `remove` / `clear` / `count`), exactly as a `Workspace` owns its files (no separate
1427
1472
  * per-value manager). `#sections` are the compacted history (oldest → newest), each a
1428
- * summarized slice that RETAINS its originals. `#summary` is the rollup (a
1473
+ * summarized slice that retains its originals. `#summary` is the rollup (a
1429
1474
  * summary-of-summaries over all sections), regenerated on each compaction (`undefined`
1430
1475
  * until the first).
1431
- * - **`view()`.** Each section folds to ONE synthetic summary message (role `'assistant'` — a
1476
+ * - **`view()`.** Each section folds to one synthetic summary message (role `'assistant'` — a
1432
1477
  * prior-context recap — keyed by the section's stable `id`), then the live messages
1433
- * verbatim. The rollup `summary` is NOT injected (it is separately pull-able); `view()`
1434
- * carries the per-section summaries, which ARE the compaction benefit.
1478
+ * verbatim. The rollup `summary` is not injected (it is separately pull-able); `view()`
1479
+ * carries the per-section summaries, which are the compaction benefit.
1435
1480
  * - **`compact()`.** Folds the oldest `count - keep` live messages into a new section
1436
1481
  * (its `summary` from `#summarize`), removes them from the live tail by id, regenerates the
1437
- * rollup (a SECOND `#summarize` over all section summaries), and emits `summary` then
1482
+ * rollup (a second `#summarize` over all section summaries), and emits `summary` then
1438
1483
  * `compact`. Returns the section, or `undefined` when nothing folds (`count <= keep`).
1439
- * THROWS a {@link ConversationError} when no `#summarize` was supplied. Two summarizer calls
1440
- * per compaction.
1484
+ * Throws a {@link ConversationError} when no `#summarize` was supplied. A compaction calls
1485
+ * the summarizer for the section digest and again for the rollup.
1441
1486
  * - **`rehydrate(id)` / `search(query)`.** `rehydrate` returns a section's full original
1442
1487
  * messages (`[]` for an unknown id) and emits `rehydrate` — a pure read (the caller decides
1443
1488
  * whether to re-add them; `rehydrate` never reinserts). `search` is a case-insensitive
1444
- * substring scan of `content` across ALL messages (every section's originals + the live tail).
1489
+ * substring scan of `content` across all messages (every section's originals + the live tail).
1445
1490
  * - **Observable.** The owned {@link emitter} ({@link ConversationEventMap}) carries
1446
- * `compact` / `summary` / `rehydrate`, emitted directly, strictly AFTER the state change;
1491
+ * `compact` / `summary` / `rehydrate`, emitted directly, strictly after the state change;
1447
1492
  * the emitter isolates a listener throw and routes it to its `error` handler (the `error`
1448
1493
  * option), so a buggy observer can never corrupt a compaction.
1449
1494
  *
@@ -1485,12 +1530,13 @@ export declare class Conversation implements ConversationInterface {
1485
1530
 
1486
1531
  /**
1487
1532
  * Names the framing label a {@link ConversationInterface}'s `view()` prefixes onto each compacted
1488
- * section's summary so a small model reads it as a CONDENSED RECAP of earlier turns — not a
1489
- * literal assistant turn to echo or treat as the live answer.
1533
+ * section's summary so a small model reads it as a condensed recap of earlier turns — the lean
1534
+ * `'[Summary of earlier messages] '` marker, never a literal assistant turn to echo or treat as
1535
+ * the live answer.
1490
1536
  *
1491
1537
  * @remarks
1492
- * Deliberately a FIXED, lean handful of tokens (a short bracketed marker) so the framing adds a
1493
- * bounded `prefix × sections` overhead and NEVER an open-ended blow-up — the
1538
+ * Deliberately a fixed, lean handful of tokens (a short bracketed marker) so the framing adds a
1539
+ * bounded `prefix × sections` overhead and never an open-ended blow-up — the
1494
1540
  * {@link ConversationInterface} no-bloat test guard pins exactly that. Kept here (beside
1495
1541
  * {@link DEFAULT_CONVERSATION_KEEP}) as the conversation layer's one tunable framing constant, so
1496
1542
  * the wording has a single source of truth as it is optimized against real small-model behavior
@@ -1500,12 +1546,13 @@ export declare class Conversation implements ConversationInterface {
1500
1546
  export declare const CONVERSATION_RECAP_PREFIX = "[Summary of earlier messages] ";
1501
1547
 
1502
1548
  /**
1503
- * Reports a conversation with no {@link ConversationSummaryHandler} to fold its messages
1504
- * with, or with a structurally invalid `sections` cap — thrown by a
1505
- * {@link ConversationInterface}'s `compact()`, carrying a machine-readable `code`.
1549
+ * Reports a conversation with no {@link ConversationSummaryHandler} to fold its messages with,
1550
+ * or with a `sections` cap below `1` — thrown by a {@link ConversationInterface}'s `compact()`
1551
+ * or its construction, carrying the machine-readable `code`
1552
+ * `'SUMMARIZER' | 'SECTIONS'`.
1506
1553
  *
1507
1554
  * @remarks
1508
- * Compaction REQUIRES a summarizer (it digests the folded slice into a section summary and
1555
+ * Compaction requires a summarizer (it digests the folded slice into a section summary and
1509
1556
  * regenerates the rollup); a conversation created without one can still store + `view()` its
1510
1557
  * live tail, but a `compact()` is a programmer error and throws this with `'SUMMARIZER'`.
1511
1558
  * A `sections` cap (on {@link import('./types.js').ConversationOptions} /
@@ -1526,7 +1573,7 @@ export declare class ConversationError extends Error {
1526
1573
  *
1527
1574
  * @remarks
1528
1575
  * `compact` carries the newly-folded {@link Section}; `collapse` carries a section
1529
- * created by folding multiple OLDER sections together (a bounded-`sections` cap enforcement,
1576
+ * created by folding multiple older sections together (a bounded-`sections` cap enforcement,
1530
1577
  * distinct from `compact`'s fresh live-tail fold); `summary` carries the regenerated
1531
1578
  * conversation rollup (refreshed on each compaction); `rehydrate` carries the `id` of a
1532
1579
  * section whose originals were pulled back. Listener isolation is the emitter's:
@@ -1543,31 +1590,32 @@ export declare type ConversationEventMap = {
1543
1590
  /** Reports a section's original messages pulled back — the section's `id`. */
1544
1591
  readonly rehydrate: readonly [id: string];
1545
1592
  /**
1546
- * Reports the bounded-`sections` cap folding the oldest sections into ONE merged section — the
1593
+ * Reports the bounded-`sections` cap folding the oldest sections into one merged section — the
1547
1594
  * merged {@link Section} that replaced them.
1548
1595
  */
1549
1596
  readonly collapse: readonly [section: Section];
1550
1597
  };
1551
1598
 
1552
1599
  /**
1553
- * Carries the data to author a {@link ConversationInterface} through a
1554
- * {@link ConversationManagerInterface} — the optional `id`, a `summarize` override, a `keep`
1555
- * override, and the reserved `on` hooks.
1600
+ * Carries the data to author a {@link ConversationInterface} through a {@link
1601
+ * ConversationManagerInterface} — the optional `id`, a `summarize` override, a `keep` override, a
1602
+ * `sections` cap override, the reserved `on` hooks, and a {@link ConversationSnapshot} to hydrate
1603
+ * from.
1556
1604
  *
1557
1605
  * @remarks
1558
- * `id` is the conversation's identity (minted when omitted). `summarize` OVERRIDES the
1606
+ * `id` is the conversation's identity (minted when omitted). `summarize` overrides the
1559
1607
  * manager's default {@link ConversationSummaryHandler} for this conversation (omitted ⇒ the
1560
1608
  * manager's default flows in). `keep` overrides the manager's default retained-tail size.
1561
1609
  * `sections` overrides the manager's default `sections` cap. `on` is the reserved listener key
1562
1610
  * (initial {@link ConversationEventMap} listeners). `snapshot` is
1563
1611
  * the construction-time hydration seam — a {@link ConversationSnapshot} whose `id` / `summary` /
1564
- * `sections` / live tail are RESTORED into the new conversation (the live `summarize` / `keep` /
1612
+ * `sections` / live tail are restored into the new conversation (the live `summarize` / `keep` /
1565
1613
  * `on` re-supplied alongside it), the conversation analogue of
1566
1614
  * {@link import('@orkestrel/workspace').WorkspaceOptions}'s `seed`, carried onto
1567
1615
  * {@link ConversationOptions.snapshot}, that a
1568
1616
  * {@link ConversationManagerInterface.open} reads a stored snapshot back through; hydration is
1569
1617
  * silent (no events). When both `snapshot.id` and `id` are given, `snapshot.id` wins (the snapshot
1570
- * IS the conversation's identity).
1618
+ * is the conversation's identity).
1571
1619
  */
1572
1620
  export declare interface ConversationInput {
1573
1621
  readonly id?: string;
@@ -1583,52 +1631,53 @@ export declare interface ConversationInput {
1583
1631
  }
1584
1632
 
1585
1633
  /**
1586
- * Groups messages ABOVE the flat {@link MessageManagerInterface} — a live
1587
- * uncompacted tail plus compacted, summarized {@link Section}s and a conversation
1588
- * rollup `summary`, with on-demand `rehydrate` and substring `search`, driven by a
1589
- * provider-agnostic {@link ConversationSummaryHandler} seam.
1634
+ * Groups messages above the flat {@link MessageManagerInterface} — a live uncompacted tail plus
1635
+ * compacted, summarized {@link Section}s and a conversation rollup `summary`, with on-demand
1636
+ * `rehydrate`, substring `search`, a cross-conversation `reference`, and a JSON `snapshot`, driven
1637
+ * by a provider-agnostic {@link ConversationSummaryHandler} seam; `summarizable` reports whether
1638
+ * that seam was supplied, and the agent loop gates automatic compaction on it.
1590
1639
  *
1591
1640
  * @remarks
1592
- * - **Live tail + sections.** The conversation OWNS its LIVE uncompacted tail DIRECTLY — a
1641
+ * - **Live tail + sections.** The conversation owns its live uncompacted tail directly — a
1593
1642
  * caller appends turns through its own message verbs (`add` mints each `id`, `message` /
1594
1643
  * `messages` look up, `remove` / `clear` drop, `count` tallies), exactly as a `Workspace`
1595
1644
  * owns its files (no separate per-value manager). `sections` are the compacted history
1596
- * (oldest → newest), each a summarized slice that RETAINS its originals. `summary` is the
1645
+ * (oldest → newest), each a summarized slice that retains its originals. `summary` is the
1597
1646
  * conversation rollup (a summary-of-summaries over all sections), regenerated on each
1598
1647
  * compaction (`undefined` until the first compaction).
1599
1648
  * - **Message verbs (the inlined store).** `add` takes one {@link MessageInput} or a batch,
1600
- * MINTS each message's `id` (a random UUID), stores it, and returns the created
1649
+ * mints each message's `id` (a random UUID), stores it, and returns the created
1601
1650
  * message(s); a stored message is immutable. `message(id)` resolves one (`undefined` when
1602
1651
  * absent); `messages()` lists the live tail in insertion order; `remove` drops one by id or
1603
- * a batch (`true` only when EVERY supplied id was removed); `clear` empties the tail;
1652
+ * a batch (`true` only when every supplied id was removed); `clear` empties the tail;
1604
1653
  * `count` is how many live messages are stored.
1605
- * - **`view()` — the model input.** Each section folds to ONE synthetic summary message,
1654
+ * - **`view()` — the model input.** Each section folds to one synthetic summary message,
1606
1655
  * followed by the live messages verbatim: `[...sections-as-summary-messages, ...live]`. The
1607
- * rollup `summary` is NOT injected (it is a separately pull-able digest for a
1608
- * cross-conversation case); `view()` carries the per-section summaries, which ARE the
1656
+ * rollup `summary` is not injected (it is a separately pull-able digest for a
1657
+ * cross-conversation case); `view()` carries the per-section summaries, which are the
1609
1658
  * compaction benefit.
1610
1659
  * - **`compact()` — fold older live → a section.** Folds the oldest `count - keep` live
1611
1660
  * messages into a new {@link Section} (its `summary` from `summarize`), removes
1612
- * them from the live tail, REGENERATES the rollup (a second `summarize` over all section
1661
+ * them from the live tail, regenerates the rollup (a second `summarize` over all section
1613
1662
  * summaries), and emits `summary` then `compact` — returning the new section (or
1614
- * `undefined` when nothing folds). TWO summarizer calls per compaction (the section digest
1615
- * + the rollup). Throws a {@link import('./errors.js').ConversationError} when no
1616
- * `summarize` was supplied.
1617
- * - **`summarizable` — whether a `compact()` CAN fold.** `true` when a
1618
- * {@link ConversationSummaryHandler} was supplied, `false` otherwise. The agent loop's AUTOMATIC
1663
+ * `undefined` when nothing folds). A compaction calls the summarizer for the section
1664
+ * digest and again for the rollup. Throws a
1665
+ * {@link import('./errors.js').ConversationError} when no `summarize` was supplied.
1666
+ * - **`summarizable` — whether a `compact()` can fold.** `true` when a
1667
+ * {@link ConversationSummaryHandler} was supplied, `false` otherwise. The agent loop's automatic
1619
1668
  * compaction (`AgentOptions.window`) gates on it so a conversation that has no summarizer is
1620
1669
  * never auto-compacted (and the loop never throws the `compact()` `SUMMARIZER` error from the
1621
- * auto path). A MANUAL `compact()` still throws without a summarizer — only the auto path is
1670
+ * auto path). A manual `compact()` still throws without a summarizer — only the auto path is
1622
1671
  * guarded.
1623
1672
  * - **`rehydrate(id)` / `search(query)` — read the retained originals.** `rehydrate` returns
1624
1673
  * a section's full original messages (`[]` for an unknown id) and emits `rehydrate` — a
1625
- * pure READ (the caller decides whether to re-add them; `rehydrate` never reinserts).
1626
- * `search` is a case-insensitive substring scan of `content` across ALL messages (every
1674
+ * pure read (the caller decides whether to re-add them; `rehydrate` never reinserts).
1675
+ * `search` is a case-insensitive substring scan of `content` across all messages (every
1627
1676
  * section's originals + the live tail).
1628
- * - **`reference(options?)` — pull THIS conversation into ANOTHER with provenance.** A PURE
1677
+ * - **`reference(options?)` — pull this conversation into another with provenance.** A pure
1629
1678
  * string render (no model call) of a self-labeled, fenced cross-conversation block — the
1630
1679
  * rollup `summary` (when included + present) plus cherry-picked excerpts — framed so a small
1631
- * model reads it as FOREIGN material. Written into the ACTIVE conversation's context through
1680
+ * model reads it as foreign material. Written into the active conversation's context through
1632
1681
  * the active workspace (`context.workspaces.active?.write(path, block)`); the cherry-pick
1633
1682
  * comes from this conversation's own `search` / `rehydrate`, never its whole history.
1634
1683
  * - **Observable.** The owned `emitter` ({@link ConversationEventMap}) carries
@@ -1643,17 +1692,18 @@ export declare interface ConversationInterface {
1643
1692
  /** Lists the compacted history, oldest → newest. */
1644
1693
  readonly sections: readonly Section[];
1645
1694
  /**
1646
- * Reports whether a `compact()` CAN fold — `true` when a {@link ConversationSummaryHandler} was supplied.
1647
- * The agent loop's AUTOMATIC compaction (`AgentOptions.window`) gates on it (a non-summarizable
1695
+ * Reports whether a `compact()` can fold — `true` when a {@link ConversationSummaryHandler} was supplied.
1696
+ * The agent loop's automatic compaction (`AgentOptions.window`) gates on it (a non-summarizable
1648
1697
  * conversation is never auto-compacted, so the auto path never throws the `SUMMARIZER` error);
1649
- * a MANUAL `compact()` still throws without a summarizer.
1698
+ * a manual `compact()` still throws without a summarizer.
1650
1699
  */
1651
1700
  readonly summarizable: boolean;
1652
- /** Counts the LIVE (uncompacted) messages stored in the tail. */
1701
+ /** Counts the live (uncompacted) messages stored in the tail. */
1653
1702
  readonly count: number;
1654
1703
  /**
1655
- * Appends one message to the live tail (or a batch) — MINTS each message's `id`
1656
- * (a random UUID) and returns the created message(s); a stored message is immutable.
1704
+ * Appends one {@link MessageInput} to the live tail, or a batch — mints each message's `id`
1705
+ * (a random UUID) and returns the created message or messages; a stored message is
1706
+ * immutable.
1657
1707
  *
1658
1708
  * @param input - One {@link MessageInput}, or a batch
1659
1709
  * @returns The created {@link Message}(s), with their minted `id`s
@@ -1661,50 +1711,52 @@ export declare interface ConversationInterface {
1661
1711
  add(input: MessageInput): Message;
1662
1712
  add(inputs: readonly MessageInput[]): readonly Message[];
1663
1713
  /**
1664
- * Looks up one LIVE message by id.
1714
+ * Looks up one live message by id (`undefined` when absent).
1665
1715
  *
1666
1716
  * @param id - The message id to resolve
1667
1717
  * @returns The {@link Message}, or `undefined` when absent
1668
1718
  */
1669
1719
  message(id: string): Message | undefined;
1670
1720
  /**
1671
- * Lists every LIVE (uncompacted) message in the tail, in insertion order.
1721
+ * Lists every live, uncompacted message in the tail, in insertion order.
1672
1722
  *
1673
1723
  * @returns The live tail, in insertion order
1674
1724
  */
1675
1725
  messages(): readonly Message[];
1676
1726
  /**
1677
- * Removes one LIVE message by id (or a batch) from the tail.
1727
+ * Removes one live message by id, or a batch, from the tail — `true` only when every
1728
+ * supplied id was removed.
1678
1729
  *
1679
1730
  * @param id - One message id, or a batch
1680
1731
  * @returns True when every supplied id was present and removed; false otherwise
1681
1732
  */
1682
1733
  remove(id: string): boolean;
1683
1734
  remove(ids: readonly string[]): boolean;
1684
- /** Empties the live tail (the compacted `sections` are untouched). */
1735
+ /** Empties the live tail, leaving the compacted `sections` untouched. */
1685
1736
  clear(): void;
1686
1737
  /**
1687
- * Builds the model input for the next turn — each section as ONE synthetic summary message,
1688
- * then the live messages verbatim (the rollup `summary` is NOT injected).
1738
+ * Builds the model input for the next turn — each section as one synthetic recap message,
1739
+ * its summary prefixed with `CONVERSATION_RECAP_PREFIX` so a small model reads it as a
1740
+ * recap rather than a literal turn, then the live tail verbatim; the rollup `summary` is
1741
+ * not injected.
1689
1742
  *
1690
1743
  * @returns `[...sections-as-summary-messages, ...live messages]`
1691
1744
  */
1692
1745
  view(): readonly Message[];
1693
1746
  /**
1694
- * Folds the older live messages into a summarized {@link Section}, regenerates the
1695
- * rollup, and emits `summary` then `compact`.
1747
+ * Folds the oldest `count - keep` live messages into a summarized {@link Section} through
1748
+ * the {@link ConversationSummaryHandler}, removes them from the live tail, regenerates the
1749
+ * rollup, and emits `summary` then `compact` — resolving `undefined` when nothing folds
1750
+ * (`count <= keep`). Throws a {@link import('./errors.js').ConversationError} when no
1751
+ * summarizer was supplied.
1696
1752
  *
1697
1753
  * @remarks
1698
- * Folds the oldest `count - keep` live messages (`keep` from `options`, else the
1699
- * conversation's own); when `count <= keep` NOTHING folds and this is a no-op resolving
1700
- * `undefined`. Otherwise it summarizes the slice into the section, removes those messages
1701
- * from the live tail, regenerates the rollup (a second `summarize` over all sections), and
1702
- * resolves the new section. Requires a {@link ConversationSummaryHandler} — THROWS a
1703
- * {@link import('./errors.js').ConversationError} when none was supplied.
1754
+ * The effective `keep` comes from `options`, else the conversation's own. Regenerating the
1755
+ * rollup runs `summarize` again, over all sections.
1704
1756
  *
1705
1757
  * @remarks
1706
1758
  * When a `sections` cap is set and the fold pushes the section count over it, an overflow
1707
- * merge step folds the oldest sections into one — if THAT merge's `summarize` call throws,
1759
+ * merge step folds the oldest sections into one — if that merge's `summarize` call throws,
1708
1760
  * the merge is skipped (sections transiently sit at `cap + 1`, no loss) but the rollup still
1709
1761
  * regenerates over the current unmerged sections (never left stale) before the error
1710
1762
  * propagates; the next successful `compact()` self-heals the section count back to `cap`.
@@ -1714,35 +1766,38 @@ export declare interface ConversationInterface {
1714
1766
  */
1715
1767
  compact(options?: CompactOptions): Promise<Section | undefined>;
1716
1768
  /**
1717
- * Returns a section's full original messages — a pure READ that emits `rehydrate`.
1769
+ * Returns a section's full original messages — a pure read that emits `rehydrate`, empty for
1770
+ * an unknown id and never reinserting.
1718
1771
  *
1719
1772
  * @param id - The {@link Section} `id` to pull back
1720
1773
  * @returns The section's retained original messages (empty when no such section)
1721
1774
  */
1722
1775
  rehydrate(id: string): readonly Message[];
1723
1776
  /**
1724
- * Searches `content` for a case-insensitive substring across ALL messages — every section's
1725
- * retained originals plus the live tail.
1777
+ * Searches `content` for a case-insensitive substring across every message — each section's
1778
+ * retained originals, then the live tail.
1726
1779
  *
1727
1780
  * @param query - The substring to match (case-insensitive)
1728
1781
  * @returns The matching messages, sections' originals first then the live tail
1729
1782
  */
1730
1783
  search(query: string): readonly Message[];
1731
1784
  /**
1732
- * Renders THIS conversation as a self-labeled, fenced PROVENANCE block to pull INTO another
1733
- * conversation — a pure string (NO model call), framed so a small model reads it as FOREIGN
1734
- * material, not as part of the live thread.
1785
+ * Renders this conversation as a self-labeled, fenced provenance block to pull into another
1786
+ * conversation — a pure string with no model call: a leading
1787
+ * `[Reference — conversation "<label>" — NOT part of this conversation]` marker, the rollup
1788
+ * `Summary:` when `summary` is not `false` and a rollup exists, and the cherry-picked
1789
+ * excerpts (`- role: content`) when `messages` is supplied. `label` defaults to the `id`.
1735
1790
  *
1736
1791
  * @remarks
1737
1792
  * The block leads with an unmistakable provenance marker
1738
1793
  * (`[Reference — conversation "<label>" — NOT part of this conversation]`), then optionally
1739
- * the rollup `Summary:` (when `options.summary !== false` AND a rollup exists), then the
1794
+ * the rollup `Summary:` (when `options.summary !== false` and a rollup exists), then the
1740
1795
  * cherry-picked `Relevant messages:` (each `- role: content`) when `options.messages` is
1741
1796
  * supplied. The intended flow is to pull another conversation B into the active conversation
1742
1797
  * A's active workspace: decide relevance from `B.summary`, select the few right turns with
1743
1798
  * `B.search(query)` / `B.rehydrate(id)`, frame them here, then
1744
1799
  * `A.context.workspaces.active?.write(\`conversation:${B.id}.md\`, B.reference({ label, messages }))`.
1745
- * Keep the excerpts CHERRY-PICKED, never B's whole history — this content enters another
1800
+ * Keep the excerpts cherry-picked, never B's whole history — this content enters another
1746
1801
  * context a small model must read.
1747
1802
  *
1748
1803
  * @param options - The {@link ConversationReferenceOptions} (label / summary / cherry-picked messages)
@@ -1750,17 +1805,18 @@ export declare interface ConversationInterface {
1750
1805
  */
1751
1806
  reference(options?: ConversationReferenceOptions): string;
1752
1807
  /**
1753
- * Serializes this conversation to a plain, JSON-serializable {@link ConversationSnapshot} — its
1754
- * `id`, the rollup `summary`, the compacted `sections`, and the live tail (its `messages()`).
1808
+ * Serializes this conversation to a plain, JSON-serializable {@link ConversationSnapshot} —
1809
+ * its `id`, the rollup `summary`, the compacted `sections`, and the live tail; the live
1810
+ * `summarize` / `keep` are configuration re-supplied on hydrate rather than serialized.
1755
1811
  *
1756
1812
  * @remarks
1757
- * The container serializes ITSELF (`{ id, summary, sections, messages: this.messages() }`) — the
1813
+ * The container serializes itself (`{ id, summary, sections, messages: this.messages() }`) — the
1758
1814
  * {@link ConversationStoreInterface} persistence seam's payload, the exact analogue of
1759
1815
  * {@link import('@orkestrel/workspace').WorkspaceInterface}'s `snapshot`. The summarizer /
1760
- * `keep` are NOT serialized — they are live
1761
- * CONFIG re-supplied on hydrate (a `ConversationSummaryHandler` is a function, not data). The snapshot
1816
+ * `keep` are not serialized — they are live
1817
+ * config re-supplied on hydrate (a `ConversationSummaryHandler` is a function, not data). The snapshot
1762
1818
  * is the durable analogue of the `snapshot` option: a {@link ConversationManagerInterface}
1763
- * HYDRATES a conversation from it through that seam (see {@link ConversationManagerInterface.open}).
1819
+ * hydrates a conversation from it through that seam (see {@link ConversationManagerInterface.open}).
1764
1820
  * Pure — the sections + messages are already plain immutable records (so the snapshot
1765
1821
  * `structuredClone`s / JSON-round-trips losslessly), and snapshotting mutates nothing.
1766
1822
  *
@@ -1770,26 +1826,27 @@ export declare interface ConversationInterface {
1770
1826
  }
1771
1827
 
1772
1828
  /**
1773
- * Registers {@link Conversation}s keyed by `id`, in insertion order, WITH an active pointer
1774
- * — the id-keyed store over the conversation layer PLUS the `active` / `switch` seam the
1775
- * {@link import('../AgentContext.js').AgentContext} renders. Event-free (a registry, like
1776
- * {@link import('@orkestrel/workspace').WorkspaceManager}); the observability lives
1777
- * on each {@link Conversation}.
1829
+ * Registers {@link Conversation}s keyed by `id`, in insertion order, with an active pointer —
1830
+ * the id-keyed store over the conversation layer, the `active` / `switch` seam the
1831
+ * {@link import('../AgentContext.js').AgentContext} renders, and the durable `open` / `save`
1832
+ * store seam. Event-free (a registry, like
1833
+ * {@link import('@orkestrel/workspace').WorkspaceManager}); the observability lives on each
1834
+ * {@link Conversation}.
1778
1835
  *
1779
1836
  * @remarks
1780
1837
  * - **Registry.** Conversations live in an insertion-ordered `Map` keyed by `id`. `add(input?)`
1781
1838
  * mints a {@link Conversation} (its `id` from `input` or `crypto.randomUUID()`), flowing the
1782
- * manager's default `#summarize` / `#keep` in unless the `input` OVERRIDES them, and stores
1783
- * it (an already-present `id` OVERWRITES — last write wins). `count` is the map size,
1839
+ * manager's default `#summarize` / `#keep` in unless the `input` overrides them, and stores
1840
+ * it (an already-present `id` overwrites — last write wins). `count` is the map size,
1784
1841
  * `conversation(id)` looks one up, `conversations()` lists them in insertion order.
1785
1842
  * - **Active pointer.** `active` is the active conversation (the agent's message source the
1786
- * context renders), `undefined` until the FIRST `add` (which auto-activates it — a registry
1843
+ * context renders), `undefined` until the first `add` (which auto-activates it — a registry
1787
1844
  * with conversations always has one active). A subsequent `add` leaves `active` unchanged.
1788
1845
  * `switch(id)` re-points `active` to the conversation with `id` and returns it; an unknown `id`
1789
1846
  * returns `undefined` and leaves `active` unchanged (the lenient lookup style — never throws,
1790
1847
  * no new error code).
1791
- * - **Removal.** `remove` drops one by id, or a batch — `true` only when EVERY supplied id was
1792
- * removed; removing the ACTIVE conversation sets `active` to `undefined`. `clear` empties the registry
1848
+ * - **Removal.** `remove` drops one by id, or a batch — `true` only when every supplied id was
1849
+ * removed; removing the active conversation sets `active` to `undefined`. `clear` empties the registry
1793
1850
  * and sets `active` to `undefined`.
1794
1851
  * - **Event-free.** A purely registry store — no Emitter, no events (each conversation owns
1795
1852
  * its own observable `emitter`).
@@ -1820,32 +1877,32 @@ export declare class ConversationManager implements ConversationManagerInterface
1820
1877
  }
1821
1878
 
1822
1879
  /**
1823
- * Registers {@link ConversationInterface}s keyed by their `id`, in insertion order, WITH an
1824
- * active pointer — the id-keyed store over the conversation layer PLUS the `active` / `switch` seam the
1825
- * {@link AgentContextInterface} renders. Event-free (a registry, like
1826
- * {@link import('@orkestrel/workspace').WorkspaceManagerInterface}); the observability lives on each
1827
- * {@link ConversationInterface}.
1880
+ * Registers {@link ConversationInterface}s keyed by their `id`, in insertion order, with an active
1881
+ * pointer — the id-keyed store over the conversation layer, the `active` / `switch` seam the {@link
1882
+ * AgentContextInterface} renders, and the durable `open` / `save` store seam. Event-free (a
1883
+ * registry, like {@link import('@orkestrel/workspace').WorkspaceManagerInterface}); the
1884
+ * observability lives on each {@link ConversationInterface}.
1828
1885
  *
1829
1886
  * @remarks
1830
1887
  * - **Registry.** `count` is how many are stored. `add(input?)` mints a
1831
1888
  * {@link ConversationInterface} (its `id` from `input` or a random UUID), flowing the
1832
1889
  * manager's default `summarize` / `keep` in unless the `input` overrides them; `add` of an
1833
- * already-present `id` OVERWRITES it (last write wins). `conversation(id)` looks one up
1890
+ * already-present `id` overwrites it (last write wins). `conversation(id)` looks one up
1834
1891
  * (`undefined` when absent); `conversations()` lists them in insertion order.
1835
1892
  * - **Active pointer.** `active` is the active conversation (the agent's message source the
1836
- * context renders), `undefined` until the FIRST `add` (which auto-activates it — a registry
1893
+ * context renders), `undefined` until the first `add` (which auto-activates it — a registry
1837
1894
  * with conversations always has one active). A subsequent `add` leaves `active` unchanged.
1838
1895
  * `switch(id)` re-points `active` to the conversation with `id` and returns it; an unknown
1839
1896
  * `id` returns `undefined` and leaves `active` unchanged (the lenient lookup style — never
1840
1897
  * throws, no new error code).
1841
- * - **Removal.** `remove` drops one by id, or a batch (array overload FIRST) — `true`
1842
- * only when EVERY supplied id was removed; removing the ACTIVE conversation sets `active` to `undefined`. `clear`
1898
+ * - **Removal.** `remove` drops one by id, or a batch (the array overload declared first) — `true`
1899
+ * only when every supplied id was removed; removing the active conversation sets `active` to `undefined`. `clear`
1843
1900
  * empties the registry and sets `active` to `undefined`.
1844
1901
  * - **Durable open / save (the optional `store` seam).** When a {@link ConversationStoreInterface}
1845
- * is supplied (the `store` option), `open(id)` HYDRATES a conversation from the store on a registry
1902
+ * is supplied (the `store` option), `open(id)` hydrates a conversation from the store on a registry
1846
1903
  * miss (rebuilding it through the `snapshot` option, flowing the manager's
1847
- * default `summarize` / `keep` in) and `save(id)` PERSISTS a registered conversation's
1848
- * {@link ConversationInterface.snapshot}. Both are LENIENT without a store — `open` resolves only
1904
+ * default `summarize` / `keep` in) and `save(id)` persists a registered conversation's
1905
+ * {@link ConversationInterface.snapshot}. Both are lenient without a store — `open` resolves only
1849
1906
  * registered ids, `save` is a no-op (`false`) — consistent with the lenient `switch`. It mirrors
1850
1907
  * the workspace package manager's `open` / `save` seam.
1851
1908
  * - **Event-free.** A purely registry store — no Emitter, no events (each conversation owns
@@ -1855,47 +1912,66 @@ export declare interface ConversationManagerInterface {
1855
1912
  readonly count: number;
1856
1913
  /** Holds the active conversation — the agent's message source the context renders; `undefined` until the first `add`. */
1857
1914
  readonly active: ConversationInterface | undefined;
1915
+ /** Looks up one conversation by id (`undefined` when absent). */
1858
1916
  conversation(id: string): ConversationInterface | undefined;
1917
+ /** Lists every conversation, in insertion order. */
1859
1918
  conversations(): readonly ConversationInterface[];
1919
+ /**
1920
+ * Mints a conversation, taking its `id` from the input or a fresh UUID and flowing the
1921
+ * manager's default `summarize` / `keep` in unless the input overrides them — auto-activates
1922
+ * the first, and an already-present `id` overwrites, last write wins.
1923
+ */
1860
1924
  add(input?: ConversationInput): ConversationInterface;
1925
+ /**
1926
+ * Re-points `active` at the conversation with `id` and returns it; an unknown `id` returns
1927
+ * `undefined` and leaves `active` unchanged, never throwing.
1928
+ */
1861
1929
  switch(id: string): ConversationInterface | undefined;
1862
1930
  /**
1863
- * Resolves a conversation by id, ACTIVATING it — from the registry if present, else HYDRATED from
1864
- * the optional {@link ConversationStoreInterface} (`store`).
1931
+ * Resolves a conversation by id and activates it — from the registry when present, else
1932
+ * hydrated from the optional {@link ConversationStoreInterface} (`store`); `undefined` when
1933
+ * it is neither registered nor stored.
1865
1934
  *
1866
1935
  * @remarks
1867
- * - If `id` is ALREADY registered, it is ACTIVATED (`switch`ed to) and returned — no store hit.
1868
- * - Else if a `store` is set, `store.get(id)` is awaited; on a HIT the snapshot is rehydrated
1936
+ * - If `id` is already registered, it is activated (`switch`ed to) and returned — no store hit.
1937
+ * - Else if a `store` is set, `store.get(id)` is awaited; on a hit the snapshot is rehydrated
1869
1938
  * into a fresh {@link ConversationInterface} through the `snapshot` option
1870
1939
  * (`add({ snapshot, ... })`, flowing the manager's default `summarize` / `keep` in), which
1871
- * registers AND activates it, and it is returned.
1872
- * - Else (no store, or a store MISS) ⇒ `undefined` (lenient — no throw).
1940
+ * registers and activates it, and it is returned.
1941
+ * - Else (no store, or a store miss) ⇒ `undefined` (lenient — no throw).
1873
1942
  *
1874
1943
  * @param id - The conversation id to open
1875
1944
  * @returns The activated {@link ConversationInterface}, or `undefined` when neither registered nor stored
1876
1945
  */
1877
1946
  open(id: string): Promise<ConversationInterface | undefined>;
1878
1947
  /**
1879
- * Persists a REGISTERED conversation's {@link ConversationInterface.snapshot} to the optional
1880
- * {@link ConversationStoreInterface} (`store`).
1948
+ * Persists a registered conversation's {@link ConversationInterface.snapshot} to the optional
1949
+ * {@link ConversationStoreInterface} (`store`) — `true` when persisted, `false` when there is
1950
+ * no store or the id is unknown, and never throwing.
1881
1951
  *
1882
1952
  * @remarks
1883
- * Lenient: when a `store` is set AND `id` is registered, `store.set(conversation.snapshot())` is
1884
- * awaited and `true` is returned; otherwise (no store, OR an unknown id) it is a NO-OP returning
1953
+ * Lenient: when a `store` is set and `id` is registered, `store.set(conversation.snapshot())` is
1954
+ * awaited and `true` is returned; otherwise (no store, or an unknown id) it is a no-op returning
1885
1955
  * `false` — never a throw, consistent with the lenient `switch`.
1886
1956
  *
1887
1957
  * @param id - The id of the registered conversation to persist
1888
1958
  * @returns True if the snapshot was persisted; false otherwise (no store, or an unknown id)
1889
1959
  */
1890
1960
  save(id: string): Promise<boolean>;
1961
+ /**
1962
+ * Removes one conversation by id, or a batch — `true` only when every supplied id was
1963
+ * removed; clears `active` when a removed conversation was the active one.
1964
+ */
1891
1965
  remove(ids: readonly string[]): boolean;
1892
1966
  remove(id: string): boolean;
1967
+ /** Removes every conversation and clears `active`. */
1893
1968
  clear(): void;
1894
1969
  }
1895
1970
 
1896
1971
  /**
1897
- * Configures `createConversationManager` — the default {@link ConversationSummaryHandler} and
1898
- * retained-tail size the conversations it creates inherit.
1972
+ * Configures `createConversationManager` — the default `ConversationSummaryHandler`, retained-tail
1973
+ * size, and `sections` cap the conversations it creates inherit, plus the optional durable `store`
1974
+ * backing `open` / `save`.
1899
1975
  *
1900
1976
  * @remarks
1901
1977
  * `summarize` is the default summarizer flowed into every conversation the manager `add`s
@@ -1916,8 +1992,8 @@ export declare interface ConversationManagerOptions {
1916
1992
  /**
1917
1993
  * Holds the optional durable {@link ConversationStoreInterface} backing
1918
1994
  * {@link ConversationManagerInterface.open} / {@link ConversationManagerInterface.save} — a memory
1919
- * / JSON / SQLite / IndexedDB store a conversation is HYDRATED from (`open` a registry-miss) and
1920
- * PERSISTED to (`save`). Omitted ⇒ the manager is registry-only: `open` resolves only what is
1995
+ * / JSON / SQLite / IndexedDB store a conversation is hydrated from (`open` a registry-miss) and
1996
+ * persisted to (`save`). Omitted ⇒ the manager is registry-only: `open` resolves only what is
1921
1997
  * already registered, and `save` is a no-op (`false`). The exact analogue of
1922
1998
  * {@link import('@orkestrel/workspace').WorkspaceManagerOptions}'s `store`.
1923
1999
  */
@@ -1926,25 +2002,26 @@ export declare interface ConversationManagerOptions {
1926
2002
 
1927
2003
  /**
1928
2004
  * Configures `createConversation` — the optional `id`, the reserved `on` hooks, the
1929
- * provider-agnostic `summarize` seam, and the retained-tail size.
2005
+ * provider-agnostic `summarize` seam, the retained-tail size, an optional cap on the compacted
2006
+ * `sections` list, and a {@link ConversationSnapshot} to hydrate from.
1930
2007
  *
1931
2008
  * @remarks
1932
2009
  * `id` is the conversation's identity (a random UUID when omitted). `on` is the reserved
1933
2010
  * listener key (initial {@link ConversationEventMap} listeners). `summarize` is the
1934
- * {@link ConversationSummaryHandler} compaction needs — ABSENT ⇒ `compact()` throws a
2011
+ * {@link ConversationSummaryHandler} compaction needs — absent ⇒ `compact()` throws a
1935
2012
  * {@link import('./errors.js').ConversationError} (a conversation can still store + view a
1936
2013
  * live tail; it cannot fold). `keep` is how many recent live messages a `compact()`
1937
- * retains VERBATIM (folding only the older ones); it defaults to
2014
+ * retains verbatim (folding only the older ones); it defaults to
1938
2015
  * {@link import('./constants.js').DEFAULT_CONVERSATION_KEEP} (`0` — a manual `compact()`
1939
- * folds the WHOLE current live tail into one section). `sections` is an optional cap on the
2016
+ * folds the whole current live tail into one section). `sections` is an optional cap on the
1940
2017
  * compacted `sections` list — when set (`>= 1`), a `compact()` that would leave more than
1941
- * `sections` sections FOLDS the oldest overflow into ONE merged section so the list never
2018
+ * `sections` sections folds the oldest overflow into one merged section so the list never
1942
2019
  * exceeds `sections`, emitting `collapse`; omitted ⇒ unlimited (the prior behavior).
1943
- * `snapshot` is the HYDRATION seam — a {@link ConversationSnapshot} whose `id`, rollup
1944
- * `summary`, compacted `sections`, and live tail are RESTORED into the new conversation, with
2020
+ * `snapshot` is the hydration seam — a {@link ConversationSnapshot} whose `id`, rollup
2021
+ * `summary`, compacted `sections`, and live tail are restored into the new conversation, with
1945
2022
  * the live `summarize` / `keep` / `on` supplied alongside it (a summarizer is a function, not
1946
- * serialized data). Restoring is SILENT (no events — nothing was edited), and a `snapshot.id`
1947
- * WINS over `id` (the snapshot IS the conversation's identity). It is what lets
2023
+ * serialized data). Restoring is silent (no events — nothing was edited), and a `snapshot.id`
2024
+ * wins over `id` (the snapshot is the conversation's identity). It is what lets
1948
2025
  * `createConversation` hydrate, and what a {@link ConversationManagerInterface.open} reads a
1949
2026
  * stored snapshot back through.
1950
2027
  */
@@ -1953,7 +2030,7 @@ export declare interface ConversationOptions {
1953
2030
  readonly on?: EmitterHooks<ConversationEventMap>;
1954
2031
  /** Holds the emitter's listener-error handler — a listener throw routes here, not to a domain event. */
1955
2032
  readonly error?: EmitterErrorHandler;
1956
- /** Supplies the summarizer compaction needs; ABSENT ⇒ `compact()` throws a `ConversationError`. */
2033
+ /** Supplies the summarizer compaction needs; absent ⇒ `compact()` throws a `ConversationError`. */
1957
2034
  readonly summarize?: ConversationSummaryHandler;
1958
2035
  /** Keeps this many recent live messages verbatim on `compact`; defaults to `DEFAULT_CONVERSATION_KEEP` (`0`). */
1959
2036
  readonly keep?: number;
@@ -1964,22 +2041,23 @@ export declare interface ConversationOptions {
1964
2041
  }
1965
2042
 
1966
2043
  /**
1967
- * Configures {@link ConversationInterface.reference} — how to render ONE conversation as a
1968
- * self-labeled, fenced PROVENANCE block to pull INTO another conversation (by writing it to
1969
- * the active context's active workspace).
2044
+ * Configures {@link ConversationInterface.reference} — how to render one conversation as a
2045
+ * self-labeled, fenced provenance block to pull into another conversation by writing it to the
2046
+ * active context's active workspace: `label` defaults to the `id`, `summary` defaults to `true`,
2047
+ * and `messages` are cherry-picked excerpts defaulting to none.
1970
2048
  *
1971
2049
  * @remarks
1972
- * The rendered block is a cross-conversation reference a SMALL model must read as foreign
1973
- * material, NOT as part of the live thread — so every member keeps it CONCISE and unmistakably
2050
+ * The rendered block is a cross-conversation reference a small model must read as foreign
2051
+ * material, not as part of the live thread — so every member keeps it concise and unmistakably
1974
2052
  * attributed:
1975
- * - `label` — the human PROVENANCE name shown in the block's leading marker (for example `'planning'`);
2053
+ * - `label` — the human provenance name shown in the block's leading marker (for example `'planning'`);
1976
2054
  * defaults to the conversation's own `id`. It is what the model attributes the content to.
1977
2055
  * - `summary` — whether to include the conversation's rollup `summary` (its summary-of-summaries)
1978
- * in the block; defaults to `true` (the rollup is included WHEN one exists — `undefined` until
2056
+ * in the block; defaults to `true` (the rollup is included when one exists — `undefined` until
1979
2057
  * the first compaction omits the `Summary:` line). Pass `false` to exclude it.
1980
- * - `messages` — the CHERRY-PICKED excerpts to include (each rendered `role: content`), default
1981
- * NONE. The intended source is the conversation's OWN `search(query)` / `rehydrate(id)` output
1982
- * (select the few relevant turns), NOT its whole history — dumping every message defeats the
2058
+ * - `messages` — the cherry-picked excerpts to include (each rendered `role: content`), default
2059
+ * none. The intended source is the conversation's own `search(query)` / `rehydrate(id)` output
2060
+ * (select the few relevant turns), not its whole history — dumping every message defeats the
1983
2061
  * point (it re-bloats the destination context a small model then has to wade through).
1984
2062
  */
1985
2063
  export declare interface ConversationReferenceOptions {
@@ -1998,11 +2076,11 @@ export declare interface ConversationReferenceOptions {
1998
2076
  * {@link import('@orkestrel/workspace').WorkspaceSnapshot}.
1999
2077
  *
2000
2078
  * @remarks
2001
- * Pure JSON DATA (no class instances, no functions): each {@link Section} and
2002
- * {@link Message} is already a PLAIN record that `structuredClone`s / JSON-round-trips
2079
+ * Pure JSON data (no class instances, no functions): each {@link Section} and
2080
+ * {@link Message} is already a plain record that `structuredClone`s / JSON-round-trips
2003
2081
  * losslessly. The snapshot carries the rollup `summary` (a summary-of-summaries; `undefined` until
2004
- * the first compaction), the compacted `sections` (each RETAINING its folded originals), and the
2005
- * live uncompacted tail `messages` — but NOT the `summarize` / `keep`, which are live CONFIG
2082
+ * the first compaction), the compacted `sections` (each retaining its folded originals), and the
2083
+ * live uncompacted tail `messages` — but not the `summarize` / `keep`, which are live config
2006
2084
  * re-supplied on hydrate (a summarizer is a function, not serializable data). The snapshot the
2007
2085
  * container produces from itself ({@link ConversationInterface.snapshot}); the durable analogue of
2008
2086
  * the {@link ConversationOptions.snapshot} hydration seam. A {@link ConversationManagerInterface}
@@ -2014,23 +2092,24 @@ export declare interface ConversationSnapshot {
2014
2092
  readonly id: string;
2015
2093
  /** Holds the rollup (a summary-of-summaries); `undefined` until the first compaction. */
2016
2094
  readonly summary?: string;
2017
- /** Lists the compacted history, oldest → newest (each section RETAINS its folded originals). */
2095
+ /** Lists the compacted history, oldest → newest (each section retains its folded originals). */
2018
2096
  readonly sections: readonly Section[];
2019
2097
  /** Lists the live uncompacted tail, in insertion order. */
2020
2098
  readonly messages: readonly Message[];
2021
2099
  }
2022
2100
 
2023
2101
  /**
2024
- * Represents one row of the table a
2025
- * {@link import('./conversations/stores/DatabaseConversationStore.js').DatabaseConversationStore}
2026
- * persists — a conversation `id` plus its {@link ConversationSnapshot} held as ONE OPAQUE JSON
2027
- * column. The exact analogue of {@link import('@orkestrel/workspace').WorkspaceSnapshotRow}.
2102
+ * Represents one row of the table a {@link
2103
+ * import('./conversations/stores/DatabaseConversationStore.js').DatabaseConversationStore} persists
2104
+ * — a conversation `id` plus its {@link ConversationSnapshot} held as one opaque JSON column, read
2105
+ * back as `unknown` and narrowed on `get`. The exact analogue of {@link
2106
+ * import('@orkestrel/workspace').WorkspaceSnapshotRow}.
2028
2107
  *
2029
2108
  * @remarks
2030
2109
  * The Database twin of {@link ConversationStoreInterface} stores the snapshot whole (the `snapshot`
2031
2110
  * column is a `rawShape`, an opaque JSON blob — exactly as
2032
2111
  * {@link import('@orkestrel/workspace').WorkspaceSnapshotRow} stores a workspace snapshot), so the
2033
- * row type stays FLAT and the sections/messages snapshot shape never
2112
+ * row type stays flat and the sections/messages snapshot shape never
2034
2113
  * forces the contract to `Infer` it. The column therefore reads back as the broad `unknown`; the
2035
2114
  * store narrows it to a {@link ConversationSnapshot} on `get`
2036
2115
  * ({@link import('./validators.js').isConversationSnapshot}, the total boundary guard). `id`
@@ -2044,30 +2123,30 @@ export declare interface ConversationSnapshotRow {
2044
2123
  }
2045
2124
 
2046
2125
  /**
2047
- * Persists a {@link ConversationSnapshot} durably — three async primitives
2048
- * (`get` / `set` / `delete`) keyed by a conversation id, the exact analogue of
2049
- * {@link import('@orkestrel/workspace').WorkspaceStoreInterface}.
2126
+ * Persists a {@link ConversationSnapshot} durably — the async `get` / `set` / `delete` primitives,
2127
+ * keyed by a conversation id and holding no expiry, the exact analogue of {@link
2128
+ * import('@orkestrel/workspace').WorkspaceStoreInterface}.
2050
2129
  *
2051
2130
  * @remarks
2052
2131
  * The store persists the {@link ConversationSnapshot} — the self-contained, pure-JSON conversation
2053
- * state — so a JSON / SQLite / IndexedDB backend swaps in WITHOUT touching the manager or the
2132
+ * state — so a JSON / SQLite / IndexedDB backend swaps in without touching the manager or the
2054
2133
  * conversation: the in-memory default
2055
2134
  * {@link import('./conversations/stores/MemoryConversationStore.js').MemoryConversationStore} and its
2056
2135
  * driver-pluggable twin
2057
2136
  * {@link import('./conversations/stores/DatabaseConversationStore.js').DatabaseConversationStore} (the
2058
- * snapshot as one opaque JSON column) share THIS one interface. Hydration is NOT a store concern
2137
+ * snapshot as one opaque JSON column) share this one interface. Hydration is not a store concern
2059
2138
  * — a {@link ConversationManagerInterface} reads a snapshot back and rebuilds the live conversation
2060
2139
  * through the {@link ConversationOptions.snapshot} seam (re-supplying the live `summarize` / `keep`; see
2061
2140
  * {@link ConversationManagerInterface.open} / {@link ConversationManagerInterface.save}).
2062
2141
  *
2063
2142
  * Every primitive is async (a `Promise`), so a durable backend (a database round-trip) fits the
2064
- * same shape as the memory one. The snapshot carries its OWN id, so `set` takes no separate id
2143
+ * same shape as the memory one. The snapshot carries its own id, so `set` takes no separate id
2065
2144
  * param (mirroring
2066
- * {@link import('@orkestrel/workspace').WorkspaceStoreInterface}'s `set`). UNLIKE a session store
2067
- * there is NO idle-TTL
2145
+ * {@link import('@orkestrel/workspace').WorkspaceStoreInterface}'s `set`). Unlike a session store
2146
+ * there is no idle-TTL
2068
2147
  * / eviction — a persisted conversation lives until an explicit `delete`. It is concrete over
2069
2148
  * {@link ConversationSnapshot} — no generic parameter, because the
2070
- * snapshot is the ONE payload a conversation store persists.
2149
+ * snapshot is the one payload a conversation store persists.
2071
2150
  */
2072
2151
  export declare interface ConversationStoreInterface {
2073
2152
  /**
@@ -2093,10 +2172,10 @@ export declare interface ConversationStoreInterface {
2093
2172
  }
2094
2173
 
2095
2174
  /**
2096
- * Summarizes a conversation, provider-agnostically — the seam the agent RUNTIME supplies so
2097
- * core never imports a provider. Given the folded messages, it resolves their digest (the
2098
- * model-written summary), used both to summarize a compacted {@link Section} and
2099
- * to regenerate a {@link ConversationInterface}'s rollup `summary`.
2175
+ * Summarizes a conversation, provider-agnostically — the seam the agent runtime supplies so core
2176
+ * never imports a provider. Given the folded messages, it resolves their digest, the model-written
2177
+ * summary used to summarize a compacted {@link Section} and to regenerate a {@link
2178
+ * ConversationInterface}'s rollup `summary`.
2100
2179
  *
2101
2180
  * @remarks
2102
2181
  * The agent runtime builds one from its `ProviderInterface` (for example
@@ -2117,10 +2196,10 @@ export declare type ConversationSummaryHandler = (messages: readonly Message[])
2117
2196
  * `generate` and a live `stream`.
2118
2197
  *
2119
2198
  * @remarks
2120
- * One private loop drives the turn; `generate` DRAINS the same stream `stream`
2199
+ * One private loop drives the turn; `generate` drains the same stream `stream`
2121
2200
  * exposes, so they can never diverge. Each turn is bounded by one cancel folded from
2122
2201
  * `signal` + `timeout` + `budget` (through `AbortSignal.any`) — any trip (or `abort()`)
2123
- * commits a PARTIAL result (the stream's `result` RESOLVES on a cancel, rejects only
2202
+ * commits a partial result (the stream's `result` resolves on a cancel, rejects only
2124
2203
  * on a genuine provider / tool error). The `scheduler` paces between turns; tool
2125
2204
  * iteration is capped at `limit` (default `DEFAULT_AGENT_LIMIT`). Tools are advertised
2126
2205
  * structurally through `context.tools.definitions()`. Two observation surfaces: the
@@ -2155,19 +2234,20 @@ export declare type ConversationSummaryHandler = (messages: readonly Message[])
2155
2234
  export declare function createAgent(provider: ProviderInterface, options?: AgentOptions): AgentInterface;
2156
2235
 
2157
2236
  /**
2158
- * Creates a richer turn context — an {@link AgentContextInterface} assembling a provider
2159
- * request from the optional system prompt, the instruction registry, the workspace registry,
2160
- * the conversation store, the tool registry, and the active scope.
2237
+ * Creates a richer turn context — an {@link AgentContextInterface} assembling a provider request
2238
+ * from the optional system prompt, the instruction registry, the workspace registry (the only
2239
+ * document channel), the conversation registry that is its `messages` source, the tool registry,
2240
+ * and the active scope, which `build()` folds into the next turn's input.
2161
2241
  *
2162
2242
  * @remarks
2163
2243
  * `system` is the optional system prompt; `tools` / `instructions` / `workspaces` are pre-built
2164
- * managers to reuse (empty ones are created when omitted, so `context.workspaces` is ALWAYS
2244
+ * managers to reuse (empty ones are created when omitted, so `context.workspaces` is always
2165
2245
  * present); `scope` is the initial active filter (`undefined` ⇒ no filtering, changeable afterwards
2166
2246
  * through `context.apply(...)`). The `messages` store is always fresh. `build()` folds the scoped
2167
- * instructions — PLUS the ACTIVE workspace's scope-filtered text files (fenced) — into ONE leading
2247
+ * instructions — plus the active workspace's scope-filtered text files (fenced) — into one leading
2168
2248
  * `system` message and appends the scoped conversation (attaching the active workspace's
2169
2249
  * scope-filtered image files' `base64` payload to the last user message), built fresh each call; the active
2170
- * workspace is the SOLE document/image context. Tools are advertised STRUCTURALLY (through
2250
+ * workspace is the sole document/image context. Tools are advertised structurally (through
2171
2251
  * `tools.definitions()`, scope-filtered by the loop), never serialized into the prompt.
2172
2252
  *
2173
2253
  * @param options - Optional `system` / `tools` / `instructions` / `workspaces` / `scope`
@@ -2188,7 +2268,7 @@ export declare function createAgentContext(options?: AgentContextOptions): Agent
2188
2268
 
2189
2269
  /**
2190
2270
  * Creates a durable, bounded-concurrency agent-job queue — a {@link QueueInterface} over
2191
- * serializable {@link AgentJobInput}s that COMPOSES `createQueue`: each job is rehydrated
2271
+ * serializable {@link AgentJobInput}s that composes `createQueue`: each job is rehydrated
2192
2272
  * through the `registry` into a live {@link AgentInterface}, run to its {@link AgentResult},
2193
2273
  * and subjected to the partial-as-configurable-failure policy.
2194
2274
  *
@@ -2201,9 +2281,9 @@ export declare function createAgentContext(options?: AgentContextOptions): Agent
2201
2281
  * (for example `createMemoryQueueStore` / `createDatabaseQueueStore`) persists outstanding
2202
2282
  * jobs; `restore()` re-enqueues them after a restart and the `registry` rehydrates the
2203
2283
  * live pieces from the names — so a job survives a crash.
2204
- * - **Partial policy.** A partial result THROWS an
2284
+ * - **Partial policy.** A partial result throws an
2205
2285
  * {@link import('./errors.js').AgentJobError} by default, so a job cancelled by its
2206
- * attempt deadline / a queue abort RETRIES while attempts remain; `partial: true`
2286
+ * attempt deadline / a queue abort retries while attempts remain; `partial: true`
2207
2287
  * resolves the partial as success instead.
2208
2288
  * - **Cancellation threads through.** The handler passes `context.signal` into
2209
2289
  * `registry.build`, so a queue `abort()` or a per-attempt timeout cancels the in-flight
@@ -2234,7 +2314,7 @@ export declare function createAgentQueue(options: AgentQueueOptions): QueueInter
2234
2314
  *
2235
2315
  * @remarks
2236
2316
  * `providers` is required; `tools` / `authorities` / `schedulers` are optional pools.
2237
- * The accessors (`provider` / `tool` / `authority` / `scheduler`) THROW an
2317
+ * The accessors (`provider` / `tool` / `authority` / `scheduler`) throw an
2238
2318
  * {@link import('./errors.js').AgentError} carrying `code: 'REGISTRY'` and the message
2239
2319
  * `unknown <category>: <name>` on an unregistered name — a misconfigured or crash-restored
2240
2320
  * job fails loudly rather than running with a missing dependency. `build(input, signal)`
@@ -2263,21 +2343,21 @@ export declare function createAgentRegistry(options: AgentRegistryOptions): Agen
2263
2343
 
2264
2344
  /**
2265
2345
  * Creates an agent-job runner — a {@link RunnerInterface} over serializable
2266
- * {@link AgentJobInput}s that COMPOSES `createRunner` (one-shot, ordered, fail-fast), each
2267
- * unit rehydrated through the `registry` and subjected to the partial policy. The runner
2268
- * enables **sub-agent fan-out**: a parent job's handler can `controller.spawn(childJob)`.
2346
+ * {@link AgentJobInput}s that composes `createRunner` (one-shot, ordered, fail-fast), each unit
2347
+ * rehydrated through the `registry` and subjected to the partial policy. The runner also carries
2348
+ * sub-agent fan-out: a parent job's handler can `controller.spawn(childJob)`.
2269
2349
  *
2270
2350
  * @remarks
2271
2351
  * - **Composes the substrate (no new engine).** Bounded `concurrency`, `retries`, the
2272
2352
  * per-attempt `timeout`, ordered results, and fail-fast are all the backing Runner's;
2273
2353
  * the handler adds only rehydration + the partial policy.
2274
2354
  * - **Sub-agent fan-out.** Each unit's handler receives a `ControllerInterface` whose
2275
- * `spawn(childJob)` launches a CHILD agent job through the same bounded queue (the
2355
+ * `spawn(childJob)` launches a child agent job through the same bounded queue (the
2276
2356
  * child's result joins the run after the declared units, in spawn order). On a bounded
2277
- * runner, FAN OUT and return — do NOT inline-`await` a spawn from within the handler (a
2357
+ * runner, fan out and return — do not inline-`await` a spawn from within the handler (a
2278
2358
  * slot-holding handler awaiting its own spawn can deadlock; see `ControllerInterface`).
2279
2359
  * - **Partial policy + cancellation.** Same as `createAgentQueue`: a partial result
2280
- * THROWS by default (the run's fail-fast engages), `partial: true` resolves it; the
2360
+ * throws by default (the run's fail-fast engages), `partial: true` resolves it; the
2281
2361
  * handler threads `controller.signal` into `registry.build`, so a runner abort / a
2282
2362
  * per-attempt timeout cancels the agent.
2283
2363
  *
@@ -2305,11 +2385,11 @@ export declare function createAgentRunner(options: AgentRunnerOptions): RunnerIn
2305
2385
  * to the configured default when none match.
2306
2386
  *
2307
2387
  * @remarks
2308
- * `rules` are evaluated in order — the FIRST whose `match` is true decides (a matched
2309
- * rule ALLOWS unless its `allowed` is explicitly `false`). When no rule matches, the
2388
+ * `rules` are evaluated in order — the first whose `match` is true decides (a matched
2389
+ * rule allows unless its `allowed` is explicitly `false`). When no rule matches, the
2310
2390
  * `fallback` decides; it defaults to `{ zone: DEFAULT_AUTHORITY_ZONE, allowed: true }`
2311
- * (allow-unmatched — a rules list of denials acts as a DENYLIST). Pass an
2312
- * `allowed: false` `fallback` to flip the gate to deny-by-default (an ALLOWLIST). Wire
2391
+ * (allow-unmatched — a rules list of denials acts as a denylist). Pass an
2392
+ * `allowed: false` `fallback` to flip the gate to deny-by-default (an allowlist). Wire
2313
2393
  * the result into `createAgent` through `AgentOptions.authority`: a denied call is fed back
2314
2394
  * to the model as a denial `ToolResult` (not executed, no budget cost), so the model
2315
2395
  * can react. Synchronous — `evaluate` returns the verdict directly.
@@ -2339,7 +2419,7 @@ export declare function createAuthority(options?: AuthorityOptions): AuthorityIn
2339
2419
  * Write and read are decoupled, so the producer never waits for a consumer: an agent's eager
2340
2420
  * pump writes each chunk into one, which is why a run's `result` settles whether or not the
2341
2421
  * live events are drained. A value pushed at an already-parked consumer is delivered, buffered
2342
- * values are yielded before the end is reported, and the FIRST failure wins.
2422
+ * values are yielded before the end is reported, and the first failure wins.
2343
2423
  *
2344
2424
  * @typeParam T - The value type the channel carries
2345
2425
  * @returns A fresh, empty {@link ChannelInterface}
@@ -2360,16 +2440,16 @@ export declare function createChannel<T>(): ChannelInterface<T>;
2360
2440
 
2361
2441
  /**
2362
2442
  * Creates a conversation — a {@link ConversationInterface} grouping messages above a flat
2363
- * message store it OWNS DIRECTLY, with compaction into summarized sections, a regenerated
2443
+ * message store it owns directly, with compaction into summarized sections, a regenerated
2364
2444
  * rollup `summary`, on-demand `rehydrate`, and substring `search`, driven by a
2365
2445
  * provider-agnostic {@link ConversationSummaryHandler} seam.
2366
2446
  *
2367
2447
  * @remarks
2368
2448
  * Append turns through the conversation's own `add` (the live tail it owns); `view()` is the model input
2369
2449
  * (each section as a summary message, then the live tail). `compact()` folds the older live
2370
- * messages into a summarized {@link Section} and regenerates the rollup — it REQUIRES
2450
+ * messages into a summarized {@link Section} and regenerates the rollup — it requires
2371
2451
  * a `summarize` (omitted ⇒ `compact()` throws a `ConversationError`); `keep` retains a recent
2372
- * tail (default `DEFAULT_CONVERSATION_KEEP` — fold ALL). `rehydrate(id)` / `search(query)` read
2452
+ * tail (default `DEFAULT_CONVERSATION_KEEP` — fold all). `rehydrate(id)` / `search(query)` read
2373
2453
  * the retained originals. Observable (`emitter` — `compact` / `summary` / `rehydrate`), wired
2374
2454
  * through the reserved `on` option; the emitter isolates a listener throw and routes it to
2375
2455
  * its `error` handler (the `error` option), so it can never corrupt a compaction.
@@ -2377,41 +2457,61 @@ export declare function createChannel<T>(): ChannelInterface<T>;
2377
2457
  * @param options - Optional `id` / `on` hooks + the `summarize` seam + `keep` (see {@link ConversationOptions})
2378
2458
  * @returns A working {@link ConversationInterface}
2379
2459
  *
2380
- * @example
2460
+ * @example Conversations & compaction
2381
2461
  * ```ts
2382
- * import type { ProviderInterface } from '@orkestrel/agent'
2383
2462
  * import { createConversation } from '@orkestrel/agent'
2463
+ * import type { ProviderInterface } from '@orkestrel/agent'
2384
2464
  *
2385
2465
  * declare const provider: ProviderInterface // any concrete implementation supplied by the host app
2466
+ * // The summarizer seam — built from the provider by the runtime; core stays provider-agnostic.
2467
+ * // Append the instruction as the FINAL user turn: a chat model emits nothing when the prompt
2468
+ * // ends on an assistant turn, so a leading-system instruction is unreliable.
2386
2469
  * const conversation = createConversation({
2387
- * // Append the instruction as the FINAL user turn — a chat model emits nothing when the
2388
- * // prompt ends on an assistant turn, so a leading-system instruction is unreliable.
2389
2470
  * summarize: async (messages) =>
2390
- * (await provider.generate([...messages, { id: 's', role: 'user', content: 'Summarize the conversation so far concisely.' }], AbortSignal.timeout(30_000))).content,
2471
+ * (
2472
+ * await provider.generate(
2473
+ * [
2474
+ * ...messages,
2475
+ * { id: 's', role: 'user', content: 'Summarize the conversation so far concisely.' },
2476
+ * ],
2477
+ * AbortSignal.timeout(30_000),
2478
+ * )
2479
+ * ).content,
2480
+ * keep: 2, // retain the two most recent turns verbatim on each compaction
2391
2481
  * })
2392
- * conversation.add({ role: 'user', content: 'Hello' })
2393
- * await conversation.compact() // folds the live tail into a summarized section
2482
+ * conversation.add([
2483
+ * { role: 'user', content: 'My name is Ada.' },
2484
+ * { role: 'assistant', content: 'Nice to meet you, Ada.' },
2485
+ * { role: 'user', content: 'What did I say my name was?' },
2486
+ * ])
2487
+ *
2488
+ * const section = await conversation.compact() // folds the older turns → a summarized section
2489
+ * conversation.view() // [<section summary message>, ...the retained recent tail] — the model input
2490
+ * conversation.summary // the regenerated rollup (a summary-of-summaries over all sections)
2491
+ * conversation.search('ada') // case-insensitive across sections' originals + the live tail
2492
+ * section && conversation.rehydrate(section.id) // the section's full original messages (a pure read)
2394
2493
  * ```
2395
2494
  */
2396
2495
  export declare function createConversation(options?: ConversationOptions): ConversationInterface;
2397
2496
 
2398
2497
  /**
2399
2498
  * Creates a conversation registry — a {@link ConversationManagerInterface} holding
2400
- * {@link ConversationInterface}s keyed by their `id` (in insertion order) WITH an active pointer:
2499
+ * {@link ConversationInterface}s keyed by their `id`, in insertion order, with an active pointer:
2401
2500
  * the id-keyed store over the conversation layer plus the `active` / `switch` seam the context
2402
- * renders.
2501
+ * renders. `add` auto-activates the first conversation and flows the registry's default
2502
+ * `summarize` / `keep` into every conversation it creates.
2403
2503
  *
2404
2504
  * @remarks
2405
2505
  * Starts empty; `add(input?)` mints a {@link ConversationInterface} (its `id` from the input
2406
2506
  * or a random UUID), flowing the manager's default `summarize` / `keep` in unless the input
2407
2507
  * overrides them, and stores it (an already-present `id` overwrites — last write wins) — and
2408
- * AUTO-ACTIVATES the FIRST one (a registry with conversations always has one `active`); a later
2508
+ * auto-activates the first one (a registry with conversations always has one `active`); a later
2409
2509
  * `add` leaves `active` unchanged. `switch(id)` re-points `active` (an unknown `id` returns
2410
2510
  * `undefined`, leaving `active` unchanged — lenient, never throws); `conversation(id)` /
2411
2511
  * `conversations()` look up; `remove` (one or a batch) reports `true` only when every supplied id
2412
- * was removed AND clears `active` if it was a removed one; `clear` empties it and clears `active`.
2512
+ * was removed and clears `active` if it was a removed one; `clear` empties it and clears `active`.
2413
2513
  * Event-free
2414
- * (each conversation owns its own observable `emitter`). A conversation created with NEITHER a
2514
+ * (each conversation owns its own observable `emitter`). A conversation created with neither a
2415
2515
  * manager default nor a per-`add` `summarize` cannot `compact` (it throws a `ConversationError`).
2416
2516
  *
2417
2517
  * @param options - Optional default `summarize` / `keep` (see {@link ConversationManagerOptions})
@@ -2429,23 +2529,24 @@ export declare function createConversation(options?: ConversationOptions): Conve
2429
2529
  export declare function createConversationManager(options?: ConversationManagerOptions): ConversationManagerInterface;
2430
2530
 
2431
2531
  /**
2432
- * Creates a {@link DatabaseConversationStore} over any {@link DriverInterface} — the durable,
2433
- * driver-pluggable backing for the conversation persistence seam, the opt-in twin of
2532
+ * Creates a {@link DatabaseConversationStore} over any {@link DriverInterface}, defaulting to
2533
+ * `createMemoryDriver()` — the durable, driver-pluggable backing for the conversation persistence
2534
+ * seam, holding each snapshot as one opaque JSON column and standing as the opt-in twin of
2434
2535
  * {@link createMemoryConversationStore}. The exact twin of
2435
2536
  * {@link import('@orkestrel/workspace').createDatabaseWorkspaceStore}.
2436
2537
  *
2437
2538
  * @remarks
2438
2539
  * Builds a one-table database (`conversations`, keyed by `id`) over the supplied driver, the snapshot
2439
- * held as ONE OPAQUE JSON COLUMN — the column map is `{ id; snapshot }` where `snapshot` is a
2540
+ * held as one opaque JSON column — the column map is `{ id; snapshot }` where `snapshot` is a
2440
2541
  * `rawShape` (a JSON blob), exactly as
2441
2542
  * {@link import('@orkestrel/workspace').createDatabaseWorkspaceStore} stores its snapshot. The
2442
- * snapshot is already a COMPLETE, self-contained, pure-JSON payload, so storing it whole is lossless
2443
- * AND keeps the row type FLAT (the column reads back as `unknown`, narrowed on `get` by
2444
- * {@link import('./validators.js').isConversationSnapshot}). The `driver` DEFAULTS to
2445
- * {@link createMemoryDriver}, so the store ALSO works in memory out of the box; pass a server
2543
+ * snapshot is already a complete, self-contained, pure-JSON payload, so storing it whole is lossless
2544
+ * and keeps the row type flat (the column reads back as `unknown`, narrowed on `get` by
2545
+ * {@link import('./validators.js').isConversationSnapshot}). The `driver` defaults to
2546
+ * {@link createMemoryDriver}, so the store also works in memory out of the box; pass a server
2446
2547
  * `createJSONDriver` / `createSQLiteDriver` (or a browser IndexedDB driver) for a persistent one —
2447
2548
  * the durability is the driver's job, the store engine is shared. It swaps in behind
2448
- * {@link ConversationStoreInterface} WITHOUT touching the manager or the conversation.
2549
+ * {@link ConversationStoreInterface} without touching the manager or the conversation.
2449
2550
  *
2450
2551
  * @param driver - The storage backend the snapshots persist to (defaults to {@link createMemoryDriver})
2451
2552
  * @returns A {@link ConversationStoreInterface} over the driver
@@ -2491,7 +2592,7 @@ export declare function createInstruction(input: InstructionInput): InstructionI
2491
2592
  * immutable instructions keyed by `name`, listed by descending `priority`.
2492
2593
  *
2493
2594
  * @remarks
2494
- * Starts empty; `add` (one or a batch) MINTS each `id` and OVERWRITES a same-name
2595
+ * Starts empty; `add` (one or a batch) mints each `id` and overwrites a same-name
2495
2596
  * instruction (last write wins); `instructions()` lists them sorted by descending
2496
2597
  * `priority` (stable for ties); `open` / `render` are the build contract a richer
2497
2598
  * context renders an instructions block with; `remove` (one or a batch) reports `true` only
@@ -2519,7 +2620,7 @@ export declare function createInstructionManager(options?: InstructionManagerOpt
2519
2620
  /**
2520
2621
  * Creates the in-memory conversation store — a {@link ConversationStoreInterface} backed by a
2521
2622
  * process-lifetime `Map` of {@link import('./types.js').ConversationSnapshot}s keyed by conversation
2522
- * id, the DEFAULT backing for the durable {@link ConversationManagerInterface.open} /
2623
+ * id, the default backing for the durable {@link ConversationManagerInterface.open} /
2523
2624
  * {@link ConversationManagerInterface.save} seam. The exact twin of
2524
2625
  * {@link import('@orkestrel/workspace').createMemoryWorkspaceStore}.
2525
2626
  *
@@ -2527,10 +2628,10 @@ export declare function createInstructionManager(options?: InstructionManagerOpt
2527
2628
  * A plain `Map` (the snapshot is already pure JSON, so no encoding is needed for the memory tier),
2528
2629
  * the structural twin of {@link import('@orkestrel/workspace').createMemoryWorkspaceStore}.
2529
2630
  * `get` / `set` / `delete` are async (the
2530
- * same shape a durable backend fits); UNLIKE a session store there is NO idle-TTL / eviction — a
2631
+ * same shape a durable backend fits); unlike a session store there is no idle-TTL / eviction — a
2531
2632
  * persisted conversation lives until an explicit `delete`. Its driver-pluggable twin is
2532
2633
  * {@link createDatabaseConversationStore} (the snapshot as one opaque JSON column over a `databases`
2533
- * table) — for a DURABLE store pass it a JSON / SQLite / IndexedDB driver, and it swaps in WITHOUT
2634
+ * table) — for a durable store pass it a JSON / SQLite / IndexedDB driver, and it swaps in without
2534
2635
  * touching the manager or the conversation. Hydration stays a manager concern: read a snapshot back
2535
2636
  * and rebuild the live conversation through the `snapshot` option (re-supplying the live
2536
2637
  * `summarize` / `keep`).
@@ -2555,9 +2656,9 @@ export declare function createMemoryConversationStore(): ConversationStoreInterf
2555
2656
  * per-category allow-lists, the `id` minted at construction.
2556
2657
  *
2557
2658
  * @remarks
2558
- * Each list is THREE-WAY: `undefined` ⇒ NO constraint on that category (all pass), `[]` ⇒
2559
- * NONE pass, a non-empty list ⇒ only the listed keys pass. `narrow(config)` composes a
2560
- * tighter child by set-INTERSECTION (an `undefined` side imposing no constraint). Stored
2659
+ * Each list is three-way: `undefined` ⇒ no constraint on that category (all pass), `[]` ⇒
2660
+ * none pass, a non-empty list ⇒ only the listed keys pass. `narrow(config)` composes a
2661
+ * tighter child by set-intersection (an `undefined` side imposing no constraint). Stored
2561
2662
  * immutable — never mutated after creation (`narrow` returns a new scope).
2562
2663
  *
2563
2664
  * @param input - `name` (required) and the optional `instructions` / `tools` / `files`
@@ -2601,18 +2702,19 @@ export declare function createScope(input: ScopeInput): ScopeInterface;
2601
2702
  export declare function createScopeManager(options?: ScopeManagerOptions): ScopeManagerInterface;
2602
2703
 
2603
2704
  /**
2604
- * Creates a stream-stateful `<think>` separator — a {@link ThinkSplitterInterface} that
2605
- * splits a thinking model's in-content `<think>…</think>` reasoning spans away from
2606
- * the answer, delta by delta, so a provider yields ONLY clean content and surfaces the
2607
- * accumulated reasoning as {@link import('./types.js').ProviderResult.thinking}.
2705
+ * Creates a fresh stream-stateful `<think>` separator — a {@link ThinkSplitterInterface} that
2706
+ * splits a thinking model's in-content `<think>…</think>` reasoning spans away from the answer,
2707
+ * delta by delta, so a provider yields clean content alone and surfaces the accumulated
2708
+ * reasoning as {@link import('./types.js').ProviderResult.thinking}. One splitter serves one
2709
+ * stream.
2608
2710
  *
2609
2711
  * @remarks
2610
2712
  * Feed each raw wire delta through `split(delta)` (it returns the clean content to
2611
2713
  * surface — possibly `''` mid-think) and settle the stream end with `flush()` (a held
2612
- * partial open tag that never completed returns as final content; an UNCLOSED think
2613
- * span lands on `thinking`). Tags split ACROSS deltas are held back until
2714
+ * partial open tag that never completed returns as final content; an unclosed think
2715
+ * span lands on `thinking`). Tags split across deltas are held back until
2614
2716
  * disambiguated, multiple spans accumulate in order, and a nested-looking `<think>`
2615
- * inside an open span is thinking text. One splitter serves ONE stream — create
2717
+ * inside an open span is thinking text. One splitter serves one stream — create
2616
2718
  * a fresh one per provider call.
2617
2719
  *
2618
2720
  * @returns A fresh {@link ThinkSplitterInterface} (state empty, outside any span)
@@ -2631,37 +2733,39 @@ export declare function createThinkSplitter(): ThinkSplitterInterface;
2631
2733
 
2632
2734
  /**
2633
2735
  * Backs a {@link ConversationStoreInterface} with one table of the `databases` layer — a
2634
- * conversation's durable state IS a row, so persistence reduces to keyed point-access (`get` / `set`
2635
- * / `delete`) over a {@link TableInterface}, the driver-pluggable twin of the plain-`Map`
2636
- * {@link import('./MemoryConversationStore.js').MemoryConversationStore}. The EXACT twin of
2736
+ * conversation's durable state is a row holding the snapshot as one opaque JSON column, narrowed
2737
+ * back on `get` by {@link import('../../validators.js').isConversationSnapshot}, so persistence
2738
+ * reduces to keyed point-access (`get` / `set` / `delete`) over a {@link TableInterface}. The
2739
+ * driver-pluggable twin of the plain-`Map`
2740
+ * {@link import('./MemoryConversationStore.js').MemoryConversationStore}, and the exact twin of
2637
2741
  * {@link import('@orkestrel/workspace').DatabaseWorkspaceStore}.
2638
2742
  *
2639
2743
  * @remarks
2640
2744
  * The store is driver-agnostic: it holds a single {@link TableInterface} whose backend (memory,
2641
2745
  * JSON, SQLite, IndexedDB) is chosen by whoever builds it (the factories), so a JSON / SQLite /
2642
- * IndexedDB backend swaps in WITHOUT touching the
2746
+ * IndexedDB backend swaps in without touching the
2643
2747
  * {@link import('../ConversationManager.js').ConversationManager} or the
2644
2748
  * {@link import('../Conversation.js').Conversation} — the same seam as
2645
2749
  * {@link import('@orkestrel/workspace').DatabaseWorkspaceStore}. The
2646
2750
  * driver defaults to memory ({@link import('../../factories.js').createDatabaseConversationStore}
2647
- * passes `createMemoryDriver()`), so it ALSO works in memory out of the box; you opt into the
2751
+ * passes `createMemoryDriver()`), so it also works in memory out of the box; you opt into the
2648
2752
  * durable plumbing by passing a JSON / SQLite / IndexedDB driver.
2649
2753
  *
2650
- * The {@link ConversationSnapshot} is stored as ONE OPAQUE JSON COLUMN — the table is a row of
2754
+ * The {@link ConversationSnapshot} is stored as one opaque JSON column — the table is a row of
2651
2755
  * `{ id; snapshot }` ({@link ConversationSnapshotRow}), the snapshot the whole JSON blob (a
2652
2756
  * `rawShape` column the factory builds) — exactly as `DatabaseWorkspaceStore` stores its snapshot.
2653
- * The snapshot is already a COMPLETE, self-contained, pure-JSON payload, so storing it whole is
2654
- * lossless AND keeps the row type flat (`snapshot` reads back as `unknown`).
2757
+ * The snapshot is already a complete, self-contained, pure-JSON payload, so storing it whole is
2758
+ * lossless and keeps the row type flat (`snapshot` reads back as `unknown`).
2655
2759
  *
2656
- * - **`set(snapshot)` upserts under the snapshot's OWN `id`** (no separate id param) — it writes
2760
+ * - **`set(snapshot)` upserts under the snapshot's own `id`** (no separate id param) — it writes
2657
2761
  * the row `{ id: snapshot.id, snapshot }`.
2658
2762
  * - **`get(id)` resolves the stored snapshot for an id**, narrowing the opaque JSON column back to
2659
2763
  * a {@link ConversationSnapshot} ({@link import('../../validators.js').isConversationSnapshot} — the
2660
2764
  * total guard for an untrusted storage read), or `undefined` if none is stored.
2661
2765
  * - **`delete(id)` drops a snapshot by id**; an absent id is a no-op (no throw).
2662
2766
  *
2663
- * UNLIKE a session store there is NO idle-TTL / eviction — a persisted conversation lives until an
2664
- * explicit `delete`. The public surface is EXACTLY `get` / `set` / `delete` — no extra members (the
2767
+ * Unlike a session store there is no idle-TTL / eviction — a persisted conversation lives until an
2768
+ * explicit `delete`. The public surface is exactly `get` / `set` / `delete` — no extra members (the
2665
2769
  * method bijection with {@link ConversationStoreInterface}). Hydration stays a caller concern: a
2666
2770
  * {@link import('../ConversationManager.js').ConversationManager} reads a snapshot back and rebuilds
2667
2771
  * the live conversation through the `snapshot` option (its `open` / `save`).
@@ -2690,36 +2794,35 @@ export declare class DatabaseConversationStore implements ConversationStoreInter
2690
2794
  constructor(table: TableInterface<ConversationSnapshotRow>);
2691
2795
  /** Resolves the persisted snapshot for `id`, narrowing the opaque JSON column back to a `ConversationSnapshot`. */
2692
2796
  get(id: string): Promise<ConversationSnapshot | undefined>;
2693
- /** Inserts or replaces under the snapshot's OWN `id` (no separate id param) — the row is `{ id, snapshot }`. */
2797
+ /** Inserts or replaces under the snapshot's own `id` (no separate id param) — the row is `{ id, snapshot }`. */
2694
2798
  set(snapshot: ConversationSnapshot): Promise<void>;
2695
2799
  /** Drops a snapshot by id; an absent id is a no-op (no throw). */
2696
2800
  delete(id: string): Promise<void>;
2697
2801
  }
2698
2802
 
2699
2803
  /**
2700
- * Caps an {@link AgentInterface} turn's tool iterations by default — the maximum
2701
- * number of context → provider → tools cycles before the loop stops, so a model that
2702
- * keeps requesting tools can never loop forever. Overridable per agent through
2703
- * `AgentOptions.limit`.
2804
+ * Caps an {@link AgentInterface} turn's tool iterations by default — `10` context → provider →
2805
+ * tools cycles before the loop stops, so a model that keeps requesting tools can never loop
2806
+ * forever. Overridable per agent through `AgentOptions.limit`.
2704
2807
  */
2705
2808
  export declare const DEFAULT_AGENT_LIMIT = 10;
2706
2809
 
2707
2810
  /**
2708
2811
  * Names the zone an {@link AuthorityInterface}'s default fallback {@link AuthorityDecision}
2709
- * carries — the classification for a tool call that matched no rule. Paired with the
2710
- * default `allowed: true` fallback, an unmatched call is allowed under this zone, so a
2711
- * rules list of denials acts as a denylist; a caller wanting deny-by-default supplies
2712
- * an `allowed: false` `fallback` of their own (see `AuthorityOptions`).
2812
+ * carries — `'default'`, the classification for a tool call that matched no rule. Paired with
2813
+ * the default `allowed: true` fallback, an unmatched call is allowed under this zone, so a
2814
+ * rules list of denials acts as a denylist; a caller wanting deny-by-default supplies an
2815
+ * `allowed: false` `fallback` of their own (see `AuthorityOptions`).
2713
2816
  */
2714
2817
  export declare const DEFAULT_AUTHORITY_ZONE = "default";
2715
2818
 
2716
2819
  /**
2717
2820
  * Sets the default number of recent live messages a {@link ConversationInterface}'s `compact()`
2718
- * RETAINS verbatim — `0`, so a manual `compact()` folds ALL of the current live messages
2719
- * into one summarized section (no tail kept). A caller retains a recent tail by passing
2720
- * `keep` (on {@link ConversationOptions}, {@link ConversationManagerOptions}, or per-fold
2721
- * through {@link CompactOptions}), folding only the older `count - keep` messages and leaving
2722
- * the most recent `keep` live for the next turn. Overridable everywhere `keep` is accepted.
2821
+ * retains verbatim — `0`, so a manual `compact()` folds every current live message into one
2822
+ * summarized section and keeps no tail. A caller retains a recent tail by passing `keep` (on
2823
+ * {@link ConversationOptions}, {@link ConversationManagerOptions}, or per-fold through
2824
+ * {@link CompactOptions}), folding only the older `count - keep` messages and leaving the most
2825
+ * recent `keep` live for the next turn. Overridable everywhere `keep` is accepted.
2723
2826
  */
2724
2827
  export declare const DEFAULT_CONVERSATION_KEEP = 0;
2725
2828
 
@@ -2745,16 +2848,19 @@ export declare const DEFAULT_CONVERSATION_KEEP = 0;
2745
2848
  export declare function denyCall(call: ToolCall, reason: string | undefined): ToolResult;
2746
2849
 
2747
2850
  /**
2748
- * Estimates the context-token footprint of a batch of messages — the default `consumer`
2749
- * estimator for an agent's context `BudgetInterface` (a budgets surface's tracking contract)
2750
- * (the {@link import('./types.js').AgentOptions} `window`).
2851
+ * Estimates the context-token footprint of a batch of messages — each message's content plus
2852
+ * {@link import('./constants.js').MESSAGE_TOKEN_OVERHEAD}, a tool-call JSON estimate, and
2853
+ * {@link import('./constants.js').IMAGE_TOKEN_ESTIMATE} for each attached image. The default
2854
+ * `consumer` estimator for an agent's context budget (the
2855
+ * {@link import('./types.js').AgentOptions} `window`), total and never throwing, and a
2856
+ * deliberate provider-agnostic approximation rather than an exact tokenizer count.
2751
2857
  *
2752
2858
  * @remarks
2753
2859
  * Sums, per message, {@link estimateTokens} over its `content` (the `ceil(length / 4)` char
2754
- * heuristic) PLUS {@link import('./constants.js').MESSAGE_TOKEN_OVERHEAD} (a fixed per-message
2755
- * role/framing overhead) PLUS, when present, {@link estimateTokens} over its JSON-stringified
2756
- * `calls` PLUS `images.length * `{@link import('./constants.js').IMAGE_TOKEN_ESTIMATE} (a coarse,
2757
- * deliberately-approximate per-image cost — a base64 length is NOT a token proxy). Deterministic
2860
+ * heuristic) plus {@link import('./constants.js').MESSAGE_TOKEN_OVERHEAD} (a fixed per-message
2861
+ * role/framing overhead) plus, when present, {@link estimateTokens} over its JSON-stringified
2862
+ * `calls` plus `images.length * `{@link import('./constants.js').IMAGE_TOKEN_ESTIMATE} (a coarse,
2863
+ * deliberately-approximate per-image cost — a base64 length is not a token proxy). Deterministic
2758
2864
  * and provider-free — the same messages always yield the same estimate, with an empty batch `0`.
2759
2865
  * It is the fully-swappable default an agent's auto-compaction context budget charges each
2760
2866
  * turn's new messages through; a caller wanting a sharper count supplies its own `consumer` to
@@ -2775,15 +2881,15 @@ export declare function denyCall(call: ToolCall, reason: string | undefined): To
2775
2881
  export declare function estimateMessages(messages: readonly Message[]): number;
2776
2882
 
2777
2883
  /**
2778
- * Estimates the context-token footprint of a string — the deterministic char-based heuristic
2779
- * {@link estimateMessages} sums over a conversation's messages (the default context-budget
2780
- * estimator).
2884
+ * Estimates the context-token footprint of a string — the deterministic `ceil(length / 4)`
2885
+ * character heuristic {@link estimateMessages} sums over a conversation's messages (the default
2886
+ * context-budget estimator).
2781
2887
  *
2782
2888
  * @remarks
2783
2889
  * Approximates `ceil(length / 4)` (≈ four characters per token — the rough average for
2784
2890
  * English text), so the same input always yields the same estimate (no model round-trip).
2785
2891
  * Empty text is `0`. This is a planning heuristic for reasoning about how much a turn's
2786
- * messages cost the next request, NOT an exact tokenizer count — it never calls a provider,
2892
+ * messages cost the next request, not an exact tokenizer count — it never calls a provider,
2787
2893
  * so the agent layer stays provider-agnostic and synchronous where it can be.
2788
2894
  *
2789
2895
  * @param text - The text to estimate (a section summary, a message's content)
@@ -2799,15 +2905,16 @@ export declare function estimateMessages(messages: readonly Message[]): number;
2799
2905
  export declare function estimateTokens(text: string): number;
2800
2906
 
2801
2907
  /**
2802
- * Filters a list of items by a {@link import('./types.js').ScopeInterface} allow-list of
2803
- * keys — the pure, total set-membership primitive the context's build step and the agent
2804
- * loop's tool-advertise step apply a scope through.
2908
+ * Filters a list of items by a {@link import('./types.js').ScopeInterface} allow-list of keys —
2909
+ * `undefined` passes everything, `[]` passes nothing, and a non-empty list passes the listed keys
2910
+ * alone, order preserved. The pure, total set-membership primitive the context's build step and
2911
+ * the agent loop's tool-advertise step apply a scope through.
2805
2912
  *
2806
2913
  * @remarks
2807
2914
  * Three-way by the allow-list's shape, so a `Scope` category cleanly expresses "all /
2808
2915
  * none / only these":
2809
- * - `undefined` ⇒ NO constraint — every item passes (returned unchanged).
2810
- * - `[]` (empty) ⇒ NONE pass (no key is in an empty set).
2916
+ * - `undefined` ⇒ no constraint — every item passes (returned unchanged).
2917
+ * - `[]` (empty) ⇒ none pass (no key is in an empty set).
2811
2918
  * - a non-empty list ⇒ only items whose `key(item)` is in the list pass.
2812
2919
  *
2813
2920
  * Order-preserving (it filters `items` in place order, never reorders) and total — never
@@ -2858,11 +2965,12 @@ export declare function handleAgentQueueJob(registry: AgentRegistryInterface, pa
2858
2965
  export declare function handleAgentRunnerJob(registry: AgentRegistryInterface, partial: boolean, controller: ControllerInterface<AgentJobInput, AgentResult>): Promise<AgentResult>;
2859
2966
 
2860
2967
  /**
2861
- * Names the coarse, deliberately-approximate per-image token cost {@link import('./helpers.js').estimateMessages}
2862
- * charges for each attached image.
2968
+ * Names the coarse, deliberately approximate per-image token cost
2969
+ * {@link import('./helpers.js').estimateMessages} charges for each attached image — `512`, because
2970
+ * a base64 payload's length is no reliable token proxy.
2863
2971
  *
2864
2972
  * @remarks
2865
- * A base64 image payload's LENGTH is NOT a reliable token proxy (a vision model's actual image
2973
+ * A base64 image payload's length is not a reliable token proxy (a vision model's actual image
2866
2974
  * token cost depends on resolution / tiling, not byte size), so this is a fixed, coarse
2867
2975
  * per-image estimate rather than a derivation from `image.length` — a planning heuristic, not an
2868
2976
  * exact count.
@@ -2870,15 +2978,15 @@ export declare function handleAgentRunnerJob(registry: AgentRegistryInterface, p
2870
2978
  export declare const IMAGE_TOKEN_ESTIMATE = 512;
2871
2979
 
2872
2980
  /**
2873
- * Represents an immutable named directive — a {@link InstructionInterface} assembled once
2874
- * from its input (`name` / `content`, an optional `priority` defaulting to `0`), the `id`
2875
- * minted at construction.
2981
+ * Represents an immutable named directive — an {@link InstructionInterface} assembled once from
2982
+ * its input (`name` / `content`, an optional `priority` defaulting to `0`), the `id` minted at
2983
+ * construction.
2876
2984
  *
2877
2985
  * @remarks
2878
2986
  * A thin immutable value object (mirroring {@link import('@orkestrel/tool').Tool}): the
2879
2987
  * constructor mints a fresh `id` (`crypto.randomUUID()`), copies the input's `name` /
2880
2988
  * `content`, resolves `priority` to the input's value or `0`, and carries the input's
2881
- * per-item `override` ONLY when supplied (assigned when present, mirroring a
2989
+ * per-item `override` only when supplied (assigned when present, mirroring a
2882
2990
  * message's `images` / `calls` present-when-given convention — kept absent otherwise).
2883
2991
  * Never mutated after construction. An
2884
2992
  * {@link import('./InstructionManager.js').InstructionManager} keys it by `name` and
@@ -2910,7 +3018,7 @@ export declare interface InstructionInput {
2910
3018
  /** Weights the ordering (higher renders first); defaults to `0` when omitted. */
2911
3019
  readonly priority?: number;
2912
3020
  /**
2913
- * Holds a fully-rendered override of THIS instruction's prompt text — the most-specific
3021
+ * Holds a fully-rendered override of this instruction's prompt text — the most-specific
2914
3022
  * level of the {@link import('./AgentContext.js').AgentContext} build cascade (beats a
2915
3023
  * manager-options / provider / built-in format for this item). Round-tripped onto the
2916
3024
  * stored {@link InstructionInterface} when given (present-when-supplied, like `images`).
@@ -2937,8 +3045,8 @@ export declare interface InstructionInterface {
2937
3045
  readonly priority: number;
2938
3046
  /**
2939
3047
  * Holds a fully-rendered per-item override of this instruction's prompt text — the
2940
- * MOST-SPECIFIC level of the {@link import('./AgentContext.js').AgentContext} build
2941
- * cascade, beating every format level for THIS item. Present only when supplied on the
3048
+ * most-specific level of the {@link import('./AgentContext.js').AgentContext} build
3049
+ * cascade, beating every format level for this item. Present only when supplied on the
2942
3050
  * {@link InstructionInput} (round-tripped through the manager, like a message's
2943
3051
  * `images`); absent ⇒ the cascade decides.
2944
3052
  */
@@ -2946,28 +3054,29 @@ export declare interface InstructionInterface {
2946
3054
  }
2947
3055
 
2948
3056
  /**
2949
- * Registers the immutable {@link Instruction}s a richer context assembles a directives
2950
- * block from — keyed by `name`, listed by descending `priority`.
3057
+ * Registers the immutable {@link Instruction}s a richer context assembles a directives block
3058
+ * from — keyed by `name` so a re-`add` overwrites, last write wins, and listed by descending
3059
+ * `priority`, carrying the `open` / `render` build contract and an observable `emitter`.
2951
3060
  *
2952
3061
  * @remarks
2953
3062
  * - **Registry.** Instructions live in an insertion-ordered `Map` keyed by `name`;
2954
- * `add` takes one {@link InstructionInput} or a batch, MINTS each instruction's
2955
- * `id`, and a re-`add` of the same name OVERWRITES it (last write wins). `count` is the
2956
- * map size, `instruction(name)` looks one up, and `instructions()` lists them SORTED by
3063
+ * `add` takes one {@link InstructionInput} or a batch, mints each instruction's
3064
+ * `id`, and a re-`add` of the same name overwrites it (last write wins). `count` is the
3065
+ * map size, `instruction(name)` looks one up, and `instructions()` lists them sorted by
2957
3066
  * descending `priority` (a stable sort, so equal priorities keep insertion order).
2958
3067
  * - **Build contract (with the manager-options override).** `open` is the section
2959
3068
  * header a context renders the instructions under; `render(instruction)` renders one
2960
- * instruction (its `content`). Each ENCAPSULATES the cascade's `[options-override →
3069
+ * instruction (its `content`). Each encapsulates the cascade's `[options-override →
2961
3070
  * built-in]` half: when `InstructionManagerOptions.format` supplies an `open` /
2962
- * `render`, `open` / `render` return IT, else the built-in — so a richer context
3071
+ * `render`, `open` / `render` return it, else the built-in — so a richer context
2963
3072
  * reads one consistent pair and layers the provider default + per-item override on top
2964
3073
  * (see {@link import('../AgentContext.js').AgentContext}). The per-item
2965
3074
  * {@link InstructionInput.override} is round-tripped onto the stored instruction.
2966
- * - **Removal.** `remove` drops one by name, or a batch — `true` only when EVERY supplied
3075
+ * - **Removal.** `remove` drops one by name, or a batch — `true` only when every supplied
2967
3076
  * name was removed; `clear` empties the registry.
2968
3077
  * - **Observable.** The owned {@link emitter} ({@link InstructionManagerEventMap})
2969
3078
  * carries `add` (the created instruction) / `remove` (the name) / `clear` for
2970
- * fire-and-forget observers. Every event is emitted directly, strictly AFTER the map
3079
+ * fire-and-forget observers. Every event is emitted directly, strictly after the map
2971
3080
  * mutation completes; the emitter isolates a listener throw and routes it to its `error`
2972
3081
  * handler (the `error` option), so a buggy observer can never corrupt a mutation.
2973
3082
  *
@@ -3020,9 +3129,9 @@ export declare type InstructionManagerEventMap = {
3020
3129
  };
3021
3130
 
3022
3131
  /**
3023
- * Registers {@link InstructionInterface}s keyed by `name` — `add` (one or a batch)
3024
- * mints each `id` and OVERWRITES a same-name instruction (last write wins);
3025
- * `instructions()` lists them SORTED by descending `priority` (stable for ties).
3132
+ * Registers {@link InstructionInterface}s keyed by `name` — `add` (one or a batch) mints each `id`
3133
+ * and overwrites a same-name instruction, last write wins, while `instructions()` lists them sorted
3134
+ * by descending `priority` and stable for ties.
3026
3135
  *
3027
3136
  * @remarks
3028
3137
  * - **Build contract.** `open` is the section header a richer context renders
@@ -3040,22 +3149,32 @@ export declare interface InstructionManagerInterface {
3040
3149
  readonly open: string;
3041
3150
  /**
3042
3151
  * Holds the manager-options format override (the {@link InstructionManagerOptions.format}
3043
- * supplied at construction), or `undefined` when none — the MANAGER-OPTIONS level of the
3152
+ * supplied at construction), or `undefined` when none — the manager-options level of the
3044
3153
  * {@link import('./AgentContext.js').AgentContext} build cascade, exposed so `build()`
3045
- * can interleave the provider default BENEATH it (`open` / `render` already
3154
+ * can interleave the provider default beneath it (`open` / `render` already
3046
3155
  * encapsulate the `[override → built-in]` half for standalone use). A `readonly` data
3047
3156
  * member, not a method.
3048
3157
  */
3049
3158
  readonly format: ContextSectionFormat<InstructionInterface> | undefined;
3159
+ /**
3160
+ * Adds one {@link InstructionInput}, or a batch — mints each `id`; a re-`add` of the same
3161
+ * name overwrites it, last write wins.
3162
+ */
3050
3163
  add(input: InstructionInput): InstructionInterface;
3051
3164
  add(inputs: readonly InstructionInput[]): readonly InstructionInterface[];
3165
+ /** Looks up one instruction by name (`undefined` when absent). */
3052
3166
  instruction(name: string): InstructionInterface | undefined;
3053
3167
  /** Lists every instruction, sorted by descending `priority` (stable for equal priorities). */
3054
3168
  instructions(): readonly InstructionInterface[];
3055
3169
  /** Renders one instruction for the prompt — its `content`. */
3056
3170
  render(instruction: InstructionInterface): string;
3171
+ /**
3172
+ * Removes one instruction by name, or a batch — `true` only when every supplied name was
3173
+ * removed.
3174
+ */
3057
3175
  remove(name: string): boolean;
3058
3176
  remove(names: readonly string[]): boolean;
3177
+ /** Removes every instruction. */
3059
3178
  clear(): void;
3060
3179
  }
3061
3180
 
@@ -3066,10 +3185,10 @@ export declare interface InstructionManagerInterface {
3066
3185
  * @remarks
3067
3186
  * `on` is the reserved listener key: initial listeners for the manager's
3068
3187
  * {@link InstructionManagerEventMap}, wired at construction. `format` is the
3069
- * MANAGER-OPTIONS level of the {@link import('./AgentContext.js').AgentContext} build
3070
- * cascade — a {@link ContextSectionFormat} the manager consults FIRST in its own
3188
+ * manager-options level of the {@link import('./AgentContext.js').AgentContext} build
3189
+ * cascade — a {@link ContextSectionFormat} the manager consults first in its own
3071
3190
  * `open` / `render` (falling back to the built-in when a member is omitted), so it
3072
- * BEATS the provider default and the built-in, while a per-item
3191
+ * beats the provider default and the built-in, while a per-item
3073
3192
  * {@link InstructionInput.override} still beats it. Omitted ⇒ the built-in framing applies.
3074
3193
  */
3075
3194
  export declare interface InstructionManagerOptions {
@@ -3081,12 +3200,12 @@ export declare interface InstructionManagerOptions {
3081
3200
  }
3082
3201
 
3083
3202
  /**
3084
- * Intersects two scope category lists under the "`undefined` is the universal set" rule — the
3085
- * primitive a scope narrows through.
3203
+ * Intersects two scope category lists under the "`undefined` is the universal set" rule — a
3204
+ * fresh copy that can only tighten, and the primitive a scope narrows through.
3086
3205
  *
3087
3206
  * @remarks
3088
- * Pure and total, and it can only TIGHTEN: `undefined` ∩ `undefined` is `undefined` (still no
3089
- * constraint); `undefined` ∩ a list is a COPY of that list (the `undefined` side imposes
3207
+ * Pure and total, and it can only tighten: `undefined` ∩ `undefined` is `undefined` (still no
3208
+ * constraint); `undefined` ∩ a list is a copy of that list (the `undefined` side imposes
3090
3209
  * nothing); a list ∩ a list keeps the child keys the parent also allows, so a parent-excluded
3091
3210
  * key can never be re-admitted. Every returned list is a fresh copy, so a later mutation of
3092
3211
  * either input cannot leak into the result.
@@ -3105,7 +3224,8 @@ export declare interface InstructionManagerOptions {
3105
3224
  export declare function intersectKeys(parent: readonly string[] | undefined, child: readonly string[] | undefined): readonly string[] | undefined;
3106
3225
 
3107
3226
  /**
3108
- * Narrows an unknown caught value to an {@link AgentError}.
3227
+ * Narrows an unknown caught value to an {@link AgentError} through `instanceof`, so a `catch`
3228
+ * can branch on its `code`.
3109
3229
  *
3110
3230
  * @param value - The value to test (typically a `catch` binding)
3111
3231
  * @returns True if `value` is an {@link AgentError}; false otherwise
@@ -3122,7 +3242,8 @@ export declare function intersectKeys(parent: readonly string[] | undefined, chi
3122
3242
  export declare function isAgentError(value: unknown): value is AgentError;
3123
3243
 
3124
3244
  /**
3125
- * Narrows an unknown caught value to an {@link AgentJobError}.
3245
+ * Narrows an unknown caught value to an {@link AgentJobError} through `instanceof`, so a
3246
+ * `catch` can recover its `partial` result.
3126
3247
  *
3127
3248
  * @param value - The value to test (typically a `catch` binding or a rejected enqueue)
3128
3249
  * @returns True if `value` is an {@link AgentJobError}; false otherwise
@@ -3139,7 +3260,8 @@ export declare function isAgentError(value: unknown): value is AgentError;
3139
3260
  export declare function isAgentJobError(value: unknown): value is AgentJobError;
3140
3261
 
3141
3262
  /**
3142
- * Narrows an unknown caught value to a {@link ConversationError}.
3263
+ * Narrows an unknown caught value to a {@link ConversationError} through `instanceof`, so a
3264
+ * `catch` can branch on its `code`.
3143
3265
  *
3144
3266
  * @param value - The value to test (typically a `catch` binding)
3145
3267
  * @returns True if `value` is a {@link ConversationError}; false otherwise
@@ -3156,19 +3278,20 @@ export declare function isAgentJobError(value: unknown): value is AgentJobError;
3156
3278
  export declare function isConversationError(value: unknown): value is ConversationError;
3157
3279
 
3158
3280
  /**
3159
- * Narrows an `unknown` to a {@link ConversationSnapshot} — the total boundary guard for an
3160
- * UNTRUSTED snapshot read (a storage row a
3281
+ * Narrows an `unknown` to a {@link ConversationSnapshot} — a `string` `id`, an optional `string`
3282
+ * `summary`, and valid `sections` and `messages` arrays; the total boundary guard for an
3283
+ * untrusted snapshot read (a storage row a
3161
3284
  * {@link import('./conversations/stores/DatabaseConversationStore.js').DatabaseConversationStore}
3162
- * reads back from its opaque JSON column, a snapshot loaded from disk). The EXACT analogue of
3163
- * {@link import('@orkestrel/workspace').isWorkspaceSnapshot}.
3285
+ * reads back from its opaque JSON column, a snapshot loaded from disk), never throwing. The exact
3286
+ * analogue of {@link import('@orkestrel/workspace').isWorkspaceSnapshot}.
3164
3287
  *
3165
3288
  * @remarks
3166
- * A total guard (it NEVER throws — adversarial input returns `false`). It checks the snapshot's
3167
- * SHAPE: a `string` `id`, an OPTIONAL `string` `summary` (present-or-absent — the rollup is
3168
- * `undefined` until the first compaction), a `sections` array EVERY element of which is a valid
3169
- * {@link Section} ({@link isSection}), and a `messages` array EVERY element of which is a
3289
+ * A total guard (it never throws — adversarial input returns `false`). It checks the snapshot's
3290
+ * shape: a `string` `id`, an optional `string` `summary` (present-or-absent — the rollup is
3291
+ * `undefined` until the first compaction), a `sections` array every element of which is a valid
3292
+ * {@link Section} ({@link isSection}), and a `messages` array every element of which is a
3170
3293
  * valid {@link Message} ({@link isMessage}) — enough to safely impose the
3171
- * {@link ConversationSnapshot} type at a storage boundary WITHOUT a cast. The structural twin of
3294
+ * {@link ConversationSnapshot} type at a storage boundary without a cast. The structural twin of
3172
3295
  * {@link import('@orkestrel/workspace').isWorkspaceSnapshot}. A malformed blob (a non-record, a missing / non-string `id`, a
3173
3296
  * non-string `summary` when present, a non-array `sections` / `messages`, or any malformed
3174
3297
  * element) resolves `false`, so a
@@ -3190,14 +3313,15 @@ export declare function isConversationSnapshot(value: unknown): value is Convers
3190
3313
 
3191
3314
  /**
3192
3315
  * Checks whether an `unknown` is structurally a {@link Message} record — the per-message step of
3193
- * the {@link isConversationSnapshot} read-boundary narrow (a total guard over an untrusted storage
3194
- * read, never an assertion). The conversation analogue of
3316
+ * the {@link isConversationSnapshot} and {@link isSection} read-boundary narrows, where a present
3317
+ * `calls` must be an array of valid {@link import('@orkestrel/tool').ToolCall}s. Total, never
3318
+ * throwing, and never an assertion; the conversation analogue of
3195
3319
  * {@link import('@orkestrel/workspace').isFile}.
3196
3320
  *
3197
3321
  * @remarks
3198
- * A total guard (it NEVER throws — adversarial input returns `false`). It checks the message's
3199
- * SHAPE: a record with a `string` `id`, a `string` `role`, a `string` `content`, and — WHEN present
3200
- * — a `calls` array EVERY element of which is a valid
3322
+ * A total guard (it never throws — adversarial input returns `false`). It checks the message's
3323
+ * shape: a record with a `string` `id`, a `string` `role`, a `string` `content`, and — when present
3324
+ * — a `calls` array every element of which is a valid
3201
3325
  * {@link import('@orkestrel/tool').ToolCall} ({@link isToolCall} — the
3202
3326
  * fail-closed deepening: a tampered `calls` element rejects the message, so the snapshot
3203
3327
  * reads back as absent rather than replaying a malformed call) and an `images` that is an array
@@ -3205,7 +3329,7 @@ export declare function isConversationSnapshot(value: unknown): value is Convers
3205
3329
  * {@link import('./types.js').MessageRole}, so any storage-read role string is accepted
3206
3330
  * defensively rather than rejected against the current literal set). Enough to safely impose the
3207
3331
  * {@link Message} type at
3208
- * a storage boundary WITHOUT a cast.
3332
+ * a storage boundary without a cast.
3209
3333
  *
3210
3334
  * @param value - The value to test (one element of a snapshot's `messages` / a section's `messages`)
3211
3335
  * @returns True if `value` has the structural shape of a {@link Message}; false otherwise
@@ -3221,7 +3345,8 @@ export declare function isConversationSnapshot(value: unknown): value is Convers
3221
3345
  export declare function isMessage(value: unknown): value is Message;
3222
3346
 
3223
3347
  /**
3224
- * Narrows an unknown caught value to a {@link ProviderAbortError}.
3348
+ * Narrows an unknown caught value to a {@link ProviderAbortError} through `instanceof`, so a
3349
+ * `catch` can recover its `partial` result.
3225
3350
  *
3226
3351
  * @param value - The value to test (typically a `catch` binding)
3227
3352
  * @returns True if `value` is a {@link ProviderAbortError}; false otherwise
@@ -3238,15 +3363,16 @@ export declare function isMessage(value: unknown): value is Message;
3238
3363
  export declare function isProviderAbortError(value: unknown): value is ProviderAbortError;
3239
3364
 
3240
3365
  /**
3241
- * Checks whether an `unknown` is structurally a {@link Section} record — the per-section step of
3242
- * the {@link isConversationSnapshot} read-boundary narrow (a total guard over an untrusted storage
3243
- * read, never an assertion).
3366
+ * Checks whether an `unknown` is structurally a {@link Section} record — a `string` `id` and
3367
+ * `summary` beside a `messages` array of valid {@link Message}s, the per-section step of the
3368
+ * {@link isConversationSnapshot} read-boundary narrow. Total, never throwing, and never an
3369
+ * assertion.
3244
3370
  *
3245
3371
  * @remarks
3246
- * A total guard (it NEVER throws — adversarial input returns `false`). It checks the section's
3247
- * SHAPE: a record with a `string` `id`, a `string` `summary`, and a `messages` array EVERY element
3372
+ * A total guard (it never throws — adversarial input returns `false`). It checks the section's
3373
+ * shape: a record with a `string` `id`, a `string` `summary`, and a `messages` array every element
3248
3374
  * of which is a valid {@link Message} record ({@link isMessage}). Enough to safely impose
3249
- * the {@link Section} type at a storage boundary WITHOUT a cast.
3375
+ * the {@link Section} type at a storage boundary without a cast.
3250
3376
  *
3251
3377
  * @param value - The value to test (one element of a snapshot's `sections` array)
3252
3378
  * @returns True if `value` has the structural shape of a {@link Section}; false otherwise
@@ -3284,26 +3410,27 @@ export declare function joinThinking(running: string | undefined, next: string):
3284
3410
 
3285
3411
  /**
3286
3412
  * Implements the {@link ConversationStoreInterface} in memory — a process-lifetime `Map` of
3287
- * {@link ConversationSnapshot}s keyed by conversation id, the DEFAULT store
3288
- * {@link import('../../factories.js').createMemoryConversationStore} builds. The EXACT twin of
3413
+ * {@link ConversationSnapshot}s keyed by conversation id, the default store
3414
+ * {@link import('../../factories.js').createMemoryConversationStore} builds and the default
3415
+ * backing for `open` / `save`. The exact twin of
3289
3416
  * {@link import('@orkestrel/workspace').MemoryWorkspaceStore}.
3290
3417
  *
3291
3418
  * @remarks
3292
3419
  * A plain `Map<string, ConversationSnapshot>` — the snapshot is already pure,
3293
3420
  * self-contained JSON, so no encoding is needed for the memory tier. Like the
3294
3421
  * {@link import('@orkestrel/workspace').MemoryWorkspaceStore} it twins,
3295
- * there is NO idle-TTL and NO eviction: a persisted conversation lives until an explicit `delete`. A
3296
- * durable backend (JSON / SQLite / IndexedDB) swaps in through the SAME interface without touching
3422
+ * there is no idle-TTL and no eviction: a persisted conversation lives until an explicit `delete`. A
3423
+ * durable backend (JSON / SQLite / IndexedDB) swaps in through the same interface without touching
3297
3424
  * the {@link import('../ConversationManager.js').ConversationManager} or the
3298
3425
  * {@link import('../Conversation.js').Conversation} — its driver-pluggable twin is
3299
3426
  * {@link import('./DatabaseConversationStore.js').DatabaseConversationStore} (the snapshot as one
3300
3427
  * opaque JSON column).
3301
3428
  *
3302
3429
  * - **`get` resolves the persisted snapshot for an id**, or `undefined` if none is stored.
3303
- * - **`set` inserts / replaces under the snapshot's OWN `id`** (no separate id param).
3430
+ * - **`set` inserts / replaces under the snapshot's own `id`** (no separate id param).
3304
3431
  * - **`delete` drops a snapshot by id**; an absent id is a no-op (no throw).
3305
3432
  *
3306
- * The public surface is EXACTLY `get` / `set` / `delete` — no extra members (the method
3433
+ * The public surface is exactly `get` / `set` / `delete` — no extra members (the method
3307
3434
  * bijection with {@link ConversationStoreInterface}). Hydration is a caller concern: a
3308
3435
  * {@link import('../ConversationManager.js').ConversationManager} reads a snapshot back and rebuilds
3309
3436
  * the live conversation through the `snapshot` option (its `open` / `save`).
@@ -3322,8 +3449,27 @@ export declare function joinThinking(running: string | undefined, next: string):
3322
3449
  */
3323
3450
  export declare class MemoryConversationStore implements ConversationStoreInterface {
3324
3451
  #private;
3452
+ /**
3453
+ * Resolves the persisted snapshot for `id`, or `undefined` if none is stored.
3454
+ *
3455
+ * @param id - The conversation id to resolve (a {@link ConversationSnapshot.id})
3456
+ * @returns The persisted snapshot, or `undefined` if absent
3457
+ */
3325
3458
  get(id: string): Promise<ConversationSnapshot | undefined>;
3459
+ /**
3460
+ * Inserts or replaces a snapshot under its own `snapshot.id` (no separate id param —
3461
+ * mirroring {@link import('@orkestrel/workspace').WorkspaceStoreInterface}'s `set`).
3462
+ *
3463
+ * @param snapshot - The snapshot to store (keyed by its `id`)
3464
+ * @returns A promise that resolves after the snapshot is stored
3465
+ */
3326
3466
  set(snapshot: ConversationSnapshot): Promise<void>;
3467
+ /**
3468
+ * Drops a snapshot by id; an absent id is a no-op (no throw).
3469
+ *
3470
+ * @param id - The conversation id to drop
3471
+ * @returns A promise that resolves after the snapshot is dropped
3472
+ */
3327
3473
  delete(id: string): Promise<void>;
3328
3474
  }
3329
3475
 
@@ -3352,10 +3498,11 @@ export declare interface Message {
3352
3498
  }
3353
3499
 
3354
3500
  /**
3355
- * Estimates the per-message role/framing overhead {@link import('./helpers.js').estimateMessages}
3356
- * adds on top of a message's content estimate — accounts for the fixed wire framing every
3357
- * conversation turn carries (its role tag, delimiters) that {@link import('./helpers.js').estimateTokens}'s
3358
- * content-only heuristic does not otherwise capture.
3501
+ * Estimates the per-message role and framing overhead {@link import('./helpers.js').estimateMessages}
3502
+ * adds on top of a message's content estimate — `4` tokens for the fixed wire framing every
3503
+ * conversation turn carries (its role tag, its delimiters) that
3504
+ * {@link import('./helpers.js').estimateTokens}'s content-only heuristic does not otherwise
3505
+ * capture.
3359
3506
  */
3360
3507
  export declare const MESSAGE_TOKEN_OVERHEAD = 4;
3361
3508
 
@@ -3376,27 +3523,39 @@ export declare interface MessageInput {
3376
3523
  }
3377
3524
 
3378
3525
  /**
3379
- * Stores immutable {@link Message}s in insertion order; `add` mints the `id`.
3526
+ * Stores immutable {@link Message}s in insertion order and mints each `id` on `add` — the
3527
+ * message-store contract {@link AgentContextInterface.messages} is typed to, which the active
3528
+ * {@link ConversationInterface} satisfies structurally.
3380
3529
  *
3381
3530
  * @remarks
3382
3531
  * - **Store.** Messages live in insertion order; `count` is how many are stored.
3383
- * `add` takes one {@link MessageInput} or a batch and MINTS each message's
3532
+ * `add` takes one {@link MessageInput} or a batch and mints each message's
3384
3533
  * `id` (a random UUID), returning the created message(s). A stored message is
3385
3534
  * immutable — created once from its input, never mutated.
3386
3535
  * - **Lookup.** `message(id)` resolves one by id (`undefined` when absent);
3387
3536
  * `messages()` lists every message in insertion order.
3388
- * - **Removal.** `remove` drops one by id, or a batch — `true` only when EVERY supplied id
3537
+ * - **Removal.** `remove` drops one by id, or a batch — `true` only when every supplied id
3389
3538
  * was removed; `clear` empties the store.
3390
3539
  * - **Event-free.** A purely data store — no Emitter, no events.
3391
3540
  */
3392
3541
  export declare interface MessageManagerInterface {
3393
3542
  readonly count: number;
3543
+ /**
3544
+ * Stores one {@link MessageInput}, or a batch — mints each message's `id` and returns the
3545
+ * created message or messages; a stored message is immutable.
3546
+ */
3394
3547
  add(input: MessageInput): Message;
3395
3548
  add(inputs: readonly MessageInput[]): readonly Message[];
3549
+ /** Looks up one stored message by id (`undefined` when absent). */
3396
3550
  message(id: string): Message | undefined;
3551
+ /** Lists every stored message, in insertion order. */
3397
3552
  messages(): readonly Message[];
3553
+ /**
3554
+ * Removes one message by id, or a batch — `true` only when every supplied id was removed.
3555
+ */
3398
3556
  remove(id: string): boolean;
3399
3557
  remove(ids: readonly string[]): boolean;
3558
+ /** Removes every stored message. */
3400
3559
  clear(): void;
3401
3560
  }
3402
3561
 
@@ -3405,8 +3564,8 @@ export declare type MessageRole = 'system' | 'user' | 'assistant' | 'tool';
3405
3564
 
3406
3565
  /**
3407
3566
  * Reports a provider stream cancelled mid-flight by its bound signal — thrown by a
3408
- * {@link ProviderInterface}'s `stream`, carrying the {@link ProviderResult} assembled
3409
- * from whatever streamed before the cancel.
3567
+ * {@link ProviderInterface}'s `stream`, carrying the {@link ProviderResult} assembled from
3568
+ * whatever streamed before the cancel and the machine-readable `code` `'ABORT'`.
3410
3569
  *
3411
3570
  * @remarks
3412
3571
  * Lets a caller recover the partial content (and any tool calls / usage seen so far)
@@ -3422,18 +3581,18 @@ export declare class ProviderAbortError extends Error {
3422
3581
  }
3423
3582
 
3424
3583
  /**
3425
- * Represents one streamed delta a {@link ProviderInterface}'s `stream` yields — a TAGGED unit
3426
- * discriminated by the channel it belongs to, so the agent loop can re-surface the two
3427
- * channels separately (answer content vs. live reasoning) as it pumps.
3584
+ * Represents one streamed delta a {@link ProviderInterface}'s `stream` yields — a unit tagged by
3585
+ * the channel it belongs to, so the agent loop can re-surface answer content and live reasoning
3586
+ * separately as it pumps.
3428
3587
  *
3429
3588
  * @remarks
3430
3589
  * The discriminant `channel` names the axis that varies: a
3431
- * `'content'` delta is a chunk of the assistant ANSWER (the deltas that accumulate into
3590
+ * `'content'` delta is a chunk of the assistant answer (the deltas that accumulate into
3432
3591
  * {@link ProviderResult.content}); a `'thinking'` delta is a chunk of the model's
3433
- * REASONING the provider separated from the answer (the daemon's native
3434
- * `message.thinking` wire channel), surfaced LIVE so a consumer can stream it into a
3592
+ * reasoning the provider separated from the answer (the daemon's native
3593
+ * `message.thinking` wire channel), surfaced live so a consumer can stream it into a
3435
3594
  * collapsible without waiting for the assembled result. `text` is the delta's literal
3436
- * text. Thinking NEVER re-enters the conversation — it is display/audit metadata, exactly
3595
+ * text. Thinking never re-enters the conversation — it is display/audit metadata, exactly
3437
3596
  * as {@link ProviderResult.thinking} (the authoritative final accumulation) is.
3438
3597
  */
3439
3598
  export declare type ProviderDelta = {
@@ -3445,10 +3604,10 @@ export declare type ProviderDelta = {
3445
3604
  };
3446
3605
 
3447
3606
  /**
3448
- * Defines the pluggable LLM inference boundary — the one contract every agent chunk depends
3449
- * on. A provider turns a conversation (plus optional tools) into either a single
3450
- * assembled {@link ProviderResult} (`generate`) or a stream of {@link ProviderDelta}s that
3451
- * RETURNS the assembled result (`stream`).
3607
+ * Defines the pluggable LLM inference boundary — the one contract every agent chunk depends on. A
3608
+ * provider turns a conversation (plus optional tools) into either a single assembled {@link
3609
+ * ProviderResult} (`generate`) or a stream of {@link ProviderDelta}s that returns the assembled
3610
+ * result (`stream`).
3452
3611
  *
3453
3612
  * @remarks
3454
3613
  * - `id` is a stable per-instance trace label; `name` identifies the backend
@@ -3464,9 +3623,9 @@ export declare interface ProviderInterface {
3464
3623
  readonly id: string;
3465
3624
  readonly name: string;
3466
3625
  /**
3467
- * Holds the model's preferred context framing, by section kind — an OPTIONAL
3626
+ * Holds the model's preferred context framing, by section kind — an optional
3468
3627
  * {@link ContextFormat} an {@link import('./AgentContext.js').AgentContext}
3469
- * applies as the PROVIDER-DEFAULT level of its build cascade (beating the managers'
3628
+ * applies as the provider-default level of its build cascade (beating the managers'
3470
3629
  * built-in framing, beaten by a manager-options or per-item override). Omitted ⇒ the
3471
3630
  * provider is framing-agnostic and the managers' built-in defaults apply unchanged.
3472
3631
  */
@@ -3482,14 +3641,14 @@ export declare interface ProviderInterface {
3482
3641
  */
3483
3642
  generate(messages: readonly Message[], signal: AbortSignal, tools?: readonly ToolDefinition[], options?: ProviderStreamOptions): Promise<ProviderResult>;
3484
3643
  /**
3485
- * Streams one turn — yields {@link ProviderDelta}s (channel-tagged `content` / `thinking`
3486
- * chunks) as they arrive and RETURNS the assembled {@link ProviderResult} (the
3487
- * concatenated content + any separated reasoning + any tool calls + any usage) when the
3488
- * stream completes.
3644
+ * Streams one turn — yields channel-tagged `content` / `thinking` {@link ProviderDelta}s as
3645
+ * they arrive and returns the assembled {@link ProviderResult} (the concatenated content,
3646
+ * any separated reasoning, any tool calls, and any usage) when the stream completes. A
3647
+ * mid-stream abort throws a `ProviderAbortError` carrying the partial result.
3489
3648
  *
3490
3649
  * @remarks
3491
- * An abort mid-stream throws a `ProviderAbortError` whose `partial` holds whatever
3492
- * streamed before the cancel, so a caller can recover the partial content.
3650
+ * The `partial` holds whatever streamed before the cancel, so a caller can recover the
3651
+ * partial content.
3493
3652
  *
3494
3653
  * @param messages - The conversation so far
3495
3654
  * @param signal - Bounds the request; an abort throws `ProviderAbortError`
@@ -3506,9 +3665,9 @@ export declare interface ProviderInterface {
3506
3665
  * and the token usage it reported.
3507
3666
  *
3508
3667
  * @remarks
3509
- * `thinking` is present only when the turn produced reasoning the provider SPLIT
3510
- * AWAY from the answer (an in-content `<think>…</think>` span a thinking model
3511
- * emitted, or a wire-side reasoning field) — `content` is always the CLEAN answer,
3668
+ * `thinking` is present only when the turn produced reasoning the provider split
3669
+ * away from the answer (an in-content `<think>…</think>` span a thinking model
3670
+ * emitted, or a wire-side reasoning field) — `content` is always the clean answer,
3512
3671
  * and the thinking never re-enters the conversation (it is display/audit metadata,
3513
3672
  * not prompt text). `tools` is present only when the model wants tool calls (an
3514
3673
  * empty array is never surfaced — its absence means "no calls"). `usage` is present
@@ -3527,17 +3686,17 @@ export declare interface ProviderResult {
3527
3686
 
3528
3687
  /**
3529
3688
  * Carries the per-call options threaded into a {@link ProviderInterface}'s `generate` / `stream` —
3530
- * the bag a caller passes to influence ONE inference call without reconfiguring the
3531
- * provider instance.
3689
+ * the bag a caller passes to influence one inference call without reconfiguring the provider
3690
+ * instance.
3532
3691
  *
3533
3692
  * @remarks
3534
- * `think` OVERRIDES the provider's constructed reasoning preference for THIS call: `true`
3693
+ * `think` overrides the provider's constructed reasoning preference for this call: `true`
3535
3694
  * asks the backend to separate reasoning natively (a thinking model returns it on its
3536
3695
  * `message.thinking` channel, surfaced as `'thinking'` {@link ProviderDelta}s + the final
3537
3696
  * {@link ProviderResult.thinking}); `false` suppresses it. `schema`, when given, asks the
3538
3697
  * backend to constrain its response to the given JSON-Schema shape (the same open
3539
3698
  * JSON-Schema record {@link ToolDefinition.parameters} already carries) — a structured-output
3540
- * request for THIS call only. Both omitted ⇒ the provider's own defaults apply (the
3699
+ * request for this call only. Both omitted ⇒ the provider's own defaults apply (the
3541
3700
  * constructor value / no schema constraint), so the contract stays backward-safe — a caller
3542
3701
  * that passes no options behaves exactly as before.
3543
3702
  */
@@ -3549,9 +3708,9 @@ export declare interface ProviderStreamOptions {
3549
3708
  }
3550
3709
 
3551
3710
  /**
3552
- * Renders a path-addressed text body as a fenced reference block — the framing an
3553
- * {@link import('./AgentContext.js').AgentContext}'s ACTIVE-workspace text-file render emits (the
3554
- * active workspace is the SOLE document/image context).
3711
+ * Renders a path-addressed text body as a fenced reference block — a `File: <path>` label line
3712
+ * over a language-tagged fence, the framing an
3713
+ * {@link import('./AgentContext.js').AgentContext}'s active-workspace text-file render emits.
3555
3714
  *
3556
3715
  * @remarks
3557
3716
  * Produces `` File: <path>\n```<language>\n<content>\n``` `` — the `File:` label line, then a
@@ -3577,10 +3736,10 @@ export declare function renderFencedFile(path: string, language: string, content
3577
3736
 
3578
3737
  /**
3579
3738
  * Renders one context section — the resolved `open`, each item's rendering, and the resolved
3580
- * `close` when one exists, blank-line joined.
3739
+ * `close` when one exists, blank-line joined; `undefined` when the section has no items.
3581
3740
  *
3582
3741
  * @remarks
3583
- * Pure and total. A section with NO items renders nothing (`undefined`), so an empty or fully
3742
+ * Pure and total. A section with no items renders nothing (`undefined`), so an empty or fully
3584
3743
  * scoped-out manager stays silent — its `open` / `close` never appear without items. `close`
3585
3744
  * is the only optional slot: an unset one (there is no built-in close) drops the
3586
3745
  * trailing line.
@@ -3602,13 +3761,13 @@ export declare function renderFencedFile(path: string, language: string, content
3602
3761
  export declare function renderSection<T>(open: string, items: readonly T[], render: (item: T) => string, close: string | undefined): string | undefined;
3603
3762
 
3604
3763
  /**
3605
- * Resolves one section's CLOSE text through the format cascade — manager-options override >
3606
- * provider default.
3764
+ * Resolves one section's close text through the format cascade — manager-options override >
3765
+ * provider default; `undefined` when neither sets one, because there is no built-in close.
3607
3766
  *
3608
3767
  * @remarks
3609
- * Pure and total. There is NO built-in close, so a section with neither level set returns
3768
+ * Pure and total. There is no built-in close, so a section with neither level set returns
3610
3769
  * `undefined` and {@link renderSection} appends no closing line. Paired with
3611
- * {@link resolveOpen}, one level can WRAP the whole group.
3770
+ * {@link resolveOpen}, one level can wrap the whole group.
3612
3771
  *
3613
3772
  * @typeParam T - The section item the manager renders
3614
3773
  * @param manager - The section source (its `format` override)
@@ -3624,14 +3783,14 @@ export declare function renderSection<T>(open: string, items: readonly T[], rend
3624
3783
  export declare function resolveClose<T>(manager: ContextSectionSourceInterface<T>, provider: ContextSectionFormat<T> | undefined): string | undefined;
3625
3784
 
3626
3785
  /**
3627
- * Resolves ONE item's rendering through the format cascade — item override >
3628
- * manager-options override > provider default > built-in rendering.
3786
+ * Resolves one item's rendering through the format cascade — item override > manager-options
3787
+ * override > provider default > built-in rendering.
3629
3788
  *
3630
3789
  * @remarks
3631
3790
  * Pure and total. The item's own `override` is the most-specific level (a fully-rendered
3632
3791
  * string for that item alone). A manager's `render(item)` already encapsulates
3633
3792
  * `[options-override → built-in]`, so it is reached only when no higher level applies — and
3634
- * there it IS the built-in rendering.
3793
+ * there it is the built-in rendering.
3635
3794
  *
3636
3795
  * @typeParam T - The section item being rendered (it may carry its own `override`)
3637
3796
  * @param manager - The section source (its `format` override + its built-in `render`)
@@ -3651,13 +3810,13 @@ export declare function resolveItem<T extends {
3651
3810
  }>(manager: ContextSectionSourceInterface<T>, provider: ContextSectionFormat<T> | undefined, item: T): string;
3652
3811
 
3653
3812
  /**
3654
- * Resolves one section's OPEN text through the format cascade — manager-options override >
3813
+ * Resolves one section's open text through the format cascade — manager-options override >
3655
3814
  * provider default > built-in header.
3656
3815
  *
3657
3816
  * @remarks
3658
- * Pure and total. The leading text has NO per-item level. A manager's `open` already
3817
+ * Pure and total. The leading text has no per-item level. A manager's `open` already
3659
3818
  * encapsulates `[options-override → built-in]`, so it is reached only when neither the
3660
- * override's `open` nor the provider's `open` applies — and there it IS the built-in header.
3819
+ * override's `open` nor the provider's `open` applies — and there it is the built-in header.
3661
3820
  *
3662
3821
  * @typeParam T - The section item the manager renders
3663
3822
  * @param manager - The section source (its `format` override + its built-in `open`)
@@ -3674,15 +3833,15 @@ export declare function resolveOpen<T>(manager: ContextSectionSourceInterface<T>
3674
3833
 
3675
3834
  /**
3676
3835
  * Holds the immutable per-run outcome an {@link AgentInterface}'s loop settles on — the value its
3677
- * run RETURNS, assembled from there into the {@link AgentResult} its `stream`'s `result`
3678
- * promise resolves.
3836
+ * run returns, assembled from there into the {@link AgentResult} its `stream`'s `result` promise
3837
+ * resolves.
3679
3838
  *
3680
3839
  * @remarks
3681
3840
  * Computed inside one run (so concurrent runs never share state) and returned once, when the
3682
3841
  * loop settles: `content` is the streamed assistant text, `thinking` the reasoning the
3683
3842
  * provider calls separated from it ({@link ProviderResult.thinking}, joined across calls —
3684
3843
  * `undefined` when none surfaced), `usage` the summed {@link TokenUsage} (present only when
3685
- * a provider call reported it), `partial` is `true` when a cancel committed the run early OR
3844
+ * a provider call reported it), `partial` is `true` when a cancel committed the run early or
3686
3845
  * when the loop exhausted its `limit` with unresolved tool intent, and `exhausted` is `true`
3687
3846
  * in that second case specifically (a distinct, non-cancel cause the {@link AgentEventMap}
3688
3847
  * `exhaust` event observes). It is the settled outcome one run returns, before the agent folds
@@ -3697,7 +3856,8 @@ export declare interface RunOutcome {
3697
3856
  }
3698
3857
 
3699
3858
  /**
3700
- * Sanitizes one reported token count into a safe non-negative integer.
3859
+ * Sanitizes one reported token count into a safe non-negative integer — a non-finite or
3860
+ * non-positive value becomes `0`, and a positive fractional value floors down.
3701
3861
  *
3702
3862
  * @param value - The token count to sanitize
3703
3863
  * @returns The floored count, or `0` when the value is non-finite or non-positive
@@ -3725,23 +3885,25 @@ export declare function sanitizeToken(value: number): number;
3725
3885
  export declare function sanitizeUsage(usage: TokenUsage): TokenUsage;
3726
3886
 
3727
3887
  /**
3728
- * Represents a named, immutable filter over a richer context's items — an optional
3729
- * allow-list per category (`instructions` / `tools` / `files`), each keyed by that
3730
- * category's identity (an instruction's `name`, a tool's `name`, a workspace file's `path`).
3888
+ * Represents a named, immutable filter over a richer context's items — an optional allow-list per
3889
+ * category (`instructions` / `tools` / `files`), each keyed by that category's identity (an
3890
+ * instruction's `name`, a tool's `name`, a workspace file's `path`) and read as an allow-list:
3891
+ * `undefined` lets everything pass, `[]` lets nothing pass, and a non-empty list passes the listed
3892
+ * keys alone. `narrow` composes a tighter child by set intersection.
3731
3893
  *
3732
3894
  * @remarks
3733
- * - **A category list is three-way.** `undefined` ⇒ NO constraint on that category (all
3734
- * pass); `[]` ⇒ NONE pass; a non-empty list ⇒ only the listed keys pass. The build
3895
+ * - **A category list is three-way.** `undefined` ⇒ no constraint on that category (all
3896
+ * pass); `[]` ⇒ none pass; a non-empty list ⇒ only the listed keys pass. The build
3735
3897
  * step / loop apply this through `filterAllowList`.
3736
- * - **Immutable.** The `id` is minted at construction; every supplied list is COPIED in
3898
+ * - **Immutable.** The `id` is minted at construction; every supplied list is copied in
3737
3899
  * (so a later mutation of the caller's array can't leak in), and the lists are
3738
- * `readonly`. A `Scope` is never mutated after construction — `narrow` returns a NEW
3900
+ * `readonly`. A `Scope` is never mutated after construction — `narrow` returns a new
3739
3901
  * one rather than altering this one.
3740
- * - **`narrow` is set-INTERSECTION (immutable composition).** A child scope's visible set
3741
- * per category is the intersection of THIS scope's list and the config's list — but
3902
+ * - **`narrow` is set-intersection (immutable composition).** A child scope's visible set
3903
+ * per category is the intersection of this scope's list and the config's list — but
3742
3904
  * `undefined` means "no constraint", so it acts as the universal set: intersecting
3743
3905
  * `undefined` with a list yields the list, and `undefined` with `undefined` stays
3744
- * `undefined`. Narrowing can only TIGHTEN, never widen — a key excluded by a parent
3906
+ * `undefined`. Narrowing can only tighten, never widen — a key excluded by a parent
3745
3907
  * can never be re-admitted by a child.
3746
3908
  *
3747
3909
  * @example
@@ -3765,16 +3927,17 @@ export declare class Scope implements ScopeInterface {
3765
3927
  }
3766
3928
 
3767
3929
  /**
3768
- * Lists the per-category allow-lists a {@link ScopeInterface} carries — an optional
3769
- * `readonly string[]` for `instructions`, for `tools`, and for `files`, each keyed by that
3770
- * category's identity (an instruction's `name`, a tool's `name`, a workspace file's
3771
- * `path`).
3930
+ * Lists the per-category allow-lists a {@link ScopeInterface} carries — an optional `readonly
3931
+ * string[]` for `instructions`, for `tools`, and for `files`, each keyed by that category's
3932
+ * identity (an instruction's `name`, a tool's `name`, a workspace file's `path`) and read as an
3933
+ * allow-list: `undefined` lets everything pass, `[]` lets nothing pass, and a non-empty list passes
3934
+ * the listed keys alone.
3772
3935
  *
3773
3936
  * @remarks
3774
- * Each list is THREE-WAY (see {@link import('./helpers.js').filterAllowList}): `undefined`
3775
- * ⇒ NO constraint on that category (all pass); `[]` ⇒ NONE pass; a non-empty list ⇒ only
3937
+ * Each list is three-way (see {@link import('./helpers.js').filterAllowList}): `undefined`
3938
+ * ⇒ no constraint on that category (all pass); `[]` ⇒ none pass; a non-empty list ⇒ only
3776
3939
  * the listed keys pass. It is the shape both a {@link ScopeInput} and `Scope.narrow`
3777
- * accept (a `name`-less narrowing config). `files` filters the ACTIVE workspace's rendered
3940
+ * accept (a `name`-less narrowing config). `files` filters the active workspace's rendered
3778
3941
  * files (by `path`) in {@link AgentContextInterface.build} — both the text files folded into
3779
3942
  * the system block and the image files attached to the last user message.
3780
3943
  */
@@ -3784,7 +3947,7 @@ export declare interface ScopeFilter {
3784
3947
  /** Lists the allowed tool `name`s (`undefined` ⇒ all, `[]` ⇒ none, else only-listed). */
3785
3948
  readonly tools?: readonly string[];
3786
3949
  /**
3787
- * Lists the allowed ACTIVE-workspace file `path`s (`undefined` ⇒ all, `[]` ⇒ none, else only-listed) —
3950
+ * Lists the allowed active-workspace file `path`s (`undefined` ⇒ all, `[]` ⇒ none, else only-listed) —
3788
3951
  * the filter {@link AgentContextInterface.build} applies to the active workspace's
3789
3952
  * {@link import('@orkestrel/workspace').WorkspaceInterface.files} before rendering them (text → the system block, image →
3790
3953
  * the last user message).
@@ -3801,33 +3964,35 @@ export declare interface ScopeInput extends ScopeFilter {
3801
3964
  }
3802
3965
 
3803
3966
  /**
3804
- * Represents a named, immutable filter over a richer context's items — the per-category
3805
- * allow-lists ({@link ScopeFilter}) plus an `id` / `name`, and a `narrow` that
3806
- * composes a tighter child by set-INTERSECTION.
3967
+ * Represents a named, immutable filter over a richer context's items — the per-category allow-lists
3968
+ * ({@link ScopeFilter}) plus an `id` / `name`, and a `narrow` that composes a tighter child by set
3969
+ * intersection.
3807
3970
  *
3808
3971
  * @remarks
3809
3972
  * Each list is three-way (`undefined` ⇒ all, `[]` ⇒ none, else only-listed). `narrow`
3810
- * returns a NEW scope whose per-category visible set is the intersection of this scope's
3973
+ * returns a new scope whose per-category visible set is the intersection of this scope's
3811
3974
  * list and the config's — with `undefined` treated as the universal set (no constraint),
3812
3975
  * so `undefined ∩ list = list` and `undefined ∩ undefined = undefined`. Narrowing can
3813
- * only TIGHTEN (a parent-excluded key never returns); the scope itself is never mutated.
3976
+ * only tighten (a parent-excluded key never returns); the scope itself is never mutated.
3814
3977
  */
3815
3978
  export declare interface ScopeInterface extends ScopeFilter {
3816
3979
  readonly id: string;
3817
3980
  readonly name: string;
3818
3981
  /**
3819
- * Composes a tighter child scope — its per-category set is the intersection of this
3820
- * scope's list and `config`'s (an `undefined` side imposing no constraint).
3982
+ * Composes a tighter child scope — each category is the set intersection of this scope's
3983
+ * list and `config`'s (an `undefined` side imposing no constraint), returned as a new
3984
+ * scope that leaves this one unchanged.
3821
3985
  *
3822
3986
  * @param config - The narrowing allow-lists (a `name`-less {@link ScopeFilter})
3823
- * @returns A NEW, tighter {@link ScopeInterface} (this one is left unchanged)
3987
+ * @returns A new, tighter {@link ScopeInterface} (this one is left unchanged)
3824
3988
  */
3825
3989
  narrow(config: ScopeFilter): ScopeInterface;
3826
3990
  }
3827
3991
 
3828
3992
  /**
3829
- * Registers the named filters a richer context reuses — immutable {@link Scope}s keyed by
3830
- * their minted `id`, in insertion order.
3993
+ * Registers the named filters a richer context reuses — immutable {@link Scope}s keyed by their
3994
+ * minted `id`, in insertion order, where `create` always mints and stores rather than overwriting,
3995
+ * and an observable `emitter` reports each change.
3831
3996
  *
3832
3997
  * @remarks
3833
3998
  * - **Registry.** Scopes live in an insertion-ordered `Map` keyed by their minted `id`;
@@ -3836,11 +4001,11 @@ export declare interface ScopeInterface extends ScopeFilter {
3836
4001
  * one up, and `scopes()` lists them in insertion order. (Unlike the name-keyed
3837
4002
  * instruction registry, a scope's key is its minted `id`, so two scopes may share a
3838
4003
  * `name`; `create` therefore always adds — it never overwrites.)
3839
- * - **Removal.** `remove` drops one by id, or a batch — `true` only when EVERY supplied id
4004
+ * - **Removal.** `remove` drops one by id, or a batch — `true` only when every supplied id
3840
4005
  * was removed; `clear` empties the registry.
3841
4006
  * - **Observable.** The owned {@link emitter} ({@link ScopeManagerEventMap}) carries
3842
4007
  * `create` (the created scope) / `remove` (the id) / `clear`. Every event is emitted
3843
- * directly, strictly AFTER the map mutation completes; the emitter isolates a listener
4008
+ * directly, strictly after the map mutation completes; the emitter isolates a listener
3844
4009
  * throw and routes it to its `error` handler (the `error` option), so a buggy observer can
3845
4010
  * never corrupt a mutation.
3846
4011
  *
@@ -3900,12 +4065,19 @@ export declare type ScopeManagerEventMap = {
3900
4065
  export declare interface ScopeManagerInterface {
3901
4066
  readonly emitter: EmitterInterface<ScopeManagerEventMap>;
3902
4067
  readonly count: number;
4068
+ /**
4069
+ * Mints a scope from a {@link ScopeInput} (an `id` plus the per-category allow-lists) and
4070
+ * stores it — always adds, never overwrites.
4071
+ */
3903
4072
  create(input: ScopeInput): ScopeInterface;
4073
+ /** Looks up one scope by id (`undefined` when absent). */
3904
4074
  scope(id: string): ScopeInterface | undefined;
3905
4075
  /** Lists every scope, in insertion order. */
3906
4076
  scopes(): readonly ScopeInterface[];
4077
+ /** Removes one scope by id, or a batch — `true` only when every supplied id was removed. */
3907
4078
  remove(id: string): boolean;
3908
4079
  remove(ids: readonly string[]): boolean;
4080
+ /** Removes every scope. */
3909
4081
  clear(): void;
3910
4082
  }
3911
4083
 
@@ -3925,9 +4097,9 @@ export declare interface ScopeManagerOptions {
3925
4097
  *
3926
4098
  * @remarks
3927
4099
  * `summary` is the model-written digest of this slice (through the
3928
- * {@link ConversationSummaryHandler}); `messages` are the folded ORIGINALS, RETAINED in full so
4100
+ * {@link ConversationSummaryHandler}); `messages` are the folded originals, retained in full so
3929
4101
  * `rehydrate` can pull them back and `search` can scan them (compaction shrinks the model
3930
- * INPUT, never discards history).
4102
+ * input, never discards history).
3931
4103
  */
3932
4104
  export declare interface Section {
3933
4105
  readonly id: string;
@@ -3938,15 +4110,17 @@ export declare interface Section {
3938
4110
  }
3939
4111
 
3940
4112
  /**
3941
- * Runs one rehydrated agent and applies the partial-as-configurable-failure policy — the
3942
- * shared job-handler step BOTH `createAgentQueue` and `createAgentRunner` settle each job
3943
- * through, so the policy can never diverge between them.
4113
+ * Runs one rehydrated agent and applies the partial-as-configurable-failure policy — a partial
4114
+ * run throws an {@link import('./errors.js').AgentJobError} unless the `partial` policy allows
4115
+ * it, and a natural finish resolves. The shared job-handler step `createAgentQueue` and
4116
+ * `createAgentRunner` both settle each job through, so the policy can never diverge between
4117
+ * them.
3944
4118
  *
3945
4119
  * @remarks
3946
- * A turn that committed PARTIAL (a cancel — abort / budget / timeout) is by default a
3947
- * FAILURE, so it THROWS an {@link import('./errors.js').AgentJobError} carrying the partial
3948
- * (the Queue's retries + a Runner's fail-fast then engage); the `partial` policy RESOLVES
3949
- * it as success instead. A natural finish ALWAYS resolves with its result.
4120
+ * A turn that committed partial (a cancel — abort / budget / timeout) is by default a
4121
+ * failure, so it throws an {@link import('./errors.js').AgentJobError} carrying the partial
4122
+ * (the Queue's retries + a Runner's fail-fast then engage); the `partial` policy resolves
4123
+ * it as success instead. A natural finish always resolves with its result.
3950
4124
  *
3951
4125
  * @param agent - The rehydrated {@link AgentInterface} to run to its {@link AgentResult}
3952
4126
  * @param partial - The partial policy. If `true`, a partial result resolves as success; if
@@ -3969,7 +4143,7 @@ export declare function settleAgentJob(agent: AgentInterface, partial: boolean):
3969
4143
  * @remarks
3970
4144
  * Iterate `events` to consume the live `T` chunks as they arrive; `await result` for
3971
4145
  * the eventual `R` outcome (it resolves once `events` completes). `abort(reason)`
3972
- * cancels the in-flight operation — for an agent turn the `result` then RESOLVES
4146
+ * cancels the in-flight operation — for an agent turn the `result` then resolves
3973
4147
  * (with a partial outcome), since a cancel is not an error.
3974
4148
  *
3975
4149
  * @typeParam T - The live event type the stream yields
@@ -4009,39 +4183,40 @@ export declare interface StreamInterface<T, R> {
4009
4183
  export declare function sumUsage(running: TokenUsage | undefined, next: TokenUsage): TokenUsage;
4010
4184
 
4011
4185
  /**
4012
- * Names the closing tag that ends a {@link THINK_OPEN} reasoning span. A span the stream never closes
4013
- * (the model was cut off mid-reasoning) is treated as thinking to its end —
4014
- * {@link import('./types.js').ThinkSplitterInterface.flush} settles it.
4186
+ * Names the closing tag that ends a {@link THINK_OPEN} reasoning span — `'</think>'`. A span the
4187
+ * stream never closes (the model was cut off mid-reasoning) is treated as thinking to its end,
4188
+ * and {@link import('./types.js').ThinkSplitterInterface.flush} settles it.
4015
4189
  */
4016
4190
  export declare const THINK_CLOSE = "</think>";
4017
4191
 
4018
4192
  /**
4019
4193
  * Names the opening tag a {@link import('./ThinkSplitter.js').ThinkSplitter} recognizes as the start of
4020
- * an in-content reasoning span — the de-facto wire convention thinking models (qwen3, DeepSeek-R1
4021
- * family) emit their chain-of-thought under when a daemon renders it inline instead of on a
4022
- * separate wire field. Paired with {@link THINK_CLOSE}.
4194
+ * an in-content reasoning span — `'<think>'`, the de-facto wire convention thinking models
4195
+ * (qwen3, DeepSeek-R1 family) emit their chain-of-thought under when a daemon renders it inline
4196
+ * instead of on a separate wire field. Paired with {@link THINK_CLOSE}.
4023
4197
  */
4024
4198
  export declare const THINK_OPEN = "<think>";
4025
4199
 
4026
4200
  /**
4027
- * Feeds raw content deltas through a tiny stream-stateful state machine that routes
4028
- * everything inside a `<think>…</think>` span to `thinking` and returns everything outside
4029
- * it as clean content, so a provider yields ONLY the answer and surfaces the reasoning as
4030
- * {@link import('./types.js').ProviderResult.thinking}.
4201
+ * Feeds raw content deltas through a tiny stream-stateful state machine that routes everything
4202
+ * inside a `<think>…</think>` span to `thinking` and returns everything outside it as clean
4203
+ * content, so a provider yields the answer alone and surfaces the reasoning as
4204
+ * {@link import('./types.js').ProviderResult.thinking}. A tag split across deltas is held until
4205
+ * disambiguated, `flush()` settles the stream end, and one splitter serves one stream.
4031
4206
  *
4032
4207
  * @remarks
4033
4208
  * - **Cross-chunk tags.** A tag may arrive split across wire deltas (`'<thi'` then
4034
- * `'nk>'`): any suffix of the pending text that is a strict PREFIX of a tag being
4035
- * scanned for is HELD BACK (neither surfaced nor routed) until the next delta — or
4209
+ * `'nk>'`): any suffix of the pending text that is a strict prefix of a tag being
4210
+ * scanned for is held back (neither surfaced nor routed) until the next delta — or
4036
4211
  * `flush()` — disambiguates it. A held tag prefix that never completes is real
4037
4212
  * content; a held close-tag prefix inside a span is thinking.
4038
- * - **The IMPLICIT leading open (the qwen3-template shape).** Some chat templates
4039
- * PRE-SEED `<think>` into the prompt scaffold, so the wire stream begins
4040
- * MID-REASONING and only a bare `</think>` appears. Before any tag event, a bare
4041
- * close therefore RECLASSIFIES everything surfaced so far (plus the pre-close
4213
+ * - **The implicit leading open (the qwen3-template shape).** Some chat templates
4214
+ * pre-seed `<think>` into the prompt scaffold, so the wire stream begins
4215
+ * mid-reasoning and only a bare `</think>` appears. Before any tag event, a bare
4216
+ * close therefore reclassifies everything surfaced so far (plus the pre-close
4042
4217
  * pending) as thinking — `content` is corrected retroactively (the already-returned
4043
4218
  * prefix cannot be recalled, so `content` is the authoritative accumulation). The
4044
- * rule is ONE-SHOT: after any tag event a bare `</think>` is plain text.
4219
+ * rule is one-shot: after any tag event a bare `</think>` is plain text.
4045
4220
  * - **Multiple spans** accumulate onto `thinking` in stream order. A nested-looking
4046
4221
  * `<think>` inside an open span is thinking text (no nesting is tracked — the
4047
4222
  * first `</think>` closes the span), matching how the models emit it.
@@ -4069,59 +4244,67 @@ export declare class ThinkSplitter implements ThinkSplitterInterface {
4069
4244
  }
4070
4245
 
4071
4246
  /**
4072
- * Splits a thinking model's in-content `<think>…</think>` reasoning spans away from the
4073
- * answer, delta by delta with per-stream state, so a provider yields ONLY clean content
4074
- * and surfaces the reasoning as {@link ProviderResult.thinking}.
4247
+ * Splits a thinking model's in-content `<think>…</think>` reasoning spans away from the answer,
4248
+ * delta by delta with per-stream state, so a provider yields clean content alone and surfaces the
4249
+ * reasoning as {@link ProviderResult.thinking}.
4075
4250
  *
4076
4251
  * @remarks
4077
- * - **Stateful across deltas.** A tag may arrive SPLIT across wire chunks (`'<thi'`
4252
+ * - **Stateful across deltas.** A tag may arrive split across wire chunks (`'<thi'`
4078
4253
  * ending one delta, `'nk>'` opening the next) — `split` holds any ambiguous tail
4079
4254
  * back until the next delta (or `flush`) disambiguates it, so a partial tag is
4080
4255
  * never leaked as content and never mis-eaten as thinking.
4081
- * - **`split(delta)`** feeds one raw content delta and returns the CLEAN content to
4256
+ * - **`split(delta)`** feeds one raw content delta and returns the clean content to
4082
4257
  * surface for it (possibly `''` — for example mid-think). Text inside a
4083
4258
  * `<think>…</think>` span accumulates on `thinking`; multiple spans accumulate in
4084
4259
  * order; a nested-looking `<think>` inside an open span is thinking text (no
4085
4260
  * nesting — the first `</think>` closes).
4086
- * - **The IMPLICIT leading open (the qwen3-template shape).** Some chat templates
4087
- * PRE-SEED `<think>` into the prompt scaffold, so the wire stream begins
4088
- * MID-REASONING and only a bare `</think>` ever appears. Before any tag event, a
4089
- * bare close therefore RECLASSIFIES everything surfaced so far (plus the pre-close
4261
+ * - **The implicit leading open (the qwen3-template shape).** Some chat templates
4262
+ * pre-seed `<think>` into the prompt scaffold, so the wire stream begins
4263
+ * mid-reasoning and only a bare `</think>` ever appears. Before any tag event, a
4264
+ * bare close therefore reclassifies everything surfaced so far (plus the pre-close
4090
4265
  * pending) as thinking — `content` is corrected retroactively, while the already
4091
4266
  * `split`-returned prefix cannot be recalled (the one shape where the per-delta
4092
- * returns over-report; `content` stays authoritative). The rule is ONE-SHOT: after
4267
+ * returns over-report; `content` stays authoritative). The rule is one-shot: after
4093
4268
  * any tag event a bare `</think>` is plain text (prose quoting the tag stays text).
4094
- * - **`flush()`** settles the stream end: an UNCLOSED `<think>` tail (the model was
4269
+ * - **`flush()`** settles the stream end: an unclosed `<think>` tail (the model was
4095
4270
  * cut off mid-reasoning) lands on `thinking`; a held partial tag that never
4096
4271
  * completed (`'<thi'` then EOF) is returned as the final clean-content delta —
4097
4272
  * it was real text after all.
4098
4273
  * - **`content` / `thinking`** are the authoritative accumulations so far (read them
4099
- * after the stream — or mid-stream for a cancel's partial); `content` is the ONE
4274
+ * after the stream — or mid-stream for a cancel's partial); `content` is the one
4100
4275
  * exact clean-content source (the per-delta returns match it except across an
4101
- * implicit-open reclassification). One splitter serves ONE stream; create a fresh
4276
+ * implicit-open reclassification). One splitter serves one stream; create a fresh
4102
4277
  * one per call ({@link import('./factories.js').createThinkSplitter}).
4103
4278
  */
4104
4279
  export declare interface ThinkSplitterInterface {
4105
- /** Holds the AUTHORITATIVE clean content accumulated so far (corrected across an implicit-open reclassification). */
4280
+ /** Holds the authoritative clean content accumulated so far (corrected across an implicit-open reclassification). */
4106
4281
  readonly content: string;
4107
4282
  /** Holds the reasoning text accumulated from every `<think>…</think>` span so far. */
4108
4283
  readonly thinking: string;
4109
- /** Feeds one raw delta; returns the clean (non-think) content to surface for it. */
4284
+ /**
4285
+ * Feeds one raw delta and returns the clean, non-think content to surface for it (possibly
4286
+ * `''`) — a tag split across deltas is held until disambiguated, never leaked as content
4287
+ * and never mis-eaten as thinking.
4288
+ */
4110
4289
  split(delta: string): string;
4111
- /** Settles the stream end — returns any held clean tail; an unclosed think span lands on `thinking`. */
4290
+ /**
4291
+ * Settles the stream end — a held partial tag that never completed returns as the final
4292
+ * content delta, and an unclosed think span's tail lands on `thinking`.
4293
+ */
4112
4294
  flush(): string;
4113
4295
  }
4114
4296
 
4115
4297
  /**
4116
4298
  * Names the section header {@link import('./AgentContext.js').AgentContext}'s `build()` renders the
4117
- * ACTIVE workspace's TEXT files under — the leading line of the dedicated workspace block in the
4118
- * system message, the carrier-split counterpart to the documents / images section headers.
4299
+ * active workspace's text files under — `'## Workspace'`, the leading line of the dedicated
4300
+ * workspace block in the system message and the carrier-split counterpart to the documents and
4301
+ * images section headers.
4119
4302
  *
4120
4303
  * @remarks
4121
- * `build()` OWNS the workspace render (a `Workspace` / `WorkspaceManager` stays file-focused — no
4304
+ * `build()` owns the workspace render (a `Workspace` / `WorkspaceManager` stays file-focused — no
4122
4305
  * `open` / `format` getters), so this header lives here as the agents module's one
4123
4306
  * workspace-section framing constant rather than on a manager. Each workspace text file renders
4124
- * beneath it as a fenced `` File: <path>\n```<language>\n<text>\n``` `` block — the SAME framing
4307
+ * beneath it as a fenced `` File: <path>\n```<language>\n<text>\n``` `` block — the same framing
4125
4308
  * the documents section uses — placed immediately after the documents section in the system block.
4126
4309
  */
4127
4310
  export declare const WORKSPACE_SECTION_HEADER = "## Workspace";