chainlesschain 0.166.76 → 0.166.78

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 (230) hide show
  1. package/README.md +19 -8
  2. package/completions/_cc +1 -1
  3. package/completions/cc.bash +1 -1
  4. package/completions/cc.fish +1 -1
  5. package/completions/cc.ps1 +1 -1
  6. package/package.json +1 -1
  7. package/src/assets/linux-subreaper/linux-arm64/manifest.json +10 -0
  8. package/src/assets/linux-subreaper/linux-arm64/supervisor +0 -0
  9. package/src/assets/linux-subreaper/linux-x64/manifest.json +10 -0
  10. package/src/assets/linux-subreaper/linux-x64/supervisor +0 -0
  11. package/src/assets/web-panel/assets/{AIOps-CNaejClV.js → AIOps-DSyZEY2G.js} +1 -1
  12. package/src/assets/web-panel/assets/{ActionButton-CF_CVKT_.js → ActionButton-DhNyZ577.js} +1 -1
  13. package/src/assets/web-panel/assets/{Analytics-a3Z6J7gv.js → Analytics-HMMpxmyi.js} +3 -3
  14. package/src/assets/web-panel/assets/{AppLayout-BFtWEnct.js → AppLayout-CwKMM5Ie.js} +5 -5
  15. package/src/assets/web-panel/assets/{Artifacts-BQ8oeMvX.js → Artifacts-CNzDmph7.js} +1 -1
  16. package/src/assets/web-panel/assets/{Audit-NOo9bmgk.js → Audit-DxWpUW3V.js} +1 -1
  17. package/src/assets/web-panel/assets/{BackgroundAgents-QRc7F3Tp.js → BackgroundAgents-C1R2ST-P.js} +1 -1
  18. package/src/assets/web-panel/assets/{Backup-UlVgLn2P.js → Backup-B6biTaEV.js} +1 -1
  19. package/src/assets/web-panel/assets/{BaseInput-BER9LJAr.js → BaseInput-CVnkD2Z5.js} +1 -1
  20. package/src/assets/web-panel/assets/{Chat-Z8z2Fdfz.js → Chat-Dbewl4Je.js} +6 -6
  21. package/src/assets/web-panel/assets/{ChatBubbleRenderer-DdmuBrdQ.js → ChatBubbleRenderer-DVZ6SwC5.js} +1 -1
  22. package/src/assets/web-panel/assets/{Checkbox-CXPgyB8L.js → Checkbox-BqqiF1JE.js} +1 -1
  23. package/src/assets/web-panel/assets/{Codegen-D1vOsLJ7.js → Codegen-BVMkGumc.js} +1 -1
  24. package/src/assets/web-panel/assets/{Col-ucLnUJC7.js → Col-DmiRHy96.js} +1 -1
  25. package/src/assets/web-panel/assets/{Community-COsV9n9t.js → Community-BDlpygqA.js} +1 -1
  26. package/src/assets/web-panel/assets/{Compact-D0EkBEYh.js → Compact-B2NME_m-.js} +1 -1
  27. package/src/assets/web-panel/assets/{Compliance-C8w9SUjt.js → Compliance-BlzDLE-R.js} +1 -1
  28. package/src/assets/web-panel/assets/{Cowork-CmVaKEJS.js → Cowork-C8raPybB.js} +3 -3
  29. package/src/assets/web-panel/assets/{Cron-B_FiMMV2.js → Cron-DA8Py0zP.js} +2 -2
  30. package/src/assets/web-panel/assets/{Crosschain-ByO3YL8N.js → Crosschain-DU2XyHqB.js} +1 -1
  31. package/src/assets/web-panel/assets/{DID-DwpsLM9r.js → DID-Df098fT_.js} +2 -2
  32. package/src/assets/web-panel/assets/{Dashboard-B_8IUvM_.js → Dashboard-D1rT702x.js} +2 -2
  33. package/src/assets/web-panel/assets/{Dropdown-Bo6WQkuX.js → Dropdown-BweXGo1O.js} +1 -1
  34. package/src/assets/web-panel/assets/{EmailListRenderer-C9LiQesx.js → EmailListRenderer-B9ShbgJH.js} +1 -1
  35. package/src/assets/web-panel/assets/EvolutionSettings-D75_iBoc.js +1 -0
  36. package/src/assets/web-panel/assets/{FamilyGuardDashboard-Dst6VUnO.js → FamilyGuardDashboard-DrznZFVs.js} +1 -1
  37. package/src/assets/web-panel/assets/{Federation-Ci7CoLkJ.js → Federation-DQZ2adIA.js} +1 -1
  38. package/src/assets/web-panel/assets/{FormItemContext-bdDyUhUM.js → FormItemContext-DN30Dowh.js} +1 -1
  39. package/src/assets/web-panel/assets/{GenericCardRenderer-CrRwOUVi.js → GenericCardRenderer-DRdt0j1e.js} +1 -1
  40. package/src/assets/web-panel/assets/{Git-Dis8h-Z-.js → Git-wwRgStzk.js} +2 -2
  41. package/src/assets/web-panel/assets/{Governance-DX7OH5w2.js → Governance-CI4Uw0Nh.js} +1 -1
  42. package/src/assets/web-panel/assets/{Inference-Cavv_Q_Z.js → Inference-5TuE2AJI.js} +1 -1
  43. package/src/assets/web-panel/assets/{KnowledgeGraph-Cck8tnZn.js → KnowledgeGraph-oXyvmFSR.js} +1 -1
  44. package/src/assets/web-panel/assets/{Logs-BQt3aGMu.js → Logs-ewudSWuv.js} +2 -2
  45. package/src/assets/web-panel/assets/MarkdownRenderer-Cz5nyufm.js +1 -0
  46. package/src/assets/web-panel/assets/{Marketplace-CdmAKNSN.js → Marketplace-DcZeWFrs.js} +1 -1
  47. package/src/assets/web-panel/assets/{McpTools-BUlJdyPY.js → McpTools-BcV9p1RS.js} +3 -3
  48. package/src/assets/web-panel/assets/{Memory-DQRTQDr-.js → Memory-CMhYvugt.js} +2 -2
  49. package/src/assets/web-panel/assets/{MobileBridge-C0dnxgsl.js → MobileBridge-5RP2uwvT.js} +1 -1
  50. package/src/assets/web-panel/assets/{MobileProjects-DQ5Gy7fa.js → MobileProjects-BIuM9Ze4.js} +1 -1
  51. package/src/assets/web-panel/assets/{Mtc-Xl7u2isS.js → Mtc-DmBszTDe.js} +5 -5
  52. package/src/assets/web-panel/assets/{MtcAudit-C3KX0574.js → MtcAudit-Czdp5ZGt.js} +2 -2
  53. package/src/assets/web-panel/assets/{Multisig-CHEhfkn8.js → Multisig-DRWUuNr-.js} +3 -3
  54. package/src/assets/web-panel/assets/{NLProgramming-Ce38mH-8.js → NLProgramming-IRQQN0-c.js} +1 -1
  55. package/src/assets/web-panel/assets/{Notes-C7nuTd7c.js → Notes-CGhD1lW9.js} +4 -4
  56. package/src/assets/web-panel/assets/{NotificationSettings-BcoEcyq8.js → NotificationSettings-BtyPgQAh.js} +1 -1
  57. package/src/assets/web-panel/assets/{OrderTableRenderer-D-t5hKkx.js → OrderTableRenderer-yUaqwCty.js} +1 -1
  58. package/src/assets/web-panel/assets/{Organization-C_BGi4xi.js → Organization-C3kTVn5i.js} +4 -4
  59. package/src/assets/web-panel/assets/{Overflow-BodhraDq.js → Overflow-C2-0iZhq.js} +1 -1
  60. package/src/assets/web-panel/assets/{P2P-BTa3sAIy.js → P2P-CISoEUxA.js} +2 -2
  61. package/src/assets/web-panel/assets/{PdhVaultBrowser-BjZslP9T.js → PdhVaultBrowser-NfTVtvKQ.js} +5 -5
  62. package/src/assets/web-panel/assets/{Permissions-u3UDzGef.js → Permissions-CfK0jJhm.js} +3 -3
  63. package/src/assets/web-panel/assets/{PersonalDataHub-Cb7ybv65.js → PersonalDataHub-OsVxxh_j.js} +4 -4
  64. package/src/assets/web-panel/assets/{Pipeline-CS24k-P7.js → Pipeline-DEmK_Ch2.js} +1 -1
  65. package/src/assets/web-panel/assets/{Privacy-Ddj6Kqs7.js → Privacy-D61s73b0.js} +1 -1
  66. package/src/assets/web-panel/assets/{ProjectInit-Bg5uQIgg.js → ProjectInit-DkLF5gHb.js} +2 -2
  67. package/src/assets/web-panel/assets/{ProjectSettings-AmPR8T12.js → ProjectSettings-BA7odTrI.js} +2 -2
  68. package/src/assets/web-panel/assets/{Projects-DGSbAyTK.js → Projects-CdI1GcAG.js} +1 -1
  69. package/src/assets/web-panel/assets/{Providers-Dc1C3lbB.js → Providers-D9BYyP1r.js} +1 -1
  70. package/src/assets/web-panel/assets/{QrScannerModal-Cv3HXpce.js → QrScannerModal-CXMItUDD.js} +1 -1
  71. package/src/assets/web-panel/assets/{QuickAsk-3dpbXARb.js → QuickAsk-8-tF9ffZ.js} +1 -1
  72. package/src/assets/web-panel/assets/{Recommend-5aGRVnJK.js → Recommend-C2QGWOSi.js} +1 -1
  73. package/src/assets/web-panel/assets/{RemoteSession-CTS2jx0p.js → RemoteSession-B1M_v1lx.js} +2 -2
  74. package/src/assets/web-panel/assets/{Reputation-BxaKI0hY.js → Reputation-D0WZHgv1.js} +1 -1
  75. package/src/assets/web-panel/assets/{Row-C23uQdwd.js → Row-D6nf9-c-.js} +1 -1
  76. package/src/assets/web-panel/assets/{RssFeed-ssX9YOhm.js → RssFeed-ClZ6M-mN.js} +3 -3
  77. package/src/assets/web-panel/assets/{Search-C24GogII.js → Search-ZWkt8vuO.js} +1 -1
  78. package/src/assets/web-panel/assets/{Security-DdAcGKkk.js → Security-BUlQut2m.js} +3 -3
  79. package/src/assets/web-panel/assets/{Services-D0dCiEuq.js → Services-Cd_3xJOc.js} +2 -2
  80. package/src/assets/web-panel/assets/{Skeleton-DEY44o0v.js → Skeleton-C8e2-cHW.js} +1 -1
  81. package/src/assets/web-panel/assets/Skills-DucVRJp1.js +1 -0
  82. package/src/assets/web-panel/assets/{Sla-B_bbo2vB.js → Sla-Csr5pUwI.js} +1 -1
  83. package/src/assets/web-panel/assets/SpeechSettings-CXvyaRAT.js +1 -0
  84. package/src/assets/web-panel/assets/{SyncSettings-CpIXql0Z.js → SyncSettings-KdsIcV5h.js} +2 -2
  85. package/src/assets/web-panel/assets/Tasks-B-eHmJm9.js +1 -0
  86. package/src/assets/web-panel/assets/{Templates-C_44nVPq.js → Templates-BglVeaLK.js} +1 -1
  87. package/src/assets/web-panel/assets/{Tenant-CyZ2ey2P.js → Tenant-BBbQ8qan.js} +1 -1
  88. package/src/assets/web-panel/assets/{Terminal-DwGNHWnp.js → Terminal-Ca_pCVBi.js} +2 -2
  89. package/src/assets/web-panel/assets/{TimelineRenderer-BTAHNkqU.js → TimelineRenderer-YD6XG_vZ.js} +1 -1
  90. package/src/assets/web-panel/assets/{Tokens-DCJWkUwc.js → Tokens-2lRoeVli.js} +1 -1
  91. package/src/assets/web-panel/assets/{Trigger-BCjDO9-E.js → Trigger-C-3XNAU9.js} +1 -1
  92. package/src/assets/web-panel/assets/{Trust-_YS8WbRb.js → Trust-k-1PxdLG.js} +1 -1
  93. package/src/assets/web-panel/assets/{UkeySign-m6R8xGq7.js → UkeySign-FG-qW646.js} +1 -1
  94. package/src/assets/web-panel/assets/{VideoEditing-xOfk29c4.js → VideoEditing-BNOe1cmd.js} +1 -1
  95. package/src/assets/web-panel/assets/{Wallet-B1Gw0awc.js → Wallet-D5C3i2Kw.js} +4 -4
  96. package/src/assets/web-panel/assets/{WebAuthn-CHK5ft18.js → WebAuthn-BOpztqd3.js} +4 -4
  97. package/src/assets/web-panel/assets/{WorkflowEditor-DEp1ukQQ.js → WorkflowEditor-BpVrpUEv.js} +1 -1
  98. package/src/assets/web-panel/assets/{chat-B2sFizun.js → chat-DIuMHb38.js} +1 -1
  99. package/src/assets/web-panel/assets/{colors-DJ17YV1E.js → colors-CTFJPyzQ.js} +1 -1
  100. package/src/assets/web-panel/assets/{compact-item-CBhJJgEC.js → compact-item-CONfmJcW.js} +1 -1
  101. package/src/assets/web-panel/assets/{createContext-BZkpvNJy.js → createContext-RkW5CRrz.js} +1 -1
  102. package/src/assets/web-panel/assets/devWarning-DaEBln_q.js +1 -0
  103. package/src/assets/web-panel/assets/{hasIn-C0ZKo6Ei.js → hasIn-CW4XOjDC.js} +1 -1
  104. package/src/assets/web-panel/assets/{index-Bc3vVG2X.js → index-7wMSBCU7.js} +1 -1
  105. package/src/assets/web-panel/assets/{index-vFMwiAN4.js → index-Akmg1WdH.js} +1 -1
  106. package/src/assets/web-panel/assets/{index-DOBXNMdh.js → index-B54qoVff.js} +1 -1
  107. package/src/assets/web-panel/assets/{index-DLo8Ls9u.js → index-B8r2t0Ch.js} +1 -1
  108. package/src/assets/web-panel/assets/{index-C7gv9dvb.js → index-B9XoBoty.js} +1 -1
  109. package/src/assets/web-panel/assets/{index-DHtpMr1G.js → index-B9aS2VLu.js} +1 -1
  110. package/src/assets/web-panel/assets/{index-Dxe0YlZe.js → index-BFs1Tznc.js} +1 -1
  111. package/src/assets/web-panel/assets/{index-DumLgj1t.js → index-BKgaRT0b.js} +1 -1
  112. package/src/assets/web-panel/assets/{index-BNp6HKFh.js → index-BM7bOUvu.js} +1 -1
  113. package/src/assets/web-panel/assets/{index-DM0rWF6z.js → index-BMg2JFmW.js} +1 -1
  114. package/src/assets/web-panel/assets/{index-4oULtRqE.js → index-BRZsPxNn.js} +1 -1
  115. package/src/assets/web-panel/assets/{index-LPPe0val.js → index-Bf19fKef.js} +1 -1
  116. package/src/assets/web-panel/assets/{index-Ctguam0K.js → index-BkAbfBF-.js} +1 -1
  117. package/src/assets/web-panel/assets/{index-DrU5xVpF.js → index-CBjb2A5R.js} +1 -1
  118. package/src/assets/web-panel/assets/{index-CCOr6Q27.js → index-CEZWQthY.js} +1 -1
  119. package/src/assets/web-panel/assets/{index-C9gYiACH.js → index-CFGLf88d.js} +1 -1
  120. package/src/assets/web-panel/assets/{index-CZW84cEf.js → index-CLUa68JH.js} +3 -3
  121. package/src/assets/web-panel/assets/{index-BoDUYyuo.js → index-CM2X25Er.js} +1 -1
  122. package/src/assets/web-panel/assets/{index-DyiCbHeL.js → index-CX4T2uKN.js} +1 -1
  123. package/src/assets/web-panel/assets/{index-CW5o1Gar.js → index-CixqfdRk.js} +1 -1
  124. package/src/assets/web-panel/assets/{index-5K2z_tgO.js → index-CkRojEip.js} +1 -1
  125. package/src/assets/web-panel/assets/{index-BOfPp5OV.js → index-Cvmc3f25.js} +1 -1
  126. package/src/assets/web-panel/assets/{index-CdxJm-HB.js → index-D-lpTPS8.js} +1 -1
  127. package/src/assets/web-panel/assets/{index-8ueG48gl.js → index-D59GbWCN.js} +1 -1
  128. package/src/assets/web-panel/assets/{index-BMxOoITz.js → index-DAESljiJ.js} +1 -1
  129. package/src/assets/web-panel/assets/{index-DLMr5KMd.js → index-DDHUx4Yz.js} +1 -1
  130. package/src/assets/web-panel/assets/index-DG1mcYTa.js +1 -0
  131. package/src/assets/web-panel/assets/{index-BGIvhCPl.js → index-DP5pPedy.js} +1 -1
  132. package/src/assets/web-panel/assets/index-DRs5Pe8u.js +1 -0
  133. package/src/assets/web-panel/assets/{index-DjdSFO0d.js → index-DSlXL6Ju.js} +1 -1
  134. package/src/assets/web-panel/assets/{index-Cn5UzvgR.js → index-DWCJnn2O.js} +1 -1
  135. package/src/assets/web-panel/assets/{index-Chct9tL8.js → index-DWY7YwDu.js} +1 -1
  136. package/src/assets/web-panel/assets/{index-BEnd5fiz.js → index-DZTwP364.js} +1 -1
  137. package/src/assets/web-panel/assets/{index-KzNhWykP.js → index-DidrMvOx.js} +1 -1
  138. package/src/assets/web-panel/assets/{index-BpyrhOeh.js → index-Dj3K5kHs.js} +1 -1
  139. package/src/assets/web-panel/assets/{index-CZlkPrxb.js → index-YaeGscSw.js} +1 -1
  140. package/src/assets/web-panel/assets/{index-Dfgxe-fw.js → index-YlMnFNOi.js} +1 -1
  141. package/src/assets/web-panel/assets/{index-IHgzfc1u.js → index-asWsB34i.js} +1 -1
  142. package/src/assets/web-panel/assets/{index-DJkoJzTU.js → index-gkjiFjQd.js} +1 -1
  143. package/src/assets/web-panel/assets/{initDefaultProps-Cqfoq0TJ.js → initDefaultProps-BOr4igh3.js} +1 -1
  144. package/src/assets/web-panel/assets/{motion-CIiVJHNu.js → motion-CK469n2j.js} +1 -1
  145. package/src/assets/web-panel/assets/{move-CFl1o_A8.js → move-DzjudlYQ.js} +1 -1
  146. package/src/assets/web-panel/assets/{mtc-parser-DYoCxcZ1.js → mtc-parser-BQaKUxC6.js} +1 -1
  147. package/src/assets/web-panel/assets/{omit-C1P2q5TY.js → omit-MciovCFD.js} +1 -1
  148. package/src/assets/web-panel/assets/{pickAttrs-BtTRpJtC.js → pickAttrs-DDPJ4zAz.js} +1 -1
  149. package/src/assets/web-panel/assets/{placementArrow-Cst2PcNM.js → placementArrow-Cznyb-jI.js} +1 -1
  150. package/src/assets/web-panel/assets/{responsiveObserve-CF5kalV2.js → responsiveObserve-AJK3SLzJ.js} +1 -1
  151. package/src/assets/web-panel/assets/{slide-CtHGqpXN.js → slide-CPQ28wu7.js} +1 -1
  152. package/src/assets/web-panel/assets/{statusUtils-N__biHXf.js → statusUtils-CFjzvqf_.js} +1 -1
  153. package/src/assets/web-panel/assets/{styleChecker-DR8V_H-i.js → styleChecker-BPyFfTuR.js} +1 -1
  154. package/src/assets/web-panel/assets/{useFlexGapSupport-D274dqun.js → useFlexGapSupport-Dq7N6R05.js} +1 -1
  155. package/src/assets/web-panel/assets/{useFs-BwHLYU5b.js → useFs-C3GS0uTc.js} +1 -1
  156. package/src/assets/web-panel/assets/{usePersonalDataHub-BiA-hVqt.js → usePersonalDataHub-BhgIVzP_.js} +1 -1
  157. package/src/assets/web-panel/assets/{vnode-Bugl94dy.js → vnode-4ZD9-MDr.js} +1 -1
  158. package/src/assets/web-panel/assets/{zoom-DEFl8GCu.js → zoom-Bx4MRVNW.js} +1 -1
  159. package/src/assets/web-panel/index.html +1 -1
  160. package/src/command-help-index.json +1 -1
  161. package/src/command-manifest.json +1 -1
  162. package/src/commands/checkpoint.js +42 -7
  163. package/src/commands/orchestrate.js +85 -25
  164. package/src/commands/session-location.js +5 -0
  165. package/src/commands/session-show.js +109 -1
  166. package/src/commands/session.js +26 -2
  167. package/src/commands/tokens.js +9 -4
  168. package/src/data/changelog.json +26 -0
  169. package/src/generated/cc-agent-protocol.schema.json +71 -0
  170. package/src/harness/jsonl-session-store.js +357 -114
  171. package/src/harness/mcp-client.js +44 -1
  172. package/src/lib/agent-router.js +35 -7
  173. package/src/lib/app-server/server.js +14 -0
  174. package/src/lib/background-agent-supervisor.js +14 -4
  175. package/src/lib/causal-observability.js +64 -1
  176. package/src/lib/checkpoint-summary-projection.js +98 -0
  177. package/src/lib/checkpoint-timeline-authority.js +15 -51
  178. package/src/lib/claude-code-bridge.js +302 -60
  179. package/src/lib/codex-app-server-adapter.js +161 -35
  180. package/src/lib/cost-budget.js +4 -0
  181. package/src/lib/decision-layer/providers.js +84 -9
  182. package/src/lib/decision-layer/runtime.js +86 -49
  183. package/src/lib/direct-model-usage.js +14 -3
  184. package/src/lib/doctor-checkup.js +31 -2
  185. package/src/lib/durable-security-store.js +6 -1
  186. package/src/lib/evolution/evolution-artifact-identity.js +21 -0
  187. package/src/lib/evolution/evolution-artifact-ports.js +5 -11
  188. package/src/lib/evolution/evolution-eval-cohort-receipt-reconciliation.js +389 -0
  189. package/src/lib/execution-location-failure-site.js +63 -0
  190. package/src/lib/execution-location-target.js +102 -8
  191. package/src/lib/external-agent-adapters.js +2 -0
  192. package/src/lib/image-file-boundary.js +154 -0
  193. package/src/lib/image-input.js +16 -3
  194. package/src/lib/llm-pricing.js +114 -8
  195. package/src/lib/mcp-call-ledger-store.js +7 -2
  196. package/src/lib/model-capabilities.js +21 -10
  197. package/src/lib/model-context-catalog.js +60 -1
  198. package/src/lib/openai-responses.js +7 -1
  199. package/src/lib/orchestrator.js +8 -2
  200. package/src/lib/process-execution-broker/index.js +93 -1
  201. package/src/lib/process-execution-broker/linux-subreaper-artifact.js +120 -0
  202. package/src/lib/process-execution-broker/linux-subreaper-helper.js +344 -0
  203. package/src/lib/process-execution-broker/linux-subreaper-process.js +326 -0
  204. package/src/lib/process-execution-broker/linux-subreaper-supervisor.c +360 -0
  205. package/src/lib/process-execution-broker/owned-posix-process-group-worker.mjs +131 -0
  206. package/src/lib/process-execution-broker/owned-posix-process-group.js +267 -0
  207. package/src/lib/process-execution-broker/process-ownership-journal.js +297 -0
  208. package/src/lib/process-execution-broker/process-ownership-quarantine.js +91 -0
  209. package/src/lib/runtime-usage-ledger.js +3 -0
  210. package/src/lib/secure-fs.js +158 -42
  211. package/src/lib/session-branch-history.js +240 -0
  212. package/src/lib/session-history-origins.js +285 -0
  213. package/src/lib/session-input-receipt.js +110 -0
  214. package/src/lib/session-resource-budget.js +8 -8
  215. package/src/lib/session-transcript-history.js +456 -0
  216. package/src/lib/session-transcript-page.js +164 -0
  217. package/src/lib/session-transcript-reference.js +38 -0
  218. package/src/lib/session-usage.js +8 -0
  219. package/src/lib/token-tracker.js +32 -54
  220. package/src/lib/usage-pricing-context.js +93 -0
  221. package/src/runtime/headless-runner.js +8 -0
  222. package/src/runtime/headless-stream.js +202 -4
  223. package/src/assets/web-panel/assets/EvolutionSettings-Pc1IpRfk.js +0 -1
  224. package/src/assets/web-panel/assets/MarkdownRenderer-BIUeeiVA.js +0 -1
  225. package/src/assets/web-panel/assets/Skills-CYt0Mu2W.js +0 -1
  226. package/src/assets/web-panel/assets/SpeechSettings-a2BBjtTL.js +0 -1
  227. package/src/assets/web-panel/assets/Tasks-BYQKU-GL.js +0 -1
  228. package/src/assets/web-panel/assets/devWarning-DZhu13vj.js +0 -1
  229. package/src/assets/web-panel/assets/index-C6iFyQYz.js +0 -1
  230. package/src/assets/web-panel/assets/index-CztThH9f.js +0 -1
