@namzu/sdk 35.0.0 → 37.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 (360) hide show
  1. package/CHANGELOG.md +218 -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 +2 -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 +2 -0
  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/contracts/schemas.d.ts +10 -10
  21. package/dist/eval/harness-verification.d.ts +63 -0
  22. package/dist/eval/harness-verification.d.ts.map +1 -0
  23. package/dist/eval/harness-verification.js +165 -0
  24. package/dist/eval/harness-verification.js.map +1 -0
  25. package/dist/eval/index.d.ts +2 -0
  26. package/dist/eval/index.d.ts.map +1 -1
  27. package/dist/eval/index.js +1 -0
  28. package/dist/eval/index.js.map +1 -1
  29. package/dist/execution/code-runtime/json-value.d.ts +10 -0
  30. package/dist/execution/code-runtime/json-value.d.ts.map +1 -0
  31. package/dist/execution/code-runtime/json-value.js +89 -0
  32. package/dist/execution/code-runtime/json-value.js.map +1 -0
  33. package/dist/execution/code-runtime/worker-program.d.ts +8 -0
  34. package/dist/execution/code-runtime/worker-program.d.ts.map +1 -0
  35. package/dist/execution/code-runtime/worker-program.js +240 -0
  36. package/dist/execution/code-runtime/worker-program.js.map +1 -0
  37. package/dist/execution/code-runtime/worker.d.ts +22 -0
  38. package/dist/execution/code-runtime/worker.d.ts.map +1 -1
  39. package/dist/execution/code-runtime/worker.js +148 -111
  40. package/dist/execution/code-runtime/worker.js.map +1 -1
  41. package/dist/manager/agent/lifecycle.d.ts +12 -0
  42. package/dist/manager/agent/lifecycle.d.ts.map +1 -1
  43. package/dist/manager/agent/lifecycle.js +306 -37
  44. package/dist/manager/agent/lifecycle.js.map +1 -1
  45. package/dist/manager/run/persistence.d.ts +2 -0
  46. package/dist/manager/run/persistence.d.ts.map +1 -1
  47. package/dist/manager/run/persistence.js +6 -0
  48. package/dist/manager/run/persistence.js.map +1 -1
  49. package/dist/provider/capabilities.d.ts +3 -1
  50. package/dist/provider/capabilities.d.ts.map +1 -1
  51. package/dist/provider/capabilities.js +13 -0
  52. package/dist/provider/capabilities.js.map +1 -1
  53. package/dist/provider/fallback.d.ts.map +1 -1
  54. package/dist/provider/fallback.js +2 -0
  55. package/dist/provider/fallback.js.map +1 -1
  56. package/dist/provider/token-budget.d.ts.map +1 -1
  57. package/dist/provider/token-budget.js +56 -8
  58. package/dist/provider/token-budget.js.map +1 -1
  59. package/dist/public-runtime.d.ts +5 -3
  60. package/dist/public-runtime.d.ts.map +1 -1
  61. package/dist/public-runtime.js +3 -2
  62. package/dist/public-runtime.js.map +1 -1
  63. package/dist/public-tools.d.ts +1 -1
  64. package/dist/public-tools.d.ts.map +1 -1
  65. package/dist/public-tools.js +1 -1
  66. package/dist/public-tools.js.map +1 -1
  67. package/dist/public-types.d.ts +1 -0
  68. package/dist/public-types.d.ts.map +1 -1
  69. package/dist/registry/tool/execute.d.ts +3 -0
  70. package/dist/registry/tool/execute.d.ts.map +1 -1
  71. package/dist/registry/tool/execute.js +11 -80
  72. package/dist/registry/tool/execute.js.map +1 -1
  73. package/dist/run/command-gate.d.ts.map +1 -1
  74. package/dist/run/command-gate.js +65 -12
  75. package/dist/run/command-gate.js.map +1 -1
  76. package/dist/run/index.d.ts +2 -0
  77. package/dist/run/index.d.ts.map +1 -1
  78. package/dist/run/index.js +1 -0
  79. package/dist/run/index.js.map +1 -1
  80. package/dist/run/memory-promoter.d.ts +3 -35
  81. package/dist/run/memory-promoter.d.ts.map +1 -1
  82. package/dist/run/memory-promoter.js +32 -40
  83. package/dist/run/memory-promoter.js.map +1 -1
  84. package/dist/run/memory-recall.d.ts +25 -0
  85. package/dist/run/memory-recall.d.ts.map +1 -0
  86. package/dist/run/memory-recall.js +228 -0
  87. package/dist/run/memory-recall.js.map +1 -0
  88. package/dist/run/reporter.d.ts.map +1 -1
  89. package/dist/run/reporter.js +1 -0
  90. package/dist/run/reporter.js.map +1 -1
  91. package/dist/run/token-budget.d.ts +2 -0
  92. package/dist/run/token-budget.d.ts.map +1 -1
  93. package/dist/run/token-budget.js +4 -0
  94. package/dist/run/token-budget.js.map +1 -1
  95. package/dist/run/workspace-fingerprint.d.ts +10 -3
  96. package/dist/run/workspace-fingerprint.d.ts.map +1 -1
  97. package/dist/run/workspace-fingerprint.js +17 -8
  98. package/dist/run/workspace-fingerprint.js.map +1 -1
  99. package/dist/runtime/query/checkpoint.d.ts +14 -0
  100. package/dist/runtime/query/checkpoint.d.ts.map +1 -1
  101. package/dist/runtime/query/checkpoint.js +82 -1
  102. package/dist/runtime/query/checkpoint.js.map +1 -1
  103. package/dist/runtime/query/executor.d.ts +6 -0
  104. package/dist/runtime/query/executor.d.ts.map +1 -1
  105. package/dist/runtime/query/executor.js +120 -24
  106. package/dist/runtime/query/executor.js.map +1 -1
  107. package/dist/runtime/query/index.d.ts +12 -8
  108. package/dist/runtime/query/index.d.ts.map +1 -1
  109. package/dist/runtime/query/index.js +55 -7
  110. package/dist/runtime/query/index.js.map +1 -1
  111. package/dist/runtime/query/iteration/index.d.ts +13 -3
  112. package/dist/runtime/query/iteration/index.d.ts.map +1 -1
  113. package/dist/runtime/query/iteration/index.js +356 -42
  114. package/dist/runtime/query/iteration/index.js.map +1 -1
  115. package/dist/runtime/query/iteration/native-output.d.ts +10 -0
  116. package/dist/runtime/query/iteration/native-output.d.ts.map +1 -0
  117. package/dist/runtime/query/iteration/native-output.js +32 -0
  118. package/dist/runtime/query/iteration/native-output.js.map +1 -0
  119. package/dist/runtime/query/iteration/phases/advisory.d.ts.map +1 -1
  120. package/dist/runtime/query/iteration/phases/advisory.js +18 -13
  121. package/dist/runtime/query/iteration/phases/advisory.js.map +1 -1
  122. package/dist/runtime/query/iteration/phases/compaction.d.ts +2 -0
  123. package/dist/runtime/query/iteration/phases/compaction.d.ts.map +1 -1
  124. package/dist/runtime/query/iteration/phases/compaction.js +32 -11
  125. package/dist/runtime/query/iteration/phases/compaction.js.map +1 -1
  126. package/dist/runtime/query/iteration/phases/context.d.ts +11 -0
  127. package/dist/runtime/query/iteration/phases/context.d.ts.map +1 -1
  128. package/dist/runtime/query/iteration/phases/context.js.map +1 -1
  129. package/dist/runtime/query/iteration/phases/tool-review.d.ts.map +1 -1
  130. package/dist/runtime/query/iteration/phases/tool-review.js +1 -1
  131. package/dist/runtime/query/iteration/phases/tool-review.js.map +1 -1
  132. package/dist/runtime/query/iteration/phases/working-memory.d.ts +1 -1
  133. package/dist/runtime/query/iteration/phases/working-memory.d.ts.map +1 -1
  134. package/dist/runtime/query/iteration/phases/working-memory.js +23 -6
  135. package/dist/runtime/query/iteration/phases/working-memory.js.map +1 -1
  136. package/dist/runtime/query/iteration/stream-turn.d.ts.map +1 -1
  137. package/dist/runtime/query/iteration/stream-turn.js +12 -5
  138. package/dist/runtime/query/iteration/stream-turn.js.map +1 -1
  139. package/dist/runtime/query/prompt.d.ts.map +1 -1
  140. package/dist/runtime/query/prompt.js +14 -4
  141. package/dist/runtime/query/prompt.js.map +1 -1
  142. package/dist/runtime/query/steering.d.ts +6 -2
  143. package/dist/runtime/query/steering.d.ts.map +1 -1
  144. package/dist/runtime/query/steering.js +17 -2
  145. package/dist/runtime/query/steering.js.map +1 -1
  146. package/dist/runtime/query/tool-call-budget.d.ts +19 -0
  147. package/dist/runtime/query/tool-call-budget.d.ts.map +1 -0
  148. package/dist/runtime/query/tool-call-budget.js +110 -0
  149. package/dist/runtime/query/tool-call-budget.js.map +1 -0
  150. package/dist/runtime/query/tooling.d.ts +2 -0
  151. package/dist/runtime/query/tooling.d.ts.map +1 -1
  152. package/dist/runtime/query/tooling.js +4 -0
  153. package/dist/runtime/query/tooling.js.map +1 -1
  154. package/dist/sandbox/file-walk-program.d.ts +3 -0
  155. package/dist/sandbox/file-walk-program.d.ts.map +1 -0
  156. package/dist/sandbox/file-walk-program.js +94 -0
  157. package/dist/sandbox/file-walk-program.js.map +1 -0
  158. package/dist/sandbox/file-walk.d.ts +12 -0
  159. package/dist/sandbox/file-walk.d.ts.map +1 -0
  160. package/dist/sandbox/file-walk.js +429 -0
  161. package/dist/sandbox/file-walk.js.map +1 -0
  162. package/dist/sandbox/index.d.ts +2 -0
  163. package/dist/sandbox/index.d.ts.map +1 -1
  164. package/dist/sandbox/index.js +1 -0
  165. package/dist/sandbox/index.js.map +1 -1
  166. package/dist/sandbox/provider/local.d.ts.map +1 -1
  167. package/dist/sandbox/provider/local.js +9 -0
  168. package/dist/sandbox/provider/local.js.map +1 -1
  169. package/dist/scheduler/completion-inbox.d.ts +3 -2
  170. package/dist/scheduler/completion-inbox.d.ts.map +1 -1
  171. package/dist/scheduler/completion-inbox.js +29 -15
  172. package/dist/scheduler/completion-inbox.js.map +1 -1
  173. package/dist/scheduler/local.d.ts.map +1 -1
  174. package/dist/scheduler/local.js +1 -0
  175. package/dist/scheduler/local.js.map +1 -1
  176. package/dist/session/handoff/capacity.d.ts +2 -2
  177. package/dist/session/handoff/capacity.d.ts.map +1 -1
  178. package/dist/session/handoff/capacity.js +3 -2
  179. package/dist/session/handoff/capacity.js.map +1 -1
  180. package/dist/store/memory/disk.d.ts +6 -2
  181. package/dist/store/memory/disk.d.ts.map +1 -1
  182. package/dist/store/memory/disk.js +42 -25
  183. package/dist/store/memory/disk.js.map +1 -1
  184. package/dist/store/memory/index.d.ts +4 -0
  185. package/dist/store/memory/index.d.ts.map +1 -1
  186. package/dist/store/memory/index.js +55 -19
  187. package/dist/store/memory/index.js.map +1 -1
  188. package/dist/store/memory/memory.d.ts +3 -2
  189. package/dist/store/memory/memory.d.ts.map +1 -1
  190. package/dist/store/memory/memory.js +11 -2
  191. package/dist/store/memory/memory.js.map +1 -1
  192. package/dist/store/memory/operation-lock.d.ts +11 -0
  193. package/dist/store/memory/operation-lock.d.ts.map +1 -0
  194. package/dist/store/memory/operation-lock.js +94 -0
  195. package/dist/store/memory/operation-lock.js.map +1 -0
  196. package/dist/tools/builtins/bash.d.ts.map +1 -1
  197. package/dist/tools/builtins/bash.js +215 -59
  198. package/dist/tools/builtins/bash.js.map +1 -1
  199. package/dist/tools/builtins/computer-use.d.ts.map +1 -1
  200. package/dist/tools/builtins/computer-use.js +60 -10
  201. package/dist/tools/builtins/computer-use.js.map +1 -1
  202. package/dist/tools/builtins/glob.d.ts +2 -1
  203. package/dist/tools/builtins/glob.d.ts.map +1 -1
  204. package/dist/tools/builtins/glob.js +95 -103
  205. package/dist/tools/builtins/glob.js.map +1 -1
  206. package/dist/tools/builtins/grep.d.ts.map +1 -1
  207. package/dist/tools/builtins/grep.js +155 -111
  208. package/dist/tools/builtins/grep.js.map +1 -1
  209. package/dist/tools/builtins/ls.js +2 -2
  210. package/dist/tools/builtins/ls.js.map +1 -1
  211. package/dist/tools/builtins/run-code.d.ts +6 -0
  212. package/dist/tools/builtins/run-code.d.ts.map +1 -1
  213. package/dist/tools/builtins/run-code.js +15 -4
  214. package/dist/tools/builtins/run-code.js.map +1 -1
  215. package/dist/tools/builtins/search-tools.d.ts.map +1 -1
  216. package/dist/tools/builtins/search-tools.js +14 -2
  217. package/dist/tools/builtins/search-tools.js.map +1 -1
  218. package/dist/tools/defineTool.d.ts +2 -0
  219. package/dist/tools/defineTool.d.ts.map +1 -1
  220. package/dist/tools/defineTool.js +3 -0
  221. package/dist/tools/defineTool.js.map +1 -1
  222. package/dist/tools/memory/delete.d.ts +4 -0
  223. package/dist/tools/memory/delete.d.ts.map +1 -0
  224. package/dist/tools/memory/delete.js +26 -0
  225. package/dist/tools/memory/delete.js.map +1 -0
  226. package/dist/tools/memory/index.d.ts +2 -0
  227. package/dist/tools/memory/index.d.ts.map +1 -1
  228. package/dist/tools/memory/index.js +6 -0
  229. package/dist/tools/memory/index.js.map +1 -1
  230. package/dist/tools/memory/save.d.ts.map +1 -1
  231. package/dist/tools/memory/save.js +3 -2
  232. package/dist/tools/memory/save.js.map +1 -1
  233. package/dist/tools/memory/search.d.ts.map +1 -1
  234. package/dist/tools/memory/search.js +12 -5
  235. package/dist/tools/memory/search.js.map +1 -1
  236. package/dist/tools/memory/update.d.ts +4 -0
  237. package/dist/tools/memory/update.d.ts.map +1 -0
  238. package/dist/tools/memory/update.js +47 -0
  239. package/dist/tools/memory/update.js.map +1 -0
  240. package/dist/types/agent/scheduler.d.ts +5 -0
  241. package/dist/types/agent/scheduler.d.ts.map +1 -1
  242. package/dist/types/agent/task.d.ts +10 -0
  243. package/dist/types/agent/task.d.ts.map +1 -1
  244. package/dist/types/computer-use/index.d.ts +6 -0
  245. package/dist/types/computer-use/index.d.ts.map +1 -1
  246. package/dist/types/computer-use/index.js.map +1 -1
  247. package/dist/types/errors/catalog.js +1 -1
  248. package/dist/types/errors/catalog.js.map +1 -1
  249. package/dist/types/hitl/index.d.ts +11 -1
  250. package/dist/types/hitl/index.d.ts.map +1 -1
  251. package/dist/types/hitl/index.js.map +1 -1
  252. package/dist/types/memory/index.d.ts +14 -1
  253. package/dist/types/memory/index.d.ts.map +1 -1
  254. package/dist/types/project/entity.d.ts +1 -0
  255. package/dist/types/project/entity.d.ts.map +1 -1
  256. package/dist/types/provider/config.d.ts +2 -0
  257. package/dist/types/provider/config.d.ts.map +1 -1
  258. package/dist/types/provider/model.d.ts +4 -0
  259. package/dist/types/provider/model.d.ts.map +1 -1
  260. package/dist/types/run/answer-review.d.ts +2 -0
  261. package/dist/types/run/answer-review.d.ts.map +1 -1
  262. package/dist/types/run/events.d.ts +9 -0
  263. package/dist/types/run/events.d.ts.map +1 -1
  264. package/dist/types/run/events.js.map +1 -1
  265. package/dist/types/run/prepare-step.d.ts +19 -1
  266. package/dist/types/run/prepare-step.d.ts.map +1 -1
  267. package/dist/types/sandbox/index.d.ts +20 -0
  268. package/dist/types/sandbox/index.d.ts.map +1 -1
  269. package/dist/types/sandbox/index.js.map +1 -1
  270. package/dist/types/structured-output/index.d.ts +8 -2
  271. package/dist/types/structured-output/index.d.ts.map +1 -1
  272. package/dist/types/tool/index.d.ts +15 -0
  273. package/dist/types/tool/index.d.ts.map +1 -1
  274. package/dist/types/tool/index.js.map +1 -1
  275. package/dist/utils/json-snapshot.d.ts +3 -0
  276. package/dist/utils/json-snapshot.d.ts.map +1 -0
  277. package/dist/utils/json-snapshot.js +79 -0
  278. package/dist/utils/json-snapshot.js.map +1 -0
  279. package/package.json +8 -1
  280. package/src/bridge/a2a/mapper.ts +2 -0
  281. package/src/bridge/sse/mapper.ts +2 -0
  282. package/src/compaction/extractor.ts +21 -8
  283. package/src/compaction/manager.ts +11 -1
  284. package/src/compaction/verifier.ts +80 -18
  285. package/src/eval/harness-verification.ts +270 -0
  286. package/src/eval/index.ts +10 -0
  287. package/src/execution/code-runtime/json-value.ts +82 -0
  288. package/src/execution/code-runtime/worker-program.ts +239 -0
  289. package/src/execution/code-runtime/worker.ts +164 -111
  290. package/src/manager/agent/lifecycle.ts +340 -45
  291. package/src/manager/run/persistence.ts +7 -0
  292. package/src/provider/capabilities.ts +25 -1
  293. package/src/provider/fallback.ts +2 -0
  294. package/src/provider/token-budget.ts +52 -8
  295. package/src/public-runtime.ts +6 -1
  296. package/src/public-tools.ts +5 -1
  297. package/src/public-types.ts +1 -0
  298. package/src/registry/tool/execute.ts +17 -79
  299. package/src/run/command-gate.ts +61 -13
  300. package/src/run/index.ts +2 -0
  301. package/src/run/memory-promoter.ts +32 -40
  302. package/src/run/memory-recall.ts +254 -0
  303. package/src/run/reporter.ts +1 -0
  304. package/src/run/token-budget.ts +4 -0
  305. package/src/run/workspace-fingerprint.ts +17 -8
  306. package/src/runtime/query/checkpoint.ts +96 -2
  307. package/src/runtime/query/executor.ts +131 -28
  308. package/src/runtime/query/index.ts +81 -16
  309. package/src/runtime/query/iteration/index.ts +406 -53
  310. package/src/runtime/query/iteration/native-output.ts +35 -0
  311. package/src/runtime/query/iteration/phases/advisory.ts +21 -11
  312. package/src/runtime/query/iteration/phases/compaction.ts +36 -14
  313. package/src/runtime/query/iteration/phases/context.ts +11 -0
  314. package/src/runtime/query/iteration/phases/tool-review.ts +5 -1
  315. package/src/runtime/query/iteration/phases/working-memory.ts +23 -5
  316. package/src/runtime/query/iteration/stream-turn.ts +11 -5
  317. package/src/runtime/query/prompt.ts +21 -4
  318. package/src/runtime/query/steering.ts +19 -2
  319. package/src/runtime/query/tool-call-budget.ts +115 -0
  320. package/src/runtime/query/tooling.ts +6 -0
  321. package/src/sandbox/file-walk-program.ts +93 -0
  322. package/src/sandbox/file-walk.ts +463 -0
  323. package/src/sandbox/index.ts +2 -0
  324. package/src/sandbox/provider/local.ts +13 -0
  325. package/src/scheduler/completion-inbox.ts +29 -19
  326. package/src/scheduler/local.ts +1 -0
  327. package/src/session/handoff/capacity.ts +7 -3
  328. package/src/store/memory/disk.ts +52 -30
  329. package/src/store/memory/index.ts +75 -27
  330. package/src/store/memory/memory.ts +18 -6
  331. package/src/store/memory/operation-lock.ts +99 -0
  332. package/src/tools/builtins/bash.ts +230 -58
  333. package/src/tools/builtins/computer-use.ts +61 -7
  334. package/src/tools/builtins/glob.ts +104 -122
  335. package/src/tools/builtins/grep.ts +166 -132
  336. package/src/tools/builtins/ls.ts +2 -2
  337. package/src/tools/builtins/run-code.ts +24 -5
  338. package/src/tools/builtins/search-tools.ts +18 -3
  339. package/src/tools/defineTool.ts +5 -0
  340. package/src/tools/memory/delete.ts +29 -0
  341. package/src/tools/memory/index.ts +6 -0
  342. package/src/tools/memory/save.ts +4 -2
  343. package/src/tools/memory/search.ts +12 -5
  344. package/src/tools/memory/update.ts +50 -0
  345. package/src/types/agent/scheduler.ts +6 -0
  346. package/src/types/agent/task.ts +13 -0
  347. package/src/types/computer-use/index.ts +6 -0
  348. package/src/types/errors/catalog.ts +1 -1
  349. package/src/types/hitl/index.ts +11 -1
  350. package/src/types/memory/index.ts +16 -1
  351. package/src/types/project/entity.ts +1 -0
  352. package/src/types/provider/config.ts +2 -0
  353. package/src/types/provider/model.ts +4 -0
  354. package/src/types/run/answer-review.ts +2 -0
  355. package/src/types/run/events.ts +10 -0
  356. package/src/types/run/prepare-step.ts +19 -1
  357. package/src/types/sandbox/index.ts +21 -0
  358. package/src/types/structured-output/index.ts +15 -2
  359. package/src/types/tool/index.ts +16 -0
  360. package/src/utils/json-snapshot.ts +76 -0
