@tangle-network/agent-eval 0.215.1 → 0.216.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 (400) hide show
  1. package/CHANGELOG.md +51 -0
  2. package/dist/adapters/http.d.ts +3 -3
  3. package/dist/{agent-profile-DmzL8KaJ.d.ts → agent-profile-VFcQncbW.d.ts} +5 -5
  4. package/dist/{agent-profile-DmzL8KaJ.d.ts.map → agent-profile-VFcQncbW.d.ts.map} +1 -1
  5. package/dist/{agent-profile-cell-BYc0bxsL.js → agent-profile-cell-BK8mlqlq.js} +3 -3
  6. package/dist/{agent-profile-cell-BYc0bxsL.js.map → agent-profile-cell-BK8mlqlq.js.map} +1 -1
  7. package/dist/agreement-irr-BEWLIF3_.js +186 -0
  8. package/dist/agreement-irr-BEWLIF3_.js.map +1 -0
  9. package/dist/analyst/index.d.ts +487 -14
  10. package/dist/analyst/index.d.ts.map +1 -1
  11. package/dist/analyst/index.js +1547 -12
  12. package/dist/analyst/index.js.map +1 -1
  13. package/dist/{analyze-runs-3xpby3p2.js → analyze-runs-C84irm4i.js} +608 -604
  14. package/dist/analyze-runs-C84irm4i.js.map +1 -0
  15. package/dist/{analyze-runs-BhFLOztS.d.ts → analyze-runs-D68fd-su.d.ts} +17 -15
  16. package/dist/analyze-runs-D68fd-su.d.ts.map +1 -0
  17. package/dist/{baseline-Dm8966du.js → baseline-Udi_PLuT.js} +5 -5
  18. package/dist/{baseline-Dm8966du.js.map → baseline-Udi_PLuT.js.map} +1 -1
  19. package/dist/{benchmark-BywPeAUo.js → benchmark-CXmVVHH2.js} +2 -2
  20. package/dist/{benchmark-BywPeAUo.js.map → benchmark-CXmVVHH2.js.map} +1 -1
  21. package/dist/{benchmark-command-CgpGi7vY.js → benchmark-command-By0vh8q7.js} +71 -70
  22. package/dist/benchmark-command-By0vh8q7.js.map +1 -0
  23. package/dist/benchmarks/index.d.ts +5 -5
  24. package/dist/benchmarks/index.js +3 -3
  25. package/dist/builder-eval/index.js +2 -2
  26. package/dist/campaign/index.d.ts +7 -7
  27. package/dist/campaign/index.js +14 -14
  28. package/dist/{campaign-CpnsCgfz.js → campaign-BudZ70zo.js} +245 -247
  29. package/dist/campaign-BudZ70zo.js.map +1 -0
  30. package/dist/{campaign-evidence-OcUciD-N.js → campaign-evidence-Clrn4hBV.js} +8 -8
  31. package/dist/campaign-evidence-Clrn4hBV.js.map +1 -0
  32. package/dist/{canonical-BsZVgBhW.js → canonical-B2RqLofv.js} +2 -2
  33. package/dist/{canonical-BsZVgBhW.js.map → canonical-B2RqLofv.js.map} +1 -1
  34. package/dist/{chat-client-DthPOYGd.js → chat-client-l-MVDlDk.js} +2 -2
  35. package/dist/{chat-client-DthPOYGd.js.map → chat-client-l-MVDlDk.js.map} +1 -1
  36. package/dist/{chat-json-call-BrKsyspg.js → chat-json-call-puMArmtW.js} +2 -2
  37. package/dist/{chat-json-call-BrKsyspg.js.map → chat-json-call-puMArmtW.js.map} +1 -1
  38. package/dist/{claim-BXcZw-jo.js → claim-q4HQhK1G.js} +4 -4
  39. package/dist/claim-q4HQhK1G.js.map +1 -0
  40. package/dist/cli.js +9 -9
  41. package/dist/cli.js.map +1 -1
  42. package/dist/cluster-bootstrap-qcUWYFl-.js +66 -0
  43. package/dist/cluster-bootstrap-qcUWYFl-.js.map +1 -0
  44. package/dist/contract/index.d.ts +11 -11
  45. package/dist/contract/index.js +1023 -1079
  46. package/dist/contract/index.js.map +1 -1
  47. package/dist/{cost-ledger-D2FnJPBF.js → cost-ledger-BP8V4kUQ.js} +835 -816
  48. package/dist/cost-ledger-BP8V4kUQ.js.map +1 -0
  49. package/dist/{cost-ledger-CO7UyEcQ.d.ts → cost-ledger-Jk62OBfF.d.ts} +12 -47
  50. package/dist/cost-ledger-Jk62OBfF.d.ts.map +1 -0
  51. package/dist/{counterfactual-DtMWvn7D.js → counterfactual-Dn3veueY.js} +2 -2
  52. package/dist/{counterfactual-DtMWvn7D.js.map → counterfactual-Dn3veueY.js.map} +1 -1
  53. package/dist/{default-registry-KP4-Tolz.js → default-registry-COhk9g36.js} +744 -759
  54. package/dist/default-registry-COhk9g36.js.map +1 -0
  55. package/dist/{default-registry-B4B7GMvI.d.ts → default-registry-DzHiGruW.d.ts} +6 -6
  56. package/dist/{default-registry-B4B7GMvI.d.ts.map → default-registry-DzHiGruW.d.ts.map} +1 -1
  57. package/dist/{define-agent-eval-BdfnqXeP.js → define-agent-eval-CNTPzIkp.js} +10 -10
  58. package/dist/define-agent-eval-CNTPzIkp.js.map +1 -0
  59. package/dist/{define-agent-eval-DfXvNho5.d.ts → define-agent-eval-WSck0CZJ.d.ts} +8 -8
  60. package/dist/{define-agent-eval-DfXvNho5.d.ts.map → define-agent-eval-WSck0CZJ.d.ts.map} +1 -1
  61. package/dist/{descriptive-CnU8Yq29.js → descriptive-DboxPZrG.js} +2 -2
  62. package/dist/{descriptive-CnU8Yq29.js.map → descriptive-DboxPZrG.js.map} +1 -1
  63. package/dist/diagnosis/index.d.ts +3 -3
  64. package/dist/diagnosis/index.js +4 -4
  65. package/dist/{dspy-rlm-engine-DZfHM7kT.js → dspy-rlm-engine-LRCu61m5.js} +3 -3
  66. package/dist/{dspy-rlm-engine-DZfHM7kT.js.map → dspy-rlm-engine-LRCu61m5.js.map} +1 -1
  67. package/dist/{effect-sizes-DiH8MGOH.js → effect-sizes-BhzEpXMc.js} +2 -2
  68. package/dist/{effect-sizes-DiH8MGOH.js.map → effect-sizes-BhzEpXMc.js.map} +1 -1
  69. package/dist/{engine-C37HS2kr.d.ts → engine-3A_4jOlI.d.ts} +5 -5
  70. package/dist/{engine-C37HS2kr.d.ts.map → engine-3A_4jOlI.d.ts.map} +1 -1
  71. package/dist/{equal-terms-Blx9Zk5I.js → equal-terms-BtdXayCJ.js} +2 -2
  72. package/dist/{equal-terms-Blx9Zk5I.js.map → equal-terms-BtdXayCJ.js.map} +1 -1
  73. package/dist/{errors-Dngq5h35.js → errors-DVZiqS7K.js} +6 -2
  74. package/dist/{errors-Dngq5h35.js.map → errors-DVZiqS7K.js.map} +1 -1
  75. package/dist/{eval-campaign-4byTtqrf.js → eval-campaign-90jeaCAI.js} +6 -6
  76. package/dist/{eval-campaign-4byTtqrf.js.map → eval-campaign-90jeaCAI.js.map} +1 -1
  77. package/dist/evaluation-6Yoi74gM.d.ts +75 -0
  78. package/dist/evaluation-6Yoi74gM.d.ts.map +1 -0
  79. package/dist/evaluation.d.ts +2 -74
  80. package/dist/evaluation.js +1 -1
  81. package/dist/{exact-types-Dlb73wN4.d.ts → exact-types-ClugMJfI.d.ts} +2 -2
  82. package/dist/{exact-types-Dlb73wN4.d.ts.map → exact-types-ClugMJfI.d.ts.map} +1 -1
  83. package/dist/experiment/index.d.ts +404 -3
  84. package/dist/experiment/index.d.ts.map +1 -1
  85. package/dist/experiment/index.js +313 -19
  86. package/dist/experiment/index.js.map +1 -1
  87. package/dist/{external-optimizer-process-GngofQML.js → external-optimizer-process-BjMGUuds.js} +3 -3
  88. package/dist/{external-optimizer-process-GngofQML.js.map → external-optimizer-process-BjMGUuds.js.map} +1 -1
  89. package/dist/{external-optimizer-subprocess-BUxifb8g.js → external-optimizer-subprocess-BqW0hHcI.js} +791 -532
  90. package/dist/external-optimizer-subprocess-BqW0hHcI.js.map +1 -0
  91. package/dist/{feedback-trajectory-BLN_6fEs.d.ts → feedback-trajectory-C4EG0nNH.d.ts} +5 -8
  92. package/dist/feedback-trajectory-C4EG0nNH.d.ts.map +1 -0
  93. package/dist/fuzz.d.ts +1 -1
  94. package/dist/fuzz.js +3 -3
  95. package/dist/hosted/index.js +1 -1
  96. package/dist/{index-CPJJr98o.d.ts → index-BFRO6chs.d.ts} +3 -2
  97. package/dist/index-BFRO6chs.d.ts.map +1 -0
  98. package/dist/{index-Ch9VxCpK.d.ts → index-BO41eGj5.d.ts} +2 -2
  99. package/dist/{index-Ch9VxCpK.d.ts.map → index-BO41eGj5.d.ts.map} +1 -1
  100. package/dist/{index-B3WBm953.d.ts → index-CyszSg4O.d.ts} +165 -162
  101. package/dist/index-CyszSg4O.d.ts.map +1 -0
  102. package/dist/{index-B7m2uzJL.d.ts → index-DPcngtwt.d.ts} +30 -17
  103. package/dist/index-DPcngtwt.d.ts.map +1 -0
  104. package/dist/{index-tYLUvk_w.d.ts → index-DV-jSzxF.d.ts} +9 -9
  105. package/dist/{index-tYLUvk_w.d.ts.map → index-DV-jSzxF.d.ts.map} +1 -1
  106. package/dist/index.d.ts +1969 -1871
  107. package/dist/index.d.ts.map +1 -1
  108. package/dist/index.js +162 -201
  109. package/dist/index.js.map +1 -1
  110. package/dist/{integrity-BvnVARVl.js → integrity-BXOsAb3i.js} +2 -2
  111. package/dist/{integrity-BvnVARVl.js.map → integrity-BXOsAb3i.js.map} +1 -1
  112. package/dist/{integrity-CCAxGVK6.d.ts → integrity-DAMEDFaC.d.ts} +2 -2
  113. package/dist/{integrity-CCAxGVK6.d.ts.map → integrity-DAMEDFaC.d.ts.map} +1 -1
  114. package/dist/{integrity-BV1ZDf42.js → integrity-dLiDe2kD.js} +2 -5
  115. package/dist/integrity-dLiDe2kD.js.map +1 -0
  116. package/dist/{internal-CRHwS9iz.js → internal-Epl-YBZW.js} +3 -3
  117. package/dist/{internal-CRHwS9iz.js.map → internal-Epl-YBZW.js.map} +1 -1
  118. package/dist/interval-CELpye1n.js +219 -0
  119. package/dist/interval-CELpye1n.js.map +1 -0
  120. package/dist/interval-ohuOJurX.d.ts +47 -0
  121. package/dist/interval-ohuOJurX.d.ts.map +1 -0
  122. package/dist/{journal-DvKCvjty.js → journal-DfRz9kps.js} +2 -2
  123. package/dist/{journal-DvKCvjty.js.map → journal-DfRz9kps.js.map} +1 -1
  124. package/dist/{judge-calibration-N44V04Se.js → judge-calibration-BpCy5XQl.js} +3 -3
  125. package/dist/{judge-calibration-N44V04Se.js.map → judge-calibration-BpCy5XQl.js.map} +1 -1
  126. package/dist/{judge-gate-DNcUrRFA.d.ts → judge-gate-CE7CQAgt.d.ts} +3 -3
  127. package/dist/{judge-gate-DNcUrRFA.d.ts.map → judge-gate-CE7CQAgt.d.ts.map} +1 -1
  128. package/dist/{judge-gate-B1qYnkpi.js → judge-gate-iY9s4L44.js} +3 -3
  129. package/dist/judge-gate-iY9s4L44.js.map +1 -0
  130. package/dist/{kind-factory-AaEhUADH.js → kind-factory-BobI5Jy3.js} +5 -5
  131. package/dist/{kind-factory-AaEhUADH.js.map → kind-factory-BobI5Jy3.js.map} +1 -1
  132. package/dist/ledger-core/index.js +3 -3
  133. package/dist/{ledger-core-B2hahzrt.js → ledger-core-Gq7yp8lP.js} +4 -4
  134. package/dist/{ledger-core-B2hahzrt.js.map → ledger-core-Gq7yp8lP.js.map} +1 -1
  135. package/dist/{llm-client-DQveoxSM.js → llm-client-CyBAoYiX.js} +192 -219
  136. package/dist/llm-client-CyBAoYiX.js.map +1 -0
  137. package/dist/{llm-judge-Cd5s5Ei6.js → llm-judge-CG12SQJq.js} +499 -921
  138. package/dist/llm-judge-CG12SQJq.js.map +1 -0
  139. package/dist/matrix/index.d.ts +2 -2
  140. package/dist/matrix/index.js +1 -1
  141. package/dist/{matrix-DXVAJMLD.d.ts → matrix-DSrSxjjy.d.ts} +4 -4
  142. package/dist/{matrix-DXVAJMLD.d.ts.map → matrix-DSrSxjjy.d.ts.map} +1 -1
  143. package/dist/{matrix-_BV9-Lk5.js → matrix-Dm0BQW7U.js} +7 -11
  144. package/dist/matrix-Dm0BQW7U.js.map +1 -0
  145. package/dist/{paired-tests-jbwPdSz5.js → mean-DHoMiudD.js} +11 -5
  146. package/dist/mean-DHoMiudD.js.map +1 -0
  147. package/dist/meta-eval/index.d.ts +3 -3
  148. package/dist/meta-eval/index.js +9 -70
  149. package/dist/meta-eval/index.js.map +1 -1
  150. package/dist/mint-DNU8QPG4.d.ts +81 -0
  151. package/dist/mint-DNU8QPG4.d.ts.map +1 -0
  152. package/dist/{mint-Csor1BLJ.js → mint-QaD5cA0u.js} +3 -3
  153. package/dist/{mint-Csor1BLJ.js.map → mint-QaD5cA0u.js.map} +1 -1
  154. package/dist/{multiplicity-D9cjmStq.js → multiplicity-DQUFcbW4.js} +2 -2
  155. package/dist/{multiplicity-D9cjmStq.js.map → multiplicity-DQUFcbW4.js.map} +1 -1
  156. package/dist/multishot/golden/index.d.ts +1 -1
  157. package/dist/multishot/golden/index.d.ts.map +1 -1
  158. package/dist/multishot/golden/index.js +3 -6
  159. package/dist/multishot/golden/index.js.map +1 -1
  160. package/dist/multishot/index.d.ts +2 -2
  161. package/dist/multishot/index.js +1 -1
  162. package/dist/nonnegative-number-DvdMxg_f.js +9 -0
  163. package/dist/nonnegative-number-DvdMxg_f.js.map +1 -0
  164. package/dist/openapi.json +1 -1
  165. package/dist/{otel-spans-C8YIJWy1.js → otel-spans-B9tUXRHF.js} +3 -3
  166. package/dist/{otel-spans-C8YIJWy1.js.map → otel-spans-B9tUXRHF.js.map} +1 -1
  167. package/dist/{paired-arms-DzKn0TfY.js → paired-arms-CwMGJsrS.js} +5 -5
  168. package/dist/{paired-arms-DzKn0TfY.js.map → paired-arms-CwMGJsrS.js.map} +1 -1
  169. package/dist/{paired-binary-Q36bhn2R.js → paired-binary-CvpFHfKZ.js} +2 -2
  170. package/dist/{paired-binary-Q36bhn2R.js.map → paired-binary-CvpFHfKZ.js.map} +1 -1
  171. package/dist/{paired-promotion-decision-BN6IQTiu.js → paired-promotion-decision-DsAPYGCm.js} +3 -3
  172. package/dist/{paired-promotion-decision-BN6IQTiu.js.map → paired-promotion-decision-DsAPYGCm.js.map} +1 -1
  173. package/dist/{search-kernel-BztlERLv.js → pareto-Cm6ndrWN.js} +883 -861
  174. package/dist/pareto-Cm6ndrWN.js.map +1 -0
  175. package/dist/pipelines/index.d.ts +2 -2
  176. package/dist/pipelines/index.js +3 -3
  177. package/dist/{power-and-mde-fK5Qocwo.js → power-and-mde-Hj2ubb4B.js} +2 -2
  178. package/dist/{power-and-mde-fK5Qocwo.js.map → power-and-mde-Hj2ubb4B.js.map} +1 -1
  179. package/dist/predicate-FdKmElA_.js +38 -0
  180. package/dist/predicate-FdKmElA_.js.map +1 -0
  181. package/dist/{prime-protocol-DcAK9pC8.js → prime-protocol-CHKgA3a6.js} +2 -2
  182. package/dist/{prime-protocol-DcAK9pC8.js.map → prime-protocol-CHKgA3a6.js.map} +1 -1
  183. package/dist/{prime-protocol-BHia9vDz.d.ts → prime-protocol-HiB9HX7E.d.ts} +3 -3
  184. package/dist/{prime-protocol-BHia9vDz.d.ts.map → prime-protocol-HiB9HX7E.d.ts.map} +1 -1
  185. package/dist/{produced-state-BGp4BX8t.js → produced-state-BsDmnwxc.js} +8 -8
  186. package/dist/{produced-state-BGp4BX8t.js.map → produced-state-BsDmnwxc.js.map} +1 -1
  187. package/dist/profile-cell.js +1 -1
  188. package/dist/{release-confidence-BK2QCB5M.d.ts → promotion-gate-BawrdPYr.d.ts} +102 -102
  189. package/dist/promotion-gate-BawrdPYr.d.ts.map +1 -0
  190. package/dist/{promotion-policy-CWW35UWq.js → promotion-policy-KO57gbyV.js} +4 -4
  191. package/dist/{promotion-policy-CWW35UWq.js.map → promotion-policy-KO57gbyV.js.map} +1 -1
  192. package/dist/{proposal-findings-CXblsskH.js → proposal-findings-CY1xKn_a.js} +2 -36
  193. package/dist/proposal-findings-CY1xKn_a.js.map +1 -0
  194. package/dist/{query-B1D1qp2Z.js → query-BUCZCK7F.js} +3 -3
  195. package/dist/{query-B1D1qp2Z.js.map → query-BUCZCK7F.js.map} +1 -1
  196. package/dist/{random-Dn5fPWkt.js → random-ByUSnV9w.js} +2 -2
  197. package/dist/{random-Dn5fPWkt.js.map → random-ByUSnV9w.js.map} +1 -1
  198. package/dist/{raw-provider-sink-rB2DYxr6.js → raw-provider-sink-DoHz4JNG.js} +2 -2
  199. package/dist/{raw-provider-sink-rB2DYxr6.js.map → raw-provider-sink-DoHz4JNG.js.map} +1 -1
  200. package/dist/{redact-Dk1ZdJEm.js → redact-B5xXKqQ3.js} +97 -98
  201. package/dist/redact-B5xXKqQ3.js.map +1 -0
  202. package/dist/{redact-Cveoq6fJ.d.ts → redact-mtCCcT8z.d.ts} +4 -20
  203. package/dist/redact-mtCCcT8z.d.ts.map +1 -0
  204. package/dist/{registry-CMYIaDgS.d.ts → registry-D7_hm2fK.d.ts} +11 -13
  205. package/dist/registry-D7_hm2fK.d.ts.map +1 -0
  206. package/dist/{release-confidence-Dbe9AS_X.js → release-confidence-CpuP65S5.js} +5 -5
  207. package/dist/{release-confidence-Dbe9AS_X.js.map → release-confidence-CpuP65S5.js.map} +1 -1
  208. package/dist/{report-command-CtIIsQKP.js → report-command-SC9nqb4M.js} +128 -177
  209. package/dist/report-command-SC9nqb4M.js.map +1 -0
  210. package/dist/reporting-html-Kvlc8oMt.js +100 -0
  211. package/dist/reporting-html-Kvlc8oMt.js.map +1 -0
  212. package/dist/reporting.d.ts +3 -3
  213. package/dist/reporting.js +6 -6
  214. package/dist/{researcher-f6mZhh58.d.ts → researcher-CEcfku-T.d.ts} +5 -5
  215. package/dist/{researcher-f6mZhh58.d.ts.map → researcher-CEcfku-T.d.ts.map} +1 -1
  216. package/dist/reward-CpCmAM8L.d.ts +78 -0
  217. package/dist/reward-CpCmAM8L.d.ts.map +1 -0
  218. package/dist/{reward-hacking-BFcQgkux.js → reward-hacking-E0d-WVcP.js} +2 -2
  219. package/dist/{reward-hacking-BFcQgkux.js.map → reward-hacking-E0d-WVcP.js.map} +1 -1
  220. package/dist/{reward-hacking-DHA7c1l8.d.ts → reward-hacking-RVdZ6Kkt.d.ts} +2 -2
  221. package/dist/{reward-hacking-DHA7c1l8.d.ts.map → reward-hacking-RVdZ6Kkt.d.ts.map} +1 -1
  222. package/dist/rl.d.ts +8 -8
  223. package/dist/rl.js +14 -14
  224. package/dist/rollout/index.d.ts +3 -2
  225. package/dist/rollout/index.js +2 -2
  226. package/dist/{rollout-D9bKKBnZ.js → rollout-DZV1t2Wg.js} +2 -2
  227. package/dist/{rollout-D9bKKBnZ.js.map → rollout-DZV1t2Wg.js.map} +1 -1
  228. package/dist/round-decimal-COrKglMh.js +10 -0
  229. package/dist/round-decimal-COrKglMh.js.map +1 -0
  230. package/dist/{rubric-predictive-validity-2SgHxoa5.d.ts → rubric-predictive-validity-C03EC7ZE.d.ts} +2 -2
  231. package/dist/{rubric-predictive-validity-2SgHxoa5.d.ts.map → rubric-predictive-validity-C03EC7ZE.d.ts.map} +1 -1
  232. package/dist/{rubric-predictive-validity-BsgkBfT0.js → rubric-predictive-validity-DaFW70y9.js} +3 -3
  233. package/dist/{rubric-predictive-validity-BsgkBfT0.js.map → rubric-predictive-validity-DaFW70y9.js.map} +1 -1
  234. package/dist/{run-record-DlTZ_lqe.js → run-record-Boc5IUTp.js} +4 -4
  235. package/dist/{run-record-DlTZ_lqe.js.map → run-record-Boc5IUTp.js.map} +1 -1
  236. package/dist/{run-record-D1Hw-Jml.d.ts → run-record-C1E24G2A.d.ts} +2 -2
  237. package/dist/{run-record-D1Hw-Jml.d.ts.map → run-record-C1E24G2A.d.ts.map} +1 -1
  238. package/dist/{run-record-ES07wfz9.js → run-record-C5e7FjhJ.js} +3 -5
  239. package/dist/run-record-C5e7FjhJ.js.map +1 -0
  240. package/dist/search/index.d.ts +46 -32
  241. package/dist/search/index.d.ts.map +1 -1
  242. package/dist/search/index.js +3 -3
  243. package/dist/{search-kernel-BqyBZ9Wm.d.ts → search-kernel-DyNEa6IU.d.ts} +14 -10
  244. package/dist/search-kernel-DyNEa6IU.d.ts.map +1 -0
  245. package/dist/{search-ledger-d7V8o9Lk.js → search-ledger-CVUGLDZp.js} +189 -199
  246. package/dist/search-ledger-CVUGLDZp.js.map +1 -0
  247. package/dist/{search-ledger-file-BqOo-bVo.js → search-ledger-file-DDQUgvCg.js} +4 -4
  248. package/dist/{search-ledger-file-BqOo-bVo.js.map → search-ledger-file-DDQUgvCg.js.map} +1 -1
  249. package/dist/search-ledger-types-p2xKfiDJ.d.ts.map +1 -1
  250. package/dist/{search-shipper-er4pK5_Y.js → search-shipper-BOSD46qv.js} +3 -3
  251. package/dist/{search-shipper-er4pK5_Y.js.map → search-shipper-BOSD46qv.js.map} +1 -1
  252. package/dist/{search-summary-CBvz3u_S.js → search-summary-BQCSWf1g.js} +5 -5
  253. package/dist/{search-summary-CBvz3u_S.js.map → search-summary-BQCSWf1g.js.map} +1 -1
  254. package/dist/{semantic-concept-judge-BPqbwIVs.js → semantic-concept-judge-BQF8te0T.js} +12 -14
  255. package/dist/semantic-concept-judge-BQF8te0T.js.map +1 -0
  256. package/dist/{sequential-D-1PPCmM.js → sequential-Bf_pbE50.js} +5 -5
  257. package/dist/{sequential-D-1PPCmM.js.map → sequential-Bf_pbE50.js.map} +1 -1
  258. package/dist/{sequential-eprocess-D1jKoihe.js → sequential-eprocess-DM_qENCl.js} +2 -2
  259. package/dist/{sequential-eprocess-D1jKoihe.js.map → sequential-eprocess-DM_qENCl.js.map} +1 -1
  260. package/dist/{server-DbcC7xMl.js → server-e9oWO_bN.js} +4 -4
  261. package/dist/{server-DbcC7xMl.js.map → server-e9oWO_bN.js.map} +1 -1
  262. package/dist/{single-run-lock-fVu3MZWH.js → single-run-lock-CV9Eyd_q.js} +2 -2
  263. package/dist/{single-run-lock-fVu3MZWH.js.map → single-run-lock-CV9Eyd_q.js.map} +1 -1
  264. package/dist/{skillopt-optimization-method-Dcepr6QL.js → skillopt-optimization-method-BiwA8nfX.js} +427 -12
  265. package/dist/skillopt-optimization-method-BiwA8nfX.js.map +1 -0
  266. package/dist/{spans-D9_ehFuk.d.ts → spans-BHAUXMGN.d.ts} +2 -2
  267. package/dist/{spans-D9_ehFuk.d.ts.map → spans-BHAUXMGN.d.ts.map} +1 -1
  268. package/dist/{statistical-heldout-1Gbmex7v.js → statistical-heldout-42NlCNDe.js} +3 -3
  269. package/dist/{statistical-heldout-1Gbmex7v.js.map → statistical-heldout-42NlCNDe.js.map} +1 -1
  270. package/dist/{statistical-heldout-CJTj2EoS.d.ts → statistical-heldout-CYpGaoDH.d.ts} +3 -3
  271. package/dist/{statistical-heldout-CJTj2EoS.d.ts.map → statistical-heldout-CYpGaoDH.d.ts.map} +1 -1
  272. package/dist/{store-otlp-DWVhUgEj.js → store-otlp-DJ9dtA5x.js} +135 -132
  273. package/dist/store-otlp-DJ9dtA5x.js.map +1 -0
  274. package/dist/{store-tool-spans-BNICrhsb.js → store-tool-spans-CIX5arAG.js} +7 -7
  275. package/dist/{store-tool-spans-BNICrhsb.js.map → store-tool-spans-CIX5arAG.js.map} +1 -1
  276. package/dist/{store-tool-spans-BNzls3OD.d.ts → store-tool-spans-DdCSPa7C.d.ts} +162 -161
  277. package/dist/store-tool-spans-DdCSPa7C.d.ts.map +1 -0
  278. package/dist/storyboard/index.d.ts.map +1 -1
  279. package/dist/storyboard/index.js +20 -3
  280. package/dist/storyboard/index.js.map +1 -1
  281. package/dist/{student-t-BQeKJx2N.js → student-t-DVPW7CdL.js} +2 -2
  282. package/dist/{student-t-BQeKJx2N.js.map → student-t-DVPW7CdL.js.map} +1 -1
  283. package/dist/{summary-report-DtdRucM0.js → summary-report-V_JACR4Y.js} +526 -614
  284. package/dist/summary-report-V_JACR4Y.js.map +1 -0
  285. package/dist/{summary-report-C-CtItCN.d.ts → summary-report-bdFDXq0b.d.ts} +10 -5
  286. package/dist/summary-report-bdFDXq0b.d.ts.map +1 -0
  287. package/dist/supervisor-run/index.d.ts +154 -150
  288. package/dist/supervisor-run/index.d.ts.map +1 -1
  289. package/dist/supervisor-run/index.js +65 -3
  290. package/dist/supervisor-run/index.js.map +1 -1
  291. package/dist/systemone-BomhHr2c.d.ts +135 -0
  292. package/dist/systemone-BomhHr2c.d.ts.map +1 -0
  293. package/dist/systemone-protocol.js +1 -1
  294. package/dist/{systemone-review-C4dZgrgN.d.ts → systemone-review-CUVcQJu6.d.ts} +2 -2
  295. package/dist/{systemone-review-C4dZgrgN.d.ts.map → systemone-review-CUVcQJu6.d.ts.map} +1 -1
  296. package/dist/{systemone-review-DTClwgmE.js → systemone-review-D7sXwsqq.js} +3 -3
  297. package/dist/{systemone-review-DTClwgmE.js.map → systemone-review-D7sXwsqq.js.map} +1 -1
  298. package/dist/systemone.d.ts +4 -134
  299. package/dist/systemone.js +4 -4
  300. package/dist/{task-failure-attributes-DngaLdE4.js → task-failure-attributes-hEmASjix.js} +2 -2
  301. package/dist/{task-failure-attributes-DngaLdE4.js.map → task-failure-attributes-hEmASjix.js.map} +1 -1
  302. package/dist/{terminal-record-BHocwFw1.js → terminal-record-DZyQZ3pz.js} +14 -10
  303. package/dist/terminal-record-DZyQZ3pz.js.map +1 -0
  304. package/dist/{tool-groups-BKRrtqy4.d.ts → tool-groups-C3NEcdCM.d.ts} +3 -3
  305. package/dist/tool-groups-C3NEcdCM.d.ts.map +1 -0
  306. package/dist/{tool-waste-Wi4g6Ekb.d.ts → tool-waste-BKgvd-TP.d.ts} +30 -30
  307. package/dist/tool-waste-BKgvd-TP.d.ts.map +1 -0
  308. package/dist/{tool-waste-BYt5rdt8.js → tool-waste-BlesqTqW.js} +5 -158
  309. package/dist/tool-waste-BlesqTqW.js.map +1 -0
  310. package/dist/{trace-questions-CLx8vt6t.d.ts → trace-questions-CM2CAocU.d.ts} +4 -4
  311. package/dist/{trace-questions-CLx8vt6t.d.ts.map → trace-questions-CM2CAocU.d.ts.map} +1 -1
  312. package/dist/trace-repair/index.d.ts +3 -3
  313. package/dist/trace-repair/index.d.ts.map +1 -1
  314. package/dist/trace-repair/index.js +7 -13
  315. package/dist/trace-repair/index.js.map +1 -1
  316. package/dist/traces.d.ts +76 -58
  317. package/dist/traces.d.ts.map +1 -1
  318. package/dist/traces.js +9 -9
  319. package/dist/trajectory-replay/index.js +3 -3
  320. package/dist/{tree-rXLW3M_4.js → tree-C1XYeXvy.js} +2277 -2339
  321. package/dist/tree-C1XYeXvy.js.map +1 -0
  322. package/dist/{types-DjOMwGY_.d.ts → types-BqkVmHfv.d.ts} +7 -1
  323. package/dist/types-BqkVmHfv.d.ts.map +1 -0
  324. package/dist/{types-DBZ7keha.d.ts → types-C02qtnG8.d.ts} +4 -46
  325. package/dist/types-C02qtnG8.d.ts.map +1 -0
  326. package/dist/{types-DHb5TI36.d.ts → types-C1tnkEgM.d.ts} +347 -6
  327. package/dist/types-C1tnkEgM.d.ts.map +1 -0
  328. package/dist/{types-DinHtRJp.d.ts → types-Cbe2fWBa.d.ts} +3 -3
  329. package/dist/{types-DinHtRJp.d.ts.map → types-Cbe2fWBa.d.ts.map} +1 -1
  330. package/dist/{types-CGEmVYOk.d.ts → types-Cq8mSbq8.d.ts} +78 -72
  331. package/dist/types-Cq8mSbq8.d.ts.map +1 -0
  332. package/dist/{types-CW5b90JH.js → types-IXD2HJzu.js} +16 -3
  333. package/dist/types-IXD2HJzu.js.map +1 -0
  334. package/dist/{verdict-DhPoXApk.js → verdict-Dl0tiT1X.js} +2 -2
  335. package/dist/{verdict-DhPoXApk.js.map → verdict-Dl0tiT1X.js.map} +1 -1
  336. package/dist/{verdict-cache-BQEsVy9n.js → verdict-cache-Bm8EKL2s.js} +2 -2
  337. package/dist/{verdict-cache-BQEsVy9n.js.map → verdict-cache-Bm8EKL2s.js.map} +1 -1
  338. package/dist/wire/index.d.ts +3 -3
  339. package/dist/wire/index.js +1 -1
  340. package/docs/concepts.md +1 -0
  341. package/docs/design/mlbenchmarks-book-review.md +1 -1
  342. package/docs/design/mlbenchmarks-review/probes.mts +23 -31
  343. package/docs/experiment.md +1 -1
  344. package/docs/finding-layers.md +69 -0
  345. package/package.json +1 -1
  346. package/dist/analyze-runs-3xpby3p2.js.map +0 -1
  347. package/dist/analyze-runs-BhFLOztS.d.ts.map +0 -1
  348. package/dist/ast-DJ6Bc7ab.js +0 -558
  349. package/dist/ast-DJ6Bc7ab.js.map +0 -1
  350. package/dist/ast-hI-vjW6J.d.ts +0 -457
  351. package/dist/ast-hI-vjW6J.d.ts.map +0 -1
  352. package/dist/benchmark-command-CgpGi7vY.js.map +0 -1
  353. package/dist/campaign-CpnsCgfz.js.map +0 -1
  354. package/dist/campaign-evidence-OcUciD-N.js.map +0 -1
  355. package/dist/claim-BXcZw-jo.js.map +0 -1
  356. package/dist/cost-ledger-CO7UyEcQ.d.ts.map +0 -1
  357. package/dist/cost-ledger-D2FnJPBF.js.map +0 -1
  358. package/dist/default-registry-KP4-Tolz.js.map +0 -1
  359. package/dist/define-agent-eval-BdfnqXeP.js.map +0 -1
  360. package/dist/evaluation.d.ts.map +0 -1
  361. package/dist/external-optimizer-subprocess-BUxifb8g.js.map +0 -1
  362. package/dist/feedback-trajectory-BLN_6fEs.d.ts.map +0 -1
  363. package/dist/index-B3WBm953.d.ts.map +0 -1
  364. package/dist/index-B7m2uzJL.d.ts.map +0 -1
  365. package/dist/index-CPJJr98o.d.ts.map +0 -1
  366. package/dist/integrity-BV1ZDf42.js.map +0 -1
  367. package/dist/judge-gate-B1qYnkpi.js.map +0 -1
  368. package/dist/llm-client-DQveoxSM.js.map +0 -1
  369. package/dist/llm-judge-Cd5s5Ei6.js.map +0 -1
  370. package/dist/matrix-_BV9-Lk5.js.map +0 -1
  371. package/dist/mint-DCGoBYhB.d.ts +0 -155
  372. package/dist/mint-DCGoBYhB.d.ts.map +0 -1
  373. package/dist/paired-tests-jbwPdSz5.js.map +0 -1
  374. package/dist/proposal-findings-CXblsskH.js.map +0 -1
  375. package/dist/redact-Cveoq6fJ.d.ts.map +0 -1
  376. package/dist/redact-Dk1ZdJEm.js.map +0 -1
  377. package/dist/registry-CMYIaDgS.d.ts.map +0 -1
  378. package/dist/release-confidence-BK2QCB5M.d.ts.map +0 -1
  379. package/dist/report-command-CtIIsQKP.js.map +0 -1
  380. package/dist/run-record-ES07wfz9.js.map +0 -1
  381. package/dist/search-kernel-BqyBZ9Wm.d.ts.map +0 -1
  382. package/dist/search-kernel-BztlERLv.js.map +0 -1
  383. package/dist/search-ledger-d7V8o9Lk.js.map +0 -1
  384. package/dist/semantic-concept-judge-BPqbwIVs.js.map +0 -1
  385. package/dist/skillopt-optimization-method-Dcepr6QL.js.map +0 -1
  386. package/dist/store-otlp-DWVhUgEj.js.map +0 -1
  387. package/dist/store-tool-spans-BNzls3OD.d.ts.map +0 -1
  388. package/dist/summary-report-C-CtItCN.d.ts.map +0 -1
  389. package/dist/summary-report-DtdRucM0.js.map +0 -1
  390. package/dist/systemone.d.ts.map +0 -1
  391. package/dist/terminal-record-BHocwFw1.js.map +0 -1
  392. package/dist/tool-groups-BKRrtqy4.d.ts.map +0 -1
  393. package/dist/tool-waste-BYt5rdt8.js.map +0 -1
  394. package/dist/tool-waste-Wi4g6Ekb.d.ts.map +0 -1
  395. package/dist/tree-rXLW3M_4.js.map +0 -1
  396. package/dist/types-CGEmVYOk.d.ts.map +0 -1
  397. package/dist/types-CW5b90JH.js.map +0 -1
  398. package/dist/types-DBZ7keha.d.ts.map +0 -1
  399. package/dist/types-DHb5TI36.d.ts.map +0 -1
  400. package/dist/types-DjOMwGY_.d.ts.map +0 -1
