@tangle-network/agent-eval 0.216.0 → 0.217.1

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 (553) hide show
  1. package/CHANGELOG.md +141 -57
  2. package/README.md +2 -2
  3. package/dist/adapters/http.d.ts +3 -3
  4. package/dist/{agent-profile-CIA2Atnt.d.ts → agent-profile-DTt8uGP9.d.ts} +5 -18
  5. package/dist/agent-profile-DTt8uGP9.d.ts.map +1 -0
  6. package/dist/{agent-profile-cell-BYc0bxsL.js → agent-profile-cell-B1V1gUZs.js} +4 -53
  7. package/dist/agent-profile-cell-B1V1gUZs.js.map +1 -0
  8. package/dist/{agent-profile-cell-BNp-Js9F.d.ts → agent-profile-cell-BcpFbNd5.d.ts} +2 -22
  9. package/dist/agent-profile-cell-BcpFbNd5.d.ts.map +1 -0
  10. package/dist/{agreement-irr-DsTURxdr.js → agreement-irr-BhAqjluA.js} +5 -5
  11. package/dist/agreement-irr-BhAqjluA.js.map +1 -0
  12. package/dist/analyst/index.d.ts +37 -170
  13. package/dist/analyst/index.d.ts.map +1 -1
  14. package/dist/analyst/index.js +17 -192
  15. package/dist/analyst/index.js.map +1 -1
  16. package/dist/{analyze-runs-3xpby3p2.js → analyze-runs-DqPJaJ4X.js} +763 -555
  17. package/dist/analyze-runs-DqPJaJ4X.js.map +1 -0
  18. package/dist/{analyze-runs-CSDAh8A7.d.ts → analyze-runs-DyeNcenW.d.ts} +18 -16
  19. package/dist/analyze-runs-DyeNcenW.d.ts.map +1 -0
  20. package/dist/authenticity/index.d.ts +0 -23
  21. package/dist/authenticity/index.d.ts.map +1 -1
  22. package/dist/authenticity/index.js +1 -34
  23. package/dist/authenticity/index.js.map +1 -1
  24. package/dist/{benchmark-command-CByl9dxG.js → benchmark-command-xQK8nOI6.js} +591 -109
  25. package/dist/benchmark-command-xQK8nOI6.js.map +1 -0
  26. package/dist/benchmarks/index.d.ts +5 -6
  27. package/dist/benchmarks/index.d.ts.map +1 -1
  28. package/dist/benchmarks/index.js +4 -4
  29. package/dist/benchmarks/index.js.map +1 -1
  30. package/dist/builder-eval/index.d.ts +3 -3
  31. package/dist/builder-eval/index.js +2 -2
  32. package/dist/builder-eval/index.js.map +1 -1
  33. package/dist/campaign/index.d.ts +8 -8
  34. package/dist/campaign/index.js +15 -15
  35. package/dist/{campaign-BQ-Jujuj.js → campaign-CJGkxAQ6.js} +256 -765
  36. package/dist/campaign-CJGkxAQ6.js.map +1 -0
  37. package/dist/{campaign-evidence-OcUciD-N.js → campaign-evidence-CQYw8_0H.js} +10 -18
  38. package/dist/{campaign-evidence-OcUciD-N.js.map → campaign-evidence-CQYw8_0H.js.map} +1 -1
  39. package/dist/{canonical-BsZVgBhW.js → canonical-Dq2hOQ8L.js} +2 -2
  40. package/dist/{canonical-BsZVgBhW.js.map → canonical-Dq2hOQ8L.js.map} +1 -1
  41. package/dist/cell-spend-DEWR3nj-.js +90 -0
  42. package/dist/cell-spend-DEWR3nj-.js.map +1 -0
  43. package/dist/{chat-client-DthPOYGd.js → chat-client-ldqxYYTN.js} +2 -2
  44. package/dist/{chat-client-DthPOYGd.js.map → chat-client-ldqxYYTN.js.map} +1 -1
  45. package/dist/{chat-json-call-BrKsyspg.js → chat-json-call-DavzexSp.js} +3 -2
  46. package/dist/chat-json-call-DavzexSp.js.map +1 -0
  47. package/dist/{claim-BXcZw-jo.js → claim-BPVuyHuy.js} +4 -4
  48. package/dist/claim-BPVuyHuy.js.map +1 -0
  49. package/dist/cli.js +113 -12
  50. package/dist/cli.js.map +1 -1
  51. package/dist/{client-BzL9niqi.d.ts → client-hwo3cJjR.d.ts} +3 -16
  52. package/dist/client-hwo3cJjR.d.ts.map +1 -0
  53. package/dist/{cluster-bootstrap-B3JywQQn.js → cluster-bootstrap-DEwwhl0C.js} +3 -3
  54. package/dist/{cluster-bootstrap-B3JywQQn.js.map → cluster-bootstrap-DEwwhl0C.js.map} +1 -1
  55. package/dist/{produced-state-ZCtDBxAE.js → completion-verifier-B_jw6C9p.js} +9 -64
  56. package/dist/completion-verifier-B_jw6C9p.js.map +1 -0
  57. package/dist/contract/index.d.ts +13 -13
  58. package/dist/contract/index.js +1041 -1473
  59. package/dist/contract/index.js.map +1 -1
  60. package/dist/{cost-ledger-D2FnJPBF.js → cost-ledger-D0352Z4d.js} +832 -817
  61. package/dist/cost-ledger-D0352Z4d.js.map +1 -0
  62. package/dist/{cost-ledger-CO7UyEcQ.d.ts → cost-ledger-Jk62OBfF.d.ts} +12 -47
  63. package/dist/cost-ledger-Jk62OBfF.d.ts.map +1 -0
  64. package/dist/dataset-DQqhOCPt.d.ts.map +1 -1
  65. package/dist/{default-registry-Cn1LQ2Ve.js → default-registry-ClYjq3QE.js} +8 -11
  66. package/dist/default-registry-ClYjq3QE.js.map +1 -0
  67. package/dist/{default-registry-BrWh62zf.d.ts → default-registry-DXgLmoDI.d.ts} +7 -50
  68. package/dist/default-registry-DXgLmoDI.d.ts.map +1 -0
  69. package/dist/{define-agent-eval-Ch3MWX6k.js → define-agent-eval-BDxNlP3D.js} +10 -10
  70. package/dist/define-agent-eval-BDxNlP3D.js.map +1 -0
  71. package/dist/{define-agent-eval-CEWkX5wZ.d.ts → define-agent-eval-BIkH_gAR.d.ts} +9 -9
  72. package/dist/define-agent-eval-BIkH_gAR.d.ts.map +1 -0
  73. package/dist/{descriptive-CnU8Yq29.js → descriptive-CVNy48rR.js} +2 -2
  74. package/dist/{descriptive-CnU8Yq29.js.map → descriptive-CVNy48rR.js.map} +1 -1
  75. package/dist/diagnosis/index.d.ts +4 -14
  76. package/dist/diagnosis/index.d.ts.map +1 -1
  77. package/dist/diagnosis/index.js +67 -28
  78. package/dist/diagnosis/index.js.map +1 -1
  79. package/dist/{dspy-rlm-engine-D-KX_e64.js → dspy-rlm-engine-DhdCr1Dc.js} +5 -10
  80. package/dist/dspy-rlm-engine-DhdCr1Dc.js.map +1 -0
  81. package/dist/{emitter-HcCmFQl_.d.ts → emitter-DABYYTcH.d.ts} +5 -5
  82. package/dist/emitter-DABYYTcH.d.ts.map +1 -0
  83. package/dist/emitter-DbMXUIVP.js.map +1 -1
  84. package/dist/{engine-C_zNWfM8.d.ts → engine-BvZ0R-36.d.ts} +18 -22
  85. package/dist/engine-BvZ0R-36.d.ts.map +1 -0
  86. package/dist/{equal-terms-Blx9Zk5I.js → equal-terms-DbPGcVtI.js} +2 -2
  87. package/dist/equal-terms-DbPGcVtI.js.map +1 -0
  88. package/dist/{errors-Dngq5h35.js → errors-BcOs5MKW.js} +6 -8
  89. package/dist/{errors-Dngq5h35.js.map → errors-BcOs5MKW.js.map} +1 -1
  90. package/dist/{eval-campaign-4byTtqrf.js → eval-campaign-BLEfBGbA.js} +6 -6
  91. package/dist/{eval-campaign-4byTtqrf.js.map → eval-campaign-BLEfBGbA.js.map} +1 -1
  92. package/dist/{evaluation-Cn2dRZIz.d.ts → evaluation-jTjC_QQD.d.ts} +8 -8
  93. package/dist/evaluation-jTjC_QQD.d.ts.map +1 -0
  94. package/dist/evaluation.d.ts +2 -2
  95. package/dist/evaluation.js +1 -1
  96. package/dist/evaluation.js.map +1 -1
  97. package/dist/{exact-types-CD0lf5Qd.d.ts → exact-types-CflbJ9f3.d.ts} +2 -2
  98. package/dist/{exact-types-CD0lf5Qd.d.ts.map → exact-types-CflbJ9f3.d.ts.map} +1 -1
  99. package/dist/{exec-ChJ6d5if.js → exec-CpbtOXVt.js} +2 -24
  100. package/dist/{exec-ChJ6d5if.js.map → exec-CpbtOXVt.js.map} +1 -1
  101. package/dist/execution-tracks-CpgFPpS5.js.map +1 -1
  102. package/dist/experiment/index.d.ts +331 -33
  103. package/dist/experiment/index.d.ts.map +1 -1
  104. package/dist/experiment/index.js +303 -101
  105. package/dist/experiment/index.js.map +1 -1
  106. package/dist/{exporters-X4xwla8A.js → exporters-Cl6IeNAu.js} +3 -3
  107. package/dist/exporters-Cl6IeNAu.js.map +1 -0
  108. package/dist/{exporters-ChTnR90l.d.ts → exporters-Dk3oEbK_.d.ts} +2 -4
  109. package/dist/{exporters-ChTnR90l.d.ts.map → exporters-Dk3oEbK_.d.ts.map} +1 -1
  110. package/dist/{external-optimizer-process-nnsY5D_4.js → external-optimizer-process-KVFGvYX1.js} +4 -3
  111. package/dist/external-optimizer-process-KVFGvYX1.js.map +1 -0
  112. package/dist/{external-optimizer-subprocess-DcerlZSG.js → external-optimizer-subprocess-XIHBOSKt.js} +551 -553
  113. package/dist/external-optimizer-subprocess-XIHBOSKt.js.map +1 -0
  114. package/dist/{extract-usage-BrnzRJ6H.js → extract-usage-BZLU01kR.js} +2 -23
  115. package/dist/{extract-usage-BrnzRJ6H.js.map → extract-usage-BZLU01kR.js.map} +1 -1
  116. package/dist/{failure-cluster-CbgEDcFJ.d.ts → failure-cluster-DN0t63Z0.d.ts} +4 -43
  117. package/dist/failure-cluster-DN0t63Z0.d.ts.map +1 -0
  118. package/dist/{failure-taxonomy-CjabTATj.js → failure-taxonomy-Bx5oWqaW.js} +2 -19
  119. package/dist/{failure-taxonomy-CjabTATj.js.map → failure-taxonomy-Bx5oWqaW.js.map} +1 -1
  120. package/dist/{feedback-trajectory-DkaDj0dj.d.ts → feedback-trajectory-BWmhRBGu.d.ts} +8 -13
  121. package/dist/feedback-trajectory-BWmhRBGu.d.ts.map +1 -0
  122. package/dist/{semantic-concept-judge-zQBG9hHU.js → findings-store-BMVQtEsm.js} +13 -255
  123. package/dist/findings-store-BMVQtEsm.js.map +1 -0
  124. package/dist/fuzz.d.ts +20 -63
  125. package/dist/fuzz.d.ts.map +1 -1
  126. package/dist/fuzz.js +62 -108
  127. package/dist/fuzz.js.map +1 -1
  128. package/dist/{hf-dataset-BR2yhuNn.js → hf-dataset-D9f7-oX7.js} +4 -24
  129. package/dist/hf-dataset-D9f7-oX7.js.map +1 -0
  130. package/dist/hosted/index.d.ts +2 -2
  131. package/dist/hosted/index.js +2 -2
  132. package/dist/{index-DHKEAv3s.d.ts → index-9jJ2fKSX.d.ts} +2 -64
  133. package/dist/index-9jJ2fKSX.d.ts.map +1 -0
  134. package/dist/{index-oQ4aHziK.d.ts → index-BLGqZ81N.d.ts} +11 -16
  135. package/dist/{index-oQ4aHziK.d.ts.map → index-BLGqZ81N.d.ts.map} +1 -1
  136. package/dist/{index-DlH0Y9gI.d.ts → index-BiT6RtNH.d.ts} +31 -43
  137. package/dist/index-BiT6RtNH.d.ts.map +1 -0
  138. package/dist/{index-Ch9VxCpK.d.ts → index-CX-GAUpw.d.ts} +4 -8
  139. package/dist/index-CX-GAUpw.d.ts.map +1 -0
  140. package/dist/{index-CPJJr98o.d.ts → index-CiRwLv2R.d.ts} +5 -68
  141. package/dist/index-CiRwLv2R.d.ts.map +1 -0
  142. package/dist/{index-NvGBiO8H.d.ts → index-ZuWx52WG.d.ts} +266 -495
  143. package/dist/index-ZuWx52WG.d.ts.map +1 -0
  144. package/dist/index.d.ts +2256 -2165
  145. package/dist/index.d.ts.map +1 -1
  146. package/dist/index.js +514 -1192
  147. package/dist/index.js.map +1 -1
  148. package/dist/{integrity-BV1ZDf42.js → integrity-DOd9Q86O.js} +7 -12
  149. package/dist/integrity-DOd9Q86O.js.map +1 -0
  150. package/dist/{integrity-BvnVARVl.js → integrity-W4CADcFc.js} +3 -7
  151. package/dist/{integrity-BvnVARVl.js.map → integrity-W4CADcFc.js.map} +1 -1
  152. package/dist/{integrity-CCAxGVK6.d.ts → integrity-_qgZLA5p.d.ts} +4 -6
  153. package/dist/{integrity-CCAxGVK6.d.ts.map → integrity-_qgZLA5p.d.ts.map} +1 -1
  154. package/dist/{internal-CRHwS9iz.js → internal-BTK91Bqt.js} +3 -3
  155. package/dist/{internal-CRHwS9iz.js.map → internal-BTK91Bqt.js.map} +1 -1
  156. package/dist/interval-Dq9gt7jx.js +219 -0
  157. package/dist/interval-Dq9gt7jx.js.map +1 -0
  158. package/dist/interval-ohuOJurX.d.ts +47 -0
  159. package/dist/interval-ohuOJurX.d.ts.map +1 -0
  160. package/dist/{journal-DvKCvjty.js → journal-CR4QikYp.js} +110 -110
  161. package/dist/journal-CR4QikYp.js.map +1 -0
  162. package/dist/json-BhdsJaOQ.js +111 -0
  163. package/dist/json-BhdsJaOQ.js.map +1 -0
  164. package/dist/{judge-calibration-N44V04Se.js → judge-calibration-BkXMIWA4.js} +3 -3
  165. package/dist/{judge-calibration-N44V04Se.js.map → judge-calibration-BkXMIWA4.js.map} +1 -1
  166. package/dist/{judge-gate-B1qYnkpi.js → judge-gate-Co5tuh57.js} +4 -27
  167. package/dist/judge-gate-Co5tuh57.js.map +1 -0
  168. package/dist/{judge-gate-DNcUrRFA.d.ts → judge-gate-DsL0yFcb.d.ts} +9 -10
  169. package/dist/judge-gate-DsL0yFcb.d.ts.map +1 -0
  170. package/dist/{kind-factory-CbZ-6tvu.js → kind-factory-Gy4fXixd.js} +88 -17
  171. package/dist/kind-factory-Gy4fXixd.js.map +1 -0
  172. package/dist/ledger-core/index.d.ts +2 -2
  173. package/dist/ledger-core/index.js +4 -4
  174. package/dist/{ledger-core-B2hahzrt.js → ledger-core-DrJhbms9.js} +5 -84
  175. package/dist/ledger-core-DrJhbms9.js.map +1 -0
  176. package/dist/{llm-client-DQveoxSM.js → llm-client-BshCREn6.js} +90 -219
  177. package/dist/llm-client-BshCREn6.js.map +1 -0
  178. package/dist/{llm-judge-PXV7Xljl.js → llm-judge-C8jMTNNG.js} +501 -931
  179. package/dist/llm-judge-C8jMTNNG.js.map +1 -0
  180. package/dist/matrix/index.d.ts +4 -4
  181. package/dist/matrix/index.js +3 -2
  182. package/dist/{matrix-_BV9-Lk5.js → matrix-B8l-Nsxd.js} +7 -96
  183. package/dist/matrix-B8l-Nsxd.js.map +1 -0
  184. package/dist/{matrix-CHMiebFx.d.ts → matrix-DHe-dwVJ.d.ts} +10 -19
  185. package/dist/matrix-DHe-dwVJ.d.ts.map +1 -0
  186. package/dist/{paired-tests-jbwPdSz5.js → mean-BbA_JCzW.js} +45 -5
  187. package/dist/mean-BbA_JCzW.js.map +1 -0
  188. package/dist/meta-eval/index.d.ts +6 -6
  189. package/dist/meta-eval/index.js +10 -10
  190. package/dist/meta-eval/index.js.map +1 -1
  191. package/dist/metrics-BKaPBtIG.js.map +1 -1
  192. package/dist/mint-BRZXuwRi.d.ts +81 -0
  193. package/dist/mint-BRZXuwRi.d.ts.map +1 -0
  194. package/dist/{mint-Csor1BLJ.js → mint-zszyYlpA.js} +4 -4
  195. package/dist/{mint-Csor1BLJ.js.map → mint-zszyYlpA.js.map} +1 -1
  196. package/dist/{multi-layer-verifier-BUaQ4C17.d.ts → multi-layer-verifier-DEgMUk6v.d.ts} +2 -2
  197. package/dist/{multi-layer-verifier-BUaQ4C17.d.ts.map → multi-layer-verifier-DEgMUk6v.d.ts.map} +1 -1
  198. package/dist/{multiplicity-D9cjmStq.js → multiplicity-Sg0U7h8j.js} +2 -2
  199. package/dist/{multiplicity-D9cjmStq.js.map → multiplicity-Sg0U7h8j.js.map} +1 -1
  200. package/dist/multishot/golden/index.d.ts +1 -23
  201. package/dist/multishot/golden/index.d.ts.map +1 -1
  202. package/dist/multishot/golden/index.js +5 -8
  203. package/dist/multishot/golden/index.js.map +1 -1
  204. package/dist/multishot/index.d.ts +3 -12
  205. package/dist/multishot/index.d.ts.map +1 -1
  206. package/dist/multishot/index.js +4 -3
  207. package/dist/multishot/index.js.map +1 -1
  208. package/dist/nonnegative-number-DvdMxg_f.js +9 -0
  209. package/dist/nonnegative-number-DvdMxg_f.js.map +1 -0
  210. package/dist/openapi.json +114 -10
  211. package/dist/{otel-spans-C8YIJWy1.js → otel-spans-CdN909k1.js} +3 -3
  212. package/dist/{otel-spans-C8YIJWy1.js.map → otel-spans-CdN909k1.js.map} +1 -1
  213. package/dist/{paired-arms-DzKn0TfY.js → paired-arms-Ct4LTKc1.js} +32 -9
  214. package/dist/paired-arms-Ct4LTKc1.js.map +1 -0
  215. package/dist/{paired-binary-Q36bhn2R.js → paired-binary-B_nejA44.js} +3 -36
  216. package/dist/paired-binary-B_nejA44.js.map +1 -0
  217. package/dist/{paired-promotion-decision-DPKz8ZnF.d.ts → paired-promotion-decision-CQMJ5xGN.d.ts} +2 -34
  218. package/dist/paired-promotion-decision-CQMJ5xGN.d.ts.map +1 -0
  219. package/dist/{paired-promotion-decision-BN6IQTiu.js → paired-promotion-decision-D0SHb-ZL.js} +3 -3
  220. package/dist/{paired-promotion-decision-BN6IQTiu.js.map → paired-promotion-decision-D0SHb-ZL.js.map} +1 -1
  221. package/dist/{search-kernel-BztlERLv.js → pareto-BzsxidFD.js} +883 -861
  222. package/dist/pareto-BzsxidFD.js.map +1 -0
  223. package/dist/pipelines/index.d.ts +16 -19
  224. package/dist/pipelines/index.d.ts.map +1 -1
  225. package/dist/pipelines/index.js +4 -68
  226. package/dist/pipelines/index.js.map +1 -1
  227. package/dist/{power-and-mde-fK5Qocwo.js → power-and-mde-N5nU4_Ly.js} +3 -3
  228. package/dist/{power-and-mde-fK5Qocwo.js.map → power-and-mde-N5nU4_Ly.js.map} +1 -1
  229. package/dist/predicate-FdKmElA_.js +38 -0
  230. package/dist/predicate-FdKmElA_.js.map +1 -0
  231. package/dist/{prime-protocol-DcAK9pC8.js → prime-protocol-BFgGrEMP.js} +3 -3
  232. package/dist/prime-protocol-BFgGrEMP.js.map +1 -0
  233. package/dist/{prime-protocol-CEE4BR9N.d.ts → prime-protocol-BWG2DQIk.d.ts} +4 -22
  234. package/dist/prime-protocol-BWG2DQIk.d.ts.map +1 -0
  235. package/dist/profile-cell.d.ts +2 -2
  236. package/dist/profile-cell.js +2 -2
  237. package/dist/{release-confidence-BK2QCB5M.d.ts → promotion-gate-DaY95yU6.d.ts} +105 -106
  238. package/dist/promotion-gate-DaY95yU6.d.ts.map +1 -0
  239. package/dist/{promotion-policy-CWW35UWq.js → promotion-policy-6A8osGr_.js} +4 -4
  240. package/dist/{promotion-policy-CWW35UWq.js.map → promotion-policy-6A8osGr_.js.map} +1 -1
  241. package/dist/{proposal-findings-BZiMTzAF.js → proposal-findings-BbWidvUk.js} +3 -3
  242. package/dist/proposal-findings-BbWidvUk.js.map +1 -0
  243. package/dist/{query-B1D1qp2Z.js → query-B_RZ36an.js} +5 -5
  244. package/dist/query-B_RZ36an.js.map +1 -0
  245. package/dist/{query-DK1nWcmp.d.ts → query-Cmv_U8vf.d.ts} +4 -24
  246. package/dist/{query-DK1nWcmp.d.ts.map → query-Cmv_U8vf.d.ts.map} +1 -1
  247. package/dist/{random-Dn5fPWkt.js → random-DDDcC7YU.js} +2 -2
  248. package/dist/{random-Dn5fPWkt.js.map → random-DDDcC7YU.js.map} +1 -1
  249. package/dist/{raw-provider-sink-rB2DYxr6.js → raw-provider-sink-75w4FWBj.js} +2 -2
  250. package/dist/{raw-provider-sink-rB2DYxr6.js.map → raw-provider-sink-75w4FWBj.js.map} +1 -1
  251. package/dist/{redact-Cveoq6fJ.d.ts → redact-DXdlFb_U.d.ts} +4 -21
  252. package/dist/redact-DXdlFb_U.d.ts.map +1 -0
  253. package/dist/{redact-Dk1ZdJEm.js → redact-mtkTiJVk.js} +92 -98
  254. package/dist/redact-mtkTiJVk.js.map +1 -0
  255. package/dist/{registry-JYfPxcVz.d.ts → registry-ssNoHzwD.d.ts} +5 -5
  256. package/dist/{registry-JYfPxcVz.d.ts.map → registry-ssNoHzwD.d.ts.map} +1 -1
  257. package/dist/{release-confidence-Dbe9AS_X.js → release-confidence-CYIFH-fp.js} +6 -11
  258. package/dist/release-confidence-CYIFH-fp.js.map +1 -0
  259. package/dist/{report-command-y8H6RSX8.js → render-C-w2EZ6p.js} +331 -554
  260. package/dist/render-C-w2EZ6p.js.map +1 -0
  261. package/dist/reporting-html-Kvlc8oMt.js +100 -0
  262. package/dist/reporting-html-Kvlc8oMt.js.map +1 -0
  263. package/dist/reporting.d.ts +6 -6
  264. package/dist/reporting.js +8 -8
  265. package/dist/{researcher-f6mZhh58.d.ts → researcher-0ABVIdGa.d.ts} +9 -9
  266. package/dist/{researcher-f6mZhh58.d.ts.map → researcher-0ABVIdGa.d.ts.map} +1 -1
  267. package/dist/reward-DrZ71vnf.d.ts +55 -0
  268. package/dist/reward-DrZ71vnf.d.ts.map +1 -0
  269. package/dist/{reward-hacking-BFcQgkux.js → reward-hacking-ByuETaIb.js} +3 -3
  270. package/dist/{reward-hacking-BFcQgkux.js.map → reward-hacking-ByuETaIb.js.map} +1 -1
  271. package/dist/{reward-hacking-DHA7c1l8.d.ts → reward-hacking-E52wq86n.d.ts} +5 -18
  272. package/dist/reward-hacking-E52wq86n.d.ts.map +1 -0
  273. package/dist/reward-nw2xZGZG.js.map +1 -1
  274. package/dist/rl.d.ts +117 -295
  275. package/dist/rl.d.ts.map +1 -1
  276. package/dist/rl.js +27 -747
  277. package/dist/rl.js.map +1 -1
  278. package/dist/rollout/index.d.ts +5 -4
  279. package/dist/rollout/index.js +7 -8
  280. package/dist/{rollout-D9bKKBnZ.js → rollout-D6C50mfA.js} +88 -13
  281. package/dist/rollout-D6C50mfA.js.map +1 -0
  282. package/dist/round-decimal-COrKglMh.js +10 -0
  283. package/dist/round-decimal-COrKglMh.js.map +1 -0
  284. package/dist/{rubric-predictive-validity-BsgkBfT0.js → rubric-predictive-validity-D3_oI72N.js} +3 -3
  285. package/dist/{rubric-predictive-validity-BsgkBfT0.js.map → rubric-predictive-validity-D3_oI72N.js.map} +1 -1
  286. package/dist/{rubric-predictive-validity-2SgHxoa5.d.ts → rubric-predictive-validity-DiwT8PbL.d.ts} +2 -2
  287. package/dist/{rubric-predictive-validity-2SgHxoa5.d.ts.map → rubric-predictive-validity-DiwT8PbL.d.ts.map} +1 -1
  288. package/dist/{run-record-D1Hw-Jml.d.ts → run-record-CaxbLq6Y.d.ts} +5 -11
  289. package/dist/run-record-CaxbLq6Y.d.ts.map +1 -0
  290. package/dist/{run-record-ES07wfz9.js → run-record-CysKLB93.js} +3 -5
  291. package/dist/run-record-CysKLB93.js.map +1 -0
  292. package/dist/{run-record-DlTZ_lqe.js → run-record-DhEJgoPz.js} +4 -4
  293. package/dist/{run-record-DlTZ_lqe.js.map → run-record-DhEJgoPz.js.map} +1 -1
  294. package/dist/sandbox-harness-BlSOu4LX.d.ts.map +1 -1
  295. package/dist/{schema-CSf6qWgZ.js → schema-Bt2vLFm3.js} +2 -14
  296. package/dist/schema-Bt2vLFm3.js.map +1 -0
  297. package/dist/schema-C-ziyJD7.d.ts.map +1 -1
  298. package/dist/{schema-2g7trUwH.d.ts → schema-D6EVKzTB.d.ts} +4 -5
  299. package/dist/schema-D6EVKzTB.d.ts.map +1 -0
  300. package/dist/{schema-BuiujZ-g.js → schema-DxcKTzbi.js} +2 -2
  301. package/dist/schema-DxcKTzbi.js.map +1 -0
  302. package/dist/search/index.d.ts +39 -53
  303. package/dist/search/index.d.ts.map +1 -1
  304. package/dist/search/index.js +4 -4
  305. package/dist/{search-kernel-CpcKH5Ih.d.ts → search-kernel-DxqjBxA-.d.ts} +18 -31
  306. package/dist/search-kernel-DxqjBxA-.d.ts.map +1 -0
  307. package/dist/{search-ledger-d7V8o9Lk.js → search-ledger-TUvB5gWH.js} +189 -199
  308. package/dist/search-ledger-TUvB5gWH.js.map +1 -0
  309. package/dist/{search-ledger-file-BqOo-bVo.js → search-ledger-file-UKCO2r8a.js} +4 -4
  310. package/dist/search-ledger-file-UKCO2r8a.js.map +1 -0
  311. package/dist/search-ledger-types-p2xKfiDJ.d.ts.map +1 -1
  312. package/dist/{search-shipper-er4pK5_Y.js → search-shipper-Cw2z3-td.js} +4 -4
  313. package/dist/search-shipper-Cw2z3-td.js.map +1 -0
  314. package/dist/{search-summary-CBvz3u_S.js → search-summary-DQIvJsSB.js} +5 -5
  315. package/dist/{search-summary-CBvz3u_S.js.map → search-summary-DQIvJsSB.js.map} +1 -1
  316. package/dist/{sequential-CzK5DarL.js → sequential-BVv1sjsw.js} +2 -32
  317. package/dist/{sequential-CzK5DarL.js.map → sequential-BVv1sjsw.js.map} +1 -1
  318. package/dist/{sequential-D-1PPCmM.js → sequential-CimQrbjv.js} +5 -5
  319. package/dist/sequential-CimQrbjv.js.map +1 -0
  320. package/dist/{sequential-BhsrMupG.d.ts → sequential-KwGspfeR.d.ts} +2 -9
  321. package/dist/{sequential-BhsrMupG.d.ts.map → sequential-KwGspfeR.d.ts.map} +1 -1
  322. package/dist/{sequential-eprocess-D1jKoihe.js → sequential-eprocess-DodI6RoF.js} +2 -2
  323. package/dist/{sequential-eprocess-D1jKoihe.js.map → sequential-eprocess-DodI6RoF.js.map} +1 -1
  324. package/dist/{server-DbcC7xMl.js → server-DoVbqqtJ.js} +101 -101
  325. package/dist/server-DoVbqqtJ.js.map +1 -0
  326. package/dist/{single-run-lock-fVu3MZWH.js → single-run-lock-U58yf8N6.js} +2 -2
  327. package/dist/{single-run-lock-fVu3MZWH.js.map → single-run-lock-U58yf8N6.js.map} +1 -1
  328. package/dist/{skillopt-optimization-method-CCtzralq.js → skillopt-optimization-method-kyL94-ri.js} +428 -91
  329. package/dist/skillopt-optimization-method-kyL94-ri.js.map +1 -0
  330. package/dist/{spans-D9_ehFuk.d.ts → spans-CVngGij3.d.ts} +2 -2
  331. package/dist/{spans-D9_ehFuk.d.ts.map → spans-CVngGij3.d.ts.map} +1 -1
  332. package/dist/{statistical-heldout-1Gbmex7v.js → statistical-heldout-Bksv92Th.js} +3 -3
  333. package/dist/statistical-heldout-Bksv92Th.js.map +1 -0
  334. package/dist/{statistical-heldout-BeR4bOdg.d.ts → statistical-heldout-C9AbgREN.d.ts} +8 -67
  335. package/dist/statistical-heldout-C9AbgREN.d.ts.map +1 -0
  336. package/dist/{steps-Bg5-KVx1.d.ts → steps-DlepJPwD.d.ts} +2 -56
  337. package/dist/steps-DlepJPwD.d.ts.map +1 -0
  338. package/dist/{store-C4avFjIi.d.ts → store-B3nWRy3B.d.ts} +2 -2
  339. package/dist/{store-C4avFjIi.d.ts.map → store-B3nWRy3B.d.ts.map} +1 -1
  340. package/dist/{store-otlp-DtB4Slsr.js → store-otlp-BteDAbHK.js} +135 -132
  341. package/dist/store-otlp-BteDAbHK.js.map +1 -0
  342. package/dist/{store-tool-spans-fZIigrpP.js → store-tool-spans-D5l_OfTJ.js} +9 -9
  343. package/dist/store-tool-spans-D5l_OfTJ.js.map +1 -0
  344. package/dist/{store-tool-spans-DR1SrCLK.d.ts → store-tool-spans-DZS0HWVf.d.ts} +157 -165
  345. package/dist/store-tool-spans-DZS0HWVf.d.ts.map +1 -0
  346. package/dist/storyboard/index.d.ts +4 -11
  347. package/dist/storyboard/index.d.ts.map +1 -1
  348. package/dist/storyboard/index.js +21 -19
  349. package/dist/storyboard/index.js.map +1 -1
  350. package/dist/{summary-report-DtdRucM0.js → summary-report-BsXJoYX5.js} +588 -598
  351. package/dist/summary-report-BsXJoYX5.js.map +1 -0
  352. package/dist/{summary-report-C-CtItCN.d.ts → summary-report-DM7tlml1.d.ts} +16 -20
  353. package/dist/summary-report-DM7tlml1.d.ts.map +1 -0
  354. package/dist/supervisor-run/index.d.ts +189 -153
  355. package/dist/supervisor-run/index.d.ts.map +1 -1
  356. package/dist/supervisor-run/index.js +58 -450
  357. package/dist/supervisor-run/index.js.map +1 -1
  358. package/dist/{systemone-CpTLAlqb.d.ts → systemone-Bp_Ac0p1.d.ts} +6 -6
  359. package/dist/{systemone-CpTLAlqb.d.ts.map → systemone-Bp_Ac0p1.d.ts.map} +1 -1
  360. package/dist/systemone-protocol.js +1 -1
  361. package/dist/{systemone-review-B_yo1xsd.d.ts → systemone-review-CwE6JGIp.d.ts} +2 -2
  362. package/dist/{systemone-review-B_yo1xsd.d.ts.map → systemone-review-CwE6JGIp.d.ts.map} +1 -1
  363. package/dist/{systemone-review-BZWfrtq1.js → systemone-review-DzdOJ8I6.js} +3 -3
  364. package/dist/{systemone-review-BZWfrtq1.js.map → systemone-review-DzdOJ8I6.js.map} +1 -1
  365. package/dist/systemone.d.ts +5 -5
  366. package/dist/systemone.js +5 -5
  367. package/dist/systemone.js.map +1 -1
  368. package/dist/{task-failure-attributes-DngaLdE4.js → task-failure-attributes-BMsblaDh.js} +3 -3
  369. package/dist/task-failure-attributes-BMsblaDh.js.map +1 -0
  370. package/dist/{terminal-record-BHocwFw1.js → terminal-record-78g6E4vh.js} +17 -13
  371. package/dist/terminal-record-78g6E4vh.js.map +1 -0
  372. package/dist/{tool-groups-mcxOXVlb.d.ts → tool-groups-DyNz2JZ_.d.ts} +3 -3
  373. package/dist/tool-groups-DyNz2JZ_.d.ts.map +1 -0
  374. package/dist/{tool-waste-Wi4g6Ekb.d.ts → tool-waste-CkjzWmeY.d.ts} +53 -56
  375. package/dist/tool-waste-CkjzWmeY.d.ts.map +1 -0
  376. package/dist/{tool-waste-D52PqU9Q.js → tool-waste-DLsjS_p-.js} +5 -5
  377. package/dist/{tool-waste-D52PqU9Q.js.map → tool-waste-DLsjS_p-.js.map} +1 -1
  378. package/dist/{trace-questions-DG7nqLQ7.d.ts → trace-questions-xxwgsuMi.d.ts} +5 -10
  379. package/dist/{trace-questions-DG7nqLQ7.d.ts.map → trace-questions-xxwgsuMi.d.ts.map} +1 -1
  380. package/dist/trace-repair/index.d.ts +15 -212
  381. package/dist/trace-repair/index.d.ts.map +1 -1
  382. package/dist/trace-repair/index.js +865 -987
  383. package/dist/trace-repair/index.js.map +1 -1
  384. package/dist/traces.d.ts +76 -86
  385. package/dist/traces.d.ts.map +1 -1
  386. package/dist/traces.js +13 -13
  387. package/dist/traces.js.map +1 -1
  388. package/dist/trajectory-replay/index.d.ts +3 -117
  389. package/dist/trajectory-replay/index.d.ts.map +1 -1
  390. package/dist/trajectory-replay/index.js +98 -56
  391. package/dist/trajectory-replay/index.js.map +1 -1
  392. package/dist/{tree-rXLW3M_4.js → tree-BGRglkKd.js} +2355 -2414
  393. package/dist/tree-BGRglkKd.js.map +1 -0
  394. package/dist/{types-B3jzCp0p.js → types-BXgASBCL.js} +2 -2
  395. package/dist/{types-B3jzCp0p.js.map → types-BXgASBCL.js.map} +1 -1
  396. package/dist/{types-oKRhQAde.d.ts → types-CW8ewATZ.d.ts} +5 -114
  397. package/dist/types-CW8ewATZ.d.ts.map +1 -0
  398. package/dist/{types-BqkVmHfv.d.ts → types-CmXY0PQf.d.ts} +2 -4
  399. package/dist/types-CmXY0PQf.d.ts.map +1 -0
  400. package/dist/{types-DBZ7keha.d.ts → types-D-mgRzlh.d.ts} +9 -72
  401. package/dist/types-D-mgRzlh.d.ts.map +1 -0
  402. package/dist/{types-B4C5nFw6.d.ts → types-D8GhJoHk.d.ts} +79 -75
  403. package/dist/types-D8GhJoHk.d.ts.map +1 -0
  404. package/dist/{types-IXD2HJzu.js → types-DqFMNTgK.js} +2 -4
  405. package/dist/types-DqFMNTgK.js.map +1 -0
  406. package/dist/{types-CfZMIzB_.d.ts → types-DtMbFw6U.d.ts} +3 -3
  407. package/dist/{types-CfZMIzB_.d.ts.map → types-DtMbFw6U.d.ts.map} +1 -1
  408. package/dist/{verdict-DhPoXApk.js → verdict-BGQmxQ8A.js} +3 -3
  409. package/dist/verdict-BGQmxQ8A.js.map +1 -0
  410. package/dist/{verdict-E4eRNf7-.d.ts → verdict-C24NELtN.d.ts} +2 -15
  411. package/dist/{verdict-E4eRNf7-.d.ts.map → verdict-C24NELtN.d.ts.map} +1 -1
  412. package/dist/{verdict-cache-BQEsVy9n.js → verdict-cache-CL_7tePD.js} +2 -2
  413. package/dist/verdict-cache-CL_7tePD.js.map +1 -0
  414. package/dist/wire/index.d.ts +32 -411
  415. package/dist/wire/index.d.ts.map +1 -1
  416. package/dist/wire/index.js +2 -2
  417. package/docs/changes/jev-evidence-review.md +1 -1
  418. package/docs/changes/jev-product-adoption.md +1 -1
  419. package/docs/changes/jev-recorded-evidence.md +1 -1
  420. package/docs/design/mlbenchmarks-book-review.md +1 -1
  421. package/docs/design/mlbenchmarks-review/probes.mts +23 -31
  422. package/docs/design/statistics-decisions.md +17 -17
  423. package/docs/design.md +1 -1
  424. package/docs/evaluation-integrity.md +1 -1
  425. package/docs/experiment.md +1 -1
  426. package/docs/proofs/campaign-attempt-retention-20261001/README.md +2 -2
  427. package/docs/public-api.md +138 -529
  428. package/docs/rollout.md +1 -1
  429. package/docs/trace-repair-admission.md +1 -1
  430. package/docs/wire-protocol.md +1 -1
  431. package/package.json +1 -1
  432. package/dist/active-curriculum-B_Lc9kfO.js +0 -61
  433. package/dist/active-curriculum-B_Lc9kfO.js.map +0 -1
  434. package/dist/agent-profile-CIA2Atnt.d.ts.map +0 -1
  435. package/dist/agent-profile-cell-BNp-Js9F.d.ts.map +0 -1
  436. package/dist/agent-profile-cell-BYc0bxsL.js.map +0 -1
  437. package/dist/agreement-irr-DsTURxdr.js.map +0 -1
  438. package/dist/analyze-runs-3xpby3p2.js.map +0 -1
  439. package/dist/analyze-runs-CSDAh8A7.d.ts.map +0 -1
  440. package/dist/ast-DJ6Bc7ab.js +0 -558
  441. package/dist/ast-DJ6Bc7ab.js.map +0 -1
  442. package/dist/ast-hI-vjW6J.d.ts +0 -457
  443. package/dist/ast-hI-vjW6J.d.ts.map +0 -1
  444. package/dist/baseline-Dm8966du.js +0 -259
  445. package/dist/baseline-Dm8966du.js.map +0 -1
  446. package/dist/benchmark-BywPeAUo.js +0 -562
  447. package/dist/benchmark-BywPeAUo.js.map +0 -1
  448. package/dist/benchmark-command-CByl9dxG.js.map +0 -1
  449. package/dist/campaign-BQ-Jujuj.js.map +0 -1
  450. package/dist/chat-json-call-BrKsyspg.js.map +0 -1
  451. package/dist/claim-BXcZw-jo.js.map +0 -1
  452. package/dist/claude-jsonl-dZir12m6.js +0 -86
  453. package/dist/claude-jsonl-dZir12m6.js.map +0 -1
  454. package/dist/client-BzL9niqi.d.ts.map +0 -1
  455. package/dist/cost-ledger-CO7UyEcQ.d.ts.map +0 -1
  456. package/dist/cost-ledger-D2FnJPBF.js.map +0 -1
  457. package/dist/counterfactual-CPaWN99-.d.ts +0 -60
  458. package/dist/counterfactual-CPaWN99-.d.ts.map +0 -1
  459. package/dist/counterfactual-DtMWvn7D.js +0 -98
  460. package/dist/counterfactual-DtMWvn7D.js.map +0 -1
  461. package/dist/default-registry-BrWh62zf.d.ts.map +0 -1
  462. package/dist/default-registry-Cn1LQ2Ve.js.map +0 -1
  463. package/dist/define-agent-eval-CEWkX5wZ.d.ts.map +0 -1
  464. package/dist/define-agent-eval-Ch3MWX6k.js.map +0 -1
  465. package/dist/dspy-rlm-engine-D-KX_e64.js.map +0 -1
  466. package/dist/effect-sizes-DiH8MGOH.js +0 -82
  467. package/dist/effect-sizes-DiH8MGOH.js.map +0 -1
  468. package/dist/emitter-HcCmFQl_.d.ts.map +0 -1
  469. package/dist/engine-C_zNWfM8.d.ts.map +0 -1
  470. package/dist/equal-terms-Blx9Zk5I.js.map +0 -1
  471. package/dist/evaluation-Cn2dRZIz.d.ts.map +0 -1
  472. package/dist/exporters-X4xwla8A.js.map +0 -1
  473. package/dist/external-optimizer-process-nnsY5D_4.js.map +0 -1
  474. package/dist/external-optimizer-subprocess-DcerlZSG.js.map +0 -1
  475. package/dist/failure-cluster-CbgEDcFJ.d.ts.map +0 -1
  476. package/dist/feedback-trajectory-DkaDj0dj.d.ts.map +0 -1
  477. package/dist/hf-dataset-BR2yhuNn.js.map +0 -1
  478. package/dist/index-CPJJr98o.d.ts.map +0 -1
  479. package/dist/index-Ch9VxCpK.d.ts.map +0 -1
  480. package/dist/index-DHKEAv3s.d.ts.map +0 -1
  481. package/dist/index-DlH0Y9gI.d.ts.map +0 -1
  482. package/dist/index-NvGBiO8H.d.ts.map +0 -1
  483. package/dist/integrity-BV1ZDf42.js.map +0 -1
  484. package/dist/journal-DvKCvjty.js.map +0 -1
  485. package/dist/judge-gate-B1qYnkpi.js.map +0 -1
  486. package/dist/judge-gate-DNcUrRFA.d.ts.map +0 -1
  487. package/dist/kind-factory-CbZ-6tvu.js.map +0 -1
  488. package/dist/ledger-core-B2hahzrt.js.map +0 -1
  489. package/dist/llm-client-DQveoxSM.js.map +0 -1
  490. package/dist/llm-judge-PXV7Xljl.js.map +0 -1
  491. package/dist/matrix-CHMiebFx.d.ts.map +0 -1
  492. package/dist/matrix-_BV9-Lk5.js.map +0 -1
  493. package/dist/mint-DCGoBYhB.d.ts +0 -155
  494. package/dist/mint-DCGoBYhB.d.ts.map +0 -1
  495. package/dist/normal-DsJZtrJc.js +0 -25
  496. package/dist/normal-DsJZtrJc.js.map +0 -1
  497. package/dist/paired-arms-DzKn0TfY.js.map +0 -1
  498. package/dist/paired-binary-Q36bhn2R.js.map +0 -1
  499. package/dist/paired-promotion-decision-DPKz8ZnF.d.ts.map +0 -1
  500. package/dist/paired-tests-jbwPdSz5.js.map +0 -1
  501. package/dist/prime-protocol-CEE4BR9N.d.ts.map +0 -1
  502. package/dist/prime-protocol-DcAK9pC8.js.map +0 -1
  503. package/dist/produced-state-ZCtDBxAE.js.map +0 -1
  504. package/dist/proposal-findings-BZiMTzAF.js.map +0 -1
  505. package/dist/query-B1D1qp2Z.js.map +0 -1
  506. package/dist/redact-Cveoq6fJ.d.ts.map +0 -1
  507. package/dist/redact-Dk1ZdJEm.js.map +0 -1
  508. package/dist/release-confidence-BK2QCB5M.d.ts.map +0 -1
  509. package/dist/release-confidence-Dbe9AS_X.js.map +0 -1
  510. package/dist/report-command-y8H6RSX8.js.map +0 -1
  511. package/dist/reward-hacking-DHA7c1l8.d.ts.map +0 -1
  512. package/dist/rollout-D9bKKBnZ.js.map +0 -1
  513. package/dist/run-record-D1Hw-Jml.d.ts.map +0 -1
  514. package/dist/run-record-ES07wfz9.js.map +0 -1
  515. package/dist/schema-2g7trUwH.d.ts.map +0 -1
  516. package/dist/schema-BuiujZ-g.js.map +0 -1
  517. package/dist/schema-CSf6qWgZ.js.map +0 -1
  518. package/dist/search-kernel-BztlERLv.js.map +0 -1
  519. package/dist/search-kernel-CpcKH5Ih.d.ts.map +0 -1
  520. package/dist/search-ledger-d7V8o9Lk.js.map +0 -1
  521. package/dist/search-ledger-file-BqOo-bVo.js.map +0 -1
  522. package/dist/search-shipper-er4pK5_Y.js.map +0 -1
  523. package/dist/semantic-concept-judge-zQBG9hHU.js.map +0 -1
  524. package/dist/sequential-D-1PPCmM.js.map +0 -1
  525. package/dist/server-DbcC7xMl.js.map +0 -1
  526. package/dist/skillopt-optimization-method-CCtzralq.js.map +0 -1
  527. package/dist/statistical-heldout-1Gbmex7v.js.map +0 -1
  528. package/dist/statistical-heldout-BeR4bOdg.d.ts.map +0 -1
  529. package/dist/steps-Bg5-KVx1.d.ts.map +0 -1
  530. package/dist/store-otlp-DtB4Slsr.js.map +0 -1
  531. package/dist/store-tool-spans-DR1SrCLK.d.ts.map +0 -1
  532. package/dist/store-tool-spans-fZIigrpP.js.map +0 -1
  533. package/dist/student-t-BQeKJx2N.js +0 -39
  534. package/dist/student-t-BQeKJx2N.js.map +0 -1
  535. package/dist/summary-report-C-CtItCN.d.ts.map +0 -1
  536. package/dist/summary-report-DtdRucM0.js.map +0 -1
  537. package/dist/task-failure-attributes-DngaLdE4.js.map +0 -1
  538. package/dist/terminal-record-BHocwFw1.js.map +0 -1
  539. package/dist/tool-groups-mcxOXVlb.d.ts.map +0 -1
  540. package/dist/tool-waste-Wi4g6Ekb.d.ts.map +0 -1
  541. package/dist/trajectory-Y1fmdlw7.d.ts +0 -24
  542. package/dist/trajectory-Y1fmdlw7.d.ts.map +0 -1
  543. package/dist/tree-rXLW3M_4.js.map +0 -1
  544. package/dist/types-B4C5nFw6.d.ts.map +0 -1
  545. package/dist/types-BqkVmHfv.d.ts.map +0 -1
  546. package/dist/types-DBZ7keha.d.ts.map +0 -1
  547. package/dist/types-IXD2HJzu.js.map +0 -1
  548. package/dist/types-oKRhQAde.d.ts.map +0 -1
  549. package/dist/usage-receipt-Cx3xNeyB.js +0 -76
  550. package/dist/usage-receipt-Cx3xNeyB.js.map +0 -1
  551. package/dist/verdict-DhPoXApk.js.map +0 -1
  552. package/dist/verdict-cache-BQEsVy9n.js.map +0 -1
  553. package/docs/design/self-improvement-evidence-audit.md +0 -263
