@animalabs/agent-framework 0.26.2 → 0.28.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 (371) hide show
  1. package/README.md +99 -8
  2. package/dist/src/agent.d.ts +291 -23
  3. package/dist/src/agent.d.ts.map +1 -1
  4. package/dist/src/agent.js +596 -61
  5. package/dist/src/agent.js.map +1 -1
  6. package/dist/src/api/server.d.ts.map +1 -1
  7. package/dist/src/api/server.js +5 -4
  8. package/dist/src/api/server.js.map +1 -1
  9. package/dist/src/auto-continue.d.ts +34 -0
  10. package/dist/src/auto-continue.d.ts.map +1 -0
  11. package/dist/src/auto-continue.js +36 -0
  12. package/dist/src/auto-continue.js.map +1 -0
  13. package/dist/src/code-execution/isolate/scripts.d.ts +11 -0
  14. package/dist/src/code-execution/isolate/scripts.d.ts.map +1 -1
  15. package/dist/src/code-execution/isolate/scripts.js +5 -1
  16. package/dist/src/code-execution/isolate/scripts.js.map +1 -1
  17. package/dist/src/cut-off-round.d.ts +24 -0
  18. package/dist/src/cut-off-round.d.ts.map +1 -0
  19. package/dist/src/cut-off-round.js +87 -0
  20. package/dist/src/cut-off-round.js.map +1 -0
  21. package/dist/src/framework.d.ts +1038 -193
  22. package/dist/src/framework.d.ts.map +1 -1
  23. package/dist/src/framework.js +5967 -1514
  24. package/dist/src/framework.js.map +1 -1
  25. package/dist/src/gate/event-gate.d.ts +405 -46
  26. package/dist/src/gate/event-gate.d.ts.map +1 -1
  27. package/dist/src/gate/event-gate.js +2646 -399
  28. package/dist/src/gate/event-gate.js.map +1 -1
  29. package/dist/src/gate/index.d.ts +3 -2
  30. package/dist/src/gate/index.d.ts.map +1 -1
  31. package/dist/src/gate/index.js +2 -1
  32. package/dist/src/gate/index.js.map +1 -1
  33. package/dist/src/gate/recipe-reconcile.d.ts +103 -0
  34. package/dist/src/gate/recipe-reconcile.d.ts.map +1 -0
  35. package/dist/src/gate/recipe-reconcile.js +325 -0
  36. package/dist/src/gate/recipe-reconcile.js.map +1 -0
  37. package/dist/src/gate/reply-judge.d.ts +116 -0
  38. package/dist/src/gate/reply-judge.d.ts.map +1 -0
  39. package/dist/src/gate/reply-judge.js +467 -0
  40. package/dist/src/gate/reply-judge.js.map +1 -0
  41. package/dist/src/gate/types.d.ts +229 -8
  42. package/dist/src/gate/types.d.ts.map +1 -1
  43. package/dist/src/heartbeat/heartbeat.d.ts +184 -0
  44. package/dist/src/heartbeat/heartbeat.d.ts.map +1 -0
  45. package/dist/src/heartbeat/heartbeat.js +752 -0
  46. package/dist/src/heartbeat/heartbeat.js.map +1 -0
  47. package/dist/src/heartbeat/reminder-time.d.ts +5 -0
  48. package/dist/src/heartbeat/reminder-time.d.ts.map +1 -0
  49. package/dist/src/heartbeat/reminder-time.js +107 -0
  50. package/dist/src/heartbeat/reminder-time.js.map +1 -0
  51. package/dist/src/index.d.ts +10 -4
  52. package/dist/src/index.d.ts.map +1 -1
  53. package/dist/src/index.js +7 -2
  54. package/dist/src/index.js.map +1 -1
  55. package/dist/src/mcpl/capability-mask.d.ts.map +1 -1
  56. package/dist/src/mcpl/capability-mask.js +3 -2
  57. package/dist/src/mcpl/capability-mask.js.map +1 -1
  58. package/dist/src/mcpl/channel-registry.d.ts +433 -113
  59. package/dist/src/mcpl/channel-registry.d.ts.map +1 -1
  60. package/dist/src/mcpl/channel-registry.js +1154 -435
  61. package/dist/src/mcpl/channel-registry.js.map +1 -1
  62. package/dist/src/mcpl/conversation-router.d.ts +16 -8
  63. package/dist/src/mcpl/conversation-router.d.ts.map +1 -1
  64. package/dist/src/mcpl/conversation-router.js +29 -15
  65. package/dist/src/mcpl/conversation-router.js.map +1 -1
  66. package/dist/src/mcpl/convert-block.d.ts.map +1 -1
  67. package/dist/src/mcpl/convert-block.js +14 -2
  68. package/dist/src/mcpl/convert-block.js.map +1 -1
  69. package/dist/src/mcpl/hook-orchestrator.d.ts +7 -1
  70. package/dist/src/mcpl/hook-orchestrator.d.ts.map +1 -1
  71. package/dist/src/mcpl/hook-orchestrator.js +32 -7
  72. package/dist/src/mcpl/hook-orchestrator.js.map +1 -1
  73. package/dist/src/mcpl/inbound-source.d.ts +26 -10
  74. package/dist/src/mcpl/inbound-source.d.ts.map +1 -1
  75. package/dist/src/mcpl/inbound-source.js +40 -69
  76. package/dist/src/mcpl/inbound-source.js.map +1 -1
  77. package/dist/src/mcpl/index.d.ts +5 -1
  78. package/dist/src/mcpl/index.d.ts.map +1 -1
  79. package/dist/src/mcpl/index.js +4 -0
  80. package/dist/src/mcpl/index.js.map +1 -1
  81. package/dist/src/mcpl/inference-router.d.ts +14 -2
  82. package/dist/src/mcpl/inference-router.d.ts.map +1 -1
  83. package/dist/src/mcpl/inference-router.js +73 -28
  84. package/dist/src/mcpl/inference-router.js.map +1 -1
  85. package/dist/src/mcpl/prose-grammar.d.ts +4 -0
  86. package/dist/src/mcpl/prose-grammar.d.ts.map +1 -1
  87. package/dist/src/mcpl/prose-grammar.js +6 -0
  88. package/dist/src/mcpl/prose-grammar.js.map +1 -1
  89. package/dist/src/mcpl/protocol-family.d.ts.map +1 -1
  90. package/dist/src/mcpl/protocol-family.js +3 -0
  91. package/dist/src/mcpl/protocol-family.js.map +1 -1
  92. package/dist/src/mcpl/push-coalescer.d.ts +20 -2
  93. package/dist/src/mcpl/push-coalescer.d.ts.map +1 -1
  94. package/dist/src/mcpl/push-coalescer.js +33 -11
  95. package/dist/src/mcpl/push-coalescer.js.map +1 -1
  96. package/dist/src/mcpl/reference-fetcher.d.ts +63 -42
  97. package/dist/src/mcpl/reference-fetcher.d.ts.map +1 -1
  98. package/dist/src/mcpl/reference-fetcher.js +177 -145
  99. package/dist/src/mcpl/reference-fetcher.js.map +1 -1
  100. package/dist/src/mcpl/references.d.ts +380 -46
  101. package/dist/src/mcpl/references.d.ts.map +1 -1
  102. package/dist/src/mcpl/references.js +736 -77
  103. package/dist/src/mcpl/references.js.map +1 -1
  104. package/dist/src/mcpl/server-connection.d.ts +93 -4
  105. package/dist/src/mcpl/server-connection.d.ts.map +1 -1
  106. package/dist/src/mcpl/server-connection.js +176 -11
  107. package/dist/src/mcpl/server-connection.js.map +1 -1
  108. package/dist/src/mcpl/tags.d.ts +9 -2
  109. package/dist/src/mcpl/tags.d.ts.map +1 -1
  110. package/dist/src/mcpl/tags.js +12 -2
  111. package/dist/src/mcpl/tags.js.map +1 -1
  112. package/dist/src/mcpl/tool-lifecycle.d.ts +11 -0
  113. package/dist/src/mcpl/tool-lifecycle.d.ts.map +1 -1
  114. package/dist/src/mcpl/tool-lifecycle.js +21 -0
  115. package/dist/src/mcpl/tool-lifecycle.js.map +1 -1
  116. package/dist/src/mcpl/tool-presence.d.ts +311 -0
  117. package/dist/src/mcpl/tool-presence.d.ts.map +1 -0
  118. package/dist/src/mcpl/tool-presence.js +697 -0
  119. package/dist/src/mcpl/tool-presence.js.map +1 -0
  120. package/dist/src/mcpl/tool-result-normalize.d.ts +9 -3
  121. package/dist/src/mcpl/tool-result-normalize.d.ts.map +1 -1
  122. package/dist/src/mcpl/tool-result-normalize.js +14 -6
  123. package/dist/src/mcpl/tool-result-normalize.js.map +1 -1
  124. package/dist/src/mcpl/tool-signature.d.ts +46 -0
  125. package/dist/src/mcpl/tool-signature.d.ts.map +1 -0
  126. package/dist/src/mcpl/tool-signature.js +321 -0
  127. package/dist/src/mcpl/tool-signature.js.map +1 -0
  128. package/dist/src/mcpl/toolset-host.d.ts +251 -0
  129. package/dist/src/mcpl/toolset-host.d.ts.map +1 -0
  130. package/dist/src/mcpl/toolset-host.js +720 -0
  131. package/dist/src/mcpl/toolset-host.js.map +1 -0
  132. package/dist/src/mcpl/toolsets-module.d.ts +83 -0
  133. package/dist/src/mcpl/toolsets-module.d.ts.map +1 -0
  134. package/dist/src/mcpl/toolsets-module.js +523 -0
  135. package/dist/src/mcpl/toolsets-module.js.map +1 -0
  136. package/dist/src/mcpl/transport.d.ts +2 -2
  137. package/dist/src/mcpl/transport.d.ts.map +1 -1
  138. package/dist/src/mcpl/transport.js +3 -2
  139. package/dist/src/mcpl/transport.js.map +1 -1
  140. package/dist/src/mcpl/types.d.ts +24 -2
  141. package/dist/src/mcpl/types.d.ts.map +1 -1
  142. package/dist/src/mcpl/types.js.map +1 -1
  143. package/dist/src/mcpl/visible-content.d.ts +7 -9
  144. package/dist/src/mcpl/visible-content.d.ts.map +1 -1
  145. package/dist/src/mcpl/visible-content.js +21 -9
  146. package/dist/src/mcpl/visible-content.js.map +1 -1
  147. package/dist/src/module-registry.d.ts +27 -9
  148. package/dist/src/module-registry.d.ts.map +1 -1
  149. package/dist/src/module-registry.js +77 -17
  150. package/dist/src/module-registry.js.map +1 -1
  151. package/dist/src/modules/discord/index.js +1 -1
  152. package/dist/src/modules/discord/index.js.map +1 -1
  153. package/dist/src/modules/history/index.d.ts +2 -1
  154. package/dist/src/modules/history/index.d.ts.map +1 -1
  155. package/dist/src/modules/history/index.js +73 -28
  156. package/dist/src/modules/history/index.js.map +1 -1
  157. package/dist/src/modules/history/semantic.d.ts +108 -6
  158. package/dist/src/modules/history/semantic.d.ts.map +1 -1
  159. package/dist/src/modules/history/semantic.js +273 -57
  160. package/dist/src/modules/history/semantic.js.map +1 -1
  161. package/dist/src/modules/workspace/answers.d.ts +22 -0
  162. package/dist/src/modules/workspace/answers.d.ts.map +1 -0
  163. package/dist/src/modules/workspace/answers.js +123 -0
  164. package/dist/src/modules/workspace/answers.js.map +1 -0
  165. package/dist/src/modules/workspace/branch-intent.d.ts +5 -3
  166. package/dist/src/modules/workspace/branch-intent.d.ts.map +1 -1
  167. package/dist/src/modules/workspace/branch-intent.js +6 -2
  168. package/dist/src/modules/workspace/branch-intent.js.map +1 -1
  169. package/dist/src/modules/workspace/direct-write.d.ts +184 -0
  170. package/dist/src/modules/workspace/direct-write.d.ts.map +1 -0
  171. package/dist/src/modules/workspace/direct-write.js +417 -0
  172. package/dist/src/modules/workspace/direct-write.js.map +1 -0
  173. package/dist/src/modules/workspace/disk-agreement.d.ts +33 -11
  174. package/dist/src/modules/workspace/disk-agreement.d.ts.map +1 -1
  175. package/dist/src/modules/workspace/disk-agreement.js +48 -17
  176. package/dist/src/modules/workspace/disk-agreement.js.map +1 -1
  177. package/dist/src/modules/workspace/edit-text.d.ts +27 -12
  178. package/dist/src/modules/workspace/edit-text.d.ts.map +1 -1
  179. package/dist/src/modules/workspace/edit-text.js +61 -29
  180. package/dist/src/modules/workspace/edit-text.js.map +1 -1
  181. package/dist/src/modules/workspace/effects.d.ts +10 -0
  182. package/dist/src/modules/workspace/effects.d.ts.map +1 -1
  183. package/dist/src/modules/workspace/effects.js +21 -14
  184. package/dist/src/modules/workspace/effects.js.map +1 -1
  185. package/dist/src/modules/workspace/index.d.ts +308 -78
  186. package/dist/src/modules/workspace/index.d.ts.map +1 -1
  187. package/dist/src/modules/workspace/index.js +2103 -720
  188. package/dist/src/modules/workspace/index.js.map +1 -1
  189. package/dist/src/modules/workspace/observe.d.ts +75 -63
  190. package/dist/src/modules/workspace/observe.d.ts.map +1 -1
  191. package/dist/src/modules/workspace/observe.js +366 -180
  192. package/dist/src/modules/workspace/observe.js.map +1 -1
  193. package/dist/src/modules/workspace/read-page.d.ts +41 -0
  194. package/dist/src/modules/workspace/read-page.d.ts.map +1 -0
  195. package/dist/src/modules/workspace/read-page.js +219 -0
  196. package/dist/src/modules/workspace/read-page.js.map +1 -0
  197. package/dist/src/modules/workspace/reconcile.d.ts.map +1 -1
  198. package/dist/src/modules/workspace/reconcile.js +26 -16
  199. package/dist/src/modules/workspace/reconcile.js.map +1 -1
  200. package/dist/src/modules/workspace/result-text.d.ts +68 -0
  201. package/dist/src/modules/workspace/result-text.d.ts.map +1 -0
  202. package/dist/src/modules/workspace/result-text.js +94 -0
  203. package/dist/src/modules/workspace/result-text.js.map +1 -0
  204. package/dist/src/modules/workspace/sync.d.ts +9 -0
  205. package/dist/src/modules/workspace/sync.d.ts.map +1 -1
  206. package/dist/src/modules/workspace/sync.js +14 -0
  207. package/dist/src/modules/workspace/sync.js.map +1 -1
  208. package/dist/src/modules/workspace/text.d.ts +29 -12
  209. package/dist/src/modules/workspace/text.d.ts.map +1 -1
  210. package/dist/src/modules/workspace/text.js +35 -33
  211. package/dist/src/modules/workspace/text.js.map +1 -1
  212. package/dist/src/modules/workspace/types.d.ts +137 -60
  213. package/dist/src/modules/workspace/types.d.ts.map +1 -1
  214. package/dist/src/modules/workspace/types.js.map +1 -1
  215. package/dist/src/modules/workspace/watcher.d.ts.map +1 -1
  216. package/dist/src/modules/workspace/watcher.js +8 -3
  217. package/dist/src/modules/workspace/watcher.js.map +1 -1
  218. package/dist/src/prose-drafts.d.ts +4 -3
  219. package/dist/src/prose-drafts.d.ts.map +1 -1
  220. package/dist/src/prose-drafts.js +3 -2
  221. package/dist/src/prose-drafts.js.map +1 -1
  222. package/dist/src/reasoning-loss-notice.d.ts +23 -0
  223. package/dist/src/reasoning-loss-notice.d.ts.map +1 -0
  224. package/dist/src/reasoning-loss-notice.js +50 -0
  225. package/dist/src/reasoning-loss-notice.js.map +1 -0
  226. package/dist/src/reasoning-loss.d.ts +24 -0
  227. package/dist/src/reasoning-loss.d.ts.map +1 -0
  228. package/dist/src/reasoning-loss.js +102 -0
  229. package/dist/src/reasoning-loss.js.map +1 -0
  230. package/dist/src/send-tools.d.ts +3 -2
  231. package/dist/src/send-tools.d.ts.map +1 -1
  232. package/dist/src/send-tools.js +3 -2
  233. package/dist/src/send-tools.js.map +1 -1
  234. package/dist/src/sent-rows.d.ts +59 -0
  235. package/dist/src/sent-rows.d.ts.map +1 -0
  236. package/dist/src/sent-rows.js +145 -0
  237. package/dist/src/sent-rows.js.map +1 -0
  238. package/dist/src/silent-heartbeat.d.ts +17 -10
  239. package/dist/src/silent-heartbeat.d.ts.map +1 -1
  240. package/dist/src/silent-heartbeat.js.map +1 -1
  241. package/dist/src/stable-hash.d.ts +3 -0
  242. package/dist/src/stable-hash.d.ts.map +1 -0
  243. package/dist/src/stable-hash.js +15 -0
  244. package/dist/src/stable-hash.js.map +1 -0
  245. package/dist/src/stored-injections.d.ts +99 -0
  246. package/dist/src/stored-injections.d.ts.map +1 -0
  247. package/dist/src/stored-injections.js +106 -0
  248. package/dist/src/stored-injections.js.map +1 -0
  249. package/dist/src/text-as-stored.d.ts +4 -3
  250. package/dist/src/text-as-stored.d.ts.map +1 -1
  251. package/dist/src/text-as-stored.js +4 -3
  252. package/dist/src/text-as-stored.js.map +1 -1
  253. package/dist/src/thinking-drops.d.ts +74 -0
  254. package/dist/src/thinking-drops.d.ts.map +1 -0
  255. package/dist/src/thinking-drops.js +96 -0
  256. package/dist/src/thinking-drops.js.map +1 -0
  257. package/dist/src/tool-args.d.ts +12 -0
  258. package/dist/src/tool-args.d.ts.map +1 -1
  259. package/dist/src/tool-args.js +35 -1
  260. package/dist/src/tool-args.js.map +1 -1
  261. package/dist/src/tool-image-ledger.d.ts +9 -8
  262. package/dist/src/tool-image-ledger.d.ts.map +1 -1
  263. package/dist/src/tool-image-ledger.js +9 -8
  264. package/dist/src/tool-image-ledger.js.map +1 -1
  265. package/dist/src/tool-presentation.d.ts.map +1 -1
  266. package/dist/src/tool-presentation.js +3 -1
  267. package/dist/src/tool-presentation.js.map +1 -1
  268. package/dist/src/tool-result-guard.d.ts +12 -6
  269. package/dist/src/tool-result-guard.d.ts.map +1 -1
  270. package/dist/src/tool-result-guard.js +44 -17
  271. package/dist/src/tool-result-guard.js.map +1 -1
  272. package/dist/src/tool-result-history.d.ts +176 -24
  273. package/dist/src/tool-result-history.d.ts.map +1 -1
  274. package/dist/src/tool-result-history.js +411 -91
  275. package/dist/src/tool-result-history.js.map +1 -1
  276. package/dist/src/tune-out/coordinator.d.ts +17 -9
  277. package/dist/src/tune-out/coordinator.d.ts.map +1 -1
  278. package/dist/src/tune-out/coordinator.js +84 -37
  279. package/dist/src/tune-out/coordinator.js.map +1 -1
  280. package/dist/src/tune-out/tools.d.ts +4 -1
  281. package/dist/src/tune-out/tools.d.ts.map +1 -1
  282. package/dist/src/types/agent.d.ts +217 -7
  283. package/dist/src/types/agent.d.ts.map +1 -1
  284. package/dist/src/types/events.d.ts +33 -9
  285. package/dist/src/types/events.d.ts.map +1 -1
  286. package/dist/src/types/framework.d.ts +39 -3
  287. package/dist/src/types/framework.d.ts.map +1 -1
  288. package/dist/src/types/module.d.ts +95 -9
  289. package/dist/src/types/module.d.ts.map +1 -1
  290. package/dist/src/types/trace.d.ts +91 -3
  291. package/dist/src/types/trace.d.ts.map +1 -1
  292. package/package.json +5 -4
  293. package/src/agent.ts +661 -67
  294. package/src/api/server.ts +5 -4
  295. package/src/auto-continue.ts +43 -0
  296. package/src/code-execution/isolate/scripts.ts +11 -3
  297. package/src/cut-off-round.ts +98 -0
  298. package/src/framework.ts +6168 -1540
  299. package/src/gate/event-gate.ts +2895 -405
  300. package/src/gate/index.ts +10 -1
  301. package/src/gate/recipe-reconcile.ts +355 -0
  302. package/src/gate/reply-judge.ts +512 -0
  303. package/src/gate/types.ts +234 -9
  304. package/src/heartbeat/heartbeat.ts +804 -0
  305. package/src/heartbeat/reminder-time.ts +107 -0
  306. package/src/index.ts +11 -4
  307. package/src/mcpl/capability-mask.ts +3 -2
  308. package/src/mcpl/channel-registry.ts +1222 -468
  309. package/src/mcpl/conversation-router.ts +34 -16
  310. package/src/mcpl/convert-block.ts +14 -1
  311. package/src/mcpl/hook-orchestrator.ts +33 -6
  312. package/src/mcpl/inbound-source.ts +42 -69
  313. package/src/mcpl/index.ts +6 -1
  314. package/src/mcpl/inference-router.ts +79 -34
  315. package/src/mcpl/prose-grammar.ts +7 -0
  316. package/src/mcpl/protocol-family.ts +2 -0
  317. package/src/mcpl/push-coalescer.ts +51 -13
  318. package/src/mcpl/reference-fetcher.ts +201 -162
  319. package/src/mcpl/references.ts +851 -77
  320. package/src/mcpl/server-connection.ts +189 -11
  321. package/src/mcpl/tags.ts +13 -2
  322. package/src/mcpl/tool-lifecycle.ts +21 -0
  323. package/src/mcpl/tool-presence.ts +716 -0
  324. package/src/mcpl/tool-result-normalize.ts +18 -6
  325. package/src/mcpl/tool-signature.ts +316 -0
  326. package/src/mcpl/toolset-host.ts +727 -0
  327. package/src/mcpl/toolsets-module.ts +545 -0
  328. package/src/mcpl/transport.ts +3 -2
  329. package/src/mcpl/types.ts +25 -2
  330. package/src/mcpl/visible-content.ts +22 -9
  331. package/src/module-registry.ts +85 -26
  332. package/src/modules/discord/index.ts +1 -1
  333. package/src/modules/history/index.ts +70 -30
  334. package/src/modules/history/semantic.ts +308 -54
  335. package/src/modules/workspace/answers.ts +133 -0
  336. package/src/modules/workspace/branch-intent.ts +10 -5
  337. package/src/modules/workspace/direct-write.ts +460 -0
  338. package/src/modules/workspace/disk-agreement.ts +52 -21
  339. package/src/modules/workspace/edit-text.ts +84 -35
  340. package/src/modules/workspace/effects.ts +22 -13
  341. package/src/modules/workspace/index.ts +2142 -723
  342. package/src/modules/workspace/observe.ts +381 -177
  343. package/src/modules/workspace/read-page.ts +228 -0
  344. package/src/modules/workspace/reconcile.ts +27 -15
  345. package/src/modules/workspace/result-text.ts +121 -0
  346. package/src/modules/workspace/sync.ts +16 -0
  347. package/src/modules/workspace/text.ts +58 -32
  348. package/src/modules/workspace/types.ts +137 -60
  349. package/src/modules/workspace/watcher.ts +8 -3
  350. package/src/prose-drafts.ts +4 -3
  351. package/src/reasoning-loss-notice.ts +62 -0
  352. package/src/reasoning-loss.ts +120 -0
  353. package/src/send-tools.ts +3 -2
  354. package/src/sent-rows.ts +162 -0
  355. package/src/silent-heartbeat.ts +17 -10
  356. package/src/stable-hash.ts +14 -0
  357. package/src/stored-injections.ts +131 -0
  358. package/src/text-as-stored.ts +4 -3
  359. package/src/thinking-drops.ts +135 -0
  360. package/src/tool-args.ts +34 -1
  361. package/src/tool-image-ledger.ts +9 -8
  362. package/src/tool-presentation.ts +3 -1
  363. package/src/tool-result-guard.ts +45 -17
  364. package/src/tool-result-history.ts +471 -90
  365. package/src/tune-out/coordinator.ts +80 -37
  366. package/src/tune-out/tools.ts +4 -1
  367. package/src/types/agent.ts +220 -7
  368. package/src/types/events.ts +33 -9
  369. package/src/types/framework.ts +36 -3
  370. package/src/types/module.ts +91 -9
  371. package/src/types/trace.ts +94 -3
