@animalabs/agent-framework 0.29.0 → 0.31.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (236) hide show
  1. package/README.md +71 -8
  2. package/dist/src/admission/admit.d.ts +90 -0
  3. package/dist/src/admission/admit.d.ts.map +1 -0
  4. package/dist/src/admission/admit.js +43 -0
  5. package/dist/src/admission/admit.js.map +1 -0
  6. package/dist/src/agent.d.ts +50 -9
  7. package/dist/src/agent.d.ts.map +1 -1
  8. package/dist/src/agent.js +125 -23
  9. package/dist/src/agent.js.map +1 -1
  10. package/dist/src/api/mcp-server-core.d.ts.map +1 -1
  11. package/dist/src/api/mcp-server-core.js +10 -3
  12. package/dist/src/api/mcp-server-core.js.map +1 -1
  13. package/dist/src/author-presentation.d.ts +50 -0
  14. package/dist/src/author-presentation.d.ts.map +1 -0
  15. package/dist/src/author-presentation.js +58 -0
  16. package/dist/src/author-presentation.js.map +1 -0
  17. package/dist/src/code-execution/isolate/render.d.ts.map +1 -1
  18. package/dist/src/code-execution/isolate/render.js +7 -6
  19. package/dist/src/code-execution/isolate/render.js.map +1 -1
  20. package/dist/src/code-execution/isolate/scripts.d.ts.map +1 -1
  21. package/dist/src/code-execution/isolate/scripts.js +5 -4
  22. package/dist/src/code-execution/isolate/scripts.js.map +1 -1
  23. package/dist/src/dendrite/index.d.ts +6 -0
  24. package/dist/src/dendrite/index.d.ts.map +1 -0
  25. package/dist/src/dendrite/index.js +3 -0
  26. package/dist/src/dendrite/index.js.map +1 -0
  27. package/dist/src/dendrite/presets.d.ts +60 -0
  28. package/dist/src/dendrite/presets.d.ts.map +1 -0
  29. package/dist/src/dendrite/presets.js +117 -0
  30. package/dist/src/dendrite/presets.js.map +1 -0
  31. package/dist/src/dendrite/registry.d.ts +260 -0
  32. package/dist/src/dendrite/registry.d.ts.map +1 -0
  33. package/dist/src/dendrite/registry.js +742 -0
  34. package/dist/src/dendrite/registry.js.map +1 -0
  35. package/dist/src/dendrite/types.d.ts +392 -0
  36. package/dist/src/dendrite/types.d.ts.map +1 -0
  37. package/dist/src/dendrite/types.js +24 -0
  38. package/dist/src/dendrite/types.js.map +1 -0
  39. package/dist/src/framework.d.ts +806 -118
  40. package/dist/src/framework.d.ts.map +1 -1
  41. package/dist/src/framework.js +4180 -1121
  42. package/dist/src/framework.js.map +1 -1
  43. package/dist/src/gate/event-gate.d.ts +36 -21
  44. package/dist/src/gate/event-gate.d.ts.map +1 -1
  45. package/dist/src/gate/event-gate.js +223 -149
  46. package/dist/src/gate/event-gate.js.map +1 -1
  47. package/dist/src/gate/recipe-reconcile.d.ts.map +1 -1
  48. package/dist/src/gate/recipe-reconcile.js +6 -5
  49. package/dist/src/gate/recipe-reconcile.js.map +1 -1
  50. package/dist/src/host-presentation.d.ts +4 -0
  51. package/dist/src/host-presentation.d.ts.map +1 -1
  52. package/dist/src/host-presentation.js +12 -10
  53. package/dist/src/host-presentation.js.map +1 -1
  54. package/dist/src/index.d.ts +6 -2
  55. package/dist/src/index.d.ts.map +1 -1
  56. package/dist/src/index.js +7 -1
  57. package/dist/src/index.js.map +1 -1
  58. package/dist/src/inference-bounds.d.ts +37 -0
  59. package/dist/src/inference-bounds.d.ts.map +1 -0
  60. package/dist/src/inference-bounds.js +84 -0
  61. package/dist/src/inference-bounds.js.map +1 -0
  62. package/dist/src/line-reader.d.ts +7 -1
  63. package/dist/src/line-reader.d.ts.map +1 -1
  64. package/dist/src/line-reader.js +17 -6
  65. package/dist/src/line-reader.js.map +1 -1
  66. package/dist/src/mcpl/channel-registry.d.ts +84 -9
  67. package/dist/src/mcpl/channel-registry.d.ts.map +1 -1
  68. package/dist/src/mcpl/channel-registry.js +136 -58
  69. package/dist/src/mcpl/channel-registry.js.map +1 -1
  70. package/dist/src/mcpl/errors.d.ts +1 -0
  71. package/dist/src/mcpl/errors.d.ts.map +1 -1
  72. package/dist/src/mcpl/errors.js +3 -0
  73. package/dist/src/mcpl/errors.js.map +1 -1
  74. package/dist/src/mcpl/inbound-source.d.ts +2 -2
  75. package/dist/src/mcpl/inbound-source.js +2 -2
  76. package/dist/src/mcpl/inference-router.d.ts +11 -1
  77. package/dist/src/mcpl/inference-router.d.ts.map +1 -1
  78. package/dist/src/mcpl/inference-router.js +65 -9
  79. package/dist/src/mcpl/inference-router.js.map +1 -1
  80. package/dist/src/mcpl/modern-connection.d.ts +10 -7
  81. package/dist/src/mcpl/modern-connection.d.ts.map +1 -1
  82. package/dist/src/mcpl/modern-connection.js +85 -74
  83. package/dist/src/mcpl/modern-connection.js.map +1 -1
  84. package/dist/src/mcpl/protocol-family.d.ts +1 -1
  85. package/dist/src/mcpl/protocol-family.d.ts.map +1 -1
  86. package/dist/src/mcpl/protocol-family.js +45 -3
  87. package/dist/src/mcpl/protocol-family.js.map +1 -1
  88. package/dist/src/mcpl/push-coalescer.d.ts +11 -7
  89. package/dist/src/mcpl/push-coalescer.d.ts.map +1 -1
  90. package/dist/src/mcpl/push-coalescer.js +21 -0
  91. package/dist/src/mcpl/push-coalescer.js.map +1 -1
  92. package/dist/src/mcpl/references.d.ts +1 -2
  93. package/dist/src/mcpl/references.d.ts.map +1 -1
  94. package/dist/src/mcpl/references.js +3 -3
  95. package/dist/src/mcpl/references.js.map +1 -1
  96. package/dist/src/mcpl/server-connection.d.ts +14 -0
  97. package/dist/src/mcpl/server-connection.d.ts.map +1 -1
  98. package/dist/src/mcpl/server-connection.js +26 -22
  99. package/dist/src/mcpl/server-connection.js.map +1 -1
  100. package/dist/src/mcpl/tool-signature.d.ts +1 -0
  101. package/dist/src/mcpl/tool-signature.d.ts.map +1 -1
  102. package/dist/src/mcpl/tool-signature.js +16 -11
  103. package/dist/src/mcpl/tool-signature.js.map +1 -1
  104. package/dist/src/mcpl/toolsets-module.d.ts.map +1 -1
  105. package/dist/src/mcpl/toolsets-module.js +7 -0
  106. package/dist/src/mcpl/toolsets-module.js.map +1 -1
  107. package/dist/src/mcpl/transport.d.ts +44 -21
  108. package/dist/src/mcpl/transport.d.ts.map +1 -1
  109. package/dist/src/mcpl/transport.js +283 -64
  110. package/dist/src/mcpl/transport.js.map +1 -1
  111. package/dist/src/mcpl/types.d.ts +17 -1
  112. package/dist/src/mcpl/types.d.ts.map +1 -1
  113. package/dist/src/mcpl/types.js.map +1 -1
  114. package/dist/src/module-registry.d.ts +32 -4
  115. package/dist/src/module-registry.d.ts.map +1 -1
  116. package/dist/src/module-registry.js +189 -25
  117. package/dist/src/module-registry.js.map +1 -1
  118. package/dist/src/modules/discord/discord-js-client.d.ts.map +1 -1
  119. package/dist/src/modules/discord/discord-js-client.js +24 -16
  120. package/dist/src/modules/discord/discord-js-client.js.map +1 -1
  121. package/dist/src/modules/sender-name.d.ts +5 -4
  122. package/dist/src/modules/sender-name.d.ts.map +1 -1
  123. package/dist/src/modules/sender-name.js +7 -5
  124. package/dist/src/modules/sender-name.js.map +1 -1
  125. package/dist/src/modules/workspace/disk-agreement.d.ts +16 -8
  126. package/dist/src/modules/workspace/disk-agreement.d.ts.map +1 -1
  127. package/dist/src/modules/workspace/disk-agreement.js +33 -12
  128. package/dist/src/modules/workspace/disk-agreement.js.map +1 -1
  129. package/dist/src/modules/workspace/index.d.ts +6 -3
  130. package/dist/src/modules/workspace/index.d.ts.map +1 -1
  131. package/dist/src/modules/workspace/index.js +61 -15
  132. package/dist/src/modules/workspace/index.js.map +1 -1
  133. package/dist/src/modules/workspace/observe.d.ts +9 -1
  134. package/dist/src/modules/workspace/observe.d.ts.map +1 -1
  135. package/dist/src/modules/workspace/observe.js +50 -10
  136. package/dist/src/modules/workspace/observe.js.map +1 -1
  137. package/dist/src/modules/workspace/reconcile.d.ts +11 -1
  138. package/dist/src/modules/workspace/reconcile.d.ts.map +1 -1
  139. package/dist/src/modules/workspace/reconcile.js +19 -8
  140. package/dist/src/modules/workspace/reconcile.js.map +1 -1
  141. package/dist/src/modules/workspace/types.d.ts +8 -0
  142. package/dist/src/modules/workspace/types.d.ts.map +1 -1
  143. package/dist/src/modules/workspace/types.js.map +1 -1
  144. package/dist/src/modules/workspace/watcher.d.ts +7 -0
  145. package/dist/src/modules/workspace/watcher.d.ts.map +1 -1
  146. package/dist/src/modules/workspace/watcher.js +7 -5
  147. package/dist/src/modules/workspace/watcher.js.map +1 -1
  148. package/dist/src/notice-tags.d.ts +2 -0
  149. package/dist/src/notice-tags.d.ts.map +1 -1
  150. package/dist/src/notice-tags.js +2 -0
  151. package/dist/src/notice-tags.js.map +1 -1
  152. package/dist/src/recovery/discord-awareness-outbox.d.ts.map +1 -1
  153. package/dist/src/recovery/discord-awareness-outbox.js +1 -9
  154. package/dist/src/recovery/discord-awareness-outbox.js.map +1 -1
  155. package/dist/src/silent-heartbeat.d.ts +4 -2
  156. package/dist/src/silent-heartbeat.d.ts.map +1 -1
  157. package/dist/src/silent-heartbeat.js +7 -4
  158. package/dist/src/silent-heartbeat.js.map +1 -1
  159. package/dist/src/stored-injections.d.ts +4 -0
  160. package/dist/src/stored-injections.d.ts.map +1 -1
  161. package/dist/src/stored-injections.js +6 -0
  162. package/dist/src/stored-injections.js.map +1 -1
  163. package/dist/src/supplied-text.d.ts +2 -0
  164. package/dist/src/supplied-text.d.ts.map +1 -1
  165. package/dist/src/supplied-text.js +16 -7
  166. package/dist/src/supplied-text.js.map +1 -1
  167. package/dist/src/tool-result-guard.js +1 -1
  168. package/dist/src/tool-result-guard.js.map +1 -1
  169. package/dist/src/tune-out/coordinator.d.ts +368 -16
  170. package/dist/src/tune-out/coordinator.d.ts.map +1 -1
  171. package/dist/src/tune-out/coordinator.js +1224 -136
  172. package/dist/src/tune-out/coordinator.js.map +1 -1
  173. package/dist/src/tune-out/tools.d.ts +115 -7
  174. package/dist/src/tune-out/tools.d.ts.map +1 -1
  175. package/dist/src/tune-out/tools.js +55 -18
  176. package/dist/src/tune-out/tools.js.map +1 -1
  177. package/dist/src/types/agent.d.ts +27 -1
  178. package/dist/src/types/agent.d.ts.map +1 -1
  179. package/dist/src/types/framework.d.ts +153 -15
  180. package/dist/src/types/framework.d.ts.map +1 -1
  181. package/dist/src/types/module.d.ts +42 -3
  182. package/dist/src/types/module.d.ts.map +1 -1
  183. package/dist/src/types/trace.d.ts +140 -3
  184. package/dist/src/types/trace.d.ts.map +1 -1
  185. package/package.json +4 -4
  186. package/src/admission/admit.ts +113 -0
  187. package/src/agent.ts +138 -31
  188. package/src/api/mcp-server-core.ts +10 -3
  189. package/src/author-presentation.ts +81 -0
  190. package/src/code-execution/isolate/render.ts +7 -6
  191. package/src/code-execution/isolate/scripts.ts +5 -4
  192. package/src/dendrite/index.ts +32 -0
  193. package/src/dendrite/presets.ts +149 -0
  194. package/src/dendrite/registry.ts +808 -0
  195. package/src/dendrite/types.ts +397 -0
  196. package/src/framework.ts +4344 -1052
  197. package/src/gate/event-gate.ts +251 -150
  198. package/src/gate/recipe-reconcile.ts +7 -5
  199. package/src/host-presentation.ts +14 -10
  200. package/src/index.ts +16 -2
  201. package/src/inference-bounds.ts +111 -0
  202. package/src/line-reader.ts +22 -5
  203. package/src/mcpl/channel-registry.ts +170 -60
  204. package/src/mcpl/errors.ts +4 -0
  205. package/src/mcpl/inbound-source.ts +2 -2
  206. package/src/mcpl/inference-router.ts +67 -10
  207. package/src/mcpl/modern-connection.ts +83 -68
  208. package/src/mcpl/protocol-family.ts +37 -4
  209. package/src/mcpl/push-coalescer.ts +21 -7
  210. package/src/mcpl/references.ts +3 -4
  211. package/src/mcpl/server-connection.ts +30 -21
  212. package/src/mcpl/tool-signature.ts +18 -11
  213. package/src/mcpl/toolsets-module.ts +7 -0
  214. package/src/mcpl/transport.ts +261 -60
  215. package/src/mcpl/types.ts +18 -1
  216. package/src/module-registry.ts +178 -25
  217. package/src/modules/discord/discord-js-client.ts +33 -29
  218. package/src/modules/sender-name.ts +8 -5
  219. package/src/modules/workspace/disk-agreement.ts +39 -15
  220. package/src/modules/workspace/index.ts +65 -14
  221. package/src/modules/workspace/observe.ts +51 -10
  222. package/src/modules/workspace/reconcile.ts +22 -8
  223. package/src/modules/workspace/types.ts +5 -0
  224. package/src/modules/workspace/watcher.ts +8 -6
  225. package/src/notice-tags.ts +2 -0
  226. package/src/recovery/discord-awareness-outbox.ts +1 -11
  227. package/src/silent-heartbeat.ts +7 -4
  228. package/src/stored-injections.ts +7 -0
  229. package/src/supplied-text.ts +17 -6
  230. package/src/tool-result-guard.ts +1 -1
  231. package/src/tune-out/coordinator.ts +1374 -141
  232. package/src/tune-out/tools.ts +166 -13
  233. package/src/types/agent.ts +30 -1
  234. package/src/types/framework.ts +157 -15
  235. package/src/types/module.ts +42 -3
  236. package/src/types/trace.ts +154 -3