@@ -1,835 +1,882 @@
1
- import { s as ValidationError } from "./errors-Dngq5h35.js";
1
+ import { s as ValidationError } from "./errors-DVZiqS7K.js";
2
2
  import { a as resolveModelPricing, i as isModelPriced, 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
+ /** Return the canonical pricing-table key, or null when the model is unpriced. */
38
+ function modelPriceKey(model) {
39
+ return isModelPriced(model) ? model : null;
40
+ }
41
+ function costForUsage(model, usage) {
42
+ assertUsage(usage);
43
+ if (!resolveModelPricing(model)) return {
44
+ costUsd: 0,
45
+ costUnknown: true
46
+ };
47
+ return {
48
+ costUsd: estimateCost(usage.inputTokens + (usage.cachedTokens ?? 0) + (usage.cacheWriteTokens ?? 0), usage.outputTokens, model),
49
+ costUnknown: false
50
+ };
51
+ }
52
+ /** Price token counts with caller-supplied per-million rates. */
53
+ function costForTokenPricing(pricing, usage) {
54
+ assertTokenCount(usage.inputTokens, "usage.inputTokens");
55
+ assertTokenCount(usage.outputTokens, "usage.outputTokens");
56
+ if (usage.cachedTokens !== void 0) assertTokenCount(usage.cachedTokens, "usage.cachedTokens");
57
+ if (usage.cacheWriteTokens !== void 0) assertTokenCount(usage.cacheWriteTokens, "usage.cacheWriteTokens");
58
+ assertNonNegative(pricing.inputUsdPerMillion, "pricing.inputUsdPerMillion");
59
+ if (pricing.cachedInputUsdPerMillion !== void 0) assertNonNegative(pricing.cachedInputUsdPerMillion, "pricing.cachedInputUsdPerMillion");
60
+ if (pricing.cacheWriteUsdPerMillion !== void 0) assertNonNegative(pricing.cacheWriteUsdPerMillion, "pricing.cacheWriteUsdPerMillion");
61
+ assertNonNegative(pricing.outputUsdPerMillion, "pricing.outputUsdPerMillion");
62
+ const cachedInputRate = pricing.cachedInputUsdPerMillion ?? pricing.inputUsdPerMillion;
63
+ const cacheWriteRate = pricing.cacheWriteUsdPerMillion ?? pricing.inputUsdPerMillion;
64
+ return usage.inputTokens / 1e6 * pricing.inputUsdPerMillion + (usage.cachedTokens ?? 0) / 1e6 * cachedInputRate + (usage.cacheWriteTokens ?? 0) / 1e6 * cacheWriteRate + usage.outputTokens / 1e6 * pricing.outputUsdPerMillion;
65
+ }
66
+ function costFromPricing(usage, pricing) {
67
+ const cachedInputRate = pricing.cachedInputUsdPerThousand ?? pricing.inputUsdPerThousand;
68
+ const cacheWriteRate = pricing.cacheWriteUsdPerThousand ?? pricing.inputUsdPerThousand;
69
+ return usage.inputTokens / 1e3 * pricing.inputUsdPerThousand + (usage.cachedTokens ?? 0) / 1e3 * cachedInputRate + (usage.cacheWriteTokens ?? 0) / 1e3 * cacheWriteRate + usage.outputTokens / 1e3 * pricing.outputUsdPerThousand;
70
+ }
71
+ function pricingSnapshot(pricing) {
72
+ costForTokenPricing(pricing, {
73
+ inputTokens: 0,
74
+ outputTokens: 0
75
+ });
76
+ return {
77
+ inputUsdPerThousand: pricing.inputUsdPerMillion / 1e3,
78
+ ...pricing.cachedInputUsdPerMillion === void 0 ? {} : { cachedInputUsdPerThousand: pricing.cachedInputUsdPerMillion / 1e3 },
79
+ ...pricing.cacheWriteUsdPerMillion === void 0 ? {} : { cacheWriteUsdPerThousand: pricing.cacheWriteUsdPerMillion / 1e3 },
80
+ outputUsdPerThousand: pricing.outputUsdPerMillion / 1e3
81
+ };
82
+ }
83
+ //#endregion
84
+ //#region src/cost-ledger/receipts.ts
85
+ /** Create, validate, filter, and detach the receipts stored by a cost ledger. */
86
+ const NonEmptyString = z.string().refine((value) => value.trim().length > 0, "must be non-empty");
87
+ const TokenCount = z.number().int().nonnegative().finite();
88
+ const NonNegative = z.number().nonnegative().finite();
89
+ const Tags = z.record(NonEmptyString, z.string());
90
+ const CostPricingSchema = z.strictObject({
91
+ inputUsdPerThousand: NonNegative,
92
+ cachedInputUsdPerThousand: NonNegative.optional(),
93
+ cacheWriteUsdPerThousand: NonNegative.optional(),
94
+ outputUsdPerThousand: NonNegative
95
+ });
96
+ const CostCallBaseShape = {
97
+ callId: NonEmptyString,
98
+ channel: NonEmptyString,
99
+ phase: NonEmptyString,
100
+ actor: NonEmptyString,
101
+ model: NonEmptyString,
102
+ maximumCostUsd: NonNegative.optional(),
103
+ tags: Tags.optional(),
104
+ timestamp: NonNegative
9
105
  };
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
- }
106
+ const PendingCostCallSchema = z.strictObject({
107
+ status: z.literal("pending"),
108
+ ...CostCallBaseShape
109
+ });
110
+ const CostReceiptBaseShape = {
111
+ status: z.literal("settled"),
112
+ ...CostCallBaseShape,
113
+ inputTokens: TokenCount,
114
+ outputTokens: TokenCount,
115
+ cachedTokens: TokenCount.optional(),
116
+ costUsd: NonNegative,
117
+ costUnknown: z.boolean(),
118
+ usageUnknown: z.boolean().default(false),
119
+ pricing: CostPricingSchema.optional(),
120
+ actualCostUsd: NonNegative.optional(),
121
+ estimatedCostUsd: NonNegative.optional(),
122
+ error: NonEmptyString.optional()
15
123
  };
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;
124
+ const CostReceiptSchema = z.strictObject({
125
+ ...CostReceiptBaseShape,
126
+ reasoningTokens: TokenCount.optional(),
127
+ cacheWriteTokens: TokenCount.optional()
128
+ }).superRefine((receipt, ctx) => validateCostReceipt(receipt, ctx));
129
+ function validateCostReceipt(receipt, ctx) {
130
+ if (receipt.reasoningTokens !== void 0 && receipt.reasoningTokens > receipt.outputTokens) ctx.addIssue({
131
+ code: "custom",
132
+ message: "reasoningTokens must not exceed outputTokens"
133
+ });
134
+ if (receipt.actualCostUsd !== void 0 && receipt.estimatedCostUsd !== void 0) ctx.addIssue({
135
+ code: "custom",
136
+ message: "actual and external estimated costs cannot both be present"
137
+ });
138
+ if (receipt.actualCostUsd !== void 0) {
139
+ if (receipt.costUnknown || receipt.costUsd !== receipt.actualCostUsd) ctx.addIssue({
140
+ code: "custom",
141
+ message: "actual cost must be known and equal costUsd"
142
+ });
143
+ if (receipt.pricing !== void 0) ctx.addIssue({
144
+ code: "custom",
145
+ message: "actual cost must not include estimated pricing"
146
+ });
147
+ return;
23
148
  }
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;
149
+ if (receipt.estimatedCostUsd !== void 0) {
150
+ if (receipt.costUnknown || receipt.costUsd !== receipt.estimatedCostUsd) ctx.addIssue({
151
+ code: "custom",
152
+ message: "external estimate must be known and equal costUsd"
153
+ });
154
+ if (receipt.pricing !== void 0) ctx.addIssue({
155
+ code: "custom",
156
+ message: "external estimate must not include token pricing"
157
+ });
158
+ return;
32
159
  }
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);
160
+ if (receipt.costUnknown) {
161
+ if (receipt.costUsd !== 0) ctx.addIssue({
162
+ code: "custom",
163
+ message: "unknown cost must have costUsd 0"
164
+ });
165
+ if (receipt.pricing !== void 0) ctx.addIssue({
166
+ code: "custom",
167
+ message: "unknown cost must not include estimated pricing"
168
+ });
169
+ return;
43
170
  }
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
- }
171
+ if (receipt.usageUnknown) ctx.addIssue({
172
+ code: "custom",
173
+ message: "known estimated cost requires known usage"
174
+ });
175
+ if (!receipt.pricing) {
176
+ ctx.addIssue({
177
+ code: "custom",
178
+ message: "known estimated cost requires a pricing snapshot"
179
+ });
180
+ return;
84
181
  }
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
- });
182
+ const expected = costFromPricing(receipt, receipt.pricing);
183
+ if (!costAmountsMatch(receipt.costUsd, expected)) ctx.addIssue({
184
+ code: "custom",
185
+ message: `estimated cost ${receipt.costUsd} does not match pricing snapshot ${expected}`
186
+ });
187
+ }
188
+ function costAmountsMatch(left, right) {
189
+ const scale = Math.max(1, Math.abs(left), Math.abs(right));
190
+ return Math.abs(left - right) <= Number.EPSILON * scale * 8;
191
+ }
192
+ function buildReceipt(pending, observed, failed = false, error) {
193
+ assertUsage(observed);
194
+ assertString(observed.model, "receipt.model");
195
+ if ([
196
+ observed.actualCostUsd,
197
+ observed.estimatedCostUsd,
198
+ observed.customTokenPricing
199
+ ].filter((value) => value !== void 0).length > 1) throw new ValidationError("CostLedger: a receipt can have only one of actualCostUsd, estimatedCostUsd, or customTokenPricing");
200
+ const customPricingSnapshot = observed.customTokenPricing === void 0 ? void 0 : pricingSnapshot(observed.customTokenPricing);
201
+ const estimated = customPricingSnapshot ? {
202
+ costUsd: costFromPricing(observed, customPricingSnapshot),
203
+ costUnknown: false
204
+ } : costForUsage(observed.model, observed);
205
+ const hasActual = observed.actualCostUsd !== void 0;
206
+ const hasExternalEstimate = observed.estimatedCostUsd !== void 0;
207
+ if (hasActual && observed.costUnknown === true) throw new ValidationError("CostLedger: a receipt cannot have both actualCostUsd and costUnknown=true");
208
+ if (hasActual) assertNonNegative(observed.actualCostUsd, "actualCostUsd");
209
+ if (hasExternalEstimate) assertNonNegative(observed.estimatedCostUsd, "estimatedCostUsd");
210
+ if (hasExternalEstimate && observed.costUnknown === true) throw new ValidationError("CostLedger: a receipt cannot have both estimatedCostUsd and costUnknown=true");
211
+ const usageUnknown = observed.usageUnknown === true;
212
+ const costUnknown = observed.costUnknown === true || !hasActual && !hasExternalEstimate && (usageUnknown || estimated.costUnknown);
213
+ const resolvedModelPricing = !customPricingSnapshot && !hasActual && !hasExternalEstimate && !costUnknown ? resolveModelPricing(observed.model) : null;
214
+ const receiptPricing = !hasActual && !hasExternalEstimate && !costUnknown ? customPricingSnapshot ?? (resolvedModelPricing ? {
215
+ inputUsdPerThousand: resolvedModelPricing.input,
216
+ outputUsdPerThousand: resolvedModelPricing.output
217
+ } : void 0) : void 0;
218
+ return parseReceipt({
219
+ status: "settled",
220
+ callId: pending.callId,
221
+ channel: pending.channel,
222
+ phase: pending.phase,
223
+ actor: pending.actor,
224
+ model: observed.model,
225
+ inputTokens: observed.inputTokens,
226
+ outputTokens: observed.outputTokens,
227
+ ...observed.reasoningTokens === void 0 ? {} : { reasoningTokens: observed.reasoningTokens },
228
+ ...observed.cachedTokens === void 0 ? {} : { cachedTokens: observed.cachedTokens },
229
+ ...observed.cacheWriteTokens === void 0 ? {} : { cacheWriteTokens: observed.cacheWriteTokens },
230
+ costUsd: costUnknown ? 0 : hasActual ? observed.actualCostUsd : hasExternalEstimate ? observed.estimatedCostUsd : estimated.costUsd,
231
+ costUnknown,
232
+ usageUnknown,
233
+ ...receiptPricing ? { pricing: receiptPricing } : {},
234
+ ...hasActual ? { actualCostUsd: observed.actualCostUsd } : {},
235
+ ...hasExternalEstimate ? { estimatedCostUsd: observed.estimatedCostUsd } : {},
236
+ ...pending.maximumCostUsd === void 0 ? {} : { maximumCostUsd: pending.maximumCostUsd },
237
+ ...failed ? { error: error ?? "paid-call-failed" } : {},
238
+ ...pending.tags ? { tags: { ...pending.tags } } : {},
239
+ timestamp: pending.timestamp
240
+ }, "provider receipt");
241
+ }
242
+ function parseReceipt(value, path) {
243
+ try {
244
+ return CostReceiptSchema.parse(value);
245
+ } catch (cause) {
246
+ throw new ValidationError(`CostLedger: invalid ${path}: ${validationMessage(cause)}`, { cause });
188
247
  }
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);
248
+ }
249
+ function parseImportedReceipt(value, path) {
250
+ if (typeof value !== "object" || value === null) return parseReceipt(value, path);
251
+ const candidate = { ...value };
252
+ if (candidate.status === "settled" && candidate.actualCostUsd === void 0 && candidate.estimatedCostUsd === void 0 && candidate.costUnknown === false && candidate.pricing === void 0 && typeof candidate.model === "string") {
253
+ const pricing = resolveModelPricing(candidate.model);
254
+ if (pricing) candidate.pricing = {
255
+ inputUsdPerThousand: pricing.input,
256
+ outputUsdPerThousand: pricing.output
257
+ };
196
258
  }
197
- list(filter) {
198
- return [...this.records.values()].filter((record) => record.status === "settled").filter((receipt) => matches(receipt, filter)).map(cloneReceipt);
259
+ return parseReceipt(candidate, path);
260
+ }
261
+ function validateAttribution(input) {
262
+ assertString(input.channel, "channel");
263
+ assertString(input.phase, "phase");
264
+ assertString(input.actor, "actor");
265
+ if (input.model !== void 0) assertString(input.model, "model");
266
+ if (input.tags !== void 0) {
267
+ const parsed = Tags.safeParse(input.tags);
268
+ if (!parsed.success) throw new ValidationError(`CostLedger: invalid tags: ${parsed.error.message}`);
199
269
  }
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
- }));
270
+ }
271
+ function matches(record, filter) {
272
+ if (!filter) return true;
273
+ if (filter.channel !== void 0 && record.channel !== filter.channel) return false;
274
+ if (filter.phase !== void 0 && record.phase !== filter.phase) return false;
275
+ return Object.entries(filter.tags ?? {}).every(([key, value]) => record.tags?.[key] === value);
276
+ }
277
+ function cloneRecord(record) {
278
+ if (record.status === "settled") return cloneReceipt(record);
279
+ return clonePendingCall(record);
280
+ }
281
+ function clonePendingCall(record) {
282
+ const { tags, ...rest } = record;
283
+ return {
284
+ ...rest,
285
+ ...tags ? { tags: { ...tags } } : {}
286
+ };
287
+ }
288
+ function cloneReceipt(receipt) {
289
+ const { pricing, tags, ...rest } = receipt;
290
+ return {
291
+ ...rest,
292
+ ...tags ? { tags: { ...tags } } : {},
293
+ ...pricing ? { pricing: { ...pricing } } : {}
294
+ };
295
+ }
296
+ //#endregion
297
+ //#region src/cost-ledger/errors.ts
298
+ /** Typed cost-accounting failures retain detached receipt evidence. */
299
+ var CostCeilingReachedError = class extends ValidationError {
300
+ constructor(ceilingUsd, committedUsd, requestedUsd, phase, actor) {
301
+ super(`CostLedger: reserving ${requestedUsd} for '${actor}' during '${phase}' would exceed ceiling ${ceilingUsd} with ${committedUsd} already committed`);
206
302
  }
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
- };
303
+ };
304
+ var CostAccountingIncompleteError = class extends ValidationError {};
305
+ var CostReservationExceededError = class extends ValidationError {
306
+ constructor(actor, actualUsd, maximumUsd) {
307
+ super(`CostLedger: '${actor}' charged ${actualUsd}, exceeding its enforced maximum ${maximumUsd}`);
273
308
  }
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;
309
+ };
310
+ var CostCallConflictError = class extends ValidationError {
311
+ callId;
312
+ receipt;
313
+ constructor(message, options = {}) {
314
+ super(message, options.cause === void 0 ? void 0 : { cause: options.cause });
315
+ this.callId = options.callId;
316
+ this.receipt = options.receipt ? cloneReceipt(options.receipt) : void 0;
283
317
  }
284
- costPerCompletedTask() {
285
- return this.completedTasks === 0 ? null : this.summary().totalCostUsd / this.completedTasks;
318
+ };
319
+ var CostLedgerPersistenceError = class extends ValidationError {
320
+ callId;
321
+ receipt;
322
+ constructor(cause, callId, receipt) {
323
+ super(`CostLedger: failed to persist${callId ? ` call '${callId}'` : ""}: ${toError(cause).message}`, { cause });
324
+ this.callId = callId;
325
+ this.receipt = receipt ? cloneReceipt(receipt) : void 0;
286
326
  }
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
- }
327
+ };
328
+ var CostReceiptCaptureError = class extends ValidationError {
329
+ callId;
330
+ receipt;
331
+ receiptError;
332
+ constructor(callId, cause, receiptError, receipt) {
333
+ super(`CostLedger: could not capture the provider receipt for call '${callId}'`, { cause });
334
+ this.callId = callId;
335
+ this.receipt = receipt ? cloneReceipt(receipt) : void 0;
336
+ this.receiptError = toError(receiptError);
324
337
  }
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);
338
+ };
339
+ //#endregion
340
+ //#region src/cost-ledger/journal.ts
341
+ /** Parse the append-only journal and enforce immutable pending-to-settled transitions. */
342
+ const CostLedgerEventSchema = z.union([
343
+ z.strictObject({
344
+ version: z.literal(1),
345
+ record: PendingCostCallSchema
346
+ }),
347
+ z.strictObject({
348
+ version: z.literal(2),
349
+ record: CostReceiptSchema
350
+ }),
351
+ z.strictObject({
352
+ version: z.literal(1),
353
+ completedTasks: TokenCount
354
+ }),
355
+ z.strictObject({
356
+ version: z.literal(1),
357
+ costCeilingUsd: NonNegative
358
+ })
359
+ ]);
360
+ function parseEvents(serialized) {
361
+ const records = /* @__PURE__ */ new Map();
362
+ let completedTasks = 0;
363
+ let costCeilingUsd;
364
+ let lineNumber = 0;
365
+ try {
366
+ for (const line of completeJournalPrefix(serialized).split("\n")) {
367
+ if (!line.trim()) continue;
368
+ lineNumber += 1;
369
+ const event = CostLedgerEventSchema.parse(JSON.parse(line));
370
+ if ("record" in event) {
371
+ const record = event.record;
372
+ validateTransition(records, record);
373
+ records.set(record.callId, cloneRecord(record));
374
+ } else if ("completedTasks" in event) {
375
+ completedTasks += event.completedTasks;
376
+ if (!Number.isSafeInteger(completedTasks)) throw new ValidationError("CostLedger: completed task count exceeds safe integer range");
377
+ } else {
378
+ if (costCeilingUsd !== void 0) throw new ValidationError("CostLedger: duplicate persisted cost ceiling");
379
+ costCeilingUsd = event.costCeilingUsd;
340
380
  }
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
381
  }
423
382
  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)
383
+ records: [...records.values()],
384
+ completedTasks,
385
+ ...costCeilingUsd === void 0 ? {} : { costCeilingUsd }
440
386
  };
