@animalabs/agent-framework 0.27.0 → 0.29.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 (344) hide show
  1. package/README.md +145 -41
  2. package/dist/src/agent.d.ts +29 -2
  3. package/dist/src/agent.d.ts.map +1 -1
  4. package/dist/src/agent.js +73 -12
  5. package/dist/src/agent.js.map +1 -1
  6. package/dist/src/api/mcp-server-core.d.ts.map +1 -1
  7. package/dist/src/api/mcp-server-core.js +3 -12
  8. package/dist/src/api/mcp-server-core.js.map +1 -1
  9. package/dist/src/api/server.d.ts.map +1 -1
  10. package/dist/src/api/server.js +11 -5
  11. package/dist/src/api/server.js.map +1 -1
  12. package/dist/src/auto-continue.d.ts +5 -2
  13. package/dist/src/auto-continue.d.ts.map +1 -1
  14. package/dist/src/auto-continue.js +9 -5
  15. package/dist/src/auto-continue.js.map +1 -1
  16. package/dist/src/code-execution/isolate/runner.d.ts +7 -5
  17. package/dist/src/code-execution/isolate/runner.d.ts.map +1 -1
  18. package/dist/src/code-execution/isolate/runner.js +7 -5
  19. package/dist/src/code-execution/isolate/runner.js.map +1 -1
  20. package/dist/src/code-execution/isolate/scripts.d.ts.map +1 -1
  21. package/dist/src/code-execution/isolate/scripts.js +3 -2
  22. package/dist/src/code-execution/isolate/scripts.js.map +1 -1
  23. package/dist/src/cut-off-round.d.ts +24 -0
  24. package/dist/src/cut-off-round.d.ts.map +1 -0
  25. package/dist/src/cut-off-round.js +87 -0
  26. package/dist/src/cut-off-round.js.map +1 -0
  27. package/dist/src/framework.d.ts +468 -125
  28. package/dist/src/framework.d.ts.map +1 -1
  29. package/dist/src/framework.js +3651 -1111
  30. package/dist/src/framework.js.map +1 -1
  31. package/dist/src/gate/event-gate.d.ts +133 -13
  32. package/dist/src/gate/event-gate.d.ts.map +1 -1
  33. package/dist/src/gate/event-gate.js +654 -59
  34. package/dist/src/gate/event-gate.js.map +1 -1
  35. package/dist/src/gate/index.d.ts +3 -2
  36. package/dist/src/gate/index.d.ts.map +1 -1
  37. package/dist/src/gate/index.js +2 -1
  38. package/dist/src/gate/index.js.map +1 -1
  39. package/dist/src/gate/reply-judge.d.ts +116 -0
  40. package/dist/src/gate/reply-judge.d.ts.map +1 -0
  41. package/dist/src/gate/reply-judge.js +467 -0
  42. package/dist/src/gate/reply-judge.js.map +1 -0
  43. package/dist/src/gate/types.d.ts +173 -2
  44. package/dist/src/gate/types.d.ts.map +1 -1
  45. package/dist/src/heartbeat/heartbeat.d.ts +202 -0
  46. package/dist/src/heartbeat/heartbeat.d.ts.map +1 -0
  47. package/dist/src/heartbeat/heartbeat.js +778 -0
  48. package/dist/src/heartbeat/heartbeat.js.map +1 -0
  49. package/dist/src/heartbeat/reminder-time.d.ts +5 -0
  50. package/dist/src/heartbeat/reminder-time.d.ts.map +1 -0
  51. package/dist/src/heartbeat/reminder-time.js +107 -0
  52. package/dist/src/heartbeat/reminder-time.js.map +1 -0
  53. package/dist/src/held-writes.d.ts +3 -3
  54. package/dist/src/held-writes.js +3 -3
  55. package/dist/src/host-presentation.d.ts +170 -0
  56. package/dist/src/host-presentation.d.ts.map +1 -0
  57. package/dist/src/host-presentation.js +561 -0
  58. package/dist/src/host-presentation.js.map +1 -0
  59. package/dist/src/index.d.ts +5 -1
  60. package/dist/src/index.d.ts.map +1 -1
  61. package/dist/src/index.js +3 -1
  62. package/dist/src/index.js.map +1 -1
  63. package/dist/src/line-reader.d.ts +4 -0
  64. package/dist/src/line-reader.d.ts.map +1 -0
  65. package/dist/src/line-reader.js +59 -0
  66. package/dist/src/line-reader.js.map +1 -0
  67. package/dist/src/mcpl/capability-mask.d.ts.map +1 -1
  68. package/dist/src/mcpl/capability-mask.js +3 -2
  69. package/dist/src/mcpl/capability-mask.js.map +1 -1
  70. package/dist/src/mcpl/channel-registry.d.ts +34 -6
  71. package/dist/src/mcpl/channel-registry.d.ts.map +1 -1
  72. package/dist/src/mcpl/channel-registry.js +133 -54
  73. package/dist/src/mcpl/channel-registry.js.map +1 -1
  74. package/dist/src/mcpl/conversation-router.d.ts.map +1 -1
  75. package/dist/src/mcpl/conversation-router.js +2 -1
  76. package/dist/src/mcpl/conversation-router.js.map +1 -1
  77. package/dist/src/mcpl/convert-block.d.ts +1 -0
  78. package/dist/src/mcpl/convert-block.d.ts.map +1 -1
  79. package/dist/src/mcpl/convert-block.js +16 -4
  80. package/dist/src/mcpl/convert-block.js.map +1 -1
  81. package/dist/src/mcpl/hook-orchestrator.d.ts.map +1 -1
  82. package/dist/src/mcpl/hook-orchestrator.js +4 -3
  83. package/dist/src/mcpl/hook-orchestrator.js.map +1 -1
  84. package/dist/src/mcpl/inbound-source.d.ts +29 -11
  85. package/dist/src/mcpl/inbound-source.d.ts.map +1 -1
  86. package/dist/src/mcpl/inbound-source.js +43 -70
  87. package/dist/src/mcpl/inbound-source.js.map +1 -1
  88. package/dist/src/mcpl/modern-connection.d.ts.map +1 -1
  89. package/dist/src/mcpl/modern-connection.js +11 -7
  90. package/dist/src/mcpl/modern-connection.js.map +1 -1
  91. package/dist/src/mcpl/protocol-family.d.ts +3 -2
  92. package/dist/src/mcpl/protocol-family.d.ts.map +1 -1
  93. package/dist/src/mcpl/protocol-family.js +25 -3
  94. package/dist/src/mcpl/protocol-family.js.map +1 -1
  95. package/dist/src/mcpl/push-handler.js +2 -2
  96. package/dist/src/mcpl/push-handler.js.map +1 -1
  97. package/dist/src/mcpl/references.d.ts +12 -40
  98. package/dist/src/mcpl/references.d.ts.map +1 -1
  99. package/dist/src/mcpl/references.js +29 -23
  100. package/dist/src/mcpl/references.js.map +1 -1
  101. package/dist/src/mcpl/server-connection.d.ts +18 -8
  102. package/dist/src/mcpl/server-connection.d.ts.map +1 -1
  103. package/dist/src/mcpl/server-connection.js +70 -30
  104. package/dist/src/mcpl/server-connection.js.map +1 -1
  105. package/dist/src/mcpl/skip-reply-wake.d.ts +25 -0
  106. package/dist/src/mcpl/skip-reply-wake.d.ts.map +1 -1
  107. package/dist/src/mcpl/skip-reply-wake.js +25 -0
  108. package/dist/src/mcpl/skip-reply-wake.js.map +1 -1
  109. package/dist/src/mcpl/tags.d.ts +9 -2
  110. package/dist/src/mcpl/tags.d.ts.map +1 -1
  111. package/dist/src/mcpl/tags.js +12 -2
  112. package/dist/src/mcpl/tags.js.map +1 -1
  113. package/dist/src/mcpl/tool-presence.d.ts +66 -14
  114. package/dist/src/mcpl/tool-presence.d.ts.map +1 -1
  115. package/dist/src/mcpl/tool-presence.js +150 -80
  116. package/dist/src/mcpl/tool-presence.js.map +1 -1
  117. package/dist/src/mcpl/tool-signature.d.ts +10 -3
  118. package/dist/src/mcpl/tool-signature.d.ts.map +1 -1
  119. package/dist/src/mcpl/tool-signature.js +60 -30
  120. package/dist/src/mcpl/tool-signature.js.map +1 -1
  121. package/dist/src/mcpl/toolset-host.d.ts +88 -55
  122. package/dist/src/mcpl/toolset-host.d.ts.map +1 -1
  123. package/dist/src/mcpl/toolset-host.js +220 -111
  124. package/dist/src/mcpl/toolset-host.js.map +1 -1
  125. package/dist/src/mcpl/toolsets-module.d.ts +27 -35
  126. package/dist/src/mcpl/toolsets-module.d.ts.map +1 -1
  127. package/dist/src/mcpl/toolsets-module.js +313 -91
  128. package/dist/src/mcpl/toolsets-module.js.map +1 -1
  129. package/dist/src/mcpl/transport.d.ts +1 -1
  130. package/dist/src/mcpl/transport.d.ts.map +1 -1
  131. package/dist/src/mcpl/transport.js +16 -16
  132. package/dist/src/mcpl/transport.js.map +1 -1
  133. package/dist/src/mcpl/types.d.ts +31 -13
  134. package/dist/src/mcpl/types.d.ts.map +1 -1
  135. package/dist/src/mcpl/types.js.map +1 -1
  136. package/dist/src/module-registry.d.ts +10 -8
  137. package/dist/src/module-registry.d.ts.map +1 -1
  138. package/dist/src/module-registry.js +15 -9
  139. package/dist/src/module-registry.js.map +1 -1
  140. package/dist/src/modules/api/index.d.ts.map +1 -1
  141. package/dist/src/modules/api/index.js +4 -2
  142. package/dist/src/modules/api/index.js.map +1 -1
  143. package/dist/src/modules/discord/index.d.ts.map +1 -1
  144. package/dist/src/modules/discord/index.js +33 -25
  145. package/dist/src/modules/discord/index.js.map +1 -1
  146. package/dist/src/modules/history/index.d.ts.map +1 -1
  147. package/dist/src/modules/history/index.js +30 -17
  148. package/dist/src/modules/history/index.js.map +1 -1
  149. package/dist/src/modules/sender-name.d.ts +7 -0
  150. package/dist/src/modules/sender-name.d.ts.map +1 -0
  151. package/dist/src/modules/sender-name.js +10 -0
  152. package/dist/src/modules/sender-name.js.map +1 -0
  153. package/dist/src/modules/workspace/answers.d.ts +26 -0
  154. package/dist/src/modules/workspace/answers.d.ts.map +1 -0
  155. package/dist/src/modules/workspace/answers.js +138 -0
  156. package/dist/src/modules/workspace/answers.js.map +1 -0
  157. package/dist/src/modules/workspace/branch-intent.d.ts +5 -3
  158. package/dist/src/modules/workspace/branch-intent.d.ts.map +1 -1
  159. package/dist/src/modules/workspace/branch-intent.js +6 -2
  160. package/dist/src/modules/workspace/branch-intent.js.map +1 -1
  161. package/dist/src/modules/workspace/direct-write.d.ts +3 -0
  162. package/dist/src/modules/workspace/direct-write.d.ts.map +1 -1
  163. package/dist/src/modules/workspace/direct-write.js +59 -24
  164. package/dist/src/modules/workspace/direct-write.js.map +1 -1
  165. package/dist/src/modules/workspace/disk-agreement.d.ts +33 -11
  166. package/dist/src/modules/workspace/disk-agreement.d.ts.map +1 -1
  167. package/dist/src/modules/workspace/disk-agreement.js +48 -17
  168. package/dist/src/modules/workspace/disk-agreement.js.map +1 -1
  169. package/dist/src/modules/workspace/edit-text.d.ts +2 -1
  170. package/dist/src/modules/workspace/edit-text.d.ts.map +1 -1
  171. package/dist/src/modules/workspace/edit-text.js +4 -2
  172. package/dist/src/modules/workspace/edit-text.js.map +1 -1
  173. package/dist/src/modules/workspace/effects.d.ts +4 -2
  174. package/dist/src/modules/workspace/effects.d.ts.map +1 -1
  175. package/dist/src/modules/workspace/effects.js +67 -50
  176. package/dist/src/modules/workspace/effects.js.map +1 -1
  177. package/dist/src/modules/workspace/index.d.ts +63 -51
  178. package/dist/src/modules/workspace/index.d.ts.map +1 -1
  179. package/dist/src/modules/workspace/index.js +980 -547
  180. package/dist/src/modules/workspace/index.js.map +1 -1
  181. package/dist/src/modules/workspace/observe.d.ts +125 -82
  182. package/dist/src/modules/workspace/observe.d.ts.map +1 -1
  183. package/dist/src/modules/workspace/observe.js +465 -241
  184. package/dist/src/modules/workspace/observe.js.map +1 -1
  185. package/dist/src/modules/workspace/read-page.d.ts.map +1 -1
  186. package/dist/src/modules/workspace/read-page.js +7 -1
  187. package/dist/src/modules/workspace/read-page.js.map +1 -1
  188. package/dist/src/modules/workspace/reconcile.d.ts +7 -1
  189. package/dist/src/modules/workspace/reconcile.d.ts.map +1 -1
  190. package/dist/src/modules/workspace/reconcile.js +156 -50
  191. package/dist/src/modules/workspace/reconcile.js.map +1 -1
  192. package/dist/src/modules/workspace/result-text.d.ts +1 -0
  193. package/dist/src/modules/workspace/result-text.d.ts.map +1 -1
  194. package/dist/src/modules/workspace/result-text.js.map +1 -1
  195. package/dist/src/modules/workspace/sync.d.ts +9 -0
  196. package/dist/src/modules/workspace/sync.d.ts.map +1 -1
  197. package/dist/src/modules/workspace/sync.js +14 -0
  198. package/dist/src/modules/workspace/sync.js.map +1 -1
  199. package/dist/src/modules/workspace/types.d.ts +96 -43
  200. package/dist/src/modules/workspace/types.d.ts.map +1 -1
  201. package/dist/src/modules/workspace/types.js.map +1 -1
  202. package/dist/src/modules/workspace/watcher.d.ts.map +1 -1
  203. package/dist/src/modules/workspace/watcher.js +8 -3
  204. package/dist/src/modules/workspace/watcher.js.map +1 -1
  205. package/dist/src/notice-tags.d.ts +79 -0
  206. package/dist/src/notice-tags.d.ts.map +1 -0
  207. package/dist/src/notice-tags.js +83 -0
  208. package/dist/src/notice-tags.js.map +1 -0
  209. package/dist/src/prose-drafts.d.ts +4 -3
  210. package/dist/src/prose-drafts.d.ts.map +1 -1
  211. package/dist/src/prose-drafts.js +3 -2
  212. package/dist/src/prose-drafts.js.map +1 -1
  213. package/dist/src/reasoning-loss-notice.d.ts +23 -0
  214. package/dist/src/reasoning-loss-notice.d.ts.map +1 -0
  215. package/dist/src/reasoning-loss-notice.js +52 -0
  216. package/dist/src/reasoning-loss-notice.js.map +1 -0
  217. package/dist/src/reasoning-loss.d.ts +24 -0
  218. package/dist/src/reasoning-loss.d.ts.map +1 -0
  219. package/dist/src/reasoning-loss.js +102 -0
  220. package/dist/src/reasoning-loss.js.map +1 -0
  221. package/dist/src/send-tools.d.ts +3 -2
  222. package/dist/src/send-tools.d.ts.map +1 -1
  223. package/dist/src/send-tools.js +3 -2
  224. package/dist/src/send-tools.js.map +1 -1
  225. package/dist/src/sent-rows.js +1 -1
  226. package/dist/src/silent-heartbeat.d.ts +1 -53
  227. package/dist/src/silent-heartbeat.d.ts.map +1 -1
  228. package/dist/src/silent-heartbeat.js +56 -3
  229. package/dist/src/silent-heartbeat.js.map +1 -1
  230. package/dist/src/supplied-text.d.ts +35 -0
  231. package/dist/src/supplied-text.d.ts.map +1 -0
  232. package/dist/src/supplied-text.js +141 -0
  233. package/dist/src/supplied-text.js.map +1 -0
  234. package/dist/src/thinking-drops.d.ts +4 -11
  235. package/dist/src/thinking-drops.d.ts.map +1 -1
  236. package/dist/src/thinking-drops.js +7 -14
  237. package/dist/src/thinking-drops.js.map +1 -1
  238. package/dist/src/tool-args.d.ts +12 -0
  239. package/dist/src/tool-args.d.ts.map +1 -1
  240. package/dist/src/tool-args.js +39 -4
  241. package/dist/src/tool-args.js.map +1 -1
  242. package/dist/src/tool-image-ledger.d.ts.map +1 -1
  243. package/dist/src/tool-image-ledger.js +2 -1
  244. package/dist/src/tool-image-ledger.js.map +1 -1
  245. package/dist/src/tool-presentation.d.ts.map +1 -1
  246. package/dist/src/tool-presentation.js +5 -4
  247. package/dist/src/tool-presentation.js.map +1 -1
  248. package/dist/src/tool-result-guard.d.ts +8 -4
  249. package/dist/src/tool-result-guard.d.ts.map +1 -1
  250. package/dist/src/tool-result-guard.js +23 -11
  251. package/dist/src/tool-result-guard.js.map +1 -1
  252. package/dist/src/tune-out/coordinator.d.ts +3 -2
  253. package/dist/src/tune-out/coordinator.d.ts.map +1 -1
  254. package/dist/src/tune-out/coordinator.js +24 -26
  255. package/dist/src/tune-out/coordinator.js.map +1 -1
  256. package/dist/src/tune-out/tools.d.ts +4 -1
  257. package/dist/src/tune-out/tools.d.ts.map +1 -1
  258. package/dist/src/types/agent.d.ts +63 -18
  259. package/dist/src/types/agent.d.ts.map +1 -1
  260. package/dist/src/types/events.d.ts +18 -8
  261. package/dist/src/types/events.d.ts.map +1 -1
  262. package/dist/src/types/framework.d.ts +58 -0
  263. package/dist/src/types/framework.d.ts.map +1 -1
  264. package/dist/src/types/module.d.ts +27 -13
  265. package/dist/src/types/module.d.ts.map +1 -1
  266. package/dist/src/types/trace.d.ts +34 -1
  267. package/dist/src/types/trace.d.ts.map +1 -1
  268. package/package.json +3 -3
  269. package/src/agent.ts +76 -12
  270. package/src/api/mcp-server-core.ts +3 -14
  271. package/src/api/server.ts +11 -5
  272. package/src/auto-continue.ts +12 -5
  273. package/src/code-execution/isolate/runner.ts +7 -5
  274. package/src/code-execution/isolate/scripts.ts +3 -2
  275. package/src/cut-off-round.ts +98 -0
  276. package/src/framework.ts +3772 -1138
  277. package/src/gate/event-gate.ts +705 -60
  278. package/src/gate/index.ts +9 -1
  279. package/src/gate/reply-judge.ts +512 -0
  280. package/src/gate/types.ts +176 -3
  281. package/src/heartbeat/heartbeat.ts +843 -0
  282. package/src/heartbeat/reminder-time.ts +107 -0
  283. package/src/held-writes.ts +3 -3
  284. package/src/host-presentation.ts +605 -0
  285. package/src/index.ts +5 -1
  286. package/src/line-reader.ts +58 -0
  287. package/src/mcpl/capability-mask.ts +3 -2
  288. package/src/mcpl/channel-registry.ts +139 -53
  289. package/src/mcpl/conversation-router.ts +2 -1
  290. package/src/mcpl/convert-block.ts +17 -4
  291. package/src/mcpl/hook-orchestrator.ts +4 -3
  292. package/src/mcpl/inbound-source.ts +45 -70
  293. package/src/mcpl/modern-connection.ts +11 -7
  294. package/src/mcpl/protocol-family.ts +24 -3
  295. package/src/mcpl/push-handler.ts +2 -2
  296. package/src/mcpl/references.ts +31 -23
  297. package/src/mcpl/server-connection.ts +76 -34
  298. package/src/mcpl/skip-reply-wake.ts +35 -0
  299. package/src/mcpl/tags.ts +13 -2
  300. package/src/mcpl/tool-presence.ts +149 -82
  301. package/src/mcpl/tool-signature.ts +64 -32
  302. package/src/mcpl/toolset-host.ts +212 -110
  303. package/src/mcpl/toolsets-module.ts +277 -91
  304. package/src/mcpl/transport.ts +18 -14
  305. package/src/mcpl/types.ts +32 -13
  306. package/src/module-registry.ts +14 -9
  307. package/src/modules/api/index.ts +4 -2
  308. package/src/modules/discord/index.ts +37 -25
  309. package/src/modules/history/index.ts +30 -18
  310. package/src/modules/sender-name.ts +9 -0
  311. package/src/modules/workspace/answers.ts +151 -0
  312. package/src/modules/workspace/branch-intent.ts +10 -5
  313. package/src/modules/workspace/direct-write.ts +59 -23
  314. package/src/modules/workspace/disk-agreement.ts +52 -21
  315. package/src/modules/workspace/edit-text.ts +7 -5
  316. package/src/modules/workspace/effects.ts +69 -50
  317. package/src/modules/workspace/index.ts +966 -556
  318. package/src/modules/workspace/observe.ts +497 -242
  319. package/src/modules/workspace/read-page.ts +7 -1
  320. package/src/modules/workspace/reconcile.ts +184 -49
  321. package/src/modules/workspace/result-text.ts +2 -0
  322. package/src/modules/workspace/sync.ts +16 -0
  323. package/src/modules/workspace/types.ts +96 -43
  324. package/src/modules/workspace/watcher.ts +8 -3
  325. package/src/notice-tags.ts +84 -0
  326. package/src/prose-drafts.ts +4 -3
  327. package/src/reasoning-loss-notice.ts +64 -0
  328. package/src/reasoning-loss.ts +120 -0
  329. package/src/send-tools.ts +3 -2
  330. package/src/sent-rows.ts +1 -1
  331. package/src/silent-heartbeat.ts +4 -3
  332. package/src/supplied-text.ts +154 -0
  333. package/src/thinking-drops.ts +10 -16
  334. package/src/tool-args.ts +38 -4
  335. package/src/tool-image-ledger.ts +2 -1
  336. package/src/tool-presentation.ts +5 -4
  337. package/src/tool-result-guard.ts +26 -11
  338. package/src/tune-out/coordinator.ts +25 -27
  339. package/src/tune-out/tools.ts +4 -1
  340. package/src/types/agent.ts +63 -18
  341. package/src/types/events.ts +18 -8
  342. package/src/types/framework.ts +59 -0
  343. package/src/types/module.ts +28 -13
  344. package/src/types/trace.ts +36 -1
