chainlesschain 0.166.97 → 0.166.99

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 (188) hide show
  1. package/README.md +20 -23
  2. package/package.json +3 -3
  3. package/src/assets/linux-subreaper/linux-arm64/manifest.json +1 -1
  4. package/src/assets/linux-subreaper/linux-x64/manifest.json +1 -1
  5. package/src/assets/web-panel/assets/{AIOps-BB9kKNVw.js → AIOps-BUgaCgVU.js} +1 -1
  6. package/src/assets/web-panel/assets/{ActionButton-DTg-lWE0.js → ActionButton-b0MpUSSZ.js} +1 -1
  7. package/src/assets/web-panel/assets/{Analytics-BWUZ0Tpc.js → Analytics-hbXTvHqO.js} +3 -3
  8. package/src/assets/web-panel/assets/{AppLayout-Dj8WDnCf.js → AppLayout-CLQoAVu4.js} +5 -5
  9. package/src/assets/web-panel/assets/{Artifacts-x8NiiPTg.js → Artifacts-ytHzl2L2.js} +1 -1
  10. package/src/assets/web-panel/assets/{Audit-q7otRAqO.js → Audit-BuhkLm0C.js} +1 -1
  11. package/src/assets/web-panel/assets/{BackgroundAgents-f6qlO2au.js → BackgroundAgents-CS81hxZV.js} +1 -1
  12. package/src/assets/web-panel/assets/{Backup-BbuX9qQS.js → Backup-DzR-_Qvi.js} +1 -1
  13. package/src/assets/web-panel/assets/{BaseInput-amgV-Y0y.js → BaseInput-r8Ku_lYw.js} +1 -1
  14. package/src/assets/web-panel/assets/{Chat-CZW3DW7j.js → Chat-C3Uxtoaa.js} +5 -5
  15. package/src/assets/web-panel/assets/ChatBubbleRenderer-RvblDu77.js +1 -0
  16. package/src/assets/web-panel/assets/{Checkbox-DXHXC52i.js → Checkbox-BnG2P5yc.js} +1 -1
  17. package/src/assets/web-panel/assets/{Codegen-DQh47r4e.js → Codegen-BdgU6HZy.js} +1 -1
  18. package/src/assets/web-panel/assets/{Col-lBOOXCD7.js → Col-DT8t9wmf.js} +1 -1
  19. package/src/assets/web-panel/assets/{Community-BNFPnBu9.js → Community-ChkxR5oe.js} +1 -1
  20. package/src/assets/web-panel/assets/{Compact-7MOWfBGb.js → Compact-DIwLeTk3.js} +1 -1
  21. package/src/assets/web-panel/assets/{Compliance-x0UA-rxk.js → Compliance-CAqzGLvW.js} +1 -1
  22. package/src/assets/web-panel/assets/{Cowork-C_eLfk_Q.js → Cowork-Bb3jejMG.js} +2 -2
  23. package/src/assets/web-panel/assets/{Cron-BP2-_Fja.js → Cron-BYRkZLta.js} +2 -2
  24. package/src/assets/web-panel/assets/{Crosschain-Dn-e1217.js → Crosschain-BD6z227t.js} +1 -1
  25. package/src/assets/web-panel/assets/{DID-D_jverif.js → DID-DA3G5Wgo.js} +2 -2
  26. package/src/assets/web-panel/assets/{Dashboard-BysweBms.js → Dashboard-yaZePHOu.js} +2 -2
  27. package/src/assets/web-panel/assets/{Dropdown-osJi0Pci.js → Dropdown-BqY5MBx2.js} +1 -1
  28. package/src/assets/web-panel/assets/{EmailListRenderer-C72k1SKQ.js → EmailListRenderer-cIWwOgHm.js} +1 -1
  29. package/src/assets/web-panel/assets/{EvolutionSettings-CAtA1F9s.js → EvolutionSettings-zvV6ymca.js} +1 -1
  30. package/src/assets/web-panel/assets/{FamilyGuardDashboard-Bi0luzvO.js → FamilyGuardDashboard-CAmh1U2b.js} +1 -1
  31. package/src/assets/web-panel/assets/{Federation-CIwntDLI.js → Federation-5qd2LCg8.js} +1 -1
  32. package/src/assets/web-panel/assets/{FormItemContext-DRfwhPW-.js → FormItemContext-Bdkj1sRJ.js} +1 -1
  33. package/src/assets/web-panel/assets/{GenericCardRenderer-COJTzZ61.js → GenericCardRenderer-B-gWN2P3.js} +1 -1
  34. package/src/assets/web-panel/assets/{Git-CwsR46lj.js → Git-BEMh_NGd.js} +2 -2
  35. package/src/assets/web-panel/assets/{Governance-B1U-u9BN.js → Governance-qLGvA2Hw.js} +1 -1
  36. package/src/assets/web-panel/assets/{Inference-vPsdYTS_.js → Inference-DblBwYuW.js} +1 -1
  37. package/src/assets/web-panel/assets/{KnowledgeGraph-CVDRZM5h.js → KnowledgeGraph-BISegVD_.js} +1 -1
  38. package/src/assets/web-panel/assets/Logs-BD2UR7kE.js +2 -0
  39. package/src/assets/web-panel/assets/MarkdownRenderer-B-TlDCmr.js +1 -0
  40. package/src/assets/web-panel/assets/{Marketplace-CtxYHchd.js → Marketplace-CHKXMOkH.js} +1 -1
  41. package/src/assets/web-panel/assets/{McpTools-BkfCbpAk.js → McpTools-B5G1elqd.js} +3 -3
  42. package/src/assets/web-panel/assets/{Memory-COp-8Z20.js → Memory-O5Ib0uTR.js} +2 -2
  43. package/src/assets/web-panel/assets/{MobileBridge-7fX-n_xn.js → MobileBridge-BaGYL7rT.js} +1 -1
  44. package/src/assets/web-panel/assets/MobileProjects-Dsctbob8.js +1 -0
  45. package/src/assets/web-panel/assets/{Mtc-CLXFZ5dV.js → Mtc-CNjJ97jg.js} +5 -5
  46. package/src/assets/web-panel/assets/{MtcAudit-yJ4eP1wB.js → MtcAudit-DjBN-Wqz.js} +5 -5
  47. package/src/assets/web-panel/assets/{Multisig-Cwb_qTh0.js → Multisig-B850R9lO.js} +3 -3
  48. package/src/assets/web-panel/assets/{NLProgramming-CkuojSSJ.js → NLProgramming-Bn8sbFfV.js} +1 -1
  49. package/src/assets/web-panel/assets/{Notes-ju-QtUhJ.js → Notes-BpLmMp3Q.js} +3 -3
  50. package/src/assets/web-panel/assets/{NotificationSettings-DjryXIC3.js → NotificationSettings-Dbk97rjb.js} +1 -1
  51. package/src/assets/web-panel/assets/{OrderTableRenderer-B4KNF8xr.js → OrderTableRenderer-BOBX_I72.js} +1 -1
  52. package/src/assets/web-panel/assets/{Organization-6-EtcVaO.js → Organization-B45DpOuE.js} +4 -4
  53. package/src/assets/web-panel/assets/{Overflow-BKja8nqr.js → Overflow-DmKH7eer.js} +1 -1
  54. package/src/assets/web-panel/assets/{P2P-BX20f9uL.js → P2P-CC4FaXTl.js} +2 -2
  55. package/src/assets/web-panel/assets/{PdhVaultBrowser-C9zwOEUo.js → PdhVaultBrowser-C2SgP4PI.js} +3 -3
  56. package/src/assets/web-panel/assets/{Permissions-YQjQVrfE.js → Permissions-BQB4QFj_.js} +3 -3
  57. package/src/assets/web-panel/assets/{PersonalDataHub-yZYclXxq.js → PersonalDataHub-Dy6GGpn4.js} +3 -3
  58. package/src/assets/web-panel/assets/{Pipeline-ChZCCXAI.js → Pipeline-B9HB5pRc.js} +1 -1
  59. package/src/assets/web-panel/assets/{Privacy-Ds7R-a0H.js → Privacy-D7pOmg-p.js} +1 -1
  60. package/src/assets/web-panel/assets/{ProjectInit-B3qz_xab.js → ProjectInit-DglBqvec.js} +2 -2
  61. package/src/assets/web-panel/assets/{ProjectSettings-BlwNctdF.js → ProjectSettings-Bho22znM.js} +2 -2
  62. package/src/assets/web-panel/assets/{Projects-BxtYpNl7.js → Projects-C0bSuM8U.js} +1 -1
  63. package/src/assets/web-panel/assets/{Providers-BE_1SS_-.js → Providers-BgAgo1Yr.js} +1 -1
  64. package/src/assets/web-panel/assets/{QrScannerModal-CMQ25oLb.js → QrScannerModal-C2fBjCC8.js} +1 -1
  65. package/src/assets/web-panel/assets/{QuickAsk-DQRFLDeP.js → QuickAsk-C8MiF-rk.js} +1 -1
  66. package/src/assets/web-panel/assets/{Recommend-ChVra4Pk.js → Recommend-D_TzHdQf.js} +1 -1
  67. package/src/assets/web-panel/assets/{RemoteSession-9vPBIowJ.js → RemoteSession-BHO7b6xE.js} +2 -2
  68. package/src/assets/web-panel/assets/{Reputation-MdbWbyQQ.js → Reputation-BPxNmNhD.js} +1 -1
  69. package/src/assets/web-panel/assets/{Row-JLcBncLR.js → Row-fwhot5Bk.js} +1 -1
  70. package/src/assets/web-panel/assets/{RssFeed-CnMXnpFv.js → RssFeed-CZbD1B-5.js} +2 -2
  71. package/src/assets/web-panel/assets/{Search-Cf5ISVUe.js → Search-BRs6YpAE.js} +1 -1
  72. package/src/assets/web-panel/assets/{Security-CywFo2EM.js → Security-CB344tKC.js} +4 -4
  73. package/src/assets/web-panel/assets/{Services-CLYnSCG3.js → Services-Beo-7fEl.js} +2 -2
  74. package/src/assets/web-panel/assets/{Skeleton-BtbhOlo1.js → Skeleton-CDXx96vD.js} +1 -1
  75. package/src/assets/web-panel/assets/{Skills-DPeqcIo2.js → Skills-b-mQTJK4.js} +1 -1
  76. package/src/assets/web-panel/assets/{Sla-BRb4SqDn.js → Sla-BvjP-IS9.js} +1 -1
  77. package/src/assets/web-panel/assets/{SpeechSettings-0Wuxts-7.js → SpeechSettings-C6wsV-cO.js} +1 -1
  78. package/src/assets/web-panel/assets/{SyncSettings-BXtsOjXL.js → SyncSettings-BQZoko-e.js} +2 -2
  79. package/src/assets/web-panel/assets/{Tasks-D455Wfhx.js → Tasks-6Z0rJJVO.js} +1 -1
  80. package/src/assets/web-panel/assets/{Templates-LGc4O0fj.js → Templates-Cc9IXtEQ.js} +1 -1
  81. package/src/assets/web-panel/assets/{Tenant-DA--0GFz.js → Tenant-BLc7AjOI.js} +1 -1
  82. package/src/assets/web-panel/assets/{Terminal-DQsA0xCq.js → Terminal-CUN49v85.js} +2 -2
  83. package/src/assets/web-panel/assets/{TimelineRenderer-VH8AuSLp.js → TimelineRenderer-CX-SksHN.js} +1 -1
  84. package/src/assets/web-panel/assets/{Tokens-B8RyzFRN.js → Tokens-Btrm0-rK.js} +1 -1
  85. package/src/assets/web-panel/assets/{Trigger-CA7lVVEf.js → Trigger-CIboUvKe.js} +1 -1
  86. package/src/assets/web-panel/assets/{Trust-wUoRRLg9.js → Trust-Rv9jEs5v.js} +1 -1
  87. package/src/assets/web-panel/assets/{UkeySign-ByoT_alW.js → UkeySign-B_xomdD5.js} +1 -1
  88. package/src/assets/web-panel/assets/{VideoEditing-D9fgAxJV.js → VideoEditing-CrvWeMow.js} +1 -1
  89. package/src/assets/web-panel/assets/{Wallet-CRkTndvj.js → Wallet-BjvWgk_7.js} +3 -3
  90. package/src/assets/web-panel/assets/{WebAuthn-VwmHOxJK.js → WebAuthn-CwfpFw92.js} +3 -3
  91. package/src/assets/web-panel/assets/{WorkflowEditor-Z0bPZc2O.js → WorkflowEditor-Dkk2QsOe.js} +1 -1
  92. package/src/assets/web-panel/assets/{chat-CfX_5qUm.js → chat-Dah1DVes.js} +1 -1
  93. package/src/assets/web-panel/assets/{colors-BK7mXUnR.js → colors-JEpgQ10k.js} +1 -1
  94. package/src/assets/web-panel/assets/{compact-item-Uq755CeO.js → compact-item--DuG_cxf.js} +1 -1
  95. package/src/assets/web-panel/assets/{createContext-DWXq8Qnk.js → createContext-BJ_GZvon.js} +1 -1
  96. package/src/assets/web-panel/assets/devWarning-B6kQEceX.js +1 -0
  97. package/src/assets/web-panel/assets/{hasIn-BXgy5JZA.js → hasIn-yZRLDmWK.js} +1 -1
  98. package/src/assets/web-panel/assets/{index-LsBPnXHh.js → index-1QZASeW1.js} +1 -1
  99. package/src/assets/web-panel/assets/{index-DSb7SKp5.js → index-9L3Pg2tc.js} +1 -1
  100. package/src/assets/web-panel/assets/{index-H13lvPme.js → index-BKl40wrO.js} +1 -1
  101. package/src/assets/web-panel/assets/{index-TDPkVyse.js → index-BM7xJKGD.js} +1 -1
  102. package/src/assets/web-panel/assets/{index-CRLOeoFE.js → index-BUjyj7qR.js} +1 -1
  103. package/src/assets/web-panel/assets/{index-JX7mXB5a.js → index-BWkKE8Oj.js} +3 -3
  104. package/src/assets/web-panel/assets/{index-VPLA-GO7.js → index-Bdg_nWD1.js} +1 -1
  105. package/src/assets/web-panel/assets/{index-Bt3tjvj-.js → index-C56b8e9s.js} +1 -1
  106. package/src/assets/web-panel/assets/{index-C3VnhfYU.js → index-C6ohEAEV.js} +1 -1
  107. package/src/assets/web-panel/assets/{index-DuhlVXh4.js → index-C8nXkCMf.js} +1 -1
  108. package/src/assets/web-panel/assets/{index-BZD1My0S.js → index-CFj7ylAJ.js} +1 -1
  109. package/src/assets/web-panel/assets/{index-BxSClhg5.js → index-CJLz3SpM.js} +1 -1
  110. package/src/assets/web-panel/assets/{index-CGy7b2rd.js → index-CQedFuDw.js} +1 -1
  111. package/src/assets/web-panel/assets/index-CSeiH6HA.js +1 -0
  112. package/src/assets/web-panel/assets/index-CayGTz6d.js +1 -0
  113. package/src/assets/web-panel/assets/{index-CqJw5WsH.js → index-CjuD8smQ.js} +1 -1
  114. package/src/assets/web-panel/assets/{index-9XsaovMH.js → index-Cmr0AzcK.js} +1 -1
  115. package/src/assets/web-panel/assets/{index-Dg9P9EDV.js → index-CxB49Mow.js} +1 -1
  116. package/src/assets/web-panel/assets/{index-QXKuGlOS.js → index-D6Le2m3d.js} +1 -1
  117. package/src/assets/web-panel/assets/{index-CarQiRSA.js → index-DFJbJ8rs.js} +1 -1
  118. package/src/assets/web-panel/assets/{index-BRQSkXde.js → index-DQ4Fch3e.js} +1 -1
  119. package/src/assets/web-panel/assets/{index-C8e4SYX4.js → index-DZBesaCN.js} +1 -1
  120. package/src/assets/web-panel/assets/{index-Ait-_UUh.js → index-DaDLWIWo.js} +1 -1
  121. package/src/assets/web-panel/assets/{index-DbjUfyVq.js → index-DbMGGcpZ.js} +1 -1
  122. package/src/assets/web-panel/assets/{index-p3BlIre2.js → index-DddwZCT9.js} +1 -1
  123. package/src/assets/web-panel/assets/{index-DdwC1i3O.js → index-DemMuw7n.js} +1 -1
  124. package/src/assets/web-panel/assets/{index-_I4nSJFc.js → index-DhX48E81.js} +1 -1
  125. package/src/assets/web-panel/assets/{index-wYTro42F.js → index-Dq-8PFhL.js} +1 -1
  126. package/src/assets/web-panel/assets/{index-XdoslBhl.js → index-DroaQypF.js} +1 -1
  127. package/src/assets/web-panel/assets/{index-DiVH_NiY.js → index-DxnkldGo.js} +1 -1
  128. package/src/assets/web-panel/assets/{index-CfYb8FjC.js → index-IjOa5lYn.js} +1 -1
  129. package/src/assets/web-panel/assets/{index-B09haI0M.js → index-L9CFyRIi.js} +1 -1
  130. package/src/assets/web-panel/assets/{index-Y77S-ZC0.js → index-VIgVth92.js} +1 -1
  131. package/src/assets/web-panel/assets/{index-D4yvdQCj.js → index-asia_JPc.js} +1 -1
  132. package/src/assets/web-panel/assets/{index-VrR8eMCk.js → index-cHx5KzUt.js} +1 -1
  133. package/src/assets/web-panel/assets/{index-D63nsr0a.js → index-kZE-K3ZO.js} +1 -1
  134. package/src/assets/web-panel/assets/{index-Ct41B4y4.js → index-o2qO_dYf.js} +1 -1
  135. package/src/assets/web-panel/assets/{index-CUR7dnMg.js → index-rkvSOceQ.js} +1 -1
  136. package/src/assets/web-panel/assets/{index-D-8lN1rG.js → index-vdTrEOj7.js} +1 -1
  137. package/src/assets/web-panel/assets/{initDefaultProps-DTuF67Yy.js → initDefaultProps-anKyyjGc.js} +1 -1
  138. package/src/assets/web-panel/assets/{motion-DZasLgsl.js → motion-Cqp0nx5A.js} +1 -1
  139. package/src/assets/web-panel/assets/{move-pPR4O1Du.js → move-Ca3mgkM2.js} +1 -1
  140. package/src/assets/web-panel/assets/{mtc-parser-Dc7fidhm.js → mtc-parser-BmwuhJ3z.js} +1 -1
  141. package/src/assets/web-panel/assets/{omit-CZ1IcubN.js → omit-C9Mf05WJ.js} +1 -1
  142. package/src/assets/web-panel/assets/{pickAttrs-BMtJilhr.js → pickAttrs-2PbxB9Ds.js} +1 -1
  143. package/src/assets/web-panel/assets/{placementArrow-D0EXaZA7.js → placementArrow-CTVbOFHt.js} +1 -1
  144. package/src/assets/web-panel/assets/{responsiveObserve-HftdThc5.js → responsiveObserve-Nrm8Vbmr.js} +1 -1
  145. package/src/assets/web-panel/assets/{slide-CT1JEPWV.js → slide-Dh4r1zqR.js} +1 -1
  146. package/src/assets/web-panel/assets/{statusUtils-rwE-IPZB.js → statusUtils-vzNoQL-r.js} +1 -1
  147. package/src/assets/web-panel/assets/{styleChecker-B2B8XHVq.js → styleChecker-BXpGfNkI.js} +1 -1
  148. package/src/assets/web-panel/assets/{useFlexGapSupport-TXNvIFVa.js → useFlexGapSupport-CVWBRdhs.js} +1 -1
  149. package/src/assets/web-panel/assets/{useFs-BcWgJKvf.js → useFs-BJWMLffI.js} +1 -1
  150. package/src/assets/web-panel/assets/{usePersonalDataHub-DWBDnOSR.js → usePersonalDataHub-CWCe5VHG.js} +1 -1
  151. package/src/assets/web-panel/assets/{vnode-Cf_LjUuu.js → vnode-D-NBEb8m.js} +1 -1
  152. package/src/assets/web-panel/assets/{zoom-DM2Bfuyl.js → zoom-C0mnhfGf.js} +1 -1
  153. package/src/assets/web-panel/index.html +1 -1
  154. package/src/commands/eval.js +79 -3
  155. package/src/commands/llm.js +40 -5
  156. package/src/data/changelog.json +26 -0
  157. package/src/lib/context-memory-kernel/message-adapter.js +41 -24
  158. package/src/lib/context-memory-kernel/segmented-memory-port.js +18 -0
  159. package/src/lib/cost-budget.js +8 -0
  160. package/src/lib/eval/runner.js +22 -1
  161. package/src/lib/eval/verify01-contracts.js +106 -51
  162. package/src/lib/eval/verify01-execution.js +148 -166
  163. package/src/lib/eval/verify01-host-evidence.js +34 -2
  164. package/src/lib/eval/verify01-workspace.js +302 -0
  165. package/src/lib/execution-location-failure-site.js +18 -0
  166. package/src/lib/execution-location-target.js +10 -0
  167. package/src/lib/llm-connection-probe.js +147 -6
  168. package/src/lib/llm-pricing.js +61 -7
  169. package/src/lib/model-capabilities.js +10 -2
  170. package/src/lib/model-catalog-review.js +1 -0
  171. package/src/lib/model-context-catalog.js +26 -1
  172. package/src/lib/provider-http-error.js +30 -11
  173. package/src/lib/provider-options.js +38 -1
  174. package/src/lib/search-command.js +4 -1
  175. package/src/lib/stream-retry.js +14 -1
  176. package/src/lib/task-progress-tracker.js +1 -0
  177. package/src/lib/usage-pricing-context.js +100 -10
  178. package/src/runtime/agent-core.js +95 -18
  179. package/src/runtime/headless-runner.js +47 -20
  180. package/src/runtime/headless-stream.js +32 -10
  181. package/src/runtime/provider-stream-state.js +7 -0
  182. package/src/assets/web-panel/assets/ChatBubbleRenderer-DgMYDmBW.js +0 -1
  183. package/src/assets/web-panel/assets/Logs-YRslKbRL.js +0 -2
  184. package/src/assets/web-panel/assets/MarkdownRenderer-CUBuc97a.js +0 -1
  185. package/src/assets/web-panel/assets/MobileProjects-DUyTVgId.js +0 -1
  186. package/src/assets/web-panel/assets/devWarning-CbtBfs7a.js +0 -1
  187. package/src/assets/web-panel/assets/index-CicoHC0s.js +0 -1
  188. package/src/assets/web-panel/assets/index-DttyUwDx.js +0 -1
