chainlesschain 0.165.1 → 0.165.3

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 (206) hide show
  1. package/README.md +248 -2
  2. package/package.json +4 -1
  3. package/src/assets/web-panel/assets/{AIOps-CYxFDrcm.js → AIOps-BiHNUlbU.js} +1 -1
  4. package/src/assets/web-panel/assets/{ActionButton-CPBtdiU2.js → ActionButton-D-UFjDRQ.js} +1 -1
  5. package/src/assets/web-panel/assets/{Analytics-Dayq7Dp7.js → Analytics-DazVsDgW.js} +3 -3
  6. package/src/assets/web-panel/assets/{AppLayout-6U7bPb2s.js → AppLayout-DXh9UfNJ.js} +5 -5
  7. package/src/assets/web-panel/assets/{Artifacts-D2Iqg_3D.js → Artifacts-CZ6tsceY.js} +1 -1
  8. package/src/assets/web-panel/assets/{Audit-CdoOB7WV.js → Audit-RyxnBr_h.js} +1 -1
  9. package/src/assets/web-panel/assets/{BackgroundAgents-DrnAVB8w.js → BackgroundAgents-BWS51Q6X.js} +1 -1
  10. package/src/assets/web-panel/assets/{Backup-CesMi5cy.js → Backup-BRtPcUul.js} +1 -1
  11. package/src/assets/web-panel/assets/{BaseInput-DaX9ptax.js → BaseInput-CGd4vZYY.js} +1 -1
  12. package/src/assets/web-panel/assets/{Chat-OrwOPxDS.js → Chat-h8ijVwCg.js} +4 -4
  13. package/src/assets/web-panel/assets/{ChatBubbleRenderer-CvPZFRxM.js → ChatBubbleRenderer-D7tcdDS9.js} +1 -1
  14. package/src/assets/web-panel/assets/{Checkbox-DiHbcysC.js → Checkbox-NyF6dPl8.js} +1 -1
  15. package/src/assets/web-panel/assets/{Codegen-CbgCkaBJ.js → Codegen-Ci4OOxr5.js} +1 -1
  16. package/src/assets/web-panel/assets/{Col-Du5hgrh4.js → Col-CwTkc9BM.js} +1 -1
  17. package/src/assets/web-panel/assets/{Community-DsPOBW-p.js → Community-DW_tM82m.js} +1 -1
  18. package/src/assets/web-panel/assets/{Compact-BwHIFkNC.js → Compact-DEvHRV4S.js} +1 -1
  19. package/src/assets/web-panel/assets/{Compliance-BvrDQSgd.js → Compliance-BbjBEEfD.js} +1 -1
  20. package/src/assets/web-panel/assets/{Cowork-gwAE6arx.js → Cowork-10IXBaBa.js} +2 -2
  21. package/src/assets/web-panel/assets/{Cron-DW-0l4uF.js → Cron-BZkbpd5I.js} +2 -2
  22. package/src/assets/web-panel/assets/{Crosschain-j-NsLesB.js → Crosschain-CFQ8L_6v.js} +1 -1
  23. package/src/assets/web-panel/assets/{DID-CibVEBOI.js → DID-BDF6AkXe.js} +2 -2
  24. package/src/assets/web-panel/assets/{Dashboard-W4z9vSfe.js → Dashboard-CoOdWMi4.js} +2 -2
  25. package/src/assets/web-panel/assets/{Dropdown-DAcrkKxG.js → Dropdown-DEsGmu8Y.js} +1 -1
  26. package/src/assets/web-panel/assets/{EmailListRenderer-6GXah-89.js → EmailListRenderer-BS89SWlK.js} +1 -1
  27. package/src/assets/web-panel/assets/{FamilyGuardDashboard-TKDCq8Ku.js → FamilyGuardDashboard-C1FpCHiI.js} +1 -1
  28. package/src/assets/web-panel/assets/{Federation-BXBLlcNm.js → Federation-BzvpVmLA.js} +1 -1
  29. package/src/assets/web-panel/assets/{FormItemContext-BoJJBkG3.js → FormItemContext-BeC259PQ.js} +1 -1
  30. package/src/assets/web-panel/assets/{GenericCardRenderer-okjsl46v.js → GenericCardRenderer-azgG3bmV.js} +1 -1
  31. package/src/assets/web-panel/assets/{Git-Rvs7i6nn.js → Git-BmSSowc5.js} +2 -2
  32. package/src/assets/web-panel/assets/{Governance-CHSUxXXS.js → Governance-CTBCSyQZ.js} +1 -1
  33. package/src/assets/web-panel/assets/{Inference-V3BlfxsB.js → Inference-DA5xyk4a.js} +1 -1
  34. package/src/assets/web-panel/assets/{KnowledgeGraph-C_NlD4aR.js → KnowledgeGraph-D1gPHNig.js} +1 -1
  35. package/src/assets/web-panel/assets/{Logs-Nn4LNxhA.js → Logs-BPmLf1AR.js} +2 -2
  36. package/src/assets/web-panel/assets/{MarkdownRenderer-SVAgNnkt.js → MarkdownRenderer-SVLOg49H.js} +1 -1
  37. package/src/assets/web-panel/assets/{Marketplace-DEmjFcg-.js → Marketplace-DtUFcR0E.js} +1 -1
  38. package/src/assets/web-panel/assets/{McpTools-DlopXipI.js → McpTools-DS_kqBv-.js} +3 -3
  39. package/src/assets/web-panel/assets/{Memory-BG3ynX60.js → Memory-Fvh7XL7V.js} +2 -2
  40. package/src/assets/web-panel/assets/{MobileBridge-DeRzWOfT.js → MobileBridge-C7itAP45.js} +1 -1
  41. package/src/assets/web-panel/assets/MobileProjects-DGbP36-3.js +1 -0
  42. package/src/assets/web-panel/assets/{Mtc-BoPbOv1C.js → Mtc-B57MiNLK.js} +6 -6
  43. package/src/assets/web-panel/assets/{MtcAudit-un-rTHp7.js → MtcAudit-BXfCUcM7.js} +4 -4
  44. package/src/assets/web-panel/assets/{Multisig-Ds0oveEB.js → Multisig-yaJ-ZcF6.js} +3 -3
  45. package/src/assets/web-panel/assets/{NLProgramming-D09JI-yY.js → NLProgramming-CoaUCKrO.js} +1 -1
  46. package/src/assets/web-panel/assets/{Notes-DTRhiKJn.js → Notes-BKLM_65R.js} +3 -3
  47. package/src/assets/web-panel/assets/{NotificationSettings-BAnnNCim.js → NotificationSettings-DoDtK9uZ.js} +1 -1
  48. package/src/assets/web-panel/assets/{OrderTableRenderer-Yr-1fSYi.js → OrderTableRenderer-BJ28TGr-.js} +1 -1
  49. package/src/assets/web-panel/assets/{Organization-S9EAolpj.js → Organization-MuGsdoIb.js} +4 -4
  50. package/src/assets/web-panel/assets/{Overflow-CqcLKqJ8.js → Overflow-BLUN9J4R.js} +1 -1
  51. package/src/assets/web-panel/assets/{P2P-Dw0F9EcU.js → P2P-DWuoBUPd.js} +2 -2
  52. package/src/assets/web-panel/assets/{PdhVaultBrowser-BDRwUevN.js → PdhVaultBrowser-CUi37YPj.js} +3 -3
  53. package/src/assets/web-panel/assets/{Permissions-D3_c3nKB.js → Permissions-BYQg2pcr.js} +4 -4
  54. package/src/assets/web-panel/assets/{PersonalDataHub-CxdMV98x.js → PersonalDataHub-CAxoV2xu.js} +6 -6
  55. package/src/assets/web-panel/assets/{Pipeline-CgjNQFLI.js → Pipeline-B33wGvIO.js} +1 -1
  56. package/src/assets/web-panel/assets/{Privacy-BHghIIht.js → Privacy-A8yXTORP.js} +1 -1
  57. package/src/assets/web-panel/assets/{ProjectInit-De6pqaKM.js → ProjectInit-D49I2I1O.js} +2 -2
  58. package/src/assets/web-panel/assets/{ProjectSettings-Bg4ZkNYQ.js → ProjectSettings-Ci73jJDw.js} +2 -2
  59. package/src/assets/web-panel/assets/Projects-CF-yD6Cn.js +1 -0
  60. package/src/assets/web-panel/assets/Providers-D-etEhg5.js +1 -0
  61. package/src/assets/web-panel/assets/{QrScannerModal-DA2f3Wts.js → QrScannerModal-Brza0ykJ.js} +1 -1
  62. package/src/assets/web-panel/assets/{QuickAsk-C1FeHDqp.js → QuickAsk-DFydhjxL.js} +1 -1
  63. package/src/assets/web-panel/assets/{Recommend-B5guaUMN.js → Recommend-DLF8_NhA.js} +1 -1
  64. package/src/assets/web-panel/assets/{RemoteSession-PDADSds3.js → RemoteSession-dyuStW3x.js} +3 -3
  65. package/src/assets/web-panel/assets/{Reputation-eTlRhgvK.js → Reputation-5F3tA6yw.js} +1 -1
  66. package/src/assets/web-panel/assets/{Row-D7AqSGY0.js → Row-Ca2A57S5.js} +1 -1
  67. package/src/assets/web-panel/assets/{RssFeed-JiuLm4Ja.js → RssFeed-B0bxBkq_.js} +3 -3
  68. package/src/assets/web-panel/assets/{Search-CwruahW3.js → Search-CFNvHalZ.js} +1 -1
  69. package/src/assets/web-panel/assets/{Security-CdhqaR0b.js → Security-DSoH3Hav.js} +4 -4
  70. package/src/assets/web-panel/assets/{Services-CU0ZIlcT.js → Services-BHpfEmBQ.js} +2 -2
  71. package/src/assets/web-panel/assets/{Skeleton-CtduPfAb.js → Skeleton-Dsh-QNmn.js} +1 -1
  72. package/src/assets/web-panel/assets/{Skills-CROXm6AY.js → Skills-BhT1NkSU.js} +1 -1
  73. package/src/assets/web-panel/assets/{Sla-DiZiABFD.js → Sla-DY9snPeJ.js} +1 -1
  74. package/src/assets/web-panel/assets/{SpeechSettings-B5pLcXUw.js → SpeechSettings-CWaX0_Cx.js} +1 -1
  75. package/src/assets/web-panel/assets/{SyncSettings-DBX6J1Oe.js → SyncSettings-B690y_TC.js} +2 -2
  76. package/src/assets/web-panel/assets/{Tasks-BLyRJd3-.js → Tasks-2N-w3zWd.js} +1 -1
  77. package/src/assets/web-panel/assets/{Templates-BKa5qzmk.js → Templates-BjwQOQYC.js} +1 -1
  78. package/src/assets/web-panel/assets/{Tenant-DnD3a4M6.js → Tenant-CUqHErxY.js} +1 -1
  79. package/src/assets/web-panel/assets/{Terminal-DEitQeTb.js → Terminal-C13rXvNy.js} +2 -2
  80. package/src/assets/web-panel/assets/{TimelineRenderer-CjHggTDq.js → TimelineRenderer-CpbWcya_.js} +1 -1
  81. package/src/assets/web-panel/assets/{Tokens-CsGT7sfl.js → Tokens-BXHLGXYC.js} +1 -1
  82. package/src/assets/web-panel/assets/{Trigger-yr4rFDrW.js → Trigger-1e5i65o3.js} +1 -1
  83. package/src/assets/web-panel/assets/{Trust-CLvu1Sjp.js → Trust-FLGqNHs5.js} +1 -1
  84. package/src/assets/web-panel/assets/{UkeySign-B0m7yUP8.js → UkeySign-BbaR_LJB.js} +1 -1
  85. package/src/assets/web-panel/assets/{VideoEditing-C0VvP4lc.js → VideoEditing-NOp4RIov.js} +1 -1
  86. package/src/assets/web-panel/assets/{Wallet-kllBAG1M.js → Wallet-B7DW7bG4.js} +4 -4
  87. package/src/assets/web-panel/assets/{WebAuthn-C54UQNLx.js → WebAuthn-BptSUWix.js} +5 -5
  88. package/src/assets/web-panel/assets/{WorkflowEditor-B7y8qSvU.js → WorkflowEditor-CAJnDOXS.js} +1 -1
  89. package/src/assets/web-panel/assets/{chat-DRzTh8CJ.js → chat-I8LgG1-Z.js} +1 -1
  90. package/src/assets/web-panel/assets/{colors-BSMwSnCx.js → colors-CWe7SOVD.js} +1 -1
  91. package/src/assets/web-panel/assets/{compact-item-BTg602H5.js → compact-item-Cx3u3CA3.js} +1 -1
  92. package/src/assets/web-panel/assets/{createContext-B6EGsdvp.js → createContext-CgD5ArwY.js} +1 -1
  93. package/src/assets/web-panel/assets/devWarning-DLv_872g.js +1 -0
  94. package/src/assets/web-panel/assets/{hasIn-DDKqJ8RD.js → hasIn-BfQWiXN8.js} +1 -1
  95. package/src/assets/web-panel/assets/{index-D5CsBShd.js → index-3iKP9OTJ.js} +1 -1
  96. package/src/assets/web-panel/assets/{index-Dfv2lKu3.js → index-87gMxqhN.js} +1 -1
  97. package/src/assets/web-panel/assets/{index-C66NpWy5.js → index-B1cX4Rxu.js} +1 -1
  98. package/src/assets/web-panel/assets/{index-DBT3YeQ9.js → index-B6yChzt1.js} +1 -1
  99. package/src/assets/web-panel/assets/{index-BVTAl5N2.js → index-BREnPKGo.js} +1 -1
  100. package/src/assets/web-panel/assets/{index-CwPUZbMI.js → index-BUAR7RY-.js} +1 -1
  101. package/src/assets/web-panel/assets/{index-th2ihDc0.js → index-Bi24S7Dw.js} +1 -1
  102. package/src/assets/web-panel/assets/{index-CmAubjDi.js → index-BiI-xPRH.js} +1 -1
  103. package/src/assets/web-panel/assets/{index-CUEU48o1.js → index-BuEQSorC.js} +1 -1
  104. package/src/assets/web-panel/assets/{index-Cf23wVMs.js → index-Bx7BNIRH.js} +1 -1
  105. package/src/assets/web-panel/assets/{index-BRqt4fO-.js → index-C-rIKccl.js} +1 -1
  106. package/src/assets/web-panel/assets/{index-C_JzIXUq.js → index-C0nDKhWv.js} +1 -1
  107. package/src/assets/web-panel/assets/{index-DiW0sDkz.js → index-C0ztiqtB.js} +1 -1
  108. package/src/assets/web-panel/assets/{index-BICn3Qh1.js → index-C1UjHdgZ.js} +1 -1
  109. package/src/assets/web-panel/assets/{index-DpTHIRfZ.js → index-CAUnl4Jv.js} +1 -1
  110. package/src/assets/web-panel/assets/{index-Co7oM1qr.js → index-CMu16vPC.js} +1 -1
  111. package/src/assets/web-panel/assets/{index-CNxg61YP.js → index-CNYFQxAW.js} +1 -1
  112. package/src/assets/web-panel/assets/{index-XFe-1twF.js → index-CQDKYbnv.js} +1 -1
  113. package/src/assets/web-panel/assets/{index-p2HYn89m.js → index-CWZ3REg6.js} +3 -3
  114. package/src/assets/web-panel/assets/{index-Bx044qDj.js → index-CcX4FSPf.js} +1 -1
  115. package/src/assets/web-panel/assets/{index-BMuGd2--.js → index-Cd79NQAx.js} +1 -1
  116. package/src/assets/web-panel/assets/{index-CGNklbP6.js → index-CdRkCwm4.js} +1 -1
  117. package/src/assets/web-panel/assets/index-CdiGCibe.js +1 -0
  118. package/src/assets/web-panel/assets/{index-rjzk9z1Q.js → index-Cy_cCJlr.js} +1 -1
  119. package/src/assets/web-panel/assets/{index-323Hhxxt.js → index-DAVy98u7.js} +1 -1
  120. package/src/assets/web-panel/assets/{index-CDTvsX8t.js → index-DCJEY2T0.js} +1 -1
  121. package/src/assets/web-panel/assets/{index-DLdrHhML.js → index-DFb-XIKy.js} +1 -1
  122. package/src/assets/web-panel/assets/{index-pqfux8vZ.js → index-DGMYTN5W.js} +1 -1
  123. package/src/assets/web-panel/assets/index-D_0z-gyz.js +1 -0
  124. package/src/assets/web-panel/assets/{index-u2YVld9W.js → index-Dcdm_Z2c.js} +1 -1
  125. package/src/assets/web-panel/assets/{index-CmAInUkX.js → index-DeizoQVZ.js} +1 -1
  126. package/src/assets/web-panel/assets/{index-CHfLYwcW.js → index-DlIyt1qF.js} +1 -1
  127. package/src/assets/web-panel/assets/{index-CWGax2QW.js → index-DmgtY58H.js} +1 -1
  128. package/src/assets/web-panel/assets/{index-Dc77VR3H.js → index-DmrdUwzU.js} +1 -1
  129. package/src/assets/web-panel/assets/{index-D1naNj4U.js → index-Doc0Ftpd.js} +1 -1
  130. package/src/assets/web-panel/assets/{index-BsR7Y2NG.js → index-DsQcURkA.js} +1 -1
  131. package/src/assets/web-panel/assets/{index-CQlHFN_g.js → index-DslTuqro.js} +1 -1
  132. package/src/assets/web-panel/assets/{index-DqFXGzzC.js → index-V-kIHzAV.js} +1 -1
  133. package/src/assets/web-panel/assets/{index-C1GFfuqN.js → index-e8BM1yY1.js} +1 -1
  134. package/src/assets/web-panel/assets/{initDefaultProps-C3Djh9fa.js → initDefaultProps-DiBszVdG.js} +1 -1
  135. package/src/assets/web-panel/assets/{motion-BzqFmbSe.js → motion-BGIFFozv.js} +1 -1
  136. package/src/assets/web-panel/assets/{move-DJo_FFaW.js → move-D5W7mp7B.js} +1 -1
  137. package/src/assets/web-panel/assets/{mtc-parser-_tlTiBvk.js → mtc-parser-JFIlxJ7F.js} +1 -1
  138. package/src/assets/web-panel/assets/{omit-CB2ZyxUg.js → omit-CQ3o6LIU.js} +1 -1
  139. package/src/assets/web-panel/assets/{pickAttrs-DZwIFD4u.js → pickAttrs-R8MIlXo3.js} +1 -1
  140. package/src/assets/web-panel/assets/{placementArrow-DxZY0dgk.js → placementArrow-sW7ylSky.js} +1 -1
  141. package/src/assets/web-panel/assets/{responsiveObserve-CzzGt7GL.js → responsiveObserve-Cnl39Vbz.js} +1 -1
  142. package/src/assets/web-panel/assets/{slide-BaIK52yz.js → slide-sn8tFd14.js} +1 -1
  143. package/src/assets/web-panel/assets/{statusUtils-3-FHu9_M.js → statusUtils-IKKY_QxZ.js} +1 -1
  144. package/src/assets/web-panel/assets/{styleChecker-BkRT68fK.js → styleChecker-BNpV4Nqs.js} +1 -1
  145. package/src/assets/web-panel/assets/{useFlexGapSupport-DHYwKS-s.js → useFlexGapSupport-BWyT_eoU.js} +1 -1
  146. package/src/assets/web-panel/assets/{useFs-DVVUhV8p.js → useFs-D09p6_U9.js} +1 -1
  147. package/src/assets/web-panel/assets/{usePersonalDataHub-CkrFKAzQ.js → usePersonalDataHub-CzW3TkJZ.js} +1 -1
  148. package/src/assets/web-panel/assets/{vnode-BuBLFz0c.js → vnode-3s3WoAKB.js} +1 -1
  149. package/src/assets/web-panel/assets/{zoom-kpm6LtXU.js → zoom-Cjy_673s.js} +1 -1
  150. package/src/assets/web-panel/index.html +1 -1
  151. package/src/command-help-index.json +1 -1
  152. package/src/commands/cowork.js +280 -5
  153. package/src/commands/plugin.js +819 -64
  154. package/src/commands/session-location.js +318 -7
  155. package/src/constants.js +2 -2
  156. package/src/data/changelog.json +27 -1
  157. package/src/gateways/ws/action-protocol.js +1 -1
  158. package/src/harness/jsonl-session-store.js +638 -2
  159. package/src/harness/prompt-compressor.js +4 -0
  160. package/src/lib/background-agent-keeper-client.js +29 -0
  161. package/src/lib/background-agent-keeper-protocol.js +78 -3
  162. package/src/lib/background-agent-launch-barrier.js +74 -0
  163. package/src/lib/background-agent-supervisor.js +208 -34
  164. package/src/lib/background-turn-bootstrap-protocol.js +4 -0
  165. package/src/lib/cowork-task-runner.js +70 -0
  166. package/src/lib/cowork-workflow.js +42 -9
  167. package/src/lib/doctor-checkup.js +34 -10
  168. package/src/lib/dynamic-workflow-draft.js +535 -0
  169. package/src/lib/dynamic-workflow-facade.js +11 -11
  170. package/src/lib/dynamic-workflow-runtime.js +2974 -0
  171. package/src/lib/execution-location-contract.js +111 -7
  172. package/src/lib/execution-location-runtime.js +3 -1
  173. package/src/lib/execution-location-target.js +910 -0
  174. package/src/lib/llm-providers.js +1 -0
  175. package/src/lib/mcp-call-ledger-store.js +35 -0
  176. package/src/lib/mcp-call-ledger.js +30 -0
  177. package/src/lib/plugin-runtime/__tests__/remote-source.test.js +34 -16
  178. package/src/lib/plugin-runtime/install.js +4956 -657
  179. package/src/lib/plugin-runtime/manifest.js +3 -1
  180. package/src/lib/plugin-runtime/marketplace-artifact-readback.js +671 -31
  181. package/src/lib/plugin-runtime/marketplace-catalog.js +68 -2
  182. package/src/lib/plugin-runtime/marketplace-impact.js +208 -15
  183. package/src/lib/plugin-runtime/marketplace-network.js +317 -0
  184. package/src/lib/plugin-runtime/marketplace-pac-worker.js +15 -0
  185. package/src/lib/plugin-runtime/marketplace-remote-artifacts.js +25 -2
  186. package/src/lib/plugin-runtime/marketplace-source-cache.js +359 -0
  187. package/src/lib/plugin-runtime/policy.js +21 -6
  188. package/src/lib/plugin-runtime/publisher-trust.js +332 -0
  189. package/src/lib/plugin-runtime/remote-source.js +323 -27
  190. package/src/lib/plugin-runtime/scopes.js +317 -41
  191. package/src/lib/plugin-runtime/transaction-journal.js +806 -0
  192. package/src/lib/public-ide-capability-manifest.js +1 -1
  193. package/src/lib/remote-membership-coordinator.js +8 -6
  194. package/src/lib/sub-agent-context.js +268 -2
  195. package/src/lib/task-model-selector.js +1 -1
  196. package/src/lib/with-file-lock.js +266 -27
  197. package/src/runtime/agent-core.js +595 -41
  198. package/src/workers/background-agent-keeper.js +147 -24
  199. package/src/workers/background-agent-worker.js +383 -134
  200. package/src/workers/background-turn-bootstrap.js +13 -8
  201. package/src/assets/web-panel/assets/MobileProjects-Tyd3o2A0.js +0 -1
  202. package/src/assets/web-panel/assets/Projects-CP8vPvzs.js +0 -1
  203. package/src/assets/web-panel/assets/Providers-CUnHbNf-.js +0 -1
  204. package/src/assets/web-panel/assets/devWarning-Dol8jLEP.js +0 -1
  205. package/src/assets/web-panel/assets/index-C3QX5tOl.js +0 -1
  206. package/src/assets/web-panel/assets/index-xYybvEic.js +0 -1
