chainlesschain 0.166.101 → 0.166.103

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 (219) hide show
  1. package/package.json +2 -2
  2. package/src/assets/linux-subreaper/linux-arm64/manifest.json +1 -1
  3. package/src/assets/linux-subreaper/linux-x64/manifest.json +1 -1
  4. package/src/assets/web-panel/assets/{AIOps-BjBS_29I.js → AIOps-BLrXpdnP.js} +1 -1
  5. package/src/assets/web-panel/assets/{ActionButton-CUnnQUaj.js → ActionButton-C0xy9uFy.js} +1 -1
  6. package/src/assets/web-panel/assets/{Analytics-BqYZxgnY.js → Analytics-C6EephQP.js} +3 -3
  7. package/src/assets/web-panel/assets/{AppLayout-m8B886ka.js → AppLayout-ZCXdOD9y.js} +5 -5
  8. package/src/assets/web-panel/assets/{Artifacts-JEOxU3Ug.js → Artifacts-D4MfZ-pl.js} +1 -1
  9. package/src/assets/web-panel/assets/{Audit-DAXS5c9J.js → Audit-BQ8c3bBu.js} +1 -1
  10. package/src/assets/web-panel/assets/{BackgroundAgents-e3a9XHw3.js → BackgroundAgents-BOA7_ljM.js} +1 -1
  11. package/src/assets/web-panel/assets/{Backup-D3Qmp68h.js → Backup-60uiQjGT.js} +1 -1
  12. package/src/assets/web-panel/assets/{BaseInput-C7CXyiUl.js → BaseInput-BDvEbGs_.js} +1 -1
  13. package/src/assets/web-panel/assets/{Chat-2AHlAGi8.js → Chat-B3IkAuFQ.js} +6 -6
  14. package/src/assets/web-panel/assets/ChatBubbleRenderer-n6BVStHf.js +1 -0
  15. package/src/assets/web-panel/assets/{Checkbox-YfBuQlBH.js → Checkbox-njGbfJWq.js} +1 -1
  16. package/src/assets/web-panel/assets/{Codegen-DCCQDfTL.js → Codegen-CF7DtdxC.js} +1 -1
  17. package/src/assets/web-panel/assets/{Col-03i2WfrV.js → Col-C_3Zix40.js} +1 -1
  18. package/src/assets/web-panel/assets/{Community-CJQIpng6.js → Community-CzU-ZC2d.js} +1 -1
  19. package/src/assets/web-panel/assets/{Compact-CCtcQ2pq.js → Compact-BgeqsPRh.js} +1 -1
  20. package/src/assets/web-panel/assets/{Compliance-Vxl7ZszJ.js → Compliance-6l7cwiqp.js} +1 -1
  21. package/src/assets/web-panel/assets/{Cowork-DN-BwA8I.js → Cowork-D4s905fI.js} +2 -2
  22. package/src/assets/web-panel/assets/{Cron-Dc2Q46X7.js → Cron-CGTYSxRS.js} +2 -2
  23. package/src/assets/web-panel/assets/{Crosschain-CQCblsl-.js → Crosschain-BnSo-Yt3.js} +1 -1
  24. package/src/assets/web-panel/assets/{DID-YYvqUR8C.js → DID-Dm4vk2X1.js} +2 -2
  25. package/src/assets/web-panel/assets/{Dashboard-Cafy3DZT.js → Dashboard-D7H-PZ_N.js} +2 -2
  26. package/src/assets/web-panel/assets/{Dropdown-BOyYpIpv.js → Dropdown-COslkgxn.js} +1 -1
  27. package/src/assets/web-panel/assets/{EmailListRenderer-B7NYjc1j.js → EmailListRenderer-CJWEetmk.js} +1 -1
  28. package/src/assets/web-panel/assets/{EvolutionSettings-C5wfxztf.js → EvolutionSettings-BbzebAWe.js} +1 -1
  29. package/src/assets/web-panel/assets/{FamilyGuardDashboard-aA7KnDGK.js → FamilyGuardDashboard-BsoTOXwk.js} +1 -1
  30. package/src/assets/web-panel/assets/{Federation-DlgXUu1L.js → Federation-Ck5kM_5H.js} +1 -1
  31. package/src/assets/web-panel/assets/{FormItemContext-B5YsrLDg.js → FormItemContext-gShxCqtF.js} +1 -1
  32. package/src/assets/web-panel/assets/{GenericCardRenderer-DaWojPFw.js → GenericCardRenderer-DarN1G-z.js} +1 -1
  33. package/src/assets/web-panel/assets/{Git-dkhh6Fx2.js → Git-CJfpLyP5.js} +2 -2
  34. package/src/assets/web-panel/assets/{Governance-Cz6vmkjc.js → Governance-CVcJmpQz.js} +1 -1
  35. package/src/assets/web-panel/assets/{Inference-DWt0hbh8.js → Inference-ComU_ig8.js} +1 -1
  36. package/src/assets/web-panel/assets/{KnowledgeGraph-BZJ0Z-nL.js → KnowledgeGraph-35hprFJy.js} +1 -1
  37. package/src/assets/web-panel/assets/{Logs-BaBBmL1A.js → Logs-BQDqBTz0.js} +2 -2
  38. package/src/assets/web-panel/assets/MarkdownRenderer-BpdGAVCC.js +1 -0
  39. package/src/assets/web-panel/assets/{Marketplace-ct8sgQ0s.js → Marketplace-B9O9OKnn.js} +1 -1
  40. package/src/assets/web-panel/assets/{McpTools-CXKCRGYQ.js → McpTools-VMKxA4Wc.js} +3 -3
  41. package/src/assets/web-panel/assets/{Memory-O7ZwlS6a.js → Memory-CcBbf3Bc.js} +2 -2
  42. package/src/assets/web-panel/assets/{MobileBridge-By12C-eC.js → MobileBridge-D7myz46N.js} +1 -1
  43. package/src/assets/web-panel/assets/{MobileProjects-Ba-EVdex.js → MobileProjects-Da5KBXyx.js} +1 -1
  44. package/src/assets/web-panel/assets/{Mtc-g-932zV2.js → Mtc-x3NPZfuL.js} +5 -5
  45. package/src/assets/web-panel/assets/{MtcAudit-BW8hB0ly.js → MtcAudit-CwnzptEC.js} +4 -4
  46. package/src/assets/web-panel/assets/{Multisig-zspLaMbT.js → Multisig-CCAxf4Ye.js} +3 -3
  47. package/src/assets/web-panel/assets/{NLProgramming-dJeUPDoq.js → NLProgramming-CptHKz-Q.js} +1 -1
  48. package/src/assets/web-panel/assets/{Notes-C4msiRQL.js → Notes-0uEp4DCJ.js} +3 -3
  49. package/src/assets/web-panel/assets/{NotificationSettings-MOCHM-qg.js → NotificationSettings-DthvrOLd.js} +1 -1
  50. package/src/assets/web-panel/assets/{OrderTableRenderer-CX0T66NM.js → OrderTableRenderer-CxXuPzZg.js} +1 -1
  51. package/src/assets/web-panel/assets/{Organization-DOZurBfk.js → Organization-BWf2tmQQ.js} +4 -4
  52. package/src/assets/web-panel/assets/{Overflow-qOT9BhUp.js → Overflow-BbvAtEth.js} +1 -1
  53. package/src/assets/web-panel/assets/{P2P-BMoy7Eo4.js → P2P-zBo6enit.js} +2 -2
  54. package/src/assets/web-panel/assets/{PdhVaultBrowser-ByyV1q-D.js → PdhVaultBrowser-D_LMQ4A4.js} +3 -3
  55. package/src/assets/web-panel/assets/{Permissions-6Qyro4ye.js → Permissions-C1ucb2ck.js} +4 -4
  56. package/src/assets/web-panel/assets/{PersonalDataHub-DR3DRNSX.js → PersonalDataHub-Bz64RddJ.js} +5 -5
  57. package/src/assets/web-panel/assets/{Pipeline-Cr6TTdud.js → Pipeline-DXJt3y3_.js} +1 -1
  58. package/src/assets/web-panel/assets/{Privacy-B70otG0l.js → Privacy-DiZ8b_ut.js} +1 -1
  59. package/src/assets/web-panel/assets/{ProjectInit-BHCqxoSk.js → ProjectInit-DfLKKrJ4.js} +2 -2
  60. package/src/assets/web-panel/assets/{ProjectSettings-B80GZpZk.js → ProjectSettings-Ct6kJuIY.js} +2 -2
  61. package/src/assets/web-panel/assets/{Projects-cq-b9-fQ.js → Projects-BBUMlZ3m.js} +1 -1
  62. package/src/assets/web-panel/assets/{Providers-dsVTimHa.js → Providers-DYVQPHvc.js} +1 -1
  63. package/src/assets/web-panel/assets/{QrScannerModal-DRJ8YepZ.js → QrScannerModal-23Il7iPp.js} +1 -1
  64. package/src/assets/web-panel/assets/{QuickAsk-BSXdEjIB.js → QuickAsk-WgOZKrv1.js} +1 -1
  65. package/src/assets/web-panel/assets/{Recommend-CQLJGyKC.js → Recommend-CRIka6xT.js} +1 -1
  66. package/src/assets/web-panel/assets/{RemoteSession-BF9WUFVZ.js → RemoteSession-DOy3GjVZ.js} +2 -2
  67. package/src/assets/web-panel/assets/{Reputation-Cy9o5tvW.js → Reputation-BXyi6xeR.js} +1 -1
  68. package/src/assets/web-panel/assets/{Row-BP346_3b.js → Row-CoMxuIcR.js} +1 -1
  69. package/src/assets/web-panel/assets/{RssFeed-BKulxXf3.js → RssFeed-87hPkoM6.js} +3 -3
  70. package/src/assets/web-panel/assets/{Search-EemQj2Dv.js → Search-B1EqFCO4.js} +1 -1
  71. package/src/assets/web-panel/assets/{Security-DcWPAwwk.js → Security-HcC41eGs.js} +4 -4
  72. package/src/assets/web-panel/assets/{Services-Bltqciay.js → Services-BqLwmvCM.js} +2 -2
  73. package/src/assets/web-panel/assets/{Skeleton-BwRyOGY8.js → Skeleton-CIMmjW4r.js} +1 -1
  74. package/src/assets/web-panel/assets/{Skills-D98qlvpJ.js → Skills-CgurezJU.js} +1 -1
  75. package/src/assets/web-panel/assets/{Sla-BUTtBMY0.js → Sla-CJuRuqPE.js} +1 -1
  76. package/src/assets/web-panel/assets/{SpeechSettings-C7kcY_98.js → SpeechSettings-BUwsbd1o.js} +1 -1
  77. package/src/assets/web-panel/assets/{SyncSettings-Bsk6lKvT.js → SyncSettings-qo04TOX-.js} +2 -2
  78. package/src/assets/web-panel/assets/Tasks-QEFENVsp.js +1 -0
  79. package/src/assets/web-panel/assets/{Templates-BUM6LwPs.js → Templates-D1PTczPW.js} +1 -1
  80. package/src/assets/web-panel/assets/{Tenant-D9TkOm7z.js → Tenant-Bi0FkEPR.js} +1 -1
  81. package/src/assets/web-panel/assets/{Terminal-CP8ZVErN.js → Terminal-DfSt3bIF.js} +2 -2
  82. package/src/assets/web-panel/assets/{TimelineRenderer-V3SoKZ1T.js → TimelineRenderer-B7bIVs4R.js} +1 -1
  83. package/src/assets/web-panel/assets/{Tokens-CCRlUTOA.js → Tokens-B6w5XrMb.js} +1 -1
  84. package/src/assets/web-panel/assets/{Trigger-CznUcPme.js → Trigger-XXVSDWiF.js} +1 -1
  85. package/src/assets/web-panel/assets/{Trust-D1GIk_NF.js → Trust-DYvlgcK-.js} +1 -1
  86. package/src/assets/web-panel/assets/{UkeySign-DHtvtyC-.js → UkeySign-XyYwJMBM.js} +1 -1
  87. package/src/assets/web-panel/assets/{VideoEditing-CVxdaJIq.js → VideoEditing-C47WbtHH.js} +1 -1
  88. package/src/assets/web-panel/assets/{Wallet-D221OjyE.js → Wallet-CYfqTj_C.js} +4 -4
  89. package/src/assets/web-panel/assets/{WebAuthn-Cw0-ESsq.js → WebAuthn-3AduFn1l.js} +3 -3
  90. package/src/assets/web-panel/assets/{WorkflowEditor-ZYScrBx3.js → WorkflowEditor-DHYEHjMJ.js} +1 -1
  91. package/src/assets/web-panel/assets/{chat-BU0e1obR.js → chat-AeehErSw.js} +1 -1
  92. package/src/assets/web-panel/assets/{colors-gzYweuha.js → colors-DKXJ8paX.js} +1 -1
  93. package/src/assets/web-panel/assets/{compact-item-ChAXal_k.js → compact-item-BOlCiomD.js} +1 -1
  94. package/src/assets/web-panel/assets/{createContext-of3FolD7.js → createContext-BAP6U85b.js} +1 -1
  95. package/src/assets/web-panel/assets/devWarning-rGldFhxo.js +1 -0
  96. package/src/assets/web-panel/assets/{hasIn-4PsK_Kx8.js → hasIn-BLmeL1Xe.js} +1 -1
  97. package/src/assets/web-panel/assets/{index-Cn1clrxx.js → index-B0IjlB9m.js} +1 -1
  98. package/src/assets/web-panel/assets/{index-BOeX7BzS.js → index-BAS2QqLn.js} +1 -1
  99. package/src/assets/web-panel/assets/{index-Cx4Z6nUl.js → index-BRcJlKSa.js} +1 -1
  100. package/src/assets/web-panel/assets/{index-DjRAIRX7.js → index-BSOenF5s.js} +1 -1
  101. package/src/assets/web-panel/assets/{index-Djfgsjfy.js → index-BTnp4Nt3.js} +1 -1
  102. package/src/assets/web-panel/assets/{index-BfI4dXbi.js → index-BhcpWl5z.js} +1 -1
  103. package/src/assets/web-panel/assets/{index-D_5LTPMH.js → index-Bn54FU3i.js} +1 -1
  104. package/src/assets/web-panel/assets/{index-CyDQNprx.js → index-Bpx54vfs.js} +1 -1
  105. package/src/assets/web-panel/assets/{index-DEXBckNR.js → index-Bs2O3f81.js} +1 -1
  106. package/src/assets/web-panel/assets/{index-Ef5YkVAn.js → index-Bt-FCVzh.js} +1 -1
  107. package/src/assets/web-panel/assets/{index-E8oDMSAo.js → index-BuUwKmEI.js} +1 -1
  108. package/src/assets/web-panel/assets/{index-BdxRVNPY.js → index-C5AKY6bJ.js} +1 -1
  109. package/src/assets/web-panel/assets/{index-Wr91cnWr.js → index-C8qi53Ki.js} +1 -1
  110. package/src/assets/web-panel/assets/{index-B5L7zddz.js → index-CFKzWIo8.js} +1 -1
  111. package/src/assets/web-panel/assets/{index-Dy0ojH6G.js → index-CRa4pAaM.js} +3 -3
  112. package/src/assets/web-panel/assets/{index-wo0De0iG.js → index-CaHhfpBi.js} +1 -1
  113. package/src/assets/web-panel/assets/{index-D-Zss5KL.js → index-CdNSmvog.js} +1 -1
  114. package/src/assets/web-panel/assets/{index-DEzjUgkl.js → index-CgtaOzMo.js} +1 -1
  115. package/src/assets/web-panel/assets/{index-DDYj14Q4.js → index-CiqeF0Pf.js} +1 -1
  116. package/src/assets/web-panel/assets/{index-D_9k680X.js → index-ClpwxOXo.js} +1 -1
  117. package/src/assets/web-panel/assets/{index-D1PGrfHE.js → index-Co7pjF53.js} +1 -1
  118. package/src/assets/web-panel/assets/index-Cw-lfvvV.js +1 -0
  119. package/src/assets/web-panel/assets/{index-CeEE_SGZ.js → index-DE7cbDDe.js} +1 -1
  120. package/src/assets/web-panel/assets/{index-CxzBcXOa.js → index-DQLQuwpA.js} +1 -1
  121. package/src/assets/web-panel/assets/{index-DEB5fQqG.js → index-DWYqOI1A.js} +1 -1
  122. package/src/assets/web-panel/assets/{index-CO2owKe0.js → index-De2fPxdb.js} +1 -1
  123. package/src/assets/web-panel/assets/{index-1dzYRBbg.js → index-DpZqbc4w.js} +1 -1
  124. package/src/assets/web-panel/assets/{index-CGFL59q4.js → index-DsQ38fVY.js} +1 -1
  125. package/src/assets/web-panel/assets/{index-DsoV9rzn.js → index-Dv8-g1pY.js} +1 -1
  126. package/src/assets/web-panel/assets/{index-yMf7zmWv.js → index-EKNODw4P.js} +1 -1
  127. package/src/assets/web-panel/assets/{index-CHv_63Cp.js → index-FPXLIXoy.js} +1 -1
  128. package/src/assets/web-panel/assets/{index-CCLsbul3.js → index-IlzfIRNh.js} +1 -1
  129. package/src/assets/web-panel/assets/{index-cFkMIx1x.js → index-OLKhib9T.js} +1 -1
  130. package/src/assets/web-panel/assets/{index-Bftq5rJR.js → index-PEe9OWEQ.js} +1 -1
  131. package/src/assets/web-panel/assets/index-QBXRSyoZ.js +1 -0
  132. package/src/assets/web-panel/assets/{index-DJVrzXtk.js → index-T28naovw.js} +1 -1
  133. package/src/assets/web-panel/assets/{index-By-pper5.js → index-ZMbXl5lo.js} +1 -1
  134. package/src/assets/web-panel/assets/{index-DZ0oKtBg.js → index-urPvyUVk.js} +1 -1
  135. package/src/assets/web-panel/assets/{index-D_ialOHx.js → index-wyKpTsGM.js} +1 -1
  136. package/src/assets/web-panel/assets/{initDefaultProps-D0Bx6pgr.js → initDefaultProps-CDWa1rnn.js} +1 -1
  137. package/src/assets/web-panel/assets/{motion-BnLuJqJ5.js → motion-CX2Cnsd5.js} +1 -1
  138. package/src/assets/web-panel/assets/{move-Bxpq9xgR.js → move-Bfe1NcEF.js} +1 -1
  139. package/src/assets/web-panel/assets/{mtc-parser-BdmrNhOs.js → mtc-parser-DbdqleHE.js} +1 -1
  140. package/src/assets/web-panel/assets/{omit-tjJD34BZ.js → omit-CE2K7NVv.js} +1 -1
  141. package/src/assets/web-panel/assets/{pickAttrs-CMFzLt7b.js → pickAttrs-y_bZgxWG.js} +1 -1
  142. package/src/assets/web-panel/assets/{placementArrow-BZf6O3cd.js → placementArrow-BOHR4zwr.js} +1 -1
  143. package/src/assets/web-panel/assets/{responsiveObserve-DFDLazsV.js → responsiveObserve-B8Jwq05-.js} +1 -1
  144. package/src/assets/web-panel/assets/{slide-CMbTvp4Y.js → slide-BD7RJ3Kn.js} +1 -1
  145. package/src/assets/web-panel/assets/{statusUtils-FOan8MI7.js → statusUtils-BuxDJeDx.js} +1 -1
  146. package/src/assets/web-panel/assets/{styleChecker-DTABspd4.js → styleChecker-DgYQ2Q0o.js} +1 -1
  147. package/src/assets/web-panel/assets/{useFlexGapSupport-CNHXWBpY.js → useFlexGapSupport-DAHF0Fwi.js} +1 -1
  148. package/src/assets/web-panel/assets/{useFs-5K-c_RoL.js → useFs-D4kDyLFp.js} +1 -1
  149. package/src/assets/web-panel/assets/{usePersonalDataHub-Di0hL4G-.js → usePersonalDataHub-BHtSxW4A.js} +1 -1
  150. package/src/assets/web-panel/assets/{vnode-DTyDv4ja.js → vnode-CHKtdqW0.js} +1 -1
  151. package/src/assets/web-panel/assets/{zoom-ontRt8ft.js → zoom-CIZAMma9.js} +1 -1
  152. package/src/assets/web-panel/index.html +1 -1
  153. package/src/command-help-index.json +1 -1
  154. package/src/commands/agent.js +64 -40
  155. package/src/commands/ask.js +6 -4
  156. package/src/commands/team.js +28 -19
  157. package/src/data/changelog.json +26 -0
  158. package/src/harness/prompt-compressor.js +2 -0
  159. package/src/lib/advisor-runtime.js +4 -2
  160. package/src/lib/agent-ipc-bus.js +2 -0
  161. package/src/lib/background-agent-keeper-client.js +3 -0
  162. package/src/lib/browser-automation.js +4 -0
  163. package/src/lib/cc-android-bridge.js +4 -0
  164. package/src/lib/chat-core.js +11 -9
  165. package/src/lib/cloud/cloud-client.js +10 -1
  166. package/src/lib/config-schema.js +18 -5
  167. package/src/lib/context-memory-kernel/memory-query-index.js +5 -2
  168. package/src/lib/context-memory-kernel/runtime.js +4 -0
  169. package/src/lib/context-memory-kernel/segmented-memory-port.js +28 -3
  170. package/src/lib/context-source-ledger.js +52 -9
  171. package/src/lib/cowork-adapter.js +4 -3
  172. package/src/lib/decision-layer/providers.js +16 -11
  173. package/src/lib/evolution/governed-hub-llm.js +31 -16
  174. package/src/lib/evolution/governed-hub-resolver.js +4 -0
  175. package/src/lib/evolution/governed-skill-synthesis-process-grader.js +4 -0
  176. package/src/lib/evomap-client.js +14 -2
  177. package/src/lib/formal-budget-authority.js +191 -59
  178. package/src/lib/formal-budget-contract.js +7 -13
  179. package/src/lib/formal-budget-errors.js +31 -0
  180. package/src/lib/formal-budget-lineage-registry.js +612 -0
  181. package/src/lib/formal-budget-provider-scope.js +143 -0
  182. package/src/lib/formal-budget-transport.js +235 -100
  183. package/src/lib/gateway-client-resilience.js +5 -0
  184. package/src/lib/goal-condition-engine.js +25 -2
  185. package/src/lib/hub-llm-client.js +25 -16
  186. package/src/lib/llm-config-defaults.js +10 -4
  187. package/src/lib/llm-connection-probe.js +17 -10
  188. package/src/lib/llm-pricing.js +16 -4
  189. package/src/lib/llm-providers.js +4 -1
  190. package/src/lib/model-capabilities.js +26 -0
  191. package/src/lib/model-catalog-review.js +18 -1
  192. package/src/lib/model-context-catalog.js +41 -1
  193. package/src/lib/model-failure-policy.js +2 -0
  194. package/src/lib/openai-responses.js +8 -0
  195. package/src/lib/plugin-runtime/marketplace-network.js +9 -5
  196. package/src/lib/process-execution-broker/credential-agent.js +7 -2
  197. package/src/lib/process-execution-broker/credential-transport.js +4 -0
  198. package/src/lib/process-execution-broker/index.js +8 -0
  199. package/src/lib/provider-stream.js +28 -13
  200. package/src/lib/sandbox-egress-worker.js +3 -0
  201. package/src/lib/skill-retrieval-router.js +1 -0
  202. package/src/lib/stream-retry.js +2 -0
  203. package/src/lib/sub-agent-context.js +6 -3
  204. package/src/lib/usage-pricing-context.js +33 -2
  205. package/src/lib/web-fetch.js +2 -0
  206. package/src/lib/web-search.js +5 -0
  207. package/src/repl/agent-repl.js +247 -153
  208. package/src/runtime/agent-core.js +228 -96
  209. package/src/runtime/coding-agent-contract-shared.cjs +14 -1
  210. package/src/runtime/headless-runner.js +1 -0
  211. package/src/runtime/headless-stream.js +1 -0
  212. package/src/runtime/mcp-tool-search.js +0 -0
  213. package/src/runtime/provider-stream-state.js +14 -1
  214. package/src/assets/web-panel/assets/ChatBubbleRenderer-D3KsyCUV.js +0 -1
  215. package/src/assets/web-panel/assets/MarkdownRenderer-C1yByobo.js +0 -1
  216. package/src/assets/web-panel/assets/Tasks-DvSrtz0P.js +0 -1
  217. package/src/assets/web-panel/assets/devWarning-Pa13TVrO.js +0 -1
  218. package/src/assets/web-panel/assets/index-BhQg-v6V.js +0 -1
  219. package/src/assets/web-panel/assets/index-DUD5o-vW.js +0 -1
