@animalabs/agent-framework 0.29.0 → 0.30.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 (104) hide show
  1. package/dist/src/admission/admit.d.ts +90 -0
  2. package/dist/src/admission/admit.d.ts.map +1 -0
  3. package/dist/src/admission/admit.js +43 -0
  4. package/dist/src/admission/admit.js.map +1 -0
  5. package/dist/src/agent.d.ts +21 -0
  6. package/dist/src/agent.d.ts.map +1 -1
  7. package/dist/src/agent.js +43 -6
  8. package/dist/src/agent.js.map +1 -1
  9. package/dist/src/author-presentation.d.ts +50 -0
  10. package/dist/src/author-presentation.d.ts.map +1 -0
  11. package/dist/src/author-presentation.js +58 -0
  12. package/dist/src/author-presentation.js.map +1 -0
  13. package/dist/src/dendrite/index.d.ts +6 -0
  14. package/dist/src/dendrite/index.d.ts.map +1 -0
  15. package/dist/src/dendrite/index.js +3 -0
  16. package/dist/src/dendrite/index.js.map +1 -0
  17. package/dist/src/dendrite/presets.d.ts +60 -0
  18. package/dist/src/dendrite/presets.d.ts.map +1 -0
  19. package/dist/src/dendrite/presets.js +117 -0
  20. package/dist/src/dendrite/presets.js.map +1 -0
  21. package/dist/src/dendrite/registry.d.ts +260 -0
  22. package/dist/src/dendrite/registry.d.ts.map +1 -0
  23. package/dist/src/dendrite/registry.js +742 -0
  24. package/dist/src/dendrite/registry.js.map +1 -0
  25. package/dist/src/dendrite/types.d.ts +392 -0
  26. package/dist/src/dendrite/types.d.ts.map +1 -0
  27. package/dist/src/dendrite/types.js +24 -0
  28. package/dist/src/dendrite/types.js.map +1 -0
  29. package/dist/src/framework.d.ts +684 -33
  30. package/dist/src/framework.d.ts.map +1 -1
  31. package/dist/src/framework.js +2998 -350
  32. package/dist/src/framework.js.map +1 -1
  33. package/dist/src/gate/event-gate.d.ts +12 -4
  34. package/dist/src/gate/event-gate.d.ts.map +1 -1
  35. package/dist/src/gate/event-gate.js +25 -5
  36. package/dist/src/gate/event-gate.js.map +1 -1
  37. package/dist/src/host-presentation.d.ts +4 -0
  38. package/dist/src/host-presentation.d.ts.map +1 -1
  39. package/dist/src/host-presentation.js +7 -3
  40. package/dist/src/host-presentation.js.map +1 -1
  41. package/dist/src/index.d.ts +5 -2
  42. package/dist/src/index.d.ts.map +1 -1
  43. package/dist/src/index.js +6 -1
  44. package/dist/src/index.js.map +1 -1
  45. package/dist/src/mcpl/channel-registry.d.ts +84 -9
  46. package/dist/src/mcpl/channel-registry.d.ts.map +1 -1
  47. package/dist/src/mcpl/channel-registry.js +136 -58
  48. package/dist/src/mcpl/channel-registry.js.map +1 -1
  49. package/dist/src/mcpl/push-coalescer.d.ts +9 -0
  50. package/dist/src/mcpl/push-coalescer.d.ts.map +1 -1
  51. package/dist/src/mcpl/push-coalescer.js +21 -0
  52. package/dist/src/mcpl/push-coalescer.js.map +1 -1
  53. package/dist/src/mcpl/toolsets-module.d.ts.map +1 -1
  54. package/dist/src/mcpl/toolsets-module.js +7 -0
  55. package/dist/src/mcpl/toolsets-module.js.map +1 -1
  56. package/dist/src/notice-tags.d.ts +2 -0
  57. package/dist/src/notice-tags.d.ts.map +1 -1
  58. package/dist/src/notice-tags.js +2 -0
  59. package/dist/src/notice-tags.js.map +1 -1
  60. package/dist/src/silent-heartbeat.d.ts +4 -2
  61. package/dist/src/silent-heartbeat.d.ts.map +1 -1
  62. package/dist/src/silent-heartbeat.js +7 -4
  63. package/dist/src/silent-heartbeat.js.map +1 -1
  64. package/dist/src/stored-injections.d.ts +4 -0
  65. package/dist/src/stored-injections.d.ts.map +1 -1
  66. package/dist/src/stored-injections.js +6 -0
  67. package/dist/src/stored-injections.js.map +1 -1
  68. package/dist/src/tune-out/coordinator.d.ts +379 -9
  69. package/dist/src/tune-out/coordinator.d.ts.map +1 -1
  70. package/dist/src/tune-out/coordinator.js +1080 -97
  71. package/dist/src/tune-out/coordinator.js.map +1 -1
  72. package/dist/src/tune-out/tools.d.ts +101 -5
  73. package/dist/src/tune-out/tools.d.ts.map +1 -1
  74. package/dist/src/tune-out/tools.js +55 -18
  75. package/dist/src/tune-out/tools.js.map +1 -1
  76. package/dist/src/types/agent.d.ts +25 -0
  77. package/dist/src/types/agent.d.ts.map +1 -1
  78. package/dist/src/types/framework.d.ts +99 -0
  79. package/dist/src/types/framework.d.ts.map +1 -1
  80. package/dist/src/types/trace.d.ts +136 -0
  81. package/dist/src/types/trace.d.ts.map +1 -1
  82. package/package.json +3 -3
  83. package/src/admission/admit.ts +113 -0
  84. package/src/agent.ts +48 -6
  85. package/src/author-presentation.ts +81 -0
  86. package/src/dendrite/index.ts +32 -0
  87. package/src/dendrite/presets.ts +149 -0
  88. package/src/dendrite/registry.ts +808 -0
  89. package/src/dendrite/types.ts +397 -0
  90. package/src/framework.ts +3239 -369
  91. package/src/gate/event-gate.ts +31 -5
  92. package/src/host-presentation.ts +10 -3
  93. package/src/index.ts +15 -2
  94. package/src/mcpl/channel-registry.ts +170 -60
  95. package/src/mcpl/push-coalescer.ts +19 -0
  96. package/src/mcpl/toolsets-module.ts +7 -0
  97. package/src/notice-tags.ts +2 -0
  98. package/src/silent-heartbeat.ts +7 -4
  99. package/src/stored-injections.ts +7 -0
  100. package/src/tune-out/coordinator.ts +1229 -98
  101. package/src/tune-out/tools.ts +152 -11
  102. package/src/types/agent.ts +28 -0
  103. package/src/types/framework.ts +102 -0
  104. package/src/types/trace.ts +150 -0
