@animalabs/agent-framework 0.22.1 → 0.22.3

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 (946) hide show
  1. package/README.md +4 -2
  2. package/dist/src/agent.d.ts +266 -28
  3. package/dist/src/agent.d.ts.map +1 -1
  4. package/dist/src/agent.js +539 -104
  5. package/dist/src/agent.js.map +1 -1
  6. package/dist/src/api/mcp-server-core.d.ts +41 -0
  7. package/dist/src/api/mcp-server-core.d.ts.map +1 -0
  8. package/dist/src/api/mcp-server-core.js +593 -0
  9. package/dist/src/api/mcp-server-core.js.map +1 -0
  10. package/dist/src/api/mcp-server.d.ts +2 -36
  11. package/dist/src/api/mcp-server.d.ts.map +1 -1
  12. package/dist/src/api/mcp-server.js +15 -595
  13. package/dist/src/api/mcp-server.js.map +1 -1
  14. package/dist/src/api/server.d.ts +9 -1
  15. package/dist/src/api/server.d.ts.map +1 -1
  16. package/dist/src/api/server.js +55 -27
  17. package/dist/src/api/server.js.map +1 -1
  18. package/dist/src/api/types.d.ts +10 -2
  19. package/dist/src/api/types.d.ts.map +1 -1
  20. package/dist/src/branch-names.d.ts +14 -0
  21. package/dist/src/branch-names.d.ts.map +1 -0
  22. package/dist/src/branch-names.js +22 -0
  23. package/dist/src/branch-names.js.map +1 -0
  24. package/dist/src/closest-names.d.ts +28 -0
  25. package/dist/src/closest-names.d.ts.map +1 -0
  26. package/dist/src/closest-names.js +98 -0
  27. package/dist/src/closest-names.js.map +1 -0
  28. package/dist/src/code-execution/py-runner.d.ts +16 -5
  29. package/dist/src/code-execution/py-runner.d.ts.map +1 -1
  30. package/dist/src/code-execution/py-runner.js +186 -74
  31. package/dist/src/code-execution/py-runner.js.map +1 -1
  32. package/dist/src/code-execution/runtime-py.d.ts.map +1 -1
  33. package/dist/src/code-execution/runtime-py.js +49 -3
  34. package/dist/src/code-execution/runtime-py.js.map +1 -1
  35. package/dist/src/code-execution/tool-definition.d.ts +12 -1
  36. package/dist/src/code-execution/tool-definition.d.ts.map +1 -1
  37. package/dist/src/code-execution/tool-definition.js +21 -3
  38. package/dist/src/code-execution/tool-definition.js.map +1 -1
  39. package/dist/src/config-checks.d.ts +28 -0
  40. package/dist/src/config-checks.d.ts.map +1 -0
  41. package/dist/src/config-checks.js +52 -0
  42. package/dist/src/config-checks.js.map +1 -0
  43. package/dist/src/deadline-timer.d.ts +21 -0
  44. package/dist/src/deadline-timer.d.ts.map +1 -0
  45. package/dist/src/deadline-timer.js +43 -0
  46. package/dist/src/deadline-timer.js.map +1 -0
  47. package/dist/src/error-message.d.ts +30 -0
  48. package/dist/src/error-message.d.ts.map +1 -0
  49. package/dist/src/error-message.js +50 -0
  50. package/dist/src/error-message.js.map +1 -0
  51. package/dist/src/framework.d.ts +1212 -192
  52. package/dist/src/framework.d.ts.map +1 -1
  53. package/dist/src/framework.js +6686 -1835
  54. package/dist/src/framework.js.map +1 -1
  55. package/dist/src/gate/event-gate.d.ts +8 -0
  56. package/dist/src/gate/event-gate.d.ts.map +1 -1
  57. package/dist/src/gate/event-gate.js +27 -3
  58. package/dist/src/gate/event-gate.js.map +1 -1
  59. package/dist/src/gate/gate-script.d.ts.map +1 -1
  60. package/dist/src/gate/gate-script.js.map +1 -1
  61. package/dist/src/index.d.ts +5 -3
  62. package/dist/src/index.d.ts.map +1 -1
  63. package/dist/src/index.js +5 -3
  64. package/dist/src/index.js.map +1 -1
  65. package/dist/src/mcpl/capability-grant.d.ts.map +1 -1
  66. package/dist/src/mcpl/channel-registry.d.ts +170 -13
  67. package/dist/src/mcpl/channel-registry.d.ts.map +1 -1
  68. package/dist/src/mcpl/channel-registry.js +499 -258
  69. package/dist/src/mcpl/channel-registry.js.map +1 -1
  70. package/dist/src/mcpl/checkpoint-manager.d.ts +21 -1
  71. package/dist/src/mcpl/checkpoint-manager.d.ts.map +1 -1
  72. package/dist/src/mcpl/checkpoint-manager.js +91 -30
  73. package/dist/src/mcpl/checkpoint-manager.js.map +1 -1
  74. package/dist/src/mcpl/conversation-router.d.ts +19 -3
  75. package/dist/src/mcpl/conversation-router.d.ts.map +1 -1
  76. package/dist/src/mcpl/conversation-router.js +23 -8
  77. package/dist/src/mcpl/conversation-router.js.map +1 -1
  78. package/dist/src/mcpl/convert-block.d.ts +20 -0
  79. package/dist/src/mcpl/convert-block.d.ts.map +1 -0
  80. package/dist/src/mcpl/convert-block.js +89 -0
  81. package/dist/src/mcpl/convert-block.js.map +1 -0
  82. package/dist/src/mcpl/errors.d.ts +13 -0
  83. package/dist/src/mcpl/errors.d.ts.map +1 -1
  84. package/dist/src/mcpl/errors.js +28 -0
  85. package/dist/src/mcpl/errors.js.map +1 -1
  86. package/dist/src/mcpl/feature-set-manager.d.ts.map +1 -1
  87. package/dist/src/mcpl/feature-set-manager.js +4 -3
  88. package/dist/src/mcpl/feature-set-manager.js.map +1 -1
  89. package/dist/src/mcpl/hook-orchestrator.d.ts +23 -0
  90. package/dist/src/mcpl/hook-orchestrator.d.ts.map +1 -1
  91. package/dist/src/mcpl/hook-orchestrator.js +83 -72
  92. package/dist/src/mcpl/hook-orchestrator.js.map +1 -1
  93. package/dist/src/mcpl/inbound-source.d.ts +114 -0
  94. package/dist/src/mcpl/inbound-source.d.ts.map +1 -0
  95. package/dist/src/mcpl/inbound-source.js +83 -0
  96. package/dist/src/mcpl/inbound-source.js.map +1 -0
  97. package/dist/src/mcpl/index.d.ts +3 -1
  98. package/dist/src/mcpl/index.d.ts.map +1 -1
  99. package/dist/src/mcpl/index.js +3 -1
  100. package/dist/src/mcpl/index.js.map +1 -1
  101. package/dist/src/mcpl/inference-router.d.ts +15 -11
  102. package/dist/src/mcpl/inference-router.d.ts.map +1 -1
  103. package/dist/src/mcpl/inference-router.js +153 -84
  104. package/dist/src/mcpl/inference-router.js.map +1 -1
  105. package/dist/src/mcpl/log-value.d.ts +54 -0
  106. package/dist/src/mcpl/log-value.d.ts.map +1 -0
  107. package/dist/src/mcpl/log-value.js +109 -0
  108. package/dist/src/mcpl/log-value.js.map +1 -0
  109. package/dist/src/mcpl/prose-stream-router.d.ts +6 -6
  110. package/dist/src/mcpl/prose-stream-router.d.ts.map +1 -1
  111. package/dist/src/mcpl/prose-stream-router.js +4 -4
  112. package/dist/src/mcpl/prose-stream-router.js.map +1 -1
  113. package/dist/src/mcpl/push-coalescer.d.ts +64 -7
  114. package/dist/src/mcpl/push-coalescer.d.ts.map +1 -1
  115. package/dist/src/mcpl/push-coalescer.js +121 -24
  116. package/dist/src/mcpl/push-coalescer.js.map +1 -1
  117. package/dist/src/mcpl/push-handler.d.ts +38 -8
  118. package/dist/src/mcpl/push-handler.d.ts.map +1 -1
  119. package/dist/src/mcpl/push-handler.js +77 -78
  120. package/dist/src/mcpl/push-handler.js.map +1 -1
  121. package/dist/src/mcpl/reference-fetcher.d.ts +14 -2
  122. package/dist/src/mcpl/reference-fetcher.d.ts.map +1 -1
  123. package/dist/src/mcpl/reference-fetcher.js +72 -30
  124. package/dist/src/mcpl/reference-fetcher.js.map +1 -1
  125. package/dist/src/mcpl/references.d.ts +49 -14
  126. package/dist/src/mcpl/references.d.ts.map +1 -1
  127. package/dist/src/mcpl/references.js +74 -21
  128. package/dist/src/mcpl/references.js.map +1 -1
  129. package/dist/src/mcpl/refusal-lines.d.ts +37 -0
  130. package/dist/src/mcpl/refusal-lines.d.ts.map +1 -0
  131. package/dist/src/mcpl/refusal-lines.js +61 -0
  132. package/dist/src/mcpl/refusal-lines.js.map +1 -0
  133. package/dist/src/mcpl/scope-manager.d.ts.map +1 -1
  134. package/dist/src/mcpl/server-connection.d.ts +107 -12
  135. package/dist/src/mcpl/server-connection.d.ts.map +1 -1
  136. package/dist/src/mcpl/server-connection.js +470 -139
  137. package/dist/src/mcpl/server-connection.js.map +1 -1
  138. package/dist/src/mcpl/server-registry.d.ts +10 -1
  139. package/dist/src/mcpl/server-registry.d.ts.map +1 -1
  140. package/dist/src/mcpl/server-registry.js +14 -3
  141. package/dist/src/mcpl/server-registry.js.map +1 -1
  142. package/dist/src/mcpl/skip-reply-wake.d.ts +36 -0
  143. package/dist/src/mcpl/skip-reply-wake.d.ts.map +1 -0
  144. package/dist/src/mcpl/skip-reply-wake.js +55 -0
  145. package/dist/src/mcpl/skip-reply-wake.js.map +1 -0
  146. package/dist/src/mcpl/tool-classes.d.ts +1 -1
  147. package/dist/src/mcpl/tool-classes.d.ts.map +1 -1
  148. package/dist/src/mcpl/tool-classes.js +3 -2
  149. package/dist/src/mcpl/tool-classes.js.map +1 -1
  150. package/dist/src/mcpl/tool-lifecycle.d.ts.map +1 -1
  151. package/dist/src/mcpl/tool-lifecycle.js.map +1 -1
  152. package/dist/src/mcpl/transport.d.ts +74 -7
  153. package/dist/src/mcpl/transport.d.ts.map +1 -1
  154. package/dist/src/mcpl/transport.js +209 -22
  155. package/dist/src/mcpl/transport.js.map +1 -1
  156. package/dist/src/mcpl/types.d.ts +43 -28
  157. package/dist/src/mcpl/types.d.ts.map +1 -1
  158. package/dist/src/mcpl/types.js.map +1 -1
  159. package/dist/src/mcpl/visible-content.d.ts +15 -0
  160. package/dist/src/mcpl/visible-content.d.ts.map +1 -1
  161. package/dist/src/mcpl/visible-content.js +25 -0
  162. package/dist/src/mcpl/visible-content.js.map +1 -1
  163. package/dist/src/module-registry.d.ts +19 -1
  164. package/dist/src/module-registry.d.ts.map +1 -1
  165. package/dist/src/module-registry.js +54 -25
  166. package/dist/src/module-registry.js.map +1 -1
  167. package/dist/src/modules/api/index.d.ts.map +1 -1
  168. package/dist/src/modules/api/index.js +1 -1
  169. package/dist/src/modules/api/index.js.map +1 -1
  170. package/dist/src/modules/discord/discord-js-client.d.ts +1 -0
  171. package/dist/src/modules/discord/discord-js-client.d.ts.map +1 -1
  172. package/dist/src/modules/discord/discord-js-client.js +25 -9
  173. package/dist/src/modules/discord/discord-js-client.js.map +1 -1
  174. package/dist/src/modules/discord/index.d.ts +29 -3
  175. package/dist/src/modules/discord/index.d.ts.map +1 -1
  176. package/dist/src/modules/discord/index.js +383 -145
  177. package/dist/src/modules/discord/index.js.map +1 -1
  178. package/dist/src/modules/discord/types.d.ts +14 -1
  179. package/dist/src/modules/discord/types.d.ts.map +1 -1
  180. package/dist/src/modules/health/index.d.ts.map +1 -1
  181. package/dist/src/modules/health/index.js +2 -1
  182. package/dist/src/modules/health/index.js.map +1 -1
  183. package/dist/src/modules/history/index.d.ts +3 -1
  184. package/dist/src/modules/history/index.d.ts.map +1 -1
  185. package/dist/src/modules/history/index.js +359 -127
  186. package/dist/src/modules/history/index.js.map +1 -1
  187. package/dist/src/modules/history/semantic.d.ts +28 -1
  188. package/dist/src/modules/history/semantic.d.ts.map +1 -1
  189. package/dist/src/modules/history/semantic.js +177 -32
  190. package/dist/src/modules/history/semantic.js.map +1 -1
  191. package/dist/src/modules/unknown-tool.d.ts +10 -0
  192. package/dist/src/modules/unknown-tool.d.ts.map +1 -0
  193. package/dist/src/modules/unknown-tool.js +17 -0
  194. package/dist/src/modules/unknown-tool.js.map +1 -0
  195. package/dist/src/modules/workspace/branch-intent.d.ts.map +1 -1
  196. package/dist/src/modules/workspace/branch-intent.js.map +1 -1
  197. package/dist/src/modules/workspace/disk-agreement.d.ts +54 -6
  198. package/dist/src/modules/workspace/disk-agreement.d.ts.map +1 -1
  199. package/dist/src/modules/workspace/disk-agreement.js +93 -27
  200. package/dist/src/modules/workspace/disk-agreement.js.map +1 -1
  201. package/dist/src/modules/workspace/effects.d.ts +64 -6
  202. package/dist/src/modules/workspace/effects.d.ts.map +1 -1
  203. package/dist/src/modules/workspace/effects.js +291 -44
  204. package/dist/src/modules/workspace/effects.js.map +1 -1
  205. package/dist/src/modules/workspace/index.d.ts +127 -27
  206. package/dist/src/modules/workspace/index.d.ts.map +1 -1
  207. package/dist/src/modules/workspace/index.js +821 -248
  208. package/dist/src/modules/workspace/index.js.map +1 -1
  209. package/dist/src/modules/workspace/observe.d.ts +117 -15
  210. package/dist/src/modules/workspace/observe.d.ts.map +1 -1
  211. package/dist/src/modules/workspace/observe.js +436 -51
  212. package/dist/src/modules/workspace/observe.js.map +1 -1
  213. package/dist/src/modules/workspace/reconcile.d.ts +75 -8
  214. package/dist/src/modules/workspace/reconcile.d.ts.map +1 -1
  215. package/dist/src/modules/workspace/reconcile.js +576 -68
  216. package/dist/src/modules/workspace/reconcile.js.map +1 -1
  217. package/dist/src/modules/workspace/types.d.ts +42 -3
  218. package/dist/src/modules/workspace/types.d.ts.map +1 -1
  219. package/dist/src/modules/workspace/types.js.map +1 -1
  220. package/dist/src/modules/workspace/watcher.d.ts +7 -2
  221. package/dist/src/modules/workspace/watcher.d.ts.map +1 -1
  222. package/dist/src/modules/workspace/watcher.js +28 -4
  223. package/dist/src/modules/workspace/watcher.js.map +1 -1
  224. package/dist/src/operator-log.d.ts.map +1 -1
  225. package/dist/src/operator-log.js.map +1 -1
  226. package/dist/src/prose-drafts.d.ts +240 -0
  227. package/dist/src/prose-drafts.d.ts.map +1 -0
  228. package/dist/src/prose-drafts.js +362 -0
  229. package/dist/src/prose-drafts.js.map +1 -0
  230. package/dist/src/prose-segments.d.ts +21 -2
  231. package/dist/src/prose-segments.d.ts.map +1 -1
  232. package/dist/src/prose-segments.js +46 -9
  233. package/dist/src/prose-segments.js.map +1 -1
  234. package/dist/src/provider-waits.d.ts.map +1 -1
  235. package/dist/src/provider-waits.js.map +1 -1
  236. package/dist/src/queue.d.ts.map +1 -1
  237. package/dist/src/record-journal.d.ts.map +1 -1
  238. package/dist/src/record-journal.js.map +1 -1
  239. package/dist/src/recovery/discord-awareness-outbox.d.ts.map +1 -1
  240. package/dist/src/recovery/discord-awareness-outbox.js.map +1 -1
  241. package/dist/src/recovery/offline-branch.d.ts +1 -0
  242. package/dist/src/recovery/offline-branch.d.ts.map +1 -1
  243. package/dist/src/recovery/offline-branch.js +32 -25
  244. package/dist/src/recovery/offline-branch.js.map +1 -1
  245. package/dist/src/recovery/recover-cli.js.map +1 -1
  246. package/dist/src/runtime/liveness-watchdog.d.ts.map +1 -1
  247. package/dist/src/runtime/liveness-watchdog.js.map +1 -1
  248. package/dist/src/safe-slice.d.ts +5 -1
  249. package/dist/src/safe-slice.d.ts.map +1 -1
  250. package/dist/src/safe-slice.js +9 -1
  251. package/dist/src/safe-slice.js.map +1 -1
  252. package/dist/src/shutdown.d.ts.map +1 -1
  253. package/dist/src/shutdown.js.map +1 -1
  254. package/dist/src/stored-removal.d.ts +73 -0
  255. package/dist/src/stored-removal.d.ts.map +1 -0
  256. package/dist/src/stored-removal.js +100 -0
  257. package/dist/src/stored-removal.js.map +1 -0
  258. package/dist/src/thinking-token-stamp.js.map +1 -1
  259. package/dist/src/tool-image-ledger.d.ts +87 -19
  260. package/dist/src/tool-image-ledger.d.ts.map +1 -1
  261. package/dist/src/tool-image-ledger.js +135 -32
  262. package/dist/src/tool-image-ledger.js.map +1 -1
  263. package/dist/src/tool-presentation.d.ts +9 -0
  264. package/dist/src/tool-presentation.d.ts.map +1 -1
  265. package/dist/src/tool-presentation.js +257 -60
  266. package/dist/src/tool-presentation.js.map +1 -1
  267. package/dist/src/tool-result-guard.d.ts.map +1 -1
  268. package/dist/src/tool-result-guard.js +7 -10
  269. package/dist/src/tool-result-guard.js.map +1 -1
  270. package/dist/src/tool-result-history.d.ts +32 -3
  271. package/dist/src/tool-result-history.d.ts.map +1 -1
  272. package/dist/src/tool-result-history.js +106 -19
  273. package/dist/src/tool-result-history.js.map +1 -1
  274. package/dist/src/tune-out/coordinator.d.ts +25 -1
  275. package/dist/src/tune-out/coordinator.d.ts.map +1 -1
  276. package/dist/src/tune-out/coordinator.js +260 -65
  277. package/dist/src/tune-out/coordinator.js.map +1 -1
  278. package/dist/src/tune-out/tools.d.ts +1 -1
  279. package/dist/src/tune-out/tools.d.ts.map +1 -1
  280. package/dist/src/types/agent.d.ts +59 -11
  281. package/dist/src/types/agent.d.ts.map +1 -1
  282. package/dist/src/types/events.d.ts +17 -0
  283. package/dist/src/types/events.d.ts.map +1 -1
  284. package/dist/src/types/framework.d.ts +31 -5
  285. package/dist/src/types/framework.d.ts.map +1 -1
  286. package/dist/src/types/inference-log.d.ts +1 -1
  287. package/dist/src/types/inference-log.d.ts.map +1 -1
  288. package/dist/src/types/module.d.ts +30 -7
  289. package/dist/src/types/module.d.ts.map +1 -1
  290. package/dist/src/types/trace.d.ts +151 -11
  291. package/dist/src/types/trace.d.ts.map +1 -1
  292. package/dist/src/usage/usage-tracker.d.ts +5 -0
  293. package/dist/src/usage/usage-tracker.d.ts.map +1 -1
  294. package/dist/src/usage/usage-tracker.js +35 -8
  295. package/dist/src/usage/usage-tracker.js.map +1 -1
  296. package/package.json +10 -9
  297. package/src/agent.ts +572 -105
  298. package/src/api/mcp-server-core.ts +681 -0
  299. package/src/api/mcp-server.ts +16 -685
  300. package/src/api/server.ts +55 -30
  301. package/src/api/types.ts +10 -2
  302. package/src/branch-names.ts +19 -0
  303. package/src/closest-names.ts +94 -0
  304. package/src/code-execution/py-runner.ts +200 -76
  305. package/src/code-execution/runtime-py.ts +49 -3
  306. package/src/code-execution/tool-definition.ts +28 -4
  307. package/src/config-checks.ts +48 -0
  308. package/src/deadline-timer.ts +44 -0
  309. package/src/error-message.ts +48 -0
  310. package/src/framework.ts +7158 -1936
  311. package/src/gate/event-gate.ts +28 -3
  312. package/src/index.ts +12 -3
  313. package/src/mcpl/channel-registry.ts +615 -289
  314. package/src/mcpl/checkpoint-manager.ts +104 -29
  315. package/src/mcpl/conversation-router.ts +28 -8
  316. package/src/mcpl/convert-block.ts +97 -0
  317. package/src/mcpl/errors.ts +28 -0
  318. package/src/mcpl/feature-set-manager.ts +4 -3
  319. package/src/mcpl/hook-orchestrator.ts +84 -77
  320. package/src/mcpl/inbound-source.ts +156 -0
  321. package/src/mcpl/index.ts +10 -1
  322. package/src/mcpl/inference-router.ts +174 -99
  323. package/src/mcpl/log-value.ts +116 -0
  324. package/src/mcpl/prose-stream-router.ts +6 -6
  325. package/src/mcpl/push-coalescer.ts +124 -24
  326. package/src/mcpl/push-handler.ts +86 -84
  327. package/src/mcpl/reference-fetcher.ts +71 -26
  328. package/src/mcpl/references.ts +81 -22
  329. package/src/mcpl/refusal-lines.ts +59 -0
  330. package/src/mcpl/server-connection.ts +496 -142
  331. package/src/mcpl/server-registry.ts +15 -4
  332. package/src/mcpl/skip-reply-wake.ts +73 -0
  333. package/src/mcpl/tool-classes.ts +3 -2
  334. package/src/mcpl/transport.ts +219 -26
  335. package/src/mcpl/types.ts +18 -3
  336. package/src/mcpl/visible-content.ts +27 -0
  337. package/src/module-registry.ts +58 -23
  338. package/src/modules/api/index.ts +1 -1
  339. package/src/modules/discord/discord-js-client.ts +26 -10
  340. package/src/modules/discord/index.ts +395 -160
  341. package/src/modules/discord/types.ts +15 -2
  342. package/src/modules/health/index.ts +2 -1
  343. package/src/modules/history/index.ts +410 -120
  344. package/src/modules/history/semantic.ts +189 -32
  345. package/src/modules/unknown-tool.ts +16 -0
  346. package/src/modules/workspace/disk-agreement.ts +125 -21
  347. package/src/modules/workspace/effects.ts +279 -35
  348. package/src/modules/workspace/index.ts +841 -261
  349. package/src/modules/workspace/observe.ts +456 -56
  350. package/src/modules/workspace/reconcile.ts +688 -76
  351. package/src/modules/workspace/types.ts +41 -2
  352. package/src/modules/workspace/watcher.ts +27 -4
  353. package/src/prose-drafts.ts +481 -0
  354. package/src/prose-segments.ts +51 -8
  355. package/src/recovery/offline-branch.ts +36 -29
  356. package/src/safe-slice.ts +9 -1
  357. package/src/stored-removal.ts +126 -0
  358. package/src/tool-image-ledger.ts +153 -34
  359. package/src/tool-presentation.ts +224 -40
  360. package/src/tool-result-guard.ts +7 -8
  361. package/src/tool-result-history.ts +124 -20
  362. package/src/tune-out/coordinator.ts +259 -65
  363. package/src/types/agent.ts +59 -13
  364. package/src/types/events.ts +17 -0
  365. package/src/types/framework.ts +31 -5
  366. package/src/types/inference-log.ts +1 -1
  367. package/src/types/module.ts +31 -7
  368. package/src/types/trace.ts +158 -12
  369. package/src/usage/usage-tracker.ts +32 -8
  370. package/dist/test/activation-request-sanitize.test.d.ts +0 -2
  371. package/dist/test/activation-request-sanitize.test.d.ts.map +0 -1
  372. package/dist/test/activation-request-sanitize.test.js +0 -89
  373. package/dist/test/activation-request-sanitize.test.js.map +0 -1
  374. package/dist/test/agent-cache-ttl.test.d.ts +0 -2
  375. package/dist/test/agent-cache-ttl.test.d.ts.map +0 -1
  376. package/dist/test/agent-cache-ttl.test.js +0 -41
  377. package/dist/test/agent-cache-ttl.test.js.map +0 -1
  378. package/dist/test/agent-runtime-settings.test.d.ts +0 -2
  379. package/dist/test/agent-runtime-settings.test.d.ts.map +0 -1
  380. package/dist/test/agent-runtime-settings.test.js +0 -462
  381. package/dist/test/agent-runtime-settings.test.js.map +0 -1
  382. package/dist/test/api-admin-gate.test.d.ts +0 -2
  383. package/dist/test/api-admin-gate.test.d.ts.map +0 -1
  384. package/dist/test/api-admin-gate.test.js +0 -116
  385. package/dist/test/api-admin-gate.test.js.map +0 -1
  386. package/dist/test/assistant-persist-refusal.test.d.ts +0 -2
  387. package/dist/test/assistant-persist-refusal.test.d.ts.map +0 -1
  388. package/dist/test/assistant-persist-refusal.test.js +0 -63
  389. package/dist/test/assistant-persist-refusal.test.js.map +0 -1
  390. package/dist/test/batched-wake-locus.test.d.ts +0 -2
  391. package/dist/test/batched-wake-locus.test.d.ts.map +0 -1
  392. package/dist/test/batched-wake-locus.test.js +0 -166
  393. package/dist/test/batched-wake-locus.test.js.map +0 -1
  394. package/dist/test/busy-agent-scheduler.test.d.ts +0 -2
  395. package/dist/test/busy-agent-scheduler.test.d.ts.map +0 -1
  396. package/dist/test/busy-agent-scheduler.test.js +0 -92
  397. package/dist/test/busy-agent-scheduler.test.js.map +0 -1
  398. package/dist/test/channel-incoming-targeting.test.d.ts +0 -2
  399. package/dist/test/channel-incoming-targeting.test.d.ts.map +0 -1
  400. package/dist/test/channel-incoming-targeting.test.js +0 -81
  401. package/dist/test/channel-incoming-targeting.test.js.map +0 -1
  402. package/dist/test/channel-label-history.test.d.ts +0 -2
  403. package/dist/test/channel-label-history.test.d.ts.map +0 -1
  404. package/dist/test/channel-label-history.test.js +0 -424
  405. package/dist/test/channel-label-history.test.js.map +0 -1
  406. package/dist/test/channel-lifecycle-provenance.test.d.ts +0 -2
  407. package/dist/test/channel-lifecycle-provenance.test.d.ts.map +0 -1
  408. package/dist/test/channel-lifecycle-provenance.test.js +0 -47
  409. package/dist/test/channel-lifecycle-provenance.test.js.map +0 -1
  410. package/dist/test/channel-registry-routing.test.d.ts +0 -2
  411. package/dist/test/channel-registry-routing.test.d.ts.map +0 -1
  412. package/dist/test/channel-registry-routing.test.js +0 -446
  413. package/dist/test/channel-registry-routing.test.js.map +0 -1
  414. package/dist/test/channel-registry-typing.test.d.ts +0 -2
  415. package/dist/test/channel-registry-typing.test.d.ts.map +0 -1
  416. package/dist/test/channel-registry-typing.test.js +0 -91
  417. package/dist/test/channel-registry-typing.test.js.map +0 -1
  418. package/dist/test/channels-changed-respond-first.test.d.ts +0 -2
  419. package/dist/test/channels-changed-respond-first.test.d.ts.map +0 -1
  420. package/dist/test/channels-changed-respond-first.test.js +0 -74
  421. package/dist/test/channels-changed-respond-first.test.js.map +0 -1
  422. package/dist/test/checkpoint-attribution.test.d.ts +0 -2
  423. package/dist/test/checkpoint-attribution.test.d.ts.map +0 -1
  424. package/dist/test/checkpoint-attribution.test.js +0 -200
  425. package/dist/test/checkpoint-attribution.test.js.map +0 -1
  426. package/dist/test/code-execution.test.d.ts +0 -11
  427. package/dist/test/code-execution.test.d.ts.map +0 -1
  428. package/dist/test/code-execution.test.js +0 -1272
  429. package/dist/test/code-execution.test.js.map +0 -1
  430. package/dist/test/component-defaults.test.d.ts +0 -2
  431. package/dist/test/component-defaults.test.d.ts.map +0 -1
  432. package/dist/test/component-defaults.test.js +0 -54
  433. package/dist/test/component-defaults.test.js.map +0 -1
  434. package/dist/test/conversation-fork-injection-scoping.test.d.ts +0 -2
  435. package/dist/test/conversation-fork-injection-scoping.test.d.ts.map +0 -1
  436. package/dist/test/conversation-fork-injection-scoping.test.js +0 -200
  437. package/dist/test/conversation-fork-injection-scoping.test.js.map +0 -1
  438. package/dist/test/conversation-router.test.d.ts +0 -2
  439. package/dist/test/conversation-router.test.d.ts.map +0 -1
  440. package/dist/test/conversation-router.test.js +0 -174
  441. package/dist/test/conversation-router.test.js.map +0 -1
  442. package/dist/test/conversation-routing.test.d.ts +0 -7
  443. package/dist/test/conversation-routing.test.d.ts.map +0 -1
  444. package/dist/test/conversation-routing.test.js +0 -387
  445. package/dist/test/conversation-routing.test.js.map +0 -1
  446. package/dist/test/deferred-wake-integrity.test.d.ts +0 -29
  447. package/dist/test/deferred-wake-integrity.test.d.ts.map +0 -1
  448. package/dist/test/deferred-wake-integrity.test.js +0 -320
  449. package/dist/test/deferred-wake-integrity.test.js.map +0 -1
  450. package/dist/test/discord-awareness-outbox.test.d.ts +0 -2
  451. package/dist/test/discord-awareness-outbox.test.d.ts.map +0 -1
  452. package/dist/test/discord-awareness-outbox.test.js +0 -267
  453. package/dist/test/discord-awareness-outbox.test.js.map +0 -1
  454. package/dist/test/discord-history-delete-window.test.d.ts +0 -2
  455. package/dist/test/discord-history-delete-window.test.d.ts.map +0 -1
  456. package/dist/test/discord-history-delete-window.test.js +0 -81
  457. package/dist/test/discord-history-delete-window.test.js.map +0 -1
  458. package/dist/test/discord-history-sync.test.d.ts +0 -2
  459. package/dist/test/discord-history-sync.test.d.ts.map +0 -1
  460. package/dist/test/discord-history-sync.test.js +0 -56
  461. package/dist/test/discord-history-sync.test.js.map +0 -1
  462. package/dist/test/ephemeral-settle.test.d.ts +0 -2
  463. package/dist/test/ephemeral-settle.test.d.ts.map +0 -1
  464. package/dist/test/ephemeral-settle.test.js +0 -354
  465. package/dist/test/ephemeral-settle.test.js.map +0 -1
  466. package/dist/test/event-gate-passthrough.test.d.ts +0 -15
  467. package/dist/test/event-gate-passthrough.test.d.ts.map +0 -1
  468. package/dist/test/event-gate-passthrough.test.js +0 -289
  469. package/dist/test/event-gate-passthrough.test.js.map +0 -1
  470. package/dist/test/event-gate-policy-mutation.test.d.ts +0 -2
  471. package/dist/test/event-gate-policy-mutation.test.d.ts.map +0 -1
  472. package/dist/test/event-gate-policy-mutation.test.js +0 -137
  473. package/dist/test/event-gate-policy-mutation.test.js.map +0 -1
  474. package/dist/test/event-gate-rate-limit.test.d.ts +0 -2
  475. package/dist/test/event-gate-rate-limit.test.d.ts.map +0 -1
  476. package/dist/test/event-gate-rate-limit.test.js +0 -627
  477. package/dist/test/event-gate-rate-limit.test.js.map +0 -1
  478. package/dist/test/event-gate-script.test.d.ts +0 -2
  479. package/dist/test/event-gate-script.test.d.ts.map +0 -1
  480. package/dist/test/event-gate-script.test.js +0 -95
  481. package/dist/test/event-gate-script.test.js.map +0 -1
  482. package/dist/test/event-gate-selfwake.test.d.ts +0 -15
  483. package/dist/test/event-gate-selfwake.test.d.ts.map +0 -1
  484. package/dist/test/event-gate-selfwake.test.js +0 -125
  485. package/dist/test/event-gate-selfwake.test.js.map +0 -1
  486. package/dist/test/event-gate-tags.test.d.ts +0 -2
  487. package/dist/test/event-gate-tags.test.d.ts.map +0 -1
  488. package/dist/test/event-gate-tags.test.js +0 -76
  489. package/dist/test/event-gate-tags.test.js.map +0 -1
  490. package/dist/test/event-gate.test.d.ts +0 -2
  491. package/dist/test/event-gate.test.d.ts.map +0 -1
  492. package/dist/test/event-gate.test.js +0 -919
  493. package/dist/test/event-gate.test.js.map +0 -1
  494. package/dist/test/explicit-prose-routing.test.d.ts +0 -11
  495. package/dist/test/explicit-prose-routing.test.d.ts.map +0 -1
  496. package/dist/test/explicit-prose-routing.test.js +0 -1394
  497. package/dist/test/explicit-prose-routing.test.js.map +0 -1
  498. package/dist/test/framework.test.d.ts +0 -5
  499. package/dist/test/framework.test.d.ts.map +0 -1
  500. package/dist/test/framework.test.js +0 -1048
  501. package/dist/test/framework.test.js.map +0 -1
  502. package/dist/test/gather-context-timeout.test.d.ts +0 -2
  503. package/dist/test/gather-context-timeout.test.d.ts.map +0 -1
  504. package/dist/test/gather-context-timeout.test.js +0 -120
  505. package/dist/test/gather-context-timeout.test.js.map +0 -1
  506. package/dist/test/health-snapshot.test.d.ts +0 -2
  507. package/dist/test/health-snapshot.test.d.ts.map +0 -1
  508. package/dist/test/health-snapshot.test.js +0 -74
  509. package/dist/test/health-snapshot.test.js.map +0 -1
  510. package/dist/test/helpers/coalescing-fixture.d.ts +0 -72
  511. package/dist/test/helpers/coalescing-fixture.d.ts.map +0 -1
  512. package/dist/test/helpers/coalescing-fixture.js +0 -146
  513. package/dist/test/helpers/coalescing-fixture.js.map +0 -1
  514. package/dist/test/helpers/coalescing-kill-child.d.ts +0 -2
  515. package/dist/test/helpers/coalescing-kill-child.d.ts.map +0 -1
  516. package/dist/test/helpers/coalescing-kill-child.js +0 -24
  517. package/dist/test/helpers/coalescing-kill-child.js.map +0 -1
  518. package/dist/test/helpers/mock-membrane.d.ts +0 -53
  519. package/dist/test/helpers/mock-membrane.d.ts.map +0 -1
  520. package/dist/test/helpers/mock-membrane.js +0 -168
  521. package/dist/test/helpers/mock-membrane.js.map +0 -1
  522. package/dist/test/helpers/pytc-stop-rows.d.ts +0 -11
  523. package/dist/test/helpers/pytc-stop-rows.d.ts.map +0 -1
  524. package/dist/test/helpers/pytc-stop-rows.js +0 -143
  525. package/dist/test/helpers/pytc-stop-rows.js.map +0 -1
  526. package/dist/test/helpers/quiesce-crash-child.d.ts +0 -2
  527. package/dist/test/helpers/quiesce-crash-child.d.ts.map +0 -1
  528. package/dist/test/helpers/quiesce-crash-child.js +0 -156
  529. package/dist/test/helpers/quiesce-crash-child.js.map +0 -1
  530. package/dist/test/history-module-overview.test.d.ts +0 -2
  531. package/dist/test/history-module-overview.test.d.ts.map +0 -1
  532. package/dist/test/history-module-overview.test.js +0 -711
  533. package/dist/test/history-module-overview.test.js.map +0 -1
  534. package/dist/test/history-module-realstore.test.d.ts +0 -2
  535. package/dist/test/history-module-realstore.test.d.ts.map +0 -1
  536. package/dist/test/history-module-realstore.test.js +0 -363
  537. package/dist/test/history-module-realstore.test.js.map +0 -1
  538. package/dist/test/history-module-semantic.test.d.ts +0 -2
  539. package/dist/test/history-module-semantic.test.d.ts.map +0 -1
  540. package/dist/test/history-module-semantic.test.js +0 -213
  541. package/dist/test/history-module-semantic.test.js.map +0 -1
  542. package/dist/test/history-module-ux.test.d.ts +0 -2
  543. package/dist/test/history-module-ux.test.d.ts.map +0 -1
  544. package/dist/test/history-module-ux.test.js +0 -304
  545. package/dist/test/history-module-ux.test.js.map +0 -1
  546. package/dist/test/history-module.test.d.ts +0 -2
  547. package/dist/test/history-module.test.d.ts.map +0 -1
  548. package/dist/test/history-module.test.js +0 -619
  549. package/dist/test/history-module.test.js.map +0 -1
  550. package/dist/test/history-semantic-review-findings.test.d.ts +0 -2
  551. package/dist/test/history-semantic-review-findings.test.d.ts.map +0 -1
  552. package/dist/test/history-semantic-review-findings.test.js +0 -338
  553. package/dist/test/history-semantic-review-findings.test.js.map +0 -1
  554. package/dist/test/history-semantic-sync-converges.test.d.ts +0 -2
  555. package/dist/test/history-semantic-sync-converges.test.d.ts.map +0 -1
  556. package/dist/test/history-semantic-sync-converges.test.js +0 -109
  557. package/dist/test/history-semantic-sync-converges.test.js.map +0 -1
  558. package/dist/test/host-quiesce.test.d.ts +0 -2
  559. package/dist/test/host-quiesce.test.d.ts.map +0 -1
  560. package/dist/test/host-quiesce.test.js +0 -863
  561. package/dist/test/host-quiesce.test.js.map +0 -1
  562. package/dist/test/inference-exhaustion-rewind.test.d.ts +0 -2
  563. package/dist/test/inference-exhaustion-rewind.test.d.ts.map +0 -1
  564. package/dist/test/inference-exhaustion-rewind.test.js +0 -309
  565. package/dist/test/inference-exhaustion-rewind.test.js.map +0 -1
  566. package/dist/test/inference-failure-bounds.test.d.ts +0 -2
  567. package/dist/test/inference-failure-bounds.test.d.ts.map +0 -1
  568. package/dist/test/inference-failure-bounds.test.js +0 -1201
  569. package/dist/test/inference-failure-bounds.test.js.map +0 -1
  570. package/dist/test/inference-failure-observability.test.d.ts +0 -2
  571. package/dist/test/inference-failure-observability.test.d.ts.map +0 -1
  572. package/dist/test/inference-failure-observability.test.js +0 -84
  573. package/dist/test/inference-failure-observability.test.js.map +0 -1
  574. package/dist/test/journal-tool.test.d.ts +0 -2
  575. package/dist/test/journal-tool.test.d.ts.map +0 -1
  576. package/dist/test/journal-tool.test.js +0 -33
  577. package/dist/test/journal-tool.test.js.map +0 -1
  578. package/dist/test/kv-unified-open-flight-retry.test.d.ts +0 -2
  579. package/dist/test/kv-unified-open-flight-retry.test.d.ts.map +0 -1
  580. package/dist/test/kv-unified-open-flight-retry.test.js +0 -189
  581. package/dist/test/kv-unified-open-flight-retry.test.js.map +0 -1
  582. package/dist/test/kv-unified-wiring.test.d.ts +0 -2
  583. package/dist/test/kv-unified-wiring.test.d.ts.map +0 -1
  584. package/dist/test/kv-unified-wiring.test.js +0 -95
  585. package/dist/test/kv-unified-wiring.test.js.map +0 -1
  586. package/dist/test/late-events-after-stop.test.d.ts +0 -2
  587. package/dist/test/late-events-after-stop.test.d.ts.map +0 -1
  588. package/dist/test/late-events-after-stop.test.js +0 -122
  589. package/dist/test/late-events-after-stop.test.js.map +0 -1
  590. package/dist/test/liveness-watchdog.test.d.ts +0 -2
  591. package/dist/test/liveness-watchdog.test.d.ts.map +0 -1
  592. package/dist/test/liveness-watchdog.test.js +0 -94
  593. package/dist/test/liveness-watchdog.test.js.map +0 -1
  594. package/dist/test/machine-close-provenance.test.d.ts +0 -2
  595. package/dist/test/machine-close-provenance.test.d.ts.map +0 -1
  596. package/dist/test/machine-close-provenance.test.js +0 -116
  597. package/dist/test/machine-close-provenance.test.js.map +0 -1
  598. package/dist/test/maintenance-timer.test.d.ts +0 -2
  599. package/dist/test/maintenance-timer.test.d.ts.map +0 -1
  600. package/dist/test/maintenance-timer.test.js +0 -265
  601. package/dist/test/maintenance-timer.test.js.map +0 -1
  602. package/dist/test/mcpl-access-provider.test.d.ts +0 -2
  603. package/dist/test/mcpl-access-provider.test.d.ts.map +0 -1
  604. package/dist/test/mcpl-access-provider.test.js +0 -20
  605. package/dist/test/mcpl-access-provider.test.js.map +0 -1
  606. package/dist/test/mcpl-awareness-barrier.test.d.ts +0 -2
  607. package/dist/test/mcpl-awareness-barrier.test.d.ts.map +0 -1
  608. package/dist/test/mcpl-awareness-barrier.test.js +0 -769
  609. package/dist/test/mcpl-awareness-barrier.test.js.map +0 -1
  610. package/dist/test/mcpl-capability-grant.test.d.ts +0 -10
  611. package/dist/test/mcpl-capability-grant.test.d.ts.map +0 -1
  612. package/dist/test/mcpl-capability-grant.test.js +0 -111
  613. package/dist/test/mcpl-capability-grant.test.js.map +0 -1
  614. package/dist/test/mcpl-capability-scoping.test.d.ts +0 -2
  615. package/dist/test/mcpl-capability-scoping.test.d.ts.map +0 -1
  616. package/dist/test/mcpl-capability-scoping.test.js +0 -266
  617. package/dist/test/mcpl-capability-scoping.test.js.map +0 -1
  618. package/dist/test/mcpl-child-env.test.d.ts +0 -2
  619. package/dist/test/mcpl-child-env.test.d.ts.map +0 -1
  620. package/dist/test/mcpl-child-env.test.js +0 -158
  621. package/dist/test/mcpl-child-env.test.js.map +0 -1
  622. package/dist/test/mcpl-coalescing.test.d.ts +0 -2
  623. package/dist/test/mcpl-coalescing.test.d.ts.map +0 -1
  624. package/dist/test/mcpl-coalescing.test.js +0 -1125
  625. package/dist/test/mcpl-coalescing.test.js.map +0 -1
  626. package/dist/test/mcpl-config-diagnostics.test.d.ts +0 -2
  627. package/dist/test/mcpl-config-diagnostics.test.d.ts.map +0 -1
  628. package/dist/test/mcpl-config-diagnostics.test.js +0 -452
  629. package/dist/test/mcpl-config-diagnostics.test.js.map +0 -1
  630. package/dist/test/mcpl-empty-content.test.d.ts +0 -2
  631. package/dist/test/mcpl-empty-content.test.d.ts.map +0 -1
  632. package/dist/test/mcpl-empty-content.test.js +0 -368
  633. package/dist/test/mcpl-empty-content.test.js.map +0 -1
  634. package/dist/test/mcpl-gate-roundtrip.test.d.ts +0 -2
  635. package/dist/test/mcpl-gate-roundtrip.test.d.ts.map +0 -1
  636. package/dist/test/mcpl-gate-roundtrip.test.js +0 -285
  637. package/dist/test/mcpl-gate-roundtrip.test.js.map +0 -1
  638. package/dist/test/mcpl-list-status.test.d.ts +0 -2
  639. package/dist/test/mcpl-list-status.test.d.ts.map +0 -1
  640. package/dist/test/mcpl-list-status.test.js +0 -82
  641. package/dist/test/mcpl-list-status.test.js.map +0 -1
  642. package/dist/test/mcpl-manifest-changed.test.d.ts +0 -2
  643. package/dist/test/mcpl-manifest-changed.test.d.ts.map +0 -1
  644. package/dist/test/mcpl-manifest-changed.test.js +0 -178
  645. package/dist/test/mcpl-manifest-changed.test.js.map +0 -1
  646. package/dist/test/mcpl-push-convert.test.d.ts +0 -2
  647. package/dist/test/mcpl-push-convert.test.d.ts.map +0 -1
  648. package/dist/test/mcpl-push-convert.test.js +0 -42
  649. package/dist/test/mcpl-push-convert.test.js.map +0 -1
  650. package/dist/test/mcpl-reconnect-events.test.d.ts +0 -2
  651. package/dist/test/mcpl-reconnect-events.test.d.ts.map +0 -1
  652. package/dist/test/mcpl-reconnect-events.test.js +0 -144
  653. package/dist/test/mcpl-reconnect-events.test.js.map +0 -1
  654. package/dist/test/mcpl-reconnect-reregistration.test.d.ts +0 -2
  655. package/dist/test/mcpl-reconnect-reregistration.test.d.ts.map +0 -1
  656. package/dist/test/mcpl-reconnect-reregistration.test.js +0 -236
  657. package/dist/test/mcpl-reconnect-reregistration.test.js.map +0 -1
  658. package/dist/test/mcpl-reference-fetcher.test.d.ts +0 -2
  659. package/dist/test/mcpl-reference-fetcher.test.d.ts.map +0 -1
  660. package/dist/test/mcpl-reference-fetcher.test.js +0 -427
  661. package/dist/test/mcpl-reference-fetcher.test.js.map +0 -1
  662. package/dist/test/mcpl-reference-fields.test.d.ts +0 -2
  663. package/dist/test/mcpl-reference-fields.test.d.ts.map +0 -1
  664. package/dist/test/mcpl-reference-fields.test.js +0 -149
  665. package/dist/test/mcpl-reference-fields.test.js.map +0 -1
  666. package/dist/test/mcpl-request-timeout.test.d.ts +0 -2
  667. package/dist/test/mcpl-request-timeout.test.d.ts.map +0 -1
  668. package/dist/test/mcpl-request-timeout.test.js +0 -138
  669. package/dist/test/mcpl-request-timeout.test.js.map +0 -1
  670. package/dist/test/mcpl-runtime-lifecycle.test.d.ts +0 -7
  671. package/dist/test/mcpl-runtime-lifecycle.test.d.ts.map +0 -1
  672. package/dist/test/mcpl-runtime-lifecycle.test.js +0 -142
  673. package/dist/test/mcpl-runtime-lifecycle.test.js.map +0 -1
  674. package/dist/test/mcpl-tool-class-listing.test.d.ts +0 -2
  675. package/dist/test/mcpl-tool-class-listing.test.d.ts.map +0 -1
  676. package/dist/test/mcpl-tool-class-listing.test.js +0 -147
  677. package/dist/test/mcpl-tool-class-listing.test.js.map +0 -1
  678. package/dist/test/mcpl-tool-classes.test.d.ts +0 -7
  679. package/dist/test/mcpl-tool-classes.test.d.ts.map +0 -1
  680. package/dist/test/mcpl-tool-classes.test.js +0 -80
  681. package/dist/test/mcpl-tool-classes.test.js.map +0 -1
  682. package/dist/test/mcpl-tool-lifecycle-e2e.test.d.ts +0 -2
  683. package/dist/test/mcpl-tool-lifecycle-e2e.test.d.ts.map +0 -1
  684. package/dist/test/mcpl-tool-lifecycle-e2e.test.js +0 -237
  685. package/dist/test/mcpl-tool-lifecycle-e2e.test.js.map +0 -1
  686. package/dist/test/mcpl-tool-lifecycle-emitter.test.d.ts +0 -11
  687. package/dist/test/mcpl-tool-lifecycle-emitter.test.d.ts.map +0 -1
  688. package/dist/test/mcpl-tool-lifecycle-emitter.test.js +0 -412
  689. package/dist/test/mcpl-tool-lifecycle-emitter.test.js.map +0 -1
  690. package/dist/test/mcpl-tool-lifecycle-script.test.d.ts +0 -2
  691. package/dist/test/mcpl-tool-lifecycle-script.test.d.ts.map +0 -1
  692. package/dist/test/mcpl-tool-lifecycle-script.test.js +0 -288
  693. package/dist/test/mcpl-tool-lifecycle-script.test.js.map +0 -1
  694. package/dist/test/mcpl-tool-lifecycle.test.d.ts +0 -11
  695. package/dist/test/mcpl-tool-lifecycle.test.d.ts.map +0 -1
  696. package/dist/test/mcpl-tool-lifecycle.test.js +0 -270
  697. package/dist/test/mcpl-tool-lifecycle.test.js.map +0 -1
  698. package/dist/test/mcpl-ws-transport.test.d.ts +0 -2
  699. package/dist/test/mcpl-ws-transport.test.d.ts.map +0 -1
  700. package/dist/test/mcpl-ws-transport.test.js +0 -258
  701. package/dist/test/mcpl-ws-transport.test.js.map +0 -1
  702. package/dist/test/module-context-integration.test.d.ts +0 -18
  703. package/dist/test/module-context-integration.test.d.ts.map +0 -1
  704. package/dist/test/module-context-integration.test.js +0 -181
  705. package/dist/test/module-context-integration.test.js.map +0 -1
  706. package/dist/test/offline-recovery-branch.test.d.ts +0 -2
  707. package/dist/test/offline-recovery-branch.test.d.ts.map +0 -1
  708. package/dist/test/offline-recovery-branch.test.js +0 -226
  709. package/dist/test/offline-recovery-branch.test.js.map +0 -1
  710. package/dist/test/operator-surgery.test.d.ts +0 -2
  711. package/dist/test/operator-surgery.test.d.ts.map +0 -1
  712. package/dist/test/operator-surgery.test.js +0 -398
  713. package/dist/test/operator-surgery.test.js.map +0 -1
  714. package/dist/test/ops-alert.test.d.ts +0 -2
  715. package/dist/test/ops-alert.test.d.ts.map +0 -1
  716. package/dist/test/ops-alert.test.js +0 -153
  717. package/dist/test/ops-alert.test.js.map +0 -1
  718. package/dist/test/overbudget-drain-breaker.test.d.ts +0 -2
  719. package/dist/test/overbudget-drain-breaker.test.d.ts.map +0 -1
  720. package/dist/test/overbudget-drain-breaker.test.js +0 -197
  721. package/dist/test/overbudget-drain-breaker.test.js.map +0 -1
  722. package/dist/test/per-agent-delivery.test.d.ts +0 -2
  723. package/dist/test/per-agent-delivery.test.d.ts.map +0 -1
  724. package/dist/test/per-agent-delivery.test.js +0 -108
  725. package/dist/test/per-agent-delivery.test.js.map +0 -1
  726. package/dist/test/physical-window-restart.test.d.ts +0 -14
  727. package/dist/test/physical-window-restart.test.d.ts.map +0 -1
  728. package/dist/test/physical-window-restart.test.js +0 -222
  729. package/dist/test/physical-window-restart.test.js.map +0 -1
  730. package/dist/test/placed-reaction-baseline.test.d.ts +0 -2
  731. package/dist/test/placed-reaction-baseline.test.d.ts.map +0 -1
  732. package/dist/test/placed-reaction-baseline.test.js +0 -312
  733. package/dist/test/placed-reaction-baseline.test.js.map +0 -1
  734. package/dist/test/present-while-acting.test.d.ts +0 -19
  735. package/dist/test/present-while-acting.test.d.ts.map +0 -1
  736. package/dist/test/present-while-acting.test.js +0 -706
  737. package/dist/test/present-while-acting.test.js.map +0 -1
  738. package/dist/test/prose-segments.test.d.ts +0 -2
  739. package/dist/test/prose-segments.test.d.ts.map +0 -1
  740. package/dist/test/prose-segments.test.js +0 -52
  741. package/dist/test/prose-segments.test.js.map +0 -1
  742. package/dist/test/prose-stream-router.test.d.ts +0 -2
  743. package/dist/test/prose-stream-router.test.d.ts.map +0 -1
  744. package/dist/test/prose-stream-router.test.js +0 -171
  745. package/dist/test/prose-stream-router.test.js.map +0 -1
  746. package/dist/test/provider-acceleration-cooldown.test.d.ts +0 -2
  747. package/dist/test/provider-acceleration-cooldown.test.d.ts.map +0 -1
  748. package/dist/test/provider-acceleration-cooldown.test.js +0 -435
  749. package/dist/test/provider-acceleration-cooldown.test.js.map +0 -1
  750. package/dist/test/provider-waits.test.d.ts +0 -2
  751. package/dist/test/provider-waits.test.d.ts.map +0 -1
  752. package/dist/test/provider-waits.test.js +0 -2196
  753. package/dist/test/provider-waits.test.js.map +0 -1
  754. package/dist/test/puppet-tool-call.test.d.ts +0 -2
  755. package/dist/test/puppet-tool-call.test.d.ts.map +0 -1
  756. package/dist/test/puppet-tool-call.test.js +0 -224
  757. package/dist/test/puppet-tool-call.test.js.map +0 -1
  758. package/dist/test/puppet-turn-reservation.test.d.ts +0 -2
  759. package/dist/test/puppet-turn-reservation.test.d.ts.map +0 -1
  760. package/dist/test/puppet-turn-reservation.test.js +0 -139
  761. package/dist/test/puppet-turn-reservation.test.js.map +0 -1
  762. package/dist/test/reaction-baseline-platform.test.d.ts +0 -2
  763. package/dist/test/reaction-baseline-platform.test.d.ts.map +0 -1
  764. package/dist/test/reaction-baseline-platform.test.js +0 -124
  765. package/dist/test/reaction-baseline-platform.test.js.map +0 -1
  766. package/dist/test/record-journal.test.d.ts +0 -6
  767. package/dist/test/record-journal.test.d.ts.map +0 -1
  768. package/dist/test/record-journal.test.js +0 -269
  769. package/dist/test/record-journal.test.js.map +0 -1
  770. package/dist/test/refusal-reaction-baseline.test.d.ts +0 -2
  771. package/dist/test/refusal-reaction-baseline.test.d.ts.map +0 -1
  772. package/dist/test/refusal-reaction-baseline.test.js +0 -81
  773. package/dist/test/refusal-reaction-baseline.test.js.map +0 -1
  774. package/dist/test/refusal-rewind.test.d.ts +0 -2
  775. package/dist/test/refusal-rewind.test.d.ts.map +0 -1
  776. package/dist/test/refusal-rewind.test.js +0 -108
  777. package/dist/test/refusal-rewind.test.js.map +0 -1
  778. package/dist/test/refusal-single-call.test.d.ts +0 -2
  779. package/dist/test/refusal-single-call.test.d.ts.map +0 -1
  780. package/dist/test/refusal-single-call.test.js +0 -177
  781. package/dist/test/refusal-single-call.test.js.map +0 -1
  782. package/dist/test/release-changelog.test.d.ts +0 -2
  783. package/dist/test/release-changelog.test.d.ts.map +0 -1
  784. package/dist/test/release-changelog.test.js +0 -159
  785. package/dist/test/release-changelog.test.js.map +0 -1
  786. package/dist/test/same-round-think-policy.test.d.ts +0 -2
  787. package/dist/test/same-round-think-policy.test.d.ts.map +0 -1
  788. package/dist/test/same-round-think-policy.test.js +0 -853
  789. package/dist/test/same-round-think-policy.test.js.map +0 -1
  790. package/dist/test/save-recent-image.test.d.ts +0 -26
  791. package/dist/test/save-recent-image.test.d.ts.map +0 -1
  792. package/dist/test/save-recent-image.test.js +0 -974
  793. package/dist/test/save-recent-image.test.js.map +0 -1
  794. package/dist/test/shutdown-errors.test.d.ts +0 -2
  795. package/dist/test/shutdown-errors.test.d.ts.map +0 -1
  796. package/dist/test/shutdown-errors.test.js +0 -662
  797. package/dist/test/shutdown-errors.test.js.map +0 -1
  798. package/dist/test/silent-heartbeat-rows.test.d.ts +0 -2
  799. package/dist/test/silent-heartbeat-rows.test.d.ts.map +0 -1
  800. package/dist/test/silent-heartbeat-rows.test.js +0 -451
  801. package/dist/test/silent-heartbeat-rows.test.js.map +0 -1
  802. package/dist/test/silent-heartbeat.test.d.ts +0 -2
  803. package/dist/test/silent-heartbeat.test.d.ts.map +0 -1
  804. package/dist/test/silent-heartbeat.test.js +0 -165
  805. package/dist/test/silent-heartbeat.test.js.map +0 -1
  806. package/dist/test/state-scaling-e2e.test.d.ts +0 -22
  807. package/dist/test/state-scaling-e2e.test.d.ts.map +0 -1
  808. package/dist/test/state-scaling-e2e.test.js +0 -206
  809. package/dist/test/state-scaling-e2e.test.js.map +0 -1
  810. package/dist/test/state-scaling.test.d.ts +0 -12
  811. package/dist/test/state-scaling.test.d.ts.map +0 -1
  812. package/dist/test/state-scaling.test.js +0 -251
  813. package/dist/test/state-scaling.test.js.map +0 -1
  814. package/dist/test/stop-with-work-in-flight.test.d.ts +0 -23
  815. package/dist/test/stop-with-work-in-flight.test.d.ts.map +0 -1
  816. package/dist/test/stop-with-work-in-flight.test.js +0 -672
  817. package/dist/test/stop-with-work-in-flight.test.js.map +0 -1
  818. package/dist/test/surgery-marks-receipt.test.d.ts +0 -2
  819. package/dist/test/surgery-marks-receipt.test.d.ts.map +0 -1
  820. package/dist/test/surgery-marks-receipt.test.js +0 -540
  821. package/dist/test/surgery-marks-receipt.test.js.map +0 -1
  822. package/dist/test/thinking-token-stamp.test.d.ts +0 -12
  823. package/dist/test/thinking-token-stamp.test.d.ts.map +0 -1
  824. package/dist/test/thinking-token-stamp.test.js +0 -129
  825. package/dist/test/thinking-token-stamp.test.js.map +0 -1
  826. package/dist/test/timezone.test.d.ts +0 -2
  827. package/dist/test/timezone.test.d.ts.map +0 -1
  828. package/dist/test/timezone.test.js +0 -18
  829. package/dist/test/timezone.test.js.map +0 -1
  830. package/dist/test/tool-batch-hook.test.d.ts +0 -8
  831. package/dist/test/tool-batch-hook.test.d.ts.map +0 -1
  832. package/dist/test/tool-batch-hook.test.js +0 -275
  833. package/dist/test/tool-batch-hook.test.js.map +0 -1
  834. package/dist/test/tool-policy.test.d.ts +0 -2
  835. package/dist/test/tool-policy.test.d.ts.map +0 -1
  836. package/dist/test/tool-policy.test.js +0 -51
  837. package/dist/test/tool-policy.test.js.map +0 -1
  838. package/dist/test/tool-presentation.test.d.ts +0 -2
  839. package/dist/test/tool-presentation.test.d.ts.map +0 -1
  840. package/dist/test/tool-presentation.test.js +0 -268
  841. package/dist/test/tool-presentation.test.js.map +0 -1
  842. package/dist/test/tool-result-content.test.d.ts +0 -2
  843. package/dist/test/tool-result-content.test.d.ts.map +0 -1
  844. package/dist/test/tool-result-content.test.js +0 -37
  845. package/dist/test/tool-result-content.test.js.map +0 -1
  846. package/dist/test/tool-result-guard.test.d.ts +0 -2
  847. package/dist/test/tool-result-guard.test.d.ts.map +0 -1
  848. package/dist/test/tool-result-guard.test.js +0 -3607
  849. package/dist/test/tool-result-guard.test.js.map +0 -1
  850. package/dist/test/tool-result-history.test.d.ts +0 -7
  851. package/dist/test/tool-result-history.test.d.ts.map +0 -1
  852. package/dist/test/tool-result-history.test.js +0 -156
  853. package/dist/test/tool-result-history.test.js.map +0 -1
  854. package/dist/test/tool-result-spill.test.d.ts +0 -13
  855. package/dist/test/tool-result-spill.test.d.ts.map +0 -1
  856. package/dist/test/tool-result-spill.test.js +0 -586
  857. package/dist/test/tool-result-spill.test.js.map +0 -1
  858. package/dist/test/tool-wrapper-prose-guard-integration.test.d.ts +0 -2
  859. package/dist/test/tool-wrapper-prose-guard-integration.test.d.ts.map +0 -1
  860. package/dist/test/tool-wrapper-prose-guard-integration.test.js +0 -485
  861. package/dist/test/tool-wrapper-prose-guard-integration.test.js.map +0 -1
  862. package/dist/test/tool-wrapper-prose-guard.test.d.ts +0 -2
  863. package/dist/test/tool-wrapper-prose-guard.test.d.ts.map +0 -1
  864. package/dist/test/tool-wrapper-prose-guard.test.js +0 -34
  865. package/dist/test/tool-wrapper-prose-guard.test.js.map +0 -1
  866. package/dist/test/tools-observe-parser-conformance.test.d.ts +0 -2
  867. package/dist/test/tools-observe-parser-conformance.test.d.ts.map +0 -1
  868. package/dist/test/tools-observe-parser-conformance.test.js +0 -129
  869. package/dist/test/tools-observe-parser-conformance.test.js.map +0 -1
  870. package/dist/test/trunk-channel-routing.test.d.ts +0 -19
  871. package/dist/test/trunk-channel-routing.test.d.ts.map +0 -1
  872. package/dist/test/trunk-channel-routing.test.js +0 -329
  873. package/dist/test/trunk-channel-routing.test.js.map +0 -1
  874. package/dist/test/tune-out-e2e.test.d.ts +0 -2
  875. package/dist/test/tune-out-e2e.test.d.ts.map +0 -1
  876. package/dist/test/tune-out-e2e.test.js +0 -142
  877. package/dist/test/tune-out-e2e.test.js.map +0 -1
  878. package/dist/test/tune-out-gate-composition.test.d.ts +0 -2
  879. package/dist/test/tune-out-gate-composition.test.d.ts.map +0 -1
  880. package/dist/test/tune-out-gate-composition.test.js +0 -221
  881. package/dist/test/tune-out-gate-composition.test.js.map +0 -1
  882. package/dist/test/tune-out-lifecycle.test.d.ts +0 -2
  883. package/dist/test/tune-out-lifecycle.test.d.ts.map +0 -1
  884. package/dist/test/tune-out-lifecycle.test.js +0 -121
  885. package/dist/test/tune-out-lifecycle.test.js.map +0 -1
  886. package/dist/test/turn-trigger-provenance.test.d.ts +0 -2
  887. package/dist/test/turn-trigger-provenance.test.d.ts.map +0 -1
  888. package/dist/test/turn-trigger-provenance.test.js +0 -137
  889. package/dist/test/turn-trigger-provenance.test.js.map +0 -1
  890. package/dist/test/unconvertible-tool-result.test.d.ts +0 -2
  891. package/dist/test/unconvertible-tool-result.test.d.ts.map +0 -1
  892. package/dist/test/unconvertible-tool-result.test.js +0 -358
  893. package/dist/test/unconvertible-tool-result.test.js.map +0 -1
  894. package/dist/test/usage-accounting.test.d.ts +0 -2
  895. package/dist/test/usage-accounting.test.d.ts.map +0 -1
  896. package/dist/test/usage-accounting.test.js +0 -13
  897. package/dist/test/usage-accounting.test.js.map +0 -1
  898. package/dist/test/usage-tracker.test.d.ts +0 -2
  899. package/dist/test/usage-tracker.test.d.ts.map +0 -1
  900. package/dist/test/usage-tracker.test.js +0 -129
  901. package/dist/test/usage-tracker.test.js.map +0 -1
  902. package/dist/test/utils-surface.test.d.ts +0 -2
  903. package/dist/test/utils-surface.test.d.ts.map +0 -1
  904. package/dist/test/utils-surface.test.js +0 -145
  905. package/dist/test/utils-surface.test.js.map +0 -1
  906. package/dist/test/workspace-branch-continuation.test.d.ts +0 -15
  907. package/dist/test/workspace-branch-continuation.test.d.ts.map +0 -1
  908. package/dist/test/workspace-branch-continuation.test.js +0 -183
  909. package/dist/test/workspace-branch-continuation.test.js.map +0 -1
  910. package/dist/test/workspace-materialize-freshness.test.d.ts +0 -16
  911. package/dist/test/workspace-materialize-freshness.test.d.ts.map +0 -1
  912. package/dist/test/workspace-materialize-freshness.test.js +0 -252
  913. package/dist/test/workspace-materialize-freshness.test.js.map +0 -1
  914. package/dist/test/workspace-path-containment.test.d.ts +0 -19
  915. package/dist/test/workspace-path-containment.test.d.ts.map +0 -1
  916. package/dist/test/workspace-path-containment.test.js +0 -91
  917. package/dist/test/workspace-path-containment.test.js.map +0 -1
  918. package/dist/test/workspace-read-file-from-disk.test.d.ts +0 -17
  919. package/dist/test/workspace-read-file-from-disk.test.d.ts.map +0 -1
  920. package/dist/test/workspace-read-file-from-disk.test.js +0 -174
  921. package/dist/test/workspace-read-file-from-disk.test.js.map +0 -1
  922. package/dist/test/workspace-read-image.test.d.ts +0 -2
  923. package/dist/test/workspace-read-image.test.d.ts.map +0 -1
  924. package/dist/test/workspace-read-image.test.js +0 -597
  925. package/dist/test/workspace-read-image.test.js.map +0 -1
  926. package/dist/test/workspace-read-text.test.d.ts +0 -2
  927. package/dist/test/workspace-read-text.test.d.ts.map +0 -1
  928. package/dist/test/workspace-read-text.test.js +0 -101
  929. package/dist/test/workspace-read-text.test.js.map +0 -1
  930. package/dist/test/workspace-restore-order.test.d.ts +0 -16
  931. package/dist/test/workspace-restore-order.test.d.ts.map +0 -1
  932. package/dist/test/workspace-restore-order.test.js +0 -140
  933. package/dist/test/workspace-restore-order.test.js.map +0 -1
  934. package/dist/test/workspace-three-way.test.d.ts +0 -12
  935. package/dist/test/workspace-three-way.test.d.ts.map +0 -1
  936. package/dist/test/workspace-three-way.test.js +0 -3194
  937. package/dist/test/workspace-three-way.test.js.map +0 -1
  938. package/dist/test/workspace-watcher.test.d.ts +0 -2
  939. package/dist/test/workspace-watcher.test.d.ts.map +0 -1
  940. package/dist/test/workspace-watcher.test.js +0 -281
  941. package/dist/test/workspace-watcher.test.js.map +0 -1
  942. package/dist/test/xml-round-persist.test.d.ts +0 -19
  943. package/dist/test/xml-round-persist.test.d.ts.map +0 -1
  944. package/dist/test/xml-round-persist.test.js +0 -235
  945. package/dist/test/xml-round-persist.test.js.map +0 -1
  946. package/dist/tsconfig.tsbuildinfo +0 -1