@@ -3583,6 +3583,10 @@ export async function executeTool(name, args, context = {}) {
3583
3583
  sessionId: context.sessionId || null,
3584
3584
  turnId: context.turnId || null,
3585
3585
  toolCallId: context.toolCallId || null,
3586
+ workflowEffectId: context.workflowEffectId || null,
3587
+ workflowChildEffectId: context.workflowChildEffectId || null,
3588
+ workflowChildSequence: context.workflowChildSequence || null,
3589
+ workflowEffectProtocol: context.workflowEffectProtocol || null,
3586
3590
  // Parent LLM config — documented at toolContext as forwarded to
3587
3591
  // spawn_sub_agent for provider/key inheritance; without this line it
3588
3592
  // never actually reached executeToolInner (sub-agents silently fell
@@ -4969,6 +4973,10 @@ async function executeToolInner(
4969
4973
  sessionId,
4970
4974
  turnId,
4971
4975
  toolCallId,
4976
+ workflowEffectId = null,
4977
+ workflowChildEffectId = null,
4978
+ workflowChildSequence = null,
4979
+ workflowEffectProtocol = null,
4972
4980
  planManager = null,
4973
4981
  permissionRules = null,
4974
4982
  effectiveAllowedToolNames = null,
@@ -6713,6 +6721,10 @@ async function executeToolInner(
6713
6721
  interaction,
6714
6722
  sessionId,
6715
6723
  llmOptions,
6724
+ workflowEffectId,
6725
+ workflowChildEffectId,
6726
+ workflowChildSequence,
6727
+ workflowEffectProtocol,
6716
6728
  subAgentDepth,
6717
6729
  subAgentBudget,
6718
6730
  sessionBudget,
@@ -7646,6 +7658,9 @@ async function executeToolInner(
7646
7658
  ? event
7647
7659
  : {
7648
7660
  ...event,
7661
+ ...(["model", "semantic-compaction"].includes(event?.source)
7662
+ ? { workflowRequestSource: event.source }
7663
+ : {}),
7649
7664
  source:
7650
7665
  event?.source === "semantic-compaction"
7651
7666
  ? "semantic-compaction"
@@ -7721,6 +7736,9 @@ async function executeToolInner(
7721
7736
  toolAdmission,
7722
7737
  cwd,
7723
7738
  llmOptions: skillLlmOptions,
7739
+ ...(strictUsageTelemetry === true && workflowChildEffectId
7740
+ ? { workflowEffectId: workflowChildEffectId }
7741
+ : {}),
7724
7742
  ...(sessionBudget ? { sessionBudget } : {}),
7725
7743
  ...(permissionRules ? { permissionRules } : {}),
7726
7744
  ...(hostManagedToolPolicy
@@ -7811,7 +7829,12 @@ async function executeToolInner(
7811
7829
  toolsUsed: result.toolsUsed,
7812
7830
  });
7813
7831
  } catch (err) {
7814
- if (err?.runtimeLedgerPersistence === true) throw err;
7832
+ if (
7833
+ err?.runtimeLedgerPersistence === true ||
7834
+ err?.workflowEffectOutcomeUnknown === true
7835
+ ) {
7836
+ throw err;
7837
+ }
7815
7838
  if (
7816
7839
  signal?.aborted ||
7817
7840
  skillExecutionSignal?.aborted ||
@@ -8035,6 +8058,14 @@ async function executeToolInner(
8035
8058
  ledgerTicket = await ledger.begin({
8036
8059
  sessionId,
8037
8060
  turnId,
8061
+ ...(workflowEffectId
8062
+ ? {
8063
+ workflowEffectId,
8064
+ workflowChildEffectId,
8065
+ workflowChildSequence,
8066
+ workflowEffectProtocol,
8067
+ }
8068
+ : {}),
8038
8069
  toolName: localToolExecutor.toolName,
8039
8070
  serverName: localToolExecutor.serverName,
8040
8071
  input: mcpWireInput,
@@ -8108,12 +8139,20 @@ async function executeToolInner(
8108
8139
  localToolExecutor.toolName,
8109
8140
  mcpWireInput,
8110
8141
  ];
8111
- if (signal || mcpDispatchAdmission) {
8142
+ if (signal || mcpDispatchAdmission || workflowEffectId) {
8112
8143
  callArguments.push({
8113
8144
  ...(signal ? { signal } : {}),
8114
8145
  ...(mcpDispatchAdmission
8115
8146
  ? { dispatchAdmission: mcpDispatchAdmission }
8116
8147
  : {}),
8148
+ ...(workflowEffectId
8149
+ ? {
8150
+ workflowEffectId,
8151
+ workflowChildEffectId,
8152
+ workflowChildSequence,
8153
+ workflowEffectProtocol,
8154
+ }
8155
+ : {}),
8117
8156
  });
8118
8157
  }
8119
8158
  pendingResult = Reflect.apply(
@@ -8242,8 +8281,9 @@ async function executeToolInner(
8242
8281
  );
8243
8282
  }
8244
8283
 
8284
+ let settledLedgerRecord;
8245
8285
  try {
8246
- await ledgerTicket.settle(
8286
+ settledLedgerRecord = await ledgerTicket.settle(
8247
8287
  protocolError
8248
8288
  ? {
8249
8289
  status: "failed",
@@ -8265,11 +8305,26 @@ async function executeToolInner(
8265
8305
  }
8266
8306
 
8267
8307
  const mcpLedgerId = safeMcpProperty(ledgerTicket, "ledgerId") || null;
8308
+ const mcpLedgerPrewritePersisted =
8309
+ safeMcpProperty(ledgerTicket, "prewritePersisted") === true;
8310
+ const mcpLedgerSettlementPersisted =
8311
+ safeMcpProperty(settledLedgerRecord, "settlementPersistence") ===
8312
+ "persisted";
8268
8313
  try {
8269
8314
  if (result && typeof result === "object") {
8270
- return attachDescriptor({ ...result, mcpLedgerId });
8315
+ return attachDescriptor({
8316
+ ...result,
8317
+ mcpLedgerId,
8318
+ mcpLedgerPrewritePersisted,
8319
+ mcpLedgerSettlementPersisted,
8320
+ });
8271
8321
  }
8272
- return attachDescriptor({ result, mcpLedgerId });
8322
+ return attachDescriptor({
8323
+ result,
8324
+ mcpLedgerId,
8325
+ mcpLedgerPrewritePersisted,
8326
+ mcpLedgerSettlementPersisted,
8327
+ });
8273
8328
  } catch (projectionError) {
8274
8329
  return attachDescriptor({
8275
8330
  error:
@@ -8296,7 +8351,18 @@ async function executeToolInner(
8296
8351
  interaction &&
8297
8352
  typeof interaction.requestHostTool === "function"
8298
8353
  ) {
8299
- const hostedResult = await interaction.requestHostTool(name, args);
8354
+ const hostedResult = workflowEffectId
8355
+ ? await interaction.requestHostTool(
8356
+ name,
8357
+ args,
8358
+ Object.freeze({
8359
+ workflowEffectId,
8360
+ workflowChildEffectId,
8361
+ workflowChildSequence,
8362
+ workflowEffectProtocol,
8363
+ }),
8364
+ )
8365
+ : await interaction.requestHostTool(name, args);
8300
8366
  if (hostedResult?.success === false) {
8301
8367
  return attachDescriptor({
8302
8368
  error:
@@ -8959,7 +9025,12 @@ function _backgroundSubAgentResultText(entry) {
8959
9025
 
8960
9026
  function _throwBackgroundSubAgentUsageFailure(entry) {
8961
9027
  const error = entry?.outcome?.fatalError;
8962
- if (error?.runtimeLedgerPersistence === true) throw error;
9028
+ if (
9029
+ error?.runtimeLedgerPersistence === true ||
9030
+ error?.workflowEffectOutcomeUnknown === true
9031
+ ) {
9032
+ throw error;
9033
+ }
8963
9034
  }
8964
9035
 
8965
9036
  function _throwSettledBackgroundUsageFailure(map) {
@@ -9514,6 +9585,9 @@ async function _executeSpawnSubAgent(args, ctx) {
9514
9585
  ? u
9515
9586
  : {
9516
9587
  ...u,
9588
+ ...(["model", "semantic-compaction"].includes(u?.source)
9589
+ ? { workflowRequestSource: u.source }
9590
+ : {}),
9517
9591
  source:
9518
9592
  u?.source === "semantic-compaction"
9519
9593
  ? "semantic-compaction"
@@ -9663,6 +9737,9 @@ async function _executeSpawnSubAgent(args, ctx) {
9663
9737
  cwd: ctx.cwd,
9664
9738
  profile: profile || null,
9665
9739
  llmOptions: subLlmOptions,
9740
+ ...(ctx.strictUsageTelemetry === true && ctx.workflowChildEffectId
9741
+ ? { workflowEffectId: ctx.workflowChildEffectId }
9742
+ : {}),
9666
9743
  depth: currentDepth + 1, // nested spawns see their own level
9667
9744
  // Same shared counter object so the child's own spawns draw from the run's
9668
9745
  // single total-sub-agent pool (breadth cap spans the whole tree).
@@ -9864,7 +9941,8 @@ async function _executeSpawnSubAgent(args, ctx) {
9864
9941
  return {
9865
9942
  result: subCtx.result,
9866
9943
  error: err.message,
9867
- ...(err?.runtimeLedgerPersistence === true
9944
+ ...(err?.runtimeLedgerPersistence === true ||
9945
+ err?.workflowEffectOutcomeUnknown === true
9868
9946
  ? { fatalError: err }
9869
9947
  : {}),
9870
9948
  };
@@ -9997,7 +10075,12 @@ async function _executeSpawnSubAgent(args, ctx) {
9997
10075
  completedAt: subCtx.completedAt,
9998
10076
  });
9999
10077
 
10000
- if (err?.runtimeLedgerPersistence === true) throw err;
10078
+ if (
10079
+ err?.runtimeLedgerPersistence === true ||
10080
+ err?.workflowEffectOutcomeUnknown === true
10081
+ ) {
10082
+ throw err;
10083
+ }
10001
10084
 
10002
10085
  return {
10003
10086
  error: `Sub-agent failed: ${err.message}`,
@@ -10077,6 +10160,72 @@ function _hasCompleteProviderUsage(usage) {
10077
10160
  );
10078
10161
  }
10079
10162
 
10163
+ const PROVIDER_REQUEST_ID_RE = /^[\x21-\x7e]{1,512}$/;
10164
+ const PROVIDER_RECEIPT_ID_RE = /^[A-Za-z0-9._:-]{1,256}$/;
10165
+
10166
+ function _normalizeProviderRequestId(value) {
10167
+ if (value == null) return null;
10168
+ if (typeof value !== "string" || !PROVIDER_REQUEST_ID_RE.test(value)) {
10169
+ throw new TypeError(
10170
+ "providerRequestId must be 1-512 printable ASCII characters",
10171
+ );
10172
+ }
10173
+ return value;
10174
+ }
10175
+
10176
+ function _physicalProviderRequestId(logicalRequestId, attempt) {
10177
+ if (!logicalRequestId) return null;
10178
+ const retry = Number(attempt);
10179
+ if (!Number.isSafeInteger(retry) || retry <= 0) return logicalRequestId;
10180
+ const suffix = `-r${retry}`;
10181
+ return `${logicalRequestId.slice(0, 512 - suffix.length)}${suffix}`;
10182
+ }
10183
+
10184
+ function _providerReceiptId(value) {
10185
+ return typeof value === "string" && PROVIDER_RECEIPT_ID_RE.test(value)
10186
+ ? value
10187
+ : null;
10188
+ }
10189
+
10190
+ function _isOfficialOpenAIEndpoint(provider, baseUrl) {
10191
+ if (provider !== "openai") return false;
10192
+ try {
10193
+ const parsed = new URL(String(baseUrl));
10194
+ return (
10195
+ parsed.protocol === "https:" &&
10196
+ parsed.hostname.toLowerCase() === "api.openai.com" &&
10197
+ !parsed.port &&
10198
+ !parsed.username &&
10199
+ !parsed.password
10200
+ );
10201
+ } catch {
10202
+ return false;
10203
+ }
10204
+ }
10205
+
10206
+ /**
10207
+ * Capture only provider-returned identifiers. X-Client-Request-Id is a
10208
+ * trace/correlation header, not an idempotency guarantee, so a locally sent
10209
+ * client id alone is deliberately not called a receipt.
10210
+ */
10211
+ function _openAIProviderRequestReceipt(response, data, clientRequestId) {
10212
+ if (!clientRequestId) return null;
10213
+ const requestId = _providerReceiptId(
10214
+ response?.headers?.get?.("x-request-id"),
10215
+ );
10216
+ const responseId = _providerReceiptId(data?.id);
10217
+ if (!requestId && !responseId) return null;
10218
+ return Object.freeze({
10219
+ protocol: "cc-provider-request-receipt/v1",
10220
+ provider: "openai",
10221
+ clientRequestId,
10222
+ requestId,
10223
+ responseId,
10224
+ requestIdentitySemantics: "trace-only",
10225
+ independentlyReadable: false,
10226
+ });
10227
+ }
10228
+
10080
10229
  /**
10081
10230
  * Send a chat completion request with tool definitions.
10082
10231
  * Supports 8 providers: ollama, anthropic, openai, deepseek, dashscope, gemini, mistral, volcengine
@@ -10095,6 +10244,10 @@ export async function chatWithTools(rawMessages, options) {
10095
10244
  signal,
10096
10245
  } = options;
10097
10246
 
10247
+ const providerRequestId = _normalizeProviderRequestId(
10248
+ options.providerRequestId,
10249
+ );
10250
+
10098
10251
  const tools = getEffectiveToolDefinitions(options);
10099
10252
 
10100
10253
  const lastUserMsg = [...rawMessages].reverse().find((m) => m.role === "user");
@@ -10140,6 +10293,7 @@ export async function chatWithTools(rawMessages, options) {
10140
10293
  ),
10141
10294
  {
10142
10295
  signal,
10296
+ retries: options.workflowEffectId ? 0 : undefined,
10143
10297
  strictRetryObserver: options.strictUsageTelemetry === true,
10144
10298
  ...(typeof options.onStreamRetry === "function"
10145
10299
  ? {
@@ -10289,6 +10443,7 @@ export async function chatWithTools(rawMessages, options) {
10289
10443
  ),
10290
10444
  {
10291
10445
  signal,
10446
+ retries: options.workflowEffectId ? 0 : undefined,
10292
10447
  strictRetryObserver: options.strictUsageTelemetry === true,
10293
10448
  ...(typeof options.onStreamRetry === "function"
10294
10449
  ? {
@@ -10381,6 +10536,10 @@ export async function chatWithTools(rawMessages, options) {
10381
10536
  `Unsupported provider: ${provider}. Supported: ollama, anthropic, openai, deepseek, dashscope, mistral, gemini, volcengine`,
10382
10537
  );
10383
10538
  }
10539
+ const supportsOpenAIRequestIdentity = _isOfficialOpenAIEndpoint(
10540
+ provider,
10541
+ url,
10542
+ );
10384
10543
 
10385
10544
  const envKey = providerApiKeyEnvs[provider] || "OPENAI_API_KEY";
10386
10545
  const key = apiKey || process.env[envKey];
@@ -10392,7 +10551,7 @@ export async function chatWithTools(rawMessages, options) {
10392
10551
  dashscope: "qwen-turbo",
10393
10552
  mistral: "mistral-large-latest",
10394
10553
  gemini: "gemini-2.0-flash",
10395
- volcengine: "doubao-seed-2-1-pro-260628",
10554
+ volcengine: "deepseek-v4-flash-260425",
10396
10555
  };
10397
10556
 
10398
10557
  // Real token streaming (--include-partial-messages) for every OpenAI-compatible
@@ -10401,7 +10560,7 @@ export async function chatWithTools(rawMessages, options) {
10401
10560
  // delta-fragmented tool_calls into the standard {message, usage} shape.
10402
10561
  if (typeof options.onToken === "function") {
10403
10562
  return await _retryStreamingChat(
10404
- () =>
10563
+ (attempt = 0) =>
10405
10564
  _chatOpenAIStreaming(
10406
10565
  `${url}/chat/completions`,
10407
10566
  {
@@ -10421,9 +10580,13 @@ export async function chatWithTools(rawMessages, options) {
10421
10580
  options.onStall,
10422
10581
  options.streamStallMs,
10423
10582
  options.streamStallTimeoutMs,
10583
+ supportsOpenAIRequestIdentity
10584
+ ? _physicalProviderRequestId(providerRequestId, attempt)
10585
+ : null,
10424
10586
  ),
10425
10587
  {
10426
10588
  signal,
10589
+ retries: options.workflowEffectId ? 0 : undefined,
10427
10590
  strictRetryObserver: options.strictUsageTelemetry === true,
10428
10591
  ...(typeof options.onStreamRetry === "function"
10429
10592
  ? {
@@ -10444,6 +10607,9 @@ export async function chatWithTools(rawMessages, options) {
10444
10607
  headers: {
10445
10608
  "Content-Type": "application/json",
10446
10609
  Authorization: `Bearer ${key}`,
10610
+ ...(supportsOpenAIRequestIdentity && providerRequestId
10611
+ ? { "X-Client-Request-Id": providerRequestId }
10612
+ : {}),
10447
10613
  },
10448
10614
  signal,
10449
10615
  body: JSON.stringify({
@@ -10466,6 +10632,10 @@ export async function chatWithTools(rawMessages, options) {
10466
10632
  }
10467
10633
  const choice = data.choices[0];
10468
10634
  const out = { message: choice.message };
10635
+ const providerReceipt = supportsOpenAIRequestIdentity
10636
+ ? _openAIProviderRequestReceipt(response, data, providerRequestId)
10637
+ : null;
10638
+ if (providerReceipt) out.providerReceipt = providerReceipt;
10469
10639
  if (_hasCompleteProviderUsage(data.usage)) {
10470
10640
  // OpenAI/DeepSeek/volcengine report cached prompt tokens AS PART of
10471
10641
  // prompt_tokens — split them out so cost prices the cached prefix at the
@@ -10708,7 +10878,7 @@ export async function _retryStreamingChat(streamFn, opts = {}) {
10708
10878
  for (;;) {
10709
10879
  const attemptStartedAt = now();
10710
10880
  try {
10711
- return await streamFn();
10881
+ return await streamFn(attempt);
10712
10882
  } catch (err) {
10713
10883
  if (attempt >= retries || !_isRetryableStreamError(err, signal))
10714
10884
  throw err;
@@ -11188,6 +11358,7 @@ function _openaiCachedTokens(usage) {
11188
11358
 
11189
11359
  function _openaiInitState() {
11190
11360
  return {
11361
+ responseId: null,
11191
11362
  text: "",
11192
11363
  tools: [],
11193
11364
  inputTokens: null,
@@ -11208,6 +11379,7 @@ function _openaiReduceLine(state, raw, onToken) {
11208
11379
  } catch {
11209
11380
  return state;
11210
11381
  }
11382
+ if (!state.responseId) state.responseId = _providerReceiptId(obj.id);
11211
11383
  const delta = obj.choices?.[0]?.delta;
11212
11384
  if (delta?.content) {
11213
11385
  state.text += delta.content;
@@ -11294,12 +11466,16 @@ async function _chatOpenAIStreaming(
11294
11466
  onStall,
11295
11467
  stallMs,
11296
11468
  stallTimeoutMs,
11469
+ providerRequestId = null,
11297
11470
  ) {
11298
11471
  const response = await fetch(apiUrl, {
11299
11472
  method: "POST",
11300
11473
  headers: {
11301
11474
  "Content-Type": "application/json",
11302
11475
  Authorization: `Bearer ${apiKey}`,
11476
+ ...(providerRequestId
11477
+ ? { "X-Client-Request-Id": providerRequestId }
11478
+ : {}),
11303
11479
  },
11304
11480
  signal,
11305
11481
  body: JSON.stringify(body),
@@ -11333,9 +11509,23 @@ async function _chatOpenAIStreaming(
11333
11509
  } catch (err) {
11334
11510
  if (_streamErrorDisposition(err, signal, state.text) === "rethrow")
11335
11511
  throw err;
11336
- return _finalizeTruncatedStream(_openaiFinalize, state);
11337
- }
11338
- return _openaiFinalize(state);
11512
+ const out = _finalizeTruncatedStream(_openaiFinalize, state);
11513
+ const providerReceipt = _openAIProviderRequestReceipt(
11514
+ response,
11515
+ { id: state.responseId },
11516
+ providerRequestId,
11517
+ );
11518
+ if (providerReceipt) out.providerReceipt = providerReceipt;
11519
+ return out;
11520
+ }
11521
+ const out = _openaiFinalize(state);
11522
+ const providerReceipt = _openAIProviderRequestReceipt(
11523
+ response,
11524
+ { id: state.responseId },
11525
+ providerRequestId,
11526
+ );
11527
+ if (providerReceipt) out.providerReceipt = providerReceipt;
11528
+ return out;
11339
11529
  }
11340
11530
 
11341
11531
  /**
@@ -11632,6 +11822,7 @@ function _managedCheckpointUncoveredWriterReason(toolContext) {
11632
11822
  * { type: "tool-executing", tool, args }
11633
11823
  * { type: "tool-result", tool, result, error }
11634
11824
  * { type: "model-usage-started", callId, provider, model, source }
11825
+ * { type: "provider-request-receipt", source, workflowEffectId, clientRequestId, requestId, responseId }
11635
11826
  * { type: "token-usage", callId, provider, model, usage, source? }
11636
11827
  * { type: "model-usage-unknown", callId, provider, model, source, code }
11637
11828
  * { type: "response-complete", content }
@@ -11655,6 +11846,154 @@ function _newModelUsageCallId(source = "model") {
11655
11846
  return `${prefix}-${randomUUID()}`;
11656
11847
  }
11657
11848
 
11849
+ const WORKFLOW_EFFECT_ID_RE = /^sha256:[a-f0-9]{64}$/;
11850
+ const WORKFLOW_CHILD_EFFECT_PROTOCOL = "cc-workflow-child-effect/v1";
11851
+ const WORKFLOW_TOOL_CALL_ID_RE = /^[\x21-\x7e]{1,512}$/;
11852
+
11853
+ function _normalizeWorkflowEffectId(value) {
11854
+ if (value == null) return null;
11855
+ if (typeof value !== "string" || !WORKFLOW_EFFECT_ID_RE.test(value)) {
11856
+ throw new TypeError("workflowEffectId must be a canonical sha256 identity");
11857
+ }
11858
+ return value;
11859
+ }
11860
+
11861
+ function _workflowProviderRequestId(workflowEffectId, source, sequence) {
11862
+ if (!workflowEffectId) return null;
11863
+ return `ccwf_${createHash("sha256")
11864
+ .update(
11865
+ `${workflowEffectId}\0${String(source || "model")}\0${String(sequence)}`,
11866
+ "utf8",
11867
+ )
11868
+ .digest("hex")}`;
11869
+ }
11870
+
11871
+ function _workflowToolEffectBinding(
11872
+ workflowEffectId,
11873
+ sequence,
11874
+ toolCallId,
11875
+ toolName,
11876
+ ) {
11877
+ if (!workflowEffectId) return null;
11878
+ if (
11879
+ !Number.isSafeInteger(sequence) ||
11880
+ sequence < 1 ||
11881
+ typeof toolCallId !== "string" ||
11882
+ !WORKFLOW_TOOL_CALL_ID_RE.test(toolCallId) ||
11883
+ typeof toolName !== "string" ||
11884
+ !toolName
11885
+ ) {
11886
+ const error = new TypeError(
11887
+ "workflow-bound tool call identity is malformed",
11888
+ );
11889
+ error.code = "CC_WORKFLOW_CHILD_EFFECT_IDENTITY_INVALID";
11890
+ throw error;
11891
+ }
11892
+ const childEffectId = `sha256:${createHash("sha256")
11893
+ .update(
11894
+ `${workflowEffectId}\0tool\0${String(sequence)}\0${toolCallId}\0${toolName}`,
11895
+ "utf8",
11896
+ )
11897
+ .digest("hex")}`;
11898
+ return Object.freeze({
11899
+ workflowEffectProtocol: WORKFLOW_CHILD_EFFECT_PROTOCOL,
11900
+ workflowEffectId,
11901
+ workflowChildEffectId: childEffectId,
11902
+ workflowChildSequence: sequence,
11903
+ });
11904
+ }
11905
+
11906
+ function _workflowNestedToolOutcomeUnknown(binding, toolName, result) {
11907
+ if (!binding || safeMcpProperty(result, "outcomeUnknown") !== true) {
11908
+ return null;
11909
+ }
11910
+ const error = new Error(
11911
+ `Workflow-bound nested tool ${toolName} has an unknown outcome and requires reconciliation`,
11912
+ );
11913
+ error.code = "CC_WORKFLOW_NESTED_TOOL_OUTCOME_UNKNOWN";
11914
+ error.workflowEffectOutcomeUnknown = true;
11915
+ error.workflowEffectId = binding.workflowEffectId;
11916
+ error.workflowChildEffectId = binding.workflowChildEffectId;
11917
+ return error;
11918
+ }
11919
+
11920
+ function _workflowCompactionOutcomeUnknown(
11921
+ cause,
11922
+ code = "CC_WORKFLOW_COMPACTION_PROVIDER_OUTCOME_UNKNOWN",
11923
+ message = "Workflow-bound semantic compaction provider outcome is unknown",
11924
+ ) {
11925
+ const error = new Error(message, cause ? { cause } : undefined);
11926
+ error.code = code;
11927
+ error.workflowEffectOutcomeUnknown = true;
11928
+ error.compactionFailureReported = false;
11929
+ return error;
11930
+ }
11931
+
11932
+ function _markWorkflowCompactionFailureReported(error) {
11933
+ if (error?.workflowEffectOutcomeUnknown === true) {
11934
+ error.compactionFailureReported = true;
11935
+ }
11936
+ return error;
11937
+ }
11938
+
11939
+ function _snapshotProviderRequestReceipt(
11940
+ value,
11941
+ expectedClientRequestId,
11942
+ expectedProvider,
11943
+ ) {
11944
+ if (value == null) return null;
11945
+ if (isProxy(value)) {
11946
+ throw new TypeError("provider request receipt must not be a Proxy");
11947
+ }
11948
+ const descriptors = Object.getOwnPropertyDescriptors(value);
11949
+ const expectedFields = [
11950
+ "clientRequestId",
11951
+ "independentlyReadable",
11952
+ "protocol",
11953
+ "provider",
11954
+ "requestId",
11955
+ "requestIdentitySemantics",
11956
+ "responseId",
11957
+ ];
11958
+ const fields = Object.keys(descriptors).sort();
11959
+ const hasOnlyDataFields =
11960
+ fields.length === expectedFields.length &&
11961
+ fields.every(
11962
+ (field, index) =>
11963
+ field === expectedFields[index] &&
11964
+ Object.hasOwn(descriptors[field], "value") &&
11965
+ descriptors[field].enumerable === true,
11966
+ );
11967
+ if (
11968
+ !value ||
11969
+ typeof value !== "object" ||
11970
+ Array.isArray(value) ||
11971
+ !hasOnlyDataFields ||
11972
+ descriptors.protocol.value !== "cc-provider-request-receipt/v1" ||
11973
+ !/^[a-z0-9][a-z0-9._-]{0,63}$/.test(descriptors.provider.value || "") ||
11974
+ descriptors.provider.value !== expectedProvider ||
11975
+ descriptors.clientRequestId.value !== expectedClientRequestId ||
11976
+ descriptors.requestIdentitySemantics.value !== "trace-only" ||
11977
+ descriptors.independentlyReadable.value !== false
11978
+ ) {
11979
+ throw new TypeError("provider request receipt is malformed");
11980
+ }
11981
+ const requestId = _providerReceiptId(descriptors.requestId.value);
11982
+ const responseId = _providerReceiptId(descriptors.responseId.value);
11983
+ if (!requestId && !responseId) {
11984
+ throw new TypeError("provider request receipt has no provider identifier");
11985
+ }
11986
+ return Object.freeze({
11987
+ protocol: "cc-provider-request-receipt/v1",
11988
+ provider: descriptors.provider.value,
11989
+ clientRequestId: expectedClientRequestId,
11990
+ requestId,
11991
+ responseId,
11992
+ requestIdentitySemantics: "trace-only",
11993
+ independentlyReadable: false,
11994
+ });
11995
+ }
11996
+
11658
11997
  function _runtimeUsageBoundaryFailure(error, code, fallbackMessage) {
11659
11998
  const failure =
11660
11999
  error && (typeof error === "object" || typeof error === "function")
@@ -11824,7 +12163,7 @@ function _assertStrictUsageObserver(observer, phase) {
11824
12163
  function _autoCompactionUsageState(options) {
11825
12164
  let state = _autoCompactionUsageStates.get(options);
11826
12165
  if (!state) {
11827
- state = { calls: [] };
12166
+ state = { calls: [], callSequence: null };
11828
12167
  _autoCompactionUsageStates.set(options, state);
11829
12168
  }
11830
12169
  return state;
@@ -11848,27 +12187,59 @@ function _instrumentAutoCompactorUsage(compactor, options) {
11848
12187
  const original = installed?.original || compactor.llmQuery;
11849
12188
  const state = _autoCompactionUsageState(options);
11850
12189
  const wrapper = async function instrumentedCompactionQuery(...args) {
12190
+ const workflowEffectId = _normalizeWorkflowEffectId(
12191
+ options.workflowEffectId,
12192
+ );
12193
+ const callSequence =
12194
+ Number.isSafeInteger(state.callSequence) && state.callSequence > 0
12195
+ ? state.callSequence
12196
+ : null;
12197
+ if (workflowEffectId && callSequence == null) {
12198
+ throw _runtimeUsageBoundaryFailure(
12199
+ null,
12200
+ "CC_COMPACTION_REQUEST_SEQUENCE_REQUIRED",
12201
+ "Workflow-bound semantic compaction requires a stable call sequence",
12202
+ );
12203
+ }
12204
+ const providerRequestId = _workflowProviderRequestId(
12205
+ workflowEffectId,
12206
+ "semantic-compaction",
12207
+ callSequence,
12208
+ );
11851
12209
  const call = {
11852
12210
  callId: _newModelUsageCallId("semantic-compaction"),
11853
- provider: options.provider || null,
11854
- model: options.model || null,
12211
+ provider: options.provider || "ollama",
12212
+ model: options.model || "unknown",
11855
12213
  source: "semantic-compaction",
12214
+ workflowEffectId,
12215
+ callSequence,
12216
+ providerRequestId,
12217
+ providerReceipt: null,
11856
12218
  observerError: null,
11857
12219
  observerFailed: false,
11858
12220
  boundaryNotified: false,
11859
12221
  };
11860
12222
  state.calls.push(call);
12223
+ const boundaryEvent = {
12224
+ type: "model-usage-started",
12225
+ callId: call.callId,
12226
+ provider: call.provider,
12227
+ model: call.model,
12228
+ source: call.source,
12229
+ ...(providerRequestId
12230
+ ? {
12231
+ workflowEffectId,
12232
+ callSequence,
12233
+ providerRequestId,
12234
+ requestIdentitySemantics: "trace-only",
12235
+ }
12236
+ : {}),
12237
+ };
11861
12238
  try {
11862
12239
  if (typeof options.onUsageBoundary === "function") {
11863
12240
  // Synchronous and before `original`: a host can durably append the
11864
12241
  // start row, and any append failure prevents provider spend.
11865
- const observation = options.onUsageBoundary({
11866
- type: "model-usage-started",
11867
- callId: call.callId,
11868
- provider: call.provider,
11869
- model: call.model,
11870
- source: call.source,
11871
- });
12242
+ const observation = options.onUsageBoundary(boundaryEvent);
11872
12243
  if (observation && typeof observation.then === "function") {
11873
12244
  void Promise.resolve(observation).catch(() => {});
11874
12245
  const error = new Error(
@@ -11879,13 +12250,54 @@ function _instrumentAutoCompactorUsage(compactor, options) {
11879
12250
  }
11880
12251
  call.boundaryNotified = true;
11881
12252
  }
12253
+ if (
12254
+ providerRequestId &&
12255
+ typeof options.onProviderRequestBoundary === "function"
12256
+ ) {
12257
+ const observation = options.onProviderRequestBoundary(boundaryEvent);
12258
+ if (observation && typeof observation.then === "function") {
12259
+ void Promise.resolve(observation).catch(() => {});
12260
+ throw _runtimeUsageBoundaryFailure(
12261
+ null,
12262
+ "CC_PROVIDER_REQUEST_BOUNDARY_ASYNC",
12263
+ "Provider request boundary observer must be synchronous",
12264
+ );
12265
+ }
12266
+ }
11882
12267
  } catch (error) {
11883
12268
  call.observerError = error;
11884
12269
  call.observerFailed = true;
11885
12270
  throw error;
11886
12271
  }
11887
12272
 
11888
- return await original.apply(this, args);
12273
+ const requestBinding = providerRequestId
12274
+ ? Object.freeze({
12275
+ workflowEffectId,
12276
+ callSequence,
12277
+ source: "semantic-compaction",
12278
+ providerRequestId,
12279
+ requestIdentitySemantics: "trace-only",
12280
+ })
12281
+ : null;
12282
+ try {
12283
+ const result = await original.apply(
12284
+ this,
12285
+ requestBinding ? [...args, requestBinding] : args,
12286
+ );
12287
+ call.providerReceipt = providerRequestId
12288
+ ? _snapshotProviderRequestReceipt(
12289
+ result?.providerReceipt,
12290
+ providerRequestId,
12291
+ call.provider,
12292
+ )
12293
+ : null;
12294
+ return result;
12295
+ } catch (error) {
12296
+ if (workflowEffectId) {
12297
+ throw _workflowCompactionOutcomeUnknown(error);
12298
+ }
12299
+ throw error;
12300
+ }
11889
12301
  };
11890
12302
 
11891
12303
  try {
@@ -11939,7 +12351,7 @@ async function _getAutoCompactor(options) {
11939
12351
  ? options.compactionLlmQuery
11940
12352
  : options.chatFn
11941
12353
  ? null
11942
- : async (prompt) => {
12354
+ : async (prompt, requestBinding = null) => {
11943
12355
  const maxOutputTokens = Math.min(
11944
12356
  4096,
11945
12357
  Math.max(
@@ -11958,14 +12370,17 @@ async function _getAutoCompactor(options) {
11958
12370
  onToken: undefined,
11959
12371
  onStall: undefined,
11960
12372
  onStreamRetry: undefined,
12373
+ providerRequestId:
12374
+ requestBinding?.providerRequestId || undefined,
11961
12375
  maxOutputTokens,
11962
12376
  },
11963
12377
  );
11964
12378
  return {
11965
12379
  summary: response?.message?.content || "",
11966
12380
  usage: response?.usage || null,
11967
- provider: options.provider || null,
11968
- model: options.model || null,
12381
+ provider: options.provider || "ollama",
12382
+ model: options.model || "unknown",
12383
+ providerReceipt: response?.providerReceipt || null,
11969
12384
  };
11970
12385
  };
11971
12386
  compressor = new PromptCompressor({
@@ -12205,6 +12620,7 @@ export async function* agentLoop(messages, options) {
12205
12620
  await import("../lib/iteration-budget.js");
12206
12621
  const budget = options.iterationBudget || new IterationBudget();
12207
12622
  const signal = options.signal || null;
12623
+ const workflowEffectId = _normalizeWorkflowEffectId(options.workflowEffectId);
12208
12624
  // Optional OpenTelemetry recorder (TelemetryRecorder). When present, the loop
12209
12625
  // emits model/tool/retry spans + a per-run counter; when absent, zero cost.
12210
12626
  const recorder = options.recorder || null;
@@ -12215,6 +12631,7 @@ export async function* agentLoop(messages, options) {
12215
12631
  options.runId ||
12216
12632
  `run-${Date.now()}-${Math.random().toString(36).slice(2, 8)}`;
12217
12633
  let automaticCompactionSettlementBlocked = false;
12634
+ let workflowChildEffectSequence = 0;
12218
12635
 
12219
12636
  const fileMutationScope = normalizeExactFileMutationScope(
12220
12637
  options.fileMutationScope,
@@ -12314,6 +12731,7 @@ export async function* agentLoop(messages, options) {
12314
12731
  mcpDispatchAdmission: hermeticExecution
12315
12732
  ? null
12316
12733
  : options.mcpDispatchAdmission || null,
12734
+ workflowEffectId,
12317
12735
  // A loop-local identity prevents one session's lazy instruction commits
12318
12736
  // from suppressing first-access delivery in another session at the same
12319
12737
  // cwd. Hosts may inject a stable identity across resumed turns.
@@ -12507,10 +12925,13 @@ export async function* agentLoop(messages, options) {
12507
12925
  // attempt inside one logical `llmCall`, where this generator cannot durably
12508
12926
  // bracket each transport attempt. Strict call-ledger sessions therefore
12509
12927
  // disable that recovery path and surface the configured provider's failure
12510
- // as unknown; legacy sessions keep the existing self-healing behavior.
12928
+ // as unknown. A workflow-bound request does the same: a hidden fallback
12929
+ // would be a second physical provider attempt under one durable effect.
12930
+ // Legacy sessions keep the existing self-healing behavior.
12511
12931
  if (
12512
12932
  options.runnableProviderFallback !== false &&
12513
- options.strictUsageTelemetry !== true
12933
+ options.strictUsageTelemetry !== true &&
12934
+ workflowEffectId == null
12514
12935
  ) {
12515
12936
  const { makeRunnableProviderFallback } =
12516
12937
  await import("../lib/runnable-provider.js");
@@ -12654,6 +13075,7 @@ export async function* agentLoop(messages, options) {
12654
13075
  if (compactor && compactor.shouldAutoCompact(messages)) {
12655
13076
  compactionUsageState = _autoCompactionUsageState(options);
12656
13077
  compactionUsageState.calls = [];
13078
+ compactionUsageState.callSequence = budget.consumed;
12657
13079
  // This is the canonical pre-provider authority snapshot. A local
12658
13080
  // micro-compact may change the working input, but the durable CAS must
12659
13081
  // still compare against the transcript state that existed before any
@@ -12750,6 +13172,16 @@ export async function* agentLoop(messages, options) {
12750
13172
  }
12751
13173
  compactionUsageCall = compactionUsageState.calls.at(-1) || null;
12752
13174
  const compactionUsage = _compactionTokenUsage(stats);
13175
+ if (compactionUsageCall?.providerReceipt) {
13176
+ yield {
13177
+ type: "provider-request-receipt",
13178
+ callId: compactionUsageCall.callId,
13179
+ workflowEffectId,
13180
+ callSequence: compactionUsageCall.callSequence,
13181
+ source: "semantic-compaction",
13182
+ ...compactionUsageCall.providerReceipt,
13183
+ };
13184
+ }
12753
13185
  if (stats.degraded === true) {
12754
13186
  const usageOutcomeUnknown = stats.summaryUsageUnknown === true;
12755
13187
  const projectedStats = usageOutcomeUnknown
@@ -12816,6 +13248,15 @@ export async function* agentLoop(messages, options) {
12816
13248
  backgroundSubAgents,
12817
13249
  backgroundUsageFailureState,
12818
13250
  );
13251
+ if (workflowEffectId) {
13252
+ throw _markWorkflowCompactionFailureReported(
13253
+ _workflowCompactionOutcomeUnknown(
13254
+ null,
13255
+ "CC_WORKFLOW_COMPACTION_USAGE_UNKNOWN",
13256
+ "Workflow-bound semantic compaction usage is unknown",
13257
+ ),
13258
+ );
13259
+ }
12819
13260
  return;
12820
13261
  }
12821
13262
  if (
@@ -12869,6 +13310,15 @@ export async function* agentLoop(messages, options) {
12869
13310
  backgroundSubAgents,
12870
13311
  backgroundUsageFailureState,
12871
13312
  );
13313
+ if (workflowEffectId) {
13314
+ throw _markWorkflowCompactionFailureReported(
13315
+ _workflowCompactionOutcomeUnknown(
13316
+ error,
13317
+ "CC_WORKFLOW_COMPACTION_SETTLEMENT_UNKNOWN",
13318
+ "Workflow-bound semantic compaction settlement is unknown",
13319
+ ),
13320
+ );
13321
+ }
12872
13322
  return;
12873
13323
  }
12874
13324
  if (!hermeticExecution) {
@@ -12916,6 +13366,12 @@ export async function* agentLoop(messages, options) {
12916
13366
  } catch (_e) {
12917
13367
  if (isAbortError(_e) || signal?.aborted) throw _e;
12918
13368
  if (_e?.runtimeLedgerPersistence === true) throw _e;
13369
+ if (
13370
+ _e?.workflowEffectOutcomeUnknown === true &&
13371
+ _e?.compactionFailureReported === true
13372
+ ) {
13373
+ throw _e;
13374
+ }
12919
13375
  if (compactionObserverFailure === _e) throw _e;
12920
13376
  const observerFailure = compactionUsageState?.calls?.find(
12921
13377
  (call) => call.observerFailed && call.observerError === _e,
@@ -12942,6 +13398,13 @@ export async function* agentLoop(messages, options) {
12942
13398
  backgroundSubAgents,
12943
13399
  backgroundUsageFailureState,
12944
13400
  );
13401
+ if (workflowEffectId) {
13402
+ throw _markWorkflowCompactionFailureReported(
13403
+ _e?.workflowEffectOutcomeUnknown === true
13404
+ ? _e
13405
+ : _workflowCompactionOutcomeUnknown(_e),
13406
+ );
13407
+ }
12945
13408
  return;
12946
13409
  }
12947
13410
  yield {
@@ -13048,12 +13511,28 @@ export async function* agentLoop(messages, options) {
13048
13511
  throwIfAborted(signal);
13049
13512
  _throwBackgroundUsageFailureState(backgroundUsageFailureState);
13050
13513
  _throwSettledBackgroundUsageFailure(backgroundSubAgents);
13514
+ const providerRequestId = _workflowProviderRequestId(
13515
+ workflowEffectId,
13516
+ "model",
13517
+ budget.consumed,
13518
+ );
13519
+ const providerCallOptions = providerRequestId
13520
+ ? { ...effectiveToolOptions, providerRequestId }
13521
+ : effectiveToolOptions;
13051
13522
  const modelUsageCall = {
13052
13523
  type: "model-usage-started",
13053
13524
  callId: _newModelUsageCallId("model"),
13054
13525
  provider: options.provider || "ollama",
13055
13526
  model: options.model || "unknown",
13056
13527
  source: "model",
13528
+ ...(providerRequestId
13529
+ ? {
13530
+ workflowEffectId,
13531
+ callSequence: budget.consumed,
13532
+ providerRequestId,
13533
+ requestIdentitySemantics: "trace-only",
13534
+ }
13535
+ : {}),
13057
13536
  };
13058
13537
  // The consumer receives this boundary before `.next()` resumes into the
13059
13538
  // provider call, so a durable append failure can prevent spend.
@@ -13079,6 +13558,7 @@ export async function* agentLoop(messages, options) {
13079
13558
  }
13080
13559
 
13081
13560
  let result;
13561
+ let providerReceipt = null;
13082
13562
  try {
13083
13563
  result = await _withSpan(
13084
13564
  recorder,
@@ -13089,7 +13569,7 @@ export async function* agentLoop(messages, options) {
13089
13569
  "agent.iteration": budget.consumed,
13090
13570
  ...(modelIdAttrs || {}),
13091
13571
  },
13092
- () => llmCall(callMessages, effectiveToolOptions),
13572
+ () => llmCall(callMessages, providerCallOptions),
13093
13573
  (span, r) => {
13094
13574
  const t = _usageTokens(r?.usage);
13095
13575
  if (t) {
@@ -13130,6 +13610,13 @@ export async function* agentLoop(messages, options) {
13130
13610
  },
13131
13611
  "model_error",
13132
13612
  );
13613
+ providerReceipt = providerRequestId
13614
+ ? _snapshotProviderRequestReceipt(
13615
+ result?.providerReceipt,
13616
+ providerRequestId,
13617
+ modelUsageCall.provider,
13618
+ )
13619
+ : null;
13133
13620
  } catch (error) {
13134
13621
  // Never retain provider error text in the usage ledger. Pause on a fixed
13135
13622
  // unknown settlement, then rethrow only after the consumer resumes.
@@ -13150,6 +13637,20 @@ export async function* agentLoop(messages, options) {
13150
13637
  if (recorder) recorder.counter("agent.model.calls", 1);
13151
13638
  const msg = result?.message;
13152
13639
 
13640
+ if (providerReceipt) {
13641
+ // Yield the provider-returned identifiers before billable usage. A host
13642
+ // that stops after a cost boundary still retains the exact request/effect
13643
+ // binding. This is trace evidence only, never an exactly-once assertion.
13644
+ yield {
13645
+ type: "provider-request-receipt",
13646
+ callId: modelUsageCall.callId,
13647
+ workflowEffectId,
13648
+ callSequence: budget.consumed,
13649
+ source: modelUsageCall.source,
13650
+ ...providerReceipt,
13651
+ };
13652
+ }
13653
+
13153
13654
  // Close the already-persisted call boundary before honoring an abort that
13154
13655
  // raced with a successful provider response. Once the transport returned,
13155
13656
  // dropping this settlement would strand a durable `started` row forever.
@@ -13375,7 +13876,13 @@ export async function* agentLoop(messages, options) {
13375
13876
  } catch {
13376
13877
  toolArgs = {};
13377
13878
  }
13378
- return { call, toolArgs };
13879
+ const workflowBinding = _workflowToolEffectBinding(
13880
+ workflowEffectId,
13881
+ workflowEffectId ? (workflowChildEffectSequence += 1) : 0,
13882
+ call.id,
13883
+ call.function.name,
13884
+ );
13885
+ return { call, toolArgs, workflowBinding };
13379
13886
  });
13380
13887
  // Yield every start boundary before dispatch. Async-generator consumers
13381
13888
  // persist each boundary before asking for the next item, so by the time
@@ -13384,20 +13891,21 @@ export async function* agentLoop(messages, options) {
13384
13891
  try {
13385
13892
  throwIfAborted(signal);
13386
13893
  _throwBackgroundUsageFailureState(backgroundUsageFailureState);
13387
- for (const { call, toolArgs } of prepared) {
13894
+ for (const { call, toolArgs, workflowBinding } of prepared) {
13388
13895
  yield {
13389
13896
  type: "tool-executing",
13390
13897
  tool: call.function.name,
13391
13898
  args: toolArgs,
13392
13899
  tool_use_id: call.id,
13393
13900
  turn_id: `${runId}:t${budget.consumed}`,
13901
+ ...(workflowBinding || {}),
13394
13902
  };
13395
- startedPrepared.push({ call, toolArgs });
13903
+ startedPrepared.push({ call, toolArgs, workflowBinding });
13396
13904
  throwIfAborted(signal);
13397
13905
  }
13398
13906
  _throwBackgroundUsageFailureState(backgroundUsageFailureState);
13399
13907
  } catch (admissionFailure) {
13400
- for (const { call } of startedPrepared) {
13908
+ for (const { call, workflowBinding } of startedPrepared) {
13401
13909
  yield {
13402
13910
  type: "tool-result",
13403
13911
  tool: call.function.name,
@@ -13405,6 +13913,7 @@ export async function* agentLoop(messages, options) {
13405
13913
  error: "tool execution cancelled before dispatch",
13406
13914
  tool_use_id: call.id,
13407
13915
  turn_id: `${runId}:t${budget.consumed}`,
13916
+ ...(workflowBinding || {}),
13408
13917
  };
13409
13918
  }
13410
13919
  throw admissionFailure;
@@ -13412,18 +13921,30 @@ export async function* agentLoop(messages, options) {
13412
13921
  // Only after every start has been consumed do we kick every read off.
13413
13922
  // Settle each promise into {result,error} so an abort before its ordered
13414
13923
  // result is consumed can never surface an unhandled rejection.
13415
- const inflight = prepared.map(({ call, toolArgs }) => {
13924
+ const inflight = prepared.map(({ call, toolArgs, workflowBinding }) => {
13416
13925
  const promise = executeTool(call.function.name, toolArgs, {
13417
13926
  ...toolContext,
13418
13927
  toolCallId: call.id,
13419
13928
  turnId: `${runId}:t${budget.consumed}`,
13929
+ ...(workflowBinding || {}),
13420
13930
  }).then(
13421
13931
  (result) => ({ result, error: null }),
13422
- (err) => ({ result: { error: err.message }, error: err.message }),
13932
+ (err) => ({
13933
+ result: {
13934
+ error: err.message,
13935
+ ...(workflowBinding
13936
+ ? {
13937
+ code: "CC_WORKFLOW_NESTED_TOOL_EXECUTION_THROWN",
13938
+ outcomeUnknown: true,
13939
+ }
13940
+ : {}),
13941
+ },
13942
+ error: err.message,
13943
+ }),
13423
13944
  );
13424
- return { call, toolArgs, promise };
13945
+ return { call, toolArgs, workflowBinding, promise };
13425
13946
  });
13426
- for (const { call, toolArgs, promise } of inflight) {
13947
+ for (const { call, toolArgs, workflowBinding, promise } of inflight) {
13427
13948
  throwIfAborted(signal);
13428
13949
  _throwBackgroundUsageFailureState(backgroundUsageFailureState);
13429
13950
  const { result: toolResult, error: toolError } = await promise;
@@ -13463,9 +13984,16 @@ export async function* agentLoop(messages, options) {
13463
13984
  error: toolError,
13464
13985
  tool_use_id: call.id,
13465
13986
  turn_id: `${runId}:t${budget.consumed}`,
13987
+ ...(workflowBinding || {}),
13466
13988
  permission_decision_id: decision?.id || null,
13467
13989
  permission_decision: decision,
13468
13990
  };
13991
+ const nestedOutcomeUnknown = _workflowNestedToolOutcomeUnknown(
13992
+ workflowBinding,
13993
+ call.function.name,
13994
+ toolResult,
13995
+ );
13996
+ if (nestedOutcomeUnknown) throw nestedOutcomeUnknown;
13469
13997
  messages.push({
13470
13998
  role: "tool",
13471
13999
  content: toolContent,
@@ -13610,6 +14138,7 @@ export async function* agentLoop(messages, options) {
13610
14138
 
13611
14139
  let managedCheckpointHandle = null;
13612
14140
  let managedCheckpointPreparationError = null;
14141
+ let workflowBinding = null;
13613
14142
  try {
13614
14143
  managedCheckpointHandle = beginManagedToolCheckpoint({
13615
14144
  enabled: toolContext.managedCheckpoint === true,
@@ -13663,12 +14192,19 @@ export async function* agentLoop(messages, options) {
13663
14192
  // event. Consumers use that event to bind hooks, telemetry and turns to
13664
14193
  // an actual invocation.
13665
14194
  if (!managedCheckpointPreparationError) {
14195
+ workflowBinding = _workflowToolEffectBinding(
14196
+ workflowEffectId,
14197
+ workflowEffectId ? (workflowChildEffectSequence += 1) : 0,
14198
+ call.id,
14199
+ toolName,
14200
+ );
13666
14201
  yield {
13667
14202
  type: "tool-executing",
13668
14203
  tool: toolName,
13669
14204
  args: toolArgs,
13670
14205
  tool_use_id: call.id,
13671
14206
  turn_id: `${runId}:t${budget.consumed}`,
14207
+ ...(workflowBinding || {}),
13672
14208
  };
13673
14209
  // The event yield is a host persistence boundary. A detached child's
13674
14210
  // fatal usage write can settle while the consumer handles it; fence
@@ -13686,6 +14222,7 @@ export async function* agentLoop(messages, options) {
13686
14222
  error: "authoritative background usage persistence failure",
13687
14223
  tool_use_id: call.id,
13688
14224
  turn_id: `${runId}:t${budget.consumed}`,
14225
+ ...(workflowBinding || {}),
13689
14226
  };
13690
14227
  throw backgroundFailure;
13691
14228
  }
@@ -13735,6 +14272,7 @@ export async function* agentLoop(messages, options) {
13735
14272
  ...toolContext,
13736
14273
  toolCallId: call.id,
13737
14274
  turnId: `${runId}:t${budget.consumed}`,
14275
+ ...(workflowBinding || {}),
13738
14276
  }),
13739
14277
  (span, r) => {
13740
14278
  span.setAttribute(
@@ -13774,7 +14312,15 @@ export async function* agentLoop(messages, options) {
13774
14312
  );
13775
14313
  } catch (err) {
13776
14314
  if (err?.runtimeLedgerPersistence === true) throw err;
13777
- toolResult = { error: err.message };
14315
+ toolResult = {
14316
+ error: err.message,
14317
+ ...(workflowBinding
14318
+ ? {
14319
+ code: "CC_WORKFLOW_NESTED_TOOL_EXECUTION_THROWN",
14320
+ outcomeUnknown: true,
14321
+ }
14322
+ : {}),
14323
+ };
13778
14324
  toolError = err.message;
13779
14325
  }
13780
14326
  }
@@ -13878,10 +14424,18 @@ export async function* agentLoop(messages, options) {
13878
14424
  error: toolError,
13879
14425
  tool_use_id: call.id,
13880
14426
  turn_id: `${runId}:t${budget.consumed}`,
14427
+ ...(workflowBinding || {}),
13881
14428
  permission_decision_id: decision?.id || null,
13882
14429
  permission_decision: decision,
13883
14430
  };
13884
14431
 
14432
+ const nestedOutcomeUnknown = _workflowNestedToolOutcomeUnknown(
14433
+ workflowBinding,
14434
+ toolName,
14435
+ toolResult,
14436
+ );
14437
+ if (nestedOutcomeUnknown) throw nestedOutcomeUnknown;
14438
+
13885
14439
  messages.push({
13886
14440
  role: "tool",
13887
14441
  content: toolContent,