@@ -2,7 +2,7 @@ import type { CompactionConfig } from '../config/runtime.js'
2
2
  import { collectChatCompletion } from '../provider/collect-chat-completion.js'
3
3
  import { resolveStreamIdleTimeoutMs, withStreamIdleTimeout } from '../provider/idle-timeout.js'
4
4
  import type { TokenUsage } from '../types/common/index.js'
5
- import type { Message } from '../types/message/index.js'
5
+ import type { Message, MessageAttachment, ToolResultBlock } from '../types/message/index.js'
6
6
  import type { LLMProvider } from '../types/provider/interface.js'
7
7
  import type { WorkingStateManager } from './manager.js'
8
8
  import { serializeState } from './serializer.js'
@@ -20,28 +20,90 @@ If the structured state is complete, respond with exactly: COMPLETE
20
20
 
21
21
  If something important is missing, respond with a brief bullet list of the missing items (no preamble, just the bullets). Each bullet should be a single concise sentence.`
22
22
 
23
- function truncateMessages(messages: Message[], budget: number): string {
24
- const lines: string[] = []
25
- let charCount = 0
26
-
27
- for (const msg of messages) {
28
- if (!msg.content) continue
29
- const prefix = `[${msg.role}]: `
30
- const content = msg.content
23
+ function* attachmentExcerpt(
24
+ attachment: MessageAttachment | Exclude<ToolResultBlock, { type: 'text' }>,
25
+ ): Generator<string> {
26
+ const kind =
27
+ attachment.type === 'stored'
28
+ ? attachment.kind
29
+ : attachment.type === 'document'
30
+ ? 'document'
31
+ : 'image'
32
+ yield `[${kind}`
33
+ if ('name' in attachment && attachment.name) {
34
+ yield ' "'
35
+ yield attachment.name
36
+ yield '"'
37
+ }
38
+ yield ': '
39
+ yield attachment.mediaType
40
+ yield ' — not included in this text excerpt]'
41
+ }
31
42
 
32
- if (charCount + prefix.length + content.length > budget) {
33
- const remaining = budget - charCount - prefix.length
34
- if (remaining > 0) {
35
- lines.push(`${prefix}${content.slice(0, remaining)}...`)
43
+ /** Visible evidence only: never stringify a whole message or its attachment bytes. */
44
+ function* conversationExcerpt(messages: readonly Message[]): Generator<string> {
45
+ let first = true
46
+ for (const message of messages) {
47
+ const hasDetails =
48
+ message.role === 'tool' ||
49
+ (message.role === 'assistant' && message.toolCalls?.length) ||
50
+ (message.role === 'user' && message.attachments?.length)
51
+ if (!message.content && !hasDetails) continue
52
+ if (!first) yield '\n\n'
53
+ first = false
54
+ yield `[${message.role}]: `
55
+ if (message.role === 'tool') {
56
+ yield '[tool result '
57
+ yield message.toolCallId
58
+ yield `; isError=${message.isError === true}]\n`
59
+ }
60
+ if (typeof message.content === 'string') yield message.content
61
+ else if (message.content) {
62
+ for (const [index, block] of message.content.entries()) {
63
+ if (index > 0) yield '\n'
64
+ if (block.type === 'text') yield block.text
65
+ else yield* attachmentExcerpt(block)
66
+ }
67
+ }
68
+ if (message.role === 'assistant') {
69
+ for (const call of message.toolCalls ?? []) {
70
+ yield '\n[tool call '
71
+ yield call.id
72
+ yield '] '
73
+ yield call.function.name
74
+ yield '('
75
+ yield call.function.arguments
76
+ yield ')'
77
+ }
78
+ }
79
+ if (message.role === 'user') {
80
+ for (const attachment of message.attachments ?? []) {
81
+ yield '\n'
82
+ yield* attachmentExcerpt(attachment)
36
83
  }
37
- break
38
84
  }
39
-
40
- lines.push(`${prefix}${content}`)
41
- charCount += prefix.length + content.length
42
85
  }
86
+ }
43
87
 
44
- return lines.join('\n\n')
88
+ function truncateMessages(messages: readonly Message[], budget: number): string {
89
+ if (budget <= 0) return ''
90
+ const parts: string[] = []
91
+ let remaining = budget
92
+ for (const part of conversationExcerpt(messages)) {
93
+ if (part.length > remaining) {
94
+ parts.push(part.slice(0, remaining))
95
+ // Role labels, separators and the omission marker all consume the
96
+ // same budget. Consume fragments lazily so huge arguments and rich
97
+ // results cannot bypass the cap or require a full serialized copy.
98
+ let prefix = parts.join('').slice(0, budget - 1)
99
+ const last = prefix.charCodeAt(prefix.length - 1)
100
+ if (last >= 0xd800 && last <= 0xdbff) prefix = prefix.slice(0, -1)
101
+ return `${prefix}…`
102
+ }
103
+ parts.push(part)
104
+ remaining -= part.length
105
+ }
106
+ return parts.join('')
45
107
  }
46
108
 
47
109
  /**
@@ -0,0 +1,270 @@
1
+ import type { CaseResult } from './types.js'
2
+
3
+ /** A host-owned outcome, with enough identity to check pairing and cite its trace. */
4
+ export interface HarnessTrial {
5
+ taskId: string
6
+ trial: number
7
+ /** Environment/seed/model/limits fingerprint. Equal within a pair, fresh in confirmation. */
8
+ conditions: string
9
+ trajectoryId: string
10
+ result: CaseResult
11
+ }
12
+
13
+ export interface HarnessAttribution {
14
+ taskId: string
15
+ effect: 'improvement' | 'regression' | 'unresolved'
16
+ reason: string
17
+ baselineTrajectories: readonly string[]
18
+ candidateTrajectories: readonly string[]
19
+ }
20
+
21
+ export interface HarnessVerificationBatch {
22
+ baselineRevision: string
23
+ candidateRevision: string
24
+ baseline: readonly HarnessTrial[]
25
+ candidate: readonly HarnessTrial[]
26
+ /** Supplied by an independent trace reviewer, never inferred from scores alone. */
27
+ attributions: readonly HarnessAttribution[]
28
+ }
29
+
30
+ export type HarnessBehaviorStatus =
31
+ | 'recovered'
32
+ | 'stable-success'
33
+ | 'regressed'
34
+ | 'still-failing'
35
+ | 'mixed'
36
+ | 'inconclusive'
37
+
38
+ export interface HarnessTaskComparison {
39
+ taskId: string
40
+ status: HarnessBehaviorStatus
41
+ baselinePasses: number
42
+ candidatePasses: number
43
+ trials: number
44
+ }
45
+
46
+ export interface HarnessComparison {
47
+ tasks: readonly HarnessTaskComparison[]
48
+ /** Paired trial pass-rate difference, not held-out pass@1 or causal evidence. */
49
+ passRateDelta: number | null
50
+ positiveEvidence: readonly string[]
51
+ regressions: readonly string[]
52
+ unresolved: readonly string[]
53
+ /** Actual recorded consumption from BOTH sides, including unsuccessful runs. */
54
+ usage: { rollouts: number; tokens: number; costUsd: number; durationMs: number }
55
+ }
56
+
57
+ function nonempty(value: string): boolean {
58
+ return typeof value === 'string' && value.trim().length > 0
59
+ }
60
+
61
+ function key(trial: HarnessTrial): string {
62
+ return JSON.stringify([trial.taskId, trial.trial])
63
+ }
64
+
65
+ function indexTrials(trials: readonly HarnessTrial[]): Map<string, HarnessTrial> {
66
+ const result = new Map<string, HarnessTrial>()
67
+ const traces = new Set<string>()
68
+ for (const trial of trials) {
69
+ if (
70
+ !nonempty(trial.taskId) ||
71
+ !nonempty(trial.conditions) ||
72
+ !nonempty(trial.trajectoryId) ||
73
+ !Number.isSafeInteger(trial.trial) ||
74
+ trial.trial < 0
75
+ )
76
+ throw new Error(
77
+ 'A harness trial needs a task, nonnegative trial index, conditions and trajectory ID.',
78
+ )
79
+ if (result.has(key(trial)) || traces.has(trial.trajectoryId))
80
+ throw new Error('Duplicate harness trial or trajectory ID.')
81
+ result.set(key(trial), trial)
82
+ traces.add(trial.trajectoryId)
83
+ }
84
+ return result
85
+ }
86
+
87
+ function measured(trial: HarnessTrial): boolean {
88
+ const { result } = trial
89
+ const scores = Object.values(result.scores)
90
+ return (
91
+ !result.run.error &&
92
+ (result.status === 'passed' || result.status === 'failed') &&
93
+ scores.length > 0 &&
94
+ scores.every((s) => !s.unavailable && Number.isFinite(s.score) && s.score >= 0 && s.score <= 1)
95
+ )
96
+ }
97
+
98
+ /** HarnessLens Table 6 comparison plus explicit, trace-linked attribution. No model calls. */
99
+ export function compareHarnessTrials(batch: HarnessVerificationBatch): HarnessComparison {
100
+ if (
101
+ !nonempty(batch.baselineRevision) ||
102
+ !nonempty(batch.candidateRevision) ||
103
+ batch.baselineRevision === batch.candidateRevision
104
+ )
105
+ throw new Error('Distinct baseline and candidate revisions are required.')
106
+ const baseline = indexTrials(batch.baseline)
107
+ const candidate = indexTrials(batch.candidate)
108
+ if (!baseline.size || baseline.size !== candidate.size)
109
+ throw new Error('Complete paired trials are required.')
110
+ const baselineTraces = new Set(batch.baseline.map((t) => t.trajectoryId))
111
+ if (batch.candidate.some((t) => baselineTraces.has(t.trajectoryId)))
112
+ throw new Error('Baseline and candidate must have distinct trajectories.')
113
+ const groups = new Map<string, HarnessTrial[]>()
114
+ for (const [id, before] of baseline) {
115
+ const after = candidate.get(id)
116
+ if (!after || before.conditions !== after.conditions)
117
+ throw new Error('Harness trial conditions do not match.')
118
+ const group = groups.get(before.taskId) ?? []
119
+ group.push(before)
120
+ groups.set(before.taskId, group)
121
+ }
122
+ const tasks: HarnessTaskComparison[] = []
123
+ for (const [taskId, before] of groups) {
124
+ if (new Set(before.map((t) => t.conditions)).size !== before.length)
125
+ throw new Error('Repeated trials need distinct controlled conditions.')
126
+ const after = before.map((t) => candidate.get(key(t)) as HarnessTrial)
127
+ const b = before.filter((t) => t.result.status === 'passed').length
128
+ const c = after.filter((t) => t.result.status === 'passed').length
129
+ const status: HarnessBehaviorStatus = ![...before, ...after].every(measured)
130
+ ? 'inconclusive'
131
+ : b === 0 && c > 0
132
+ ? 'recovered'
133
+ : b > 0 && c === after.length
134
+ ? 'stable-success'
135
+ : b > 0 && c === 0
136
+ ? 'regressed'
137
+ : b === 0 && c === 0
138
+ ? 'still-failing'
139
+ : 'mixed'
140
+ tasks.push({ taskId, status, baselinePasses: b, candidatePasses: c, trials: before.length })
141
+ }
142
+ const positive = new Set<string>()
143
+ const regressions = new Set<string>()
144
+ const unresolved = new Set(
145
+ tasks.filter((t) => t.status === 'inconclusive' || t.status === 'mixed').map((t) => t.taskId),
146
+ )
147
+ // Conservative Namzu policy: even an unattributed observed regression blocks promotion.
148
+ for (const task of tasks) if (task.status === 'regressed') regressions.add(task.taskId)
149
+ for (const evidence of batch.attributions) {
150
+ const task = tasks.find((t) => t.taskId === evidence.taskId)
151
+ const cites = (ids: readonly string[], trials: readonly HarnessTrial[]) =>
152
+ ids.length > 0 &&
153
+ ids.every((id) => trials.some((t) => t.taskId === evidence.taskId && t.trajectoryId === id))
154
+ if (
155
+ !task ||
156
+ !nonempty(evidence.reason) ||
157
+ !cites(evidence.baselineTrajectories, batch.baseline) ||
158
+ !cites(evidence.candidateTrajectories, batch.candidate) ||
159
+ !['improvement', 'regression', 'unresolved'].includes(evidence.effect)
160
+ )
161
+ throw new Error('Attribution must explain and cite both sides of an existing task.')
162
+ if (evidence.effect === 'regression') regressions.add(task.taskId)
163
+ else if (evidence.effect === 'unresolved') unresolved.add(task.taskId)
164
+ else if (
165
+ task.status === 'recovered' ||
166
+ (task.status === 'stable-success' && task.candidatePasses > task.baselinePasses)
167
+ )
168
+ positive.add(task.taskId)
169
+ }
170
+ const usage = { rollouts: baseline.size * 2, tokens: 0, costUsd: 0, durationMs: 0 }
171
+ for (const trial of [...batch.baseline, ...batch.candidate]) {
172
+ const values = [
173
+ trial.result.run.totalTokens,
174
+ trial.result.run.totalCostUsd,
175
+ trial.result.run.durationMs,
176
+ ]
177
+ if (values.some((n) => !Number.isFinite(n) || n < 0))
178
+ throw new Error('Invalid recorded harness usage.')
179
+ usage.tokens += trial.result.run.totalTokens
180
+ usage.costUsd += trial.result.run.totalCostUsd
181
+ usage.durationMs += trial.result.run.durationMs
182
+ }
183
+ return {
184
+ tasks,
185
+ positiveEvidence: [...positive],
186
+ regressions: [...regressions],
187
+ unresolved: [...unresolved],
188
+ usage,
189
+ passRateDelta: tasks.some((t) => t.status === 'inconclusive')
190
+ ? null
191
+ : tasks.reduce((sum, t) => sum + t.candidatePasses - t.baselinePasses, 0) / baseline.size,
192
+ }
193
+ }
194
+
195
+ export interface HarnessReview {
196
+ decision: 'accept' | 'reject' | 'inconclusive'
197
+ reason: string
198
+ verification: HarnessComparison
199
+ confirmation?: HarnessComparison
200
+ }
201
+
202
+ /**
203
+ * Evaluate recorded evidence; never applies a patch. Requires at least five tasks,
204
+ * exactly two trials per task, and a same-size confirmation with at most two reused tasks.
205
+ * Hosts own isolated execution, task selection, scoring and independent trace review.
206
+ */
207
+ export function reviewHarnessCandidate(
208
+ verification: HarnessVerificationBatch,
209
+ confirmation?: HarnessVerificationBatch,
210
+ ): HarnessReview {
211
+ const first = compareHarnessTrials(verification)
212
+ const second = confirmation ? compareHarnessTrials(confirmation) : undefined
213
+ const result = (decision: HarnessReview['decision'], reason: string): HarnessReview => ({
214
+ decision,
215
+ reason,
216
+ verification: first,
217
+ ...(second ? { confirmation: second } : {}),
218
+ })
219
+ const sufficient = (report: HarnessComparison) =>
220
+ report.tasks.length >= 5 && report.tasks.every((t) => t.trials === 2)
221
+ if (!sufficient(first))
222
+ return result(
223
+ 'inconclusive',
224
+ 'Verification requires at least five distinct tasks and two paired trials per task.',
225
+ )
226
+ if (first.regressions.length || second?.regressions.length)
227
+ return result('reject', 'Observed or attributed regression blocks promotion.')
228
+ if (first.unresolved.length || second?.unresolved.length)
229
+ return result('inconclusive', 'Incomplete or ambiguous behavioral evidence.')
230
+ if (!first.positiveEvidence.length)
231
+ return result(
232
+ 'reject',
233
+ 'A metric increase or preservation alone is not attributable improvement.',
234
+ )
235
+ if (!confirmation || !second)
236
+ return result('inconclusive', 'A complete fresh confirmation round is required.')
237
+ if (
238
+ verification.baselineRevision !== confirmation.baselineRevision ||
239
+ verification.candidateRevision !== confirmation.candidateRevision
240
+ )
241
+ return result('inconclusive', 'Revisions changed between verification and confirmation.')
242
+ const firstTasks = new Set(first.tasks.map((t) => t.taskId))
243
+ if (
244
+ !sufficient(second) ||
245
+ second.tasks.length !== first.tasks.length ||
246
+ second.tasks.filter((t) => firstTasks.has(t.taskId)).length > 2
247
+ )
248
+ return result(
249
+ 'inconclusive',
250
+ 'Confirmation must use the same batch size with at most two reused tasks.',
251
+ )
252
+ const conditions = new Set(verification.baseline.map((t) => t.conditions))
253
+ const traces = new Set(
254
+ [...verification.baseline, ...verification.candidate].map((t) => t.trajectoryId),
255
+ )
256
+ if (
257
+ confirmation.baseline.some((t) => conditions.has(t.conditions)) ||
258
+ [...confirmation.baseline, ...confirmation.candidate].some((t) => traces.has(t.trajectoryId))
259
+ )
260
+ return result('inconclusive', 'Confirmation requires fresh conditions and trajectories.')
261
+ if (!second.positiveEvidence.length || second.passRateDelta === null || second.passRateDelta <= 0)
262
+ return result(
263
+ 'reject',
264
+ 'Confirmation needs attributable improvement and a positive primary-metric difference.',
265
+ )
266
+ return result(
267
+ 'accept',
268
+ 'Both rounds support improvement without observed regression; confirmation improves the paired pass rate.',
269
+ )
270
+ }
package/src/eval/index.ts CHANGED
@@ -1,4 +1,14 @@
1
1
  export { evalRunFromQuery, evalRunFromRun } from './from-run.js'
2
+ export { compareHarnessTrials, reviewHarnessCandidate } from './harness-verification.js'
3
+ export type {
4
+ HarnessTrial,
5
+ HarnessAttribution,
6
+ HarnessVerificationBatch,
7
+ HarnessBehaviorStatus,
8
+ HarnessTaskComparison,
9
+ HarnessComparison,
10
+ HarnessReview,
11
+ } from './harness-verification.js'
2
12
  export { formatReport, runExperiment } from './experiment.js'
3
13
  export type { ExperimentConfig } from './experiment.js'
4
14
  export { judgeScorer } from './judge.js'
@@ -0,0 +1,82 @@
1
+ /**
2
+ * Serialize application data before sending it to the interpreter.
3
+ *
4
+ * JSON.stringify alone can allocate an arbitrarily large intermediate string.
5
+ * This writer accounts for each piece, refuses cycles and non-JSON values, and
6
+ * limits nesting. It never installs application objects in the guest realm.
7
+ * Undefined is supported only as a top-level result, represented out of band.
8
+ */
9
+ export function encodeCodeValue(value: unknown, maxBytes: number): string | undefined {
10
+ if (value === undefined) return undefined
11
+ const pieces: string[] = []
12
+ const ancestors = new Set<object>()
13
+ let bytes = 0
14
+
15
+ const append = (text: string): void => {
16
+ bytes += Buffer.byteLength(text)
17
+ if (bytes > maxBytes) throw new Error(`Code runtime value exceeds ${maxBytes} bytes.`)
18
+ pieces.push(text)
19
+ }
20
+ const quote = (text: string): void => {
21
+ if (text.length > maxBytes - bytes) {
22
+ throw new Error(`Code runtime value exceeds ${maxBytes} bytes.`)
23
+ }
24
+ append(JSON.stringify(text))
25
+ }
26
+ const visit = (item: unknown, depth: number): void => {
27
+ if (depth > 64) throw new Error('Code runtime value exceeds 64 levels of nesting.')
28
+ if (item === null) {
29
+ append('null')
30
+ return
31
+ }
32
+ if (typeof item === 'string') {
33
+ quote(item)
34
+ return
35
+ }
36
+ if (typeof item === 'boolean') {
37
+ append(String(item))
38
+ return
39
+ }
40
+ if (typeof item === 'number' && Number.isFinite(item)) {
41
+ append(String(item))
42
+ return
43
+ }
44
+ if (typeof item !== 'object') throw new Error('Code runtime values must be JSON-safe.')
45
+ if (ancestors.has(item)) throw new Error('Code runtime values must not contain cycles.')
46
+ const array = Array.isArray(item)
47
+ if (
48
+ !array &&
49
+ Object.getPrototypeOf(item) !== Object.prototype &&
50
+ Object.getPrototypeOf(item) !== null
51
+ ) {
52
+ throw new Error('Code runtime values must contain only plain objects and arrays.')
53
+ }
54
+ ancestors.add(item)
55
+ if (array) {
56
+ if (item.length > maxBytes) throw new Error(`Code runtime value exceeds ${maxBytes} bytes.`)
57
+ append('[')
58
+ for (let index = 0; index < item.length; index++) {
59
+ if (index > 0) append(',')
60
+ visit(item[index], depth + 1)
61
+ }
62
+ append(']')
63
+ } else {
64
+ append('{')
65
+ const keys = Object.keys(item)
66
+ for (const [index, key] of keys.entries()) {
67
+ if (index > 0) append(',')
68
+ quote(key)
69
+ append(':')
70
+ const descriptor = Object.getOwnPropertyDescriptor(item, key)
71
+ if (!descriptor || !('value' in descriptor)) {
72
+ throw new Error('Code runtime values must not contain accessors.')
73
+ }
74
+ visit(descriptor.value, depth + 1)
75
+ }
76
+ append('}')
77
+ }
78
+ ancestors.delete(item)
79
+ }
80
+ visit(value, 0)
81
+ return pieces.join('')
82
+ }