@@ -1,835 +1,878 @@
1
- import { s as ValidationError } from "./errors-Dngq5h35.js";
2
- import { a as resolveModelPricing, i as isModelPriced, n as estimateCost } from "./metrics-BKaPBtIG.js";
1
+ import { s as ValidationError } from "./errors-BcOs5MKW.js";
2
+ import { a as resolveModelPricing, n as estimateCost } from "./metrics-BKaPBtIG.js";
3
3
  import { z } from "zod";
4
- //#region src/cost-ledger.ts
5
- var CostCeilingReachedError = class extends ValidationError {
6
- constructor(ceilingUsd, committedUsd, requestedUsd, phase, actor) {
7
- super(`CostLedger: reserving ${requestedUsd} for '${actor}' during '${phase}' would exceed ceiling ${ceilingUsd} with ${committedUsd} already committed`);
4
+ //#region src/cost-ledger/validation.ts
5
+ /** Validate cost and usage primitives without admitting work or consulting pricing. */
6
+ function toError(value) {
7
+ return value instanceof Error ? value : new Error(String(value));
8
+ }
9
+ function validationMessage(cause) {
10
+ return cause instanceof z.ZodError ? z.prettifyError(cause) : toError(cause).message;
11
+ }
12
+ function assertUsage(usage) {
13
+ assertTokenCount(usage.inputTokens, "inputTokens");
14
+ assertTokenCount(usage.outputTokens, "outputTokens");
15
+ if (usage.reasoningTokens !== void 0) {
16
+ assertTokenCount(usage.reasoningTokens, "reasoningTokens");
17
+ if (usage.reasoningTokens > usage.outputTokens) throw new ValidationError("CostLedger: reasoningTokens must not exceed outputTokens");
8
18
  }
19
+ if (usage.cachedTokens !== void 0) assertTokenCount(usage.cachedTokens, "cachedTokens");
20
+ if (usage.cacheWriteTokens !== void 0) assertTokenCount(usage.cacheWriteTokens, "cacheWriteTokens");
21
+ }
22
+ function assertTokenCount(value, name) {
23
+ if (typeof value !== "number" || !Number.isInteger(value) || value < 0) throw new ValidationError(`CostLedger: ${name} must be a non-negative integer, got ${String(value)}`);
24
+ }
25
+ function assertNonNegative(value, name) {
26
+ if (typeof value !== "number" || !Number.isFinite(value) || value < 0) throw new ValidationError(`CostLedger: ${name} must be a non-negative finite number, got ${String(value)}`);
27
+ }
28
+ function assertTimeout(value, name) {
29
+ if (typeof value !== "number" || !Number.isSafeInteger(value) || value < 0 || value > 2147483647) throw new ValidationError(`CostLedger: ${name} must be a non-negative safe integer no greater than 2147483647, got ${String(value)}`);
30
+ }
31
+ function assertString(value, name) {
32
+ if (typeof value !== "string" || value.trim().length === 0) throw new ValidationError(`CostLedger: ${name} must be a non-empty string`);
33
+ }
34
+ //#endregion
35
+ //#region src/cost-ledger/pricing.ts
36
+ /** Model-price lookup and caller-supplied token pricing, including receipt snapshots. */
37
+ function costForUsage(model, usage) {
38
+ assertUsage(usage);
39
+ if (!resolveModelPricing(model)) return {
40
+ costUsd: 0,
41
+ costUnknown: true
42
+ };
43
+ return {
44
+ costUsd: estimateCost(usage.inputTokens + (usage.cachedTokens ?? 0) + (usage.cacheWriteTokens ?? 0), usage.outputTokens, model),
45
+ costUnknown: false
46
+ };
47
+ }
48
+ /** Price token counts with caller-supplied per-million rates. */
49
+ function costForTokenPricing(pricing, usage) {
50
+ assertTokenCount(usage.inputTokens, "usage.inputTokens");
51
+ assertTokenCount(usage.outputTokens, "usage.outputTokens");
52
+ if (usage.cachedTokens !== void 0) assertTokenCount(usage.cachedTokens, "usage.cachedTokens");
53
+ if (usage.cacheWriteTokens !== void 0) assertTokenCount(usage.cacheWriteTokens, "usage.cacheWriteTokens");
54
+ assertNonNegative(pricing.inputUsdPerMillion, "pricing.inputUsdPerMillion");
55
+ if (pricing.cachedInputUsdPerMillion !== void 0) assertNonNegative(pricing.cachedInputUsdPerMillion, "pricing.cachedInputUsdPerMillion");
56
+ if (pricing.cacheWriteUsdPerMillion !== void 0) assertNonNegative(pricing.cacheWriteUsdPerMillion, "pricing.cacheWriteUsdPerMillion");
57
+ assertNonNegative(pricing.outputUsdPerMillion, "pricing.outputUsdPerMillion");
58
+ const cachedInputRate = pricing.cachedInputUsdPerMillion ?? pricing.inputUsdPerMillion;
59
+ const cacheWriteRate = pricing.cacheWriteUsdPerMillion ?? pricing.inputUsdPerMillion;
60
+ return usage.inputTokens / 1e6 * pricing.inputUsdPerMillion + (usage.cachedTokens ?? 0) / 1e6 * cachedInputRate + (usage.cacheWriteTokens ?? 0) / 1e6 * cacheWriteRate + usage.outputTokens / 1e6 * pricing.outputUsdPerMillion;
61
+ }
62
+ function costFromPricing(usage, pricing) {
63
+ const cachedInputRate = pricing.cachedInputUsdPerThousand ?? pricing.inputUsdPerThousand;
64
+ const cacheWriteRate = pricing.cacheWriteUsdPerThousand ?? pricing.inputUsdPerThousand;
65
+ return usage.inputTokens / 1e3 * pricing.inputUsdPerThousand + (usage.cachedTokens ?? 0) / 1e3 * cachedInputRate + (usage.cacheWriteTokens ?? 0) / 1e3 * cacheWriteRate + usage.outputTokens / 1e3 * pricing.outputUsdPerThousand;
66
+ }
67
+ function pricingSnapshot(pricing) {
68
+ costForTokenPricing(pricing, {
69
+ inputTokens: 0,
70
+ outputTokens: 0
71
+ });
72
+ return {
73
+ inputUsdPerThousand: pricing.inputUsdPerMillion / 1e3,
74
+ ...pricing.cachedInputUsdPerMillion === void 0 ? {} : { cachedInputUsdPerThousand: pricing.cachedInputUsdPerMillion / 1e3 },
75
+ ...pricing.cacheWriteUsdPerMillion === void 0 ? {} : { cacheWriteUsdPerThousand: pricing.cacheWriteUsdPerMillion / 1e3 },
76
+ outputUsdPerThousand: pricing.outputUsdPerMillion / 1e3
77
+ };
78
+ }
79
+ //#endregion
80
+ //#region src/cost-ledger/receipts.ts
81
+ /** Create, validate, filter, and detach the receipts stored by a cost ledger. */
82
+ const NonEmptyString = z.string().refine((value) => value.trim().length > 0, "must be non-empty");
83
+ const TokenCount = z.number().int().nonnegative().finite();
84
+ const NonNegative = z.number().nonnegative().finite();
85
+ const Tags = z.record(NonEmptyString, z.string());
86
+ const CostPricingSchema = z.strictObject({
87
+ inputUsdPerThousand: NonNegative,
88
+ cachedInputUsdPerThousand: NonNegative.optional(),
89
+ cacheWriteUsdPerThousand: NonNegative.optional(),
90
+ outputUsdPerThousand: NonNegative
91
+ });
92
+ const CostCallBaseShape = {
93
+ callId: NonEmptyString,
94
+ channel: NonEmptyString,
95
+ phase: NonEmptyString,
96
+ actor: NonEmptyString,
97
+ model: NonEmptyString,
98
+ maximumCostUsd: NonNegative.optional(),
99
+ tags: Tags.optional(),
100
+ timestamp: NonNegative
9
101
  };
10
- var CostAccountingIncompleteError = class extends ValidationError {};
11
- var CostReservationExceededError = class extends ValidationError {
12
- constructor(actor, actualUsd, maximumUsd) {
13
- super(`CostLedger: '${actor}' charged ${actualUsd}, exceeding its enforced maximum ${maximumUsd}`);
14
- }
102
+ const PendingCostCallSchema = z.strictObject({
103
+ status: z.literal("pending"),
104
+ ...CostCallBaseShape
105
+ });
106
+ const CostReceiptBaseShape = {
107
+ status: z.literal("settled"),
108
+ ...CostCallBaseShape,
109
+ inputTokens: TokenCount,
110
+ outputTokens: TokenCount,
111
+ cachedTokens: TokenCount.optional(),
112
+ costUsd: NonNegative,
113
+ costUnknown: z.boolean(),
114
+ usageUnknown: z.boolean().default(false),
115
+ pricing: CostPricingSchema.optional(),
116
+ actualCostUsd: NonNegative.optional(),
117
+ estimatedCostUsd: NonNegative.optional(),
118
+ error: NonEmptyString.optional()
15
119
  };
16
- var CostCallConflictError = class extends ValidationError {
17
- callId;
18
- receipt;
19
- constructor(message, options = {}) {
20
- super(message, options.cause === void 0 ? void 0 : { cause: options.cause });
21
- this.callId = options.callId;
22
- this.receipt = options.receipt ? cloneReceipt(options.receipt) : void 0;
120
+ const CostReceiptSchema = z.strictObject({
121
+ ...CostReceiptBaseShape,
122
+ reasoningTokens: TokenCount.optional(),
123
+ cacheWriteTokens: TokenCount.optional()
124
+ }).superRefine((receipt, ctx) => validateCostReceipt(receipt, ctx));
125
+ function validateCostReceipt(receipt, ctx) {
126
+ if (receipt.reasoningTokens !== void 0 && receipt.reasoningTokens > receipt.outputTokens) ctx.addIssue({
127
+ code: "custom",
128
+ message: "reasoningTokens must not exceed outputTokens"
129
+ });
130
+ if (receipt.actualCostUsd !== void 0 && receipt.estimatedCostUsd !== void 0) ctx.addIssue({
131
+ code: "custom",
132
+ message: "actual and external estimated costs cannot both be present"
133
+ });
134
+ if (receipt.actualCostUsd !== void 0) {
135
+ if (receipt.costUnknown || receipt.costUsd !== receipt.actualCostUsd) ctx.addIssue({
136
+ code: "custom",
137
+ message: "actual cost must be known and equal costUsd"
138
+ });
139
+ if (receipt.pricing !== void 0) ctx.addIssue({
140
+ code: "custom",
141
+ message: "actual cost must not include estimated pricing"
142
+ });
143
+ return;
23
144
  }
24
- };
25
- var CostLedgerPersistenceError = class extends ValidationError {
26
- callId;
27
- receipt;
28
- constructor(cause, callId, receipt) {
29
- super(`CostLedger: failed to persist${callId ? ` call '${callId}'` : ""}: ${toError(cause).message}`, { cause });
30
- this.callId = callId;
31
- this.receipt = receipt ? cloneReceipt(receipt) : void 0;
145
+ if (receipt.estimatedCostUsd !== void 0) {
146
+ if (receipt.costUnknown || receipt.costUsd !== receipt.estimatedCostUsd) ctx.addIssue({
147
+ code: "custom",
148
+ message: "external estimate must be known and equal costUsd"
149
+ });
150
+ if (receipt.pricing !== void 0) ctx.addIssue({
151
+ code: "custom",
152
+ message: "external estimate must not include token pricing"
153
+ });
154
+ return;
32
155
  }
33
- };
34
- var CostReceiptCaptureError = class extends ValidationError {
35
- callId;
36
- receipt;
37
- receiptError;
38
- constructor(callId, cause, receiptError, receipt) {
39
- super(`CostLedger: could not capture the provider receipt for call '${callId}'`, { cause });
40
- this.callId = callId;
41
- this.receipt = receipt ? cloneReceipt(receipt) : void 0;
42
- this.receiptError = toError(receiptError);
156
+ if (receipt.costUnknown) {
157
+ if (receipt.costUsd !== 0) ctx.addIssue({
158
+ code: "custom",
159
+ message: "unknown cost must have costUsd 0"
160
+ });
161
+ if (receipt.pricing !== void 0) ctx.addIssue({
162
+ code: "custom",
163
+ message: "unknown cost must not include estimated pricing"
164
+ });
165
+ return;
43
166
  }
44
- };
45
- /** Run-wide paid-call admission, durable call state, receipts, and summaries. */
46
- var CostLedger = class {
47
- records = /* @__PURE__ */ new Map();
48
- activeCallIds = /* @__PURE__ */ new Set();
49
- lateCallIds = /* @__PURE__ */ new Set();
50
- idleWaiters = /* @__PURE__ */ new Set();
51
- completedTasks = 0;
52
- revision = "memory";
53
- costLimitPersisted = false;
54
- costCeilingUsd;
55
- persistence;
56
- constructor(input) {
57
- const options = typeof input === "number" ? { costCeilingUsd: input } : input ?? {};
58
- this.persistence = options.persistence;
59
- if (options.costCeilingUsd !== void 0) assertNonNegative(options.costCeilingUsd, "costCeilingUsd");
60
- let persistedCostCeilingUsd;
61
- if (this.persistence) {
62
- let stored;
63
- try {
64
- stored = this.persistence.read();
65
- } catch (cause) {
66
- throw new CostLedgerPersistenceError(cause);
67
- }
68
- assertString(stored.revision, "persistence revision");
69
- this.revision = stored.revision;
70
- const restored = parseEvents(stored.events);
71
- for (const record of restored.records) this.records.set(record.callId, record);
72
- this.completedTasks = restored.completedTasks;
73
- persistedCostCeilingUsd = restored.costCeilingUsd;
74
- }
75
- if (options.costCeilingUsd !== void 0 && persistedCostCeilingUsd !== void 0 && options.costCeilingUsd !== persistedCostCeilingUsd) throw new ValidationError(`CostLedger: requested cost ceiling ${options.costCeilingUsd} does not match persisted ceiling ${persistedCostCeilingUsd}`);
76
- this.costCeilingUsd = persistedCostCeilingUsd ?? options.costCeilingUsd;
77
- this.costLimitPersisted = !this.persistence || this.costCeilingUsd === void 0 || persistedCostCeilingUsd !== void 0;
78
- if (this.costCeilingUsd !== void 0 && [...this.records.values()].some((record) => record.status === "pending" && record.maximumCostUsd === void 0)) throw new ValidationError("CostLedger: capped event log contains an unbounded pending call");
79
- if (options.receipts?.length) {
80
- const imported = options.receipts.map((receipt, index) => parseImportedReceipt(receipt, `imported receipt ${index + 1}`));
81
- this.ensureCostLimitPersisted();
82
- for (const receipt of imported) this.appendRecord(receipt);
83
- }
167
+ if (receipt.usageUnknown) ctx.addIssue({
168
+ code: "custom",
169
+ message: "known estimated cost requires known usage"
170
+ });
171
+ if (!receipt.pricing) {
172
+ ctx.addIssue({
173
+ code: "custom",
174
+ message: "known estimated cost requires a pricing snapshot"
175
+ });
176
+ return;
84
177
  }
85
- async runPaidCall(input) {
86
- let callId;
87
- let pending;
88
- try {
89
- callId = resolveCallId(input.callId);
90
- validateAttribution(input);
91
- if (input.signal?.aborted) return {
92
- succeeded: false,
93
- callId,
94
- error: abortError(input.signal)
95
- };
96
- this.ensureCostLimitPersisted(callId);
97
- const maximumCostUsd = this.resolveMaximum(input.maximumCharge);
98
- const existing = this.records.get(callId);
99
- if (existing) return {
100
- succeeded: false,
101
- callId,
102
- error: new CostCallConflictError(existing.status === "pending" ? `CostLedger: callId '${callId}' is unresolved and must be reconciled before retry` : `CostLedger: callId '${callId}' already exists`, { callId })
103
- };
104
- if (!pending) {
105
- while (true) {
106
- if (this.records.has(callId)) return {
107
- succeeded: false,
108
- callId,
109
- error: new CostCallConflictError(`CostLedger: callId '${callId}' already exists`)
110
- };
111
- const admission = this.admissionState();
112
- if (admission.unresolvedCalls > 0) return {
113
- succeeded: false,
114
- callId,
115
- error: new CostAccountingIncompleteError(`CostLedger: ${admission.unresolvedCalls} unresolved call(s) must be reconciled before new paid work`)
116
- };
117
- if (this.costCeilingUsd === void 0) break;
118
- if (admission.budgetBreached) return {
119
- succeeded: false,
120
- callId,
121
- error: new CostAccountingIncompleteError(`CostLedger: a settled call exceeded its enforced maximum; refusing paid call '${input.actor}' during '${input.phase}'`)
122
- };
123
- const { committedCostUsd } = admission;
124
- if (committedCostUsd + maximumCostUsd > this.costCeilingUsd) return {
125
- succeeded: false,
126
- callId,
127
- error: new CostCeilingReachedError(this.costCeilingUsd, committedCostUsd, maximumCostUsd, input.phase, input.actor)
128
- };
129
- if (committedCostUsd + admission.reservedCostUsd + maximumCostUsd <= this.costCeilingUsd) break;
130
- await this.waitForReservationRelease(input.signal);
131
- }
132
- pending = {
133
- status: "pending",
134
- callId,
135
- channel: input.channel,
136
- phase: input.phase,
137
- actor: input.actor,
138
- model: pendingModel(input),
139
- ...maximumCostUsd === void 0 ? {} : { maximumCostUsd },
140
- ...input.tags ? { tags: { ...input.tags } } : {},
141
- timestamp: Date.now()
142
- };
143
- this.appendRecord(pending);
144
- this.activeCallIds.add(callId);
145
- }
146
- } catch (error) {
147
- return {
148
- succeeded: false,
149
- ...callId ? { callId } : {},
150
- error: toError(error)
151
- };
152
- }
153
- try {
154
- return await this.execute(input, pending);
155
- } catch (error) {
156
- return {
157
- succeeded: false,
158
- callId: pending.callId,
159
- error: toError(error)
160
- };
161
- } finally {
162
- if (!this.lateCallIds.has(pending.callId)) this.releaseActiveCall(pending.callId);
163
- }
164
- }
165
- /** Wait until every call started by this ledger has produced a durable outcome. */
166
- async waitForIdle(options = {}) {
167
- const hasActiveMatch = () => [...this.activeCallIds].some((callId) => {
168
- const record = this.records.get(callId);
169
- return record !== void 0 && matches(record, options.filter);
170
- });
171
- if (!hasActiveMatch()) return true;
172
- const timeoutMs = options.timeoutMs ?? 5e3;
173
- assertTimeout(timeoutMs, "waitForIdle.timeoutMs");
174
- return new Promise((resolve) => {
175
- let timer;
176
- const finish = (settled) => {
177
- this.idleWaiters.delete(onIdle);
178
- if (timer !== void 0) clearTimeout(timer);
179
- resolve(settled);
180
- };
181
- const onIdle = () => {
182
- if (!hasActiveMatch()) finish(true);
183
- };
184
- this.idleWaiters.add(onIdle);
185
- timer = setTimeout(() => finish(false), timeoutMs);
186
- onIdle();
187
- });
178
+ const expected = costFromPricing(receipt, receipt.pricing);
179
+ if (!costAmountsMatch(receipt.costUsd, expected)) ctx.addIssue({
180
+ code: "custom",
181
+ message: `estimated cost ${receipt.costUsd} does not match pricing snapshot ${expected}`
182
+ });
183
+ }
184
+ function costAmountsMatch(left, right) {
185
+ const scale = Math.max(1, Math.abs(left), Math.abs(right));
186
+ return Math.abs(left - right) <= Number.EPSILON * scale * 8;
187
+ }
188
+ function buildReceipt(pending, observed, failed = false, error) {
189
+ assertUsage(observed);
190
+ assertString(observed.model, "receipt.model");
191
+ if ([
192
+ observed.actualCostUsd,
193
+ observed.estimatedCostUsd,
194
+ observed.customTokenPricing
195
+ ].filter((value) => value !== void 0).length > 1) throw new ValidationError("CostLedger: a receipt can have only one of actualCostUsd, estimatedCostUsd, or customTokenPricing");
196
+ const customPricingSnapshot = observed.customTokenPricing === void 0 ? void 0 : pricingSnapshot(observed.customTokenPricing);
197
+ const estimated = customPricingSnapshot ? {
198
+ costUsd: costFromPricing(observed, customPricingSnapshot),
199
+ costUnknown: false
200
+ } : costForUsage(observed.model, observed);
201
+ const hasActual = observed.actualCostUsd !== void 0;
202
+ const hasExternalEstimate = observed.estimatedCostUsd !== void 0;
203
+ if (hasActual && observed.costUnknown === true) throw new ValidationError("CostLedger: a receipt cannot have both actualCostUsd and costUnknown=true");
204
+ if (hasActual) assertNonNegative(observed.actualCostUsd, "actualCostUsd");
205
+ if (hasExternalEstimate) assertNonNegative(observed.estimatedCostUsd, "estimatedCostUsd");
206
+ if (hasExternalEstimate && observed.costUnknown === true) throw new ValidationError("CostLedger: a receipt cannot have both estimatedCostUsd and costUnknown=true");
207
+ const usageUnknown = observed.usageUnknown === true;
208
+ const costUnknown = observed.costUnknown === true || !hasActual && !hasExternalEstimate && (usageUnknown || estimated.costUnknown);
209
+ const resolvedModelPricing = !customPricingSnapshot && !hasActual && !hasExternalEstimate && !costUnknown ? resolveModelPricing(observed.model) : null;
210
+ const receiptPricing = !hasActual && !hasExternalEstimate && !costUnknown ? customPricingSnapshot ?? (resolvedModelPricing ? {
211
+ inputUsdPerThousand: resolvedModelPricing.input,
212
+ outputUsdPerThousand: resolvedModelPricing.output
213
+ } : void 0) : void 0;
214
+ return parseReceipt({
215
+ status: "settled",
216
+ callId: pending.callId,
217
+ channel: pending.channel,
218
+ phase: pending.phase,
219
+ actor: pending.actor,
220
+ model: observed.model,
221
+ inputTokens: observed.inputTokens,
222
+ outputTokens: observed.outputTokens,
223
+ ...observed.reasoningTokens === void 0 ? {} : { reasoningTokens: observed.reasoningTokens },
224
+ ...observed.cachedTokens === void 0 ? {} : { cachedTokens: observed.cachedTokens },
225
+ ...observed.cacheWriteTokens === void 0 ? {} : { cacheWriteTokens: observed.cacheWriteTokens },
226
+ costUsd: costUnknown ? 0 : hasActual ? observed.actualCostUsd : hasExternalEstimate ? observed.estimatedCostUsd : estimated.costUsd,
227
+ costUnknown,
228
+ usageUnknown,
229
+ ...receiptPricing ? { pricing: receiptPricing } : {},
230
+ ...hasActual ? { actualCostUsd: observed.actualCostUsd } : {},
231
+ ...hasExternalEstimate ? { estimatedCostUsd: observed.estimatedCostUsd } : {},
232
+ ...pending.maximumCostUsd === void 0 ? {} : { maximumCostUsd: pending.maximumCostUsd },
233
+ ...failed ? { error: error ?? "paid-call-failed" } : {},
234
+ ...pending.tags ? { tags: { ...pending.tags } } : {},
235
+ timestamp: pending.timestamp
236
+ }, "provider receipt");
237
+ }
238
+ function parseReceipt(value, path) {
239
+ try {
240
+ return CostReceiptSchema.parse(value);
241
+ } catch (cause) {
242
+ throw new ValidationError(`CostLedger: invalid ${path}: ${validationMessage(cause)}`, { cause });
188
243
  }
189
- /** Settle a call left pending by a crashed process after reconciling with the provider. */
190
- reconcile(callId, observed, options = {}) {
191
- const pending = this.records.get(callId);
192
- if (pending?.status !== "pending") throw new CostCallConflictError(`CostLedger: no pending call '${callId}'`);
193
- if (this.activeCallIds.has(callId)) throw new CostCallConflictError(`CostLedger: call '${callId}' is still active`);
194
- this.ensureCostLimitPersisted(callId);
195
- return this.commitReceipt(pending, observed, options.failed === true || options.error !== void 0, options.error);
244
+ }
245
+ function parseImportedReceipt(value, path) {
246
+ if (typeof value !== "object" || value === null) return parseReceipt(value, path);
247
+ const candidate = { ...value };
248
+ if (candidate.status === "settled" && candidate.actualCostUsd === void 0 && candidate.estimatedCostUsd === void 0 && candidate.costUnknown === false && candidate.pricing === void 0 && typeof candidate.model === "string") {
249
+ const pricing = resolveModelPricing(candidate.model);
250
+ if (pricing) candidate.pricing = {
251
+ inputUsdPerThousand: pricing.input,
252
+ outputUsdPerThousand: pricing.output
253
+ };
196
254
  }
197
- list(filter) {
198
- return [...this.records.values()].filter((record) => record.status === "settled").filter((receipt) => matches(receipt, filter)).map(cloneReceipt);
255
+ return parseReceipt(candidate, path);
256
+ }
257
+ function validateAttribution(input) {
258
+ assertString(input.channel, "channel");
259
+ assertString(input.phase, "phase");
260
+ assertString(input.actor, "actor");
261
+ if (input.model !== void 0) assertString(input.model, "model");
262
+ if (input.tags !== void 0) {
263
+ const parsed = Tags.safeParse(input.tags);
264
+ if (!parsed.success) throw new ValidationError(`CostLedger: invalid tags: ${parsed.error.message}`);
199
265
  }
200
- /** Read pending calls without exposing mutable ledger state. */
201
- listPending(filter) {
202
- return [...this.records.values()].filter((record) => record.status === "pending").filter((record) => matches(record, filter)).map((record) => ({
203
- ...clonePendingCall(record),
204
- state: this.lateCallIds.has(record.callId) ? "late" : this.activeCallIds.has(record.callId) ? "active" : "interrupted"
205
- }));
266
+ }
267
+ function matches(record, filter) {
268
+ if (!filter) return true;
269
+ if (filter.channel !== void 0 && record.channel !== filter.channel) return false;
270
+ if (filter.phase !== void 0 && record.phase !== filter.phase) return false;
271
+ return Object.entries(filter.tags ?? {}).every(([key, value]) => record.tags?.[key] === value);
272
+ }
273
+ function cloneRecord(record) {
274
+ if (record.status === "settled") return cloneReceipt(record);
275
+ return clonePendingCall(record);
276
+ }
277
+ function clonePendingCall(record) {
278
+ const { tags, ...rest } = record;
279
+ return {
280
+ ...rest,
281
+ ...tags ? { tags: { ...tags } } : {}
282
+ };
283
+ }
284
+ function cloneReceipt(receipt) {
285
+ const { pricing, tags, ...rest } = receipt;
286
+ return {
287
+ ...rest,
288
+ ...tags ? { tags: { ...tags } } : {},
289
+ ...pricing ? { pricing: { ...pricing } } : {}
290
+ };
291
+ }
292
+ //#endregion
293
+ //#region src/cost-ledger/errors.ts
294
+ /** Typed cost-accounting failures retain detached receipt evidence. */
295
+ var CostCeilingReachedError = class extends ValidationError {
296
+ constructor(ceilingUsd, committedUsd, requestedUsd, phase, actor) {
297
+ super(`CostLedger: reserving ${requestedUsd} for '${actor}' during '${phase}' would exceed ceiling ${ceilingUsd} with ${committedUsd} already committed`);
206
298
  }
207
- summary(filter) {
208
- const records = [...this.records.values()].filter((record) => matches(record, filter));
209
- const pending = records.filter((record) => record.status === "pending");
210
- const receipts = records.filter((record) => record.status === "settled");
211
- const byChannel = /* @__PURE__ */ new Map();
212
- const unpriced = /* @__PURE__ */ new Set();
213
- const incompleteReasons = pending.map((record) => `call '${record.callId}' for '${record.actor}' is pending`);
214
- let inputTokens = 0;
215
- let outputTokens = 0;
216
- let reasoningTokens = 0;
217
- let cachedTokens = 0;
218
- let cacheWriteTokens = 0;
219
- let totalCostUsd = 0;
220
- for (const receipt of receipts) {
221
- inputTokens += receipt.inputTokens;
222
- outputTokens += receipt.outputTokens;
223
- reasoningTokens += receipt.reasoningTokens ?? 0;
224
- cachedTokens += receipt.cachedTokens ?? 0;
225
- cacheWriteTokens += receipt.cacheWriteTokens ?? 0;
226
- totalCostUsd += receipt.costUsd;
227
- if (receipt.costUnknown) {
228
- unpriced.add(receipt.model);
229
- incompleteReasons.push(receipt.error ?? `cost unknown for '${receipt.actor}' using '${receipt.model}'`);
230
- }
231
- if (receipt.usageUnknown) incompleteReasons.push(`token usage unknown for '${receipt.actor}' using '${receipt.model}'`);
232
- if (receipt.maximumCostUsd !== void 0 && receipt.costUsd > receipt.maximumCostUsd) incompleteReasons.push(`'${receipt.actor}' charged ${receipt.costUsd}, exceeding its enforced maximum ${receipt.maximumCostUsd}`);
233
- const rollup = byChannel.get(receipt.channel) ?? emptyRollup(receipt.channel);
234
- rollup.calls += 1;
235
- rollup.inputTokens += receipt.inputTokens;
236
- rollup.outputTokens += receipt.outputTokens;
237
- rollup.reasoningTokens = (rollup.reasoningTokens ?? 0) + (receipt.reasoningTokens ?? 0);
238
- rollup.cachedTokens += receipt.cachedTokens ?? 0;
239
- rollup.cacheWriteTokens = (rollup.cacheWriteTokens ?? 0) + (receipt.cacheWriteTokens ?? 0);
240
- rollup.costUsd += receipt.costUsd;
241
- if (receipt.costUnknown) rollup.unpricedCalls += 1;
242
- if (receipt.usageUnknown) rollup.unknownUsageCalls += 1;
243
- byChannel.set(receipt.channel, rollup);
244
- }
245
- return {
246
- totalCalls: receipts.length,
247
- pendingCalls: pending.length,
248
- unresolvedCalls: pending.filter((record) => !this.activeCallIds.has(record.callId) || this.lateCallIds.has(record.callId)).length,
249
- reservedCostUsd: pending.reduce((sum, record) => sum + (record.maximumCostUsd ?? 0), 0),
250
- inputTokens,
251
- outputTokens,
252
- reasoningTokens,
253
- cachedTokens,
254
- cacheWriteTokens,
255
- totalCostUsd,
256
- costProvenance: pending.length > 0 || receipts.some((receipt) => receipt.costUnknown) ? {
257
- kind: "uncaptured",
258
- usd: null
259
- } : receipts.every((receipt) => receipt.actualCostUsd !== void 0) ? {
260
- kind: "observed",
261
- usd: totalCostUsd
262
- } : {
263
- kind: "estimated",
264
- usd: totalCostUsd
265
- },
266
- byChannel: [...byChannel.values()].sort((a, b) => a.channel.localeCompare(b.channel)),
267
- unpricedModels: [...unpriced].sort(),
268
- fullyPriced: unpriced.size === 0,
269
- usageComplete: pending.length === 0 && receipts.every((receipt) => !receipt.usageUnknown),
270
- accountingComplete: incompleteReasons.length === 0,
271
- incompleteReasons: [...new Set(incompleteReasons)]
272
- };
299
+ };
300
+ var CostAccountingIncompleteError = class extends ValidationError {};
301
+ var CostReservationExceededError = class extends ValidationError {
302
+ constructor(actor, actualUsd, maximumUsd) {
303
+ super(`CostLedger: '${actor}' charged ${actualUsd}, exceeding its enforced maximum ${maximumUsd}`);
273
304
  }
274
- markCompleted(count = 1) {
275
- if (!Number.isInteger(count) || count < 0) throw new ValidationError(`CostLedger.markCompleted: count must be a non-negative integer, got ${count}`);
276
- if (count === 0) return;
277
- this.ensureCostLimitPersisted();
278
- this.appendEvent({
279
- version: 1,
280
- completedTasks: count
281
- });
282
- this.completedTasks += count;
305
+ };
306
+ var CostCallConflictError = class extends ValidationError {
307
+ callId;
308
+ receipt;
309
+ constructor(message, options = {}) {
310
+ super(message, options.cause === void 0 ? void 0 : { cause: options.cause });
311
+ this.callId = options.callId;
312
+ this.receipt = options.receipt ? cloneReceipt(options.receipt) : void 0;
283
313
  }
284
- costPerCompletedTask() {
285
- return this.completedTasks === 0 ? null : this.summary().totalCostUsd / this.completedTasks;
314
+ };
315
+ var CostLedgerPersistenceError = class extends ValidationError {
316
+ callId;
317
+ receipt;
318
+ constructor(cause, callId, receipt) {
319
+ super(`CostLedger: failed to persist${callId ? ` call '${callId}'` : ""}: ${toError(cause).message}`, { cause });
320
+ this.callId = callId;
321
+ this.receipt = receipt ? cloneReceipt(receipt) : void 0;
286
322
  }
287
- async execute(input, pending) {
288
- const signal = input.signal ?? new AbortController().signal;
289
- if (signal.aborted) return this.commitOutcome(pending, abortError(signal), {
290
- model: pending.model,
291
- inputTokens: 0,
292
- outputTokens: 0,
293
- actualCostUsd: 0
294
- });
295
- const operation = Promise.resolve().then(() => input.execute(signal, pending.callId));
296
- const settled = await settle(operation, signal);
297
- if (settled.kind === "aborted") {
298
- this.lateCallIds.add(pending.callId);
299
- this.captureLateOutcome(input, pending, operation);
300
- return paidFailure(pending.callId, abortError(signal));
301
- }
302
- if (settled.kind === "error") {
303
- let observed;
304
- try {
305
- observed = input.receiptFromError?.(settled.error);
306
- } catch (receiptError) {
307
- return this.captureFailure(pending, settled.error, receiptError);
308
- }
309
- return this.commitOutcome(pending, settled.error, observed ?? unknownReceipt(pending.model));
310
- }
311
- try {
312
- const receipt = this.commitReceipt(pending, input.receipt(settled.value));
313
- if (receipt.maximumCostUsd !== void 0 && receipt.costUsd > receipt.maximumCostUsd) return paidFailure(pending.callId, new CostReservationExceededError(pending.actor, receipt.costUsd, receipt.maximumCostUsd), receipt);
314
- return {
315
- succeeded: true,
316
- callId: pending.callId,
317
- value: settled.value,
318
- receipt
319
- };
320
- } catch (receiptError) {
321
- if (receiptError instanceof CostLedgerPersistenceError || receiptError instanceof CostCallConflictError) return paidFailure(pending.callId, receiptError);
322
- return this.captureFailure(pending, receiptError, receiptError);
323
- }
323
+ };
324
+ var CostReceiptCaptureError = class extends ValidationError {
325
+ callId;
326
+ receipt;
327
+ receiptError;
328
+ constructor(callId, cause, receiptError, receipt) {
329
+ super(`CostLedger: could not capture the provider receipt for call '${callId}'`, { cause });
330
+ this.callId = callId;
331
+ this.receipt = receipt ? cloneReceipt(receipt) : void 0;
332
+ this.receiptError = toError(receiptError);
324
333
  }
325
- captureLateOutcome(input, pending, operation) {
326
- operation.then((value) => {
327
- if (this.records.get(pending.callId)?.status !== "pending") return;
328
- try {
329
- this.commitReceipt(pending, input.receipt(value));
330
- } catch {}
331
- }, (cause) => {
332
- if (this.records.get(pending.callId)?.status !== "pending") return;
333
- const error = toError(cause);
334
- try {
335
- const observed = input.receiptFromError?.(error);
336
- this.commitReceipt(pending, observed ?? unknownReceipt(pending.model), true);
337
- } catch (receiptError) {
338
- if (receiptError instanceof CostLedgerPersistenceError || receiptError instanceof CostCallConflictError) return;
339
- this.captureFailure(pending, error, receiptError);
334
+ };
335
+ //#endregion
336
+ //#region src/cost-ledger/journal.ts
337
+ /** Parse the append-only journal and enforce immutable pending-to-settled transitions. */
338
+ const CostLedgerEventSchema = z.union([
339
+ z.strictObject({
340
+ version: z.literal(1),
341
+ record: PendingCostCallSchema
342
+ }),
343
+ z.strictObject({
344
+ version: z.literal(2),
345
+ record: CostReceiptSchema
346
+ }),
347
+ z.strictObject({
348
+ version: z.literal(1),
349
+ completedTasks: TokenCount
350
+ }),
351
+ z.strictObject({
352
+ version: z.literal(1),
353
+ costCeilingUsd: NonNegative
354
+ })
355
+ ]);
356
+ function parseEvents(serialized) {
357
+ const records = /* @__PURE__ */ new Map();
358
+ let completedTasks = 0;
359
+ let costCeilingUsd;
360
+ let lineNumber = 0;
361
+ try {
362
+ for (const line of completeJournalPrefix(serialized).split("\n")) {
363
+ if (!line.trim()) continue;
364
+ lineNumber += 1;
365
+ const event = CostLedgerEventSchema.parse(JSON.parse(line));
366
+ if ("record" in event) {
367
+ const record = event.record;
368
+ validateTransition(records, record);
369
+ records.set(record.callId, cloneRecord(record));
370
+ } else if ("completedTasks" in event) {
371
+ completedTasks += event.completedTasks;
372
+ if (!Number.isSafeInteger(completedTasks)) throw new ValidationError("CostLedger: completed task count exceeds safe integer range");
373
+ } else {
374
+ if (costCeilingUsd !== void 0) throw new ValidationError("CostLedger: duplicate persisted cost ceiling");
375
+ costCeilingUsd = event.costCeilingUsd;
340
376
  }
341
- }).finally(() => {
342
- this.lateCallIds.delete(pending.callId);
343
- this.releaseActiveCall(pending.callId);
344
- });
345
- }
346
- releaseActiveCall(callId) {
347
- this.activeCallIds.delete(callId);
348
- for (const resolve of [...this.idleWaiters]) resolve();
349
- }
350
- async waitForReservationRelease(signal) {
351
- if (signal?.aborted) throw abortError(signal);
352
- await new Promise((resolve, reject) => {
353
- let finished = false;
354
- const finish = (error) => {
355
- if (finished) return;
356
- finished = true;
357
- this.idleWaiters.delete(onRelease);
358
- signal?.removeEventListener("abort", onAbort);
359
- if (error) reject(error);
360
- else resolve();
361
- };
362
- const onRelease = () => finish();
363
- const onAbort = () => finish(abortError(signal));
364
- this.idleWaiters.add(onRelease);
365
- signal?.addEventListener("abort", onAbort, { once: true });
366
- if (this.activeCallIds.size === 0) onRelease();
367
- });
368
- }
369
- commitOutcome(pending, error, observed) {
370
- try {
371
- const receipt = this.commitReceipt(pending, observed, true);
372
- return paidFailure(pending.callId, error, receipt);
373
- } catch (receiptError) {
374
- if (receiptError instanceof CostLedgerPersistenceError || receiptError instanceof CostCallConflictError) return paidFailure(pending.callId, receiptError);
375
- return this.captureFailure(pending, error, receiptError);
376
- }
377
- }
378
- captureFailure(pending, cause, receiptError) {
379
- try {
380
- const receipt = this.commitReceipt(pending, unknownReceipt(pending.model), true);
381
- return paidFailure(pending.callId, new CostReceiptCaptureError(pending.callId, cause, receiptError, receipt), receipt);
382
- } catch (error) {
383
- const typed = error instanceof Error ? error : toError(error);
384
- return paidFailure(pending.callId, typed);
385
- }
386
- }
387
- commitReceipt(pending, observed, failed = false, error) {
388
- const receipt = buildReceipt(pending, observed, failed, error);
389
- if (this.records.get(pending.callId)?.status !== "pending") throw new CostCallConflictError(`CostLedger: call '${pending.callId}' is not pending`);
390
- this.appendRecord(receipt);
391
- return cloneReceipt(receipt);
392
- }
393
- resolveMaximum(maximum) {
394
- if (!maximum) {
395
- if (this.costCeilingUsd !== void 0) throw new CostAccountingIncompleteError("CostLedger: capped paid calls require a hard maximumCharge before execution");
396
- return;
397
- }
398
- if ("externallyEnforcedMaximumUsd" in maximum) {
399
- assertNonNegative(maximum.externallyEnforcedMaximumUsd, "maximumCharge.externallyEnforcedMaximumUsd");
400
- return maximum.externallyEnforcedMaximumUsd;
401
- }
402
- if ("customTokenPricing" in maximum) return costForTokenPricing(maximum.customTokenPricing, maximum);
403
- const priced = costForUsage(maximum.model, maximum);
404
- if (priced.costUnknown) {
405
- if (this.costCeilingUsd !== void 0) throw new CostAccountingIncompleteError(`CostLedger: cannot reserve unpriced model '${maximum.model}' in a capped run`);
406
- return;
407
- }
408
- return priced.costUsd;
409
- }
410
- /** Compute admission totals in record order without building reporting rollups. */
411
- admissionState() {
412
- let unresolvedCalls = 0;
413
- let reservedCostUsd = 0;
414
- let committedCostUsd = 0;
415
- let budgetBreached = false;
416
- for (const record of this.records.values()) if (record.status === "pending") {
417
- if (!this.activeCallIds.has(record.callId) || this.lateCallIds.has(record.callId)) unresolvedCalls += 1;
418
- reservedCostUsd += record.maximumCostUsd ?? 0;
419
- } else {
420
- if (record.maximumCostUsd !== void 0 && record.costUsd > record.maximumCostUsd) budgetBreached = true;
421
- committedCostUsd += record.costUnknown ? record.maximumCostUsd ?? record.costUsd : record.costUsd;
422
377
  }
423
378
  return {
424
- unresolvedCalls,
425
- reservedCostUsd,
426
- committedCostUsd,
427
- budgetBreached
428
- };
429
- }
430
- appendRecord(record) {
431
- const callId = record.callId;
432
- const receipt = record.status === "settled" ? record : void 0;
433
- validateTransition(this.records, record);
434
- const event = record.status === "settled" ? {
435
- version: 2,
436
- record: cloneReceipt(record)
437
- } : {
438
- version: 1,
439
- record: clonePendingCall(record)
379
+ records: [...records.values()],
380
+ completedTasks,
381
+ ...costCeilingUsd === void 0 ? {} : { costCeilingUsd }
440
382
  };
441
- this.appendEvent(event, callId, receipt);
442
- this.records.set(callId, cloneRecord(record));
383
+ } catch (cause) {
384
+ throw new ValidationError(`CostLedger: invalid persisted event ${lineNumber || 1}: ${validationMessage(cause)}`, { cause });
443
385
  }
444
- ensureCostLimitPersisted(callId) {
445
- if (this.costLimitPersisted || this.costCeilingUsd === void 0) return;
446
- this.appendEvent({
447
- version: 1,
448
- costCeilingUsd: this.costCeilingUsd
449
- }, callId);
450
- this.costLimitPersisted = true;
386
+ }
387
+ function completeJournalPrefix(serialized) {
388
+ if (!serialized || serialized.endsWith("\n")) return serialized;
389
+ const finalNewline = serialized.lastIndexOf("\n");
390
+ const tail = serialized.slice(finalNewline + 1);
391
+ try {
392
+ JSON.parse(tail);
393
+ } catch {
394
+ return finalNewline < 0 ? "" : serialized.slice(0, finalNewline + 1);
451
395
  }
452
- appendEvent(event, callId, receipt) {
453
- try {
454
- if (this.persistence) {
455
- const nextRevision = this.persistence.append(this.revision, `${JSON.stringify(event)}\n`);
456
- if (nextRevision === void 0) throw new CostCallConflictError(`CostLedger: persisted revision changed while writing call '${callId}'`, {
457
- callId,
458
- receipt
459
- });
460
- assertString(nextRevision, "persistence revision");
461
- this.revision = nextRevision;
462
- }
463
- } catch (cause) {
464
- if (cause instanceof CostCallConflictError) throw cause;
465
- throw new CostLedgerPersistenceError(cause, callId, receipt);
396
+ throw new ValidationError("CostLedger: complete final persisted event is missing its newline terminator");
397
+ }
398
+ function validateTransition(records, record) {
399
+ const current = records.get(record.callId);
400
+ if (!current) return;
401
+ if (record.status === "pending" || current.status === "settled") throw new CostCallConflictError(`CostLedger: duplicate callId '${record.callId}'`);
402
+ if (!sameAttribution(current, record)) throw new ValidationError(`CostLedger: receipt attribution changed for call '${record.callId}'`);
403
+ }
404
+ function sameAttribution(before, after) {
405
+ return before.channel === after.channel && before.phase === after.phase && before.actor === after.actor && before.maximumCostUsd === after.maximumCostUsd && before.timestamp === after.timestamp && sameTags(before.tags, after.tags);
406
+ }
407
+ function sameTags(left, right) {
408
+ const leftEntries = Object.entries(left ?? {}).sort(([a], [b]) => a.localeCompare(b));
409
+ const rightEntries = Object.entries(right ?? {}).sort(([a], [b]) => a.localeCompare(b));
410
+ return JSON.stringify(leftEntries) === JSON.stringify(rightEntries);
411
+ }
412
+ //#endregion
413
+ //#region src/cost-ledger/summary.ts
414
+ function summarizeCostLedger(records, activeCallIds, lateCallIds) {
415
+ const pending = records.filter((record) => record.status === "pending");
416
+ const receipts = records.filter((record) => record.status === "settled");
417
+ const byChannel = /* @__PURE__ */ new Map();
418
+ const unpriced = /* @__PURE__ */ new Set();
419
+ const incompleteReasons = pending.map((record) => `call '${record.callId}' for '${record.actor}' is pending`);
420
+ let inputTokens = 0;
421
+ let outputTokens = 0;
422
+ let reasoningTokens = 0;
423
+ let cachedTokens = 0;
424
+ let cacheWriteTokens = 0;
425
+ let totalCostUsd = 0;
426
+ for (const receipt of receipts) {
427
+ inputTokens += receipt.inputTokens;
428
+ outputTokens += receipt.outputTokens;
429
+ reasoningTokens += receipt.reasoningTokens ?? 0;
430
+ cachedTokens += receipt.cachedTokens ?? 0;
431
+ cacheWriteTokens += receipt.cacheWriteTokens ?? 0;
432
+ totalCostUsd += receipt.costUsd;
433
+ if (receipt.costUnknown) {
434
+ unpriced.add(receipt.model);
435
+ incompleteReasons.push(receipt.error ?? `cost unknown for '${receipt.actor}' using '${receipt.model}'`);
466
436
  }
437
+ if (receipt.usageUnknown) incompleteReasons.push(`token usage unknown for '${receipt.actor}' using '${receipt.model}'`);
438
+ if (receipt.maximumCostUsd !== void 0 && receipt.costUsd > receipt.maximumCostUsd) incompleteReasons.push(`'${receipt.actor}' charged ${receipt.costUsd}, exceeding its enforced maximum ${receipt.maximumCostUsd}`);
439
+ const rollup = byChannel.get(receipt.channel) ?? emptyRollup(receipt.channel);
440
+ rollup.calls += 1;
441
+ rollup.inputTokens += receipt.inputTokens;
442
+ rollup.outputTokens += receipt.outputTokens;
443
+ rollup.reasoningTokens = (rollup.reasoningTokens ?? 0) + (receipt.reasoningTokens ?? 0);
444
+ rollup.cachedTokens += receipt.cachedTokens ?? 0;
445
+ rollup.cacheWriteTokens = (rollup.cacheWriteTokens ?? 0) + (receipt.cacheWriteTokens ?? 0);
446
+ rollup.costUsd += receipt.costUsd;
447
+ if (receipt.costUnknown) rollup.unpricedCalls += 1;
448
+ if (receipt.usageUnknown) rollup.unknownUsageCalls += 1;
449
+ byChannel.set(receipt.channel, rollup);
467
450
  }
468
- };
469
- /** Return the canonical pricing-table key, or null when the model is unpriced. */
470
- function modelPriceKey(model) {
471
- return isModelPriced(model) ? model : null;
472
- }
473
- function costForUsage(model, usage) {
474
- assertUsage(usage);
475
- if (!resolveModelPricing(model)) return {
476
- costUsd: 0,
477
- costUnknown: true
478
- };
479
451
  return {
480
- costUsd: estimateCost(usage.inputTokens + (usage.cachedTokens ?? 0) + (usage.cacheWriteTokens ?? 0), usage.outputTokens, model),
481
- costUnknown: false
452
+ totalCalls: receipts.length,
453
+ pendingCalls: pending.length,
454
+ unresolvedCalls: pending.filter((record) => !activeCallIds.has(record.callId) || lateCallIds.has(record.callId)).length,
455
+ reservedCostUsd: pending.reduce((sum, record) => sum + (record.maximumCostUsd ?? 0), 0),
456
+ inputTokens,
457
+ outputTokens,
458
+ reasoningTokens,
459
+ cachedTokens,
460
+ cacheWriteTokens,
461
+ totalCostUsd,
462
+ costProvenance: pending.length > 0 || receipts.some((receipt) => receipt.costUnknown) ? {
463
+ kind: "uncaptured",
464
+ usd: null
465
+ } : receipts.every((receipt) => receipt.actualCostUsd !== void 0) ? {
466
+ kind: "observed",
467
+ usd: totalCostUsd
468
+ } : {
469
+ kind: "estimated",
470
+ usd: totalCostUsd
471
+ },
472
+ byChannel: [...byChannel.values()].sort((a, b) => a.channel.localeCompare(b.channel)),
473
+ unpricedModels: [...unpriced].sort(),
474
+ fullyPriced: unpriced.size === 0,
475
+ usageComplete: pending.length === 0 && receipts.every((receipt) => !receipt.usageUnknown),
476
+ accountingComplete: incompleteReasons.length === 0,
477
+ incompleteReasons: [...new Set(incompleteReasons)]
482
478
  };
483
479
  }
484
- /** Price token counts with caller-supplied per-million rates. */
485
- function costForTokenPricing(pricing, usage) {
486
- assertTokenCount(usage.inputTokens, "usage.inputTokens");
487
- assertTokenCount(usage.outputTokens, "usage.outputTokens");
488
- if (usage.cachedTokens !== void 0) assertTokenCount(usage.cachedTokens, "usage.cachedTokens");
489
- if (usage.cacheWriteTokens !== void 0) assertTokenCount(usage.cacheWriteTokens, "usage.cacheWriteTokens");
490
- assertNonNegative(pricing.inputUsdPerMillion, "pricing.inputUsdPerMillion");
491
- if (pricing.cachedInputUsdPerMillion !== void 0) assertNonNegative(pricing.cachedInputUsdPerMillion, "pricing.cachedInputUsdPerMillion");
492
- if (pricing.cacheWriteUsdPerMillion !== void 0) assertNonNegative(pricing.cacheWriteUsdPerMillion, "pricing.cacheWriteUsdPerMillion");
493
- assertNonNegative(pricing.outputUsdPerMillion, "pricing.outputUsdPerMillion");
494
- const cachedInputRate = pricing.cachedInputUsdPerMillion ?? pricing.inputUsdPerMillion;
495
- const cacheWriteRate = pricing.cacheWriteUsdPerMillion ?? pricing.inputUsdPerMillion;
496
- return usage.inputTokens / 1e6 * pricing.inputUsdPerMillion + (usage.cachedTokens ?? 0) / 1e6 * cachedInputRate + (usage.cacheWriteTokens ?? 0) / 1e6 * cacheWriteRate + usage.outputTokens / 1e6 * pricing.outputUsdPerMillion;
497
- }
498
- async function settle(promise, signal) {
499
- return await new Promise((resolve) => {
500
- let done = false;
501
- const finish = (value) => {
502
- if (done) return;
503
- done = true;
504
- signal.removeEventListener("abort", onAbort);
505
- resolve(value);
506
- };
507
- const onAbort = () => finish({ kind: "aborted" });
508
- signal.addEventListener("abort", onAbort, { once: true });
509
- if (signal.aborted) onAbort();
510
- promise.then((value) => finish({
511
- kind: "value",
512
- value
513
- }), (error) => finish({
514
- kind: "error",
515
- error: toError(error)
516
- }));
517
- });
518
- }
519
- function buildReceipt(pending, observed, failed = false, error) {
520
- assertUsage(observed);
521
- assertString(observed.model, "receipt.model");
522
- if ([
523
- observed.actualCostUsd,
524
- observed.estimatedCostUsd,
525
- observed.customTokenPricing
526
- ].filter((value) => value !== void 0).length > 1) throw new ValidationError("CostLedger: a receipt can have only one of actualCostUsd, estimatedCostUsd, or customTokenPricing");
527
- const customPricingSnapshot = observed.customTokenPricing === void 0 ? void 0 : pricingSnapshot(observed.customTokenPricing);
528
- const estimated = customPricingSnapshot ? {
529
- costUsd: costFromPricing(observed, customPricingSnapshot),
530
- costUnknown: false
531
- } : costForUsage(observed.model, observed);
532
- const hasActual = observed.actualCostUsd !== void 0;
533
- const hasExternalEstimate = observed.estimatedCostUsd !== void 0;
534
- if (hasActual && observed.costUnknown === true) throw new ValidationError("CostLedger: a receipt cannot have both actualCostUsd and costUnknown=true");
535
- if (hasActual) assertNonNegative(observed.actualCostUsd, "actualCostUsd");
536
- if (hasExternalEstimate) assertNonNegative(observed.estimatedCostUsd, "estimatedCostUsd");
537
- if (hasExternalEstimate && observed.costUnknown === true) throw new ValidationError("CostLedger: a receipt cannot have both estimatedCostUsd and costUnknown=true");
538
- const usageUnknown = observed.usageUnknown === true;
539
- const costUnknown = observed.costUnknown === true || !hasActual && !hasExternalEstimate && (usageUnknown || estimated.costUnknown);
540
- const resolvedModelPricing = !customPricingSnapshot && !hasActual && !hasExternalEstimate && !costUnknown ? resolveModelPricing(observed.model) : null;
541
- const receiptPricing = !hasActual && !hasExternalEstimate && !costUnknown ? customPricingSnapshot ?? (resolvedModelPricing ? {
542
- inputUsdPerThousand: resolvedModelPricing.input,
543
- outputUsdPerThousand: resolvedModelPricing.output
544
- } : void 0) : void 0;
545
- return parseReceipt({
546
- status: "settled",
547
- callId: pending.callId,
548
- channel: pending.channel,
549
- phase: pending.phase,
550
- actor: pending.actor,
551
- model: observed.model,
552
- inputTokens: observed.inputTokens,
553
- outputTokens: observed.outputTokens,
554
- ...observed.reasoningTokens === void 0 ? {} : { reasoningTokens: observed.reasoningTokens },
555
- ...observed.cachedTokens === void 0 ? {} : { cachedTokens: observed.cachedTokens },
556
- ...observed.cacheWriteTokens === void 0 ? {} : { cacheWriteTokens: observed.cacheWriteTokens },
557
- costUsd: costUnknown ? 0 : hasActual ? observed.actualCostUsd : hasExternalEstimate ? observed.estimatedCostUsd : estimated.costUsd,
558
- costUnknown,
559
- usageUnknown,
560
- ...receiptPricing ? { pricing: receiptPricing } : {},
561
- ...hasActual ? { actualCostUsd: observed.actualCostUsd } : {},
562
- ...hasExternalEstimate ? { estimatedCostUsd: observed.estimatedCostUsd } : {},
563
- ...pending.maximumCostUsd === void 0 ? {} : { maximumCostUsd: pending.maximumCostUsd },
564
- ...failed ? { error: error ?? "paid-call-failed" } : {},
565
- ...pending.tags ? { tags: { ...pending.tags } } : {},
566
- timestamp: pending.timestamp
567
- }, "provider receipt");
480
+ function emptyRollup(channel) {
481
+ return {
482
+ channel,
483
+ calls: 0,
484
+ inputTokens: 0,
485
+ outputTokens: 0,
486
+ reasoningTokens: 0,
487
+ cachedTokens: 0,
488
+ cacheWriteTokens: 0,
489
+ costUsd: 0,
490
+ unpricedCalls: 0,
491
+ unknownUsageCalls: 0
492
+ };
568
493
  }
569
- const NonEmptyString = z.string().refine((value) => value.trim().length > 0, "must be non-empty");
570
- const TokenCount = z.number().int().nonnegative().finite();
571
- const NonNegative = z.number().nonnegative().finite();
572
- const Tags = z.record(NonEmptyString, z.string());
573
- const CostPricingSchema = z.strictObject({
574
- inputUsdPerThousand: NonNegative,
575
- cachedInputUsdPerThousand: NonNegative.optional(),
576
- cacheWriteUsdPerThousand: NonNegative.optional(),
577
- outputUsdPerThousand: NonNegative
578
- });
579
- const CostCallBaseShape = {
580
- callId: NonEmptyString,
581
- channel: NonEmptyString,
582
- phase: NonEmptyString,
583
- actor: NonEmptyString,
584
- model: NonEmptyString,
585
- maximumCostUsd: NonNegative.optional(),
586
- tags: Tags.optional(),
587
- timestamp: NonNegative
588
- };
589
- const PendingCostCallSchema = z.strictObject({
590
- status: z.literal("pending"),
591
- ...CostCallBaseShape
592
- });
593
- const CostReceiptBaseShape = {
594
- status: z.literal("settled"),
595
- ...CostCallBaseShape,
596
- inputTokens: TokenCount,
597
- outputTokens: TokenCount,
598
- cachedTokens: TokenCount.optional(),
599
- costUsd: NonNegative,
600
- costUnknown: z.boolean(),
601
- usageUnknown: z.boolean().default(false),
602
- pricing: CostPricingSchema.optional(),
603
- actualCostUsd: NonNegative.optional(),
604
- estimatedCostUsd: NonNegative.optional(),
605
- error: NonEmptyString.optional()
606
- };
607
- const CostReceiptSchema = z.strictObject({
608
- ...CostReceiptBaseShape,
609
- reasoningTokens: TokenCount.optional(),
610
- cacheWriteTokens: TokenCount.optional()
611
- }).superRefine((receipt, ctx) => validateCostReceipt(receipt, ctx));
612
- function validateCostReceipt(receipt, ctx) {
613
- if (receipt.reasoningTokens !== void 0 && receipt.reasoningTokens > receipt.outputTokens) ctx.addIssue({
614
- code: "custom",
615
- message: "reasoningTokens must not exceed outputTokens"
616
- });
617
- if (receipt.actualCostUsd !== void 0 && receipt.estimatedCostUsd !== void 0) ctx.addIssue({
618
- code: "custom",
619
- message: "actual and external estimated costs cannot both be present"
620
- });
621
- if (receipt.actualCostUsd !== void 0) {
622
- if (receipt.costUnknown || receipt.costUsd !== receipt.actualCostUsd) ctx.addIssue({
623
- code: "custom",
624
- message: "actual cost must be known and equal costUsd"
625
- });
626
- if (receipt.pricing !== void 0) ctx.addIssue({
627
- code: "custom",
628
- message: "actual cost must not include estimated pricing"
629
- });
630
- return;
494
+ //#endregion
495
+ //#region src/cost-ledger.ts
496
+ /** Run-wide paid-call admission, durable call state, receipts, and summaries. */
497
+ var CostLedger = class {
498
+ records = /* @__PURE__ */ new Map();
499
+ activeCallIds = /* @__PURE__ */ new Set();
500
+ lateCallIds = /* @__PURE__ */ new Set();
501
+ idleWaiters = /* @__PURE__ */ new Set();
502
+ completedTasks = 0;
503
+ revision = "memory";
504
+ costLimitPersisted = false;
505
+ costCeilingUsd;
506
+ persistence;
507
+ constructor(input) {
508
+ const options = typeof input === "number" ? { costCeilingUsd: input } : input ?? {};
509
+ this.persistence = options.persistence;
510
+ if (options.costCeilingUsd !== void 0) assertNonNegative(options.costCeilingUsd, "costCeilingUsd");
511
+ let persistedCostCeilingUsd;
512
+ if (this.persistence) {
513
+ let stored;
514
+ try {
515
+ stored = this.persistence.read();
516
+ } catch (cause) {
517
+ throw new CostLedgerPersistenceError(cause);
518
+ }
519
+ assertString(stored.revision, "persistence revision");
520
+ this.revision = stored.revision;
521
+ const restored = parseEvents(stored.events);
522
+ for (const record of restored.records) this.records.set(record.callId, record);
523
+ this.completedTasks = restored.completedTasks;
524
+ persistedCostCeilingUsd = restored.costCeilingUsd;
525
+ }
526
+ if (options.costCeilingUsd !== void 0 && persistedCostCeilingUsd !== void 0 && options.costCeilingUsd !== persistedCostCeilingUsd) throw new ValidationError(`CostLedger: requested cost ceiling ${options.costCeilingUsd} does not match persisted ceiling ${persistedCostCeilingUsd}`);
527
+ this.costCeilingUsd = persistedCostCeilingUsd ?? options.costCeilingUsd;
528
+ this.costLimitPersisted = !this.persistence || this.costCeilingUsd === void 0 || persistedCostCeilingUsd !== void 0;
529
+ if (this.costCeilingUsd !== void 0 && [...this.records.values()].some((record) => record.status === "pending" && record.maximumCostUsd === void 0)) throw new ValidationError("CostLedger: capped event log contains an unbounded pending call");
530
+ if (options.receipts?.length) {
531
+ const imported = options.receipts.map((receipt, index) => parseImportedReceipt(receipt, `imported receipt ${index + 1}`));
532
+ this.ensureCostLimitPersisted();
533
+ for (const receipt of imported) this.appendRecord(receipt);
534
+ }
535
+ }
536
+ async runPaidCall(input) {
537
+ let callId;
538
+ let pending;
539
+ try {
540
+ callId = resolveCallId(input.callId);
541
+ validateAttribution(input);
542
+ if (input.signal?.aborted) return {
543
+ succeeded: false,
544
+ callId,
545
+ error: abortError(input.signal)
546
+ };
547
+ this.ensureCostLimitPersisted(callId);
548
+ const maximumCostUsd = this.resolveMaximum(input.maximumCharge);
549
+ const existing = this.records.get(callId);
550
+ if (existing) return {
551
+ succeeded: false,
552
+ callId,
553
+ error: new CostCallConflictError(existing.status === "pending" ? `CostLedger: callId '${callId}' is unresolved and must be reconciled before retry` : `CostLedger: callId '${callId}' already exists`, { callId })
554
+ };
555
+ if (!pending) {
556
+ while (true) {
557
+ if (this.records.has(callId)) return {
558
+ succeeded: false,
559
+ callId,
560
+ error: new CostCallConflictError(`CostLedger: callId '${callId}' already exists`)
561
+ };
562
+ const admission = this.admissionState();
563
+ if (admission.unresolvedCalls > 0) return {
564
+ succeeded: false,
565
+ callId,
566
+ error: new CostAccountingIncompleteError(`CostLedger: ${admission.unresolvedCalls} unresolved call(s) must be reconciled before new paid work`)
567
+ };
568
+ if (this.costCeilingUsd === void 0) break;
569
+ if (admission.budgetBreached) return {
570
+ succeeded: false,
571
+ callId,
572
+ error: new CostAccountingIncompleteError(`CostLedger: a settled call exceeded its enforced maximum; refusing paid call '${input.actor}' during '${input.phase}'`)
573
+ };
574
+ const { committedCostUsd } = admission;
575
+ if (committedCostUsd + maximumCostUsd > this.costCeilingUsd) return {
576
+ succeeded: false,
577
+ callId,
578
+ error: new CostCeilingReachedError(this.costCeilingUsd, committedCostUsd, maximumCostUsd, input.phase, input.actor)
579
+ };
580
+ if (committedCostUsd + admission.reservedCostUsd + maximumCostUsd <= this.costCeilingUsd) break;
581
+ await this.waitForReservationRelease(input.signal);
582
+ }
583
+ pending = {
584
+ status: "pending",
585
+ callId,
586
+ channel: input.channel,
587
+ phase: input.phase,
588
+ actor: input.actor,
589
+ model: pendingModel(input),
590
+ ...maximumCostUsd === void 0 ? {} : { maximumCostUsd },
591
+ ...input.tags ? { tags: { ...input.tags } } : {},
592
+ timestamp: Date.now()
593
+ };
594
+ this.appendRecord(pending);
595
+ this.activeCallIds.add(callId);
596
+ }
597
+ } catch (error) {
598
+ return {
599
+ succeeded: false,
600
+ ...callId ? { callId } : {},
601
+ error: toError(error)
602
+ };
603
+ }
604
+ try {
605
+ return await this.execute(input, pending);
606
+ } catch (error) {
607
+ return {
608
+ succeeded: false,
609
+ callId: pending.callId,
610
+ error: toError(error)
611
+ };
612
+ } finally {
613
+ if (!this.lateCallIds.has(pending.callId)) this.releaseActiveCall(pending.callId);
614
+ }
631
615
  }
632
- if (receipt.estimatedCostUsd !== void 0) {
633
- if (receipt.costUnknown || receipt.costUsd !== receipt.estimatedCostUsd) ctx.addIssue({
634
- code: "custom",
635
- message: "external estimate must be known and equal costUsd"
616
+ /** Wait until every call started by this ledger has produced a durable outcome. */
617
+ async waitForIdle(options = {}) {
618
+ const hasActiveMatch = () => [...this.activeCallIds].some((callId) => {
619
+ const record = this.records.get(callId);
620
+ return record !== void 0 && matches(record, options.filter);
636
621
  });
637
- if (receipt.pricing !== void 0) ctx.addIssue({
638
- code: "custom",
639
- message: "external estimate must not include token pricing"
622
+ if (!hasActiveMatch()) return true;
623
+ const timeoutMs = options.timeoutMs ?? 5e3;
624
+ assertTimeout(timeoutMs, "waitForIdle.timeoutMs");
625
+ return new Promise((resolve) => {
626
+ let timer;
627
+ const finish = (settled) => {
628
+ this.idleWaiters.delete(onIdle);
629
+ if (timer !== void 0) clearTimeout(timer);
630
+ resolve(settled);
631
+ };
632
+ const onIdle = () => {
633
+ if (!hasActiveMatch()) finish(true);
634
+ };
635
+ this.idleWaiters.add(onIdle);
636
+ timer = setTimeout(() => finish(false), timeoutMs);
637
+ onIdle();
640
638
  });
641
- return;
642
639
  }
643
- if (receipt.costUnknown) {
644
- if (receipt.costUsd !== 0) ctx.addIssue({
645
- code: "custom",
646
- message: "unknown cost must have costUsd 0"
647
- });
648
- if (receipt.pricing !== void 0) ctx.addIssue({
649
- code: "custom",
650
- message: "unknown cost must not include estimated pricing"
640
+ /** Settle a call left pending by a crashed process after reconciling with the provider. */
641
+ reconcile(callId, observed, options = {}) {
642
+ const pending = this.records.get(callId);
643
+ if (pending?.status !== "pending") throw new CostCallConflictError(`CostLedger: no pending call '${callId}'`);
644
+ if (this.activeCallIds.has(callId)) throw new CostCallConflictError(`CostLedger: call '${callId}' is still active`);
645
+ this.ensureCostLimitPersisted(callId);
646
+ return this.commitReceipt(pending, observed, options.failed === true || options.error !== void 0, options.error);
647
+ }
648
+ list(filter) {
649
+ return [...this.records.values()].filter((record) => record.status === "settled").filter((receipt) => matches(receipt, filter)).map(cloneReceipt);
650
+ }
651
+ /** Read pending calls without exposing mutable ledger state. */
652
+ listPending(filter) {
653
+ return [...this.records.values()].filter((record) => record.status === "pending").filter((record) => matches(record, filter)).map((record) => ({
654
+ ...clonePendingCall(record),
655
+ state: this.lateCallIds.has(record.callId) ? "late" : this.activeCallIds.has(record.callId) ? "active" : "interrupted"
656
+ }));
657
+ }
658
+ summary(filter) {
659
+ return summarizeCostLedger([...this.records.values()].filter((record) => matches(record, filter)), this.activeCallIds, this.lateCallIds);
660
+ }
661
+ markCompleted(count = 1) {
662
+ if (!Number.isInteger(count) || count < 0) throw new ValidationError(`CostLedger.markCompleted: count must be a non-negative integer, got ${count}`);
663
+ if (count === 0) return;
664
+ this.ensureCostLimitPersisted();
665
+ this.appendEvent({
666
+ version: 1,
667
+ completedTasks: count
651
668
  });
652
- return;
669
+ this.completedTasks += count;
653
670
  }
654
- if (receipt.usageUnknown) ctx.addIssue({
655
- code: "custom",
656
- message: "known estimated cost requires known usage"
657
- });
658
- if (!receipt.pricing) {
659
- ctx.addIssue({
660
- code: "custom",
661
- message: "known estimated cost requires a pricing snapshot"
671
+ costPerCompletedTask() {
672
+ return this.completedTasks === 0 ? null : this.summary().totalCostUsd / this.completedTasks;
673
+ }
674
+ async execute(input, pending) {
675
+ const signal = input.signal ?? new AbortController().signal;
676
+ if (signal.aborted) return this.commitOutcome(pending, abortError(signal), {
677
+ model: pending.model,
678
+ inputTokens: 0,
679
+ outputTokens: 0,
680
+ actualCostUsd: 0
662
681
  });
663
- return;
682
+ const operation = Promise.resolve().then(() => input.execute(signal, pending.callId));
683
+ const settled = await settle(operation, signal);
684
+ if (settled.kind === "aborted") {
685
+ this.lateCallIds.add(pending.callId);
686
+ this.captureLateOutcome(input, pending, operation);
687
+ return paidFailure(pending.callId, abortError(signal));
688
+ }
689
+ if (settled.kind === "error") {
690
+ let observed;
691
+ try {
692
+ observed = input.receiptFromError?.(settled.error);
693
+ } catch (receiptError) {
694
+ return this.captureFailure(pending, settled.error, receiptError);
695
+ }
696
+ return this.commitOutcome(pending, settled.error, observed ?? unknownReceipt(pending.model));
697
+ }
698
+ try {
699
+ const receipt = this.commitReceipt(pending, input.receipt(settled.value));
700
+ if (receipt.maximumCostUsd !== void 0 && receipt.costUsd > receipt.maximumCostUsd) return paidFailure(pending.callId, new CostReservationExceededError(pending.actor, receipt.costUsd, receipt.maximumCostUsd), receipt);
701
+ return {
702
+ succeeded: true,
703
+ callId: pending.callId,
704
+ value: settled.value,
705
+ receipt
706
+ };
707
+ } catch (receiptError) {
708
+ if (receiptError instanceof CostLedgerPersistenceError || receiptError instanceof CostCallConflictError) return paidFailure(pending.callId, receiptError);
709
+ return this.captureFailure(pending, receiptError, receiptError);
710
+ }
664
711
  }
665
- const expected = costFromPricing(receipt, receipt.pricing);
666
- if (!costAmountsMatch(receipt.costUsd, expected)) ctx.addIssue({
667
- code: "custom",
668
- message: `estimated cost ${receipt.costUsd} does not match pricing snapshot ${expected}`
669
- });
670
- }
671
- function costAmountsMatch(left, right) {
672
- const scale = Math.max(1, Math.abs(left), Math.abs(right));
673
- return Math.abs(left - right) <= Number.EPSILON * scale * 8;
674
- }
675
- const CostLedgerEventSchema = z.union([
676
- z.strictObject({
677
- version: z.literal(1),
678
- record: PendingCostCallSchema
679
- }),
680
- z.strictObject({
681
- version: z.literal(2),
682
- record: CostReceiptSchema
683
- }),
684
- z.strictObject({
685
- version: z.literal(1),
686
- completedTasks: TokenCount
687
- }),
688
- z.strictObject({
689
- version: z.literal(1),
690
- costCeilingUsd: NonNegative
691
- })
692
- ]);
693
- function parseEvents(serialized) {
694
- const records = /* @__PURE__ */ new Map();
695
- let completedTasks = 0;
696
- let costCeilingUsd;
697
- let lineNumber = 0;
698
- try {
699
- for (const line of completeJournalPrefix(serialized).split("\n")) {
700
- if (!line.trim()) continue;
701
- lineNumber += 1;
702
- const event = CostLedgerEventSchema.parse(JSON.parse(line));
703
- if ("record" in event) {
704
- const record = event.record;
705
- validateTransition(records, record);
706
- records.set(record.callId, cloneRecord(record));
707
- } else if ("completedTasks" in event) {
708
- completedTasks += event.completedTasks;
709
- if (!Number.isSafeInteger(completedTasks)) throw new ValidationError("CostLedger: completed task count exceeds safe integer range");
710
- } else {
711
- if (costCeilingUsd !== void 0) throw new ValidationError("CostLedger: duplicate persisted cost ceiling");
712
- costCeilingUsd = event.costCeilingUsd;
712
+ captureLateOutcome(input, pending, operation) {
713
+ operation.then((value) => {
714
+ if (this.records.get(pending.callId)?.status !== "pending") return;
715
+ try {
716
+ this.commitReceipt(pending, input.receipt(value));
717
+ } catch {}
718
+ }, (cause) => {
719
+ if (this.records.get(pending.callId)?.status !== "pending") return;
720
+ const error = toError(cause);
721
+ try {
722
+ const observed = input.receiptFromError?.(error);
723
+ this.commitReceipt(pending, observed ?? unknownReceipt(pending.model), true);
724
+ } catch (receiptError) {
725
+ if (receiptError instanceof CostLedgerPersistenceError || receiptError instanceof CostCallConflictError) return;
726
+ this.captureFailure(pending, error, receiptError);
713
727
  }
728
+ }).finally(() => {
729
+ this.lateCallIds.delete(pending.callId);
730
+ this.releaseActiveCall(pending.callId);
731
+ });
732
+ }
733
+ releaseActiveCall(callId) {
734
+ this.activeCallIds.delete(callId);
735
+ for (const resolve of [...this.idleWaiters]) resolve();
736
+ }
737
+ async waitForReservationRelease(signal) {
738
+ if (signal?.aborted) throw abortError(signal);
739
+ await new Promise((resolve, reject) => {
740
+ let finished = false;
741
+ const finish = (error) => {
742
+ if (finished) return;
743
+ finished = true;
744
+ this.idleWaiters.delete(onRelease);
745
+ signal?.removeEventListener("abort", onAbort);
746
+ if (error) reject(error);
747
+ else resolve();
748
+ };
749
+ const onRelease = () => finish();
750
+ const onAbort = () => finish(abortError(signal));
751
+ this.idleWaiters.add(onRelease);
752
+ signal?.addEventListener("abort", onAbort, { once: true });
753
+ if (this.activeCallIds.size === 0) onRelease();
754
+ });
755
+ }
756
+ commitOutcome(pending, error, observed) {
757
+ try {
758
+ const receipt = this.commitReceipt(pending, observed, true);
759
+ return paidFailure(pending.callId, error, receipt);
760
+ } catch (receiptError) {
761
+ if (receiptError instanceof CostLedgerPersistenceError || receiptError instanceof CostCallConflictError) return paidFailure(pending.callId, receiptError);
762
+ return this.captureFailure(pending, error, receiptError);
714
763
  }
715
- return {
716
- records: [...records.values()],
717
- completedTasks,
718
- ...costCeilingUsd === void 0 ? {} : { costCeilingUsd }
719
- };
720
- } catch (cause) {
721
- throw new ValidationError(`CostLedger: invalid persisted event ${lineNumber || 1}: ${validationMessage(cause)}`, { cause });
722
764
  }
723
- }
724
- function completeJournalPrefix(serialized) {
725
- if (!serialized || serialized.endsWith("\n")) return serialized;
726
- const finalNewline = serialized.lastIndexOf("\n");
727
- const tail = serialized.slice(finalNewline + 1);
728
- try {
729
- JSON.parse(tail);
730
- } catch {
731
- return finalNewline < 0 ? "" : serialized.slice(0, finalNewline + 1);
765
+ captureFailure(pending, cause, receiptError) {
766
+ try {
767
+ const receipt = this.commitReceipt(pending, unknownReceipt(pending.model), true);
768
+ return paidFailure(pending.callId, new CostReceiptCaptureError(pending.callId, cause, receiptError, receipt), receipt);
769
+ } catch (error) {
770
+ const typed = error instanceof Error ? error : toError(error);
771
+ return paidFailure(pending.callId, typed);
772
+ }
732
773
  }
733
- throw new ValidationError("CostLedger: complete final persisted event is missing its newline terminator");
734
- }
735
- function validateTransition(records, record) {
736
- const current = records.get(record.callId);
737
- if (!current) return;
738
- if (record.status === "pending" || current.status === "settled") throw new CostCallConflictError(`CostLedger: duplicate callId '${record.callId}'`);
739
- if (!sameAttribution(current, record)) throw new ValidationError(`CostLedger: receipt attribution changed for call '${record.callId}'`);
740
- }
741
- function sameAttribution(before, after) {
742
- return before.channel === after.channel && before.phase === after.phase && before.actor === after.actor && before.maximumCostUsd === after.maximumCostUsd && before.timestamp === after.timestamp && sameTags(before.tags, after.tags);
743
- }
744
- function sameTags(left, right) {
745
- const leftEntries = Object.entries(left ?? {}).sort(([a], [b]) => a.localeCompare(b));
746
- const rightEntries = Object.entries(right ?? {}).sort(([a], [b]) => a.localeCompare(b));
747
- return JSON.stringify(leftEntries) === JSON.stringify(rightEntries);
748
- }
749
- function parseReceipt(value, path) {
750
- try {
751
- return CostReceiptSchema.parse(value);
752
- } catch (cause) {
753
- throw new ValidationError(`CostLedger: invalid ${path}: ${validationMessage(cause)}`, { cause });
774
+ commitReceipt(pending, observed, failed = false, error) {
775
+ const receipt = buildReceipt(pending, observed, failed, error);
776
+ if (this.records.get(pending.callId)?.status !== "pending") throw new CostCallConflictError(`CostLedger: call '${pending.callId}' is not pending`);
777
+ this.appendRecord(receipt);
778
+ return cloneReceipt(receipt);
754
779
  }
755
- }
756
- function parseImportedReceipt(value, path) {
757
- if (typeof value !== "object" || value === null) return parseReceipt(value, path);
758
- const candidate = { ...value };
759
- if (candidate.status === "settled" && candidate.actualCostUsd === void 0 && candidate.estimatedCostUsd === void 0 && candidate.costUnknown === false && candidate.pricing === void 0 && typeof candidate.model === "string") {
760
- const pricing = resolveModelPricing(candidate.model);
761
- if (pricing) candidate.pricing = {
762
- inputUsdPerThousand: pricing.input,
763
- outputUsdPerThousand: pricing.output
780
+ resolveMaximum(maximum) {
781
+ if (!maximum) {
782
+ if (this.costCeilingUsd !== void 0) throw new CostAccountingIncompleteError("CostLedger: capped paid calls require a hard maximumCharge before execution");
783
+ return;
784
+ }
785
+ if ("externallyEnforcedMaximumUsd" in maximum) {
786
+ assertNonNegative(maximum.externallyEnforcedMaximumUsd, "maximumCharge.externallyEnforcedMaximumUsd");
787
+ return maximum.externallyEnforcedMaximumUsd;
788
+ }
789
+ if ("customTokenPricing" in maximum) return costForTokenPricing(maximum.customTokenPricing, maximum);
790
+ const priced = costForUsage(maximum.model, maximum);
791
+ if (priced.costUnknown) {
792
+ if (this.costCeilingUsd !== void 0) throw new CostAccountingIncompleteError(`CostLedger: cannot reserve unpriced model '${maximum.model}' in a capped run`);
793
+ return;
794
+ }
795
+ return priced.costUsd;
796
+ }
797
+ /** Compute admission totals in record order without building reporting rollups. */
798
+ admissionState() {
799
+ let unresolvedCalls = 0;
800
+ let reservedCostUsd = 0;
801
+ let committedCostUsd = 0;
802
+ let budgetBreached = false;
803
+ for (const record of this.records.values()) if (record.status === "pending") {
804
+ if (!this.activeCallIds.has(record.callId) || this.lateCallIds.has(record.callId)) unresolvedCalls += 1;
805
+ reservedCostUsd += record.maximumCostUsd ?? 0;
806
+ } else {
807
+ if (record.maximumCostUsd !== void 0 && record.costUsd > record.maximumCostUsd) budgetBreached = true;
808
+ committedCostUsd += record.costUnknown ? record.maximumCostUsd ?? record.costUsd : record.costUsd;
809
+ }
810
+ return {
811
+ unresolvedCalls,
812
+ reservedCostUsd,
813
+ committedCostUsd,
814
+ budgetBreached
764
815
  };
765
816
  }
766
- return parseReceipt(candidate, path);
767
- }
768
- function validateAttribution(input) {
769
- assertString(input.channel, "channel");
770
- assertString(input.phase, "phase");
771
- assertString(input.actor, "actor");
772
- if (input.model !== void 0) assertString(input.model, "model");
773
- if (input.tags !== void 0) {
774
- const parsed = Tags.safeParse(input.tags);
775
- if (!parsed.success) throw new ValidationError(`CostLedger: invalid tags: ${parsed.error.message}`);
817
+ appendRecord(record) {
818
+ const callId = record.callId;
819
+ const receipt = record.status === "settled" ? record : void 0;
820
+ validateTransition(this.records, record);
821
+ const event = record.status === "settled" ? {
822
+ version: 2,
823
+ record: cloneReceipt(record)
824
+ } : {
825
+ version: 1,
826
+ record: clonePendingCall(record)
827
+ };
828
+ this.appendEvent(event, callId, receipt);
829
+ this.records.set(callId, cloneRecord(record));
776
830
  }
777
- }
778
- function matches(record, filter) {
779
- if (!filter) return true;
780
- if (filter.channel !== void 0 && record.channel !== filter.channel) return false;
781
- if (filter.phase !== void 0 && record.phase !== filter.phase) return false;
782
- return Object.entries(filter.tags ?? {}).every(([key, value]) => record.tags?.[key] === value);
783
- }
784
- function cloneRecord(record) {
785
- if (record.status === "settled") return cloneReceipt(record);
786
- return clonePendingCall(record);
787
- }
788
- function clonePendingCall(record) {
789
- const { tags, ...rest } = record;
790
- return {
791
- ...rest,
792
- ...tags ? { tags: { ...tags } } : {}
793
- };
794
- }
795
- function cloneReceipt(receipt) {
796
- const { pricing, tags, ...rest } = receipt;
797
- return {
798
- ...rest,
799
- ...tags ? { tags: { ...tags } } : {},
800
- ...pricing ? { pricing: { ...pricing } } : {}
801
- };
802
- }
803
- function costFromPricing(usage, pricing) {
804
- const cachedInputRate = pricing.cachedInputUsdPerThousand ?? pricing.inputUsdPerThousand;
805
- const cacheWriteRate = pricing.cacheWriteUsdPerThousand ?? pricing.inputUsdPerThousand;
806
- return usage.inputTokens / 1e3 * pricing.inputUsdPerThousand + (usage.cachedTokens ?? 0) / 1e3 * cachedInputRate + (usage.cacheWriteTokens ?? 0) / 1e3 * cacheWriteRate + usage.outputTokens / 1e3 * pricing.outputUsdPerThousand;
807
- }
808
- function pricingSnapshot(pricing) {
809
- costForTokenPricing(pricing, {
810
- inputTokens: 0,
811
- outputTokens: 0
831
+ ensureCostLimitPersisted(callId) {
832
+ if (this.costLimitPersisted || this.costCeilingUsd === void 0) return;
833
+ this.appendEvent({
834
+ version: 1,
835
+ costCeilingUsd: this.costCeilingUsd
836
+ }, callId);
837
+ this.costLimitPersisted = true;
838
+ }
839
+ appendEvent(event, callId, receipt) {
840
+ try {
841
+ if (this.persistence) {
842
+ const nextRevision = this.persistence.append(this.revision, `${JSON.stringify(event)}\n`);
843
+ if (nextRevision === void 0) throw new CostCallConflictError(`CostLedger: persisted revision changed while writing call '${callId}'`, {
844
+ callId,
845
+ receipt
846
+ });
847
+ assertString(nextRevision, "persistence revision");
848
+ this.revision = nextRevision;
849
+ }
850
+ } catch (cause) {
851
+ if (cause instanceof CostCallConflictError) throw cause;
852
+ throw new CostLedgerPersistenceError(cause, callId, receipt);
853
+ }
854
+ }
855
+ };
856
+ async function settle(promise, signal) {
857
+ return await new Promise((resolve) => {
858
+ let done = false;
859
+ const finish = (value) => {
860
+ if (done) return;
861
+ done = true;
862
+ signal.removeEventListener("abort", onAbort);
863
+ resolve(value);
864
+ };
865
+ const onAbort = () => finish({ kind: "aborted" });
866
+ signal.addEventListener("abort", onAbort, { once: true });
867
+ if (signal.aborted) onAbort();
868
+ promise.then((value) => finish({
869
+ kind: "value",
870
+ value
871
+ }), (error) => finish({
872
+ kind: "error",
873
+ error: toError(error)
874
+ }));
812
875
  });
813
- return {
814
- inputUsdPerThousand: pricing.inputUsdPerMillion / 1e3,
815
- ...pricing.cachedInputUsdPerMillion === void 0 ? {} : { cachedInputUsdPerThousand: pricing.cachedInputUsdPerMillion / 1e3 },
816
- ...pricing.cacheWriteUsdPerMillion === void 0 ? {} : { cacheWriteUsdPerThousand: pricing.cacheWriteUsdPerMillion / 1e3 },
817
- outputUsdPerThousand: pricing.outputUsdPerMillion / 1e3
818
- };
819
- }
820
- function emptyRollup(channel) {
821
- return {
822
- channel,
823
- calls: 0,
824
- inputTokens: 0,
825
- outputTokens: 0,
826
- reasoningTokens: 0,
827
- cachedTokens: 0,
828
- cacheWriteTokens: 0,
829
- costUsd: 0,
830
- unpricedCalls: 0,
831
- unknownUsageCalls: 0
832
- };
833
876
  }
834
877
  function pendingModel(input) {
835
878
  if (input.model) return input.model;
@@ -860,9 +903,6 @@ function abortError(signal) {
860
903
  error.name = "AbortError";
861
904
  return error;
862
905
  }
863
- function toError(value) {
864
- return value instanceof Error ? value : new Error(String(value));
865
- }
866
906
  function paidFailure(callId, error, receipt) {
867
907
  return {
868
908
  succeeded: false,
@@ -871,32 +911,7 @@ function paidFailure(callId, error, receipt) {
871
911
  ...receipt ? { receipt: cloneReceipt(receipt) } : {}
872
912
  };
873
913
  }
874
- function validationMessage(cause) {
875
- return cause instanceof z.ZodError ? z.prettifyError(cause) : toError(cause).message;
876
- }
877
- function assertUsage(usage) {
878
- assertTokenCount(usage.inputTokens, "inputTokens");
879
- assertTokenCount(usage.outputTokens, "outputTokens");
880
- if (usage.reasoningTokens !== void 0) {
881
- assertTokenCount(usage.reasoningTokens, "reasoningTokens");
882
- if (usage.reasoningTokens > usage.outputTokens) throw new ValidationError("CostLedger: reasoningTokens must not exceed outputTokens");
883
- }
884
- if (usage.cachedTokens !== void 0) assertTokenCount(usage.cachedTokens, "cachedTokens");
885
- if (usage.cacheWriteTokens !== void 0) assertTokenCount(usage.cacheWriteTokens, "cacheWriteTokens");
886
- }
887
- function assertTokenCount(value, name) {
888
- if (typeof value !== "number" || !Number.isInteger(value) || value < 0) throw new ValidationError(`CostLedger: ${name} must be a non-negative integer, got ${String(value)}`);
889
- }
890
- function assertNonNegative(value, name) {
891
- if (typeof value !== "number" || !Number.isFinite(value) || value < 0) throw new ValidationError(`CostLedger: ${name} must be a non-negative finite number, got ${String(value)}`);
892
- }
893
- function assertTimeout(value, name) {
894
- if (typeof value !== "number" || !Number.isSafeInteger(value) || value < 0 || value > 2147483647) throw new ValidationError(`CostLedger: ${name} must be a non-negative safe integer no greater than 2147483647, got ${String(value)}`);
895
- }
896
- function assertString(value, name) {
897
- if (typeof value !== "string" || value.trim().length === 0) throw new ValidationError(`CostLedger: ${name} must be a non-empty string`);
898
- }
899
914
  //#endregion
900
- export { CostLedgerPersistenceError as a, costForTokenPricing as c, CostLedger as i, costForUsage as l, CostCallConflictError as n, CostReceiptCaptureError as o, CostCeilingReachedError as r, CostReservationExceededError as s, CostAccountingIncompleteError as t, modelPriceKey as u };
915
+ export { CostLedgerPersistenceError as a, costForTokenPricing as c, CostCeilingReachedError as i, costForUsage as l, CostAccountingIncompleteError as n, CostReceiptCaptureError as o, CostCallConflictError as r, CostReservationExceededError as s, CostLedger as t };
901
916
 
902
- //# sourceMappingURL=cost-ledger-D2FnJPBF.js.map
917
+ //# sourceMappingURL=cost-ledger-D0352Z4d.js.map