@animalabs/agent-framework 0.31.0 → 0.33.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 (298) hide show
  1. package/README.md +204 -14
  2. package/dist/src/admission/admit.d.ts +18 -0
  3. package/dist/src/admission/admit.d.ts.map +1 -1
  4. package/dist/src/admission/admit.js +16 -3
  5. package/dist/src/admission/admit.js.map +1 -1
  6. package/dist/src/agent.d.ts +185 -78
  7. package/dist/src/agent.d.ts.map +1 -1
  8. package/dist/src/agent.js +279 -102
  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 +50 -12
  12. package/dist/src/api/mcp-server-core.js.map +1 -1
  13. package/dist/src/api/server.d.ts.map +1 -1
  14. package/dist/src/api/server.js +4 -20
  15. package/dist/src/api/server.js.map +1 -1
  16. package/dist/src/code-execution/isolate/scripts.d.ts +12 -8
  17. package/dist/src/code-execution/isolate/scripts.d.ts.map +1 -1
  18. package/dist/src/code-execution/isolate/scripts.js +24 -0
  19. package/dist/src/code-execution/isolate/scripts.js.map +1 -1
  20. package/dist/src/config-checks.d.ts +7 -0
  21. package/dist/src/config-checks.d.ts.map +1 -1
  22. package/dist/src/config-checks.js +14 -0
  23. package/dist/src/config-checks.js.map +1 -1
  24. package/dist/src/context-manager-errors.d.ts +25 -0
  25. package/dist/src/context-manager-errors.d.ts.map +1 -0
  26. package/dist/src/context-manager-errors.js +31 -0
  27. package/dist/src/context-manager-errors.js.map +1 -0
  28. package/dist/src/context-options.d.ts +67 -0
  29. package/dist/src/context-options.d.ts.map +1 -0
  30. package/dist/src/context-options.js +85 -0
  31. package/dist/src/context-options.js.map +1 -0
  32. package/dist/src/deferred-import.d.ts +93 -0
  33. package/dist/src/deferred-import.d.ts.map +1 -0
  34. package/dist/src/deferred-import.js +177 -0
  35. package/dist/src/deferred-import.js.map +1 -0
  36. package/dist/src/dendrite/audience.d.ts +223 -0
  37. package/dist/src/dendrite/audience.d.ts.map +1 -0
  38. package/dist/src/dendrite/audience.js +202 -0
  39. package/dist/src/dendrite/audience.js.map +1 -0
  40. package/dist/src/dendrite/index.d.ts +5 -3
  41. package/dist/src/dendrite/index.d.ts.map +1 -1
  42. package/dist/src/dendrite/index.js +2 -1
  43. package/dist/src/dendrite/index.js.map +1 -1
  44. package/dist/src/dendrite/presets.d.ts +10 -5
  45. package/dist/src/dendrite/presets.d.ts.map +1 -1
  46. package/dist/src/dendrite/presets.js +17 -5
  47. package/dist/src/dendrite/presets.js.map +1 -1
  48. package/dist/src/dendrite/registry.d.ts +62 -7
  49. package/dist/src/dendrite/registry.d.ts.map +1 -1
  50. package/dist/src/dendrite/registry.js +179 -10
  51. package/dist/src/dendrite/registry.js.map +1 -1
  52. package/dist/src/dendrite/types.d.ts +91 -8
  53. package/dist/src/dendrite/types.d.ts.map +1 -1
  54. package/dist/src/foreign-rounds.d.ts +69 -0
  55. package/dist/src/foreign-rounds.d.ts.map +1 -0
  56. package/dist/src/foreign-rounds.js +152 -0
  57. package/dist/src/foreign-rounds.js.map +1 -0
  58. package/dist/src/framework.d.ts +1977 -820
  59. package/dist/src/framework.d.ts.map +1 -1
  60. package/dist/src/framework.js +7571 -3457
  61. package/dist/src/framework.js.map +1 -1
  62. package/dist/src/gate/event-gate.d.ts +85 -15
  63. package/dist/src/gate/event-gate.d.ts.map +1 -1
  64. package/dist/src/gate/event-gate.js +421 -47
  65. package/dist/src/gate/event-gate.js.map +1 -1
  66. package/dist/src/gate/index.d.ts +1 -1
  67. package/dist/src/gate/index.d.ts.map +1 -1
  68. package/dist/src/gate/index.js.map +1 -1
  69. package/dist/src/gate/rule-scope.d.ts +30 -0
  70. package/dist/src/gate/rule-scope.d.ts.map +1 -0
  71. package/dist/src/gate/rule-scope.js +41 -0
  72. package/dist/src/gate/rule-scope.js.map +1 -0
  73. package/dist/src/gate/suppress-script-worker.d.ts +2 -0
  74. package/dist/src/gate/suppress-script-worker.d.ts.map +1 -0
  75. package/dist/src/gate/suppress-script-worker.js +103 -0
  76. package/dist/src/gate/suppress-script-worker.js.map +1 -0
  77. package/dist/src/gate/suppress-scripts.d.ts +105 -0
  78. package/dist/src/gate/suppress-scripts.d.ts.map +1 -0
  79. package/dist/src/gate/suppress-scripts.js +403 -0
  80. package/dist/src/gate/suppress-scripts.js.map +1 -0
  81. package/dist/src/gate/suppression-review.d.ts +143 -0
  82. package/dist/src/gate/suppression-review.d.ts.map +1 -0
  83. package/dist/src/gate/suppression-review.js +463 -0
  84. package/dist/src/gate/suppression-review.js.map +1 -0
  85. package/dist/src/gate/suppression-stats.d.ts +125 -0
  86. package/dist/src/gate/suppression-stats.d.ts.map +1 -0
  87. package/dist/src/gate/suppression-stats.js +214 -0
  88. package/dist/src/gate/suppression-stats.js.map +1 -0
  89. package/dist/src/gate/types.d.ts +135 -7
  90. package/dist/src/gate/types.d.ts.map +1 -1
  91. package/dist/src/gate/wake-onboarding.d.ts +119 -0
  92. package/dist/src/gate/wake-onboarding.d.ts.map +1 -0
  93. package/dist/src/gate/wake-onboarding.js +277 -0
  94. package/dist/src/gate/wake-onboarding.js.map +1 -0
  95. package/dist/src/held-writes.d.ts +31 -23
  96. package/dist/src/held-writes.d.ts.map +1 -1
  97. package/dist/src/held-writes.js +44 -59
  98. package/dist/src/held-writes.js.map +1 -1
  99. package/dist/src/index.d.ts +5 -2
  100. package/dist/src/index.d.ts.map +1 -1
  101. package/dist/src/index.js +3 -0
  102. package/dist/src/index.js.map +1 -1
  103. package/dist/src/jsonrpc-envelope.d.ts +69 -0
  104. package/dist/src/jsonrpc-envelope.d.ts.map +1 -0
  105. package/dist/src/jsonrpc-envelope.js +66 -0
  106. package/dist/src/jsonrpc-envelope.js.map +1 -0
  107. package/dist/src/mcpl/channel-registry.d.ts +131 -15
  108. package/dist/src/mcpl/channel-registry.d.ts.map +1 -1
  109. package/dist/src/mcpl/channel-registry.js +290 -46
  110. package/dist/src/mcpl/channel-registry.js.map +1 -1
  111. package/dist/src/mcpl/checkpoint-manager.d.ts +2 -4
  112. package/dist/src/mcpl/checkpoint-manager.d.ts.map +1 -1
  113. package/dist/src/mcpl/checkpoint-manager.js.map +1 -1
  114. package/dist/src/mcpl/feature-set-manager.d.ts +2 -4
  115. package/dist/src/mcpl/feature-set-manager.d.ts.map +1 -1
  116. package/dist/src/mcpl/feature-set-manager.js.map +1 -1
  117. package/dist/src/mcpl/inbound-source.d.ts +2 -1
  118. package/dist/src/mcpl/inbound-source.d.ts.map +1 -1
  119. package/dist/src/mcpl/inbound-source.js +2 -1
  120. package/dist/src/mcpl/inbound-source.js.map +1 -1
  121. package/dist/src/mcpl/inference-router.d.ts +6 -6
  122. package/dist/src/mcpl/inference-router.d.ts.map +1 -1
  123. package/dist/src/mcpl/inference-router.js.map +1 -1
  124. package/dist/src/mcpl/push-coalescer.d.ts +132 -22
  125. package/dist/src/mcpl/push-coalescer.d.ts.map +1 -1
  126. package/dist/src/mcpl/push-coalescer.js +105 -15
  127. package/dist/src/mcpl/push-coalescer.js.map +1 -1
  128. package/dist/src/mcpl/push-handler.d.ts +9 -7
  129. package/dist/src/mcpl/push-handler.d.ts.map +1 -1
  130. package/dist/src/mcpl/push-handler.js.map +1 -1
  131. package/dist/src/mcpl/server-connection.d.ts +13 -10
  132. package/dist/src/mcpl/server-connection.d.ts.map +1 -1
  133. package/dist/src/mcpl/server-connection.js +134 -56
  134. package/dist/src/mcpl/server-connection.js.map +1 -1
  135. package/dist/src/mcpl/tool-classes.d.ts.map +1 -1
  136. package/dist/src/mcpl/tool-classes.js +3 -0
  137. package/dist/src/mcpl/tool-classes.js.map +1 -1
  138. package/dist/src/mcpl/types.d.ts +8 -2
  139. package/dist/src/mcpl/types.d.ts.map +1 -1
  140. package/dist/src/mcpl/types.js.map +1 -1
  141. package/dist/src/module-registry.d.ts +24 -1
  142. package/dist/src/module-registry.d.ts.map +1 -1
  143. package/dist/src/module-registry.js +68 -18
  144. package/dist/src/module-registry.js.map +1 -1
  145. package/dist/src/modules/discord/index.d.ts +45 -8
  146. package/dist/src/modules/discord/index.d.ts.map +1 -1
  147. package/dist/src/modules/discord/index.js +237 -86
  148. package/dist/src/modules/discord/index.js.map +1 -1
  149. package/dist/src/modules/history/index.d.ts +59 -0
  150. package/dist/src/modules/history/index.d.ts.map +1 -1
  151. package/dist/src/modules/history/index.js +432 -67
  152. package/dist/src/modules/history/index.js.map +1 -1
  153. package/dist/src/modules/history/semantic.d.ts +6 -5
  154. package/dist/src/modules/history/semantic.d.ts.map +1 -1
  155. package/dist/src/modules/history/semantic.js +15 -22
  156. package/dist/src/modules/history/semantic.js.map +1 -1
  157. package/dist/src/modules/workspace/disk-agreement.d.ts +1 -1
  158. package/dist/src/modules/workspace/disk-agreement.js +1 -1
  159. package/dist/src/modules/workspace/index.d.ts +28 -7
  160. package/dist/src/modules/workspace/index.d.ts.map +1 -1
  161. package/dist/src/modules/workspace/index.js +76 -22
  162. package/dist/src/modules/workspace/index.js.map +1 -1
  163. package/dist/src/notice-tags.d.ts +10 -1
  164. package/dist/src/notice-tags.d.ts.map +1 -1
  165. package/dist/src/notice-tags.js +10 -1
  166. package/dist/src/notice-tags.js.map +1 -1
  167. package/dist/src/operator-log.d.ts +36 -3
  168. package/dist/src/operator-log.d.ts.map +1 -1
  169. package/dist/src/operator-log.js +2 -2
  170. package/dist/src/operator-log.js.map +1 -1
  171. package/dist/src/presentation.d.ts +746 -0
  172. package/dist/src/presentation.d.ts.map +1 -0
  173. package/dist/src/presentation.js +1435 -0
  174. package/dist/src/presentation.js.map +1 -0
  175. package/dist/src/prose-drafts.d.ts +15 -11
  176. package/dist/src/prose-drafts.d.ts.map +1 -1
  177. package/dist/src/prose-drafts.js +16 -12
  178. package/dist/src/prose-drafts.js.map +1 -1
  179. package/dist/src/read-marks.d.ts +192 -0
  180. package/dist/src/read-marks.d.ts.map +1 -0
  181. package/dist/src/read-marks.js +242 -0
  182. package/dist/src/read-marks.js.map +1 -0
  183. package/dist/src/recovery/offline-branch.d.ts +91 -6
  184. package/dist/src/recovery/offline-branch.d.ts.map +1 -1
  185. package/dist/src/recovery/offline-branch.js +273 -29
  186. package/dist/src/recovery/offline-branch.js.map +1 -1
  187. package/dist/src/recovery/recover-cli.js +22 -3
  188. package/dist/src/recovery/recover-cli.js.map +1 -1
  189. package/dist/src/send-tools.d.ts +5 -9
  190. package/dist/src/send-tools.d.ts.map +1 -1
  191. package/dist/src/send-tools.js +40 -7
  192. package/dist/src/send-tools.js.map +1 -1
  193. package/dist/src/stored-injections.d.ts +2 -2
  194. package/dist/src/stored-injections.js +2 -2
  195. package/dist/src/stored-removal.d.ts +17 -4
  196. package/dist/src/stored-removal.d.ts.map +1 -1
  197. package/dist/src/stored-removal.js +29 -5
  198. package/dist/src/stored-removal.js.map +1 -1
  199. package/dist/src/tool-result-guard.d.ts +12 -1
  200. package/dist/src/tool-result-guard.d.ts.map +1 -1
  201. package/dist/src/tool-result-guard.js +42 -8
  202. package/dist/src/tool-result-guard.js.map +1 -1
  203. package/dist/src/tune-out/coordinator.d.ts +1159 -79
  204. package/dist/src/tune-out/coordinator.d.ts.map +1 -1
  205. package/dist/src/tune-out/coordinator.js +3709 -363
  206. package/dist/src/tune-out/coordinator.js.map +1 -1
  207. package/dist/src/tune-out/tools.d.ts +114 -17
  208. package/dist/src/tune-out/tools.d.ts.map +1 -1
  209. package/dist/src/tune-out/tools.js +87 -27
  210. package/dist/src/tune-out/tools.js.map +1 -1
  211. package/dist/src/tune-out/window-anchor.d.ts +143 -0
  212. package/dist/src/tune-out/window-anchor.d.ts.map +1 -0
  213. package/dist/src/tune-out/window-anchor.js +202 -0
  214. package/dist/src/tune-out/window-anchor.js.map +1 -0
  215. package/dist/src/types/agent.d.ts +86 -31
  216. package/dist/src/types/agent.d.ts.map +1 -1
  217. package/dist/src/types/events.d.ts +2 -0
  218. package/dist/src/types/events.d.ts.map +1 -1
  219. package/dist/src/types/framework.d.ts +43 -21
  220. package/dist/src/types/framework.d.ts.map +1 -1
  221. package/dist/src/types/module.d.ts +180 -69
  222. package/dist/src/types/module.d.ts.map +1 -1
  223. package/dist/src/types/trace.d.ts +510 -36
  224. package/dist/src/types/trace.d.ts.map +1 -1
  225. package/package.json +3 -3
  226. package/src/admission/admit.ts +32 -3
  227. package/src/agent.ts +323 -120
  228. package/src/api/mcp-server-core.ts +54 -17
  229. package/src/api/server.ts +4 -23
  230. package/src/code-execution/isolate/scripts.ts +28 -3
  231. package/src/config-checks.ts +14 -0
  232. package/src/context-manager-errors.ts +37 -0
  233. package/src/context-options.ts +96 -0
  234. package/src/deferred-import.ts +239 -0
  235. package/src/dendrite/audience.ts +315 -0
  236. package/src/dendrite/index.ts +14 -2
  237. package/src/dendrite/presets.ts +18 -6
  238. package/src/dendrite/registry.ts +209 -12
  239. package/src/dendrite/types.ts +92 -8
  240. package/src/foreign-rounds.ts +199 -0
  241. package/src/framework.ts +7814 -3585
  242. package/src/gate/event-gate.ts +428 -65
  243. package/src/gate/index.ts +3 -0
  244. package/src/gate/rule-scope.ts +45 -0
  245. package/src/gate/suppress-script-worker.ts +89 -0
  246. package/src/gate/suppress-scripts.ts +414 -0
  247. package/src/gate/suppression-review.ts +517 -0
  248. package/src/gate/suppression-stats.ts +314 -0
  249. package/src/gate/types.ts +141 -7
  250. package/src/gate/wake-onboarding.ts +309 -0
  251. package/src/held-writes.ts +49 -60
  252. package/src/index.ts +9 -2
  253. package/src/jsonrpc-envelope.ts +81 -0
  254. package/src/mcpl/channel-registry.ts +353 -85
  255. package/src/mcpl/checkpoint-manager.ts +3 -2
  256. package/src/mcpl/feature-set-manager.ts +2 -1
  257. package/src/mcpl/inbound-source.ts +2 -1
  258. package/src/mcpl/inference-router.ts +7 -4
  259. package/src/mcpl/push-coalescer.ts +193 -34
  260. package/src/mcpl/push-handler.ts +10 -5
  261. package/src/mcpl/server-connection.ts +141 -60
  262. package/src/mcpl/tool-classes.ts +3 -0
  263. package/src/mcpl/types.ts +8 -2
  264. package/src/module-registry.ts +73 -17
  265. package/src/modules/discord/index.ts +229 -81
  266. package/src/modules/history/index.ts +439 -70
  267. package/src/modules/history/semantic.ts +15 -21
  268. package/src/modules/workspace/disk-agreement.ts +1 -1
  269. package/src/modules/workspace/index.ts +85 -23
  270. package/src/notice-tags.ts +10 -1
  271. package/src/operator-log.ts +36 -3
  272. package/src/presentation.ts +1676 -0
  273. package/src/prose-drafts.ts +16 -12
  274. package/src/read-marks.ts +328 -0
  275. package/src/recovery/offline-branch.ts +346 -32
  276. package/src/recovery/recover-cli.ts +21 -3
  277. package/src/send-tools.ts +40 -7
  278. package/src/stored-injections.ts +2 -2
  279. package/src/stored-removal.ts +31 -7
  280. package/src/tool-result-guard.ts +41 -7
  281. package/src/tune-out/coordinator.ts +4089 -457
  282. package/src/tune-out/tools.ts +160 -43
  283. package/src/tune-out/window-anchor.ts +277 -0
  284. package/src/types/agent.ts +90 -31
  285. package/src/types/events.ts +2 -0
  286. package/src/types/framework.ts +43 -21
  287. package/src/types/module.ts +181 -68
  288. package/src/types/trace.ts +542 -40
  289. package/dist/src/reasoning-loss-notice.d.ts +0 -23
  290. package/dist/src/reasoning-loss-notice.d.ts.map +0 -1
  291. package/dist/src/reasoning-loss-notice.js +0 -52
  292. package/dist/src/reasoning-loss-notice.js.map +0 -1
  293. package/dist/src/reasoning-loss.d.ts +0 -24
  294. package/dist/src/reasoning-loss.d.ts.map +0 -1
  295. package/dist/src/reasoning-loss.js +0 -102
  296. package/dist/src/reasoning-loss.js.map +0 -1
  297. package/src/reasoning-loss-notice.ts +0 -64
  298. package/src/reasoning-loss.ts +0 -120
