@tangle-network/agent-eval 0.217.1 → 0.219.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 (258) hide show
  1. package/CHANGELOG.md +57 -1
  2. package/dist/adapters/http.d.ts +3 -3
  3. package/dist/adapters/http.d.ts.map +1 -1
  4. package/dist/adapters/http.js +1 -0
  5. package/dist/adapters/http.js.map +1 -1
  6. package/dist/{agent-profile-DTt8uGP9.d.ts → agent-profile-D01Io2Xw.d.ts} +4 -4
  7. package/dist/{agent-profile-DTt8uGP9.d.ts.map → agent-profile-D01Io2Xw.d.ts.map} +1 -1
  8. package/dist/analyst/index.d.ts +13 -13
  9. package/dist/analyst/index.d.ts.map +1 -1
  10. package/dist/analyst/index.js +10 -10
  11. package/dist/analyst/index.js.map +1 -1
  12. package/dist/{analyze-runs-DyeNcenW.d.ts → analyze-runs-BWAHBDAw.d.ts} +4 -4
  13. package/dist/{analyze-runs-DyeNcenW.d.ts.map → analyze-runs-BWAHBDAw.d.ts.map} +1 -1
  14. package/dist/{benchmark-command-xQK8nOI6.js → benchmark-command-BzmMTnvC.js} +664 -565
  15. package/dist/benchmark-command-BzmMTnvC.js.map +1 -0
  16. package/dist/benchmarks/index.d.ts +5 -5
  17. package/dist/benchmarks/index.js +3 -3
  18. package/dist/benchmarks/index.js.map +1 -1
  19. package/dist/campaign/index.d.ts +8 -8
  20. package/dist/campaign/index.js +11 -11
  21. package/dist/{campaign-CJGkxAQ6.js → campaign-BVPC6ODQ.js} +452 -282
  22. package/dist/campaign-BVPC6ODQ.js.map +1 -0
  23. package/dist/{campaign-evidence-CQYw8_0H.js → campaign-evidence-DunzcJGv.js} +2 -2
  24. package/dist/campaign-evidence-DunzcJGv.js.map +1 -0
  25. package/dist/{chat-client-ldqxYYTN.js → chat-client-CMQ8_h4J.js} +2 -2
  26. package/dist/{chat-client-ldqxYYTN.js.map → chat-client-CMQ8_h4J.js.map} +1 -1
  27. package/dist/{chat-json-call-DavzexSp.js → chat-json-call-BrZKn0L3.js} +2 -2
  28. package/dist/{chat-json-call-DavzexSp.js.map → chat-json-call-BrZKn0L3.js.map} +1 -1
  29. package/dist/cli.js +10 -10
  30. package/dist/{completion-verifier-B_jw6C9p.js → completion-verifier-Cigap8CG.js} +5 -5
  31. package/dist/{completion-verifier-B_jw6C9p.js.map → completion-verifier-Cigap8CG.js.map} +1 -1
  32. package/dist/contract/index.d.ts +11 -11
  33. package/dist/contract/index.js +91 -11
  34. package/dist/contract/index.js.map +1 -1
  35. package/dist/{cost-ledger-D0352Z4d.js → cost-ledger-BGZB6yY2.js} +75 -2
  36. package/dist/cost-ledger-BGZB6yY2.js.map +1 -0
  37. package/dist/{cost-ledger-Jk62OBfF.d.ts → cost-ledger-C1W3ICmP.d.ts} +26 -2
  38. package/dist/cost-ledger-C1W3ICmP.d.ts.map +1 -0
  39. package/dist/{default-registry-ClYjq3QE.js → default-registry-BrKmT01n.js} +310 -278
  40. package/dist/{default-registry-ClYjq3QE.js.map → default-registry-BrKmT01n.js.map} +1 -1
  41. package/dist/{default-registry-DXgLmoDI.d.ts → default-registry-Cwg_QN3d.d.ts} +6 -6
  42. package/dist/{default-registry-DXgLmoDI.d.ts.map → default-registry-Cwg_QN3d.d.ts.map} +1 -1
  43. package/dist/{define-agent-eval-BIkH_gAR.d.ts → define-agent-eval-C2nFhHPu.d.ts} +8 -8
  44. package/dist/{define-agent-eval-BIkH_gAR.d.ts.map → define-agent-eval-C2nFhHPu.d.ts.map} +1 -1
  45. package/dist/{define-agent-eval-BDxNlP3D.js → define-agent-eval-UQY3VbJ2.js} +165 -105
  46. package/dist/define-agent-eval-UQY3VbJ2.js.map +1 -0
  47. package/dist/diagnosis/index.d.ts +2 -2
  48. package/dist/{dspy-rlm-engine-DhdCr1Dc.js → dspy-rlm-engine-Bn_Mt_LW.js} +3 -3
  49. package/dist/{dspy-rlm-engine-DhdCr1Dc.js.map → dspy-rlm-engine-Bn_Mt_LW.js.map} +1 -1
  50. package/dist/{engine-BvZ0R-36.d.ts → engine-BpGGw6cd.d.ts} +3 -3
  51. package/dist/{engine-BvZ0R-36.d.ts.map → engine-BpGGw6cd.d.ts.map} +1 -1
  52. package/dist/eval-campaign-BUMIxKTE.js +393 -0
  53. package/dist/eval-campaign-BUMIxKTE.js.map +1 -0
  54. package/dist/{evaluation-jTjC_QQD.d.ts → evaluation-CBdQt_kr.d.ts} +4 -4
  55. package/dist/{evaluation-jTjC_QQD.d.ts.map → evaluation-CBdQt_kr.d.ts.map} +1 -1
  56. package/dist/evaluation.d.ts +1 -1
  57. package/dist/evaluation.js +1 -1
  58. package/dist/{exact-types-CflbJ9f3.d.ts → exact-types-BYFmYq44.d.ts} +2 -2
  59. package/dist/{exact-types-CflbJ9f3.d.ts.map → exact-types-BYFmYq44.d.ts.map} +1 -1
  60. package/dist/experiment/index.d.ts +24 -1
  61. package/dist/experiment/index.d.ts.map +1 -1
  62. package/dist/experiment/index.js +110 -71
  63. package/dist/experiment/index.js.map +1 -1
  64. package/dist/{exporters-Cl6IeNAu.js → exporters-DWvM16LE.js} +2 -2
  65. package/dist/{exporters-Cl6IeNAu.js.map → exporters-DWvM16LE.js.map} +1 -1
  66. package/dist/{external-optimizer-process-KVFGvYX1.js → external-optimizer-process-wOLfzsCC.js} +2 -2
  67. package/dist/{external-optimizer-process-KVFGvYX1.js.map → external-optimizer-process-wOLfzsCC.js.map} +1 -1
  68. package/dist/{external-optimizer-subprocess-XIHBOSKt.js → external-optimizer-subprocess-D670Oxf2.js} +4 -4
  69. package/dist/{external-optimizer-subprocess-XIHBOSKt.js.map → external-optimizer-subprocess-D670Oxf2.js.map} +1 -1
  70. package/dist/{feedback-trajectory-BWmhRBGu.d.ts → feedback-trajectory-DhB9WzYg.d.ts} +3 -3
  71. package/dist/{feedback-trajectory-BWmhRBGu.d.ts.map → feedback-trajectory-DhB9WzYg.d.ts.map} +1 -1
  72. package/dist/{findings-store-BMVQtEsm.js → findings-store-CvNo712L.js} +6 -6
  73. package/dist/{findings-store-BMVQtEsm.js.map → findings-store-CvNo712L.js.map} +1 -1
  74. package/dist/fuzz.d.ts +1 -1
  75. package/dist/fuzz.js +1 -1
  76. package/dist/{hf-dataset-D9f7-oX7.js → hf-dataset-CKxIJQba.js} +3 -3
  77. package/dist/{hf-dataset-D9f7-oX7.js.map → hf-dataset-CKxIJQba.js.map} +1 -1
  78. package/dist/hosted/index.js +1 -1
  79. package/dist/{index-CX-GAUpw.d.ts → index-CHxwfW5g.d.ts} +2 -2
  80. package/dist/{index-CX-GAUpw.d.ts.map → index-CHxwfW5g.d.ts.map} +1 -1
  81. package/dist/{index-BLGqZ81N.d.ts → index-CVFStrQD.d.ts} +8 -8
  82. package/dist/{index-BLGqZ81N.d.ts.map → index-CVFStrQD.d.ts.map} +1 -1
  83. package/dist/{index-9jJ2fKSX.d.ts → index-CalAsXMR.d.ts} +7 -5
  84. package/dist/index-CalAsXMR.d.ts.map +1 -0
  85. package/dist/{index-CiRwLv2R.d.ts → index-D7fmC-1K.d.ts} +3 -4
  86. package/dist/index-D7fmC-1K.d.ts.map +1 -0
  87. package/dist/{index-BiT6RtNH.d.ts → index-DAXfpVf7.d.ts} +10 -10
  88. package/dist/{index-BiT6RtNH.d.ts.map → index-DAXfpVf7.d.ts.map} +1 -1
  89. package/dist/{index-ZuWx52WG.d.ts → index-Q6DvdcwI.d.ts} +67 -24
  90. package/dist/index-Q6DvdcwI.d.ts.map +1 -0
  91. package/dist/index.d.ts +26 -26
  92. package/dist/index.d.ts.map +1 -1
  93. package/dist/index.js +615 -692
  94. package/dist/index.js.map +1 -1
  95. package/dist/{integrity-DOd9Q86O.js → integrity-C8oUeB0g.js} +322 -197
  96. package/dist/integrity-C8oUeB0g.js.map +1 -0
  97. package/dist/{integrity-_qgZLA5p.d.ts → integrity-CCwvezWS.d.ts} +2 -2
  98. package/dist/{integrity-_qgZLA5p.d.ts.map → integrity-CCwvezWS.d.ts.map} +1 -1
  99. package/dist/{journal-CR4QikYp.js → journal-C7om8Gum.js} +48 -38
  100. package/dist/journal-C7om8Gum.js.map +1 -0
  101. package/dist/judge-gate-Co5tuh57.js.map +1 -1
  102. package/dist/{judge-gate-DsL0yFcb.d.ts → judge-gate-Dc_mXQsL.d.ts} +2 -2
  103. package/dist/judge-gate-Dc_mXQsL.d.ts.map +1 -0
  104. package/dist/{kind-factory-Gy4fXixd.js → kind-factory-BhxbtUsQ.js} +2 -2
  105. package/dist/{kind-factory-Gy4fXixd.js.map → kind-factory-BhxbtUsQ.js.map} +1 -1
  106. package/dist/ledger-core/index.d.ts +1 -1
  107. package/dist/ledger-core/index.js +2 -2
  108. package/dist/ledger-core/lock-holder.d.ts +2 -0
  109. package/dist/ledger-core/lock-holder.js +181 -0
  110. package/dist/ledger-core/lock-holder.js.map +1 -0
  111. package/dist/{ledger-core-DrJhbms9.js → ledger-core-CAxUdDk0.js} +2 -2
  112. package/dist/{ledger-core-DrJhbms9.js.map → ledger-core-CAxUdDk0.js.map} +1 -1
  113. package/dist/{llm-client-BshCREn6.js → llm-client-DXuOTseU.js} +239 -249
  114. package/dist/llm-client-DXuOTseU.js.map +1 -0
  115. package/dist/{llm-judge-C8jMTNNG.js → llm-judge-Cc8vDJh_.js} +648 -459
  116. package/dist/llm-judge-Cc8vDJh_.js.map +1 -0
  117. package/dist/lock-holder-DaJbfpci.d.ts +86 -0
  118. package/dist/lock-holder-DaJbfpci.d.ts.map +1 -0
  119. package/dist/matrix/index.d.ts +2 -2
  120. package/dist/{matrix-DHe-dwVJ.d.ts → matrix-Cf-AGxGh.d.ts} +4 -4
  121. package/dist/{matrix-DHe-dwVJ.d.ts.map → matrix-Cf-AGxGh.d.ts.map} +1 -1
  122. package/dist/meta-eval/index.d.ts +2 -2
  123. package/dist/{mint-zszyYlpA.js → mint-CbdwjTPW.js} +2 -2
  124. package/dist/{mint-zszyYlpA.js.map → mint-CbdwjTPW.js.map} +1 -1
  125. package/dist/{mint-BRZXuwRi.d.ts → mint-CkzpVPdz.d.ts} +3 -3
  126. package/dist/{mint-BRZXuwRi.d.ts.map → mint-CkzpVPdz.d.ts.map} +1 -1
  127. package/dist/multishot/golden/index.d.ts +1 -1
  128. package/dist/multishot/index.d.ts +2 -2
  129. package/dist/multishot/index.js.map +1 -1
  130. package/dist/openapi.json +1 -1
  131. package/dist/{pareto-BzsxidFD.js → pareto-BiBnQXAE.js} +306 -212
  132. package/dist/pareto-BiBnQXAE.js.map +1 -0
  133. package/dist/pipelines/index.d.ts.map +1 -1
  134. package/dist/pipelines/index.js.map +1 -1
  135. package/dist/{prime-protocol-BWG2DQIk.d.ts → prime-protocol-CckHBxGu.d.ts} +3 -3
  136. package/dist/{prime-protocol-BWG2DQIk.d.ts.map → prime-protocol-CckHBxGu.d.ts.map} +1 -1
  137. package/dist/{promotion-gate-DaY95yU6.d.ts → promotion-gate-CkVZHagC.d.ts} +3 -3
  138. package/dist/{promotion-gate-DaY95yU6.d.ts.map → promotion-gate-CkVZHagC.d.ts.map} +1 -1
  139. package/dist/{proposal-findings-BbWidvUk.js → proposal-findings-E1aSC_cU.js} +2 -2
  140. package/dist/{proposal-findings-BbWidvUk.js.map → proposal-findings-E1aSC_cU.js.map} +1 -1
  141. package/dist/{registry-ssNoHzwD.d.ts → registry-B_yG-1jh.d.ts} +5 -5
  142. package/dist/{registry-ssNoHzwD.d.ts.map → registry-B_yG-1jh.d.ts.map} +1 -1
  143. package/dist/{render-C-w2EZ6p.js → render-Cs34y0iX.js} +404 -208
  144. package/dist/render-Cs34y0iX.js.map +1 -0
  145. package/dist/reporting.d.ts +3 -3
  146. package/dist/{researcher-0ABVIdGa.d.ts → researcher-H0p44OYC.d.ts} +5 -5
  147. package/dist/{researcher-0ABVIdGa.d.ts.map → researcher-H0p44OYC.d.ts.map} +1 -1
  148. package/dist/{reward-DrZ71vnf.d.ts → reward-BeUgVVC_.d.ts} +2 -2
  149. package/dist/{reward-DrZ71vnf.d.ts.map → reward-BeUgVVC_.d.ts.map} +1 -1
  150. package/dist/{reward-hacking-E52wq86n.d.ts → reward-hacking-WTxUbtbb.d.ts} +2 -2
  151. package/dist/{reward-hacking-E52wq86n.d.ts.map → reward-hacking-WTxUbtbb.d.ts.map} +1 -1
  152. package/dist/rl.d.ts +8 -8
  153. package/dist/rl.js +4 -4
  154. package/dist/rollout/index.d.ts +3 -3
  155. package/dist/rollout/index.js +5 -5
  156. package/dist/{rollout-D6C50mfA.js → rollout-Dd1ucT_M.js} +5 -5
  157. package/dist/{rollout-D6C50mfA.js.map → rollout-Dd1ucT_M.js.map} +1 -1
  158. package/dist/{rubric-predictive-validity-DiwT8PbL.d.ts → rubric-predictive-validity-noY7uE03.d.ts} +2 -2
  159. package/dist/{rubric-predictive-validity-DiwT8PbL.d.ts.map → rubric-predictive-validity-noY7uE03.d.ts.map} +1 -1
  160. package/dist/{run-record-CaxbLq6Y.d.ts → run-record-C3awiXPf.d.ts} +2 -2
  161. package/dist/{run-record-CaxbLq6Y.d.ts.map → run-record-C3awiXPf.d.ts.map} +1 -1
  162. package/dist/schema-C-ziyJD7.d.ts.map +1 -1
  163. package/dist/{schema-DxcKTzbi.js → schema-CvhfLjtZ.js} +77 -47
  164. package/dist/schema-CvhfLjtZ.js.map +1 -0
  165. package/dist/search/index.d.ts +2 -2
  166. package/dist/search/index.d.ts.map +1 -1
  167. package/dist/search/index.js +2 -2
  168. package/dist/{search-kernel-DxqjBxA-.d.ts → search-kernel-Dloxd6gs.d.ts} +5 -5
  169. package/dist/{search-kernel-DxqjBxA-.d.ts.map → search-kernel-Dloxd6gs.d.ts.map} +1 -1
  170. package/dist/{search-ledger-TUvB5gWH.js → search-ledger-CZRqtFbW.js} +252 -245
  171. package/dist/search-ledger-CZRqtFbW.js.map +1 -0
  172. package/dist/{search-ledger-file-UKCO2r8a.js → search-ledger-file-Bd5Tioq6.js} +3 -3
  173. package/dist/{search-ledger-file-UKCO2r8a.js.map → search-ledger-file-Bd5Tioq6.js.map} +1 -1
  174. package/dist/{search-shipper-Cw2z3-td.js → search-shipper-Dn3NLsuH.js} +3 -3
  175. package/dist/{search-shipper-Cw2z3-td.js.map → search-shipper-Dn3NLsuH.js.map} +1 -1
  176. package/dist/{search-summary-DQIvJsSB.js → search-summary-D4bwYnAE.js} +3 -3
  177. package/dist/{search-summary-DQIvJsSB.js.map → search-summary-D4bwYnAE.js.map} +1 -1
  178. package/dist/{server-DoVbqqtJ.js → server-8TS8XCvg.js} +3 -3
  179. package/dist/{server-DoVbqqtJ.js.map → server-8TS8XCvg.js.map} +1 -1
  180. package/dist/{single-run-lock-U58yf8N6.js → single-run-lock-Dekd8_Wv.js} +7 -7
  181. package/dist/single-run-lock-Dekd8_Wv.js.map +1 -0
  182. package/dist/{skillopt-optimization-method-kyL94-ri.js → skillopt-optimization-method-DLKqdhcR.js} +1384 -1059
  183. package/dist/skillopt-optimization-method-DLKqdhcR.js.map +1 -0
  184. package/dist/{statistical-heldout-C9AbgREN.d.ts → statistical-heldout-3z3I-kJN.d.ts} +3 -3
  185. package/dist/{statistical-heldout-C9AbgREN.d.ts.map → statistical-heldout-3z3I-kJN.d.ts.map} +1 -1
  186. package/dist/{store-otlp-BteDAbHK.js → store-otlp-dyWE3wAG.js} +2 -2
  187. package/dist/{store-otlp-BteDAbHK.js.map → store-otlp-dyWE3wAG.js.map} +1 -1
  188. package/dist/{store-tool-spans-D5l_OfTJ.js → store-tool-spans-DIUgZbzu.js} +3 -3
  189. package/dist/{store-tool-spans-D5l_OfTJ.js.map → store-tool-spans-DIUgZbzu.js.map} +1 -1
  190. package/dist/{store-tool-spans-DZS0HWVf.d.ts → store-tool-spans-DPwXHQkH.d.ts} +7 -7
  191. package/dist/{store-tool-spans-DZS0HWVf.d.ts.map → store-tool-spans-DPwXHQkH.d.ts.map} +1 -1
  192. package/dist/{summary-report-DM7tlml1.d.ts → summary-report-C8V49Jt3.d.ts} +18 -3
  193. package/dist/summary-report-C8V49Jt3.d.ts.map +1 -0
  194. package/dist/supervisor-run/index.d.ts.map +1 -1
  195. package/dist/supervisor-run/index.js +3 -3
  196. package/dist/{systemone-Bp_Ac0p1.d.ts → systemone-DVA7t76V.d.ts} +6 -6
  197. package/dist/{systemone-Bp_Ac0p1.d.ts.map → systemone-DVA7t76V.d.ts.map} +1 -1
  198. package/dist/{systemone-review-CwE6JGIp.d.ts → systemone-review-CUBMuTLi.d.ts} +2 -2
  199. package/dist/{systemone-review-CwE6JGIp.d.ts.map → systemone-review-CUBMuTLi.d.ts.map} +1 -1
  200. package/dist/systemone.d.ts +3 -3
  201. package/dist/{terminal-record-78g6E4vh.js → terminal-record-D4Rv-j1W.js} +241 -193
  202. package/dist/{terminal-record-78g6E4vh.js.map → terminal-record-D4Rv-j1W.js.map} +1 -1
  203. package/dist/{tool-groups-DyNz2JZ_.d.ts → tool-groups-LISbBWCg.d.ts} +3 -3
  204. package/dist/tool-groups-LISbBWCg.d.ts.map +1 -0
  205. package/dist/{trace-questions-xxwgsuMi.d.ts → trace-questions-C42fYEE4.d.ts} +4 -4
  206. package/dist/{trace-questions-xxwgsuMi.d.ts.map → trace-questions-C42fYEE4.d.ts.map} +1 -1
  207. package/dist/trace-repair/index.d.ts +3 -3
  208. package/dist/traces.d.ts +6 -6
  209. package/dist/traces.js +3 -3
  210. package/dist/trajectory-replay/index.d.ts +4 -1
  211. package/dist/trajectory-replay/index.d.ts.map +1 -1
  212. package/dist/trajectory-replay/index.js +854 -823
  213. package/dist/trajectory-replay/index.js.map +1 -1
  214. package/dist/{tree-BGRglkKd.js → tree-DSqwJpL9.js} +122 -14
  215. package/dist/tree-DSqwJpL9.js.map +1 -0
  216. package/dist/{types-CW8ewATZ.d.ts → types-8yQzNm8u.d.ts} +4 -4
  217. package/dist/{types-CW8ewATZ.d.ts.map → types-8yQzNm8u.d.ts.map} +1 -1
  218. package/dist/{types-D8GhJoHk.d.ts → types-CHfn1zg5.d.ts} +70 -72
  219. package/dist/types-CHfn1zg5.d.ts.map +1 -0
  220. package/dist/{types-DtMbFw6U.d.ts → types-D8GXK9Z5.d.ts} +3 -3
  221. package/dist/{types-DtMbFw6U.d.ts.map → types-D8GXK9Z5.d.ts.map} +1 -1
  222. package/dist/{types-D-mgRzlh.d.ts → types-eMhdacVp.d.ts} +2 -2
  223. package/dist/{types-D-mgRzlh.d.ts.map → types-eMhdacVp.d.ts.map} +1 -1
  224. package/dist/wire/index.d.ts +3 -3
  225. package/dist/wire/index.js +1 -1
  226. package/docs/campaign-proposers.md +16 -0
  227. package/docs/concepts.md +31 -0
  228. package/docs/design/statistics-decisions.md +1 -1
  229. package/docs/eval-surface-map.md +1 -0
  230. package/docs/profile-json-identity.md +1 -2
  231. package/docs/public-api.md +100 -88
  232. package/package.json +8 -6
  233. package/dist/benchmark-command-xQK8nOI6.js.map +0 -1
  234. package/dist/campaign-CJGkxAQ6.js.map +0 -1
  235. package/dist/campaign-evidence-CQYw8_0H.js.map +0 -1
  236. package/dist/cost-ledger-D0352Z4d.js.map +0 -1
  237. package/dist/cost-ledger-Jk62OBfF.d.ts.map +0 -1
  238. package/dist/define-agent-eval-BDxNlP3D.js.map +0 -1
  239. package/dist/eval-campaign-BLEfBGbA.js +0 -343
  240. package/dist/eval-campaign-BLEfBGbA.js.map +0 -1
  241. package/dist/index-9jJ2fKSX.d.ts.map +0 -1
  242. package/dist/index-CiRwLv2R.d.ts.map +0 -1
  243. package/dist/index-ZuWx52WG.d.ts.map +0 -1
  244. package/dist/integrity-DOd9Q86O.js.map +0 -1
  245. package/dist/journal-CR4QikYp.js.map +0 -1
  246. package/dist/judge-gate-DsL0yFcb.d.ts.map +0 -1
  247. package/dist/llm-client-BshCREn6.js.map +0 -1
  248. package/dist/llm-judge-C8jMTNNG.js.map +0 -1
  249. package/dist/pareto-BzsxidFD.js.map +0 -1
  250. package/dist/render-C-w2EZ6p.js.map +0 -1
  251. package/dist/schema-DxcKTzbi.js.map +0 -1
  252. package/dist/search-ledger-TUvB5gWH.js.map +0 -1
  253. package/dist/single-run-lock-U58yf8N6.js.map +0 -1
  254. package/dist/skillopt-optimization-method-kyL94-ri.js.map +0 -1
  255. package/dist/summary-report-DM7tlml1.d.ts.map +0 -1
  256. package/dist/tool-groups-DyNz2JZ_.d.ts.map +0 -1
  257. package/dist/tree-BGRglkKd.js.map +0 -1
  258. package/dist/types-D8GhJoHk.d.ts.map +0 -1