@@ -1,14 +1,15 @@
1
1
  import { type PresentationSnapshot } from "./tool-presentation.js";
2
2
  import { JsStore } from '@animalabs/chronicle';
3
- import type { Membrane, NormalizedRequest } from '@animalabs/membrane';
3
+ import type { Membrane, ContentBlock, NormalizedRequest } from '@animalabs/membrane';
4
4
  import { type RetrySettings } from '@animalabs/membrane/retry';
5
5
  import { ContextManager } from '@animalabs/context-manager';
6
- import type { TokenBudget } from '@animalabs/context-manager';
6
+ import type { MessageMetadata, TokenBudget } from '@animalabs/context-manager';
7
7
  import type { FrameworkConfig, ErrorPolicy, ErrorAction, TraceEventListener, InferenceLogQuery, InferenceLogQueryResult, InferenceLogEntryWithId, ProcessLogQuery, ProcessLogQueryResult, ProcessLogEntryWithId, ProcessEvent, ToolCall, ToolResult, AgentConfig, InferenceRequest, Module, ContextMaintenanceSnapshot, AgentRuntimeSettingsPatch, AgentRuntimeSettingsSnapshot, SameRoundThinkTextPolicy } from './types/index.js';
8
8
  import { Agent, type RenderStats } from './agent.js';
9
9
  import { type ToolClass, type ToolClassSource } from './mcpl/tool-classes.js';
10
10
  import { ChannelRegistry } from './mcpl/channel-registry.js';
11
11
  import { ConversationRouter } from './mcpl/conversation-router.js';
12
+ import type { ActivationRecord, AgentEndReason, AgentRecord, AgentSpec, EndOutcome, HeldMail, PolicyEpoch } from './dendrite/index.js';
12
13
  /**
13
14
  * The framework's own tools that belong to the host's built-in toolset
14
15
  * ("settings", host-presentation.ts) rather than the tool list: the ones an
@@ -17,6 +18,7 @@ import { ConversationRouter } from './mcpl/conversation-router.js';
17
18
  */
18
19
  export declare const BUILTIN_TOOLSET_TOOLS: ReadonlySet<string>;
19
20
  import type { SessionUsageSnapshot } from './usage/types.js';
21
+ import type { ContextStrategy } from '@animalabs/context-manager';
20
22
  import { type DiscordAwarenessView, type DiscordAwarenessCancelReceipt, type DiscordAwarenessMarks, type DiscordAwarenessRetractReceipt } from './recovery/discord-awareness-outbox.js';
21
23
  import { type SurgeryMarkerReceipt, type SurgeryMarksPreview, type OperatorLogEntry, type OperatorLogInput, type OperatorRequester } from './operator-log.js';
22
24
  /**
@@ -91,15 +93,16 @@ export interface HostModeStatus {
91
93
  activeTurnAgents: string[];
92
94
  /** Wakes that own provider admission while waiting for an in-flight
93
95
  * auxiliary call — no turn token yet, but a turn is one settle away. The
94
- * admission continuation rechecks quiesce and requeues them; `drained`
95
- * is false until it has. A parked continuation of a turn is counted here
96
- * and, as a turn alive, in `activeTurns` and `activeTurnAgents`. */
96
+ * admission continuation rechecks quiesce and provider holds, and requeues
97
+ * a wake either keeps from starting; `drained` is false until it has. A
98
+ * parked continuation of a turn is counted here and, as a turn alive, in
99
+ * `activeTurns` and `activeTurnAgents`. */
97
100
  parkedAdmissions: number;
