@animalabs/agent-framework 0.22.2 → 0.22.4

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 (940) 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 +143 -41
  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/thinking-token-stamp.d.ts +12 -0
  206. package/dist/src/thinking-token-stamp.d.ts.map +1 -1
  207. package/dist/src/thinking-token-stamp.js +34 -3
  208. package/dist/src/thinking-token-stamp.js.map +1 -1
  209. package/dist/src/tool-image-ledger.d.ts +87 -19
  210. package/dist/src/tool-image-ledger.d.ts.map +1 -1
  211. package/dist/src/tool-image-ledger.js +135 -32
  212. package/dist/src/tool-image-ledger.js.map +1 -1
  213. package/dist/src/tool-presentation.d.ts +9 -0
  214. package/dist/src/tool-presentation.d.ts.map +1 -1
  215. package/dist/src/tool-presentation.js +257 -60
  216. package/dist/src/tool-presentation.js.map +1 -1
  217. package/dist/src/tool-result-guard.d.ts.map +1 -1
  218. package/dist/src/tool-result-guard.js +7 -10
  219. package/dist/src/tool-result-guard.js.map +1 -1
  220. package/dist/src/tool-result-history.d.ts +32 -3
  221. package/dist/src/tool-result-history.d.ts.map +1 -1
  222. package/dist/src/tool-result-history.js +106 -19
  223. package/dist/src/tool-result-history.js.map +1 -1
  224. package/dist/src/tune-out/coordinator.d.ts +25 -1
  225. package/dist/src/tune-out/coordinator.d.ts.map +1 -1
  226. package/dist/src/tune-out/coordinator.js +260 -65
  227. package/dist/src/tune-out/coordinator.js.map +1 -1
  228. package/dist/src/types/agent.d.ts +17 -5
  229. package/dist/src/types/agent.d.ts.map +1 -1
  230. package/dist/src/types/events.d.ts +17 -0
  231. package/dist/src/types/events.d.ts.map +1 -1
  232. package/dist/src/types/framework.d.ts +21 -5
  233. package/dist/src/types/framework.d.ts.map +1 -1
  234. package/dist/src/types/inference-log.d.ts +1 -1
  235. package/dist/src/types/inference-log.d.ts.map +1 -1
  236. package/dist/src/types/module.d.ts +23 -4
  237. package/dist/src/types/module.d.ts.map +1 -1
  238. package/dist/src/types/trace.d.ts +95 -6
  239. package/dist/src/types/trace.d.ts.map +1 -1
  240. package/dist/src/usage/usage-tracker.d.ts +5 -0
  241. package/dist/src/usage/usage-tracker.d.ts.map +1 -1
  242. package/dist/src/usage/usage-tracker.js +35 -8
  243. package/dist/src/usage/usage-tracker.js.map +1 -1
  244. package/package.json +6 -4
  245. package/src/agent.ts +169 -41
  246. package/src/api/mcp-server-core.ts +1 -1
  247. package/src/api/server.ts +4 -1
  248. package/src/api/types.ts +1 -1
  249. package/src/branch-names.ts +19 -0
  250. package/src/closest-names.ts +94 -0
  251. package/src/code-execution/py-runner.ts +200 -76
  252. package/src/code-execution/runtime-py.ts +49 -3
  253. package/src/code-execution/tool-definition.ts +28 -4
  254. package/src/config-checks.ts +48 -0
  255. package/src/deadline-timer.ts +44 -0
  256. package/src/error-message.ts +48 -0
  257. package/src/framework.ts +5352 -1388
  258. package/src/gate/event-gate.ts +28 -3
  259. package/src/index.ts +11 -2
  260. package/src/mcpl/channel-registry.ts +517 -286
  261. package/src/mcpl/checkpoint-manager.ts +104 -29
  262. package/src/mcpl/conversation-router.ts +28 -8
  263. package/src/mcpl/convert-block.ts +97 -0
  264. package/src/mcpl/errors.ts +28 -0
  265. package/src/mcpl/hook-orchestrator.ts +84 -77
  266. package/src/mcpl/inbound-source.ts +156 -0
  267. package/src/mcpl/index.ts +10 -1
  268. package/src/mcpl/inference-router.ts +174 -99
  269. package/src/mcpl/push-coalescer.ts +60 -24
  270. package/src/mcpl/push-handler.ts +20 -90
  271. package/src/mcpl/reference-fetcher.ts +71 -26
  272. package/src/mcpl/references.ts +81 -22
  273. package/src/mcpl/server-connection.ts +427 -132
  274. package/src/mcpl/server-registry.ts +15 -4
  275. package/src/mcpl/skip-reply-wake.ts +73 -0
  276. package/src/mcpl/transport.ts +120 -18
  277. package/src/mcpl/types.ts +14 -3
  278. package/src/mcpl/visible-content.ts +27 -0
  279. package/src/module-registry.ts +58 -23
  280. package/src/modules/api/index.ts +1 -1
  281. package/src/modules/discord/discord-js-client.ts +26 -10
  282. package/src/modules/discord/index.ts +391 -158
  283. package/src/modules/discord/types.ts +15 -2
  284. package/src/modules/health/index.ts +2 -1
  285. package/src/modules/history/index.ts +410 -120
  286. package/src/modules/history/semantic.ts +189 -32
  287. package/src/modules/unknown-tool.ts +16 -0
  288. package/src/modules/workspace/disk-agreement.ts +51 -3
  289. package/src/modules/workspace/effects.ts +279 -35
  290. package/src/modules/workspace/index.ts +810 -260
  291. package/src/modules/workspace/observe.ts +194 -20
  292. package/src/modules/workspace/reconcile.ts +619 -64
  293. package/src/modules/workspace/types.ts +18 -4
  294. package/src/modules/workspace/watcher.ts +27 -4
  295. package/src/prose-drafts.ts +481 -0
  296. package/src/prose-segments.ts +51 -8
  297. package/src/recovery/offline-branch.ts +4 -1
  298. package/src/safe-slice.ts +9 -1
  299. package/src/thinking-token-stamp.ts +34 -3
  300. package/src/tool-image-ledger.ts +153 -34
  301. package/src/tool-presentation.ts +224 -40
  302. package/src/tool-result-guard.ts +7 -8
  303. package/src/tool-result-history.ts +124 -20
  304. package/src/tune-out/coordinator.ts +259 -65
  305. package/src/types/agent.ts +17 -7
  306. package/src/types/events.ts +17 -0
  307. package/src/types/framework.ts +21 -5
  308. package/src/types/inference-log.ts +1 -1
  309. package/src/types/module.ts +24 -4
  310. package/src/types/trace.ts +101 -6
  311. package/src/usage/usage-tracker.ts +32 -8
  312. package/dist/test/activation-request-sanitize.test.d.ts +0 -2
  313. package/dist/test/activation-request-sanitize.test.d.ts.map +0 -1
  314. package/dist/test/activation-request-sanitize.test.js +0 -89
  315. package/dist/test/activation-request-sanitize.test.js.map +0 -1
  316. package/dist/test/agent-cache-ttl.test.d.ts +0 -2
  317. package/dist/test/agent-cache-ttl.test.d.ts.map +0 -1
  318. package/dist/test/agent-cache-ttl.test.js +0 -41
  319. package/dist/test/agent-cache-ttl.test.js.map +0 -1
  320. package/dist/test/agent-runtime-settings.test.d.ts +0 -2
  321. package/dist/test/agent-runtime-settings.test.d.ts.map +0 -1
  322. package/dist/test/agent-runtime-settings.test.js +0 -1598
  323. package/dist/test/agent-runtime-settings.test.js.map +0 -1
  324. package/dist/test/api-admin-gate.test.d.ts +0 -2
  325. package/dist/test/api-admin-gate.test.d.ts.map +0 -1
  326. package/dist/test/api-admin-gate.test.js +0 -116
  327. package/dist/test/api-admin-gate.test.js.map +0 -1
  328. package/dist/test/assistant-persist-refusal.test.d.ts +0 -2
  329. package/dist/test/assistant-persist-refusal.test.d.ts.map +0 -1
  330. package/dist/test/assistant-persist-refusal.test.js +0 -63
  331. package/dist/test/assistant-persist-refusal.test.js.map +0 -1
  332. package/dist/test/batched-wake-locus.test.d.ts +0 -2
  333. package/dist/test/batched-wake-locus.test.d.ts.map +0 -1
  334. package/dist/test/batched-wake-locus.test.js +0 -166
  335. package/dist/test/batched-wake-locus.test.js.map +0 -1
  336. package/dist/test/busy-agent-scheduler.test.d.ts +0 -2
  337. package/dist/test/busy-agent-scheduler.test.d.ts.map +0 -1
  338. package/dist/test/busy-agent-scheduler.test.js +0 -92
  339. package/dist/test/busy-agent-scheduler.test.js.map +0 -1
  340. package/dist/test/channel-incoming-targeting.test.d.ts +0 -2
  341. package/dist/test/channel-incoming-targeting.test.d.ts.map +0 -1
  342. package/dist/test/channel-incoming-targeting.test.js +0 -81
  343. package/dist/test/channel-incoming-targeting.test.js.map +0 -1
  344. package/dist/test/channel-label-history.test.d.ts +0 -2
  345. package/dist/test/channel-label-history.test.d.ts.map +0 -1
  346. package/dist/test/channel-label-history.test.js +0 -424
  347. package/dist/test/channel-label-history.test.js.map +0 -1
  348. package/dist/test/channel-lifecycle-provenance.test.d.ts +0 -2
  349. package/dist/test/channel-lifecycle-provenance.test.d.ts.map +0 -1
  350. package/dist/test/channel-lifecycle-provenance.test.js +0 -47
  351. package/dist/test/channel-lifecycle-provenance.test.js.map +0 -1
  352. package/dist/test/channel-registry-routing.test.d.ts +0 -2
  353. package/dist/test/channel-registry-routing.test.d.ts.map +0 -1
  354. package/dist/test/channel-registry-routing.test.js +0 -446
  355. package/dist/test/channel-registry-routing.test.js.map +0 -1
  356. package/dist/test/channel-registry-typing.test.d.ts +0 -2
  357. package/dist/test/channel-registry-typing.test.d.ts.map +0 -1
  358. package/dist/test/channel-registry-typing.test.js +0 -91
  359. package/dist/test/channel-registry-typing.test.js.map +0 -1
  360. package/dist/test/channels-changed-respond-first.test.d.ts +0 -2
  361. package/dist/test/channels-changed-respond-first.test.d.ts.map +0 -1
  362. package/dist/test/channels-changed-respond-first.test.js +0 -74
  363. package/dist/test/channels-changed-respond-first.test.js.map +0 -1
  364. package/dist/test/checkpoint-attribution.test.d.ts +0 -2
  365. package/dist/test/checkpoint-attribution.test.d.ts.map +0 -1
  366. package/dist/test/checkpoint-attribution.test.js +0 -200
  367. package/dist/test/checkpoint-attribution.test.js.map +0 -1
  368. package/dist/test/code-execution.test.d.ts +0 -11
  369. package/dist/test/code-execution.test.d.ts.map +0 -1
  370. package/dist/test/code-execution.test.js +0 -1272
  371. package/dist/test/code-execution.test.js.map +0 -1
  372. package/dist/test/component-defaults.test.d.ts +0 -2
  373. package/dist/test/component-defaults.test.d.ts.map +0 -1
  374. package/dist/test/component-defaults.test.js +0 -54
  375. package/dist/test/component-defaults.test.js.map +0 -1
  376. package/dist/test/conversation-fork-injection-scoping.test.d.ts +0 -2
  377. package/dist/test/conversation-fork-injection-scoping.test.d.ts.map +0 -1
  378. package/dist/test/conversation-fork-injection-scoping.test.js +0 -200
  379. package/dist/test/conversation-fork-injection-scoping.test.js.map +0 -1
  380. package/dist/test/conversation-router.test.d.ts +0 -2
  381. package/dist/test/conversation-router.test.d.ts.map +0 -1
  382. package/dist/test/conversation-router.test.js +0 -174
  383. package/dist/test/conversation-router.test.js.map +0 -1
  384. package/dist/test/conversation-routing.test.d.ts +0 -7
  385. package/dist/test/conversation-routing.test.d.ts.map +0 -1
  386. package/dist/test/conversation-routing.test.js +0 -621
  387. package/dist/test/conversation-routing.test.js.map +0 -1
  388. package/dist/test/deferred-wake-integrity.test.d.ts +0 -29
  389. package/dist/test/deferred-wake-integrity.test.d.ts.map +0 -1
  390. package/dist/test/deferred-wake-integrity.test.js +0 -320
  391. package/dist/test/deferred-wake-integrity.test.js.map +0 -1
  392. package/dist/test/discord-awareness-outbox.test.d.ts +0 -2
  393. package/dist/test/discord-awareness-outbox.test.d.ts.map +0 -1
  394. package/dist/test/discord-awareness-outbox.test.js +0 -371
  395. package/dist/test/discord-awareness-outbox.test.js.map +0 -1
  396. package/dist/test/discord-history-delete-window.test.d.ts +0 -2
  397. package/dist/test/discord-history-delete-window.test.d.ts.map +0 -1
  398. package/dist/test/discord-history-delete-window.test.js +0 -81
  399. package/dist/test/discord-history-delete-window.test.js.map +0 -1
  400. package/dist/test/discord-history-sync.test.d.ts +0 -2
  401. package/dist/test/discord-history-sync.test.d.ts.map +0 -1
  402. package/dist/test/discord-history-sync.test.js +0 -56
  403. package/dist/test/discord-history-sync.test.js.map +0 -1
  404. package/dist/test/discord-typing-keepalive.test.d.ts +0 -2
  405. package/dist/test/discord-typing-keepalive.test.d.ts.map +0 -1
  406. package/dist/test/discord-typing-keepalive.test.js +0 -77
  407. package/dist/test/discord-typing-keepalive.test.js.map +0 -1
  408. package/dist/test/ephemeral-settle.test.d.ts +0 -2
  409. package/dist/test/ephemeral-settle.test.d.ts.map +0 -1
  410. package/dist/test/ephemeral-settle.test.js +0 -354
  411. package/dist/test/ephemeral-settle.test.js.map +0 -1
  412. package/dist/test/event-gate-passthrough.test.d.ts +0 -15
  413. package/dist/test/event-gate-passthrough.test.d.ts.map +0 -1
  414. package/dist/test/event-gate-passthrough.test.js +0 -289
  415. package/dist/test/event-gate-passthrough.test.js.map +0 -1
  416. package/dist/test/event-gate-policy-mutation.test.d.ts +0 -2
  417. package/dist/test/event-gate-policy-mutation.test.d.ts.map +0 -1
  418. package/dist/test/event-gate-policy-mutation.test.js +0 -137
  419. package/dist/test/event-gate-policy-mutation.test.js.map +0 -1
  420. package/dist/test/event-gate-rate-limit.test.d.ts +0 -2
  421. package/dist/test/event-gate-rate-limit.test.d.ts.map +0 -1
  422. package/dist/test/event-gate-rate-limit.test.js +0 -627
  423. package/dist/test/event-gate-rate-limit.test.js.map +0 -1
  424. package/dist/test/event-gate-script.test.d.ts +0 -2
  425. package/dist/test/event-gate-script.test.d.ts.map +0 -1
  426. package/dist/test/event-gate-script.test.js +0 -95
  427. package/dist/test/event-gate-script.test.js.map +0 -1
  428. package/dist/test/event-gate-selfwake.test.d.ts +0 -15
  429. package/dist/test/event-gate-selfwake.test.d.ts.map +0 -1
  430. package/dist/test/event-gate-selfwake.test.js +0 -125
  431. package/dist/test/event-gate-selfwake.test.js.map +0 -1
  432. package/dist/test/event-gate-tags.test.d.ts +0 -2
  433. package/dist/test/event-gate-tags.test.d.ts.map +0 -1
  434. package/dist/test/event-gate-tags.test.js +0 -76
  435. package/dist/test/event-gate-tags.test.js.map +0 -1
  436. package/dist/test/event-gate.test.d.ts +0 -2
  437. package/dist/test/event-gate.test.d.ts.map +0 -1
  438. package/dist/test/event-gate.test.js +0 -919
  439. package/dist/test/event-gate.test.js.map +0 -1
  440. package/dist/test/explicit-prose-routing.test.d.ts +0 -11
  441. package/dist/test/explicit-prose-routing.test.d.ts.map +0 -1
  442. package/dist/test/explicit-prose-routing.test.js +0 -1715
  443. package/dist/test/explicit-prose-routing.test.js.map +0 -1
  444. package/dist/test/framework.test.d.ts +0 -5
  445. package/dist/test/framework.test.d.ts.map +0 -1
  446. package/dist/test/framework.test.js +0 -1048
  447. package/dist/test/framework.test.js.map +0 -1
  448. package/dist/test/gather-context-timeout.test.d.ts +0 -2
  449. package/dist/test/gather-context-timeout.test.d.ts.map +0 -1
  450. package/dist/test/gather-context-timeout.test.js +0 -120
  451. package/dist/test/gather-context-timeout.test.js.map +0 -1
  452. package/dist/test/health-snapshot.test.d.ts +0 -2
  453. package/dist/test/health-snapshot.test.d.ts.map +0 -1
  454. package/dist/test/health-snapshot.test.js +0 -74
  455. package/dist/test/health-snapshot.test.js.map +0 -1
  456. package/dist/test/helpers/coalescing-fixture.d.ts +0 -74
  457. package/dist/test/helpers/coalescing-fixture.d.ts.map +0 -1
  458. package/dist/test/helpers/coalescing-fixture.js +0 -152
  459. package/dist/test/helpers/coalescing-fixture.js.map +0 -1
  460. package/dist/test/helpers/coalescing-kill-child.d.ts +0 -2
  461. package/dist/test/helpers/coalescing-kill-child.d.ts.map +0 -1
  462. package/dist/test/helpers/coalescing-kill-child.js +0 -24
  463. package/dist/test/helpers/coalescing-kill-child.js.map +0 -1
  464. package/dist/test/helpers/mock-membrane.d.ts +0 -53
  465. package/dist/test/helpers/mock-membrane.d.ts.map +0 -1
  466. package/dist/test/helpers/mock-membrane.js +0 -168
  467. package/dist/test/helpers/mock-membrane.js.map +0 -1
  468. package/dist/test/helpers/pytc-stop-rows.d.ts +0 -11
  469. package/dist/test/helpers/pytc-stop-rows.d.ts.map +0 -1
  470. package/dist/test/helpers/pytc-stop-rows.js +0 -143
  471. package/dist/test/helpers/pytc-stop-rows.js.map +0 -1
  472. package/dist/test/helpers/quiesce-crash-child.d.ts +0 -2
  473. package/dist/test/helpers/quiesce-crash-child.d.ts.map +0 -1
  474. package/dist/test/helpers/quiesce-crash-child.js +0 -156
  475. package/dist/test/helpers/quiesce-crash-child.js.map +0 -1
  476. package/dist/test/hide-then-turn.test.d.ts +0 -2
  477. package/dist/test/hide-then-turn.test.d.ts.map +0 -1
  478. package/dist/test/hide-then-turn.test.js +0 -101
  479. package/dist/test/hide-then-turn.test.js.map +0 -1
  480. package/dist/test/history-module-overview.test.d.ts +0 -2
  481. package/dist/test/history-module-overview.test.d.ts.map +0 -1
  482. package/dist/test/history-module-overview.test.js +0 -711
  483. package/dist/test/history-module-overview.test.js.map +0 -1
  484. package/dist/test/history-module-realstore.test.d.ts +0 -2
  485. package/dist/test/history-module-realstore.test.d.ts.map +0 -1
  486. package/dist/test/history-module-realstore.test.js +0 -363
  487. package/dist/test/history-module-realstore.test.js.map +0 -1
  488. package/dist/test/history-module-semantic.test.d.ts +0 -2
  489. package/dist/test/history-module-semantic.test.d.ts.map +0 -1
  490. package/dist/test/history-module-semantic.test.js +0 -213
  491. package/dist/test/history-module-semantic.test.js.map +0 -1
  492. package/dist/test/history-module-ux.test.d.ts +0 -2
  493. package/dist/test/history-module-ux.test.d.ts.map +0 -1
  494. package/dist/test/history-module-ux.test.js +0 -304
  495. package/dist/test/history-module-ux.test.js.map +0 -1
  496. package/dist/test/history-module.test.d.ts +0 -2
  497. package/dist/test/history-module.test.d.ts.map +0 -1
  498. package/dist/test/history-module.test.js +0 -619
  499. package/dist/test/history-module.test.js.map +0 -1
  500. package/dist/test/history-semantic-review-findings.test.d.ts +0 -2
  501. package/dist/test/history-semantic-review-findings.test.d.ts.map +0 -1
  502. package/dist/test/history-semantic-review-findings.test.js +0 -338
  503. package/dist/test/history-semantic-review-findings.test.js.map +0 -1
  504. package/dist/test/history-semantic-sync-converges.test.d.ts +0 -2
  505. package/dist/test/history-semantic-sync-converges.test.d.ts.map +0 -1
  506. package/dist/test/history-semantic-sync-converges.test.js +0 -109
  507. package/dist/test/history-semantic-sync-converges.test.js.map +0 -1
  508. package/dist/test/host-quiesce.test.d.ts +0 -2
  509. package/dist/test/host-quiesce.test.d.ts.map +0 -1
  510. package/dist/test/host-quiesce.test.js +0 -988
  511. package/dist/test/host-quiesce.test.js.map +0 -1
  512. package/dist/test/inference-exhaustion-rewind.test.d.ts +0 -2
  513. package/dist/test/inference-exhaustion-rewind.test.d.ts.map +0 -1
  514. package/dist/test/inference-exhaustion-rewind.test.js +0 -387
  515. package/dist/test/inference-exhaustion-rewind.test.js.map +0 -1
  516. package/dist/test/inference-failure-bounds.test.d.ts +0 -2
  517. package/dist/test/inference-failure-bounds.test.d.ts.map +0 -1
  518. package/dist/test/inference-failure-bounds.test.js +0 -1202
  519. package/dist/test/inference-failure-bounds.test.js.map +0 -1
  520. package/dist/test/inference-failure-observability.test.d.ts +0 -2
  521. package/dist/test/inference-failure-observability.test.d.ts.map +0 -1
  522. package/dist/test/inference-failure-observability.test.js +0 -84
  523. package/dist/test/inference-failure-observability.test.js.map +0 -1
  524. package/dist/test/journal-tool.test.d.ts +0 -2
  525. package/dist/test/journal-tool.test.d.ts.map +0 -1
  526. package/dist/test/journal-tool.test.js +0 -33
  527. package/dist/test/journal-tool.test.js.map +0 -1
  528. package/dist/test/kv-unified-open-flight-retry.test.d.ts +0 -2
  529. package/dist/test/kv-unified-open-flight-retry.test.d.ts.map +0 -1
  530. package/dist/test/kv-unified-open-flight-retry.test.js +0 -189
  531. package/dist/test/kv-unified-open-flight-retry.test.js.map +0 -1
  532. package/dist/test/kv-unified-wiring.test.d.ts +0 -2
  533. package/dist/test/kv-unified-wiring.test.d.ts.map +0 -1
  534. package/dist/test/kv-unified-wiring.test.js +0 -95
  535. package/dist/test/kv-unified-wiring.test.js.map +0 -1
  536. package/dist/test/late-events-after-stop.test.d.ts +0 -2
  537. package/dist/test/late-events-after-stop.test.d.ts.map +0 -1
  538. package/dist/test/late-events-after-stop.test.js +0 -122
  539. package/dist/test/late-events-after-stop.test.js.map +0 -1
  540. package/dist/test/liveness-watchdog.test.d.ts +0 -2
  541. package/dist/test/liveness-watchdog.test.d.ts.map +0 -1
  542. package/dist/test/liveness-watchdog.test.js +0 -94
  543. package/dist/test/liveness-watchdog.test.js.map +0 -1
  544. package/dist/test/machine-close-provenance.test.d.ts +0 -2
  545. package/dist/test/machine-close-provenance.test.d.ts.map +0 -1
  546. package/dist/test/machine-close-provenance.test.js +0 -116
  547. package/dist/test/machine-close-provenance.test.js.map +0 -1
  548. package/dist/test/maintenance-timer.test.d.ts +0 -2
  549. package/dist/test/maintenance-timer.test.d.ts.map +0 -1
  550. package/dist/test/maintenance-timer.test.js +0 -1827
  551. package/dist/test/maintenance-timer.test.js.map +0 -1
  552. package/dist/test/mcp-server-bin.test.d.ts +0 -2
  553. package/dist/test/mcp-server-bin.test.d.ts.map +0 -1
  554. package/dist/test/mcp-server-bin.test.js +0 -142
  555. package/dist/test/mcp-server-bin.test.js.map +0 -1
  556. package/dist/test/mcpl-access-provider.test.d.ts +0 -2
  557. package/dist/test/mcpl-access-provider.test.d.ts.map +0 -1
  558. package/dist/test/mcpl-access-provider.test.js +0 -20
  559. package/dist/test/mcpl-access-provider.test.js.map +0 -1
  560. package/dist/test/mcpl-awareness-barrier.test.d.ts +0 -2
  561. package/dist/test/mcpl-awareness-barrier.test.d.ts.map +0 -1
  562. package/dist/test/mcpl-awareness-barrier.test.js +0 -769
  563. package/dist/test/mcpl-awareness-barrier.test.js.map +0 -1
  564. package/dist/test/mcpl-capability-grant.test.d.ts +0 -10
  565. package/dist/test/mcpl-capability-grant.test.d.ts.map +0 -1
  566. package/dist/test/mcpl-capability-grant.test.js +0 -111
  567. package/dist/test/mcpl-capability-grant.test.js.map +0 -1
  568. package/dist/test/mcpl-capability-scoping.test.d.ts +0 -2
  569. package/dist/test/mcpl-capability-scoping.test.d.ts.map +0 -1
  570. package/dist/test/mcpl-capability-scoping.test.js +0 -266
  571. package/dist/test/mcpl-capability-scoping.test.js.map +0 -1
  572. package/dist/test/mcpl-child-env.test.d.ts +0 -2
  573. package/dist/test/mcpl-child-env.test.d.ts.map +0 -1
  574. package/dist/test/mcpl-child-env.test.js +0 -158
  575. package/dist/test/mcpl-child-env.test.js.map +0 -1
  576. package/dist/test/mcpl-coalesced-content-parity.test.d.ts +0 -2
  577. package/dist/test/mcpl-coalesced-content-parity.test.d.ts.map +0 -1
  578. package/dist/test/mcpl-coalesced-content-parity.test.js +0 -532
  579. package/dist/test/mcpl-coalesced-content-parity.test.js.map +0 -1
  580. package/dist/test/mcpl-coalescing.test.d.ts +0 -2
  581. package/dist/test/mcpl-coalescing.test.d.ts.map +0 -1
  582. package/dist/test/mcpl-coalescing.test.js +0 -1125
  583. package/dist/test/mcpl-coalescing.test.js.map +0 -1
  584. package/dist/test/mcpl-config-diagnostics.test.d.ts +0 -2
  585. package/dist/test/mcpl-config-diagnostics.test.d.ts.map +0 -1
  586. package/dist/test/mcpl-config-diagnostics.test.js +0 -452
  587. package/dist/test/mcpl-config-diagnostics.test.js.map +0 -1
  588. package/dist/test/mcpl-empty-content.test.d.ts +0 -2
  589. package/dist/test/mcpl-empty-content.test.d.ts.map +0 -1
  590. package/dist/test/mcpl-empty-content.test.js +0 -368
  591. package/dist/test/mcpl-empty-content.test.js.map +0 -1
  592. package/dist/test/mcpl-gate-roundtrip.test.d.ts +0 -2
  593. package/dist/test/mcpl-gate-roundtrip.test.d.ts.map +0 -1
  594. package/dist/test/mcpl-gate-roundtrip.test.js +0 -285
  595. package/dist/test/mcpl-gate-roundtrip.test.js.map +0 -1
  596. package/dist/test/mcpl-list-status.test.d.ts +0 -2
  597. package/dist/test/mcpl-list-status.test.d.ts.map +0 -1
  598. package/dist/test/mcpl-list-status.test.js +0 -82
  599. package/dist/test/mcpl-list-status.test.js.map +0 -1
  600. package/dist/test/mcpl-manifest-changed.test.d.ts +0 -2
  601. package/dist/test/mcpl-manifest-changed.test.d.ts.map +0 -1
  602. package/dist/test/mcpl-manifest-changed.test.js +0 -178
  603. package/dist/test/mcpl-manifest-changed.test.js.map +0 -1
  604. package/dist/test/mcpl-push-convert.test.d.ts +0 -2
  605. package/dist/test/mcpl-push-convert.test.d.ts.map +0 -1
  606. package/dist/test/mcpl-push-convert.test.js +0 -42
  607. package/dist/test/mcpl-push-convert.test.js.map +0 -1
  608. package/dist/test/mcpl-reconnect-events.test.d.ts +0 -2
  609. package/dist/test/mcpl-reconnect-events.test.d.ts.map +0 -1
  610. package/dist/test/mcpl-reconnect-events.test.js +0 -144
  611. package/dist/test/mcpl-reconnect-events.test.js.map +0 -1
  612. package/dist/test/mcpl-reconnect-reregistration.test.d.ts +0 -2
  613. package/dist/test/mcpl-reconnect-reregistration.test.d.ts.map +0 -1
  614. package/dist/test/mcpl-reconnect-reregistration.test.js +0 -238
  615. package/dist/test/mcpl-reconnect-reregistration.test.js.map +0 -1
  616. package/dist/test/mcpl-reference-fetcher.test.d.ts +0 -2
  617. package/dist/test/mcpl-reference-fetcher.test.d.ts.map +0 -1
  618. package/dist/test/mcpl-reference-fetcher.test.js +0 -427
  619. package/dist/test/mcpl-reference-fetcher.test.js.map +0 -1
  620. package/dist/test/mcpl-reference-fields.test.d.ts +0 -2
  621. package/dist/test/mcpl-reference-fields.test.d.ts.map +0 -1
  622. package/dist/test/mcpl-reference-fields.test.js +0 -149
  623. package/dist/test/mcpl-reference-fields.test.js.map +0 -1
  624. package/dist/test/mcpl-rejection-log-lines.test.d.ts +0 -2
  625. package/dist/test/mcpl-rejection-log-lines.test.d.ts.map +0 -1
  626. package/dist/test/mcpl-rejection-log-lines.test.js +0 -349
  627. package/dist/test/mcpl-rejection-log-lines.test.js.map +0 -1
  628. package/dist/test/mcpl-request-timeout.test.d.ts +0 -2
  629. package/dist/test/mcpl-request-timeout.test.d.ts.map +0 -1
  630. package/dist/test/mcpl-request-timeout.test.js +0 -138
  631. package/dist/test/mcpl-request-timeout.test.js.map +0 -1
  632. package/dist/test/mcpl-runtime-lifecycle.test.d.ts +0 -7
  633. package/dist/test/mcpl-runtime-lifecycle.test.d.ts.map +0 -1
  634. package/dist/test/mcpl-runtime-lifecycle.test.js +0 -142
  635. package/dist/test/mcpl-runtime-lifecycle.test.js.map +0 -1
  636. package/dist/test/mcpl-stderr-tail.test.d.ts +0 -2
  637. package/dist/test/mcpl-stderr-tail.test.d.ts.map +0 -1
  638. package/dist/test/mcpl-stderr-tail.test.js +0 -210
  639. package/dist/test/mcpl-stderr-tail.test.js.map +0 -1
  640. package/dist/test/mcpl-tool-class-listing.test.d.ts +0 -2
  641. package/dist/test/mcpl-tool-class-listing.test.d.ts.map +0 -1
  642. package/dist/test/mcpl-tool-class-listing.test.js +0 -147
  643. package/dist/test/mcpl-tool-class-listing.test.js.map +0 -1
  644. package/dist/test/mcpl-tool-classes.test.d.ts +0 -7
  645. package/dist/test/mcpl-tool-classes.test.d.ts.map +0 -1
  646. package/dist/test/mcpl-tool-classes.test.js +0 -80
  647. package/dist/test/mcpl-tool-classes.test.js.map +0 -1
  648. package/dist/test/mcpl-tool-lifecycle-e2e.test.d.ts +0 -2
  649. package/dist/test/mcpl-tool-lifecycle-e2e.test.d.ts.map +0 -1
  650. package/dist/test/mcpl-tool-lifecycle-e2e.test.js +0 -237
  651. package/dist/test/mcpl-tool-lifecycle-e2e.test.js.map +0 -1
  652. package/dist/test/mcpl-tool-lifecycle-emitter.test.d.ts +0 -11
  653. package/dist/test/mcpl-tool-lifecycle-emitter.test.d.ts.map +0 -1
  654. package/dist/test/mcpl-tool-lifecycle-emitter.test.js +0 -412
  655. package/dist/test/mcpl-tool-lifecycle-emitter.test.js.map +0 -1
  656. package/dist/test/mcpl-tool-lifecycle-script.test.d.ts +0 -2
  657. package/dist/test/mcpl-tool-lifecycle-script.test.d.ts.map +0 -1
  658. package/dist/test/mcpl-tool-lifecycle-script.test.js +0 -288
  659. package/dist/test/mcpl-tool-lifecycle-script.test.js.map +0 -1
  660. package/dist/test/mcpl-tool-lifecycle.test.d.ts +0 -11
  661. package/dist/test/mcpl-tool-lifecycle.test.d.ts.map +0 -1
  662. package/dist/test/mcpl-tool-lifecycle.test.js +0 -270
  663. package/dist/test/mcpl-tool-lifecycle.test.js.map +0 -1
  664. package/dist/test/mcpl-transport-close.test.d.ts +0 -2
  665. package/dist/test/mcpl-transport-close.test.d.ts.map +0 -1
  666. package/dist/test/mcpl-transport-close.test.js +0 -373
  667. package/dist/test/mcpl-transport-close.test.js.map +0 -1
  668. package/dist/test/mcpl-transport-spawn.test.d.ts +0 -2
  669. package/dist/test/mcpl-transport-spawn.test.d.ts.map +0 -1
  670. package/dist/test/mcpl-transport-spawn.test.js +0 -58
  671. package/dist/test/mcpl-transport-spawn.test.js.map +0 -1
  672. package/dist/test/mcpl-ws-transport.test.d.ts +0 -2
  673. package/dist/test/mcpl-ws-transport.test.d.ts.map +0 -1
  674. package/dist/test/mcpl-ws-transport.test.js +0 -259
  675. package/dist/test/mcpl-ws-transport.test.js.map +0 -1
  676. package/dist/test/module-context-integration.test.d.ts +0 -18
  677. package/dist/test/module-context-integration.test.d.ts.map +0 -1
  678. package/dist/test/module-context-integration.test.js +0 -181
  679. package/dist/test/module-context-integration.test.js.map +0 -1
  680. package/dist/test/offline-recovery-branch.test.d.ts +0 -2
  681. package/dist/test/offline-recovery-branch.test.d.ts.map +0 -1
  682. package/dist/test/offline-recovery-branch.test.js +0 -570
  683. package/dist/test/offline-recovery-branch.test.js.map +0 -1
  684. package/dist/test/operator-surgery.test.d.ts +0 -2
  685. package/dist/test/operator-surgery.test.d.ts.map +0 -1
  686. package/dist/test/operator-surgery.test.js +0 -595
  687. package/dist/test/operator-surgery.test.js.map +0 -1
  688. package/dist/test/ops-alert.test.d.ts +0 -2
  689. package/dist/test/ops-alert.test.d.ts.map +0 -1
  690. package/dist/test/ops-alert.test.js +0 -153
  691. package/dist/test/ops-alert.test.js.map +0 -1
  692. package/dist/test/overbudget-drain-breaker.test.d.ts +0 -2
  693. package/dist/test/overbudget-drain-breaker.test.d.ts.map +0 -1
  694. package/dist/test/overbudget-drain-breaker.test.js +0 -198
  695. package/dist/test/overbudget-drain-breaker.test.js.map +0 -1
  696. package/dist/test/pack-installs-alone.test.d.ts +0 -2
  697. package/dist/test/pack-installs-alone.test.d.ts.map +0 -1
  698. package/dist/test/pack-installs-alone.test.js +0 -284
  699. package/dist/test/pack-installs-alone.test.js.map +0 -1
  700. package/dist/test/per-agent-delivery.test.d.ts +0 -2
  701. package/dist/test/per-agent-delivery.test.d.ts.map +0 -1
  702. package/dist/test/per-agent-delivery.test.js +0 -108
  703. package/dist/test/per-agent-delivery.test.js.map +0 -1
  704. package/dist/test/physical-window-restart.test.d.ts +0 -16
  705. package/dist/test/physical-window-restart.test.d.ts.map +0 -1
  706. package/dist/test/physical-window-restart.test.js +0 -487
  707. package/dist/test/physical-window-restart.test.js.map +0 -1
  708. package/dist/test/placed-reaction-baseline.test.d.ts +0 -2
  709. package/dist/test/placed-reaction-baseline.test.d.ts.map +0 -1
  710. package/dist/test/placed-reaction-baseline.test.js +0 -312
  711. package/dist/test/placed-reaction-baseline.test.js.map +0 -1
  712. package/dist/test/present-while-acting.test.d.ts +0 -19
  713. package/dist/test/present-while-acting.test.d.ts.map +0 -1
  714. package/dist/test/present-while-acting.test.js +0 -1649
  715. package/dist/test/present-while-acting.test.js.map +0 -1
  716. package/dist/test/prose-segments.test.d.ts +0 -2
  717. package/dist/test/prose-segments.test.d.ts.map +0 -1
  718. package/dist/test/prose-segments.test.js +0 -52
  719. package/dist/test/prose-segments.test.js.map +0 -1
  720. package/dist/test/prose-stream-router.test.d.ts +0 -2
  721. package/dist/test/prose-stream-router.test.d.ts.map +0 -1
  722. package/dist/test/prose-stream-router.test.js +0 -171
  723. package/dist/test/prose-stream-router.test.js.map +0 -1
  724. package/dist/test/provider-acceleration-cooldown.test.d.ts +0 -2
  725. package/dist/test/provider-acceleration-cooldown.test.d.ts.map +0 -1
  726. package/dist/test/provider-acceleration-cooldown.test.js +0 -435
  727. package/dist/test/provider-acceleration-cooldown.test.js.map +0 -1
  728. package/dist/test/provider-waits.test.d.ts +0 -2
  729. package/dist/test/provider-waits.test.d.ts.map +0 -1
  730. package/dist/test/provider-waits.test.js +0 -2259
  731. package/dist/test/provider-waits.test.js.map +0 -1
  732. package/dist/test/puppet-tool-call.test.d.ts +0 -2
  733. package/dist/test/puppet-tool-call.test.d.ts.map +0 -1
  734. package/dist/test/puppet-tool-call.test.js +0 -226
  735. package/dist/test/puppet-tool-call.test.js.map +0 -1
  736. package/dist/test/puppet-turn-reservation.test.d.ts +0 -2
  737. package/dist/test/puppet-turn-reservation.test.d.ts.map +0 -1
  738. package/dist/test/puppet-turn-reservation.test.js +0 -139
  739. package/dist/test/puppet-turn-reservation.test.js.map +0 -1
  740. package/dist/test/reaction-baseline-platform.test.d.ts +0 -2
  741. package/dist/test/reaction-baseline-platform.test.d.ts.map +0 -1
  742. package/dist/test/reaction-baseline-platform.test.js +0 -124
  743. package/dist/test/reaction-baseline-platform.test.js.map +0 -1
  744. package/dist/test/record-journal.test.d.ts +0 -6
  745. package/dist/test/record-journal.test.d.ts.map +0 -1
  746. package/dist/test/record-journal.test.js +0 -269
  747. package/dist/test/record-journal.test.js.map +0 -1
  748. package/dist/test/refusal-reaction-baseline.test.d.ts +0 -2
  749. package/dist/test/refusal-reaction-baseline.test.d.ts.map +0 -1
  750. package/dist/test/refusal-reaction-baseline.test.js +0 -81
  751. package/dist/test/refusal-reaction-baseline.test.js.map +0 -1
  752. package/dist/test/refusal-rewind.test.d.ts +0 -2
  753. package/dist/test/refusal-rewind.test.d.ts.map +0 -1
  754. package/dist/test/refusal-rewind.test.js +0 -117
  755. package/dist/test/refusal-rewind.test.js.map +0 -1
  756. package/dist/test/refusal-single-call.test.d.ts +0 -2
  757. package/dist/test/refusal-single-call.test.d.ts.map +0 -1
  758. package/dist/test/refusal-single-call.test.js +0 -177
  759. package/dist/test/refusal-single-call.test.js.map +0 -1
  760. package/dist/test/release-bump.test.d.ts +0 -2
  761. package/dist/test/release-bump.test.d.ts.map +0 -1
  762. package/dist/test/release-bump.test.js +0 -248
  763. package/dist/test/release-bump.test.js.map +0 -1
  764. package/dist/test/release-changelog.test.d.ts +0 -2
  765. package/dist/test/release-changelog.test.d.ts.map +0 -1
  766. package/dist/test/release-changelog.test.js +0 -159
  767. package/dist/test/release-changelog.test.js.map +0 -1
  768. package/dist/test/release-holds.test.d.ts +0 -2
  769. package/dist/test/release-holds.test.d.ts.map +0 -1
  770. package/dist/test/release-holds.test.js +0 -456
  771. package/dist/test/release-holds.test.js.map +0 -1
  772. package/dist/test/same-round-think-policy.test.d.ts +0 -2
  773. package/dist/test/same-round-think-policy.test.d.ts.map +0 -1
  774. package/dist/test/same-round-think-policy.test.js +0 -853
  775. package/dist/test/same-round-think-policy.test.js.map +0 -1
  776. package/dist/test/save-recent-image.test.d.ts +0 -26
  777. package/dist/test/save-recent-image.test.d.ts.map +0 -1
  778. package/dist/test/save-recent-image.test.js +0 -974
  779. package/dist/test/save-recent-image.test.js.map +0 -1
  780. package/dist/test/shutdown-errors.test.d.ts +0 -2
  781. package/dist/test/shutdown-errors.test.d.ts.map +0 -1
  782. package/dist/test/shutdown-errors.test.js +0 -662
  783. package/dist/test/shutdown-errors.test.js.map +0 -1
  784. package/dist/test/silent-heartbeat-rows.test.d.ts +0 -2
  785. package/dist/test/silent-heartbeat-rows.test.d.ts.map +0 -1
  786. package/dist/test/silent-heartbeat-rows.test.js +0 -451
  787. package/dist/test/silent-heartbeat-rows.test.js.map +0 -1
  788. package/dist/test/silent-heartbeat.test.d.ts +0 -2
  789. package/dist/test/silent-heartbeat.test.d.ts.map +0 -1
  790. package/dist/test/silent-heartbeat.test.js +0 -165
  791. package/dist/test/silent-heartbeat.test.js.map +0 -1
  792. package/dist/test/state-scaling-e2e.test.d.ts +0 -22
  793. package/dist/test/state-scaling-e2e.test.d.ts.map +0 -1
  794. package/dist/test/state-scaling-e2e.test.js +0 -206
  795. package/dist/test/state-scaling-e2e.test.js.map +0 -1
  796. package/dist/test/state-scaling.test.d.ts +0 -12
  797. package/dist/test/state-scaling.test.d.ts.map +0 -1
  798. package/dist/test/state-scaling.test.js +0 -251
  799. package/dist/test/state-scaling.test.js.map +0 -1
  800. package/dist/test/stop-with-host-operations.test.d.ts +0 -20
  801. package/dist/test/stop-with-host-operations.test.d.ts.map +0 -1
  802. package/dist/test/stop-with-host-operations.test.js +0 -1174
  803. package/dist/test/stop-with-host-operations.test.js.map +0 -1
  804. package/dist/test/stop-with-work-in-flight.test.d.ts +0 -23
  805. package/dist/test/stop-with-work-in-flight.test.d.ts.map +0 -1
  806. package/dist/test/stop-with-work-in-flight.test.js +0 -784
  807. package/dist/test/stop-with-work-in-flight.test.js.map +0 -1
  808. package/dist/test/surgery-marks-receipt.test.d.ts +0 -2
  809. package/dist/test/surgery-marks-receipt.test.d.ts.map +0 -1
  810. package/dist/test/surgery-marks-receipt.test.js +0 -540
  811. package/dist/test/surgery-marks-receipt.test.js.map +0 -1
  812. package/dist/test/thinking-token-stamp.test.d.ts +0 -12
  813. package/dist/test/thinking-token-stamp.test.d.ts.map +0 -1
  814. package/dist/test/thinking-token-stamp.test.js +0 -129
  815. package/dist/test/thinking-token-stamp.test.js.map +0 -1
  816. package/dist/test/timezone.test.d.ts +0 -2
  817. package/dist/test/timezone.test.d.ts.map +0 -1
  818. package/dist/test/timezone.test.js +0 -18
  819. package/dist/test/timezone.test.js.map +0 -1
  820. package/dist/test/tool-batch-hook.test.d.ts +0 -8
  821. package/dist/test/tool-batch-hook.test.d.ts.map +0 -1
  822. package/dist/test/tool-batch-hook.test.js +0 -275
  823. package/dist/test/tool-batch-hook.test.js.map +0 -1
  824. package/dist/test/tool-policy.test.d.ts +0 -2
  825. package/dist/test/tool-policy.test.d.ts.map +0 -1
  826. package/dist/test/tool-policy.test.js +0 -51
  827. package/dist/test/tool-policy.test.js.map +0 -1
  828. package/dist/test/tool-presentation.test.d.ts +0 -2
  829. package/dist/test/tool-presentation.test.d.ts.map +0 -1
  830. package/dist/test/tool-presentation.test.js +0 -268
  831. package/dist/test/tool-presentation.test.js.map +0 -1
  832. package/dist/test/tool-result-content.test.d.ts +0 -2
  833. package/dist/test/tool-result-content.test.d.ts.map +0 -1
  834. package/dist/test/tool-result-content.test.js +0 -37
  835. package/dist/test/tool-result-content.test.js.map +0 -1
  836. package/dist/test/tool-result-guard.test.d.ts +0 -2
  837. package/dist/test/tool-result-guard.test.d.ts.map +0 -1
  838. package/dist/test/tool-result-guard.test.js +0 -3729
  839. package/dist/test/tool-result-guard.test.js.map +0 -1
  840. package/dist/test/tool-result-history.test.d.ts +0 -7
  841. package/dist/test/tool-result-history.test.d.ts.map +0 -1
  842. package/dist/test/tool-result-history.test.js +0 -156
  843. package/dist/test/tool-result-history.test.js.map +0 -1
  844. package/dist/test/tool-result-spill.test.d.ts +0 -13
  845. package/dist/test/tool-result-spill.test.d.ts.map +0 -1
  846. package/dist/test/tool-result-spill.test.js +0 -586
  847. package/dist/test/tool-result-spill.test.js.map +0 -1
  848. package/dist/test/tool-wrapper-prose-guard-integration.test.d.ts +0 -2
  849. package/dist/test/tool-wrapper-prose-guard-integration.test.d.ts.map +0 -1
  850. package/dist/test/tool-wrapper-prose-guard-integration.test.js +0 -485
  851. package/dist/test/tool-wrapper-prose-guard-integration.test.js.map +0 -1
  852. package/dist/test/tool-wrapper-prose-guard.test.d.ts +0 -2
  853. package/dist/test/tool-wrapper-prose-guard.test.d.ts.map +0 -1
  854. package/dist/test/tool-wrapper-prose-guard.test.js +0 -34
  855. package/dist/test/tool-wrapper-prose-guard.test.js.map +0 -1
  856. package/dist/test/tools-observe-parser-conformance.test.d.ts +0 -2
  857. package/dist/test/tools-observe-parser-conformance.test.d.ts.map +0 -1
  858. package/dist/test/tools-observe-parser-conformance.test.js +0 -129
  859. package/dist/test/tools-observe-parser-conformance.test.js.map +0 -1
  860. package/dist/test/trunk-channel-routing.test.d.ts +0 -19
  861. package/dist/test/trunk-channel-routing.test.d.ts.map +0 -1
  862. package/dist/test/trunk-channel-routing.test.js +0 -652
  863. package/dist/test/trunk-channel-routing.test.js.map +0 -1
  864. package/dist/test/tune-out-e2e.test.d.ts +0 -2
  865. package/dist/test/tune-out-e2e.test.d.ts.map +0 -1
  866. package/dist/test/tune-out-e2e.test.js +0 -142
  867. package/dist/test/tune-out-e2e.test.js.map +0 -1
  868. package/dist/test/tune-out-gate-composition.test.d.ts +0 -2
  869. package/dist/test/tune-out-gate-composition.test.d.ts.map +0 -1
  870. package/dist/test/tune-out-gate-composition.test.js +0 -221
  871. package/dist/test/tune-out-gate-composition.test.js.map +0 -1
  872. package/dist/test/tune-out-lifecycle.test.d.ts +0 -2
  873. package/dist/test/tune-out-lifecycle.test.d.ts.map +0 -1
  874. package/dist/test/tune-out-lifecycle.test.js +0 -121
  875. package/dist/test/tune-out-lifecycle.test.js.map +0 -1
  876. package/dist/test/turn-trigger-provenance.test.d.ts +0 -2
  877. package/dist/test/turn-trigger-provenance.test.d.ts.map +0 -1
  878. package/dist/test/turn-trigger-provenance.test.js +0 -137
  879. package/dist/test/turn-trigger-provenance.test.js.map +0 -1
  880. package/dist/test/unconvertible-tool-result.test.d.ts +0 -2
  881. package/dist/test/unconvertible-tool-result.test.d.ts.map +0 -1
  882. package/dist/test/unconvertible-tool-result.test.js +0 -358
  883. package/dist/test/unconvertible-tool-result.test.js.map +0 -1
  884. package/dist/test/unsent-compiles.test.d.ts +0 -2
  885. package/dist/test/unsent-compiles.test.d.ts.map +0 -1
  886. package/dist/test/unsent-compiles.test.js +0 -139
  887. package/dist/test/unsent-compiles.test.js.map +0 -1
  888. package/dist/test/usage-accounting.test.d.ts +0 -2
  889. package/dist/test/usage-accounting.test.d.ts.map +0 -1
  890. package/dist/test/usage-accounting.test.js +0 -13
  891. package/dist/test/usage-accounting.test.js.map +0 -1
  892. package/dist/test/usage-tracker.test.d.ts +0 -2
  893. package/dist/test/usage-tracker.test.d.ts.map +0 -1
  894. package/dist/test/usage-tracker.test.js +0 -129
  895. package/dist/test/usage-tracker.test.js.map +0 -1
  896. package/dist/test/utils-surface.test.d.ts +0 -2
  897. package/dist/test/utils-surface.test.d.ts.map +0 -1
  898. package/dist/test/utils-surface.test.js +0 -145
  899. package/dist/test/utils-surface.test.js.map +0 -1
  900. package/dist/test/workspace-branch-continuation.test.d.ts +0 -15
  901. package/dist/test/workspace-branch-continuation.test.d.ts.map +0 -1
  902. package/dist/test/workspace-branch-continuation.test.js +0 -183
  903. package/dist/test/workspace-branch-continuation.test.js.map +0 -1
  904. package/dist/test/workspace-materialize-freshness.test.d.ts +0 -16
  905. package/dist/test/workspace-materialize-freshness.test.d.ts.map +0 -1
  906. package/dist/test/workspace-materialize-freshness.test.js +0 -252
  907. package/dist/test/workspace-materialize-freshness.test.js.map +0 -1
  908. package/dist/test/workspace-path-containment.test.d.ts +0 -19
  909. package/dist/test/workspace-path-containment.test.d.ts.map +0 -1
  910. package/dist/test/workspace-path-containment.test.js +0 -91
  911. package/dist/test/workspace-path-containment.test.js.map +0 -1
  912. package/dist/test/workspace-read-file-from-disk.test.d.ts +0 -17
  913. package/dist/test/workspace-read-file-from-disk.test.d.ts.map +0 -1
  914. package/dist/test/workspace-read-file-from-disk.test.js +0 -174
  915. package/dist/test/workspace-read-file-from-disk.test.js.map +0 -1
  916. package/dist/test/workspace-read-image.test.d.ts +0 -2
  917. package/dist/test/workspace-read-image.test.d.ts.map +0 -1
  918. package/dist/test/workspace-read-image.test.js +0 -597
  919. package/dist/test/workspace-read-image.test.js.map +0 -1
  920. package/dist/test/workspace-read-text.test.d.ts +0 -2
  921. package/dist/test/workspace-read-text.test.d.ts.map +0 -1
  922. package/dist/test/workspace-read-text.test.js +0 -101
  923. package/dist/test/workspace-read-text.test.js.map +0 -1
  924. package/dist/test/workspace-restore-order.test.d.ts +0 -16
  925. package/dist/test/workspace-restore-order.test.d.ts.map +0 -1
  926. package/dist/test/workspace-restore-order.test.js +0 -140
  927. package/dist/test/workspace-restore-order.test.js.map +0 -1
  928. package/dist/test/workspace-three-way.test.d.ts +0 -12
  929. package/dist/test/workspace-three-way.test.d.ts.map +0 -1
  930. package/dist/test/workspace-three-way.test.js +0 -4094
  931. package/dist/test/workspace-three-way.test.js.map +0 -1
  932. package/dist/test/workspace-watcher.test.d.ts +0 -2
  933. package/dist/test/workspace-watcher.test.d.ts.map +0 -1
  934. package/dist/test/workspace-watcher.test.js +0 -281
  935. package/dist/test/workspace-watcher.test.js.map +0 -1
  936. package/dist/test/xml-round-persist.test.d.ts +0 -19
  937. package/dist/test/xml-round-persist.test.d.ts.map +0 -1
  938. package/dist/test/xml-round-persist.test.js +0 -235
  939. package/dist/test/xml-round-persist.test.js.map +0 -1
  940. package/dist/tsconfig.tsbuildinfo +0 -1