441
- this.appendEvent(event, callId, receipt);
442
- this.records.set(callId, cloneRecord(record));
387
+ } catch (cause) {
388
+ throw new ValidationError(`CostLedger: invalid persisted event ${lineNumber || 1}: ${validationMessage(cause)}`, { cause });
443
389
  }
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;
390
+ }
391
+ function completeJournalPrefix(serialized) {
392
+ if (!serialized || serialized.endsWith("\n")) return serialized;
393
+ const finalNewline = serialized.lastIndexOf("\n");
394
+ const tail = serialized.slice(finalNewline + 1);
395
+ try {
396
+ JSON.parse(tail);
397
+ } catch {
398
+ return finalNewline < 0 ? "" : serialized.slice(0, finalNewline + 1);
451
399
  }
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);
400
+ throw new ValidationError("CostLedger: complete final persisted event is missing its newline terminator");
401
+ }
402
+ function validateTransition(records, record) {
403
+ const current = records.get(record.callId);
404
+ if (!current) return;
405
+ if (record.status === "pending" || current.status === "settled") throw new CostCallConflictError(`CostLedger: duplicate callId '${record.callId}'`);
406
+ if (!sameAttribution(current, record)) throw new ValidationError(`CostLedger: receipt attribution changed for call '${record.callId}'`);
407
+ }
408
+ function sameAttribution(before, after) {
409
+ 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);
410
+ }
411
+ function sameTags(left, right) {
412
+ const leftEntries = Object.entries(left ?? {}).sort(([a], [b]) => a.localeCompare(b));
413
+ const rightEntries = Object.entries(right ?? {}).sort(([a], [b]) => a.localeCompare(b));
414
+ return JSON.stringify(leftEntries) === JSON.stringify(rightEntries);
415
+ }
416
+ //#endregion
417
+ //#region src/cost-ledger/summary.ts
418
+ function summarizeCostLedger(records, activeCallIds, lateCallIds) {
419
+ const pending = records.filter((record) => record.status === "pending");
420
+ const receipts = records.filter((record) => record.status === "settled");
421
+ const byChannel = /* @__PURE__ */ new Map();
422
+ const unpriced = /* @__PURE__ */ new Set();
423
+ const incompleteReasons = pending.map((record) => `call '${record.callId}' for '${record.actor}' is pending`);
424
+ let inputTokens = 0;
425
+ let outputTokens = 0;
426
+ let reasoningTokens = 0;
427
+ let cachedTokens = 0;
428
+ let cacheWriteTokens = 0;
429
+ let totalCostUsd = 0;
430
+ for (const receipt of receipts) {
431
+ inputTokens += receipt.inputTokens;
432
+ outputTokens += receipt.outputTokens;
433
+ reasoningTokens += receipt.reasoningTokens ?? 0;
434
+ cachedTokens += receipt.cachedTokens ?? 0;
435
+ cacheWriteTokens += receipt.cacheWriteTokens ?? 0;
436
+ totalCostUsd += receipt.costUsd;
437
+ if (receipt.costUnknown) {
438
+ unpriced.add(receipt.model);
439
+ incompleteReasons.push(receipt.error ?? `cost unknown for '${receipt.actor}' using '${receipt.model}'`);
466
440
  }
441
+ if (receipt.usageUnknown) incompleteReasons.push(`token usage unknown for '${receipt.actor}' using '${receipt.model}'`);
442
+ if (receipt.maximumCostUsd !== void 0 && receipt.costUsd > receipt.maximumCostUsd) incompleteReasons.push(`'${receipt.actor}' charged ${receipt.costUsd}, exceeding its enforced maximum ${receipt.maximumCostUsd}`);
443
+ const rollup = byChannel.get(receipt.channel) ?? emptyRollup(receipt.channel);
444
+ rollup.calls += 1;
445
+ rollup.inputTokens += receipt.inputTokens;
446
+ rollup.outputTokens += receipt.outputTokens;
447
+ rollup.reasoningTokens = (rollup.reasoningTokens ?? 0) + (receipt.reasoningTokens ?? 0);
448
+ rollup.cachedTokens += receipt.cachedTokens ?? 0;
449
+ rollup.cacheWriteTokens = (rollup.cacheWriteTokens ?? 0) + (receipt.cacheWriteTokens ?? 0);
450
+ rollup.costUsd += receipt.costUsd;
451
+ if (receipt.costUnknown) rollup.unpricedCalls += 1;
452
+ if (receipt.usageUnknown) rollup.unknownUsageCalls += 1;
453
+ byChannel.set(receipt.channel, rollup);
467
454
  }
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
455
  return {
480
- costUsd: estimateCost(usage.inputTokens + (usage.cachedTokens ?? 0) + (usage.cacheWriteTokens ?? 0), usage.outputTokens, model),
481
- costUnknown: false
456
+ totalCalls: receipts.length,
457
+ pendingCalls: pending.length,
458
+ unresolvedCalls: pending.filter((record) => !activeCallIds.has(record.callId) || lateCallIds.has(record.callId)).length,
459
+ reservedCostUsd: pending.reduce((sum, record) => sum + (record.maximumCostUsd ?? 0), 0),
460
+ inputTokens,
461
+ outputTokens,
462
+ reasoningTokens,
463
+ cachedTokens,
464
+ cacheWriteTokens,
465
+ totalCostUsd,
466
+ costProvenance: pending.length > 0 || receipts.some((receipt) => receipt.costUnknown) ? {
467
+ kind: "uncaptured",
468
+ usd: null
469
+ } : receipts.every((receipt) => receipt.actualCostUsd !== void 0) ? {
470
+ kind: "observed",
471
+ usd: totalCostUsd
472
+ } : {
473
+ kind: "estimated",
474
+ usd: totalCostUsd
475
+ },
476
+ byChannel: [...byChannel.values()].sort((a, b) => a.channel.localeCompare(b.channel)),
477
+ unpricedModels: [...unpriced].sort(),
478
+ fullyPriced: unpriced.size === 0,
479
+ usageComplete: pending.length === 0 && receipts.every((receipt) => !receipt.usageUnknown),
480
+ accountingComplete: incompleteReasons.length === 0,
481
+ incompleteReasons: [...new Set(incompleteReasons)]
482
482
  };
483
483
  }
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");
484
+ function emptyRollup(channel) {
485
+ return {
486
+ channel,
487
+ calls: 0,
488
+ inputTokens: 0,
489
+ outputTokens: 0,
490
+ reasoningTokens: 0,
491
+ cachedTokens: 0,
492
+ cacheWriteTokens: 0,
493
+ costUsd: 0,
494
+ unpricedCalls: 0,
495
+ unknownUsageCalls: 0
496
+ };
568
497
  }
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;
498
+ //#endregion
499
+ //#region src/cost-ledger.ts
500
+ /** Run-wide paid-call admission, durable call state, receipts, and summaries. */
501
+ var CostLedger = class {
502
+ records = /* @__PURE__ */ new Map();
503
+ activeCallIds = /* @__PURE__ */ new Set();
504
+ lateCallIds = /* @__PURE__ */ new Set();
505
+ idleWaiters = /* @__PURE__ */ new Set();
506
+ completedTasks = 0;
507
+ revision = "memory";
508
+ costLimitPersisted = false;
509
+ costCeilingUsd;
510
+ persistence;
511
+ constructor(input) {
512
+ const options = typeof input === "number" ? { costCeilingUsd: input } : input ?? {};
513
+ this.persistence = options.persistence;
514
+ if (options.costCeilingUsd !== void 0) assertNonNegative(options.costCeilingUsd, "costCeilingUsd");
515
+ let persistedCostCeilingUsd;
516
+ if (this.persistence) {
517
+ let stored;
518
+ try {
519
+ stored = this.persistence.read();
520
+ } catch (cause) {
521
+ throw new CostLedgerPersistenceError(cause);
522
+ }
523
+ assertString(stored.revision, "persistence revision");
524
+ this.revision = stored.revision;
525
+ const restored = parseEvents(stored.events);
526
+ for (const record of restored.records) this.records.set(record.callId, record);
527
+ this.completedTasks = restored.completedTasks;
528
+ persistedCostCeilingUsd = restored.costCeilingUsd;
529
+ }
530
+ 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}`);
531
+ this.costCeilingUsd = persistedCostCeilingUsd ?? options.costCeilingUsd;
532
+ this.costLimitPersisted = !this.persistence || this.costCeilingUsd === void 0 || persistedCostCeilingUsd !== void 0;
533
+ 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");
534
+ if (options.receipts?.length) {
535
+ const imported = options.receipts.map((receipt, index) => parseImportedReceipt(receipt, `imported receipt ${index + 1}`));
536
+ this.ensureCostLimitPersisted();
537
+ for (const receipt of imported) this.appendRecord(receipt);
538
+ }
539
+ }
540
+ async runPaidCall(input) {
541
+ let callId;
542
+ let pending;
543
+ try {
544
+ callId = resolveCallId(input.callId);
545
+ validateAttribution(input);
546
+ if (input.signal?.aborted) return {
547
+ succeeded: false,
548
+ callId,
549
+ error: abortError(input.signal)
550
+ };
551
+ this.ensureCostLimitPersisted(callId);
552
+ const maximumCostUsd = this.resolveMaximum(input.maximumCharge);
553
+ const existing = this.records.get(callId);
554
+ if (existing) return {
555
+ succeeded: false,
556
+ callId,
557
+ error: new CostCallConflictError(existing.status === "pending" ? `CostLedger: callId '${callId}' is unresolved and must be reconciled before retry` : `CostLedger: callId '${callId}' already exists`, { callId })
558
+ };
559
+ if (!pending) {
560
+ while (true) {
561
+ if (this.records.has(callId)) return {
562
+ succeeded: false,
563
+ callId,
564
+ error: new CostCallConflictError(`CostLedger: callId '${callId}' already exists`)
565
+ };
566
+ const admission = this.admissionState();
567
+ if (admission.unresolvedCalls > 0) return {
568
+ succeeded: false,
569
+ callId,
570
+ error: new CostAccountingIncompleteError(`CostLedger: ${admission.unresolvedCalls} unresolved call(s) must be reconciled before new paid work`)
571
+ };
572
+ if (this.costCeilingUsd === void 0) break;
573
+ if (admission.budgetBreached) return {
574
+ succeeded: false,
575
+ callId,
576
+ error: new CostAccountingIncompleteError(`CostLedger: a settled call exceeded its enforced maximum; refusing paid call '${input.actor}' during '${input.phase}'`)
577
+ };
578
+ const { committedCostUsd } = admission;
579
+ if (committedCostUsd + maximumCostUsd > this.costCeilingUsd) return {
580
+ succeeded: false,
581
+ callId,
582
+ error: new CostCeilingReachedError(this.costCeilingUsd, committedCostUsd, maximumCostUsd, input.phase, input.actor)
583
+ };
584
+ if (committedCostUsd + admission.reservedCostUsd + maximumCostUsd <= this.costCeilingUsd) break;
585
+ await this.waitForReservationRelease(input.signal);
586
+ }
587
+ pending = {
588
+ status: "pending",
589
+ callId,
590
+ channel: input.channel,
591
+ phase: input.phase,
592
+ actor: input.actor,
593
+ model: pendingModel(input),
594
+ ...maximumCostUsd === void 0 ? {} : { maximumCostUsd },
595
+ ...input.tags ? { tags: { ...input.tags } } : {},
596
+ timestamp: Date.now()
597
+ };
598
+ this.appendRecord(pending);
599
+ this.activeCallIds.add(callId);
600
+ }
601
+ } catch (error) {
602
+ return {
603
+ succeeded: false,
604
+ ...callId ? { callId } : {},
605
+ error: toError(error)
606
+ };
607
+ }
608
+ try {
609
+ return await this.execute(input, pending);
610
+ } catch (error) {
611
+ return {
612
+ succeeded: false,
613
+ callId: pending.callId,
614
+ error: toError(error)
615
+ };
616
+ } finally {
617
+ if (!this.lateCallIds.has(pending.callId)) this.releaseActiveCall(pending.callId);
618
+ }
631
619
  }
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"
620
+ /** Wait until every call started by this ledger has produced a durable outcome. */
621
+ async waitForIdle(options = {}) {
622
+ const hasActiveMatch = () => [...this.activeCallIds].some((callId) => {
623
+ const record = this.records.get(callId);
624
+ return record !== void 0 && matches(record, options.filter);
636
625
  });
637
- if (receipt.pricing !== void 0) ctx.addIssue({
638
- code: "custom",
639
- message: "external estimate must not include token pricing"
626
+ if (!hasActiveMatch()) return true;
627
+ const timeoutMs = options.timeoutMs ?? 5e3;
628
+ assertTimeout(timeoutMs, "waitForIdle.timeoutMs");
629
+ return new Promise((resolve) => {
630
+ let timer;
631
+ const finish = (settled) => {
632
+ this.idleWaiters.delete(onIdle);
633
+ if (timer !== void 0) clearTimeout(timer);
634
+ resolve(settled);
635
+ };
636
+ const onIdle = () => {
637
+ if (!hasActiveMatch()) finish(true);
638
+ };
639
+ this.idleWaiters.add(onIdle);
640
+ timer = setTimeout(() => finish(false), timeoutMs);
641
+ onIdle();
640
642
  });
641
- return;
642
643
  }
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"
644
+ /** Settle a call left pending by a crashed process after reconciling with the provider. */
645
+ reconcile(callId, observed, options = {}) {
646
+ const pending = this.records.get(callId);
647
+ if (pending?.status !== "pending") throw new CostCallConflictError(`CostLedger: no pending call '${callId}'`);
648
+ if (this.activeCallIds.has(callId)) throw new CostCallConflictError(`CostLedger: call '${callId}' is still active`);
649
+ this.ensureCostLimitPersisted(callId);
650
+ return this.commitReceipt(pending, observed, options.failed === true || options.error !== void 0, options.error);
651
+ }
652
+ list(filter) {
653
+ return [...this.records.values()].filter((record) => record.status === "settled").filter((receipt) => matches(receipt, filter)).map(cloneReceipt);
654
+ }
655
+ /** Read pending calls without exposing mutable ledger state. */
656
+ listPending(filter) {
657
+ return [...this.records.values()].filter((record) => record.status === "pending").filter((record) => matches(record, filter)).map((record) => ({
658
+ ...clonePendingCall(record),
659
+ state: this.lateCallIds.has(record.callId) ? "late" : this.activeCallIds.has(record.callId) ? "active" : "interrupted"
660
+ }));
661
+ }
662
+ summary(filter) {
663
+ return summarizeCostLedger([...this.records.values()].filter((record) => matches(record, filter)), this.activeCallIds, this.lateCallIds);
664
+ }
665
+ markCompleted(count = 1) {
666
+ if (!Number.isInteger(count) || count < 0) throw new ValidationError(`CostLedger.markCompleted: count must be a non-negative integer, got ${count}`);
667
+ if (count === 0) return;
668
+ this.ensureCostLimitPersisted();
669
+ this.appendEvent({
670
+ version: 1,
671
+ completedTasks: count
651
672
  });
652
- return;
673
+ this.completedTasks += count;
653
674
  }
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"
675
+ costPerCompletedTask() {
676
+ return this.completedTasks === 0 ? null : this.summary().totalCostUsd / this.completedTasks;
677
+ }
678
+ async execute(input, pending) {
679
+ const signal = input.signal ?? new AbortController().signal;
680
+ if (signal.aborted) return this.commitOutcome(pending, abortError(signal), {
681
+ model: pending.model,
682
+ inputTokens: 0,
683
+ outputTokens: 0,
684
+ actualCostUsd: 0
662
685
  });
663
- return;
686
+ const operation = Promise.resolve().then(() => input.execute(signal, pending.callId));
687
+ const settled = await settle(operation, signal);
688
+ if (settled.kind === "aborted") {
689
+ this.lateCallIds.add(pending.callId);
690
+ this.captureLateOutcome(input, pending, operation);
691
+ return paidFailure(pending.callId, abortError(signal));
692
+ }
693
+ if (settled.kind === "error") {
694
+ let observed;
695
+ try {
696
+ observed = input.receiptFromError?.(settled.error);
697
+ } catch (receiptError) {
698
+ return this.captureFailure(pending, settled.error, receiptError);
699
+ }
700
+ return this.commitOutcome(pending, settled.error, observed ?? unknownReceipt(pending.model));
701
+ }
702
+ try {
703
+ const receipt = this.commitReceipt(pending, input.receipt(settled.value));
704
+ if (receipt.maximumCostUsd !== void 0 && receipt.costUsd > receipt.maximumCostUsd) return paidFailure(pending.callId, new CostReservationExceededError(pending.actor, receipt.costUsd, receipt.maximumCostUsd), receipt);
705
+ return {
706
+ succeeded: true,
707
+ callId: pending.callId,
708
+ value: settled.value,
709
+ receipt
710
+ };
711
+ } catch (receiptError) {
712
+ if (receiptError instanceof CostLedgerPersistenceError || receiptError instanceof CostCallConflictError) return paidFailure(pending.callId, receiptError);
713
+ return this.captureFailure(pending, receiptError, receiptError);
714
+ }
664
715
  }
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;
716
+ captureLateOutcome(input, pending, operation) {
717
+ operation.then((value) => {
718
+ if (this.records.get(pending.callId)?.status !== "pending") return;
719
+ try {
720
+ this.commitReceipt(pending, input.receipt(value));
721
+ } catch {}
722
+ }, (cause) => {
723
+ if (this.records.get(pending.callId)?.status !== "pending") return;
724
+ const error = toError(cause);
725
+ try {
726
+ const observed = input.receiptFromError?.(error);
727
+ this.commitReceipt(pending, observed ?? unknownReceipt(pending.model), true);
728
+ } catch (receiptError) {
729
+ if (receiptError instanceof CostLedgerPersistenceError || receiptError instanceof CostCallConflictError) return;
730
+ this.captureFailure(pending, error, receiptError);
713
731
  }
732
+ }).finally(() => {
733
+ this.lateCallIds.delete(pending.callId);
734
+ this.releaseActiveCall(pending.callId);
735
+ });
736
+ }
737
+ releaseActiveCall(callId) {
738
+ this.activeCallIds.delete(callId);
739
+ for (const resolve of [...this.idleWaiters]) resolve();
740
+ }
741
+ async waitForReservationRelease(signal) {
742
+ if (signal?.aborted) throw abortError(signal);
743
+ await new Promise((resolve, reject) => {
744
+ let finished = false;
745
+ const finish = (error) => {
746
+ if (finished) return;
747
+ finished = true;
748
+ this.idleWaiters.delete(onRelease);
749
+ signal?.removeEventListener("abort", onAbort);
750
+ if (error) reject(error);
751
+ else resolve();
752
+ };
753
+ const onRelease = () => finish();
754
+ const onAbort = () => finish(abortError(signal));
755
+ this.idleWaiters.add(onRelease);
756
+ signal?.addEventListener("abort", onAbort, { once: true });
757
+ if (this.activeCallIds.size === 0) onRelease();
758
+ });
759
+ }
760
+ commitOutcome(pending, error, observed) {
761
+ try {
762
+ const receipt = this.commitReceipt(pending, observed, true);
763
+ return paidFailure(pending.callId, error, receipt);
764
+ } catch (receiptError) {
765
+ if (receiptError instanceof CostLedgerPersistenceError || receiptError instanceof CostCallConflictError) return paidFailure(pending.callId, receiptError);
766
+ return this.captureFailure(pending, error, receiptError);
714
767
  }
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
768
  }
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);
769
+ captureFailure(pending, cause, receiptError) {
770
+ try {
771
+ const receipt = this.commitReceipt(pending, unknownReceipt(pending.model), true);
772
+ return paidFailure(pending.callId, new CostReceiptCaptureError(pending.callId, cause, receiptError, receipt), receipt);
773
+ } catch (error) {
774
+ const typed = error instanceof Error ? error : toError(error);
775
+ return paidFailure(pending.callId, typed);
776
+ }
732
777
  }
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 });
778
+ commitReceipt(pending, observed, failed = false, error) {
779
+ const receipt = buildReceipt(pending, observed, failed, error);
780
+ if (this.records.get(pending.callId)?.status !== "pending") throw new CostCallConflictError(`CostLedger: call '${pending.callId}' is not pending`);
781
+ this.appendRecord(receipt);
782
+ return cloneReceipt(receipt);
754
783
  }
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
784
+ resolveMaximum(maximum) {
785
+ if (!maximum) {
786
+ if (this.costCeilingUsd !== void 0) throw new CostAccountingIncompleteError("CostLedger: capped paid calls require a hard maximumCharge before execution");
787
+ return;
788
+ }
789
+ if ("externallyEnforcedMaximumUsd" in maximum) {
790
+ assertNonNegative(maximum.externallyEnforcedMaximumUsd, "maximumCharge.externallyEnforcedMaximumUsd");
791
+ return maximum.externallyEnforcedMaximumUsd;
792
+ }
793
+ if ("customTokenPricing" in maximum) return costForTokenPricing(maximum.customTokenPricing, maximum);
794
+ const priced = costForUsage(maximum.model, maximum);
795
+ if (priced.costUnknown) {
796
+ if (this.costCeilingUsd !== void 0) throw new CostAccountingIncompleteError(`CostLedger: cannot reserve unpriced model '${maximum.model}' in a capped run`);
797
+ return;
798
+ }
799
+ return priced.costUsd;
800
+ }
801
+ /** Compute admission totals in record order without building reporting rollups. */
802
+ admissionState() {
803
+ let unresolvedCalls = 0;
804
+ let reservedCostUsd = 0;
805
+ let committedCostUsd = 0;
806
+ let budgetBreached = false;
807
+ for (const record of this.records.values()) if (record.status === "pending") {
808
+ if (!this.activeCallIds.has(record.callId) || this.lateCallIds.has(record.callId)) unresolvedCalls += 1;
809
+ reservedCostUsd += record.maximumCostUsd ?? 0;
810
+ } else {
811
+ if (record.maximumCostUsd !== void 0 && record.costUsd > record.maximumCostUsd) budgetBreached = true;
812
+ committedCostUsd += record.costUnknown ? record.maximumCostUsd ?? record.costUsd : record.costUsd;
813
+ }
814
+ return {
815
+ unresolvedCalls,
816
+ reservedCostUsd,
817
+ committedCostUsd,
818
+ budgetBreached
764
819
  };
765
820
  }
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}`);
821
+ appendRecord(record) {
822
+ const callId = record.callId;
823
+ const receipt = record.status === "settled" ? record : void 0;
824
+ validateTransition(this.records, record);
825
+ const event = record.status === "settled" ? {
826
+ version: 2,
827
+ record: cloneReceipt(record)
828
+ } : {
829
+ version: 1,
830
+ record: clonePendingCall(record)
831
+ };
832
+ this.appendEvent(event, callId, receipt);
833
+ this.records.set(callId, cloneRecord(record));
776
834
  }
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
835
+ ensureCostLimitPersisted(callId) {
836
+ if (this.costLimitPersisted || this.costCeilingUsd === void 0) return;
837
+ this.appendEvent({
838
+ version: 1,
839
+ costCeilingUsd: this.costCeilingUsd
840
+ }, callId);
841
+ this.costLimitPersisted = true;
842
+ }
843
+ appendEvent(event, callId, receipt) {
844
+ try {
845
+ if (this.persistence) {
846
+ const nextRevision = this.persistence.append(this.revision, `${JSON.stringify(event)}\n`);
847
+ if (nextRevision === void 0) throw new CostCallConflictError(`CostLedger: persisted revision changed while writing call '${callId}'`, {
848
+ callId,
849
+ receipt
850
+ });
851
+ assertString(nextRevision, "persistence revision");
852
+ this.revision = nextRevision;
853
+ }
854
+ } catch (cause) {
855
+ if (cause instanceof CostCallConflictError) throw cause;
856
+ throw new CostLedgerPersistenceError(cause, callId, receipt);
857
+ }
858
+ }
859
+ };
860
+ async function settle(promise, signal) {
861
+ return await new Promise((resolve) => {
862
+ let done = false;
863
+ const finish = (value) => {
864
+ if (done) return;
865
+ done = true;
866
+ signal.removeEventListener("abort", onAbort);
867
+ resolve(value);
868
+ };
869
+ const onAbort = () => finish({ kind: "aborted" });
870
+ signal.addEventListener("abort", onAbort, { once: true });
871
+ if (signal.aborted) onAbort();
872
+ promise.then((value) => finish({
873
+ kind: "value",
874
+ value
875
+ }), (error) => finish({
876
+ kind: "error",
877
+ error: toError(error)
878
+ }));
812
879
  });
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
880
  }
834
881
  function pendingModel(input) {
835
882
  if (input.model) return input.model;
@@ -860,9 +907,6 @@ function abortError(signal) {
860
907
  error.name = "AbortError";
861
908
  return error;
862
909
  }
863
- function toError(value) {
864
- return value instanceof Error ? value : new Error(String(value));
865
- }
866
910
  function paidFailure(callId, error, receipt) {
867
911
  return {
868
912
  succeeded: false,
@@ -871,32 +915,7 @@ function paidFailure(callId, error, receipt) {
871
915
  ...receipt ? { receipt: cloneReceipt(receipt) } : {}
872
916
  };
873
917
  }
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
918
  //#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 };
919
+ 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, modelPriceKey as u };
901
920
 
902
- //# sourceMappingURL=cost-ledger-D2FnJPBF.js.map
921
+ //# sourceMappingURL=cost-ledger-BP8V4kUQ.js.map