@namzu/sdk 36.0.0 → 38.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 (412) hide show
  1. package/CHANGELOG.md +244 -0
  2. package/README.md +68 -41
  3. package/dist/bridge/a2a/mapper.d.ts.map +1 -1
  4. package/dist/bridge/a2a/mapper.js +4 -0
  5. package/dist/bridge/a2a/mapper.js.map +1 -1
  6. package/dist/bridge/sse/mapper.d.ts.map +1 -1
  7. package/dist/bridge/sse/mapper.js +16 -1
  8. package/dist/bridge/sse/mapper.js.map +1 -1
  9. package/dist/compaction/extractor.d.ts +1 -1
  10. package/dist/compaction/extractor.d.ts.map +1 -1
  11. package/dist/compaction/extractor.js +15 -7
  12. package/dist/compaction/extractor.js.map +1 -1
  13. package/dist/compaction/manager.d.ts +2 -0
  14. package/dist/compaction/manager.d.ts.map +1 -1
  15. package/dist/compaction/manager.js +12 -1
  16. package/dist/compaction/manager.js.map +1 -1
  17. package/dist/compaction/verifier.d.ts.map +1 -1
  18. package/dist/compaction/verifier.js +82 -15
  19. package/dist/compaction/verifier.js.map +1 -1
  20. package/dist/config/runtime.d.ts +16 -6
  21. package/dist/config/runtime.d.ts.map +1 -1
  22. package/dist/config/runtime.js +2 -0
  23. package/dist/config/runtime.js.map +1 -1
  24. package/dist/contracts/api.d.ts +1 -1
  25. package/dist/contracts/api.d.ts.map +1 -1
  26. package/dist/contracts/schemas.d.ts +10 -10
  27. package/dist/eval/harness-verification.d.ts +63 -0
  28. package/dist/eval/harness-verification.d.ts.map +1 -0
  29. package/dist/eval/harness-verification.js +165 -0
  30. package/dist/eval/harness-verification.js.map +1 -0
  31. package/dist/eval/index.d.ts +2 -0
  32. package/dist/eval/index.d.ts.map +1 -1
  33. package/dist/eval/index.js +1 -0
  34. package/dist/eval/index.js.map +1 -1
  35. package/dist/execution/code-runtime/json-value.d.ts +10 -0
  36. package/dist/execution/code-runtime/json-value.d.ts.map +1 -0
  37. package/dist/execution/code-runtime/json-value.js +89 -0
  38. package/dist/execution/code-runtime/json-value.js.map +1 -0
  39. package/dist/execution/code-runtime/worker-program.d.ts +8 -0
  40. package/dist/execution/code-runtime/worker-program.d.ts.map +1 -0
  41. package/dist/execution/code-runtime/worker-program.js +240 -0
  42. package/dist/execution/code-runtime/worker-program.js.map +1 -0
  43. package/dist/execution/code-runtime/worker.d.ts +22 -0
  44. package/dist/execution/code-runtime/worker.d.ts.map +1 -1
  45. package/dist/execution/code-runtime/worker.js +148 -111
  46. package/dist/execution/code-runtime/worker.js.map +1 -1
  47. package/dist/manager/agent/lifecycle.d.ts +12 -0
  48. package/dist/manager/agent/lifecycle.d.ts.map +1 -1
  49. package/dist/manager/agent/lifecycle.js +316 -46
  50. package/dist/manager/agent/lifecycle.js.map +1 -1
  51. package/dist/manager/run/persistence.d.ts +2 -0
  52. package/dist/manager/run/persistence.d.ts.map +1 -1
  53. package/dist/manager/run/persistence.js +6 -0
  54. package/dist/manager/run/persistence.js.map +1 -1
  55. package/dist/prompt/coding-agent-doctrine.d.ts +2 -2
  56. package/dist/prompt/coding-agent-doctrine.d.ts.map +1 -1
  57. package/dist/prompt/coding-agent-doctrine.js +11 -5
  58. package/dist/prompt/coding-agent-doctrine.js.map +1 -1
  59. package/dist/provider/capabilities.d.ts +5 -1
  60. package/dist/provider/capabilities.d.ts.map +1 -1
  61. package/dist/provider/capabilities.js +24 -0
  62. package/dist/provider/capabilities.js.map +1 -1
  63. package/dist/provider/fallback.d.ts.map +1 -1
  64. package/dist/provider/fallback.js +6 -2
  65. package/dist/provider/fallback.js.map +1 -1
  66. package/dist/public-runtime.d.ts +4 -1
  67. package/dist/public-runtime.d.ts.map +1 -1
  68. package/dist/public-runtime.js +3 -1
  69. package/dist/public-runtime.js.map +1 -1
  70. package/dist/public-tools.d.ts +2 -1
  71. package/dist/public-tools.d.ts.map +1 -1
  72. package/dist/public-tools.js +2 -1
  73. package/dist/public-tools.js.map +1 -1
  74. package/dist/public-types.d.ts +2 -0
  75. package/dist/public-types.d.ts.map +1 -1
  76. package/dist/registry/tool/execute.d.ts +3 -0
  77. package/dist/registry/tool/execute.d.ts.map +1 -1
  78. package/dist/registry/tool/execute.js +11 -80
  79. package/dist/registry/tool/execute.js.map +1 -1
  80. package/dist/run/command-gate.d.ts.map +1 -1
  81. package/dist/run/command-gate.js +65 -12
  82. package/dist/run/command-gate.js.map +1 -1
  83. package/dist/run/index.d.ts +2 -0
  84. package/dist/run/index.d.ts.map +1 -1
  85. package/dist/run/index.js +1 -0
  86. package/dist/run/index.js.map +1 -1
  87. package/dist/run/memory-promoter.d.ts +3 -35
  88. package/dist/run/memory-promoter.d.ts.map +1 -1
  89. package/dist/run/memory-promoter.js +32 -40
  90. package/dist/run/memory-promoter.js.map +1 -1
  91. package/dist/run/memory-recall.d.ts +25 -0
  92. package/dist/run/memory-recall.d.ts.map +1 -0
  93. package/dist/run/memory-recall.js +228 -0
  94. package/dist/run/memory-recall.js.map +1 -0
  95. package/dist/run/reporter.d.ts.map +1 -1
  96. package/dist/run/reporter.js +2 -0
  97. package/dist/run/reporter.js.map +1 -1
  98. package/dist/run/token-budget.d.ts +12 -4
  99. package/dist/run/token-budget.d.ts.map +1 -1
  100. package/dist/run/token-budget.js +49 -14
  101. package/dist/run/token-budget.js.map +1 -1
  102. package/dist/run/workspace-fingerprint.d.ts +10 -3
  103. package/dist/run/workspace-fingerprint.d.ts.map +1 -1
  104. package/dist/run/workspace-fingerprint.js +17 -8
  105. package/dist/run/workspace-fingerprint.js.map +1 -1
  106. package/dist/runtime/query/checkpoint.d.ts +14 -0
  107. package/dist/runtime/query/checkpoint.d.ts.map +1 -1
  108. package/dist/runtime/query/checkpoint.js +82 -1
  109. package/dist/runtime/query/checkpoint.js.map +1 -1
  110. package/dist/runtime/query/executor.d.ts +8 -3
  111. package/dist/runtime/query/executor.d.ts.map +1 -1
  112. package/dist/runtime/query/executor.js +94 -30
  113. package/dist/runtime/query/executor.js.map +1 -1
  114. package/dist/runtime/query/index.d.ts +7 -8
  115. package/dist/runtime/query/index.d.ts.map +1 -1
  116. package/dist/runtime/query/index.js +55 -7
  117. package/dist/runtime/query/index.js.map +1 -1
  118. package/dist/runtime/query/iteration/index.d.ts +12 -0
  119. package/dist/runtime/query/iteration/index.d.ts.map +1 -1
  120. package/dist/runtime/query/iteration/index.js +348 -38
  121. package/dist/runtime/query/iteration/index.js.map +1 -1
  122. package/dist/runtime/query/iteration/native-output.d.ts +10 -0
  123. package/dist/runtime/query/iteration/native-output.d.ts.map +1 -0
  124. package/dist/runtime/query/iteration/native-output.js +32 -0
  125. package/dist/runtime/query/iteration/native-output.js.map +1 -0
  126. package/dist/runtime/query/iteration/phases/advisory.d.ts.map +1 -1
  127. package/dist/runtime/query/iteration/phases/advisory.js +18 -13
  128. package/dist/runtime/query/iteration/phases/advisory.js.map +1 -1
  129. package/dist/runtime/query/iteration/phases/compaction.d.ts +2 -0
  130. package/dist/runtime/query/iteration/phases/compaction.d.ts.map +1 -1
  131. package/dist/runtime/query/iteration/phases/compaction.js +32 -11
  132. package/dist/runtime/query/iteration/phases/compaction.js.map +1 -1
  133. package/dist/runtime/query/iteration/phases/context.d.ts +9 -0
  134. package/dist/runtime/query/iteration/phases/context.d.ts.map +1 -1
  135. package/dist/runtime/query/iteration/phases/context.js.map +1 -1
  136. package/dist/runtime/query/iteration/phases/tool-review.d.ts.map +1 -1
  137. package/dist/runtime/query/iteration/phases/tool-review.js +1 -1
  138. package/dist/runtime/query/iteration/phases/tool-review.js.map +1 -1
  139. package/dist/runtime/query/iteration/phases/working-memory.d.ts +1 -1
  140. package/dist/runtime/query/iteration/phases/working-memory.d.ts.map +1 -1
  141. package/dist/runtime/query/iteration/phases/working-memory.js +23 -6
  142. package/dist/runtime/query/iteration/phases/working-memory.js.map +1 -1
  143. package/dist/runtime/query/iteration/stream-turn.d.ts.map +1 -1
  144. package/dist/runtime/query/iteration/stream-turn.js +12 -0
  145. package/dist/runtime/query/iteration/stream-turn.js.map +1 -1
  146. package/dist/runtime/query/observation-context.d.ts +10 -0
  147. package/dist/runtime/query/observation-context.d.ts.map +1 -0
  148. package/dist/runtime/query/observation-context.js +84 -0
  149. package/dist/runtime/query/observation-context.js.map +1 -0
  150. package/dist/runtime/query/request-context.d.ts +30 -0
  151. package/dist/runtime/query/request-context.d.ts.map +1 -0
  152. package/dist/runtime/query/request-context.js +76 -0
  153. package/dist/runtime/query/request-context.js.map +1 -0
  154. package/dist/runtime/query/request-rich-content.d.ts.map +1 -1
  155. package/dist/runtime/query/request-rich-content.js +6 -3
  156. package/dist/runtime/query/request-rich-content.js.map +1 -1
  157. package/dist/runtime/query/review-policy.d.ts +3 -0
  158. package/dist/runtime/query/review-policy.d.ts.map +1 -1
  159. package/dist/runtime/query/review-policy.js +4 -1
  160. package/dist/runtime/query/review-policy.js.map +1 -1
  161. package/dist/runtime/query/steering.d.ts +6 -2
  162. package/dist/runtime/query/steering.d.ts.map +1 -1
  163. package/dist/runtime/query/steering.js +17 -2
  164. package/dist/runtime/query/steering.js.map +1 -1
  165. package/dist/runtime/query/tool-call-budget.d.ts +19 -0
  166. package/dist/runtime/query/tool-call-budget.d.ts.map +1 -0
  167. package/dist/runtime/query/tool-call-budget.js +110 -0
  168. package/dist/runtime/query/tool-call-budget.js.map +1 -0
  169. package/dist/runtime/query/tooling.d.ts +3 -0
  170. package/dist/runtime/query/tooling.d.ts.map +1 -1
  171. package/dist/runtime/query/tooling.js +5 -0
  172. package/dist/runtime/query/tooling.js.map +1 -1
  173. package/dist/sandbox/file-walk-program.d.ts.map +1 -1
  174. package/dist/sandbox/file-walk-program.js +8 -0
  175. package/dist/sandbox/file-walk-program.js.map +1 -1
  176. package/dist/sandbox/file-walk.d.ts.map +1 -1
  177. package/dist/sandbox/file-walk.js +9 -0
  178. package/dist/sandbox/file-walk.js.map +1 -1
  179. package/dist/scheduler/completion-inbox.d.ts.map +1 -1
  180. package/dist/scheduler/completion-inbox.js +3 -0
  181. package/dist/scheduler/completion-inbox.js.map +1 -1
  182. package/dist/scheduler/local.d.ts.map +1 -1
  183. package/dist/scheduler/local.js +1 -0
  184. package/dist/scheduler/local.js.map +1 -1
  185. package/dist/session/handoff/capacity.d.ts +2 -2
  186. package/dist/session/handoff/capacity.d.ts.map +1 -1
  187. package/dist/session/handoff/capacity.js +3 -2
  188. package/dist/session/handoff/capacity.js.map +1 -1
  189. package/dist/store/memory/disk.d.ts +6 -2
  190. package/dist/store/memory/disk.d.ts.map +1 -1
  191. package/dist/store/memory/disk.js +42 -25
  192. package/dist/store/memory/disk.js.map +1 -1
  193. package/dist/store/memory/index.d.ts +4 -0
  194. package/dist/store/memory/index.d.ts.map +1 -1
  195. package/dist/store/memory/index.js +55 -19
  196. package/dist/store/memory/index.js.map +1 -1
  197. package/dist/store/memory/memory.d.ts +3 -2
  198. package/dist/store/memory/memory.d.ts.map +1 -1
  199. package/dist/store/memory/memory.js +11 -2
  200. package/dist/store/memory/memory.js.map +1 -1
  201. package/dist/store/memory/operation-lock.d.ts +11 -0
  202. package/dist/store/memory/operation-lock.d.ts.map +1 -0
  203. package/dist/store/memory/operation-lock.js +94 -0
  204. package/dist/store/memory/operation-lock.js.map +1 -0
  205. package/dist/store/run/token-budget-disk.js +3 -0
  206. package/dist/store/run/token-budget-disk.js.map +1 -1
  207. package/dist/tools/builtins/computer-use.d.ts.map +1 -1
  208. package/dist/tools/builtins/computer-use.js +60 -10
  209. package/dist/tools/builtins/computer-use.js.map +1 -1
  210. package/dist/tools/builtins/edit.d.ts.map +1 -1
  211. package/dist/tools/builtins/edit.js +12 -26
  212. package/dist/tools/builtins/edit.js.map +1 -1
  213. package/dist/tools/builtins/file-write-result.d.ts +4 -0
  214. package/dist/tools/builtins/file-write-result.d.ts.map +1 -0
  215. package/dist/tools/builtins/file-write-result.js +72 -0
  216. package/dist/tools/builtins/file-write-result.js.map +1 -0
  217. package/dist/tools/builtins/glob.d.ts.map +1 -1
  218. package/dist/tools/builtins/glob.js +8 -1
  219. package/dist/tools/builtins/glob.js.map +1 -1
  220. package/dist/tools/builtins/grep.d.ts.map +1 -1
  221. package/dist/tools/builtins/grep.js +10 -0
  222. package/dist/tools/builtins/grep.js.map +1 -1
  223. package/dist/tools/builtins/job.d.ts.map +1 -1
  224. package/dist/tools/builtins/job.js +6 -0
  225. package/dist/tools/builtins/job.js.map +1 -1
  226. package/dist/tools/builtins/read-file.d.ts.map +1 -1
  227. package/dist/tools/builtins/read-file.js +10 -0
  228. package/dist/tools/builtins/read-file.js.map +1 -1
  229. package/dist/tools/builtins/run-code.d.ts +6 -0
  230. package/dist/tools/builtins/run-code.d.ts.map +1 -1
  231. package/dist/tools/builtins/run-code.js +15 -4
  232. package/dist/tools/builtins/run-code.js.map +1 -1
  233. package/dist/tools/builtins/search-tools.d.ts.map +1 -1
  234. package/dist/tools/builtins/search-tools.js +14 -2
  235. package/dist/tools/builtins/search-tools.js.map +1 -1
  236. package/dist/tools/builtins/write-file.d.ts.map +1 -1
  237. package/dist/tools/builtins/write-file.js +30 -44
  238. package/dist/tools/builtins/write-file.js.map +1 -1
  239. package/dist/tools/defineTool.d.ts +2 -0
  240. package/dist/tools/defineTool.d.ts.map +1 -1
  241. package/dist/tools/defineTool.js +3 -0
  242. package/dist/tools/defineTool.js.map +1 -1
  243. package/dist/tools/file-read-tracker.d.ts +4 -0
  244. package/dist/tools/file-read-tracker.d.ts.map +1 -0
  245. package/dist/tools/file-read-tracker.js +16 -0
  246. package/dist/tools/file-read-tracker.js.map +1 -0
  247. package/dist/tools/memory/delete.d.ts +4 -0
  248. package/dist/tools/memory/delete.d.ts.map +1 -0
  249. package/dist/tools/memory/delete.js +26 -0
  250. package/dist/tools/memory/delete.js.map +1 -0
  251. package/dist/tools/memory/index.d.ts +2 -0
  252. package/dist/tools/memory/index.d.ts.map +1 -1
  253. package/dist/tools/memory/index.js +6 -0
  254. package/dist/tools/memory/index.js.map +1 -1
  255. package/dist/tools/memory/save.d.ts.map +1 -1
  256. package/dist/tools/memory/save.js +3 -2
  257. package/dist/tools/memory/save.js.map +1 -1
  258. package/dist/tools/memory/search.d.ts.map +1 -1
  259. package/dist/tools/memory/search.js +12 -5
  260. package/dist/tools/memory/search.js.map +1 -1
  261. package/dist/tools/memory/update.d.ts +4 -0
  262. package/dist/tools/memory/update.d.ts.map +1 -0
  263. package/dist/tools/memory/update.js +47 -0
  264. package/dist/tools/memory/update.js.map +1 -0
  265. package/dist/tools/task/list.js +2 -2
  266. package/dist/tools/task/list.js.map +1 -1
  267. package/dist/types/agent/scheduler.d.ts +5 -0
  268. package/dist/types/agent/scheduler.d.ts.map +1 -1
  269. package/dist/types/agent/task.d.ts +10 -0
  270. package/dist/types/agent/task.d.ts.map +1 -1
  271. package/dist/types/computer-use/index.d.ts +6 -0
  272. package/dist/types/computer-use/index.d.ts.map +1 -1
  273. package/dist/types/computer-use/index.js.map +1 -1
  274. package/dist/types/errors/catalog.js +1 -1
  275. package/dist/types/errors/catalog.js.map +1 -1
  276. package/dist/types/hitl/index.d.ts +11 -1
  277. package/dist/types/hitl/index.d.ts.map +1 -1
  278. package/dist/types/hitl/index.js.map +1 -1
  279. package/dist/types/memory/index.d.ts +14 -1
  280. package/dist/types/memory/index.d.ts.map +1 -1
  281. package/dist/types/plugin/index.d.ts +7 -0
  282. package/dist/types/plugin/index.d.ts.map +1 -1
  283. package/dist/types/plugin/index.js.map +1 -1
  284. package/dist/types/project/entity.d.ts +1 -0
  285. package/dist/types/project/entity.d.ts.map +1 -1
  286. package/dist/types/provider/chat.d.ts +4 -0
  287. package/dist/types/provider/chat.d.ts.map +1 -1
  288. package/dist/types/provider/config.d.ts +4 -0
  289. package/dist/types/provider/config.d.ts.map +1 -1
  290. package/dist/types/provider/model.d.ts +4 -0
  291. package/dist/types/provider/model.d.ts.map +1 -1
  292. package/dist/types/provider/stream.d.ts +6 -0
  293. package/dist/types/provider/stream.d.ts.map +1 -1
  294. package/dist/types/run/answer-review.d.ts +2 -0
  295. package/dist/types/run/answer-review.d.ts.map +1 -1
  296. package/dist/types/run/config.d.ts +2 -0
  297. package/dist/types/run/config.d.ts.map +1 -1
  298. package/dist/types/run/events.d.ts +19 -0
  299. package/dist/types/run/events.d.ts.map +1 -1
  300. package/dist/types/run/events.js.map +1 -1
  301. package/dist/types/run/prepare-step.d.ts +19 -1
  302. package/dist/types/run/prepare-step.d.ts.map +1 -1
  303. package/dist/types/sandbox/index.d.ts +1 -0
  304. package/dist/types/sandbox/index.d.ts.map +1 -1
  305. package/dist/types/sandbox/index.js.map +1 -1
  306. package/dist/types/structured-output/index.d.ts +8 -2
  307. package/dist/types/structured-output/index.d.ts.map +1 -1
  308. package/dist/types/tool/index.d.ts +15 -0
  309. package/dist/types/tool/index.d.ts.map +1 -1
  310. package/dist/types/tool/index.js.map +1 -1
  311. package/dist/types/tool/presentation.d.ts +4 -0
  312. package/dist/types/tool/presentation.d.ts.map +1 -1
  313. package/dist/utils/json-snapshot.d.ts +3 -0
  314. package/dist/utils/json-snapshot.d.ts.map +1 -0
  315. package/dist/utils/json-snapshot.js +79 -0
  316. package/dist/utils/json-snapshot.js.map +1 -0
  317. package/package.json +4 -2
  318. package/src/bridge/a2a/mapper.ts +4 -0
  319. package/src/bridge/sse/mapper.ts +16 -1
  320. package/src/compaction/extractor.ts +21 -8
  321. package/src/compaction/manager.ts +11 -1
  322. package/src/compaction/verifier.ts +80 -18
  323. package/src/config/runtime.ts +2 -0
  324. package/src/contracts/api.ts +1 -0
  325. package/src/eval/harness-verification.ts +270 -0
  326. package/src/eval/index.ts +10 -0
  327. package/src/execution/code-runtime/json-value.ts +82 -0
  328. package/src/execution/code-runtime/worker-program.ts +239 -0
  329. package/src/execution/code-runtime/worker.ts +164 -111
  330. package/src/manager/agent/lifecycle.ts +352 -54
  331. package/src/manager/run/persistence.ts +7 -0
  332. package/src/prompt/coding-agent-doctrine.ts +11 -5
  333. package/src/provider/capabilities.ts +41 -1
  334. package/src/provider/fallback.ts +9 -2
  335. package/src/public-runtime.ts +6 -0
  336. package/src/public-tools.ts +7 -1
  337. package/src/public-types.ts +7 -0
  338. package/src/registry/tool/execute.ts +17 -79
  339. package/src/run/command-gate.ts +61 -13
  340. package/src/run/index.ts +2 -0
  341. package/src/run/memory-promoter.ts +32 -40
  342. package/src/run/memory-recall.ts +254 -0
  343. package/src/run/reporter.ts +2 -0
  344. package/src/run/token-budget.ts +55 -14
  345. package/src/run/workspace-fingerprint.ts +17 -8
  346. package/src/runtime/query/checkpoint.ts +96 -2
  347. package/src/runtime/query/executor.ts +100 -29
  348. package/src/runtime/query/index.ts +76 -16
  349. package/src/runtime/query/iteration/index.ts +405 -46
  350. package/src/runtime/query/iteration/native-output.ts +35 -0
  351. package/src/runtime/query/iteration/phases/advisory.ts +21 -11
  352. package/src/runtime/query/iteration/phases/compaction.ts +36 -14
  353. package/src/runtime/query/iteration/phases/context.ts +9 -0
  354. package/src/runtime/query/iteration/phases/tool-review.ts +5 -1
  355. package/src/runtime/query/iteration/phases/working-memory.ts +23 -5
  356. package/src/runtime/query/iteration/stream-turn.ts +15 -0
  357. package/src/runtime/query/observation-context.ts +86 -0
  358. package/src/runtime/query/request-context.ts +103 -0
  359. package/src/runtime/query/request-rich-content.ts +8 -3
  360. package/src/runtime/query/review-policy.ts +7 -1
  361. package/src/runtime/query/steering.ts +19 -2
  362. package/src/runtime/query/tool-call-budget.ts +115 -0
  363. package/src/runtime/query/tooling.ts +8 -0
  364. package/src/sandbox/file-walk-program.ts +8 -0
  365. package/src/sandbox/file-walk.ts +9 -0
  366. package/src/scheduler/completion-inbox.ts +3 -0
  367. package/src/scheduler/local.ts +1 -0
  368. package/src/session/handoff/capacity.ts +7 -3
  369. package/src/store/memory/disk.ts +52 -30
  370. package/src/store/memory/index.ts +75 -27
  371. package/src/store/memory/memory.ts +18 -6
  372. package/src/store/memory/operation-lock.ts +99 -0
  373. package/src/store/run/token-budget-disk.ts +3 -0
  374. package/src/tools/builtins/computer-use.ts +61 -7
  375. package/src/tools/builtins/edit.ts +12 -27
  376. package/src/tools/builtins/file-write-result.ts +84 -0
  377. package/src/tools/builtins/glob.ts +7 -1
  378. package/src/tools/builtins/grep.ts +10 -0
  379. package/src/tools/builtins/job.ts +8 -0
  380. package/src/tools/builtins/read-file.ts +10 -0
  381. package/src/tools/builtins/run-code.ts +24 -5
  382. package/src/tools/builtins/search-tools.ts +18 -3
  383. package/src/tools/builtins/write-file.ts +39 -44
  384. package/src/tools/defineTool.ts +5 -0
  385. package/src/tools/file-read-tracker.ts +16 -0
  386. package/src/tools/memory/delete.ts +29 -0
  387. package/src/tools/memory/index.ts +6 -0
  388. package/src/tools/memory/save.ts +4 -2
  389. package/src/tools/memory/search.ts +12 -5
  390. package/src/tools/memory/update.ts +50 -0
  391. package/src/tools/task/list.ts +2 -2
  392. package/src/types/agent/scheduler.ts +6 -0
  393. package/src/types/agent/task.ts +13 -0
  394. package/src/types/computer-use/index.ts +6 -0
  395. package/src/types/errors/catalog.ts +1 -1
  396. package/src/types/hitl/index.ts +11 -1
  397. package/src/types/memory/index.ts +16 -1
  398. package/src/types/plugin/index.ts +10 -0
  399. package/src/types/project/entity.ts +1 -0
  400. package/src/types/provider/chat.ts +2 -0
  401. package/src/types/provider/config.ts +4 -0
  402. package/src/types/provider/model.ts +4 -0
  403. package/src/types/provider/stream.ts +7 -0
  404. package/src/types/run/answer-review.ts +2 -0
  405. package/src/types/run/config.ts +2 -0
  406. package/src/types/run/events.ts +20 -0
  407. package/src/types/run/prepare-step.ts +19 -1
  408. package/src/types/sandbox/index.ts +1 -0
  409. package/src/types/structured-output/index.ts +15 -2
  410. package/src/types/tool/index.ts +16 -0
  411. package/src/types/tool/presentation.ts +4 -0
  412. package/src/utils/json-snapshot.ts +76 -0