@@ -39,21 +39,62 @@ function projectNotification(notification) {
39
39
  if (method === "turn/started") {
40
40
  return { method: "turn/started", params: { turn: params.turn } };
41
41
  }
42
+ const deltaKinds = {
43
+ "item/agentMessage/delta": "assistant_message",
44
+ "item/commandExecution/outputDelta": "tool",
45
+ "item/fileChange/outputDelta": "tool",
46
+ "item/reasoning/textDelta": "reasoning",
47
+ "item/reasoning/summaryTextDelta": "reasoning",
48
+ };
49
+ if (Object.hasOwn(deltaKinds, method)) {
50
+ return {
51
+ method: "item/delta",
52
+ params: {
53
+ item: {
54
+ id: params.itemId,
55
+ kind: deltaKinds[method],
56
+ status: "streaming",
57
+ delta: params.delta || "",
58
+ },
59
+ },
60
+ ...(method === "item/agentMessage/delta"
61
+ ? {
62
+ outputDelta: String(params.delta || ""),
63
+ outputItemId: params.itemId,
64
+ }
65
+ : {}),
66
+ };
67
+ }
68
+ if (method === "thread/tokenUsage/updated") {
69
+ return {
70
+ method: "thread/usage",
71
+ params: { tokenUsage: params.tokenUsage },
72
+ usage: params.tokenUsage?.last || null,
73
+ };
74
+ }
42
75
  if (["item/started", "item/updated", "item/completed"].includes(method)) {
43
76
  const item = params.item || {};
44
- const status = method === "item/completed" ? "completed" : "streaming";
77
+ const tool = item.type === "commandExecution" || item.type === "fileChange";
78
+ let status = method === "item/completed" ? "completed" : "streaming";
79
+ // item/completed means lifecycle closure, not successful execution. A
80
+ // declined approval still closes the tool item before interrupting the
81
+ // turn. Preserve that outcome and never infer success for unknown states.
82
+ if (method === "item/completed" && tool) {
83
+ status = ["completed", "failed", "declined"].includes(item.status)
84
+ ? item.status
85
+ : "unknown";
86
+ }
45
87
  return {
46
88
  method: method === "item/updated" ? "item/delta" : method,
47
89
  params: {
48
90
  item: {
49
91
  id: item.id,
50
92
  kind:
51
- item.type === "agent_message"
93
+ item.type === "agentMessage"
52
94
  ? "assistant_message"
53
95
  : item.type === "reasoning"
54
96
  ? "reasoning"
55
- : item.type === "command_execution" ||
56
- item.type === "file_change"
97
+ : tool
57
98
  ? "tool"
58
99
  : "artifact",
59
100
  status,
@@ -61,9 +102,10 @@ function projectNotification(notification) {
61
102
  },
62
103
  },
63
104
  output:
64
- method === "item/completed" && item.type === "agent_message"
105
+ method === "item/completed" && item.type === "agentMessage"
65
106
  ? String(item.text || "")
66
- : "",
107
+ : undefined,
108
+ outputItemId: item.id,
67
109
  };
68
110
  }
69
111
  if (method === "turn/completed" || method === "turn/failed") {
@@ -160,44 +202,97 @@ export class CodexAppServerAdapter extends EventEmitter {
160
202
  }
161
203
  const notifications = [];
162
204
  const unknownMethods = new Set();
163
- let output = "";
205
+ const outputItems = new Map();
206
+ let usage = null;
164
207
  let activeThreadId = threadId;
208
+ let activeTurnId = null;
165
209
  let submissionStarted = false;
166
210
  let admissionObserved = false;
167
211
  let observedTerminal = null;
168
212
  let terminalResolve;
169
- let terminalReject;
170
- const terminal = new Promise((resolve, reject) => {
213
+ const terminal = new Promise((resolve) => {
171
214
  terminalResolve = resolve;
172
- terminalReject = reject;
173
215
  });
216
+ let deadlineReject;
217
+ const deadline = new Promise((_, reject) => {
218
+ deadlineReject = reject;
219
+ });
220
+ // Attach immediately: startup/RPC may hang or reject before terminal await.
221
+ deadline.catch(() => {});
174
222
  const timer = setTimeout(
175
223
  () =>
176
- terminalReject(
224
+ deadlineReject(
177
225
  adapterError(
178
226
  "CC_CODEX_APP_SERVER_TIMEOUT",
179
- "Codex App Server turn timed out after admission",
227
+ "Codex App Server request timed out",
180
228
  ),
181
229
  ),
182
230
  this.timeoutMs,
183
231
  );
184
232
  timer.unref?.();
233
+ const withinDeadline = (pending) => Promise.race([pending, deadline]);
234
+ let buffered = [];
235
+ let retainedBytes = 0;
236
+ let eventFailure = null;
237
+ const retain = (notification) => {
238
+ retainedBytes += Buffer.byteLength(JSON.stringify(notification));
239
+ if (
240
+ retainedBytes > 4 * 1024 * 1024 ||
241
+ notifications.length + buffered.length >= 4096
242
+ ) {
243
+ eventFailure = adapterError(
244
+ "CC_CODEX_APP_SERVER_EVENT_LIMIT",
245
+ "Codex App Server event retention limit exceeded",
246
+ );
247
+ deadlineReject(eventFailure);
248
+ return false;
249
+ }
250
+ return true;
251
+ };
185
252
  const onNotification = (notification) => {
253
+ if (observedTerminal || eventFailure || !submissionStarted) return;
254
+ const params = notification?.params || {};
255
+ const eventThread =
256
+ params.threadId ||
257
+ (notification.method === "thread/started" ? params.thread?.id : null);
258
+ if (!eventThread || eventThread !== activeThreadId) return;
259
+ if (!activeTurnId) {
260
+ if (retain(notification)) buffered.push(notification);
261
+ return;
262
+ }
263
+ const eventTurn = params.turnId || params.turn?.id;
264
+ // Thread-wide events carry no turn. Only thread/started is safe to
265
+ // project here; usage and terminal events require the exact turn ID.
266
+ if (
267
+ notification.method !== "thread/started" &&
268
+ eventTurn !== activeTurnId
269
+ )
270
+ return;
271
+ if (!retain(notification)) return;
186
272
  const projected = projectNotification(notification);
187
- if (projected.unknownMethod) unknownMethods.add(projected.unknownMethod);
188
- else {
273
+ if (projected.unknownMethod) {
274
+ if (unknownMethods.size < 64)
275
+ unknownMethods.add(projected.unknownMethod);
276
+ } else {
277
+ projected.params = {
278
+ ...projected.params,
279
+ threadId: activeThreadId,
280
+ turnId: activeTurnId,
281
+ };
189
282
  notifications.push(projected);
190
283
  this.emit("notification", projected);
191
284
  }
192
- if (
193
- submissionStarted &&
194
- (projected.method === "turn/started" ||
195
- projected.method?.startsWith("item/") ||
196
- Boolean(projected.terminal))
197
- ) {
198
- admissionObserved = true;
285
+ if (projected.outputItemId) {
286
+ if (projected.output !== undefined)
287
+ outputItems.set(projected.outputItemId, projected.output);
288
+ else if (projected.outputDelta)
289
+ outputItems.set(
290
+ projected.outputItemId,
291
+ (outputItems.get(projected.outputItemId) || "") +
292
+ projected.outputDelta,
293
+ );
199
294
  }
200
- if (projected.output) output = projected.output;
295
+ if (projected.usage) usage = projected.usage;
201
296
  if (projected.terminal) {
202
297
  observedTerminal = projected;
203
298
  terminalResolve(projected);
@@ -208,10 +303,11 @@ export class CodexAppServerAdapter extends EventEmitter {
208
303
  Object.freeze({
209
304
  protocol: CODEX_APP_SERVER_PROTOCOL,
210
305
  threadId: activeThreadId,
306
+ turnId: activeTurnId,
211
307
  terminal: terminalEvent.terminal,
212
- output,
308
+ output: [...outputItems.values()].join("\n"),
213
309
  error: terminalEvent.error || null,
214
- usage: terminalEvent.usage || null,
310
+ usage: terminalEvent.usage || usage,
215
311
  notifications: Object.freeze(notifications),
216
312
  unknownMethods: Object.freeze([...unknownMethods].sort()),
217
313
  fallback: false,
@@ -219,13 +315,14 @@ export class CodexAppServerAdapter extends EventEmitter {
219
315
  });
220
316
  try {
221
317
  if (!this.client.running && typeof this.client.start === "function") {
222
- await this.client.start();
318
+ await withinDeadline(this.client.start());
223
319
  }
224
320
  if (!activeThreadId) {
225
- const started = await this.client.request("thread/start", {
226
- ephemeral: false,
227
- provider: "codex",
228
- });
321
+ const started = await withinDeadline(
322
+ this.client.request("thread/start", {
323
+ ephemeral: false,
324
+ }),
325
+ );
229
326
  activeThreadId = started?.thread?.id;
230
327
  }
231
328
  if (!activeThreadId) {
@@ -238,20 +335,49 @@ export class CodexAppServerAdapter extends EventEmitter {
238
335
  // the server did not accept the input. Never launch a second execution
239
336
  // path from that ambiguous state.
240
337
  submissionStarted = true;
241
- const started = await this.client.request("turn/start", {
242
- threadId: activeThreadId,
243
- input: [{ type: "text", text: String(prompt || "") }],
244
- });
338
+ const started = await withinDeadline(
339
+ this.client.request("turn/start", {
340
+ threadId: activeThreadId,
341
+ input: [{ type: "text", text: String(prompt || "") }],
342
+ }),
343
+ );
344
+ activeTurnId = started?.turn?.id;
345
+ if (typeof activeTurnId !== "string" || !activeTurnId) {
346
+ throw adapterError(
347
+ "CC_CODEX_APP_SERVER_PROTOCOL_FAILED",
348
+ "Codex App Server did not return a turn identity",
349
+ );
350
+ }
245
351
  admissionObserved = true;
352
+ if (eventFailure) throw eventFailure;
353
+ const early = buffered;
354
+ buffered = [];
355
+ retainedBytes = 0;
356
+ for (const notification of early) onNotification(notification);
357
+ if (eventFailure) throw eventFailure;
358
+ // Some servers finish before writing the RPC response, including items
359
+ // in the response without separate item notifications.
360
+ if (!observedTerminal)
361
+ for (const item of started.turn.items || []) {
362
+ onNotification({
363
+ method: "item/completed",
364
+ params: { threadId: activeThreadId, turnId: activeTurnId, item },
365
+ });
366
+ }
367
+ if (eventFailure) throw eventFailure;
246
368
  const initialStatus = String(started?.turn?.status || "");
247
369
  const terminalEvent = ["completed", "failed", "interrupted"].includes(
248
370
  initialStatus,
249
371
  )
250
372
  ? projectNotification({
251
373
  method: "turn/completed",
252
- params: { turn: started.turn, usage: started.turn.usage || null },
374
+ params: {
375
+ threadId: activeThreadId,
376
+ turn: started.turn,
377
+ usage: started.turn.usage || null,
378
+ },
253
379
  })
254
- : await terminal;
380
+ : await withinDeadline(terminal);
255
381
  return buildResult(terminalEvent);
256
382
  } catch (error) {
257
383
  if (!submissionStarted) {
@@ -18,6 +18,7 @@
18
18
  */
19
19
 
20
20
  import { estimateCost } from "./llm-pricing.js";
21
+ import { projectUsagePricingContext } from "./usage-pricing-context.js";
21
22
 
22
23
  /** Parse a `--max-budget-usd` value into a positive number, or null when unset. */
23
24
  export function parseBudgetUsd(value) {
@@ -64,6 +65,7 @@ export class CostBudget {
64
65
  // or it undercounts real spend on a cached Anthropic run and stops too late.
65
66
  const cacheReadTokens = usage?.cache_read_input_tokens || 0;
66
67
  const cacheCreationTokens = usage?.cache_creation_input_tokens || 0;
68
+ const pricingContext = projectUsagePricingContext(usage || {});
67
69
  const est = estimateCost({
68
70
  provider,
69
71
  model,
@@ -71,6 +73,8 @@ export class CostBudget {
71
73
  outputTokens: usage?.output_tokens || 0,
72
74
  cacheReadTokens,
73
75
  cacheCreationTokens,
76
+ serviceTier: pricingContext.service_tier ?? "standard",
77
+ regionalProcessing: pricingContext.regional_processing === true,
74
78
  table: this.table,
75
79
  });
76
80
  const tokens =
@@ -14,6 +14,9 @@ const PROVIDERS = Object.freeze({
14
14
  "system-one": { label: "System One" },
15
15
  });
16
16
 
17
+ export const MAX_DECISION_REQUEST_BYTES = 256 * 1024;
18
+ export const MAX_DECISION_RESPONSE_BYTES = 256 * 1024;
19
+
17
20
  function boundedText(value, label, limit = 160) {
18
21
  if (
19
22
  typeof value !== "string" ||
@@ -98,6 +101,71 @@ function providerError(status, provider) {
98
101
  return error;
99
102
  }
100
103
 
104
+ function bodyTooLarge(kind, maximum) {
105
+ const error = new Error(`decision ${kind} exceeds ${maximum} bytes`);
106
+ error.code = `CC_DECISION_${kind.toUpperCase()}_TOO_LARGE`;
107
+ return error;
108
+ }
109
+
110
+ async function readBoundedJsonResponse(response) {
111
+ const declared = response.headers?.get?.("content-length");
112
+ if (
113
+ declared != null &&
114
+ /^\d+$/u.test(declared) &&
115
+ BigInt(declared) > BigInt(MAX_DECISION_RESPONSE_BYTES)
116
+ ) {
117
+ try {
118
+ await response.body?.cancel?.();
119
+ } catch {
120
+ // The declared size remains authoritative even if cancellation fails.
121
+ }
122
+ throw bodyTooLarge("response", MAX_DECISION_RESPONSE_BYTES);
123
+ }
124
+
125
+ // A real Fetch Response has a stream; injected test transports may only
126
+ // expose json(). The latter is checked after parsing because it is trusted.
127
+ if (!response.body?.getReader) {
128
+ const value = await response.json();
129
+ if (
130
+ Buffer.byteLength(JSON.stringify(value), "utf8") >
131
+ MAX_DECISION_RESPONSE_BYTES
132
+ ) {
133
+ throw bodyTooLarge("response", MAX_DECISION_RESPONSE_BYTES);
134
+ }
135
+ return value;
136
+ }
137
+
138
+ const reader = response.body.getReader();
139
+ const chunks = [];
140
+ let total = 0;
141
+ try {
142
+ for (;;) {
143
+ const { done, value } = await reader.read();
144
+ if (done) break;
145
+ const chunkBytes = value?.byteLength;
146
+ if (
147
+ !Number.isSafeInteger(chunkBytes) ||
148
+ total + chunkBytes > MAX_DECISION_RESPONSE_BYTES
149
+ ) {
150
+ throw bodyTooLarge("response", MAX_DECISION_RESPONSE_BYTES);
151
+ }
152
+ const chunk = Buffer.from(value);
153
+ total += chunk.length;
154
+ chunks.push(chunk);
155
+ }
156
+ return JSON.parse(new TextDecoder().decode(Buffer.concat(chunks, total)));
157
+ } catch (error) {
158
+ try {
159
+ await reader.cancel();
160
+ } catch {
161
+ // The original read, size, or JSON error remains authoritative.
162
+ }
163
+ throw error;
164
+ } finally {
165
+ reader.releaseLock();
166
+ }
167
+ }
168
+
101
169
  export function createDecisionProvider({
102
170
  provider,
103
171
  model,
@@ -119,6 +187,14 @@ export function createDecisionProvider({
119
187
  provider: options.provider,
120
188
  model: options.model,
121
189
  decide: async (request, { signal } = {}) => {
190
+ const body = JSON.stringify({
191
+ model: options.model,
192
+ state: request.payload.state,
193
+ questions: request.payload.questions,
194
+ });
195
+ if (Buffer.byteLength(body, "utf8") > MAX_DECISION_REQUEST_BYTES) {
196
+ throw bodyTooLarge("request", MAX_DECISION_REQUEST_BYTES);
197
+ }
122
198
  const response = await fetchImpl(endpoint, {
123
199
  method: "POST",
124
200
  headers: {
@@ -127,23 +203,22 @@ export function createDecisionProvider({
127
203
  : { authorization: `Bearer ${secret}` }),
128
204
  "content-type": "application/json",
129
205
  },
130
- body: JSON.stringify({
131
- model: options.model,
132
- state: request.payload.state,
133
- questions: request.payload.questions,
134
- }),
206
+ body,
135
207
  signal,
136
208
  redirect: "error",
137
209
  });
138
210
  if (!response?.ok) {
139
211
  throw providerError(response?.status ?? 0, options.provider);
140
212
  }
141
- const body = await response.json();
213
+ const responseBody = await readBoundedJsonResponse(response);
142
214
  return {
143
215
  provider: options.provider,
144
- model: typeof body?.model === "string" ? body.model : options.model,
145
- answers: body?.answers,
146
- usage: body?.usage,
216
+ model:
217
+ typeof responseBody?.model === "string"
218
+ ? responseBody.model
219
+ : options.model,
220
+ answers: responseBody?.answers,
221
+ usage: responseBody?.usage,
147
222
  };
148
223
  },
149
224
  });
@@ -38,12 +38,28 @@ function timeoutSignal(signal, timeoutMs) {
38
38
 
39
39
  function projectUnavailable(error) {
40
40
  if (error?.name === "TimeoutError") return "provider-timeout";
41
+ if (error?.code === "CC_DECISION_USAGE_UNKNOWN_BLOCKED") {
42
+ return "provider-usage-unknown-blocked";
43
+ }
41
44
  if (error?.code === "CC_DECISION_PROVIDER_HTTP_ERROR") {
42
45
  return "provider-http-error";
43
46
  }
44
47
  return "provider-unavailable";
45
48
  }
46
49
 
50
+ function unavailableOutcome(reasonCode) {
51
+ return {
52
+ status: "unavailable",
53
+ reasonCode,
54
+ selectedCandidateId: null,
55
+ selectedDigest: null,
56
+ selectedSkillId: null,
57
+ needsSkillProbability: null,
58
+ choiceConfidence: null,
59
+ resultDigest: null,
60
+ };
61
+ }
62
+
47
63
  function asPersistenceError(error) {
48
64
  if (error?.runtimeLedgerPersistence === true) return error;
49
65
  try {
@@ -63,6 +79,7 @@ export function createSkillDecisionRuntime({
63
79
  persist = null,
64
80
  observe = null,
65
81
  sessionBudget = null,
82
+ initialUsageUnknown = false,
66
83
  thresholds = {},
67
84
  timeoutMs = DEFAULT_TIMEOUT_MS,
68
85
  idGenerator = () => randomUUID(),
@@ -84,6 +101,7 @@ export function createSkillDecisionRuntime({
84
101
  let providerAuthority = null;
85
102
  let boundTenantId = null;
86
103
  let boundSessionId = null;
104
+ let unknownUsageSeen = initialUsageUnknown === true;
87
105
  if (normalizedMode !== "off") {
88
106
  providerAuthority = captureDecisionProviderAuthority(provider);
89
107
  boundTenantId = requiredText(tenantId, "tenantId");
@@ -104,6 +122,11 @@ export function createSkillDecisionRuntime({
104
122
  }
105
123
  };
106
124
 
125
+ const persistDecisionUsage = async (type, event) => {
126
+ await persist(type, event);
127
+ if (type === "model_usage_unknown") unknownUsageSeen = true;
128
+ };
129
+
107
130
  const runtime = Object.freeze({
108
131
  schema: SKILL_DECISION_RUNTIME_SCHEMA,
109
132
  mode: normalizedMode,
@@ -144,56 +167,70 @@ export function createSkillDecisionRuntime({
144
167
  }
145
168
  let outcome;
146
169
  let requestSignal = null;
147
- try {
148
- const raw = await runMeteredDirectModelCall({
149
- sessionId: boundSessionId,
150
- persist,
151
- provider: providerAuthority.provider,
152
- model: providerAuthority.model,
153
- source: "model",
154
- operationId: `decision:${decisionId}`,
155
- sessionBudget,
156
- call: () => {
157
- requestSignal = timeoutSignal(signal, timeoutMs);
158
- return providerAuthority.decide(request, {
159
- signal: requestSignal,
160
- });
161
- },
162
- });
163
- const normalized = normalizeSkillDecisionProviderResult(request, raw);
164
- const resolved = resolveSkillDecision(request, normalized, thresholds);
165
- outcome = {
166
- status: resolved.status,
167
- reasonCode: resolved.reasonCode,
168
- selectedCandidateId: resolved.selectedCandidateId,
169
- selectedDigest: resolved.selectedDigest,
170
- selectedSkillId: resolved.selectedSkillId,
171
- needsSkillProbability: resolved.needsSkillProbability,
172
- choiceConfidence: resolved.choiceConfidence,
173
- resultDigest: resolved.resultDigest,
174
- };
175
- } catch (error) {
176
- const localTimeout =
177
- !signal?.aborted &&
178
- requestSignal?.aborted &&
179
- requestSignal.reason === error &&
180
- error?.name === "TimeoutError";
181
- if (
182
- signal?.aborted ||
183
- (isTerminalModelFailure(error) && !localTimeout)
184
- ) {
185
- throw error;
170
+ if (unknownUsageSeen) {
171
+ outcome = unavailableOutcome("provider-usage-unknown-blocked");
172
+ } else {
173
+ try {
174
+ const { result: raw, settlement } = await runMeteredDirectModelCall({
175
+ sessionId: boundSessionId,
176
+ persist: persistDecisionUsage,
177
+ provider: providerAuthority.provider,
178
+ model: providerAuthority.model,
179
+ source: "model",
180
+ operationId: `decision:${decisionId}`,
181
+ sessionBudget,
182
+ includeSettlement: true,
183
+ call: () => {
184
+ if (unknownUsageSeen) {
185
+ const error = new Error("decision usage recovery is required");
186
+ error.code = "CC_DECISION_USAGE_UNKNOWN_BLOCKED";
187
+ throw error;
188
+ }
189
+ requestSignal = timeoutSignal(signal, timeoutMs);
190
+ return providerAuthority.decide(request, {
191
+ signal: requestSignal,
192
+ });
193
+ },
194
+ });
195
+ if (settlement !== "known") {
196
+ // The metered call already persisted model_usage_unknown. Without a
197
+ // budget root it may return the answer; never expose that answer.
198
+ outcome = unavailableOutcome("provider-usage-unknown");
199
+ } else {
200
+ const normalized = normalizeSkillDecisionProviderResult(
201
+ request,
202
+ raw,
203
+ );
204
+ const resolved = resolveSkillDecision(
205
+ request,
206
+ normalized,
207
+ thresholds,
208
+ );
209
+ outcome = {
210
+ status: resolved.status,
211
+ reasonCode: resolved.reasonCode,
212
+ selectedCandidateId: resolved.selectedCandidateId,
213
+ selectedDigest: resolved.selectedDigest,
214
+ selectedSkillId: resolved.selectedSkillId,
215
+ needsSkillProbability: resolved.needsSkillProbability,
216
+ choiceConfidence: resolved.choiceConfidence,
217
+ resultDigest: resolved.resultDigest,
218
+ };
219
+ }
220
+ } catch (error) {
221
+ const localTimeout =
222
+ !signal?.aborted &&
223
+ requestSignal?.aborted &&
224
+ requestSignal.reason === error &&
225
+ error?.name === "TimeoutError";
226
+ if (
227
+ signal?.aborted ||
228
+ (isTerminalModelFailure(error) && !localTimeout)
229
+ ) {
230
+ throw error;
231
+ }
232
+ outcome = unavailableOutcome(projectUnavailable(error));
186
233
  }
187
- outcome = {
188
- status: "unavailable",
189
- reasonCode: projectUnavailable(error),
190
- selectedCandidateId: null,
191
- selectedDigest: null,
192
- selectedSkillId: null,
193
- needsSkillProbability: null,
194
- choiceConfidence: null,
195
- resultDigest: null,
196
- };
197
234
  }
198
235
  const finishedAt = now();
199
236
  if (
@@ -54,6 +54,7 @@ function unknownUsageEvent({
54
54
  * Meter one direct provider call that runs outside agentLoop. The started row is
55
55
  * durable before the callback resumes into provider work; every outcome then
56
56
  * settles known or unknown without persisting prompts, responses, or errors.
57
+ * Opt-in includeSettlement returns that persisted status with the raw result.
57
58
  */
58
59
  export async function runMeteredDirectModelCall({
59
60
  sessionId,
@@ -63,6 +64,7 @@ export async function runMeteredDirectModelCall({
63
64
  source = "model",
64
65
  operationId = undefined,
65
66
  sessionBudget = null,
67
+ includeSettlement = false,
66
68
  call,
67
69
  }) {
68
70
  if (typeof call !== "function") {
@@ -78,7 +80,12 @@ export async function runMeteredDirectModelCall({
78
80
  );
79
81
  }
80
82
  }
81
- if (!sessionId) return call();
83
+ if (!sessionId) {
84
+ if (includeSettlement) {
85
+ throw new TypeError("direct model settlement requires a session");
86
+ }
87
+ return call();
88
+ }
82
89
  if (typeof persist !== "function") {
83
90
  throw new TypeError("metered direct model call requires persistence");
84
91
  }
@@ -96,6 +103,9 @@ export async function runMeteredDirectModelCall({
96
103
  `direct model call ${source}`,
97
104
  );
98
105
  let result;
106
+ let settlement = "unknown";
107
+ const returnSettled = (status) =>
108
+ includeSettlement ? Object.freeze({ result, settlement: status }) : result;
99
109
  try {
100
110
  result = await call();
101
111
  } catch (error) {
@@ -139,7 +149,7 @@ export async function runMeteredDirectModelCall({
139
149
  if (markSessionBudgetUsageUnknown(sessionBudget, unknown)) {
140
150
  rejectSessionBudgetUsageUnknown(unknown, `direct model call ${source}`);
141
151
  }
142
- return result;
152
+ return returnSettled("unknown");
143
153
  }
144
154
  await persistUsageEvent(persist, "token_usage", event);
145
155
  recordSessionBudgetUsage(
@@ -147,6 +157,7 @@ export async function runMeteredDirectModelCall({
147
157
  event,
148
158
  `direct model call ${source} usage settlement`,
149
159
  );
160
+ settlement = "known";
150
161
  } else {
151
162
  const unknown = unknownUsageEvent({
152
163
  callId,
@@ -161,5 +172,5 @@ export async function runMeteredDirectModelCall({
161
172
  rejectSessionBudgetUsageUnknown(unknown, `direct model call ${source}`);
162
173
  }
163
174
  }
164
- return result;
175
+ return returnSettled(settlement);
165
176
  }