@animalabs/agent-framework 0.22.2 → 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 (935) hide show
  1. package/README.md +3 -1
  2. package/dist/src/agent.d.ts +77 -12
  3. package/dist/src/agent.d.ts.map +1 -1
  4. package/dist/src/agent.js +136 -40
  5. package/dist/src/agent.js.map +1 -1
  6. package/dist/src/api/mcp-server-core.js +1 -1
  7. package/dist/src/api/mcp-server-core.js.map +1 -1
  8. package/dist/src/api/server.d.ts.map +1 -1
  9. package/dist/src/api/server.js +5 -1
  10. package/dist/src/api/server.js.map +1 -1
  11. package/dist/src/api/types.d.ts +1 -1
  12. package/dist/src/api/types.d.ts.map +1 -1
  13. package/dist/src/branch-names.d.ts +14 -0
  14. package/dist/src/branch-names.d.ts.map +1 -0
  15. package/dist/src/branch-names.js +22 -0
  16. package/dist/src/branch-names.js.map +1 -0
  17. package/dist/src/closest-names.d.ts +28 -0
  18. package/dist/src/closest-names.d.ts.map +1 -0
  19. package/dist/src/closest-names.js +98 -0
  20. package/dist/src/closest-names.js.map +1 -0
  21. package/dist/src/code-execution/py-runner.d.ts +16 -5
  22. package/dist/src/code-execution/py-runner.d.ts.map +1 -1
  23. package/dist/src/code-execution/py-runner.js +186 -74
  24. package/dist/src/code-execution/py-runner.js.map +1 -1
  25. package/dist/src/code-execution/runtime-py.d.ts.map +1 -1
  26. package/dist/src/code-execution/runtime-py.js +49 -3
  27. package/dist/src/code-execution/runtime-py.js.map +1 -1
  28. package/dist/src/code-execution/tool-definition.d.ts +12 -1
  29. package/dist/src/code-execution/tool-definition.d.ts.map +1 -1
  30. package/dist/src/code-execution/tool-definition.js +21 -3
  31. package/dist/src/code-execution/tool-definition.js.map +1 -1
  32. package/dist/src/config-checks.d.ts +28 -0
  33. package/dist/src/config-checks.d.ts.map +1 -0
  34. package/dist/src/config-checks.js +52 -0
  35. package/dist/src/config-checks.js.map +1 -0
  36. package/dist/src/deadline-timer.d.ts +21 -0
  37. package/dist/src/deadline-timer.d.ts.map +1 -0
  38. package/dist/src/deadline-timer.js +43 -0
  39. package/dist/src/deadline-timer.js.map +1 -0
  40. package/dist/src/error-message.d.ts +30 -0
  41. package/dist/src/error-message.d.ts.map +1 -0
  42. package/dist/src/error-message.js +50 -0
  43. package/dist/src/error-message.js.map +1 -0
  44. package/dist/src/framework.d.ts +828 -88
  45. package/dist/src/framework.d.ts.map +1 -1
  46. package/dist/src/framework.js +5011 -1326
  47. package/dist/src/framework.js.map +1 -1
  48. package/dist/src/gate/event-gate.d.ts +8 -0
  49. package/dist/src/gate/event-gate.d.ts.map +1 -1
  50. package/dist/src/gate/event-gate.js +27 -3
  51. package/dist/src/gate/event-gate.js.map +1 -1
  52. package/dist/src/index.d.ts +4 -2
  53. package/dist/src/index.d.ts.map +1 -1
  54. package/dist/src/index.js +4 -2
  55. package/dist/src/index.js.map +1 -1
  56. package/dist/src/mcpl/channel-registry.d.ts +144 -6
  57. package/dist/src/mcpl/channel-registry.d.ts.map +1 -1
  58. package/dist/src/mcpl/channel-registry.js +424 -263
  59. package/dist/src/mcpl/channel-registry.js.map +1 -1
  60. package/dist/src/mcpl/checkpoint-manager.d.ts +21 -1
  61. package/dist/src/mcpl/checkpoint-manager.d.ts.map +1 -1
  62. package/dist/src/mcpl/checkpoint-manager.js +91 -30
  63. package/dist/src/mcpl/checkpoint-manager.js.map +1 -1
  64. package/dist/src/mcpl/conversation-router.d.ts +19 -3
  65. package/dist/src/mcpl/conversation-router.d.ts.map +1 -1
  66. package/dist/src/mcpl/conversation-router.js +23 -8
  67. package/dist/src/mcpl/conversation-router.js.map +1 -1
  68. package/dist/src/mcpl/convert-block.d.ts +20 -0
  69. package/dist/src/mcpl/convert-block.d.ts.map +1 -0
  70. package/dist/src/mcpl/convert-block.js +89 -0
  71. package/dist/src/mcpl/convert-block.js.map +1 -0
  72. package/dist/src/mcpl/errors.d.ts +13 -0
  73. package/dist/src/mcpl/errors.d.ts.map +1 -1
  74. package/dist/src/mcpl/errors.js +28 -0
  75. package/dist/src/mcpl/errors.js.map +1 -1
  76. package/dist/src/mcpl/hook-orchestrator.d.ts +23 -0
  77. package/dist/src/mcpl/hook-orchestrator.d.ts.map +1 -1
  78. package/dist/src/mcpl/hook-orchestrator.js +83 -72
  79. package/dist/src/mcpl/hook-orchestrator.js.map +1 -1
  80. package/dist/src/mcpl/inbound-source.d.ts +114 -0
  81. package/dist/src/mcpl/inbound-source.d.ts.map +1 -0
  82. package/dist/src/mcpl/inbound-source.js +83 -0
  83. package/dist/src/mcpl/inbound-source.js.map +1 -0
  84. package/dist/src/mcpl/index.d.ts +3 -1
  85. package/dist/src/mcpl/index.d.ts.map +1 -1
  86. package/dist/src/mcpl/index.js +3 -1
  87. package/dist/src/mcpl/index.js.map +1 -1
  88. package/dist/src/mcpl/inference-router.d.ts +15 -11
  89. package/dist/src/mcpl/inference-router.d.ts.map +1 -1
  90. package/dist/src/mcpl/inference-router.js +153 -84
  91. package/dist/src/mcpl/inference-router.js.map +1 -1
  92. package/dist/src/mcpl/push-coalescer.d.ts +33 -11
  93. package/dist/src/mcpl/push-coalescer.d.ts.map +1 -1
  94. package/dist/src/mcpl/push-coalescer.js +52 -20
  95. package/dist/src/mcpl/push-coalescer.js.map +1 -1
  96. package/dist/src/mcpl/push-handler.d.ts +16 -9
  97. package/dist/src/mcpl/push-handler.d.ts.map +1 -1
  98. package/dist/src/mcpl/push-handler.js +18 -83
  99. package/dist/src/mcpl/push-handler.js.map +1 -1
  100. package/dist/src/mcpl/reference-fetcher.d.ts +14 -2
  101. package/dist/src/mcpl/reference-fetcher.d.ts.map +1 -1
  102. package/dist/src/mcpl/reference-fetcher.js +72 -30
  103. package/dist/src/mcpl/reference-fetcher.js.map +1 -1
  104. package/dist/src/mcpl/references.d.ts +47 -12
  105. package/dist/src/mcpl/references.d.ts.map +1 -1
  106. package/dist/src/mcpl/references.js +74 -21
  107. package/dist/src/mcpl/references.js.map +1 -1
  108. package/dist/src/mcpl/server-connection.d.ts +89 -10
  109. package/dist/src/mcpl/server-connection.d.ts.map +1 -1
  110. package/dist/src/mcpl/server-connection.js +405 -129
  111. package/dist/src/mcpl/server-connection.js.map +1 -1
  112. package/dist/src/mcpl/server-registry.d.ts +10 -1
  113. package/dist/src/mcpl/server-registry.d.ts.map +1 -1
  114. package/dist/src/mcpl/server-registry.js +14 -3
  115. package/dist/src/mcpl/server-registry.js.map +1 -1
  116. package/dist/src/mcpl/skip-reply-wake.d.ts +36 -0
  117. package/dist/src/mcpl/skip-reply-wake.d.ts.map +1 -0
  118. package/dist/src/mcpl/skip-reply-wake.js +55 -0
  119. package/dist/src/mcpl/skip-reply-wake.js.map +1 -0
  120. package/dist/src/mcpl/transport.d.ts +51 -2
  121. package/dist/src/mcpl/transport.d.ts.map +1 -1
  122. package/dist/src/mcpl/transport.js +114 -20
  123. package/dist/src/mcpl/transport.js.map +1 -1
  124. package/dist/src/mcpl/types.d.ts +14 -3
  125. package/dist/src/mcpl/types.d.ts.map +1 -1
  126. package/dist/src/mcpl/types.js.map +1 -1
  127. package/dist/src/mcpl/visible-content.d.ts +15 -0
  128. package/dist/src/mcpl/visible-content.d.ts.map +1 -1
  129. package/dist/src/mcpl/visible-content.js +25 -0
  130. package/dist/src/mcpl/visible-content.js.map +1 -1
  131. package/dist/src/module-registry.d.ts +19 -1
  132. package/dist/src/module-registry.d.ts.map +1 -1
  133. package/dist/src/module-registry.js +54 -25
  134. package/dist/src/module-registry.js.map +1 -1
  135. package/dist/src/modules/api/index.js +1 -1
  136. package/dist/src/modules/api/index.js.map +1 -1
  137. package/dist/src/modules/discord/discord-js-client.d.ts +1 -0
  138. package/dist/src/modules/discord/discord-js-client.d.ts.map +1 -1
  139. package/dist/src/modules/discord/discord-js-client.js +25 -9
  140. package/dist/src/modules/discord/discord-js-client.js.map +1 -1
  141. package/dist/src/modules/discord/index.d.ts +29 -3
  142. package/dist/src/modules/discord/index.d.ts.map +1 -1
  143. package/dist/src/modules/discord/index.js +379 -143
  144. package/dist/src/modules/discord/index.js.map +1 -1
  145. package/dist/src/modules/discord/types.d.ts +14 -1
  146. package/dist/src/modules/discord/types.d.ts.map +1 -1
  147. package/dist/src/modules/health/index.d.ts.map +1 -1
  148. package/dist/src/modules/health/index.js +2 -1
  149. package/dist/src/modules/health/index.js.map +1 -1
  150. package/dist/src/modules/history/index.d.ts +3 -1
  151. package/dist/src/modules/history/index.d.ts.map +1 -1
  152. package/dist/src/modules/history/index.js +359 -127
  153. package/dist/src/modules/history/index.js.map +1 -1
  154. package/dist/src/modules/history/semantic.d.ts +28 -1
  155. package/dist/src/modules/history/semantic.d.ts.map +1 -1
  156. package/dist/src/modules/history/semantic.js +177 -32
  157. package/dist/src/modules/history/semantic.js.map +1 -1
  158. package/dist/src/modules/unknown-tool.d.ts +10 -0
  159. package/dist/src/modules/unknown-tool.d.ts.map +1 -0
  160. package/dist/src/modules/unknown-tool.js +17 -0
  161. package/dist/src/modules/unknown-tool.js.map +1 -0
  162. package/dist/src/modules/workspace/disk-agreement.d.ts +32 -2
  163. package/dist/src/modules/workspace/disk-agreement.d.ts.map +1 -1
  164. package/dist/src/modules/workspace/disk-agreement.js +30 -2
  165. package/dist/src/modules/workspace/disk-agreement.js.map +1 -1
  166. package/dist/src/modules/workspace/effects.d.ts +64 -6
  167. package/dist/src/modules/workspace/effects.d.ts.map +1 -1
  168. package/dist/src/modules/workspace/effects.js +291 -44
  169. package/dist/src/modules/workspace/effects.js.map +1 -1
  170. package/dist/src/modules/workspace/index.d.ts +119 -23
  171. package/dist/src/modules/workspace/index.d.ts.map +1 -1
  172. package/dist/src/modules/workspace/index.js +793 -247
  173. package/dist/src/modules/workspace/index.js.map +1 -1
  174. package/dist/src/modules/workspace/observe.d.ts +75 -8
  175. package/dist/src/modules/workspace/observe.d.ts.map +1 -1
  176. package/dist/src/modules/workspace/observe.js +174 -14
  177. package/dist/src/modules/workspace/observe.js.map +1 -1
  178. package/dist/src/modules/workspace/reconcile.d.ts +58 -7
  179. package/dist/src/modules/workspace/reconcile.d.ts.map +1 -1
  180. package/dist/src/modules/workspace/reconcile.js +521 -56
  181. package/dist/src/modules/workspace/reconcile.js.map +1 -1
  182. package/dist/src/modules/workspace/types.d.ts +18 -4
  183. package/dist/src/modules/workspace/types.d.ts.map +1 -1
  184. package/dist/src/modules/workspace/types.js.map +1 -1
  185. package/dist/src/modules/workspace/watcher.d.ts +7 -2
  186. package/dist/src/modules/workspace/watcher.d.ts.map +1 -1
  187. package/dist/src/modules/workspace/watcher.js +28 -4
  188. package/dist/src/modules/workspace/watcher.js.map +1 -1
  189. package/dist/src/prose-drafts.d.ts +240 -0
  190. package/dist/src/prose-drafts.d.ts.map +1 -0
  191. package/dist/src/prose-drafts.js +362 -0
  192. package/dist/src/prose-drafts.js.map +1 -0
  193. package/dist/src/prose-segments.d.ts +21 -2
  194. package/dist/src/prose-segments.d.ts.map +1 -1
  195. package/dist/src/prose-segments.js +46 -9
  196. package/dist/src/prose-segments.js.map +1 -1
  197. package/dist/src/recovery/offline-branch.d.ts +1 -0
  198. package/dist/src/recovery/offline-branch.d.ts.map +1 -1
  199. package/dist/src/recovery/offline-branch.js +3 -1
  200. package/dist/src/recovery/offline-branch.js.map +1 -1
  201. package/dist/src/safe-slice.d.ts +5 -1
  202. package/dist/src/safe-slice.d.ts.map +1 -1
  203. package/dist/src/safe-slice.js +9 -1
  204. package/dist/src/safe-slice.js.map +1 -1
  205. package/dist/src/tool-image-ledger.d.ts +87 -19
  206. package/dist/src/tool-image-ledger.d.ts.map +1 -1
  207. package/dist/src/tool-image-ledger.js +135 -32
  208. package/dist/src/tool-image-ledger.js.map +1 -1
  209. package/dist/src/tool-presentation.d.ts +9 -0
  210. package/dist/src/tool-presentation.d.ts.map +1 -1
  211. package/dist/src/tool-presentation.js +257 -60
  212. package/dist/src/tool-presentation.js.map +1 -1
  213. package/dist/src/tool-result-guard.d.ts.map +1 -1
  214. package/dist/src/tool-result-guard.js +7 -10
  215. package/dist/src/tool-result-guard.js.map +1 -1
  216. package/dist/src/tool-result-history.d.ts +32 -3
  217. package/dist/src/tool-result-history.d.ts.map +1 -1
  218. package/dist/src/tool-result-history.js +106 -19
  219. package/dist/src/tool-result-history.js.map +1 -1
  220. package/dist/src/tune-out/coordinator.d.ts +25 -1
  221. package/dist/src/tune-out/coordinator.d.ts.map +1 -1
  222. package/dist/src/tune-out/coordinator.js +260 -65
  223. package/dist/src/tune-out/coordinator.js.map +1 -1
  224. package/dist/src/types/agent.d.ts +17 -5
  225. package/dist/src/types/agent.d.ts.map +1 -1
  226. package/dist/src/types/events.d.ts +17 -0
  227. package/dist/src/types/events.d.ts.map +1 -1
  228. package/dist/src/types/framework.d.ts +21 -5
  229. package/dist/src/types/framework.d.ts.map +1 -1
  230. package/dist/src/types/inference-log.d.ts +1 -1
  231. package/dist/src/types/inference-log.d.ts.map +1 -1
  232. package/dist/src/types/module.d.ts +23 -4
  233. package/dist/src/types/module.d.ts.map +1 -1
  234. package/dist/src/types/trace.d.ts +95 -6
  235. package/dist/src/types/trace.d.ts.map +1 -1
  236. package/dist/src/usage/usage-tracker.d.ts +5 -0
  237. package/dist/src/usage/usage-tracker.d.ts.map +1 -1
  238. package/dist/src/usage/usage-tracker.js +35 -8
  239. package/dist/src/usage/usage-tracker.js.map +1 -1
  240. package/package.json +3 -4
  241. package/src/agent.ts +162 -40
  242. package/src/api/mcp-server-core.ts +1 -1
  243. package/src/api/server.ts +4 -1
  244. package/src/api/types.ts +1 -1
  245. package/src/branch-names.ts +19 -0
  246. package/src/closest-names.ts +94 -0
  247. package/src/code-execution/py-runner.ts +200 -76
  248. package/src/code-execution/runtime-py.ts +49 -3
  249. package/src/code-execution/tool-definition.ts +28 -4
  250. package/src/config-checks.ts +48 -0
  251. package/src/deadline-timer.ts +44 -0
  252. package/src/error-message.ts +48 -0
  253. package/src/framework.ts +5352 -1388
  254. package/src/gate/event-gate.ts +28 -3
  255. package/src/index.ts +11 -2
  256. package/src/mcpl/channel-registry.ts +517 -286
  257. package/src/mcpl/checkpoint-manager.ts +104 -29
  258. package/src/mcpl/conversation-router.ts +28 -8
  259. package/src/mcpl/convert-block.ts +97 -0
  260. package/src/mcpl/errors.ts +28 -0
  261. package/src/mcpl/hook-orchestrator.ts +84 -77
  262. package/src/mcpl/inbound-source.ts +156 -0
  263. package/src/mcpl/index.ts +10 -1
  264. package/src/mcpl/inference-router.ts +174 -99
  265. package/src/mcpl/push-coalescer.ts +60 -24
  266. package/src/mcpl/push-handler.ts +20 -90
  267. package/src/mcpl/reference-fetcher.ts +71 -26
  268. package/src/mcpl/references.ts +81 -22
  269. package/src/mcpl/server-connection.ts +427 -132
  270. package/src/mcpl/server-registry.ts +15 -4
  271. package/src/mcpl/skip-reply-wake.ts +73 -0
  272. package/src/mcpl/transport.ts +120 -18
  273. package/src/mcpl/types.ts +14 -3
  274. package/src/mcpl/visible-content.ts +27 -0
  275. package/src/module-registry.ts +58 -23
  276. package/src/modules/api/index.ts +1 -1
  277. package/src/modules/discord/discord-js-client.ts +26 -10
  278. package/src/modules/discord/index.ts +391 -158
  279. package/src/modules/discord/types.ts +15 -2
  280. package/src/modules/health/index.ts +2 -1
  281. package/src/modules/history/index.ts +410 -120
  282. package/src/modules/history/semantic.ts +189 -32
  283. package/src/modules/unknown-tool.ts +16 -0
  284. package/src/modules/workspace/disk-agreement.ts +51 -3
  285. package/src/modules/workspace/effects.ts +279 -35
  286. package/src/modules/workspace/index.ts +810 -260
  287. package/src/modules/workspace/observe.ts +194 -20
  288. package/src/modules/workspace/reconcile.ts +619 -64
  289. package/src/modules/workspace/types.ts +18 -4
  290. package/src/modules/workspace/watcher.ts +27 -4
  291. package/src/prose-drafts.ts +481 -0
  292. package/src/prose-segments.ts +51 -8
  293. package/src/recovery/offline-branch.ts +4 -1
  294. package/src/safe-slice.ts +9 -1
  295. package/src/tool-image-ledger.ts +153 -34
  296. package/src/tool-presentation.ts +224 -40
  297. package/src/tool-result-guard.ts +7 -8
  298. package/src/tool-result-history.ts +124 -20
  299. package/src/tune-out/coordinator.ts +259 -65
  300. package/src/types/agent.ts +17 -7
  301. package/src/types/events.ts +17 -0
  302. package/src/types/framework.ts +21 -5
  303. package/src/types/inference-log.ts +1 -1
  304. package/src/types/module.ts +24 -4
  305. package/src/types/trace.ts +101 -6
  306. package/src/usage/usage-tracker.ts +32 -8
  307. package/dist/test/activation-request-sanitize.test.d.ts +0 -2
  308. package/dist/test/activation-request-sanitize.test.d.ts.map +0 -1
  309. package/dist/test/activation-request-sanitize.test.js +0 -89
  310. package/dist/test/activation-request-sanitize.test.js.map +0 -1
  311. package/dist/test/agent-cache-ttl.test.d.ts +0 -2
  312. package/dist/test/agent-cache-ttl.test.d.ts.map +0 -1
  313. package/dist/test/agent-cache-ttl.test.js +0 -41
  314. package/dist/test/agent-cache-ttl.test.js.map +0 -1
  315. package/dist/test/agent-runtime-settings.test.d.ts +0 -2
  316. package/dist/test/agent-runtime-settings.test.d.ts.map +0 -1
  317. package/dist/test/agent-runtime-settings.test.js +0 -1598
  318. package/dist/test/agent-runtime-settings.test.js.map +0 -1
  319. package/dist/test/api-admin-gate.test.d.ts +0 -2
  320. package/dist/test/api-admin-gate.test.d.ts.map +0 -1
  321. package/dist/test/api-admin-gate.test.js +0 -116
  322. package/dist/test/api-admin-gate.test.js.map +0 -1
  323. package/dist/test/assistant-persist-refusal.test.d.ts +0 -2
  324. package/dist/test/assistant-persist-refusal.test.d.ts.map +0 -1
  325. package/dist/test/assistant-persist-refusal.test.js +0 -63
  326. package/dist/test/assistant-persist-refusal.test.js.map +0 -1
  327. package/dist/test/batched-wake-locus.test.d.ts +0 -2
  328. package/dist/test/batched-wake-locus.test.d.ts.map +0 -1
  329. package/dist/test/batched-wake-locus.test.js +0 -166
  330. package/dist/test/batched-wake-locus.test.js.map +0 -1
  331. package/dist/test/busy-agent-scheduler.test.d.ts +0 -2
  332. package/dist/test/busy-agent-scheduler.test.d.ts.map +0 -1
  333. package/dist/test/busy-agent-scheduler.test.js +0 -92
  334. package/dist/test/busy-agent-scheduler.test.js.map +0 -1
  335. package/dist/test/channel-incoming-targeting.test.d.ts +0 -2
  336. package/dist/test/channel-incoming-targeting.test.d.ts.map +0 -1
  337. package/dist/test/channel-incoming-targeting.test.js +0 -81
  338. package/dist/test/channel-incoming-targeting.test.js.map +0 -1
  339. package/dist/test/channel-label-history.test.d.ts +0 -2
  340. package/dist/test/channel-label-history.test.d.ts.map +0 -1
  341. package/dist/test/channel-label-history.test.js +0 -424
  342. package/dist/test/channel-label-history.test.js.map +0 -1
  343. package/dist/test/channel-lifecycle-provenance.test.d.ts +0 -2
  344. package/dist/test/channel-lifecycle-provenance.test.d.ts.map +0 -1
  345. package/dist/test/channel-lifecycle-provenance.test.js +0 -47
  346. package/dist/test/channel-lifecycle-provenance.test.js.map +0 -1
  347. package/dist/test/channel-registry-routing.test.d.ts +0 -2
  348. package/dist/test/channel-registry-routing.test.d.ts.map +0 -1
  349. package/dist/test/channel-registry-routing.test.js +0 -446
  350. package/dist/test/channel-registry-routing.test.js.map +0 -1
  351. package/dist/test/channel-registry-typing.test.d.ts +0 -2
  352. package/dist/test/channel-registry-typing.test.d.ts.map +0 -1
  353. package/dist/test/channel-registry-typing.test.js +0 -91
  354. package/dist/test/channel-registry-typing.test.js.map +0 -1
  355. package/dist/test/channels-changed-respond-first.test.d.ts +0 -2
  356. package/dist/test/channels-changed-respond-first.test.d.ts.map +0 -1
  357. package/dist/test/channels-changed-respond-first.test.js +0 -74
  358. package/dist/test/channels-changed-respond-first.test.js.map +0 -1
  359. package/dist/test/checkpoint-attribution.test.d.ts +0 -2
  360. package/dist/test/checkpoint-attribution.test.d.ts.map +0 -1
  361. package/dist/test/checkpoint-attribution.test.js +0 -200
  362. package/dist/test/checkpoint-attribution.test.js.map +0 -1
  363. package/dist/test/code-execution.test.d.ts +0 -11
  364. package/dist/test/code-execution.test.d.ts.map +0 -1
  365. package/dist/test/code-execution.test.js +0 -1272
  366. package/dist/test/code-execution.test.js.map +0 -1
  367. package/dist/test/component-defaults.test.d.ts +0 -2
  368. package/dist/test/component-defaults.test.d.ts.map +0 -1
  369. package/dist/test/component-defaults.test.js +0 -54
  370. package/dist/test/component-defaults.test.js.map +0 -1
  371. package/dist/test/conversation-fork-injection-scoping.test.d.ts +0 -2
  372. package/dist/test/conversation-fork-injection-scoping.test.d.ts.map +0 -1
  373. package/dist/test/conversation-fork-injection-scoping.test.js +0 -200
  374. package/dist/test/conversation-fork-injection-scoping.test.js.map +0 -1
  375. package/dist/test/conversation-router.test.d.ts +0 -2
  376. package/dist/test/conversation-router.test.d.ts.map +0 -1
  377. package/dist/test/conversation-router.test.js +0 -174
  378. package/dist/test/conversation-router.test.js.map +0 -1
  379. package/dist/test/conversation-routing.test.d.ts +0 -7
  380. package/dist/test/conversation-routing.test.d.ts.map +0 -1
  381. package/dist/test/conversation-routing.test.js +0 -621
  382. package/dist/test/conversation-routing.test.js.map +0 -1
  383. package/dist/test/deferred-wake-integrity.test.d.ts +0 -29
  384. package/dist/test/deferred-wake-integrity.test.d.ts.map +0 -1
  385. package/dist/test/deferred-wake-integrity.test.js +0 -320
  386. package/dist/test/deferred-wake-integrity.test.js.map +0 -1
  387. package/dist/test/discord-awareness-outbox.test.d.ts +0 -2
  388. package/dist/test/discord-awareness-outbox.test.d.ts.map +0 -1
  389. package/dist/test/discord-awareness-outbox.test.js +0 -371
  390. package/dist/test/discord-awareness-outbox.test.js.map +0 -1
  391. package/dist/test/discord-history-delete-window.test.d.ts +0 -2
  392. package/dist/test/discord-history-delete-window.test.d.ts.map +0 -1
  393. package/dist/test/discord-history-delete-window.test.js +0 -81
  394. package/dist/test/discord-history-delete-window.test.js.map +0 -1
  395. package/dist/test/discord-history-sync.test.d.ts +0 -2
  396. package/dist/test/discord-history-sync.test.d.ts.map +0 -1
  397. package/dist/test/discord-history-sync.test.js +0 -56
  398. package/dist/test/discord-history-sync.test.js.map +0 -1
  399. package/dist/test/discord-typing-keepalive.test.d.ts +0 -2
  400. package/dist/test/discord-typing-keepalive.test.d.ts.map +0 -1
  401. package/dist/test/discord-typing-keepalive.test.js +0 -77
  402. package/dist/test/discord-typing-keepalive.test.js.map +0 -1
  403. package/dist/test/ephemeral-settle.test.d.ts +0 -2
  404. package/dist/test/ephemeral-settle.test.d.ts.map +0 -1
  405. package/dist/test/ephemeral-settle.test.js +0 -354
  406. package/dist/test/ephemeral-settle.test.js.map +0 -1
  407. package/dist/test/event-gate-passthrough.test.d.ts +0 -15
  408. package/dist/test/event-gate-passthrough.test.d.ts.map +0 -1
  409. package/dist/test/event-gate-passthrough.test.js +0 -289
  410. package/dist/test/event-gate-passthrough.test.js.map +0 -1
  411. package/dist/test/event-gate-policy-mutation.test.d.ts +0 -2
  412. package/dist/test/event-gate-policy-mutation.test.d.ts.map +0 -1
  413. package/dist/test/event-gate-policy-mutation.test.js +0 -137
  414. package/dist/test/event-gate-policy-mutation.test.js.map +0 -1
  415. package/dist/test/event-gate-rate-limit.test.d.ts +0 -2
  416. package/dist/test/event-gate-rate-limit.test.d.ts.map +0 -1
  417. package/dist/test/event-gate-rate-limit.test.js +0 -627
  418. package/dist/test/event-gate-rate-limit.test.js.map +0 -1
  419. package/dist/test/event-gate-script.test.d.ts +0 -2
  420. package/dist/test/event-gate-script.test.d.ts.map +0 -1
  421. package/dist/test/event-gate-script.test.js +0 -95
  422. package/dist/test/event-gate-script.test.js.map +0 -1
  423. package/dist/test/event-gate-selfwake.test.d.ts +0 -15
  424. package/dist/test/event-gate-selfwake.test.d.ts.map +0 -1
  425. package/dist/test/event-gate-selfwake.test.js +0 -125
  426. package/dist/test/event-gate-selfwake.test.js.map +0 -1
  427. package/dist/test/event-gate-tags.test.d.ts +0 -2
  428. package/dist/test/event-gate-tags.test.d.ts.map +0 -1
  429. package/dist/test/event-gate-tags.test.js +0 -76
  430. package/dist/test/event-gate-tags.test.js.map +0 -1
  431. package/dist/test/event-gate.test.d.ts +0 -2
  432. package/dist/test/event-gate.test.d.ts.map +0 -1
  433. package/dist/test/event-gate.test.js +0 -919
  434. package/dist/test/event-gate.test.js.map +0 -1
  435. package/dist/test/explicit-prose-routing.test.d.ts +0 -11
  436. package/dist/test/explicit-prose-routing.test.d.ts.map +0 -1
  437. package/dist/test/explicit-prose-routing.test.js +0 -1715
  438. package/dist/test/explicit-prose-routing.test.js.map +0 -1
  439. package/dist/test/framework.test.d.ts +0 -5
  440. package/dist/test/framework.test.d.ts.map +0 -1
  441. package/dist/test/framework.test.js +0 -1048
  442. package/dist/test/framework.test.js.map +0 -1
  443. package/dist/test/gather-context-timeout.test.d.ts +0 -2
  444. package/dist/test/gather-context-timeout.test.d.ts.map +0 -1
  445. package/dist/test/gather-context-timeout.test.js +0 -120
  446. package/dist/test/gather-context-timeout.test.js.map +0 -1
  447. package/dist/test/health-snapshot.test.d.ts +0 -2
  448. package/dist/test/health-snapshot.test.d.ts.map +0 -1
  449. package/dist/test/health-snapshot.test.js +0 -74
  450. package/dist/test/health-snapshot.test.js.map +0 -1
  451. package/dist/test/helpers/coalescing-fixture.d.ts +0 -74
  452. package/dist/test/helpers/coalescing-fixture.d.ts.map +0 -1
  453. package/dist/test/helpers/coalescing-fixture.js +0 -152
  454. package/dist/test/helpers/coalescing-fixture.js.map +0 -1
  455. package/dist/test/helpers/coalescing-kill-child.d.ts +0 -2
  456. package/dist/test/helpers/coalescing-kill-child.d.ts.map +0 -1
  457. package/dist/test/helpers/coalescing-kill-child.js +0 -24
  458. package/dist/test/helpers/coalescing-kill-child.js.map +0 -1
  459. package/dist/test/helpers/mock-membrane.d.ts +0 -53
  460. package/dist/test/helpers/mock-membrane.d.ts.map +0 -1
  461. package/dist/test/helpers/mock-membrane.js +0 -168
  462. package/dist/test/helpers/mock-membrane.js.map +0 -1
  463. package/dist/test/helpers/pytc-stop-rows.d.ts +0 -11
  464. package/dist/test/helpers/pytc-stop-rows.d.ts.map +0 -1
  465. package/dist/test/helpers/pytc-stop-rows.js +0 -143
  466. package/dist/test/helpers/pytc-stop-rows.js.map +0 -1
  467. package/dist/test/helpers/quiesce-crash-child.d.ts +0 -2
  468. package/dist/test/helpers/quiesce-crash-child.d.ts.map +0 -1
  469. package/dist/test/helpers/quiesce-crash-child.js +0 -156
  470. package/dist/test/helpers/quiesce-crash-child.js.map +0 -1
  471. package/dist/test/hide-then-turn.test.d.ts +0 -2
  472. package/dist/test/hide-then-turn.test.d.ts.map +0 -1
  473. package/dist/test/hide-then-turn.test.js +0 -101
  474. package/dist/test/hide-then-turn.test.js.map +0 -1
  475. package/dist/test/history-module-overview.test.d.ts +0 -2
  476. package/dist/test/history-module-overview.test.d.ts.map +0 -1
  477. package/dist/test/history-module-overview.test.js +0 -711
  478. package/dist/test/history-module-overview.test.js.map +0 -1
  479. package/dist/test/history-module-realstore.test.d.ts +0 -2
  480. package/dist/test/history-module-realstore.test.d.ts.map +0 -1
  481. package/dist/test/history-module-realstore.test.js +0 -363
  482. package/dist/test/history-module-realstore.test.js.map +0 -1
  483. package/dist/test/history-module-semantic.test.d.ts +0 -2
  484. package/dist/test/history-module-semantic.test.d.ts.map +0 -1
  485. package/dist/test/history-module-semantic.test.js +0 -213
  486. package/dist/test/history-module-semantic.test.js.map +0 -1
  487. package/dist/test/history-module-ux.test.d.ts +0 -2
  488. package/dist/test/history-module-ux.test.d.ts.map +0 -1
  489. package/dist/test/history-module-ux.test.js +0 -304
  490. package/dist/test/history-module-ux.test.js.map +0 -1
  491. package/dist/test/history-module.test.d.ts +0 -2
  492. package/dist/test/history-module.test.d.ts.map +0 -1
  493. package/dist/test/history-module.test.js +0 -619
  494. package/dist/test/history-module.test.js.map +0 -1
  495. package/dist/test/history-semantic-review-findings.test.d.ts +0 -2
  496. package/dist/test/history-semantic-review-findings.test.d.ts.map +0 -1
  497. package/dist/test/history-semantic-review-findings.test.js +0 -338
  498. package/dist/test/history-semantic-review-findings.test.js.map +0 -1
  499. package/dist/test/history-semantic-sync-converges.test.d.ts +0 -2
  500. package/dist/test/history-semantic-sync-converges.test.d.ts.map +0 -1
  501. package/dist/test/history-semantic-sync-converges.test.js +0 -109
  502. package/dist/test/history-semantic-sync-converges.test.js.map +0 -1
  503. package/dist/test/host-quiesce.test.d.ts +0 -2
  504. package/dist/test/host-quiesce.test.d.ts.map +0 -1
  505. package/dist/test/host-quiesce.test.js +0 -988
  506. package/dist/test/host-quiesce.test.js.map +0 -1
  507. package/dist/test/inference-exhaustion-rewind.test.d.ts +0 -2
  508. package/dist/test/inference-exhaustion-rewind.test.d.ts.map +0 -1
  509. package/dist/test/inference-exhaustion-rewind.test.js +0 -387
  510. package/dist/test/inference-exhaustion-rewind.test.js.map +0 -1
  511. package/dist/test/inference-failure-bounds.test.d.ts +0 -2
  512. package/dist/test/inference-failure-bounds.test.d.ts.map +0 -1
  513. package/dist/test/inference-failure-bounds.test.js +0 -1202
  514. package/dist/test/inference-failure-bounds.test.js.map +0 -1
  515. package/dist/test/inference-failure-observability.test.d.ts +0 -2
  516. package/dist/test/inference-failure-observability.test.d.ts.map +0 -1
  517. package/dist/test/inference-failure-observability.test.js +0 -84
  518. package/dist/test/inference-failure-observability.test.js.map +0 -1
  519. package/dist/test/journal-tool.test.d.ts +0 -2
  520. package/dist/test/journal-tool.test.d.ts.map +0 -1
  521. package/dist/test/journal-tool.test.js +0 -33
  522. package/dist/test/journal-tool.test.js.map +0 -1
  523. package/dist/test/kv-unified-open-flight-retry.test.d.ts +0 -2
  524. package/dist/test/kv-unified-open-flight-retry.test.d.ts.map +0 -1
  525. package/dist/test/kv-unified-open-flight-retry.test.js +0 -189
  526. package/dist/test/kv-unified-open-flight-retry.test.js.map +0 -1
  527. package/dist/test/kv-unified-wiring.test.d.ts +0 -2
  528. package/dist/test/kv-unified-wiring.test.d.ts.map +0 -1
  529. package/dist/test/kv-unified-wiring.test.js +0 -95
  530. package/dist/test/kv-unified-wiring.test.js.map +0 -1
  531. package/dist/test/late-events-after-stop.test.d.ts +0 -2
  532. package/dist/test/late-events-after-stop.test.d.ts.map +0 -1
  533. package/dist/test/late-events-after-stop.test.js +0 -122
  534. package/dist/test/late-events-after-stop.test.js.map +0 -1
  535. package/dist/test/liveness-watchdog.test.d.ts +0 -2
  536. package/dist/test/liveness-watchdog.test.d.ts.map +0 -1
  537. package/dist/test/liveness-watchdog.test.js +0 -94
  538. package/dist/test/liveness-watchdog.test.js.map +0 -1
  539. package/dist/test/machine-close-provenance.test.d.ts +0 -2
  540. package/dist/test/machine-close-provenance.test.d.ts.map +0 -1
  541. package/dist/test/machine-close-provenance.test.js +0 -116
  542. package/dist/test/machine-close-provenance.test.js.map +0 -1
  543. package/dist/test/maintenance-timer.test.d.ts +0 -2
  544. package/dist/test/maintenance-timer.test.d.ts.map +0 -1
  545. package/dist/test/maintenance-timer.test.js +0 -1827
  546. package/dist/test/maintenance-timer.test.js.map +0 -1
  547. package/dist/test/mcp-server-bin.test.d.ts +0 -2
  548. package/dist/test/mcp-server-bin.test.d.ts.map +0 -1
  549. package/dist/test/mcp-server-bin.test.js +0 -142
  550. package/dist/test/mcp-server-bin.test.js.map +0 -1
  551. package/dist/test/mcpl-access-provider.test.d.ts +0 -2
  552. package/dist/test/mcpl-access-provider.test.d.ts.map +0 -1
  553. package/dist/test/mcpl-access-provider.test.js +0 -20
  554. package/dist/test/mcpl-access-provider.test.js.map +0 -1
  555. package/dist/test/mcpl-awareness-barrier.test.d.ts +0 -2
  556. package/dist/test/mcpl-awareness-barrier.test.d.ts.map +0 -1
  557. package/dist/test/mcpl-awareness-barrier.test.js +0 -769
  558. package/dist/test/mcpl-awareness-barrier.test.js.map +0 -1
  559. package/dist/test/mcpl-capability-grant.test.d.ts +0 -10
  560. package/dist/test/mcpl-capability-grant.test.d.ts.map +0 -1
  561. package/dist/test/mcpl-capability-grant.test.js +0 -111
  562. package/dist/test/mcpl-capability-grant.test.js.map +0 -1
  563. package/dist/test/mcpl-capability-scoping.test.d.ts +0 -2
  564. package/dist/test/mcpl-capability-scoping.test.d.ts.map +0 -1
  565. package/dist/test/mcpl-capability-scoping.test.js +0 -266
  566. package/dist/test/mcpl-capability-scoping.test.js.map +0 -1
  567. package/dist/test/mcpl-child-env.test.d.ts +0 -2
  568. package/dist/test/mcpl-child-env.test.d.ts.map +0 -1
  569. package/dist/test/mcpl-child-env.test.js +0 -158
  570. package/dist/test/mcpl-child-env.test.js.map +0 -1
  571. package/dist/test/mcpl-coalesced-content-parity.test.d.ts +0 -2
  572. package/dist/test/mcpl-coalesced-content-parity.test.d.ts.map +0 -1
  573. package/dist/test/mcpl-coalesced-content-parity.test.js +0 -532
  574. package/dist/test/mcpl-coalesced-content-parity.test.js.map +0 -1
  575. package/dist/test/mcpl-coalescing.test.d.ts +0 -2
  576. package/dist/test/mcpl-coalescing.test.d.ts.map +0 -1
  577. package/dist/test/mcpl-coalescing.test.js +0 -1125
  578. package/dist/test/mcpl-coalescing.test.js.map +0 -1
  579. package/dist/test/mcpl-config-diagnostics.test.d.ts +0 -2
  580. package/dist/test/mcpl-config-diagnostics.test.d.ts.map +0 -1
  581. package/dist/test/mcpl-config-diagnostics.test.js +0 -452
  582. package/dist/test/mcpl-config-diagnostics.test.js.map +0 -1
  583. package/dist/test/mcpl-empty-content.test.d.ts +0 -2
  584. package/dist/test/mcpl-empty-content.test.d.ts.map +0 -1
  585. package/dist/test/mcpl-empty-content.test.js +0 -368
  586. package/dist/test/mcpl-empty-content.test.js.map +0 -1
  587. package/dist/test/mcpl-gate-roundtrip.test.d.ts +0 -2
  588. package/dist/test/mcpl-gate-roundtrip.test.d.ts.map +0 -1
  589. package/dist/test/mcpl-gate-roundtrip.test.js +0 -285
  590. package/dist/test/mcpl-gate-roundtrip.test.js.map +0 -1
  591. package/dist/test/mcpl-list-status.test.d.ts +0 -2
  592. package/dist/test/mcpl-list-status.test.d.ts.map +0 -1
  593. package/dist/test/mcpl-list-status.test.js +0 -82
  594. package/dist/test/mcpl-list-status.test.js.map +0 -1
  595. package/dist/test/mcpl-manifest-changed.test.d.ts +0 -2
  596. package/dist/test/mcpl-manifest-changed.test.d.ts.map +0 -1
  597. package/dist/test/mcpl-manifest-changed.test.js +0 -178
  598. package/dist/test/mcpl-manifest-changed.test.js.map +0 -1
  599. package/dist/test/mcpl-push-convert.test.d.ts +0 -2
  600. package/dist/test/mcpl-push-convert.test.d.ts.map +0 -1
  601. package/dist/test/mcpl-push-convert.test.js +0 -42
  602. package/dist/test/mcpl-push-convert.test.js.map +0 -1
  603. package/dist/test/mcpl-reconnect-events.test.d.ts +0 -2
  604. package/dist/test/mcpl-reconnect-events.test.d.ts.map +0 -1
  605. package/dist/test/mcpl-reconnect-events.test.js +0 -144
  606. package/dist/test/mcpl-reconnect-events.test.js.map +0 -1
  607. package/dist/test/mcpl-reconnect-reregistration.test.d.ts +0 -2
  608. package/dist/test/mcpl-reconnect-reregistration.test.d.ts.map +0 -1
  609. package/dist/test/mcpl-reconnect-reregistration.test.js +0 -238
  610. package/dist/test/mcpl-reconnect-reregistration.test.js.map +0 -1
  611. package/dist/test/mcpl-reference-fetcher.test.d.ts +0 -2
  612. package/dist/test/mcpl-reference-fetcher.test.d.ts.map +0 -1
  613. package/dist/test/mcpl-reference-fetcher.test.js +0 -427
  614. package/dist/test/mcpl-reference-fetcher.test.js.map +0 -1
  615. package/dist/test/mcpl-reference-fields.test.d.ts +0 -2
  616. package/dist/test/mcpl-reference-fields.test.d.ts.map +0 -1
  617. package/dist/test/mcpl-reference-fields.test.js +0 -149
  618. package/dist/test/mcpl-reference-fields.test.js.map +0 -1
  619. package/dist/test/mcpl-rejection-log-lines.test.d.ts +0 -2
  620. package/dist/test/mcpl-rejection-log-lines.test.d.ts.map +0 -1
  621. package/dist/test/mcpl-rejection-log-lines.test.js +0 -349
  622. package/dist/test/mcpl-rejection-log-lines.test.js.map +0 -1
  623. package/dist/test/mcpl-request-timeout.test.d.ts +0 -2
  624. package/dist/test/mcpl-request-timeout.test.d.ts.map +0 -1
  625. package/dist/test/mcpl-request-timeout.test.js +0 -138
  626. package/dist/test/mcpl-request-timeout.test.js.map +0 -1
  627. package/dist/test/mcpl-runtime-lifecycle.test.d.ts +0 -7
  628. package/dist/test/mcpl-runtime-lifecycle.test.d.ts.map +0 -1
  629. package/dist/test/mcpl-runtime-lifecycle.test.js +0 -142
  630. package/dist/test/mcpl-runtime-lifecycle.test.js.map +0 -1
  631. package/dist/test/mcpl-stderr-tail.test.d.ts +0 -2
  632. package/dist/test/mcpl-stderr-tail.test.d.ts.map +0 -1
  633. package/dist/test/mcpl-stderr-tail.test.js +0 -210
  634. package/dist/test/mcpl-stderr-tail.test.js.map +0 -1
  635. package/dist/test/mcpl-tool-class-listing.test.d.ts +0 -2
  636. package/dist/test/mcpl-tool-class-listing.test.d.ts.map +0 -1
  637. package/dist/test/mcpl-tool-class-listing.test.js +0 -147
  638. package/dist/test/mcpl-tool-class-listing.test.js.map +0 -1
  639. package/dist/test/mcpl-tool-classes.test.d.ts +0 -7
  640. package/dist/test/mcpl-tool-classes.test.d.ts.map +0 -1
  641. package/dist/test/mcpl-tool-classes.test.js +0 -80
  642. package/dist/test/mcpl-tool-classes.test.js.map +0 -1
  643. package/dist/test/mcpl-tool-lifecycle-e2e.test.d.ts +0 -2
  644. package/dist/test/mcpl-tool-lifecycle-e2e.test.d.ts.map +0 -1
  645. package/dist/test/mcpl-tool-lifecycle-e2e.test.js +0 -237
  646. package/dist/test/mcpl-tool-lifecycle-e2e.test.js.map +0 -1
  647. package/dist/test/mcpl-tool-lifecycle-emitter.test.d.ts +0 -11
  648. package/dist/test/mcpl-tool-lifecycle-emitter.test.d.ts.map +0 -1
  649. package/dist/test/mcpl-tool-lifecycle-emitter.test.js +0 -412
  650. package/dist/test/mcpl-tool-lifecycle-emitter.test.js.map +0 -1
  651. package/dist/test/mcpl-tool-lifecycle-script.test.d.ts +0 -2
  652. package/dist/test/mcpl-tool-lifecycle-script.test.d.ts.map +0 -1
  653. package/dist/test/mcpl-tool-lifecycle-script.test.js +0 -288
  654. package/dist/test/mcpl-tool-lifecycle-script.test.js.map +0 -1
  655. package/dist/test/mcpl-tool-lifecycle.test.d.ts +0 -11
  656. package/dist/test/mcpl-tool-lifecycle.test.d.ts.map +0 -1
  657. package/dist/test/mcpl-tool-lifecycle.test.js +0 -270
  658. package/dist/test/mcpl-tool-lifecycle.test.js.map +0 -1
  659. package/dist/test/mcpl-transport-close.test.d.ts +0 -2
  660. package/dist/test/mcpl-transport-close.test.d.ts.map +0 -1
  661. package/dist/test/mcpl-transport-close.test.js +0 -373
  662. package/dist/test/mcpl-transport-close.test.js.map +0 -1
  663. package/dist/test/mcpl-transport-spawn.test.d.ts +0 -2
  664. package/dist/test/mcpl-transport-spawn.test.d.ts.map +0 -1
  665. package/dist/test/mcpl-transport-spawn.test.js +0 -58
  666. package/dist/test/mcpl-transport-spawn.test.js.map +0 -1
  667. package/dist/test/mcpl-ws-transport.test.d.ts +0 -2
  668. package/dist/test/mcpl-ws-transport.test.d.ts.map +0 -1
  669. package/dist/test/mcpl-ws-transport.test.js +0 -259
  670. package/dist/test/mcpl-ws-transport.test.js.map +0 -1
  671. package/dist/test/module-context-integration.test.d.ts +0 -18
  672. package/dist/test/module-context-integration.test.d.ts.map +0 -1
  673. package/dist/test/module-context-integration.test.js +0 -181
  674. package/dist/test/module-context-integration.test.js.map +0 -1
  675. package/dist/test/offline-recovery-branch.test.d.ts +0 -2
  676. package/dist/test/offline-recovery-branch.test.d.ts.map +0 -1
  677. package/dist/test/offline-recovery-branch.test.js +0 -570
  678. package/dist/test/offline-recovery-branch.test.js.map +0 -1
  679. package/dist/test/operator-surgery.test.d.ts +0 -2
  680. package/dist/test/operator-surgery.test.d.ts.map +0 -1
  681. package/dist/test/operator-surgery.test.js +0 -595
  682. package/dist/test/operator-surgery.test.js.map +0 -1
  683. package/dist/test/ops-alert.test.d.ts +0 -2
  684. package/dist/test/ops-alert.test.d.ts.map +0 -1
  685. package/dist/test/ops-alert.test.js +0 -153
  686. package/dist/test/ops-alert.test.js.map +0 -1
  687. package/dist/test/overbudget-drain-breaker.test.d.ts +0 -2
  688. package/dist/test/overbudget-drain-breaker.test.d.ts.map +0 -1
  689. package/dist/test/overbudget-drain-breaker.test.js +0 -198
  690. package/dist/test/overbudget-drain-breaker.test.js.map +0 -1
  691. package/dist/test/pack-installs-alone.test.d.ts +0 -2
  692. package/dist/test/pack-installs-alone.test.d.ts.map +0 -1
  693. package/dist/test/pack-installs-alone.test.js +0 -284
  694. package/dist/test/pack-installs-alone.test.js.map +0 -1
  695. package/dist/test/per-agent-delivery.test.d.ts +0 -2
  696. package/dist/test/per-agent-delivery.test.d.ts.map +0 -1
  697. package/dist/test/per-agent-delivery.test.js +0 -108
  698. package/dist/test/per-agent-delivery.test.js.map +0 -1
  699. package/dist/test/physical-window-restart.test.d.ts +0 -16
  700. package/dist/test/physical-window-restart.test.d.ts.map +0 -1
  701. package/dist/test/physical-window-restart.test.js +0 -487
  702. package/dist/test/physical-window-restart.test.js.map +0 -1
  703. package/dist/test/placed-reaction-baseline.test.d.ts +0 -2
  704. package/dist/test/placed-reaction-baseline.test.d.ts.map +0 -1
  705. package/dist/test/placed-reaction-baseline.test.js +0 -312
  706. package/dist/test/placed-reaction-baseline.test.js.map +0 -1
  707. package/dist/test/present-while-acting.test.d.ts +0 -19
  708. package/dist/test/present-while-acting.test.d.ts.map +0 -1
  709. package/dist/test/present-while-acting.test.js +0 -1649
  710. package/dist/test/present-while-acting.test.js.map +0 -1
  711. package/dist/test/prose-segments.test.d.ts +0 -2
  712. package/dist/test/prose-segments.test.d.ts.map +0 -1
  713. package/dist/test/prose-segments.test.js +0 -52
  714. package/dist/test/prose-segments.test.js.map +0 -1
  715. package/dist/test/prose-stream-router.test.d.ts +0 -2
  716. package/dist/test/prose-stream-router.test.d.ts.map +0 -1
  717. package/dist/test/prose-stream-router.test.js +0 -171
  718. package/dist/test/prose-stream-router.test.js.map +0 -1
  719. package/dist/test/provider-acceleration-cooldown.test.d.ts +0 -2
  720. package/dist/test/provider-acceleration-cooldown.test.d.ts.map +0 -1
  721. package/dist/test/provider-acceleration-cooldown.test.js +0 -435
  722. package/dist/test/provider-acceleration-cooldown.test.js.map +0 -1
  723. package/dist/test/provider-waits.test.d.ts +0 -2
  724. package/dist/test/provider-waits.test.d.ts.map +0 -1
  725. package/dist/test/provider-waits.test.js +0 -2259
  726. package/dist/test/provider-waits.test.js.map +0 -1
  727. package/dist/test/puppet-tool-call.test.d.ts +0 -2
  728. package/dist/test/puppet-tool-call.test.d.ts.map +0 -1
  729. package/dist/test/puppet-tool-call.test.js +0 -226
  730. package/dist/test/puppet-tool-call.test.js.map +0 -1
  731. package/dist/test/puppet-turn-reservation.test.d.ts +0 -2
  732. package/dist/test/puppet-turn-reservation.test.d.ts.map +0 -1
  733. package/dist/test/puppet-turn-reservation.test.js +0 -139
  734. package/dist/test/puppet-turn-reservation.test.js.map +0 -1
  735. package/dist/test/reaction-baseline-platform.test.d.ts +0 -2
  736. package/dist/test/reaction-baseline-platform.test.d.ts.map +0 -1
  737. package/dist/test/reaction-baseline-platform.test.js +0 -124
  738. package/dist/test/reaction-baseline-platform.test.js.map +0 -1
  739. package/dist/test/record-journal.test.d.ts +0 -6
  740. package/dist/test/record-journal.test.d.ts.map +0 -1
  741. package/dist/test/record-journal.test.js +0 -269
  742. package/dist/test/record-journal.test.js.map +0 -1
  743. package/dist/test/refusal-reaction-baseline.test.d.ts +0 -2
  744. package/dist/test/refusal-reaction-baseline.test.d.ts.map +0 -1
  745. package/dist/test/refusal-reaction-baseline.test.js +0 -81
  746. package/dist/test/refusal-reaction-baseline.test.js.map +0 -1
  747. package/dist/test/refusal-rewind.test.d.ts +0 -2
  748. package/dist/test/refusal-rewind.test.d.ts.map +0 -1
  749. package/dist/test/refusal-rewind.test.js +0 -117
  750. package/dist/test/refusal-rewind.test.js.map +0 -1
  751. package/dist/test/refusal-single-call.test.d.ts +0 -2
  752. package/dist/test/refusal-single-call.test.d.ts.map +0 -1
  753. package/dist/test/refusal-single-call.test.js +0 -177
  754. package/dist/test/refusal-single-call.test.js.map +0 -1
  755. package/dist/test/release-bump.test.d.ts +0 -2
  756. package/dist/test/release-bump.test.d.ts.map +0 -1
  757. package/dist/test/release-bump.test.js +0 -248
  758. package/dist/test/release-bump.test.js.map +0 -1
  759. package/dist/test/release-changelog.test.d.ts +0 -2
  760. package/dist/test/release-changelog.test.d.ts.map +0 -1
  761. package/dist/test/release-changelog.test.js +0 -159
  762. package/dist/test/release-changelog.test.js.map +0 -1
  763. package/dist/test/release-holds.test.d.ts +0 -2
  764. package/dist/test/release-holds.test.d.ts.map +0 -1
  765. package/dist/test/release-holds.test.js +0 -456
  766. package/dist/test/release-holds.test.js.map +0 -1
  767. package/dist/test/same-round-think-policy.test.d.ts +0 -2
  768. package/dist/test/same-round-think-policy.test.d.ts.map +0 -1
  769. package/dist/test/same-round-think-policy.test.js +0 -853
  770. package/dist/test/same-round-think-policy.test.js.map +0 -1
  771. package/dist/test/save-recent-image.test.d.ts +0 -26
  772. package/dist/test/save-recent-image.test.d.ts.map +0 -1
  773. package/dist/test/save-recent-image.test.js +0 -974
  774. package/dist/test/save-recent-image.test.js.map +0 -1
  775. package/dist/test/shutdown-errors.test.d.ts +0 -2
  776. package/dist/test/shutdown-errors.test.d.ts.map +0 -1
  777. package/dist/test/shutdown-errors.test.js +0 -662
  778. package/dist/test/shutdown-errors.test.js.map +0 -1
  779. package/dist/test/silent-heartbeat-rows.test.d.ts +0 -2
  780. package/dist/test/silent-heartbeat-rows.test.d.ts.map +0 -1
  781. package/dist/test/silent-heartbeat-rows.test.js +0 -451
  782. package/dist/test/silent-heartbeat-rows.test.js.map +0 -1
  783. package/dist/test/silent-heartbeat.test.d.ts +0 -2
  784. package/dist/test/silent-heartbeat.test.d.ts.map +0 -1
  785. package/dist/test/silent-heartbeat.test.js +0 -165
  786. package/dist/test/silent-heartbeat.test.js.map +0 -1
  787. package/dist/test/state-scaling-e2e.test.d.ts +0 -22
  788. package/dist/test/state-scaling-e2e.test.d.ts.map +0 -1
  789. package/dist/test/state-scaling-e2e.test.js +0 -206
  790. package/dist/test/state-scaling-e2e.test.js.map +0 -1
  791. package/dist/test/state-scaling.test.d.ts +0 -12
  792. package/dist/test/state-scaling.test.d.ts.map +0 -1
  793. package/dist/test/state-scaling.test.js +0 -251
  794. package/dist/test/state-scaling.test.js.map +0 -1
  795. package/dist/test/stop-with-host-operations.test.d.ts +0 -20
  796. package/dist/test/stop-with-host-operations.test.d.ts.map +0 -1
  797. package/dist/test/stop-with-host-operations.test.js +0 -1174
  798. package/dist/test/stop-with-host-operations.test.js.map +0 -1
  799. package/dist/test/stop-with-work-in-flight.test.d.ts +0 -23
  800. package/dist/test/stop-with-work-in-flight.test.d.ts.map +0 -1
  801. package/dist/test/stop-with-work-in-flight.test.js +0 -784
  802. package/dist/test/stop-with-work-in-flight.test.js.map +0 -1
  803. package/dist/test/surgery-marks-receipt.test.d.ts +0 -2
  804. package/dist/test/surgery-marks-receipt.test.d.ts.map +0 -1
  805. package/dist/test/surgery-marks-receipt.test.js +0 -540
  806. package/dist/test/surgery-marks-receipt.test.js.map +0 -1
  807. package/dist/test/thinking-token-stamp.test.d.ts +0 -12
  808. package/dist/test/thinking-token-stamp.test.d.ts.map +0 -1
  809. package/dist/test/thinking-token-stamp.test.js +0 -129
  810. package/dist/test/thinking-token-stamp.test.js.map +0 -1
  811. package/dist/test/timezone.test.d.ts +0 -2
  812. package/dist/test/timezone.test.d.ts.map +0 -1
  813. package/dist/test/timezone.test.js +0 -18
  814. package/dist/test/timezone.test.js.map +0 -1
  815. package/dist/test/tool-batch-hook.test.d.ts +0 -8
  816. package/dist/test/tool-batch-hook.test.d.ts.map +0 -1
  817. package/dist/test/tool-batch-hook.test.js +0 -275
  818. package/dist/test/tool-batch-hook.test.js.map +0 -1
  819. package/dist/test/tool-policy.test.d.ts +0 -2
  820. package/dist/test/tool-policy.test.d.ts.map +0 -1
  821. package/dist/test/tool-policy.test.js +0 -51
  822. package/dist/test/tool-policy.test.js.map +0 -1
  823. package/dist/test/tool-presentation.test.d.ts +0 -2
  824. package/dist/test/tool-presentation.test.d.ts.map +0 -1
  825. package/dist/test/tool-presentation.test.js +0 -268
  826. package/dist/test/tool-presentation.test.js.map +0 -1
  827. package/dist/test/tool-result-content.test.d.ts +0 -2
  828. package/dist/test/tool-result-content.test.d.ts.map +0 -1
  829. package/dist/test/tool-result-content.test.js +0 -37
  830. package/dist/test/tool-result-content.test.js.map +0 -1
  831. package/dist/test/tool-result-guard.test.d.ts +0 -2
  832. package/dist/test/tool-result-guard.test.d.ts.map +0 -1
  833. package/dist/test/tool-result-guard.test.js +0 -3729
  834. package/dist/test/tool-result-guard.test.js.map +0 -1
  835. package/dist/test/tool-result-history.test.d.ts +0 -7
  836. package/dist/test/tool-result-history.test.d.ts.map +0 -1
  837. package/dist/test/tool-result-history.test.js +0 -156
  838. package/dist/test/tool-result-history.test.js.map +0 -1
  839. package/dist/test/tool-result-spill.test.d.ts +0 -13
  840. package/dist/test/tool-result-spill.test.d.ts.map +0 -1
  841. package/dist/test/tool-result-spill.test.js +0 -586
  842. package/dist/test/tool-result-spill.test.js.map +0 -1
  843. package/dist/test/tool-wrapper-prose-guard-integration.test.d.ts +0 -2
  844. package/dist/test/tool-wrapper-prose-guard-integration.test.d.ts.map +0 -1
  845. package/dist/test/tool-wrapper-prose-guard-integration.test.js +0 -485
  846. package/dist/test/tool-wrapper-prose-guard-integration.test.js.map +0 -1
  847. package/dist/test/tool-wrapper-prose-guard.test.d.ts +0 -2
  848. package/dist/test/tool-wrapper-prose-guard.test.d.ts.map +0 -1
  849. package/dist/test/tool-wrapper-prose-guard.test.js +0 -34
  850. package/dist/test/tool-wrapper-prose-guard.test.js.map +0 -1
  851. package/dist/test/tools-observe-parser-conformance.test.d.ts +0 -2
  852. package/dist/test/tools-observe-parser-conformance.test.d.ts.map +0 -1
  853. package/dist/test/tools-observe-parser-conformance.test.js +0 -129
  854. package/dist/test/tools-observe-parser-conformance.test.js.map +0 -1
  855. package/dist/test/trunk-channel-routing.test.d.ts +0 -19
  856. package/dist/test/trunk-channel-routing.test.d.ts.map +0 -1
  857. package/dist/test/trunk-channel-routing.test.js +0 -652
  858. package/dist/test/trunk-channel-routing.test.js.map +0 -1
  859. package/dist/test/tune-out-e2e.test.d.ts +0 -2
  860. package/dist/test/tune-out-e2e.test.d.ts.map +0 -1
  861. package/dist/test/tune-out-e2e.test.js +0 -142
  862. package/dist/test/tune-out-e2e.test.js.map +0 -1
  863. package/dist/test/tune-out-gate-composition.test.d.ts +0 -2
  864. package/dist/test/tune-out-gate-composition.test.d.ts.map +0 -1
  865. package/dist/test/tune-out-gate-composition.test.js +0 -221
  866. package/dist/test/tune-out-gate-composition.test.js.map +0 -1
  867. package/dist/test/tune-out-lifecycle.test.d.ts +0 -2
  868. package/dist/test/tune-out-lifecycle.test.d.ts.map +0 -1
  869. package/dist/test/tune-out-lifecycle.test.js +0 -121
  870. package/dist/test/tune-out-lifecycle.test.js.map +0 -1
  871. package/dist/test/turn-trigger-provenance.test.d.ts +0 -2
  872. package/dist/test/turn-trigger-provenance.test.d.ts.map +0 -1
  873. package/dist/test/turn-trigger-provenance.test.js +0 -137
  874. package/dist/test/turn-trigger-provenance.test.js.map +0 -1
  875. package/dist/test/unconvertible-tool-result.test.d.ts +0 -2
  876. package/dist/test/unconvertible-tool-result.test.d.ts.map +0 -1
  877. package/dist/test/unconvertible-tool-result.test.js +0 -358
  878. package/dist/test/unconvertible-tool-result.test.js.map +0 -1
  879. package/dist/test/unsent-compiles.test.d.ts +0 -2
  880. package/dist/test/unsent-compiles.test.d.ts.map +0 -1
  881. package/dist/test/unsent-compiles.test.js +0 -139
  882. package/dist/test/unsent-compiles.test.js.map +0 -1
  883. package/dist/test/usage-accounting.test.d.ts +0 -2
  884. package/dist/test/usage-accounting.test.d.ts.map +0 -1
  885. package/dist/test/usage-accounting.test.js +0 -13
  886. package/dist/test/usage-accounting.test.js.map +0 -1
  887. package/dist/test/usage-tracker.test.d.ts +0 -2
  888. package/dist/test/usage-tracker.test.d.ts.map +0 -1
  889. package/dist/test/usage-tracker.test.js +0 -129
  890. package/dist/test/usage-tracker.test.js.map +0 -1
  891. package/dist/test/utils-surface.test.d.ts +0 -2
  892. package/dist/test/utils-surface.test.d.ts.map +0 -1
  893. package/dist/test/utils-surface.test.js +0 -145
  894. package/dist/test/utils-surface.test.js.map +0 -1
  895. package/dist/test/workspace-branch-continuation.test.d.ts +0 -15
  896. package/dist/test/workspace-branch-continuation.test.d.ts.map +0 -1
  897. package/dist/test/workspace-branch-continuation.test.js +0 -183
  898. package/dist/test/workspace-branch-continuation.test.js.map +0 -1
  899. package/dist/test/workspace-materialize-freshness.test.d.ts +0 -16
  900. package/dist/test/workspace-materialize-freshness.test.d.ts.map +0 -1
  901. package/dist/test/workspace-materialize-freshness.test.js +0 -252
  902. package/dist/test/workspace-materialize-freshness.test.js.map +0 -1
  903. package/dist/test/workspace-path-containment.test.d.ts +0 -19
  904. package/dist/test/workspace-path-containment.test.d.ts.map +0 -1
  905. package/dist/test/workspace-path-containment.test.js +0 -91
  906. package/dist/test/workspace-path-containment.test.js.map +0 -1
  907. package/dist/test/workspace-read-file-from-disk.test.d.ts +0 -17
  908. package/dist/test/workspace-read-file-from-disk.test.d.ts.map +0 -1
  909. package/dist/test/workspace-read-file-from-disk.test.js +0 -174
  910. package/dist/test/workspace-read-file-from-disk.test.js.map +0 -1
  911. package/dist/test/workspace-read-image.test.d.ts +0 -2
  912. package/dist/test/workspace-read-image.test.d.ts.map +0 -1
  913. package/dist/test/workspace-read-image.test.js +0 -597
  914. package/dist/test/workspace-read-image.test.js.map +0 -1
  915. package/dist/test/workspace-read-text.test.d.ts +0 -2
  916. package/dist/test/workspace-read-text.test.d.ts.map +0 -1
  917. package/dist/test/workspace-read-text.test.js +0 -101
  918. package/dist/test/workspace-read-text.test.js.map +0 -1
  919. package/dist/test/workspace-restore-order.test.d.ts +0 -16
  920. package/dist/test/workspace-restore-order.test.d.ts.map +0 -1
  921. package/dist/test/workspace-restore-order.test.js +0 -140
  922. package/dist/test/workspace-restore-order.test.js.map +0 -1
  923. package/dist/test/workspace-three-way.test.d.ts +0 -12
  924. package/dist/test/workspace-three-way.test.d.ts.map +0 -1
  925. package/dist/test/workspace-three-way.test.js +0 -4094
  926. package/dist/test/workspace-three-way.test.js.map +0 -1
  927. package/dist/test/workspace-watcher.test.d.ts +0 -2
  928. package/dist/test/workspace-watcher.test.d.ts.map +0 -1
  929. package/dist/test/workspace-watcher.test.js +0 -281
  930. package/dist/test/workspace-watcher.test.js.map +0 -1
  931. package/dist/test/xml-round-persist.test.d.ts +0 -19
  932. package/dist/test/xml-round-persist.test.d.ts.map +0 -1
  933. package/dist/test/xml-round-persist.test.js +0 -235
  934. package/dist/test/xml-round-persist.test.js.map +0 -1
  935. package/dist/tsconfig.tsbuildinfo +0 -1