package/src/send-tools.ts CHANGED
@@ -1,12 +1,45 @@
1
1
  /**
2
- * Tools whose call delivers the resident's message to a channel or person,
3
- * by bare name (an MCPL server's `<prefix>--` stripped). The framework reads
4
- * a call of one as an explicit send that silences the round's auto-routed
5
- * prose where it may have posted; the history module's semantic index reads
6
- * its message argument as what the resident wrote to someone, whether or not
7
- * it was delivered.
2
+ * Tools whose call carries the resident's words, by bare name (an MCPL
3
+ * server's `<prefix>--` stripped); edit_message's words are the new text of a
4
+ * message it sent. The framework reads a call of a `silences` one as an
5
+ * explicit send that silences the round's auto-routed prose where it may have
6
+ * posted; the history module reads the words of any of them as what the
7
+ * resident wrote to someone, whether or not it was delivered. With prose
8
+ * routing disabled the resident speaks through these.
8
9
  */
9
- export const SEND_TOOLS = new Set(['channel_publish', 'send_message', 'reply_message', 'send_dm']);
10
+ const SPEECH_TOOLS: ReadonlyMap<string, { words: readonly string[]; silences: boolean }> = new Map([
11
+ // channel_publish still takes `text` from older callers.
12
+ ['channel_publish', { words: ['content', 'text'], silences: true }],
13
+ // telegram-mcpl's send_message takes `message`.
14
+ ['send_message', { words: ['content', 'message', 'text'], silences: true }],
15
+ ['reply_message', { words: ['content', 'text'], silences: true }],
16
+ ['send_dm', { words: ['content', 'text'], silences: true }],
17
+ // telegram-mcpl's reply, file send, scheduled send and poll.
18
+ ['reply_to_message', { words: ['text'], silences: true }],
19
+ ['send_file', { words: ['caption'], silences: false }],
20
+ ['send_scheduled_message', { words: ['message'], silences: false }],
21
+ ['create_poll', { words: ['question'], silences: false }],
22
+ // telegram-mcpl's edit_message takes `new_text`.
23
+ ['edit_message', { words: ['content', 'new_text', 'text'], silences: false }],
24
+ // slack-mcpl's upload_file posts `comment` with the file; its `content` is
25
+ // the file.
26
+ ['upload_file', { words: ['comment'], silences: false }],
27
+ // Eidoverse's say and whisper take `text`.
28
+ ['say', { words: ['text'], silences: true }],
29
+ ['whisper', { words: ['text'], silences: true }],
30
+ ]);
31
+
32
+ export const SILENCING_SENDS = new Set([...SPEECH_TOOLS].filter(([, tool]) => tool.silences).map(([name]) => name));
10
33
 