package/README.md CHANGED
@@ -118,11 +118,11 @@ interface Module {
118
118
 
119
119
  // Optional
120
120
  onAgentSpeech?(agentName: string, content: ContentBlock[], context: SpeechContext): Promise<void>;
121
- gatherContext?(agentName: string): Promise<ContextInjection[]>;
121
+ gatherContext?(agentName: string): Promise<ModuleContextInjection[]>;
122
122
  }
123
123
  ```
124
124
 
125
- An `EventResponse` can add/edit/remove messages, request inference, signal tool changes, and atomically update module state:
125
+ An `EventResponse` can add/edit/remove messages, update module state, request inference, and signal tool changes. The framework applies its message changes, then its state update, then its inference request; when one of these throws, what came before it stays applied, that step may have taken effect in part, and the rest of that response isn't:
126
126
 
127
127
  ```typescript
128
128
  return {
@@ -150,7 +150,7 @@ Each agent has a `ContextManager` (from `@connectome/context-manager`) that main
150
150
  - **PassthroughStrategy** - No compression, raw message replay up to budget
151
151
  - **AutobiographicalStrategy** - Chunks old messages and summarizes them into diary entries, preserving recent context uncompressed
152
152
 
153
- Before inference, modules and MCPL hooks can inject additional context via `gatherContext()`.
153
+ Before inference, modules and MCPL hooks can inject additional context via `gatherContext()`. An `afterUser` injection is stored in the agent's window, as the message `compile()` would have placed after the last user message, so it stays where the agent saw it: the replies after it keep their thinking, and the cache keeps the turns before it. A source's unchanged content isn't stored again while the copy the agent will read as current has it whole: the one its last request held, or a newer one a start stored whose compile then didn't record (it threw, or the start failed before it); once a fold has summarized it or the strategy's window has passed it, it's stored again, as one more row. Where a changed one lands right after the agent's own latest message, with no one else's message between, `[Continue]` still ends the request, after it. A stored row is history to the strategy, capped, sharded, budgeted and folded like any message. Its metadata carries `system: true`, `kind: 'context-injection'` and `contextInjection: { agent, namespace, contentHash, part, parts }`, which `storedInjectionMarkOf` reads, and every other agent's view leaves it out. A module's injection can set `placedEachCompile: true` to be placed by `compile()` at each start instead, near the end, at the cost of the thinking of every reply after its old place.
154
154
 
155
155
  ### Persistence
156
156
 
@@ -347,8 +347,9 @@ three ways:
347
347
  configuration error: `allowHostCommands: true`, an `enabledCapabilities`
348
348
  pattern that matches a capability denied by default, `channelSubscription:
349
349
  'auto'` or a non-empty list, a scope's non-empty `whitelist`, a
350
- `toolLifecycle` `observe` or `inputs` block, and a
351
- `toolLifecycle.maxInputBytes` or an `autofetch` bound above its default.
350
+ `toolLifecycle` `observe` or `inputs` block, a
351
+ `toolLifecycle.maxInputBytes` or an `autofetch` bound above its default,
352
+ and `toolHints: true`.
352
353
  A setting
353
354
  that only takes something away, or repeats a default, is already
354
355
  satisfied, so it is accepted: `enabledFeatureSets` and the rest of
@@ -429,6 +430,94 @@ backlog is simply its unread backlog. Receipts and subject history are kept in
429
430
  the `mcpl/coalescing` state (retry window 1 h); audit lines are
430
431
  `mcpl:coalescing` trace events.
431
432
 
433
+ #### Tool presence and toolsets (RFC-014)
434
+
435
+ A server configured with `toolHints: true` (default false) is offered
436
+ `experimental.mcpl.toolHints`, and its hints count only if it advertised
437
+ `toolHints` too. Without it nothing changes: every tool is listed as before,
438
+ and the host advertises and reads nothing new.
439
+
440
+ With it, the server's static tools stay in the tool list as before, and its
441
+ dynamic tools (those in a toolset, or hinted `mcpl/presence: "dynamic"`) never
442
+ enter it, since every change to the list rebuilds the prompt cache. The
443
+ framework registers a `toolsets` module with four constant tools:
444
+
445
+ - `toolsets--open {server?, toolset?, instance?, options?}` opens a toolset (or
446
+ a named instance of one), and answers with what the server shows on opening
447
+ and the tools usable now;
448
+ - `toolsets--act {server?, tool, instance?, args?}` calls a dynamic tool down
449
+ the same path as a direct call of it (the agent's `allowedTools`, the
450
+ server's tool policy, the state exchange, the reading of its result, RFC-007
451
+ observers and RFC-008 class rules, which see the server's tool and its class),
452
+ with only the instance added, in
453
+ `_meta["mcpl/instance"]`. It first checks `args` against the definition in
454
+ force for that instance; that check is bounded, and leaves `pattern` and
455
+ anything nested or branching too far to the server, which checks every
456
+ call itself;
457
+ - `toolsets--look {server?, toolset?, instance?, tool?}` restates what is open
458
+ and what can be opened, or one tool's signature, description, class and
459
+ input schema. It
460
+ re-reads each server that presents toolsets first, and says so when it
461
+ couldn't; what that changed
462
+ is in the answer when look restates everything, and otherwise told as a
463
+ notice;
464
+ - `toolsets--close {server?, toolset?, instance?}` closes it.
465
+
466
+ `server` can be left out when only one server has the name. By our reading of
467
+ the code, a server with no toolsets stops presenting them once its latest `tools/list` has no dynamic
468
+ tool, so until the rebuild, act takes its last one only with `server` named.
469
+ Hint changes apply
470
+ as their message is read, in `rev` order, whatever becomes of the message (a
471
+ refused push, a result that came after its timeout). A move between static and
472
+ dynamic takes effect when the server's `tools/list` states it, and the tool
473
+ list follows at its next rebuild that lists the server, whichever refresh
474
+ brings it (a move is no reason to rebuild the tool list early). Until then the
475
+ tool is called at either place, where the tool list shows it or where the
476
+ server's latest list put it (RFC-014 §4.2 keeps it working where it is until
477
+ the move applies), and
478
+ once that rebuild has published the list, a notice says where it went. A list
479
+ read while a rebuild is under way can undo a move that rebuild then publishes;
480
+ neither is told, and the next rebuild puts the tool back.
481
+ A skipped rev re-reads `tools/list` and then `toolsets/list`, which the host
482
+ also reads after every (re)connect, adopting what the server kept open and
483
+ never re-opening anything.
484
+ What changed is told where it happened: after a call's own result, after the
485
+ push that explains it, or as a notice (`kind: 'mcpl-toolsets'`, which wakes
486
+ nothing) for a standalone `tools/hints`, a late result, an adoption, a
487
+ recovery, or a call whose result may not reach the agent (a script's, a
488
+ module's or a host's, or one the framework makes itself); an open, close or
489
+ look made that way also shows its caller the change, unless the change has
490
+ already gone as a notice (below). A dynamic tool's change also goes as a notice
491
+ when it wouldn't fit whole within its result's inline cap, or when its call
492
+ fails after the result was read. A call's change also goes as a notice, ahead of its
493
+ result, when a later change goes to the agent before the call's caller has
494
+ taken it, so changes are told in the order they were read (the agent's window
495
+ can still show a call's result, a push's event, or a change its taker couldn't
496
+ show after a change read later). The model's own call's change counts as told
497
+ once its result is handed back: if the turn is stopped while the call is out
498
+ (or, by our reading of the code, the agent is gone), the result is dropped and the change with it, and
499
+ `toolsets--look` shows the state it left. Notices and reminders
500
+ need the server's `pushEvents` grant, like any delivery; without it, a change
501
+ that would go as a notice is dropped, and `toolsets--look` shows the state. A new tool's first sentence is told with its
502
+ definition until text describing it has reached the model, except that, by our reading of the code, a puppet's
503
+ open, close or look whose result the store refuses has already counted it. Suggestions are shown, never acted on. Each
504
+ `ended` id is told once while the
505
+ host runs (told ids are kept in memory), short of rare interleavings, such as a
506
+ `toolsets--look` overlapping other reads of the same server, that can tell one
507
+ twice. When an
508
+ open toolset's announcements have left an agent's context (compressed or out
509
+ of the window), the module's `gatherContext` restates what is open, as a
510
+ stored `afterUser` injection (namespace `mcpl-toolsets`), at that agent's next
511
+ start.
512
+
513
+ A dynamic tool called by its prefixed name is refused, pointing at
514
+ `toolsets--act`, unless the tool list or the server's latest list shows it as
515
+ static (a move waiting for its rebuild). Calls to an undeclared toolset's
516
+ tools are refused while the host has that group closed (RFC-014 §5.4), except
517
+ by a tool's listed name until the rebuild that publishes its move into the
518
+ group. Projection and surface mode are not implemented: a `surface` server's
519
+ static tools are listed like any server's.
520
+
432
521
  #### Per-channel conversation routing (deprecated)
433
522
 
434
523
  > **Deprecated: `FrameworkConfig.conversations` (`ConversationRouter`).** Per-channel conversation routing sends each channel's traffic to its own fork agent, spawned from a template agent and closed after an idle TTL. It is being retired ([#235](https://github.com/anima-research/agent-framework/issues/235)). Its `'mention'` bind/trigger rule, the default for channels, reads `metadata.mentioned`, which discord-mcpl does not set, so on Discord channels an @-mention never binds a fork or triggers a bound one. Don't adopt it in new hosts. Existing configurations still route exactly as before, and the framework logs one `[deprecated]` line when it is created with `conversations` set. Removal is a follow-up.
@@ -439,7 +528,7 @@ the `mcpl/coalescing` state (retry window 1 h); audit lines are
439
528
  2. **Drive**: Framework iterates stream events (tokens, tool-calls, complete, error)
440
529
  3. **Tool yield**: Stream yields tool calls → framework dispatches concurrently → collects results
441
530
  4. **Resume**: All results in → stream resumes with tool results
442
- 5. **Budget restart**: If input tokens exceed `maxStreamTokens`, the stream is cancelled, context is recompressed, and a fresh stream starts
531
+ 5. **Budget restart**: If input tokens exceed `maxStreamTokens`, the stream is cancelled, context is recompressed, and a fresh stream starts. An agent whose model binds its thinking (`thinkingBinding.binds`) with `physicalWindowTokens` set skips this, and the window projection restarts it instead before a request the window can't hold
443
532
  6. **Complete**: Final response saved to context, agent returns to idle
444
533
 
445
534
  ### Abort / Cancellation
@@ -451,9 +540,11 @@ framework.abortInference('assistant', 'user requested stop');
451
540
 
452
541
  The non-streaming path uses `AbortSignal` forwarded to `membrane.stream()`, which returns an `AbortedResponse` with partial content. The streaming path cancels the `YieldingStream` directly.
453
542
 
454
- A turn whose stream is cancelled this way, or by `agent.cancelStream()`, ends as a stop, whether the stream reports the cancel as `aborted`, as an `error`, or by just closing: one `inference:aborted` carrying the caller's reason (`user` when none was given), a `[turn-interrupted]` note in the agent's context, and never `inference:exhausted`, which is for failed inferences. A stream that membrane aborts on its own, at a deadline or on an error (reason `timeout` or `error`), is a failed inference. `stop()` and an operator's quiesce abandon end a turn as a stop too, with their own reasons, `shutdown` and `quiesce_abandoned`, and write no note. A stopped stream still writes its inference-log row, with `success: false`.
543
+ A turn whose stream is cancelled this way, or by `agent.cancelStream()`, ends as a stop, whether the stream reports the cancel as `aborted`, as an `error`, or by just closing: one `inference:aborted` carrying the caller's reason (`user` when none was given), a `[turn-interrupted]` note in the agent's context, and never `inference:exhausted`, which is for failed inferences. A stream that membrane aborts on its own, at a deadline or on an error (reason `timeout` or `error`), is a failed inference. `stop()` and an operator's quiesce abandon end a turn as a stop too, with their own reasons, `shutdown` and `quiesce_abandoned`, and write no note, except the `[speech-not-posted]` notice when the turn's rounds left speech unposted (XML tool mode, or a membrane without `roundContent`; see below). A stopped stream still writes its inference-log row, with `success: false`.
544
+
545
+ A caller's stop and an operator's quiesce abandon also reach a turn that has no live stream: one running its modules' `gatherContext`, its MCPL hooks or its compile, one waiting to retry a failed inference or compile (`abortInference()` and an operator's abandon end the wait, and a stop through `Agent.cancelStream()` waits for it to run out), and one whose tool-result guard is waiting to retry after a refusal, which holds only the round's finished stream. The turn ends at its next check, before it sends anything more, as a stop on a live stream ends it, and a turn whose compile fails after the stop ends at the failure, before a provider hold, the error policy's retry or `inference:exhausted`. A caller's stop leaves the note saying the turn was stopped before it sent anything or before it finished, and an operator's abandon leaves none, except the `[speech-not-posted]` notice when the turn's rounds left speech unposted. `abortInference()` returns `true` for such a turn. In the guard's wait, `stop()` ends the turn as a stop with reason `shutdown`, and an operator's abandon ends it as the abandon, even when a caller's stop came first; with both, it ends as `stop()`'s. `stop()` drops a turn in its hooks, its compile or a wait to retry before it sends anything, as before, and drops one whose compile fails while it runs, once a caller's stop has reached it, rather than ending it as that stop. While the failure of a turn's stream is reported (`inference:failed`), the agent no longer holds that stream, so `abortInference()` from a listener reports `false`. A failure to build a turn's request is reported while the turn's check is still ahead, so there `abortInference()` reports `true`, and the turn ends at that check. A caller's stop made where no check of a turn is ahead stops nothing, and doesn't end the agent's next turn: while the agent is idle, while a turn finishes its last delivery, and while a non-streaming turn's tool results wait to start the turn's next call. A turn whose continuation (a budget restart's, or a tool-result guard's retry) waits to start, or whose failed call a provider-capacity hold or a provider's stated wait keeps for its retry, is ended by `abortInference()`, by an operator's quiesce abandon and by `stop()`: the continuation or retry is dropped, and the turn ends with the caller's reason, `quiesce_abandoned` or `shutdown`. After `abortInference()` or an abandon, wakes that arrived meanwhile still run (after the abandon, once the host resumes): those a hold keeps beside the retry, and those the scheduler merged into the retry's or the continuation's start before that start began, which the stop or the abandon puts back in the queue. A stop through `Agent.cancelStream()` stops nothing there.
455
546
 