@@ -41,7 +41,9 @@
41
41
  import { Worker } from 'node:worker_threads';
42
42
  import { fileURLToPath } from 'node:url';
43
43
  import { dirname, join } from 'node:path';
44
- import { SemanticIndexClient, SemanticIndexer, messageIndexText } from './semantic.js';
44
+ import { EmbedServiceError, SemanticIndexClient, SemanticIndexer, messageIndexText } from './semantic.js';
45
+ import { unknownToolMessage } from '../unknown-tool.js';
46
+ import { safeSlice } from '../../safe-slice.js';
45
47
  // ============================================================================
46
48
  // Limits
47
49
  // ============================================================================
@@ -84,9 +86,14 @@ const AROUND_MAX = 100;
84
86
  * `extract({aroundId})` will fetch to order them by sequence — real stores
85
87
  * see a handful; past this the call fails loudly rather than guessing. */
86
88
  const AROUND_TIE_CAP = 5000;
87
- function tieCapError(anchorId, n) {
88
- return new Error(`Message ${anchorId} shares its timestamp with ${n} messages (more than ${AROUND_TIE_CAP}), too many to order ` +
89
- 'around it. Use extract with from/to set to that instant instead.');
89
+ function tieCapError(anchorId, ms, channelId) {
90
+ const at = new Date(ms).toISOString();
91
+ // The channel is the agent's to send back, so it's quoted whole: a cut one
92
+ // couldn't be sent. It's one the store holds, with all those messages in it.
93
+ const inChannel = channelId !== undefined ? ` and "channelId" set to ${JSON.stringify(channelId)}` : '';
94
+ return new Error(`Nothing was read: more than ${AROUND_TIE_CAP} messages share the timestamp of message ${shown(anchorId)}, ${at}, too ` +
95
+ `many for aroundId to put in order. To read them, call history--extract with "from" and "to" both set to ${at}` +
96
+ `${inChannel}; it pages through them with "offset" and "limit".`);
90
97
  }
91
98
  /** Largest valid Date value (ms) — an open newest edge. */
92
99
  const MAX_DATE_MS = 8.64e15;
@@ -109,9 +116,13 @@ const SEMANTIC_DEFAULT_LIMIT = 10;
109
116
  const SEMANTIC_MAX_LIMIT = 50;
110
117
  /** Largest k sent to the embed-service when over-fetching past dropped hits (its own cap is 200). */
111
118
  const SEMANTIC_MAX_FETCH = 200;
112
- /** Local snippet: the leading SEMANTIC_SNIPPET_CHARS of the current text. */
119
+ /**
120
+ * Local snippet: the leading SEMANTIC_SNIPPET_CHARS of the current text, one
121
+ * fewer where the last would split a surrogate pair, since the snippet reaches
122
+ * the agent's context.
123
+ */
113
124
  function snippetOf(text) {
114
- return text.length <= SEMANTIC_SNIPPET_CHARS ? text : `${text.slice(0, SEMANTIC_SNIPPET_CHARS)}…`;
125
+ return text.length <= SEMANTIC_SNIPPET_CHARS ? text : `${safeSlice(text, 0, SEMANTIC_SNIPPET_CHARS)}…`;
115
126
  }
116
127
  const SEMANTIC_SNIPPET_CHARS = 400;
117
128
  /**
@@ -229,7 +240,9 @@ export class HistoryModule {
229
240
  * you're trying to deliver a message, nonsense advice from a read-only
230
241
  * history tool. This module always uses its own read-only-appropriate
231
242
  * wording instead, regardless of which branch of the live resolver
232
- * produced the miss.
243
+ * produced the miss. Its refusals open with "Nothing was read", which
244
+ * holds because every tool that resolves a channel here only reads (see
245
+ * the note above the helpers).
233
246
  */
234
247
  resolveChannel(input) {
235
248
  if (!input || !this.channelRegistry)
@@ -238,8 +251,10 @@ export class HistoryModule {
238
251
  if (!('error' in resolved))
239
252
  return resolved.channelId;
240
253
  if (input.startsWith('#') || input.startsWith('@') || DM_MENTION_RE.test(input)) {
241
- const suggestions = resolved.candidates?.length ? ` Did you mean: ${resolved.candidates.join(', ')}?` : '';
242
- throw new Error(`No channel history found for "${input}" — it may never have been seen by this resident, or predates this feature.${suggestions}`);
254
+ const suggestions = resolved.candidates?.length ? ` Did you mean ${quotedList(resolved.candidates, 'or')}?` : '';
255
+ throw new Error(`Nothing was read: no channel history matches ${shown(input)}. This host may never have seen a channel by that ` +
256
+ `name, or saw it before it kept channel names.${suggestions} Each message history--search returns carries ` +
257
+ 'its "channelId", so searching for something said in that channel shows its id; pass that id as "channelId".');
243
258
  }
244
259
  return input;
245
260
  }
@@ -279,8 +294,14 @@ export class HistoryModule {
279
294
  ? cm.queryMessagesByTimeAndChannel({ fromMs: ms, toMs: ms, channelId, limit: 0 }).matchedCount
280
295
  : cm.queryMessagesByTime({ fromMs: ms, toMs: ms, limit: AROUND_TIE_CAP + 1 }).messages.length;
281
296
  if (n > AROUND_TIE_CAP) {
282
- throw new Error(`More than ${AROUND_TIE_CAP} messages share the instant ${new Date(ms).toISOString()}; a continuation can't step ` +
283
- 'through them. Narrow the search with channelId/author instead.');
297
+ // The count is by channel alone, so an author filter can't bring it down.
298
+ const at = new Date(ms).toISOString();
299
+ throw new Error(`Nothing was searched: more than ${AROUND_TIE_CAP} messages share the instant ${at}, too many for a ` +
300
+ `continuation to step past. To read them, call history--extract with "from" and "to" both set to ${at}` +
301
+ (channelId !== undefined
302
+ ? ' and the same "channelId"; it pages through them with "offset" and "limit".'
303
+ : '; it pages through them with "offset" and "limit". Searching one channel, with "channelId", may also ' +
304
+ 'bring them under the limit.'));
284
305
  }
285
306
  return n;
286
307
  }
@@ -331,13 +352,16 @@ export class HistoryModule {
331
352
  */
332
353
  relocateWindowOffset(windowOffset, afterId, q) {
333
354
  if (windowOffset === 0) {
334
- if (afterId != null)
335
- throw new Error('"afterId" only applies together with a windowOffset > 0.');
355
+ if (afterId != null) {
356
+ throw new Error('Nothing was read: "afterId" goes with a "windowOffset" above 0, both copied from a truncated response\'s ' +
357
+ '"resume". For a first page, leave afterId out; to continue, copy the fields of that "resume" into the call.');
358
+ }
336
359
  return { windowOffset, shift: 0 };
337
360
  }
338
361
  if (afterId == null) {
339
- throw new Error('"windowOffset" needs the "afterId" from the same `resume` object — without it a message added or removed ' +
340
- 'since the previous call would be silently skipped. Pass the whole `resume` object back.');
362
+ throw new Error('Nothing was read: "windowOffset" needs the "afterId" from the same "resume", or a message added or removed ' +
363
+ 'since the previous call would be skipped unseen. Copy the fields of the previous response\'s "resume" into ' +
364
+ 'the call.');
341
365
  }
342
366
  const cm = this.cm;
343
367
  const at = cm.queryMessagesByTimeAndChannel({ ...q, limit: 1, offset: windowOffset - 1 }).messages[0];
@@ -347,9 +371,9 @@ export class HistoryModule {
347
371
  const around = cm.queryMessagesByTimeAndChannel({ ...q, limit: 2 * RELOCATE_RADIUS + 1, offset: lo }).messages;
348
372
  const i = around.findIndex((m) => String(m.id) === afterId);
349
373
  if (i === -1) {
350
- throw new Error(`The window changed since the previous call: message ${afterId}, where that scan stopped, is no longer ` +
351
- `within ${RELOCATE_RADIUS} positions of windowOffset ${windowOffset} (it may have been deleted). ` +
352
- 'Restart the scan without windowOffset/afterId, or narrow it with from/to.');
374
+ throw new Error(`Nothing was read: the window changed since the previous call. Message ${shown(afterId)}, where that scan stopped, ` +
375
+ `is no longer within ${RELOCATE_RADIUS} positions of windowOffset ${windowOffset}; it may have been deleted. ` +
376
+ 'Restart the scan without "windowOffset" and "afterId", over the same range or one narrowed with "from" and "to".');
353
377
  }
354
378
  const relocated = lo + i + 1;
355
379
  return { windowOffset: relocated, shift: relocated - windowOffset };
@@ -589,7 +613,7 @@ export class HistoryModule {
589
613
  excludeAuthor: EXCLUDE_AUTHOR_SCHEMA,
590
614
  order: { type: 'string', enum: ['oldest', 'newest'], description: 'Scan and return oldest-first (default) or newest-first.' },
591
615
  limit: { type: 'number', description: `Max matches to return (default ${SEARCH_DEFAULT_LIMIT}, hard cap ${SEARCH_MAX_LIMIT}). Must be a non-negative integer.` },
592
- maxScan: { type: 'number', description: `Max candidate messages to scan (default ${SEARCH_DEFAULT_MAX_SCAN}, hard cap ${SEARCH_MAX_MAX_SCAN}). Must be a non-negative integer.` },
616
+ maxScan: { type: 'number', description: `Max candidate messages to scan (default ${SEARCH_DEFAULT_MAX_SCAN}, hard cap ${SEARCH_MAX_MAX_SCAN}). Must be a whole number, 1 or more.` },
593
617
  skipSequences: {
594
618
  type: 'array',
595
619
  items: { type: 'number' },
@@ -661,7 +685,10 @@ export class HistoryModule {
661
685
  'Purely a read: nothing is written to your history. Hits are checked against your current branch ' +
662
686
  'before they come back: a message you undid or a summary from a branch you left is dropped and ' +
663
687
  'counted in index.droppedOffBranch; a message edited down to nothing searchable is dropped and ' +
664
- 'counted in index.droppedStale. Message snippets always show the current text of the message.',
688
+ 'counted in index.droppedStale. When that leaves fewer than `limit` hits and the index may hold more, it ' +
689
+ 'searches again, deeper, down to its first 200 hits; if a search after the first fails, the hits found so ' +
690
+ 'far come back, with why in index.searchAgainError. Message snippets ' +
691
+ 'always show the current text of the message.',
665
692
  inputSchema: {
666
693
  type: 'object',
667
694
  properties: {
@@ -681,7 +708,11 @@ export class HistoryModule {
681
708
  async handleToolCall(call) {
682
709
  try {
683
710
  if (!this.cm) {
684
- throw new Error('HistoryModule not bound — host must call bind(contextManager) before tool dispatch.');
711
+ // The host's mistake, named for whoever runs it; the agent reads what
712
+ // it can do about it, which is nothing.
713
+ console.error('[history] a tool was called before the host bound the module: call bind(contextManager) before tool dispatch');
714
+ throw new Error("The history tools aren't available: this host hasn't finished setting up the history module, so nothing " +
715
+ "was read. Calling them again won't change that; ask whoever runs this host.");
685
716
  }
686
717
  switch (call.name) {
687
718
  case 'stats':
@@ -695,7 +726,7 @@ export class HistoryModule {
695
726
  case 'semantic_search':
696
727
  return await this.handleSemanticSearch((call.input ?? {}));
697
728
  default:
698
- return { success: false, isError: true, error: `Unknown tool: ${call.name}` };
729
+ return { success: false, isError: true, error: unknownToolMessage(this.name, call.name, this.getTools()) };
699
730
  }
700
731
  }
701
732
  catch (error) {
@@ -758,19 +789,28 @@ export class HistoryModule {
758
789
  handleExtract(input) {
759
790
  if (input.aroundId !== undefined)
760
791
  return this.handleExtractAround(input);
761
- if (input.before !== undefined || input.after !== undefined || input.allChannels !== undefined) {
762
- throw new Error('"before"/"after"/"allChannels" only apply together with "aroundId".');
792
+ const aroundOnly = ['before', 'after', 'allChannels'].filter((k) => input[k] !== undefined);
793
+ if (aroundOnly.length > 0) {
794
+ const one = aroundOnly.length === 1;
795
+ throw new Error(`Nothing was read: ${quotedList(aroundOnly, 'and')} ${one ? 'goes' : 'go'} with "aroundId", which reads the ` +
796
+ `conversation around one message. Pass aroundId too, or leave ${one ? 'it' : 'them'} out to read a range ` +
797
+ 'with "from", "to" and "channelId".');
763
798
  }
764
799
  const channelId = this.resolveChannel(input.channelId);
765
800
  const fromMs = parseIsoDate(input.from, 'from');
766
801
  const toMs = parseIsoDate(input.to, 'to');
767
- const limit = clampCount(input.limit, EXTRACT_DEFAULT_LIMIT, EXTRACT_MAX_LIMIT, 'limit');
768
- const offset = clampCount(input.offset, 0, NATIVE_OFFSET_MAX, 'offset');
802
+ const limit = clampCount(input.limit, EXTRACT_DEFAULT_LIMIT, EXTRACT_MAX_LIMIT, 'limit', 'read');
803
+ const offset = clampCount(input.offset, 0, NATIVE_OFFSET_MAX, 'offset', 'read');
769
804
  const format = input.format ?? 'text';
770
805
  const authorFilter = buildAuthorFilter(input.author, input.excludeAuthor);
771
806
  const cm = this.cm;
772
- if (!authorFilter && (input.windowOffset !== undefined || input.afterId !== undefined || input.seqMark !== undefined)) {
773
- throw new Error('"windowOffset"/"afterId" only apply together with author/excludeAuthor (they resume a filtered scan). Use offset.');
807
+ const resumeOnly = ['windowOffset', 'afterId', 'seqMark'].filter((k) => input[k] !== undefined);
808
+ if (!authorFilter && resumeOnly.length > 0) {
809
+ const one = resumeOnly.length === 1;
810
+ throw new Error(`Nothing was read: ${quotedList(resumeOnly, 'and')} ${one ? 'resumes' : 'resume'} an author-filtered ` +
811
+ `extract, so ${one ? 'it goes' : 'they go'} with the "author" or "excludeAuthor" of the call that returned ` +
812
+ `${one ? 'it' : 'them'}: repeat that call with the fields of its "resume". To page through a range without an ` +
813
+ 'author filter, use "offset".');
774
814
  }
775
815
  if (authorFilter) {
776
816
  // No native author index: page through the time/channel window and
@@ -783,10 +823,9 @@ export class HistoryModule {
783
823
  // channel-scoped window pages in append order, and Discord catch-up
784
824
  // appends old-timestamped messages late, so "continue from the last
785
825
  // timestamp seen" would skip them.
786
- const maxScan = clampCount(input.maxScan, EXTRACT_FILTER_DEFAULT_MAX_SCAN, EXTRACT_FILTER_MAX_MAX_SCAN, 'maxScan');
787
- if (maxScan === 0)
788
- throw new Error('"maxScan" must be at least 1 for an author-filtered extract.');
789
- const requestedOffset = clampCount(input.windowOffset, 0, NATIVE_OFFSET_MAX, 'windowOffset');
826
+ // An author-filtered extract has to examine at least 1 message.
827
+ const maxScan = clampCount(input.maxScan, EXTRACT_FILTER_DEFAULT_MAX_SCAN, EXTRACT_FILTER_MAX_MAX_SCAN, 'maxScan', 'read', 1);
828
+ const requestedOffset = clampCount(input.windowOffset, 0, NATIVE_OFFSET_MAX, 'windowOffset', 'read');
790
829
  // A position is only meaningful against the window it was taken in:
791
830
  // a removal before it (every discord:delete, host hide, /undo) shifts
792
831
  // later positions left, and a message inserted before it (a
@@ -806,7 +845,8 @@ export class HistoryModule {
806
845
  let unverified = false;
807
846
  if (channelId === undefined && windowOffset > 0) {
808
847
  if (typeof input.seqMark !== 'number') {
809
- throw new Error('"windowOffset" without channelId needs the "seqMark" from the same `resume` object. Pass the whole `resume` object back.');
848
+ throw new Error('Nothing was read: "windowOffset" without "channelId" needs the "seqMark" from the same "resume". Copy the ' +
849
+ 'fields of the previous response\'s "resume" into the call.');
810
850
  }
811
851
  const cursor = cm.queryMessagesByTimeAndChannel({ fromMs, toMs, limit: 1, offset: windowOffset - 1 }).messages[0];
812
852
  if (cursor) {
@@ -980,32 +1020,38 @@ export class HistoryModule {
980
1020
  * via edgeWindow, which is exact by timestamp).
981
1021
  */
982
1022
  handleExtractAround(input) {
983
- if (input.from !== undefined ||
984
- input.to !== undefined ||
985
- input.offset !== undefined ||
986
- input.windowOffset !== undefined ||
987
- input.limit !== undefined) {
988
- throw new Error('"aroundId" cannot be combined with from/to/offset/windowOffset/limit — it picks its own window; size it with before/after.');
1023
+ const windowFields = ['from', 'to', 'offset', 'windowOffset', 'limit'].filter((k) => input[k] !== undefined);
1024
+ if (windowFields.length > 0) {
1025
+ throw new Error(`Nothing was read: "aroundId" picks its own window, so it doesn't take ${quotedList(windowFields, 'or')}. Size ` +
1026
+ 'the window with "before" and "after", or leave out "aroundId" to read a range.');
989
1027
  }
990
1028
  if (input.author !== undefined || input.excludeAuthor !== undefined) {
991
- throw new Error('"aroundId" returns the whole conversation around a message; author filters do not apply. Use search/extract with author instead.');
1029
+ throw new Error('Nothing was read: "aroundId" reads the whole conversation around one message, so author filters don\'t ' +
1030
+ 'apply to it. To find someone\'s messages, use history--search or history--extract with "author".');
992
1031
  }
993
1032
  if (input.allChannels && input.channelId !== undefined) {
994
- throw new Error('Pass either "channelId" or "allChannels", not both.');
1033
+ throw new Error('Nothing was read: "channelId" and "allChannels" can\'t go together. Leave out "channelId" to read around the ' +
1034
+ 'message in every channel, or leave out both to read around it in its own channel.');
995
1035
  }
996
- const before = clampCount(input.before, AROUND_DEFAULT, AROUND_MAX, 'before');
997
- const after = clampCount(input.after, AROUND_DEFAULT, AROUND_MAX, 'after');
1036
+ const before = clampCount(input.before, AROUND_DEFAULT, AROUND_MAX, 'before', 'read');
1037
+ const after = clampCount(input.after, AROUND_DEFAULT, AROUND_MAX, 'after', 'read');
998
1038
  const format = input.format ?? 'text';
999
1039
  const cm = this.cm;
1000
1040
  // semantic_search (#173) hands out `msg:<id>` / `sum:<id>`; accept the
1001
1041
  // message form as-is, and say plainly what a summary id is.
1002
1042
  const rawId = String(input.aroundId);
1003
1043
  if (/^sum:/.test(rawId)) {
1004
- throw new Error(`${rawId} is a compression summary, not a message — use overview for summaries, or aroundId with a msg: hit.`);
1044
+ throw new Error(`Nothing was read: ${shown(rawId)} is a compression summary, not a message. history--overview reads ` +
1045
+ 'summaries; "aroundId" takes a message, such as ' +
1046
+ (this.semanticCfg
1047
+ ? 'the "messageId" of a history--semantic_search hit.'
1048
+ : 'the "id" of a history--search or history--extract result.'));
1005
1049
  }
1006
1050
  const anchor = cm.getMessage(rawId.replace(/^msg:/, ''));
1007
1051
  if (!anchor) {
1008
- throw new Error(`No message with id ${JSON.stringify(input.aroundId)} in this history.`);
1052
+ throw new Error(`Nothing was read: no message in your history has the id ${shown(input.aroundId)}. Pass the "id" ` +
1053
+ 'of a history--search or history--extract result' +
1054
+ (this.semanticCfg ? ', or the "messageId" of a history--semantic_search hit.' : '.'));
1009
1055
  }
1010
1056
  const anchorId = String(anchor.id);
1011
1057
  const anchorChannel = getChannelId(anchor);
@@ -1020,22 +1066,22 @@ export class HistoryModule {
1020
1066
  if (channelId !== undefined) {
1021
1067
  const n = cm.queryMessagesByTimeAndChannel({ fromMs: t, toMs: t, channelId, limit: 0 }).matchedCount;
1022
1068
  if (n > AROUND_TIE_CAP)
1023
- throw tieCapError(anchorId, n);
1069
+ throw tieCapError(anchorId, t, channelId);
1024
1070
  ties = cm.queryMessagesByTimeAndChannel({ fromMs: t, toMs: t, channelId, limit: n }).messages;
1025
1071
  }
1026
1072
  else {
1027
1073
  ties = cm.queryMessagesByTime({ fromMs: t, toMs: t, limit: AROUND_TIE_CAP + 1 }).messages;
1028
1074
  if (ties.length > AROUND_TIE_CAP)
1029
- throw tieCapError(anchorId, ties.length);
1075
+ throw tieCapError(anchorId, t, undefined);
1030
1076
  }
1031
1077
  ties = [...ties].sort((x, y) => x.sequence - y.sequence);
1032
1078
  const idx = ties.findIndex((m) => String(m.id) === anchorId);
1033
1079
  if (idx === -1) {
1034
1080
  // The anchor is in the store and every message of its millisecond in
1035
1081
  // `channelId` was fetched, so only an explicit channelId excludes it.
1036
- throw new Error(`Message ${anchorId} is not in channel ${JSON.stringify(input.channelId)}` +
1037
- (anchorChannel ? ` (it is in ${anchorChannel}).` : '.') +
1038
- ' Omit channelId to use the anchor\'s own channel.');
1082
+ throw new Error(`Nothing was read: message ${shown(anchorId)} isn't in channel ${shown(input.channelId)}` +
1083
+ (anchorChannel ? ` (it's in ${shown(anchorChannel)}).` : '.') +
1084
+ ' Leave out "channelId" to read around it in its own channel.');
1039
1085
  }
1040
1086
  const tiesBefore = ties.slice(Math.max(0, idx - before), idx);
1041
1087
  const tiesAfter = ties.slice(idx + 1, idx + 1 + after);
@@ -1061,22 +1107,29 @@ export class HistoryModule {
1061
1107
  // search
1062
1108
  // ==========================================================================
1063
1109
  async handleSearch(input) {
1064
- if (!input.query) {
1065
- throw new Error('search requires a non-empty "query".');
1110
+ // A finite number is searched as its text, as a regular expression made
1111
+ // from it reads it; any other value that isn't text is refused.
1112
+ const given = input.query;
1113
+ const query = typeof given === 'number' && Number.isFinite(given) ? String(given) : given;
1114
+ if (typeof query !== 'string' || query === '') {
1115
+ throw new Error('Nothing was searched: "query" must be the text to look for; ' +
1116
+ `${given === undefined ? 'this call gave none' : `it's ${shown(given)}`}.`);
1066
1117
  }
1067
1118
  const channelId = this.resolveChannel(input.channelId);
1068
1119
  const fromMs = parseIsoDate(input.from, 'from');
1069
1120
  const toMs = parseIsoDate(input.to, 'to');
1070
- const limit = clampCount(input.limit, SEARCH_DEFAULT_LIMIT, SEARCH_MAX_LIMIT, 'limit');
1071
- const maxScan = clampCount(input.maxScan, SEARCH_DEFAULT_MAX_SCAN, SEARCH_MAX_MAX_SCAN, 'maxScan');
1121
+ const limit = clampCount(input.limit, SEARCH_DEFAULT_LIMIT, SEARCH_MAX_LIMIT, 'limit', 'searched');
1122
+ // A search has to scan at least 1 message.
1123
+ const maxScan = clampCount(input.maxScan, SEARCH_DEFAULT_MAX_SCAN, SEARCH_MAX_MAX_SCAN, 'maxScan', 'searched', 1);
1072
1124
  const caseSensitive = input.caseSensitive ?? false;
1073
1125
  const flags = caseSensitive ? '' : 'i';
1074
1126
  const order = input.order ?? 'oldest';
1075
1127
  if (order !== 'oldest' && order !== 'newest') {
1076
- throw new Error(`"order" must be "oldest" or "newest", got ${JSON.stringify(input.order)}.`);
1128
+ throw new Error(`Nothing was searched: "order" must be "oldest" or "newest", or left out for "oldest"; it's ${shown(input.order)}.`);
1077
1129
  }
1078
1130
  if (input.wholeWord && input.regex) {
1079
- throw new Error('"wholeWord" applies to substring search only; in regex mode write \\b around the pattern instead.');
1131
+ throw new Error('Nothing was searched: "wholeWord" applies to a search for text, not a regular expression. In a regular ' +
1132
+ 'expression, write \\b around the pattern instead, or set "regex" to false.');
1080
1133
  }
1081
1134
  const authorFilter = buildAuthorFilter(input.author, input.excludeAuthor);
1082
1135
  // Validate regex SYNTAX up front — an invalid pattern is a clean tool
@@ -1086,13 +1139,17 @@ export class HistoryModule {
1086
1139
  // than here.
1087
1140
  if (input.regex) {
1088
1141
  try {
1089
- new RegExp(input.query, flags);
1142
+ new RegExp(query, flags);
1090
1143
  }
1091
1144
  catch (error) {
1092
- throw new Error(`Invalid regex "${input.query}": ${error instanceof Error ? error.message : String(error)}`);
1145
+ // V8's message restates the pattern; the reason alone follows it.
1146
+ const reason = (error instanceof Error ? error.message : String(error))
1147
+ .replace(/^Invalid regular expression: \/.*\/[a-z]*: /s, '');
1148
+ throw new Error(`Nothing was searched: "query" ${shown(query)} isn't a valid regular expression (${reason}). ` +
1149
+ 'Fix the pattern, or set "regex" to false to search for the text as written.');
1093
1150
  }
1094
1151
  }
1095
- const needle = caseSensitive ? input.query : input.query.toLowerCase();
1152
+ const needle = caseSensitive ? query : query.toLowerCase();
1096
1153
  const cm = this.cm;
1097
1154
  // The candidate window is the oldest (order:"oldest") or newest
1098
1155
  // (order:"newest", via edgeWindow — see there for why not an offset
@@ -1100,8 +1157,7 @@ export class HistoryModule {
1100
1157
  // detected up front rather than
1101
1158
  // silently scanning maxScan candidates and returning as if that were the
1102
1159
  // whole window. See the tool description's `truncated` contract.
1103
- if (maxScan === 0)
1104
- throw new Error('"maxScan" must be at least 1 — a zero-message scan can never make progress.');
1160
+ //
1105
1161
  // Continuation: `skipSequences` names what the previous call already
1106
1162
  // scanned at exactly the resume bound's millisecond (the bound is
1107
1163
  // inclusive). Identified by sequence range rather than a count, so a
@@ -1111,7 +1167,9 @@ export class HistoryModule {
1111
1167
  const skipRange = parseSkipSequences(input.skipSequences);
1112
1168
  const edgeMs = order === 'oldest' ? fromMs : toMs;
1113
1169
  if (skipRange && edgeMs === undefined) {
1114
- throw new Error(`"skipSequences" only applies together with "${order === 'oldest' ? 'from' : 'to'}" — pass the whole \`resume\` object back.`);
1170
+ throw new Error(`Nothing was searched: "skipSequences" goes with the "${order === 'oldest' ? 'from' : 'to'}" from the same ` +
1171
+ '"resume". Copy the fields of the previous response\'s "resume" into the call, or leave "skipSequences" ' +
1172
+ 'out for a new search.');
1115
1173
  }
1116
1174
  const isSkipped = (m) => !!skipRange && m.timestamp.getTime() === edgeMs && m.sequence >= skipRange[0] && m.sequence <= skipRange[1];
1117
1175
  let windowMessages;
@@ -1192,7 +1250,7 @@ export class HistoryModule {
1192
1250
  // through a worker thread instead, which can be forcibly terminated
1193
1251
  // on a deadline. See search-regex-worker.ts's header for the full
1194
1252
  // rationale.
1195
- const { matches, scanned } = await this.searchWithRegexWorker(candidates, input.query, flags, limit);
1253
+ const { matches, scanned } = await this.searchWithRegexWorker(candidates, query, flags, limit);
1196
1254
  return { success: true, data: { scanned, ...poolInfo, truncated, ...resumeInfo(scanned), matches } };
1197
1255
  }
1198
1256
  // Plain substring search (String.prototype.indexOf) is inherently
@@ -1249,22 +1307,27 @@ export class HistoryModule {
1249
1307
  const { matches: rawMatches, scanned } = await new Promise((resolve, reject) => {
1250
1308
  worker = new Worker(SEARCH_WORKER_PATH, { workerData: { texts, pattern, flags, limit } });
1251
1309
  const timer = setTimeout(() => {
1252
- reject(new Error(`search timed out after ${SEARCH_REGEX_TIMEOUT_MS}ms while matching regex "${pattern}" against ` +
1253
- `up to ${texts.length} candidate(s) — the pattern may be catastrophically slow (exponential ` +
1254
- 'backtracking) against this data; try a simpler pattern, a literal substring search ' +
1255
- '(regex:false), or a smaller maxScan.'));
1310
+ reject(new Error(`The search stopped, and returned nothing: matching the regular expression ${shown(pattern)} ` +
1311
+ `against up to ${texts.length} ${texts.length === 1 ? 'message' : 'messages'} took longer than ` +
1312
+ `${SEARCH_REGEX_TIMEOUT_MS} ms, as a ` +
1313
+ 'pattern that backtracks heavily can. Try a simpler pattern, set "regex" to false to search for the ' +
1314
+ 'text as written, or lower "maxScan".'));
1256
1315
  }, SEARCH_REGEX_TIMEOUT_MS);
1257
1316
  timer.unref?.();
1258
1317
  worker.once('message', (msg) => {
1259
1318
  clearTimeout(timer);
1260
- if (msg.type === 'error')
1261
- reject(new Error(msg.error));
1262
- else
1319
+ if (msg.type === 'error') {
1320
+ reject(new Error(`The search stopped, and returned nothing: matching the regular expression ${shown(pattern)} ` +
1321
+ `failed (${msg.error}). Try a simpler pattern, or set "regex" to false to search for the text as written.`));
1322
+ }
1323
+ else {
1263
1324
  resolve({ matches: msg.matches, scanned: msg.scanned });
1325
+ }
1264
1326
  });
1265
1327
  worker.once('error', (err) => {
1266
1328
  clearTimeout(timer);
1267
- reject(err);
1329
+ reject(new Error(`The search stopped, and returned nothing: the worker matching the regular expression ${shown(pattern)} ` +
1330
+ `failed (${err.message}). Set "regex" to false to search for the text as written.`));
1268
1331
  });
1269
1332
  });
1270
1333
  const matches = rawMatches.map(({ candidateIndex, matchIndex, matchLength }) => {
@@ -1294,36 +1357,46 @@ export class HistoryModule {
1294
1357
  // ==========================================================================
1295
1358
  async handleSemanticSearch(input) {
1296
1359
  if (!this.semanticCfg || !this.semanticClient) {
1297
- throw new Error('semantic_search is not configured for this resident (no embed-service in the recipe).');
1360
+ throw new Error("Nothing was searched: this host has no semantic index set up, so history--semantic_search isn't available " +
1361
+ "here, and calling it again won't change that. history--search finds messages by their words.");
1362
+ }
1363
+ if (typeof input.query !== 'string' || !input.query.trim()) {
1364
+ throw new Error('Nothing was searched: "query" must be a sentence describing what you\'re looking for; ' +
1365
+ `${input.query === undefined ? 'this call gave none' : `it's ${shown(input.query)}`}.`);
1298
1366
  }
1299
- if (typeof input.query !== 'string' || !input.query.trim())
1300
- throw new Error('query must be a non-empty string');
1301
- const limit = clampCount(input.limit, SEMANTIC_DEFAULT_LIMIT, SEMANTIC_MAX_LIMIT, 'limit');
1302
- if (limit < 1)
1303
- throw new Error('limit must be at least 1');
1367
+ // A search has to return at least 1 hit.
1368
+ const limit = clampCount(input.limit, SEMANTIC_DEFAULT_LIMIT, SEMANTIC_MAX_LIMIT, 'limit', 'searched', 1);
1304
1369
  const fromMs = parseIsoDate(input.from, 'from');
1305
1370
  const toMs = parseIsoDate(input.to, 'to');
1306
- if (fromMs !== undefined && toMs !== undefined && fromMs > toMs)
1307
- throw new Error('`from` must not be after `to`');
1371
+ assertOrderedRange(fromMs, toMs, input.from, input.to);
1308
1372
  const channelId = this.resolveChannel(input.channelId);
1309
1373
  // Summaries carry no channel, so a channel filter on a summaries-only
1310
1374
  // search can only ever match nothing. Say so instead of returning [].
1311
1375
  const wantsSummariesOnly = input.level !== undefined || input.kinds === 'summaries';
1312
1376
  if (channelId && wantsSummariesOnly) {
1313
- throw new Error('channelId cannot be combined with kinds="summaries" or level: summaries are not per-channel. Drop channelId, or search kinds="messages".');
1377
+ const picks = [
1378
+ ...(input.kinds === 'summaries' ? ['"kinds": "summaries"'] : []),
1379
+ ...(input.level !== undefined ? ['"level"'] : []),
1380
+ ];
1381
+ const fields = [...(input.kinds === 'summaries' ? ['kinds'] : []), ...(input.level !== undefined ? ['level'] : [])];
1382
+ throw new Error(`Nothing was searched: summaries aren't kept by channel, so "channelId" can't go with ${picks.join(' or ')}. ` +
1383
+ `Leave out "channelId" to search summaries, or leave out ${quotedList(fields, 'and')} to search that ` +
1384
+ 'channel\'s messages.');
1314
1385
  }
1315
1386
  if (input.level !== undefined && input.kinds === 'messages') {
1316
- throw new Error('level applies to summaries only and cannot be combined with kinds="messages".');
1387
+ throw new Error('Nothing was searched: "level" picks summaries, and "kinds" is "messages", so the two can\'t go together. ' +
1388
+ 'Leave out "kinds" to search summaries of that level, or leave out "level" to search messages.');
1317
1389
  }
1318
1390
  let kinds;
1319
1391
  if (wantsSummariesOnly)
1320
1392
  kinds = ['summary'];
1321
1393
  else if (input.kinds === 'messages' || channelId)
1322
1394
  kinds = ['message'];
1323
- if (input.level !== undefined && (!Number.isInteger(input.level) || input.level < 0))
1324
- throw new Error('level must be a non-negative integer');
1395
+ if (input.level !== undefined && (!Number.isInteger(input.level) || input.level < 0)) {
1396
+ throw new Error(`Nothing was searched: "level" must be a whole number, 0 or more, such as 1; it's ${shown(input.level)}.`);
1397
+ }
1325
1398
  if (input.minScore !== undefined && (typeof input.minScore !== 'number' || input.minScore < -1 || input.minScore > 1)) {
1326
- throw new Error('minScore must be a number in -1..1');
1399
+ throw new Error(`Nothing was searched: "minScore" must be a number from -1 to 1, or left out; it's ${shown(input.minScore)}.`);
1327
1400
  }
1328
1401
  // Bounded catch-up so the newest messages are searchable; never block on a backlog.
1329
1402
  let sync = null;
@@ -1339,6 +1412,49 @@ export class HistoryModule {
1339
1412
  ts_to: toMs === undefined ? undefined : toMs / 1000,
1340
1413
  channel: channelId, kinds, level: input.level, min_score: input.minScore, snippet: SEMANTIC_SNIPPET_CHARS,
1341
1414
  });
1415
+ // The client says what went wrong with the service; what that means for
1416
+ // this call, and what the agent can do, is said here. The service's own
1417
+ // source isn't in this repository, so a 404's advice holds whether it
1418
+ // means this store's index doesn't exist yet or a route the service lacks.
1419
+ const failure = (e) => {
1420
+ const status = e instanceof EmbedServiceError ? e.status : null;
1421
+ const reason = e instanceof Error ? e.message : String(e);
1422
+ const later = {
1423
+ reason, mayPass: true,
1424
+ advice: 'You can try again later; if it keeps happening, ask whoever runs this host',
1425
+ };
1426
+ if (status === 404) {
1427
+ return {
1428
+ reason, mayPass: true,
1429
+ advice: "If this store's index doesn't exist yet, the first messages indexed create it, and a later call " +
1430
+ 'can work; if it keeps happening, ask whoever runs this host',
1431
+ };
1432
+ }
1433
+ if (status === 408 || status === 429 || (status !== null && status >= 500))
1434
+ return later;
1435
+ // An answer without what a search reads: a page shown while the service
1436
+ // restarts clears, and an address that points at something else doesn't.
1437
+ if (status !== null && status >= 200 && status < 300) {
1438
+ return {
1439
+ reason, mayPass: true,
1440
+ advice: 'If the service was restarting, a later call can work; if its address points at something else, ' +
1441
+ "none will until whoever runs this host fixes the semantic index's settings",
1442
+ };
1443
+ }
1444
+ if (status !== null) {
1445
+ return {
1446
+ reason, mayPass: false,
1447
+ advice: "Calling it again the same way won't change that; if it keeps happening, ask whoever runs this host",
1448
+ };
1449
+ }
1450
+ // No answer: the service down or slow, or the connection dropped, which
1451
+ // clears, or its address or certificate wrong, which doesn't.
1452
+ return {
1453
+ reason, mayPass: true,
1454
+ advice: 'If the service is down or slow, or the connection dropped, a later call can work; if its address ' +
1455
+ "or certificate is wrong, none will until whoever runs this host fixes the semantic index's settings",
1456
+ };
1457
+ };
1342
1458
  // The remote index is append-only and knows nothing about branches: a
1343
1459
  // message removed from the agent's reach by /undo, /checkout, /restore or
1344
1460
  // /newtopic keeps its id (a new message gets a fresh one) and stays
@@ -1364,7 +1480,7 @@ export class HistoryModule {
1364
1480
  const m = cm.getMessage(msgId);
1365
1481
  if (!m)
1366
1482
  return 'offBranch';
1367
- const text = messageIndexText(m, includePrivate).slice(0, this.semanticCfg.maxChars ?? 32_000);
1483
+ const text = safeSlice(messageIndexText(m, includePrivate), 0, this.semanticCfg.maxChars ?? 32_000);
1368
1484
  if (!text)
1369
1485
  return 'stale';
1370
1486
  currentText.set(h.id, text);
@@ -1375,11 +1491,22 @@ export class HistoryModule {
1375
1491
  return 'ok';
1376
1492
  };
1377
1493
  let k = limit;
1378
- let res = await runSearch(k);
1494
+ let res;
1495
+ try {
1496
+ res = await runSearch(k);
1497
+ }
1498
+ catch (e) {
1499
+ const { reason, advice } = failure(e);
1500
+ throw new Error(`Nothing was searched: ${reason}. ${advice}. history--search finds messages by their words meanwhile.`);
1501
+ }
1379
1502
  let droppedOffBranch = 0;
1380
1503
  let droppedStale = 0;
1504
+ // Why searching again for more hits failed, when it did. The search
1505
+ // before it answered, so its hits on this branch are returned.
1506
+ let searchAgainError = null;
1381
1507
  let onBranch = [];
1382
- for (;;) {
1508
+ // The last answer's hits on this branch, checked as they are now.
1509
+ const check = () => {
1383
1510
  droppedOffBranch = 0;
1384
1511
  droppedStale = 0;
1385
1512
  onBranch = res.hits.filter((h) => {
@@ -1390,26 +1517,61 @@ export class HistoryModule {
1390
1517
  droppedStale++;
1391
1518
  return v === 'ok';
1392
1519
  });
1520
+ };
1521
+ for (;;) {
1522
+ check();
1393
1523
  if (onBranch.length >= limit || res.hits.length < k || k >= SEMANTIC_MAX_FETCH)
1394
1524
  break;
1395
1525
  k = Math.min(SEMANTIC_MAX_FETCH, k * 4);
1396
- res = await runSearch(k);
1526
+ try {
1527
+ res = await runSearch(k);
1528
+ }
1529
+ catch (e) {
1530
+ const { reason, mayPass } = failure(e);
1531
+ searchAgainError = `searching again for more hits failed: ${reason}. ` +
1532
+ (mayPass ? 'Calling again may bring more.' : "Calling again the same way won't change that.");
1533
+ // A message may have been edited, deleted or taken off this branch
1534
+ // while that search waited, so the hits are checked again.
1535
+ check();
1536
+ break;
1537
+ }
1397
1538
  }
1398
1539
  onBranch = onBranch.slice(0, limit);
1399
- const hits = onBranch.map((h) => ({
1400
- id: h.id,
1401
- /** Raw message id for a `msg:` hit (null for summaries) — pass it to extract({ aroundId }). */
1402
- messageId: h.id.startsWith('msg:') ? h.id.slice(4) : null,
1403
- kind: h.kind,
1404
- level: h.level,
1405
- score: h.score,
1406
- timestamp: h.ts === null ? null : new Date(h.ts * 1000).toISOString(),
1407
- channelId: h.channel,
1408
- participant: h.meta.participant ?? null,
1409
- author: h.meta.author ?? null,
1410
- snippet: currentText.has(h.id) ? snippetOf(currentText.get(h.id)) : (h.text ?? ''),
1411
- chars: currentText.has(h.id) ? currentText.get(h.id).length : h.chars,
1412
- }));
1540
+ // A ts that makes no date reads as no timestamp, as a null one does, and a
1541
+ // meta that isn't an object as no participant or author. The hit is still
1542
+ // returned, but the index holds data written wrong, so the host is told.
1543
+ // The index writes ts as a number of seconds, and text holding one reads
1544
+ // as main read it; nothing else makes a date, and reading it can't throw.
1545
+ const unread = [];
1546
+ const hits = onBranch.map((h) => {
1547
+ const ts = h.ts;
1548
+ const seconds = typeof ts === 'number' ? ts : typeof ts === 'string' && ts.trim() !== '' ? Number(ts) : NaN;
1549
+ const at = new Date(seconds * 1000);
1550
+ const timestamp = Number.isNaN(at.getTime()) ? null : at.toISOString();
1551
+ const meta = typeof h.meta === 'object' && h.meta !== null && !Array.isArray(h.meta)
1552
+ ? h.meta
1553
+ : null;
1554
+ const missing = [...(h.ts !== null && timestamp === null ? ['ts'] : []), ...(meta === null ? ['meta'] : [])];
1555
+ if (missing.length > 0)
1556
+ unread.push(`${shown(h.id)} (${missing.join(' and ')})`);
1557
+ return {
1558
+ id: h.id,
1559
+ /** Raw message id for a `msg:` hit (null for summaries) — pass it to extract({ aroundId }). */
1560
+ messageId: h.id.startsWith('msg:') ? h.id.slice(4) : null,
1561
+ kind: h.kind,
1562
+ level: h.level,
1563
+ score: h.score,
1564
+ timestamp,
1565
+ channelId: h.channel,
1566
+ participant: meta?.participant ?? null,
1567
+ author: meta?.author ?? null,
1568
+ snippet: currentText.has(h.id) ? snippetOf(currentText.get(h.id)) : (h.text ?? ''),
1569
+ chars: currentText.has(h.id) ? currentText.get(h.id).length : h.chars,
1570
+ };
1571
+ });
1572
+ if (unread.length > 0) {
1573
+ this.indexer?.warn(`a search returned hits whose ts or meta couldn't be read, without them: ${unread.join(', ')}`);
1574
+ }
1413
1575
  return {
1414
1576
  success: true,
1415
1577
  data: {
@@ -1421,8 +1583,10 @@ export class HistoryModule {
1421
1583
  lastError: this.indexer?.lastError ?? null,
1422
1584
  /** Hits the index returned for messages/summaries not on the current branch (undone, checked out past). */
1423
1585
  droppedOffBranch,
1424
- /** Hits for messages whose current text has nothing indexable (edited blank; the index delete is pending). */
1586
+ /** Hits for messages whose current text has nothing indexable (edited blank; the index keeps such a message until its delete goes through, and on a service without /delete it never does). */
1425
1587
  droppedStale,
1588
+ /** When too few hits were on this branch and searching again for more failed: why, and whether calling again can help. */
1589
+ searchAgainError,
1426
1590
  },
1427
1591
  timingMs: res.timing_ms,
1428
1592
  },
@@ -1433,7 +1597,7 @@ export class HistoryModule {
1433
1597
  const fromMs = parseIsoDate(input.from, 'from');
1434
1598
  const toMs = parseIsoDate(input.to, 'to');
1435
1599
  assertOrderedRange(fromMs, toMs, input.from, input.to);
1436
- const limit = clampCount(input.limit, OVERVIEW_DEFAULT_LIMIT, OVERVIEW_MAX_LIMIT, 'limit');
1600
+ const limit = clampCount(input.limit, OVERVIEW_DEFAULT_LIMIT, OVERVIEW_MAX_LIMIT, 'limit', 'read');
1437
1601
  const cm = this.cm;
1438
1602
  let entries;
1439
1603
  if (input.level !== undefined) {
@@ -1792,6 +1956,11 @@ export class HistoryModule {
1792
1956
  // ============================================================================
1793
1957
  // Helpers
1794
1958
  // ============================================================================
1959
+ // The checks here (and resolveChannel) are shared by several tools. Their
1960
+ // refusals open with "Nothing was read", or for clampCount with the outcome
1961
+ // its caller names, and "Nothing was read" holds because every history tool
1962
+ // only reads. A tool that changes something should give its refusals an
1963
+ // opener of its own rather than reach these.
1795
1964
  /** Parse an ISO 8601 date string to Unix ms. Throws a clear error (not a
1796
1965
  * crash) on an unparseable string; returns undefined for an omitted field
1797
1966
  * (open-ended bound). */
@@ -1800,7 +1969,8 @@ function parseIsoDate(value, field) {
1800
1969
  return undefined;
1801
1970
  const ms = Date.parse(value);
1802
1971
  if (Number.isNaN(ms)) {
1803
- throw new Error(`Invalid ISO 8601 date for "${field}": ${JSON.stringify(value)}`);
1972
+ throw new Error(`Nothing was read: "${field}" is ${shown(value)}, which isn't an ISO 8601 date. Write it like 2026-03-01 or ` +
1973
+ '2026-03-01T09:00:00Z.');
1804
1974
  }
1805
1975
  return ms;
1806
1976
  }
@@ -1813,7 +1983,8 @@ function parseIsoDate(value, field) {
1813
1983
  */
1814
1984
  function assertOrderedRange(fromMs, toMs, fromRaw, toRaw) {
1815
1985
  if (fromMs !== undefined && toMs !== undefined && fromMs > toMs) {
1816
- throw new Error(`"from" (${fromRaw}) must not be after "to" (${toRaw}).`);
1986
+ throw new Error(`Nothing was read: "from" (${shown(fromRaw)}) is after "to" (${shown(toRaw)}), so the range holds nothing. Swap them, ` +
1987
+ 'or correct the one that\'s wrong.');
1817
1988
  }
1818
1989
  }
1819
1990
  /**
@@ -1824,24 +1995,51 @@ function assertOrderedRange(fromMs, toMs, fromRaw, toRaw) {
1824
1995
  * "hard cap" and reach a native chronicle call expecting an unsigned
1825
1996
  * pagination argument (observed: `extract({limit:-1})` returning every
1826
1997
  * message in the store instead of being capped). Rejects (rather than
1827
- * silently clamping) anything that isn't a finite non-negative integer, so
1828
- * a caller mistake is surfaced as a clean tool error instead of silently
1829
- * doing something other than what was asked.
1998
+ * silently clamping) anything that isn't a whole number of at least `min`,
1999
+ * so a caller mistake is surfaced as a clean tool error instead of silently
2000
+ * doing something other than what was asked. The refusal opens with what
2001
+ * didn't happen for the calling tool (`outcome`), and gives the range and
2002
+ * the default.
1830
2003
  */
1831
- function clampCount(value, def, max, field) {
2004
+ function clampCount(value, def, max, field, outcome, min = 0) {
1832
2005
  if (value === undefined)
1833
2006
  return def;
1834
- if (typeof value !== 'number' || !Number.isFinite(value)) {
1835
- throw new Error(`"${field}" must be a finite number, got ${JSON.stringify(value)}.`);
1836
- }
1837
- if (!Number.isInteger(value)) {
1838
- throw new Error(`"${field}" must be an integer, got ${value}.`);
1839
- }
1840
- if (value < 0) {
1841
- throw new Error(`"${field}" must be >= 0, got ${value}.`);
2007
+ if (typeof value !== 'number' || !Number.isInteger(value) || value < min) {
2008
+ throw new Error(`Nothing was ${outcome}: "${field}" is ${shown(value)}, which isn't a whole number from ${min} to ${max}. `
2009
+ + `Pass one, or leave it out for ${def}.`);
1842
2010
  }
1843
2011
  return Math.min(value, max);
1844
2012
  }
2013
+ /**
2014
+ * A value a message names, the call's or the store's, as the message quotes
2015
+ * it: its JSON, or what String() gives where JSON can't give the value itself,
2016
+ * cut to 80 UTF-16 units, or one fewer where the 80th would split a surrogate
2017
+ * pair: the message stays in the agent's context, and half a pair isn't
2018
+ * well-formed text. Inside a list or an object, JSON writes Infinity and NaN
2019
+ * as null, and so does the quote. A value the message gives the agent to send
2020
+ * is quoted whole instead, since a cut one couldn't be sent.
2021
+ */
2022
+ function shown(value) {
2023
+ let text;
2024
+ // A value JSON can't give, such as a cycle, or Infinity or NaN as the whole
2025
+ // value, which JSON.stringify gives as null, is shown as String() shows it.
2026
+ if (typeof value !== 'number' || Number.isFinite(value)) {
2027
+ try {
2028
+ text = JSON.stringify(value);
2029
+ }
2030
+ catch { /* String() below */ }
2031
+ }
2032
+ text ??= String(value);
2033
+ return text.length <= 80 ? text : `${safeSlice(text, 0, 80)}…`;
2034
+ }
2035
+ /**
2036
+ * Names in prose, each quoted whole: "a"; "a" and "b"; "a", "b" and "c" (or
2037
+ * "or"). They're the tools' own field names, or names the agent can send.
2038
+ */
2039
+ function quotedList(names, joiner) {
2040
+ const quoted = names.map((name) => JSON.stringify(name));
2041
+ return quoted.length <= 1 ? quoted.join('') : `${quoted.slice(0, -1).join(', ')} ${joiner} ${quoted[quoted.length - 1]}`;
2042
+ }
1845
2043
  /** channelId lives at metadata.external.channelId — same path context-manager's
1846
2044
  * own native index reads from (message-store.ts's CHANNEL_FIELD). Metadata's
1847
2045
  * index-signature type means this needs an explicit narrow, same as
@@ -2024,7 +2222,9 @@ function codePointBefore(s, i) {
2024
2222
  return s[i - 1];
2025
2223
  }
2026
2224
  /**
2027
- * First occurrence of `needle` in `text`. With `wholeWord`, an occurrence
2225
+ * First occurrence of `needle` in `text`, as the units of `text` it covers.
2226
+ * Without `caseSensitive`, `needle` is lower case already, and is found in
2227
+ * `text.toLowerCase()`. With `wholeWord`, an occurrence
2028
2228
  * only counts when it isn't glued to a letter/digit/underscore on either
2029
2229
  * side (Unicode-aware, so Cyrillic words work too) — "mission" no longer
2030
2230
  * hits inside "uncommissioned". Word-ness is checked only on the sides
@@ -2033,6 +2233,12 @@ function codePointBefore(s, i) {
2033
2233
  */
2034
2234
  function matchSubstring(text, needle, caseSensitive, wholeWord = false) {
2035
2235
  const haystack = caseSensitive ? text : text.toLowerCase();
2236
+ const hit = firstOccurrence(haystack, needle, wholeWord);
2237
+ // Lowering can lengthen a character, as it does `İ` (one unit to two). Then
2238
+ // the lowered text's units aren't the text's, and the snippet cuts the text.
2239
+ return hit !== null && haystack.length !== text.length ? inTextUnits(text, hit) : hit;
2240
+ }
2241
+ function firstOccurrence(haystack, needle, wholeWord) {
2036
2242
  if (!wholeWord) {
2037
2243
  const index = haystack.indexOf(needle);
2038
2244
  return index === -1 ? null : { index, length: needle.length };
@@ -2050,6 +2256,26 @@ function matchSubstring(text, needle, caseSensitive, wholeWord = false) {
2050
2256
  from = index + 1;
2051
2257
  }
2052
2258
  }
2259
+ /**
2260
+ * The units of `text` that a hit in `text.toLowerCase()` covers. Each code
2261
+ * point of `text` takes as many units there as its own lower case has, so a
2262
+ * hit that starts or ends inside a character's lower case takes in the whole
2263
+ * character.
2264
+ */
2265
+ function inTextUnits(text, hit) {
2266
+ const end = hit.index + hit.length;
2267
+ let start = -1;
2268
+ let lowered = 0;
2269
+ let at = 0;
2270
+ while (at < text.length && lowered < end) {
2271
+ const cp = text.codePointAt(at);
2272
+ lowered += String.fromCodePoint(cp).toLowerCase().length;
2273
+ if (start === -1 && lowered > hit.index)
2274
+ start = at;
2275
+ at += cp > 0xffff ? 2 : 1;
2276
+ }
2277
+ return { index: start, length: at - start };
2278
+ }
2053
2279
  // ============================================================================
2054
2280
  // author filtering
2055
2281
  // ============================================================================
@@ -2073,7 +2299,9 @@ function parseSkipSequences(v) {
2073
2299
  v.length !== 2 ||
2074
2300
  !v.every((x) => typeof x === 'number' && Number.isInteger(x) && x >= 0) ||
2075
2301
  v[0] > v[1]) {
2076
- throw new Error('"skipSequences" must be [lo, hi], two non-negative integers with lo <= hi — copy it from `resume`.');
2302
+ throw new Error('Nothing was searched: "skipSequences" must be two whole numbers, 0 or more, the first no larger than the ' +
2303
+ `second, as a search's "resume" gives it; it's ${shown(v)}. Copy it from "resume" with its "from" or "to", ` +
2304
+ 'or leave it out for a new search.');
2077
2305
  }
2078
2306
  return [v[0], v[1]];
2079
2307
  }
@@ -2096,12 +2324,16 @@ function toAuthorSet(spec, field) {
2096
2324
  if (spec === undefined)
2097
2325
  return null;
2098
2326
  const list = Array.isArray(spec) ? spec : [spec];
2099
- if (list.some((s) => typeof s !== 'string')) {
2100
- throw new Error(`"${field}" must be a string or an array of strings.`);
2327
+ const odd = list.findIndex((s) => typeof s !== 'string');
2328
+ if (odd !== -1) {
2329
+ throw new Error(`Nothing was read: "${field}" must list names or ids as text, such as ["alice", "1234"], and ` +
2330
+ `${shown(list[odd])} isn't text.`);
2101
2331
  }
2102
2332
  const set = new Set(list.map(normalizeAuthorSpec).filter((s) => s.length > 0));
2103
- if (set.size === 0)
2104
- throw new Error(`"${field}" must name at least one author.`);
2333
+ if (set.size === 0) {
2334
+ throw new Error(`Nothing was read: "${field}" names no one: ${list.length > 0 ? 'its entries are blank' : 'the list is empty'}. ` +
2335
+ `List at least one name or id, such as ["alice"], or leave "${field}" out.`);
2336
+ }
2105
2337
  return set;
2106
2338
  }
2107
2339
  /**
@@ -2132,14 +2364,14 @@ function buildAuthorFilter(include, exclude) {
2132
2364
  /** ~SNIPPET_CONTEXT_CHARS of surrounding context on each side of a match, or
2133
2365
  * the first ~SNIPPET_FALLBACK_CHARS of content when no meaningful match
2134
2366
  * position is given (kept simple on purpose — this is a readability aid,
2135
- * not a highlighting engine). */
2367
+ * not a highlighting engine). Neither end splits a surrogate pair. */
2136
2368
  function snippetAround(text, index, length) {
2137
2369
  if (index < 0)
2138
- return text.slice(0, SNIPPET_FALLBACK_CHARS);
2370
+ return safeSlice(text, 0, SNIPPET_FALLBACK_CHARS);
2139
2371
  const start = Math.max(0, index - SNIPPET_CONTEXT_CHARS);
2140
2372
  const end = Math.min(text.length, index + length + SNIPPET_CONTEXT_CHARS);
2141
2373
  const prefix = start > 0 ? '…' : '';
2142
2374
  const suffix = end < text.length ? '…' : '';
2143
- return prefix + text.slice(start, end) + suffix;
2375
+ return prefix + safeSlice(text, start, end) + suffix;
2144
2376
  }
2145
2377
  //# sourceMappingURL=index.js.map