@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
@@ -1,11 +1,12 @@
1
1
  import { readFile } from 'node:fs/promises'
2
2
 
3
3
  import { z } from 'zod'
4
- import type { ToolResult } from '../../types/tool/index.js'
4
+ import type { ToolContext, ToolResult } from '../../types/tool/index.js'
5
5
  import { defineTool } from '../defineTool.js'
6
6
  import { resolveWithinAnyReal, toolRoots } from '../paths.js'
7
7
  import { atomicWriteFile } from './atomic-write-file.js'
8
8
  import { fingerprintContent, staleFileError } from './content-fingerprint.js'
9
+ import { applyEdit, normalizeEditInput } from './edit-apply.js'
9
10
  import { withFileMutationLock } from './file-mutation-lock.js'
10
11
 
11
12
  /**
@@ -131,7 +132,7 @@ const inputSchema = z
131
132
  },
132
133
  )
133
134
 
134
- type EditInput = z.infer<typeof inputSchema>
135
+ export type EditInput = z.infer<typeof inputSchema>
135
136
 
136
137
  /**
137
138
  * What a capable provider constrains the model to emit: one shape, closed.
@@ -244,19 +245,38 @@ const modelInputSchema: Record<string, unknown> = {
244
245
  additionalProperties: false,
245
246
  }
246
247
 
247
- type NormalizedEditInput =
248
- | {
249
- operation: 'replace'
250
- oldString: string
251
- newString: string
252
- replace_all: boolean
253
- }
254
- | {
255
- operation: 'insert'
256
- insertLine: number | 'end'
257
- newString: string
258
- replace_all: boolean
259
- }
248
+ /**
249
+ * Advance the ledger to the body this edit just wrote.
250
+ *
251
+ * `recordEdit` where the host's tracker offers it, so the observation carries
252
+ * the call that produced it and the path keeps a chain back to the write it
253
+ * started from; `recordRead` otherwise, which is exactly what this line did
254
+ * before chains existed — and what it still does when no call id is in hand,
255
+ * since a hop nobody can name is a hop nobody can replay. Both advance the
256
+ * fingerprint, which is what the next mutation's drift check reads.
257
+ */
258
+ function recordEditedContent(context: ToolContext, key: string, content: string): void {
259
+ const tracker = context.fileReadTracker
260
+ if (!tracker) return
261
+ if (tracker.recordEdit && context.toolUseId) {
262
+ tracker.recordEdit(key, content, context.toolUseId)
263
+ return
264
+ }
265
+ tracker.recordRead(key, content)
266
+ }
267
+
268
+ /**
269
+ * Tell the ledger the path it holds is behind the disk, on the way out.
270
+ *
271
+ * This branch has just read the real file and found it moved, which is the
272
+ * one moment a reader with no filesystem of its own can learn that for free.
273
+ * The flag carries no body: recording what was found here would re-baseline
274
+ * the comparison directly above and admit the mutation it is refusing. It is
275
+ * optional on the interface, so a tracker without it keeps today's behavior.
276
+ */
277
+ function recordDrift(context: ToolContext, key: string): void {
278
+ context.fileReadTracker?.recordDriftObserved?.(key)
279
+ }
260
280
 