98
101
  /** Inference requests waiting to start: queued (parked by the quiesce wake
99
102
  * gate while quiesced, or, while serving, until the scheduler's next pass
100
103
  * takes them), in a scheduler pass's hands, or held by a provider hold (an
101
104
  * acceleration or host hold, or a provider's stated wait). There, a start
102
- * that carries a turn on counts as the wakes merged into it. A start parked
105
+ * merged from several requests counts as those it took in. A start parked
103
106
  * on provider admission behind an auxiliary call counts once in
104
107
  * `parkedAdmissions` instead, however many wakes are merged into it.
105
108
  * Continuations of a turn (budget restart, tool results) and a held turn's
@@ -191,9 +194,15 @@ interface InferenceToolSnapshot {
191
194
  * schedule, jittered, 10 s doubling to 5 min (by default 13 tries, where
192
195
  * membrane's settings have 7: about 30 min).
193
196
  * - rate limited (429): the base schedule with at least 5 tries.
194
- * - any other retryable failure, a stream deadline on a sent request
195
- * included (membrane leaves those to its caller): the base schedule (by
196
- * default 3 tries, 1 s then 2 s).
197
+ * - a deadline expiry, which membrane leaves to its caller: a progress
198
+ * bound's cut (FrameworkConfig.inferenceBounds), the adapter's own
199
+ * watchdogs, the SDK's request timeout or a runtime's fetch timeout. The
200
+ * deadline schedule: by default 2 tries, 1 s apart, so one fresh call. For
201
+ * one, the framework's `attempt` counts that call's consecutive expiries,
202
+ * not the turn's other failures, so each call a deadline cuts gets its
203
+ * fresh call. Settings with no deadline schedule give it their base one.
204
+ * - any other retryable failure: the base schedule (by default 3 tries, 1 s
205
+ * then 2 s).
197
206
  * A provider's stated wait (`retryAfterMs`) is waited when it is longer than
198
207
  * the backoff, up to the schedule's ceiling, which by default is at least the
199
208
  * framework's own cap (PROVIDER_ACCELERATION_MAX_COOLDOWN_MS, ten minutes);
@@ -211,6 +220,92 @@ export declare class DefaultErrorPolicy implements ErrorPolicy {
211
220
  constructor(settings?: RetrySettings);
212
221
  onInferenceError(error: Error, _agentName: string, attempt: number): ErrorAction;
213
222
  }
223
+ /**
224
+ * For tests only: `framework`'s abandon takes `ms` as its grace in place of
225
+ * {@link ABANDON_GRACE_MS}. Set it only where the test holds every turn the
226
+ * abandon reaches past the grace, so no turn can end within it and a short
227
+ * grace only brings the abandon's report sooner.
228
+ */
229
+ export declare function setAbandonGraceForTests(framework: AgentFramework, ms: number): void;
230
+ /**
231
+ * The admission record on a stored message: it was held from the residents
232
+ * by a policy epoch (`metadata.tuneOut = { epochId }`). ONE predicate for
233
+ * "held from the resident", read by the compiled-view filter and by the
234
+ * mid-turn injection alike (#232 H1), so the window and the wire agree.
235
+ */
236
+ export declare const heldFromResidents: (metadata: Record<string, unknown> | undefined) => boolean;
237
+ /** Options for {@link AgentFramework.deriveAgent}. */
238
+ export interface DeriveAgentOptions {
239
+ /** The new agent's name. Single-use within this framework's lifetime. */
240
+ name: string;
241
+ /** The live agent whose context and configuration are inherited. */
242
+ from: string;
243
+ /** How context is inherited. Default `'shared'`. */
244
+ mode?: 'shared' | 'copy';
245
+ /** `'shared'` only. Default `'reuse'`. */
246
+ solve?: 'reuse' | 'fresh';
247
+ /**
248
+ * `'shared'` only. Also inherit the parent's refusal ledger (what it
249
+ * declined to compress). Default false; set for a fork that stands in
250
+ * for the parent's attention. Recorded as `inherit.refusals`.
251
+ */
252
+ inheritRefusals?: boolean;
253
+ /**
254
+ * A fresh strategy instance for the child. Strategy instances hold state
255
+ * and are never shared; to reuse the parent's rendering it must be the
256
+ * same class with compatible configuration. Default: passthrough.
257
+ */
258
+ strategy?: ContextStrategy;
259
+ /** Identity and settings overrides. Everything not named is the parent's. */
260
+ config?: Partial<Omit<AgentConfig, 'name' | 'strategy'>>;
261
+ /**
262
+ * The parent's tool round in flight, if any. While a tool call runs, the
263
+ * assistant turn that made it is not in the parent's store yet. By
264
+ * default the child's branch gets that turn verbatim (as its own, like
265
+ * the rest of the inheritance) followed by a tool-result message: results
266
+ * the parent has already received as they are; the call that derived the
267
+ * child with `madeBy.result`, or a note saying it did; and any other call
268
+ * still running with a note that its result was not available. So a fork
269
+ * sees the call that made it and never meets a dangling `tool_use`.
270
+ * `madeBy` defaults to the only open call when there is exactly one.
271
+ * `include: false` leaves the round out, and the child starts from the
272
+ * last stored message before it.
273
+ */
274
+ pendingRound?: {
275
+ include?: boolean;
276
+ madeBy?: {
277
+ toolUseId: string;
278
+ result: string;
279
+ };
280
+ /** Results, from the child's side, for other calls still open, by tool-use id. */
281
+ results?: Record<string, string>;
282
+ };
283
+ /** Ordinary messages appended to the child before it runs. */
284
+ framing?: Array<{
285
+ participant: string;
286
+ content: ContentBlock[];
287
+ metadata?: MessageMetadata;
288
+ }>;
289
+ /** Who spawned it. Default: `from`. */
290
+ spawnedBy?: string;
291
+ /** Where its completion returns. */
292
+ resultTo?: import('./dendrite/index.js').ResultRoute;
293
+ /** What happens to it when its spawner ends. Default `'orphan'`. */
294
+ onParentEnd?: import('./dendrite/index.js').ParentEndPolicy;
295
+ deadlineMs?: number;
296
+ idleTimeoutMs?: number;
297
+ maxTurns?: number;
298
+ /** Preset label for discovery. Default `'task-fork'`. */
299
+ kind?: string;
300
+ metadata?: Record<string, unknown>;
301
+ }
302
+ /** Rejection delivered to the caller awaiting a bounded run that was ended from outside. */
303
+ export declare class AgentStoppedError extends Error {
304
+ readonly agentName: string;
305
+ readonly reason: AgentEndReason;
306
+ readonly by?: string | undefined;
307
+ constructor(agentName: string, reason: AgentEndReason, by?: string | undefined, detail?: string);
308
+ }
214
309
  export interface ReinitAlertText {
215
310
  opening: string;
216
311
  message: string;
@@ -333,9 +428,9 @@ export declare class AgentFramework {
333
428
  private store;
334
429
  private ownsStore;
335
430
  private stopPromise;
336
- private stopCompleted;
431
+ private stopState;
432
+ private closedStopFailure;
337
433
  private ownedStoreClosed;
338
- private ownedStoreManagersClosed;
339
434
  /** Whether the latest stop() got through its teardown with nothing failed:
340
435
  * every step and every wait up to and including the one on awareness
341
436
  * drains, whatever failed after that, in the storage work that finishes
@@ -351,8 +446,8 @@ export declare class AgentFramework {
351
446
  * promise: a stream it cancelled or an event loop still in a call; and a
352
447
  * stream whose cancel threw, which stop() doesn't wait for. A later
353
448
  * stop() waits for each again, beside what it finds, whatever has happened
354
- * since to the entry it was found under (a run's end removes its stream's,
355
- * a start() replaces the loop), so neither a budget nor a cancel that
449
+ * since to the entry it was found under (a run's end removes its stream's),
450
+ * so neither a budget nor a cancel that
356
451
  * threw lets the store close under work still running. Each leaves once it
357
452
  * settles. */
358
453
  private readonly leftRunning;
@@ -389,6 +484,13 @@ export declare class AgentFramework {
389
484
  private quiesceReason?;
390
485
  private quiescedAt?;
391
486
  private traceListeners;
487
+ /** Traces emitted before start() — registry restore, interrupted work,
488
+ * resumed epochs — replayed to listeners that attach afterwards, since a
489
+ * host attaches its sinks after create() returns. Dropped at start().
490
+ * It keeps the first 1,000, the start of the stream, and counts the rest
491
+ * (earlyTracesDropped), which a replay ends by naming. */
492
+ private earlyTraces;
493
+ private earlyTracesDropped;
392
494
  private syncIntervalMs;
393
495
  private syncTimer;
394
496
  private maintenanceIntervalMs;
@@ -411,6 +513,9 @@ export declare class AgentFramework {
411
513
  private providerAccelerationLastRecovery;
412
514
  private providerAccelerationDefaultCooldownMs;
413
515
  private providerAccelerationJitterMs;
516
+ private inferenceBounds;
517
+ private readonly deadlineCuts;
518
+ private readonly freshCallsCut;
414
519
  private providerHoldHook;
415
520
  /** Provider waits (stated retry-after) per (agent, model), kept across restarts. */
416
521
  private providerWaits;
@@ -418,8 +523,6 @@ export declare class AgentFramework {
418
523
  private retryWaitWakers;
419
524
  private waitingTraceEveryMs;
420
525
  private providerAdmissionClosed;
421
- /** Invalidates framework turns still assembling when stop begins. */
422
- private lifecycleGeneration;
423
526
  /** Last time we reported stale (busy-requeued) inference requests, per agent. */
424
527
  private staleWarnAt;
425
528
  /** Per-agent last inference activity (epoch ms), for /healthz + doctor tooling. */
@@ -442,8 +545,9 @@ export declare class AgentFramework {
442
545
  private midTurnInputSignals;
443
546
  /** Last outbound locus announced to each agent as a durable `[routing]`
444
547
  * window message. Announce-on-change only: steady state emits nothing
445
- * (KV-safe, no per-turn chatter). In-memory — after a process restart the
446
- * first turn's locus is announced once to re-establish the baseline. */
548
+ * (KV-safe, no per-turn chatter). Kept in the store as well
549
+ * (rememberAnnouncedLocus), so a restart compares with what the agent was
550
+ * last told rather than with nothing. */
447
551
  private lastAnnouncedLocus;
448
552
  /** Every resident's held drafts: plain speech that was suppressed, bounced
449
553
  * or left without a destination, never published except by their
@@ -527,6 +631,13 @@ export declare class AgentFramework {
527
631
  private usedEphemeralAgentNames;
528
632
  /** One-shot generation tickets minted by createEphemeralAgent. */
529
633
  private ephemeralCandidates;
634
+ /**
635
+ * Derived agent → the agent whose tool presentation it shows. A derived
636
+ * agent that inherits its parent's tools must advertise the identical
637
+ * tool block (it is the front of the shared request prefix), including
638
+ * the parent's resident-edited visibility and descriptions.
639
+ */
640
+ private toolSurfaceOwners;
530
641
  /** Every agent createEphemeralAgent made, for as long as the object lives:
531
642
  * its usage counts in the usage record's one shared ephemeral entry. Kept
532
643
  * by the object, not the run's record (ephemeralRuns), which its cleanup
@@ -543,6 +654,7 @@ export declare class AgentFramework {
543
654
  private turnRearmMs;
544
655
  private turnRearms;
545
656
  private exhaustingRearms;
657
+ private rearmDeadlineCuts;
546
658
  private statedWaitRuns;
547
659
  /** N consecutive failed inferences ⇒ the agent is treated as hard-down and
548
660
  * escalated loudly to stderr. */
@@ -595,8 +707,25 @@ export declare class AgentFramework {
595
707
  private subconsciousStrategy;
596
708
  /** Its config (speak_in_channel gate, voice block provenance). */
597
709
  private subconsciousConfig;
598
- /** Tune-out coordinator (issue #77); non-null iff subconscious + channels. */
710
+ /** Tune-out coordinator (issue #77); non-null iff a reader is configured + channels. */
599
711
  private tuneOutCoordinator;
712
+ /** Residents are offered `tune_out` (a reader is configured, or `tuneOut.enabled`). */
713
+ private tuneOutOffered;
714
+ /**
715
+ * The reply anchor a coalesced delivery would set, parked until the
716
+ * acceptance is acknowledged to the server (handleCoalescedIncoming): an
717
+ * acceptance whose commit fails after its delivery moves no anchor, and the
718
+ * retry the receipt answers, which delivers nothing again, commits the one
719
+ * its first attempt parked. Keyed by server and event id; bounded.
720
+ */
721
+ private parkedAnchors;
722
+ /** `tuneOut.announce`: the excepted channel hears the all-except scope open and close. */
723
+ private tuneOutAnnounce;
724
+ /** `speech.locus`: where prose goes when nothing names a destination (see FrameworkConfig). */
725
+ private speechLocus;
726
+ /** `subconscious.reader: 'forks'`: the reader is a succession of forks (Dendrite). */
727
+ private readerForks;
728
+ private readerForkCounter;
600
729
  /** Agents an abandon could not cancel (token held, no stream) — surfaced
601
730
  * in HostModeStatus until the next quiesce/resume. */
602
731
  private lastUnabandonable;
@@ -614,6 +743,24 @@ export declare class AgentFramework {
614
743
  /** True once the cap has been met in the current run, so its line is
615
744
  * logged once a run, whatever began the run. */
616
745
  private deferredWritesCapLogged;
746
+ /** The agent registry and its ended log, as recovery files beside the store
747
+ * (nissa's #546 finding 3): Chronicle state follows the store's branch, and
748
+ * an undo or an operator's surgery must not erase a result held for
749
+ * delivery or the record of work that ran. The file wins where it exists;
750
+ * the branch-local state is read only for stores that predate it. */
751
+ private agentRegistryPath;
752
+ private agentRegistryEndedPath;
753
+ /** The ended log as the recovery file keeps it: the newest records, bounded. */
754
+ private endedRecovery;
755
+ /** The branch-local ended log by name (its newest entry for each), and how far it is indexed (findEndedAgentRecord). */
756
+ private readonly endedLogIndex;
757
+ /** The ended log's entries by the namespace their context holds (the latest for each). */
758
+ private readonly endedLogNamespaceIndex;
759
+ /** Namespaces this process opened for an ephemeral agent's context, by owner: candidates not yet registered included. */
760
+ private readonly namespaceOwners;
761
+ private endedLogIndexed;
762
+ /** The last indexed entry's mark, so a log that changed under the index is seen. */
763
+ private endedLogTail;
617
764
  /** Branch-independent recovery files (see FrameworkConfig.hostModePath /
618
765
  * deferredWritesPath). Undefined → branch-local slot fallback. */
619
766
  private hostModePath;
@@ -743,12 +890,27 @@ export declare class AgentFramework {
743
890
  private coalescingSnapshotDirty;
744
891
  private coalescingRecentReceipts;
745
892
  /**
746
- * Agents that read the residents' shared un-namespaced message slot: every
747
- * ordinary resident (their context managers are not isolated) and the
748
- * subconscious (isolated, but merging that slot read-only). A message in
749
- * that slot is unread only if NONE of them has compiled past it. Forks and
750
- * ephemeral agents have isolated slots and are their own only readers.
751
- */
893
+ * Dendrite agent registry — every agent this framework runs, with its
894
+ * roles, lifetime and relationships. `agents` stays the map of live Agent
895
+ * OBJECTS (the generation identity streams are checked against); the
896
+ * registry is what says what each of them is for. Selection sites read
897
+ * roles from here instead of excluding kinds by hand.
898
+ */
899
+ private readonly registry;
900
+ /** Tell the first adoption candidate when task work is orphaned (config.dendrite.announceOrphans). */
901
+ private announceOrphans;
902
+ /**
903
+ * After this many derivations of one kind from one agent, that agent hears
904
+ * a count line every so many instead of a line per fork
905
+ * (config.dendrite.collapseDerivationNoticesAfter; 0 = never collapse).
906
+ */
907
+ private collapseDerivationNoticesAfter;
908
+ /** The host's say over each derivation, ephemeral spawn and resume (config.dendrite.beforeDerive). */
909
+ private beforeDerive?;
910
+ /** What a source is told of a derivation (config.dendrite.derivationNotice); absent, the default line. */
911
+ private derivationNoticeHook?;
912
+ /** Per source agent, per kind: how many derivations, since when, and at which count the last note went. */
913
+ private derivationTallies;
752
914
  private readonly sharedSlotAgents;
753
915
  /** The batched-wake lines already written (placeWakeLines), so every agent a
754
916
  * wake was for, and every later start of it, writes each at most once. */
@@ -757,6 +919,7 @@ export declare class AgentFramework {
757
919
  * in the round counted by their share of the bound: such a round is
758
920
  * stored by its share whether or not it fits (buildStoredToolResultContent). */
759
921
  private readonly toolRoundsByShare;
922
+ /** Group commit: one fsync per event-loop turn, shared by every waiter. */
760
923
  /** The windows of forks and runs deregistered while the host was quiesced,
761
924
  * by agent name (releaseWindowNowOrAfterResume); resume() releases them
762
925
  * (runReleasesAfterResume), or stop() passes on what they left, unread or
@@ -765,6 +928,7 @@ export declare class AgentFramework {
765
928
  private readonly releasesAfterResume;
766
929
  private readonly managerReleases;
767
930
  private readonly releasedByCleanup;
931
+ private readonly resumesPending;
768
932
  private readonly openManagers;
769
933
  private readonly openManagerRefs;
770
934
  private readonly storeSees;
@@ -778,19 +942,13 @@ export declare class AgentFramework {
778
942
  private conversationRouter;
779
943
  /** Agent configs by name — fork agents are built from the template's config. */
780
944
  private agentConfigs;
781
- /**
782
- * Fork agent → its home channel. Permanent (unlike router bindings, which
783
- * expire): publish/injection scoping must survive unbinding so the closure
784
- * turn still lands in the right channel.
785
- */
786
- private conversationAgentHomes;
787
945
  /** Forks being spawned, by channel id, each until its spawn settles (see
788
946
  * routeConversation). The promise never rejects. */
789
947
  private readonly conversationSpawns;
790
948
  /** Last idle-TTL sweep timestamp. */
791
949
  private lastConversationSweep;
792
950
  /** Forks whose TTL closure turn has been queued — disposed (removed from
793
- * agents/agentConfigs/conversationAgentHomes) when their stream ends. */
951
+ * agents/agentConfigs and ended in the registry) when their stream ends. */
794
952
  private closingConversationAgents;
795
953
  private codeExecution;
796
954
  private scriptToolWaiters;
@@ -977,9 +1135,7 @@ export declare class AgentFramework {
977
1135
  * maintenance, event loop and operator operations, so a dump shows what
978
1136
  * those waits are on, and before its modules and MCPL servers stop, so a
979
1137
  * stop() whose teardown hangs, fails or times out doesn't keep it listed.
980
- * With none in the set, one line says no framework is running. A framework
981
- * started again after a completed stop() doesn't rejoin; whether that
982
- * lifecycle is supported is #315.
1138
+ * With none in the set, one line says no framework is running.
983
1139
  *
984
1140
  * One listener serves the process, installed by the first create() to
985
1141
  * reach the join and kept: once a process's last SIGUSR2 listener is
@@ -992,18 +1148,35 @@ export declare class AgentFramework {
992
1148
  private printDiagnostics;
993
1149
  /**
994
1150
  * Start the event loop. A start() on a running framework does nothing.
995
- * Refused, with an error, from a stop() call until that stop() settles,
996
- * since that stop would wait on the lifecycle a start() begins, or tear it
997
- * down under it. What a start() after a settled stop() should do is #315's
998
- * question.
1151
+ * A stop ends its instance (#315): once a stop() is admitted, start() and
1152
+ * addModule() are refused with an error, for good. While that stop() runs,
1153
+ * the error says the framework is stopping. Once it has settled, the error
1154
+ * says what to do: create a new AgentFramework on the store, and after a
1155
+ * failed stop(), call stop() again first, until one resolves. When a
1156
+ * failed stop() left its owned store closed, so that it can't be tried
1157
+ * again, the error carries that failure as its cause.
1158
+ *
1159
+ * A new instance on the store keeps what the store holds. With the
1160
+ * heartbeat on and the same heartbeat state file (heartbeat.statePath, or
1161
+ * its default), it keeps the heartbeat's schedule as it reads it from that
1162
+ * file: a tick or a reminder that fell due meanwhile fires once, shortly
1163
+ * after it starts. What an instance holds only in memory is lost with it,
1164
+ * as on a process restart: an agent's sleep and its wake, a self-wake, the
1165
+ * inference requests still queued (a budget restart, a heartbeat's wake, a
1166
+ * nudge), a re-armed turn's wait and count, and the redo stack. #627 is
1167
+ * about keeping a sleep and a self-wake across a restart. To pause and
1168
+ * resume one framework in place, use quiesce() and resume().
999
1169
  */
1000
1170
  start(): void;
1001
1171
  /**
1002
- * Stop the event loop. Until it settles, start() and addModule() are
1003
- * refused. Each step of the teardown runs whatever an earlier one did: one
1004
- * that throws, such as a host stream's cancel(), fails the stop() once the
1005
- * rest has run. When a step or a wait up to and including
1006
- * the wait on awareness drains fails or times out, storage stays open and
1172
+ * Stop the event loop, and with it this framework, for good: once a stop()
1173
+ * is admitted, start() and addModule() are refused, as start() says. A
1174
+ * stop() whose budget is refused, which it rejects with a RangeError, is
1175
+ * not admitted and changes nothing. Each step of the teardown runs
1176
+ * whatever an earlier one did: one that throws, such as a host stream's
1177
+ * cancel(), fails the stop() once the rest has run. When a step or a wait
1178
+ * up to and including the wait on awareness drains fails or times out,
1179
+ * storage stays open and
1007
1180
  * stop() can be called again; one that fails after it, in the storage work
1008
1181
  * that finishes the stop, fails the stop() without keeping storage open.
1009
1182
  * A timed-out wait lets teardown go on while what it waited for may still
@@ -1011,7 +1184,10 @@ export declare class AgentFramework {
1011
1184
  * @param teardownTimeoutMs Optional budget for each of stop()'s waits, in
1012
1185
  * turn: on the streams it cancels, on maintenance in flight (a pass or an
1013
1186
  * over-budget drain kick), on the event loop, on an operator's operations
1014
- * already running, on modules and MCPL together, then on Discord awareness
1187
+ * already running, on modules and MCPL (its servers and the inference
1188
+ * requests they made) together, where a module whose start() is still
1189
+ * running counts until that start() has settled and its stop() returned,
1190
+ * then on Discord awareness
1015
1191
  * drains, which send nothing once stop() has begun, recording the call the
1016
1192
  * close ended. With a budget, a stop() can take up to six of them, besides
1017
1193
  * the withheld-spill deadline of a guard's write still under way. Omit to
@@ -1034,9 +1210,7 @@ export declare class AgentFramework {
1034
1210
  * dropped, though a write the stream already had under way can still
1035
1211
  * land in the run's namespace after them.
1036
1212
  * - an event loop still in a call, such as a module's onProcess, finishes
1037
- * that call and the rest of its iteration, and then exits. A start()
1038
- * made once that stop() has failed runs its own loop beside that last
1039
- * iteration.
1213
+ * that call and the rest of its iteration, and then exits.
1040
1214
  * - a later stop() waits again, within its own budget, for any stream or
1041
1215
  * loop this one left running, so the store never closes under it.
1042
1216
  *
@@ -1049,14 +1223,7 @@ export declare class AgentFramework {
1049
1223
  * entries, and once it has left, its stream's late events are dropped.
1050
1224
  */
1051
1225
  stop(teardownTimeoutMs?: number | undefined): Promise<void>;
1052
- /** What start() and addModule() pass before either begins work of a
1053
- * lifecycle. A stop() still running refuses both, from the moment it
1054
- * claims its attempt until that attempt settles. A failed stop() has
1055
- * cleared its attempt, unless it closed an owned store, or the context
1056
- * managers it closes before that store, which are refused first. A
1057
- * completed stop() is cleared, and the call goes on as before;
1058
- * whether a lifecycle should begin after a stop() is #315's question. */
1059
- private resetCompletedStop;
1226
+ private refuseOnceStopped;
1060
1227
  /** Register before invoking the body, so the set holds the operation for
1061
1228
  * its whole life: its synchronous trace callbacks can reenter stop(), and
1062
1229
  * that stop() must find it. Invocation stays in this stack, preserving
@@ -1155,7 +1322,10 @@ export declare class AgentFramework {
1155
1322
  */
1156
1323
  private heartbeatWakeBefore;
1157
1324
  /** The agents the heartbeat wakes: the residents, not conversation forks,
1158
- * ephemeral runs or the subconscious, which keep windows of their own. */
1325
+ * ephemeral runs or the subconscious, which keep windows of their own.
1326
+ * Read from the registry by role, as an untargeted push's recipients are
1327
+ * (the heartbeat's wakes were heartbeat-mcpl's pushes): the agents whose
1328
+ * spec takes untargeted inbound, in registration order. */
1159
1329
  private heartbeatTargets;
1160
1330
  /**
1161
1331
  * The event a heartbeat wake is to the gate: a push from the server id
@@ -1245,6 +1415,7 @@ export declare class AgentFramework {
1245
1415
  * inference on it. True = extended in place (held requests stay held). */
1246
1416
  private extendHostProviderHold;
1247
1417
  private holdProviderAcceleration;
1418
+ private takeAsTransient;
1248
1419
  private rearmExhaustedTurn;
1249
1420
  /**
1250
1421
  * A provider's stated wait on a turn that doesn't own provider admission:
@@ -1402,10 +1573,13 @@ export declare class AgentFramework {
1402
1573
  * it, or, through the deprecated queue handle, without the trace.
1403
1574
  */
1404
1575
  private pushModuleEvent;
1576
+ private dropRetiredModuleEvent;
1405
1577
  /**
1406
1578
  * Add a trace event listener for observability.
1407
1579
  */
1408
- onTrace(listener: TraceEventListener): () => void;
1580
+ onTrace(listener: TraceEventListener, options?: {
1581
+ replay?: boolean;
1582
+ }): () => void;
1409
1583
  /**
1410
1584
  * Public accessor for the MCPL channel registry.
1411
1585
  * Null when no MCPL servers are configured.
@@ -1420,14 +1594,20 @@ export declare class AgentFramework {
1420
1594
  offTrace(listener: TraceEventListener): void;
1421
1595
  private removeTraceRegistration;
1422
1596
  /**
1423
- * Add a module at runtime. Refused, with a rejection, while a stop() is
1424
- * still running: a module added then would either be stopped by that stop
1425
- * or, once the stop has taken its list of modules to stop, stay started
1426
- * past it.
1597
+ * Add a module at runtime. Refused, with a rejection, once a stop() has
1598
+ * been admitted, before anything else is checked: while that stop() runs,
1599
+ * a module added then would either be stopped by it or, once it has taken
1600
+ * its list of modules to stop, stay started past it; once it has settled,
1601
+ * the framework has stopped for good, as start() says. A stop() admitted
1602
+ * while the module's start() runs stops the module once that start() has
1603
+ * settled; if that start() fulfils, this rejects the same way then, with
1604
+ * no `module:added`, and if it rejects, this rejects with its error.
1427
1605
  */
1428
1606
  addModule(module: Module): Promise<void>;
1429
1607
  /**
1430
- * Remove a module at runtime.
1608
+ * Remove a module at runtime. A module whose start() is still running is
1609
+ * stopped once that start() has settled; this waits for that and for its
1610
+ * stop(), with no time limit.
1431
1611
  */
1432
1612
  removeModule(name: string): Promise<void>;
1433
1613
  /**
@@ -1497,7 +1677,7 @@ export declare class AgentFramework {
1497
1677
  * Get all available tools from all modules and MCPL servers.
1498
1678
  */
1499
1679
  getAllTools(): import('./types/index.js').ToolDefinition[];
1500
- /** The registered workspace module, if any (used by save_image). */
1680
+ /** The registered workspace module, if any (used by save_recent_image). */
1501
1681
  private getWorkspaceModule;
1502
1682
  /** RFC-005 host-mediated reference fetcher (lazy; needs server configs +
1503
1683
  * a read-write workspace mount without an include for storage). */
@@ -1628,15 +1808,11 @@ export declare class AgentFramework {
1628
1808
  private stallSkips;
1629
1809
  /** See WITHHELD_SPILL_DEADLINE_MS; an instance field so tests can shorten it. */
1630
1810
  private withheldSpillDeadlineMs;
1631
- /** The lifecycle generation whose stop() has let the running annotations
1632
- * finish: a withheld original is then no longer written to a workspace
1633
- * that is stopping, and its stub names the audit record. A start() after
1634
- * that stop() has finished has a generation of its own, so the spill gate
1635
- * is open again for an instance kept with a store it doesn't own and that
1636
- * is still open (start() doesn't restore stopped modules or MCPL
1637
- * connections, and refuses an owned store that stop() closed). A start()
1638
- * made while a stop() is still running is refused. */
1639
- private guardSpillsClosedFor;
1811
+ /** Set once a stop() has let the running annotations finish, and cleared
1812
+ * as each stop() begins: while set, a withheld original is no longer
1813
+ * written to a workspace that is stopping, and its stub names the audit
1814
+ * record. */
1815
+ private guardSpillsClosed;
1640
1816
  /** A new agent's guard: its persisted setting, the tool-results spill its
1641
1817
  * withheld originals are written to, and the set stop() waits on
1642
1818
  * (agent-framework #277). The setting is read from framework/state's
@@ -1879,8 +2055,9 @@ export declare class AgentFramework {
1879
2055
  * memory-only: they land within the turn, at a tool boundary or at its
1880
2056
  * end, and a crash before then loses them. That window runs to the turn's
1881
2057
  * end for a message held there and what is queued behind it, and, on a
1882
- * stream that declares it can't carry injected messages (membrane's XML
1883
- * prefill path, from 0.6.0), for every message deferred during the turn.
2058
+ * stream that doesn't declare it carries injected messages (membrane's XML
2059
+ * prefill path declares it can't), for every message deferred during the
2060
+ * turn.
1884
2061
  *
1885
2062
  * A write that fails, or a queue over the cap, which writes nothing,
1886
2063
  * leaves the record as it last held it, except that store only, a write
@@ -2248,11 +2425,336 @@ export declare class AgentFramework {
2248
2425
  * ContextManager, before the store. Until then the ContextManager stays
2249
2426
  * open.
2250
2427
  */
2251
- createEphemeralAgent(config: AgentConfig): Promise<{
2428
+ createEphemeralAgent(config: AgentConfig,
2429
+ /**
2430
+ * How the registry should describe this agent. Omitted: an independent
2431
+ * fresh worker with no spawner and no result route, which is what every
2432
+ * caller of this method got before the registry existed. Supplying a
2433
+ * spec (see the presets in `dendrite/`) declares who spawned it, where
2434
+ * its result goes and what it inherited, so lifecycle rules — orphan
2435
+ * notice, reparenting, held results — apply to it.
2436
+ */
2437
+ spec?: Omit<AgentSpec, 'name'>): Promise<{
2252
2438
  agent: Agent;
2253
2439
  contextManager: ContextManager;
2254
2440
  cleanup: () => void;
2255
2441
  }>;
2442
+ /**
2443
+ * Derive a new agent from a live one: the parent's context at a
2444
+ * checkpoint, a private continuation, and — unless overridden — the
2445
+ * parent's whole configuration (model, thinking, cache TTL, provider
2446
+ * params, prompt, tools). The parent keeps running.
2447
+ *
2448
+ * The returned agent is a bounded job, driven with
2449
+ * `runEphemeralToCompletion` exactly like one from `createEphemeralAgent`.
2450
+ *
2451
+ * **Inheritance.** `mode: 'shared'` (the default) gives the child the
2452
+ * parent's messages and fold state through shared storage: nothing is
2453
+ * copied, the child folds with the parent's memory tree, and neither can
2454
+ * alter what the other reads. It needs a store that supports derivation
2455
+ * (`ContextManager.supportsDerivation`), and is refused, not silently
2456
+ * downgraded, without one. `mode: 'copy'`
2457
+ * is the historical mechanism — the parent's compiled context re-added as
2458
+ * the child's own messages — and works everywhere.
2459
+ *
2460
+ * **Rendering.** With `solve: 'reuse'` (the default) and nothing
2461
+ * overridden, the child's first request is the parent's request plus the
2462
+ * child's framing: the same system prompt and tool block, the parent's
2463
+ * turns presented as the child's own, and a cache marker on the end of
2464
+ * the parent's request so the prefix it wrote is read back. `solve:
2465
+ * 'fresh'` deliberately re-solves, e.g. at another budget; so does any
2466
+ * override that changes what is rendered. Those are operating choices —
2467
+ * the presentation changes and the provider cache misses.
2468
+ *
2469
+ * **Framing** is ordinary messages appended to the child before it runs:
2470
+ * the task, and whatever tells it which stream it is. The parent's turn
2471
+ * in flight is not in its store yet (see `getPendingAssistantRound`), so
2472
+ * a fork made from inside a tool call starts from the message before the
2473
+ * turn that made it.
2474
+ *
2475
+ * Context isolation is not process or filesystem isolation: parent and
2476
+ * child share tools, any shell and the workspace.
2477
+ */
2478
+ deriveAgent(options: DeriveAgentOptions): Promise<{
2479
+ agent: Agent;
2480
+ contextManager: ContextManager;
2481
+ cleanup: () => void;
2482
+ }>;
2483
+ private discardEphemeralCandidate;
2484
+ /**
2485
+ * The default wording for the call that derived a child: who it is, what
2486
+ * kind, and how long — the fields the consent event names, so the fork
2487
+ * never has to infer its own lifetime from context (Linn, 10-09).
2488
+ */
2489
+ private derivedNote;
2490
+ /**
2491
+ * The parent's in-flight tool round, reproduced on the child's branch so
2492
+ * the child sees the call that made it (see `DeriveAgentOptions.pendingRound`).
2493
+ */
2494
+ private framePendingRound;
2495
+ /**
2496
+ * The assistant turn an agent has produced but not yet stored: its tool
2497
+ * calls and any text before them, held until every tool result is in so
2498
+ * the pair lands adjacently. A host deriving an agent from inside one of
2499
+ * those tool calls can reproduce the turn in the child's framing.
2500
+ */
2501
+ getPendingAssistantRound(agentName: string): ContentBlock[] | undefined;
2502
+ /**
2503
+ * Bring an ended bounded job back as a new incarnation of the same
2504
+ * identity, on the context it left: an isolated agent's own namespace, or
2505
+ * a derived agent's own branch. Nothing is re-derived and nothing is
2506
+ * re-seeded — the agent continues from its last stored message, which is
2507
+ * the end of its last complete round (a round whose tool results never
2508
+ * all arrived was never stored).
2509
+ *
2510
+ * Use it for a job that was stopped, failed, or was interrupted by a
2511
+ * restart. Configuration is not persisted with an agent, so the caller
2512
+ * supplies it again; the role mapping a derived agent used is restored
2513
+ * from its record unless the config sets one. Relationships are kept
2514
+ * where the other agent still exists; a job whose spawner or result
2515
+ * recipient is gone resumes without that edge and can be reparented.
2516
+ *
2517
+ * External effects are not replayed and not undone: a tool the previous
2518
+ * incarnation ran before it ended has had its effect, and a call it never
2519
+ * received a result for may be made again by the model. Drive the result
2520
+ * with `runEphemeralToCompletion`.
2521
+ */
2522
+ resumeAgent(name: string, config: Omit<AgentConfig, 'name'>): Promise<{
2523
+ agent: Agent;
2524
+ contextManager: ContextManager;
2525
+ cleanup: () => void;
2526
+ }>;
2527
+ /**
2528
+ * A context to read an agent's history from, without changing the live
2529
+ * system.
2530
+ *
2531
+ * - A live agent: a snapshot derived from its context — at the head, or
2532
+ * at `atSequence` for an earlier state. The snapshot is its own branch;
2533
+ * the agent keeps running and is not affected by anything done to it.
2534
+ * - An ended agent: the context it left, reopened where it lives.
2535
+ *
2536
+ * The returned manager uses a passthrough strategy: it shows what is
2537
+ * stored, raw. An ended agent's context is the real one — treat it as
2538
+ * read-only unless you mean to change what a later resume starts from.
2539
+ */
2540
+ inspectAgentContext(name: string, options?: {
2541
+ atSequence?: number;
2542
+ }): Promise<ContextManager>;
2543
+ /** Open the context an ended agent left, wherever it lives. */
2544
+ private reopenAgentContext;
2545
+ /** Open a derived agent's context on a branch of its own (see deriveAgent). */
2546
+ private deriveSharedContext;
2547
+ /** Flat list of registered agents with their roles, lifetime and relationships. */
2548
+ listAgents(options?: {
2549
+ includeEnded?: boolean;
2550
+ }): AgentRecord[];
2551
+ /** One agent's record: the live one, else its most recent ended one. */
2552
+ getAgentRecord(name: string): AgentRecord | null;
2553
+ /** The agent that owns default delivery, or null before any is declared. */
2554
+ getPrimaryAgentName(): string | null;
2555
+ /**
2556
+ * Activations in flight, each with the agent that owns the work. Derived
2557
+ * from the live turn state, so it cannot disagree with what is running.
2558
+ */
2559
+ listActivations(): ActivationRecord[];
2560
+ /**
2561
+ * Policy epochs currently in force (tune-out holds), read from the
2562
+ * coordinator's own durable state — not mirrored. An epoch is neither an
2563
+ * agent nor a task: ending one leaves both running.
2564
+ */
2565
+ listPolicyEpochs(): PolicyEpoch[];
2566
+ /**
2567
+ * Cancel an agent's activation in flight, leaving the agent registered.
2568
+ * For a bounded job, whose lifetime is that one run, this ends the job.
2569
+ * Returns false when nothing was running.
2570
+ */
2571
+ cancelActivation(name: string, options?: {
2572
+ by?: string;
2573
+ reason?: string;
2574
+ }): boolean;
2575
+ /**
2576
+ * End an agent: cancel its run, remove it from the framework, and settle
2577
+ * what it spawned — attention tenants end with it; task work is orphaned,
2578
+ * notified and offered for reparenting, and keeps running.
2579
+ *
2580
+ * The default-delivery owner cannot be stopped (the framework needs
2581
+ * exactly one); cancel its activation instead. A persistent agent stopped
2582
+ * here is declared by configuration and returns at the next boot.
2583
+ */
2584
+ stopAgent(name: string, options?: {
2585
+ by?: string;
2586
+ reason?: string;
2587
+ }): EndOutcome;
2588
+ /**
2589
+ * Give an agent a new parent. Clears its orphan state; a result route
2590
+ * whose recipient is gone follows the new parent, and the mail it already
2591
+ * produced for the lost recipient, results and messages, is delivered to
2592
+ * the new one.
2593
+ */
2594
+ reparentAgent(name: string, newParent: string, options?: {
2595
+ by?: string;
2596
+ }): AgentRecord;
2597
+ /**
2598
+ * An explicit message from one agent to another: the sender's verbatim
2599
+ * content, in the recipient's context under the SENDER's name, with the
2600
+ * sender's identity and incarnation and the causal chain in metadata.
2601
+ * Never an unmarked insertion into the recipient's own voice.
2602
+ */
2603
+ sendAgentMessage(from: string, to: string, content: ContentBlock[], options?: {
2604
+ causedBy?: string[];
2605
+ wake?: boolean;
2606
+ }): {
2607
+ mailId: string;
2608
+ delivered: boolean;
2609
+ };
2610
+ /**
2611
+ * Return a bounded job's result along the agent's declared result route.
2612
+ * The result is recorded durably before delivery is attempted, so it is
2613
+ * neither lost nor delivered twice across a restart; if the recipient is
2614
+ * gone it is held as attributed mail until the agent is reparented.
2615
+ *
2616
+ * May be called after the agent's run has ended — its record stays
2617
+ * inspectable. Refused for a `tool-result` route: there the awaiting
2618
+ * caller already holds the result and delivers it itself.
2619
+ */
2620
+ deliverAgentResult(from: string, content: ContentBlock[], options?: {
2621
+ causedBy?: string[];
2622
+ }): {
2623
+ mailId: string;
2624
+ delivered: boolean;
2625
+ to: string;
2626
+ };
2627
+ /** Communications not yet handed to their recipient, and why. */
2628
+ listHeldMail(filter?: {
2629
+ to?: string;
2630
+ from?: string;
2631
+ }): HeldMail[];
2632
+ /**
2633
+ * Try to hand one held item to its recipient. True when the message is in
2634
+ * (or queued for) the recipient's context; false when it stays held
2635
+ * because nobody can receive it. The held copy is released by
2636
+ * `addMessage` at the moment the message enters the store.
2637
+ */
2638
+ private attemptMailDelivery;
2639
+ /**
2640
+ * An ended orphan's result held for a recipient that is gone: its first
2641
+ * adoption candidate is told it exists and how it arrives, since nothing
2642
+ * else would surface it (reparentAgent delivers it).
2643
+ */
2644
+ private tellResultHeld;
2645
+ /** A host-framed lifecycle fact in an agent's context. Never voiced as anyone. */
2646
+ private lifecycleNotice;
2647
+ /**
2648
+ * The creation ("consent") event: names what kind of agent this is, what
2649
+ * ends it and what happens to it when its spawner ends. A derived agent's
2650
+ * creation is also told to the agent it was derived from (#270, Linn:
2651
+ * "told when the body changes" as a property, not a courtesy): one
2652
+ * host-framed line in the source's context, built from the same facts as
2653
+ * the trace, with no wake; a host's derivationNotice can replace the line
2654
+ * or send none. Both derivation paths announce after the
2655
+ * fork's branch or copy exists, so a fork never inherits the notice about
2656
+ * itself; a source that has ended is told nothing (lifecycleNotice).
2657
+ */
2658
+ private announceAgentCreated;
2659
+ /** The derivation notice's text, addressed to the agent `from` the record was derived. */
2660
+ private derivationNotice;
2661
+ /** What a derived agent is, to the agent it was derived from: "a task-fork on your weights, …; …; …". */
2662
+ private derivationDescription;
2663
+ /**
2664
+ * Remove an ended agent's live object from the framework. A bounded run
2665
+ * is ended through its awaiting caller (whose teardown owns the
2666
+ * name-keyed state); any other agent is torn down here.
2667
+ */
2668
+ private teardownEndedAgent;
2669
+ private forgetFailureAccounting;
2670
+ /**
2671
+ * Everything the process holds for a live, non-ephemeral agent that has
2672
+ * ended, released once, on every path an agent ends by — stopAgent, the
2673
+ * idle reap of a conversation fork, an end that cascades from a parent's
2674
+ * (nissa's #546 finding 5: a stop that skipped the window release dropped a
2675
+ * write queued for the agent at the next flush, and a failure notice it
2676
+ * never read reached no one). The window release delivers what the agent
2677
+ * never read to the primary, now or after a resume, as the idle reap did.
2678
+ */
2679
+ private releaseAgentRuntime;
2680
+ /**
2681
+ * Carry out what the registry decided when an agent ended: tear down the
2682
+ * attention tenants that end with it, and tell each orphan — and the
2683
+ * first agent that could adopt it — what happened.
2684
+ */
2685
+ private settleEndedAgent;
2686
+ /** An agent whose spawner has ended, and its first adoption candidate, are told; the trace says so. */
2687
+ private announceOrphaned;
2688
+ /** The registry's snapshot: the recovery file first (atomic, fsynced; it
2689
+ * wins at the next boot), then the branch-local state, kept for inspection
2690
+ * and for stores read by older code. Either write failing fails the call
2691
+ * that changed the registry (nissa's #546 finding 2): a change that isn't
2692
+ * durable isn't a success. */
2693
+ private persistAgentRegistry;
2694
+ /** An ended record: appended to the branch-local log, and the recovery
2695
+ * file rewritten with the newest records (as many as a restart reads). */
2696
+ private appendEndedAgentRecord;
2697
+ /**
2698
+ * A requested change was put back in the registry's memory: the recovery
2699
+ * files, each written before the branch-local store, are rewritten from it
2700
+ * (the snapshot's and the ended log's), so neither keeps the change the
2701
+ * caller was told failed. The branch-local snapshot needs no rewrite: it is
2702
+ * the last write a change makes, so a change that failed never reached it.
2703
+ * The branch-local ended log is append-only, so an end appended before the
2704
+ * failure stays there. It is read at boot only where no ended recovery
2705
+ * file exists (or the rewrite of that file failed too); the restore then
2706
+ * drops a bounded agent it lists as ended for the reason recorded, with no
2707
+ * restart notice to its recipient, while a persistent agent waits to be
2708
+ * re-declared as it would anyway. A rewrite that fails is reported, the
2709
+ * next is still made, and the caller's own error goes on.
2710
+ */
2711
+ private rewriteAgentRegistryAfterRollback;
2712
+ /**
2713
+ * An ended record past the registry's memory, from the branch-local ended
2714
+ * log. A scan of the whole log takes tens of milliseconds at a few thousand
2715
+ * ends, and a name nobody used (a tool call's typo) is a miss, so the log is
2716
+ * indexed by name once, at the first lookup, and each later lookup indexes
2717
+ * only what was appended since. A log that changed under the index (a
2718
+ * branch switch) is indexed again: one that shrank, one whose last indexed
2719
+ * entry is no longer the one indexed, or one whose entry no longer carries
2720
+ * the name indexed for it.
2721
+ */
2722
+ private findEndedAgentRecord;
2723
+ /**
2724
+ * The ended log's latest record whose own context a namespace holds. A
2725
+ * shared fork's record names its parent's namespace, where it owns only a
2726
+ * branch, so it is indexed by name alone.
2727
+ */
2728
+ private findInEndedLog;
2729
+ /** Another agent whose context a namespace holds: opened in this process, in the registry, or in the ended log. */
2730
+ private namespaceHolder;
2731
+ /** The ended log's recovery file, rewritten as the newest records (as many as a restart reads). */
2732
+ private rewriteEndedRecovery;
2733
+ /**
2734
+ * Load the previous process's registry. Returns the bounded work it
2735
+ * interrupted. A registry that can't be read, or that reads as anything
2736
+ * but a version-1 registry, refuses the start and names the state (nissa's
2737
+ * #546 finding 1, main's rule for the framework's own state): taken as
2738
+ * empty, the results it holds for delivery and the records of the work it
2739
+ * ran would be overwritten by this boot's first registration.
2740
+ */
2741
+ private restoreAgentRegistry;
2742
+ /**
2743
+ * Boot reconciliation, once configuration has declared its agents.
2744
+ * Restart behaviour follows from lifetime: persistent agents were just
2745
+ * re-created; everything else that was live was interrupted, and the
2746
+ * recipient of an interrupted job's result is told so. Results held from
2747
+ * before the restart are delivered now, exactly once.
2748
+ */
2749
+ private reconcileAgentRegistry;
2750
+ /**
2751
+ * Deliver held mail that hasn't landed. Its copy may have reached the
2752
+ * recipient's store in the same sync that the release missed, and then it
2753
+ * is released instead; and a write the deferred queue still holds for it
2754
+ * lands at the next flush and releases it then (releaseLandedMail). Either
2755
+ * way a second delivery would put it in the window twice under one mail id.
2756
+ */
2757
+ private deliverHeldMail;
2256
2758
  private createDeferred;
2257
2759
  /** Liveness ping for an active ephemeral run (no-op otherwise). */
2258
2760
  private touchEphemeralRun;
@@ -2262,15 +2764,16 @@ export declare class AgentFramework {
2262
2764
  private recordEphemeralToolCalls;
2263
2765
  /**
2264
2766
  * A start dropped before its stream sends anything (its agent was replaced,
2265
- * or stop() closed admission or ended the lifecycle the start began in)
2266
- * ends the logical turn it was running. stop() ends every open turn
2267
- * (openLogical), but a fresh start that awaited its batches' assembly
2268
- * across a stop() reaches its routing after it and opens its turn. That
2269
- * turn would then stay open, and the agent's first start after a restart
2270
- * would continue the dropped turn's routing. The identity check leaves any
2271
- * other turn open.
2767
+ * or stop() closed admission) ends the logical turn it was running. stop()
2768
+ * ends every open turn (openLogical), but a fresh start that awaited its
2769
+ * batches' assembly across a stop() reaches its routing after it and opens
2770
+ * its turn. That turn would then stay open, and the next start of the
2771
+ * agent's name would continue the dropped turn's routing. The identity
2772
+ * check leaves any other turn open.
2272
2773
  */
2273
2774
  private endDroppedTurn;
2775
+ private pinTurnInputs;
2776
+ private releaseTurnInputs;
2274
2777
  /** A logical turn's end, for every agent: it closes the agent's open
2275
2778
  * logical turn when it is the settling stream's own (openLogical), and
2276
2779
  * settles an active ephemeral run. The run's tool-call count comes from
@@ -2310,8 +2813,11 @@ export declare class AgentFramework {
2310
2813
  /** Tune-out (issue #77): divert a channel to your subconscious. Present
2311
2814
  * only when the subconscious resident is configured. */
2312
2815
  private static readonly TUNE_OUT_TOOL;
2816
+ /** `focus`: the resident-facing alias for `tune_out` with scope "all-except" (#232 decision 2). */
2817
+ private static readonly FOCUS_TOOL;
2313
2818
  /** Synthesized sleep/wake tool definitions (present when a gate is wired). */
2314
2819
  private static readonly SLEEP_TOOLS;
2820
+ private static readonly WAKE_ADD_RULE_FIELDS;
2315
2821
  /** Synthesized wake-rule tools: add/remove a gate.json policy at runtime.
2316
2822
  * Present when a gate is wired. They write validated policies into the
2317
2823
  * hot-reloaded gate.json (same validation as load), so a rule takes effect
@@ -2326,14 +2832,14 @@ export declare class AgentFramework {
2326
2832
  /** Synthesized drafts tool — present whenever MCPL channels are
2327
2833
  * configured. A resident's held drafts (src/prose-drafts.ts): plain speech
2328
2834
  * that was not sent, never published except by its resident's resend, and
2329
- * kept as that module's retention says. Nullable
2330
- * fields, cast like save_recent_image's: a caller whose provider presents
2331
- * every property as required can still say "not in use". */
2835
+ * kept as that module's retention says. Its optional fields are nullable,
2836
+ * as save_recent_image's selectors are: a caller whose provider presents
2837
+ * every property as required can still say "not in use" (fieldInUse). */
2332
2838
  private static readonly DRAFTS_TOOL;
2333
- /** Synthesized save_image tool — present when a workspace module is
2839
+ /** Synthesized save_recent_image tool — present when a workspace module is
2334
2840
  * registered. Lets the agent persist an image it has already seen in its
2335
2841
  * own context (Discord attachments arrive inlined as base64 and are
2336
- * otherwise unreachable as files). */
2842
+ * otherwise unreachable as files). Its three selectors are nullable. */
2337
2843
  private static readonly SAVE_IMAGE_TOOL;
2338
2844
  /** Synthesized fetch_reference tool — RFC-005 on-demand dereference.
2339
2845
  * Present when a workspace module is registered (storage target). */
@@ -2870,6 +3376,28 @@ export declare class AgentFramework {
2870
3376
  * into the resident's window, which accumulates there.
2871
3377
  */
2872
3378
  private createSubconsciousAgent;
3379
+ /**
3380
+ * `subconscious.reader: 'forks'`: no persistent agent. The coordinator
3381
+ * asks for a fork per invocation (see invokeReaderFork); the config is
3382
+ * kept for the voice block, the speech switch and the strategy factory.
3383
+ */
3384
+ private configureReaderForks;
3385
+ /**
3386
+ * One reader invocation: derive a fork of the resident at its head with
3387
+ * the resident's refusals, hand it the held traffic since the last look
3388
+ * as ordinary framing, and run it. It reports through `deliver_summary`
3389
+ * (attributed mail), may cancel the hold, and ends when its turn ends.
3390
+ */
3391
+ private invokeReaderFork;
3392
+ /**
3393
+ * Held messages still queued behind the resident's turn, as rows of a
3394
+ * reader fork's backlog: each named by its held handle, as module rows name
3395
+ * it until it lands (heldRows), at a provisional sequence past the
3396
+ * resident's last stored message, and timed when it was first held.
3397
+ */
3398
+ private queuedReaderRows;
3399
+ /** A reader fork's own words to the resident: attributed mail when it has a route, else under its name. */
3400
+ private deliverFromReader;
2873
3401
  private runLoop;
2874
3402
  private processNextEvent;
2875
3403
  private handleProcessEvent;
@@ -2895,6 +3423,14 @@ export declare class AgentFramework {
2895
3423
  * Convert an incoming MCPL channel message to a context message.
2896
3424
  * This replaces the old MCPLModule.onProcess() message conversion.
2897
3425
  */
3426
+ /**
3427
+ * A delivered inbound message becomes the latest delivered inbound (the
3428
+ * channel context's reply anchor; the legacy speech fallback) through the
3429
+ * registry's noteDelivered — at once for a plain channels/incoming, whose
3430
+ * acceptance the registry answers synchronously; parked for a coalesced one
3431
+ * until its acceptance is acknowledged (see parkedAnchors).
3432
+ */
3433
+ private noteDeliveredOrPark;
2898
3434
  private handleMcplChannelIncoming;
2899
3435
  /**
2900
3436
  * Route an incoming channel message through the ConversationRouter:
@@ -3142,7 +3678,8 @@ export declare class AgentFramework {
3142
3678
  * placed in its agent's deferred queue (wakeToRead), at `readsDeferredWrite`,
3143
3679
  * marked ambient when every notice the render folds was (`allAmbient`). */
3144
3680
  private queueCoalescedWakes;
3145
- /** Withdraw unstarted wakes whose sole cause is this subject (§4.2). */
3681
+ /** Withdraw unstarted wakes whose sole cause is this subject (§4.2), and
3682
+ * a merged start whose every request is withdrawn. */
3146
3683
  private cancelCoalescedWakes;
3147
3684
  /**
3148
3685
  * A placement in the deferred queue is upgraded in place once the flush has
@@ -3185,6 +3722,27 @@ export declare class AgentFramework {
3185
3722
  * channels answer to is never resolved to either.
3186
3723
  */
3187
3724
  private channelNamed;
3725
+ /**
3726
+ * A live agent's home channel, from its registry record (channelOfHome):
3727
+ * defined for a conversation fork, and only for one. Undefined for an agent
3728
+ * with none, and for one that has ended.
3729
+ */
3730
+ private homeOf;
3731
+ /**
3732
+ * The channel a registry record's `homeChannel` names: the channel on its
3733
+ * server. A bare channel id, as a record written before homes carried
3734
+ * their server keeps, is read as a wake that names its channel without its
3735
+ * server is (channelNamed): the one registered channel it names, read when
3736
+ * it's used, since the servers registered at that moment are what it can
3737
+ * mean. An id that names no one registered channel, as one no server
3738
+ * registers now or two servers do, is the home on no server (an empty
3739
+ * serverId, which channelNamed reads as none given), so the agent keeps a
3740
+ * home. A path that reads the pair finds no server registering it, and
3741
+ * refuses it; one that reads the name reads what the name means then: none
3742
+ * or two channels, which it refuses, or, once one server alone registers
3743
+ * the id, that server's channel.
3744
+ */
3745
+ private channelOfHome;
3188
3746
  /**
3189
3747
  * Explicit mode's typing channel for one start of a turn, which has no
3190
3748
  * locus, read once as the start opens (driveStream then shows what the
@@ -3225,6 +3783,23 @@ export declare class AgentFramework {
3225
3783
  * it takes their agent up (passRequests). */
3226
3784
  private processInferenceRequests;
3227
3785
  private runInferencePass;
3786
+ /**
3787
+ * `channel_publish` with no channel goes where the turn's plain speech
3788
+ * would: the frozen turn locus (the waking delivery's channel, or one
3789
+ * opened this turn), then the registry's own resolution. Under
3790
+ * `speech.locus: 'delivery'` the registry alone has no default, and the
3791
+ * tool failed on the very turn its own delivery woke (first live run,
3792
+ * 2026-10-12). Both dispatch paths — the stream driver's and
3793
+ * executeToolCall's — pass through here. Only a call made inside the turn
3794
+ * (callingTurnOf) takes the turn's locus: one made outside it, as a script
3795
+ * left running after its turn makes or a host's executeToolCall naming the
3796
+ * agent, takes none of the turn's channels. A conversation fork's home
3797
+ * isn't the turn's but the fork's own, so such a call from a fork naming
3798
+ * no channel still goes there (homeOf), as the fork's dispatched calls do
3799
+ * (dispatchChannelToolCall); anyone else's takes the registry's own
3800
+ * default.
3801
+ */
3802
+ private publishInputWithTurnLocus;
3228
3803
  /**
3229
3804
  * Stamps for the rows the agent's reply stores in its current turn: its
3230
3805
  * assistant responses, its tool_result rows (through `storeResults`), and
@@ -3426,14 +4001,20 @@ export declare class AgentFramework {
3426
4001
  * announced baseline alone (announceLocusIfChanged).
3427
4002
  */
3428
4003
  private noticeHeartbeatTurn;
4004
+ private rememberAnnouncedLocus;
4005
+ private forgetAnnouncedLocus;
4006
+ /** The stored baseline's entry for the agent set (rememberAnnouncedLocus),
4007
+ * or removed (undefined) when the agent ends without coming back. */
4008
+ private writeAnnouncedLocus;
3429
4009
  /**
3430
4010
  * Announce-on-change locus notice (turn-frozen routing). Appends a durable
3431
4011
  * `[routing]` window message when the turn's effective outbound locus
3432
4012
  * differs from the last one announced — the agent must never have to guess
3433
4013
  * where its plain prose lands. Durable append (never retracted) keeps the
3434
- * KV prefix stable; change-only keeps it out of steady-state turns. The
3435
- * first resolution after boot announces only a non-null locus ("prose has
3436
- * no destination" is the unremarkable boot default). Never triggers
4014
+ * KV prefix stable; change-only keeps it out of steady-state turns. An
4015
+ * agent never told of a locus, here or before a restart, hears only of a
4016
+ * non-null one ("prose has no destination" is the unremarkable start).
4017
+ * Never triggers
3437
4018
  * inference; never locus-eligible itself (system + no channel metadata).
3438
4019
  */
3439
4020
  private announceLocusIfChanged;
@@ -3445,7 +4026,11 @@ export declare class AgentFramework {
3445
4026
  * as the agent's first view) that addressed the agent, or that follows up
3446
4027
  * in a channel the turn sent into (TurnRouting.engaged). Undefined for any
3447
4028
  * other message. A tool boundary weighs the messages it injects by it,
3448
- * and noteArrival the ones no boundary of the turn weighs.
4029
+ * and noteArrival the ones no boundary of the turn weighs. The rule is
4030
+ * pure; what is done with its answer is `speech.locus`'s: under
4031
+ * `'latest-inbound'` the locus moves, under `'delivery'` (the default) the
4032
+ * agent is told it was addressed from elsewhere and the locus stays
4033
+ * (addressedElsewhereNotice).
3449
4034
  */
3450
4035
  private repinChannel;
3451
4036
  /** Whether `agent` has a turn alive: starting, streaming or waiting on its tools. */
@@ -3544,13 +4129,15 @@ export declare class AgentFramework {
3544
4129
  * Weigh a message that no tool boundary of the agent's open logical turn
3545
4130
  * will weigh: one that would re-pin the locus becomes one of the turn's
3546
4131
  * arrivals (TurnRouting.arrivals). A message the agent's own view leaves
3547
- * out, such as one a tune-out diverted (metadata.tuneOut), never enters
3548
- * its compiled view, so the agent won't see it, and it moves nothing.
4132
+ * out (agentSees), such as one held from the residents (heldFromResidents,
4133
+ * the admission stage's one predicate, which every resident's view filter
4134
+ * reads) or another agent's stored context injection, never enters its
4135
+ * compiled view, so the agent won't see it, and it moves nothing.
3549
4136
  */
3550
4137
  private noteArrival;
3551
4138
  /**
3552
4139
  * Whether `agent`'s store is the residents' one message slot, which every
3553
- * ordinary resident reads (sharedSlotAgents). The subconscious reads that
4140
+ * ordinary resident reads (`readsSharedSlot` in the registry). The subconscious reads that
3554
4141
  * slot through a merged view, but its own store is isolated, as a fork's
3555
4142
  * or an ephemeral agent's is.
3556
4143
  */
@@ -3591,6 +4178,23 @@ export declare class AgentFramework {
3591
4178
  * so the agent's next turn announces where its speech lands.
3592
4179
  */
3593
4180
  private repinTurnLocus;
4181
+ /**
4182
+ * Under `speech.locus: 'delivery'`: tell the agent that someone addressed
4183
+ * it from another channel while its turn was busy, since incoming traffic
4184
+ * never moves the locus and a neutral message carries nothing that names
4185
+ * its channel (first live run, 2026-10-12, finding C). Once per channel
4186
+ * per turn (TurnRouting.addressedElsewhere); nothing for the turn's own
4187
+ * locus. Stored durably; returned as stored for a live stream to inject
4188
+ * with its boundary's other messages. Undefined when nothing was stored.
4189
+ */
4190
+ private addressedElsewhereNotice;
4191
+ /**
4192
+ * The arrivals a start of the turn consumes under `speech.locus:
4193
+ * 'delivery'`: each one that addressed the agent, whose message is still
4194
+ * in the store, gets the addressed-elsewhere notice, oldest first. A
4195
+ * follow-up in an engaged channel addressed nobody and is not announced.
4196
+ */
4197
+ private noticeAddressedArrivals;
3594
4198
  /**
3595
4199
  * Durable window notice for a channel the agent did not ask to open: a
3596
4200
  * subscription-policy admission, announced as the decision before its
@@ -3956,9 +4560,8 @@ export declare class AgentFramework {
3956
4560
  * gets inference:aborted with `reason`, and lastInference records its end
3957
4561
  * as driveStream's would, when the record is still this turn's. Nothing of
3958
4562
  * the kind when another turn of this agent's name holds the turn token (one
3959
- * begun after a stop and start, or by a replacement agent object): the
3960
- * event and the record carry only the name, so this frame's would end that
3961
- * newer turn instead.
4563
+ * begun by a replacement agent object): the event and the record carry only
4564
+ * the name, so this frame's would end that newer turn instead.
3962
4565
  */
3963
4566
  private abortDroppedTurn;
3964
4567
  /**
@@ -4027,7 +4630,11 @@ export declare class AgentFramework {
4027
4630
  private driveStream;
4028
4631
  /**
4029
4632
  * Execute a tool call and return the result.
4030
- * Routes to the appropriate handler (module registry or MCPL).
4633
+ * Routes it where the agent's own call of the name goes: to the
4634
+ * framework's own tools the agent has (agent_settings, the workspace and
4635
+ * gate tools, think, journal, prose_help and the rest), the channel tools,
4636
+ * MCPL or the module registry. skip_reply, which ends the turn it's called
4637
+ * in, is refused, since this call isn't made in one.
4031
4638
  * Its one caller in the framework is the operator's puppet
4032
4639
  * (puppetToolCall), which puts the agent's inline cap on the call as
4033
4640
  * resultMaxChars; a host may call it as well.
@@ -4041,8 +4648,10 @@ export declare class AgentFramework {
4041
4648
  * (ctx.callTool → executeToolCallFrom with {kind:'module'}), which is exempt
4042
4649
  * from agent allowlists. Registered agents' allowedTools is enforced at
4043
4650
  * dispatch, including namespaced utility names. Genuinely unidentified public callers (including
4044
- * unknown legacy names) remain unrestricted. Framework-created identities
4045
- * are refused while unregistered, even if their configured list allows it.
4651
+ * unknown legacy names) remain unrestricted. A name the framework made in
4652
+ * this process is refused while it isn't registered, even if its configured
4653
+ * list allows the tool; after a restart, such a name is a host's caller name
4654
+ * like any other.
4046
4655
  */
4047
4656
  executeToolCall(call: ToolCall): Promise<ToolResult>;
4048
4657
  /**
@@ -4066,8 +4675,11 @@ export declare class AgentFramework {
4066
4675
  * wire ordering. For its own duration the puppet HOLDS the turn-alive
4067
4676
  * marker (wakes requeue, cross-turn writers defer), so a wake landing
4068
4677
  * during the tool's execution cannot start a turn underneath the pair.
4069
- * - Refused for tools outside the agent's own surface (canUseTool): the
4070
- * stored pair must be an act the agent could genuinely have taken.
4678
+ * - Refused for tools outside the agent's own surface (the tools it may
4679
+ * call, availableToolsForPresentation), and for skip_reply, by name or
4680
+ * through a toolsets--act that reaches it, which ends the turn it's
4681
+ * called in: the stored pair must be an act the agent could genuinely
4682
+ * have taken.
4071
4683
  * - The call executes FOR REAL through the shared dispatch (MCPL,
4072
4684
  * channel tools, utils, modules) with the agent's provenance — a
4073
4685
  * puppeted walk_to actually moves the avatar.
@@ -4107,6 +4719,29 @@ export declare class AgentFramework {
4107
4719
  * tool it makes, under that tool's model-facing name and with its
4108
4720
  * arguments, its id kept; or the reason it can't be sent. */
4109
4721
  private resolveToolsetAct;
4722
+ /**
4723
+ * A reader reads and reports: a reader fork (registry kind
4724
+ * 'subconscious-fork', in every incarnation) may call only its own tools,
4725
+ * and speak_in_channel where allowChannelSpeech allows it. Every other
4726
+ * tool the resident has stays in its block (the shared prefix) and is
4727
+ * refused here, so with speech off a fork can post nowhere (scout's
4728
+ * condition, 2026-10-19). It's decided at each call from what the reader
4729
+ * may call, not from what it is shown, so a tool added or moved out of
4730
+ * the block later is refused too.
4731
+ */
4732
+ private readerRefuses;
4733
+ /**
4734
+ * What a reader fork may call: exactly its own tools and the speech its
4735
+ * configuration allows, never widened or narrowed by its resident's
4736
+ * allowedTools. The resident's list bounds the resident's own surface;
4737
+ * the reader's tools are the framework's, for reading on its behalf. A
4738
+ * denyToolsAtDispatch entry the fork takes from its resident that names
4739
+ * one of them still refuses it (mayCallTool checks the deny first): a
4740
+ * resident never holds a reader tool, so such an entry is about readers.
4741
+ * The fork still shows its resident's block (the shared prefix): what it
4742
+ * may call is decided here, at each call, apart from what it is shown.
4743
+ */
4744
+ private readerMayCall;
4110
4745
  /** A toolsets--act call a host toolset resolved (HostPresentation.resolveAct):
4111
4746
  * its refusal answered, or the tool's own call dispatched in its place,
4112
4747
  * with the act's id, so its result is the act's. */
@@ -4456,9 +5091,15 @@ export declare class AgentFramework {
4456
5091
  * that. Never prefix-map insertion order.
4457
5092
  */
4458
5093
  private resolveMcplTool;
4459
- /** Registered policy; framework-created identities have no dispatch authority
4460
- * while unregistered. Genuine legacy caller names retain their surface. */
5094
+ /** Registered policy. Within this process, a name the framework made has no
5095
+ * dispatch authority while it isn't registered; after a restart, a host call names
5096
+ * its caller as any host call does. Genuine legacy caller names retain
5097
+ * their surface. */
4461
5098
  private canAgentUseTool;
5099
+ /** Whether a call of `toolName` as `agentName` is refused at dispatch (AgentConfig.denyToolsAtDispatch, or a reader's own rule). */
5100
+ private deniedAtDispatch;
5101
+ /** Whether `agentName` may call `toolName`: the one rule dispatch applies (agentToolPermissionFailure), for whatever else judges a call. */
5102
+ private mayCallTool;
4462
5103
  private agentToolPermissionFailure;
4463
5104
  private markedInputFailure;
4464
5105
  private cutOffResults;
@@ -4496,6 +5137,9 @@ export declare class AgentFramework {
4496
5137
  * (`refusedHere`) counts as one the list refuses.
4497
5138
  */
4498
5139
  private roundCallOf;
5140
+ private toolRoute;
5141
+ private pushToolResult;
5142
+ private awaitedToolAnswer;
4499
5143
  /**
4500
5144
  * Dispatch a call the agent made. `turnId` is the turn it was made in
4501
5145
  * (TurnRouting.turnId), as its caller knows it: a model's call, the turn
@@ -4571,6 +5215,14 @@ export declare class AgentFramework {
4571
5215
  * the start now beginning (no tool boundary will weigh it), and one for
4572
5216
  * every other resident's open turn. */
4573
5217
  private noteStored;
5218
+ /**
5219
+ * Held agent mail is released only when its message has actually entered
5220
+ * the recipient's store — never on a deferral. Called at every site that
5221
+ * writes a message into a context: the direct path above and the two
5222
+ * deferred-write flushes (turn start, tool boundary). Both writes reach
5223
+ * disk in the same sync, so a crash keeps either both or neither.
5224
+ */
5225
+ private releaseLandedMail;
4574
5226
  /**
4575
5227
  * Splice out the deferred messages addressed to `agentName` (explicitly
4576
5228
  * via forAgent, or implicitly when it is the primary), leaving other
@@ -4873,11 +5525,9 @@ export declare class AgentFramework {
4873
5525
  * at a tool boundary whose stream declares it carries the messages
4874
5526
  * injected there (markContextConsumed). So a notice such a stream carried
4875
5527
  * is under it. One a boundary stored without sending (a turn a tool ended,
4876
- * a budget restart) is above it, and so is one injected into a stream that
4877
- * doesn't declare it carries injections, which may have dropped it:
4878
- * counted as unread, it goes to the primary even if the agent heard it,
4879
- * rather than to no one where the stream dropped it. null when the window
4880
- * can't be read, which is logged.
5528
+ * a budget restart, the direct API's boundary, which has no stream) is
5529
+ * above it until a compile sends it, and counts as unread. null when the
5530
+ * window can't be read, which is logged.
4881
5531
  */
4882
5532
  private releasedWindow;
4883
5533
  /**
@@ -5008,7 +5658,7 @@ export declare class AgentFramework {
5008
5658
  * The writes the framework holds for the store `reader` reads, in queue
5009
5659
  * order: those addressed to it and, when it's an ordinary resident, those
5010
5660
  * addressed to any ordinary resident, since residents share one message
5011
- * slot (sharedSlotAgents). A write whose target is gone isn't among them:
5661
+ * slot (`readsSharedSlot` in the registry). A write whose target is gone isn't among them:
5012
5662
  * no module reads that agent's store, and the write waits for its window's
5013
5663
  * release (drainDeferredFor) or, at its flush, is dropped (addMessage), a
5014
5664
  * failed reply, or a channel notice its reader could act on, passing to the
@@ -5669,9 +6319,10 @@ export declare class AgentFramework {
5669
6319
  private runDisconnectMcplServer;
5670
6320
  /**
5671
6321
  * Restart an MCPL server at runtime: disconnect, then reconnect with the
5672
- * same (or an updated) config. This actually respawns a stdio child —
5673
- * unlike `reconnect: true`, which only retries after transport-level
5674
- * failures. Throws if the server has no stored config and none is given.
6322
+ * same (or an updated) config. This respawns a stdio child at once,
6323
+ * whatever its state; `reconnect: true` spawns a fresh child only after
6324
+ * the connection fails or its child exits. Throws if the server has no
6325
+ * stored config and none is given.
5675
6326
  * What its connect would refuse is refused before the running server is
5676
6327
  * torn down. Until the connect, a connect or a restart started meanwhile
5677
6328
  * is refused the id and the tool prefix the restart moves the server to,
@@ -5944,6 +6595,15 @@ export declare class AgentFramework {
5944
6595
  * error and nothing is written.
5945
6596
  */
5946
6597
  private dispatchWakeRuleToolCall;
6598
+ /**
6599
+ * A reader's own tool (SUBCONSCIOUS_TOOL_NAMES), for both entries that run
6600
+ * an agent's call: the dispatcher's, for the model's call, and
6601
+ * executeToolCallFrom's, for a host's or the puppet's. The tools are
6602
+ * advertised to residents so reader forks share their prefix, and only a
6603
+ * registered reader may use them. A rejection is answered with a failed
6604
+ * result, never left unhandled.
6605
+ */
6606
+ private readerToolCall;
5947
6607
  /**
5948
6608
  * Handle the synthesized `sleep` / `wake` tools. `sleep` arms the gate's
5949
6609
  * suppression window, optionally announces in the sticky channel, and ends
@@ -5951,6 +6611,35 @@ export declare class AgentFramework {
5951
6611
  */
5952
6612
  /** tune_out tool (residents): enter or cancel a channel tune-out. */
5953
6613
  private dispatchTuneOutToolCall;
6614
+ /** `focus` is `tune_out` with scope "all-except". */
6615
+ private handleFocusTool;
6616
+ /**
6617
+ * A tune-out call's refusal for a channel it can't resolve: main's words
6618
+ * for a name no registered channel, and none of the calling turn's own,
6619
+ * answers to, and the registry's own otherwise, as for an id that is
6620
+ * ambiguous across servers (#232 gap 8).
6621
+ */
6622
+ private unknownChannelWords;
6623
+ /**
6624
+ * The tune_out tool's body. Channel resolution is server-qualified
6625
+ * (ChannelRegistry.resolveChannel): with a `serverId`, that server's
6626
+ * channel with the id; inside the calling turn, a name one of the turn's
6627
+ * own channels answers to by its id means that channel; otherwise the one
6628
+ * channel the name means, which may be server-qualified, and a name two
6629
+ * servers' channels answer to is refused with them as candidates (#232
6630
+ * gap 8). `turn` is the turn that made the call (callingTurnOf), the only
6631
+ * one whose speech an all-except entry moves.
6632
+ */
6633
+ private handleTuneOutTool;
6634
+ /**
6635
+ * The admission stage for one inbound event: the pure decision over the
6636
+ * framework's policy inputs (recipients, the hold in force, the wake
6637
+ * gate), traced. Callers apply it; nothing downstream re-asks.
6638
+ */
6639
+ private admitInbound;
6640
+ private commitDeliveries;
6641
+ /** The history-reading tool the primary resident actually has, if any (#232 gap 11). */
6642
+ private residentHistoryTool;
5954
6643
  private dispatchSleepToolCall;
5955
6644
  /**
5956
6645
  * Handle the synthesized `read_image` tool: read image bytes from a
@@ -5972,10 +6661,9 @@ export declare class AgentFramework {
5972
6661
  * every sibling in the round to settle; if one never does, fail closed
5973
6662
  * rather than trust an index the batch may still change. Sibling saves
5974
6663
  * produce no images and are not waited on (two saves in one batch would
5975
- * otherwise deadlock into a double timeout). A script's own calls
5976
- * (`pytc-…`) skip the barrier: the batch's pending siblings include the
5977
- * code_execution call running that script, so waiting on them would wait
5978
- * on itself.
6664
+ * otherwise deadlock into a double timeout). Only the round's own calls
6665
+ * wait: a call that isn't among its pending calls, a script's (`pytc-…`)
6666
+ * or an awaited call's, counts the images the agent has now.
5979
6667
  */
5980
6668
  private awaitSiblingToolCalls;
5981
6669
  /**