@@ -1,4 +1,9 @@
1
- import type { LLMProvider, ProviderCapabilities } from '../types/provider/index.js'
1
+ import type {
2
+ ChatCompletionParams,
3
+ LLMProvider,
4
+ ProviderCapabilities,
5
+ } from '../types/provider/index.js'
6
+ import { ProviderRequestError } from './errors.js'
2
7
 
3
8
  /**
4
9
  * Fully-resolved capability set: every flag present, no optionals left.
@@ -59,3 +64,38 @@ export function resolveProviderCapabilities(
59
64
  maxOutputTokens: declared?.maxOutputTokens,
60
65
  }
61
66
  }
67
+
68
+ /** Require explicit wire support before dispatching a native JSON Schema request. */
69
+ export function assertNativeStructuredOutputSupported(
70
+ provider: Pick<LLMProvider, 'id' | 'capabilities'>,
71
+ params: Pick<ChatCompletionParams, 'responseFormat'>,
72
+ ): void {
73
+ if (
74
+ params.responseFormat?.type === 'json_schema' &&
75
+ provider.capabilities?.supportsNativeStructuredOutput !== true
76
+ ) {
77
+ throw new ProviderRequestError({
78
+ kind: 'bad_request',
79
+ providerId: provider.id,
80
+ providerCode: 'native_structured_output_unsupported',
81
+ detail:
82
+ 'Native JSON Schema output requires a provider that declares supportsNativeStructuredOutput: true.',
83
+ })
84
+ }
85
+ }
86
+
87
+ /** Refuse a hosted search request before dispatch when the route cannot honor it. */
88
+ export function assertHostedWebSearchSupported(
89
+ provider: Pick<LLMProvider, 'id' | 'capabilities'>,
90
+ params: Pick<ChatCompletionParams, 'webSearch'>,
91
+ ): void {
92
+ if (params.webSearch && provider.capabilities?.supportsHostedWebSearch !== true) {
93
+ throw new ProviderRequestError({
94
+ kind: 'bad_request',
95
+ providerId: provider.id,
96
+ providerCode: 'hosted_web_search_unsupported',
97
+ detail:
98
+ 'This provider does not support hosted web search. Disable web.search or select a supported provider.',
99
+ })
100
+ }
101
+ }
@@ -31,6 +31,10 @@ import type {
31
31
  ThinkingConfig,
32
32
  } from '../types/provider/index.js'
