@namzu/sdk 38.2.1 → 40.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (602) hide show
  1. package/CHANGELOG.md +851 -0
  2. package/dist/advisory/executor.d.ts +10 -1
  3. package/dist/advisory/executor.d.ts.map +1 -1
  4. package/dist/advisory/executor.js +5 -26
  5. package/dist/advisory/executor.js.map +1 -1
  6. package/dist/advisory/history.d.ts +9 -0
  7. package/dist/advisory/history.d.ts.map +1 -0
  8. package/dist/advisory/history.js +120 -0
  9. package/dist/advisory/history.js.map +1 -0
  10. package/dist/advisory/index.d.ts +1 -1
  11. package/dist/advisory/index.d.ts.map +1 -1
  12. package/dist/advisory/index.js.map +1 -1
  13. package/dist/agents/ReactiveAgent.d.ts.map +1 -1
  14. package/dist/agents/ReactiveAgent.js +3 -0
  15. package/dist/agents/ReactiveAgent.js.map +1 -1
  16. package/dist/agents/runAgent.d.ts +10 -0
  17. package/dist/agents/runAgent.d.ts.map +1 -1
  18. package/dist/agents/runAgent.js +3 -0
  19. package/dist/agents/runAgent.js.map +1 -1
  20. package/dist/compaction/manual.d.ts +6 -0
  21. package/dist/compaction/manual.d.ts.map +1 -1
  22. package/dist/compaction/manual.js +21 -2
  23. package/dist/compaction/manual.js.map +1 -1
  24. package/dist/compaction/summary.d.ts.map +1 -1
  25. package/dist/compaction/summary.js +4 -1
  26. package/dist/compaction/summary.js.map +1 -1
  27. package/dist/config/runtime.js +2 -2
  28. package/dist/config/runtime.js.map +1 -1
  29. package/dist/connector/mcp/adapter.d.ts.map +1 -1
  30. package/dist/connector/mcp/adapter.js +20 -6
  31. package/dist/connector/mcp/adapter.js.map +1 -1
  32. package/dist/contracts/schemas.js +1 -1
  33. package/dist/contracts/schemas.js.map +1 -1
  34. package/dist/eval/harness-protection.d.ts +18 -0
  35. package/dist/eval/harness-protection.d.ts.map +1 -0
  36. package/dist/eval/harness-protection.js +58 -0
  37. package/dist/eval/harness-protection.js.map +1 -0
  38. package/dist/eval/harness-verification.d.ts +6 -1
  39. package/dist/eval/harness-verification.d.ts.map +1 -1
  40. package/dist/eval/harness-verification.js +19 -2
  41. package/dist/eval/harness-verification.js.map +1 -1
  42. package/dist/eval/index.d.ts +1 -0
  43. package/dist/eval/index.d.ts.map +1 -1
  44. package/dist/eval/index.js.map +1 -1
  45. package/dist/manager/resident/activity.d.ts +50 -0
  46. package/dist/manager/resident/activity.d.ts.map +1 -0
  47. package/dist/manager/resident/activity.js +125 -0
  48. package/dist/manager/resident/activity.js.map +1 -0
  49. package/dist/manager/resident/agenda.d.ts +13 -1
  50. package/dist/manager/resident/agenda.d.ts.map +1 -1
  51. package/dist/manager/resident/agenda.js +40 -5
  52. package/dist/manager/resident/agenda.js.map +1 -1
  53. package/dist/manager/resident/consumption.d.ts +104 -0
  54. package/dist/manager/resident/consumption.d.ts.map +1 -0
  55. package/dist/manager/resident/consumption.js +233 -0
  56. package/dist/manager/resident/consumption.js.map +1 -0
  57. package/dist/manager/resident/evidence-recall.d.ts +24 -0
  58. package/dist/manager/resident/evidence-recall.d.ts.map +1 -0
  59. package/dist/manager/resident/evidence-recall.js +295 -0
  60. package/dist/manager/resident/evidence-recall.js.map +1 -0
  61. package/dist/manager/resident/history-disk.d.ts +10 -0
  62. package/dist/manager/resident/history-disk.d.ts.map +1 -0
  63. package/dist/manager/resident/history-disk.js +50 -0
  64. package/dist/manager/resident/history-disk.js.map +1 -0
  65. package/dist/manager/resident/history.d.ts +79 -0
  66. package/dist/manager/resident/history.d.ts.map +1 -0
  67. package/dist/manager/resident/history.js +203 -0
  68. package/dist/manager/resident/history.js.map +1 -0
  69. package/dist/manager/resident/initiative.d.ts.map +1 -1
  70. package/dist/manager/resident/initiative.js +11 -3
  71. package/dist/manager/resident/initiative.js.map +1 -1
  72. package/dist/manager/resident/learning-cycle.d.ts +131 -0
  73. package/dist/manager/resident/learning-cycle.d.ts.map +1 -0
  74. package/dist/manager/resident/learning-cycle.js +306 -0
  75. package/dist/manager/resident/learning-cycle.js.map +1 -0
  76. package/dist/manager/resident/learning-observation.d.ts +80 -0
  77. package/dist/manager/resident/learning-observation.d.ts.map +1 -0
  78. package/dist/manager/resident/learning-observation.js +22 -0
  79. package/dist/manager/resident/learning-observation.js.map +1 -0
  80. package/dist/manager/resident/learning-store.d.ts +106 -0
  81. package/dist/manager/resident/learning-store.d.ts.map +1 -0
  82. package/dist/manager/resident/learning-store.js +598 -0
  83. package/dist/manager/resident/learning-store.js.map +1 -0
  84. package/dist/manager/resident/learning.d.ts +246 -3
  85. package/dist/manager/resident/learning.d.ts.map +1 -1
  86. package/dist/manager/resident/learning.js +96 -6
  87. package/dist/manager/resident/learning.js.map +1 -1
  88. package/dist/manager/resident/outbox.d.ts +4 -4
  89. package/dist/manager/resident/store.d.ts +37 -4
  90. package/dist/manager/resident/store.d.ts.map +1 -1
  91. package/dist/manager/resident/store.js +27 -3
  92. package/dist/manager/resident/store.js.map +1 -1
  93. package/dist/manager/resident/tool-evidence.d.ts +71 -0
  94. package/dist/manager/resident/tool-evidence.d.ts.map +1 -0
  95. package/dist/manager/resident/tool-evidence.js +285 -0
  96. package/dist/manager/resident/tool-evidence.js.map +1 -0
  97. package/dist/manager/run/persistence.d.ts +8 -0
  98. package/dist/manager/run/persistence.d.ts.map +1 -1
  99. package/dist/manager/run/persistence.js +18 -0
  100. package/dist/manager/run/persistence.js.map +1 -1
  101. package/dist/plugin/loader.d.ts.map +1 -1
  102. package/dist/plugin/loader.js +5 -3
  103. package/dist/plugin/loader.js.map +1 -1
  104. package/dist/prompt/coding-agent-doctrine.d.ts +1 -1
  105. package/dist/prompt/coding-agent-doctrine.d.ts.map +1 -1
  106. package/dist/prompt/coding-agent-doctrine.js +2 -0
  107. package/dist/prompt/coding-agent-doctrine.js.map +1 -1
  108. package/dist/prompt/index.d.ts +2 -0
  109. package/dist/prompt/index.d.ts.map +1 -1
  110. package/dist/prompt/index.js +1 -0
  111. package/dist/prompt/index.js.map +1 -1
  112. package/dist/prompt/resident-learning.d.ts +19 -0
  113. package/dist/prompt/resident-learning.d.ts.map +1 -0
  114. package/dist/prompt/resident-learning.js +125 -0
  115. package/dist/prompt/resident-learning.js.map +1 -0
  116. package/dist/prompt/resident-step.d.ts +8 -1
  117. package/dist/prompt/resident-step.d.ts.map +1 -1
  118. package/dist/prompt/resident-step.js +65 -4
  119. package/dist/prompt/resident-step.js.map +1 -1
  120. package/dist/provider/collect-chat-completion.d.ts +2 -1
  121. package/dist/provider/collect-chat-completion.d.ts.map +1 -1
  122. package/dist/provider/collect-chat-completion.js +7 -6
  123. package/dist/provider/collect-chat-completion.js.map +1 -1
  124. package/dist/provider/fallback.d.ts.map +1 -1
  125. package/dist/provider/fallback.js +2 -1
  126. package/dist/provider/fallback.js.map +1 -1
  127. package/dist/provider/stream-text.d.ts +16 -0
  128. package/dist/provider/stream-text.d.ts.map +1 -0
  129. package/dist/provider/stream-text.js +51 -0
  130. package/dist/provider/stream-text.js.map +1 -0
  131. package/dist/public-runtime.d.ts +16 -4
  132. package/dist/public-runtime.d.ts.map +1 -1
  133. package/dist/public-runtime.js +17 -4
  134. package/dist/public-runtime.js.map +1 -1
  135. package/dist/public-tools.d.ts +13 -0
  136. package/dist/public-tools.d.ts.map +1 -1
  137. package/dist/public-tools.js +16 -0
  138. package/dist/public-tools.js.map +1 -1
  139. package/dist/public-types.d.ts +15 -3
  140. package/dist/public-types.d.ts.map +1 -1
  141. package/dist/registry/tool/execute.d.ts.map +1 -1
  142. package/dist/registry/tool/execute.js +2 -3
  143. package/dist/registry/tool/execute.js.map +1 -1
  144. package/dist/registry/tool/portable.d.ts +65 -0
  145. package/dist/registry/tool/portable.d.ts.map +1 -0
  146. package/dist/registry/tool/portable.js +244 -0
  147. package/dist/registry/tool/portable.js.map +1 -0
  148. package/dist/registry/tool/schema.d.ts +32 -5
  149. package/dist/registry/tool/schema.d.ts.map +1 -1
  150. package/dist/registry/tool/schema.js +35 -9
  151. package/dist/registry/tool/schema.js.map +1 -1
  152. package/dist/registry/toolset/catalog.js +8 -8
  153. package/dist/registry/toolset/catalog.js.map +1 -1
  154. package/dist/run/LimitChecker.js +3 -3
  155. package/dist/run/LimitChecker.js.map +1 -1
  156. package/dist/run/evidence-query.d.ts +41 -0
  157. package/dist/run/evidence-query.d.ts.map +1 -0
  158. package/dist/run/evidence-query.js +270 -0
  159. package/dist/run/evidence-query.js.map +1 -0
  160. package/dist/run/evidence-recall.d.ts +99 -0
  161. package/dist/run/evidence-recall.d.ts.map +1 -0
  162. package/dist/run/evidence-recall.js +633 -0
  163. package/dist/run/evidence-recall.js.map +1 -0
  164. package/dist/run/index.d.ts +2 -0
  165. package/dist/run/index.d.ts.map +1 -1
  166. package/dist/run/index.js +1 -0
  167. package/dist/run/index.js.map +1 -1
  168. package/dist/run/json-claim-verifier.d.ts +83 -0
  169. package/dist/run/json-claim-verifier.d.ts.map +1 -0
  170. package/dist/run/json-claim-verifier.js +200 -0
  171. package/dist/run/json-claim-verifier.js.map +1 -0
  172. package/dist/run/preparation-context-error.d.ts +10 -0
  173. package/dist/run/preparation-context-error.d.ts.map +1 -0
  174. package/dist/run/preparation-context-error.js +15 -0
  175. package/dist/run/preparation-context-error.js.map +1 -0
  176. package/dist/run-query/index.d.ts +3 -1
  177. package/dist/run-query/index.d.ts.map +1 -1
  178. package/dist/runtime/jobs/awaited-jobs.d.ts +215 -0
  179. package/dist/runtime/jobs/awaited-jobs.d.ts.map +1 -0
  180. package/dist/runtime/jobs/awaited-jobs.js +259 -0
  181. package/dist/runtime/jobs/awaited-jobs.js.map +1 -0
  182. package/dist/runtime/jobs/registry.d.ts +33 -2
  183. package/dist/runtime/jobs/registry.d.ts.map +1 -1
  184. package/dist/runtime/jobs/registry.js +37 -0
  185. package/dist/runtime/jobs/registry.js.map +1 -1
  186. package/dist/runtime/query/callback-inference.d.ts +8 -0
  187. package/dist/runtime/query/callback-inference.d.ts.map +1 -0
  188. package/dist/runtime/query/callback-inference.js +89 -0
  189. package/dist/runtime/query/callback-inference.js.map +1 -0
  190. package/dist/runtime/query/checkpoint.d.ts +4 -0
  191. package/dist/runtime/query/checkpoint.d.ts.map +1 -1
  192. package/dist/runtime/query/checkpoint.js +13 -0
  193. package/dist/runtime/query/checkpoint.js.map +1 -1
  194. package/dist/runtime/query/events.d.ts +1 -0
  195. package/dist/runtime/query/events.d.ts.map +1 -1
  196. package/dist/runtime/query/events.js +18 -0
  197. package/dist/runtime/query/events.js.map +1 -1
  198. package/dist/runtime/query/executor.d.ts +35 -1
  199. package/dist/runtime/query/executor.d.ts.map +1 -1
  200. package/dist/runtime/query/executor.js +77 -8
  201. package/dist/runtime/query/executor.js.map +1 -1
  202. package/dist/runtime/query/file-evidence-context.d.ts +5 -0
  203. package/dist/runtime/query/file-evidence-context.d.ts.map +1 -0
  204. package/dist/runtime/query/file-evidence-context.js +180 -0
  205. package/dist/runtime/query/file-evidence-context.js.map +1 -0
  206. package/dist/runtime/query/file-evidence-replay.d.ts +260 -0
  207. package/dist/runtime/query/file-evidence-replay.d.ts.map +1 -0
  208. package/dist/runtime/query/file-evidence-replay.js +647 -0
  209. package/dist/runtime/query/file-evidence-replay.js.map +1 -0
  210. package/dist/runtime/query/file-evidence-seed.d.ts +50 -0
  211. package/dist/runtime/query/file-evidence-seed.d.ts.map +1 -0
  212. package/dist/runtime/query/file-evidence-seed.js +100 -0
  213. package/dist/runtime/query/file-evidence-seed.js.map +1 -0
  214. package/dist/runtime/query/guard.d.ts.map +1 -1
  215. package/dist/runtime/query/guard.js +4 -0
  216. package/dist/runtime/query/guard.js.map +1 -1
  217. package/dist/runtime/query/index.d.ts +10 -1
  218. package/dist/runtime/query/index.d.ts.map +1 -1
  219. package/dist/runtime/query/index.js +133 -26
  220. package/dist/runtime/query/index.js.map +1 -1
  221. package/dist/runtime/query/iteration/index.d.ts +92 -36
  222. package/dist/runtime/query/iteration/index.d.ts.map +1 -1
  223. package/dist/runtime/query/iteration/index.js +420 -117
  224. package/dist/runtime/query/iteration/index.js.map +1 -1
  225. package/dist/runtime/query/iteration/phases/advisory.d.ts +2 -1
  226. package/dist/runtime/query/iteration/phases/advisory.d.ts.map +1 -1
  227. package/dist/runtime/query/iteration/phases/advisory.js +2 -1
  228. package/dist/runtime/query/iteration/phases/advisory.js.map +1 -1
  229. package/dist/runtime/query/iteration/phases/context.d.ts +12 -1
  230. package/dist/runtime/query/iteration/phases/context.d.ts.map +1 -1
  231. package/dist/runtime/query/iteration/phases/context.js.map +1 -1
  232. package/dist/runtime/query/iteration/phases/tool-review.d.ts.map +1 -1
  233. package/dist/runtime/query/iteration/phases/tool-review.js +8 -1
  234. package/dist/runtime/query/iteration/phases/tool-review.js.map +1 -1
  235. package/dist/runtime/query/iteration/provider-rejected-image.d.ts +2 -1
  236. package/dist/runtime/query/iteration/provider-rejected-image.d.ts.map +1 -1
  237. package/dist/runtime/query/iteration/provider-rejected-image.js +5 -2
  238. package/dist/runtime/query/iteration/provider-rejected-image.js.map +1 -1
  239. package/dist/runtime/query/iteration/stream-turn.d.ts +4 -1
  240. package/dist/runtime/query/iteration/stream-turn.d.ts.map +1 -1
  241. package/dist/runtime/query/iteration/stream-turn.js +22 -8
  242. package/dist/runtime/query/iteration/stream-turn.js.map +1 -1
  243. package/dist/runtime/query/plugin-hooks.d.ts +14 -0
  244. package/dist/runtime/query/plugin-hooks.d.ts.map +1 -1
  245. package/dist/runtime/query/plugin-hooks.js +18 -0
  246. package/dist/runtime/query/plugin-hooks.js.map +1 -1
  247. package/dist/runtime/query/repeat-call.d.ts +17 -4
  248. package/dist/runtime/query/repeat-call.d.ts.map +1 -1
  249. package/dist/runtime/query/repeat-call.js +26 -19
  250. package/dist/runtime/query/repeat-call.js.map +1 -1
  251. package/dist/runtime/query/resume-pending.d.ts +18 -33
  252. package/dist/runtime/query/resume-pending.d.ts.map +1 -1
  253. package/dist/runtime/query/resume-pending.js +59 -42
  254. package/dist/runtime/query/resume-pending.js.map +1 -1
  255. package/dist/runtime/query/review-policy.d.ts +4 -4
  256. package/dist/runtime/query/review-policy.d.ts.map +1 -1
  257. package/dist/runtime/query/review-policy.js +10 -9
  258. package/dist/runtime/query/review-policy.js.map +1 -1
  259. package/dist/runtime/query/sandbox-lifecycle.d.ts.map +1 -1
  260. package/dist/runtime/query/sandbox-lifecycle.js +4 -0
  261. package/dist/runtime/query/sandbox-lifecycle.js.map +1 -1
  262. package/dist/runtime/query/steering.d.ts +11 -1
  263. package/dist/runtime/query/steering.d.ts.map +1 -1
  264. package/dist/runtime/query/steering.js +12 -1
  265. package/dist/runtime/query/steering.js.map +1 -1
  266. package/dist/runtime/query/tool-output-budget.d.ts +10 -6
  267. package/dist/runtime/query/tool-output-budget.d.ts.map +1 -1
  268. package/dist/runtime/query/tool-output-budget.js +54 -12
  269. package/dist/runtime/query/tool-output-budget.js.map +1 -1
  270. package/dist/runtime/query/tooling.d.ts +5 -1
  271. package/dist/runtime/query/tooling.d.ts.map +1 -1
  272. package/dist/runtime/query/tooling.js +5 -0
  273. package/dist/runtime/query/tooling.js.map +1 -1
  274. package/dist/scheduler/completion-inbox.d.ts +49 -0
  275. package/dist/scheduler/completion-inbox.d.ts.map +1 -1
  276. package/dist/scheduler/completion-inbox.js +122 -2
  277. package/dist/scheduler/completion-inbox.js.map +1 -1
  278. package/dist/store/evidence/compaction-archive.d.ts +109 -0
  279. package/dist/store/evidence/compaction-archive.d.ts.map +1 -0
  280. package/dist/store/evidence/compaction-archive.js +125 -0
  281. package/dist/store/evidence/compaction-archive.js.map +1 -0
  282. package/dist/store/evidence/compaction-provenance.d.ts +7 -0
  283. package/dist/store/evidence/compaction-provenance.d.ts.map +1 -0
  284. package/dist/store/evidence/compaction-provenance.js +49 -0
  285. package/dist/store/evidence/compaction-provenance.js.map +1 -0
  286. package/dist/store/evidence/compaction-text.d.ts +16 -0
  287. package/dist/store/evidence/compaction-text.d.ts.map +1 -0
  288. package/dist/store/evidence/compaction-text.js +51 -0
  289. package/dist/store/evidence/compaction-text.js.map +1 -0
  290. package/dist/store/evidence/disk.d.ts +11 -0
  291. package/dist/store/evidence/disk.d.ts.map +1 -0
  292. package/dist/store/evidence/disk.js +367 -0
  293. package/dist/store/evidence/disk.js.map +1 -0
  294. package/dist/store/evidence/format.d.ts +25 -0
  295. package/dist/store/evidence/format.d.ts.map +1 -0
  296. package/dist/store/evidence/format.js +115 -0
  297. package/dist/store/evidence/format.js.map +1 -0
  298. package/dist/store/evidence/index-page.d.ts +208 -0
  299. package/dist/store/evidence/index-page.d.ts.map +1 -0
  300. package/dist/store/evidence/index-page.js +262 -0
  301. package/dist/store/evidence/index-page.js.map +1 -0
  302. package/dist/store/evidence/io.d.ts +24 -0
  303. package/dist/store/evidence/io.d.ts.map +1 -0
  304. package/dist/store/evidence/io.js +69 -0
  305. package/dist/store/evidence/io.js.map +1 -0
  306. package/dist/store/evidence/linked.d.ts +9 -0
  307. package/dist/store/evidence/linked.d.ts.map +1 -0
  308. package/dist/store/evidence/linked.js +314 -0
  309. package/dist/store/evidence/linked.js.map +1 -0
  310. package/dist/store/evidence/passages.d.ts +15 -0
  311. package/dist/store/evidence/passages.d.ts.map +1 -0
  312. package/dist/store/evidence/passages.js +72 -0
  313. package/dist/store/evidence/passages.js.map +1 -0
  314. package/dist/store/evidence/record-chain.d.ts +42 -0
  315. package/dist/store/evidence/record-chain.d.ts.map +1 -0
  316. package/dist/store/evidence/record-chain.js +111 -0
  317. package/dist/store/evidence/record-chain.js.map +1 -0
  318. package/dist/store/evidence/search-input.d.ts +21 -0
  319. package/dist/store/evidence/search-input.d.ts.map +1 -0
  320. package/dist/store/evidence/search-input.js +44 -0
  321. package/dist/store/evidence/search-input.js.map +1 -0
  322. package/dist/store/evidence/selection.d.ts +9 -0
  323. package/dist/store/evidence/selection.d.ts.map +1 -0
  324. package/dist/store/evidence/selection.js +17 -0
  325. package/dist/store/evidence/selection.js.map +1 -0
  326. package/dist/store/evidence/source-kind.d.ts +11 -0
  327. package/dist/store/evidence/source-kind.d.ts.map +1 -0
  328. package/dist/store/evidence/source-kind.js +26 -0
  329. package/dist/store/evidence/source-kind.js.map +1 -0
  330. package/dist/store/evidence/source-text.d.ts +51 -0
  331. package/dist/store/evidence/source-text.d.ts.map +1 -0
  332. package/dist/store/evidence/source-text.js +213 -0
  333. package/dist/store/evidence/source-text.js.map +1 -0
  334. package/dist/store/evidence/types.d.ts +162 -0
  335. package/dist/store/evidence/types.d.ts.map +1 -0
  336. package/dist/store/evidence/types.js +2 -0
  337. package/dist/store/evidence/types.js.map +1 -0
  338. package/dist/store/memory/disk.d.ts +2 -0
  339. package/dist/store/memory/disk.d.ts.map +1 -1
  340. package/dist/store/memory/disk.js +2 -1
  341. package/dist/store/memory/disk.js.map +1 -1
  342. package/dist/store/run/disk.d.ts +10 -0
  343. package/dist/store/run/disk.d.ts.map +1 -1
  344. package/dist/store/run/disk.js +87 -7
  345. package/dist/store/run/disk.js.map +1 -1
  346. package/dist/store/run/memory.d.ts +1 -0
  347. package/dist/store/run/memory.d.ts.map +1 -1
  348. package/dist/store/run/memory.js +10 -0
  349. package/dist/store/run/memory.js.map +1 -1
  350. package/dist/store/run/tool-executions.d.ts +13 -0
  351. package/dist/store/run/tool-executions.d.ts.map +1 -0
  352. package/dist/store/run/tool-executions.js +99 -0
  353. package/dist/store/run/tool-executions.js.map +1 -0
  354. package/dist/store/session/index.d.ts +2 -0
  355. package/dist/store/session/index.d.ts.map +1 -1
  356. package/dist/store/session/index.js +1 -0
  357. package/dist/store/session/index.js.map +1 -1
  358. package/dist/store/session/sqlite.d.ts +57 -0
  359. package/dist/store/session/sqlite.d.ts.map +1 -0
  360. package/dist/store/session/sqlite.js +430 -0
  361. package/dist/store/session/sqlite.js.map +1 -0
  362. package/dist/tools/builtins/bash.d.ts.map +1 -1
  363. package/dist/tools/builtins/bash.js +4 -10
  364. package/dist/tools/builtins/bash.js.map +1 -1
  365. package/dist/tools/builtins/edit-apply.d.ts +126 -0
  366. package/dist/tools/builtins/edit-apply.d.ts.map +1 -0
  367. package/dist/tools/builtins/edit-apply.js +360 -0
  368. package/dist/tools/builtins/edit-apply.js.map +1 -0
  369. package/dist/tools/builtins/edit.d.ts +143 -1
  370. package/dist/tools/builtins/edit.d.ts.map +1 -1
  371. package/dist/tools/builtins/edit.js +37 -219
  372. package/dist/tools/builtins/edit.js.map +1 -1
  373. package/dist/tools/builtins/index.d.ts +1 -0
  374. package/dist/tools/builtins/index.d.ts.map +1 -1
  375. package/dist/tools/builtins/index.js +9 -3
  376. package/dist/tools/builtins/index.js.map +1 -1
  377. package/dist/tools/builtins/job.d.ts.map +1 -1
  378. package/dist/tools/builtins/job.js +5 -6
  379. package/dist/tools/builtins/job.js.map +1 -1
  380. package/dist/tools/builtins/read-file.d.ts +2 -2
  381. package/dist/tools/builtins/read-file.d.ts.map +1 -1
  382. package/dist/tools/builtins/read-file.js +50 -65
  383. package/dist/tools/builtins/read-file.js.map +1 -1
  384. package/dist/tools/builtins/read-render.d.ts +56 -0
  385. package/dist/tools/builtins/read-render.d.ts.map +1 -0
  386. package/dist/tools/builtins/read-render.js +73 -0
  387. package/dist/tools/builtins/read-render.js.map +1 -0
  388. package/dist/tools/builtins/wait-for-job-bounds.d.ts +67 -0
  389. package/dist/tools/builtins/wait-for-job-bounds.d.ts.map +1 -0
  390. package/dist/tools/builtins/wait-for-job-bounds.js +108 -0
  391. package/dist/tools/builtins/wait-for-job-bounds.js.map +1 -0
  392. package/dist/tools/builtins/wait-for-job.d.ts +6 -0
  393. package/dist/tools/builtins/wait-for-job.d.ts.map +1 -0
  394. package/dist/tools/builtins/wait-for-job.js +162 -0
  395. package/dist/tools/builtins/wait-for-job.js.map +1 -0
  396. package/dist/tools/builtins/write-file.js +7 -2
  397. package/dist/tools/builtins/write-file.js.map +1 -1
  398. package/dist/tools/coordinator/index.d.ts.map +1 -1
  399. package/dist/tools/coordinator/index.js +1 -7
  400. package/dist/tools/coordinator/index.js.map +1 -1
  401. package/dist/tools/defineTool.d.ts +2 -1
  402. package/dist/tools/defineTool.d.ts.map +1 -1
  403. package/dist/tools/defineTool.js +1 -1
  404. package/dist/tools/defineTool.js.map +1 -1
  405. package/dist/tools/file-read-tracker.d.ts.map +1 -1
  406. package/dist/tools/file-read-tracker.js +90 -3
  407. package/dist/tools/file-read-tracker.js.map +1 -1
  408. package/dist/tools/resident-history.d.ts +10 -0
  409. package/dist/tools/resident-history.d.ts.map +1 -0
  410. package/dist/tools/resident-history.js +80 -0
  411. package/dist/tools/resident-history.js.map +1 -0
  412. package/dist/tools/resident-tool-evidence.d.ts +5 -0
  413. package/dist/tools/resident-tool-evidence.d.ts.map +1 -0
  414. package/dist/tools/resident-tool-evidence.js +57 -0
  415. package/dist/tools/resident-tool-evidence.js.map +1 -0
  416. package/dist/types/advisory/config.d.ts +7 -0
  417. package/dist/types/advisory/config.d.ts.map +1 -1
  418. package/dist/types/agent/reactive.d.ts +1 -0
  419. package/dist/types/agent/reactive.d.ts.map +1 -1
  420. package/dist/types/authorization/index.d.ts +9 -9
  421. package/dist/types/authorization/index.d.ts.map +1 -1
  422. package/dist/types/authorization/index.js +1 -1
  423. package/dist/types/authorization/index.js.map +1 -1
  424. package/dist/types/hitl/index.d.ts +4 -0
  425. package/dist/types/hitl/index.d.ts.map +1 -1
  426. package/dist/types/hitl/index.js.map +1 -1
  427. package/dist/types/message/index.d.ts +16 -2
  428. package/dist/types/message/index.d.ts.map +1 -1
  429. package/dist/types/message/index.js +10 -1
  430. package/dist/types/message/index.js.map +1 -1
  431. package/dist/types/provider/chat.d.ts +2 -0
  432. package/dist/types/provider/chat.d.ts.map +1 -1
  433. package/dist/types/provider/stream.d.ts +4 -0
  434. package/dist/types/provider/stream.d.ts.map +1 -1
  435. package/dist/types/run/answer-review.d.ts +34 -3
  436. package/dist/types/run/answer-review.d.ts.map +1 -1
  437. package/dist/types/run/config.d.ts +3 -0
  438. package/dist/types/run/config.d.ts.map +1 -1
  439. package/dist/types/run/entity.d.ts +20 -0
  440. package/dist/types/run/entity.d.ts.map +1 -1
  441. package/dist/types/run/events.d.ts +31 -8
  442. package/dist/types/run/events.d.ts.map +1 -1
  443. package/dist/types/run/events.js.map +1 -1
  444. package/dist/types/run/prepare-step.d.ts +53 -8
  445. package/dist/types/run/prepare-step.d.ts.map +1 -1
  446. package/dist/types/run/store.d.ts +29 -4
  447. package/dist/types/run/store.d.ts.map +1 -1
  448. package/dist/types/run/store.js +0 -28
  449. package/dist/types/run/store.js.map +1 -1
  450. package/dist/types/sandbox/index.d.ts +15 -14
  451. package/dist/types/sandbox/index.d.ts.map +1 -1
  452. package/dist/types/sandbox/index.js.map +1 -1
  453. package/dist/types/tool/index.d.ts +124 -1
  454. package/dist/types/tool/index.d.ts.map +1 -1
  455. package/dist/types/tool/index.js.map +1 -1
  456. package/dist/utils/await-with-abort.d.ts +8 -0
  457. package/dist/utils/await-with-abort.d.ts.map +1 -0
  458. package/dist/utils/await-with-abort.js +28 -0
  459. package/dist/utils/await-with-abort.js.map +1 -0
  460. package/dist/utils/env.d.ts +19 -0
  461. package/dist/utils/env.d.ts.map +1 -0
  462. package/dist/utils/env.js +25 -0
  463. package/dist/utils/env.js.map +1 -0
  464. package/dist/utils/evidence-time.d.ts +3 -0
  465. package/dist/utils/evidence-time.d.ts.map +1 -0
  466. package/dist/utils/evidence-time.js +10 -0
  467. package/dist/utils/evidence-time.js.map +1 -0
  468. package/dist/utils/evidence-tokens.d.ts +13 -0
  469. package/dist/utils/evidence-tokens.d.ts.map +1 -0
  470. package/dist/utils/evidence-tokens.js +29 -0
  471. package/dist/utils/evidence-tokens.js.map +1 -0
  472. package/package.json +1 -1
  473. package/src/advisory/executor.ts +15 -30
  474. package/src/advisory/history.ts +126 -0
  475. package/src/advisory/index.ts +5 -1
  476. package/src/agents/ReactiveAgent.ts +3 -0
  477. package/src/agents/runAgent.ts +14 -1
  478. package/src/compaction/manual.ts +30 -2
  479. package/src/compaction/summary.ts +4 -1
  480. package/src/config/runtime.ts +2 -2
  481. package/src/connector/mcp/adapter.ts +20 -6
  482. package/src/contracts/schemas.ts +1 -1
  483. package/src/eval/harness-protection.ts +79 -0
  484. package/src/eval/harness-verification.ts +31 -1
  485. package/src/eval/index.ts +1 -0
  486. package/src/manager/resident/activity.ts +187 -0
  487. package/src/manager/resident/agenda.ts +59 -5
  488. package/src/manager/resident/consumption.ts +311 -0
  489. package/src/manager/resident/evidence-recall.ts +363 -0
  490. package/src/manager/resident/history-disk.ts +63 -0
  491. package/src/manager/resident/history.ts +312 -0
  492. package/src/manager/resident/initiative.ts +13 -3
  493. package/src/manager/resident/learning-cycle.ts +499 -0
  494. package/src/manager/resident/learning-observation.ts +39 -0
  495. package/src/manager/resident/learning-store.ts +813 -0
  496. package/src/manager/resident/learning.ts +132 -8
  497. package/src/manager/resident/store.ts +31 -3
  498. package/src/manager/resident/tool-evidence.ts +412 -0
  499. package/src/manager/run/persistence.ts +18 -0
  500. package/src/plugin/loader.ts +8 -3
  501. package/src/prompt/coding-agent-doctrine.ts +2 -0
  502. package/src/prompt/index.ts +2 -0
  503. package/src/prompt/resident-learning.ts +143 -0
  504. package/src/prompt/resident-step.ts +83 -3
  505. package/src/provider/collect-chat-completion.ts +7 -6
  506. package/src/provider/fallback.ts +2 -1
  507. package/src/provider/stream-text.ts +56 -0
  508. package/src/public-runtime.ts +39 -1
  509. package/src/public-tools.ts +21 -0
  510. package/src/public-types.ts +98 -0
  511. package/src/registry/tool/execute.ts +2 -4
  512. package/src/registry/tool/portable.ts +264 -0
  513. package/src/registry/tool/schema.ts +38 -8
  514. package/src/registry/toolset/catalog.ts +8 -9
  515. package/src/run/LimitChecker.ts +3 -3
  516. package/src/run/evidence-query.ts +333 -0
  517. package/src/run/evidence-recall.ts +854 -0
  518. package/src/run/index.ts +11 -0
  519. package/src/run/json-claim-verifier.ts +298 -0
  520. package/src/run/preparation-context-error.ts +16 -0
  521. package/src/run-query/index.ts +1 -1
  522. package/src/runtime/jobs/awaited-jobs.ts +271 -0
  523. package/src/runtime/jobs/registry.ts +50 -0
  524. package/src/runtime/query/callback-inference.ts +94 -0
  525. package/src/runtime/query/checkpoint.ts +14 -0
  526. package/src/runtime/query/events.ts +22 -0
  527. package/src/runtime/query/executor.ts +100 -10
  528. package/src/runtime/query/file-evidence-context.ts +209 -0
  529. package/src/runtime/query/file-evidence-replay.ts +776 -0
  530. package/src/runtime/query/file-evidence-seed.ts +126 -0
  531. package/src/runtime/query/guard.ts +2 -0
  532. package/src/runtime/query/index.ts +153 -27
  533. package/src/runtime/query/iteration/index.ts +467 -110
  534. package/src/runtime/query/iteration/phases/advisory.ts +3 -0
  535. package/src/runtime/query/iteration/phases/context.ts +12 -0
  536. package/src/runtime/query/iteration/phases/tool-review.ts +7 -0
  537. package/src/runtime/query/iteration/provider-rejected-image.ts +6 -1
  538. package/src/runtime/query/iteration/stream-turn.ts +35 -8
  539. package/src/runtime/query/plugin-hooks.ts +20 -0
  540. package/src/runtime/query/repeat-call.ts +28 -18
  541. package/src/runtime/query/resume-pending.ts +65 -40
  542. package/src/runtime/query/review-policy.ts +13 -9
  543. package/src/runtime/query/sandbox-lifecycle.ts +3 -0
  544. package/src/runtime/query/steering.ts +11 -0
  545. package/src/runtime/query/tool-output-budget.ts +65 -13
  546. package/src/runtime/query/tooling.ts +10 -1
  547. package/src/scheduler/completion-inbox.ts +124 -2
  548. package/src/store/evidence/compaction-archive.ts +139 -0
  549. package/src/store/evidence/compaction-provenance.ts +52 -0
  550. package/src/store/evidence/compaction-text.ts +61 -0
  551. package/src/store/evidence/disk.ts +461 -0
  552. package/src/store/evidence/format.ts +126 -0
  553. package/src/store/evidence/index-page.ts +292 -0
  554. package/src/store/evidence/io.ts +95 -0
  555. package/src/store/evidence/linked.ts +365 -0
  556. package/src/store/evidence/passages.ts +88 -0
  557. package/src/store/evidence/record-chain.ts +108 -0
  558. package/src/store/evidence/search-input.ts +62 -0
  559. package/src/store/evidence/selection.ts +25 -0
  560. package/src/store/evidence/source-kind.ts +36 -0
  561. package/src/store/evidence/source-text.ts +285 -0
  562. package/src/store/evidence/types.ts +177 -0
  563. package/src/store/memory/disk.ts +4 -1
  564. package/src/store/run/disk.ts +110 -8
  565. package/src/store/run/memory.ts +10 -0
  566. package/src/store/run/tool-executions.ts +112 -0
  567. package/src/store/session/index.ts +2 -0
  568. package/src/store/session/sqlite.ts +584 -0
  569. package/src/tools/builtins/bash.ts +4 -10
  570. package/src/tools/builtins/edit-apply.ts +456 -0
  571. package/src/tools/builtins/edit.ts +39 -270
  572. package/src/tools/builtins/index.ts +9 -3
  573. package/src/tools/builtins/job.ts +5 -6
  574. package/src/tools/builtins/read-file.ts +56 -77
  575. package/src/tools/builtins/read-render.ts +104 -0
  576. package/src/tools/builtins/wait-for-job-bounds.ts +179 -0
  577. package/src/tools/builtins/wait-for-job.ts +184 -0
  578. package/src/tools/builtins/write-file.ts +7 -2
  579. package/src/tools/coordinator/index.ts +1 -7
  580. package/src/tools/defineTool.ts +4 -2
  581. package/src/tools/file-read-tracker.ts +86 -2
  582. package/src/tools/resident-history.ts +86 -0
  583. package/src/tools/resident-tool-evidence.ts +68 -0
  584. package/src/types/advisory/config.ts +7 -0
  585. package/src/types/agent/reactive.ts +1 -0
  586. package/src/types/authorization/index.ts +2 -2
  587. package/src/types/hitl/index.ts +4 -0
  588. package/src/types/message/index.ts +22 -0
  589. package/src/types/provider/chat.ts +2 -0
  590. package/src/types/provider/stream.ts +4 -0
  591. package/src/types/run/answer-review.ts +34 -3
  592. package/src/types/run/config.ts +3 -0
  593. package/src/types/run/entity.ts +21 -0
  594. package/src/types/run/events.ts +31 -8
  595. package/src/types/run/prepare-step.ts +59 -8
  596. package/src/types/run/store.ts +35 -4
  597. package/src/types/sandbox/index.ts +15 -14
  598. package/src/types/tool/index.ts +123 -1
  599. package/src/utils/await-with-abort.ts +26 -0
  600. package/src/utils/env.ts +23 -0
  601. package/src/utils/evidence-time.ts +9 -0
  602. package/src/utils/evidence-tokens.ts +32 -0