@@ -0,0 +1,302 @@
1
+ /** Shared file boundaries and snapshots; no process broker or npm dependencies. */
2
+ import fs from "node:fs";
3
+ import path from "node:path";
4
+ import { createHash } from "node:crypto";
5
+ import { evalDigest } from "./evidence.js";
6
+ const MAX_BYTES = 16 * 1024 * 1024;
7
+ export const MAX_SNAPSHOT_BYTES = 512 * 1024 * 1024;
8
+ const MAX_DIFF_BYTES = 32 * 1024 * 1024;
9
+ const EMPTY_DELIVERABLE_DIGEST = evalDigest(Buffer.alloc(0));
10
+
11
+ export function requireValue(condition, message) {
12
+ if (!condition) throw new Error(message);
13
+ }
14
+
15
+ export function relativeFile(value) {
16
+ requireValue(
17
+ typeof value === "string" &&
18
+ value.length > 0 &&
19
+ !value.includes("\0") &&
20
+ !/[\\:*?<>|"]/u.test(value) &&
21
+ !value.startsWith("/") &&
22
+ value.split("/").every((part) => part && !/[. ]$/u.test(part)),
23
+ "review paths must be exact relative files",
24
+ );
25
+ return value;
26
+ }
27
+ export function readBytes(file) {
28
+ const descriptor = fs.openSync(file, "r");
29
+ try {
30
+ const before = fs.fstatSync(descriptor, { bigint: true });
31
+ requireValue(
32
+ before.isFile() && before.size <= BigInt(MAX_BYTES),
33
+ "input must be a regular file within 16 MiB",
34
+ );
35
+ const bytes = Buffer.alloc(Number(before.size) + 1);
36
+ let count = 0;
37
+ while (count < bytes.length) {
38
+ const size = fs.readSync(
39
+ descriptor,
40
+ bytes,
41
+ count,
42
+ bytes.length - count,
43
+ null,
44
+ );
45
+ if (!size) break;
46
+ count += size;
47
+ }
48
+ const after = fs.fstatSync(descriptor, { bigint: true });
49
+ requireValue(
50
+ count === Number(before.size) &&
51
+ ["dev", "ino", "size", "mtimeNs", "ctimeNs"].every(
52
+ (key) => before[key] === after[key],
53
+ ),
54
+ "input changed during read",
55
+ );
56
+ return bytes.subarray(0, count);
57
+ } finally {
58
+ fs.closeSync(descriptor);
59
+ }
60
+ }
61
+
62
+ export function canonicalDirectory(directory) {
63
+ const absolute = path.resolve(directory);
64
+ const canonical = (fs.realpathSync.native || fs.realpathSync)(absolute);
65
+ const same =
66
+ process.platform === "win32"
67
+ ? canonical.toLowerCase() === absolute.toLowerCase()
68
+ : canonical === absolute;
69
+ const stat = fs.lstatSync(absolute);
70
+ requireValue(
71
+ same && stat.isDirectory() && !stat.isSymbolicLink(),
72
+ "task directory must be canonical and unaliased",
73
+ );
74
+ return canonical;
75
+ }
76
+
77
+ /** Trusted preparation only: a seed contains no answer and never overwrites
78
+ * a project file. Existing source paths are not passed to this helper. */
79
+ export function seedVerify01Deliverables(directory, expectedFiles, budget) {
80
+ const root = canonicalDirectory(directory);
81
+ requireValue(
82
+ Array.isArray(expectedFiles) &&
83
+ expectedFiles.length > 0 &&
84
+ new Set(expectedFiles).size === expectedFiles.length,
85
+ "deliverable paths must be distinct",
86
+ );
87
+ expectedFiles.forEach(relativeFile);
88
+ const seeds = [];
89
+ for (const relative of expectedFiles) {
90
+ budget.remainingMs("deliverable-preparation");
91
+ let current = root;
92
+ for (const part of relative.split("/").slice(0, -1)) {
93
+ current = path.join(current, part);
94
+ within(root, current);
95
+ try {
96
+ fs.mkdirSync(current, { mode: 0o700 });
97
+ } catch (error) {
98
+ if (error.code !== "EEXIST") throw error;
99
+ }
100
+ canonicalDirectory(current);
101
+ }
102
+ const target = path.join(root, relative);
103
+ within(root, target);
104
+ const fd = fs.openSync(
105
+ target,
106
+ fs.constants.O_WRONLY |
107
+ fs.constants.O_CREAT |
108
+ fs.constants.O_EXCL |
109
+ (fs.constants.O_NOFOLLOW || 0),
110
+ 0o600,
111
+ );
112
+ try {
113
+ const stat = fs.fstatSync(fd);
114
+ requireValue(
115
+ stat.isFile() && stat.nlink === 1 && stat.size === 0,
116
+ "seed must be an empty unaliased regular file",
117
+ );
118
+ regularPath(root, relative);
119
+ const named = fs.lstatSync(target);
120
+ requireValue(
121
+ named.dev === stat.dev && named.ino === stat.ino,
122
+ "seed path changed identity during preparation",
123
+ );
124
+ canonicalDirectory(path.dirname(target));
125
+ seeds.push(
126
+ Object.freeze({
127
+ path: relative,
128
+ before: null,
129
+ origin: "trusted-empty-deliverable-preparation",
130
+ digest: EMPTY_DELIVERABLE_DIGEST,
131
+ bytes: 0,
132
+ requestedMode: 0o600,
133
+ mode: stat.mode & 0o777,
134
+ preparedAt: new Date().toISOString(),
135
+ }),
136
+ );
137
+ } finally {
138
+ fs.closeSync(fd);
139
+ }
140
+ }
141
+ return Object.freeze(seeds);
142
+ }
143
+
144
+ export function within(root, file) {
145
+ const relative = path.relative(root, file);
146
+ requireValue(
147
+ relative &&
148
+ relative !== ".." &&
149
+ !relative.startsWith(`..${path.sep}`) &&
150
+ !path.isAbsolute(relative),
151
+ "path escapes its declared root",
152
+ );
153
+ }
154
+
155
+ export function regularPath(root, relative) {
156
+ relativeFile(relative);
157
+ const file = path.join(root, relative);
158
+ within(root, file);
159
+ let current = root;
160
+ for (const segment of relative.split("/")) {
161
+ current = path.join(current, segment);
162
+ requireValue(
163
+ !fs.lstatSync(current).isSymbolicLink(),
164
+ "review/project paths must not traverse links",
165
+ );
166
+ }
167
+ requireValue(
168
+ fs.lstatSync(file).isFile(),
169
+ "review/project artifact must be a regular file",
170
+ );
171
+ return file;
172
+ }
173
+
174
+ export function snapshotVerify01Workspace(directory, budget, stage) {
175
+ const files = new Map();
176
+ let total = 0;
177
+ let dependencyBytes = 0;
178
+ let dependencyFiles = 0;
179
+ const dependencyHash = createHash("sha256");
180
+ const buffer = Buffer.alloc(64 * 1024);
181
+ const visit = (current) => {
182
+ for (const entry of fs
183
+ .readdirSync(current, { withFileTypes: true })
184
+ .sort((a, b) => a.name.localeCompare(b.name, "en"))) {
185
+ budget.remainingMs(stage);
186
+ const full = path.join(current, entry.name);
187
+ const relative = path.relative(directory, full).split(path.sep).join("/");
188
+ if (entry.isDirectory()) visit(full);
189
+ else {
190
+ requireValue(
191
+ entry.isFile() || entry.isSymbolicLink(),
192
+ "task snapshot contains an unsupported filesystem object",
193
+ );
194
+ // Preserve link identities without following them into another root.
195
+ const dependency = relative.split("/").includes("node_modules");
196
+ if (dependency && entry.isSymbolicLink()) {
197
+ // A dependency linked outside the isolated workspace cannot be
198
+ // fingerprinted by this capture contract; never silently omit it.
199
+ within(directory, fs.realpathSync(full));
200
+ }
201
+ let bytes = entry.isSymbolicLink()
202
+ ? Buffer.from(fs.readlinkSync(full))
203
+ : dependency
204
+ ? null
205
+ : readBytes(full);
206
+ let digest, size;
207
+ if (dependency && bytes === null) {
208
+ const hash = createHash("sha256");
209
+ const fd = fs.openSync(full, "r");
210
+ size = 0;
211
+ try {
212
+ let count;
213
+ while (
214
+ (count = fs.readSync(fd, buffer, 0, buffer.length, null)) > 0
215
+ ) {
216
+ budget.remainingMs(stage);
217
+ size += count;
218
+ requireValue(
219
+ dependencyBytes + size <= 16 * 1024 ** 3,
220
+ "dependency fingerprint exceeds 16 GiB",
221
+ );
222
+ hash.update(buffer.subarray(0, count));
223
+ }
224
+ } finally {
225
+ fs.closeSync(fd);
226
+ }
227
+ digest = `sha256:${hash.digest("hex")}`;
228
+ } else {
229
+ size = bytes.length;
230
+ digest = evalDigest(bytes);
231
+ }
232
+ if (dependency) {
233
+ dependencyBytes += size;
234
+ dependencyFiles++;
235
+ bytes = null;
236
+ } else total += size;
237
+ requireValue(
238
+ total <= MAX_SNAPSHOT_BYTES &&
239
+ files.size - dependencyFiles < 100000 &&
240
+ dependencyFiles <= 1000000,
241
+ "task snapshot exceeds its capture bound",
242
+ );
243
+ const value = {
244
+ type: entry.isSymbolicLink() ? "link" : "file",
245
+ mode: fs.lstatSync(full).mode & 0o777,
246
+ bytes,
247
+ size,
248
+ digest,
249
+ dependency,
250
+ };
251
+ files.set(relative, value);
252
+ if (dependency)
253
+ dependencyHash.update(
254
+ JSON.stringify([relative, value.type, value.mode, size, digest]) +
255
+ "\n",
256
+ );
257
+ }
258
+ }
259
+ };
260
+ visit(directory);
261
+ files.dependencyBoundary = {
262
+ contract:
263
+ "all node_modules files and link identities streamed with SHA-256; links never followed; dependency bodies omitted; every change rejected",
264
+ files: dependencyFiles,
265
+ bytes: dependencyBytes,
266
+ digest: `sha256:${dependencyHash.digest("hex")}`,
267
+ };
268
+ return files;
269
+ }
270
+
271
+ export function diffVerify01Workspace(before, after) {
272
+ const result = [];
273
+ let total = 0;
274
+ for (const file of [...new Set([...before.keys(), ...after.keys()])].sort()) {
275
+ const old = before.get(file),
276
+ next = after.get(file);
277
+ if (
278
+ old?.digest === next?.digest &&
279
+ old?.type === next?.type &&
280
+ old?.mode === next?.mode
281
+ )
282
+ continue;
283
+ total += (old?.bytes?.length || 0) + (next?.bytes?.length || 0);
284
+ requireValue(
285
+ total <= MAX_DIFF_BYTES,
286
+ "task diff exceeds 32 MiB; preserve workspace for independent inspection",
287
+ );
288
+ const describe = (value) =>
289
+ value
290
+ ? {
291
+ type: value.type,
292
+ mode: value.mode,
293
+ digest: value.digest,
294
+ bytes: value.size,
295
+ dependency: value.dependency,
296
+ bytesBase64: value.bytes?.toString("base64") ?? null,
297
+ }
298
+ : null;
299
+ result.push({ path: file, before: describe(old), after: describe(next) });
300
+ }
301
+ return result;
302
+ }
@@ -27,6 +27,24 @@ export function readExecutionLocationStorageFailure(stderr) {
27
27
  return match ? `${match[1]}${match[2] || ""}` : null;
28
28
  }
29
29
 
30
+ export function readExecutionLocationStorageLaunchFailure(stderr) {
31
+ const match = String(stderr || "")
32
+ .slice(0, MAX_DIAGNOSTIC_CHARS)
33
+ .match(
34
+ /\[windows-acl-launch:(inspect|repair|preflight):(spawn|timeout):(startup|initialize|traversal|lookup|repair-lock|repair-inspect|repair-write|verify):(EACCES|EPERM|ENOENT|ETIMEDOUT|EINVAL|ENOSYS|ENOMEM|EMFILE|ENFILE|ENOBUFS|EBUSY|UNKNOWN):(unknown|-?(?:0|[1-9][0-9]{0,4})):(spawnSync|spawn|unknown)\]/u,
35
+ );
36
+ if (!match) return null;
37
+ const [, operation, failureStage, progressStage, code, rawErrno, syscall] =
38
+ match;
39
+ const errno = rawErrno === "unknown" ? null : Number(rawErrno);
40
+ if (
41
+ (errno !== null && Math.abs(errno) > 65535) ||
42
+ (failureStage === "timeout") !== (code === "ETIMEDOUT")
43
+ )
44
+ return null;
45
+ return { operation, failureStage, progressStage, code, errno, syscall };
46
+ }
47
+
30
48
  export function executionLocationFailureSite(error) {
31
49
  const stack = String(error?.stack || "").slice(0, MAX_DIAGNOSTIC_CHARS);
32
50
  for (const frame of stack.split(/\r?\n/u).slice(1)) {
@@ -7,6 +7,7 @@ import { TextDecoder } from "node:util";
7
7
  import {
8
8
  readExecutionLocationFailureSite,
9
9
  readExecutionLocationStorageFailure,
10
+ readExecutionLocationStorageLaunchFailure,
10
11
  } from "./execution-location-failure-site.js";
11
12
  import {
12
13
  EXECUTION_LOCATION_TARGET_ATTESTATION_SCHEMA,
@@ -1039,6 +1040,10 @@ function targetProcessFailure(result) {
1039
1040
  error.failureCategory = failureCategory;
1040
1041
  if (failureSite) error.failureSite = failureSite;
1041
1042
  if (storageFailure) error.storageFailure = storageFailure;
1043
+ const storageLaunchFailure = readExecutionLocationStorageLaunchFailure(
1044
+ result.stderr,
1045
+ );
1046
+ if (storageLaunchFailure) error.storageLaunchFailure = storageLaunchFailure;
1042
1047
  return error;
1043
1048
  }
1044
1049
 
@@ -1108,6 +1113,11 @@ function runTargetCommand(profile, cliArgs, deps = {}, options = {}) {
1108
1113
  error.failureCategory = failureCategory;
1109
1114
  if (failureSite) error.failureSite = failureSite;
1110
1115
  if (storageFailure) error.storageFailure = storageFailure;
1116
+ const storageLaunchFailure = readExecutionLocationStorageLaunchFailure(
1117
+ result?.stderr,
1118
+ );
1119
+ if (storageLaunchFailure)
1120
+ error.storageLaunchFailure = storageLaunchFailure;
1111
1121
  throw error;
1112
1122
  }
1113
1123
  return options.interactive ? null : result.stdout;
@@ -1,13 +1,141 @@
1
1
  import { formatProviderResponseError } from "./provider-http-error.js";
2
+ import { estimateCost } from "./llm-pricing.js";
2
3
 
3
4
  // Reasoning models spend the same output allowance on thinking before the
4
5
  // final answer. A 16-token probe can therefore receive HTTP 200 with only
5
6
  // reasoning_content and finish_reason=length from an otherwise usable model.
6
7
  const PROBE_OUTPUT_TOKENS = 1024;
8
+ export const LLM_PROBE_SCHEMA = "chainlesschain.llm-connection-probe/v1";
9
+
10
+ const count = (value) => Number.isSafeInteger(value) && value >= 0;
11
+
12
+ /** Preserve missing/malformed usage as unknown, including cached prompt tokens. */
13
+ export function normalizeLlmProbeUsage(provider, data) {
14
+ if (!data || typeof data !== "object" || Array.isArray(data)) return null;
15
+ let usage;
16
+ if (provider === "ollama") {
17
+ usage = {
18
+ input_tokens: data.prompt_eval_count,
19
+ output_tokens: data.eval_count,
20
+ };
21
+ } else if (provider === "anthropic") {
22
+ usage = data.usage;
23
+ } else if (provider === "gemini") {
24
+ const raw = data.usageMetadata;
25
+ if (
26
+ !raw ||
27
+ !count(raw.candidatesTokenCount) ||
28
+ !count(raw.thoughtsTokenCount === undefined ? 0 : raw.thoughtsTokenCount)
29
+ )
30
+ return null;
31
+ const cached =
32
+ raw.cachedContentTokenCount === undefined
33
+ ? 0
34
+ : raw.cachedContentTokenCount;
35
+ if (
36
+ !count(raw.promptTokenCount) ||
37
+ !count(cached) ||
38
+ cached > raw.promptTokenCount
39
+ )
40
+ return null;
41
+ usage = {
42
+ input_tokens: raw.promptTokenCount - cached,
43
+ output_tokens: raw.candidatesTokenCount + (raw.thoughtsTokenCount ?? 0),
44
+ cache_read_input_tokens: cached,
45
+ };
46
+ } else {
47
+ const raw = data.usage;
48
+ if (!raw || !count(raw.prompt_tokens) || !count(raw.completion_tokens))
49
+ return null;
50
+ const detailed = raw.prompt_tokens_details?.cached_tokens;
51
+ const legacy = raw.prompt_cache_hit_tokens;
52
+ const cached =
53
+ detailed === undefined ? (legacy === undefined ? 0 : legacy) : detailed;
54
+ if (
55
+ !count(cached) ||
56
+ cached > raw.prompt_tokens ||
57
+ (detailed !== undefined && legacy !== undefined && detailed !== legacy)
58
+ )
59
+ return null;
60
+ usage = {
61
+ input_tokens: raw.prompt_tokens - cached,
62
+ output_tokens: raw.completion_tokens,
63
+ cache_read_input_tokens: cached,
64
+ };
65
+ }
66
+ if (!usage || typeof usage !== "object" || Array.isArray(usage)) return null;
67
+ const normalized = {
68
+ input_tokens: usage.input_tokens,
69
+ output_tokens: usage.output_tokens,
70
+ cache_read_input_tokens:
71
+ usage.cache_read_input_tokens === undefined
72
+ ? 0
73
+ : usage.cache_read_input_tokens,
74
+ cache_creation_input_tokens:
75
+ usage.cache_creation_input_tokens === undefined
76
+ ? 0
77
+ : usage.cache_creation_input_tokens,
78
+ };
79
+ return Object.values(normalized).every(count) ? normalized : null;
80
+ }
81
+
82
+ export function priceLlmProbeUsage(target, usage) {
83
+ if (
84
+ !usage ||
85
+ ![
86
+ usage.input_tokens,
87
+ usage.output_tokens,
88
+ usage.cache_read_input_tokens,
89
+ usage.cache_creation_input_tokens,
90
+ ].every(count)
91
+ )
92
+ return null;
93
+ const estimate = estimateCost({
94
+ provider: target.provider,
95
+ model: target.model,
96
+ inputTokens: usage.input_tokens,
97
+ outputTokens: usage.output_tokens,
98
+ cacheReadTokens: usage.cache_read_input_tokens,
99
+ cacheCreationTokens: usage.cache_creation_input_tokens,
100
+ });
101
+ return estimate.matched && Number.isFinite(estimate.totalCost)
102
+ ? estimate.totalCost
103
+ : null;
104
+ }
105
+
106
+ export function llmProbeReceipt(
107
+ target,
108
+ { ok = false, reply = null, usage = null } = {},
109
+ ) {
110
+ const normalizedUsage =
111
+ usage === null
112
+ ? null
113
+ : {
114
+ input_tokens: usage.input_tokens,
115
+ output_tokens: usage.output_tokens,
116
+ cache_read_input_tokens: usage.cache_read_input_tokens,
117
+ cache_creation_input_tokens: usage.cache_creation_input_tokens,
118
+ };
119
+ return {
120
+ schema: LLM_PROBE_SCHEMA,
121
+ ok,
122
+ provider: target.provider,
123
+ model: target.model,
124
+ reply:
125
+ target.apiKey && typeof reply === "string"
126
+ ? reply.replaceAll(target.apiKey, "[REDACTED]")
127
+ : reply,
128
+ usage: normalizedUsage,
129
+ totalCostUsd: priceLlmProbeUsage(target, normalizedUsage),
130
+ currency: "USD",
131
+ costBasis: "token-estimate",
132
+ billingVerified: false,
133
+ };
134
+ }
7
135
 
8
136
  export async function probeLlmConnection(
9
137
  target,
10
- { fetchImpl = fetch, timeoutMs = 20_000 } = {},
138
+ { fetchImpl = fetch, timeoutMs = 20_000, includeUsage = false } = {},
11
139
  ) {
12
140
  const base = target.baseUrl.replace(/\/+$/, "");
13
141
  const headers = { "Content-Type": "application/json" };
@@ -50,6 +178,7 @@ export async function probeLlmConnection(
50
178
  }
51
179
  const controller = new AbortController();
52
180
  const timer = setTimeout(() => controller.abort(), timeoutMs);
181
+ let usage = null;
53
182
  try {
54
183
  const response = await fetchImpl(url, {
55
184
  method: "POST",
@@ -60,9 +189,12 @@ export async function probeLlmConnection(
60
189
  });
61
190
  if (!response.ok)
62
191
  throw new Error(
63
- await formatProviderResponseError(target.provider, response),
192
+ await formatProviderResponseError(target.provider, response, {
193
+ secrets: [target.apiKey],
194
+ }),
64
195
  );
65
196
  const data = await response.json();
197
+ usage = normalizeLlmProbeUsage(target.provider, data);
66
198
  const text =
67
199
  target.provider === "ollama"
68
200
  ? data.response
@@ -91,11 +223,20 @@ export async function probeLlmConnection(
91
223
  "The endpoint returned no model text; check the protocol and model",
92
224
  );
93
225
  }
94
- return text.trim().slice(0, 100);
226
+ const reply = (
227
+ target.apiKey ? text.replaceAll(target.apiKey, "[REDACTED]") : text
228
+ )
229
+ .trim()
230
+ .slice(0, 100);
231
+ return includeUsage
232
+ ? llmProbeReceipt(target, { ok: true, reply, usage })
233
+ : reply;
95
234
  } catch (error) {
96
- if (controller.signal.aborted)
97
- throw new Error(`Connection test timed out after ${timeoutMs / 1000}s`);
98
- throw error;
235
+ const failure = controller.signal.aborted
236
+ ? new Error(`Connection test timed out after ${timeoutMs / 1000}s`)
237
+ : error;
238
+ if (includeUsage) failure.probe = llmProbeReceipt(target, { usage });
239
+ throw failure;
99
240
  } finally {
100
241
  clearTimeout(timer);
101
242
  }
@@ -216,13 +216,18 @@ export function normalizePricingTerms(value) {
216
216
  const allowed = new Set([
217
217
  "cacheReadMultiplier",
218
218
  "cacheWriteMultiplier",
219
+ "cacheWrite1hMultiplier",
219
220
  "longContext",
220
221
  "serviceMultipliers",
221
222
  ]);
222
223
  if (!object(value) || Reflect.ownKeys(value).some((key) => !allowed.has(key)))
223
224
  fail();
224
225
  const result = {};
225
- for (const key of ["cacheReadMultiplier", "cacheWriteMultiplier"]) {
226
+ for (const key of [
227
+ "cacheReadMultiplier",
228
+ "cacheWriteMultiplier",
229
+ "cacheWrite1hMultiplier",
230
+ ]) {
226
231
  if (!Object.hasOwn(value, key)) continue;
227
232
  if (!finite(value[key])) fail();
228
233
  result[key] = value[key];
@@ -289,8 +294,15 @@ export function lookupRate(provider, model, table = PRICE_TABLE) {
289
294
  // An unrecognized new generation must not inherit an older family price.
290
295
  // Explicit operator overrides remain authoritative.
291
296
  if (
292
- ["opus", "sonnet"].includes(e.match) &&
293
- Number(/^claude-(?:opus|sonnet)-(\d+)(?:[.-]|$)/u.exec(m)?.[1]) >= 5 &&
297
+ e.match === "haiku" &&
298
+ /(?:^|[.:/])(?:claude-)?haiku-(?:[5-9]|\d{2,})(?:[.-]|$)/u.test(m) &&
299
+ !e.explicitOverride
300
+ )
301
+ continue;
302
+ if (
303
+ ["opus", "sonnet", "haiku"].includes(e.match) &&
304
+ Number(/^claude-(?:opus|sonnet|haiku)-(\d+)(?:[.-]|$)/u.exec(m)?.[1]) >=
305
+ 5 &&
294
306
  !e.explicitOverride
295
307
  )
296
308
  continue;
@@ -337,18 +349,42 @@ export function estimateCost({
337
349
  outputTokens = 0,
338
350
  cacheReadTokens = 0,
339
351
  cacheCreationTokens = 0,
352
+ cacheCreation5mTokens,
353
+ cacheCreation1hTokens,
354
+ cacheCreationInvalid = false,
355
+ pricingContextInvalid = false,
340
356
  requestInputTokens,
341
357
  serviceTier = "standard",
342
358
  regionalProcessing = false,
343
359
  table,
344
360
  } = {}) {
345
361
  const rate = lookupRate(provider, model, table);
362
+ const splitPresent =
363
+ cacheCreation5mTokens != null || cacheCreation1hTokens != null;
364
+ const splitValid =
365
+ splitPresent &&
366
+ Number.isSafeInteger(cacheCreation5mTokens) &&
367
+ cacheCreation5mTokens >= 0 &&
368
+ Number.isSafeInteger(cacheCreation1hTokens) &&
369
+ cacheCreation1hTokens >= 0 &&
370
+ cacheCreation5mTokens + cacheCreation1hTokens === cacheCreationTokens;
371
+ const missingCacheEvidence =
372
+ cacheCreationInvalid ||
373
+ (splitPresent && !splitValid) ||
374
+ (rate?.terms?.cacheWrite1hMultiplier != null &&
375
+ cacheCreationTokens > 0 &&
376
+ !splitValid);
346
377
  const tierMultiplier = rate?.terms?.serviceMultipliers
347
378
  ? Object.hasOwn(rate.terms.serviceMultipliers, serviceTier)
348
379
  ? rate.terms.serviceMultipliers[serviceTier]
349
380
  : null
350
381
  : 1;
351
- if (!rate || tierMultiplier == null) {
382
+ if (
383
+ !rate ||
384
+ tierMultiplier == null ||
385
+ missingCacheEvidence ||
386
+ pricingContextInvalid
387
+ ) {
352
388
  return {
353
389
  inputCost: 0,
354
390
  outputCost: 0,
@@ -384,9 +420,14 @@ export function estimateCost({
384
420
  inputMultiplier *
385
421
  multiplier;
386
422
  const cacheCreationCost =
387
- (Number(cacheCreationTokens) / 1e6) *
423
+ ((splitValid
424
+ ? cacheCreation5mTokens *
425
+ (rate.terms?.cacheWriteMultiplier ?? CACHE_WRITE_MULTIPLIER) +
426
+ cacheCreation1hTokens * (rate.terms?.cacheWrite1hMultiplier ?? 2)
427
+ : Number(cacheCreationTokens) *
428
+ (rate.terms?.cacheWriteMultiplier ?? CACHE_WRITE_MULTIPLIER)) /
429
+ 1e6) *
388
430
  rate.in *
389
- (rate.terms?.cacheWriteMultiplier ?? CACHE_WRITE_MULTIPLIER) *
390
431
  inputMultiplier *
391
432
  multiplier;
392
433
  return {
@@ -419,6 +460,15 @@ export function priceRollup(aggregate, { table } = {}) {
419
460
  outputTokens: row.outputTokens,
420
461
  cacheReadTokens: row.cacheReadTokens,
421
462
  cacheCreationTokens: row.cacheCreationTokens,
463
+ cacheCreation5mTokens: row.cacheCreation5mTokens,
464
+ cacheCreation1hTokens: row.cacheCreation1hTokens,
465
+ cacheCreationInvalid: row.cacheCreationInvalid,
466
+ pricingContextInvalid:
467
+ row.pricingContextInvalid === true ||
468
+ (String(row.provider).toLowerCase() === "anthropic" &&
469
+ String(row.model).toLowerCase() === "claude-haiku-5-5" &&
470
+ row.regionalProcessing == null &&
471
+ row.regional_processing == null),
422
472
  serviceTier: row.serviceTier ?? row.service_tier ?? "standard",
423
473
  regionalProcessing:
424
474
  row.regionalProcessing ?? row.regional_processing ?? false,
@@ -479,7 +529,11 @@ export function priceRollup(aggregate, { table } = {}) {
479
529
  for (const row of byModel) {
480
530
  if (row.matched) {
481
531
  totalCost += row.cost;
482
- } else if (row.totalTokens > 0) {
532
+ } else if (
533
+ row.totalTokens > 0 ||
534
+ row.cacheReadTokens > 0 ||
535
+ row.cacheCreationTokens > 0
536
+ ) {
483
537
  unpriced.push({
484
538
  provider: row.provider,
485
539
  model: row.model,