33
33
  import type { Logger } from '../utils/logger.js'
34
+ import {
35
+ assertHostedWebSearchSupported,
36
+ assertNativeStructuredOutputSupported,
37
+ } from './capabilities.js'
34
38
 
35
39
  /**
36
40
  * One member of the chain: a constructed provider, and the model to ask it for.
@@ -209,13 +213,14 @@ function shouldFallOver(err: unknown, providerId: string): boolean {
209
213
  */
210
214
  function isOutputChunk(chunk: StreamChunk): boolean {
211
215
  if (chunk.retry !== undefined || chunk.fallback !== undefined) return false
212
- const { content, toolCalls, toolCallEnd, reasoning, citation } = chunk.delta
216
+ const { content, toolCalls, toolCallEnd, reasoning, citation, hostedTool } = chunk.delta
213
217
  return Boolean(
214
218
  content ||
215
219
  toolCalls?.length ||
216
220
  toolCallEnd ||
217
221
  reasoning !== undefined ||
218
- citation !== undefined,
222
+ citation !== undefined ||
223
+ hostedTool !== undefined,
219
224
  )
220
225
  }
221
226
 
@@ -396,6 +401,8 @@ export function withProviderFallback(
396
401
  chainIndex: cursor,
397
402
  },
398
403
  }
