@animalabs/agent-framework 0.32.0 → 0.34.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (368) hide show
  1. package/README.md +340 -22
  2. package/dist/src/admission/admit.d.ts +18 -0
  3. package/dist/src/admission/admit.d.ts.map +1 -1
  4. package/dist/src/admission/admit.js +16 -3
  5. package/dist/src/admission/admit.js.map +1 -1
  6. package/dist/src/agent.d.ts +208 -80
  7. package/dist/src/agent.d.ts.map +1 -1
  8. package/dist/src/agent.js +345 -113
  9. package/dist/src/agent.js.map +1 -1
  10. package/dist/src/api/mcp-server-core.d.ts.map +1 -1
  11. package/dist/src/api/mcp-server-core.js +50 -12
  12. package/dist/src/api/mcp-server-core.js.map +1 -1
  13. package/dist/src/api/server.d.ts.map +1 -1
  14. package/dist/src/api/server.js +4 -20
  15. package/dist/src/api/server.js.map +1 -1
  16. package/dist/src/append-all.d.ts +5 -0
  17. package/dist/src/append-all.d.ts.map +1 -0
  18. package/dist/src/append-all.js +8 -0
  19. package/dist/src/append-all.js.map +1 -0
  20. package/dist/src/code-execution/isolate/scripts.d.ts +12 -8
  21. package/dist/src/code-execution/isolate/scripts.d.ts.map +1 -1
  22. package/dist/src/code-execution/isolate/scripts.js +24 -0
  23. package/dist/src/code-execution/isolate/scripts.js.map +1 -1
  24. package/dist/src/config-checks.d.ts +7 -0
  25. package/dist/src/config-checks.d.ts.map +1 -1
  26. package/dist/src/config-checks.js +14 -0
  27. package/dist/src/config-checks.js.map +1 -1
  28. package/dist/src/context-manager-errors.d.ts +25 -0
  29. package/dist/src/context-manager-errors.d.ts.map +1 -0
  30. package/dist/src/context-manager-errors.js +31 -0
  31. package/dist/src/context-manager-errors.js.map +1 -0
  32. package/dist/src/context-options.d.ts +70 -0
  33. package/dist/src/context-options.d.ts.map +1 -0
  34. package/dist/src/context-options.js +90 -0
  35. package/dist/src/context-options.js.map +1 -0
  36. package/dist/src/cut-off-round.js +4 -4
  37. package/dist/src/deferred-import.d.ts +93 -0
  38. package/dist/src/deferred-import.d.ts.map +1 -0
  39. package/dist/src/deferred-import.js +177 -0
  40. package/dist/src/deferred-import.js.map +1 -0
  41. package/dist/src/dendrite/audience.d.ts +223 -0
  42. package/dist/src/dendrite/audience.d.ts.map +1 -0
  43. package/dist/src/dendrite/audience.js +202 -0
  44. package/dist/src/dendrite/audience.js.map +1 -0
  45. package/dist/src/dendrite/index.d.ts +5 -3
  46. package/dist/src/dendrite/index.d.ts.map +1 -1
  47. package/dist/src/dendrite/index.js +2 -1
  48. package/dist/src/dendrite/index.js.map +1 -1
  49. package/dist/src/dendrite/presets.d.ts +10 -5
  50. package/dist/src/dendrite/presets.d.ts.map +1 -1
  51. package/dist/src/dendrite/presets.js +17 -5
  52. package/dist/src/dendrite/presets.js.map +1 -1
  53. package/dist/src/dendrite/registry.d.ts +62 -7
  54. package/dist/src/dendrite/registry.d.ts.map +1 -1
  55. package/dist/src/dendrite/registry.js +183 -12
  56. package/dist/src/dendrite/registry.js.map +1 -1
  57. package/dist/src/dendrite/types.d.ts +91 -8
  58. package/dist/src/dendrite/types.d.ts.map +1 -1
  59. package/dist/src/failure-text.d.ts +36 -0
  60. package/dist/src/failure-text.d.ts.map +1 -0
  61. package/dist/src/failure-text.js +89 -0
  62. package/dist/src/failure-text.js.map +1 -0
  63. package/dist/src/foreign-rounds.d.ts +69 -0
  64. package/dist/src/foreign-rounds.d.ts.map +1 -0
  65. package/dist/src/foreign-rounds.js +152 -0
  66. package/dist/src/foreign-rounds.js.map +1 -0
  67. package/dist/src/framework.d.ts +2064 -842
  68. package/dist/src/framework.d.ts.map +1 -1
  69. package/dist/src/framework.js +8586 -3739
  70. package/dist/src/framework.js.map +1 -1
  71. package/dist/src/gate/event-gate.d.ts +125 -21
  72. package/dist/src/gate/event-gate.d.ts.map +1 -1
  73. package/dist/src/gate/event-gate.js +487 -72
  74. package/dist/src/gate/event-gate.js.map +1 -1
  75. package/dist/src/gate/index.d.ts +1 -1
  76. package/dist/src/gate/index.d.ts.map +1 -1
  77. package/dist/src/gate/index.js.map +1 -1
  78. package/dist/src/gate/reply-judge.d.ts +4 -0
  79. package/dist/src/gate/reply-judge.d.ts.map +1 -1
  80. package/dist/src/gate/reply-judge.js +12 -3
  81. package/dist/src/gate/reply-judge.js.map +1 -1
  82. package/dist/src/gate/rule-scope.d.ts +30 -0
  83. package/dist/src/gate/rule-scope.d.ts.map +1 -0
  84. package/dist/src/gate/rule-scope.js +41 -0
  85. package/dist/src/gate/rule-scope.js.map +1 -0
  86. package/dist/src/gate/suppress-script-worker.d.ts +2 -0
  87. package/dist/src/gate/suppress-script-worker.d.ts.map +1 -0
  88. package/dist/src/gate/suppress-script-worker.js +103 -0
  89. package/dist/src/gate/suppress-script-worker.js.map +1 -0
  90. package/dist/src/gate/suppress-scripts.d.ts +105 -0
  91. package/dist/src/gate/suppress-scripts.d.ts.map +1 -0
  92. package/dist/src/gate/suppress-scripts.js +403 -0
  93. package/dist/src/gate/suppress-scripts.js.map +1 -0
  94. package/dist/src/gate/suppression-review.d.ts +143 -0
  95. package/dist/src/gate/suppression-review.d.ts.map +1 -0
  96. package/dist/src/gate/suppression-review.js +463 -0
  97. package/dist/src/gate/suppression-review.js.map +1 -0
  98. package/dist/src/gate/suppression-stats.d.ts +125 -0
  99. package/dist/src/gate/suppression-stats.d.ts.map +1 -0
  100. package/dist/src/gate/suppression-stats.js +214 -0
  101. package/dist/src/gate/suppression-stats.js.map +1 -0
  102. package/dist/src/gate/types.d.ts +142 -7
  103. package/dist/src/gate/types.d.ts.map +1 -1
  104. package/dist/src/gate/wake-onboarding.d.ts +119 -0
  105. package/dist/src/gate/wake-onboarding.d.ts.map +1 -0
  106. package/dist/src/gate/wake-onboarding.js +277 -0
  107. package/dist/src/gate/wake-onboarding.js.map +1 -0
  108. package/dist/src/heartbeat/heartbeat.js +1 -1
  109. package/dist/src/heartbeat/heartbeat.js.map +1 -1
  110. package/dist/src/held-writes.d.ts +31 -23
  111. package/dist/src/held-writes.d.ts.map +1 -1
  112. package/dist/src/held-writes.js +44 -59
  113. package/dist/src/held-writes.js.map +1 -1
  114. package/dist/src/index.d.ts +6 -2
  115. package/dist/src/index.d.ts.map +1 -1
  116. package/dist/src/index.js +4 -0
  117. package/dist/src/index.js.map +1 -1
  118. package/dist/src/inference-bounds.d.ts +2 -1
  119. package/dist/src/inference-bounds.d.ts.map +1 -1
  120. package/dist/src/inference-bounds.js +9 -6
  121. package/dist/src/inference-bounds.js.map +1 -1
  122. package/dist/src/jsonrpc-envelope.d.ts +69 -0
  123. package/dist/src/jsonrpc-envelope.d.ts.map +1 -0
  124. package/dist/src/jsonrpc-envelope.js +66 -0
  125. package/dist/src/jsonrpc-envelope.js.map +1 -0
  126. package/dist/src/mcpl/channel-registry.d.ts +188 -28
  127. package/dist/src/mcpl/channel-registry.d.ts.map +1 -1
  128. package/dist/src/mcpl/channel-registry.js +426 -70
  129. package/dist/src/mcpl/channel-registry.js.map +1 -1
  130. package/dist/src/mcpl/checkpoint-manager.d.ts +2 -4
  131. package/dist/src/mcpl/checkpoint-manager.d.ts.map +1 -1
  132. package/dist/src/mcpl/checkpoint-manager.js.map +1 -1
  133. package/dist/src/mcpl/feature-set-manager.d.ts +2 -4
  134. package/dist/src/mcpl/feature-set-manager.d.ts.map +1 -1
  135. package/dist/src/mcpl/feature-set-manager.js.map +1 -1
  136. package/dist/src/mcpl/inbound-source.d.ts +2 -1
  137. package/dist/src/mcpl/inbound-source.d.ts.map +1 -1
  138. package/dist/src/mcpl/inbound-source.js +2 -1
  139. package/dist/src/mcpl/inbound-source.js.map +1 -1
  140. package/dist/src/mcpl/inference-router.d.ts +6 -6
  141. package/dist/src/mcpl/inference-router.d.ts.map +1 -1
  142. package/dist/src/mcpl/inference-router.js.map +1 -1
  143. package/dist/src/mcpl/modern-connection.d.ts +109 -15
  144. package/dist/src/mcpl/modern-connection.d.ts.map +1 -1
  145. package/dist/src/mcpl/modern-connection.js +593 -86
  146. package/dist/src/mcpl/modern-connection.js.map +1 -1
  147. package/dist/src/mcpl/protocol-family.d.ts +3 -1
  148. package/dist/src/mcpl/protocol-family.d.ts.map +1 -1
  149. package/dist/src/mcpl/protocol-family.js +15 -9
  150. package/dist/src/mcpl/protocol-family.js.map +1 -1
  151. package/dist/src/mcpl/push-coalescer.d.ts +132 -22
  152. package/dist/src/mcpl/push-coalescer.d.ts.map +1 -1
  153. package/dist/src/mcpl/push-coalescer.js +105 -15
  154. package/dist/src/mcpl/push-coalescer.js.map +1 -1
  155. package/dist/src/mcpl/push-handler.d.ts +9 -7
  156. package/dist/src/mcpl/push-handler.d.ts.map +1 -1
  157. package/dist/src/mcpl/push-handler.js.map +1 -1
  158. package/dist/src/mcpl/server-connection.d.ts +50 -28
  159. package/dist/src/mcpl/server-connection.d.ts.map +1 -1
  160. package/dist/src/mcpl/server-connection.js +165 -72
  161. package/dist/src/mcpl/server-connection.js.map +1 -1
  162. package/dist/src/mcpl/tool-classes.d.ts.map +1 -1
  163. package/dist/src/mcpl/tool-classes.js +3 -0
  164. package/dist/src/mcpl/tool-classes.js.map +1 -1
  165. package/dist/src/mcpl/tool-presence.d.ts.map +1 -1
  166. package/dist/src/mcpl/tool-presence.js +10 -6
  167. package/dist/src/mcpl/tool-presence.js.map +1 -1
  168. package/dist/src/mcpl/toolset-host.d.ts.map +1 -1
  169. package/dist/src/mcpl/toolset-host.js +7 -6
  170. package/dist/src/mcpl/toolset-host.js.map +1 -1
  171. package/dist/src/mcpl/toolsets-module.d.ts.map +1 -1
  172. package/dist/src/mcpl/toolsets-module.js +2 -1
  173. package/dist/src/mcpl/toolsets-module.js.map +1 -1
  174. package/dist/src/mcpl/types.d.ts +33 -6
  175. package/dist/src/mcpl/types.d.ts.map +1 -1
  176. package/dist/src/mcpl/types.js.map +1 -1
  177. package/dist/src/module-registry.d.ts +24 -1
  178. package/dist/src/module-registry.d.ts.map +1 -1
  179. package/dist/src/module-registry.js +68 -18
  180. package/dist/src/module-registry.js.map +1 -1
  181. package/dist/src/modules/discord/index.d.ts +45 -8
  182. package/dist/src/modules/discord/index.d.ts.map +1 -1
  183. package/dist/src/modules/discord/index.js +238 -87
  184. package/dist/src/modules/discord/index.js.map +1 -1
  185. package/dist/src/modules/health/index.js +2 -2
  186. package/dist/src/modules/health/index.js.map +1 -1
  187. package/dist/src/modules/history/index.d.ts +59 -0
  188. package/dist/src/modules/history/index.d.ts.map +1 -1
  189. package/dist/src/modules/history/index.js +432 -67
  190. package/dist/src/modules/history/index.js.map +1 -1
  191. package/dist/src/modules/history/semantic.d.ts +6 -5
  192. package/dist/src/modules/history/semantic.d.ts.map +1 -1
  193. package/dist/src/modules/history/semantic.js +18 -25
  194. package/dist/src/modules/history/semantic.js.map +1 -1
  195. package/dist/src/modules/workspace/disk-agreement.d.ts +1 -1
  196. package/dist/src/modules/workspace/disk-agreement.js +1 -1
  197. package/dist/src/modules/workspace/index.d.ts +28 -7
  198. package/dist/src/modules/workspace/index.d.ts.map +1 -1
  199. package/dist/src/modules/workspace/index.js +80 -25
  200. package/dist/src/modules/workspace/index.js.map +1 -1
  201. package/dist/src/modules/workspace/observe.d.ts.map +1 -1
  202. package/dist/src/modules/workspace/observe.js +2 -1
  203. package/dist/src/modules/workspace/observe.js.map +1 -1
  204. package/dist/src/modules/workspace/reconcile.d.ts.map +1 -1
  205. package/dist/src/modules/workspace/reconcile.js +3 -2
  206. package/dist/src/modules/workspace/reconcile.js.map +1 -1
  207. package/dist/src/notice-tags.d.ts +20 -9
  208. package/dist/src/notice-tags.d.ts.map +1 -1
  209. package/dist/src/notice-tags.js +20 -9
  210. package/dist/src/notice-tags.js.map +1 -1
  211. package/dist/src/operator-log.d.ts +36 -3
  212. package/dist/src/operator-log.d.ts.map +1 -1
  213. package/dist/src/operator-log.js +2 -2
  214. package/dist/src/operator-log.js.map +1 -1
  215. package/dist/src/presentation.d.ts +747 -0
  216. package/dist/src/presentation.d.ts.map +1 -0
  217. package/dist/src/presentation.js +1437 -0
  218. package/dist/src/presentation.js.map +1 -0
  219. package/dist/src/prose-drafts.d.ts +15 -11
  220. package/dist/src/prose-drafts.d.ts.map +1 -1
  221. package/dist/src/prose-drafts.js +16 -12
  222. package/dist/src/prose-drafts.js.map +1 -1
  223. package/dist/src/read-marks.d.ts +192 -0
  224. package/dist/src/read-marks.d.ts.map +1 -0
  225. package/dist/src/read-marks.js +242 -0
  226. package/dist/src/read-marks.js.map +1 -0
  227. package/dist/src/reasoning-loss.d.ts +5 -0
  228. package/dist/src/reasoning-loss.d.ts.map +1 -0
  229. package/dist/src/reasoning-loss.js +8 -0
  230. package/dist/src/reasoning-loss.js.map +1 -0
  231. package/dist/src/recovery/offline-branch.d.ts +91 -6
  232. package/dist/src/recovery/offline-branch.d.ts.map +1 -1
  233. package/dist/src/recovery/offline-branch.js +277 -32
  234. package/dist/src/recovery/offline-branch.js.map +1 -1
  235. package/dist/src/recovery/recover-cli.js +24 -4
  236. package/dist/src/recovery/recover-cli.js.map +1 -1
  237. package/dist/src/send-tools.d.ts +5 -9
  238. package/dist/src/send-tools.d.ts.map +1 -1
  239. package/dist/src/send-tools.js +40 -7
  240. package/dist/src/send-tools.js.map +1 -1
  241. package/dist/src/sent-rows.js +1 -1
  242. package/dist/src/stored-injections.d.ts +2 -2
  243. package/dist/src/stored-injections.js +2 -2
  244. package/dist/src/stored-removal.d.ts +17 -4
  245. package/dist/src/stored-removal.d.ts.map +1 -1
  246. package/dist/src/stored-removal.js +29 -5
  247. package/dist/src/stored-removal.js.map +1 -1
  248. package/dist/src/supplied-text.d.ts +1 -1
  249. package/dist/src/supplied-text.js +3 -3
  250. package/dist/src/supplied-text.js.map +1 -1
  251. package/dist/src/thinking-drops.d.ts +2 -0
  252. package/dist/src/thinking-drops.d.ts.map +1 -1
  253. package/dist/src/thinking-drops.js.map +1 -1
  254. package/dist/src/tool-presentation.d.ts.map +1 -1
  255. package/dist/src/tool-presentation.js +38 -9
  256. package/dist/src/tool-presentation.js.map +1 -1
  257. package/dist/src/tool-result-guard.d.ts +12 -1
  258. package/dist/src/tool-result-guard.d.ts.map +1 -1
  259. package/dist/src/tool-result-guard.js +42 -8
  260. package/dist/src/tool-result-guard.js.map +1 -1
  261. package/dist/src/tune-out/coordinator.d.ts +1170 -81
  262. package/dist/src/tune-out/coordinator.d.ts.map +1 -1
  263. package/dist/src/tune-out/coordinator.js +3732 -369
  264. package/dist/src/tune-out/coordinator.js.map +1 -1
  265. package/dist/src/tune-out/tools.d.ts +114 -17
  266. package/dist/src/tune-out/tools.d.ts.map +1 -1
  267. package/dist/src/tune-out/tools.js +89 -28
  268. package/dist/src/tune-out/tools.js.map +1 -1
  269. package/dist/src/tune-out/window-anchor.d.ts +143 -0
  270. package/dist/src/tune-out/window-anchor.d.ts.map +1 -0
  271. package/dist/src/tune-out/window-anchor.js +202 -0
  272. package/dist/src/tune-out/window-anchor.js.map +1 -0
  273. package/dist/src/types/agent.d.ts +121 -25
  274. package/dist/src/types/agent.d.ts.map +1 -1
  275. package/dist/src/types/events.d.ts +2 -0
  276. package/dist/src/types/events.d.ts.map +1 -1
  277. package/dist/src/types/framework.d.ts +72 -17
  278. package/dist/src/types/framework.d.ts.map +1 -1
  279. package/dist/src/types/inference-log.d.ts +1 -0
  280. package/dist/src/types/inference-log.d.ts.map +1 -1
  281. package/dist/src/types/module.d.ts +180 -69
  282. package/dist/src/types/module.d.ts.map +1 -1
  283. package/dist/src/types/trace.d.ts +573 -39
  284. package/dist/src/types/trace.d.ts.map +1 -1
  285. package/package.json +4 -4
  286. package/src/admission/admit.ts +32 -3
  287. package/src/agent.ts +392 -132
  288. package/src/api/mcp-server-core.ts +54 -17
  289. package/src/api/server.ts +4 -23
  290. package/src/append-all.ts +6 -0
  291. package/src/code-execution/isolate/scripts.ts +28 -3
  292. package/src/config-checks.ts +14 -0
  293. package/src/context-manager-errors.ts +37 -0
  294. package/src/context-options.ts +106 -0
  295. package/src/cut-off-round.ts +4 -4
  296. package/src/deferred-import.ts +239 -0
  297. package/src/dendrite/audience.ts +315 -0
  298. package/src/dendrite/index.ts +14 -2
  299. package/src/dendrite/presets.ts +18 -6
  300. package/src/dendrite/registry.ts +213 -14
  301. package/src/dendrite/types.ts +92 -8
  302. package/src/failure-text.ts +88 -0
  303. package/src/foreign-rounds.ts +199 -0
  304. package/src/framework.ts +8796 -3813
  305. package/src/gate/event-gate.ts +518 -91
  306. package/src/gate/index.ts +3 -0
  307. package/src/gate/reply-judge.ts +12 -3
  308. package/src/gate/rule-scope.ts +45 -0
  309. package/src/gate/suppress-script-worker.ts +89 -0
  310. package/src/gate/suppress-scripts.ts +414 -0
  311. package/src/gate/suppression-review.ts +517 -0
  312. package/src/gate/suppression-stats.ts +314 -0
  313. package/src/gate/types.ts +148 -7
  314. package/src/gate/wake-onboarding.ts +309 -0
  315. package/src/heartbeat/heartbeat.ts +1 -1
  316. package/src/held-writes.ts +49 -60
  317. package/src/index.ts +10 -2
  318. package/src/inference-bounds.ts +11 -6
  319. package/src/jsonrpc-envelope.ts +81 -0
  320. package/src/mcpl/channel-registry.ts +513 -116
  321. package/src/mcpl/checkpoint-manager.ts +3 -2
  322. package/src/mcpl/feature-set-manager.ts +2 -1
  323. package/src/mcpl/inbound-source.ts +2 -1
  324. package/src/mcpl/inference-router.ts +7 -4
  325. package/src/mcpl/modern-connection.ts +629 -91
  326. package/src/mcpl/protocol-family.ts +15 -9
  327. package/src/mcpl/push-coalescer.ts +193 -34
  328. package/src/mcpl/push-handler.ts +10 -5
  329. package/src/mcpl/server-connection.ts +169 -75
  330. package/src/mcpl/tool-classes.ts +3 -0
  331. package/src/mcpl/tool-presence.ts +10 -5
  332. package/src/mcpl/toolset-host.ts +7 -6
  333. package/src/mcpl/toolsets-module.ts +2 -1
  334. package/src/mcpl/types.ts +33 -6
  335. package/src/module-registry.ts +73 -17
  336. package/src/modules/discord/index.ts +230 -82
  337. package/src/modules/health/index.ts +2 -2
  338. package/src/modules/history/index.ts +439 -70
  339. package/src/modules/history/semantic.ts +18 -24
  340. package/src/modules/workspace/disk-agreement.ts +1 -1
  341. package/src/modules/workspace/index.ts +89 -26
  342. package/src/modules/workspace/observe.ts +2 -1
  343. package/src/modules/workspace/reconcile.ts +3 -2
  344. package/src/notice-tags.ts +21 -9
  345. package/src/operator-log.ts +36 -3
  346. package/src/presentation.ts +1678 -0
  347. package/src/prose-drafts.ts +16 -12
  348. package/src/read-marks.ts +328 -0
  349. package/src/reasoning-loss.ts +7 -0
  350. package/src/recovery/offline-branch.ts +350 -35
  351. package/src/recovery/recover-cli.ts +23 -4
  352. package/src/send-tools.ts +40 -7
  353. package/src/sent-rows.ts +1 -1
  354. package/src/stored-injections.ts +2 -2
  355. package/src/stored-removal.ts +31 -7
  356. package/src/supplied-text.ts +3 -3
  357. package/src/thinking-drops.ts +2 -0
  358. package/src/tool-presentation.ts +34 -9
  359. package/src/tool-result-guard.ts +41 -7
  360. package/src/tune-out/coordinator.ts +4121 -472
  361. package/src/tune-out/tools.ts +162 -44
  362. package/src/tune-out/window-anchor.ts +277 -0
  363. package/src/types/agent.ts +122 -25
  364. package/src/types/events.ts +2 -0
  365. package/src/types/framework.ts +73 -17
  366. package/src/types/inference-log.ts +1 -0
  367. package/src/types/module.ts +181 -68
  368. package/src/types/trace.ts +607 -43