@@ -1,1598 +0,0 @@
1
- import { describe, it } from 'node:test';
2
- import assert from 'node:assert/strict';
3
- import { mkdtempSync, rmSync } from 'node:fs';
4
- import { tmpdir } from 'node:os';
5
- import { join } from 'node:path';
6
- import { JsStore } from '@animalabs/chronicle';
7
- import { AutobiographicalStrategy, ContextManager } from '@animalabs/context-manager';
8
- import { Agent, AgentFramework, BudgetPreflightError } from '../src/index.js';
9
- const membrane = {};
10
- function strategy() {
11
- return new AutobiographicalStrategy({
12
- adaptiveResolution: true,
13
- foldingStrategy: 'kv-stable',
14
- recentWindowTokens: 30_000,
15
- kvStableReachTokens: 8_000,
16
- });
17
- }
18
- describe('agent runtime settings', () => {
19
- it('agent_settings is one typed tool for the hot runtime surface', async () => {
20
- const dir = mkdtempSync(join(tmpdir(), 'agent-settings-'));
21
- const framework = await AgentFramework.create({
22
- storePath: join(dir, 'store'),
23
- membrane,
24
- agents: [{
25
- name: 'agent',
26
- model: 'test-model',
27
- systemPrompt: 'test',
28
- strategy: strategy(),
29
- contextBudgetTokens: 100_000,
30
- maxTokens: 10_000,
31
- }],
32
- modules: [],
33
- });
34
- try {
35
- const tool = framework.getAllTools().find((candidate) => candidate.name === 'agent_settings');
36
- assert.ok(tool, 'general-purpose settings tool is exposed');
37
- assert.deepEqual(tool.inputSchema.properties.same_round_think_text_policy, {
38
- type: 'string',
39
- enum: ['public', 'private'],
40
- description: 'Routing policy for ordinary text emitted in the same native assistant round as think(). ' +
41
- "Omitted in the recipe preserves the compatibility carry-forward: public.",
42
- });
43
- assert.deepEqual(framework.getAgentRuntimeSettings('agent'), {
44
- contextBudgetTokens: 100_000,
45
- effectiveContextBudgetTokens: 100_000,
46
- tailTokens: 30_000,
47
- transitionPaceTokens: 8_000,
48
- sameRoundThinkTextPolicy: 'public',
49
- sameRoundThinkTextPolicySource: 'compatibility_default',
50
- transition: 'stable',
51
- });
52
- assert.deepEqual(framework.updateAgentRuntimeSettings('agent', {
53
- contextBudgetTokens: 60_000,
54
- tailTokens: 20_000,
55
- transitionPaceTokens: 4_000,
56
- sameRoundThinkTextPolicy: 'private',
57
- }), {
58
- contextBudgetTokens: 60_000,
59
- effectiveContextBudgetTokens: 100_000,
60
- tailTokens: 20_000,
61
- transitionPaceTokens: 4_000,
62
- sameRoundThinkTextPolicy: 'private',
63
- sameRoundThinkTextPolicySource: 'runtime_override',
64
- transition: 'converging',
65
- });
66
- assert.equal(framework.cancelAgentRuntimeSettingsTransition('agent').transition, 'stable');
67
- assert.deepEqual(framework.resetAgentRuntimeSettings('agent'), {
68
- contextBudgetTokens: 100_000,
69
- effectiveContextBudgetTokens: 100_000,
70
- tailTokens: 30_000,
71
- transitionPaceTokens: 8_000,
72
- sameRoundThinkTextPolicy: 'public',
73
- sameRoundThinkTextPolicySource: 'compatibility_default',
74
- transition: 'stable',
75
- });
76
- }
77
- finally {
78
- await framework.stop();
79
- rmSync(dir, { recursive: true, force: true });
80
- }
81
- });
82
- it('runtime overrides persist across framework restart', async () => {
83
- const dir = mkdtempSync(join(tmpdir(), 'agent-settings-persist-'));
84
- const storePath = join(dir, 'store');
85
- const config = () => ({
86
- storePath,
87
- membrane,
88
- agents: [{
89
- name: 'agent',
90
- model: 'test-model',
91
- systemPrompt: 'test',
92
- strategy: strategy(),
93
- contextBudgetTokens: 100_000,
94
- maxTokens: 10_000,
95
- sameRoundThinkTextPolicy: 'public',
96
- }],
97
- modules: [],
98
- });
99
- let framework = await AgentFramework.create(config());
100
- framework.updateAgentRuntimeSettings('agent', {
101
- contextBudgetTokens: 70_000,
102
- tailTokens: 18_000,
103
- transitionPaceTokens: 5_000,
104
- sameRoundThinkTextPolicy: 'private',
105
- });
106
- await framework.stop();
107
- try {
108
- framework = await AgentFramework.create(config());
109
- // The descent was still running at the stop, so it resumes paced from the
110
- // recipe's budget.
111
- assert.deepEqual(framework.getAgentRuntimeSettings('agent'), {
112
- contextBudgetTokens: 70_000,
113
- effectiveContextBudgetTokens: 100_000,
114
- tailTokens: 18_000,
115
- transitionPaceTokens: 5_000,
116
- sameRoundThinkTextPolicy: 'private',
117
- sameRoundThinkTextPolicySource: 'runtime_override',
118
- transition: 'converging',
119
- });
120
- }
121
- finally {
122
- await framework.stop();
123
- rmSync(dir, { recursive: true, force: true });
124
- }
125
- });
126
- // context-manager #162: a lower budget the agent had reached comes back reached.
127
- describe('a reached budget across a restart', () => {
128
- const persisted = (framework) => framework.getStore().getStateJson('framework/state')
129
- ?.agentRuntimeSettings?.agent;
130
- const writeRecord = (framework, record) => {
131
- const store = framework.getStore();
132
- const state = (store.getStateJson('framework/state') ?? {});
133
- store.setStateJson('framework/state', { ...state, agentRuntimeSettings: { ...state.agentRuntimeSettings, agent: record } });
134
- };
135
- const setup = () => {
136
- const dir = mkdtempSync(join(tmpdir(), 'agent-settings-reached-'));
137
- const config = () => ({
138
- storePath: join(dir, 'store'),
139
- membrane,
140
- agents: [{
141
- name: 'agent', model: 'test-model', systemPrompt: 'test',
142
- strategy: strategy(), contextBudgetTokens: 100_000, maxTokens: 10_000,
143
- }],
144
- modules: [],
145
- });
146
- return { dir, config };
147
- };
148
- const budgets = (framework) => {
149
- const s = framework.getAgentRuntimeSettings('agent');
150
- return { target: s.contextBudgetTokens, effective: s.effectiveContextBudgetTokens, transition: s.transition };
151
- };
152
- const compile = (framework) => framework.getAgent('agent').compileContext();
153
- /** Run `fn` with ContextManager.prototype[method] replaced. */
154
- async function withPatched(method, impl, fn) {
155
- const proto = ContextManager.prototype;
156
- const original = proto[method];
157
- proto[method] = impl;
158
- try {
159
- return await fn();
160
- }
161
- finally {
162
- proto[method] = original;
163
- }
164
- }
165
- const quietErrors = () => {
166
- const lines = [];
167
- const original = console.error;
168
- console.error = (...args) => { lines.push(args.map(String).join(' ')); };
169
- return { lines, restore: () => { console.error = original; } };
170
- };
171
- /** Each test's framework, stopped and removed afterwards. */
172
- async function run(fn) {
173
- const { dir, config } = setup();
174
- let framework = await AgentFramework.create(config());
175
- try {
176
- await fn({
177
- config,
178
- framework: () => framework,
179
- restart: async () => { await framework.stop(); framework = await AgentFramework.create(config()); return framework; },
180
- });
181
- }
182
- finally {
183
- await framework.stop();
184
- rmSync(dir, { recursive: true, force: true });
185
- }
186
- }
187
- it('a descent that settled comes back settled, and the first compile plans at it', async () => {
188
- await run(async ({ framework, restart }) => {
189
- framework().updateAgentRuntimeSettings('agent', { contextBudgetTokens: 60_000 });
190
- assert.deepEqual(budgets(framework()), { target: 60_000, effective: 100_000, transition: 'converging' });
191
- assert.deepEqual(persisted(framework()), { contextBudgetTokens: 60_000 }, 'not reached yet');
192
- // The store is empty, so the first compile's frontier fits and the descent settles.
193
- await compile(framework());
194
- assert.deepEqual(budgets(framework()), { target: 60_000, effective: 60_000, transition: 'stable' });
195
- assert.deepEqual(persisted(framework()), { contextBudgetTokens: 60_000, contextBudgetReachedTokens: 60_000 }, 'the settle is recorded');
196
- const restarted = await restart();
197
- assert.deepEqual(budgets(restarted), { target: 60_000, effective: 60_000, transition: 'stable' });
198
- // The record's proof stands until a compile here says otherwise, so a
199
- // persisting call before any compile keeps it.
200
- restarted.updateAgentRuntimeSettings('agent', { tailTokens: 20_000 });
201
- assert.equal(persisted(restarted)?.contextBudgetReachedTokens, 60_000);
202
- const planned = [];
203
- const cm = restarted.getAgent('agent').getContextManager();
204
- const original = cm.compile.bind(cm);
205
- cm.compile = (budget, ...rest) => { planned.push(budget?.maxTokens ?? -1); return original(budget, ...rest); };
206
- await compile(restarted);
207
- assert.deepEqual(planned, [60_000], 'the first compile after the restart plans at the reached budget');
208
- });
209
- });
210
- it('a restored descent that settles after the restart is recorded then', async () => {
211
- await run(async ({ framework, restart }) => {
212
- framework().updateAgentRuntimeSettings('agent', { contextBudgetTokens: 60_000 });
213
- const restarted = await restart();
214
- assert.deepEqual(budgets(restarted), { target: 60_000, effective: 100_000, transition: 'converging' });
215
- await compile(restarted);
216
- assert.deepEqual(persisted(restarted), { contextBudgetTokens: 60_000, contextBudgetReachedTokens: 60_000 });
217
- });
218
- });
219
- it('an immediate decrease is recorded once a compile fits at it, not before', async () => {
220
- await run(async ({ framework, restart }) => {
221
- framework().updateAgentRuntimeSettings('agent', { contextBudgetTokens: 60_000, immediate: true });
222
- assert.deepEqual(persisted(framework()), { contextBudgetTokens: 60_000 }, 'nothing has compiled at it yet');
223
- await compile(framework());
224
- assert.deepEqual(persisted(framework()), { contextBudgetTokens: 60_000, contextBudgetReachedTokens: 60_000 });
225
- assert.deepEqual(budgets(await restart()), { target: 60_000, effective: 60_000, transition: 'stable' });
226
- });
227
- });
228
- it('an immediate decrease that never compiled comes back paced', async () => {
229
- await run(async ({ framework, restart }) => {
230
- framework().updateAgentRuntimeSettings('agent', { contextBudgetTokens: 60_000, immediate: true });
231
- assert.deepEqual(budgets(await restart()), { target: 60_000, effective: 100_000, transition: 'converging' });
232
- });
233
- });
234
- it('a compile refused at the reached budget withdraws the record, and the restart paces', async () => {
235
- await run(async ({ framework, restart }) => {
236
- framework().updateAgentRuntimeSettings('agent', { contextBudgetTokens: 60_000, immediate: true });
237
- await compile(framework());
238
- const refusal = Object.assign(new Error('over budget'), { name: 'OverBudgetError' });
239
- await withPatched('compile', async () => { throw refusal; }, async () => {
240
- await assert.rejects(() => compile(framework()), /over budget/);
241
- });
242
- assert.deepEqual(persisted(framework()), { contextBudgetTokens: 60_000 });
243
- assert.deepEqual(budgets(await restart()), { target: 60_000, effective: 100_000, transition: 'converging' });
244
- });
245
- });
246
- it('a reached budget the preflight says no longer fits restores paced, with a line saying why', async () => {
247
- await run(async ({ framework, restart }) => {
248
- framework().updateAgentRuntimeSettings('agent', { contextBudgetTokens: 60_000, immediate: true });
249
- await compile(framework());
250
- const log = quietErrors();
251
- try {
252
- // A restart with a new maxTokens or strategy configuration raised the folded floor.
253
- const restarted = await withPatched('previewContext', (budget) => ({
254
- finalTokens: 70_000, budgetTokens: budget.maxTokens, fits: 70_000 <= budget.maxTokens,
255
- }), restart);
256
- assert.deepEqual(budgets(restarted), { target: 60_000, effective: 100_000, transition: 'converging' });
257
- }
258
- finally {
259
- log.restore();
260
- }
261
- // One line, written once the restore is made, saying why and what it made.
262
- assert.deepEqual(log.lines.filter((line) => line.includes('[agent-settings]')), [
263
- '[agent-settings] agent: its record says a compile fit at contextBudgetTokens=60000, but the folded floor renders ' +
264
- '70000 tokens against it now; restored it paced instead: contextBudgetTokens is 60000, and compiles plan at 100000 (converging)',
265
- ]);
266
- });
267
- });
268
- it('a reached budget the preflight says fits but that fails to apply at once restores paced, with a line naming that step', async () => {
269
- await run(async ({ framework, restart }) => {
270
- framework().updateAgentRuntimeSettings('agent', { contextBudgetTokens: 60_000, immediate: true });
271
- await compile(framework());
272
- const proto = Agent.prototype;
273
- const original = proto.restoreRuntimeSettings;
274
- proto.restoreRuntimeSettings = function (settings, opts) {
275
- if (opts?.provenBudget !== undefined)
276
- throw new Error('hot settings refused');
277
- return original.call(this, settings, opts);
278
- };
279
- const log = quietErrors();
280
- let restarted;
281
- try {
282
- restarted = await restart();
283
- }
284
- finally {
285
- proto.restoreRuntimeSettings = original;
286
- log.restore();
287
- }
288
- assert.deepEqual(budgets(restarted), { target: 60_000, effective: 100_000, transition: 'converging' });
289
- assert.ok(log.lines.some((line) => line.includes('applying it at once failed (hot settings refused), though the preflight says it fits now')), log.lines.join('\n'));
290
- assert.ok(!log.lines.some((line) => line.includes("can't be checked")), log.lines.join('\n'));
291
- });
292
- });
293
- it('a record without the field, or with one for another budget, restores paced', async () => {
294
- await run(async ({ framework, restart }) => {
295
- // An earlier release's record; then one an older release carried
296
- // forward beside a budget it changed.
297
- writeRecord(framework(), { contextBudgetTokens: 60_000 });
298
- assert.equal(budgets(await restart()).transition, 'converging');
299
- writeRecord(framework(), { contextBudgetTokens: 70_000, contextBudgetReachedTokens: 60_000 });
300
- assert.deepEqual(budgets(await restart()), { target: 70_000, effective: 100_000, transition: 'converging' });
301
- });
302
- });
303
- it('an invalid field is ignored with a bounded line, and a record holding only it still boots', async () => {
304
- await run(async ({ framework, restart }) => {
305
- const log = quietErrors();
306
- try {
307
- for (const invalid of ['yes'.repeat(100), [60_000], { budget: 60_000 }, null]) {
308
- writeRecord(framework(), { contextBudgetTokens: 60_000, contextBudgetReachedTokens: invalid });
309
- assert.equal(budgets(await restart()).transition, 'converging', JSON.stringify(invalid));
310
- }
311
- writeRecord(framework(), { contextBudgetReachedTokens: -5 });
312
- assert.deepEqual(budgets(await restart()), { target: 100_000, effective: 100_000, transition: 'stable' }, 'the recipe budget');
313
- }
314
- finally {
315
- log.restore();
316
- }
317
- // The line names the kind of value, never its content.
318
- const lines = log.lines.filter((l) => l.includes('ignoring an invalid persisted contextBudgetReachedTokens'));
319
- const line = (kind) => `[agent-settings] ignoring an invalid persisted contextBudgetReachedTokens for agent "agent": ${kind}`;
320
- assert.deepEqual(lines, [
321
- line('a string'),
322
- line('an array'),
323
- line('an object'),
324
- line('null'),
325
- line('a number that isn\'t a positive safe integer'),
326
- ], log.lines.join('\n'));
327
- });
328
- });
329
- it('a malformed persisted budget, tail or pace is ignored with a line naming its kind, and the rest restores', async () => {
330
- await run(async ({ framework, restart }) => {
331
- writeRecord(framework(), { contextBudgetTokens: 'x'.repeat(100), tailTokens: -1, transitionPaceTokens: 4_000 });
332
- const log = quietErrors();
333
- let restarted;
334
- try {
335
- restarted = await restart();
336
- }
337
- finally {
338
- log.restore();
339
- }
340
- const { contextBudgetTokens, effectiveContextBudgetTokens, tailTokens, transitionPaceTokens } = restarted.getAgentRuntimeSettings('agent');
341
- assert.deepEqual({ contextBudgetTokens, effectiveContextBudgetTokens, tailTokens, transitionPaceTokens }, { contextBudgetTokens: 100_000, effectiveContextBudgetTokens: 100_000, tailTokens: 30_000, transitionPaceTokens: 4_000 });
342
- assert.deepEqual(log.lines.filter((l) => l.includes('[agent-settings]')), [
343
- '[agent-settings] ignoring an invalid persisted contextBudgetTokens for agent "agent": a string',
344
- '[agent-settings] ignoring an invalid persisted tailTokens for agent "agent": a number that isn\'t a non-negative safe integer',
345
- ]);
346
- restarted.updateAgentRuntimeSettings('agent', { tailTokens: 20_000 });
347
- assert.deepEqual(persisted(restarted), { transitionPaceTokens: 4_000, tailTokens: 20_000 }, 'a later write leaves them out');
348
- });
349
- await run(async ({ framework, restart }) => {
350
- writeRecord(framework(), { transitionPaceTokens: 0, tailTokens: 20_000 });
351
- const log = quietErrors();
352
- let restarted;
353
- try {
354
- restarted = await restart();
355
- }
356
- finally {
357
- log.restore();
358
- }
359
- assert.equal(restarted.getAgentRuntimeSettings('agent').tailTokens, 20_000);
360
- assert.deepEqual(log.lines.filter((l) => l.includes('[agent-settings]')), [
361
- '[agent-settings] ignoring an invalid persisted transitionPaceTokens for agent "agent": a number that isn\'t a positive safe integer',
362
- ]);
363
- restarted.updateAgentRuntimeSettings('agent', { sameRoundThinkTextPolicy: 'private' });
364
- assert.deepEqual(persisted(restarted), { tailTokens: 20_000, sameRoundThinkTextPolicy: 'private' }, 'a later write leaves the pace out');
365
- });
366
- });
367
- it('a patch cannot set the field', async () => {
368
- await run(async ({ framework }) => {
369
- framework().updateAgentRuntimeSettings('agent', { contextBudgetTokens: 60_000, contextBudgetReachedTokens: 60_000 });
370
- assert.deepEqual(framework().getAgent('agent').getRuntimeSettingsOverrides(), { contextBudgetTokens: 60_000 });
371
- assert.deepEqual(persisted(framework()), { contextBudgetTokens: 60_000 });
372
- });
373
- });
374
- it('every persisting call keeps the field true to the live state', async () => {
375
- await run(async ({ framework }) => {
376
- const f = framework();
377
- f.updateAgentRuntimeSettings('agent', { contextBudgetTokens: 60_000, immediate: true });
378
- await compile(f);
379
- f.updateAgentRuntimeSettings('agent', { tailTokens: 20_000 });
380
- assert.deepEqual(persisted(f), { contextBudgetTokens: 60_000, tailTokens: 20_000, contextBudgetReachedTokens: 60_000 }, 'another setting keeps it');
381
- f.cancelAgentRuntimeSettingsTransition('agent');
382
- assert.equal(persisted(f)?.contextBudgetReachedTokens, 60_000, 'a cancel with no descent keeps it');
383
- f.updateAgentRuntimeSettings('agent', { contextBudgetTokens: 50_000 });
384
- assert.deepEqual(persisted(f), { contextBudgetTokens: 50_000, tailTokens: 20_000 }, 'a new descent has reached nothing');
385
- f.cancelAgentRuntimeSettingsTransition('agent');
386
- assert.deepEqual(persisted(f), { contextBudgetTokens: 60_000, tailTokens: 20_000, contextBudgetReachedTokens: 60_000 }, 'cancelled back to the reached budget');
387
- f.resetAgentRuntimeSettings('agent', ['contextBudgetTokens']);
388
- assert.deepEqual(persisted(f), { tailTokens: 20_000 }, 'reset to the recipe');
389
- });
390
- });
391
- it('a settle marks only the persisted budget it reached', async () => {
392
- await run(async ({ framework }) => {
393
- framework().updateAgentRuntimeSettings('agent', { contextBudgetTokens: 80_000 });
394
- framework().updateAgentRuntimeSettings('agent', { contextBudgetTokens: 60_000 }, { persist: false });
395
- await compile(framework());
396
- assert.deepEqual(budgets(framework()), { target: 60_000, effective: 60_000, transition: 'stable' });
397
- assert.deepEqual(persisted(framework()), { contextBudgetTokens: 80_000 }, "the record's 80k was never compiled at");
398
- });
399
- });
400
- it('a descent applied without persisting settles without writing anything', async () => {
401
- await run(async ({ framework, restart }) => {
402
- framework().updateAgentRuntimeSettings('agent', { contextBudgetTokens: 60_000 }, { persist: false });
403
- const log = quietErrors();
404
- try {
405
- await compile(framework());
406
- }
407
- finally {
408
- log.restore();
409
- }
410
- assert.deepEqual(log.lines.filter((l) => l.includes('[agent-settings]')), [], 'no record is no error');
411
- assert.deepEqual(budgets(framework()), { target: 60_000, effective: 60_000, transition: 'stable' });
412
- assert.equal(persisted(framework()), undefined, 'nothing written for an ephemeral descent');
413
- assert.deepEqual(budgets(await restart()), { target: 100_000, effective: 100_000, transition: 'stable' }, 'the recipe budget');
414
- });
415
- });
416
- it('a failed write of the field is logged, and the compile stands', async () => {
417
- await run(async ({ framework }) => {
418
- framework().updateAgentRuntimeSettings('agent', { contextBudgetTokens: 60_000, immediate: true });
419
- const store = framework().getStore();
420
- const original = store.setStateJson.bind(store);
421
- store.setStateJson = () => { throw new Error('disk full'); };
422
- const log = quietErrors();
423
- try {
424
- await compile(framework());
425
- }
426
- finally {
427
- store.setStateJson = original;
428
- log.restore();
429
- }
430
- assert.ok(log.lines.some((l) => l.includes("couldn't record agent's compile at budget 60000")), log.lines.join('\n'));
431
- assert.deepEqual(persisted(framework()), { contextBudgetTokens: 60_000 });
432
- // The next compile at that budget records it, once writes work again.
433
- await compile(framework());
434
- assert.deepEqual(persisted(framework()), { contextBudgetTokens: 60_000, contextBudgetReachedTokens: 60_000 });
435
- });
436
- });
437
- it('a budget changed while a compile runs is not proven by that compile', async () => {
438
- await run(async ({ framework }) => {
439
- const f = framework();
440
- const original = ContextManager.prototype.compile;
441
- // The compile was asked for at the recipe's 100k; the budget drops to
442
- // 60k at once while it runs.
443
- await withPatched('compile', async function (...args) {
444
- f.updateAgentRuntimeSettings('agent', { contextBudgetTokens: 60_000, immediate: true });
445
- return original.apply(this, args);
446
- }, () => compile(f));
447
- assert.deepEqual(persisted(f), { contextBudgetTokens: 60_000 }, 'the 100k compile proves nothing about 60k');
448
- assert.equal(f.getAgent('agent').getProvenContextBudgetTokens(), undefined, 'and no proof stands for the live budget: that compile planned at 100k');
449
- await compile(f);
450
- assert.deepEqual(persisted(f), { contextBudgetTokens: 60_000, contextBudgetReachedTokens: 60_000 });
451
- });
452
- });
453
- it('a compile refused after the budget changed under it withdraws its own budget\'s marker, and leaves the new budget\'s proof', async () => {
454
- await run(async ({ framework }) => {
455
- const f = framework();
456
- f.updateAgentRuntimeSettings('agent', { contextBudgetTokens: 60_000, immediate: true });
457
- await compile(f);
458
- assert.equal(persisted(f)?.contextBudgetReachedTokens, 60_000);
459
- const original = ContextManager.prototype.compile;
460
- const refusal = Object.assign(new Error('over budget'), { name: 'OverBudgetError' });
461
- let release;
462
- const held = new Promise((resolve) => { release = resolve; });
463
- let calls = 0;
464
- // The first compile plans at 60k and is refused only after the budget
465
- // went to 80k, unpersisted, and a second compile fit there.
466
- await withPatched('compile', async function (...args) {
467
- if (++calls === 1) {
468
- await held;
469
- throw refusal;
470
- }
471
- return original.apply(this, args);
472
- }, async () => {
473
- const first = compile(f);
474
- f.updateAgentRuntimeSettings('agent', { contextBudgetTokens: 80_000 }, { persist: false });
475
- await compile(f);
476
- release();
477
- await assert.rejects(first, /over budget/);
478
- });
479
- assert.deepEqual(persisted(f), { contextBudgetTokens: 60_000 }, 'the record still holds 60k, now without its marker');
480
- assert.equal(f.getAgent('agent').getProvenContextBudgetTokens(), 80_000, 'the refusal at 60k says nothing about 80k');
481
- });
482
- });
483
- /**
484
- * Two compiles at 60k, the first held until `between` has run: `firstFits`
485
- * says how the first ends, and the second, started after it, ends the
486
- * other way. Each selects at its start, as the context manager does (a fit
487
- * calls the real compile then, a refusal is decided then); only the
488
- * first's outcome is held.
489
- */
490
- async function twoCompilesAt60k(f, firstFits, between) {
491
- const original = ContextManager.prototype.compile;
492
- const refusal = Object.assign(new Error('over budget'), { name: 'OverBudgetError' });
493
- let release;
494
- const held = new Promise((resolve) => { release = resolve; });
495
- let calls = 0;
496
- await withPatched('compile', async function (...args) {
497
- const isFirst = ++calls === 1;
498
- const outcome = isFirst !== firstFits ? Promise.reject(refusal) : original.apply(this, args);
499
- outcome.catch(() => { }); // returned below
500
- if (isFirst)
501
- await held;
502
- return outcome;
503
- }, async () => {
504
- const first = compile(f);
505
- first.catch(() => { }); // asserted below; if between() fails, its refusal is not left unhandled
506
- try {
507
- await between();
508
- }
509
- finally {
510
- release();
511
- }
512
- if (firstFits)
513
- await first;
514
- else
515
- await assert.rejects(first, /over budget/);
516
- });
517
- }
518
- it('of two compiles at one budget, the one that started later decides, whichever finishes last', async () => {
519
- // A refusal planned before a fit at the same budget, with nothing changed between them.
520
- await run(async ({ framework }) => {
521
- const f = framework();
522
- f.updateAgentRuntimeSettings('agent', { contextBudgetTokens: 60_000, immediate: true });
523
- await twoCompilesAt60k(f, false, async () => {
524
- await compile(f);
525
- assert.deepEqual(persisted(f), { contextBudgetTokens: 60_000, contextBudgetReachedTokens: 60_000 }, 'the second compile fit at 60k');
526
- });
527
- assert.deepEqual(persisted(f), { contextBudgetTokens: 60_000, contextBudgetReachedTokens: 60_000 }, 'the later-started fit stands');
528
- assert.equal(f.getAgent('agent').getProvenContextBudgetTokens(), 60_000);
529
- });
530
- // A refusal planned before the budget went to 80k and came back to 60k,
531
- // where a second compile fit; then, in a second run, the budget moves to
532
- // 70k unpersisted before the refusal arrives.
533
- for (const moveAway of [false, true]) {
534
- await run(async ({ framework }) => {
535
- const f = framework();
536
- f.updateAgentRuntimeSettings('agent', { contextBudgetTokens: 60_000, immediate: true });
537
- await twoCompilesAt60k(f, false, async () => {
538
- f.updateAgentRuntimeSettings('agent', { contextBudgetTokens: 80_000 });
539
- f.updateAgentRuntimeSettings('agent', { contextBudgetTokens: 60_000, immediate: true });
540
- await compile(f);
541
- assert.deepEqual(persisted(f), { contextBudgetTokens: 60_000, contextBudgetReachedTokens: 60_000 }, 'the second compile fit at 60k');
542
- if (moveAway)
543
- f.updateAgentRuntimeSettings('agent', { contextBudgetTokens: 70_000 }, { persist: false });
544
- });
545
- assert.deepEqual(persisted(f), { contextBudgetTokens: 60_000, contextBudgetReachedTokens: 60_000 }, 'the later-started fit stands');
546
- assert.equal(f.getAgent('agent').getProvenContextBudgetTokens(), moveAway ? undefined : 60_000);
547
- });
548
- }
549
- // A fit planned before a refusal at the same budget.
550
- await run(async ({ framework }) => {
551
- const f = framework();
552
- f.updateAgentRuntimeSettings('agent', { contextBudgetTokens: 60_000, immediate: true });
553
- await compile(f);
554
- await twoCompilesAt60k(f, true, async () => {
555
- await assert.rejects(compile(f), /over budget/);
556
- assert.deepEqual(persisted(f), { contextBudgetTokens: 60_000 }, 'the second compile\'s refusal withdrew the marker');
557
- });
558
- assert.deepEqual(persisted(f), { contextBudgetTokens: 60_000 }, 'the later-started refusal stands');
559
- assert.equal(f.getAgent('agent').getProvenContextBudgetTokens(), undefined);
560
- });
561
- });
562
- it("a later-started compile whose fit isn't credited still outranks an earlier-started refusal at its budget", async () => {
563
- await run(async ({ framework }) => {
564
- const f = framework();
565
- f.updateAgentRuntimeSettings('agent', { contextBudgetTokens: 60_000, immediate: true });
566
- await compile(f);
567
- assert.deepEqual(persisted(f), { contextBudgetTokens: 60_000, contextBudgetReachedTokens: 60_000 });
568
- const original = ContextManager.prototype.compile;
569
- const refusal = Object.assign(new Error('over budget'), { name: 'OverBudgetError' });
570
- let releaseFirst;
571
- let releaseSecond;
572
- const held = [
573
- new Promise((resolve) => { releaseFirst = resolve; }),
574
- new Promise((resolve) => { releaseSecond = resolve; }),
575
- ];
576
- let calls = 0;
577
- await withPatched('compile', async function (...args) {
578
- const n = calls++;
579
- // Each selects at its start; only its outcome is held.
580
- const outcome = n === 0 ? Promise.reject(refusal) : original.apply(this, args);
581
- outcome.catch(() => { }); // returned below
582
- await held[n];
583
- return outcome;
584
- }, async () => {
585
- // Both plan at 60k. The second fits while the budget moves to 70k
586
- // unpersisted, so nothing credits it; the first is refused after it.
587
- const first = compile(f);
588
- first.catch(() => { }); // asserted below
589
- try {
590
- const second = compile(f);
591
- f.updateAgentRuntimeSettings('agent', { contextBudgetTokens: 70_000 }, { persist: false });
592
- releaseSecond();
593
- await second;
594
- }
595
- finally {
596
- releaseFirst();
597
- releaseSecond();
598
- }
599
- await assert.rejects(first, /over budget/);
600
- });
601
- assert.deepEqual(persisted(f), { contextBudgetTokens: 60_000, contextBudgetReachedTokens: 60_000 }, 'the earlier-started refusal is ignored');
602
- });
603
- });
604
- it("a settle's credit outranks an earlier-started refusal at its target", async () => {
605
- await run(async ({ framework }) => {
606
- const f = framework();
607
- f.updateAgentRuntimeSettings('agent', { contextBudgetTokens: 60_000, immediate: true });
608
- const original = ContextManager.prototype.compile;
609
- const refusal = Object.assign(new Error('over budget'), { name: 'OverBudgetError' });
610
- let release;
611
- const held = new Promise((resolve) => { release = resolve; });
612
- let calls = 0;
613
- await withPatched('compile', async function (...args) {
614
- if (++calls === 1) {
615
- await held;
616
- throw refusal;
617
- }
618
- return original.apply(this, args);
619
- }, async () => {
620
- // The first plans at 60k and is refused only after the budget went to
621
- // 80k and paced back down, and a compile at 80k settled that descent.
622
- const first = compile(f);
623
- first.catch(() => { }); // asserted below
624
- try {
625
- f.updateAgentRuntimeSettings('agent', { contextBudgetTokens: 80_000 });
626
- f.updateAgentRuntimeSettings('agent', { contextBudgetTokens: 60_000 });
627
- assert.equal(budgets(f).transition, 'converging');
628
- await compile(f);
629
- assert.deepEqual(budgets(f), { target: 60_000, effective: 60_000, transition: 'stable' });
630
- assert.deepEqual(persisted(f), { contextBudgetTokens: 60_000, contextBudgetReachedTokens: 60_000 }, 'the settle credited 60k');
631
- }
632
- finally {
633
- release();
634
- }
635
- await assert.rejects(first, /over budget/);
636
- });
637
- assert.deepEqual(persisted(f), { contextBudgetTokens: 60_000, contextBudgetReachedTokens: 60_000 }, 'the settle outranks the earlier-started refusal');
638
- });
639
- });
640
- it('a settle credits its target only from the latest compile to end at the budget it planned at', async () => {
641
- await run(async ({ framework }) => {
642
- const f = framework();
643
- f.updateAgentRuntimeSettings('agent', { contextBudgetTokens: 60_000 });
644
- assert.equal(budgets(f).transition, 'converging');
645
- const original = ContextManager.prototype.compile;
646
- const refusal = Object.assign(new Error('over budget'), { name: 'OverBudgetError' });
647
- let release;
648
- const held = new Promise((resolve) => { release = resolve; });
649
- let calls = 0;
650
- await withPatched('compile', async function (...args) {
651
- if (++calls > 1)
652
- throw refusal;
653
- // The first selects at its start; only its outcome is held.
654
- const outcome = original.apply(this, args);
655
- await held;
656
- return outcome;
657
- }, async () => {
658
- // Both plan at 100k. The second is refused there first; the first
659
- // then fits and settles the descent to 60k.
660
- const first = compile(f);
661
- try {
662
- await assert.rejects(compile(f), /over budget/);
663
- }
664
- finally {
665
- release();
666
- }
667
- await first;
668
- });
669
- assert.deepEqual(budgets(f), { target: 60_000, effective: 60_000, transition: 'stable' }, 'the first compile settled the descent');
670
- assert.deepEqual(persisted(f), { contextBudgetTokens: 60_000 }, 'and credits nothing: a later-started compile was refused at 100k');
671
- assert.equal(f.getAgent('agent').getProvenContextBudgetTokens(), undefined);
672
- });
673
- });
674
- it('the start order keeps nothing once no compile runs, through descents and compiles at once', async () => {
675
- await run(async ({ framework }) => {
676
- const f = framework();
677
- // What it keeps is visible only inside the agent.
678
- const kept = () => [...f.getAgent('agent').latestEndedStart.keys()];
679
- // Descents to three budgets, each settled by a compile.
680
- for (const budget of [90_000, 75_000, 60_000]) {
681
- f.updateAgentRuntimeSettings('agent', { contextBudgetTokens: budget });
682
- await compile(f);
683
- assert.deepEqual(budgets(f), { target: budget, effective: budget, transition: 'stable' });
684
- assert.deepEqual(kept(), [], `after the descent to ${budget}`);
685
- }
686
- // Two at once: the later-started one's place at 60k is kept while the earlier one runs.
687
- await twoCompilesAt60k(f, false, async () => {
688
- await compile(f);
689
- assert.deepEqual(kept(), [60_000], 'kept while an earlier-started compile runs');
690
- });
691
- assert.deepEqual(kept(), [], 'and dropped once it ends');
692
- });
693
- });
694
- it('of two compiles in flight across a settle, the one that finishes later proves nothing it planned before it', async () => {
695
- await run(async ({ framework }) => {
696
- const f = framework();
697
- f.updateAgentRuntimeSettings('agent', { contextBudgetTokens: 60_000 });
698
- const original = ContextManager.prototype.compile;
699
- let release;
700
- const held = new Promise((resolve) => { release = resolve; });
701
- let calls = 0;
702
- // Both plan at the live 100k; the first is held until the second has
703
- // finished and settled the descent.
704
- await withPatched('compile', async function (...args) {
705
- const n = ++calls;
706
- const result = await original.apply(this, args);
707
- if (n === 1)
708
- await held;
709
- return result;
710
- }, async () => {
711
- const first = compile(f);
712
- await compile(f);
713
- assert.deepEqual(budgets(f), { target: 60_000, effective: 60_000, transition: 'stable' });
714
- assert.deepEqual(persisted(f), { contextBudgetTokens: 60_000, contextBudgetReachedTokens: 60_000 }, 'the second settled it');
715
- release();
716
- await first;
717
- });
718
- assert.equal(f.getAgent('agent').getProvenContextBudgetTokens(), 60_000, "the first's 100k plan doesn't replace the proof");
719
- f.updateAgentRuntimeSettings('agent', { tailTokens: 20_000 });
720
- assert.equal(persisted(f)?.contextBudgetReachedTokens, 60_000, 'so a persisting call keeps the marker');
721
- });
722
- });
723
- it('a proof stands only until the live budget changes: back at a proven budget, nothing is marked before a compile fits', async () => {
724
- await run(async ({ framework }) => {
725
- const f = framework();
726
- f.updateAgentRuntimeSettings('agent', { contextBudgetTokens: 60_000, immediate: true });
727
- await compile(f);
728
- assert.equal(persisted(f)?.contextBudgetReachedTokens, 60_000);
729
- f.updateAgentRuntimeSettings('agent', { contextBudgetTokens: 80_000 });
730
- f.updateAgentRuntimeSettings('agent', { contextBudgetTokens: 60_000, immediate: true });
731
- assert.deepEqual(persisted(f), { contextBudgetTokens: 60_000 }, 'back at once: no compile has fit at it since');
732
- f.updateAgentRuntimeSettings('agent', { contextBudgetTokens: 80_000 });
733
- f.updateAgentRuntimeSettings('agent', { contextBudgetTokens: 60_000 });
734
- assert.equal(budgets(f).transition, 'converging');
735
- assert.deepEqual(persisted(f), { contextBudgetTokens: 60_000 }, 'back paced: the descent has reached nothing');
736
- await compile(f);
737
- assert.deepEqual(persisted(f), { contextBudgetTokens: 60_000, contextBudgetReachedTokens: 60_000 }, 'its settle marks it');
738
- });
739
- });
740
- it('a descent re-armed to the same target while a compile runs is not credited to that compile', async () => {
741
- await run(async ({ framework }) => {
742
- const f = framework();
743
- f.updateAgentRuntimeSettings('agent', { contextBudgetTokens: 60_000 });
744
- const original = ContextManager.prototype.compile;
745
- // The compile plans at the live 100k; meanwhile the budget is raised
746
- // at once and lowered back, paced, to the same 60k.
747
- await withPatched('compile', async function (...args) {
748
- f.updateAgentRuntimeSettings('agent', { contextBudgetTokens: 120_000 });
749
- f.updateAgentRuntimeSettings('agent', { contextBudgetTokens: 60_000 });
750
- return original.apply(this, args);
751
- }, () => compile(f));
752
- assert.deepEqual(persisted(f), { contextBudgetTokens: 60_000 }, 'the compile planned at 100k under another descent');
753
- });
754
- // The same with the live budget left alone: the descent is cancelled and
755
- // armed again, to the same 60k, while the compile runs.
756
- await run(async ({ framework }) => {
757
- const f = framework();
758
- f.updateAgentRuntimeSettings('agent', { contextBudgetTokens: 60_000 });
759
- const original = ContextManager.prototype.compile;
760
- await withPatched('compile', async function (...args) {
761
- f.cancelAgentRuntimeSettingsTransition('agent');
762
- f.updateAgentRuntimeSettings('agent', { contextBudgetTokens: 60_000 });
763
- return original.apply(this, args);
764
- }, () => compile(f));
765
- assert.equal(persisted(f)?.contextBudgetReachedTokens, undefined, 'a descent armed again is another descent');
766
- });
767
- // And armed again directly, to the same 60k, with nothing in between.
768
- await run(async ({ framework }) => {
769
- const f = framework();
770
- f.updateAgentRuntimeSettings('agent', { contextBudgetTokens: 60_000 });
771
- const original = ContextManager.prototype.compile;
772
- await withPatched('compile', async function (...args) {
773
- f.updateAgentRuntimeSettings('agent', { contextBudgetTokens: 60_000 });
774
- return original.apply(this, args);
775
- }, () => compile(f));
776
- assert.deepEqual(budgets(f), { target: 60_000, effective: 60_000, transition: 'stable' }, 'the re-armed descent settled');
777
- assert.equal(persisted(f)?.contextBudgetReachedTokens, undefined, 'a descent armed again to the same target is another descent');
778
- });
779
- // And armed again by a reset to the recipe's budget, below the live one.
780
- await run(async ({ framework }) => {
781
- const f = framework();
782
- f.updateAgentRuntimeSettings('agent', { contextBudgetTokens: 120_000 });
783
- f.resetAgentRuntimeSettings('agent', ['contextBudgetTokens']);
784
- assert.deepEqual(budgets(f), { target: 100_000, effective: 120_000, transition: 'converging' });
785
- const original = ContextManager.prototype.compile;
786
- await withPatched('compile', async function (...args) {
787
- f.resetAgentRuntimeSettings('agent', ['contextBudgetTokens']);
788
- return original.apply(this, args);
789
- }, () => compile(f));
790
- assert.deepEqual(budgets(f), { target: 100_000, effective: 100_000, transition: 'stable' }, 'the re-armed descent settled');
791
- // Setting the budget it now runs at keeps any proof the settle gave it.
792
- f.updateAgentRuntimeSettings('agent', { contextBudgetTokens: 100_000, immediate: true });
793
- assert.deepEqual(persisted(f), { contextBudgetTokens: 100_000 }, 'a descent armed again by a reset is another descent');
794
- });
795
- });
796
- it('a compile without a budget through compileWithInjections proves and records it too', async () => {
797
- await run(async ({ framework }) => {
798
- const f = framework();
799
- f.updateAgentRuntimeSettings('agent', { contextBudgetTokens: 60_000, immediate: true });
800
- await f.getAgent('agent').compileWithInjections();
801
- assert.deepEqual(persisted(f), { contextBudgetTokens: 60_000, contextBudgetReachedTokens: 60_000 });
802
- });
803
- });
804
- it('a record that cannot be read is logged, and told again at the next compile', async () => {
805
- await run(async ({ framework }) => {
806
- const f = framework();
807
- f.updateAgentRuntimeSettings('agent', { contextBudgetTokens: 60_000, immediate: true });
808
- const store = f.getStore();
809
- const original = store.getStateJson.bind(store);
810
- store.getStateJson = () => { throw new Error('store unreadable'); };
811
- const log = quietErrors();
812
- try {
813
- await compile(f);
814
- }
815
- finally {
816
- store.getStateJson = original;
817
- log.restore();
818
- }
819
- assert.ok(log.lines.some((l) => l.includes("couldn't record agent's compile at budget 60000")), log.lines.join('\n'));
820
- assert.deepEqual(persisted(f), { contextBudgetTokens: 60_000 });
821
- await compile(f);
822
- assert.deepEqual(persisted(f), { contextBudgetTokens: 60_000, contextBudgetReachedTokens: 60_000 });
823
- });
824
- });
825
- it("a record the boot can't read is logged, and the agent boots at the recipe's", async () => {
826
- await run(async ({ framework, restart }) => {
827
- framework().updateAgentRuntimeSettings('agent', { contextBudgetTokens: 60_000, immediate: true });
828
- // Only the boot's read of the record fails.
829
- const proto = JsStore.prototype;
830
- const original = proto.getStateJson;
831
- proto.getStateJson = function (...args) {
832
- if (new Error().stack?.includes('readAgentRuntimeSettings'))
833
- throw new Error('store unreadable');
834
- return original.apply(this, args);
835
- };
836
- const log = quietErrors();
837
- let restarted;
838
- try {
839
- restarted = await restart();
840
- }
841
- finally {
842
- proto.getStateJson = original;
843
- log.restore();
844
- }
845
- assert.deepEqual(budgets(restarted), { target: 100_000, effective: 100_000, transition: 'stable' });
846
- assert.ok(log.lines.some((l) => l.includes("agent: its persisted settings can't be read (store unreadable); it boots at the recipe's")), log.lines.join('\n'));
847
- });
848
- });
849
- it('after a withdrawal that failed and a persisting write without the marker, the next fit writes it again', async () => {
850
- await run(async ({ framework }) => {
851
- const f = framework();
852
- f.updateAgentRuntimeSettings('agent', { contextBudgetTokens: 60_000, immediate: true });
853
- await compile(f);
854
- assert.equal(persisted(f)?.contextBudgetReachedTokens, 60_000);
855
- const store = f.getStore();
856
- const write = store.setStateJson.bind(store);
857
- store.setStateJson = () => { throw new Error('disk full'); };
858
- const refusal = Object.assign(new Error('over budget'), { name: 'OverBudgetError' });
859
- const log = quietErrors();
860
- try {
861
- await withPatched('compile', async () => { throw refusal; }, async () => {
862
- await assert.rejects(() => compile(f), /over budget/);
863
- });
864
- }
865
- finally {
866
- store.setStateJson = write;
867
- log.restore();
868
- }
869
- f.updateAgentRuntimeSettings('agent', { tailTokens: 20_000 });
870
- assert.deepEqual(persisted(f), { contextBudgetTokens: 60_000, tailTokens: 20_000 }, 'the refusal stands in the record now');
871
- await compile(f);
872
- assert.equal(persisted(f)?.contextBudgetReachedTokens, 60_000, 'the next fit is told, and written');
873
- });
874
- });
875
- /** Apply `budget` at once and compile, so it's proven, then restart: the boot applies it at once. */
876
- async function provenAtBoot(h, budget) {
877
- h.framework().updateAgentRuntimeSettings('agent', { contextBudgetTokens: budget, immediate: true });
878
- await compile(h.framework());
879
- const restarted = await h.restart();
880
- assert.deepEqual(budgets(restarted), { target: budget, effective: budget, transition: 'stable' }, 'applied at once at boot');
881
- return restarted;
882
- }
883
- /**
884
- * A compile whose first plan the context manager refuses, after `meanwhile`
885
- * ran while that plan was under way: the budget each plan was asked for,
886
- * the record as the second began, the log, and what it threw.
887
- */
888
- async function refusedFirst(f, meanwhile) {
889
- const original = ContextManager.prototype.compile;
890
- const planned = [];
891
- let recordAtRetry;
892
- const refusal = Object.assign(new Error('over budget'), { name: 'OverBudgetError' });
893
- const log = quietErrors();
894
- let thrown;
895
- try {
896
- await withPatched('compile', async function (budget, ...rest) {
897
- planned.push(budget?.maxTokens ?? -1);
898
- if (planned.length === 1) {
899
- meanwhile?.();
900
- throw refusal;
901
- }
902
- recordAtRetry = { ...persisted(f) };
903
- return original.apply(this, [budget, ...rest]);
904
- }, () => compile(f));
905
- }
906
- catch (error) {
907
- thrown = error;
908
- }
909
- finally {
910
- log.restore();
911
- }
912
- return { planned, recordAtRetry, lines: log.lines, thrown };
913
- }
914
- it('a budget applied at once at boot whose first compile is refused is restored paced, and the compile goes on', async () => {
915
- await run(async (h) => {
916
- const restarted = await provenAtBoot(h, 60_000);
917
- const { planned, recordAtRetry, lines, thrown } = await refusedFirst(restarted);
918
- assert.equal(thrown, undefined);
919
- assert.deepEqual(planned, [60_000, 100_000], 'refused at the boot budget, then compiled from the recipe\'s');
920
- assert.deepEqual(recordAtRetry, { contextBudgetTokens: 60_000 }, 'the refusal withdrew the marker before the compile went on');
921
- assert.ok(lines.some((l) => l.includes('restored it as a paced descent from the recipe\'s budget')), lines.join('\n'));
922
- assert.equal(budgets(restarted).target, 60_000, 'the descent to it is armed (or settled)');
923
- assert.equal(persisted(restarted)?.contextBudgetTokens, 60_000);
924
- });
925
- });
926
- it('a dry run under a budget the boot applied at once proves nothing: the fallback stays armed, whether the preview fits or is refused', async () => {
927
- await run(async (h) => {
928
- const restarted = await provenAtBoot(h, 60_000);
929
- const recorded = persisted(restarted);
930
- // A preview that fits notes nothing and keeps the fallback.
931
- await restarted.previewActivation('agent');
932
- // A preview refused at the boot budget restores nothing from a preview.
933
- const refusal = Object.assign(new Error('over budget'), { name: 'OverBudgetError' });
934
- const log = quietErrors();
935
- try {
936
- await withPatched('compile', async () => { throw refusal; }, async () => {
937
- await assert.rejects(restarted.previewActivation('agent'), /over budget/);
938
- });
939
- }
940
- finally {
941
- log.restore();
942
- }
943
- assert.ok(!log.lines.some((l) => l.includes('the context manager refused')), log.lines.join('\n'));
944
- assert.deepEqual(budgets(restarted), { target: 60_000, effective: 60_000, transition: 'stable' }, 'still the boot budget, applied at once');
945
- assert.deepEqual(persisted(restarted), recorded, 'neither preview wrote the record');
946
- // The fallback is still armed: the first sent compile refused at the
947
- // boot budget restores it paced, and goes on.
948
- const { planned, lines, thrown } = await refusedFirst(restarted);
949
- assert.equal(thrown, undefined);
950
- assert.deepEqual(planned, [60_000, 100_000]);
951
- assert.ok(lines.some((l) => l.includes('restored it as a paced descent from the recipe\'s budget')), lines.join('\n'));
952
- });
953
- });
954
- it("the fallback runs once: if the recipe's budget is refused too, its compile reports that refusal", { timeout: 20_000 }, async () => {
955
- // Restored paced, and kept set where the strategy can't prepare a smaller window.
956
- for (const canPace of [true, false]) {
957
- await run(async (h) => {
958
- const restarted = await provenAtBoot(h, 60_000);
959
- if (!canPace) {
960
- const cm = restarted.getAgent('agent').getContextManager();
961
- const hot = cm.updateHotContextSettings.bind(cm);
962
- cm.updateHotContextSettings = (update) => {
963
- if (typeof update.preparedWindowTokens === 'number')
964
- throw new Error('no smaller window here');
965
- return hot(update);
966
- };
967
- }
968
- const refusal = Object.assign(new Error('over budget'), { name: 'OverBudgetError' });
969
- const planned = [];
970
- const log = quietErrors();
971
- try {
972
- await withPatched('compile', async function (budget) {
973
- planned.push(budget?.maxTokens ?? -1);
974
- throw refusal;
975
- }, async () => {
976
- await assert.rejects(compile(restarted), /over budget/);
977
- });
978
- }
979
- finally {
980
- log.restore();
981
- }
982
- assert.deepEqual(planned, [60_000, 100_000], `one fallback, then the refusal at the recipe's budget (canPace ${canPace})`);
983
- assert.equal(log.lines.filter((l) => l.includes('the context manager refused')).length, 1, `one fallback line (canPace ${canPace})`);
984
- assert.equal(budgets(restarted).target, 60_000, 'the boot budget stays set');
985
- });
986
- }
987
- });
988
- it('a budget at or above the recipe\'s, applied at once at boot, has no paced restore to fall back to: its refusal is the compile\'s', async () => {
989
- await run(async (h) => {
990
- const restarted = await provenAtBoot(h, 120_000);
991
- const { planned, lines, thrown } = await refusedFirst(restarted);
992
- assert.equal(thrown?.message, 'over budget');
993
- assert.deepEqual(planned, [120_000], 'no second compile');
994
- assert.ok(!lines.some((l) => l.includes('paced')), lines.join('\n'));
995
- assert.deepEqual(budgets(restarted), { target: 120_000, effective: 120_000, transition: 'stable' });
996
- assert.deepEqual(persisted(restarted), { contextBudgetTokens: 120_000 }, 'the refusal withdrew the marker');
997
- });
998
- });
999
- it("a refused budget the boot applied at once that can't be restored paced: the agent compiles at the recipe's, keeping the budget set", async () => {
1000
- await run(async (h) => {
1001
- const restarted = await provenAtBoot(h, 60_000);
1002
- // The strategy can't prepare a smaller window now.
1003
- const cm = restarted.getAgent('agent').getContextManager();
1004
- const hot = cm.updateHotContextSettings.bind(cm);
1005
- cm.updateHotContextSettings = (update) => {
1006
- if (typeof update.preparedWindowTokens === 'number')
1007
- throw new Error('no smaller window here');
1008
- return hot(update);
1009
- };
1010
- const { planned, lines, thrown } = await refusedFirst(restarted);
1011
- assert.equal(thrown, undefined);
1012
- assert.deepEqual(planned, [60_000, 100_000]);
1013
- assert.ok(lines.some((l) => l.includes("couldn't restore it paced (no smaller window here), so it compiles at the recipe's budget, with contextBudgetTokens=60000 kept set")), lines.join('\n'));
1014
- assert.deepEqual(budgets(restarted), { target: 60_000, effective: 100_000, transition: 'stable' }, 'set to 60k, live at the recipe\'s');
1015
- restarted.updateAgentRuntimeSettings('agent', { tailTokens: 20_000 });
1016
- assert.deepEqual(persisted(restarted), { contextBudgetTokens: 60_000, tailTokens: 20_000 }, 'a later write keeps the budget');
1017
- });
1018
- });
1019
- it('after the boot, a tail change keeps the fallback, and any write of the budget ends it', async () => {
1020
- await run(async (h) => {
1021
- h.framework().updateAgentRuntimeSettings('agent', { tailTokens: 15_000 });
1022
- const restarted = await provenAtBoot(h, 60_000);
1023
- restarted.updateAgentRuntimeSettings('agent', { tailTokens: 20_000 });
1024
- const { planned, thrown } = await refusedFirst(restarted);
1025
- assert.equal(thrown, undefined);
1026
- assert.deepEqual(planned, [60_000, 100_000], 'restored paced');
1027
- assert.equal(restarted.getAgentRuntimeSettings('agent').tailTokens, 20_000, 'the fallback re-applies only the budget, not the boot\'s tail');
1028
- });
1029
- // Each write of the budget, before the first compile or while it runs,
1030
- // is the operator's decision: the refusal is that compile's own.
1031
- const writes = [
1032
- ['a paced decrease', (f) => { f.updateAgentRuntimeSettings('agent', { contextBudgetTokens: 50_000 }); }, false, 60_000,
1033
- { target: 50_000, effective: 60_000, transition: 'converging' }],
1034
- ['the same budget at once', (f) => { f.updateAgentRuntimeSettings('agent', { contextBudgetTokens: 60_000, immediate: true }); }, false, 60_000,
1035
- { target: 60_000, effective: 60_000, transition: 'stable' }],
1036
- ['the same budget, unpersisted', (f) => { f.updateAgentRuntimeSettings('agent', { contextBudgetTokens: 60_000 }, { persist: false }); }, false, 60_000,
1037
- { target: 60_000, effective: 60_000, transition: 'stable' }],
1038
- ['a reset of the budget', (f) => { f.resetAgentRuntimeSettings('agent', ['contextBudgetTokens']); }, false, 100_000,
1039
- { target: 100_000, effective: 100_000, transition: 'stable' }],
1040
- ['an increase while the first compile runs', (f) => { f.updateAgentRuntimeSettings('agent', { contextBudgetTokens: 80_000 }); }, true, 60_000,
1041
- { target: 80_000, effective: 80_000, transition: 'stable' }],
1042
- ];
1043
- for (const [what, write, meanwhile, refusedAt, after] of writes) {
1044
- await run(async (h) => {
1045
- const restarted = await provenAtBoot(h, 60_000);
1046
- if (!meanwhile)
1047
- write(restarted);
1048
- const { planned, thrown } = await refusedFirst(restarted, meanwhile ? () => write(restarted) : undefined);
1049
- assert.equal(thrown?.message, 'over budget', what);
1050
- assert.deepEqual(planned, [refusedAt], `${what}: no fallback`);
1051
- assert.deepEqual(budgets(restarted), after, what);
1052
- });
1053
- }
1054
- // And a compile that fits at it ends the fallback too.
1055
- await run(async (h) => {
1056
- const restarted = await provenAtBoot(h, 60_000);
1057
- await compile(restarted);
1058
- const { planned, thrown } = await refusedFirst(restarted);
1059
- assert.equal(thrown?.message, 'over budget');
1060
- assert.deepEqual(planned, [60_000], 'once a compile has fit at it, a refusal is the compile\'s own');
1061
- });
1062
- });
1063
- /** A writer at the usual maxTokens leaves `record`; the agent then boots with maxTokens raised to 70k, above a persisted 60k. */
1064
- async function bootRaised(record, fn) {
1065
- const { dir, config } = setup();
1066
- const raised = () => ({ ...config(), agents: config().agents.map((a) => ({ ...a, maxTokens: 70_000 })) });
1067
- try {
1068
- const writer = await AgentFramework.create(config());
1069
- writeRecord(writer, record);
1070
- await writer.stop();
1071
- const log = quietErrors();
1072
- let booted;
1073
- try {
1074
- booted = await AgentFramework.create(raised());
1075
- }
1076
- finally {
1077
- log.restore();
1078
- }
1079
- try {
1080
- await fn(booted, log.lines);
1081
- }
1082
- finally {
1083
- await booted.stop();
1084
- }
1085
- }
1086
- finally {
1087
- rmSync(dir, { recursive: true, force: true });
1088
- }
1089
- }
1090
- it("a persisted budget the agent can't take now (maxTokens raised above it) stays set but unapplied, and it runs at the recipe's, with a line", async () => {
1091
- const refused = 'contextBudgetTokens must be a safe integer greater than max response tokens (70000)';
1092
- const kept = `contextBudgetTokens=60000 (${refused}) can't be applied now, so it stays set but unapplied: ` +
1093
- 'contextBudgetTokens is 60000, and compiles plan at 100000';
1094
- const cases = [
1095
- // One line, which keeps why a reached budget wasn't applied at once.
1096
- [{ contextBudgetTokens: 60_000, contextBudgetReachedTokens: 60_000 },
1097
- `[agent-settings] agent: its record says a compile fit at contextBudgetTokens=60000, but whether it fits now can't be checked (${refused}); ${kept}`],
1098
- [{ contextBudgetTokens: 60_000 }, `[agent-settings] agent: ${kept}`],
1099
- ];
1100
- for (const [record, line] of cases) {
1101
- await bootRaised(record, (booted, lines) => {
1102
- assert.deepEqual(budgets(booted), { target: 60_000, effective: 100_000, transition: 'stable' }, JSON.stringify(record));
1103
- assert.deepEqual(lines.filter((l) => l.includes('[agent-settings]')), [line], JSON.stringify(record));
1104
- });
1105
- }
1106
- });
1107
- it('a reached budget applies at once on its own, though a tail beside it can\'t be applied', async () => {
1108
- await run(async ({ framework, restart }) => {
1109
- framework().updateAgentRuntimeSettings('agent', { tailTokens: 20_000 });
1110
- framework().updateAgentRuntimeSettings('agent', { contextBudgetTokens: 60_000, immediate: true });
1111
- await compile(framework());
1112
- assert.deepEqual(persisted(framework()), { tailTokens: 20_000, contextBudgetTokens: 60_000, contextBudgetReachedTokens: 60_000 });
1113
- // The strategy refuses a live tail now; it takes a budget as before.
1114
- const proto = ContextManager.prototype;
1115
- const original = proto.updateHotContextSettings;
1116
- proto.updateHotContextSettings = function (update) {
1117
- if (update.tailTokens !== undefined)
1118
- throw new Error('no live tail here');
1119
- return original.call(this, update);
1120
- };
1121
- const log = quietErrors();
1122
- let restarted;
1123
- try {
1124
- restarted = await restart();
1125
- }
1126
- finally {
1127
- proto.updateHotContextSettings = original;
1128
- log.restore();
1129
- }
1130
- assert.deepEqual(budgets(restarted), { target: 60_000, effective: 60_000, transition: 'stable' }, 'the budget applied at once');
1131
- assert.deepEqual(log.lines.filter((l) => l.includes('[agent-settings]')), [
1132
- "[agent-settings] agent: tailTokens=20000 (no live tail here) can't be applied now, so it stays set but unapplied: " +
1133
- 'contextBudgetTokens is 60000, and compiles plan at 60000',
1134
- ]);
1135
- });
1136
- });
1137
- it("on a strategy without live settings, a tail and a lower budget stay set but unapplied, a later write keeps them, and a reset clears the tail", async () => {
1138
- const dir = mkdtempSync(join(tmpdir(), 'agent-settings-no-hot-'));
1139
- // The context manager's default strategy has no live settings.
1140
- const config = () => ({
1141
- storePath: join(dir, 'store'), membrane,
1142
- agents: [{ name: 'agent', model: 'test-model', systemPrompt: 'test', contextBudgetTokens: 100_000, maxTokens: 10_000 }],
1143
- modules: [],
1144
- });
1145
- let framework = await AgentFramework.create(config());
1146
- try {
1147
- writeRecord(framework, { contextBudgetTokens: 60_000, tailTokens: 20_000 });
1148
- await framework.stop();
1149
- const log = quietErrors();
1150
- try {
1151
- framework = await AgentFramework.create(config());
1152
- }
1153
- finally {
1154
- log.restore();
1155
- }
1156
- assert.deepEqual(framework.getAgentRuntimeSettings('agent'), {
1157
- contextBudgetTokens: 60_000,
1158
- effectiveContextBudgetTokens: 100_000,
1159
- sameRoundThinkTextPolicy: 'public',
1160
- sameRoundThinkTextPolicySource: 'compatibility_default',
1161
- transition: 'stable',
1162
- });
1163
- assert.deepEqual(log.lines.filter((l) => l.includes('[agent-settings]')), [
1164
- '[agent-settings] agent: tailTokens=20000 (The active context strategy does not support live tail/transition settings), ' +
1165
- 'contextBudgetTokens=60000 (The active context strategy cannot prepare a smaller window live) ' +
1166
- "can't be applied now, so they stay set but unapplied: contextBudgetTokens is 60000, and compiles plan at 100000",
1167
- ]);
1168
- framework.updateAgentRuntimeSettings('agent', { sameRoundThinkTextPolicy: 'private' });
1169
- assert.deepEqual(persisted(framework), { contextBudgetTokens: 60_000, tailTokens: 20_000, sameRoundThinkTextPolicy: 'private' });
1170
- framework.resetAgentRuntimeSettings('agent', ['tailTokens']);
1171
- assert.deepEqual(persisted(framework), { contextBudgetTokens: 60_000, sameRoundThinkTextPolicy: 'private' }, 'the reset clears the kept tail');
1172
- }
1173
- finally {
1174
- await framework.stop();
1175
- rmSync(dir, { recursive: true, force: true });
1176
- }
1177
- });
1178
- it("each persisted setting is restored on its own: a private policy governs and a tail applies when the budget can't, and a later write keeps the budget", async () => {
1179
- await bootRaised({ contextBudgetTokens: 60_000, tailTokens: 20_000, sameRoundThinkTextPolicy: 'private' }, (booted) => {
1180
- const { contextBudgetTokens, effectiveContextBudgetTokens, tailTokens, sameRoundThinkTextPolicy, sameRoundThinkTextPolicySource } = booted.getAgentRuntimeSettings('agent');
1181
- assert.deepEqual({ contextBudgetTokens, effectiveContextBudgetTokens, tailTokens, sameRoundThinkTextPolicy, sameRoundThinkTextPolicySource }, { contextBudgetTokens: 60_000, effectiveContextBudgetTokens: 100_000, tailTokens: 20_000, sameRoundThinkTextPolicy: 'private', sameRoundThinkTextPolicySource: 'runtime_override' });
1182
- // The snapshot each request takes, which routes its same-round text and describes its think tool.
1183
- const request = booted
1184
- .captureInferenceToolSnapshot(booted.getAgent('agent'));
1185
- assert.equal(request.sameRoundThinkTextPolicy, 'private');
1186
- booted.updateAgentRuntimeSettings('agent', { tailTokens: 25_000 });
1187
- assert.deepEqual(persisted(booted), { contextBudgetTokens: 60_000, tailTokens: 25_000, sameRoundThinkTextPolicy: 'private' });
1188
- });
1189
- });
1190
- it("a patch's preview plans at the reach its next compile plans at", async () => {
1191
- // The reach of every kv-stable plan, a preview's or a compile's, as the
1192
- // strategy hands it to the planner.
1193
- const proto = AutobiographicalStrategy.prototype;
1194
- const original = proto.buildPicker;
1195
- let reaches = [];
1196
- proto.buildPicker = function (...args) {
1197
- const picker = original.apply(this, args);
1198
- reaches.push(this._lastKvStable?.opts?.reachTokens);
1199
- return picker;
1200
- };
1201
- // Preview `patch` after `before`, then apply it and compile: the reach both planned at.
1202
- const both = async (before, patch) => {
1203
- let reach;
1204
- await run(async ({ framework }) => {
1205
- const f = framework();
1206
- before(f);
1207
- reaches = [];
1208
- f.previewAgentRuntimeSettings('agent', patch);
1209
- const previewed = reaches;
1210
- reaches = [];
1211
- f.updateAgentRuntimeSettings('agent', patch, { persist: false });
1212
- reaches = [];
1213
- await compile(f);
1214
- assert.ok(previewed.length > 0 && reaches.length > 0, `${JSON.stringify(patch)}: planned ${JSON.stringify({ previewed, reaches })}`);
1215
- assert.deepEqual([...new Set(previewed)], [...new Set(reaches)], JSON.stringify(patch));
1216
- reach = reaches[0];
1217
- });
1218
- return reach;
1219
- };
1220
- const none = () => { };
1221
- try {
1222
- // The recipe's reach is 8k; no descent is under way unless `before` arms one.
1223
- assert.equal(await both(none, { contextBudgetTokens: 60_000, transitionPaceTokens: 4_000, immediate: true }), 8_000, 'an immediate change: the configured reach');
1224
- assert.equal(await both(none, { contextBudgetTokens: 60_000, transitionPaceTokens: 4_000 }), 4_000, 'a paced decrease: its pace');
1225
- assert.equal(await both(none, { transitionPaceTokens: 4_000 }), 8_000, 'a pace with no descent: the configured reach');
1226
- const descending = (f) => { f.updateAgentRuntimeSettings('agent', { contextBudgetTokens: 60_000 }); };
1227
- assert.equal(await both(descending, { transitionPaceTokens: 4_000 }), 4_000, 'a pace during a descent: that pace');
1228
- const paced = (f) => { f.updateAgentRuntimeSettings('agent', { transitionPaceTokens: 4_000 }); };
1229
- assert.equal(await both(paced, { contextBudgetTokens: 60_000 }), 4_000, 'a paced decrease without a pace: the live one');
1230
- }
1231
- finally {
1232
- proto.buildPicker = original;
1233
- }
1234
- });
1235
- it('a descent ended by an immediate change to its own target is not credited to the compile that ran meanwhile', async () => {
1236
- await run(async ({ framework }) => {
1237
- const f = framework();
1238
- f.updateAgentRuntimeSettings('agent', { contextBudgetTokens: 60_000 });
1239
- assert.equal(budgets(f).transition, 'converging');
1240
- const original = ContextManager.prototype.compile;
1241
- // The compile plans at the live 100k; the same 60k is applied at once
1242
- // while it runs, ending the descent without a settle.
1243
- await withPatched('compile', async function (...args) {
1244
- f.updateAgentRuntimeSettings('agent', { contextBudgetTokens: 60_000, immediate: true });
1245
- return original.apply(this, args);
1246
- }, () => compile(f));
1247
- assert.deepEqual(budgets(f), { target: 60_000, effective: 60_000, transition: 'stable' });
1248
- assert.deepEqual(persisted(f), { contextBudgetTokens: 60_000 }, 'nothing settled, and the compile planned at 100k');
1249
- });
1250
- });
1251
- });
1252
- it('reset-all skips tail controls unsupported by the active strategy', async () => {
1253
- const dir = mkdtempSync(join(tmpdir(), 'agent-settings-basic-'));
1254
- const framework = await AgentFramework.create({
1255
- storePath: join(dir, 'store'),
1256
- membrane,
1257
- agents: [{ name: 'agent', model: 'test-model', systemPrompt: 'test' }],
1258
- modules: [],
1259
- });
1260
- try {
1261
- assert.deepEqual(framework.resetAgentRuntimeSettings('agent'), {
1262
- contextBudgetTokens: 100_000,
1263
- effectiveContextBudgetTokens: 100_000,
1264
- sameRoundThinkTextPolicy: 'public',
1265
- sameRoundThinkTextPolicySource: 'compatibility_default',
1266
- transition: 'stable',
1267
- });
1268
- }
1269
- finally {
1270
- await framework.stop();
1271
- rmSync(dir, { recursive: true, force: true });
1272
- }
1273
- });
1274
- it('same_round_think_text_policy reports recipe/runtime/default sources and rejects invalid values', async () => {
1275
- const dir = mkdtempSync(join(tmpdir(), 'agent-settings-think-policy-'));
1276
- const framework = await AgentFramework.create({
1277
- storePath: join(dir, 'store'),
1278
- membrane,
1279
- agents: [{
1280
- name: 'agent',
1281
- model: 'test-model',
1282
- systemPrompt: 'test',
1283
- sameRoundThinkTextPolicy: 'private',
1284
- }],
1285
- modules: [],
1286
- });
1287
- try {
1288
- assert.deepEqual(framework.getAgentRuntimeSettings('agent'), {
1289
- contextBudgetTokens: 100_000,
1290
- effectiveContextBudgetTokens: 100_000,
1291
- sameRoundThinkTextPolicy: 'private',
1292
- sameRoundThinkTextPolicySource: 'recipe',
1293
- transition: 'stable',
1294
- });
1295
- assert.deepEqual(framework.updateAgentRuntimeSettings('agent', { sameRoundThinkTextPolicy: 'public' }), {
1296
- contextBudgetTokens: 100_000,
1297
- effectiveContextBudgetTokens: 100_000,
1298
- sameRoundThinkTextPolicy: 'public',
1299
- sameRoundThinkTextPolicySource: 'runtime_override',
1300
- transition: 'stable',
1301
- });
1302
- assert.deepEqual(framework.resetAgentRuntimeSettings('agent', ['sameRoundThinkTextPolicy']), {
1303
- contextBudgetTokens: 100_000,
1304
- effectiveContextBudgetTokens: 100_000,
1305
- sameRoundThinkTextPolicy: 'private',
1306
- sameRoundThinkTextPolicySource: 'recipe',
1307
- transition: 'stable',
1308
- });
1309
- assert.throws(() => framework.updateAgentRuntimeSettings('agent', { sameRoundThinkTextPolicy: 'bogus' }), /sameRoundThinkTextPolicy must be 'public' or 'private'/);
1310
- }
1311
- finally {
1312
- await framework.stop();
1313
- rmSync(dir, { recursive: true, force: true });
1314
- }
1315
- });
1316
- it('fails closed on an invalid persisted same_round_think_text_policy override before any provider call', async () => {
1317
- const dir = mkdtempSync(join(tmpdir(), 'agent-settings-invalid-persisted-'));
1318
- const storePath = join(dir, 'store');
1319
- const store = JsStore.openOrCreate({ path: storePath });
1320
- try {
1321
- store.registerState({ id: 'framework/state', strategy: 'snapshot' });
1322
- }
1323
- catch {
1324
- // Already registered.
1325
- }
1326
- store.setStateJson('framework/state', {
1327
- agentRuntimeSettings: {
1328
- agent: {
1329
- sameRoundThinkTextPolicy: 'bogus',
1330
- },
1331
- },
1332
- });
1333
- store.close();
1334
- let providerCalls = 0;
1335
- const rejectingMembrane = {
1336
- complete: async () => {
1337
- providerCalls++;
1338
- throw new Error('provider should not be called');
1339
- },
1340
- streamYielding: () => {
1341
- providerCalls++;
1342
- throw new Error('provider should not be called');
1343
- },
1344
- };
1345
- try {
1346
- await assert.rejects(() => AgentFramework.create({
1347
- storePath,
1348
- membrane: rejectingMembrane,
1349
- agents: [{
1350
- name: 'agent',
1351
- model: 'test-model',
1352
- systemPrompt: 'test',
1353
- }],
1354
- modules: [],
1355
- }), /Invalid persisted sameRoundThinkTextPolicy/);
1356
- assert.equal(providerCalls, 0);
1357
- }
1358
- finally {
1359
- rmSync(dir, { recursive: true, force: true });
1360
- }
1361
- });
1362
- });
1363
- it('immediate: a budget decrease with immediate=true applies now — no descent, no persisted flag', async () => {
1364
- const dir = mkdtempSync(join(tmpdir(), 'agent-settings-immediate-'));
1365
- const framework = await AgentFramework.create({
1366
- storePath: join(dir, 'store'),
1367
- membrane,
1368
- agents: [{
1369
- name: 'agent',
1370
- model: 'test-model',
1371
- systemPrompt: 'test',
1372
- strategy: strategy(),
1373
- contextBudgetTokens: 100_000,
1374
- maxTokens: 10_000,
1375
- }],
1376
- modules: [],
1377
- });
1378
- try {
1379
- // Baseline: a plain decrease starts a paced descent.
1380
- const gradual = framework.updateAgentRuntimeSettings('agent', { contextBudgetTokens: 60_000 });
1381
- assert.equal(gradual.transition, 'converging');
1382
- assert.equal(gradual.contextBudgetTokens, 60_000, 'snapshot reports the TARGET while converging');
1383
- // Immediate: applies now AND cancels the in-flight descent.
1384
- const now = framework.updateAgentRuntimeSettings('agent', {
1385
- contextBudgetTokens: 50_000,
1386
- immediate: true,
1387
- });
1388
- assert.equal(now.transition, 'stable', 'no descent — the drop is live');
1389
- assert.equal(now.contextBudgetTokens, 50_000);
1390
- // The mode flag is never persisted as an override.
1391
- const overrides = framework.getAgent('agent').getRuntimeSettingsOverrides();
1392
- assert.equal(overrides.immediate, undefined, 'immediate is a mode, not a setting');
1393
- assert.equal(overrides.contextBudgetTokens, 50_000);
1394
- }
1395
- finally {
1396
- await framework.stop();
1397
- rmSync(dir, { recursive: true, force: true });
1398
- }
1399
- });
1400
- // ---------------------------------------------------------------------------
1401
- // Budget preflight (issue #122; supersedes feat/budget-preflight-guard).
1402
- // The preview stub stands in for the strategy's previewContext so verdicts are
1403
- // deterministic; the mapping under test is the framework's, not the picker's.
1404
- // ---------------------------------------------------------------------------
1405
- function stubPreview(framework, agentName, impl) {
1406
- const cm = framework.getAgent(agentName).getContextManager();
1407
- if (impl === undefined) {
1408
- cm.previewContext = undefined;
1409
- }
1410
- else {
1411
- cm.previewContext = (budget) => impl(budget);
1412
- }
1413
- }
1414
- const infeasibleAt = (floor) => (budget) => ({
1415
- finalTokens: floor,
1416
- budgetTokens: budget.maxTokens,
1417
- fits: floor <= budget.maxTokens,
1418
- exhausted: floor > budget.maxTokens,
1419
- headTokens: 10_000,
1420
- tailTokens: 30_000,
1421
- middleTokens: floor - 40_000,
1422
- middleChunkCount: 7,
1423
- deepestLevel: 3,
1424
- resolutions: {},
1425
- moves: 0,
1426
- producedCount: 0,
1427
- });
1428
- async function withPreflightFramework(fn) {
1429
- const dir = mkdtempSync(join(tmpdir(), 'agent-settings-preflight-'));
1430
- const framework = await AgentFramework.create({
1431
- storePath: join(dir, 'store'),
1432
- membrane,
1433
- agents: [{
1434
- name: 'agent',
1435
- model: 'test-model',
1436
- systemPrompt: 'test',
1437
- strategy: strategy(),
1438
- contextBudgetTokens: 550_000,
1439
- maxTokens: 10_000,
1440
- }],
1441
- modules: [],
1442
- });
1443
- try {
1444
- await fn(framework);
1445
- }
1446
- finally {
1447
- await framework.stop();
1448
- rmSync(dir, { recursive: true, force: true });
1449
- }
1450
- }
1451
- it('preflight: an immediate infeasible budget throws typed, allowInfeasible overrides', async () => {
1452
- await withPreflightFramework(async (framework) => {
1453
- stubPreview(framework, 'agent', infeasibleAt(450_000));
1454
- assert.throws(() => framework.updateAgentRuntimeSettings('agent', {
1455
- contextBudgetTokens: 260_000,
1456
- immediate: true,
1457
- }), (error) => {
1458
- assert.ok(error instanceof BudgetPreflightError);
1459
- assert.equal(error.preview.path, 'immediate');
1460
- assert.equal(error.preview.effective?.fits, false);
1461
- assert.equal(error.preview.effective?.finalTokens, 450_000);
1462
- assert.match(error.message, /450000 tokens against hard budget 260000/);
1463
- return true;
1464
- });
1465
- // The refused patch must not have been applied.
1466
- assert.equal(framework.getAgentRuntimeSettings('agent').contextBudgetTokens, 550_000);
1467
- const applied = framework.updateAgentRuntimeSettings('agent', { contextBudgetTokens: 260_000, immediate: true }, { allowInfeasible: true });
1468
- assert.equal(applied.contextBudgetTokens, 260_000);
1469
- });
1470
- });
1471
- it('preflight: a paced descent below the floor NEVER blocks — the compile budget is unchanged', async () => {
1472
- await withPreflightFramework(async (framework) => {
1473
- stubPreview(framework, 'agent', infeasibleAt(450_000));
1474
- // 260k < 550k live, no `immediate` → paced. The superseded branch guard
1475
- // previewed 260k as the compile budget and refused this exact patch; the
1476
- // real compile stays at 550k (feasible), so it must apply.
1477
- const applied = framework.updateAgentRuntimeSettings('agent', {
1478
- contextBudgetTokens: 260_000,
1479
- });
1480
- assert.equal(applied.transition, 'converging');
1481
- assert.equal(applied.contextBudgetTokens, 260_000, 'snapshot reports the target');
1482
- });
1483
- });
1484
- it('preflight: a feasible immediate change applies without ceremony', async () => {
1485
- await withPreflightFramework(async (framework) => {
1486
- stubPreview(framework, 'agent', infeasibleAt(200_000));
1487
- const applied = framework.updateAgentRuntimeSettings('agent', {
1488
- contextBudgetTokens: 260_000,
1489
- immediate: true,
1490
- });
1491
- assert.equal(applied.contextBudgetTokens, 260_000);
1492
- });
1493
- });
1494
- it('preflight: preview-unavailable applies with a warn, never blocks', async () => {
1495
- await withPreflightFramework(async (framework) => {
1496
- stubPreview(framework, 'agent', undefined);
1497
- const applied = framework.updateAgentRuntimeSettings('agent', {
1498
- contextBudgetTokens: 260_000,
1499
- immediate: true,
1500
- });
1501
- assert.equal(applied.contextBudgetTokens, 260_000);
1502
- });
1503
- });
1504
- it('previewAgentRuntimeSettings: structured reasons for the strategy throw paths', async () => {
1505
- await withPreflightFramework(async (framework) => {
1506
- const cases = [
1507
- [
1508
- 'AutobiographicalStrategy.previewContext requires reinitialization for the current branch generation',
1509
- 'branch_generation_changed',
1510
- ],
1511
- ['previewContext is already running; previews must not overlap', 'preview_in_flight'],
1512
- [
1513
- 'previewContext requires adaptiveResolution; the hierarchical path has no fold plan to preview',
1514
- 'no_adaptive_resolution',
1515
- ],
1516
- ['some novel failure', 'some novel failure'],
1517
- ];
1518
- for (const [message, reason] of cases) {
1519
- stubPreview(framework, 'agent', () => { throw new Error(message); });
1520
- const preview = framework.previewAgentRuntimeSettings('agent', {
1521
- contextBudgetTokens: 600_000,
1522
- });
1523
- assert.equal(preview.available, false, message);
1524
- assert.equal(preview.reason, reason);
1525
- }
1526
- });
1527
- });
1528
- it('previewAgentRuntimeSettings: paced patches report effective=live plus an advisory target', async () => {
1529
- await withPreflightFramework(async (framework) => {
1530
- stubPreview(framework, 'agent', infeasibleAt(450_000));
1531
- const preview = framework.previewAgentRuntimeSettings('agent', {
1532
- contextBudgetTokens: 260_000,
1533
- });
1534
- assert.equal(preview.path, 'paced');
1535
- assert.equal(preview.available, true);
1536
- assert.equal(preview.effective?.budgetTokens, 550_000, 'effective = UNCHANGED live budget');
1537
- assert.equal(preview.effective?.fits, true);
1538
- assert.equal(preview.advisory?.targetTokens, 260_000);
1539
- assert.equal(preview.advisory?.fits, false);
1540
- // No patch = the resume-gate case: verdict for current settings.
1541
- const current = framework.previewAgentRuntimeSettings('agent');
1542
- assert.equal(current.path, 'none');
1543
- assert.equal(current.effective?.budgetTokens, 550_000);
1544
- });
1545
- });
1546
- it('preflight: a boot restore without a matching reached budget is never preflighted, so an infeasible persisted budget cannot brick startup', async () => {
1547
- const dir = mkdtempSync(join(tmpdir(), 'agent-settings-preflight-boot-'));
1548
- const storePath = join(dir, 'store');
1549
- const config = () => ({
1550
- storePath,
1551
- membrane,
1552
- agents: [{
1553
- name: 'agent',
1554
- model: 'test-model',
1555
- systemPrompt: 'test',
1556
- strategy: strategy(),
1557
- contextBudgetTokens: 550_000,
1558
- maxTokens: 10_000,
1559
- }],
1560
- modules: [],
1561
- });
1562
- let framework = await AgentFramework.create(config());
1563
- try {
1564
- stubPreview(framework, 'agent', infeasibleAt(450_000));
1565
- framework.updateAgentRuntimeSettings('agent', { contextBudgetTokens: 260_000, immediate: true }, { allowInfeasible: true });
1566
- await framework.stop();
1567
- // Recreate WITHOUT a stub: restore goes through Agent.restoreRuntimeSettings,
1568
- // bypassing the framework wrapper — must not throw regardless of feasibility.
1569
- framework = await AgentFramework.create(config());
1570
- assert.equal(framework.getAgentRuntimeSettings('agent').contextBudgetTokens, 260_000);
1571
- }
1572
- finally {
1573
- await framework.stop();
1574
- rmSync(dir, { recursive: true, force: true });
1575
- }
1576
- });
1577
- it('preflight: no-op and increasing patches never throw on an already-over-floor agent', async () => {
1578
- await withPreflightFramework(async (framework) => {
1579
- stubPreview(framework, 'agent', infeasibleAt(600_000)); // floor above even 550k live
1580
- // No-op rewrite of the current budget: settings-plane writeback shape.
1581
- const rewrite = framework.updateAgentRuntimeSettings('agent', {
1582
- contextBudgetTokens: 550_000,
1583
- immediate: true,
1584
- });
1585
- assert.equal(rewrite.contextBudgetTokens, 550_000);
1586
- // Strict improvement (increase) on a wedged agent must apply, not throw.
1587
- const raise = framework.updateAgentRuntimeSettings('agent', {
1588
- contextBudgetTokens: 700_000,
1589
- });
1590
- assert.equal(raise.contextBudgetTokens, 700_000);
1591
- // A LOWERING that does not fit still throws.
1592
- assert.throws(() => framework.updateAgentRuntimeSettings('agent', {
1593
- contextBudgetTokens: 500_000,
1594
- immediate: true,
1595
- }), BudgetPreflightError);
1596
- });
1597
- });
1598
- //# sourceMappingURL=agent-runtime-settings.test.js.map