404
+ assertNativeStructuredOutputSupported(member.provider, request)
405
+ assertHostedWebSearchSupported(member.provider, request)
399
406
  let produced = false
400
407
  try {
401
408
  for await (const chunk of member.provider.chatStream(request)) {
@@ -380,6 +380,8 @@ export type {
380
380
  // nothing.
381
381
  export { RUN_MEMORY_TAG, createMemoryPromoter } from './run/index.js'
382
382
  export type { MemoryPromoterOptions } from './run/index.js'
383
+ export { createMemoryRecallStep } from './run/memory-recall.js'
384
+ export type { MemoryRecallOptions } from './run/memory-recall.js'
383
385
 
384
386
  // ─── personas, skills, advisory ──────────────────────────────────────────
385
387
 
@@ -1111,6 +1113,8 @@ export { anyOf, hasToolCall, stepCountIs } from './types/run/step.js'
1111
1113
  // ─── evaluation harness ──────────────────────────────────────────────────
1112
1114
 
1113
1115
  export {
1116
+ compareHarnessTrials,
1117
+ reviewHarnessCandidate,
1114
1118
  completionScorer,
1115
1119
  containsScorer,
1116
1120
  customScorer,
@@ -1335,3 +1339,5 @@ export { WORKING_STATE_MIME } from './connector/mcp/adapter.js'
1335
1339
  export { TokenBudget, validateTokenBudgetSnapshot } from './run/token-budget.js'
1336
1340
  export { DiskTokenBudgetStore, openTokenBudget } from './store/run/token-budget-disk.js'
1337
1341
  export { validateTokenBudgetBinding } from './types/run/token-budget-store.js'
1342
+
1343
+ export { snapshotRequestContext, diffRequestContext } from './runtime/query/request-context.js'
@@ -97,7 +97,11 @@ export {
97
97
  buildTaskUpdateTool,
98
98
  } from './tools/task/index.js'
99
99
  export { buildAdvisoryTools } from './tools/advisory/index.js'
100
- export { buildMemoryTools } from './tools/memory/index.js'
100
+ export {
101
+ buildMemoryTools,
102
+ buildUpdateMemoryTool,
103
+ buildDeleteMemoryTool,
104
+ } from './tools/memory/index.js'
101
105
  export { buildCoordinatorTools } from './tools/coordinator/index.js'
102
106
  export {
103
107
  buildAskUserQuestionTool,
@@ -121,3 +125,5 @@ export {
121
125
  createConnectorRouterTool,
122
126
  createConnectorTools,
123
127
  } from './connector/tools/index.js'
128
+
129
+ export { createFileReadTracker } from './tools/file-read-tracker.js'
@@ -19,6 +19,7 @@ export type * from './types/common/index.js'
19
19
  export type { CoalesceOptions } from './streaming/coalesce.js'
20
20
  export type * from './types/bidi/index.js'
21
21
  export type * from './types/tool/index.js'
22
+ export type { WorkerCodeRuntimeOptions } from './execution/code-runtime/worker.js'
22
23
  export type {
23
24
  CodeRunOutcome,
24
25
  CodeRunResult,
@@ -438,3 +439,9 @@ export type {
438
439
  DiskTokenBudgetStoreConfig,
439
440
  OpenTokenBudgetOptions,
440
441
  } from './store/run/token-budget-disk.js'
442
+
443
+ export type {
444
+ RequestContextPart,
445
+ RequestContextSnapshot,
446
+ RequestContextChange,
447
+ } from './runtime/query/request-context.js'
@@ -18,6 +18,7 @@ import type {
18
18
  ToolTierConfig,
19
19
  } from '../../types/tool/index.js'
20
20
  import { toErrorMessage } from '../../utils/error.js'
21
+ import { cloneJsonValue as clonePreparedInput } from '../../utils/json-snapshot.js'
21
22
  import { ManagedRegistry } from '../ManagedRegistry.js'
22
23
  import { renderToolSchema } from './schema.js'
23
24
  import { ToolResultHalted, screenToolResult } from './screen.js'
@@ -90,82 +91,6 @@ export function assertToolName(name: string): void {
90
91
  )
91
92
  }
92
93
 
93
- function clonePreparedInput(value: unknown, freeze: boolean, path = '$'): unknown {
94
- const active = new WeakSet<object>()
95
- const copies = new WeakMap<object, object>()
96
-
97
- const clone = (candidate: unknown, at: string): unknown => {
98
- if (candidate === null || typeof candidate === 'string' || typeof candidate === 'boolean') {
99
- return candidate
100
- }
101
- if (typeof candidate === 'number') {
102
- if (!Number.isFinite(candidate) || Object.is(candidate, -0)) {
103
- throw new TypeError(`${at} must be a finite JSON number`)
104
- }
105
- return candidate
106
- }
107
- if (typeof candidate !== 'object') {
108
- throw new TypeError(`${at} must be a JSON value, not ${typeof candidate}`)
109
- }
110
- if (active.has(candidate)) throw new TypeError(`${at} contains a cycle`)
111
- const existing = copies.get(candidate)
112
- if (existing) return existing
113
-
114
- active.add(candidate)
115
- try {
116
- if (Array.isArray(candidate)) {
117
- const extra = Reflect.ownKeys(candidate).filter(
118
- (key) => key !== 'length' && (typeof key !== 'string' || !/^(0|[1-9]\d*)$/.test(key)),
119
- )
120
- if (extra.length > 0) throw new TypeError(`${at} has non-JSON array properties`)
121
- const result: unknown[] = new Array(candidate.length)
122
- copies.set(candidate, result)
123
- for (let index = 0; index < candidate.length; index++) {
124
- const descriptor = Object.getOwnPropertyDescriptor(candidate, String(index))
125
- if (!descriptor) throw new TypeError(`${at}[${index}] is a sparse array hole`)
126
- if (!descriptor.enumerable || !('value' in descriptor)) {
127
- throw new TypeError(`${at}[${index}] must be an enumerable data property`)
128
- }
129
- result[index] = clone(descriptor.value, `${at}[${index}]`)
130
- }
131
- if (freeze) Object.freeze(result)
132
- return result
133
- }
134
-
135
- const prototype = Object.getPrototypeOf(candidate)
136
- if (prototype !== Object.prototype && prototype !== null) {
137
- throw new TypeError(`${at} must be a plain JSON object`)
138
- }
139
- // JSON does not preserve prototypes. Canonicalize both admitted plain
140
- // shapes to an ordinary object so a disk checkpoint round-trip compares
141
- // equal to a fresh preparation of the same semantic value. Properties
142
- // are still defined explicitly, so a literal "__proto__" key remains
143
- // data rather than changing this object's prototype.
144
- const result: Record<string, unknown> = {}
145
- copies.set(candidate, result)
146
- for (const key of Reflect.ownKeys(candidate)) {
147
- if (typeof key !== 'string') throw new TypeError(`${at} has a symbol property`)
148
- const descriptor = Object.getOwnPropertyDescriptor(candidate, key)
149
- if (!descriptor?.enumerable || !('value' in descriptor)) {
150
- throw new TypeError(`${at}.${key} must be an enumerable data property`)
151
- }
152
- Object.defineProperty(result, key, {
153
- value: clone(descriptor.value, `${at}.${key}`),
154
- enumerable: true,
155
- writable: !freeze,
156
- configurable: !freeze,
157
- })
158
- }
159
- if (freeze) Object.freeze(result)
160
- return result
161
- } finally {
162
- active.delete(candidate)
163
- }
164
- }
165
-
166
- return clone(value, path)
167
- }
168
-
169
94
  /**
170
95
  * Two sources contributed the same tool name and neither may take it.
171
96
  *
@@ -364,17 +289,30 @@ export class ToolRegistry extends ManagedRegistry<ToolDefinition> {
364
289
  * would churn that prefix repeatedly and is rejected.
365
290
  */
366
291
  searchDeferred(query: string): ToolDefinition[] {
292
+ return this.searchByAvailability(query, ['deferred'])
293
+ }
294
+
295
+ /** Active matches use the same ranking, also recognizing exact short or generic names. */
296
+ searchActive(query: string): ToolDefinition[] {
297
+ return this.searchByAvailability(query, ['active'], true)
298
+ }
299
+
300
+ private searchByAvailability(
301
+ query: string,
302
+ states: ToolAvailability[],
303
+ allowExactName = false,
304
+ ): ToolDefinition[] {
367
305
  const q = query.toLowerCase().trim()
368
306
  if (q.length === 0) return []
369
307
  const terms = q.split(/\s+/).filter((tok) => tok.length >= 3 && !SEARCH_STOP_TOKENS.has(tok))
370
- if (terms.length === 0) return []
308
+ if (terms.length === 0 && !allowExactName) return []
371
309
 
372
310
  const scored: Array<{ tool: ToolDefinition; score: number }> = []
373
- for (const tool of this.getByAvailability(['deferred'])) {
311
+ for (const tool of this.getByAvailability(states)) {
374
312
  const name = tool.name.toLowerCase()
375
313
  const description = tool.description.toLowerCase()
376
314
  const argumentNames = listArgumentNames(tool)
377
- let score = 0
315
+ let score = allowExactName && terms.length === 0 && name === q ? SEARCH_WEIGHT_NAME_EXACT : 0
378
316
  for (const term of terms) {
379
317
  if (name === term) {
380
318
  score += SEARCH_WEIGHT_NAME_EXACT
@@ -110,11 +110,18 @@ export interface CommandGateOptions {
110
110
 
111
111
  /** Head and tail of a command's output, with the middle marked as dropped. */
112
112
  export function clipOutput(text: string, max: number): string {
113
+ if (!Number.isSafeInteger(max) || max < 0) {
114
+ throw new RangeError('maxOutputChars must be a nonnegative safe integer.')
115
+ }
113
116
  const trimmed = text.trimEnd()
114
117
  if (trimmed.length <= max) return trimmed
115
- const half = Math.floor(max / 2)
116
- const dropped = trimmed.length - half * 2
117
- return `${trimmed.slice(0, half)}\n… ${dropped} characters omitted …\n${trimmed.slice(-half)}`
118
+ const markerBudget = `\n… ${trimmed.length} characters omitted …\n`.length
119
+ if (max < markerBudget) return max === 0 ? '' : '…'
120
+ const retained = max - markerBudget
121
+ const head = Math.ceil(retained / 2)
122
+ const tail = retained - head
123
+ const marker = `\n… ${trimmed.length - retained} characters omitted …\n`
124
+ return `${trimmed.slice(0, head)}${marker}${tail > 0 ? trimmed.slice(-tail) : ''}`
118
125
  }
119
126
 
120
127
  interface LastFailure {
@@ -142,7 +149,7 @@ function failureFeedback(
142
149
  `Retained output is incomplete: ${truncatedStreams.join(' and ')} ${truncatedStreams.length === 1 ? 'was' : 'were'} truncated by the execution context. Re-run with a narrower command or filter to recover the missing diagnostics.`,
143
150
  ]
144
151
  return [
145
- `The answer was not accepted: \`${command}\` failed (attempt ${attempt}, exit ${result.exitCode}).`,
152
+ `The answer was not accepted: \`${command}\` failed (attempt ${attempt}, exit ${result.exitCode}${result.termination ? `, terminated: ${result.termination.origin}` : ''}).`,
146
153
  '',
147
154
  'Output:',
148
155
  '```',
@@ -158,9 +165,9 @@ function unchangedFeedback(command: string, attempt: number): string {
158
165
  return [
159
166
  `The answer was not accepted, and \`${command}\` was NOT re-run (attempt ${attempt}).`,
160
167
  '',
161
- 'The workspace is byte-for-byte identical to what it was when that command last failed — no file was created, edited or deleted since. Running it again would produce the failure you have already been shown.',
168
+ 'The configured change detector reports the same state as after the last failure. The default detector covers the Git commit and Git-visible working state; ignored files and external inputs may have changed.',
162
169
  '',
163
- 'Edit something before trying to finish again. If you believe the change you described was made, verify it by reading the file: it is not on disk.',
170
+ 'Check that the intended fix is present and addresses the reported failure. If verification depends on state outside the detector, the host should supply a matching fingerprint or return null to re-run checks.',
164
171
  ].join('\n')
165
172
  }
166
173
 
@@ -183,20 +190,39 @@ export function createCommandGate(options: CommandGateOptions): ReviewAnswer {
183
190
  const timeoutMs = options.timeoutMs ?? DEFAULT_GATE_TIMEOUT_MS
184
191
  const maxRetries = options.maxRetries ?? DEFAULT_GATE_MAX_RETRIES
185
192
  const maxOutputChars = options.maxOutputChars ?? DEFAULT_GATE_OUTPUT_CHARS
193
+ // Validate before a reviewer is installed: malformed limits cannot turn
194
+ // a formatting exception during verification into an unreviewed answer.
195
+ clipOutput('', maxOutputChars)
186
196
 
187
197
  // Built once and reused: constructing a context per attempt would re-stat
188
198
  // the directory for no gain, and the context holds nothing per-run.
189
199
  const context = new LocalExecutionContext({ id: 'namzu-command-gate', cwd })
190
200
  const exec: GateExec =
191
201
  options.exec ?? ((command, args, opts) => context.executeCommand(command, args, opts))
192
- const fingerprint =
193
- options.fingerprint ?? (() => fingerprintWorkspace({ cwd, exec, timeoutMs: 20_000 }))
202
+ const readFingerprint = async (signal?: AbortSignal): Promise<string | null> => {
203
+ if (signal?.aborted) return null
204
+ try {
205
+ return options.fingerprint
206
+ ? await options.fingerprint()
207
+ : await fingerprintWorkspace({
208
+ cwd,
209
+ timeoutMs: 20_000,
210
+ exec: (command, args, commandOptions) =>
211
+ exec(command, args, { ...commandOptions, ...(signal ? { signal } : {}) }),
212
+ })
213
+ } catch {
214
+ return null
215
+ }
216
+ }
194
217
 
195
218
  let attempt = 0
196
219
  let last: LastFailure | undefined
197
220
  let executions = 0
198
221
 
199
- return async (): Promise<AnswerReview> => {
222
+ return async (_answer, reviewContext): Promise<AnswerReview> => {
223
+ const signal = reviewContext.signal
224
+ if (signal?.aborted)
225
+ return { accept: false, feedback: 'Verification was cancelled before admission.' }
200
226
  attempt += 1
201
227
 
202
228
  // A gate that already failed, over a tree nothing has touched since.
@@ -209,7 +235,7 @@ export function createCommandGate(options: CommandGateOptions): ReviewAnswer {
209
235
  // that deleted it killed no test, which is what a dead condition looks
210
236
  // like from the outside.
211
237
  if (last && last.fingerprint !== null) {
212
- const now = await fingerprint()
238
+ const now = await readFingerprint(signal)
213
239
  if (now === last.fingerprint) {
214
240
  return { accept: false, feedback: unchangedFeedback(last.command, attempt) }
215
241
  }
@@ -221,20 +247,42 @@ export function createCommandGate(options: CommandGateOptions): ReviewAnswer {
221
247
 
222
248
  executions += 1
223
249
  for (const command of commands) {
250
+ if (signal?.aborted)
251
+ return { accept: false, feedback: 'Verification was cancelled before admission.' }
224
252
  // `shell: true` because the operator handed over a command LINE —
225
253
  // `pnpm test -- --run`, with its flags and its quoting — and taking
226
254
  // that as an executable name plus literal arguments would fail on
227
255
  // every gate anyone would actually write. Explicit, per the note on
228
256
  // `LocalExecutionContext.executeCommand`: shell interpretation is
229
257
  // opt-in, and this is the opt-in.
230
- const result = await exec(command, [], { cwd, timeoutMs, shell: true })
231
- if (result.exitCode === 0) continue
258
+ let result: CommandResult
259
+ try {
260
+ result = await exec(command, [], {
261
+ cwd,
262
+ timeoutMs,
263
+ shell: true,
264
+ ...(signal ? { signal } : {}),
265
+ })
266
+ } catch (error) {
267
+ // A command that could not be observed completing is not a pass.
268
+ // Keep this inside the builtin reviewer: generic review callbacks
269
+ // historically fail open on throws. No fabricated exit status.
270
+ last = { command, fingerprint: null }
271
+ return {
272
+ accept: false,
273
+ feedback: `The answer was not accepted: verification with \`${command}\` could not complete (attempt ${attempt}).\n${clipOutput(error instanceof Error ? error.message : String(error), maxOutputChars)}\nCheck the execution problem and any partial effects before retrying. Do not claim verification passed.`,
274
+ }
275
+ }
276
+ if (signal?.aborted) return { accept: false, feedback: 'Verification was cancelled.' }
277
+ if (result.exitCode === 0 && result.termination === undefined) continue
232
278
 
233
279
  // Taken AFTER the failure, not before the run: the comparison next
234
280
  // time is against the tree this verdict was formed over. A snapshot
235
281
  // from before the command would miss anything the command itself
236
282
  // wrote — a formatter, a snapshot updater, a lockfile.
237
- last = { command, fingerprint: await fingerprint() }
283
+ // Interrupted verification is not a stable failure of these source
284
+ // bytes. Allow another check even when no tracked file has changed.
285
+ last = { command, fingerprint: result.termination ? null : await readFingerprint(signal) }
238
286
  return { accept: false, feedback: failureFeedback(command, attempt, result, maxOutputChars) }
239
287
  }
240
288
 
package/src/run/index.ts CHANGED
@@ -27,3 +27,5 @@ export type { LimitCheckerState, LimitCheckResult } from './LimitChecker.js'
27
27
 
28
28
  export { RUN_MEMORY_TAG, createMemoryPromoter } from './memory-promoter.js'
29
29
  export type { MemoryPromoterOptions } from './memory-promoter.js'
30
+ export { createMemoryRecallStep } from './memory-recall.js'
31
+ export type { MemoryRecallOptions } from './memory-recall.js'
@@ -1,41 +1,10 @@
1
1
  /**
2
- * The default {@link PromoteMemory}: write what a run learned into a
3
- * {@link MemoryStore}, or write nothing at all.
4
- *
5
- * `promoteMemory` is called once at settle with the compaction extractor's
6
- * already-structured output — decisions, discoveries, user requirements,
7
- * failures, environment facts — and **nothing shipped supplied the hook**.
8
- * So the structure the compaction pass had spent tokens producing was
9
- * serialized into one system message and dropped on the floor when the run
10
- * ended, exactly as its own module comment says. This is the supplier, and
11
- * it is mostly a filter: the hard part — extracting facts from a transcript
12
- * — already happened.
13
- *
14
- * ## The filter, which is the only decision here
15
- *
16
- * **A run that learned nothing must leave nothing.** Not an empty record,
17
- * not a record whose body says "no decisions" — nothing. A promoter that
18
- * wrote a row per run would fill the store with the runs least worth
19
- * remembering, and `search_memory` would then return them: the model reads
20
- * that store on later runs, so noise here is not merely wasted disk, it is
21
- * context spent on a run that did nothing.
22
- *
23
- * What counts as having learned something is the five KNOWLEDGE categories —
24
- * decisions, discoveries, user requirements, failures, environment. Not
25
- * `task`, which every run has because it is the prompt restated. Not
26
- * `files`, which every run that opened anything has, and which says what was
27
- * touched rather than what was learned. A run whose only trace is "it read
28
- * six files" is the exact record this filter exists to refuse.
29
- *
30
- * ## What it does NOT do
31
- *
32
- * Deduplicate against what is already stored, merge with a previous run's
33
- * record, or expire anything. Each is a policy with real trade-offs and a
34
- * host that wants one owns it — `promoteMemory` is a callback precisely so
35
- * that the runtime does not decide this. This is the obvious default, not
36
- * the only possible one.
2
+ * Select useful extracted claims for durable recall. Exact repeated claim sets
3
+ * are suppressed when already stored; archived claims are not reactivated.
4
+ * This deterministic filter does not verify truth or reconcile paraphrases.
37
5
  */
38
6
 
7
+ import { createHash } from 'node:crypto'
39
8
  import type { MemoryStore } from '../types/memory/index.js'
40
9
  import type { PromoteMemory, RunMemoryCandidate } from '../types/run/memory-promotion.js'
41
10
 
@@ -85,15 +54,18 @@ function knowledge(
85
54
  ): readonly (readonly [string, readonly string[]])[] {
86
55
  const out: (readonly [string, readonly string[]])[] = []
87
56
  for (const [key, heading] of KNOWLEDGE) {
88
- const items = candidate[key] as readonly string[]
57
+ const items = [
58
+ ...new Set((candidate[key] as readonly string[]).map((item) => item.trim()).filter(Boolean)),
59
+ ]
89
60
  if (items.length > 0) out.push([heading, items.slice(0, cap)])
90
61
  }
91
62
  return out
92
63
  }
93
64
 
94
- /** A one-line summary naming what kind of knowledge the record holds. */
65
+ /** Carry actual claims into search results, with their category attribution. */
95
66
  function summarize(sections: readonly (readonly [string, readonly string[]])[]): string {
96
- return sections.map(([heading, items]) => `${heading.toLowerCase()} (${items.length})`).join(', ')
67
+ const text = sections.map(([heading, items]) => `${heading}: ${items[0]}`).join('; ')
68
+ return text.length <= 600 ? text : `${text.slice(0, 599).replace(/[\uD800-\uDBFF]$/, '')}…`
97
69
  }
98
70
 
99
71
  function render(
@@ -131,6 +103,8 @@ function render(
131
103
  */
132
104
  export function createMemoryPromoter(options: MemoryPromoterOptions): PromoteMemory {
133
105
  const cap = options.maxPerCategory ?? 20
106
+ if (!Number.isSafeInteger(cap) || cap < 1)
107
+ throw new Error('maxPerCategory must be a positive integer')
134
108
  const tags = [RUN_MEMORY_TAG, ...(options.tags ?? [])]
135
109
 
136
110
  return async (candidate: RunMemoryCandidate): Promise<void> => {
@@ -139,17 +113,35 @@ export function createMemoryPromoter(options: MemoryPromoterOptions): PromoteMem
139
113
  // of rows describing runs that discovered nothing is a store whose
140
114
  // search results are mostly noise, and the model reads that store.
141
115
  if (sections.length === 0) return
116
+ const digest = createHash('sha256').update(JSON.stringify(sections)).digest('hex')
117
+ const knowledgeTag = `knowledge:${digest}`
118
+ // A prior exact claim, including one deliberately archived, need not be
119
+ // saved again. This is not a cross-process uniqueness guarantee: the
120
+ // store's individual operations are atomic, not this read/create pair.
121
+ const existing = await options.store.list({
122
+ tags: [...tags, knowledgeTag],
123
+ })
124
+ for (const entry of existing.entries) {
125
+ const full = await options.store.get(entry.id)
126
+ if (full?.metadata?.source === RUN_MEMORY_TAG && full.metadata.knowledgeDigest === digest)
127
+ return
128
+ }
142
129
 
143
130
  await options.store.create({
144
131
  title: candidate.task.trim() || `Run ${candidate.runId}`,
145
132
  summary: summarize(sections),
146
133
  content: render(candidate, sections),
147
- tags,
134
+ tags: [...tags, knowledgeTag],
148
135
  format: 'markdown',
149
136
  // The run id, so a record can be traced back to the run that formed
150
137
  // it. Evidence rather than decoration: without it a surprising
151
138
  // memory cannot be checked against what actually happened.
152
- metadata: { runId: candidate.runId, source: RUN_MEMORY_TAG },
139
+ metadata: {
140
+ runId: candidate.runId,
141
+ source: RUN_MEMORY_TAG,
142
+ knowledgeDigest: digest,
143
+ verification: 'unverified',
144
+ },
153
145
  })
154
146
  }
155
147
  }