@@ -0,0 +1,104 @@
1
+ /**
2
+ * How `read` turns a file's body into the text the model sees.
3
+ *
4
+ * Pulled out of the tool for the reason `edit-apply` was: a second caller —
5
+ * the resume seed, deciding whether a `read` receipt in history shows exactly
6
+ * the body it already believes the file had — has to produce byte-for-byte
7
+ * what the tool produced, and a parallel implementation of the numbering or
8
+ * the window arithmetic would silently stop agreeing with it.
9
+ *
10
+ * Pure by construction: no filesystem access, no `ToolContext`.
11
+ */
12
+
13
+ /**
14
+ * Lines returned when the caller specifies no window.
15
+ *
16
+ * Chosen to cover the overwhelming majority of source files whole while
17
+ * bounding the pathological case.
18
+ */
19
+ export const DEFAULT_READ_LINES = 2000
20
+
21
+ /** The window fields of `read`'s input; the path plays no part in rendering. */
22
+ export interface ReadWindowRequest {
23
+ /**
24
+ * `[start, end]`, 1-indexed inclusive.
25
+ *
26
+ * Typed as a number array rather than a pair because the tool's schema
27
+ * pins the length at two with `.length(2)` instead of a `z.tuple` — a
28
+ * tuple renders as draft-07 `items: [a, b]`, which a 2020-12 wire refuses.
29
+ * The parse still rejects any other length, so a caller reaching here has
30
+ * two numbers; `resolveReadWindow` reads them defensively anyway, because
31
+ * this interface is also implemented by hand elsewhere in the kernel.
32
+ */
33
+ readonly readRange?: readonly number[]
34
+ readonly offset?: number
35
+ readonly limit?: number
36
+ }
37
+
38
+ export interface RenderedRead {
39
+ /** Exactly what `read` returns as its output for this body and window. */
40
+ readonly output: string
41
+ readonly totalLines: number
42
+ readonly returnedLines: number
43
+ /** Whether the window left any of the file out, which is what adds the notice. */
44
+ readonly partial: boolean
45
+ }
46
+
47
+ /**
48
+ * Render `content` the way `read` renders it.
49
+ *
50
+ * The numbering is what makes this reversible enough to compare against: every
51
+ * line goes out behind its own `${n}\t`, so two different bodies cannot render
52
+ * to one string, and the partial-view notice below — whose lines carry no such
53
+ * prefix — cannot be mistaken for part of a body.
54
+ */
55
+ export function renderNumberedRead(content: string, input: ReadWindowRequest): RenderedRead {
56
+ const lines = content.split('\n')
57
+ const { start, end } = resolveReadWindow(input, lines.length)
58
+ const selected = lines.slice(start, end)
59
+ const numbered = selected.map((line, i) => `${start + i + 1}\t${line}`).join('\n')
60
+ return {
61
+ output: numbered + partialViewNotice(start, selected.length, lines.length),
62
+ totalLines: lines.length,
63
+ returnedLines: selected.length,
64
+ partial: selected.length < lines.length,
65
+ }
66
+ }
67
+
68
+ /**
69
+ * Tell the model, explicitly, when it is looking at a window rather than
70
+ * the file.
71
+ *
72
+ * Without this a truncated read is indistinguishable from a short file, and
73
+ * the agent reasons about a fragment as if it were the whole thing — the
74
+ * most expensive silent failure a read tool can have. The notice names the
75
+ * exact next call rather than describing it.
76
+ */
77
+ function partialViewNotice(start: number, returned: number, total: number): string {
78
+ if (returned >= total) return ''
79
+ const shownTo = start + returned
80
+ return [
81
+ '',
82
+ '',
83
+ `[PARTIAL view — lines ${start + 1}-${shownTo} of ${total}.`,
84
+ `Continue with read({ offset: ${shownTo}, limit: N }), or narrow with grep.]`,
85
+ ].join('\n')
86
+ }
87
+
88
+ export function resolveReadWindow(
89
+ input: ReadWindowRequest,
90
+ totalLines: number,
91
+ ): { start: number; end: number } {
92
+ const [first, last] = input.readRange ?? []
93
+ if (first !== undefined && last !== undefined) {
94
+ const start = Math.max(0, first - 1)
95
+ const end = Math.min(totalLines, Math.max(start, last))
96
+ return { start, end }
97
+ }
98
+ const start = Math.max(0, input.offset ?? 0)
99
+ // A bare `read({ path })` used to return the entire file, so a 2 MB
100
+ // lockfile became ~500k tokens in one tool_result. Default to a window
101
+ // and say so in the output; the model asks for more when it needs it.
102
+ const end = input.limit ? start + input.limit : Math.min(totalLines, start + DEFAULT_READ_LINES)
103
+ return { start, end }
104
+ }
@@ -0,0 +1,179 @@
1
+ import type { BackgroundJobRegistryRef } from '../../types/tool/index.js'
2
+
3
+ /**
4
+ * Waiting on a background job, bounded by two different questions — the
5
+ * shell-job counterpart to `waitForTaskWithBounds`
6
+ * (`../coordinator/wait-with-idle-bound.ts`), which this mirrors.
7
+ *
8
+ * A delegated agent task reports its own progress through
9
+ * `TaskScheduler.onTaskProgress`. A shell job has no such channel: the only
10
+ * signal it ever produces is bytes on stdout/stderr. So where the task
11
+ * version resets its idle clock on a progress EVENT, this one resets it on
12
+ * OBSERVED OUTPUT GROWTH — read on every tick, compared against the last
13
+ * tick's offset. A tick that finds nothing new is not progress; treating it
14
+ * as progress would make the idle bound unable to fire for a wedged job at
15
+ * all, which is the exact failure this exists to catch.
16
+ *
17
+ * - the **run bound** counts elapsed time and is never refreshed. It
18
+ * exists for a job that stays busy forever (a server, a stuck build).
19
+ * - the **idle bound** counts time since output last grew, and resets
20
+ * whenever it does. It exists for a job that stopped producing anything
21
+ * without exiting.
22
+ *
23
+ * Neither bound cancels the job. A wait that ran out is a statement about
24
+ * the WAITER, not the work — the job keeps running, and its output is still
25
+ * there to read with `job` or a later `wait_for_job` call.
26
+ */
27
+ export interface JobWaitOptions {
28
+ /** Elapsed-time ceiling, never refreshed. */
29
+ readonly runMs: number
30
+ /**
31
+ * Time-without-new-output ceiling, refreshed whenever `read` returns
32
+ * more than it did last tick. Omit to bound by the run clock alone.
33
+ */
34
+ readonly idleMs?: number
35
+ /** Resume from here rather than the start of what the job has retained. */
36
+ readonly fromOffset?: number
37
+ /** Stop preempts a wait that has not resolved yet; the job is untouched. */
38
+ readonly signal?: AbortSignal
39
+ }
40
+
41
+ interface JobWaitProgress {
42
+ readonly output: string
43
+ readonly nextOffset: number
44
+ readonly droppedBytes: number
45
+ }
46
+
47
+ export type JobWaitOutcome =
48
+ | ({
49
+ readonly kind: 'exited'
50
+ readonly status: string
51
+ readonly exitCode?: number
52
+ } & JobWaitProgress)
53
+ | ({
54
+ readonly kind: 'timeout'
55
+ /** Which clock ran out. */
56
+ readonly cause: 'idle' | 'run'
57
+ readonly elapsedMs: number
58
+ } & JobWaitProgress)
59
+
60
+ /**
61
+ * How often the bounds are checked, and how often output is drained.
62
+ *
63
+ * Coarse on purpose, same reasoning as the task version's own interval:
64
+ * both bounds are measured in minutes, so a second of latency noticing
65
+ * either one is irrelevant, and this is an internal timer, not a model
66
+ * turn — it costs nothing external no matter how often it fires.
67
+ */
68
+ const POLL_INTERVAL_MS = 1_000
69
+
70
+ /**
71
+ * Await a job under both bounds, accumulating its output as it goes.
72
+ *
73
+ * Returns the output gathered so far either way: a completed wait has all
74
+ * of it, and a timed-out one has everything read up to the moment it gave
75
+ * up, so the caller never has to throw away a partial answer.
76
+ */
77
+ export async function waitForJobWithBounds(
78
+ jobs: Pick<BackgroundJobRegistryRef, 'read' | 'waitForExit'>,
79
+ id: string,
80
+ options: JobWaitOptions,
81
+ now: () => number = Date.now,
82
+ ): Promise<JobWaitOutcome> {
83
+ if (!jobs.waitForExit) {
84
+ throw new Error('This background job registry cannot wait for a job to exit.')
85
+ }
86
+ const waitForExit = jobs.waitForExit.bind(jobs)
87
+
88
+ const startedAt = now()
89
+ let lastProgressAt = startedAt
90
+ let cursor = options.fromOffset ?? 0
91
+ let output = ''
92
+ let droppedBytes = 0
93
+ let settled = false
94
+
95
+ /** Read whatever is new since `cursor`, and count it as progress if it is. */
96
+ const drain = (): void => {
97
+ const chunk = jobs.read(id, { fromOffset: cursor })
98
+ if (chunk.droppedBytes > 0) droppedBytes += chunk.droppedBytes
99
+ if (chunk.nextOffset > cursor) lastProgressAt = now()
100
+ cursor = chunk.nextOffset
101
+ if (chunk.chunk) output += chunk.chunk
102
+ }
103
+
104
+ try {
105
+ const exited = waitForExit(id, { signal: options.signal }).then((job): JobWaitOutcome => {
106
+ // One last read: the job can exit between ticks, and the bytes
107
+ // it wrote in its final moment are exactly the ones a caller
108
+ // most wants — the error, the summary line, the exit trace.
109
+ drain()
110
+ return {
111
+ kind: 'exited',
112
+ status: job.status,
113
+ ...(job.exitCode === undefined ? {} : { exitCode: job.exitCode }),
114
+ output,
115
+ nextOffset: cursor,
116
+ droppedBytes,
117
+ }
118
+ })
119
+
120
+ const expiry = new Promise<JobWaitOutcome>((resolve) => {
121
+ // Polled rather than scheduled, for the same reason the task
122
+ // version is: the idle deadline MOVES on every byte of new
123
+ // output, and a timer armed for it would have to be cleared and
124
+ // rearmed on every tick that mattered.
125
+ const tick = setInterval(() => {
126
+ if (settled) return
127
+ drain()
128
+ const elapsed = now() - startedAt
129
+ if (elapsed >= options.runMs) {
130
+ clearInterval(tick)
131
+ resolve({
132
+ kind: 'timeout',
133
+ cause: 'run',
134
+ elapsedMs: elapsed,
135
+ output,
136
+ nextOffset: cursor,
137
+ droppedBytes,
138
+ })
139
+ return
140
+ }
141
+ if (options.idleMs !== undefined) {
142
+ const quietFor = now() - lastProgressAt
143
+ if (quietFor >= options.idleMs) {
144
+ clearInterval(tick)
145
+ resolve({
146
+ kind: 'timeout',
147
+ cause: 'idle',
148
+ elapsedMs: elapsed,
149
+ output,
150
+ nextOffset: cursor,
151
+ droppedBytes,
152
+ })
153
+ }
154
+ }
155
+ }, POLL_INTERVAL_MS)
156
+ // Never the reason a process stays alive — this races a real
157
+ // exit promise, so the wait is held open by work that is
158
+ // genuinely outstanding rather than by this timer.
159
+ ;(tick as { unref?: () => void }).unref?.()
160
+ })
161
+
162
+ return await Promise.race([exited, expiry])
163
+ } finally {
164
+ settled = true
165
+ }
166
+ }
167
+
168
+ /** What to tell the model, in the words that fit what actually happened. */
169
+ export function describeJobWaitTimeout(
170
+ id: string,
171
+ outcome: Extract<JobWaitOutcome, { kind: 'timeout' }>,
172
+ ): string {
173
+ const seconds = Math.round(outcome.elapsedMs / 1000)
174
+ const resume = `call wait_for_job again, or job read with from_offset ${outcome.nextOffset}, to see what it does next`
175
+ if (outcome.cause === 'idle') {
176
+ return `Job ${id} went quiet: no new output for a while, after ${seconds}s. It has not been stopped and may still be working — ${resume}.`
177
+ }
178
+ return `Job ${id} has been running for ${seconds}s without finishing. It has not been stopped — ${resume}.`
179
+ }
@@ -0,0 +1,184 @@
1
+ import { z } from 'zod'
2
+
3
+ import { readPositiveIntEnv } from '../../utils/env.js'
4
+ import { defineTool } from '../defineTool.js'
5
+ import { describeJobWaitTimeout, waitForJobWithBounds } from './wait-for-job-bounds.js'
6
+
7
+ /**
8
+ * Block until a background job ends, instead of reading it in a loop.
9
+ *
10
+ * `job`'s own tool used to say, in as many words, "poll a job with action
11
+ * read" — and a model that took the instruction literally paid for it: one
12
+ * recorded run launched a single background job, then spent six `job read`
13
+ * calls, three `job list` calls and an improvised `sleep 30` waiting on it,
14
+ * burning more tokens on the wait than the work it was waiting for cost.
15
+ * `wait_for_task` already solved this for delegated agent work by blocking
16
+ * inside ONE tool call instead of asking the model to check back; this is
17
+ * the same fix for shell jobs, built the same way — see
18
+ * `wait-for-job-bounds.ts` and its task-surface counterpart.
19
+ */
20
+
21
+ const DEFAULT_TIMEOUT_MS = readPositiveIntEnv('NAMZU_JOB_WAIT_TIMEOUT_MS', 5 * 60 * 1000)
22
+ const DEFAULT_IDLE_TIMEOUT_MS = readPositiveIntEnv('NAMZU_JOB_WAIT_IDLE_MS', 2 * 60 * 1000)
23
+
24
+ /**
25
+ * The longest either bound will accept from the model.
26
+ *
27
+ * Same number `wait_for_task` uses for a delegated agent, and the same
28
+ * reasoning applies: a generic stopwatch is the wrong instrument for a job
29
+ * that is making progress, so this is "how long is too long" rather than a
30
+ * guess at any one job's real duration, and a request past it is REFUSED by
31
+ * the schema rather than silently clamped — see `bash`'s own `timeout` field
32
+ * for the same trade.
33
+ */
34
+ const MAX_WAIT_MS = readPositiveIntEnv('NAMZU_JOB_WAIT_MAX_MS', 60 * 60 * 1000)
35
+
36
+ const inputSchema = z.object({
37
+ id: z.string().describe('The job id, as returned by bash with run_in_background.'),
38
+ timeout_ms: z
39
+ .number()
40
+ .int()
41
+ .positive()
42
+ .max(MAX_WAIT_MS)
43
+ .optional()
44
+ .describe(
45
+ `Give up after this long even if the job keeps producing output, in milliseconds. Default: ${DEFAULT_TIMEOUT_MS}, maximum: ${MAX_WAIT_MS}. The job is never stopped by this running out.`,
46
+ ),
47
+ idle_timeout_ms: z
48
+ .number()
49
+ .int()
50
+ .positive()
51
+ .max(MAX_WAIT_MS)
52
+ .optional()
53
+ .describe(
54
+ `Give up if the job produces no new output for this long, in milliseconds. Default: ${DEFAULT_IDLE_TIMEOUT_MS}. Resets on every new byte of output, so a job that is still working is not cut off; only real silence ends the wait early.`,
55
+ ),
56
+ })
57
+
58
+ type WaitForJobInput = z.infer<typeof inputSchema>
59
+
60
+ export const WaitForJobTool = defineTool({
61
+ name: 'wait_for_job',
62
+ description:
63
+ 'Block until a background job started by bash with run_in_background ends, and return its accumulated output in one call. Use this instead of calling job with action "read" in a loop: it costs one call and no waiting turns. Gives up — WITHOUT stopping the job — if it runs too long or goes quiet for too long; either outcome says so, and the job keeps running either way.',
64
+ inputSchema,
65
+ category: 'shell',
66
+ permissions: ['shell_execute'],
67
+ // Waiting is watching, not acting: this tool only ever reads a job's
68
+ // output and status through the same registry `job read` uses, and has
69
+ // no branch that touches a job's lifetime. `wait_for_task` is `readOnly:
70
+ // true` for the identical reason, and unlike `job` there is no second
71
+ // action here that would make this a function of input.
72
+ readOnly: true,
73
+ destructive: false,
74
+ concurrencySafe: true,
75
+ // A tool whose whole purpose is to wait must not be cut off for waiting.
76
+ // A margin over MAX_WAIT_MS so the tool's own bound — which reports a
77
+ // clean timeout result — always fires before the executor's harsher
78
+ // "abandoned" one would.
79
+ timeoutMs: MAX_WAIT_MS + 30_000,
80
+
81
+ presentCall(input) {
82
+ return {
83
+ kind: 'generic',
84
+ presentation: 'activity',
85
+ label: `Wait for background job · ${input.id ?? '(missing id)'}`,
86
+ }
87
+ },
88
+
89
+ async execute(input: WaitForJobInput, context) {
90
+ if (!context.backgroundJobs) {
91
+ return {
92
+ success: false,
93
+ output: '',
94
+ error: 'This host provides no background job registry, so there is no job to wait for.',
95
+ }
96
+ }
97
+ const jobs = context.backgroundJobs
98
+
99
+ try {
100
+ jobs.get(input.id)
101
+ } catch (err) {
102
+ return {
103
+ success: false,
104
+ output: '',
105
+ error: err instanceof Error ? err.message : String(err),
106
+ }
107
+ }
108
+
109
+ if (!jobs.waitForExit) {
110
+ return {
111
+ success: false,
112
+ output: '',
113
+ error:
114
+ 'This host\'s background job registry cannot wait for a job to exit. Use job with action "read" instead.',
115
+ }
116
+ }
117
+
118
+ // The wait IS the intent, so it is recorded before the bounds are: a
119
+ // call that gives up at `timeout_ms` with the job still running is the
120
+ // case the kernel's hold exists to back up, and one that started the
121
+ // wait and then ended its turn is the same case a beat later. Nothing
122
+ // infers this from the job's existence — a dev server the model never
123
+ // waited on never holds a run open. See `runtime/jobs/awaited-jobs.ts`.
124
+ jobs.markAwaited?.(input.id)
125
+
126
+ let outcome: Awaited<ReturnType<typeof waitForJobWithBounds>>
127
+ try {
128
+ outcome = await waitForJobWithBounds(jobs, input.id, {
129
+ runMs: input.timeout_ms ?? DEFAULT_TIMEOUT_MS,
130
+ idleMs: input.idle_timeout_ms ?? DEFAULT_IDLE_TIMEOUT_MS,
131
+ signal: context.abortSignal,
132
+ })
133
+ } catch {
134
+ // The signal fired before either bound did — Stop, or the run's
135
+ // own deadline. The job is untouched: ending a WAIT is not
136
+ // ending the WORK. The executor has already raced this same
137
+ // signal against the whole call and reports the cancellation
138
+ // itself; this only keeps that rejection from reaching the
139
+ // model as an unlabelled tool failure.
140
+ return {
141
+ success: false,
142
+ output: `This wait for job ${input.id} was abandoned before it finished; it is still running and was not stopped. Call wait_for_job again, or job read with from_offset, to pick up where this left off.`,
143
+ data: { jobId: input.id, abandoned: true },
144
+ }
145
+ }
146
+
147
+ if (outcome.kind === 'timeout') {
148
+ return {
149
+ success: false,
150
+ output: describeJobWaitTimeout(input.id, outcome),
151
+ data: {
152
+ jobId: input.id,
153
+ timedOut: outcome.cause,
154
+ nextOffset: outcome.nextOffset,
155
+ droppedBytes: outcome.droppedBytes,
156
+ },
157
+ }
158
+ }
159
+
160
+ // The dropped count is stated, never absorbed — same rule `job read`
161
+ // follows, for the same reason: a job whose middle vanished quietly
162
+ // reads as a complete result that happens to be short.
163
+ const notice =
164
+ outcome.droppedBytes > 0
165
+ ? `[${outcome.droppedBytes} bytes were dropped before this point — the job produced output faster than the retention cap holds]\n`
166
+ : ''
167
+ const status =
168
+ outcome.exitCode === undefined
169
+ ? outcome.status
170
+ : `${outcome.status} with code ${outcome.exitCode}`
171
+
172
+ return {
173
+ success: true,
174
+ output: `${notice}${outcome.output || '(no output)'}\n\n[job ${input.id} is ${status}; next_offset ${outcome.nextOffset}]`,
175
+ data: {
176
+ jobId: input.id,
177
+ status: outcome.status,
178
+ nextOffset: outcome.nextOffset,
179
+ droppedBytes: outcome.droppedBytes,
180
+ ...(outcome.exitCode === undefined ? {} : { exitCode: outcome.exitCode }),
181
+ },
182
+ }
183
+ },
184
+ })
@@ -150,7 +150,7 @@ export const WriteFileTool = defineTool({
150
150
  // This write is now the runtime's newest observation. Recording only
151
151
  // the boolean would leave an older content fingerprint in place and
152
152
  // make the next same-run write refuse its own predecessor as drift.
153
- context.fileReadTracker?.recordRead(valid.path, content)
153
+ context.fileReadTracker?.recordRead(valid.path, content, context.toolUseId)
154
154
  return fileWriteResult(
155
155
  valid.path,
156
156
  current === null ? null : current?.toString('utf-8'),
@@ -171,7 +171,7 @@ export const WriteFileTool = defineTool({
171
171
  // leaves the destination truncated — and this tool overwrites a
172
172
  // whole file, so the truncation is the user's previous work.
173
173
  await atomicWriteFile(hostPath, content)
174
- context.fileReadTracker?.recordRead(hostPath, content)
174
+ context.fileReadTracker?.recordRead(hostPath, content, context.toolUseId)
175
175
 
176
176
  return fileWriteResult(hostPath, current, content)
177
177
  })
@@ -204,6 +204,11 @@ function enforceFreshOverwrite(
204
204
  // fingerprint the host never promised to capture.
205
205
  const observed = context.fileReadTracker?.fingerprint?.(key)
206
206
  if (observed !== undefined && observed !== fingerprintContent(currentContent)) {
207
+ // The disk has just been read and found moved. Say so — without saying
208
+ // what was found, which would re-baseline the comparison right above —
209
+ // so a reader that cannot touch the filesystem stops referencing this
210
+ // path. Optional on the interface; an older tracker keeps its behavior.
211
+ context.fileReadTracker?.recordDriftObserved?.(key)
207
212
  return { success: false, output: '', error: staleFileError(key, 'write') }
208
213
  }
209
214
  return null
@@ -8,6 +8,7 @@ import type { ResumeHandler } from '../../types/hitl/index.js'
8
8
  import type { RunId, TaskId } from '../../types/ids/index.js'
9
9
  import type { TaskStore } from '../../types/task/index.js'
10
10
  import type { ToolDefinition } from '../../types/tool/index.js'
11
+ import { readPositiveIntEnv } from '../../utils/env.js'
11
12
  import { toErrorMessage } from '../../utils/error.js'
12
13
  import { asTaskId } from '../../utils/id.js'
13
14
  import { defineTool } from '../defineTool.js'
@@ -374,13 +375,6 @@ export const DELEGATION_TIMEOUT_MS = 60 * 60 * 1000
374
375
  */
375
376
  export const DELEGATION_IDLE_MS = readPositiveIntEnv('NAMZU_DELEGATION_IDLE_MS', 5 * 60 * 1000)
376
377
 
377
- function readPositiveIntEnv(key: string, fallback: number): number {
378
- const value = process.env[key]?.trim()
379
- if (!value) return fallback
380
- const parsed = Number(value)
381
- return Number.isSafeInteger(parsed) && parsed > 0 ? parsed : fallback
382
- }
383
-
384
378
  /**
385
379
  * The answer a delegated child produced, as the string a parent model reads.
386
380
  *
@@ -17,7 +17,8 @@ export interface DefineToolOptions<S extends z.ZodType> {
17
17
  validationErrorHint?: string
18
18
  category: ToolDefinition['category']
19
19
  permissions: ToolPermission[]
20
- readOnly: boolean
20
+ /** Whether this exact call only observes state; conservative for unknown inputs. */
21
+ readOnly: boolean | ((input: z.infer<S>) => boolean)
21
22
  destructive: boolean | ((input: z.infer<S>) => boolean)
22
23
  concurrencySafe: boolean
23
24
  /** Batch ordering boundary; see {@link ToolDefinition.executionBarrier}. */
@@ -88,7 +89,8 @@ export function defineTool<S extends z.ZodType>(
88
89
  : {}),
89
90
  category: options.category,
90
91
  permissions: options.permissions,
91
- isReadOnly: () => options.readOnly,
92
+ isReadOnly:
93
+ typeof options.readOnly === 'function' ? options.readOnly : () => options.readOnly as boolean,
92
94
  isDestructive:
93
95
  typeof options.destructive === 'function'
94
96
  ? options.destructive
@@ -5,12 +5,96 @@ import { fingerprintContent } from './builtins/content-fingerprint.js'
5
5
  export function createFileReadTracker(): FileReadTracker {
6
6
  const paths = new Set<string>()
7
7
  const fingerprints = new Map<string, string>()
8
+ const writes = new Map<string, string>()
9
+ // Edits stacked on top of `writes.get(key)`, in order. Kept beside the
10
+ // write id rather than replacing it, because the write is the base a
11
+ // replay starts from and is still needed once edits sit on it — while
12
+ // `writeCallId` must stop reporting it the moment the file's body stops
13
+ // being that call's body.
14
+ const chains = new Map<string, string[]>()
15
+ // Reads whose receipt still holds the whole body, with the fingerprint of
16
+ // the rendering that receipt is supposed to be. Kept apart from `writes`
17
+ // rather than folded into it: a write's body is the model's own argument
18
+ // and an edit can be replayed onto it, while this one exists only as text
19
+ // formatted for a reader — so it roots nothing, and the rendering is the
20
+ // only thing anyone is allowed to check it against.
21
+ const reads = new Map<string, { callId: string; renderedFingerprint: string }>()
22
+ // Paths a built-in mutation refused for drift. A flag and not an
23
+ // observation: the refusing tool did read the disk, but it reported only
24
+ // that what it found differs — writing a fingerprint from it would
25
+ // re-baseline the very check that refused and let the next mutation
26
+ // through. So this touches nothing `fingerprint`, `hasRead`, `writeCallId`,
27
+ // `editChain` or `readWitness` answers; it says only that what this ledger
28
+ // holds for the path is known to be behind the disk.
29
+ const drifted = new Set<string>()
30
+ // One observation, whatever witness the caller goes on to record against it.
31
+ // A shared function rather than `this.recordRead`, so a destructured method
32
+ // keeps working.
33
+ function observe(key: string, content?: string, fullWriteCallId?: string): void {
34
+ paths.add(key)
35
+ drifted.delete(key)
36
+ const next = content === undefined ? undefined : fingerprintContent(content)
37
+ if (next === undefined || next !== fingerprints.get(key)) {
38
+ writes.delete(key)
39
+ chains.delete(key)
40
+ reads.delete(key)
41
+ }
42
+ if (next !== undefined) fingerprints.set(key, next)
43
+ else fingerprints.delete(key)
44
+ if (next !== undefined && fullWriteCallId) {
45
+ writes.set(key, fullWriteCallId)
46
+ // A full body arrived whole in one call, so the chain is empty
47
+ // again: nothing has been applied on top of what is now on disk.
48
+ chains.delete(key)
49
+ }
50
+ }
8
51
  return {
9
- recordRead(key, content) {
52
+ recordRead: observe,
53
+ recordFullRead(key, content, callId, renderedFingerprint) {
54
+ observe(key, content)
55
+ // A surviving write witness outranks this one: it names a body the
56
+ // model composed itself, and the chain machinery can replay onto it.
57
+ // This is the same observation either way — only the witness differs.
58
+ if (!writes.has(key)) reads.set(key, { callId, renderedFingerprint })
59
+ },
60
+ readWitness: (key) => reads.get(key),
61
+ recordEdit(key, content, callId) {
62
+ // Both conditions are about the PRE-image, not this edit. A chain
63
+ // replays only if the content this edit ran against is itself
64
+ // reproducible: there has to be a witnessed write underneath it, and
65
+ // a fingerprint for what the edit actually started from — which is
66
+ // also the value the tool's own drift check compared before writing.
67
+ // Without both, this is an observation of a body nobody can replay.
68
+ const chained = writes.has(key) && fingerprints.has(key) && callId.length > 0
10
69
  paths.add(key)
11
- if (content !== undefined) fingerprints.set(key, fingerprintContent(content))
70
+ drifted.delete(key)
71
+ // Unconditionally, even where the content is unchanged: a read
72
+ // witness points at a receipt showing the body BEFORE this edit, and
73
+ // no chain can be rooted at a rendering to carry it forward.
74
+ reads.delete(key)
75
+ fingerprints.set(key, fingerprintContent(content))
76
+ if (!chained) {
77
+ writes.delete(key)
78
+ chains.delete(key)
79
+ return
80
+ }
81
+ chains.set(key, [...(chains.get(key) ?? []), callId])
12
82
  },
83
+ recordDriftObserved(key) {
84
+ drifted.add(key)
85
+ },
86
+ driftObserved: (key) => drifted.has(key),
13
87
  hasRead: (key) => paths.has(key),
14
88
  fingerprint: (key) => fingerprints.get(key),
89
+ // Withheld while edits sit on top of it. A consumer that knows only this
90
+ // method asks "is the current body the body of a call I can see?", and
91
+ // once an edit has landed the honest answer is no.
92
+ writeCallId: (key) => (chains.has(key) ? undefined : writes.get(key)),
93
+ editChain: (key) => {
94
+ const editCallIds = chains.get(key)
95
+ const rootWriteCallId = writes.get(key)
96
+ if (!editCallIds?.length || rootWriteCallId === undefined) return undefined
97
+ return { rootWriteCallId, editCallIds: [...editCallIds] }
98
+ },
15
99
  }
16
100
  }