456
- A caller's stop and an operator's quiesce abandon also reach a turn that has no live stream: one running its modules' `gatherContext`, its MCPL hooks or its compile, one waiting to retry a failed inference or compile (`abortInference()` and an operator's abandon end the wait, and a stop through `Agent.cancelStream()` waits for it to run out), and one whose tool-result guard is waiting to retry after a refusal, which holds only the round's finished stream. The turn ends at its next check, before it sends anything more, as a stop on a live stream ends it, and a turn whose compile fails after the stop ends at the failure, before a provider hold, the error policy's retry or `inference:exhausted`. A caller's stop leaves the note saying the turn was stopped before it sent anything or before it finished, and an operator's abandon leaves none. `abortInference()` returns `true` for such a turn. In the guard's wait, `stop()` ends the turn as a stop with reason `shutdown`, and an operator's abandon ends it as the abandon, even when a caller's stop came first; with both, it ends as `stop()`'s. `stop()` drops a turn in its hooks, its compile or a wait to retry before it sends anything, as before, and drops one whose compile fails while it runs, once a caller's stop has reached it, rather than ending it as that stop. While the failure of a turn's stream is reported (`inference:failed`), the agent no longer holds that stream, so `abortInference()` from a listener reports `false`. A failure to build a turn's request is reported while the turn's check is still ahead, so there `abortInference()` reports `true`, and the turn ends at that check. A caller's stop made where no check of a turn is ahead stops nothing, and doesn't end the agent's next turn: while the agent is idle, while a turn finishes its last delivery, and while a non-streaming turn's tool results wait to start the turn's next call. A turn whose continuation (a budget restart's, or a tool-result guard's retry) waits to start, or whose failed call a provider-capacity hold or a provider's stated wait keeps for its retry, is ended by `abortInference()`, by an operator's quiesce abandon and by `stop()`: the continuation or retry is dropped, and the turn ends with the caller's reason, `quiesce_abandoned` or `shutdown`. After `abortInference()` or an abandon, wakes that arrived meanwhile still run (after the abandon, once the host resumes): those a hold keeps beside the retry, and those the scheduler merged into the retry's or the continuation's start before that start began, which the stop or the abandon puts back in the queue. A stop through `Agent.cancelStream()` stops nothing there.
547
+ In XML tool mode, or with a membrane that gives a tool round no `roundContent`, such a round's speech reaches a channel only when its stream completes. When the stream ends any other way (a failure, a stop, a tool that ends the turn, an error policy's retry, a context-budget or tool-result-guard restart, a quiesce abandon or `stop()`), the rounds' words are already in the agent's context, and a `[speech-not-posted]` notice tells the agent that nothing it wrote before its tool calls in those rounds was posted, so it can send what should go out again. It's written once for those rounds: where the turn ends, or before a retry's or a restart's request is sent. A turn its own `skip_reply` ends, a silent turn, a round still waiting on its tools when its stream ends (which never reaches the context) and the rounds of a stream that completes get none. In XML tool mode with thinking on, a round whose text was only thinking gets the notice too, since the framework has only the round's raw text there. A failed turn's `[inference-failed]` note says that its earlier rounds ran when any round reached the context with its results, and that a round's tool calls were started and may have taken effect when any of its streams ended before that round's results came back; a caller's stop says the latter in its `[turn-interrupted]` note too. A turn that fails, or that a caller stops, writes no `[delivered]` receipt, so when its rounds' plain speech was delivered live (native tool mode, in locus or hybrid routing), its `[inference-failed]` note, or the stop's `[turn-interrupted]` note, says that speech was handed on for delivery as written and that no `[delivered]` line was written for it. When some of its speech was still being routed as the turn ended, the note also says it may yet be posted and to check the channel before sending it again. A delivery that finished undelivered gets neither: a channel delivery's `[discord-send-failed]` note, or a refused `>>>` envelope's bounce, already says what happened. A quiesce abandon and `stop()` write neither note.
457
548
 