@@ -14,6 +14,7 @@ import { maskNegotiatedCapabilities } from './capability-mask.js';
14
14
  import { CapabilityGrant, expandAdvertisementShorthand } from './capability-grant.js';
15
15
  import { CAPABILITY_DISABLED, boundedForLog, describeCause } from './errors.js';
16
16
  import { logDetail, logValue, logValueRedacted, loggedCode } from './log-value.js';
17
+ import { jsonKind, readEnvelope } from '../jsonrpc-envelope.js';
17
18
  import { LEGACY_MCP_PROTOCOL_VERSION, MODERN_MCP_PROTOCOL_VERSION, checkServerConfig, logDroppedLine, redactServerText, redactedData, serverTextRedactor, } from './protocol-family.js';
18
19
  import { McplMethod } from './types.js';
19
20
  /** Timeout for the initialize handshake in milliseconds.
@@ -79,20 +80,27 @@ const UNSUPPORTED_PROTOCOL_VERSION_CODE = -32022;
79
80
  * end. Generous: real inventories fit in a handful of pages. */
80
81
  const MAX_TOOL_LIST_PAGES = 100;
81
82
  /**
82
- * The server and this engine have no protocol revision in common, so the
83
- * connection was never established. This is a protocol-negotiation fact, not
84
- * a request outcome. Retrying cannot change it: each engine offers one
85
- * revision, and only configuration can fix the mismatch. A connection that
86
- * gets this error does not schedule reconnects. The legacy engine and the
87
- * modern one (ModernMcpConnection, whose pinned revision the server refused)
88
- * both throw it, so its readers treat them alike.
83
+ * This engine and the server could not negotiate a protocol revision, so the
84
+ * connect that throws it established no connection. Usually they share none. Over HTTP it
85
+ * can also be the SDK's own refusal: after a -32022 whose list names a
86
+ * revision from 2026-07-28 on that this client doesn't speak, the SDK
87
+ * negotiates no further, even when the list also names a 2025 revision both
88
+ * speak. This is a protocol-negotiation fact, not a request outcome.
89
+ * Retrying cannot change it: each engine offers the same revisions every
90
+ * time (`offeredRevisions`), and only configuration, or the server's
91
+ * operator, can fix the mismatch. A connection that gets this error does not
92
+ * schedule reconnects. The legacy engine and the modern one
93
+ * (ModernMcpConnection) both throw it, so its readers treat them alike.
89
94
  *
90
- * - `rejected`: the server refused the offered revision: the legacy engine's
91
- * `initialize` answered with error -32022, or a modern server's discovery
92
- * or error naming no common revision. `supported` is the server's own list,
93
- * when it gave one.
94
- * - `mismatch`: the server answered the legacy engine's `initialize` with a
95
- * revision other than 2024-11-05, or with none.
95
+ * - `rejected`: the server refused the revision offered. The legacy
96
+ * engine's `initialize` was answered with error -32022. A modern server's
97
+ * discovery or -32022 error named no revision in common (over HTTP, a
98
+ * discovery's list counts once the server has refused the `initialize`
99
+ * tried after it too), or, over HTTP, named one this client doesn't speak,
100
+ * as above. `supported` is the server's own list, when it gave one.
101
+ * - `mismatch`: the server answered `initialize` with a revision that
102
+ * handshake doesn't accept, or with none: the legacy engine's, or a modern
103
+ * connection's 2025 handshake over HTTP.
96
104
  */