@@ -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
  /**
@@ -211,6 +213,85 @@ export declare class DefaultErrorPolicy implements ErrorPolicy {
211
213
  constructor(settings?: RetrySettings);
212
214
  onInferenceError(error: Error, _agentName: string, attempt: number): ErrorAction;
213
215
  }
216
+ /**
217
+ * The admission record on a stored message: it was held from the residents
218
+ * by a policy epoch (`metadata.tuneOut = { epochId }`). ONE predicate for
219
+ * "held from the resident", read by the compiled-view filter and by the
220
+ * mid-turn injection alike (#232 H1), so the window and the wire agree.
221
+ */
222
+ export declare const heldFromResidents: (metadata: Record<string, unknown> | undefined) => boolean;
223
+ /** Options for {@link AgentFramework.deriveAgent}. */
224
+ export interface DeriveAgentOptions {
225
+ /** The new agent's name. Single-use within this framework's lifetime. */
226
+ name: string;
227
+ /** The live agent whose context and configuration are inherited. */
228
+ from: string;
229
+ /** How context is inherited. Default `'shared'`. */
230
+ mode?: 'shared' | 'copy';
231
+ /** `'shared'` only. Default `'reuse'`. */
232
+ solve?: 'reuse' | 'fresh';
233
+ /**
234
+ * `'shared'` only. Also inherit the parent's refusal ledger (what it
235
+ * declined to compress). Default false; set for a fork that stands in
236
+ * for the parent's attention. Recorded as `inherit.refusals`.
237
+ */
238
+ inheritRefusals?: boolean;
239
+ /**
240
+ * A fresh strategy instance for the child. Strategy instances hold state
241
+ * and are never shared; to reuse the parent's rendering it must be the
242
+ * same class with compatible configuration. Default: passthrough.
243
+ */
244
+ strategy?: ContextStrategy;
245
+ /** Identity and settings overrides. Everything not named is the parent's. */
246
+ config?: Partial<Omit<AgentConfig, 'name' | 'strategy'>>;
247
+ /**
248
+ * The parent's tool round in flight, if any. While a tool call runs, the
249
+ * assistant turn that made it is not in the parent's store yet. By
250
+ * default the child's branch gets that turn verbatim (as its own, like
251
+ * the rest of the inheritance) followed by a tool-result message: results
252
+ * the parent has already received as they are; the call that derived the
253
+ * child with `madeBy.result`, or a note saying it did; and any other call
254
+ * still running with a note that its result was not available. So a fork
255
+ * sees the call that made it and never meets a dangling `tool_use`.
256
+ * `madeBy` defaults to the only open call when there is exactly one.
257
+ * `include: false` leaves the round out, and the child starts from the
258
+ * last stored message before it.
259
+ */
260
+ pendingRound?: {
261
+ include?: boolean;
262
+ madeBy?: {
263
+ toolUseId: string;
264
+ result: string;
265
+ };
266
+ /** Results, from the child's side, for other calls still open, by tool-use id. */
267
+ results?: Record<string, string>;
268
+ };
269
+ /** Ordinary messages appended to the child before it runs. */
270
+ framing?: Array<{
271
+ participant: string;
272
+ content: ContentBlock[];
273
+ metadata?: MessageMetadata;
274
+ }>;
275
+ /** Who spawned it. Default: `from`. */
276
+ spawnedBy?: string;
277
+ /** Where its completion returns. */
278
+ resultTo?: import('./dendrite/index.js').ResultRoute;
279
+ /** What happens to it when its spawner ends. Default `'orphan'`. */
280
+ onParentEnd?: import('./dendrite/index.js').ParentEndPolicy;
281
+ deadlineMs?: number;
282
+ idleTimeoutMs?: number;
283
+ maxTurns?: number;
284
+ /** Preset label for discovery. Default `'task-fork'`. */
285
+ kind?: string;
286
+ metadata?: Record<string, unknown>;
287
+ }
288
+ /** Rejection delivered to the caller awaiting a bounded run that was ended from outside. */
289
+ export declare class AgentStoppedError extends Error {
290
+ readonly agentName: string;
291
+ readonly reason: AgentEndReason;
292
+ readonly by?: string | undefined;
293
+ constructor(agentName: string, reason: AgentEndReason, by?: string | undefined, detail?: string);
294
+ }
214
295
  export interface ReinitAlertText {
215
296
  opening: string;
216
297
  message: string;
@@ -389,6 +470,13 @@ export declare class AgentFramework {
389
470
  private quiesceReason?;
390
471
  private quiescedAt?;
391
472
  private traceListeners;
473
+ /** Traces emitted before start() — registry restore, interrupted work,
474
+ * resumed epochs — replayed to listeners that attach afterwards, since a
475
+ * host attaches its sinks after create() returns. Dropped at start().
476
+ * It keeps the first 1,000, the start of the stream, and counts the rest
477
+ * (earlyTracesDropped), which a replay ends by naming. */
478
+ private earlyTraces;
479
+ private earlyTracesDropped;
392
480
  private syncIntervalMs;
393
481
  private syncTimer;
394
482
  private maintenanceIntervalMs;
@@ -442,8 +530,9 @@ export declare class AgentFramework {
442
530
  private midTurnInputSignals;
443
531
  /** Last outbound locus announced to each agent as a durable `[routing]`
444
532
  * 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. */
533
+ * (KV-safe, no per-turn chatter). Kept in the store as well
534
+ * (rememberAnnouncedLocus), so a restart compares with what the agent was
535
+ * last told rather than with nothing. */
447
536
  private lastAnnouncedLocus;
448
537
  /** Every resident's held drafts: plain speech that was suppressed, bounced
449
538
  * or left without a destination, never published except by their
@@ -527,6 +616,13 @@ export declare class AgentFramework {
527
616
  private usedEphemeralAgentNames;
528
617
  /** One-shot generation tickets minted by createEphemeralAgent. */
529
618
  private ephemeralCandidates;
619
+ /**
620
+ * Derived agent → the agent whose tool presentation it shows. A derived
621
+ * agent that inherits its parent's tools must advertise the identical
622
+ * tool block (it is the front of the shared request prefix), including
623
+ * the parent's resident-edited visibility and descriptions.
624
+ */
625
+ private toolSurfaceOwners;
530
626
  /** Every agent createEphemeralAgent made, for as long as the object lives:
531
627
  * its usage counts in the usage record's one shared ephemeral entry. Kept
532
628
  * by the object, not the run's record (ephemeralRuns), which its cleanup
@@ -595,8 +691,25 @@ export declare class AgentFramework {
595
691
  private subconsciousStrategy;
596
692
  /** Its config (speak_in_channel gate, voice block provenance). */
597
693
  private subconsciousConfig;
598
- /** Tune-out coordinator (issue #77); non-null iff subconscious + channels. */
694
+ /** Tune-out coordinator (issue #77); non-null iff a reader is configured + channels. */
599
695
  private tuneOutCoordinator;
696
+ /** Residents are offered `tune_out` (a reader is configured, or `tuneOut.enabled`). */
697
+ private tuneOutOffered;
698
+ /**
699
+ * The reply anchor a coalesced delivery would set, parked until the
700
+ * acceptance is acknowledged to the server (handleCoalescedIncoming): an
701
+ * acceptance whose commit fails after its delivery moves no anchor, and the
702
+ * retry the receipt answers, which delivers nothing again, commits the one
703
+ * its first attempt parked. Keyed by server and event id; bounded.
704
+ */
705
+ private parkedAnchors;
706
+ /** `tuneOut.announce`: the excepted channel hears the all-except scope open and close. */
707
+ private tuneOutAnnounce;
708
+ /** `speech.locus`: where prose goes when nothing names a destination (see FrameworkConfig). */
709
+ private speechLocus;
710
+ /** `subconscious.reader: 'forks'`: the reader is a succession of forks (Dendrite). */
711
+ private readerForks;
712
+ private readerForkCounter;
600
713
  /** Agents an abandon could not cancel (token held, no stream) — surfaced
601
714
  * in HostModeStatus until the next quiesce/resume. */
602
715
  private lastUnabandonable;
@@ -614,6 +727,24 @@ export declare class AgentFramework {
614
727
  /** True once the cap has been met in the current run, so its line is
615
728
  * logged once a run, whatever began the run. */
616
729
  private deferredWritesCapLogged;
730
+ /** The agent registry and its ended log, as recovery files beside the store
731
+ * (nissa's #546 finding 3): Chronicle state follows the store's branch, and
732
+ * an undo or an operator's surgery must not erase a result held for
733
+ * delivery or the record of work that ran. The file wins where it exists;
734
+ * the branch-local state is read only for stores that predate it. */
735
+ private agentRegistryPath;
736
+ private agentRegistryEndedPath;
737
+ /** The ended log as the recovery file keeps it: the newest records, bounded. */
738
+ private endedRecovery;
739
+ /** The branch-local ended log by name (its newest entry for each), and how far it is indexed (findEndedAgentRecord). */
740
+ private readonly endedLogIndex;
741
+ /** The ended log's entries by the namespace their context holds (the latest for each). */
742
+ private readonly endedLogNamespaceIndex;
743
+ /** Namespaces this process opened for an ephemeral agent's context, by owner: candidates not yet registered included. */
744
+ private readonly namespaceOwners;
745
+ private endedLogIndexed;
746
+ /** The last indexed entry's mark, so a log that changed under the index is seen. */
747
+ private endedLogTail;
617
748
  /** Branch-independent recovery files (see FrameworkConfig.hostModePath /
618
749
  * deferredWritesPath). Undefined → branch-local slot fallback. */
619
750
  private hostModePath;
@@ -743,12 +874,27 @@ export declare class AgentFramework {
743
874
  private coalescingSnapshotDirty;
744
875
  private coalescingRecentReceipts;
745
876
  /**
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
- */
877
+ * Dendrite agent registry — every agent this framework runs, with its
878
+ * roles, lifetime and relationships. `agents` stays the map of live Agent
879
+ * OBJECTS (the generation identity streams are checked against); the
880
+ * registry is what says what each of them is for. Selection sites read
881
+ * roles from here instead of excluding kinds by hand.
882
+ */
883
+ private readonly registry;
884
+ /** Tell the first adoption candidate when task work is orphaned (config.dendrite.announceOrphans). */
885
+ private announceOrphans;
886
+ /**
887
+ * After this many derivations of one kind from one agent, that agent hears
888
+ * a count line every so many instead of a line per fork
889
+ * (config.dendrite.collapseDerivationNoticesAfter; 0 = never collapse).
890
+ */
891
+ private collapseDerivationNoticesAfter;
892
+ /** The host's say over each derivation, ephemeral spawn and resume (config.dendrite.beforeDerive). */
893
+ private beforeDerive?;
894
+ /** What a source is told of a derivation (config.dendrite.derivationNotice); absent, the default line. */
895
+ private derivationNoticeHook?;
896
+ /** Per source agent, per kind: how many derivations, since when, and at which count the last note went. */
897
+ private derivationTallies;
752
898
  private readonly sharedSlotAgents;
753
899
  /** The batched-wake lines already written (placeWakeLines), so every agent a
754
900
  * wake was for, and every later start of it, writes each at most once. */
@@ -757,6 +903,7 @@ export declare class AgentFramework {
757
903
  * in the round counted by their share of the bound: such a round is
758
904
  * stored by its share whether or not it fits (buildStoredToolResultContent). */
759
905
  private readonly toolRoundsByShare;
906
+ /** Group commit: one fsync per event-loop turn, shared by every waiter. */
760
907
  /** The windows of forks and runs deregistered while the host was quiesced,
761
908
  * by agent name (releaseWindowNowOrAfterResume); resume() releases them
762
909
  * (runReleasesAfterResume), or stop() passes on what they left, unread or
@@ -765,6 +912,7 @@ export declare class AgentFramework {
765
912
  private readonly releasesAfterResume;
766
913
  private readonly managerReleases;
767
914
  private readonly releasedByCleanup;
915
+ private readonly resumesPending;
768
916
  private readonly openManagers;
769
917
  private readonly openManagerRefs;
770
918
  private readonly storeSees;
@@ -778,19 +926,13 @@ export declare class AgentFramework {
778
926
  private conversationRouter;
779
927
  /** Agent configs by name — fork agents are built from the template's config. */
780
928
  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
929
  /** Forks being spawned, by channel id, each until its spawn settles (see
788
930
  * routeConversation). The promise never rejects. */
789
931
  private readonly conversationSpawns;
790
932
  /** Last idle-TTL sweep timestamp. */
791
933
  private lastConversationSweep;
792
934
  /** Forks whose TTL closure turn has been queued — disposed (removed from
793
- * agents/agentConfigs/conversationAgentHomes) when their stream ends. */
935
+ * agents/agentConfigs and ended in the registry) when their stream ends. */
794
936
  private closingConversationAgents;
795
937
  private codeExecution;
796
938
  private scriptToolWaiters;
@@ -1155,7 +1297,10 @@ export declare class AgentFramework {
1155
1297
  */
1156
1298
  private heartbeatWakeBefore;
1157
1299
  /** The agents the heartbeat wakes: the residents, not conversation forks,
1158
- * ephemeral runs or the subconscious, which keep windows of their own. */
1300
+ * ephemeral runs or the subconscious, which keep windows of their own.
1301
+ * Read from the registry by role, as an untargeted push's recipients are
1302
+ * (the heartbeat's wakes were heartbeat-mcpl's pushes): the agents whose
1303
+ * spec takes untargeted inbound, in registration order. */
1159
1304
  private heartbeatTargets;
1160
1305
  /**
1161
1306
  * The event a heartbeat wake is to the gate: a push from the server id
@@ -1405,7 +1550,9 @@ export declare class AgentFramework {
1405
1550
  /**
1406
1551
  * Add a trace event listener for observability.
1407
1552
  */
1408
- onTrace(listener: TraceEventListener): () => void;
1553
+ onTrace(listener: TraceEventListener, options?: {
1554
+ replay?: boolean;
1555
+ }): () => void;
1409
1556
  /**
1410
1557
  * Public accessor for the MCPL channel registry.
1411
1558
  * Null when no MCPL servers are configured.
@@ -2248,11 +2395,334 @@ export declare class AgentFramework {
2248
2395
  * ContextManager, before the store. Until then the ContextManager stays
2249
2396
  * open.
2250
2397
  */
2251
- createEphemeralAgent(config: AgentConfig): Promise<{
2398
+ createEphemeralAgent(config: AgentConfig,
2399
+ /**
2400
+ * How the registry should describe this agent. Omitted: an independent
2401
+ * fresh worker with no spawner and no result route, which is what every
2402
+ * caller of this method got before the registry existed. Supplying a
2403
+ * spec (see the presets in `dendrite/`) declares who spawned it, where
2404
+ * its result goes and what it inherited, so lifecycle rules — orphan
2405
+ * notice, reparenting, held results — apply to it.
2406
+ */
2407
+ spec?: Omit<AgentSpec, 'name'>): Promise<{
2252
2408
  agent: Agent;
2253
2409
  contextManager: ContextManager;
2254
2410
  cleanup: () => void;
2255
2411
  }>;
2412
+ /**
2413
+ * Derive a new agent from a live one: the parent's context at a
2414
+ * checkpoint, a private continuation, and — unless overridden — the
2415
+ * parent's whole configuration (model, thinking, cache TTL, provider
2416
+ * params, prompt, tools). The parent keeps running.
2417
+ *
2418
+ * The returned agent is a bounded job, driven with
2419
+ * `runEphemeralToCompletion` exactly like one from `createEphemeralAgent`.
2420
+ *
2421
+ * **Inheritance.** `mode: 'shared'` (the default) gives the child the
2422
+ * parent's messages and fold state through shared storage: nothing is
2423
+ * copied, the child folds with the parent's memory tree, and neither can
2424
+ * alter what the other reads. It needs branch-bound store handles and is
2425
+ * refused, not silently downgraded, where they are missing. `mode: 'copy'`
2426
+ * is the historical mechanism — the parent's compiled context re-added as
2427
+ * the child's own messages — and works everywhere.
2428
+ *
2429
+ * **Rendering.** With `solve: 'reuse'` (the default) and nothing
2430
+ * overridden, the child's first request is the parent's request plus the
2431
+ * child's framing: the same system prompt and tool block, the parent's
2432
+ * turns presented as the child's own, and a cache marker on the end of
2433
+ * the parent's request so the prefix it wrote is read back. `solve:
2434
+ * 'fresh'` deliberately re-solves, e.g. at another budget; so does any
2435
+ * override that changes what is rendered. Those are operating choices —
2436
+ * the presentation changes and the provider cache misses.
2437
+ *
2438
+ * **Framing** is ordinary messages appended to the child before it runs:
2439
+ * the task, and whatever tells it which stream it is. The parent's turn
2440
+ * in flight is not in its store yet (see `getPendingAssistantRound`), so
2441
+ * a fork made from inside a tool call starts from the message before the
2442
+ * turn that made it.
2443
+ *
2444
+ * Context isolation is not process or filesystem isolation: parent and
2445
+ * child share tools, any shell and the workspace.
2446
+ */
2447
+ deriveAgent(options: DeriveAgentOptions): Promise<{
2448
+ agent: Agent;
2449
+ contextManager: ContextManager;
2450
+ cleanup: () => void;
2451
+ }>;
2452
+ private discardEphemeralCandidate;
2453
+ /**
2454
+ * The default wording for the call that derived a child: who it is, what
2455
+ * kind, and how long — the fields the consent event names, so the fork
2456
+ * never has to infer its own lifetime from context (Linn, 10-09).
2457
+ */
2458
+ private derivedNote;
2459
+ /**
2460
+ * The parent's in-flight tool round, reproduced on the child's branch so
2461
+ * the child sees the call that made it (see `DeriveAgentOptions.pendingRound`).
2462
+ */
2463
+ private framePendingRound;
2464
+ /**
2465
+ * The assistant turn an agent has produced but not yet stored: its tool
2466
+ * calls and any text before them, held until every tool result is in so
2467
+ * the pair lands adjacently. A host deriving an agent from inside one of
2468
+ * those tool calls can reproduce the turn in the child's framing.
2469
+ */
2470
+ getPendingAssistantRound(agentName: string): ContentBlock[] | undefined;
2471
+ /**
2472
+ * Bring an ended bounded job back as a new incarnation of the same
2473
+ * identity, on the context it left: an isolated agent's own namespace, or
2474
+ * a derived agent's own branch. Nothing is re-derived and nothing is
2475
+ * re-seeded — the agent continues from its last stored message, which is
2476
+ * the end of its last complete round (a round whose tool results never
2477
+ * all arrived was never stored).
2478
+ *
2479
+ * Use it for a job that was stopped, failed, or was interrupted by a
2480
+ * restart. Configuration is not persisted with an agent, so the caller
2481
+ * supplies it again; the role mapping a derived agent used is restored
2482
+ * from its record unless the config sets one. Relationships are kept
2483
+ * where the other agent still exists; a job whose spawner or result
2484
+ * recipient is gone resumes without that edge and can be reparented.
2485
+ *
2486
+ * External effects are not replayed and not undone: a tool the previous
2487
+ * incarnation ran before it ended has had its effect, and a call it never
2488
+ * received a result for may be made again by the model. Drive the result
2489
+ * with `runEphemeralToCompletion`.
2490
+ */
2491
+ resumeAgent(name: string, config: Omit<AgentConfig, 'name'>): Promise<{
2492
+ agent: Agent;
2493
+ contextManager: ContextManager;
2494
+ cleanup: () => void;
2495
+ }>;
2496
+ /**
2497
+ * A context to read an agent's history from, without changing the live
2498
+ * system.
2499
+ *
2500
+ * - A live agent: a snapshot derived from its context — at the head, or
2501
+ * at `atSequence` for an earlier state. The snapshot is its own branch;
2502
+ * the agent keeps running and is not affected by anything done to it.
2503
+ * - An ended agent: the context it left, reopened where it lives.
2504
+ *
2505
+ * The returned manager uses a passthrough strategy: it shows what is
2506
+ * stored, raw. An ended agent's context is the real one — treat it as
2507
+ * read-only unless you mean to change what a later resume starts from.
2508
+ */
2509
+ inspectAgentContext(name: string, options?: {
2510
+ atSequence?: number;
2511
+ }): Promise<ContextManager>;
2512
+ /** Open the context an ended agent left, wherever it lives. */
2513
+ private reopenAgentContext;
2514
+ /** Open a derived agent's context on a branch of its own (see deriveAgent). */
2515
+ private deriveSharedContext;
2516
+ /** Flat list of registered agents with their roles, lifetime and relationships. */
2517
+ listAgents(options?: {
2518
+ includeEnded?: boolean;
2519
+ }): AgentRecord[];
2520
+ /** One agent's record: the live one, else its most recent ended one. */
2521
+ getAgentRecord(name: string): AgentRecord | null;
2522
+ /** The agent that owns default delivery, or null before any is declared. */
2523
+ getPrimaryAgentName(): string | null;
2524
+ /**
2525
+ * Activations in flight, each with the agent that owns the work. Derived
2526
+ * from the live turn state, so it cannot disagree with what is running.
2527
+ */
2528
+ listActivations(): ActivationRecord[];
2529
+ /**
2530
+ * Policy epochs currently in force (tune-out holds), read from the
2531
+ * coordinator's own durable state — not mirrored. An epoch is neither an
2532
+ * agent nor a task: ending one leaves both running.
2533
+ */
2534
+ listPolicyEpochs(): PolicyEpoch[];
2535
+ /**
2536
+ * Cancel an agent's activation in flight, leaving the agent registered.
2537
+ * For a bounded job, whose lifetime is that one run, this ends the job.
2538
+ * Returns false when nothing was running.
2539
+ */
2540
+ cancelActivation(name: string, options?: {
2541
+ by?: string;
2542
+ reason?: string;
2543
+ }): boolean;
2544
+ /**
2545
+ * End an agent: cancel its run, remove it from the framework, and settle
2546
+ * what it spawned — attention tenants end with it; task work is orphaned,
2547
+ * notified and offered for reparenting, and keeps running.
2548
+ *
2549
+ * The default-delivery owner cannot be stopped (the framework needs
2550
+ * exactly one); cancel its activation instead. A persistent agent stopped
2551
+ * here is declared by configuration and returns at the next boot.
2552
+ */
2553
+ stopAgent(name: string, options?: {
2554
+ by?: string;
2555
+ reason?: string;
2556
+ }): EndOutcome;
2557
+ /**
2558
+ * Give an agent a new parent. Clears its orphan state; a result route
2559
+ * whose recipient is gone follows the new parent, and the mail it already
2560
+ * produced for the lost recipient, results and messages, is delivered to
2561
+ * the new one.
2562
+ */
2563
+ reparentAgent(name: string, newParent: string, options?: {
2564
+ by?: string;
2565
+ }): AgentRecord;
2566
+ /**
2567
+ * An explicit message from one agent to another: the sender's verbatim
2568
+ * content, in the recipient's context under the SENDER's name, with the
2569
+ * sender's identity and incarnation and the causal chain in metadata.
2570
+ * Never an unmarked insertion into the recipient's own voice.
2571
+ */
2572
+ sendAgentMessage(from: string, to: string, content: ContentBlock[], options?: {
2573
+ causedBy?: string[];
2574
+ wake?: boolean;
2575
+ }): {
2576
+ mailId: string;
2577
+ delivered: boolean;
2578
+ };
2579
+ /**
2580
+ * Return a bounded job's result along the agent's declared result route.
2581
+ * The result is recorded durably before delivery is attempted, so it is
2582
+ * neither lost nor delivered twice across a restart; if the recipient is
2583
+ * gone it is held as attributed mail until the agent is reparented.
2584
+ *
2585
+ * May be called after the agent's run has ended — its record stays
2586
+ * inspectable. Refused for a `tool-result` route: there the awaiting
2587
+ * caller already holds the result and delivers it itself.
2588
+ */
2589
+ deliverAgentResult(from: string, content: ContentBlock[], options?: {
2590
+ causedBy?: string[];
2591
+ }): {
2592
+ mailId: string;
2593
+ delivered: boolean;
2594
+ to: string;
2595
+ };
2596
+ /** Communications not yet handed to their recipient, and why. */
2597
+ listHeldMail(filter?: {
2598
+ to?: string;
2599
+ from?: string;
2600
+ }): HeldMail[];
2601
+ /**
2602
+ * Try to hand one held item to its recipient. True when the message is in
2603
+ * (or queued for) the recipient's context; false when it stays held
2604
+ * because nobody can receive it. The held copy is released by
2605
+ * `addMessage` at the moment the message enters the store.
2606
+ */
2607
+ private attemptMailDelivery;
2608
+ /**
2609
+ * An ended orphan's result held for a recipient that is gone: its first
2610
+ * adoption candidate is told it exists and how it arrives, since nothing
2611
+ * else would surface it (reparentAgent delivers it).
2612
+ */
2613
+ private tellResultHeld;
2614
+ /** A host-framed lifecycle fact in an agent's context. Never voiced as anyone. */
2615
+ private lifecycleNotice;
2616
+ /**
2617
+ * The creation ("consent") event: names what kind of agent this is, what
2618
+ * ends it and what happens to it when its spawner ends. A derived agent's
2619
+ * creation is also told to the agent it was derived from (#270, Linn:
2620
+ * "told when the body changes" as a property, not a courtesy): one
2621
+ * host-framed line in the source's context, built from the same facts as
2622
+ * the trace, with no wake; a host's derivationNotice can replace the line
2623
+ * or send none. Both derivation paths announce after the
2624
+ * fork's branch or copy exists, so a fork never inherits the notice about
2625
+ * itself; a source that has ended is told nothing (lifecycleNotice).
2626
+ */
2627
+ private announceAgentCreated;
2628
+ /** The derivation notice's text, addressed to the agent `from` the record was derived. */
2629
+ private derivationNotice;
2630
+ /** What a derived agent is, to the agent it was derived from: "a task-fork on your weights, …; …; …". */
2631
+ private derivationDescription;
2632
+ /**
2633
+ * Remove an ended agent's live object from the framework. A bounded run
2634
+ * is ended through its awaiting caller (whose teardown owns the
2635
+ * name-keyed state); any other agent is torn down here.
2636
+ */
2637
+ private teardownEndedAgent;
2638
+ /**
2639
+ * Everything the process holds for a live, non-ephemeral agent that has
2640
+ * ended, released once, on every path an agent ends by — stopAgent, the
2641
+ * idle reap of a conversation fork, an end that cascades from a parent's
2642
+ * (nissa's #546 finding 5: a stop that skipped the window release dropped a
2643
+ * write queued for the agent at the next flush, and a failure notice it
2644
+ * never read reached no one). The window release delivers what the agent
2645
+ * never read to the primary, now or after a resume, as the idle reap did.
2646
+ */
2647
+ private releaseAgentRuntime;
2648
+ /**
2649
+ * Carry out what the registry decided when an agent ended: tear down the
2650
+ * attention tenants that end with it, and tell each orphan — and the
2651
+ * first agent that could adopt it — what happened.
2652
+ */
2653
+ private settleEndedAgent;
2654
+ /** An agent whose spawner has ended, and its first adoption candidate, are told; the trace says so. */
2655
+ private announceOrphaned;
2656
+ /** The registry's snapshot: the recovery file first (atomic, fsynced; it
2657
+ * wins at the next boot), then the branch-local state, kept for inspection
2658
+ * and for stores read by older code. Either write failing fails the call
2659
+ * that changed the registry (nissa's #546 finding 2): a change that isn't
2660
+ * durable isn't a success. */
2661
+ private persistAgentRegistry;
2662
+ /** An ended record: appended to the branch-local log, and the recovery
2663
+ * file rewritten with the newest records (as many as a restart reads). */
2664
+ private appendEndedAgentRecord;
2665
+ /**
2666
+ * A requested change was put back in the registry's memory: the recovery
2667
+ * files, each written before the branch-local store, are rewritten from it
2668
+ * (the snapshot's and the ended log's), so neither keeps the change the
2669
+ * caller was told failed. The branch-local snapshot needs no rewrite: it is
2670
+ * the last write a change makes, so a change that failed never reached it.
2671
+ * The branch-local ended log is append-only, so an end appended before the
2672
+ * failure stays there. It is read at boot only where no ended recovery
2673
+ * file exists (or the rewrite of that file failed too); the restore then
2674
+ * drops a bounded agent it lists as ended for the reason recorded, with no
2675
+ * restart notice to its recipient, while a persistent agent waits to be
2676
+ * re-declared as it would anyway. A rewrite that fails is reported, the
2677
+ * next is still made, and the caller's own error goes on.
2678
+ */
2679
+ private rewriteAgentRegistryAfterRollback;
2680
+ /**
2681
+ * An ended record past the registry's memory, from the branch-local ended
2682
+ * log. A scan of the whole log takes tens of milliseconds at a few thousand
2683
+ * ends, and a name nobody used (a tool call's typo) is a miss, so the log is
2684
+ * indexed by name once, at the first lookup, and each later lookup indexes
2685
+ * only what was appended since. A log that changed under the index (a
2686
+ * branch switch) is indexed again: one that shrank, one whose last indexed
2687
+ * entry is no longer the one indexed, or one whose entry no longer carries
2688
+ * the name indexed for it.
2689
+ */
2690
+ private findEndedAgentRecord;
2691
+ /**
2692
+ * The ended log's latest record whose own context a namespace holds. A
2693
+ * shared fork's record names its parent's namespace, where it owns only a
2694
+ * branch, so it is indexed by name alone.
2695
+ */
2696
+ private findInEndedLog;
2697
+ /** Another agent whose context a namespace holds: opened in this process, in the registry, or in the ended log. */
2698
+ private namespaceHolder;
2699
+ /** The ended log's recovery file, rewritten as the newest records (as many as a restart reads). */
2700
+ private rewriteEndedRecovery;
2701
+ /**
2702
+ * Load the previous process's registry. Returns the bounded work it
2703
+ * interrupted. A registry that can't be read, or that reads as anything
2704
+ * but a version-1 registry, refuses the start and names the state (nissa's
2705
+ * #546 finding 1, main's rule for the framework's own state): taken as
2706
+ * empty, the results it holds for delivery and the records of the work it
2707
+ * ran would be overwritten by this boot's first registration.
2708
+ */
2709
+ private restoreAgentRegistry;
2710
+ /**
2711
+ * Boot reconciliation, once configuration has declared its agents.
2712
+ * Restart behaviour follows from lifetime: persistent agents were just
2713
+ * re-created; everything else that was live was interrupted, and the
2714
+ * recipient of an interrupted job's result is told so. Results held from
2715
+ * before the restart are delivered now, exactly once.
2716
+ */
2717
+ private reconcileAgentRegistry;
2718
+ /**
2719
+ * Deliver held mail that hasn't landed. Its copy may have reached the
2720
+ * recipient's store in the same sync that the release missed, and then it
2721
+ * is released instead; and a write the deferred queue still holds for it
2722
+ * lands at the next flush and releases it then (releaseLandedMail). Either
2723
+ * way a second delivery would put it in the window twice under one mail id.
2724
+ */
2725
+ private deliverHeldMail;
2256
2726
  private createDeferred;
2257
2727
  /** Liveness ping for an active ephemeral run (no-op otherwise). */
2258
2728
  private touchEphemeralRun;
@@ -2310,6 +2780,8 @@ export declare class AgentFramework {
2310
2780
  /** Tune-out (issue #77): divert a channel to your subconscious. Present
2311
2781
  * only when the subconscious resident is configured. */
2312
2782
  private static readonly TUNE_OUT_TOOL;
2783
+ /** `focus`: the resident-facing alias for `tune_out` with scope "all-except" (#232 decision 2). */
2784
+ private static readonly FOCUS_TOOL;
2313
2785
  /** Synthesized sleep/wake tool definitions (present when a gate is wired). */
2314
2786
  private static readonly SLEEP_TOOLS;
2315
2787
  /** Synthesized wake-rule tools: add/remove a gate.json policy at runtime.
@@ -2870,6 +3342,28 @@ export declare class AgentFramework {
2870
3342
  * into the resident's window, which accumulates there.
2871
3343
  */
2872
3344
  private createSubconsciousAgent;
3345
+ /**
3346
+ * `subconscious.reader: 'forks'`: no persistent agent. The coordinator
3347
+ * asks for a fork per invocation (see invokeReaderFork); the config is
3348
+ * kept for the voice block, the speech switch and the strategy factory.
3349
+ */
3350
+ private configureReaderForks;
3351
+ /**
3352
+ * One reader invocation: derive a fork of the resident at its head with
3353
+ * the resident's refusals, hand it the held traffic since the last look
3354
+ * as ordinary framing, and run it. It reports through `deliver_summary`
3355
+ * (attributed mail), may cancel the hold, and ends when its turn ends.
3356
+ */
3357
+ private invokeReaderFork;
3358
+ /**
3359
+ * Held messages still queued behind the resident's turn, as rows of a
3360
+ * reader fork's backlog: each named by its held handle, as module rows name
3361
+ * it until it lands (heldRows), at a provisional sequence past the
3362
+ * resident's last stored message, and timed when it was first held.
3363
+ */
3364
+ private queuedReaderRows;
3365
+ /** A reader fork's own words to the resident: attributed mail when it has a route, else under its name. */
3366
+ private deliverFromReader;
2873
3367
  private runLoop;
2874
3368
  private processNextEvent;
2875
3369
  private handleProcessEvent;
@@ -2895,6 +3389,14 @@ export declare class AgentFramework {
2895
3389
  * Convert an incoming MCPL channel message to a context message.
2896
3390
  * This replaces the old MCPLModule.onProcess() message conversion.
2897
3391
  */
3392
+ /**
3393
+ * A delivered inbound message becomes the latest delivered inbound (the
3394
+ * channel context's reply anchor; the legacy speech fallback) through the
3395
+ * registry's noteDelivered — at once for a plain channels/incoming, whose
3396
+ * acceptance the registry answers synchronously; parked for a coalesced one
3397
+ * until its acceptance is acknowledged (see parkedAnchors).
3398
+ */
3399
+ private noteDeliveredOrPark;
2898
3400
  private handleMcplChannelIncoming;
2899
3401
  /**
2900
3402
  * Route an incoming channel message through the ConversationRouter:
@@ -3185,6 +3687,27 @@ export declare class AgentFramework {
3185
3687
  * channels answer to is never resolved to either.
3186
3688
  */
3187
3689
  private channelNamed;
3690
+ /**
3691
+ * A live agent's home channel, from its registry record (channelOfHome):
3692
+ * defined for a conversation fork, and only for one. Undefined for an agent
3693
+ * with none, and for one that has ended.
3694
+ */
3695
+ private homeOf;
3696
+ /**
3697
+ * The channel a registry record's `homeChannel` names: the channel on its
3698
+ * server. A bare channel id, as a record written before homes carried
3699
+ * their server keeps, is read as a wake that names its channel without its
3700
+ * server is (channelNamed): the one registered channel it names, read when
3701
+ * it's used, since the servers registered at that moment are what it can
3702
+ * mean. An id that names no one registered channel, as one no server
3703
+ * registers now or two servers do, is the home on no server (an empty
3704
+ * serverId, which channelNamed reads as none given), so the agent keeps a
3705
+ * home. A path that reads the pair finds no server registering it, and
3706
+ * refuses it; one that reads the name reads what the name means then: none
3707
+ * or two channels, which it refuses, or, once one server alone registers
3708
+ * the id, that server's channel.
3709
+ */
3710
+ private channelOfHome;
3188
3711
  /**
3189
3712
  * Explicit mode's typing channel for one start of a turn, which has no
3190
3713
  * locus, read once as the start opens (driveStream then shows what the
@@ -3225,6 +3748,23 @@ export declare class AgentFramework {
3225
3748
  * it takes their agent up (passRequests). */
3226
3749
  private processInferenceRequests;
3227
3750
  private runInferencePass;
3751
+ /**
3752
+ * `channel_publish` with no channel goes where the turn's plain speech
3753
+ * would: the frozen turn locus (the waking delivery's channel, or one
3754
+ * opened this turn), then the registry's own resolution. Under
3755
+ * `speech.locus: 'delivery'` the registry alone has no default, and the
3756
+ * tool failed on the very turn its own delivery woke (first live run,
3757
+ * 2026-10-12). Both dispatch paths — the stream driver's and
3758
+ * executeToolCall's — pass through here. Only a call made inside the turn
3759
+ * (callingTurnOf) takes the turn's locus: one made outside it, as a script
3760
+ * left running after its turn makes or a host's executeToolCall naming the
3761
+ * agent, takes none of the turn's channels. A conversation fork's home
3762
+ * isn't the turn's but the fork's own, so such a call from a fork naming
3763
+ * no channel still goes there (homeOf), as the fork's dispatched calls do
3764
+ * (dispatchChannelToolCall); anyone else's takes the registry's own
3765
+ * default.
3766
+ */
3767
+ private publishInputWithTurnLocus;
3228
3768
  /**
3229
3769
  * Stamps for the rows the agent's reply stores in its current turn: its
3230
3770
  * assistant responses, its tool_result rows (through `storeResults`), and
@@ -3426,14 +3966,20 @@ export declare class AgentFramework {
3426
3966
  * announced baseline alone (announceLocusIfChanged).
3427
3967
  */
3428
3968
  private noticeHeartbeatTurn;
3969
+ private rememberAnnouncedLocus;
3970
+ private forgetAnnouncedLocus;
3971
+ /** The stored baseline's entry for the agent set (rememberAnnouncedLocus),
3972
+ * or removed (undefined) when the agent ends without coming back. */
3973
+ private writeAnnouncedLocus;
3429
3974
  /**
3430
3975
  * Announce-on-change locus notice (turn-frozen routing). Appends a durable
3431
3976
  * `[routing]` window message when the turn's effective outbound locus
3432
3977
  * differs from the last one announced — the agent must never have to guess
3433
3978
  * 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
3979
+ * KV prefix stable; change-only keeps it out of steady-state turns. An
3980
+ * agent never told of a locus, here or before a restart, hears only of a
3981
+ * non-null one ("prose has no destination" is the unremarkable start).
3982
+ * Never triggers
3437
3983
  * inference; never locus-eligible itself (system + no channel metadata).
3438
3984
  */
3439
3985
  private announceLocusIfChanged;
@@ -3445,7 +3991,11 @@ export declare class AgentFramework {
3445
3991
  * as the agent's first view) that addressed the agent, or that follows up
3446
3992
  * in a channel the turn sent into (TurnRouting.engaged). Undefined for any
3447
3993
  * other message. A tool boundary weighs the messages it injects by it,
3448
- * and noteArrival the ones no boundary of the turn weighs.
3994
+ * and noteArrival the ones no boundary of the turn weighs. The rule is
3995
+ * pure; what is done with its answer is `speech.locus`'s: under
3996
+ * `'latest-inbound'` the locus moves, under `'delivery'` (the default) the
3997
+ * agent is told it was addressed from elsewhere and the locus stays
3998
+ * (addressedElsewhereNotice).
3449
3999
  */
3450
4000
  private repinChannel;
3451
4001
  /** Whether `agent` has a turn alive: starting, streaming or waiting on its tools. */
@@ -3544,13 +4094,15 @@ export declare class AgentFramework {
3544
4094
  * Weigh a message that no tool boundary of the agent's open logical turn
3545
4095
  * will weigh: one that would re-pin the locus becomes one of the turn's
3546
4096
  * 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.
4097
+ * out (agentSees), such as one held from the residents (heldFromResidents,
4098
+ * the admission stage's one predicate, which every resident's view filter
4099
+ * reads) or another agent's stored context injection, never enters its
4100
+ * compiled view, so the agent won't see it, and it moves nothing.
3549
4101
  */
3550
4102
  private noteArrival;
3551
4103
  /**
3552
4104
  * Whether `agent`'s store is the residents' one message slot, which every
3553
- * ordinary resident reads (sharedSlotAgents). The subconscious reads that
4105
+ * ordinary resident reads (`readsSharedSlot` in the registry). The subconscious reads that
3554
4106
  * slot through a merged view, but its own store is isolated, as a fork's
3555
4107
  * or an ephemeral agent's is.
3556
4108
  */
@@ -3591,6 +4143,23 @@ export declare class AgentFramework {
3591
4143
  * so the agent's next turn announces where its speech lands.
3592
4144
  */
3593
4145
  private repinTurnLocus;
4146
+ /**
4147
+ * Under `speech.locus: 'delivery'`: tell the agent that someone addressed
4148
+ * it from another channel while its turn was busy, since incoming traffic
4149
+ * never moves the locus and a neutral message carries nothing that names
4150
+ * its channel (first live run, 2026-10-12, finding C). Once per channel
4151
+ * per turn (TurnRouting.addressedElsewhere); nothing for the turn's own
4152
+ * locus. Stored durably; returned as stored for a live stream to inject
4153
+ * with its boundary's other messages. Undefined when nothing was stored.
4154
+ */
4155
+ private addressedElsewhereNotice;
4156
+ /**
4157
+ * The arrivals a start of the turn consumes under `speech.locus:
4158
+ * 'delivery'`: each one that addressed the agent, whose message is still
4159
+ * in the store, gets the addressed-elsewhere notice, oldest first. A
4160
+ * follow-up in an engaged channel addressed nobody and is not announced.
4161
+ */
4162
+ private noticeAddressedArrivals;
3594
4163
  /**
3595
4164
  * Durable window notice for a channel the agent did not ask to open: a
3596
4165
  * subscription-policy admission, announced as the decision before its
@@ -4041,8 +4610,10 @@ export declare class AgentFramework {
4041
4610
  * (ctx.callTool → executeToolCallFrom with {kind:'module'}), which is exempt
4042
4611
  * from agent allowlists. Registered agents' allowedTools is enforced at
4043
4612
  * 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.
4613
+ * unknown legacy names) remain unrestricted. A name the framework made in
4614
+ * this process is refused while it isn't registered, even if its configured
4615
+ * list allows the tool; after a restart, such a name is a host's caller name
4616
+ * like any other.
4046
4617
  */
4047
4618
  executeToolCall(call: ToolCall): Promise<ToolResult>;
4048
4619
  /**
@@ -4107,6 +4678,29 @@ export declare class AgentFramework {
4107
4678
  * tool it makes, under that tool's model-facing name and with its
4108
4679
  * arguments, its id kept; or the reason it can't be sent. */
4109
4680
  private resolveToolsetAct;
4681
+ /**
4682
+ * A reader reads and reports: a reader fork (registry kind
4683
+ * 'subconscious-fork', in every incarnation) may call only its own tools,
4684
+ * and speak_in_channel where allowChannelSpeech allows it. Every other
4685
+ * tool the resident has stays in its block (the shared prefix) and is
4686
+ * refused here, so with speech off a fork can post nowhere (scout's
4687
+ * condition, 2026-10-19). It's decided at each call from what the reader
4688
+ * may call, not from what it is shown, so a tool added or moved out of
4689
+ * the block later is refused too.
4690
+ */
4691
+ private readerRefuses;
4692
+ /**
4693
+ * What a reader fork may call: exactly its own tools and the speech its
4694
+ * configuration allows, never widened or narrowed by its resident's
4695
+ * allowedTools. The resident's list bounds the resident's own surface;
4696
+ * the reader's tools are the framework's, for reading on its behalf. A
4697
+ * denyToolsAtDispatch entry the fork takes from its resident that names
4698
+ * one of them still refuses it (mayCallTool checks the deny first): a
4699
+ * resident never holds a reader tool, so such an entry is about readers.
4700
+ * The fork still shows its resident's block (the shared prefix): what it
4701
+ * may call is decided here, at each call, apart from what it is shown.
4702
+ */
4703
+ private readerMayCall;
4110
4704
  /** A toolsets--act call a host toolset resolved (HostPresentation.resolveAct):
4111
4705
  * its refusal answered, or the tool's own call dispatched in its place,
4112
4706
  * with the act's id, so its result is the act's. */
@@ -4456,9 +5050,15 @@ export declare class AgentFramework {
4456
5050
  * that. Never prefix-map insertion order.
4457
5051
  */
4458
5052
  private resolveMcplTool;
4459
- /** Registered policy; framework-created identities have no dispatch authority
4460
- * while unregistered. Genuine legacy caller names retain their surface. */
5053
+ /** Registered policy. Within this process, a name the framework made has no
5054
+ * dispatch authority while it isn't registered; after a restart, a host call names
5055
+ * its caller as any host call does. Genuine legacy caller names retain
5056
+ * their surface. */
4461
5057
  private canAgentUseTool;
5058
+ /** Whether a call of `toolName` as `agentName` is refused at dispatch (AgentConfig.denyToolsAtDispatch, or a reader's own rule). */
5059
+ private deniedAtDispatch;
5060
+ /** Whether `agentName` may call `toolName`: the one rule dispatch applies (agentToolPermissionFailure), for whatever else judges a call. */
5061
+ private mayCallTool;
4462
5062
  private agentToolPermissionFailure;
4463
5063
  private markedInputFailure;
4464
5064
  private cutOffResults;
@@ -4571,6 +5171,14 @@ export declare class AgentFramework {
4571
5171
  * the start now beginning (no tool boundary will weigh it), and one for
4572
5172
  * every other resident's open turn. */
4573
5173
  private noteStored;
5174
+ /**
5175
+ * Held agent mail is released only when its message has actually entered
5176
+ * the recipient's store — never on a deferral. Called at every site that
5177
+ * writes a message into a context: the direct path above and the two
5178
+ * deferred-write flushes (turn start, tool boundary). Both writes reach
5179
+ * disk in the same sync, so a crash keeps either both or neither.
5180
+ */
5181
+ private releaseLandedMail;
4574
5182
  /**
4575
5183
  * Splice out the deferred messages addressed to `agentName` (explicitly
4576
5184
  * via forAgent, or implicitly when it is the primary), leaving other
@@ -5008,7 +5616,7 @@ export declare class AgentFramework {
5008
5616
  * The writes the framework holds for the store `reader` reads, in queue
5009
5617
  * order: those addressed to it and, when it's an ordinary resident, those
5010
5618
  * addressed to any ordinary resident, since residents share one message
5011
- * slot (sharedSlotAgents). A write whose target is gone isn't among them:
5619
+ * slot (`readsSharedSlot` in the registry). A write whose target is gone isn't among them:
5012
5620
  * no module reads that agent's store, and the write waits for its window's
5013
5621
  * release (drainDeferredFor) or, at its flush, is dropped (addMessage), a
5014
5622
  * failed reply, or a channel notice its reader could act on, passing to the
@@ -5944,6 +6552,15 @@ export declare class AgentFramework {
5944
6552
  * error and nothing is written.
5945
6553
  */
5946
6554
  private dispatchWakeRuleToolCall;
6555
+ /**
6556
+ * A reader's own tool (SUBCONSCIOUS_TOOL_NAMES), for both entries that run
6557
+ * an agent's call: the dispatcher's, for the model's call, and
6558
+ * executeToolCallFrom's, for a host's or the puppet's. The tools are
6559
+ * advertised to residents so reader forks share their prefix, and only a
6560
+ * registered reader may use them. A rejection is answered with a failed
6561
+ * result, never left unhandled.
6562
+ */
6563
+ private readerToolCall;
5947
6564
  /**
5948
6565
  * Handle the synthesized `sleep` / `wake` tools. `sleep` arms the gate's
5949
6566
  * suppression window, optionally announces in the sticky channel, and ends
@@ -5951,6 +6568,40 @@ export declare class AgentFramework {
5951
6568
  */
5952
6569
  /** tune_out tool (residents): enter or cancel a channel tune-out. */
5953
6570
  private dispatchTuneOutToolCall;
6571
+ /** `focus` is `tune_out` with scope "all-except". */
6572
+ private handleFocusTool;
6573
+ /**
6574
+ * A tune-out call's refusal for a channel it can't resolve: main's words
6575
+ * for a name no registered channel, and none of the calling turn's own,
6576
+ * answers to, and the registry's own otherwise, as for an id that is
6577
+ * ambiguous across servers (#232 gap 8).
6578
+ */
6579
+ private unknownChannelWords;
6580
+ /**
6581
+ * The tune_out tool's body. Channel resolution is server-qualified
6582
+ * (ChannelRegistry.resolveChannel): with a `serverId`, that server's
6583
+ * channel with the id; inside the calling turn, a name one of the turn's
6584
+ * own channels answers to by its id means that channel; otherwise the one
6585
+ * channel the name means, which may be server-qualified, and a name two
6586
+ * servers' channels answer to is refused with them as candidates (#232
6587
+ * gap 8). `turn` is the turn that made the call (callingTurnOf), the only
6588
+ * one whose speech an all-except entry moves.
6589
+ */
6590
+ private handleTuneOutTool;
6591
+ /**
6592
+ * The admission stage for one inbound event: the pure decision over the
6593
+ * framework's policy inputs (recipients, the hold in force, the wake
6594
+ * gate), traced. Callers apply it; nothing downstream re-asks.
6595
+ */
6596
+ private admitInbound;
6597
+ /**
6598
+ * Make delivered messages durable now, including those the delivery left
6599
+ * in the deferred queue: a tune-out release flips durable epoch state
6600
+ * first, so its dump must not be lost to a crash in between (#232 gap 6).
6601
+ */
6602
+ private commitDeliveries;
6603
+ /** The history-reading tool the primary resident actually has, if any (#232 gap 11). */
6604
+ private residentHistoryTool;
5954
6605
  private dispatchSleepToolCall;
5955
6606
  /**
5956
6607
  * Handle the synthesized `read_image` tool: read image bytes from a