@@ -3,17 +3,17 @@ import { t as mean$1 } from "./mean-BbA_JCzW.js";
3
3
  import { t as decidePairedPromotion } from "./paired-promotion-decision-D0SHb-ZL.js";
4
4
  import { a as heldoutSignificance, o as pairHoldout } from "./statistical-heldout-Bksv92Th.js";
5
5
  import { n as contentHash, t as canonicalJson } from "./verdict-cache-CL_7tePD.js";
6
- import { E as assertSearchHistoryAdmissionOptions, J as evaluationUnitMap, K as assertIndependentEvaluationSplit, Q as runCampaign, S as developmentClaim, T as surfaceNode, X as reserveFinalEvidence, Y as exposeFinalEvidence, c as assertGepaCandidatePopulationSummary, d as costFromLedgerSummary, et as resolveRunDir, f as optimizationTokenUsageFromSummary, l as readGepaCandidatePopulationArtifact, q as captureFinalEvidencePolicy, s as executeOptimizationMethod, u as combineComparisonCosts, w as surfaceDiff, x as SearchRecorder, z as captureJudge } from "./llm-judge-C8jMTNNG.js";
7
- import { D as surfaceContentHash, I as assertCompleteCampaign, P as assertCampaignDesign, f as campaignBreakdown, t as createCampaignEvidenceReceipt } from "./campaign-evidence-CQYw8_0H.js";
8
- import { a as mapConcurrent } from "./journal-CR4QikYp.js";
6
+ import { E as assertSearchHistoryAdmissionOptions, J as evaluationUnitMap, K as assertIndependentEvaluationSplit, Q as runCampaign, S as developmentClaim, T as surfaceNode, X as reserveFinalEvidence, Y as exposeFinalEvidence, c as assertGepaCandidatePopulationSummary, d as costFromLedgerSummary, et as resolveRunDir, f as optimizationTokenUsageFromSummary, l as readGepaCandidatePopulationArtifact, q as captureFinalEvidencePolicy, s as executeOptimizationMethod, u as combineComparisonCosts, w as surfaceDiff, x as SearchRecorder, z as captureJudge } from "./llm-judge-Cc8vDJh_.js";
7
+ import { D as surfaceContentHash, I as assertCompleteCampaign, P as assertCampaignDesign, f as campaignBreakdown, t as createCampaignEvidenceReceipt } from "./campaign-evidence-DunzcJGv.js";
8
+ import { a as mapConcurrent } from "./journal-C7om8Gum.js";
9
9
  import { t as deepFreezeCanonicalJson } from "./deep-freeze-CurcOQg3.js";
10
- import { M as fsCampaignStorage, _ as resolveExternalOptimizerCallbackLimits, d as assertExternalOptimizerModelBudget, f as assertJsonValue, g as removeCredentialEnvironment, h as isExternalTextCandidate, i as startExternalOptimizerModelProxy, j as createRunCostLedger, m as isCandidateText, n as closeExternalOptimizerResources, p as assertNoCredentialValues, r as runWithCleanup, t as runExternalOptimizerProcess, v as resolveExternalOptimizerProcessLimits, y as safePathComponent } from "./external-optimizer-subprocess-XIHBOSKt.js";
10
+ import { M as fsCampaignStorage, _ as resolveExternalOptimizerCallbackLimits, d as assertExternalOptimizerModelBudget, f as assertJsonValue, g as removeCredentialEnvironment, h as isExternalTextCandidate, i as startExternalOptimizerModelProxy, j as createRunCostLedger, m as isCandidateText, n as closeExternalOptimizerResources, p as assertNoCredentialValues, r as runWithCleanup, t as runExternalOptimizerProcess, v as resolveExternalOptimizerProcessLimits, y as safePathComponent } from "./external-optimizer-subprocess-D670Oxf2.js";
11
11
  import { r as summarizeEvaluationUnits, t as defineEvaluationClaim } from "./claim-BPVuyHuy.js";
12
- import { n as openSearchLedger } from "./search-ledger-TUvB5gWH.js";
13
- import { t as acquireSingleRunLock } from "./single-run-lock-U58yf8N6.js";
12
+ import { n as openSearchLedger } from "./search-ledger-CZRqtFbW.js";
13
+ import { t as acquireSingleRunLock } from "./single-run-lock-Dekd8_Wv.js";
14
14
  import { n as isRecord } from "./json-BhdsJaOQ.js";
15
- import { _ as combineAbortSignals, d as assertServedModelPolicy } from "./llm-client-BshCREn6.js";
16
- import { t as startExternalOptimizerCallback } from "./external-optimizer-process-KVFGvYX1.js";
15
+ import { _ as combineAbortSignals, d as assertServedModelPolicy } from "./llm-client-DXuOTseU.js";
16
+ import { t as startExternalOptimizerCallback } from "./external-optimizer-process-wOLfzsCC.js";
17
17
  import { createHash, randomBytes } from "node:crypto";
18
18
  import { mkdir } from "node:fs/promises";
19
19
  import { isDeepStrictEqual } from "node:util";