@@ -1,5 +1,7 @@
1
1
  import { createHash, randomUUID } from 'node:crypto';
2
2
  import { fchmodSync, closeSync, fstatSync, lstatSync, openSync, readSync, renameSync, unlinkSync, writeFileSync } from 'node:fs';
3
+ import { closestNames } from './closest-names.js';
4
+ import { boundedErrorMessage, errorMessage } from './error-message.js';
3
5
  import type { ToolDefinition, ToolResult } from './types/events.js';
4
6
 
5
7
  export interface ToolPresentationConfig {
@@ -22,23 +24,138 @@ export interface PresentationSnapshot {
22
24
  entries: { name: string; source: string; visible: boolean; originalDescription: string; description: string; descriptionSource?: string; inputSchema: ToolDefinition['inputSchema'] }[];
23
25
  }
24
26
  const MAX_BYTES = 256 * 1024;
27
+ const MAX_DESCRIPTION_CHARS = 32768;
25
28
  const protectedNames = new Set(['set_tool_visibility', 'set_tool_description', 'workspace--read']);
26
29
  export const isPresentationTool = (name: string): boolean => name === 'set_tool_visibility' || name === 'set_tool_description';
27
30
  const hash = (value: string): string => createHash('sha256').update(value).digest('hex');
28
31
 
29
- export function parsePresentation(raw: string): PresentationDocument {
30
- const doc = JSON.parse(raw);
31
- if (!doc || doc.version !== 1 || !doc.tools || typeof doc.tools !== 'object' || Array.isArray(doc.tools)
32
- || Object.keys(doc).some(k => !['version', 'tools'].includes(k))) throw new Error('Expected {"version":1,"tools":{...}}');
33
- for (const [name, value] of Object.entries(doc.tools)) {
34
- if (!name || !value || typeof value !== 'object' || Array.isArray(value)) throw new Error(`Invalid override: ${name}`);
32
+ /**
33
+ * A presentation or defaults file this host can't use. Each problem is a
34
+ * clause about the file, such as `the entry for "x" has "visible": "no",
35
+ * which must be true or false`; whoever reports it names the file and says
36
+ * what follows from it.
37
+ */
38
+ class PresentationFileError extends Error {
39
+ constructor(problems: string[]) {
40
+ const more = problems.length - 10;
41
+ super((more > 0 ? [...problems.slice(0, 10), `${more} more problem${more === 1 ? '' : 's'}`] : problems).join('; '));
42
+ }
43
+ }
44
+
45
+ /** An edit refused, in words for the agent: its message is the whole result. */
46
+ class PresentationRefusal extends Error {}
47
+
48
+ const count = (n: number): string => n.toLocaleString('en-US');
49
+
50
+ /** A text's length in code points, so a character outside the Basic Multilingual Plane, such as 😀, counts once where UTF-16 counts it twice. */
51
+ const characters = (text: string): number => [...text].length;
52
+
53
+ /** A text's first `n` characters, never splitting a code point. */
54
+ const firstCharacters = (text: string, n: number): string => [...text].slice(0, n).join('');
55
+
56
+ /** A name as a message quotes it: whole up to 60 characters, and past that cut, with its length, since a file can hold a key of any size. */
57
+ function quoted(name: string): string {
58
+ return characters(name) <= 60 ? JSON.stringify(name) : `${JSON.stringify(firstCharacters(name, 57))}... (${count(characters(name))} characters)`;
59
+ }
60
+
61
+ /** A file's problem as a message quotes it: its own clauses whole, and anything else bounded, since nobody wrote that text for its reader. */
62
+ const problemText = (error: unknown): string => error instanceof PresentationFileError ? error.message : boundedErrorMessage(error);
63
+
64
+ /** A value as a message quotes it: short JSON for a scalar, the kind of anything bigger. */
65
+ function shown(value: unknown): string {
66
+ if (Array.isArray(value)) return 'an array';
67
+ if (value !== null && typeof value === 'object') return 'an object';
68
+ const json = JSON.stringify(value) ?? String(value);
69
+ return characters(json) > 40 ? `${firstCharacters(json, 37)}...` : json;
70
+ }
71
+
72
+ /** Names quoted and joined: "a", "a" and "b", "a", "b" and "c"; past ten, the first ten and how many more, since a file can hold any number of keys. Each is quoted by `quote`: quoted() by default, which cuts a file's long keys, or JSON.stringify for names the agent should copy whole. */
73
+ function quotedList(names: string[], conjunction: 'and' | 'or' = 'and', quote: (name: string) => string = quoted): string {
74
+ const each = names.slice(0, 10).map((name) => quote(name));
75
+ if (names.length > 10) return `${each.join(', ')} ${conjunction} ${count(names.length - 10)} more`;
76
+ return each.length > 1 ? `${each.slice(0, -1).join(', ')} ${conjunction} ${each[each.length - 1]}` : each.join('');
77
+ }
78
+
79
+ /**
80
+ * Every problem that keeps a document from being used, each by where it is;
81
+ * none for a usable one. A defaults file (`descriptionsOnly`) may set
82
+ * descriptions only, since visibility is the resident's to choose.
83
+ */
84
+ function documentProblems(doc: unknown, descriptionsOnly: boolean): string[] {
85
+ if (!doc || typeof doc !== 'object' || Array.isArray(doc)) return [`its top level is ${shown(doc)}, not an object like {"version":1,"tools":{}}`];
86
+ const top = doc as Record<string, unknown>;
87
+ const problems: string[] = [];
88
+ if (top.version !== 1) problems.push(`"version" must be 1, and ${Object.hasOwn(top, 'version') ? `it is ${shown(top.version)}` : "it's missing"}`);
89
+ const extra = Object.keys(top).filter((key) => key !== 'version' && key !== 'tools');
90
+ if (extra.length) problems.push(`only "version" and "tools" belong at the top level, not ${quotedList(extra)}`);
91
+ const tools = top.tools;
92
+ if (!tools || typeof tools !== 'object' || Array.isArray(tools)) {
93
+ problems.push(`"tools" must be an object of tool names, and ${Object.hasOwn(top, 'tools') ? `it is ${shown(tools)}` : "it's missing"}`);
94
+ return problems;
95
+ }
96
+ const setsVisibility: string[] = [];
97
+ for (const [name, value] of Object.entries(tools)) {
98
+ if (!name) { problems.push('"tools" has an entry with an empty name'); continue; }
99
+ const entry = `the entry for ${quoted(name)}`;
100
+ if (!value || typeof value !== 'object' || Array.isArray(value)) { problems.push(`${entry} is ${shown(value)}, not an object such as {"visible":false}`); continue; }
35
101
  const item = value as Record<string, unknown>;
36
- if (Object.keys(item).some(k => !['description', 'visible'].includes(k))
37
- || ('description' in item && (typeof item.description !== 'string' || item.description.length > 32768))
38
- || ('visible' in item && typeof item.visible !== 'boolean')) throw new Error(`Invalid description/visibility for ${name}`);
39
- if (protectedNames.has(name) && item.visible === false) throw new Error(`Cannot hide recovery tool ${name}`);
102
+ const unknown = Object.keys(item).filter((key) => key !== 'description' && key !== 'visible');
103
+ if (unknown.length) problems.push(`${entry} has ${quotedList(unknown)}, and an entry may have only ${descriptionsOnly ? '"description"' : '"description" and "visible"'}`);
104
+ if (Object.hasOwn(item, 'description')) {
105
+ if (typeof item.description !== 'string') problems.push(`${entry} has a "description" that is ${shown(item.description)}, not a string`);
106
+ else if (characters(item.description) > MAX_DESCRIPTION_CHARS) problems.push(`${entry} has a "description" of ${count(characters(item.description))} characters, over the ${count(MAX_DESCRIPTION_CHARS)} allowed`);
107
+ }
108
+ if (!Object.hasOwn(item, 'visible')) continue;
109
+ if (descriptionsOnly) setsVisibility.push(name);
110
+ else if (typeof item.visible !== 'boolean') problems.push(`${entry} has "visible": ${shown(item.visible)}, which must be true or false`);
111
+ else if (!item.visible && protectedNames.has(name)) problems.push(`${entry} hides it, which isn't allowed, since workspace--read, set_tool_visibility and set_tool_description are how the catalogue is read and how these settings are undone`);
40
112
  }
41
- return doc;
113
+ if (setsVisibility.length) problems.push(`it sets "visible" for ${quotedList(setsVisibility)}, and a defaults file may set only descriptions, since visibility is yours to choose`);
114
+ return problems;
115
+ }
116
+
117
+ function parseDocument(raw: string, descriptionsOnly: boolean): PresentationDocument {
118
+ let doc: unknown;
119
+ try { doc = JSON.parse(raw); }
120
+ catch (error) { throw new PresentationFileError([`it isn't valid JSON: ${errorMessage(error)}`]); }
121
+ const problems = documentProblems(doc, descriptionsOnly);
122
+ if (problems.length) throw new PresentationFileError(problems);
123
+ return doc as PresentationDocument;
124
+ }
125
+
126
+ /** A resident's presentation document, or an error naming every problem that keeps it from being used. */
127
+ export function parsePresentation(raw: string): PresentationDocument {
128
+ return parseDocument(raw, false);
129
+ }
130
+
131
+ /**
132
+ * What an agent is told when an edit fails. Every throw in `edit()` comes
133
+ * before its rename, and the cleanup after it never throws, so nothing was
134
+ * changed: a refusal says so in its own words, a file this host can't use is
135
+ * the host's to repair, and anything else is reported as the error it is.
136
+ */
137
+ function editFailure(error: unknown): string {
138
+ if (error instanceof PresentationRefusal) return error.message;
139
+ if (error instanceof PresentationFileError) return `Nothing was changed: your tool presentation file can't be used (${error.message}), and these tools won't write over it until it's repaired. Ask whoever runs this host to repair it.`;
140
+ const code = (error as NodeJS.ErrnoException | null)?.code;
141
+ return `Nothing was changed: the edit failed (${typeof code === 'string' ? code : boundedErrorMessage(error)}). Ask whoever runs this host to check your tool presentation file and its directory.`;
142
+ }
143
+
144
+ /** Whether a path is a symbolic link, so an open that found nothing can tell a dangling link from no file. */
145
+ function isLink(path: string): boolean {
146
+ try { return lstatSync(path).isSymbolicLink(); } catch { return false; }
147
+ }
148
+
149
+ /** Runs one step of an edit's cleanup, which must not throw: it returns what the step threw, if it did. */
150
+ function tidy(step: () => void): { error: unknown } | undefined {
151
+ try { step(); return undefined; } catch (error) { return { error }; }
152
+ }
153
+
154
+ /** What an edit says when its lock couldn't be removed afterwards, since every later edit will meet that lock. */
155
+ function lockLeftBehind(error: unknown): string {
156
+ const code = (error as NodeJS.ErrnoException | undefined)?.code;
157
+ return `This edit couldn't remove its lock afterwards, the presentation file's name with .lock added${typeof code === 'string' ? ` (${code})` : ''}. `
158
+ + 'Until whoever runs this host removes it, set_tool_visibility and set_tool_description will be refused, saying an edit left its lock behind.';
42
159
  }
43
160
 
44
161
  export function presentationTools(path: string): ToolDefinition[] {
@@ -57,43 +174,50 @@ export class ToolPresentation {
57
174
  private read(path = this.config.path, allowMissing = true): string {
58
175
  let fd: number;
59
176
  try { fd = openSync(path, 'r'); }
60
- catch (error) { if (allowMissing && (error as NodeJS.ErrnoException).code === 'ENOENT') return '{"version":1,"tools":{}}'; throw error; }
177
+ catch (error) {
178
+ const code = (error as NodeJS.ErrnoException).code;
179
+ if (code === 'ENOENT') {
180
+ if (isLink(path)) throw new PresentationFileError(["it's a symbolic link to a file that doesn't exist"]);
181
+ if (allowMissing) return '{"version":1,"tools":{}}';
182
+ throw new PresentationFileError(["it doesn't exist"]);
183
+ }
184
+ throw new PresentationFileError([`it couldn't be opened: ${code ?? boundedErrorMessage(error)}`]);
185
+ }
61
186
  try {
62
187
  const stat = fstatSync(fd);
63
- if (!stat.isFile() || stat.size > MAX_BYTES) throw new Error('Presentation must be a regular file under 256 KiB');
188
+ if (!stat.isFile()) throw new PresentationFileError(["it isn't a regular file"]);
189
+ if (stat.size > MAX_BYTES) throw new PresentationFileError([`it's ${count(stat.size)} bytes, over the ${count(MAX_BYTES)} (256 KiB) this host reads`]);
64
190
  const data = Buffer.alloc(MAX_BYTES + 1);
65
- let size = 0, count = 0;
66
- while (size < data.length && (count = readSync(fd, data, size, data.length - size, null)) > 0) size += count;
67
- if (size > MAX_BYTES) throw new Error('Presentation exceeds 256 KiB');
191
+ let size = 0, bytesRead = 0;
192
+ while (size < data.length && (bytesRead = readSync(fd, data, size, data.length - size, null)) > 0) size += bytesRead;
193
+ if (size > MAX_BYTES) throw new PresentationFileError([`it grew past ${count(MAX_BYTES)} bytes (256 KiB) while it was being read`]);
68
194
  return data.subarray(0,size).toString('utf8');
69
195
  } finally { closeSync(fd); }
70
196
  }
71
197
  resolve(tools: ToolDefinition[], sources: ReadonlyMap<string, string> = new Map()): PresentationSnapshot {
72
198
  let raw = '', doc: PresentationDocument = {version:1,tools:{}}, diagnostics: string[] = [];
73
199
  try { raw = this.read(); doc = parsePresentation(raw); }
74
- catch (error) { diagnostics.push(`Overrides not applied: ${String(error)}. Default visibility and component descriptions retained.`); }
200
+ catch (error) { diagnostics.push(`Your tool presentation file can't be used (${problemText(error)}), so none of its settings apply: every tool is visible and shows its configured default description, or its installed one where none is configured. set_tool_visibility and set_tool_description won't change the file until it's repaired; ask whoever runs this host to repair it.`); }
75
201
  const defaults = new Map<string, {description: string; path: string}>();
76
202
  const configuredSources = new Set<string>();
77
203
  for (const profile of this.config.defaults ?? []) {
78
204
  if (configuredSources.has(profile.source)) {
79
- diagnostics.push(`Duplicate defaults source ignored: ${profile.source}`); continue;
205
+ diagnostics.push(`The description defaults for ${JSON.stringify(profile.source)} are configured twice; only the first is read, and the other is ignored. Ask whoever runs this host to remove the duplicate.`); continue;
80
206
  }
81
207
  configuredSources.add(profile.source);
82
208
  // Absent components contribute neither tools nor missing-file errors.
83
209
  if (!tools.some(t => (sources.get(t.name) ?? 'Unattributed') === profile.source)) continue;
84
210
  try {
85
- const profileDoc = parsePresentation(this.read(profile.path, false));
86
- if (Object.values(profileDoc.tools).some(item => Object.keys(item).some(k => k !== 'description')))
87
- throw new Error('Component defaults may contain descriptions only; visibility belongs to the resident');
211
+ const profileDoc = parseDocument(this.read(profile.path, false), true);
88
212
  for (const tool of tools) {
89
213
  if ((sources.get(tool.name) ?? 'Unattributed') !== profile.source) continue;
90
214
  const item = Object.hasOwn(profileDoc.tools, tool.name) ? profileDoc.tools[tool.name] : undefined;
91
215
  if (item?.description !== undefined) defaults.set(tool.name, {description:item.description,path:profile.path});
92
216
  }
93
- } catch (error) { diagnostics.push(`Component defaults not applied (${profile.source}): ${String(error)}`); }
217
+ } catch (error) { diagnostics.push(`The description defaults for ${JSON.stringify(profile.source)} can't be used (${problemText(error)}), so its tools show their installed descriptions, or yours where you set one. Ask whoever runs this host to fix that defaults file.`); }
94
218
  }
95
219
  const names = new Set(tools.map(t => t.name));
96
- for (const name of Object.keys(doc.tools)) if (!names.has(name)) diagnostics.push(`Not currently available: ${name}`);
220
+ for (const name of Object.keys(doc.tools)) if (!names.has(name)) diagnostics.push(`Not currently available: ${quoted(name)}`);
97
221
  const entries = tools.map(tool => {
98
222
  const override = Object.hasOwn(doc.tools, tool.name) ? doc.tools[tool.name] : undefined;
99
223
  // Always retain a usable discovery signpost, even when its wording is overridden.
@@ -111,39 +235,98 @@ export class ToolPresentation {
111
235
  edit(tool: string, input: unknown, available: ToolDefinition[]): ToolResult {
112
236
  const lock = this.config.path + '.lock';
113
237
  let fd: number | undefined, tempFd: number | undefined, temp: string | undefined;
238
+ let result: ToolResult, lockLeft: { error: unknown } | undefined;
114
239
  try {
115
- if (!isPresentationTool(tool)) throw new Error('Unknown editing tool');
116
- const value = input as Record<string, unknown>;
240
+ if (!isPresentationTool(tool)) throw new Error(`${tool} isn't a tool presentation editing tool`);
117
241
  const field = tool === 'set_tool_visibility' ? 'visible' : 'description';
118
- if (!value || typeof value !== 'object' || Array.isArray(value) || typeof value.name !== 'string'
119
- || Object.keys(value).some(k=> !['name',field].includes(k)) || !Object.hasOwn(value,field)) throw new Error('Invalid editing arguments');
120
- if (!available.some(t=>t.name===value.name)) throw new Error('Tool is not currently available to this agent');
121
- if (field === 'visible' ? typeof value.visible !== 'boolean' : value.description !== null && typeof value.description !== 'string') throw new Error(`Invalid ${field}`);
122
- fd = openSync(lock, 'wx', 0o600);
242
+ const name = this.editedName(tool, field, input, available);
243
+ const value = input as Record<string, unknown>;
244
+ try { fd = openSync(lock, 'wx', 0o600); }
245
+ catch (error) {
246
+ if ((error as NodeJS.ErrnoException).code !== 'EEXIST') throw error;
247
+ throw new PresentationRefusal("Nothing was changed: an earlier edit of your tool presentation file left its lock behind, or another edit is in progress. Call this again in a few seconds. If it fails the same way, ask whoever runs this host to remove the stale lock, the presentation file's name with .lock added, once nothing is editing the file.");
248
+ }
123
249
  let mode = 0o600;
124
- try { const stat = lstatSync(this.config.path); if (stat.isSymbolicLink()) throw new Error('Edit the target file directly; tool editing refuses symlinks'); mode = stat.mode & 0o777; }
250
+ try {
251
+ const stat = lstatSync(this.config.path);
252
+ if (stat.isSymbolicLink()) throw new PresentationRefusal("Nothing was changed: your tool presentation file is a symbolic link, and these tools don't write through links. Ask whoever runs this host to make the change in the file it points to, or to replace the link with that file.");
253
+ mode = stat.mode & 0o777;
254
+ }
125
255
  catch (error) { if ((error as NodeJS.ErrnoException).code !== 'ENOENT') throw error; }
126
256
  const before = this.read(), doc = parsePresentation(before);
127
- const old = Object.hasOwn(doc.tools,value.name) ? doc.tools[value.name] : {};
257
+ const old = Object.hasOwn(doc.tools,name) ? doc.tools[name] : {};
128
258
  const updated = {...old};
129
259
  if (field === 'description' && value.description === null) delete updated.description;
130
260
  else Object.assign(updated,{[field]:value[field]});
131
- Object.defineProperty(doc.tools,value.name,{value:updated,enumerable:true,writable:true,configurable:true});
261
+ Object.defineProperty(doc.tools,name,{value:updated,enumerable:true,writable:true,configurable:true});
132
262
  const next = JSON.stringify(doc,null,2)+'\n';
263
+ // editedName has checked what this adds, so this can't fail on the agent's input;
264
+ // it keeps a gap in those checks from writing a file the host would then ignore.
133
265
  parsePresentation(next);
134
- if (Buffer.byteLength(next)>MAX_BYTES) throw new Error('Presentation exceeds 256 KiB');
266
+ const size = Buffer.byteLength(next);
267
+ if (size>MAX_BYTES) throw new PresentationRefusal(`Nothing was changed: with this change your tool presentation file would be ${count(size)} bytes, ${count(size - MAX_BYTES)} over its limit of ${count(MAX_BYTES)} (256 KiB). `
268
+ + (field === 'description' ? 'Use a shorter description, or make room by restoring descriptions you no longer need with "description": null.' : 'Make room by restoring descriptions you no longer need with set_tool_description and "description": null.')
269
+ + ' Entries for tools no longer available to you can be removed only by whoever runs this host.');
135
270
  temp = this.config.path + '.' + randomUUID() + '.tmp';
136
271
  tempFd = openSync(temp,'wx',0o600);
137
272
  writeFileSync(tempFd,next);
138
273
  fchmodSync(tempFd,mode); // preserve permissions on the opened inode, never a replacement path
139
- if (this.read() !== before) throw new Error('File changed concurrently; retry after reading it');
274
+ if (this.read() !== before) throw new PresentationRefusal('Nothing was changed: your tool presentation file changed while this edit was being made. Call this again; it applies to the file as it is now.');
140
275
  const opened = fstatSync(tempFd), named = lstatSync(temp);
141
276
  if (!named.isFile() || named.dev !== opened.dev || named.ino !== opened.ino)
142
- throw new Error('Temporary file changed concurrently; retry after checking the directory');
277
+ throw new PresentationRefusal('Nothing was changed: the temporary copy this edit was writing was replaced while it was written. Call this again; if it fails the same way, ask whoever runs this host to check what else writes beside your tool presentation file.');
143
278
  renameSync(temp,this.config.path); temp=undefined;
144
- return {success:true,data:{name:value.name,[field]:value[field],effective:'next newly compiled request',catalogue:this.config.cataloguePath}};
145
- } catch (error) { return {success:false,isError:true,error:String(error)}; }
146
- finally { if(tempFd!==undefined) closeSync(tempFd); if(temp) try{unlinkSync(temp);}catch{} if(fd!==undefined){closeSync(fd);unlinkSync(lock);} }
279
+ result = {success:true,data:{name,[field]:value[field],effective:'next newly compiled request',catalogue:this.config.cataloguePath}};
280
+ } catch (error) { result = {success:false,isError:true,error:editFailure(error)}; }
281
+ finally {
282
+ // After the rename the edit's result must stand, so no cleanup step may throw.
283
+ const tempFdToClose = tempFd, tempToRemove = temp, lockFd = fd;
284
+ if (tempFdToClose !== undefined) tidy(() => closeSync(tempFdToClose));
285
+ if (tempToRemove) tidy(() => unlinkSync(tempToRemove));
286
+ if (lockFd !== undefined) {
287
+ tidy(() => closeSync(lockFd));
288
+ lockLeft = tidy(() => unlinkSync(lock));
289
+ // A lock already gone was removed by something else, so none is left.
290
+ if ((lockLeft?.error as NodeJS.ErrnoException | undefined)?.code === 'ENOENT') lockLeft = undefined;
291
+ }
292
+ }
293
+ if (!lockLeft) return result;
294
+ return result.success
295
+ ? {...result,data:{...(result.data as Record<string, unknown>),note:lockLeftBehind(lockLeft.error)}}
296
+ : {...result,error:`${result.error} ${lockLeftBehind(lockLeft.error)}`};
297
+ }
298
+ /**
299
+ * The name of the tool an edit is for, once the agent's arguments hold up;
300
+ * otherwise a refusal naming every problem with them and the call to make.
301
+ * The limits a file would refuse (a description's length, the tools that
302
+ * can't be hidden) are checked here too, so they read as the agent's input
303
+ * rather than as a problem with the file.
304
+ */
305
+ private editedName(tool: string, field: 'visible' | 'description', input: unknown, available: ToolDefinition[]): string {
306
+ const usage = field === 'visible'
307
+ ? `set_tool_visibility takes {"name": a tool's exact name, "visible": true or false}.`
308
+ : `set_tool_description takes {"name": a tool's exact name, "description": the new text, or null to restore the default}.`;
309
+ if (!input || typeof input !== 'object' || Array.isArray(input)) throw new PresentationRefusal(`Nothing was changed: the arguments were ${shown(input)}, not an object. ${usage}`);
310
+ const args = input as Record<string, unknown>, problems: string[] = [];
311
+ if (!Object.hasOwn(args, 'name')) problems.push('"name" is missing');
312
+ else if (typeof args.name !== 'string') problems.push(`"name" is ${shown(args.name)}, not a string`);
313
+ if (!Object.hasOwn(args, field)) problems.push(`"${field}" is missing`);
314
+ else if (field === 'visible' ? typeof args.visible !== 'boolean' : args.description !== null && typeof args.description !== 'string')
315
+ problems.push(`"${field}" is ${shown(args[field])}, not ${field === 'visible' ? 'true or false' : 'a string or null'}`);
316
+ const extra = Object.keys(args).filter((key) => key !== 'name' && key !== field);
317
+ if (extra.length) problems.push(`${quotedList(extra)} ${extra.length > 1 ? "aren't arguments" : "isn't an argument"} of ${tool}`);
318
+ if (problems.length) throw new PresentationRefusal(`Nothing was changed: ${problems.join('; ')}. ${usage}`);
319
+ const name = args.name as string;
320
+ if (!available.some((t) => t.name === name)) {
321
+ const near = closestNames(name, available.map((t) => t.name));
322
+ throw new PresentationRefusal(`Nothing was changed: no tool named ${quoted(name)} is available to you.${near.length ? ` Did you mean ${quotedList(near, 'or', JSON.stringify)}?` : ''}`
323
+ + ` Copy the exact name from your tool catalogue's index, workspace--read {"path":${JSON.stringify(this.config.cataloguePath)},"limit":140}, reading on with "offset" if the index runs past that.`);
324
+ }
325
+ if (field === 'description' && typeof args.description === 'string' && characters(args.description) > MAX_DESCRIPTION_CHARS)
326
+ throw new PresentationRefusal(`Nothing was changed: the description is ${count(characters(args.description))} characters, over the ${count(MAX_DESCRIPTION_CHARS)} allowed. Shorten it and call set_tool_description again.`);
327
+ if (field === 'visible' && args.visible === false && protectedNames.has(name))
328
+ throw new PresentationRefusal(`Nothing was changed: ${name} can't be hidden, since workspace--read, set_tool_visibility and set_tool_description are how you read the catalogue and undo these changes. Calling this again won't change that.`);
329
+ return name;
147
330
  }
148
331
  }
149
332
  export function renderCatalogue(snapshot: PresentationSnapshot): string {
@@ -164,7 +347,8 @@ export function renderCatalogue(snapshot: PresentationSnapshot): string {
164
347
  `Read details: workspace--read {"path":${JSON.stringify(snapshot.cataloguePath)},"offset":LINE,"limit":LINES}.`,
165
348
  'Line references below belong to this revision; reread the index after changes.', '',
166
349
  ];
167
- for (const diagnostic of snapshot.diagnostics) lines.push('Diagnostic: '+diagnostic);
350
+ // One line each: a quoted parse error can hold the file's own line breaks.
351
+ for (const diagnostic of snapshot.diagnostics) lines.push('Diagnostic: '+diagnostic.replace(/\r\n|\r|\n/g, '\\n'));
168
352
  lines.push('## Index by source', '');
169
353
  const index = new Map<string, number>();
170
354
  for (const [source, entries] of groups) {
@@ -3,8 +3,8 @@ import { isDeepStrictEqual } from 'node:util';
3
3
  import type { ContextManager, MessageId, MessageMetadata } from '@animalabs/context-manager';
4
4
  import type { ContentBlock, NormalizedMessage, ToolResult } from '@animalabs/membrane';
5
5
  import type { CompletedToolCall } from './types/index.js';
6
- import { isStateExistsError } from './module-registry.js';
7
- import { toolResultDataToHistoryString } from './tool-result-history.js';
6
+ import { ensureStateRegistered } from './module-registry.js';
7
+ import { rfc005TextOf, toolResultDataToHistoryString } from './tool-result-history.js';
8
8
  import { safeSlice } from './safe-slice.js';
9
9
 
10
10
  export const TOOL_RESULT_GUARD_NOTICE = 'Tool result withheld by the guard. The tool has already executed.';
@@ -101,7 +101,10 @@ export function keptWhenWithheld(result: CompletedToolCall['result'], maxChars:
101
101
  const fields = data as Record<string, unknown>;
102
102
  const kept = Object.fromEntries(keys.filter((key) => Object.hasOwn(fields, key)).map((key) => [key, fields[key]]));
103
103
  if (Object.keys(kept).length === 0) return undefined;
104
- const whole = toolResultDataToHistoryString(kept);
104
+ // Data that RFC-005 shows as text, such as a reference's stub, keeps that
105
+ // text: picked out of it, a kept uri would lose the type that makes it a
106
+ // reference, and be written out of the stub that hides it.
107
+ const whole = rfc005TextOf(fields) ?? toolResultDataToHistoryString(kept);
105
108
  if (!maxChars || whole.length <= maxChars) return whole;
106
109
  // Never half a surrogate pair: the stub goes to the provider as text, so
107
110
  // the cut can be one character short of the cap.
@@ -295,11 +298,7 @@ export class ToolResultGuard {
295
298
  private write(record: Record<string, unknown>): void {
296
299
  const store = this.cm.getStore();
297
300
  if (!this.registered) {
298
- try {
299
- store.registerState({ id: TOOL_RESULT_GUARD_AUDIT_STATE, strategy: 'append_log' });
300
- } catch (error) {
301
- if (!isStateExistsError(error)) throw error;
302
- }
301
+ ensureStateRegistered(store, { id: TOOL_RESULT_GUARD_AUDIT_STATE, strategy: 'append_log' });
303
302
  this.registered = true;
304
303
  }
305
304
  store.appendToStateJson(TOOL_RESULT_GUARD_AUDIT_STATE, record);
@@ -11,11 +11,24 @@
11
11
  *
12
12
  * For MCP-shaped content arrays, this helper keeps text blocks verbatim and
13
13
  * replaces image blocks with a short `[image: mimeType, ~NKB]` placeholder.
14
- * For anything else it falls back to JSON.
14
+ * For anything else it falls back to JSON, written by RFC-005's rules at
15
+ * every depth (historyJson): a reference is shown as its stub wherever it
16
+ * sits in the data, so its uri never reaches history, and inline data that
17
+ * claims a uri or a disposition is withheld.
15
18
  */
16
19
 
17
20
  import { INLINE_WITHHELD_TEXT, isInlineContradiction, referenceStubOrNull } from './mcpl/references.js';
18
- import { formatPreservedImageSlots, formatToolImagePlaceholder, splitPreservingImageSlots } from './tool-image-ledger.js';
21
+ import { NON_STRING_TEXT_PLACEHOLDER } from './mcpl/visible-content.js';
22
+ import { formatToolImagePlaceholder, toolResultCutAt } from './tool-image-ledger.js';
23
+
24
+ /** Where one block of a content array sits in its history text, and what
25
+ * kind of block it was: text, an inline image (its placeholder), an RFC-005
26
+ * reference (its stub), or inline data withheld for a contradiction. */
27
+ export interface HistoryBlockSpan {
28
+ kind: 'text' | 'image' | 'reference' | 'withheld';
29
+ start: number;
30
+ end: number;
31
+ }
19
32
 
20
33
  export interface HistorySerializeOptions {
21
34
  /**
@@ -25,6 +38,13 @@ export interface HistorySerializeOptions {
25
38
  * handle in history; null leaves the legacy ref-less form.
26
39
  */
27
40
  imageRef?: (blockIndex: number, image: { data: string; mimeType: string }) => string | null;
41
+ /**
42
+ * Called once a content array has been serialized block by block, rather
43
+ * than given up on for the fallback, with where each block sits in the
44
+ * joined text, before any cut at `maxChars`. The framework reads from it
45
+ * what a result's live copy showed (#403).
46
+ */
47
+ onBlocks?: (spans: HistoryBlockSpan[]) => void;
28
48
  }
29
49
 
30
50
  /**
@@ -54,7 +74,7 @@ export function toolResultDataToHistoryString(
54
74
  const fromArray = tryHistoryStringFromContentArray(data, options);
55
75
  // JSON leaves out undefined, a function and a symbol: a result with no data
56
76
  // is stored as no text, as an empty content array is.
57
- const str = fromArray ?? (JSON.stringify(data) as string | undefined) ?? '';
77
+ const str = fromArray ?? historyJson(data) ?? '';
58
78
  return maxChars ? truncateForHistory(str, maxChars) : str;
59
79
  }
60
80
 
@@ -80,52 +100,136 @@ export function nonErrorResultText(
80
100
  return toolResultDataToHistoryString(data, maxChars, options);
81
101
  }
82
102
 
83
- /** Bounded copy of an arbitrary string with the standard truncation notice.
84
- * Image slots past the cut are re-appended, never dropped (issue #104). */
103
+ /** Bounded copy of an arbitrary string with the standard truncation notice,
104
+ * cut at the cap as a tool result's stored copy is (toolResultCutAt), so it
105
+ * never ends in part of a slot. Each of its callers' readers sees this
106
+ * very text, never the images behind a placeholder, so nothing past the cut
107
+ * is kept for save_recent_image's index (#403). The framework stores a tool
108
+ * result with spillOrTruncate, which keeps the slots past its cut that the
109
+ * result's live copy showed. */
85
110
  export function truncateForHistory(str: string, maxChars: number): string {
86
111
  if (str.length <= maxChars) return str;
87
- const { head, tail } = splitPreservingImageSlots(str, maxChars);
88
- return head
89
- + '\n\n[truncated — original was ' + str.length + ' chars]'
90
- + formatPreservedImageSlots(tail);
112
+ return str.slice(0, toolResultCutAt(str, maxChars)) + '\n\n[truncated — original was ' + str.length + ' chars]';
91
113
  }
92
114
 
93
115
  /**
94
116
  * If `data` is an MCP content array whose every block has a shape we
95
117
  * recognize, return a history-safe string (images → placeholders). Otherwise
96
- * return `null` to defer to the caller's fallback (JSON, usually).
118
+ * return `null` to defer to the fallback, historyJson, which shows a
119
+ * reference anywhere in the data as its stub.
97
120
  */
98
121
  function tryHistoryStringFromContentArray(data: unknown, options?: HistorySerializeOptions): string | null {
99
122
  if (!Array.isArray(data)) return null;
100
- const parts: string[] = [];
123
+ const parts: Array<{ kind: HistoryBlockSpan['kind']; text: string }> = [];
101
124
  for (const [blockIndex, raw] of data.entries()) {
102
125
  if (!raw || typeof raw !== 'object') return null;
103
126
  const b = raw as { type?: unknown; text?: unknown; data?: unknown; mimeType?: unknown };
104
- if (b.type === 'text' && typeof b.text === 'string') {
105
- parts.push(b.text);
127
+ if (b.type === 'text') {
128
+ // A text that isn't a string shows as the converters' placeholder,
129
+ // rather than sending the whole array to the JSON fallback.
130
+ parts.push({ kind: 'text', text: typeof b.text === 'string' ? b.text : NON_STRING_TEXT_PLACEHOLDER });
106
131
  } else if (isInlineContradiction(b)) {
107
132
  // RFC-005 vector 2: checked before the data branch so inline data
108
133
  // claiming bulk disposition is withheld, not rendered.
109
- parts.push(INLINE_WITHHELD_TEXT);
134
+ parts.push({ kind: 'withheld', text: INLINE_WITHHELD_TEXT });
110
135
  } else if (b.type === 'image' && typeof b.data === 'string' && typeof b.mimeType === 'string') {
111
136
  // Decoded byte estimate from base64 length (3/4 ratio, rounded).
112
137
  const approxBytes = Math.floor(b.data.length * 3 / 4);
113
138
  const ref = options?.imageRef?.(blockIndex, { data: b.data, mimeType: b.mimeType }) ?? null;
114
- parts.push(formatToolImagePlaceholder(b.mimeType, formatSize(approxBytes), ref));
139
+ parts.push({ kind: 'image', text: formatToolImagePlaceholder(b.mimeType, formatSize(approxBytes), ref) });
115
140
  } else if (b.type === 'resource' || ((b.type === 'image' || b.type === 'audio') && typeof (b as { uri?: unknown }).uri === 'string')) {
116
141
  // RFC-005 reference block: a bounded stub, never the raw block JSON
117
142
  // (which used to inline the URI — and the whole array — into history).
118
- // Image-typed stubs still occupy a slot in save_recent_image's
119
- // inventory (a failing one — bytes live behind fetch_reference), so
120
- // the index never slides past an image the resident saw.
143
+ // A stub that shows an image type occupies a slot in
144
+ // save_recent_image's inventory (a failing one — bytes live behind
145
+ // fetch_reference), so the index never slides past an image the
146
+ // resident saw.
121
147
  const stub = referenceStubOrNull(b, 'from tool result');
122
148
  if (stub === null) return null;
123
- parts.push(stub);
149
+ parts.push({ kind: 'reference', text: stub });
124
150
  } else {
125
151
  return null;
126
152
  }
127
153
  }
128
- return parts.join('\n');
154
+ if (options?.onBlocks) {
155
+ const spans: HistoryBlockSpan[] = [];
156
+ let start = 0;
157
+ for (const part of parts) {
158
+ spans.push({ kind: part.kind, start, end: start + part.text.length });
159
+ start += part.text.length + 1; // the newline that joins them
160
+ }
161
+ options.onBlocks(spans);
162
+ }
163
+ return parts.map((part) => part.text).join('\n');
164
+ }
165
+
166
+ /**
167
+ * Whether RFC-005 governs a value of a tool result's data, wherever it sits.
168
+ * A reference is a `resource` with a uri, at its top level or under
169
+ * `resource` (where MCP embeds a resource's uri), or an `image` or `audio`
170
+ * given by uri; inline data is an `image` or `audio` whose data is a string.
171
+ * A uri that is null, absent or empty counts as none, and data that isn't a
172
+ * string isn't inline data, so a record that only shares one of those type
173
+ * names is data. A uri of any other value, string or not, counts, so a
174
+ * credential fails closed.
175
+ */
176
+ function governedByRfc005(b: Record<string, unknown>): boolean {
177
+ if (b.type === 'resource') return hasUri(b.uri) || (isPlainRecord(b.resource) && hasUri(b.resource.uri));
178
+ if (b.type === 'image' || b.type === 'audio') return typeof b.data === 'string' || hasUri(b.uri);
179
+ return false;
180
+ }
181
+
182
+ function hasUri(value: unknown): boolean {
183
+ return value !== undefined && value !== null && value !== '';
184
+ }
185
+
186
+ function isPlainRecord(value: unknown): value is Record<string, unknown> {
187
+ return typeof value === 'object' && value !== null && !Array.isArray(value);
188
+ }
189
+
190
+ /**
191
+ * A value of a tool result's data as history shows it, by RFC-005's rules,
192
+ * wherever it sits in the data. A value RFC-005 governs (governedByRfc005) is
193
+ * shown as the reference lanes show it: a reference as its stub, an invalid
194
+ * one (such as a uri that isn't a string, or MCP's embedded resource, whose
195
+ * uri isn't at its top level) as an unrecognized-block line, and inline data
196
+ * that also claims a uri or a disposition as withheld, so no uri is ever
197
+ * shown. Inline data that claims neither is itself, as is any other value:
198
+ * a block of another type keeps its fields, a `resource_link`'s uri among
199
+ * them, since RFC-005 governs references.
200
+ */
201
+ function shownInHistory(value: unknown): unknown {
202
+ if (!value || typeof value !== 'object' || Array.isArray(value)) return value;
203
+ const b = value as Record<string, unknown>;
204
+ if (!governedByRfc005(b)) return value;
205
+ if ((b.type === 'image' || b.type === 'audio') && typeof b.data === 'string') {
206
+ // JSON writes every field, so here inline data beside a uri of any value
207
+ // is withheld, not only beside a string one as in the lanes, which show
208
+ // no uri: an object can carry a credential. An empty uri carries none.
209
+ return hasUri(b.uri) || b.disposition !== undefined ? INLINE_WITHHELD_TEXT : value;
210
+ }
211
+ return referenceStubOrNull(b, 'from tool result') ?? value;
212
+ }
213
+
214
+ /**
215
+ * The text RFC-005 shows a value of a tool result's data as, when it shows it
216
+ * as text rather than as its fields: a reference's stub, an invalid one's
217
+ * unrecognized-block line, or inline data withheld. Null for any other value.
218
+ */
219
+ export function rfc005TextOf(value: unknown): string | null {
220
+ const shown = shownInHistory(value);
221
+ return shown !== value && typeof shown === 'string' ? shown : null;
222
+ }
223
+
224
+ /**
225
+ * JSON of a tool result's data with each value in it shown as history shows
226
+ * it (shownInHistory), at any depth. Data that is itself shown as text, such
227
+ * as a bare reference, is that text.
228
+ */
229
+ function historyJson(data: unknown): string | undefined {
230
+ const root = shownInHistory(data);
231
+ if (root !== data && typeof root === 'string') return root;
232
+ return JSON.stringify(data, (_key, value: unknown) => shownInHistory(value)) as string | undefined;
129
233
  }
130
234
 
131
235
  function formatSize(bytes: number): string {