@@ -38,16 +38,18 @@ export async function reconcileConfigLlmProvider(cfgLlm = {}) {
38
38
  if (!cfgLlm || !cfgLlm.provider || !cfgLlm.baseUrl) {
39
39
  return { llm: cfgLlm, changed: false };
40
40
  }
41
- const { inferProviderFromBaseUrl, modelForeignToProvider } =
42
- await import("./runnable-provider.js");
41
+ const { inferProviderFromBaseUrl, modelForeignToProvider } = await import(
42
+ "./runnable-provider.js"
43
+ );
43
44
  const inferred = inferProviderFromBaseUrl(cfgLlm.baseUrl);
44
45
  if (!inferred || inferred === cfgLlm.provider) {
45
46
  return { llm: cfgLlm, changed: false };
46
47
  }
47
48
  const corrected = { ...cfgLlm, provider: inferred };
48
49
  if (modelForeignToProvider(inferred, cfgLlm.model)) {
49
- const { selectModelForTask, TaskType } =
50
- await import("./task-model-selector.js");
50
+ const { selectModelForTask, TaskType } = await import(
51
+ "./task-model-selector.js"
52
+ );
51
53
  const def = selectModelForTask(inferred, TaskType.CHAT);
52
54
  if (def) corrected.model = def;
53
55
  }
@@ -88,6 +90,8 @@ export function applyConfigLlmDefaults(options = {}, cfgLlm = {}, opts = {}) {
88
90
  options.provider === cfgLlm.provider
89
91
  ) {
90
92
  if (!options.baseUrl && cfgLlm.baseUrl) options.baseUrl = cfgLlm.baseUrl;
93
+ if (options.serviceTier == null && cfgLlm.serviceTier != null)
94
+ options.serviceTier = cfgLlm.serviceTier;
91
95
  backfillApiKey(options, cfgLlm);
92
96
  if (!options.model && !opts.explicitModel && cfgLlm.model) {
93
97
  options.model = cfgLlm.model;
@@ -96,6 +100,8 @@ export function applyConfigLlmDefaults(options = {}, cfgLlm = {}, opts = {}) {
96
100
  }
97
101
  if (options.provider || !cfgLlm.provider) return options;
98
102
  options.provider = cfgLlm.provider;
103
+ if (options.serviceTier == null && cfgLlm.serviceTier != null)
104
+ options.serviceTier = cfgLlm.serviceTier;
99
105
  if (opts.explicitModel) {
100
106
  options.model = opts.explicitModel;
101
107
  } else if (cfgLlm.model) {
@@ -1,5 +1,7 @@
1
1
  import { formatProviderResponseError } from "./provider-http-error.js";
2
2
  import { estimateCost } from "./llm-pricing.js";
3
+ import { providerFetch } from "./formal-budget-provider-scope.js";
4
+ import { isFormalBudgetError } from "./formal-budget-errors.js";
3
5
 
4
6
  // Reasoning models spend the same output allowance on thinking before the
5
7
  // final answer. A 16-token probe can therefore receive HTTP 200 with only
@@ -180,13 +182,17 @@ export async function probeLlmConnection(
180
182
  const timer = setTimeout(() => controller.abort(), timeoutMs);
181
183
  let usage = null;
182
184
  try {
183
- const response = await fetchImpl(url, {
184
- method: "POST",
185
- headers,
186
- body: JSON.stringify(body),
187
- signal: controller.signal,
188
- redirect: "error",
189
- });
185
+ const response = await providerFetch(
186
+ url,
187
+ {
188
+ method: "POST",
189
+ headers,
190
+ body: JSON.stringify(body),
191
+ signal: controller.signal,
192
+ redirect: "error",
193
+ },
194
+ fetchImpl,
195
+ );
190
196
  if (!response.ok)
191
197
  throw new Error(
192
198
  await formatProviderResponseError(target.provider, response, {
@@ -232,9 +238,10 @@ export async function probeLlmConnection(
232
238
  ? llmProbeReceipt(target, { ok: true, reply, usage })
233
239
  : reply;
234
240
  } catch (error) {
235
- const failure = controller.signal.aborted
236
- ? new Error(`Connection test timed out after ${timeoutMs / 1000}s`)
237
- : error;
241
+ const failure =
242
+ controller.signal.aborted && !isFormalBudgetError(error)
243
+ ? new Error(`Connection test timed out after ${timeoutMs / 1000}s`)
244
+ : error;
238
245
  if (includeUsage) failure.probe = llmProbeReceipt(target, { usage });
239
246
  throw failure;
240
247
  } finally {
@@ -67,6 +67,9 @@ export const PRICE_TABLE = Object.freeze({
67
67
  exact: true,
68
68
  terms: Object.freeze({
69
69
  ...GPT6_PRICING_TERMS,
70
+ ...(model.serviceMultipliers
71
+ ? { serviceMultipliers: model.serviceMultipliers }
72
+ : {}),
70
73
  ...(model.cacheReadMultiplier == null
71
74
  ? {}
72
75
  : { cacheReadMultiplier: model.cacheReadMultiplier }),
@@ -259,9 +262,16 @@ export function normalizePricingTerms(value) {
259
262
  Reflect.ownKeys(tiers).length === 0 ||
260
263
  Reflect.ownKeys(tiers).some(
261
264
  (key) =>
262
- !["standard", "default", "auto", "batch", "flex", "fast"].includes(
263
- key,
264
- ) || !finite(tiers[key]),
265
+ ![
266
+ "standard",
267
+ "default",
268
+ "auto",
269
+ "batch",
270
+ "flex",
271
+ "fast",
272
+ "priority",
273
+ "ultrafast",
274
+ ].includes(key) || !finite(tiers[key]),
265
275
  )
266
276
  )
267
277
  fail();
@@ -378,7 +388,9 @@ export function estimateCost({
378
388
  ? Object.hasOwn(rate.terms.serviceMultipliers, serviceTier)
379
389
  ? rate.terms.serviceMultipliers[serviceTier]
380
390
  : null
381
- : 1;
391
+ : ["standard", "default"].includes(serviceTier)
392
+ ? 1
393
+ : null;
382
394
  if (
383
395
  !rate ||
384
396
  tierMultiplier == null ||
@@ -5,6 +5,8 @@
5
5
  /**
6
6
  * Built-in provider definitions.
7
7
  */
8
+ import { providerFetch } from "./formal-budget-provider-scope.js";
9
+ import { isFormalBudgetError } from "./formal-budget-errors.js";
8
10
  export const BUILT_IN_PROVIDERS = {
9
11
  ollama: {
10
12
  name: "ollama",
@@ -134,8 +136,9 @@ async function _fetchWithTimeout(
134
136
  const timer = setTimeout(() => controller.abort(), ms);
135
137
  if (timer && typeof timer.unref === "function") timer.unref();
136
138
  try {
137
- return await fetch(url, { ...opts, signal: controller.signal });
139
+ return await providerFetch(url, { ...opts, signal: controller.signal });
138
140
  } catch (e) {
141
+ if (isFormalBudgetError(e)) throw e;
139
142
  if (controller.signal.aborted) {
140
143
  throw new Error(`provider test timed out after ${ms / 1000}s`);
141
144
  }
@@ -263,6 +263,10 @@ export function resolveModelCapabilityProfile({
263
263
  const profile = {
264
264
  schema: PROFILE_SCHEMA,
265
265
  catalogVersion: MODEL_CAPABILITY_CATALOG_VERSION,
266
+ reviewedAt: documented ? documented.reviewedAt || "2026-10-05" : null,
267
+ supportedServiceTiers: documented?.serviceTiers
268
+ ? [...documented.serviceTiers]
269
+ : ["standard"],
266
270
  profileId: `model-capability-v1:${identityDigest.slice(7, 39)}`,
267
271
  provider: selectedProvider || "unknown",
268
272
  model: selectedModel,
@@ -288,3 +292,25 @@ export function resolveModelCapabilityProfile({
288
292
  profile.digest = canonicalDigest(profile, PROFILE_SCHEMA);
289
293
  return deepFreeze(profile);
290
294
  }
295
+
296
+ /** Resolve a requested live tier without certifying account availability. */
297
+ export function resolveModelServiceTier(profile, serviceTier) {
298
+ const requested = serviceTier ?? "standard";
299
+ if (
300
+ typeof requested !== "string" ||
301
+ !profile?.supportedServiceTiers?.includes(requested)
302
+ ) {
303
+ throw Object.assign(
304
+ new RangeError(
305
+ `Unsupported service tier ${String(requested)} for ${profile?.provider || "unknown"}/${profile?.model || "unknown"}`,
306
+ ),
307
+ { code: "CC_MODEL_SERVICE_TIER_UNSUPPORTED" },
308
+ );
309
+ }
310
+ return Object.freeze({
311
+ requestedServiceTier: requested,
312
+ requestServiceTier: requested === "standard" ? null : requested,
313
+ effectiveServiceTier: null,
314
+ accountVerified: false,
315
+ });
316
+ }
@@ -65,8 +65,12 @@ export function reviewModelCatalog(review, snapshots = {}) {
65
65
  "runtimeProtocol",
66
66
  "contextWindowTokens",
67
67
  "advertisedMaxOutputTokens",
68
+ "reviewedAt",
68
69
  ]) {
69
- if (Object.hasOwn(expected, field) && actual[field] !== expected[field])
70
+ if (
71
+ Object.hasOwn(expected, field) &&
72
+ !isDeepStrictEqual(actual[field], expected[field])
73
+ )
70
74
  mismatches.push({
71
75
  model: expected.model,
72
76
  field,
@@ -80,6 +84,19 @@ export function reviewModelCatalog(review, snapshots = {}) {
80
84
  field: "official-source",
81
85
  actual: null,
82
86
  });
87
+ if (
88
+ Object.hasOwn(expected, "supportedServiceTiers") &&
89
+ !isDeepStrictEqual(
90
+ actual.supportedServiceTiers,
91
+ expected.supportedServiceTiers,
92
+ )
93
+ )
94
+ mismatches.push({
95
+ model: expected.model,
96
+ field: "supportedServiceTiers",
97
+ expected: expected.supportedServiceTiers,
98
+ actual: actual.supportedServiceTiers,
99
+ });
83
100
  for (const field of ["in", "out"]) {
84
101
  if (rate?.[field] !== expected.pricing[field])
85
102
  mismatches.push({
@@ -45,7 +45,7 @@ export const CONTEXT_WINDOWS = Object.freeze({
45
45
  }),
46
46
  });
47
47
 
48
- export const MODEL_CAPABILITY_CATALOG_VERSION = "2026-10-05";
48
+ export const MODEL_CAPABILITY_CATALOG_VERSION = "2026-10-15";
49
49
 
50
50
  // Explicit ownership prevents a model name served by an unrelated provider
51
51
  // from silently inheriting another provider's catalog window.
@@ -86,6 +86,26 @@ export const LEGACY_MODEL_PROVIDERS = Object.freeze({
86
86
  // named models, not endpoint access, account entitlement, or a live CLI run.
87
87
  export const DOCUMENTED_OPENAI_MODELS = Object.freeze({
88
88
  "gpt-6.1-sol": Object.freeze({
89
+ reviewedAt: "2026-10-15",
90
+ serviceTiers: Object.freeze([
91
+ "standard",
92
+ "default",
93
+ "auto",
94
+ "fast",
95
+ "priority",
96
+ "flex",
97
+ "ultrafast",
98
+ ]),
99
+ serviceMultipliers: Object.freeze({
100
+ standard: 1,
101
+ default: 1,
102
+ auto: 1,
103
+ batch: 0.5,
104
+ flex: 0.5,
105
+ fast: 2,
106
+ priority: 2,
107
+ ultrafast: 6,
108
+ }),
89
109
  contextWindowTokens: 1050000,
90
110
  advertisedMaxOutputTokens: 128000,
91
111
  requiresResponsesForTools: true,
@@ -106,6 +126,26 @@ export const DOCUMENTED_OPENAI_MODELS = Object.freeze({
106
126
  ]),
107
127
  }),
108
128
  "gpt-6-astra": Object.freeze({
129
+ reviewedAt: "2026-10-15",
130
+ serviceTiers: Object.freeze([
131
+ "standard",
132
+ "default",
133
+ "auto",
134
+ "fast",
135
+ "priority",
136
+ "flex",
137
+ "ultrafast",
138
+ ]),
139
+ serviceMultipliers: Object.freeze({
140
+ standard: 1,
141
+ default: 1,
142
+ auto: 1,
143
+ batch: 0.5,
144
+ flex: 0.5,
145
+ fast: 2,
146
+ priority: 2,
147
+ ultrafast: 6,
148
+ }),
109
149
  contextWindowTokens: 1050000,
110
150
  advertisedMaxOutputTokens: 128000,
111
151
  requiresResponsesForTools: true,
@@ -1,4 +1,5 @@
1
1
  import { isAbortError } from "./abort-utils.js";
2
+ import { isFormalBudgetError } from "./formal-budget-errors.js";
2
3
 
3
4
  export function isEvolutionIngressFailure(error) {
4
5
  const visited = new Set();
@@ -21,6 +22,7 @@ export function isTerminalModelFailure(error) {
21
22
  current.code === "CC_AGENT_EVOLUTION_INGRESS_FAILED" ||
22
23
  current.runtimeLedgerPersistence === true ||
23
24
  current.workflowEffectOutcomeUnknown === true ||
25
+ isFormalBudgetError(current) ||
24
26
  /^(?:CC|ERR)_SESSION_BUDGET_/u.test(current.code || "") ||
25
27
  isAbortError(current)
26
28
  ) {
@@ -1,3 +1,5 @@
1
+ import { resolveModelServiceTier } from "./model-capabilities.js";
2
+
1
3
  const RESPONSES_FAILURE_CODE = "CC_OPENAI_RESPONSES_FAILED";
2
4
  const MAX_REASONING_ITEMS = 16;
3
5
  const MAX_REASONING_SUMMARY_CHARS = 8_192;
@@ -177,7 +179,12 @@ export function createOpenAIResponsesBody({
177
179
  reasoning = null,
178
180
  stream = false,
179
181
  modelProfile = null,
182
+ serviceTier = null,
180
183
  }) {
184
+ const tier =
185
+ serviceTier == null
186
+ ? null
187
+ : resolveModelServiceTier(modelProfile, serviceTier).requestServiceTier;
181
188
  if (
182
189
  modelProfile?.advertisedMaxOutputTokens != null &&
183
190
  maxOutputTokens > modelProfile.advertisedMaxOutputTokens
@@ -195,6 +202,7 @@ export function createOpenAIResponsesBody({
195
202
  ...(maxOutputTokens ? { max_output_tokens: maxOutputTokens } : {}),
196
203
  ...(reasoning ? { reasoning } : {}),
197
204
  ...(stream ? { stream: true } : {}),
205
+ ...(tier ? { service_tier: tier } : {}),
198
206
  };
199
207
  }
200
208
 
@@ -3,6 +3,10 @@ import fs from "node:fs";
3
3
  import tls from "node:tls";
4
4
  import { Worker } from "node:worker_threads";
5
5
  import { Agent, ProxyAgent, fetch as undiciFetch } from "undici";
6
+ import {
7
+ requireUnscopedDescendantControl,
8
+ requireUnscopedExternalToolAccess,
9
+ } from "../formal-budget-provider-scope.js";
6
10
 
7
11
  export const MAX_MARKETPLACE_CA_BUNDLE_BYTES = 1024 * 1024;
8
12
  export const MAX_MARKETPLACE_PROXY_URL_LENGTH = 4096;
@@ -15,6 +19,7 @@ export const DEFAULT_MARKETPLACE_PAC_TIMEOUT_MS = 2_000;
15
19
  * deliberately ignored: callers pass CLI flags or CC_PLUGIN_REGISTRY_* values.
16
20
  */
17
21
  export function createMarketplaceNetworkTransport(options = {}) {
22
+ requireUnscopedExternalToolAccess();
18
23
  const proxy = normalizeProxyUrl(options.proxyUrl);
19
24
  const pac = options.pacFile ? readMarketplacePacFile(options.pacFile) : null;
20
25
  if (proxy && pac) {
@@ -49,6 +54,7 @@ export function createMarketplaceNetworkTransport(options = {}) {
49
54
 
50
55
  return {
51
56
  fetch: async (url, fetchOptions = {}) => {
57
+ requireUnscopedExternalToolAccess();
52
58
  const route = pac
53
59
  ? parsePacResult(
54
60
  await resolveMarketplacePac(pac.script, url, {
@@ -99,11 +105,9 @@ export function readMarketplacePacFile(file) {
99
105
  };
100
106
  }
101
107
 
102
- export function resolveMarketplacePac(
103
- script,
104
- url,
105
- { timeoutMs = DEFAULT_MARKETPLACE_PAC_TIMEOUT_MS } = {},
106
- ) {
108
+ export function resolveMarketplacePac(script, url, options = {}) {
109
+ requireUnscopedDescendantControl();
110
+ const { timeoutMs = DEFAULT_MARKETPLACE_PAC_TIMEOUT_MS } = options;
107
111
  const timeout = Number(timeoutMs);
108
112
  if (!Number.isInteger(timeout) || timeout < 100 || timeout > 10_000) {
109
113
  throw new Error("Marketplace PAC timeout must be between 100 and 10000 ms");
@@ -14,6 +14,7 @@
14
14
 
15
15
  import crypto from "node:crypto";
16
16
  import { CredentialTransport } from "./credential-transport.js";
17
+ import { requireUnscopedDescendantControl } from "../formal-budget-provider-scope.js";
17
18
 
18
19
  const REDACTED_VALUE = "***REDACTED***";
19
20
  const DEFAULT_TTL_MS = 60_000;
@@ -644,6 +645,7 @@ class CredentialAgent {
644
645
  * self-asserted approval metadata.
645
646
  */
646
647
  issueCredentialRef(request = {}) {
648
+ requireUnscopedDescendantControl();
647
649
  if (!this.isEnabled()) {
648
650
  this._recordAudit({
649
651
  event: "credential_ref_issue",
@@ -842,6 +844,7 @@ class CredentialAgent {
842
844
  * request object; child-provided claims are not sufficient attestation.
843
845
  */
844
846
  resolveCredentialRef(refId, request = {}) {
847
+ requireUnscopedDescendantControl();
845
848
  const refFingerprint = this._fingerprint(refId);
846
849
  if (!this.isEnabled()) {
847
850
  this._recordAudit({
@@ -1002,8 +1005,8 @@ class CredentialAgent {
1002
1005
  _canIssueForContext(context) {
1003
1006
  return Boolean(
1004
1007
  context?.approved === true &&
1005
- context.approvalId &&
1006
- normalizeProcessTarget(context.target?.process ?? context.process),
1008
+ context.approvalId &&
1009
+ normalizeProcessTarget(context.target?.process ?? context.process),
1007
1010
  );
1008
1011
  }
1009
1012
 
@@ -1025,6 +1028,7 @@ class CredentialAgent {
1025
1028
  * Strip sensitive and reserved environment variables from spawn options.
1026
1029
  */
1027
1030
  filterEnvironment(env = process.env, context = null) {
1031
+ requireUnscopedDescendantControl();
1028
1032
  const safeEnv = {};
1029
1033
  const redacted = [];
1030
1034
  const reservedRemoved = [];
@@ -1232,6 +1236,7 @@ class CredentialAgent {
1232
1236
  * Apply filtering and issue references for a broker-approved spawn.
1233
1237
  */
1234
1238
  applyWithReport(spawnOptions) {
1239
+ requireUnscopedDescendantControl();
1235
1240
  if (!spawnOptions || typeof spawnOptions !== "object") {
1236
1241
  throw credentialError(
1237
1242
  CREDENTIAL_ERROR_CODES.INVALID_REQUEST,
@@ -10,6 +10,7 @@ import net from "node:net";
10
10
  import os from "node:os";
11
11
  import path from "node:path";
12
12
  import { Worker } from "node:worker_threads";
13
+ import { requireUnscopedDescendantControl } from "../formal-budget-provider-scope.js";
13
14
 
14
15
  const TRANSPORT_VERSION = "local-ipc-v1";
15
16
  const DEFAULT_TIMEOUT_MS = 5000;
@@ -34,6 +35,7 @@ export function credentialTransportEndpoint(agentId, options = {}) {
34
35
 
35
36
  export class CredentialTransport {
36
37
  constructor(options = {}) {
38
+ requireUnscopedDescendantControl();
37
39
  if (!options.agentId) {
38
40
  throw transportError(
39
41
  "CC_CREDENTIAL_INVALID_REQUEST",
@@ -156,6 +158,7 @@ export class CredentialTransport {
156
158
  }
157
159
 
158
160
  registerCredential(record) {
161
+ requireUnscopedDescendantControl();
159
162
  if (!this.isAvailable()) {
160
163
  throw (
161
164
  this.error ||
@@ -265,6 +268,7 @@ async function connectWithRetry(endpoint, deadline) {
265
268
  * approved target process.
266
269
  */
267
270
  export async function resolveCredentialRefOverTransport(refId, options = {}) {
271
+ requireUnscopedDescendantControl();
268
272
  const env = options.env || process.env;
269
273
  const endpoint = options.endpoint || env.CC_CREDENTIAL_ENDPOINT;
270
274
  const capabilityToken =
@@ -30,6 +30,7 @@ import * as fs from "node:fs";
30
30
  import * as tty from "node:tty";
31
31
  import { createRequire } from "node:module";
32
32
  import { AsyncLocalStorage } from "node:async_hooks";
33
+ import { requireUnscopedDescendantControl } from "../formal-budget-provider-scope.js";
33
34
 
34
35
  const require = createRequire(import.meta.url);
35
36
 
@@ -4692,6 +4693,7 @@ class ProcessExecutionBroker extends EventEmitter {
4692
4693
  }
4693
4694
 
4694
4695
  spawn(command, args, options = {}) {
4696
+ requireUnscopedDescendantControl();
4695
4697
  assertProcessOwnershipAvailable();
4696
4698
  options = this._withAmbientProcessContext(command, options);
4697
4699
  const executionId = crypto.randomUUID();
@@ -5156,6 +5158,7 @@ class ProcessExecutionBroker extends EventEmitter {
5156
5158
  }
5157
5159
 
5158
5160
  spawnSync(command, args, options = {}) {
5161
+ requireUnscopedDescendantControl();
5159
5162
  assertProcessOwnershipAvailable();
5160
5163
  options = this._withAmbientProcessContext(command, options);
5161
5164
  const executionId = crypto.randomUUID();
@@ -5745,6 +5748,7 @@ class ProcessExecutionBroker extends EventEmitter {
5745
5748
  }
5746
5749
 
5747
5750
  exec(command, options, callback) {
5751
+ requireUnscopedDescendantControl();
5748
5752
  const opts = typeof options === "function" ? {} : options;
5749
5753
  const cb = typeof options === "function" ? options : callback;
5750
5754
  if (this._requiresExplicitLinuxWorkspaceShell(opts.cwd || process.cwd())) {
@@ -5763,6 +5767,7 @@ class ProcessExecutionBroker extends EventEmitter {
5763
5767
  }
5764
5768
 
5765
5769
  execSync(command, options = {}) {
5770
+ requireUnscopedDescendantControl();
5766
5771
  if (
5767
5772
  this._requiresExplicitLinuxWorkspaceShell(options.cwd || process.cwd())
5768
5773
  ) {
@@ -5804,6 +5809,7 @@ class ProcessExecutionBroker extends EventEmitter {
5804
5809
  }
5805
5810
 
5806
5811
  execFile(file, args, options, callback) {
5812
+ requireUnscopedDescendantControl();
5807
5813
  if (typeof args === "function") {
5808
5814
  callback = args;
5809
5815
  args = [];
@@ -5897,6 +5903,7 @@ class ProcessExecutionBroker extends EventEmitter {
5897
5903
  }
5898
5904
 
5899
5905
  execFileSync(file, args, options = {}) {
5906
+ requireUnscopedDescendantControl();
5900
5907
  if (!Array.isArray(args)) {
5901
5908
  options = args || {};
5902
5909
  args = [];
@@ -5917,6 +5924,7 @@ class ProcessExecutionBroker extends EventEmitter {
5917
5924
  }
5918
5925
 
5919
5926
  fork(modulePath, args, options = {}) {
5927
+ requireUnscopedDescendantControl();
5920
5928
  return this.spawn(process.execPath, [modulePath, ...(args || [])], {
5921
5929
  ...options,
5922
5930
  origin: options.origin || "fork",
@@ -1,3 +1,7 @@
1
+ import {
2
+ hasFormalBudgetProviderScope,
3
+ providerFetch,
4
+ } from "./formal-budget-provider-scope.js";
1
5
  /**
2
6
  * Provider streaming adapters — shared by `cc stream` and the Hosted Session
3
7
  * API `stream.run` WS route. Each builder returns an AsyncIterable<string>
@@ -47,16 +51,19 @@ export async function* ollamaTokenStream({
47
51
  signal,
48
52
  requireCompletion = false,
49
53
  }) {
50
- const res = await fetch(`${baseUrl}/api/${messages ? "chat" : "generate"}`, {
51
- method: "POST",
52
- headers: { "Content-Type": "application/json" },
53
- body: JSON.stringify(
54
- messages
55
- ? { model, messages, stream: true }
56
- : { model, prompt, stream: true },
57
- ),
58
- signal,
59
- });
54
+ const res = await providerFetch(
55
+ `${baseUrl}/api/${messages ? "chat" : "generate"}`,
56
+ {
57
+ method: "POST",
58
+ headers: { "Content-Type": "application/json" },
59
+ body: JSON.stringify(
60
+ messages
61
+ ? { model, messages, stream: true }
62
+ : { model, prompt, stream: true },
63
+ ),
64
+ signal,
65
+ },
66
+ );
60
67
  if (!res.ok || !res.body) {
61
68
  throw new Error(`Ollama ${res.status} ${res.statusText}`);
62
69
  }
@@ -88,7 +95,8 @@ export async function* openAIStream({
88
95
  signal,
89
96
  requireCompletion = false,
90
97
  }) {
91
- const res = await fetch(`${baseUrl}/chat/completions`, {
98
+ const governed = hasFormalBudgetProviderScope();
99
+ const res = await providerFetch(`${baseUrl}/chat/completions`, {
92
100
  method: "POST",
93
101
  headers: {
94
102
  "Content-Type": "application/json",
@@ -98,17 +106,24 @@ export async function* openAIStream({
98
106
  model,
99
107
  messages: messages ?? [{ role: "user", content: prompt }],
100
108
  stream: true,
109
+ ...(governed ? { stream_options: { include_usage: true } } : {}),
101
110
  }),
102
111
  signal,
103
112
  });
104
113
  if (!res.ok || !res.body) {
105
114
  throw new Error(`${res.status} ${res.statusText}`);
106
115
  }
116
+ let completed = false;
107
117
  for await (const raw of responseLines(res.body)) {
108
118
  const line = raw.trim();
109
119
  if (!line || !line.startsWith("data:")) continue;
110
120
  const payload = line.slice(5).trim();
111
- if (payload === "[DONE]") return;
121
+ if (payload === "[DONE]") {
122
+ completed = true;
123
+ if (!governed) return;
124
+ // A governed stream must reach EOF so durable accounting can settle.
125
+ continue;
126
+ }
112
127
  try {
113
128
  const obj = JSON.parse(payload);
114
129
  if (requireCompletion && obj.error)
@@ -120,7 +135,7 @@ export async function* openAIStream({
120
135
  /* skip */
121
136
  }
122
137
  }
123
- if (requireCompletion)
138
+ if (requireCompletion && !completed)
124
139
  throw new Error("OpenAI stream ended before its completion marker");
125
140
  }
126
141
 
@@ -5,6 +5,7 @@
5
5
  */
6
6
  import { Worker } from "node:worker_threads";
7
7
  import path from "node:path";
8
+ import { requireUnscopedDescendantControl } from "./formal-budget-provider-scope.js";
8
9
 
9
10
  const RESPONSE_TIMEOUT_MS = 10_000;
10
11
 
@@ -15,6 +16,7 @@ function workerError(code) {
15
16
  }
16
17
 
17
18
  export async function startEgressProxyWorker(policy, options = {}) {
19
+ requireUnscopedDescendantControl();
18
20
  const bindHost = options.bindHost || "127.0.0.1";
19
21
  const socketPath = options.socketPath || null;
20
22
  if (socketPath) {
@@ -156,6 +158,7 @@ export async function startEgressProxyWorker(policy, options = {}) {
156
158
  return revision;
157
159
  },
158
160
  async updatePolicy(nextPolicy, expectedRevision) {
161
+ requireUnscopedDescendantControl();
159
162
  const response = await request("update", {
160
163
  policy: nextPolicy,
161
164
  expectedRevision,
@@ -248,6 +248,7 @@ export function routeSkillDescriptors({
248
248
  schema: SKILL_RETRIEVAL_RESULT_SCHEMA,
249
249
  query: query.trim(),
250
250
  selected: returned.length > 0 && !topConflict ? returned[0] : null,
251
+ matchedCount: candidates.length,
251
252
  candidates: Object.freeze(returned.map(Object.freeze)),
252
253
  conflicts: Object.freeze(conflicts.map(Object.freeze)),
253
254
  rejected: Object.freeze(rejected.map(Object.freeze)),
@@ -18,6 +18,7 @@ import {
18
18
  raceWithAbort,
19
19
  throwIfAborted,
20
20
  } from "./abort-utils.js";
21
+ import { isFormalBudgetError } from "./formal-budget-errors.js";
21
22
 
22
23
  /** Bounded auto-retry budget for streaming connection drops (Claude-Code 2.1.181). */
23
24
  export const STREAM_RETRY_MAX = 2;
@@ -243,6 +244,7 @@ export function resolveStreamRetryMax(env = process.env) {
243
244
  * @returns {boolean}
244
245
  */
245
246
  export function isRetryableStreamError(err, signal) {
247
+ if (isFormalBudgetError(err)) return false;
246
248
  if (isAbortError(err)) return false;
247
249
  if (signal && signal.aborted) return false;
248
250
  if (!err) return false;
@@ -21,6 +21,7 @@ import {
21
21
  } from "../runtime/agent-core.js";
22
22
  import { feature } from "./feature-flags.js";
23
23
  import { isEvolutionIngressFailure } from "./model-failure-policy.js";
24
+ import { isFormalBudgetError } from "./formal-budget-errors.js";
24
25
  import { captureAgentEvolutionIngress } from "./evolution/agent-evolution-ingress.js";
25
26
  import {
26
27
  createWorktree,
@@ -609,6 +610,7 @@ export class SubAgentContext {
609
610
  } catch (err) {
610
611
  if (
611
612
  isEvolutionIngressFailure(err) ||
613
+ isFormalBudgetError(err) ||
612
614
  err?.runtimeLedgerPersistence === true ||
613
615
  this._workflowEffectId
614
616
  ) {
@@ -1212,6 +1214,7 @@ export class SubAgentContext {
1212
1214
  } catch (err) {
1213
1215
  if (
1214
1216
  isEvolutionIngressFailure(err) ||
1217
+ isFormalBudgetError(err) ||
1215
1218
  err?.runtimeLedgerPersistence === true ||
1216
1219
  this._workflowEffectId
1217
1220
  ) {
@@ -1543,9 +1546,9 @@ export class SubAgentContext {
1543
1546
  isAborted() {
1544
1547
  return Boolean(
1545
1548
  this._signal?.aborted ||
1546
- this._abortController.signal.aborted ||
1547
- this._runAbortController?.signal.aborted ||
1548
- this.sessionBudget?.signal?.aborted,
1549
+ this._abortController.signal.aborted ||
1550
+ this._runAbortController?.signal.aborted ||
1551
+ this.sessionBudget?.signal?.aborted,
1549
1552
  );
1550
1553
  }
1551
1554