@@ -1,15 +1,16 @@
1
1
  /**
2
2
  * How a dynamic tool reads to a model when it reaches the conversation
3
3
  * instead of the tool list (MCPL RFC-014 §8.3): a compact signature, its
4
- * first sentence the first time a definition is shown, the whole definition
5
- * on request. Also the host's own argument check against a tool's current
6
- * definition (RFC-014 §6.1: "the host checks arguments for that instance
7
- * against it").
4
+ * first sentence the first time a definition is shown, and on request its
5
+ * description, input schema and class. Also the host's own argument check
6
+ * against a tool's current definition (RFC-014 §6.1: "the host checks
7
+ * arguments for that instance against it").
8
8
  *
9
9
  * Ported from mcpl-cc-bridge's tool-render.ts and schema-check.ts, the
10
10
  * reference host of RFC-014. Dependency-free.
11
11
  */
12
12
  import { createHash } from 'node:crypto';
13
+ import { nameToTypeBack, quotedValue, suppliedValue } from '../supplied-text.js';
13
14
 
14
15
  export type JsonSchema = Record<string, unknown>;
15
16
 
@@ -24,11 +25,25 @@ export interface HintedTool {
24
25
 
25
26
  const isObj = (v: unknown): v is Record<string, unknown> => typeof v === 'object' && v !== null && !Array.isArray(v);
26
27
 
28
+ /** How deep a server's value may nest and still be written out, the same on every runtime. */
29
+ const DEEPEST = 64;
30
+
31
+ function nestsWithin(value: unknown, depth = 0): boolean {
32
+ if (value === null || typeof value !== 'object') return true;
33
+ return depth <= DEEPEST && Object.values(value).every((v) => nestsWithin(v, depth + 1));
34
+ }
35
+
36
+ /** A schema's literal value (an enum's, a const or a default) as JSON, or … where it's nested too deeply to write. */
37
+ function literal(value: unknown): string {
38
+ return nestsWithin(value) ? quotedValue(value) : '…';
39
+ }
40
+
27
41
  function typeSig(schema: JsonSchema | undefined, depth = 0): string {
28
42
  if (!schema || typeof schema !== 'object') return 'any';
43
+ if (depth > 8) return '…';
29
44
  if (Array.isArray(schema.enum)) {
30
45
  // The enum is often the menu (a decision's options): all of it unless it is long.
31
- const vals = (schema.enum as unknown[]).map((v) => JSON.stringify(v));
46
+ const vals = (schema.enum as unknown[]).map(literal);
32
47
  if (vals.length <= 8 || vals.join('|').length <= 400) return vals.join('|');
33
48
  let shown = 0;
34
49
  let len = 0;
@@ -38,10 +53,12 @@ function typeSig(schema: JsonSchema | undefined, depth = 0): string {
38
53
  }
39
54
  return `${vals.slice(0, Math.max(shown, 4)).join('|')}|…(${vals.length} in all)`;
40
55
  }
41
- if (schema.const !== undefined) return JSON.stringify(schema.const);
56
+ if (schema.const !== undefined) return literal(schema.const);
42
57
  const alts = (schema.oneOf ?? schema.anyOf) as JsonSchema[] | undefined;
43
58
  if (Array.isArray(alts)) return alts.map((s) => typeSig(s, depth + 1)).join(' | ');
44
- const t = Array.isArray(schema.type) ? (schema.type as string[]).join('|') : (schema.type as string | undefined);
59
+ // Only text names a type: entries that aren't text are left out, and a type with none reads as no type.
60
+ const types = (Array.isArray(schema.type) ? schema.type : [schema.type]).filter((x): x is string => typeof x === 'string');
61
+ const t = types.length ? types.join('|') : undefined;
45
62
  switch (t) {
46
63
  case 'integer':
47
64
  case 'number': {
@@ -64,12 +81,12 @@ function typeSig(schema: JsonSchema | undefined, depth = 0): string {
64
81
  if (!isObj(props) || Object.keys(props).length === 0) return 'object';
65
82
  if (depth >= 3) return '{…}';
66
83
  const req = new Set(Array.isArray(schema.required) ? (schema.required as string[]) : []);
67
- return `{${Object.entries(props).map(([k, v]) => `${k}${req.has(k) ? '' : '?'}: ${typeSig(v, depth + 1)}`).join(', ')}}`;
84
+ return `{${Object.entries(props).map(([k, v]) => `${nameToTypeBack(k)}${req.has(k) ? '' : '?'}: ${typeSig(v, depth + 1)}`).join(', ')}}`;
68
85
  }
69
86
  case undefined:
70
87
  return 'any';
71
88
  default:
72
- return t;
89
+ return suppliedValue(t);
73
90
  }
74
91
  }
75
92
 
@@ -81,10 +98,10 @@ export function signature(tool: HintedTool): string {
81
98
  const props = (isObj(s.properties) ? s.properties : {}) as Record<string, JsonSchema>;
82
99
  const req = new Set(Array.isArray(s.required) ? (s.required as string[]) : []);
83
100
  const params = Object.entries(props).map(([k, v]) => {
84
- const def = isObj(v) && v.default !== undefined ? ` =${JSON.stringify(v.default)}` : '';
85
- return `${k}${req.has(k) ? '' : '?'}: ${typeSig(v, 1)}${def}`;
101
+ const def = isObj(v) && v.default !== undefined ? ` =${literal(v.default)}` : '';
102
+ return `${nameToTypeBack(k)}${req.has(k) ? '' : '?'}: ${typeSig(v, 1)}${def}`;
86
103
  });
87
- return `${tool.name}(${params.join(', ')})`;
104
+ return `${nameToTypeBack(String(tool.name))}(${params.join(', ')})`;
88
105
  }
89
106
 
90
107
  /** An options schema as `{size?: 9|13|19 =9, …}` (a toolset's options). */
@@ -94,22 +111,23 @@ export function objectSignature(schema: unknown): string {
94
111
  }
95
112
 
96
113
  /** First sentence of a description, bounded. */
97
- export function firstSentence(text: string | undefined, max = 140): string {
98
- const t = (text ?? '').trim().replace(/\s+/g, ' ');
114
+ export function firstSentence(text: unknown, max = 140): string {
115
+ const t = (typeof text === 'string' ? text : '').trim().replace(/\s+/g, ' ');
99
116
  // A sentence ends at . ! ? followed by a capital, a bracket, or the end, so "e.g. \"D4\"" does not end it.
100
117
  const m = t.match(/^(.+?[.!?])(?=\s+[A-Z([]|$)/);
101
- const s = m ? m[1]! : t;
102
- return s.length > max ? s.slice(0, max - 1) + '…' : s;
118
+ const s = [...(m ? m[1]! : t)];
119
+ return s.length > max ? s.slice(0, max - 1).join('') + '…' : s.join('');
103
120
  }
104
121
 
105
- function canonicalJson(value: unknown): string {
122
+ function canonicalJson(value: unknown, depth = 0): string {
106
123
  if (value === null || typeof value !== 'object') return JSON.stringify(value) ?? 'null';
107
- if (Array.isArray(value)) return `[${value.map(canonicalJson).join(',')}]`;
124
+ if (depth > DEEPEST) return '"…"';
125
+ if (Array.isArray(value)) return `[${value.map((v) => canonicalJson(v, depth + 1)).join(',')}]`;
108
126
  const obj = value as Record<string, unknown>;
109
127
  return `{${Object.keys(obj)
110
128
  .sort()
111
129
  .filter((k) => obj[k] !== undefined)
112
- .map((k) => `${JSON.stringify(k)}:${canonicalJson(obj[k])}`)
130
+ .map((k) => `${JSON.stringify(k)}:${canonicalJson(obj[k], depth + 1)}`)
113
131
  .join(',')}}`;
114
132
  }
115
133
 
@@ -121,31 +139,45 @@ export function toolDigest(tool: HintedTool): string {
121
139
  .slice(0, 22);
122
140
  }
123
141
 
142
+ /** The definitions a model has been shown, by digest: has and add are all rendering needs. */
143
+ export type Shown = { has(digest: string): boolean; add(digest: string): void };
144
+
124
145
  /**
125
146
  * Tool lines as the model reads them. A definition the model has been shown
126
147
  * gets its signature only; a new or changed one also gets its first
127
148
  * sentence. `shown` is updated.
128
149
  */
129
- export function renderToolLines(tools: HintedTool[], shown: Set<string>, opts: { describeAll?: boolean; indent?: string } = {}): string[] {
150
+ export function renderToolLines(tools: HintedTool[], shown: Shown, opts: { describeAll?: boolean; indent?: string } = {}): string[] {
130
151
  const indent = opts.indent ?? ' ';
131
152
  return tools.map((t) => {
132
153
  const d = toolDigest(t);
133
154
  const describe = opts.describeAll || !shown.has(d);
134
155
  shown.add(d);
135
156
  const sentence = describe ? firstSentence(t.description) : '';
136
- return `${indent}${signature(t)}${sentence ? ` — ${sentence}` : ''}`;
157
+ return `${indent}${signature(t)}${sentence ? ` — ${suppliedValue(sentence)}` : ''}`;
137
158
  });
138
159
  }
139
160
 
140
- /** The whole definition, for `look` naming a tool. */
161
+ /** A server's value as JSON, or a note where it's nested too deeply, or too long, to show. */
162
+ export function jsonText(value: unknown, space?: number): string {
163
+ if (!nestsWithin(value)) return '(nested too deeply to show)';
164
+ try {
165
+ return JSON.stringify(value) === undefined ? '' : quotedValue(value, space);
166
+ } catch {
167
+ return '(too long to show)';
168
+ }
169
+ }
170
+
171
+ /** A tool's signature, description, class and input schema, for `look` naming a tool. */
141
172
  export function renderToolDefinition(tool: HintedTool): string {
142
173
  const cls = tool._meta?.['mcpl/class'];
174
+ const classes = Array.isArray(cls) ? cls.filter((c): c is string => typeof c === 'string') : [];
143
175
  return [
144
176
  signature(tool),
145
- tool.description ?? '',
146
- ...(Array.isArray(cls) ? [`class: ${cls.join(', ')}`] : []),
177
+ typeof tool.description === 'string' ? suppliedValue(tool.description) : '',
178
+ ...(classes.length ? [`class: ${classes.map(suppliedValue).join(', ')}`] : []),
147
179
  'inputSchema:',
148
- JSON.stringify(tool.inputSchema ?? {}, null, 2),
180
+ jsonText(tool.inputSchema ?? {}, 2),
149
181
  ]
150
182
  .filter((l) => l !== '')
151
183
  .join('\n');
@@ -221,15 +253,15 @@ function check(schema: unknown, value: unknown, at: string, depth: number, budge
221
253
  const s = schema;
222
254
  if (s.type !== undefined) {
223
255
  const types = Array.isArray(s.type) ? (s.type as string[]) : [s.type as string];
224
- if (!types.some((t) => typeOk(t, value))) return `${at}: must be ${types.join(' or ')}`;
256
+ if (!types.some((t) => typeOk(t, value))) return `${at}: must be ${types.map(suppliedValue).join(' or ')}`;
225
257
  }
226
258
  if (Array.isArray(s.enum) || s.const !== undefined) {
227
259
  const own = canonicalJson(value);
228
260
  if (Array.isArray(s.enum)) {
229
261
  spend(budget, s.enum.length);
230
- if (!s.enum.some((e) => canonicalJson(e) === own)) return `${at}: must be one of ${s.enum.map((e) => JSON.stringify(e)).join('|')}`;
262
+ if (!s.enum.some((e) => canonicalJson(e) === own)) return `${at}: must be one of ${s.enum.map((e) => quotedValue(e)).join('|')}`;
231
263
  }
232
- if (s.const !== undefined && canonicalJson(s.const) !== own) return `${at}: must be ${JSON.stringify(s.const)}`;
264
+ if (s.const !== undefined && canonicalJson(s.const) !== own) return `${at}: must be ${quotedValue(s.const)}`;
233
265
  }
234
266
  if (typeof value === 'string') {
235
267
  const n = [...value].length;
@@ -255,16 +287,16 @@ function check(schema: unknown, value: unknown, at: string, depth: number, budge
255
287
  if (isObj(value)) {
256
288
  const props = isObj(s.properties) ? s.properties : {};
257
289
  for (const r of Array.isArray(s.required) ? (s.required as unknown[]) : []) {
258
- if (typeof r === 'string' && !Object.hasOwn(value, r)) return `${at}.${r}: required`;
290
+ if (typeof r === 'string' && !Object.hasOwn(value, r)) return `${at}.${nameToTypeBack(r)}: required`;
259
291
  }
260
292
  for (const [k, v] of Object.entries(value)) {
261
293
  if (Object.hasOwn(props, k)) {
262
- const e = check(props[k], v, `${at}.${k}`, depth + 1, budget);
294
+ const e = check(props[k], v, `${at}.${nameToTypeBack(k)}`, depth + 1, budget);
263
295
  if (e) return e;
264
296
  } else if (s.additionalProperties === false) {
265
- return `${at}.${k}: not an argument of this tool`;
297
+ return `${at}.${nameToTypeBack(k)}: not an argument of this tool`;
266
298
  } else if (isObj(s.additionalProperties)) {
267
- const e = check(s.additionalProperties, v, `${at}.${k}`, depth + 1, budget);
299
+ const e = check(s.additionalProperties, v, `${at}.${nameToTypeBack(k)}`, depth + 1, budget);
268
300
  if (e) return e;
269
301
  }
270
302
  }