458
549
  ## API Server
459
550
 
@@ -1,6 +1,8 @@
1
- import type { Membrane, NormalizedRequest, ContentBlock, YieldingStream } from '@animalabs/membrane';
1
+ import type { Membrane, NormalizedMessage, NormalizedRequest, ContentBlock, ThinkingBindingEntry, YieldingStream } from '@animalabs/membrane';
2
2
  import type { CacheWireReceipt } from './kv-unified-wire.js';
3
3
  import { ToolResultGuard } from './tool-result-guard.js';
4
+ import { type PlacedDrop } from './thinking-drops.js';
5
+ import { type SentRow } from './sent-rows.js';
4
6
  import { type RequestOnlyPrompt, type SilentHeartbeatTick } from './silent-heartbeat.js';
5
7
  import { type ResolvedClockConfig } from './clock-rows.js';
6
8
  export interface ActivationRequestOptions {
@@ -9,13 +11,46 @@ export interface ActivationRequestOptions {
9
11
  /** A request that will never be sent (a preview): compile it as a dry
10
12
  * run (see `compileWithInjections` for what that leaves alone). */
11
13
  dryRun?: boolean;
14
+ /** Messages added to the compile's: a preview's stand-in for the context
15
+ * injections a start would store before its compile
16
+ * (stored-injections.ts), put where that compile would render them, as
17
+ * the window's newest rows. A preview stores nothing, so the compile
18
+ * doesn't weigh them against the budget or shape them as it would the
19
+ * stored rows. */
20
+ appendedMessages?: NormalizedMessage[];
21
+ /** `false`: the caller retries this stream's failures itself, so membrane
22
+ * sends a failed round once and hands the error up. The framework's turns
23
+ * pass it (its errorPolicy is their retry layer); a direct caller of
24
+ * startStream keeps membrane's retries. */
25
+ membraneRetries?: boolean;
26
+ }
27
+ /** A compile's render stats, as context-manager's `getRenderStats()` types
28
+ * them; each compile carries its own, where the strategy records them, in
29
+ * `CompileResult.renderStats`. */
30
+ export type RenderStats = NonNullable<ReturnType<ContextManager['getRenderStats']>>;
31
+ /** The render stats of the dry compile that built `request`, or null: see
32
+ * `AgentFramework.getRequestCompileStats`. */
33
+ export declare function dryCompileStatsOf(request: object): RenderStats | null;
34
+ /**
35
+ * What a compile is told when the agent's model binds its thinking: `compile()`'s options for a context manager
36
+ * that keeps a thinking-binding record, as agent-framework holds the binding (with the participant whose messages
37
+ * are the agent's own replies) and as digests of the request's head (bindingCompileOptions).
38
+ */
39
+ export interface BindingCompileOptions {
40
+ thinkingBinding?: {
41
+ binds: boolean;
42
+ dropBlock: boolean;
43
+ participant: string;
44
+ };
45
+ identity?: RequestIdentity;
12
46
  }
13
47
  export interface StartStreamResult {
14
48
  stream: YieldingStream;
15
49
  request: NormalizedRequest;
16
50
  /** The request-only `[Continue]` prompt this request's reply follows, if
17
51
  * any, read from the request: a new one when it ends on `[Continue]`;
18
- * else, when it ends on tool results, the prompt of the reply that called
52
+ * else, when it ends on tool results, or on tool results and then
53
+ * stored context injections alone, the prompt of the reply that called
19
54
  * those tools (`toolLoopPrompt`); else none. The framework stamps the
20
55
  * reply's rows with it (`metadata.promptedBy`), for later compiles to
21
56
  * render it before them. */
@@ -25,21 +60,54 @@ export interface StartStreamResult {
25
60
  wireReceipt: CacheWireReceipt;
26
61
  } | undefined;
27
62
  drainKvSubmissionIds?: () => string[];
63
+ /** Where each block a call of this stream reports the provider dropped came from: a stored reply this
64
+ * request's compile rendered, a round the stream appended, or neither (placeThinkingDrops). Optional, so a
65
+ * stand-in for the stream start needn't supply it; without it, no drop can be placed. */
66
+ placeDrops?: (entries: readonly ThinkingBindingEntry[]) => PlacedDrop[];
67
+ /** The compile's `thinkingRecordedAfter`, when it gave one: a reply stored at or below it predates the branch's
68
+ * thinking-binding record, so the provider may drop its thinking with no strip having missed. */
69
+ thinkingRecordedAfter?: number;
70
+ /** The key (`branchKey`) of the branch the compile read, when its provenance names one. */
71
+ thinkingBranch?: string;
72
+ /** Tells the context manager what the stream's later rounds carried after the compiled messages, every round so
73
+ * far in sent order, with this request's head (context-manager's `noteRequestSent`). Present only where the
74
+ * model binds its thinking and the context manager keeps a record it can be told of. */
75
+ noteRequestSent?: (rows: readonly SentRow[]) => boolean;
76
+ /** The stored bodies the request's compile carried, by each body's first message id (its provenance's raw bodies).
77
+ * Absent when the compile reports no provenance. */
78
+ carriedBodies?: ReadonlySet<MessageId>;
28
79
  }
29
- import type { ContextManager, TokenBudget, ContextInjection, CompileResult, MessageMetadata } from '@animalabs/context-manager';
80
+ import type { ContextManager, TokenBudget, ContextInjection, CompileResult, MessageId, MessageMetadata, RequestIdentity, ThinkingStrip } from '@animalabs/context-manager';
30
81
  import type { AgentConfig, AgentState, SameRoundThinkTextPolicy, SameRoundThinkTextPolicySource, ToolCallId, ToolCall, ToolResult, ToolDefinition, AgentInfo, InferenceResult, InferenceOptions, AgentRuntimeSettingsPatch, AgentRuntimeSettingsSnapshot, AgentRuntimeSettingsOverrides } from './types/index.js';
31
82
  /**
32
83
  * Refuse an agent config whose `promptCaching`, `toolResultGuard`,
33
- * `toolWrapperProseGuard`, `thinking.enabled` or `refusalHandling.autoRewind`
34
- * holds anything but true or false (assertBooleanSetting), or whose `thinking`
35
- * or `refusalHandling` is anything but an object, null or false
36
- * (holdsSettings). The constructor runs it first, so the rule holds wherever
37
- * an Agent is built. `create()` also runs it for each of its agents before
38
- * anything opens, and `createEphemeralAgent` before it reserves the name, so a
39
- * refusal there leaves nothing behind. Membrane reads `thinking.enabled`, and
40
- * the refusal is here because the setting is AgentConfig's.
84
+ * `toolWrapperProseGuard`, `thinking.enabled`, `thinkingBinding.dropBlock`,
85
+ * `thinkingBinding.binds` or `refusalHandling.autoRewind` holds anything but true or false
86
+ * (assertBooleanSetting, where null counts as left out), or whose `thinking`, `thinkingBinding` or
87
+ * `refusalHandling` is anything but an object, null or false (holdsSettings),
88
+ * or whose `autoContinue` resolveAutoContinue refuses. The constructor runs it
89
+ * first, so the rule holds wherever an Agent is built. `create()` also runs it
90
+ * for each of its agents before anything opens, and `createEphemeralAgent`
91
+ * before it reserves the name, so a refusal there leaves nothing behind.
92
+ * Membrane reads `thinking.enabled`, and the refusal is here because the
93
+ * setting is AgentConfig's.
41
94
  */
42
95
  export declare function assertAgentSwitches(config: AgentConfig): void;
96
+ /** `AutoContinueConfig.maxConsecutive` when left out. */
97
+ export declare const DEFAULT_AUTO_CONTINUE_MAX = 3;
98
+ /**
99
+ * `AgentConfig.autoContinue` resolved: undefined when off (left out, null or
100
+ * false), else its cap. `true` takes the default cap; an object takes
101
+ * `maxConsecutive`, a whole number from 1 to 20 (the default when left out).
102
+ * Any other value is refused.
103
+ */
104
+ export declare function resolveAutoContinue(config: AgentConfig): {
105
+ maxConsecutive: number;
106
+ } | undefined;
107
+ export declare function branchKey(branch: {
108
+ readonly id: string;
109
+ readonly created: number;
110
+ }): string;
43
111
  /**
44
112
  * An agent wraps a context manager and manages inference state.
45
113
  */
@@ -63,6 +131,12 @@ export declare class Agent {
63
131
  * blocks are preserved through Chronicle.
64
132
  */
65
133
  readonly thinking: AgentConfig['thinking'];
134
+ /** Whether requests ask the provider to drop signed thinking whose earlier
135
+ * conversation changed (see AgentConfig.thinkingBinding.dropBlock). */
136
+ private readonly thinkingDropBlock;
137
+ /** Whether the model binds its signed thinking to the conversation before
138
+ * it (see AgentConfig.thinkingBinding.binds). */
139
+ private readonly thinkingBinds;
66
140
  /** Refusal auto-rewind policy (see AgentConfig.refusalHandling). */
67
141
  readonly refusalHandling: AgentConfig['refusalHandling'];
68
142
  readonly toolResultGuard: ToolResultGuard;
@@ -70,6 +144,11 @@ export declare class Agent {
70
144
  readonly proseRouting: 'locus' | 'explicit' | 'hybrid' | 'disabled';
71
145
  /** Exact whole-response known-tool wrapper containment (default off). */
72
146
  readonly toolWrapperProseGuard: boolean;
147
+ /** Continuation after a turn the model ends itself (see
148
+ * AgentConfig.autoContinue); undefined when off. */
149
+ readonly autoContinue: {
150
+ maxConsecutive: number;
151
+ } | undefined;
73
152
  /** Clock rows' interval and precision (see AgentConfig.clock); undefined
74
153
  * when the agent writes none of its own (a resident still reads those
75
154
  * another resident writes into the shared slot). */
@@ -402,6 +481,48 @@ export declare class Agent {
402
481
  branch: string;
403
482
  sequence: number;
404
483
  } | null;
484
+ /**
485
+ * The newest consumed watermark a request carried that was answered: its
486
+ * round's tool calls, or its completion, came back. A message a boundary
487
+ * injected counts as heard only once a request carrying it is answered;
488
+ * the consumed watermark moves when the stream is handed it, before its
489
+ * request runs, so a request that fails, ending its stream with an error,
490
+ * leaves this as it was.
491
+ */
492
+ private answeredWatermark;
493
+ getAnsweredWatermark(): {
494
+ branch: string;
495
+ sequence: number;
496
+ } | null;
497
+ /** A request that carried `watermark` was answered. Requests are answered
498
+ * in the order they're sent, and the consumed watermark only advances
499
+ * within a branch, so the latest is the newest. */
500
+ markAnswered(watermark: {
501
+ branch: string;
502
+ sequence: number;
503
+ } | null): void;
504
+ /**
505
+ * Per destination (a server's channel, by its key), the newest consumed
506
+ * watermark the agent had read when it published there by a route the
507
+ * framework sees (its prose, a sleep's announcement, a channel_publish, a
508
+ * draft resend, or a send tool whose channel the framework records), on
509
+ * the branch it was taken on. A wake that carries a channel, unless it's
510
+ * marked ambient (InferenceRequest.ambient), keeps its turn unless the
511
+ * agent spoke there after reading the write the wake is for. It
512
+ * lives as long as this Agent: an agent made again starts it empty, and
513
+ * such a wake then stays.
514
+ */
515
+ private publishedThrough;
516
+ /** Note a publish into `destination` (its key), made having read through
517
+ * `readThrough`: the consumed watermark when its words were written, or
518
+ * its call made. */
519
+ notePublished(destination: string, readThrough: {
520
+ branch: string;
521
+ sequence: number;
522
+ } | null): void;
523
+ /** Whether the agent published into `destination` (its key) having read
524
+ * the row stored at `sequence` on `branch`. */
525
+ publishedAfterReading(destination: string, branch: string, sequence: number): boolean;
405
526
  /** Mark everything currently stored as consumed (the agent's creation, at
406
527
  * boot or later, and a tool boundary that injected messages into a live
407
528
  * stream declaring it carries them; see consumedWatermark). */
@@ -432,14 +553,114 @@ export declare class Agent {
432
553
  * reaches here).
433
554
  */
434
555
  private applyCompileWatermark;
556
+ /**
557
+ * The branch now (`branchKey`) and its head, as `pendingWatermark` reads it: a message stored on that branch later
558
+ * has a larger sequence. Sequences are numbered per branch, so one compares with another only on the same branch.
559
+ */
560
+ branchHead(): {
561
+ branch: string;
562
+ sequence: number;
563
+ } | undefined;
435
564
  /** The watermark a successful compile will establish (taken before, applied after). */
436
565
  private pendingWatermark;
437
566
  /** A committing compile, as for a request that is sent: the context
438
567
  * manager commits what it commits for one, the consumed watermark moves,
439
568
  * and a prepared budget change settles. To inspect what the agent would
440
569
  * see, use the framework's `previewActivation`, which compiles as a dry
441
- * run. */
570
+ * run. It isn't told the agent's thinking binding (`thinkingBinding.binds`),
571
+ * so a context manager that keeps a thinking-binding record neither reads
572
+ * nor writes the record here, and what it returns keeps thinking whose
573
+ * earlier conversation changed. */
442
574
  compileContext(budget?: TokenBudget): Promise<CompileResult>;
575
+ /**
576
+ * The stored context injections of this agent's that the last compile it
577
+ * built to send rendered (stored-injections.ts), the framework's activation
578
+ * request's or the direct API's: for each namespace and content, the parts
579
+ * the compile held, and the branch it read. A compile built to send whose
580
+ * request then isn't sent (a stop, a failure) still records: its rows stay
581
+ * in the window all the same. Undefined before the first, as after a
582
+ * restart. The framework's same-content skip reads it (renderedInjection).
583
+ */
584
+ private renderedInjections?;
585
+ /**
586
+ * Per branch (by id and created), the point a stored injection on it has
587
+ * to come after to have been in no request yet (unsentInjection): the
588
+ * newest row of this agent's window on that branch when the first plan
589
+ * there since its last compile built to send (a start's, or a preview's,
590
+ * which stores nothing) asked about a unit, before that plan's start
591
+ * stored anything. Each compile built to send that records what it
592
+ * held unsets its branch's, a restart unsets them all, and a plan asks
593
+ * here before it stores a unit, so every one of this agent's stored
594
+ * injections on a branch after its point was stored since that compile.
595
+ * Kept per branch, so a start or preview on another branch doesn't move
596
+ * this one's past a copy no request has had.
597
+ */
598
+ private readonly unsentSince;
599
+ /**
600
+ * A host's hook, called with the messages of each compile built to send
601
+ * (never a dry run), as the compile is recorded: what the request carries,
602
+ * after compression and the window have done their work. The framework
603
+ * uses it to tell when an MCPL toolset's announcement has left the context
604
+ * (RFC-014 §8.3 reminders). It must not change the messages; one that
605
+ * throws is logged, and the start goes on.
606
+ */
607
+ onCompiledToSend?: (messages: readonly unknown[]) => void;
608
+ /**
609
+ * A host's hook, called with each committing compile's `thinkingStrip` (never a dry run's) and the key of the
610
+ * branch it read (`branchKey`), as the compile returns, whether or not its request is then sent, since the
611
+ * context manager's binding record takes the strip either way. One that throws is logged. The framework sets it
612
+ * at the agent's first stream unless a host has set one, so a host's own observer stands in for the framework's,
613
+ * whose `[reasoning]` line for the agent then isn't told.
614
+ */
615
+ onThinkingStrip?: (strip: ThinkingStrip, branch: string) => void;
616
+ /**
617
+ * The newest content of `namespace` among this agent's rows stored since
618
+ * its last compile built to send (unsentSince), and whether every part of
619
+ * it is among them: rows a start stored whose compile then didn't record
620
+ * (it threw, or the start failed before it), which no request has had
621
+ * yet, and which are newer than anything renderedInjection knows. Undefined when there are none, as at every
622
+ * start whose last compile was built and recorded. A fold between that
623
+ * start and the next (a host's own committing compile, or the compression
624
+ * an over-budget retry waits for) can summarize them all the same: the
625
+ * next request then has the summary's word for them, and the start after
626
+ * it stores them again, as after any fold. The window is read back 64
627
+ * rows at a time from the newest, stopping at that point.
628
+ */
629
+ unsentInjection(namespace: string): {
630
+ contentHash: string;
631
+ whole: boolean;
632
+ } | undefined;
633
+ /** Record which of this agent's stored injections a compile built to send
634
+ * rendered. Another agent's stored rows never reach this agent's compile,
635
+ * since every compile of a shared store leaves them out by its view
636
+ * filter (isAnotherAgentsInjection): a compile of a shared store without
637
+ * that filter would mix them in here. */
638
+ private noteRenderedInjections;
639
+ /**
640
+ * The newest content of `namespace` among this agent's stored injections
641
+ * that the last compile built to send rendered, by its newest copy: its
642
+ * content hash, and whether every part of that content was there in some
643
+ * copy, every shard, however the strategy shaped it. Undefined when none
644
+ * was, when this agent hasn't built a request since it started, or when
645
+ * the window's branch has changed since.
646
+ */
647
+ renderedInjection(namespace: string): {
648
+ contentHash: string;
649
+ whole: boolean;
650
+ } | undefined;
651
+ /**
652
+ * Whether compiled message `i` of `result` is a row of this agent's stored
653
+ * context injections (stored-injections.ts): rendered as an injection's
654
+ * participant, and each of its stored rows, by the compile's provenance,
655
+ * carrying this agent's mark. A speaker merely named like an injection's
656
+ * participant isn't one. Only such a message's rows are read, so a start
657
+ * reads the store for those alone.
658
+ */
659
+ private isStoredInjectionRow;
660
+ /** A stored row's injection mark, or undefined for any other row, and for
661
+ * one the store can't read just now, which is logged: a start doesn't fail
662
+ * on it (the row then counts as no stored injection). */
663
+ private storedMarkOf;
443
664
  /**
444
665
  * Compile the context with injections (e.g. from MCPL servers), which the
445
666
  * context manager merges into the compiled messages. Without
@@ -451,15 +672,23 @@ export declare class Agent {
451
672
  compileWithInjections(budget?: TokenBudget, injections?: ContextInjection[], opts?: {
452
673
  kvUnifiedImmutablePrefixHash?: string;
453
674
  dryRun?: boolean;
454
- }): Promise<CompileResult>;
675
+ } & BindingCompileOptions): Promise<CompileResult>;
455
676
  /**
456
677
  * Run inference and return result with tool calls and speech content.
457
- * Updates agent state during execution.
678
+ * Updates agent state during execution. Its compile commits. With
679
+ * `thinkingBinding.binds` it also writes the context manager's
680
+ * thinking-binding record, so then call it only while none of this agent's
681
+ * requests is streaming: a stream open meanwhile then has its later notes
682
+ * write nothing, and its replies go without their thinking at the next
683
+ * compile. Its own reply is never noted, so with `binds` its thinking is
684
+ * left out at the compile after it's stored.
458
685
  */
459
686
  runInference(availableTools: ToolDefinition[], budget?: TokenBudget, options?: InferenceOptions): Promise<InferenceResult>;
460
687
  /**
461
688
  * Run inference with context injections.
462
- * Same as runInference but passes injections through to compile.
689
+ * Same as runInference but passes injections through to compile. Its
690
+ * compile commits, and with `thinkingBinding.binds` writes the
691
+ * thinking-binding record, as runInference's does (see there).
463
692
  */
464
693
  runInferenceWithInjections(availableTools: ToolDefinition[], injections?: ContextInjection[], budget?: TokenBudget, options?: InferenceOptions): Promise<InferenceResult>;
465
694
  /**
@@ -486,7 +715,10 @@ export declare class Agent {
486
715
  * watermark); a preview passes `options.dryRun`, so its compile commits
487
716
  * none of that (see `compileWithInjections` for what a dry run still
488
717
  * leaves). Either way the context manager is handed the compression tool
489
- * definitions. Safe to call regardless of the agent's current status.
718
+ * definitions. Safe to call regardless of the agent's current status,
719
+ * except that with `thinkingBinding.binds` a compile that isn't a dry run
720
+ * writes the context manager's binding record, so while one of the
721
+ * agent's requests streams, a call to look passes `options.dryRun`.
490
722
  * It doesn't wait for the tool-result guard's annotations, so a preview
491
723
  * never waits on a workspace write (rollback, undo and redo report one), and
492
724
  * may show a withheld stub before its place is added; the activation waits
@@ -495,13 +727,47 @@ export declare class Agent {
495
727
  private assembleActivationRequest;
496
728
  /**
497
729
  * The request fields that come from this agent's own settings: its model
498
- * config, prompt caching and cache TTL, prefill message, provider
499
- * parameters and participant name. Every request the agent sends takes
500
- * them from here, a framework turn's (assembleActivationRequest) and the
501
- * direct API's (runInferenceWithInjections), so a setting reaches both or
502
- * neither.
730
+ * config, thinking binding, prompt caching and cache TTL, prefill message,
731
+ * provider parameters and participant name. Every request the agent sends
732
+ * takes them from here, a framework turn's (assembleActivationRequest) and
733
+ * the direct API's (runInferenceWithInjections), so a setting reaches both
734
+ * or neither.
503
735
  */
504
736
  private requestSettings;
737
+ /**
738
+ * The thinking config a request carries: the agent's own, with the binding
739
+ * control added when `thinkingBinding.dropBlock` asks for it. A model whose
740
+ * thinking is always on takes the control whatever `enabled` says, so an
741
+ * agent with no thinking config of its own still sends one, holding only
742
+ * the control and `enabled: false`. Membrane sends nothing from it to any
743
+ * other model, since thinking is off there.
744
+ */
745
+ private requestThinking;
746
+ /** The stream's way to tell the context manager what its later rounds sent, with the head its compile was given:
747
+ * where the agent's model binds its thinking (context-manager's `noteRequestSent`). */
748
+ private requestNotes;
749
+ /**
750
+ * The binding a compile of this agent is told of (bindingCompileOptions), and a preview of its context too: the
751
+ * participant whose messages are its replies is its own name. Undefined where the model doesn't bind.
752
+ * @internal For the framework's preview and its budget rule; not a host API.
753
+ */
754
+ thinkingBindingOption(): {
755
+ binds: true;
756
+ dropBlock: boolean;
757
+ participant: string;
758
+ } | undefined;
759
+ /**
760
+ * What a compile the agent sends tells the context manager when the model binds its thinking
761
+ * (`thinkingBinding.binds`): the binding as set, with the agent's own name as the participant whose messages
762
+ * are its replies (an agent stores its replies under its name), and a digest of each part of the request ahead of
763
+ * its messages, so a changed one can stand for a first difference where the context manager keeps a
764
+ * thinking-binding record. The system text is the one the request will carry, built from the system-position
765
+ * injections given to the compile as the kv-unified prefix hash builds it; the tools are the ones it will carry, in
766
+ * their order; `request` covers the thinking config, `maxTokens` and `providerParams`, where a host puts its own
767
+ * thinking config and `tool_choice`, and `prefillUserMessage`, which membrane sends as a leading user turn ahead
768
+ * of a conversation that would begin with the assistant. Nothing without `binds`: the compile is as it was.
769
+ */
770
+ private bindingCompileOptions;
505
771
  /** The request `assembleActivationRequest` builds (see there), for preview
506
772
  * and debug tooling: what this agent's next activation would send. */
507
773
  buildActivationRequest(availableTools: ToolDefinition[], injections?: ContextInjection[], budget?: TokenBudget, compressionTools?: ToolDefinition[], options?: ActivationRequestOptions): Promise<NormalizedRequest>;
@@ -530,7 +796,7 @@ export declare class Agent {
530
796
  * Add an assistant response to context.
531
797
  * Called by framework when stream completes.
532
798
  */
533
- addAssistantResponse(content: ContentBlock[], metadata?: MessageMetadata): void;
799
+ addAssistantResponse(content: ContentBlock[], metadata?: MessageMetadata): MessageId | undefined;
534
800
  /**
535
801
  * Transition back to streaming state after tool results are provided.
536
802
  */
@@ -558,7 +824,9 @@ export declare class Agent {
558
824
  * one is still ahead; otherwise the next start drops it. `reason` is
559
825
  * provenance for the framework's inference:aborted trace and marker
560
826
  * metadata (e.g. 'zombie_reclaim', 'subagent_cancel'); it never reaches
561
- * the provider.
827
+ * the provider. When the stream's cancel() throws, the throw goes on to
828
+ * the caller, and the agent still holds the stream, its cancel record as
829
+ * it was before the call.
562
830
  */
563
831
  cancelStream(reason?: string): void;
564
832
  /** Collect (and clear) the cancelStream() made while this agent held no