97
105
  export class McplProtocolVersionError extends Error {
98
106
  kind;
@@ -101,6 +109,7 @@ export class McplProtocolVersionError extends Error {
101
109
  code;
102
110
  data;
103
111
  offered;
112
+ offeredRevisions;
104
113
  constructor(message, kind,
105
114
  /** Revision the server answered with (`mismatch`; null when it gave
106
115
  * none), redacted as the server's words are. */
@@ -110,9 +119,15 @@ export class McplProtocolVersionError extends Error {
110
119
  /** The JSON-RPC error's code, and its data with each string in it
111
120
  * redacted (`rejected`). */
112
121
  code, data,
113
- /** The revision this client offered: the legacy engine's, unless a
114
- * modern connection's. */
115
- offered = MCP_PROTOCOL_VERSION) {
122
+ /** The revision this client offered first, in its order of preference:
123
+ * the legacy engine's (2024-11-05), a modern connection's over stdio
124
+ * (2026-07-28), or over HTTP 2026-07-28, the first of
125
+ * `offeredRevisions`. */
126
+ offered = MCP_PROTOCOL_VERSION,
127
+ /** Every revision this client offered, in its order of preference: the
128
+ * legacy engine's one, a modern connection's one over stdio, or its
129
+ * list over HTTP. */
130
+ offeredRevisions = [offered]) {
116
131
  super(message);
117
132
  this.kind = kind;
118
133
  this.returned = returned;
@@ -120,6 +135,7 @@ export class McplProtocolVersionError extends Error {
120
135
  this.code = code;
121
136
  this.data = data;
122
137
  this.offered = offered;
138
+ this.offeredRevisions = offeredRevisions;
123
139
  this.name = 'McplProtocolVersionError';
124
140
  }
125
141
  }
@@ -239,11 +255,27 @@ export class McplRequestError extends Error {
239
255
  this.name = 'McplRequestError';
240
256
  }
241
257
  }
242
- /** A request's method for a log line, whatever the server sent there. */
243
- function describeMethod(method) {
244
- return typeof method === 'string'
245
- ? `method ${logValue(method)}`
246
- : `a method of type ${method === null ? 'null' : typeof method}`;
258
+ /** Whether a response that can't be matched to a request of ours, its id
259
+ * being neither a string nor a number or missing, is logged: only a
260
+ * JSON-RPC 2.0 error is, since that's how a server says it couldn't read a
261
+ * message of ours (JSON-RPC 2.0 §5). Anything else id-less, such as a
262
+ * server's own JSON log line with `"id": null`, is ignored silently, as it
263
+ * was before #475, so a server's log output can't fill the host's. */
264
+ function isJsonRpcError(response) {
265
+ return response.jsonrpc === '2.0' && Object.hasOwn(response, 'error');
266
+ }
267
+ /** The log line for such an error. The host's own request ids are numbers,
268
+ * so it can't be matched to one. Once connected it may be the answer to a
269
+ * request of ours, which gets nothing from it and ends as any unanswered
270
+ * request does, by its timeout where it has one. (During the handshake an
271
+ * error with id null or no id answers initialize.) Its error member is the
272
+ * server's text, whatever JSON value it is, so it's printed redacted with
273
+ * `redact`, the server's redaction (logValueRedacted), as handleResponse
274
+ * prints a matched error's code and message. */
275
+ function unmatchedResponse(serverId, response, redact) {
276
+ const which = Object.hasOwn(response, 'id') ? `whose id is ${jsonKind(response.id)}` : 'with no id';
277
+ return `[mcpl] ${serverId}: ignored a response ${which}, which can't be matched to a request of ours; ` +
278
+ `its error: ${logValueRedacted(response.error, redact)}`;
247
279
  }
248
280
  /**
249
281
  * McplServerConnection manages a single JSON-RPC 2.0 connection to an
@@ -542,13 +574,14 @@ export class McplServerConnection extends EventEmitter {
542
574
  // Reconnect state (adapted from Anarchid/agent-framework@mcpl-module-proto)
543
575
  config = null;
544
576
  /** The redactor of the server's text for `config`, made at its first error
545
- * answer, by when `config` is set, and kept: a framework-launched child's
546
- * `env` is a getter that reads the awareness ledger, so a redactor built
547
- * per answer would read it per answer (#540's review, R1-2). An answer
548
- * takes one build of it for its words, data and log line (`now()`), so
549
- * it reads the ledger at most once. It builds again only after a build
550
- * that failed, which withholds that answer's text, or once a dial notes
551
- * something new (serverTextRedactor). */
577
+ * answer or response it can't match (handleResponse), by when `config`
578
+ * is set, and kept: a framework-launched child's `env` is a getter that
579
+ * reads the awareness ledger, so a redactor built per answer would read
580
+ * it per answer (#540's review, R1-2). An answer takes one build of it
581
+ * for its words, data and log line (`now()`), so it reads the ledger at
582
+ * most once. It builds again only after a build that failed, which
583
+ * withholds that answer's text, or once a dial notes something new
584
+ * (serverTextRedactor). */
552
585
  redactor = null;
553
586
  hostCapabilities = null;
554
587
  reconnectEnabled = false;
@@ -1154,16 +1187,36 @@ export class McplServerConnection extends EventEmitter {
1154
1187
  // initialize response, whatever its id: a server's own ids can start
1155
1188
  // at 0, this handshake's. MCP lets a server ping before
1156
1189
  // initialization completes, and the ping gets its empty result, as
1157
- // on a connected transport. Anything else it sends now is ignored.
1158
- if ('method' in msg) {
1159
- const request = msg;
1160
- if (request.method === 'ping' && request.id != null) {
1161
- transport.writeLine(JSON.stringify({ jsonrpc: '2.0', id: request.id, result: {} }));
1162
- }
1190
+ // on a connected transport, `"id": null` included
1191
+ // (src/jsonrpc-envelope.ts). Anything else it sends now is ignored,
1192
+ // an invalid request included. Of its responses, the one with
1193
+ // initialize's id answers it, and so does a JSON-RPC 2.0 error with
1194
+ // id null or with no id: a peer answers a request it couldn't read
1195
+ // that way (JSON-RPC 2.0 §5; MCP 2025-11-25, Basic), initialize is
1196
+ // the only request this host has out, and a peer never answers a
1197
+ // response. Such an error means the server can't read this host's
1198
+ // messages, so the handshake fails at once, with the error's message.
1199
+ // `"jsonrpc": "2.0"` keeps a server's own JSON log line with an
1200
+ // error key and id null, or no id, from failing it; one with
1201
+ // initialize's id is taken for the answer, whatever its jsonrpc. Of
1202
+ // the other responses, a JSON-RPC 2.0 error whose id is neither a
1203
+ // string nor a number is logged, as on a connected transport, and
1204
+ // any other is ignored.
1205
+ const envelope = readEnvelope(msg);
1206
+ if (envelope.kind === 'request' && envelope.method === 'ping') {
1207
+ transport.writeLine(JSON.stringify({ jsonrpc: '2.0', id: envelope.id, result: {} }));
1163
1208
  return;
1164
1209
  }
1165
- if (msg.id !== initId)
1210
+ if (envelope.kind !== 'response')
1166
1211
  return;
1212
+ const namesNoRequest = msg.id === null || !Object.hasOwn(msg, 'id');
1213
+ const answersInitialize = msg.id === initId || (namesNoRequest && msg.jsonrpc === '2.0' && Boolean(msg.error));
1214
+ if (!answersInitialize) {
1215
+ if (typeof msg.id !== 'string' && typeof msg.id !== 'number' && isJsonRpcError(msg)) {
1216
+ console.error(unmatchedResponse(config.id, msg, (text) => redactServerText(text, config)));
1217
+ }
1218
+ return;
1219
+ }
1167
1220
  cleanup();
1168
1221
  if (msg.error) {
1169
1222
  // describeCause rather than the template's own conversion: the
@@ -1486,8 +1539,9 @@ export class McplServerConnection extends EventEmitter {
1486
1539
  * following `nextCursor` across pages (2024-11-05 pagination). Cursors are
1487
1540
  * opaque strings, `''` included: only an absent or null `nextCursor` ends
1488
1541
  * the inventory (a null one is how some servers say "no more", and main
1489
- * read it as a complete page). A page that isn't well formed (no `tools` array, a cursor
1490
- * that isn't a string), or cursors that don't terminate (a repeat, or more
1542
+ * read it as a complete page). A page that isn't well formed (no `tools` array, an entry
1543
+ * that isn't an object with a string `name`, a cursor that isn't a string), or cursors
1544
+ * that don't terminate (a repeat, or more
1491
1545
  * than {@link MAX_TOOL_LIST_PAGES} pages), are errors, never a partial or
1492
1546
  * empty inventory published as complete. The read tap (RFC-014) is handed
1493
1547
  * the complete inventory once, with the last page's `_meta`, as the last
@@ -1502,10 +1556,13 @@ export class McplServerConnection extends EventEmitter {
1502
1556
  let first;
1503
1557
  const read = [];
1504
1558
  const revs = new Set();
1559
+ const isTool = (entry) => !!entry && typeof entry === 'object' && typeof entry.name === 'string';
1505
1560
  const onRead = (result) => {
1506
1561
  if (!result || typeof result !== 'object' || !Array.isArray(result.tools))
1507
1562
  return;
1508
1563
  const r = result;
1564
+ if (!r.tools.every(isTool))
1565
+ return;
1509
1566
  for (const t of r.tools)
1510
1567
  read.push(t);
1511
1568
  const rev = r._meta?.['mcpl/rev'];
@@ -1524,6 +1581,9 @@ export class McplServerConnection extends EventEmitter {
1524
1581
  if (!result || typeof result !== 'object' || !Array.isArray(result.tools)) {
1525
1582
  throw malformed('no tools array');
1526
1583
  }
1584
+ const unreadable = result.tools.findIndex((entry) => !isTool(entry));
1585
+ if (unreadable !== -1)
1586
+ throw malformed(`entry ${unreadable + 1} isn't an object with a string name`);
1527
1587
  first ??= result;
1528
1588
  for (const t of result.tools)
1529
1589
  tools.push(t);
@@ -2103,23 +2163,46 @@ export class McplServerConnection extends EventEmitter {
2103
2163
  }
2104
2164
  /** Contain synchronous dispatch failures; async RPC handlers own their promises. */
2105
2165
  dispatchMessage(msg, epoch) {
2106
- // Is this a response to one of our outbound requests?
2107
- if ('id' in msg && msg.id != null && !('method' in msg)) {
2108
- const late = epoch !== this.transportEpoch;
2109
- // RFC-014: its hints apply as it's read, whether or not anyone still
2110
- // waits for it. A dead transport's revs are its own, so a response
2111
- // read after its boundary is never tapped.
2112
- if (!late)
2113
- this.tapResponse(msg);
2114
- this.handleResponse(msg, late);
2115
- return;
2166
+ // The envelope is read once, here (src/jsonrpc-envelope.ts says how).
2167
+ const envelope = readEnvelope(msg);
2168
+ switch (envelope.kind) {
2169
+ case 'response': {
2170
+ // Never answered, so a server that answers what it can't read, with
2171
+ // id null, can't start an exchange of errors with us. One read after
2172
+ // its transport's boundary is late (handleResponse).
2173
+ const late = epoch !== this.transportEpoch;
2174
+ // RFC-014: its hints apply as it's read, whether or not anyone still
2175
+ // waits for it. A dead transport's revs are its own, so a response
2176
+ // read after its boundary is never tapped.
2177
+ if (!late)
2178
+ this.tapResponse(msg);
2179
+ this.handleResponse(msg, late);
2180
+ return;
2181
+ }
2182
+ case 'neither':
2183
+ // Not JSON-RPC: ignored like the server's other unrelated output.
2184
+ return;
2185
+ case 'invalid': {
2186
+ // Answered on the transport it came on, as every request is. One
2187
+ // read after that transport's boundary is the dead process's and
2188
+ // isn't answered: sendErrorResponse logs the answer it didn't send.
2189
+ this.sendErrorResponse(envelope.id, envelope.error.code, envelope.error.message, undefined, epoch);
2190
+ if (epoch !== this.transportEpoch)
2191
+ return;
2192
+ const forMethod = envelope.method !== undefined ? ` for method ${logValue(envelope.method)}` : '';
2193
+ console.error(`[mcpl] ${this.id}: answered -32600 to an invalid request${forMethod}: ${envelope.problems}`);
2194
+ return;
2195
+ }
2116
2196
  }
2117
- // It is an inbound request or notification from the server
2197
+ // It is an inbound request or notification from the server, its method
2198
+ // a string. A request's id is a string, a number or null, and `"id": null`
2199
+ // is answered with id null; a notification has none.
2118
2200
  const request = msg;
2201
+ const requestId = envelope.kind === 'request' ? envelope.id : undefined;
2119
2202
  // Read after its transport's boundary, it is the dead process's: the
2120
2203
  // boundary's rule applies (afterBoundary).
2121
2204
  if (epoch !== this.transportEpoch) {
2122
- this.afterBoundary(request, epoch);
2205
+ this.afterBoundary(request, requestId, epoch);
2123
2206
  return;
2124
2207
  }
2125
2208
  // MCP's ping, which either side may send: its receiver answers promptly
@@ -2128,8 +2211,8 @@ export class McplServerConnection extends EventEmitter {
2128
2211
  // paused plane mustn't hold that answer. A ping sent as a notification
2129
2212
  // has nothing to answer. The handshake answers one too.
2130
2213
  if (request.method === 'ping') {
2131
- if (request.id != null)
2132
- this.sendResponse(request.id, {});
2214
+ if (requestId !== undefined)
2215
+ this.sendResponse(requestId, {});
2133
2216
  return;
2134
2217
  }
2135
2218
  // RFC-014 §6.1: a push's hints apply as it's read, before the plane gate
@@ -2140,11 +2223,11 @@ export class McplServerConnection extends EventEmitter {
2140
2223
  this.tap({ kind: 'push', params: request.params });
2141
2224
  else if (request.method === 'tools/hints' && this.readTap) {
2142
2225
  this.tap({ kind: 'hints', params: request.params });
2143
- if (request.id != null)
2144
- this.sendResponse(request.id, {});
2226
+ if (requestId !== undefined)
2227
+ this.sendResponse(requestId, {});
2145
2228
  return;
2146
2229
  }
2147
- const eventName = typeof request.method === 'string' && Object.hasOwn(McplServerConnection.METHOD_TO_EVENT, request.method)
2230
+ const eventName = Object.hasOwn(McplServerConnection.METHOD_TO_EVENT, request.method)
2148
2231
  ? McplServerConnection.METHOD_TO_EVENT[request.method] : undefined;
2149
2232
  // §7 is removed in 0.5.0: scope/elevate is no longer a method. Answer
2150
2233
  // rather than hang (§6.6 — a method that will never be answered MUST
@@ -2155,8 +2238,8 @@ export class McplServerConnection extends EventEmitter {
2155
2238
  // routed, control-plane classified, and mutating declarations — a
2156
2239
  // live ungated self-attestation path (PR #79 review blocker 4).
2157
2240
  if (request.method === McplMethod.FeatureSetsChanged) {
2158
- if (request.id != null) {
2159
- this.sendErrorResponse(request.id, -32601, 'featureSets/changed removed in MCPL 0.5.0 (superseded by mcpl/manifestChanged, SPEC §17)');
2241
+ if (requestId !== undefined) {
2242
+ this.sendErrorResponse(requestId, -32601, 'featureSets/changed removed in MCPL 0.5.0 (superseded by mcpl/manifestChanged, SPEC §17)');
2160
2243
  }
2161
2244
  else {
2162
2245
  console.error(`[mcpl] ${this.id}: discarded featureSets/changed — removed in 0.5.0 (§6.7/§17)`);
@@ -2164,8 +2247,8 @@ export class McplServerConnection extends EventEmitter {
2164
2247
  return;
2165
2248
  }
2166
2249
  if (request.method === McplMethod.ScopeElevate) {
2167
- if (request.id != null) {
2168
- this.sendErrorResponse(request.id, -32601, 'scope/elevate removed in MCPL 0.5.0 (SPEC §7)');
2250
+ if (requestId !== undefined) {
2251
+ this.sendErrorResponse(requestId, -32601, 'scope/elevate removed in MCPL 0.5.0 (SPEC §7)');
2169
2252
  }
2170
2253
  return;
2171
2254
  }
@@ -2175,19 +2258,18 @@ export class McplServerConnection extends EventEmitter {
2175
2258
  // rejecting here, at line receipt, was wrong for staged connections.
2176
2259
  if (!eventName) {
2177
2260
  // §6.6: a request that will never be answered MUST get an error, so a
2178
- // request (it has an id) whose method isn't a string, or isn't one this
2179
- // host handles, is answered -32601. A notification nobody handles is
2180
- // ignored, as JSON-RPC asks.
2181
- if (request.id != null) {
2182
- this.sendErrorResponse(request.id, -32601, 'Method not found');
2183
- console.error(`[mcpl] ${this.id}: answered -32601 to a request for ${describeMethod(request.method)}, which this host doesn't handle`);
2261
+ // request whose method isn't one this host handles is answered -32601.
2262
+ // A notification nobody handles is ignored, as JSON-RPC asks.
2263
+ if (requestId !== undefined) {
2264
+ this.sendErrorResponse(requestId, -32601, 'Method not found');
2265
+ console.error(`[mcpl] ${this.id}: answered -32601 to a request for method ${logValue(request.method)}, which this host doesn't handle`);
2184
2266
  }
2185
2267
  return;
2186
2268
  }
2187
2269
  // Emit the typed event with params and (for requests) a respond callback
2188
- if (request.id != null) {
2270
+ if (requestId !== undefined) {
2189
2271
  // Server expects a response — provide a respond helper
2190
- this.dispatchInboundEvent(eventName, request.params, this.responderFor(request.id, epoch));
2272
+ this.dispatchInboundEvent(eventName, request.params, this.responderFor(requestId, epoch));
2191
2273
  }
2192
2274
  else {
2193
2275
  // Notification — no response expected
@@ -2197,7 +2279,8 @@ export class McplServerConnection extends EventEmitter {
2197
2279
  /**
2198
2280
  * A request's responder, bound to the transport it came on (`epoch`): an
2199
2281
  * answer, or a streamed inference's chunk, sent after that transport has
2200
- * closed reaches nothing, never a server that didn't ask it.
2282
+ * closed reaches nothing, never a server that didn't ask it. A request
2283
+ * sent with id null is answered with id null.
2201
2284
  */
2202
2285
  responderFor(id, epoch) {
2203
2286
  return {
@@ -2222,15 +2305,15 @@ export class McplServerConnection extends EventEmitter {
2222
2305
  * it while its writer lives, with no grant to come, so it drops and logs
2223
2306
  * all of it; hold's bounds cap what any other keeps.
2224
2307
  */
2225
- afterBoundary(request, epoch) {
2226
- const event = typeof request.method === 'string' && Object.hasOwn(McplServerConnection.METHOD_TO_EVENT, request.method)
2308
+ afterBoundary(request, requestId, epoch) {
2309
+ const event = Object.hasOwn(McplServerConnection.METHOD_TO_EVENT, request.method)
2227
2310
  ? McplServerConnection.METHOD_TO_EVENT[request.method] : undefined;
2228
2311
  if (this.closedForGood || event === undefined || !McplServerConnection.WORLD_EVENTS.has(event)) {
2229
2312
  console.error(`[mcpl] ${this.id}: dropped a message read after its transport closed` +
2230
- `${this.closedForGood ? ', with no transport to come' : ''}: ${describeMethod(request.method)}`);
2313
+ `${this.closedForGood ? ', with no transport to come' : ''}: method ${logValue(request.method)}`);
2231
2314
  return;
2232
2315
  }
2233
- this.hold(event, request.id != null ? [request.params, this.responderFor(request.id, epoch)] : [request.params], true);
2316
+ this.hold(event, requestId !== undefined ? [request.params, this.responderFor(requestId, epoch)] : [request.params], true);
2234
2317
  }
2235
2318
  /** Live delivery and delayed plane flushes share the same containment boundary. */
2236
2319
  dispatchInboundEvent(event, ...args) {
@@ -2283,7 +2366,7 @@ export class McplServerConnection extends EventEmitter {
2283
2366
  /** Tap a response to a hinted request (RFC-014): its result's hints, or a
2284
2367
  * list's statement, apply now, awaited or not. */
2285
2368
  tapResponse(response) {
2286
- if (!this.readTap)
2369
+ if (!this.readTap || response.id === null)
2287
2370
  return;
2288
2371
  const sent = this.hintedRequests.get(response.id);
2289
2372
  if (!sent)
@@ -2298,6 +2381,16 @@ export class McplServerConnection extends EventEmitter {
2298
2381
  * Handle a JSON-RPC response by resolving/rejecting the corresponding pending request.
2299
2382
  */
2300
2383
  handleResponse(response, late = false) {
2384
+ // A response whose id is neither a string nor a number, or that has
2385
+ // none, can't be matched to a request of ours, on this transport or an
2386
+ // earlier one. It isn't an orphan, which is a late answer to one, so
2387
+ // it's ignored, and logged when it's a JSON-RPC 2.0 error.
2388
+ if (typeof response.id !== 'string' && typeof response.id !== 'number') {
2389
+ if (isJsonRpcError(response)) {
2390
+ console.error(unmatchedResponse(this.id, response, (this.redactor ??= serverTextRedactor(this.config ?? {})).now()));
2391
+ }
2392
+ return;
2393
+ }
2301
2394
  // One read after its transport's boundary answers a request the close
2302
2395
  // ended. It's matched against none of this connection's request records,
2303
2396
  // since the next transport numbers its requests afresh, and goes the way