11
34
  /** Strip the `server--` MCPL prefix from a tool name. */
12
35
  export const bareToolName = (n: string): string => n.split('--').pop()!;
36
+
37
+ export function speechOf(name: unknown, input: unknown): { tool: string; words: string } | undefined {
38
+ if (typeof name !== 'string' || typeof input !== 'object' || input === null) return undefined;
39
+ const tool = bareToolName(name);
40
+ const row = SPEECH_TOOLS.get(tool);
41
+ if (!row) return undefined;
42
+ const args = input as Record<string, unknown>;
43
+ const words = row.words.map((arg) => args[arg]).find((value) => value !== undefined && value !== null);
44
+ return typeof words === 'string' && words.trim().length > 0 ? { tool, words } : undefined;
45
+ }
@@ -14,8 +14,8 @@
14
14
  * a start stored whose compile then didn't record) has the same content,
15
15
  * every part of it, and the compile
16
16
  * then renders
17
- * it from the store like any message, where it stays. While the window is
18
- * held (AgentFramework's slotHeldFrom), `compile()` places it instead. Being a
17
+ * it from the store like any message, where it stays. While the host is
18
+ * quiesced, `compile()` places it instead. Being a
19
19
  * message, it's history to the strategy: capped by its per-message bound,
20
20
  * sharded, selected by the budget and folded like any other.
21
21
  *
@@ -50,13 +50,14 @@ export function locateMessageIndices(
50
50
 
51
51
  /**
52
52
  * Inclusive slot range of the body-group run containing `index` (the slot
53
- * itself when it is not sharded). Delegates to the store's own
54
- * `alignToBodyGroups` edge walk — one contiguity assumption, not two.
53
+ * itself when it is not sharded), and the ids of its rows in store order.
54
+ * Delegates to the store's own `alignToBodyGroups` edge walk — one
55
+ * contiguity assumption, not two.
55
56
  */
56
57
  export function bodyGroupRun(
57
58
  cm: SurgeryReadableCm,
58
59
  index: number,
59
- ): { from: number; to: number; fromId: string; toId: string; group: boolean } {
60
+ ): { from: number; to: number; fromId: string; toId: string; group: boolean; ids: MessageId[] } {
60
61
  const win = cm.getMessageWindow(index, 1, { alignToBodyGroups: true, resolveBlobs: false });
61
62
  const from = win.startIndex;
62
63
  const to = win.startIndex + win.messages.length - 1;
@@ -66,6 +67,7 @@ export function bodyGroupRun(
66
67
  fromId: String(win.messages[0].id),
67
68
  toId: String(win.messages[win.messages.length - 1].id),
68
69
  group: win.messages[0].bodyGroupId !== undefined,
70
+ ids: win.messages.map((m) => String(m.id) as MessageId),
69
71
  };
70
72
  }
71
73
 
@@ -90,23 +92,45 @@ export function removeStoredMessages(cm: Removals, first: StoredLike, last: Stor
90
92
  * Remove one stored message by its id, with the rest of its body when it's
91
93
  * in one: a module or a coalescer removes a message it added by the id
92
94
  * `addMessage` returned, which for a long message stored in shards is its
93
- * first shard's.
95
+ * first shard's. Returns the ids of every row it removed, in store order:
96
+ * the id given for a message outside any body, each shard's for a body, so
97
+ * a caller can take them out of the windows of the other agents that held
98
+ * them (#291).
94
99
  */
95
- export function removeStoredMessage(cm: ContextManager, id: MessageId): void {
100
+ export function removeStoredMessage(cm: ContextManager, id: MessageId): MessageId[] {
96
101
  const message = cm.getMessage(id) as StoredLike | null;
97
102
  if (!message?.bodyGroupId) {
98
103
  cm.removeMessage(id);
99
- return;
104
+ return [id];
100
105
  }
101
106
  // Found in blob-free windows: a full read of the branch would inflate every
102
107
  // attachment on it, once for each message a sweep removes.
103
108
  const index = locateMessageIndex(cm, String(id));
104
109
  if (index < 0) {
105
110
  cm.removeMessage(id);
106
- return;
111
+ return [id];
107
112
  }
108
113
  const run = bodyGroupRun(cm, index);
109
114
  cm.removeMessages(run.fromId as MessageId, run.toId as MessageId);
115
+ return run.ids;
116
+ }
117
+
118
+ /**
119
+ * The ids of the stored messages `firstId`..`lastId` (inclusive, in store
120
+ * order, every shard of a body), read before a removal of that interval so
121
+ * the caller knows what it took. Both ends are found tail-first and the
122
+ * rows between them read in one blob-free window. Empty when either end is
123
+ * not on the active branch; the ends may be given in either order.
124
+ */
125
+ export function storedIdsBetween(cm: SurgeryReadableCm, firstId: string, lastId: string): MessageId[] {
126
+ const found = locateMessageIndices(cm, new Set([firstId, lastId]));
127
+ const first = found.get(firstId);
128
+ const last = found.get(lastId);
129
+ if (!first || !last) return [];
130
+ const from = Math.min(first.index, last.index);
131
+ const to = Math.max(first.index, last.index);
132
+ const { messages } = cm.getMessageWindow(from, to - from + 1, { resolveBlobs: false });
133
+ return messages.map((m) => String(m.id) as MessageId);
110
134
  }
111
135
 
112
136
  /** removeStoredMessages for an interval known by its ids. */
@@ -7,6 +7,7 @@ import { ensureStateRegistered } from './module-registry.js';
7
7
  import { classifyBlock } from './mcpl/references.js';
8
8
  import { resultClaimsOf, rfc005TextOf, toolResultDataToHistoryString } from './tool-result-history.js';
9
9
  import { safeSlice } from './safe-slice.js';
10
+ import { asOwnRow, presentLandedThenRethrow } from './dendrite/audience.js';
10
11
 
11
12
  export const TOOL_RESULT_GUARD_NOTICE = 'Tool result withheld by the guard. The tool has already executed.';
12
13
  export type WithheldNoticeKind = 'ran' | 'refused' | 'error';
@@ -195,6 +196,16 @@ export class ToolResultGuard {
195
196
 
196
197
  get enabled(): boolean { return this.override ?? this.configured; }
197
198
  setHost(host: WithheldHost | undefined): void { this.host = host; }
199
+
200
+ /** Where the results message is told of once stored (the agent's own-row sink, Agent.setOwnRowSink). */
201
+ private ownRowSink?: (ids: readonly MessageId[]) => void;
202
+ /**
203
+ * Install where storeResults tells of the results message it stores, once
204
+ * the add has returned (the presentation index presents it in the agent's
205
+ * window then, #291), or take it off with undefined. An idempotent retry
206
+ * of a batch already staged stores nothing and tells nothing.
207
+ */
208
+ setOwnRowSink(sink: ((ids: readonly MessageId[]) => void) | undefined): void { this.ownRowSink = sink; }
198
209
  /** Settles once every annotation started so far has finished: each of
199
210
  * those stubs has been edited to say where its original is, or its edit
200
211
  * failed and waits in the storage queue, retried in order until it lands
@@ -343,7 +354,9 @@ export class ToolResultGuard {
343
354
 
344
355
  /** `keptCap` is where what a stub keeps of a withheld result is cut: the
345
356
  * cap the caller stored `content` under, less the stub's notice room where
346
- * its message's bound sets it (toolResultShare, tool-image-ledger.ts). */
357
+ * its message's bound sets it (toolResultShare, tool-image-ledger.ts).
358
+ * The results are the agent's own row, stamped so (asOwnRow) on top of
359
+ * the caller's `metadata`, guarded or not. */
347
360
  storeResults(
348
361
  content: ContentBlock[],
349
362
  wireResults: ToolResult[],
@@ -352,7 +365,17 @@ export class ToolResultGuard {
352
365
  /** Where what a stub keeps is cut. */
353
366
  keptCap: number | undefined,
354
367
  ): MessageId {
355
- if (!this.enabled) return this.cm.addMessage('user', content, metadata);
368
+ metadata = asOwnRow(metadata, this.agentName);
369
+ if (!this.enabled) {
370
+ let id: MessageId;
371
+ try {
372
+ id = this.cm.addMessage('user', content, metadata);
373
+ } catch (error) {
374
+ presentLandedThenRethrow(error, this.agentName, this.ownRowSink, (row) => this.cm.getMessage(row) !== null);
375
+ }
376
+ this.ownRowSink?.([id]);
377
+ return id;
378
+ }
356
379
  if (this.pending) {
357
380
  // Idempotent for the same not-yet-submitted batch: a caller that
358
381
  // retries after a failure between staging and submission (e.g. a
@@ -392,9 +415,19 @@ export class ToolResultGuard {
392
415
  // chunk is ever summarized from the placeholder; released after the
393
416
  // settlement edit. Holds are in-memory only — a reopened manager has none,
394
417
  // which is correct since a reopened guard has no pending batch.
395
- const messageId = this.cm.addMessage('user', withheld, metadata, undefined, { holdCompression: true });
418
+ // A write that throws with rows of it stored presents them, as one that
419
+ // returned would be, and throws on with no batch pending, as before.
420
+ let messageId: MessageId;
421
+ try {
422
+ messageId = this.cm.addMessage('user', withheld, metadata, undefined, { holdCompression: true });
423
+ } catch (error) {
424
+ presentLandedThenRethrow(error, this.agentName, this.ownRowSink, (row) => this.cm.getMessage(row) !== null);
425
+ }
396
426
  this.pending = { id, messageId, content, withheld, wireResults,
397
427
  branch: this.cm.currentBranch().name, submitted: false, durable: false, kept, notices };
428
+ // Told before the durability barrier below, so the sync that makes the
429
+ // audit durable carries the row's presentation too.
430
+ this.ownRowSink?.([messageId]);
398
431
  // Durability barrier: the audit must reach Chronicle's chain heads before
399
432
  // the originals can go to a provider. On a failed sync the batch fails
400
433
  // CLOSED: the placeholders go on the wire instead (the turn continues,
@@ -575,8 +608,9 @@ export class ToolResultGuard {
575
608
  let deadlineSpent = false;
576
609
  for (const [index, block] of pending.content.entries()) {
577
610
  if (block.type !== 'tool_result') continue;
578
- // Once the store has left the batch's branch (a rollback, an undo, a
579
- // host's switch), write no more. This result and every later one is
611
+ // Once the store has left the batch's branch (a rollback, a
612
+ // suppression, a host's switch; an undo moves no branch), write no
613
+ // more. This result and every later one is
580
614
  // skipped, and its original stays in the audit record. Nothing
581
615
  // yields from here to the edit's own branch check, so while the
582
616
  // store is away the stub stays as it is. A write already under way
@@ -606,8 +640,8 @@ export class ToolResultGuard {
606
640
  // Declined where it would have committed, since the workspace had
607
641
  // left the batch's branch. Nothing was written, and no more are, as
608
642
  // for the results the branch check above stops. If the branch is
609
- // back by the edit, as after an undo and a redo, the stubs of this
610
- // result and the later ones name the audit record.
643
+ // back by the edit, as after a host's switch away and back, the stubs
644
+ // of this result and the later ones name the audit record.
611
645
  if (spill && 'skipped' in spill && spill.skipped === 'branch_changed') branchLeft = true;
612
646
  // A batch that used its deadline is said once, here, where the
613
647
  // batch is known; the host returns the skip without a line.