261
281
  export const EditTool = defineTool({
262
282
  name: 'edit',
@@ -365,6 +385,7 @@ export const EditTool = defineTool({
365
385
  const content = buffer.toString('utf-8')
366
386
  const seen = context.fileReadTracker?.fingerprint?.(parsed.data.path)
367
387
  if (seen !== undefined && seen !== fingerprintContent(content)) {
388
+ recordDrift(context, parsed.data.path)
368
389
  return { success: false as const, output: '', error: staleFileError(parsed.data.path) }
369
390
  }
370
391
  const result = applyEdit(content, normalized.operations)
@@ -373,7 +394,7 @@ export const EditTool = defineTool({
373
394
  }
374
395
 
375
396
  await context.sandbox.writeFile(parsed.data.path, result.content)
376
- context.fileReadTracker?.recordRead(parsed.data.path, result.content)
397
+ recordEditedContent(context, parsed.data.path, result.content)
377
398
  return {
378
399
  success: true as const,
379
400
  output: `Edited ${parsed.data.path}: ${result.replacements} replacement(s) [sandboxed]`,
@@ -386,6 +407,7 @@ export const EditTool = defineTool({
386
407
 
387
408
  const seen = context.fileReadTracker?.fingerprint?.(hostPath)
388
409
  if (seen !== undefined && seen !== fingerprintContent(content)) {
410
+ recordDrift(context, hostPath)
389
411
  return { success: false as const, output: '', error: staleFileError(hostPath) }
390
412
  }
391
413
  const result = applyEdit(content, normalized.operations)
@@ -398,7 +420,7 @@ export const EditTool = defineTool({
398
420
  // This runtime is now the last writer, so the next edit in the same
399
421
  // turn compares against what we just wrote rather than the read
400
422
  // before it.
401
- context.fileReadTracker?.recordRead(hostPath, result.content)
423
+ recordEditedContent(context, hostPath, result.content)
402
424
  return {
403
425
  success: true as const,
404
426
  output: `Edited ${hostPath}: ${result.replacements} replacement(s)`,
@@ -407,256 +429,3 @@ export const EditTool = defineTool({
407
429
  })
408
430
  },
409
431
  })
410
-
411
- /**
412
- * Turn one call into the ordered list of operations it stands for.
413
- *
414
- * A list rather than a single operation because the batch shape is not a
415
- * different kind of edit, only a longer one. Keeping ONE representation is
416
- * what stops the two shapes diverging: everything below this function — the
417
- * uniqueness check, the CRLF reconciliation, the identical-text refusal, the
418
- * atomic write — sees a list of length one for a single edit and never learns
419
- * which shape the caller used.
420
- */
421
- function normalizeEditInput(
422
- input: EditInput,
423
- ): { success: true; operations: NormalizedEditInput[] } | { success: false; error: string } {
424
- if (input.edits !== undefined) {
425
- return {
426
- success: true,
427
- operations: input.edits.map((edit) => ({
428
- operation: 'replace' as const,
429
- oldString: edit.old_string,
430
- newString: edit.new_string,
431
- replace_all: edit.replace_all ?? false,
432
- })),
433
- }
434
- }
435
-
436
- const newString = input.new_string ?? input.newStr
437
- if (typeof newString !== 'string') {
438
- return { success: false, error: 'Either new_string or newStr is required.' }
439
- }
440
-
441
- if (input.insertLine !== undefined) {
442
- const insertLine = normalizeInsertLine(input.insertLine)
443
- if (!insertLine.success) return insertLine
444
- return {
445
- success: true,
446
- operations: [
447
- {
448
- operation: 'insert',
449
- insertLine: insertLine.value,
450
- newString,
451
- replace_all: input.replace_all ?? false,
452
- },
453
- ],
454
- }
455
- }
456
-
457
- const oldString = input.old_string ?? input.oldStr
458
- if (typeof oldString !== 'string') {
459
- return { success: false, error: 'Either old_string/oldStr or insertLine is required.' }
460
- }
461
- return {
462
- success: true,
463
- operations: [
464
- {
465
- operation: 'replace',
466
- oldString,
467
- newString,
468
- replace_all: input.replace_all ?? false,
469
- },
470
- ],
471
- }
472
- }
473
-
474
- /**
475
- * Spellings of "the end of the file" a model reaches for.
476
- *
477
- * Liberal here and strict in the schema, which is the right way round: the
478
- * schema makes `"end"` the only emittable string for a provider that
479
- * constrains, and this catches the rest for one that does not. None of these
480
- * is ambiguous — accepting them is not guessing at intent, it is declining to
481
- * spend a round trip on a synonym.
482
- */
483
- const END_ALIASES = new Set(['end', 'eof', 'append', 'last', 'end_of_file', 'end-of-file'])
484
-
485
- function normalizeInsertLine(
486
- value: string | number,
487
- ): { success: true; value: number | 'end' } | { success: false; error: string } {
488
- if (typeof value === 'string') {
489
- const normalized = value.trim().toLowerCase()
490
- // `"end"` is the only spelling the model-facing schema admits, so a
491
- // constrained decoder cannot produce anything else. These aliases are
492
- // for the providers that do not constrain: a model reading "appends to
493
- // the file" reaches for the word it knows, and every one of these says
494
- // the same unambiguous thing. Refusing them bought strictness and cost
495
- // a full model round trip per occurrence — measured by a consuming host
496
- // as the single largest source of tool-call waste in its runs.
497
- if (END_ALIASES.has(normalized)) return { success: true, value: 'end' }
498
- const parsed = Number(value)
499
- if (Number.isInteger(parsed) && parsed >= 0) return { success: true, value: parsed }
500
- return {
501
- success: false,
502
- error: `insertLine must be a non-negative line number or "end" (also accepted: ${[...END_ALIASES].filter((a) => a !== 'end').join(', ')}). Received ${JSON.stringify(value)}.`,
503
- }
504
- }
505
- return { success: true, value }
506
- }
507
-
508
- /**
509
- * Apply every operation in order, or none of them.
510
- *
511
- * "Or none" is the whole reason this takes a list. Four related changes sent
512
- * as four calls are four chances to stop halfway, and the file left behind
513
- * after the third succeeded and the fourth did not is in a state no one wrote
514
- * and no one is looking at. Here the fold runs entirely in memory and the
515
- * caller writes once, so a failure anywhere leaves the file exactly as it was.
516
- *
517
- * Each operation matches against the content as the ones before it left it,
518
- * not against the original. That is what lets a later edit target text an
519
- * earlier one produced — and it is also why a failure names the INDEX: by the
520
- * time hunk 3 fails, the string it was looking for may have been consumed by
521
- * hunk 1, and "old_string not found" without a position sends the model to
522
- * re-check the wrong hunk.
523
- */
524
- function applyEdit(
525
- content: string,
526
- operations: readonly NormalizedEditInput[],
527
- ): { success: true; content: string; replacements: number } | { success: false; error: string } {
528
- let current = content
529
- let replacements = 0
530
-
531
- for (const [index, operation] of operations.entries()) {
532
- const result = applyOne(current, operation)
533
- if (!result.success) {
534
- return {
535
- success: false,
536
- error:
537
- operations.length === 1
538
- ? result.error
539
- : `edits[${index}] of ${operations.length}: ${result.error} Nothing was written — the whole batch is refused, so the file is exactly as it was.`,
540
- }
541
- }
542
- current = result.content
543
- replacements += result.replacements
544
- }
545
-
546
- return { success: true, content: current, replacements }
547
- }
548
-
549
- function applyOne(
550
- content: string,
551
- input: NormalizedEditInput,
552
- ): { success: true; content: string; replacements: number } | { success: false; error: string } {
553
- if (input.operation === 'insert') {
554
- return applyLineInsert(content, input)
555
- }
556
-
557
- const replacement = normalizeLineEndings(content, input)
558
-
559
- if (!content.includes(replacement.oldString)) {
560
- return {
561
- success: false,
562
- error:
563
- 'old_string/oldStr not found in file. Make sure the string matches exactly, including whitespace and indentation.',
564
- }
565
- }
566
-
567
- if (replacement.replace_all) {
568
- const parts = content.split(replacement.oldString)
569
- const replacements = parts.length - 1
570
- return {
571
- success: true,
572
- content: parts.join(replacement.newString),
573
- replacements,
574
- }
575
- }
576
-
577
- // Uniqueness check: old_string/oldStr must appear exactly once
578
- const firstIndex = content.indexOf(replacement.oldString)
579
- const secondIndex = content.indexOf(replacement.oldString, firstIndex + 1)
580
-
581
- if (secondIndex !== -1) {
582
- const lineNumber = content.slice(0, firstIndex).split('\n').length
583
- const secondLine = content.slice(0, secondIndex).split('\n').length
584
- return {
585
- success: false,
586
- error: `old_string/oldStr is not unique — found at lines ${lineNumber} and ${secondLine}. Provide more surrounding context to make it unique, or use replace_all: true.`,
587
- }
588
- }
589
-
590
- return {
591
- success: true,
592
- content:
593
- content.slice(0, firstIndex) +
594
- replacement.newString +
595
- content.slice(firstIndex + replacement.oldString.length),
596
- replacements: 1,
597
- }
598
- }
599
-
600
- function applyLineInsert(
601
- content: string,
602
- input: Extract<NormalizedEditInput, { operation: 'insert' }>,
603
- ): { success: true; content: string; replacements: number } {
604
- const hasTrailingNewline = content.endsWith('\n')
605
- const lines = content.split('\n')
606
- if (hasTrailingNewline) lines.pop()
607
-
608
- const line =
609
- input.insertLine === 'end'
610
- ? lines.length
611
- : Math.min(Math.max(input.insertLine, 0), lines.length)
612
- const inserted = input.newString.endsWith('\n')
613
- ? input.newString.slice(0, -1).split('\n')
614
- : input.newString.split('\n')
615
- lines.splice(line, 0, ...inserted)
616
- return {
617
- success: true,
618
- content: `${lines.join('\n')}${hasTrailingNewline ? '\n' : ''}`,
619
- replacements: 1,
620
- }
621
- }
622
-
623
- /**
624
- * Reconcile the caller's line endings with the file's.
625
- *
626
- * A model reading a CRLF file and writing back LF (or the reverse) produces
627
- * an `old_string` that is correct in every visible way and matches nothing.
628
- * The failure reads as "your text is wrong" when the text is right and only
629
- * the invisible half of each line break differs.
630
- *
631
- * Only applied when the file is CONSISTENT. A mixed-ending file has no
632
- * single right answer, and rewriting boundaries there would corrupt the
633
- * half that was already correct.
634
- */
635
- function normalizeLineEndings(
636
- content: string,
637
- input: Extract<NormalizedEditInput, { operation: 'replace' }>,
638
- ): Extract<NormalizedEditInput, { operation: 'replace' }> {
639
- const withoutCrlf = content.replaceAll('\r\n', '')
640
- const usesOnlyCrlf = content.includes('\r\n') && !withoutCrlf.includes('\n')
641
- if (usesOnlyCrlf) {
642
- return {
643
- ...input,
644
- oldString: content.includes(input.oldString)
645
- ? input.oldString
646
- : input.oldString.replaceAll('\r\n', '\n').replaceAll('\n', '\r\n'),
647
- newString: input.newString.replaceAll('\r\n', '\n').replaceAll('\n', '\r\n'),
648
- }
649
- }
650
-
651
- const usesOnlyLf = content.includes('\n') && !content.includes('\r\n')
652
- if (usesOnlyLf) {
653
- return {
654
- ...input,
655
- oldString: content.includes(input.oldString)
656
- ? input.oldString
657
- : input.oldString.replaceAll('\r\n', '\n'),
658
- newString: input.newString.replaceAll('\r\n', '\n'),
659
- }
660
- }
661
- return input
662
- }
@@ -6,6 +6,7 @@ export { GlobTool } from './glob.js'
6
6
  export { LSP_TOOL_NAME, LspTool, getCodeNavigationTools } from './lsp.js'
7
7
  export { GrepTool } from './grep.js'
8
8
  export { JobTool } from './job.js'
9
+ export { WaitForJobTool } from './wait-for-job.js'
9
10
  export { SKILL_TOOL_NAME, SkillTool, parseAllowedTools } from './skill.js'
10
11
  export {
11
12
  WEB_FETCH_TOOL_NAME,
@@ -29,6 +30,7 @@ import { GrepTool } from './grep.js'
29
30
  import { JobTool } from './job.js'
30
31
  import { ReadFileTool } from './read-file.js'
31
32
  import { VerifyOutputsTool } from './verify-outputs.js'
33
+ import { WaitForJobTool } from './wait-for-job.js'
32
34
  import { WriteFileTool } from './write-file.js'
33
35
  // Note: createStructuredOutputTool is not included in getBuiltinTools()
34
36
  // because it requires a schema parameter and is created per-use case.
@@ -46,10 +48,13 @@ export function getBuiltinTools(): ToolDefinition[] {
46
48
  // `job` ships alongside `bash` rather than being opt-in, because the two
47
49
  // are one capability. `bash run_in_background` returns an id, and an id
48
50
  // with no tool that reads it is the exact shape of the suggestion that
49
- // was removed from bash's schema for being unbacked.
51
+ // was removed from bash's schema for being unbacked. `wait_for_job`
52
+ // ships with it for the same reason `job` does: a job with nothing that
53
+ // can block on it is a suggestion with the same missing half.
50
54
  //
51
- // It costs nothing where the host provides no registry: the tool refuses
52
- // and says so, which is a truthful answer rather than a missing one.
55
+ // It costs nothing where the host provides no registry: both tools
56
+ // refuse and say so, which is a truthful answer rather than a missing
57
+ // one.
53
58
  return [
54
59
  BashTool,
55
60
  EditTool,
@@ -58,6 +63,7 @@ export function getBuiltinTools(): ToolDefinition[] {
58
63
  JobTool,
59
64
  ReadFileTool,
60
65
  VerifyOutputsTool,
66
+ WaitForJobTool,
61
67
  WriteFileTool,
62
68
  ]
63
69
  }
@@ -43,15 +43,14 @@ type JobInput = z.infer<typeof inputSchema>
43
43
  export const JobTool = defineTool({
44
44
  name: 'job',
45
45
  description:
46
- 'Reads, lists and stops background jobs started by bash with run_in_background. Poll a job with action "read", passing the previous call\'s next_offset to see only new output.',
46
+ 'Reads, lists and stops background jobs started by bash with run_in_background. Do NOT call action "read" in a loop to find out whether a job finished: use wait_for_job instead — it blocks until the job ends (or goes quiet, or runs long) and returns the output in one call, with no waiting turns spent checking. Use "read" to see output while a job keeps running, or to pick up after a wait_for_job call gave up, passing the previous call\'s next_offset to see only new output.',
47
47
  inputSchema,
48
48
  category: 'shell',
49
49
  permissions: ['shell_execute'],
50
- // `read` and `list` observe; `kill` stops work. The tool as a whole is not
51
- // read-only, and claiming otherwise would let a read-only permission
52
- // preset hand the model a way to terminate a running process.
53
- readOnly: false,
54
- destructive: (input: JobInput) => input.action === 'kill',
50
+ // The static permission describes the full capability. The prepared action
51
+ // determines whether this call only observes its owner-bound registry.
52
+ readOnly: (input: JobInput) => input?.action === 'read' || input?.action === 'list',
53
+ destructive: (input: JobInput) => input?.action === 'kill',
55
54
  concurrencySafe: true,
56
55
 
57
56
  presentCall(input) {
@@ -1,13 +1,26 @@
1
1
  import { readFile } from 'node:fs/promises'
2
2
  import { extname } from 'node:path'
3
3
  import { z } from 'zod'
4
+ import type { ToolContext } from '../../types/tool/index.js'
4
5
  import { defineTool } from '../defineTool.js'
5
6
  import { resolveWithinAnyReal, toolRoots } from '../paths.js'
7
+ import { fingerprintContent } from './content-fingerprint.js'
8
+ import { type RenderedRead, renderNumberedRead } from './read-render.js'
6
9
 
7
10
  const inputSchema = z.object({
8
11
  path: z.string().describe('Path to the file to read (absolute or relative)'),
12
+ // A two-element ARRAY, not a `z.tuple`, and the distinction is the whole
13
+ // reason this comment exists. Both members carry the identical constraint,
14
+ // so the tuple bought nothing — and it rendered as the draft-07 tuple
15
+ // `items: [a, b]`, which a wire that validates against JSON Schema 2020-12
16
+ // refuses outright. It was the only tuple in the first-party tool surface,
17
+ // and it took down every other tool in the same request with it. The
18
+ // spelling below means the same thing to the model (`[10, 40]` either way)
19
+ // and to the parser, and reads identically in both dialects. See
20
+ // `registry/tool/portable.ts`.
9
21
  readRange: z
10
- .tuple([z.coerce.number().int().min(1), z.coerce.number().int().min(1)])
22
+ .array(z.coerce.number().int().min(1))
23
+ .length(2)
11
24
  .optional()
12
25
  .describe(
13
26
  'Optional 1-indexed inclusive line range, e.g. [10, 40]. When provided it takes precedence over offset/limit.',
@@ -59,26 +72,16 @@ export const ReadFileTool = defineTool({
59
72
  }
60
73
  }
61
74
  const content = buffer.toString('utf-8')
62
- const lines = content.split('\n')
75
+ const rendered = renderNumberedRead(content, input)
76
+ recordObservedRead(context, input.path, content, rendered)
63
77
 
64
- const { start, end } = resolveReadWindow(input, lines.length)
65
- const selectedLines = lines.slice(start, end)
66
-
67
- const numberedLines = selectedLines.map((line, i) => `${start + i + 1}\t${line}`).join('\n')
68
-
69
- // The WHOLE body, not the selected window: a later edit is checked
70
- // against the file, and a partial read must not fingerprint a
71
- // fragment as if it were the file.
72
- context.fileReadTracker?.recordRead(input.path, content)
73
-
74
- const partial = selectedLines.length < lines.length
75
78
  return {
76
79
  success: true,
77
- output: numberedLines + partialViewNotice(start, selectedLines.length, lines.length),
80
+ output: rendered.output,
78
81
  data: {
79
- totalLines: lines.length,
80
- returnedLines: selectedLines.length,
81
- truncated: partial,
82
+ totalLines: rendered.totalLines,
83
+ returnedLines: rendered.returnedLines,
84
+ truncated: rendered.partial,
82
85
  path: input.path,
83
86
  sandboxed: true,
84
87
  },
@@ -99,30 +102,52 @@ export const ReadFileTool = defineTool({
99
102
  }
100
103
  }
101
104
  const content = buffer.toString('utf-8')
102
- const lines = content.split('\n')
103
-
104
- const { start, end } = resolveReadWindow(input, lines.length)
105
- const selectedLines = lines.slice(start, end)
106
-
107
- const numberedLines = selectedLines.map((line, i) => `${start + i + 1}\t${line}`).join('\n')
108
-
109
- context.fileReadTracker?.recordRead(filePath, content)
110
-
111
- const isPartial = selectedLines.length < lines.length
105
+ const rendered = renderNumberedRead(content, input)
106
+ recordObservedRead(context, filePath, content, rendered)
112
107
 
113
108
  return {
114
109
  success: true,
115
- output: numberedLines + partialViewNotice(start, selectedLines.length, lines.length),
110
+ output: rendered.output,
116
111
  data: {
117
- totalLines: lines.length,
118
- returnedLines: selectedLines.length,
119
- truncated: isPartial,
112
+ totalLines: rendered.totalLines,
113
+ returnedLines: rendered.returnedLines,
114
+ truncated: rendered.partial,
120
115
  path: filePath,
121
116
  },
122
117
  }
123
118
  },
124
119
  })
125
120
 
121
+ /**
122
+ * Put this read on the observation ledger.
123
+ *
124
+ * Always the WHOLE body, not the selected window: a later edit is checked
125
+ * against the file, and a partial read must not fingerprint a fragment as if it
126
+ * were the file.
127
+ *
128
+ * A read that returned the file whole additionally witnesses itself, so the
129
+ * derived work context can reference the body without the model reading it
130
+ * again. The witness is the fingerprint of the RENDERING — this call's own
131
+ * `output`, byte for byte — because the rendering is what the receipt carries,
132
+ * and the body is in front of the model only while the receipt is still exactly
133
+ * that. A read whose window left any of the file out witnesses nothing: it
134
+ * shows a fragment, and the fingerprint of the file cannot say which one.
135
+ */
136
+ function recordObservedRead(
137
+ context: ToolContext,
138
+ key: string,
139
+ content: string,
140
+ rendered: RenderedRead,
141
+ ): void {
142
+ const tracker = context.fileReadTracker
143
+ if (!tracker) return
144
+ if (!rendered.partial && tracker.recordFullRead && context.toolUseId) {
145
+ tracker.recordFullRead(key, content, context.toolUseId, fingerprintContent(rendered.output))
146
+ return
147
+ }
148
+ tracker.recordRead(key, content)
149
+ }
150
+
126
151
  function describeStructuredBinaryRead(path: string, buffer: Buffer): string | null {
127
152
  const ext = extname(path).toLowerCase()
128
153
  if (ext === '.docx') return buildStructuredBinaryGuidance(path, 'DOCX', 'python-docx')
@@ -146,49 +171,3 @@ function buildStructuredBinaryGuidance(path: string, format: string, extractor:
146
171
  'If extraction fails, report the exact filename and extraction error instead of claiming the attachment is unavailable.',
147
172
  ].join('\n')
148
173
  }
149
-
150
- /**
151
- * Lines returned when the caller specifies no window.
152
- *
153
- * Chosen to cover the overwhelming majority of source files whole while
154
- * bounding the pathological case.
155
- */
156
- const DEFAULT_READ_LINES = 2000
157
-
158
- /**
159
- * Tell the model, explicitly, when it is looking at a window rather than
160
- * the file.
161
- *
162
- * Without this a truncated read is indistinguishable from a short file, and
163
- * the agent reasons about a fragment as if it were the whole thing — the
164
- * most expensive silent failure a read tool can have. The notice names the
165
- * exact next call rather than describing it.
166
- */
167
- function partialViewNotice(start: number, returned: number, total: number): string {
168
- if (returned >= total) return ''
169
- const shownTo = start + returned
170
- return [
171
- '',
172
- '',
173
- `[PARTIAL view — lines ${start + 1}-${shownTo} of ${total}.`,
174
- `Continue with read({ offset: ${shownTo}, limit: N }), or narrow with grep.]`,
175
- ].join('\n')
176
- }
177
-
178
- function resolveReadWindow(
179
- input: z.infer<typeof inputSchema>,
180
- totalLines: number,
181
- ): { start: number; end: number } {
182
- if (input.readRange) {
183
- const [first, last] = input.readRange
184
- const start = Math.max(0, first - 1)
185
- const end = Math.min(totalLines, Math.max(start, last))
186
- return { start, end }
187
- }
188
- const start = Math.max(0, input.offset ?? 0)
189
- // A bare `read({ path })` used to return the entire file, so a 2 MB
190
- // lockfile became ~500k tokens in one tool_result. Default to a window
191
- // and say so in the output; the model asks for more when it needs it.
192
- const end = input.limit ? start + input.limit : Math.min(totalLines, start + DEFAULT_READ_LINES)
193
- return { start, end }
194
- }