@@ -368,6 +368,7 @@ async function scoreOneScenario(args) {
368
368
  info: {
369
369
  scenarioId: row.scenarioId,
370
370
  dimensions: breakdown.dimensions,
371
+ scores: { ...breakdown.dimensions },
371
372
  status: "scored",
372
373
  ...row.notes ? { notes: row.notes } : {},
373
374
  ...artifact !== void 0 ? { artifact } : {}
@@ -567,270 +568,341 @@ function externalTextOptimizationMethod(config) {
567
568
  const snapshot = snapshotExternalTextOptimizationConfig(config);
568
569
  return {
569
570
  name: snapshot.name,
570
- async optimize(input) {
571
- const seedCandidate = encodeExternalTextCandidate(input.baselineSurface);
572
- const expectsComponents = typeof seedCandidate !== "string";
573
- const maxCandidateChars = snapshot.maxCandidateChars ?? DEFAULT_MAX_CANDIDATE_CHARS;
574
- const maxEvidenceChars = snapshot.maxEvidenceChars ?? DEFAULT_MAX_EVIDENCE_CHARS;
575
- const attemptId = randomBytes(16).toString("hex");
576
- const storage = input.runOptions.storage ?? fsCampaignStorage();
577
- const resume = snapshot.resume ?? "never";
578
- const trainSet = Object.freeze(input.trainScenarios.map((scenario) => describeExternalScenario(scenario, snapshot.name, maxEvidenceChars, snapshot.describeScenario)));
579
- const selectionSet = Object.freeze(input.selectionScenarios.map((scenario) => describeExternalScenario(scenario, snapshot.name, maxEvidenceChars, snapshot.describeScenario)));
580
- const methodDir = `${input.runDir}/external/${safePathComponent(snapshot.name)}`;
581
- const runId = externalOptimizerRunKey({
582
- material: {
583
- optimizer: {
584
- kind: snapshot.source.kind,
585
- package: snapshot.source.package,
586
- version: snapshot.source.version,
587
- ...snapshot.source.sourceUrl ? { sourceUrl: snapshot.source.sourceUrl } : {},
588
- ...snapshot.source.revision ? { revision: snapshot.source.revision } : {}
589
- },
590
- method: snapshot.name,
591
- evaluationId: snapshot.evaluationId,
592
- dispatchRef: input.runOptions.dispatchRef ?? null,
593
- objective: snapshot.objective,
594
- background: snapshot.background ?? "",
595
- seed: input.seed,
596
- seedCandidate,
597
- trainSet,
598
- selectionSet,
599
- maxEvaluations: snapshot.maxEvaluations,
600
- maxOptimizerCostUsd: snapshot.maxOptimizerCostUsd,
601
- maxCandidateChars,
602
- maxEvidenceChars
603
- },
604
- attemptId,
605
- resumeEnabled: resume !== "never"
606
- });
607
- const stateDir = `${methodDir}/state/${runId}`;
608
- const artifactDir = `${methodDir}/attempts/${attemptId}`;
609
- const manifestPath = `${stateDir}/run-manifest.jsonl`;
610
- const evaluationCostPhase = "external.evaluation";
611
- const optimizerCostPhase = "external.optimizer";
612
- storage.ensureDir(stateDir);
613
- storage.ensureDir(artifactDir);
614
- if (resume !== "never") await mkdir(stateDir, { recursive: true });
615
- const lock = resume === "never" ? void 0 : acquireSingleRunLock({
616
- lockPath: `${stateDir}.lock`,
617
- releaseOnExit: true
618
- });
619
- let releaseLock = true;
620
- try {
621
- let manifest = resume === "never" ? void 0 : readExternalOptimizerRunManifest(storage.read(manifestPath), storage.exists(manifestPath), manifestPath, runId);
622
- const restoreRequested = manifest !== void 0;
623
- if (resume === "required" && !restoreRequested) throw new Error(`${snapshot.name}: no compatible run state is available to resume`);
624
- if (resume === "never" && restoreRequested) throw new Error(`${snapshot.name}: fresh optimizer run unexpectedly found prior state`);
625
- if (resume !== "never") manifest = appendExternalOptimizerRunManifestEvent({
626
- storage,
627
- path: manifestPath,
628
- revision: manifest?.revision ?? 0,
629
- event: {
630
- runId,
631
- attemptId,
632
- status: "partial"
633
- }
634
- });
635
- const runBudget = openExternalOptimizerRunBudget({
636
- storage,
637
- runDir: methodDir,
638
- runKey: runId,
639
- attemptId,
640
- maxEvaluations: snapshot.maxEvaluations
641
- });
642
- const optimizerLedger = createRunCostLedger({
643
- storage,
644
- runDir: `${stateDir}/cost`,
645
- costCeilingUsd: snapshot.maxOptimizerCostUsd
646
- });
647
- const scenarioById = mapExternalScenarios(input.trainScenarios, input.selectionScenarios, `${snapshot.name} optimizer`);
648
- const score = createExternalTextEvaluator({
649
- input,
650
- label: `${snapshot.name} optimizer`,
651
- runDir: artifactDir,
652
- compatibleRunId: runId,
653
- costPhase: evaluationCostPhase,
654
- costTags: runBudget.attemptTags,
655
- costLedger: input.costLedger,
656
- scenarioById,
657
- maxCandidateChars,
658
- maxEvidenceChars,
659
- describeArtifact: snapshot.describeArtifact
660
- });
661
- let acceptingEvaluations = true;
662
- const activeEvaluations = /* @__PURE__ */ new Set();
663
- const controller = new AbortController();
664
- const optimizerCostMeter = { async runPaidCall(request) {
665
- const call = {
666
- methodResult: void 0,
667
- providerStarted: false
668
- };
669
- const subLimitResult = await optimizerLedger.runPaidCall({
670
- ...request,
671
- channel: request.channel ?? "optimizer",
672
- phase: optimizerCostPhase,
673
- tags: runBudget.attemptTags,
674
- signal: request.signal ? AbortSignal.any([controller.signal, request.signal]) : controller.signal,
675
- execute: async (signal, callId) => {
676
- call.methodResult = await input.costLedger.runPaidCall({
677
- ...request,
678
- callId,
679
- channel: request.channel ?? "optimizer",
680
- phase: optimizerCostPhase,
681
- tags: runBudget.attemptTags,
682
- signal,
683
- execute: (methodSignal, methodCallId) => {
684
- call.providerStarted = true;
685
- return request.execute(methodSignal, methodCallId);
686
- }
687
- });
688
- if (!call.methodResult.succeeded) throw new Error(`${snapshot.name}: method cost account rejected optimizer call`, { cause: call.methodResult.error });
689
- return call.methodResult.value;
690
- },
691
- receipt: () => {
692
- if (!call.methodResult?.succeeded) throw new Error(`${snapshot.name}: optimizer call completed without a receipt`);
693
- return mirroredCostReceipt(call.methodResult.receipt);
694
- },
695
- receiptFromError: () => {
696
- if (call.methodResult?.receipt) return mirroredCostReceipt(call.methodResult.receipt);
697
- if (!call.providerStarted) return noChargeReceipt(modelBeforeExecution(request));
698
- }
699
- });
700
- if (call.methodResult === void 0) return subLimitResult;
701
- if (!call.methodResult.succeeded) return call.methodResult;
702
- return subLimitResult.succeeded ? call.methodResult : subLimitResult;
703
- } };
704
- Object.freeze(optimizerCostMeter);
705
- const evaluate = (request, signal = controller.signal) => {
706
- if (!acceptingEvaluations) throw new Error(`${snapshot.name}: evaluate cannot be called after run() completes`);
707
- if (runBudget.acceptEvaluation() === void 0) throw new Error(`${snapshot.name}: maxEvaluations limit reached`);
708
- const combinedSignal = signal === controller.signal ? controller.signal : AbortSignal.any([controller.signal, signal]);
709
- const pending = score(cloneExternalEvaluationRequest(request), combinedSignal);
710
- activeEvaluations.add(pending);
711
- const remove = () => activeEvaluations.delete(pending);
712
- pending.then(remove, remove);
713
- return pending;
714
- };
715
- const started = Date.now();
716
- const timeoutMs = snapshot.timeoutMs ?? DEFAULT_TIMEOUT_MS;
717
- const timeout = setTimeout(() => controller.abort(/* @__PURE__ */ new Error(`${snapshot.name}: optimizer exceeded ${timeoutMs}ms`)), timeoutMs);
718
- let result;
719
- let runError;
720
- let outstandingAtCompletion = 0;
721
- let paidCallsAtCompletion = 0;
722
- let runSettled = false;
723
- const runPromise = Promise.resolve().then(() => snapshot.run(Object.freeze({
724
- runId,
725
- name: snapshot.name,
726
- objective: snapshot.objective,
727
- evaluationId: snapshot.evaluationId,
728
- ...snapshot.background ? { background: snapshot.background } : {},
729
- seedCandidate: cloneExternalTextCandidate(seedCandidate),
730
- trainSet,
731
- selectionSet,
732
- maxEvaluations: snapshot.maxEvaluations,
733
- seed: input.seed,
734
- stateDir,
735
- restoreRequested,
736
- artifactDir,
737
- signal: controller.signal,
738
- cost: optimizerCostMeter,
739
- evaluate
740
- })));
741
- runPromise.then(() => {
742
- runSettled = true;
743
- }, () => {
744
- runSettled = true;
745
- });
746
- try {
747
- result = await raceWithAbort(runPromise, controller.signal);
748
- outstandingAtCompletion = activeEvaluations.size;
749
- paidCallsAtCompletion = optimizerLedger.summary().pendingCalls;
750
- } catch (error) {
751
- runError = error;
752
- } finally {
753
- acceptingEvaluations = false;
754
- clearTimeout(timeout);
755
- }
756
- await Promise.allSettled([...activeEvaluations]);
757
- const paidCallsSettled = await optimizerLedger.waitForIdle({ timeoutMs: 5e3 });
758
- if (runError !== void 0) {
759
- if ((!runSettled || !paidCallsSettled) && lock) {
760
- releaseLock = false;
761
- Promise.allSettled([runPromise, optimizerLedger.waitForIdle({ timeoutMs: MAX_TIMER_DELAY_MS$2 })]).then(() => lock.release());
762
- }
763
- throw runError;
764
- }
765
- if (!paidCallsSettled) {
766
- if (lock) {
767
- releaseLock = false;
768
- Promise.allSettled([runPromise, optimizerLedger.waitForIdle({ timeoutMs: MAX_TIMER_DELAY_MS$2 })]).then(() => lock.release());
769
- }
770
- throw new Error(`${snapshot.name}: optimizer paid calls did not settle`);
771
- }
772
- if (paidCallsAtCompletion > 0) throw new Error(`${snapshot.name}: run() completed with ${paidCallsAtCompletion} outstanding paid call(s); await every context.cost.runPaidCall()`);
773
- if (outstandingAtCompletion > 0) throw new Error(`${snapshot.name}: run() completed with ${outstandingAtCompletion} outstanding evaluation(s); await every evaluate() call`);
774
- assertExternalTextOptimizerResult(result, snapshot.name, maxCandidateChars, expectsComponents);
775
- if (result.resumed !== restoreRequested) throw new Error(`${snapshot.name}: optimizer reported resumed=${String(result.resumed)} but restoreRequested=${String(restoreRequested)}`);
776
- const evaluationCost = costFromLedgerSummary(input.costLedger.summary({
777
- phase: evaluationCostPhase,
778
- tags: runBudget.runTags
779
- }));
780
- const optimizerFilter = {
781
- phase: optimizerCostPhase,
782
- tags: runBudget.runTags
783
- };
784
- const optimizerReceipts = input.costLedger.list(optimizerFilter);
785
- const optimizerSummary = input.costLedger.summary(optimizerFilter);
786
- const optimizerCost = costFromLedgerSummary(optimizerSummary);
787
- assertExternalCostAccounting(result.costAccounting, optimizerSummary.totalCalls, snapshot.name);
788
- const externalCostReason = result.costAccounting.kind === "external" ? result.costAccounting.reason : void 0;
789
- const tokenUsage = optimizationTokenUsageFromSummary(optimizerSummary, optimizerReceipts);
790
- if (resume !== "never") appendExternalOptimizerRunManifestEvent({
791
- storage,
792
- path: manifestPath,
793
- revision: manifest.revision,
794
- event: {
795
- runId,
796
- attemptId,
797
- status: "completed"
571
+ optimize: (input) => optimizeExternalText(snapshot, input)
572
+ };
573
+ }
574
+ const EVALUATION_COST_PHASE = "external.evaluation";
575
+ const OPTIMIZER_COST_PHASE = "external.optimizer";
576
+ async function optimizeExternalText(snapshot, input) {
577
+ const run = await prepareExternalRun(snapshot, input);
578
+ try {
579
+ const { manifest, restoreRequested } = restoreRunManifest(run);
580
+ const accounts = openRunAccounts(run);
581
+ const session = startOptimizerSession(run, accounts, restoreRequested);
582
+ return finishRun(run, accounts, session, manifest, await awaitOptimizerResult(run, accounts, session, restoreRequested));
583
+ } finally {
584
+ if (run.releaseLock) run.lock?.release();
585
+ }
586
+ }
587
+ function describeExternalScenarios(scenarios, snapshot, maxEvidenceChars) {
588
+ return Object.freeze(scenarios.map((scenario) => describeExternalScenario(scenario, snapshot.name, maxEvidenceChars, snapshot.describeScenario)));
589
+ }
590
+ /** Run identity, scenario descriptions and directories, then the resume lock. */
591
+ async function prepareExternalRun(snapshot, input) {
592
+ const seedCandidate = encodeExternalTextCandidate(input.baselineSurface);
593
+ const maxCandidateChars = snapshot.maxCandidateChars ?? DEFAULT_MAX_CANDIDATE_CHARS;
594
+ const maxEvidenceChars = snapshot.maxEvidenceChars ?? DEFAULT_MAX_EVIDENCE_CHARS;
595
+ const attemptId = randomBytes(16).toString("hex");
596
+ const storage = input.runOptions.storage ?? fsCampaignStorage();
597
+ const resume = snapshot.resume ?? "never";
598
+ const trainSet = describeExternalScenarios(input.trainScenarios, snapshot, maxEvidenceChars);
599
+ const selectionSet = describeExternalScenarios(input.selectionScenarios, snapshot, maxEvidenceChars);
600
+ const methodDir = `${input.runDir}/external/${safePathComponent(snapshot.name)}`;
601
+ const runId = externalOptimizerRunKey({
602
+ material: {
603
+ optimizer: {
604
+ kind: snapshot.source.kind,
605
+ package: snapshot.source.package,
606
+ version: snapshot.source.version,
607
+ ...snapshot.source.sourceUrl ? { sourceUrl: snapshot.source.sourceUrl } : {},
608
+ ...snapshot.source.revision ? { revision: snapshot.source.revision } : {}
609
+ },
610
+ method: snapshot.name,
611
+ evaluationId: snapshot.evaluationId,
612
+ dispatchRef: input.runOptions.dispatchRef ?? null,
613
+ objective: snapshot.objective,
614
+ background: snapshot.background ?? "",
615
+ seed: input.seed,
616
+ seedCandidate,
617
+ trainSet,
618
+ selectionSet,
619
+ maxEvaluations: snapshot.maxEvaluations,
620
+ maxOptimizerCostUsd: snapshot.maxOptimizerCostUsd,
621
+ maxCandidateChars,
622
+ maxEvidenceChars
623
+ },
624
+ attemptId,
625
+ resumeEnabled: resume !== "never"
626
+ });
627
+ const stateDir = `${methodDir}/state/${runId}`;
628
+ const artifactDir = `${methodDir}/attempts/${attemptId}`;
629
+ storage.ensureDir(stateDir);
630
+ storage.ensureDir(artifactDir);
631
+ if (resume !== "never") await mkdir(stateDir, { recursive: true });
632
+ const lock = resume === "never" ? void 0 : acquireSingleRunLock({
633
+ lockPath: `${stateDir}.lock`,
634
+ releaseOnExit: true
635
+ });
636
+ return {
637
+ snapshot,
638
+ input,
639
+ seedCandidate,
640
+ expectsComponents: typeof seedCandidate !== "string",
641
+ maxCandidateChars,
642
+ maxEvidenceChars,
643
+ attemptId,
644
+ storage,
645
+ resume,
646
+ trainSet,
647
+ selectionSet,
648
+ methodDir,
649
+ runId,
650
+ stateDir,
651
+ artifactDir,
652
+ manifestPath: `${stateDir}/run-manifest.jsonl`,
653
+ lock,
654
+ releaseLock: true
655
+ };
656
+ }
657
+ /** Reads prior state when resuming, and records this attempt as partial. */
658
+ function restoreRunManifest(run) {
659
+ const { snapshot, storage, manifestPath, runId, attemptId, resume } = run;
660
+ let manifest = resume === "never" ? void 0 : readExternalOptimizerRunManifest(storage.read(manifestPath), storage.exists(manifestPath), manifestPath, runId);
661
+ const restoreRequested = manifest !== void 0;
662
+ if (resume === "required" && !restoreRequested) throw new Error(`${snapshot.name}: no compatible run state is available to resume`);
663
+ if (resume === "never" && restoreRequested) throw new Error(`${snapshot.name}: fresh optimizer run unexpectedly found prior state`);
664
+ if (resume !== "never") manifest = appendExternalOptimizerRunManifestEvent({
665
+ storage,
666
+ path: manifestPath,
667
+ revision: manifest?.revision ?? 0,
668
+ event: {
669
+ runId,
670
+ attemptId,
671
+ status: "partial"
672
+ }
673
+ });
674
+ return {
675
+ manifest,
676
+ restoreRequested
677
+ };
678
+ }
679
+ function openRunAccounts(run) {
680
+ const { snapshot, storage, methodDir, runId, attemptId, stateDir } = run;
681
+ return {
682
+ runBudget: openExternalOptimizerRunBudget({
683
+ storage,
684
+ runDir: methodDir,
685
+ runKey: runId,
686
+ attemptId,
687
+ maxEvaluations: snapshot.maxEvaluations
688
+ }),
689
+ optimizerLedger: createRunCostLedger({
690
+ storage,
691
+ runDir: `${stateDir}/cost`,
692
+ costCeilingUsd: snapshot.maxOptimizerCostUsd
693
+ })
694
+ };
695
+ }
696
+ /** Optimizer paid calls, charged to the optimizer's own limit and mirrored into the method's account. */
697
+ function createOptimizerCostMeter(run, accounts, controller) {
698
+ const { snapshot, input } = run;
699
+ const { runBudget, optimizerLedger } = accounts;
700
+ return Object.freeze({ async runPaidCall(request) {
701
+ const call = {
702
+ methodResult: void 0,
703
+ providerStarted: false
704
+ };
705
+ const subLimitResult = await optimizerLedger.runPaidCall({
706
+ ...request,
707
+ channel: request.channel ?? "optimizer",
708
+ phase: OPTIMIZER_COST_PHASE,
709
+ tags: runBudget.attemptTags,
710
+ signal: request.signal ? AbortSignal.any([controller.signal, request.signal]) : controller.signal,
711
+ execute: async (signal, callId) => {
712
+ call.methodResult = await input.costLedger.runPaidCall({
713
+ ...request,
714
+ callId,
715
+ channel: request.channel ?? "optimizer",
716
+ phase: OPTIMIZER_COST_PHASE,
717
+ tags: runBudget.attemptTags,
718
+ signal,
719
+ execute: (methodSignal, methodCallId) => {
720
+ call.providerStarted = true;
721
+ return request.execute(methodSignal, methodCallId);
798
722
  }
799
723
  });
800
- const measuredCost = combineComparisonCosts([{
801
- label: "evaluation",
802
- cost: evaluationCost
803
- }, {
804
- label: "optimizer",
805
- cost: optimizerCost
806
- }]);
807
- return {
808
- winnerSurface: decodeExternalTextCandidate(result.bestCandidate),
809
- cost: {
810
- ...measuredCost,
811
- ...externalCostReason ? { costProvenance: {
812
- kind: "uncaptured",
813
- usd: null
814
- } } : {},
815
- accountingComplete: measuredCost.accountingComplete && externalCostReason === void 0,
816
- incompleteReasons: [...measuredCost.incompleteReasons, ...externalCostReason ? [`optimizer: external spend is not observed: ${externalCostReason}`] : []]
817
- },
818
- durationMs: Date.now() - started,
819
- provenance: {
820
- source: {
821
- ...snapshot.source,
822
- evidence: "declared"
823
- },
824
- runId,
825
- resumed: result.resumed,
826
- evaluationCount: runBudget.acceptedEvaluations(),
827
- artifactDir,
828
- ...tokenUsage ? { tokenUsage } : {}
829
- }
830
- };
831
- } finally {
832
- if (releaseLock) lock?.release();
724
+ if (!call.methodResult.succeeded) throw new Error(`${snapshot.name}: method cost account rejected optimizer call`, { cause: call.methodResult.error });
725
+ return call.methodResult.value;
726
+ },
727
+ receipt: () => {
728
+ if (!call.methodResult?.succeeded) throw new Error(`${snapshot.name}: optimizer call completed without a receipt`);
729
+ return mirroredCostReceipt(call.methodResult.receipt);
730
+ },
731
+ receiptFromError: () => {
732
+ if (call.methodResult?.receipt) return mirroredCostReceipt(call.methodResult.receipt);
733
+ if (!call.providerStarted) return noChargeReceipt(modelBeforeExecution(request));
833
734
  }
735
+ });
736
+ if (call.methodResult === void 0) return subLimitResult;
737
+ if (!call.methodResult.succeeded) return call.methodResult;
738
+ return subLimitResult.succeeded ? call.methodResult : subLimitResult;
739
+ } });
740
+ }
741
+ /** Starts the optimizer with its evaluator, cost meter, timeout and frozen context. */
742
+ function startOptimizerSession(run, accounts, restoreRequested) {
743
+ const { snapshot, input, runId, stateDir, artifactDir } = run;
744
+ const { runBudget } = accounts;
745
+ const scenarioById = mapExternalScenarios(input.trainScenarios, input.selectionScenarios, `${snapshot.name} optimizer`);
746
+ const score = createExternalTextEvaluator({
747
+ input,
748
+ label: `${snapshot.name} optimizer`,
749
+ runDir: artifactDir,
750
+ compatibleRunId: runId,
751
+ costPhase: EVALUATION_COST_PHASE,
752
+ costTags: runBudget.attemptTags,
753
+ costLedger: input.costLedger,
754
+ scenarioById,
755
+ maxCandidateChars: run.maxCandidateChars,
756
+ maxEvidenceChars: run.maxEvidenceChars,
757
+ describeArtifact: snapshot.describeArtifact
758
+ });
759
+ const controller = new AbortController();
760
+ const activeEvaluations = /* @__PURE__ */ new Set();
761
+ const state = {
762
+ acceptingEvaluations: true,
763
+ runSettled: false
764
+ };
765
+ const optimizerCostMeter = createOptimizerCostMeter(run, accounts, controller);
766
+ const evaluate = (request, signal = controller.signal) => {
767
+ if (!state.acceptingEvaluations) throw new Error(`${snapshot.name}: evaluate cannot be called after run() completes`);
768
+ if (runBudget.acceptEvaluation() === void 0) throw new Error(`${snapshot.name}: maxEvaluations limit reached`);
769
+ const combinedSignal = signal === controller.signal ? controller.signal : AbortSignal.any([controller.signal, signal]);
770
+ const pending = score(cloneExternalEvaluationRequest(request), combinedSignal);
771
+ activeEvaluations.add(pending);
772
+ const remove = () => activeEvaluations.delete(pending);
773
+ pending.then(remove, remove);
774
+ return pending;
775
+ };
776
+ const started = Date.now();
777
+ const timeoutMs = snapshot.timeoutMs ?? DEFAULT_TIMEOUT_MS;
778
+ const timeout = setTimeout(() => controller.abort(/* @__PURE__ */ new Error(`${snapshot.name}: optimizer exceeded ${timeoutMs}ms`)), timeoutMs);
779
+ const runPromise = Promise.resolve().then(() => snapshot.run(Object.freeze({
780
+ runId,
781
+ name: snapshot.name,
782
+ objective: snapshot.objective,
783
+ evaluationId: snapshot.evaluationId,
784
+ ...snapshot.background ? { background: snapshot.background } : {},
785
+ seedCandidate: cloneExternalTextCandidate(run.seedCandidate),
786
+ trainSet: run.trainSet,
787
+ selectionSet: run.selectionSet,
788
+ maxEvaluations: snapshot.maxEvaluations,
789
+ seed: input.seed,
790
+ stateDir,
791
+ restoreRequested,
792
+ artifactDir,
793
+ signal: controller.signal,
794
+ cost: optimizerCostMeter,
795
+ evaluate
796
+ })));
797
+ const markSettled = () => {
798
+ state.runSettled = true;
799
+ };
800
+ runPromise.then(markSettled, markSettled);
801
+ return {
802
+ controller,
803
+ activeEvaluations,
804
+ runPromise,
805
+ timeout,
806
+ started,
807
+ state
808
+ };
809
+ }
810
+ /** Waits for the optimizer, then refuses a run that left evaluations or paid calls outstanding. */
811
+ async function awaitOptimizerResult(run, accounts, session, restoreRequested) {
812
+ const { snapshot, lock } = run;
813
+ const { optimizerLedger } = accounts;
814
+ let result;
815
+ let runError;
816
+ let outstandingAtCompletion = 0;
817
+ let paidCallsAtCompletion = 0;
818
+ try {
819
+ result = await raceWithAbort(session.runPromise, session.controller.signal);
820
+ outstandingAtCompletion = session.activeEvaluations.size;
821
+ paidCallsAtCompletion = optimizerLedger.summary().pendingCalls;
822
+ } catch (error) {
823
+ runError = error;
824
+ } finally {
825
+ session.state.acceptingEvaluations = false;
826
+ clearTimeout(session.timeout);
827
+ }
828
+ await Promise.allSettled([...session.activeEvaluations]);
829
+ const paidCallsSettled = await optimizerLedger.waitForIdle({ timeoutMs: 5e3 });
830
+ const handOffLock = () => {
831
+ if (!lock) return;
832
+ run.releaseLock = false;
833
+ Promise.allSettled([session.runPromise, optimizerLedger.waitForIdle({ timeoutMs: MAX_TIMER_DELAY_MS$2 })]).then(() => lock.release());
834
+ };
835
+ if (runError !== void 0) {
836
+ if (!session.state.runSettled || !paidCallsSettled) handOffLock();
837
+ throw runError;
838
+ }
839
+ if (!paidCallsSettled) {
840
+ handOffLock();
841
+ throw new Error(`${snapshot.name}: optimizer paid calls did not settle`);
842
+ }
843
+ if (paidCallsAtCompletion > 0) throw new Error(`${snapshot.name}: run() completed with ${paidCallsAtCompletion} outstanding paid call(s); await every context.cost.runPaidCall()`);
844
+ if (outstandingAtCompletion > 0) throw new Error(`${snapshot.name}: run() completed with ${outstandingAtCompletion} outstanding evaluation(s); await every evaluate() call`);
845
+ assertExternalTextOptimizerResult(result, snapshot.name, run.maxCandidateChars, run.expectsComponents);
846
+ if (result.resumed !== restoreRequested) throw new Error(`${snapshot.name}: optimizer reported resumed=${String(result.resumed)} but restoreRequested=${String(restoreRequested)}`);
847
+ return result;
848
+ }
849
+ /** Measures evaluation and optimizer spend, records completion, and builds the method result. */
850
+ function finishRun(run, accounts, session, manifest, result) {
851
+ const { snapshot, input, storage, runId, attemptId } = run;
852
+ const { runBudget } = accounts;
853
+ const evaluationCost = costFromLedgerSummary(input.costLedger.summary({
854
+ phase: EVALUATION_COST_PHASE,
855
+ tags: runBudget.runTags
856
+ }));
857
+ const optimizerFilter = {
858
+ phase: OPTIMIZER_COST_PHASE,
859
+ tags: runBudget.runTags
860
+ };
861
+ const optimizerReceipts = input.costLedger.list(optimizerFilter);
862
+ const optimizerSummary = input.costLedger.summary(optimizerFilter);
863
+ const optimizerCost = costFromLedgerSummary(optimizerSummary);
864
+ assertExternalCostAccounting(result.costAccounting, optimizerSummary.totalCalls, snapshot.name);
865
+ const externalCostReason = result.costAccounting.kind === "external" ? result.costAccounting.reason : void 0;
866
+ const tokenUsage = optimizationTokenUsageFromSummary(optimizerSummary, optimizerReceipts);
867
+ if (run.resume !== "never") appendExternalOptimizerRunManifestEvent({
868
+ storage,
869
+ path: run.manifestPath,
870
+ revision: manifest.revision,
871
+ event: {
872
+ runId,
873
+ attemptId,
874
+ status: "completed"
875
+ }
876
+ });
877
+ const measuredCost = combineComparisonCosts([{
878
+ label: "evaluation",
879
+ cost: evaluationCost
880
+ }, {
881
+ label: "optimizer",
882
+ cost: optimizerCost
883
+ }]);
884
+ return {
885
+ winnerSurface: decodeExternalTextCandidate(result.bestCandidate),
886
+ cost: {
887
+ ...measuredCost,
888
+ ...externalCostReason ? { costProvenance: {
889
+ kind: "uncaptured",
890
+ usd: null
891
+ } } : {},
892
+ accountingComplete: measuredCost.accountingComplete && externalCostReason === void 0,
893
+ incompleteReasons: [...measuredCost.incompleteReasons, ...externalCostReason ? [`optimizer: external spend is not observed: ${externalCostReason}`] : []]
894
+ },
895
+ durationMs: Date.now() - session.started,
896
+ provenance: {
897
+ source: {
898
+ ...snapshot.source,
899
+ evidence: "declared"
900
+ },
901
+ runId,
902
+ resumed: result.resumed,
903
+ evaluationCount: runBudget.acceptedEvaluations(),
904
+ artifactDir: run.artifactDir,
905
+ ...tokenUsage ? { tokenUsage } : {}
834
906
  }
835
907
  };
836
908
  }
@@ -1000,30 +1072,6 @@ function heldOutGate(options) {
1000
1072
  };
1001
1073
  }
1002
1074
  //#endregion
1003
- //#region src/campaign/external-optimizer-accounting.ts
1004
- const TOKEN_USAGE_FIELDS = [
1005
- "inputTokens",
1006
- "outputTokens",
1007
- "totalTokens",
1008
- "calls"
1009
- ];
1010
- function assertPriorExternalOptimizerUsage(summary, budget, name) {
1011
- if (!summary.usageComplete || budget.maxCostUsd !== void 0 && !summary.accountingComplete) throw new Error(`${name}: cannot resume optimizer-model work with incomplete bounded usage`);
1012
- if (summary.totalCalls > budget.maxRequests || budget.maxCostUsd !== void 0 && summary.totalCostUsd > budget.maxCostUsd + Number.EPSILON) throw new Error(`${name}: prior optimizer-model usage exceeds the configured budget`);
1013
- }
1014
- function assertExternalOptimizerTokenUsage(usage, name, optimizer) {
1015
- if (usage === void 0) return;
1016
- for (const field of TOKEN_USAGE_FIELDS) if (!Number.isSafeInteger(usage[field]) || usage[field] < 0) throw new Error(`${name}: ${optimizer} bridge returned invalid tokenUsage.${field}`);
1017
- if (usage.totalTokens !== usage.inputTokens + usage.outputTokens) throw new Error(`${name}: ${optimizer} bridge returned inconsistent tokenUsage.totalTokens`);
1018
- if (usage.requestAttempts !== void 0 && (!Number.isSafeInteger(usage.requestAttempts) || usage.requestAttempts < usage.calls)) throw new Error(`${name}: ${optimizer} bridge returned invalid tokenUsage.requestAttempts`);
1019
- }
1020
- function assertExternalOptimizerCompletionCount(upstream, requestAttempts, successfulCompletions, name, optimizer) {
1021
- if (!upstream) throw new Error(`${name}: ${optimizer} did not report optimizer token usage`);
1022
- if (!Number.isSafeInteger(requestAttempts) || !Number.isSafeInteger(successfulCompletions) || requestAttempts < 0 || successfulCompletions < 0 || successfulCompletions > requestAttempts) throw new Error(`${name}: optimizer model proxy returned invalid request counts`);
1023
- if (upstream.calls !== successfulCompletions) throw new Error(`${name}: ${optimizer} reported ${upstream.calls} successful model calls but the proxy completed ${successfulCompletions} across ${requestAttempts} attempts`);
1024
- if (upstream.requestAttempts !== void 0 && upstream.requestAttempts !== requestAttempts) throw new Error(`${name}: ${optimizer} reported ${upstream.requestAttempts} model attempts but the proxy received ${requestAttempts}`);
1025
- }
1026
- //#endregion
1027
1075
  //#region src/campaign/external-optimizer-run-config.ts
1028
1076
  function externalOptimizerRunnerIdentity(runner, module) {
1029
1077
  return {
@@ -1048,72 +1096,6 @@ function snapshotJson(value, label) {
1048
1096
  return JSON.parse(serialized);
1049
1097
  }
1050
1098
  //#endregion
1051
- //#region src/campaign/external-optimizer-source.ts
1052
- function assertExternalOptimizerPackageSource(value, expectedPackage, name, optimizer) {
1053
- assertExternalOptimizerPackageIdentity(value, expectedPackage, name, optimizer);
1054
- assertExternalOptimizerSourceDetails(value, name, optimizer);
1055
- }
1056
- function assertExternalOptimizerPackageIdentity(value, expectedPackage, name, optimizer) {
1057
- if (!isRecord(value) || value.package !== expectedPackage || typeof value.version !== "string" || value.version.length === 0 || value.version !== value.version.trim()) throw new Error(`${name}: ${optimizer} bridge returned invalid upstream package provenance`);
1058
- }
1059
- function assertExternalOptimizerSourceDetails(value, name, optimizer) {
1060
- if (value.sourceUrl !== void 0 && (typeof value.sourceUrl !== "string" || value.sourceUrl.length === 0 || value.sourceUrl !== value.sourceUrl.trim())) throw new Error(`${name}: ${optimizer} bridge returned an invalid upstream sourceUrl`);
1061
- if (value.revision !== void 0 && (typeof value.revision !== "string" || value.revision.length === 0 || value.revision !== value.revision.trim())) throw new Error(`${name}: ${optimizer} bridge returned an invalid upstream revision`);
1062
- if (value.sourceSha256 !== void 0 && (typeof value.sourceSha256 !== "string" || !/^[0-9a-f]{64}$/.test(value.sourceSha256))) throw new Error(`${name}: ${optimizer} bridge returned an invalid upstream sourceSha256`);
1063
- }
1064
- function observedExternalOptimizerPackageSource(value) {
1065
- return {
1066
- kind: "package",
1067
- evidence: "observed",
1068
- package: value.package,
1069
- version: value.version,
1070
- ...value.sourceUrl ? { sourceUrl: value.sourceUrl } : {},
1071
- ...value.revision ? { revision: value.revision } : {},
1072
- ...value.sourceSha256 ? { sourceSha256: value.sourceSha256 } : {}
1073
- };
1074
- }
1075
- //#endregion
1076
- //#region src/campaign/external-optimizer-runtime.ts
1077
- async function inspectExternalOptimizerRuntime(args) {
1078
- const result = await runExternalOptimizerProcess({
1079
- label: `${args.label} source inspection`,
1080
- tempPrefix: `agent-eval-${args.package}-inspect-`,
1081
- module: args.module,
1082
- input: {
1083
- operation: "inspect",
1084
- engineModules: [...args.engineModules ?? []]
1085
- },
1086
- ...args.runner ? { runner: args.runner } : {},
1087
- timeoutMs: args.timeoutMs,
1088
- ...args.signal ? { signal: args.signal } : {}
1089
- });
1090
- assertExternalOptimizerRuntimeIdentity(result.runtime, args.package, args.label);
1091
- return result.runtime;
1092
- }
1093
- function observedExternalOptimizerRuntime(runtime) {
1094
- return {
1095
- source: observedExternalOptimizerPackageSource(runtime.optimizer),
1096
- bridge: observedExternalOptimizerPackageSource(runtime.bridge),
1097
- modules: runtime.engineModules.map((module) => ({ ...module })),
1098
- python: { ...runtime.python }
1099
- };
1100
- }
1101
- function assertExternalOptimizerRunBinding(args) {
1102
- if (!isDeepStrictEqual(args.returnedSource, args.runtime.optimizer)) throw new Error(`${args.label}: optimizer package changed after source inspection`);
1103
- if (args.returnedRunId !== args.runId) throw new Error(`${args.label}: bridge returned a different run ID`);
1104
- if (args.resume === "never" && args.resumed) throw new Error(`${args.label}: fresh run reported restored state`);
1105
- if (args.resume === "required" && !args.resumed) throw new Error(`${args.label}: required resume did not restore state`);
1106
- if (!args.runId.startsWith(args.compatibleRunId)) throw new Error(`${args.label}: run ID is not bound to its compatible identity`);
1107
- }
1108
- function assertExternalOptimizerRuntimeIdentity(value, expectedPackage, label) {
1109
- if (!isRecord(value)) throw new Error(`${label}: source inspection returned no runtime identity`);
1110
- assertExternalOptimizerPackageSource(value.bridge, "agent-eval-rpc", label, "bridge");
1111
- assertExternalOptimizerPackageSource(value.optimizer, expectedPackage, label, expectedPackage);
1112
- if (!value.bridge.sourceSha256 || !value.optimizer.sourceSha256) throw new Error(`${label}: source inspection omitted package source hashes`);
1113
- if (!isRecord(value.python) || typeof value.python.implementation !== "string" || value.python.implementation.length === 0 || value.python.implementation !== value.python.implementation.trim() || typeof value.python.version !== "string" || value.python.version.length === 0 || value.python.version !== value.python.version.trim()) throw new Error(`${label}: source inspection returned an invalid Python runtime`);
1114
- if (!Array.isArray(value.engineModules) || value.engineModules.some((module) => !isRecord(module) || typeof module.module !== "string" || module.module.length === 0 || module.module !== module.module.trim() || typeof module.sourceSha256 !== "string" || !/^[0-9a-f]{64}$/.test(module.sourceSha256))) throw new Error(`${label}: source inspection returned invalid engine modules`);
1115
- }
1116
- //#endregion
1117
1099
  //#region src/campaign/optimizer-model.ts
1118
1100
  function assertOptimizerModel(value, label) {
1119
1101
  if (!value || typeof value !== "object") throw new Error(`${label} is required`);
@@ -1311,6 +1293,96 @@ function addEvaluationLimit(total, increment) {
1311
1293
  return next;
1312
1294
  }
1313
1295
  //#endregion
1296
+ //#region src/campaign/external-optimizer-accounting.ts
1297
+ const TOKEN_USAGE_FIELDS = [
1298
+ "inputTokens",
1299
+ "outputTokens",
1300
+ "totalTokens",
1301
+ "calls"
1302
+ ];
1303
+ function assertPriorExternalOptimizerUsage(summary, budget, name) {
1304
+ if (!summary.usageComplete || budget.maxCostUsd !== void 0 && !summary.accountingComplete) throw new Error(`${name}: cannot resume optimizer-model work with incomplete bounded usage`);
1305
+ if (summary.totalCalls > budget.maxRequests || budget.maxCostUsd !== void 0 && summary.totalCostUsd > budget.maxCostUsd + Number.EPSILON) throw new Error(`${name}: prior optimizer-model usage exceeds the configured budget`);
1306
+ }
1307
+ function assertExternalOptimizerTokenUsage(usage, name, optimizer) {
1308
+ if (usage === void 0) return;
1309
+ for (const field of TOKEN_USAGE_FIELDS) if (!Number.isSafeInteger(usage[field]) || usage[field] < 0) throw new Error(`${name}: ${optimizer} bridge returned invalid tokenUsage.${field}`);
1310
+ if (usage.totalTokens !== usage.inputTokens + usage.outputTokens) throw new Error(`${name}: ${optimizer} bridge returned inconsistent tokenUsage.totalTokens`);
1311
+ if (usage.requestAttempts !== void 0 && (!Number.isSafeInteger(usage.requestAttempts) || usage.requestAttempts < usage.calls)) throw new Error(`${name}: ${optimizer} bridge returned invalid tokenUsage.requestAttempts`);
1312
+ }
1313
+ function assertExternalOptimizerCompletionCount(upstream, requestAttempts, successfulCompletions, name, optimizer) {
1314
+ if (!upstream) throw new Error(`${name}: ${optimizer} did not report optimizer token usage`);
1315
+ if (!Number.isSafeInteger(requestAttempts) || !Number.isSafeInteger(successfulCompletions) || requestAttempts < 0 || successfulCompletions < 0 || successfulCompletions > requestAttempts) throw new Error(`${name}: optimizer model proxy returned invalid request counts`);
1316
+ if (upstream.calls !== successfulCompletions) throw new Error(`${name}: ${optimizer} reported ${upstream.calls} successful model calls but the proxy completed ${successfulCompletions} across ${requestAttempts} attempts`);
1317
+ if (upstream.requestAttempts !== void 0 && upstream.requestAttempts !== requestAttempts) throw new Error(`${name}: ${optimizer} reported ${upstream.requestAttempts} model attempts but the proxy received ${requestAttempts}`);
1318
+ }
1319
+ //#endregion
1320
+ //#region src/campaign/external-optimizer-source.ts
1321
+ function assertExternalOptimizerPackageSource(value, expectedPackage, name, optimizer) {
1322
+ assertExternalOptimizerPackageIdentity(value, expectedPackage, name, optimizer);
1323
+ assertExternalOptimizerSourceDetails(value, name, optimizer);
1324
+ }
1325
+ function assertExternalOptimizerPackageIdentity(value, expectedPackage, name, optimizer) {
1326
+ if (!isRecord(value) || value.package !== expectedPackage || typeof value.version !== "string" || value.version.length === 0 || value.version !== value.version.trim()) throw new Error(`${name}: ${optimizer} bridge returned invalid upstream package provenance`);
1327
+ }
1328
+ function assertExternalOptimizerSourceDetails(value, name, optimizer) {
1329
+ if (value.sourceUrl !== void 0 && (typeof value.sourceUrl !== "string" || value.sourceUrl.length === 0 || value.sourceUrl !== value.sourceUrl.trim())) throw new Error(`${name}: ${optimizer} bridge returned an invalid upstream sourceUrl`);
1330
+ if (value.revision !== void 0 && (typeof value.revision !== "string" || value.revision.length === 0 || value.revision !== value.revision.trim())) throw new Error(`${name}: ${optimizer} bridge returned an invalid upstream revision`);
1331
+ if (value.sourceSha256 !== void 0 && (typeof value.sourceSha256 !== "string" || !/^[0-9a-f]{64}$/.test(value.sourceSha256))) throw new Error(`${name}: ${optimizer} bridge returned an invalid upstream sourceSha256`);
1332
+ }
1333
+ function observedExternalOptimizerPackageSource(value) {
1334
+ return {
1335
+ kind: "package",
1336
+ evidence: "observed",
1337
+ package: value.package,
1338
+ version: value.version,
1339
+ ...value.sourceUrl ? { sourceUrl: value.sourceUrl } : {},
1340
+ ...value.revision ? { revision: value.revision } : {},
1341
+ ...value.sourceSha256 ? { sourceSha256: value.sourceSha256 } : {}
1342
+ };
1343
+ }
1344
+ //#endregion
1345
+ //#region src/campaign/external-optimizer-runtime.ts
1346
+ async function inspectExternalOptimizerRuntime(args) {
1347
+ const result = await runExternalOptimizerProcess({
1348
+ label: `${args.label} source inspection`,
1349
+ tempPrefix: `agent-eval-${args.package}-inspect-`,
1350
+ module: args.module,
1351
+ input: {
1352
+ operation: "inspect",
1353
+ engineModules: [...args.engineModules ?? []]
1354
+ },
1355
+ ...args.runner ? { runner: args.runner } : {},
1356
+ timeoutMs: args.timeoutMs,
1357
+ ...args.signal ? { signal: args.signal } : {}
1358
+ });
1359
+ assertExternalOptimizerRuntimeIdentity(result.runtime, args.package, args.label);
1360
+ return result.runtime;
1361
+ }
1362
+ function observedExternalOptimizerRuntime(runtime) {
1363
+ return {
1364
+ source: observedExternalOptimizerPackageSource(runtime.optimizer),
1365
+ bridge: observedExternalOptimizerPackageSource(runtime.bridge),
1366
+ modules: runtime.engineModules.map((module) => ({ ...module })),
1367
+ python: { ...runtime.python }
1368
+ };
1369
+ }
1370
+ function assertExternalOptimizerRunBinding(args) {
1371
+ if (!isDeepStrictEqual(args.returnedSource, args.runtime.optimizer)) throw new Error(`${args.label}: optimizer package changed after source inspection`);
1372
+ if (args.returnedRunId !== args.runId) throw new Error(`${args.label}: bridge returned a different run ID`);
1373
+ if (args.resume === "never" && args.resumed) throw new Error(`${args.label}: fresh run reported restored state`);
1374
+ if (args.resume === "required" && !args.resumed) throw new Error(`${args.label}: required resume did not restore state`);
1375
+ if (!args.runId.startsWith(args.compatibleRunId)) throw new Error(`${args.label}: run ID is not bound to its compatible identity`);
1376
+ }
1377
+ function assertExternalOptimizerRuntimeIdentity(value, expectedPackage, label) {
1378
+ if (!isRecord(value)) throw new Error(`${label}: source inspection returned no runtime identity`);
1379
+ assertExternalOptimizerPackageSource(value.bridge, "agent-eval-rpc", label, "bridge");
1380
+ assertExternalOptimizerPackageSource(value.optimizer, expectedPackage, label, expectedPackage);
1381
+ if (!value.bridge.sourceSha256 || !value.optimizer.sourceSha256) throw new Error(`${label}: source inspection omitted package source hashes`);
1382
+ if (!isRecord(value.python) || typeof value.python.implementation !== "string" || value.python.implementation.length === 0 || value.python.implementation !== value.python.implementation.trim() || typeof value.python.version !== "string" || value.python.version.length === 0 || value.python.version !== value.python.version.trim()) throw new Error(`${label}: source inspection returned an invalid Python runtime`);
1383
+ if (!Array.isArray(value.engineModules) || value.engineModules.some((module) => !isRecord(module) || typeof module.module !== "string" || module.module.length === 0 || module.module !== module.module.trim() || typeof module.sourceSha256 !== "string" || !/^[0-9a-f]{64}$/.test(module.sourceSha256))) throw new Error(`${label}: source inspection returned invalid engine modules`);
1384
+ }
1385
+ //#endregion
1314
1386
  //#region src/campaign/gepa-optimization-result.ts
1315
1387
  function assertGepaBridgeOutput(result, name, maxCandidateChars, recipeKind, maxEvaluations, maxPopulationCandidates, scenarioIds, expectsComponents, requiresCandidatePopulation) {
1316
1388
  if (result.recipeKind !== recipeKind) throw new Error(`${name}: GEPA bridge reported recipe '${String(result.recipeKind)}'`);
@@ -1733,24 +1805,7 @@ async function recordExternalSearch(input) {
1733
1805
  });
1734
1806
  }
1735
1807
  //#endregion
1736
- //#region src/campaign/gepa-optimization-method.ts
1737
- /**
1738
- * Turn an optional GEPA installation into an `OptimizationMethod`.
1739
- *
1740
- * GEPA receives only serialized train and selection cases. The caller's final
1741
- * test partition stays inside `compareOptimizationMethods`, which invokes this
1742
- * method without a test-set field. The local callback routes every candidate
1743
- * evaluation through the same dispatch and judges used by other methods.
1744
- */
1745
- /**
1746
- * Environment for a bridge child that spawns `claude` CLI subprocesses.
1747
- *
1748
- * Both agent CLI engines start the CLI with the bridge's own environment, so
1749
- * these variables travel bridge → engine → CLI. They merge AFTER
1750
- * `removeCredentialEnvironment`: the ephemeral loopback token is the only
1751
- * credential the child may see, and a caller-supplied ANTHROPIC_AUTH_TOKEN is
1752
- * stripped like any other credential.
1753
- */
1808
+ //#region src/campaign/gepa-optimization-run.ts
1754
1809
  function anthropicShimEnvironment(proxy, optimizer) {
1755
1810
  return {
1756
1811
  ANTHROPIC_BASE_URL: new URL(proxy.baseUrl).origin,
@@ -1763,370 +1818,545 @@ function anthropicShimEnvironment(proxy, optimizer) {
1763
1818
  API_TIMEOUT_MS: String((optimizer.budget.requestTimeoutMs ?? 3e5) + 6e4)
1764
1819
  };
1765
1820
  }
1766
- function gepaOptimizationMethod(config) {
1767
- assertGepaOptimizationConfig(config);
1768
- config = snapshotGepaOptimizationConfig(config);
1769
- const name = config.name ?? defaultGepaMethodName(config.recipe);
1821
+ /** Spend the optimizer booked to its own candidate generation. Unknown stays
1822
+ * unknown: the bridge reports proposer cost only when the engine measured it. */
1823
+ function optimizerAccounting(tokenUsage, proposerCostUsd) {
1824
+ return {
1825
+ tokens: tokenUsage?.inputTokens === void 0 || tokenUsage.outputTokens === void 0 ? {
1826
+ status: "unknown",
1827
+ reason: "the optimizer bridge reported no token usage"
1828
+ } : {
1829
+ status: "known",
1830
+ inputTokens: tokenUsage.inputTokens,
1831
+ outputTokens: tokenUsage.outputTokens,
1832
+ cachedTokens: 0
1833
+ },
1834
+ cost: proposerCostUsd === void 0 ? {
1835
+ status: "unknown",
1836
+ knownLowerBoundUsd: 0,
1837
+ reason: "the optimizer bridge reported no proposer cost"
1838
+ } : {
1839
+ status: "known",
1840
+ usd: proposerCostUsd,
1841
+ source: "provider"
1842
+ }
1843
+ };
1844
+ }
1845
+ /** What the GEPA run key is hashed over; fields added later join only when enabled so earlier run keys keep their identity. */
1846
+ function gepaRunMaterial(config, input, parts) {
1847
+ const { name, runtimeIdentity, bridgeRunner, seedCandidate, trainSet, selectionSet, maxCandidateChars, maxPopulationCandidates, maxEvidenceChars } = parts;
1770
1848
  return {
1849
+ optimizer: "gepa",
1850
+ runtime: runtimeIdentity,
1851
+ method: name,
1852
+ evaluationId: config.evaluationId,
1853
+ dispatchRef: input.runOptions.dispatchRef ?? null,
1854
+ seed: input.seed,
1855
+ recipe: snapshotJson(config.recipe, "GEPA run settings"),
1856
+ engineModules: config.engineModules ?? [],
1857
+ objective: config.objective,
1858
+ background: config.background ?? "",
1859
+ seedCandidate,
1860
+ trainSet,
1861
+ selectionSet,
1862
+ maxCandidateChars,
1863
+ maxPopulationCandidates,
1864
+ maxEvidenceChars,
1865
+ evaluationCallbackLimits: resolveExternalOptimizerCallbackLimits(config.evaluationCallbackLimits),
1866
+ optimizerModel: config.optimizer ? {
1867
+ model: config.optimizer.model,
1868
+ callRef: config.optimizer.callRef,
1869
+ budget: config.optimizer.budget,
1870
+ ...config.optimizer.anthropicEndpoint === true ? { anthropicEndpoint: true } : {}
1871
+ } : null,
1872
+ runner: externalOptimizerRunnerIdentity(bridgeRunner, "agent_eval_rpc.gepa_bridge"),
1873
+ trustResumeState: config.trustResumeState === true
1874
+ };
1875
+ }
1876
+ /** Starts the callback server the GEPA bridge calls back into: evaluations are counted against the run budget and observed into the log. */
1877
+ async function startGepaCallback(config, input, parts) {
1878
+ const { runDir, runId, runBudget, observationLog, evaluationLimit, maxCandidateChars, maxEvidenceChars } = parts;
1879
+ const signal = input.runOptions.signal;
1880
+ const scenarioById = mapExternalScenarios(input.trainScenarios, input.selectionScenarios, "GEPA bridge");
1881
+ const evaluate = createExternalTextEvaluator({
1882
+ input,
1883
+ label: "GEPA bridge",
1884
+ runDir,
1885
+ compatibleRunId: runId,
1886
+ costPhase: "gepa.external-evaluation",
1887
+ costTags: runBudget.attemptTags,
1888
+ costLedger: input.costLedger,
1889
+ scenarioById,
1890
+ maxCandidateChars,
1891
+ maxEvidenceChars,
1892
+ describeArtifact: config.describeArtifact
1893
+ });
1894
+ let attemptEvaluationCount = 0;
1895
+ return startExternalOptimizerCallback({
1896
+ token: randomBytes(32).toString("hex"),
1897
+ maxEvaluations: evaluationLimit,
1898
+ acceptEvaluation: () => {
1899
+ if (runBudget.acceptEvaluation() === void 0) return void 0;
1900
+ attemptEvaluationCount += 1;
1901
+ return attemptEvaluationCount;
1902
+ },
1903
+ evaluate,
1904
+ observe: observationLog.observe,
1905
+ ...config.evaluationCallbackLimits ? { limits: config.evaluationCallbackLimits } : {},
1906
+ ...signal ? { signal } : {}
1907
+ });
1908
+ }
1909
+ /** The settled inputs of one GEPA run: its identity, budgets, evaluation callback and logs. */
1910
+ async function prepareGepaRun(config, input, name) {
1911
+ const signal = input.runOptions.signal;
1912
+ signal?.throwIfAborted();
1913
+ if (typeof input.baselineSurface !== "string" && input.baselineSurface.kind !== "components") throw new Error(`${name}: GEPA bridge supports text and component surfaces`);
1914
+ const expectsComponents = typeof input.baselineSurface !== "string";
1915
+ if (expectsComponents) assertGepaComponentRecipe(config.recipe, name);
1916
+ const started = Date.now();
1917
+ const maxCandidateChars = config.maxCandidateChars ?? 2e5;
1918
+ const maxEvidenceChars = config.maxEvidenceChars ?? 1e5;
1919
+ const timeoutMs = config.timeoutMs ?? 18e5;
1920
+ const storage = input.runOptions.storage ?? fsCampaignStorage();
1921
+ const runDir = `${input.runDir}/gepa`;
1922
+ storage.ensureDir(runDir);
1923
+ const costLedger = input.costLedger;
1924
+ const attemptId = randomBytes(16).toString("hex");
1925
+ const resume = config.resume ?? "never";
1926
+ const bridgeRunner = config.optimizer && config.runner ? {
1927
+ ...config.runner,
1928
+ env: removeCredentialEnvironment(config.runner.env ?? {})
1929
+ } : config.runner;
1930
+ const runtimeIdentity = await inspectExternalOptimizerRuntime({
1931
+ label: name,
1932
+ package: "gepa",
1933
+ module: "agent_eval_rpc.gepa_bridge",
1934
+ engineModules: config.engineModules,
1935
+ ...bridgeRunner ? { runner: bridgeRunner } : {},
1936
+ timeoutMs,
1937
+ ...signal ? { signal } : {}
1938
+ });
1939
+ const seedCandidate = encodeExternalTextCandidate(input.baselineSurface);
1940
+ const trainSet = input.trainScenarios.map((scenario) => describeExternalScenario(scenario, "GEPA", maxEvidenceChars, config.describeScenario));
1941
+ const selectionSet = input.selectionScenarios.map((scenario) => describeExternalScenario(scenario, "GEPA", maxEvidenceChars, config.describeScenario));
1942
+ const evaluationLimit = gepaRecipeEvaluationLimit(config.recipe, input.selectionScenarios.length);
1943
+ const maxPopulationCandidates = Math.min(Number.MAX_SAFE_INTEGER, evaluationLimit + 1);
1944
+ const populationScenarioIds = (selectionSet.length > 0 ? selectionSet : trainSet).map((scenario) => scenario.id);
1945
+ const runMaterial = gepaRunMaterial(config, input, {
1771
1946
  name,
1772
- async optimize(input) {
1773
- const signal = input.runOptions.signal;
1774
- signal?.throwIfAborted();
1775
- if (typeof input.baselineSurface !== "string" && input.baselineSurface.kind !== "components") throw new Error(`${name}: GEPA bridge supports text and component surfaces`);
1776
- const expectsComponents = typeof input.baselineSurface !== "string";
1777
- if (expectsComponents) assertGepaComponentRecipe(config.recipe, name);
1778
- const started = Date.now();
1779
- const maxCandidateChars = config.maxCandidateChars ?? 2e5;
1780
- const maxEvidenceChars = config.maxEvidenceChars ?? 1e5;
1781
- const timeoutMs = config.timeoutMs ?? 18e5;
1782
- const storage = input.runOptions.storage ?? fsCampaignStorage();
1783
- const runDir = `${input.runDir}/gepa`;
1784
- storage.ensureDir(runDir);
1785
- const costLedger = input.costLedger;
1786
- const attemptId = randomBytes(16).toString("hex");
1787
- const resume = config.resume ?? "never";
1788
- const bridgeRunner = config.optimizer && config.runner ? {
1789
- ...config.runner,
1790
- env: removeCredentialEnvironment(config.runner.env ?? {})
1791
- } : config.runner;
1792
- const runtimeIdentity = await inspectExternalOptimizerRuntime({
1793
- label: name,
1794
- package: "gepa",
1795
- module: "agent_eval_rpc.gepa_bridge",
1796
- engineModules: config.engineModules,
1797
- ...bridgeRunner ? { runner: bridgeRunner } : {},
1798
- timeoutMs,
1799
- ...signal ? { signal } : {}
1800
- });
1801
- const seedCandidate = encodeExternalTextCandidate(input.baselineSurface);
1802
- const trainSet = input.trainScenarios.map((scenario) => describeExternalScenario(scenario, "GEPA", maxEvidenceChars, config.describeScenario));
1803
- const selectionSet = input.selectionScenarios.map((scenario) => describeExternalScenario(scenario, "GEPA", maxEvidenceChars, config.describeScenario));
1804
- const evaluationLimit = gepaRecipeEvaluationLimit(config.recipe, input.selectionScenarios.length);
1805
- const maxPopulationCandidates = Math.min(Number.MAX_SAFE_INTEGER, evaluationLimit + 1);
1806
- const populationScenarioIds = (selectionSet.length > 0 ? selectionSet : trainSet).map((scenario) => scenario.id);
1807
- const runMaterial = {
1808
- optimizer: "gepa",
1809
- runtime: runtimeIdentity,
1810
- method: name,
1811
- evaluationId: config.evaluationId,
1812
- dispatchRef: input.runOptions.dispatchRef ?? null,
1813
- seed: input.seed,
1814
- recipe: snapshotJson(config.recipe, "GEPA run settings"),
1815
- engineModules: config.engineModules ?? [],
1816
- objective: config.objective,
1817
- background: config.background ?? "",
1818
- seedCandidate,
1819
- trainSet,
1820
- selectionSet,
1821
- maxCandidateChars,
1822
- maxPopulationCandidates,
1823
- maxEvidenceChars,
1824
- evaluationCallbackLimits: resolveExternalOptimizerCallbackLimits(config.evaluationCallbackLimits),
1825
- optimizerModel: config.optimizer ? {
1826
- model: config.optimizer.model,
1947
+ runtimeIdentity,
1948
+ bridgeRunner,
1949
+ seedCandidate,
1950
+ trainSet,
1951
+ selectionSet,
1952
+ maxCandidateChars,
1953
+ maxPopulationCandidates,
1954
+ maxEvidenceChars
1955
+ });
1956
+ const compatibleRunId = externalOptimizerCompatibleRunKey(runMaterial);
1957
+ const runId = externalOptimizerRunKey({
1958
+ material: runMaterial,
1959
+ attemptId,
1960
+ resumeEnabled: resume !== "never" && gepaRecipeSupportsResume(config.recipe)
1961
+ });
1962
+ const runBudget = openExternalOptimizerRunBudget({
1963
+ storage,
1964
+ runDir,
1965
+ runKey: runId,
1966
+ attemptId,
1967
+ maxEvaluations: evaluationLimit
1968
+ });
1969
+ const observationLog = openExternalOptimizerObservationLog({
1970
+ storage,
1971
+ path: `${runDir}/observations-${attemptId}.jsonl`
1972
+ });
1973
+ return {
1974
+ signal,
1975
+ expectsComponents,
1976
+ started,
1977
+ maxCandidateChars,
1978
+ maxEvidenceChars,
1979
+ timeoutMs,
1980
+ storage,
1981
+ runDir,
1982
+ costLedger,
1983
+ attemptId,
1984
+ resume,
1985
+ bridgeRunner,
1986
+ runtimeIdentity,
1987
+ seedCandidate,
1988
+ trainSet,
1989
+ selectionSet,
1990
+ evaluationLimit,
1991
+ maxPopulationCandidates,
1992
+ populationScenarioIds,
1993
+ compatibleRunId,
1994
+ runId,
1995
+ runBudget,
1996
+ observationLog,
1997
+ executionLog: config.optimizer ? openExternalOptimizerExecutionLog({
1998
+ storage,
1999
+ path: `${runDir}/model-executions-${attemptId}.jsonl`
2000
+ }) : void 0,
2001
+ callback: await startGepaCallback(config, input, {
2002
+ runDir,
2003
+ runId,
2004
+ runBudget,
2005
+ observationLog,
2006
+ evaluationLimit,
2007
+ maxCandidateChars,
2008
+ maxEvidenceChars
2009
+ }),
2010
+ name,
2011
+ config,
2012
+ input
2013
+ };
2014
+ }
2015
+ /** Start the optimizer model proxy when one is configured, run the GEPA bridge, and release the resources either way. */
2016
+ async function runBridge(ctx) {
2017
+ const { signal, maxCandidateChars, maxEvidenceChars, timeoutMs, runDir, costLedger, attemptId, resume, bridgeRunner, runtimeIdentity, seedCandidate, trainSet, selectionSet, maxPopulationCandidates, compatibleRunId, runId, runBudget, executionLog, callback, name, config, input } = ctx;
2018
+ const runnerEnv = bridgeRunner?.env ?? {};
2019
+ let modelProxy;
2020
+ const bridgeRunnerForSpawn = () => {
2021
+ if (!modelProxy) return bridgeRunner;
2022
+ const anthropicChildEnv = config.optimizer?.anthropicEndpoint === true && gepaRecipeHasAgentCliEngine(config.recipe) ? anthropicShimEnvironment(modelProxy, config.optimizer) : void 0;
2023
+ if (!bridgeRunner && !anthropicChildEnv) return bridgeRunner;
2024
+ return {
2025
+ ...bridgeRunner ?? {},
2026
+ env: {
2027
+ ...removeCredentialEnvironment(runnerEnv),
2028
+ ...anthropicChildEnv ?? {}
2029
+ }
2030
+ };
2031
+ };
2032
+ const closeResources = () => closeExternalOptimizerResources({
2033
+ label: name,
2034
+ callback,
2035
+ ...modelProxy ? { modelProxy } : {}
2036
+ });
2037
+ const { result, outputDir } = await runWithCleanup({
2038
+ label: `${name} optimizer resources`,
2039
+ run: async () => {
2040
+ if (config.optimizer) {
2041
+ const priorOptimizerUsage = costLedger.summary({
2042
+ phase: "gepa.optimizer-model",
2043
+ tags: runBudget.runTags
2044
+ });
2045
+ assertPriorExternalOptimizerUsage(priorOptimizerUsage, config.optimizer.budget, name);
2046
+ modelProxy = await startExternalOptimizerModelProxy({
2047
+ call: config.optimizer.call,
1827
2048
  callRef: config.optimizer.callRef,
2049
+ recordExecution: executionLog.observe,
2050
+ model: config.optimizer.model,
1828
2051
  budget: config.optimizer.budget,
1829
- ...config.optimizer.anthropicEndpoint === true ? { anthropicEndpoint: true } : {}
1830
- } : null,
1831
- runner: externalOptimizerRunnerIdentity(bridgeRunner, "agent_eval_rpc.gepa_bridge"),
1832
- trustResumeState: config.trustResumeState === true
1833
- };
1834
- const compatibleRunId = externalOptimizerCompatibleRunKey(runMaterial);
1835
- const runId = externalOptimizerRunKey({
1836
- material: runMaterial,
1837
- attemptId,
1838
- resumeEnabled: resume !== "never" && gepaRecipeSupportsResume(config.recipe)
1839
- });
1840
- const runBudget = openExternalOptimizerRunBudget({
1841
- storage,
1842
- runDir,
1843
- runKey: runId,
1844
- attemptId,
1845
- maxEvaluations: evaluationLimit
1846
- });
1847
- const observationLog = openExternalOptimizerObservationLog({
1848
- storage,
1849
- path: `${runDir}/observations-${attemptId}.jsonl`
1850
- });
1851
- const executionLog = config.optimizer ? openExternalOptimizerExecutionLog({
1852
- storage,
1853
- path: `${runDir}/model-executions-${attemptId}.jsonl`
1854
- }) : void 0;
1855
- const scenarioById = mapExternalScenarios(input.trainScenarios, input.selectionScenarios, "GEPA bridge");
1856
- const evaluate = createExternalTextEvaluator({
1857
- input,
1858
- label: "GEPA bridge",
1859
- runDir,
1860
- compatibleRunId: runId,
1861
- costPhase: "gepa.external-evaluation",
1862
- costTags: runBudget.attemptTags,
1863
- costLedger,
1864
- scenarioById,
1865
- maxCandidateChars,
1866
- maxEvidenceChars,
1867
- describeArtifact: config.describeArtifact
1868
- });
1869
- let attemptEvaluationCount = 0;
1870
- const callback = await startExternalOptimizerCallback({
1871
- token: randomBytes(32).toString("hex"),
1872
- maxEvaluations: evaluationLimit,
1873
- acceptEvaluation: () => {
1874
- if (runBudget.acceptEvaluation() === void 0) return void 0;
1875
- attemptEvaluationCount += 1;
1876
- return attemptEvaluationCount;
1877
- },
1878
- evaluate,
1879
- observe: observationLog.observe,
1880
- ...config.evaluationCallbackLimits ? { limits: config.evaluationCallbackLimits } : {},
1881
- ...signal ? { signal } : {}
1882
- });
1883
- const runnerEnv = bridgeRunner?.env ?? {};
1884
- let modelProxy;
1885
- const bridgeRunnerForSpawn = () => {
1886
- if (!modelProxy) return bridgeRunner;
1887
- const anthropicChildEnv = config.optimizer?.anthropicEndpoint === true && gepaRecipeHasAgentCliEngine(config.recipe) ? anthropicShimEnvironment(modelProxy, config.optimizer) : void 0;
1888
- if (!bridgeRunner && !anthropicChildEnv) return bridgeRunner;
1889
- return {
1890
- ...bridgeRunner ?? {},
1891
- env: {
1892
- ...removeCredentialEnvironment(runnerEnv),
1893
- ...anthropicChildEnv ?? {}
1894
- }
1895
- };
1896
- };
1897
- const closeResources = () => closeExternalOptimizerResources({
1898
- label: name,
1899
- callback,
1900
- ...modelProxy ? { modelProxy } : {}
1901
- });
1902
- const { result, outputDir } = await runWithCleanup({
1903
- label: `${name} optimizer resources`,
1904
- run: async () => {
1905
- if (config.optimizer) {
1906
- const priorOptimizerUsage = costLedger.summary({
1907
- phase: "gepa.optimizer-model",
1908
- tags: runBudget.runTags
1909
- });
1910
- assertPriorExternalOptimizerUsage(priorOptimizerUsage, config.optimizer.budget, name);
1911
- modelProxy = await startExternalOptimizerModelProxy({
1912
- call: config.optimizer.call,
1913
- callRef: config.optimizer.callRef,
1914
- recordExecution: executionLog.observe,
1915
- model: config.optimizer.model,
1916
- budget: config.optimizer.budget,
1917
- ...config.optimizer.servedModelPolicy ? { servedModelPolicy: config.optimizer.servedModelPolicy } : {},
1918
- ...config.optimizer.anthropicEndpoint === true ? { anthropicEndpoint: true } : {},
1919
- costLedger,
1920
- phase: "gepa.optimizer-model",
1921
- actor: name,
1922
- tags: { ...runBudget.attemptTags },
1923
- initialUsage: {
1924
- requests: priorOptimizerUsage.totalCalls,
1925
- ...priorOptimizerUsage.costProvenance.kind === "uncaptured" ? {} : { costUsd: priorOptimizerUsage.totalCostUsd }
1926
- },
1927
- ...signal ? { signal } : {}
1928
- });
1929
- }
1930
- const outputDir = `${runDir}/external`;
1931
- await mkdir(outputDir, { recursive: true });
1932
- return {
1933
- result: await runExternalOptimizerProcess({
1934
- label: "GEPA bridge",
1935
- tempPrefix: "agent-eval-gepa-",
1936
- module: "agent_eval_rpc.gepa_bridge",
1937
- input: {
1938
- attemptId,
1939
- compatibleRunId,
1940
- runId,
1941
- runtimeIdentity,
1942
- resume,
1943
- trustedResumeState: config.trustResumeState === true,
1944
- evaluationId: config.evaluationId,
1945
- seed: input.seed,
1946
- callbackUrl: callback.url,
1947
- callbackToken: callback.token,
1948
- timeoutMs,
1949
- engineModules: config.engineModules ?? [],
1950
- recipe: config.recipe,
1951
- objective: config.objective,
1952
- ...config.background ? { background: config.background } : {},
1953
- seedCandidate,
1954
- trainSet,
1955
- selectionSet,
1956
- maxCandidateChars,
1957
- maxPopulationCandidates,
1958
- maxEvidenceChars,
1959
- outputDir,
1960
- ...modelProxy && config.optimizer ? { modelProxy: {
1961
- baseUrl: modelProxy.baseUrl,
1962
- apiKey: modelProxy.apiKey,
1963
- model: config.optimizer.model,
1964
- budget: config.optimizer.budget,
1965
- ...config.optimizer.anthropicEndpoint === true ? { anthropicEndpoint: true } : {}
1966
- } } : {}
1967
- },
1968
- runner: bridgeRunnerForSpawn(),
1969
- timeoutMs,
1970
- ...signal ? { signal } : {}
1971
- }),
1972
- outputDir
1973
- };
1974
- },
1975
- cleanup: closeResources
1976
- });
1977
- signal?.throwIfAborted();
1978
- assertGepaBridgeOutput(result, name, maxCandidateChars, config.recipe.kind, evaluationLimit, maxPopulationCandidates, populationScenarioIds, expectsComponents, config.recipe.kind === "engine" && config.recipe.run.engine === "gepa");
1979
- assertExternalOptimizerRunBinding({
1980
- label: name,
1981
- runtime: runtimeIdentity,
1982
- returnedSource: result.upstream,
1983
- compatibleRunId,
1984
- runId,
1985
- returnedRunId: result.runId,
1986
- resume,
1987
- resumed: result.resumed
1988
- });
1989
- if (callback.evaluations() !== result.totalEvaluations) throw new Error(`${name}: GEPA reported ${result.totalEvaluations} evaluations but the callback received ${callback.evaluations()}`);
1990
- const population = result.candidatePopulation ? readGepaCandidatePopulationArtifact({
1991
- summary: result.candidatePopulation,
1992
- storage
1993
- }) : null;
1994
- if (population) {
1995
- const selected = population.candidates[population.bestIndex];
1996
- const selectedHash = contentHash({
1997
- kind: "external-text-candidate",
1998
- candidate: result.bestCandidate
2052
+ ...config.optimizer.servedModelPolicy ? { servedModelPolicy: config.optimizer.servedModelPolicy } : {},
2053
+ ...config.optimizer.anthropicEndpoint === true ? { anthropicEndpoint: true } : {},
2054
+ costLedger,
2055
+ phase: "gepa.optimizer-model",
2056
+ actor: name,
2057
+ tags: { ...runBudget.attemptTags },
2058
+ initialUsage: {
2059
+ requests: priorOptimizerUsage.totalCalls,
2060
+ ...priorOptimizerUsage.costProvenance.kind === "uncaptured" ? {} : { costUsd: priorOptimizerUsage.totalCostUsd }
2061
+ },
2062
+ ...signal ? { signal } : {}
1999
2063
  });
2000
- if (selected?.candidateHash !== selectedHash) throw new Error(`${name}: GEPA candidate population identifies a different winner`);
2001
2064
  }
2002
- const searchHistory = config.searchLedger ? await recordGepaSearch({
2003
- name,
2004
- path: config.searchLedger.path ?? `${runDir}/search-ledger.jsonl`,
2005
- searchId: runId,
2006
- identity: config.searchLedger.identity,
2007
- storage,
2008
- seed: input.seed,
2009
- baselineSurface: input.baselineSurface,
2010
- trainScenarios: input.trainScenarios,
2011
- selectionScenarios: input.selectionScenarios,
2012
- evaluationLimit,
2013
- ...population ? { population } : {
2014
- population: null,
2015
- selected: decodeExternalTextCandidate(result.bestCandidate)
2016
- },
2017
- observations: readExternalOptimizerObservationArtifact({
2018
- summary: observationLog.summary(),
2019
- storage
2020
- }),
2021
- generationAccounting: optimizerAccounting(result.tokenUsage, result.proposerCostUsd)
2022
- }) : void 0;
2023
- const evaluationCost = costFromLedgerSummary(costLedger.summary({
2024
- phase: "gepa.external-evaluation",
2025
- tags: runBudget.runTags
2026
- }));
2027
- const optimizerSummary = costLedger.summary({
2028
- phase: "gepa.optimizer-model",
2029
- tags: runBudget.runTags
2030
- });
2031
- const optimizerReceipts = costLedger.list({
2032
- phase: "gepa.optimizer-model",
2033
- tags: runBudget.runTags
2034
- });
2035
- const optimizerCost = costFromLedgerSummary(optimizerSummary);
2036
- const reportedProposerCost = result.proposerCostUsd ?? 0;
2037
- if (modelProxy) {
2038
- modelProxy.assertExecutionComplete();
2039
- const wires = modelProxy.wireUsage();
2040
- assertExternalOptimizerCompletionCount(result.tokenUsage, wires.openai.requestAttempts, wires.openai.successfulCompletions, name, "GEPA");
2041
- if (config.optimizer?.anthropicEndpoint === true) {
2042
- const anthropicReceipts = costLedger.list({
2043
- phase: "gepa.optimizer-model",
2044
- tags: {
2045
- ...runBudget.attemptTags,
2046
- wire: "anthropic"
2047
- }
2048
- });
2049
- if (anthropicReceipts.length !== wires.anthropic.requestAttempts) throw new Error(`${name}: the Anthropic endpoint admitted ${wires.anthropic.requestAttempts} model calls but the ledger holds ${anthropicReceipts.length} receipts`);
2050
- }
2051
- }
2052
- const tokenUsage = modelProxy ? optimizationTokenUsageFromSummary(optimizerSummary, optimizerReceipts) : void 0;
2053
- const runtime = observedExternalOptimizerRuntime(runtimeIdentity);
2054
- const meteredCost = modelProxy ? combineComparisonCosts([{
2055
- label: "evaluation",
2056
- cost: evaluationCost
2057
- }, {
2058
- label: "optimizer model",
2059
- cost: optimizerCost
2060
- }]) : void 0;
2061
- const externalTotalCostUsd = evaluationCost.totalCostUsd + reportedProposerCost;
2065
+ const outputDir = `${runDir}/external`;
2066
+ await mkdir(outputDir, { recursive: true });
2062
2067
  return {
2063
- winnerSurface: decodeExternalTextCandidate(result.bestCandidate),
2064
- ...searchHistory ? { searchHistory } : {},
2065
- cost: modelProxy ? meteredCost : {
2066
- totalCostUsd: externalTotalCostUsd,
2067
- costProvenance: result.proposerCostAccounting === "reported" && evaluationCost.costProvenance.kind !== "uncaptured" ? {
2068
- kind: "estimated",
2069
- usd: externalTotalCostUsd
2070
- } : {
2071
- kind: "uncaptured",
2072
- usd: null
2068
+ result: await runExternalOptimizerProcess({
2069
+ label: "GEPA bridge",
2070
+ tempPrefix: "agent-eval-gepa-",
2071
+ module: "agent_eval_rpc.gepa_bridge",
2072
+ input: {
2073
+ attemptId,
2074
+ compatibleRunId,
2075
+ runId,
2076
+ runtimeIdentity,
2077
+ resume,
2078
+ trustedResumeState: config.trustResumeState === true,
2079
+ evaluationId: config.evaluationId,
2080
+ seed: input.seed,
2081
+ callbackUrl: callback.url,
2082
+ callbackToken: callback.token,
2083
+ timeoutMs,
2084
+ engineModules: config.engineModules ?? [],
2085
+ recipe: config.recipe,
2086
+ objective: config.objective,
2087
+ ...config.background ? { background: config.background } : {},
2088
+ seedCandidate,
2089
+ trainSet,
2090
+ selectionSet,
2091
+ maxCandidateChars,
2092
+ maxPopulationCandidates,
2093
+ maxEvidenceChars,
2094
+ outputDir,
2095
+ ...modelProxy && config.optimizer ? { modelProxy: {
2096
+ baseUrl: modelProxy.baseUrl,
2097
+ apiKey: modelProxy.apiKey,
2098
+ model: config.optimizer.model,
2099
+ budget: config.optimizer.budget,
2100
+ ...config.optimizer.anthropicEndpoint === true ? { anthropicEndpoint: true } : {}
2101
+ } } : {}
2073
2102
  },
2074
- accountingComplete: false,
2075
- incompleteReasons: [
2076
- ...evaluationCost.incompleteReasons,
2077
- result.proposerCostAccounting === "reported" ? "GEPA proposer cost is externally reported and has no agent-eval receipt" : "GEPA proposer cost is unavailable",
2078
- ...result.resumed ? ["GEPA proposer cost before this resumed attempt is unavailable"] : []
2079
- ]
2080
- },
2081
- durationMs: Date.now() - started,
2082
- provenance: {
2083
- ...runtime,
2084
- ...config.optimizer ? {
2085
- optimizerModel: config.optimizer.model,
2086
- optimizerCallRef: config.optimizer.callRef
2087
- } : {},
2088
- ...modelProxy && config.optimizer?.anthropicEndpoint === true ? { anthropicEndpoint: modelProxy.wireUsage().anthropic } : {},
2089
- compatibleRunId,
2090
- runId,
2091
- resumed: result.resumed,
2092
- seedApplied: result.seedApplied,
2093
- evaluationCount: runBudget.acceptedEvaluations(),
2094
- ...result.upstreamReportedEvaluations !== void 0 ? { upstreamReportedEvaluations: result.upstreamReportedEvaluations } : {},
2095
- artifactDir: outputDir,
2096
- ...tokenUsage ? { tokenUsage } : {},
2097
- observations: observationLog.summary(),
2098
- ...result.candidatePopulation ? { gepaCandidatePopulation: result.candidatePopulation } : {},
2099
- ...executionLog ? { modelExecutions: executionLog.summary() } : {}
2100
- }
2103
+ runner: bridgeRunnerForSpawn(),
2104
+ timeoutMs,
2105
+ ...signal ? { signal } : {}
2106
+ }),
2107
+ outputDir
2101
2108
  };
2109
+ },
2110
+ cleanup: closeResources
2111
+ });
2112
+ return {
2113
+ result,
2114
+ outputDir,
2115
+ modelProxy
2116
+ };
2117
+ }
2118
+ /** Check the bridge output against the run it was started for, and return the candidate population it reports. */
2119
+ function verifyBridgeResult(ctx, result) {
2120
+ const { signal, expectsComponents, maxCandidateChars, storage, resume, runtimeIdentity, evaluationLimit, maxPopulationCandidates, populationScenarioIds, compatibleRunId, runId, callback, name, config } = ctx;
2121
+ signal?.throwIfAborted();
2122
+ assertGepaBridgeOutput(result, name, maxCandidateChars, config.recipe.kind, evaluationLimit, maxPopulationCandidates, populationScenarioIds, expectsComponents, config.recipe.kind === "engine" && config.recipe.run.engine === "gepa");
2123
+ assertExternalOptimizerRunBinding({
2124
+ label: name,
2125
+ runtime: runtimeIdentity,
2126
+ returnedSource: result.upstream,
2127
+ compatibleRunId,
2128
+ runId,
2129
+ returnedRunId: result.runId,
2130
+ resume,
2131
+ resumed: result.resumed
2132
+ });
2133
+ if (callback.evaluations() !== result.totalEvaluations) throw new Error(`${name}: GEPA reported ${result.totalEvaluations} evaluations but the callback received ${callback.evaluations()}`);
2134
+ const population = result.candidatePopulation ? readGepaCandidatePopulationArtifact({
2135
+ summary: result.candidatePopulation,
2136
+ storage
2137
+ }) : null;
2138
+ if (population) {
2139
+ const selected = population.candidates[population.bestIndex];
2140
+ const selectedHash = contentHash({
2141
+ kind: "external-text-candidate",
2142
+ candidate: result.bestCandidate
2143
+ });
2144
+ if (selected?.candidateHash !== selectedHash) throw new Error(`${name}: GEPA candidate population identifies a different winner`);
2145
+ }
2146
+ return population;
2147
+ }
2148
+ /** Every recipe records its search in the search ledger when one is configured. */
2149
+ async function recordGepaSearchHistory(ctx, result, population) {
2150
+ const { storage, runDir, evaluationLimit, runId, observationLog, name, config, input } = ctx;
2151
+ return config.searchLedger ? await recordGepaSearch({
2152
+ name,
2153
+ path: config.searchLedger.path ?? `${runDir}/search-ledger.jsonl`,
2154
+ searchId: runId,
2155
+ identity: config.searchLedger.identity,
2156
+ storage,
2157
+ seed: input.seed,
2158
+ baselineSurface: input.baselineSurface,
2159
+ trainScenarios: input.trainScenarios,
2160
+ selectionScenarios: input.selectionScenarios,
2161
+ evaluationLimit,
2162
+ ...population ? { population } : {
2163
+ population: null,
2164
+ selected: decodeExternalTextCandidate(result.bestCandidate)
2165
+ },
2166
+ observations: readExternalOptimizerObservationArtifact({
2167
+ summary: observationLog.summary(),
2168
+ storage
2169
+ }),
2170
+ generationAccounting: optimizerAccounting(result.tokenUsage, result.proposerCostUsd)
2171
+ }) : void 0;
2172
+ }
2173
+ /** Evaluation and optimizer-model cost, with the proxy's completeness checks. */
2174
+ function gepaCosts(ctx, result, modelProxy) {
2175
+ const { costLedger, runtimeIdentity, runBudget, name, config } = ctx;
2176
+ const evaluationCost = costFromLedgerSummary(costLedger.summary({
2177
+ phase: "gepa.external-evaluation",
2178
+ tags: runBudget.runTags
2179
+ }));
2180
+ const optimizerSummary = costLedger.summary({
2181
+ phase: "gepa.optimizer-model",
2182
+ tags: runBudget.runTags
2183
+ });
2184
+ const optimizerReceipts = costLedger.list({
2185
+ phase: "gepa.optimizer-model",
2186
+ tags: runBudget.runTags
2187
+ });
2188
+ const optimizerCost = costFromLedgerSummary(optimizerSummary);
2189
+ const reportedProposerCost = result.proposerCostUsd ?? 0;
2190
+ if (modelProxy) {
2191
+ modelProxy.assertExecutionComplete();
2192
+ const wires = modelProxy.wireUsage();
2193
+ assertExternalOptimizerCompletionCount(result.tokenUsage, wires.openai.requestAttempts, wires.openai.successfulCompletions, name, "GEPA");
2194
+ if (config.optimizer?.anthropicEndpoint === true) {
2195
+ const anthropicReceipts = costLedger.list({
2196
+ phase: "gepa.optimizer-model",
2197
+ tags: {
2198
+ ...runBudget.attemptTags,
2199
+ wire: "anthropic"
2200
+ }
2201
+ });
2202
+ if (anthropicReceipts.length !== wires.anthropic.requestAttempts) throw new Error(`${name}: the Anthropic endpoint admitted ${wires.anthropic.requestAttempts} model calls but the ledger holds ${anthropicReceipts.length} receipts`);
2102
2203
  }
2204
+ }
2205
+ return {
2206
+ evaluationCost,
2207
+ tokenUsage: modelProxy ? optimizationTokenUsageFromSummary(optimizerSummary, optimizerReceipts) : void 0,
2208
+ runtime: observedExternalOptimizerRuntime(runtimeIdentity),
2209
+ meteredCost: modelProxy ? combineComparisonCosts([{
2210
+ label: "evaluation",
2211
+ cost: evaluationCost
2212
+ }, {
2213
+ label: "optimizer model",
2214
+ cost: optimizerCost
2215
+ }]) : void 0,
2216
+ externalTotalCostUsd: evaluationCost.totalCostUsd + reportedProposerCost
2103
2217
  };
2104
2218
  }
2105
- /** Spend the optimizer booked to its own candidate generation. Unknown stays
2106
- * unknown: the bridge reports proposer cost only when the engine measured it. */
2107
- function optimizerAccounting(tokenUsage, proposerCostUsd) {
2219
+ /** The method result: the winning surface, its cost and the provenance of the run. */
2220
+ function buildGepaOutcome(ctx, result, outputDir, modelProxy, searchHistory, costs) {
2221
+ const { started, compatibleRunId, runId, runBudget, observationLog, executionLog, config } = ctx;
2222
+ const { evaluationCost, tokenUsage, runtime, meteredCost, externalTotalCostUsd } = costs;
2108
2223
  return {
2109
- tokens: tokenUsage?.inputTokens === void 0 || tokenUsage.outputTokens === void 0 ? {
2110
- status: "unknown",
2111
- reason: "the optimizer bridge reported no token usage"
2112
- } : {
2113
- status: "known",
2114
- inputTokens: tokenUsage.inputTokens,
2115
- outputTokens: tokenUsage.outputTokens,
2116
- cachedTokens: 0
2224
+ winnerSurface: decodeExternalTextCandidate(result.bestCandidate),
2225
+ ...searchHistory ? { searchHistory } : {},
2226
+ cost: modelProxy ? meteredCost : {
2227
+ totalCostUsd: externalTotalCostUsd,
2228
+ costProvenance: result.proposerCostAccounting === "reported" && evaluationCost.costProvenance.kind !== "uncaptured" ? {
2229
+ kind: "estimated",
2230
+ usd: externalTotalCostUsd
2231
+ } : {
2232
+ kind: "uncaptured",
2233
+ usd: null
2234
+ },
2235
+ accountingComplete: false,
2236
+ incompleteReasons: [
2237
+ ...evaluationCost.incompleteReasons,
2238
+ result.proposerCostAccounting === "reported" ? "GEPA proposer cost is externally reported and has no agent-eval receipt" : "GEPA proposer cost is unavailable",
2239
+ ...result.resumed ? ["GEPA proposer cost before this resumed attempt is unavailable"] : []
2240
+ ]
2117
2241
  },
2118
- cost: proposerCostUsd === void 0 ? {
2119
- status: "unknown",
2120
- knownLowerBoundUsd: 0,
2121
- reason: "the optimizer bridge reported no proposer cost"
2122
- } : {
2123
- status: "known",
2124
- usd: proposerCostUsd,
2125
- source: "provider"
2242
+ durationMs: Date.now() - started,
2243
+ provenance: {
2244
+ ...runtime,
2245
+ ...config.optimizer ? {
2246
+ optimizerModel: config.optimizer.model,
2247
+ optimizerCallRef: config.optimizer.callRef
2248
+ } : {},
2249
+ ...modelProxy && config.optimizer?.anthropicEndpoint === true ? { anthropicEndpoint: modelProxy.wireUsage().anthropic } : {},
2250
+ compatibleRunId,
2251
+ runId,
2252
+ resumed: result.resumed,
2253
+ seedApplied: result.seedApplied,
2254
+ evaluationCount: runBudget.acceptedEvaluations(),
2255
+ ...result.upstreamReportedEvaluations !== void 0 ? { upstreamReportedEvaluations: result.upstreamReportedEvaluations } : {},
2256
+ artifactDir: outputDir,
2257
+ ...tokenUsage ? { tokenUsage } : {},
2258
+ observations: observationLog.summary(),
2259
+ ...result.candidatePopulation ? { gepaCandidatePopulation: result.candidatePopulation } : {},
2260
+ ...executionLog ? { modelExecutions: executionLog.summary() } : {}
2261
+ }
2262
+ };
2263
+ }
2264
+ //#endregion
2265
+ //#region src/campaign/gepa-optimization-method.ts
2266
+ /**
2267
+ * Turn an optional GEPA installation into an `OptimizationMethod`.
2268
+ *
2269
+ * GEPA receives only serialized train and selection cases. The caller's final
2270
+ * test partition stays inside `compareOptimizationMethods`, which invokes this
2271
+ * method without a test-set field. The local callback routes every candidate
2272
+ * evaluation through the same dispatch and judges used by other methods.
2273
+ */
2274
+ /**
2275
+ * Environment for a bridge child that spawns `claude` CLI subprocesses.
2276
+ *
2277
+ * Both agent CLI engines start the CLI with the bridge's own environment, so
2278
+ * these variables travel bridge → engine → CLI. They merge AFTER
2279
+ * `removeCredentialEnvironment`: the ephemeral loopback token is the only
2280
+ * credential the child may see, and a caller-supplied ANTHROPIC_AUTH_TOKEN is
2281
+ * stripped like any other credential.
2282
+ */
2283
+ function gepaOptimizationMethod(config) {
2284
+ assertGepaOptimizationConfig(config);
2285
+ config = snapshotGepaOptimizationConfig(config);
2286
+ const name = config.name ?? defaultGepaMethodName(config.recipe);
2287
+ return {
2288
+ name,
2289
+ async optimize(input) {
2290
+ const ctx = await prepareGepaRun(config, input, name);
2291
+ const { result, outputDir, modelProxy } = await runBridge(ctx);
2292
+ return buildGepaOutcome(ctx, result, outputDir, modelProxy, await recordGepaSearchHistory(ctx, result, verifyBridgeResult(ctx, result)), gepaCosts(ctx, result, modelProxy));
2126
2293
  }
2127
2294
  };
2128
2295
  }
2129
2296
  //#endregion
2297
+ //#region src/campaign/presets/comparison-controls.ts
2298
+ /** Admission checks for the shared controls of a method comparison. */
2299
+ /** The caller-supplied judges, dispatch function and references, and the baseline surface. */
2300
+ function assertCallerInputs(opts) {
2301
+ if (opts.optimizationRunOptions && "costCeiling" in opts.optimizationRunOptions) throw new Error("compareOptimizationMethods: optimizationRunOptions.costCeiling is not supported; costCeiling covers optimization and final scoring");
2302
+ if (!opts.judges || opts.judges.length === 0) throw new Error("compareOptimizationMethods: at least one judge is required");
2303
+ if (typeof opts.dispatchWithSurface !== "function") throw new Error("compareOptimizationMethods: dispatchWithSurface must be a function");
2304
+ if (opts.dispatchRef !== void 0 && (typeof opts.dispatchRef !== "string" || opts.dispatchRef.trim().length === 0 || opts.dispatchRef.trim() !== opts.dispatchRef)) throw new Error("compareOptimizationMethods: dispatchRef must be trimmed and non-empty when provided");
2305
+ const optimizationDispatchRef = opts.optimizationRunOptions?.dispatchRef;
2306
+ if (optimizationDispatchRef !== void 0 && (typeof optimizationDispatchRef !== "string" || optimizationDispatchRef.trim().length === 0 || optimizationDispatchRef.trim() !== optimizationDispatchRef)) throw new Error("compareOptimizationMethods: optimizationRunOptions.dispatchRef must be trimmed and non-empty when provided");
2307
+ if (opts.dispatchRef !== void 0 && optimizationDispatchRef !== void 0 && opts.dispatchRef !== optimizationDispatchRef) throw new Error("compareOptimizationMethods: dispatchRef must match optimizationRunOptions.dispatchRef when both are provided");
2308
+ try {
2309
+ surfaceContentHash(opts.baselineSurface);
2310
+ } catch (cause) {
2311
+ throw new Error("compareOptimizationMethods: baselineSurface is invalid", { cause });
2312
+ }
2313
+ }
2314
+ /** Every judge has a unique trimmed name, a score function and uniquely keyed dimensions. */
2315
+ function assertJudges(opts) {
2316
+ const judgeNames = /* @__PURE__ */ new Set();
2317
+ for (const judge of opts.judges) {
2318
+ if (!judge || typeof judge !== "object" || typeof judge.name !== "string" || judge.name.trim().length === 0 || judge.name.trim() !== judge.name || typeof judge.score !== "function" || !Array.isArray(judge.dimensions) || judge.dimensions.length === 0) throw new Error("compareOptimizationMethods: every judge needs a trimmed name, at least one dimension, and score(input)");
2319
+ if (judgeNames.has(judge.name)) throw new Error(`compareOptimizationMethods: duplicate judge name '${judge.name}'`);
2320
+ judgeNames.add(judge.name);
2321
+ const dimensionKeys = /* @__PURE__ */ new Set();
2322
+ for (const dimension of judge.dimensions) {
2323
+ if (!dimension || typeof dimension.key !== "string" || dimension.key.trim().length === 0 || dimension.key.trim() !== dimension.key || typeof dimension.description !== "string" || dimension.description.trim().length === 0) throw new Error(`compareOptimizationMethods: judge '${judge.name}' has an invalid dimension`);
2324
+ if (dimensionKeys.has(dimension.key)) throw new Error(`compareOptimizationMethods: judge '${judge.name}' has duplicate dimension '${dimension.key}'`);
2325
+ dimensionKeys.add(dimension.key);
2326
+ }
2327
+ }
2328
+ }
2329
+ /** The run directory and the seed, resamples and confidence that fix the paired intervals. */
2330
+ function assertStatistics(opts, seed, resamples, confidence) {
2331
+ if (typeof opts.runDir !== "string" || opts.runDir.trim().length === 0) throw new Error("compareOptimizationMethods: runDir must be a non-empty string");
2332
+ if (!Number.isSafeInteger(seed)) throw new Error(`compareOptimizationMethods: seed must be a safe integer, got ${String(seed)}`);
2333
+ if (!Number.isSafeInteger(resamples) || resamples <= 0 || resamples > 1e6) throw new Error(`compareOptimizationMethods: resamples must be a positive safe integer no greater than 1000000, got ${String(resamples)}`);
2334
+ assertConfidence(confidence);
2335
+ const minimumResamples = minimumBootstrapResamples(confidence, opts.methods.length * (opts.methods.length + 1) / 2);
2336
+ if (resamples < minimumResamples) throw new Error(`compareOptimizationMethods: resamples must be at least ${minimumResamples} for simultaneous confidence ${confidence} across ${opts.methods.length} methods, got ${resamples}`);
2337
+ }
2338
+ /** Concurrency, timeout and cost limits. */
2339
+ function assertLimits(opts) {
2340
+ if (opts.optimizationConcurrency !== void 0 && (!Number.isSafeInteger(opts.optimizationConcurrency) || opts.optimizationConcurrency <= 0)) throw new Error("compareOptimizationMethods: optimizationConcurrency must be a positive safe integer");
2341
+ if (opts.maxConcurrency !== void 0 && (!Number.isSafeInteger(opts.maxConcurrency) || opts.maxConcurrency <= 0)) throw new Error("compareOptimizationMethods: maxConcurrency must be a positive safe integer");
2342
+ if (opts.dispatchTimeoutMs !== void 0 && (!Number.isSafeInteger(opts.dispatchTimeoutMs) || opts.dispatchTimeoutMs < 0 || opts.dispatchTimeoutMs > 2147483647)) throw new Error("compareOptimizationMethods: dispatchTimeoutMs must be a non-negative safe integer no greater than 2147483647");
2343
+ if (opts.costCeiling !== void 0 && (!Number.isFinite(opts.costCeiling) || opts.costCeiling < 0)) throw new Error("compareOptimizationMethods: costCeiling must be a finite number greater than or equal to 0");
2344
+ if (opts.costCeiling !== void 0 && opts.costLedger !== void 0 && opts.costLedger.costCeilingUsd !== opts.costCeiling) throw new Error("compareOptimizationMethods: costCeiling must match the shared CostLedger ceiling");
2345
+ }
2346
+ function assertComparisonControls(opts, seed, resamples, confidence) {
2347
+ assertCallerInputs(opts);
2348
+ assertJudges(opts);
2349
+ assertStatistics(opts, seed, resamples, confidence);
2350
+ assertLimits(opts);
2351
+ }
2352
+ function assertConfidence(confidence) {
2353
+ if (!Number.isFinite(confidence) || confidence <= 0 || confidence >= 1) throw new Error(`compareOptimizationMethods: confidence must be a finite number in (0,1), got ${String(confidence)}`);
2354
+ }
2355
+ function minimumBootstrapResamples(confidence, comparisonCount) {
2356
+ const exact = 2 * comparisonCount / (1 - confidence);
2357
+ return Math.ceil(exact - Number.EPSILON * Math.max(1, exact) * 32);
2358
+ }
2359
+ //#endregion
2130
2360
  //#region src/campaign/presets/compare-optimization-methods.ts
2131
2361
  /**
2132
2362
  * Compare optimization methods on shared train, selection, and test data.
@@ -2140,16 +2370,21 @@ function optimizerAccounting(tokenUsage, proposerCostUsd) {
2140
2370
  /**
2141
2371
  * Compare complete optimization methods on disjoint train, selection, and final test data.
2142
2372
  */
2143
- async function compareOptimizationMethods(opts) {
2144
- opts = {
2145
- ...opts,
2146
- methods: opts.methods.map((method) => ({ ...method })),
2147
- trainScenarios: structuredClone(opts.trainScenarios),
2148
- selectionScenarios: structuredClone(opts.selectionScenarios),
2149
- testScenarios: structuredClone(opts.testScenarios),
2150
- judges: opts.judges.map(captureJudge),
2151
- claim: opts.claim && defineEvaluationClaim(opts.claim),
2152
- finalEvidence: opts.finalEvidence && captureFinalEvidencePolicy(opts.finalEvidence)
2373
+ async function compareOptimizationMethods(rawOpts) {
2374
+ return comparisonResult(pairwiseAgainstBest(scoreMethods(await measureWinners(await reserveTestMeasurement(await optimizeAllMethods(await finalTestScoring(normalizeComparisonOptions({ rawOpts }))))))));
2375
+ }
2376
+ /** The captured options, the derived statistics settings, the run directory and the cost ledger. */
2377
+ function normalizeComparisonOptions(prev) {
2378
+ const { rawOpts } = prev;
2379
+ const opts = {
2380
+ ...rawOpts,
2381
+ methods: rawOpts.methods.map((method) => ({ ...method })),
2382
+ trainScenarios: structuredClone(rawOpts.trainScenarios),
2383
+ selectionScenarios: structuredClone(rawOpts.selectionScenarios),
2384
+ testScenarios: structuredClone(rawOpts.testScenarios),
2385
+ judges: rawOpts.judges.map(captureJudge),
2386
+ claim: rawOpts.claim && defineEvaluationClaim(rawOpts.claim),
2387
+ finalEvidence: rawOpts.finalEvidence && captureFinalEvidencePolicy(rawOpts.finalEvidence)
2153
2388
  };
2154
2389
  assertOptimizationMethods(opts.methods);
2155
2390
  assertComparisonPartitions(opts);
@@ -2174,6 +2409,28 @@ async function compareOptimizationMethods(opts) {
2174
2409
  runDir: `${resolvedRunDir}/cost`,
2175
2410
  costCeilingUsd: opts.costCeiling
2176
2411
  });
2412
+ return {
2413
+ ...prev,
2414
+ opts,
2415
+ searchHistoryPolicy,
2416
+ seed,
2417
+ confidence,
2418
+ optimizationConcurrency,
2419
+ comparisonCount,
2420
+ intervalConfidence,
2421
+ minimumResamples,
2422
+ resamples,
2423
+ evidence,
2424
+ evidenceBySurface,
2425
+ storage,
2426
+ resolvedRunDir,
2427
+ baselineSurface,
2428
+ costLedger
2429
+ };
2430
+ }
2431
+ /** Scoring a surface on the final test set, and aligning the scores to the designed scenarios. */
2432
+ async function finalTestScoring(prev) {
2433
+ const { opts, seed, intervalConfidence, resamples, evidence, evidenceBySurface, storage, resolvedRunDir, costLedger } = prev;
2177
2434
  const scoreOnTest = async (surface, tag, costPhase) => {
2178
2435
  const measuredSurface = structuredClone(surface);
2179
2436
  const campaign = await runCampaign({
@@ -2227,6 +2484,20 @@ async function compareOptimizationMethods(opts) {
2227
2484
  if (missing.length > 0) throw new Error(`compareOptimizationMethods: ${label} produced no test score for scenario(s) [${missing.join(", ")}]. A cell failed or its judges returned nothing. Fix the dispatch or judge; the comparison will not replace missing scores with zero.`);
2228
2485
  return scenarioIds.map((id) => byScenario[id]);
2229
2486
  };
2487
+ return {
2488
+ ...prev,
2489
+ scoreOnTest,
2490
+ scenarioIds,
2491
+ unitByScenario,
2492
+ units,
2493
+ aggregateUnits,
2494
+ decisionOptions,
2495
+ align
2496
+ };
2497
+ }
2498
+ /** Reserve final evidence, then finish every method before the first final-test call. */
2499
+ async function optimizeAllMethods(prev) {
2500
+ const { opts, seed, optimizationConcurrency, storage, resolvedRunDir, baselineSurface, costLedger } = prev;
2230
2501
  if (opts.claim?.generalization === "new-units") assertIndependentEvaluationSplit(opts.claim, opts.testScenarios, [...opts.trainScenarios, ...opts.selectionScenarios]);
2231
2502
  if (opts.finalEvidence) await reserveFinalEvidence(opts.finalEvidence, opts.claim, opts.testScenarios, [...opts.trainScenarios, ...opts.selectionScenarios]);
2232
2503
  const optimizationOwner = new AbortController();
@@ -2258,7 +2529,16 @@ async function compareOptimizationMethods(opts) {
2258
2529
  label: `method '${result.name}'`,
2259
2530
  cost: result.cost
2260
2531
  }))).totalCostUsd, opts.costCeiling, "optimization");
2261
- const testCostPhase = `compareOptimizationMethods.test:${contentHash({
2532
+ return {
2533
+ ...prev,
2534
+ optimizationOwner,
2535
+ optimized
2536
+ };
2537
+ }
2538
+ /** The identity of the final test and the exposure of its evidence. */
2539
+ async function reserveTestMeasurement(prev) {
2540
+ const { opts, seed, baselineSurface, optimized } = prev;
2541
+ const testCostIdentity = contentHash({
2262
2542
  baseline: surfaceContentHash(baselineSurface),
2263
2543
  winners: optimized.map((winner) => ({
2264
2544
  name: winner.name,
@@ -2276,8 +2556,19 @@ async function compareOptimizationMethods(opts) {
2276
2556
  dispatch: callerDispatchRef(opts),
2277
2557
  seed,
2278
2558
  reps: opts.reps ?? 1
2279
- })}`;
2559
+ });
2560
+ const testCostPhase = `compareOptimizationMethods.test:${testCostIdentity}`;
2280
2561
  const finalEvidence = opts.finalEvidence ? await exposeFinalEvidence(opts.finalEvidence, opts.claim, opts.testScenarios, [baselineSurface, ...optimized.map((method) => method.winnerSurface)]) : void 0;
2562
+ return {
2563
+ ...prev,
2564
+ testCostIdentity,
2565
+ testCostPhase,
2566
+ finalEvidence
2567
+ };
2568
+ }
2569
+ /** One final-test measurement per distinct surface. */
2570
+ async function measureWinners(prev) {
2571
+ const { baselineSurface, scoreOnTest, align, optimized, testCostPhase } = prev;
2281
2572
  const baselineArr = align(await scoreOnTest(baselineSurface, "test/baseline", testCostPhase), "baseline");
2282
2573
  const testScoresBySurface = /* @__PURE__ */ new Map([[surfaceContentHash(baselineSurface), baselineArr]]);
2283
2574
  const winners = [];
@@ -2293,6 +2584,16 @@ async function compareOptimizationMethods(opts) {
2293
2584
  arr
2294
2585
  });
2295
2586
  }
2587
+ return {
2588
+ ...prev,
2589
+ baselineArr,
2590
+ testScoresBySurface,
2591
+ winners
2592
+ };
2593
+ }
2594
+ /** Per-method scores, ranked by lift with cost breaking complete ties. */
2595
+ function scoreMethods(prev) {
2596
+ const { evidence, evidenceBySurface, baselineSurface, scenarioIds, units, aggregateUnits, decisionOptions, baselineArr, winners } = prev;
2296
2597
  const scores = winners.map((w) => {
2297
2598
  const baselineUnits = aggregateUnits(baselineArr);
2298
2599
  const winnerUnits = aggregateUnits(w.arr);
@@ -2353,6 +2654,15 @@ async function compareOptimizationMethods(opts) {
2353
2654
  s.rank = i + 1;
2354
2655
  });
2355
2656
  const best = scores[0];
2657
+ return {
2658
+ ...prev,
2659
+ scores,
2660
+ best
2661
+ };
2662
+ }
2663
+ /** The best method against every other, in both directions. */
2664
+ function pairwiseAgainstBest(prev) {
2665
+ const { aggregateUnits, decisionOptions, winners, scores, best } = prev;
2356
2666
  const byName = new Map(winners.map((w) => [w.name, w]));
2357
2667
  const bestArr = aggregateUnits(byName.get(best.name).arr);
2358
2668
  const pairwise = scores.slice(1).map((other) => {
@@ -2370,6 +2680,16 @@ async function compareOptimizationMethods(opts) {
2370
2680
  decision
2371
2681
  };
2372
2682
  });
2683
+ return {
2684
+ ...prev,
2685
+ byName,
2686
+ bestArr,
2687
+ pairwise
2688
+ };
2689
+ }
2690
+ /** Total cost against the ceiling, then the comparison record. */
2691
+ function comparisonResult(prev) {
2692
+ const { opts, searchHistoryPolicy, seed, confidence, comparisonCount, intervalConfidence, resamples, costLedger, scenarioIds, units, optimized, testCostPhase, finalEvidence, scores, best, pairwise } = prev;
2373
2693
  const optimizationCost = combineComparisonCosts(scores.map((score) => ({
2374
2694
  label: `method '${score.name}'`,
2375
2695
  cost: score.optimizationCost
@@ -2431,43 +2751,6 @@ function assertOptimizationMethods(methods) {
2431
2751
  pathOwners.set(pathKey, method.name);
2432
2752
  }
2433
2753
  }
2434
- function assertComparisonControls(opts, seed, resamples, confidence) {
2435
- if (opts.optimizationRunOptions && "costCeiling" in opts.optimizationRunOptions) throw new Error("compareOptimizationMethods: optimizationRunOptions.costCeiling is not supported; costCeiling covers optimization and final scoring");
2436
- if (!opts.judges || opts.judges.length === 0) throw new Error("compareOptimizationMethods: at least one judge is required");
2437
- if (typeof opts.dispatchWithSurface !== "function") throw new Error("compareOptimizationMethods: dispatchWithSurface must be a function");
2438
- if (opts.dispatchRef !== void 0 && (typeof opts.dispatchRef !== "string" || opts.dispatchRef.trim().length === 0 || opts.dispatchRef.trim() !== opts.dispatchRef)) throw new Error("compareOptimizationMethods: dispatchRef must be trimmed and non-empty when provided");
2439
- const optimizationDispatchRef = opts.optimizationRunOptions?.dispatchRef;
2440
- if (optimizationDispatchRef !== void 0 && (typeof optimizationDispatchRef !== "string" || optimizationDispatchRef.trim().length === 0 || optimizationDispatchRef.trim() !== optimizationDispatchRef)) throw new Error("compareOptimizationMethods: optimizationRunOptions.dispatchRef must be trimmed and non-empty when provided");
2441
- if (opts.dispatchRef !== void 0 && optimizationDispatchRef !== void 0 && opts.dispatchRef !== optimizationDispatchRef) throw new Error("compareOptimizationMethods: dispatchRef must match optimizationRunOptions.dispatchRef when both are provided");
2442
- try {
2443
- surfaceContentHash(opts.baselineSurface);
2444
- } catch (cause) {
2445
- throw new Error("compareOptimizationMethods: baselineSurface is invalid", { cause });
2446
- }
2447
- const judgeNames = /* @__PURE__ */ new Set();
2448
- for (const judge of opts.judges) {
2449
- if (!judge || typeof judge !== "object" || typeof judge.name !== "string" || judge.name.trim().length === 0 || judge.name.trim() !== judge.name || typeof judge.score !== "function" || !Array.isArray(judge.dimensions) || judge.dimensions.length === 0) throw new Error("compareOptimizationMethods: every judge needs a trimmed name, at least one dimension, and score(input)");
2450
- if (judgeNames.has(judge.name)) throw new Error(`compareOptimizationMethods: duplicate judge name '${judge.name}'`);
2451
- judgeNames.add(judge.name);
2452
- const dimensionKeys = /* @__PURE__ */ new Set();
2453
- for (const dimension of judge.dimensions) {
2454
- if (!dimension || typeof dimension.key !== "string" || dimension.key.trim().length === 0 || dimension.key.trim() !== dimension.key || typeof dimension.description !== "string" || dimension.description.trim().length === 0) throw new Error(`compareOptimizationMethods: judge '${judge.name}' has an invalid dimension`);
2455
- if (dimensionKeys.has(dimension.key)) throw new Error(`compareOptimizationMethods: judge '${judge.name}' has duplicate dimension '${dimension.key}'`);
2456
- dimensionKeys.add(dimension.key);
2457
- }
2458
- }
2459
- if (typeof opts.runDir !== "string" || opts.runDir.trim().length === 0) throw new Error("compareOptimizationMethods: runDir must be a non-empty string");
2460
- if (!Number.isSafeInteger(seed)) throw new Error(`compareOptimizationMethods: seed must be a safe integer, got ${String(seed)}`);
2461
- if (!Number.isSafeInteger(resamples) || resamples <= 0 || resamples > 1e6) throw new Error(`compareOptimizationMethods: resamples must be a positive safe integer no greater than 1000000, got ${String(resamples)}`);
2462
- assertConfidence(confidence);
2463
- const minimumResamples = minimumBootstrapResamples(confidence, opts.methods.length * (opts.methods.length + 1) / 2);
2464
- if (resamples < minimumResamples) throw new Error(`compareOptimizationMethods: resamples must be at least ${minimumResamples} for simultaneous confidence ${confidence} across ${opts.methods.length} methods, got ${resamples}`);
2465
- if (opts.optimizationConcurrency !== void 0 && (!Number.isSafeInteger(opts.optimizationConcurrency) || opts.optimizationConcurrency <= 0)) throw new Error("compareOptimizationMethods: optimizationConcurrency must be a positive safe integer");
2466
- if (opts.maxConcurrency !== void 0 && (!Number.isSafeInteger(opts.maxConcurrency) || opts.maxConcurrency <= 0)) throw new Error("compareOptimizationMethods: maxConcurrency must be a positive safe integer");
2467
- if (opts.dispatchTimeoutMs !== void 0 && (!Number.isSafeInteger(opts.dispatchTimeoutMs) || opts.dispatchTimeoutMs < 0 || opts.dispatchTimeoutMs > 2147483647)) throw new Error("compareOptimizationMethods: dispatchTimeoutMs must be a non-negative safe integer no greater than 2147483647");
2468
- if (opts.costCeiling !== void 0 && (!Number.isFinite(opts.costCeiling) || opts.costCeiling < 0)) throw new Error("compareOptimizationMethods: costCeiling must be a finite number greater than or equal to 0");
2469
- if (opts.costCeiling !== void 0 && opts.costLedger !== void 0 && opts.costLedger.costCeilingUsd !== opts.costCeiling) throw new Error("compareOptimizationMethods: costCeiling must match the shared CostLedger ceiling");
2470
- }
2471
2754
  function assertComparisonPartitions(opts) {
2472
2755
  const partitions = [
2473
2756
  {
@@ -2508,13 +2791,6 @@ function assertComparisonPartitions(opts) {
2508
2791
  function slug(name) {
2509
2792
  return name.replace(/[^a-z0-9]+/gi, "-").replace(/^-|-$/g, "").toLowerCase() || "method";
2510
2793
  }
2511
- function assertConfidence(confidence) {
2512
- if (!Number.isFinite(confidence) || confidence <= 0 || confidence >= 1) throw new Error(`compareOptimizationMethods: confidence must be a finite number in (0,1), got ${String(confidence)}`);
2513
- }
2514
- function minimumBootstrapResamples(confidence, comparisonCount) {
2515
- const exact = 2 * comparisonCount / (1 - confidence);
2516
- return Math.ceil(exact - Number.EPSILON * Math.max(1, exact) * 32);
2517
- }
2518
2794
  function createOptimizationMethodInput(opts, methodName, resolvedRunDir, seed, baselineSurface, costLedger, optimizationSignal) {
2519
2795
  const methodRunDir = `${resolvedRunDir}/optimization/${slug(methodName)}`;
2520
2796
  const signal = combineAbortSignals(opts.signal, opts.optimizationRunOptions?.signal, optimizationSignal);
@@ -2626,298 +2902,347 @@ function assertSkillOptBridgeOutput(result, name, maxCandidateChars, maxEvaluati
2626
2902
  function skillOptOptimizationMethod(config) {
2627
2903
  assertSkillOptOptimizationConfig(config);
2628
2904
  config = snapshotSkillOptOptimizationConfig(config);
2629
- const name = config.name ?? "skillopt";
2905
+ const snapshot = config;
2906
+ const name = snapshot.name ?? "skillopt";
2630
2907
  return {
2631
2908
  name,
2632
- async optimize(input) {
2633
- const signal = input.runOptions.signal;
2634
- signal?.throwIfAborted();
2635
- if (typeof input.baselineSurface !== "string") throw new Error(`${name}: SkillOpt requires a string baselineSurface`);
2636
- const started = Date.now();
2637
- const maxCandidateChars = config.maxCandidateChars ?? 2e5;
2638
- const maxEvidenceChars = config.maxEvidenceChars ?? 1e5;
2639
- const storage = input.runOptions.storage ?? fsCampaignStorage();
2640
- const runDir = `${input.runDir}/skillopt`;
2641
- storage.ensureDir(runDir);
2642
- const costLedger = input.costLedger;
2643
- const attemptId = randomBytes(16).toString("hex");
2644
- const resume = config.resume ?? "never";
2645
- const bridgeRunner = config.runner ? {
2646
- ...config.runner,
2647
- env: removeCredentialEnvironment(config.runner.env ?? {})
2648
- } : void 0;
2649
- const runtimeIdentity = await inspectExternalOptimizerRuntime({
2650
- label: name,
2651
- package: "skillopt",
2652
- module: "agent_eval_rpc.skillopt_bridge",
2653
- ...bridgeRunner ? { runner: bridgeRunner } : {},
2654
- timeoutMs: config.timeoutMs ?? 36e5,
2655
- ...signal ? { signal } : {}
2656
- });
2657
- const trainSet = input.trainScenarios.map((scenario) => describeExternalScenario(scenario, "SkillOpt", maxEvidenceChars, config.describeScenario));
2658
- const selectionSet = input.selectionScenarios.map((scenario) => describeExternalScenario(scenario, "SkillOpt", maxEvidenceChars, config.describeScenario));
2659
- const runMaterial = {
2660
- optimizer: "skillopt",
2661
- runtime: runtimeIdentity,
2662
- method: name,
2663
- evaluationId: config.evaluationId,
2664
- dispatchRef: input.runOptions.dispatchRef ?? null,
2665
- seed: input.seed,
2666
- trainer: snapshotJson(config.trainer, "SkillOpt run settings"),
2667
- objective: config.objective,
2668
- background: config.background ?? "",
2669
- optimizerModel: {
2670
- model: config.optimizer.model,
2671
- callRef: config.optimizer.callRef,
2672
- budget: config.optimizer.budget
2673
- },
2674
- seedCandidate: input.baselineSurface,
2675
- trainSet,
2676
- selectionSet,
2677
- maxEvaluations: config.maxEvaluations,
2678
- hardScoreThreshold: config.hardScoreThreshold ?? 1,
2679
- maxCandidateChars,
2680
- maxEvidenceChars,
2681
- evaluationCallbackLimits: resolveExternalOptimizerCallbackLimits(config.evaluationCallbackLimits),
2682
- runner: externalOptimizerRunnerIdentity(bridgeRunner, "agent_eval_rpc.skillopt_bridge")
2683
- };
2684
- const compatibleRunId = externalOptimizerCompatibleRunKey(runMaterial);
2685
- const runId = externalOptimizerRunKey({
2686
- material: runMaterial,
2687
- attemptId,
2688
- resumeEnabled: resume !== "never"
2689
- });
2690
- const runBudget = openExternalOptimizerRunBudget({
2691
- storage,
2692
- runDir,
2693
- runKey: runId,
2694
- attemptId,
2695
- maxEvaluations: config.maxEvaluations
2696
- });
2697
- const observationLog = openExternalOptimizerObservationLog({
2698
- storage,
2699
- path: `${runDir}/observations-${attemptId}.jsonl`
2700
- });
2701
- const executionLog = openExternalOptimizerExecutionLog({
2702
- storage,
2703
- path: `${runDir}/model-executions-${attemptId}.jsonl`
2704
- });
2705
- const scenarioById = mapExternalScenarios(input.trainScenarios, input.selectionScenarios, "SkillOpt bridge");
2706
- const evaluate = createExternalTextEvaluator({
2707
- input,
2708
- label: "SkillOpt bridge",
2709
- runDir,
2710
- compatibleRunId: runId,
2711
- costPhase: "skillopt.external-evaluation",
2712
- costTags: runBudget.attemptTags,
2713
- costLedger,
2714
- scenarioById,
2715
- maxCandidateChars,
2716
- maxEvidenceChars,
2717
- describeArtifact: config.describeArtifact
2718
- });
2719
- let attemptEvaluationCount = 0;
2720
- const callback = await startExternalOptimizerCallback({
2721
- token: randomBytes(32).toString("hex"),
2722
- maxEvaluations: config.maxEvaluations,
2723
- acceptEvaluation: () => {
2724
- if (runBudget.acceptEvaluation() === void 0) return void 0;
2725
- attemptEvaluationCount += 1;
2726
- return attemptEvaluationCount;
2727
- },
2728
- evaluate,
2729
- observe: observationLog.observe,
2730
- ...config.evaluationCallbackLimits ? { limits: config.evaluationCallbackLimits } : {},
2731
- ...signal ? { signal } : {}
2732
- });
2733
- const runnerEnv = bridgeRunner?.env ?? {};
2734
- let activeModelProxy;
2735
- const closeResources = () => closeExternalOptimizerResources({
2736
- label: name,
2737
- callback,
2738
- ...activeModelProxy ? { modelProxy: activeModelProxy } : {}
2739
- });
2740
- const { result, outputDir, modelProxy } = await runWithCleanup({
2741
- label: `${name} optimizer resources`,
2742
- run: async () => {
2743
- const priorOptimizerUsage = costLedger.summary({
2744
- phase: "skillopt.optimizer-model",
2745
- tags: runBudget.runTags
2746
- });
2747
- assertPriorExternalOptimizerUsage(priorOptimizerUsage, config.optimizer.budget, name);
2748
- const modelProxy = await startExternalOptimizerModelProxy({
2749
- call: config.optimizer.call,
2750
- callRef: config.optimizer.callRef,
2751
- recordExecution: executionLog.observe,
2752
- model: config.optimizer.model,
2753
- budget: config.optimizer.budget,
2754
- ...config.optimizer.servedModelPolicy ? { servedModelPolicy: config.optimizer.servedModelPolicy } : {},
2755
- costLedger,
2756
- phase: "skillopt.optimizer-model",
2757
- actor: name,
2758
- tags: { ...runBudget.attemptTags },
2759
- initialUsage: {
2760
- requests: priorOptimizerUsage.totalCalls,
2761
- ...priorOptimizerUsage.costProvenance.kind === "uncaptured" ? {} : { costUsd: priorOptimizerUsage.totalCostUsd }
2762
- },
2763
- ...signal ? { signal } : {}
2764
- });
2765
- activeModelProxy = modelProxy;
2766
- const outputDir = `${runDir}/external`;
2767
- await mkdir(outputDir, { recursive: true });
2768
- return {
2769
- result: await runExternalOptimizerProcess({
2770
- label: "SkillOpt bridge",
2771
- tempPrefix: "agent-eval-skillopt-",
2772
- module: "agent_eval_rpc.skillopt_bridge",
2773
- input: {
2774
- attemptId,
2775
- compatibleRunId,
2776
- runId,
2777
- runtimeIdentity,
2778
- resume,
2779
- evaluationId: config.evaluationId,
2780
- seed: input.seed,
2781
- callbackUrl: callback.url,
2782
- callbackToken: callback.token,
2783
- objective: config.objective,
2784
- ...config.background ? { background: config.background } : {},
2785
- trainer: config.trainer,
2786
- optimizerModel: config.optimizer.model,
2787
- modelBudget: config.optimizer.budget,
2788
- seedCandidate: input.baselineSurface,
2789
- trainSet,
2790
- selectionSet,
2791
- maxEvaluations: config.maxEvaluations,
2792
- hardScoreThreshold: config.hardScoreThreshold ?? 1,
2793
- maxCandidateChars,
2794
- maxEvidenceChars,
2795
- outputDir
2796
- },
2797
- runner: {
2798
- ...bridgeRunner,
2799
- env: {
2800
- ...removeCredentialEnvironment(runnerEnv),
2801
- OPENAI_COMPATIBLE_BASE_URL: modelProxy.baseUrl,
2802
- OPENAI_COMPATIBLE_API_KEY: modelProxy.apiKey,
2803
- OPTIMIZER_OPENAI_COMPATIBLE_BASE_URL: modelProxy.baseUrl,
2804
- OPTIMIZER_OPENAI_COMPATIBLE_API_KEY: modelProxy.apiKey,
2805
- TARGET_OPENAI_COMPATIBLE_BASE_URL: modelProxy.baseUrl,
2806
- TARGET_OPENAI_COMPATIBLE_API_KEY: modelProxy.apiKey,
2807
- OPENAI_COMPATIBLE_MODEL: config.optimizer.model,
2808
- OPENAI_COMPATIBLE_MAX_TOKENS: String(config.optimizer.budget.maxOutputTokensPerRequest),
2809
- OPTIMIZER_OPENAI_COMPATIBLE_MODEL: config.optimizer.model,
2810
- OPTIMIZER_OPENAI_COMPATIBLE_MAX_TOKENS: String(config.optimizer.budget.maxOutputTokensPerRequest),
2811
- TARGET_OPENAI_COMPATIBLE_MODEL: config.optimizer.model,
2812
- TARGET_OPENAI_COMPATIBLE_MAX_TOKENS: String(config.optimizer.budget.maxOutputTokensPerRequest)
2813
- }
2814
- },
2815
- timeoutMs: config.timeoutMs ?? 36e5,
2816
- ...signal ? { signal } : {}
2817
- }),
2818
- outputDir,
2819
- modelProxy
2820
- };
2821
- },
2822
- cleanup: closeResources
2823
- });
2824
- signal?.throwIfAborted();
2825
- assertSkillOptBridgeOutput(result, name, maxCandidateChars, config.maxEvaluations);
2826
- assertExternalOptimizerRunBinding({
2827
- label: name,
2828
- runtime: runtimeIdentity,
2829
- returnedSource: result.upstream,
2830
- compatibleRunId,
2831
- runId,
2832
- returnedRunId: result.runId,
2833
- resume,
2834
- resumed: result.resumed
2835
- });
2836
- if (callback.evaluations() !== result.totalEvaluations) throw new Error(`${name}: SkillOpt reported ${result.totalEvaluations} evaluations but the callback received ${callback.evaluations()}`);
2837
- const evaluationCost = costFromLedgerSummary(costLedger.summary({
2838
- phase: "skillopt.external-evaluation",
2839
- tags: runBudget.runTags
2840
- }));
2841
- const optimizerUsage = costLedger.summary({
2909
+ optimize: (input) => optimizeWithSkillOpt(snapshot, name, input)
2910
+ };
2911
+ }
2912
+ async function optimizeWithSkillOpt(config, name, input) {
2913
+ const signal = input.runOptions.signal;
2914
+ signal?.throwIfAborted();
2915
+ if (typeof input.baselineSurface !== "string") throw new Error(`${name}: SkillOpt requires a string baselineSurface`);
2916
+ const context = await prepareSkillOptRun(config, name, input);
2917
+ const { result, outputDir, modelProxy } = await runSkillOptBridge(context);
2918
+ signal?.throwIfAborted();
2919
+ return finishSkillOptRun(context, result, outputDir, modelProxy);
2920
+ }
2921
+ /** Resolve identities, open the run's budget and logs, and start the evaluation callback. */
2922
+ async function prepareSkillOptRun(config, name, input) {
2923
+ const signal = input.runOptions.signal;
2924
+ const started = Date.now();
2925
+ const maxCandidateChars = config.maxCandidateChars ?? 2e5;
2926
+ const maxEvidenceChars = config.maxEvidenceChars ?? 1e5;
2927
+ const storage = input.runOptions.storage ?? fsCampaignStorage();
2928
+ const runDir = `${input.runDir}/skillopt`;
2929
+ storage.ensureDir(runDir);
2930
+ const costLedger = input.costLedger;
2931
+ const attemptId = randomBytes(16).toString("hex");
2932
+ const resume = config.resume ?? "never";
2933
+ const bridgeRunner = config.runner ? {
2934
+ ...config.runner,
2935
+ env: removeCredentialEnvironment(config.runner.env ?? {})
2936
+ } : void 0;
2937
+ const runtimeIdentity = await inspectExternalOptimizerRuntime({
2938
+ label: name,
2939
+ package: "skillopt",
2940
+ module: "agent_eval_rpc.skillopt_bridge",
2941
+ ...bridgeRunner ? { runner: bridgeRunner } : {},
2942
+ timeoutMs: config.timeoutMs ?? 36e5,
2943
+ ...signal ? { signal } : {}
2944
+ });
2945
+ const trainSet = input.trainScenarios.map((scenario) => describeExternalScenario(scenario, "SkillOpt", maxEvidenceChars, config.describeScenario));
2946
+ const selectionSet = input.selectionScenarios.map((scenario) => describeExternalScenario(scenario, "SkillOpt", maxEvidenceChars, config.describeScenario));
2947
+ const runMaterial = {
2948
+ optimizer: "skillopt",
2949
+ runtime: runtimeIdentity,
2950
+ method: name,
2951
+ evaluationId: config.evaluationId,
2952
+ dispatchRef: input.runOptions.dispatchRef ?? null,
2953
+ seed: input.seed,
2954
+ trainer: snapshotJson(config.trainer, "SkillOpt run settings"),
2955
+ objective: config.objective,
2956
+ background: config.background ?? "",
2957
+ optimizerModel: {
2958
+ model: config.optimizer.model,
2959
+ callRef: config.optimizer.callRef,
2960
+ budget: config.optimizer.budget
2961
+ },
2962
+ seedCandidate: input.baselineSurface,
2963
+ trainSet,
2964
+ selectionSet,
2965
+ maxEvaluations: config.maxEvaluations,
2966
+ hardScoreThreshold: config.hardScoreThreshold ?? 1,
2967
+ maxCandidateChars,
2968
+ maxEvidenceChars,
2969
+ evaluationCallbackLimits: resolveExternalOptimizerCallbackLimits(config.evaluationCallbackLimits),
2970
+ runner: externalOptimizerRunnerIdentity(bridgeRunner, "agent_eval_rpc.skillopt_bridge")
2971
+ };
2972
+ const compatibleRunId = externalOptimizerCompatibleRunKey(runMaterial);
2973
+ const runId = externalOptimizerRunKey({
2974
+ material: runMaterial,
2975
+ attemptId,
2976
+ resumeEnabled: resume !== "never"
2977
+ });
2978
+ const runBudget = openExternalOptimizerRunBudget({
2979
+ storage,
2980
+ runDir,
2981
+ runKey: runId,
2982
+ attemptId,
2983
+ maxEvaluations: config.maxEvaluations
2984
+ });
2985
+ const observationLog = openExternalOptimizerObservationLog({
2986
+ storage,
2987
+ path: `${runDir}/observations-${attemptId}.jsonl`
2988
+ });
2989
+ const executionLog = openExternalOptimizerExecutionLog({
2990
+ storage,
2991
+ path: `${runDir}/model-executions-${attemptId}.jsonl`
2992
+ });
2993
+ const scenarioById = mapExternalScenarios(input.trainScenarios, input.selectionScenarios, "SkillOpt bridge");
2994
+ const evaluate = createExternalTextEvaluator({
2995
+ input,
2996
+ label: "SkillOpt bridge",
2997
+ runDir,
2998
+ compatibleRunId: runId,
2999
+ costPhase: "skillopt.external-evaluation",
3000
+ costTags: runBudget.attemptTags,
3001
+ costLedger,
3002
+ scenarioById,
3003
+ maxCandidateChars,
3004
+ maxEvidenceChars,
3005
+ describeArtifact: config.describeArtifact
3006
+ });
3007
+ let attemptEvaluationCount = 0;
3008
+ return {
3009
+ config,
3010
+ input,
3011
+ name,
3012
+ signal,
3013
+ started,
3014
+ maxCandidateChars,
3015
+ maxEvidenceChars,
3016
+ storage,
3017
+ runDir,
3018
+ attemptId,
3019
+ resume,
3020
+ bridgeRunner,
3021
+ runtimeIdentity,
3022
+ trainSet,
3023
+ selectionSet,
3024
+ compatibleRunId,
3025
+ runId,
3026
+ runBudget,
3027
+ observationLog,
3028
+ executionLog,
3029
+ callback: await startExternalOptimizerCallback({
3030
+ token: randomBytes(32).toString("hex"),
3031
+ maxEvaluations: config.maxEvaluations,
3032
+ acceptEvaluation: () => {
3033
+ if (runBudget.acceptEvaluation() === void 0) return void 0;
3034
+ attemptEvaluationCount += 1;
3035
+ return attemptEvaluationCount;
3036
+ },
3037
+ evaluate,
3038
+ observe: observationLog.observe,
3039
+ ...config.evaluationCallbackLimits ? { limits: config.evaluationCallbackLimits } : {},
3040
+ ...signal ? { signal } : {}
3041
+ })
3042
+ };
3043
+ }
3044
+ /** Start the metered model proxy and run the Python bridge, always closing the callback and proxy. */
3045
+ async function runSkillOptBridge(context) {
3046
+ const { config, input, name, signal, runDir, runBudget, callback } = context;
3047
+ const costLedger = input.costLedger;
3048
+ const runnerEnv = context.bridgeRunner?.env ?? {};
3049
+ let activeModelProxy;
3050
+ const closeResources = () => closeExternalOptimizerResources({
3051
+ label: name,
3052
+ callback,
3053
+ ...activeModelProxy ? { modelProxy: activeModelProxy } : {}
3054
+ });
3055
+ return runWithCleanup({
3056
+ label: `${name} optimizer resources`,
3057
+ run: async () => {
3058
+ const priorOptimizerUsage = costLedger.summary({
2842
3059
  phase: "skillopt.optimizer-model",
2843
3060
  tags: runBudget.runTags
2844
3061
  });
2845
- const optimizerReceipts = costLedger.list({
3062
+ assertPriorExternalOptimizerUsage(priorOptimizerUsage, config.optimizer.budget, name);
3063
+ const modelProxy = await startExternalOptimizerModelProxy({
3064
+ call: config.optimizer.call,
3065
+ callRef: config.optimizer.callRef,
3066
+ recordExecution: context.executionLog.observe,
3067
+ model: config.optimizer.model,
3068
+ budget: config.optimizer.budget,
3069
+ ...config.optimizer.servedModelPolicy ? { servedModelPolicy: config.optimizer.servedModelPolicy } : {},
3070
+ costLedger,
2846
3071
  phase: "skillopt.optimizer-model",
2847
- tags: runBudget.runTags
3072
+ actor: name,
3073
+ tags: { ...runBudget.attemptTags },
3074
+ initialUsage: {
3075
+ requests: priorOptimizerUsage.totalCalls,
3076
+ ...priorOptimizerUsage.costProvenance.kind === "uncaptured" ? {} : { costUsd: priorOptimizerUsage.totalCostUsd }
3077
+ },
3078
+ ...signal ? { signal } : {}
2848
3079
  });
2849
- const optimizerCost = costFromLedgerSummary(optimizerUsage);
2850
- modelProxy.assertExecutionComplete();
2851
- assertExternalOptimizerCompletionCount(result.tokenUsage, modelProxy.requestAttempts(), modelProxy.successfulCompletions(), name, "SkillOpt");
2852
- const tokenUsage = optimizationTokenUsageFromSummary(optimizerUsage, optimizerReceipts);
2853
- const runtime = observedExternalOptimizerRuntime(runtimeIdentity);
2854
- const combinedCost = combineComparisonCosts([{
2855
- label: "evaluation",
2856
- cost: evaluationCost
2857
- }, {
2858
- label: "optimizer model",
2859
- cost: optimizerCost
2860
- }]);
2861
- const searchHistory = config.searchLedger ? await recordSkillOptSearch({
2862
- name,
2863
- path: config.searchLedger.path ?? `${runDir}/search-ledger.jsonl`,
2864
- searchId: runId,
2865
- identity: config.searchLedger.identity,
2866
- storage,
2867
- seed: input.seed,
2868
- baselineSurface: input.baselineSurface,
2869
- trainScenarios: input.trainScenarios,
2870
- selectionScenarios: input.selectionScenarios,
2871
- evaluationLimit: config.maxEvaluations,
2872
- observations: readExternalOptimizerObservationArtifact({
2873
- summary: observationLog.summary(),
2874
- storage
2875
- }),
2876
- selected: result.bestCandidate,
2877
- generationAccounting: {
2878
- tokens: optimizerUsage.usageComplete ? {
2879
- status: "known",
2880
- inputTokens: optimizerUsage.inputTokens,
2881
- outputTokens: optimizerUsage.outputTokens,
2882
- cachedTokens: optimizerUsage.cachedTokens
2883
- } : {
2884
- status: "unknown",
2885
- reason: "an optimizer call reported no token usage"
2886
- },
2887
- cost: optimizerCost.accountingComplete ? {
2888
- status: "known",
2889
- usd: optimizerCost.totalCostUsd,
2890
- source: "provider"
2891
- } : {
2892
- status: "unknown",
2893
- knownLowerBoundUsd: optimizerCost.totalCostUsd,
2894
- reason: optimizerCost.incompleteReasons.join("; ") || "optimizer spend incomplete"
2895
- }
2896
- }
2897
- }) : void 0;
3080
+ activeModelProxy = modelProxy;
3081
+ const outputDir = `${runDir}/external`;
3082
+ await mkdir(outputDir, { recursive: true });
2898
3083
  return {
2899
- winnerSurface: result.bestCandidate,
2900
- ...searchHistory ? { searchHistory } : {},
2901
- cost: combinedCost,
2902
- durationMs: Date.now() - started,
2903
- provenance: {
2904
- ...runtime,
2905
- optimizerModel: config.optimizer.model,
2906
- optimizerCallRef: config.optimizer.callRef,
2907
- compatibleRunId,
2908
- runId,
2909
- resumed: result.resumed,
2910
- evaluationCount: runBudget.acceptedEvaluations(),
2911
- artifactDir: outputDir,
2912
- ...tokenUsage ? { tokenUsage } : {},
2913
- observations: observationLog.summary(),
2914
- modelExecutions: executionLog.summary()
2915
- }
3084
+ result: await runExternalOptimizerProcess({
3085
+ label: "SkillOpt bridge",
3086
+ tempPrefix: "agent-eval-skillopt-",
3087
+ module: "agent_eval_rpc.skillopt_bridge",
3088
+ input: {
3089
+ attemptId: context.attemptId,
3090
+ compatibleRunId: context.compatibleRunId,
3091
+ runId: context.runId,
3092
+ runtimeIdentity: context.runtimeIdentity,
3093
+ resume: context.resume,
3094
+ evaluationId: config.evaluationId,
3095
+ seed: input.seed,
3096
+ callbackUrl: callback.url,
3097
+ callbackToken: callback.token,
3098
+ objective: config.objective,
3099
+ ...config.background ? { background: config.background } : {},
3100
+ trainer: config.trainer,
3101
+ optimizerModel: config.optimizer.model,
3102
+ modelBudget: config.optimizer.budget,
3103
+ seedCandidate: input.baselineSurface,
3104
+ trainSet: context.trainSet,
3105
+ selectionSet: context.selectionSet,
3106
+ maxEvaluations: config.maxEvaluations,
3107
+ hardScoreThreshold: config.hardScoreThreshold ?? 1,
3108
+ maxCandidateChars: context.maxCandidateChars,
3109
+ maxEvidenceChars: context.maxEvidenceChars,
3110
+ outputDir
3111
+ },
3112
+ runner: {
3113
+ ...context.bridgeRunner,
3114
+ env: {
3115
+ ...removeCredentialEnvironment(runnerEnv),
3116
+ ...skillOptModelEnvironment(config, modelProxy)
3117
+ }
3118
+ },
3119
+ timeoutMs: config.timeoutMs ?? 36e5,
3120
+ ...signal ? { signal } : {}
3121
+ }),
3122
+ outputDir,
3123
+ modelProxy
2916
3124
  };
3125
+ },
3126
+ cleanup: closeResources
3127
+ });
3128
+ }
3129
+ /** Point every OpenAI-compatible client the bridge uses at the metered model proxy. */
3130
+ function skillOptModelEnvironment(config, modelProxy) {
3131
+ const maxTokens = String(config.optimizer.budget.maxOutputTokensPerRequest);
3132
+ return {
3133
+ OPENAI_COMPATIBLE_BASE_URL: modelProxy.baseUrl,
3134
+ OPENAI_COMPATIBLE_API_KEY: modelProxy.apiKey,
3135
+ OPTIMIZER_OPENAI_COMPATIBLE_BASE_URL: modelProxy.baseUrl,
3136
+ OPTIMIZER_OPENAI_COMPATIBLE_API_KEY: modelProxy.apiKey,
3137
+ TARGET_OPENAI_COMPATIBLE_BASE_URL: modelProxy.baseUrl,
3138
+ TARGET_OPENAI_COMPATIBLE_API_KEY: modelProxy.apiKey,
3139
+ OPENAI_COMPATIBLE_MODEL: config.optimizer.model,
3140
+ OPENAI_COMPATIBLE_MAX_TOKENS: maxTokens,
3141
+ OPTIMIZER_OPENAI_COMPATIBLE_MODEL: config.optimizer.model,
3142
+ OPTIMIZER_OPENAI_COMPATIBLE_MAX_TOKENS: maxTokens,
3143
+ TARGET_OPENAI_COMPATIBLE_MODEL: config.optimizer.model,
3144
+ TARGET_OPENAI_COMPATIBLE_MAX_TOKENS: maxTokens
3145
+ };
3146
+ }
3147
+ /** Validate the bridge output against the run, total its spend, and build the method result. */
3148
+ async function finishSkillOptRun(context, result, outputDir, modelProxy) {
3149
+ const { config, input, name, runBudget, callback, observationLog, executionLog } = context;
3150
+ const { runtimeIdentity, compatibleRunId, runId } = context;
3151
+ const costLedger = input.costLedger;
3152
+ assertSkillOptBridgeOutput(result, name, context.maxCandidateChars, config.maxEvaluations);
3153
+ assertExternalOptimizerRunBinding({
3154
+ label: name,
3155
+ runtime: runtimeIdentity,
3156
+ returnedSource: result.upstream,
3157
+ compatibleRunId,
3158
+ runId,
3159
+ returnedRunId: result.runId,
3160
+ resume: context.resume,
3161
+ resumed: result.resumed
3162
+ });
3163
+ if (callback.evaluations() !== result.totalEvaluations) throw new Error(`${name}: SkillOpt reported ${result.totalEvaluations} evaluations but the callback received ${callback.evaluations()}`);
3164
+ const evaluationCost = costFromLedgerSummary(costLedger.summary({
3165
+ phase: "skillopt.external-evaluation",
3166
+ tags: runBudget.runTags
3167
+ }));
3168
+ const optimizerUsage = costLedger.summary({
3169
+ phase: "skillopt.optimizer-model",
3170
+ tags: runBudget.runTags
3171
+ });
3172
+ const optimizerReceipts = costLedger.list({
3173
+ phase: "skillopt.optimizer-model",
3174
+ tags: runBudget.runTags
3175
+ });
3176
+ const optimizerCost = costFromLedgerSummary(optimizerUsage);
3177
+ modelProxy.assertExecutionComplete();
3178
+ assertExternalOptimizerCompletionCount(result.tokenUsage, modelProxy.requestAttempts(), modelProxy.successfulCompletions(), name, "SkillOpt");
3179
+ const tokenUsage = optimizationTokenUsageFromSummary(optimizerUsage, optimizerReceipts);
3180
+ const runtime = observedExternalOptimizerRuntime(runtimeIdentity);
3181
+ const combinedCost = combineComparisonCosts([{
3182
+ label: "evaluation",
3183
+ cost: evaluationCost
3184
+ }, {
3185
+ label: "optimizer model",
3186
+ cost: optimizerCost
3187
+ }]);
3188
+ const searchHistory = config.searchLedger ? await recordSkillOptSearch({
3189
+ name,
3190
+ path: config.searchLedger.path ?? `${context.runDir}/search-ledger.jsonl`,
3191
+ searchId: runId,
3192
+ identity: config.searchLedger.identity,
3193
+ storage: context.storage,
3194
+ seed: input.seed,
3195
+ baselineSurface: input.baselineSurface,
3196
+ trainScenarios: input.trainScenarios,
3197
+ selectionScenarios: input.selectionScenarios,
3198
+ evaluationLimit: config.maxEvaluations,
3199
+ observations: readExternalOptimizerObservationArtifact({
3200
+ summary: observationLog.summary(),
3201
+ storage: context.storage
3202
+ }),
3203
+ selected: result.bestCandidate,
3204
+ generationAccounting: {
3205
+ tokens: optimizerUsage.usageComplete ? {
3206
+ status: "known",
3207
+ inputTokens: optimizerUsage.inputTokens,
3208
+ outputTokens: optimizerUsage.outputTokens,
3209
+ cachedTokens: optimizerUsage.cachedTokens
3210
+ } : {
3211
+ status: "unknown",
3212
+ reason: "an optimizer call reported no token usage"
3213
+ },
3214
+ cost: optimizerCost.accountingComplete ? {
3215
+ status: "known",
3216
+ usd: optimizerCost.totalCostUsd,
3217
+ source: "provider"
3218
+ } : {
3219
+ status: "unknown",
3220
+ knownLowerBoundUsd: optimizerCost.totalCostUsd,
3221
+ reason: optimizerCost.incompleteReasons.join("; ") || "optimizer spend incomplete"
3222
+ }
3223
+ }
3224
+ }) : void 0;
3225
+ return {
3226
+ winnerSurface: result.bestCandidate,
3227
+ ...searchHistory ? { searchHistory } : {},
3228
+ cost: combinedCost,
3229
+ durationMs: Date.now() - context.started,
3230
+ provenance: {
3231
+ ...runtime,
3232
+ optimizerModel: config.optimizer.model,
3233
+ optimizerCallRef: config.optimizer.callRef,
3234
+ compatibleRunId,
3235
+ runId,
3236
+ resumed: result.resumed,
3237
+ evaluationCount: runBudget.acceptedEvaluations(),
3238
+ artifactDir: outputDir,
3239
+ ...tokenUsage ? { tokenUsage } : {},
3240
+ observations: observationLog.summary(),
3241
+ modelExecutions: executionLog.summary()
2917
3242
  }
2918
3243
  };
2919
3244
  }
2920
3245
  //#endregion
2921
3246
  export { importExternalEvaluations as a, composeGate as c, readExternalOptimizerObservationArtifact as d, externalSurface as i, externalTextOptimizationMethod as l, compareOptimizationMethods as n, importGepaPopulation as o, gepaOptimizationMethod as r, heldOutGate as s, skillOptOptimizationMethod as t, decodeExternalTextCandidate as u };
2922
3247
 
2923
- //# sourceMappingURL=skillopt-optimization-method-kyL94-ri.js.map
3248
+ //# sourceMappingURL=skillopt-optimization-method-DLKqdhcR.js.map