chainlesschain 0.165.3 → 0.165.4

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 (203) hide show
  1. package/README.md +151 -29
  2. package/package.json +2 -2
  3. package/src/assets/web-panel/assets/{AIOps-BiHNUlbU.js → AIOps-C__nnraW.js} +1 -1
  4. package/src/assets/web-panel/assets/{ActionButton-D-UFjDRQ.js → ActionButton-CsKWHEZ-.js} +1 -1
  5. package/src/assets/web-panel/assets/{Analytics-DazVsDgW.js → Analytics-BhIjfjWO.js} +3 -3
  6. package/src/assets/web-panel/assets/{AppLayout-DXh9UfNJ.js → AppLayout-BjuXFzWZ.js} +5 -5
  7. package/src/assets/web-panel/assets/{Artifacts-CZ6tsceY.js → Artifacts-k6whDkZJ.js} +1 -1
  8. package/src/assets/web-panel/assets/{Audit-RyxnBr_h.js → Audit-C4FBMYRh.js} +1 -1
  9. package/src/assets/web-panel/assets/{BackgroundAgents-BWS51Q6X.js → BackgroundAgents-C_vRrSXk.js} +1 -1
  10. package/src/assets/web-panel/assets/{Backup-BRtPcUul.js → Backup-CngFZeVp.js} +1 -1
  11. package/src/assets/web-panel/assets/{BaseInput-CGd4vZYY.js → BaseInput-B_H9EBRm.js} +1 -1
  12. package/src/assets/web-panel/assets/{Chat-h8ijVwCg.js → Chat-DLEC5kt7.js} +4 -4
  13. package/src/assets/web-panel/assets/ChatBubbleRenderer-xijcWkJe.js +1 -0
  14. package/src/assets/web-panel/assets/{Checkbox-NyF6dPl8.js → Checkbox-m3ClR4xh.js} +1 -1
  15. package/src/assets/web-panel/assets/{Codegen-Ci4OOxr5.js → Codegen-CmLSFrgp.js} +1 -1
  16. package/src/assets/web-panel/assets/{Col-CwTkc9BM.js → Col-DFGQteHN.js} +1 -1
  17. package/src/assets/web-panel/assets/{Community-DW_tM82m.js → Community-EUUVORHE.js} +1 -1
  18. package/src/assets/web-panel/assets/{Compact-DEvHRV4S.js → Compact-2PSg0Yr7.js} +1 -1
  19. package/src/assets/web-panel/assets/{Compliance-BbjBEEfD.js → Compliance-CcKur7gB.js} +1 -1
  20. package/src/assets/web-panel/assets/{Cowork-10IXBaBa.js → Cowork-DK_Fezfa.js} +2 -2
  21. package/src/assets/web-panel/assets/{Cron-BZkbpd5I.js → Cron-Dbw89xl7.js} +2 -2
  22. package/src/assets/web-panel/assets/{Crosschain-CFQ8L_6v.js → Crosschain-CH66h_Ec.js} +1 -1
  23. package/src/assets/web-panel/assets/{DID-BDF6AkXe.js → DID-D1igRb17.js} +2 -2
  24. package/src/assets/web-panel/assets/{Dashboard-CoOdWMi4.js → Dashboard-DVAsrobk.js} +2 -2
  25. package/src/assets/web-panel/assets/{Dropdown-DEsGmu8Y.js → Dropdown-Dl7W8AQs.js} +1 -1
  26. package/src/assets/web-panel/assets/{EmailListRenderer-BS89SWlK.js → EmailListRenderer-D5tpaEQC.js} +1 -1
  27. package/src/assets/web-panel/assets/{FamilyGuardDashboard-C1FpCHiI.js → FamilyGuardDashboard-O_VQf8gq.js} +1 -1
  28. package/src/assets/web-panel/assets/{Federation-BzvpVmLA.js → Federation-BTVcgS9n.js} +1 -1
  29. package/src/assets/web-panel/assets/{FormItemContext-BeC259PQ.js → FormItemContext-BRnkJAIz.js} +1 -1
  30. package/src/assets/web-panel/assets/{GenericCardRenderer-azgG3bmV.js → GenericCardRenderer-8OWSCkDj.js} +1 -1
  31. package/src/assets/web-panel/assets/{Git-BmSSowc5.js → Git-WXLYTQj2.js} +2 -2
  32. package/src/assets/web-panel/assets/{Governance-CTBCSyQZ.js → Governance-BezaUhtc.js} +1 -1
  33. package/src/assets/web-panel/assets/{Inference-DA5xyk4a.js → Inference-CuRay3Gu.js} +1 -1
  34. package/src/assets/web-panel/assets/{KnowledgeGraph-D1gPHNig.js → KnowledgeGraph-DfWLDW1m.js} +1 -1
  35. package/src/assets/web-panel/assets/{Logs-BPmLf1AR.js → Logs-C55y2pPY.js} +2 -2
  36. package/src/assets/web-panel/assets/MarkdownRenderer-hDpWdiBc.js +1 -0
  37. package/src/assets/web-panel/assets/{Marketplace-DtUFcR0E.js → Marketplace-Dk08Uycg.js} +1 -1
  38. package/src/assets/web-panel/assets/{McpTools-DS_kqBv-.js → McpTools-C11fSB5V.js} +3 -3
  39. package/src/assets/web-panel/assets/{Memory-Fvh7XL7V.js → Memory-mr0eZc97.js} +2 -2
  40. package/src/assets/web-panel/assets/{MobileBridge-C7itAP45.js → MobileBridge-C0iCSRbb.js} +1 -1
  41. package/src/assets/web-panel/assets/MobileProjects-CY-xMG8Z.js +1 -0
  42. package/src/assets/web-panel/assets/{Mtc-B57MiNLK.js → Mtc-Bplqc_Wc.js} +6 -6
  43. package/src/assets/web-panel/assets/{MtcAudit-BXfCUcM7.js → MtcAudit-BlzwsoSM.js} +4 -4
  44. package/src/assets/web-panel/assets/{Multisig-yaJ-ZcF6.js → Multisig-BBLmTty6.js} +3 -3
  45. package/src/assets/web-panel/assets/{NLProgramming-CoaUCKrO.js → NLProgramming-DtT1uf1W.js} +1 -1
  46. package/src/assets/web-panel/assets/{Notes-BKLM_65R.js → Notes-DcqQAxTK.js} +3 -3
  47. package/src/assets/web-panel/assets/{NotificationSettings-DoDtK9uZ.js → NotificationSettings-cb0kWoZe.js} +1 -1
  48. package/src/assets/web-panel/assets/{OrderTableRenderer-BJ28TGr-.js → OrderTableRenderer-kw9HZQNN.js} +1 -1
  49. package/src/assets/web-panel/assets/{Organization-MuGsdoIb.js → Organization-DlTlbkUN.js} +4 -4
  50. package/src/assets/web-panel/assets/{Overflow-BLUN9J4R.js → Overflow-pp1qs-oY.js} +1 -1
  51. package/src/assets/web-panel/assets/{P2P-DWuoBUPd.js → P2P-BESLnyYz.js} +2 -2
  52. package/src/assets/web-panel/assets/{PdhVaultBrowser-CUi37YPj.js → PdhVaultBrowser-B-J1mGuf.js} +3 -3
  53. package/src/assets/web-panel/assets/{Permissions-BYQg2pcr.js → Permissions-B36PeT1_.js} +4 -4
  54. package/src/assets/web-panel/assets/{PersonalDataHub-CAxoV2xu.js → PersonalDataHub-CTK2ad-3.js} +6 -6
  55. package/src/assets/web-panel/assets/{Pipeline-B33wGvIO.js → Pipeline-zJNGXsac.js} +1 -1
  56. package/src/assets/web-panel/assets/{Privacy-A8yXTORP.js → Privacy-b9fz0Qf0.js} +1 -1
  57. package/src/assets/web-panel/assets/{ProjectInit-D49I2I1O.js → ProjectInit-DjZbZgiB.js} +2 -2
  58. package/src/assets/web-panel/assets/{ProjectSettings-Ci73jJDw.js → ProjectSettings-C-hHJXlD.js} +2 -2
  59. package/src/assets/web-panel/assets/Projects-BC9KSDM6.js +1 -0
  60. package/src/assets/web-panel/assets/Providers-Dz-CAYYU.js +1 -0
  61. package/src/assets/web-panel/assets/{QrScannerModal-Brza0ykJ.js → QrScannerModal-A0yoQ3-3.js} +1 -1
  62. package/src/assets/web-panel/assets/{QuickAsk-DFydhjxL.js → QuickAsk-DrFgFJNC.js} +1 -1
  63. package/src/assets/web-panel/assets/{Recommend-DLF8_NhA.js → Recommend-KC8hF1g4.js} +1 -1
  64. package/src/assets/web-panel/assets/{RemoteSession-dyuStW3x.js → RemoteSession-DGTPIk6u.js} +3 -3
  65. package/src/assets/web-panel/assets/{Reputation-5F3tA6yw.js → Reputation-QmbwM7Yk.js} +1 -1
  66. package/src/assets/web-panel/assets/{Row-Ca2A57S5.js → Row-BxjJylia.js} +1 -1
  67. package/src/assets/web-panel/assets/{RssFeed-B0bxBkq_.js → RssFeed-B7Wda1J6.js} +3 -3
  68. package/src/assets/web-panel/assets/{Search-CFNvHalZ.js → Search-_plQ_YSA.js} +1 -1
  69. package/src/assets/web-panel/assets/{Security-DSoH3Hav.js → Security-CD2YJZfx.js} +4 -4
  70. package/src/assets/web-panel/assets/{Services-BHpfEmBQ.js → Services-qQE7NmwE.js} +2 -2
  71. package/src/assets/web-panel/assets/{Skeleton-Dsh-QNmn.js → Skeleton-DgQqkFf7.js} +1 -1
  72. package/src/assets/web-panel/assets/{Skills-BhT1NkSU.js → Skills-C4C0oFFt.js} +1 -1
  73. package/src/assets/web-panel/assets/{Sla-DY9snPeJ.js → Sla-Px2N2B5c.js} +1 -1
  74. package/src/assets/web-panel/assets/{SpeechSettings-CWaX0_Cx.js → SpeechSettings-DN6C3lQd.js} +1 -1
  75. package/src/assets/web-panel/assets/{SyncSettings-B690y_TC.js → SyncSettings-jm5aH_m7.js} +2 -2
  76. package/src/assets/web-panel/assets/{Tasks-2N-w3zWd.js → Tasks-DlkJcv67.js} +1 -1
  77. package/src/assets/web-panel/assets/{Templates-BjwQOQYC.js → Templates-DyrTHUBs.js} +1 -1
  78. package/src/assets/web-panel/assets/{Tenant-CUqHErxY.js → Tenant-mC434PtL.js} +1 -1
  79. package/src/assets/web-panel/assets/{Terminal-C13rXvNy.js → Terminal-o0_s3NgK.js} +2 -2
  80. package/src/assets/web-panel/assets/{TimelineRenderer-CpbWcya_.js → TimelineRenderer-DAGlAXOw.js} +1 -1
  81. package/src/assets/web-panel/assets/{Tokens-BXHLGXYC.js → Tokens-BnulS_bs.js} +1 -1
  82. package/src/assets/web-panel/assets/{Trigger-1e5i65o3.js → Trigger-suQbVXYM.js} +1 -1
  83. package/src/assets/web-panel/assets/{Trust-FLGqNHs5.js → Trust-DbIJAPo5.js} +1 -1
  84. package/src/assets/web-panel/assets/{UkeySign-BbaR_LJB.js → UkeySign-CQNpbIHi.js} +1 -1
  85. package/src/assets/web-panel/assets/{VideoEditing-NOp4RIov.js → VideoEditing-D8aWCERk.js} +1 -1
  86. package/src/assets/web-panel/assets/{Wallet-B7DW7bG4.js → Wallet-CuLpYfZc.js} +3 -3
  87. package/src/assets/web-panel/assets/{WebAuthn-BptSUWix.js → WebAuthn-CsfG8ZMc.js} +5 -5
  88. package/src/assets/web-panel/assets/{WorkflowEditor-CAJnDOXS.js → WorkflowEditor-BYsEAZbd.js} +1 -1
  89. package/src/assets/web-panel/assets/{chat-I8LgG1-Z.js → chat-FT4Um3-I.js} +1 -1
  90. package/src/assets/web-panel/assets/{colors-CWe7SOVD.js → colors-CKbS_Wlt.js} +1 -1
  91. package/src/assets/web-panel/assets/{compact-item-Cx3u3CA3.js → compact-item-CFJtzuJM.js} +1 -1
  92. package/src/assets/web-panel/assets/{createContext-CgD5ArwY.js → createContext-B9kSRW6K.js} +1 -1
  93. package/src/assets/web-panel/assets/devWarning-DJZ0gAMu.js +1 -0
  94. package/src/assets/web-panel/assets/{hasIn-BfQWiXN8.js → hasIn-DR-x0Xpi.js} +1 -1
  95. package/src/assets/web-panel/assets/{index-DAVy98u7.js → index-7jHr_A_k.js} +1 -1
  96. package/src/assets/web-panel/assets/{index-DlIyt1qF.js → index-B3ZX81mK.js} +1 -1
  97. package/src/assets/web-panel/assets/{index-CWZ3REg6.js → index-B7osrXqy.js} +3 -3
  98. package/src/assets/web-panel/assets/{index-DGMYTN5W.js → index-BGbPnC5x.js} +1 -1
  99. package/src/assets/web-panel/assets/{index-DFb-XIKy.js → index-BI5hP_qy.js} +1 -1
  100. package/src/assets/web-panel/assets/{index-CAUnl4Jv.js → index-BK3TiKVq.js} +1 -1
  101. package/src/assets/web-panel/assets/{index-BUAR7RY-.js → index-BVPU43b1.js} +1 -1
  102. package/src/assets/web-panel/assets/{index-Cd79NQAx.js → index-BW-t9n-q.js} +1 -1
  103. package/src/assets/web-panel/assets/{index-BiI-xPRH.js → index-BfFCQHL3.js} +1 -1
  104. package/src/assets/web-panel/assets/index-Bizb4hkw.js +1 -0
  105. package/src/assets/web-panel/assets/{index-B6yChzt1.js → index-Bt4fS2eL.js} +1 -1
  106. package/src/assets/web-panel/assets/{index-e8BM1yY1.js → index-BwR7yc2h.js} +1 -1
  107. package/src/assets/web-panel/assets/{index-V-kIHzAV.js → index-Bzz0C1BZ.js} +1 -1
  108. package/src/assets/web-panel/assets/{index-Bx7BNIRH.js → index-C2JvmYRc.js} +1 -1
  109. package/src/assets/web-panel/assets/{index-87gMxqhN.js → index-CGaXUsIs.js} +1 -1
  110. package/src/assets/web-panel/assets/{index-Cy_cCJlr.js → index-CJmIQ9XR.js} +1 -1
  111. package/src/assets/web-panel/assets/{index-C1UjHdgZ.js → index-C_enk9I_.js} +1 -1
  112. package/src/assets/web-panel/assets/{index-Bi24S7Dw.js → index-Cr2FLUsD.js} +1 -1
  113. package/src/assets/web-panel/assets/{index-CcX4FSPf.js → index-CvrCCqJt.js} +1 -1
  114. package/src/assets/web-panel/assets/{index-DmrdUwzU.js → index-D4LfPvWA.js} +1 -1
  115. package/src/assets/web-panel/assets/{index-Dcdm_Z2c.js → index-DMGmg497.js} +1 -1
  116. package/src/assets/web-panel/assets/{index-DCJEY2T0.js → index-DShSkww-.js} +1 -1
  117. package/src/assets/web-panel/assets/{index-C0ztiqtB.js → index-DTxNy0ZU.js} +1 -1
  118. package/src/assets/web-panel/assets/{index-C-rIKccl.js → index-DW4BWjTk.js} +1 -1
  119. package/src/assets/web-panel/assets/{index-CdRkCwm4.js → index-DWdqx7zI.js} +1 -1
  120. package/src/assets/web-panel/assets/{index-C0nDKhWv.js → index-Dap9c3eD.js} +1 -1
  121. package/src/assets/web-panel/assets/{index-CQDKYbnv.js → index-DcfxhKXR.js} +1 -1
  122. package/src/assets/web-panel/assets/{index-BuEQSorC.js → index-DdkIhfi-.js} +1 -1
  123. package/src/assets/web-panel/assets/{index-3iKP9OTJ.js → index-DeSgw-WV.js} +1 -1
  124. package/src/assets/web-panel/assets/{index-Doc0Ftpd.js → index-DiNUEpSQ.js} +1 -1
  125. package/src/assets/web-panel/assets/{index-BREnPKGo.js → index-DjEP7WkH.js} +1 -1
  126. package/src/assets/web-panel/assets/{index-CNYFQxAW.js → index-DtkFqPVA.js} +1 -1
  127. package/src/assets/web-panel/assets/{index-DslTuqro.js → index-KqDaCApw.js} +1 -1
  128. package/src/assets/web-panel/assets/index-OHSl-xCh.js +1 -0
  129. package/src/assets/web-panel/assets/{index-CMu16vPC.js → index-OSzjTzGM.js} +1 -1
  130. package/src/assets/web-panel/assets/{index-DsQcURkA.js → index-QBSeNVO3.js} +1 -1
  131. package/src/assets/web-panel/assets/{index-DeizoQVZ.js → index-WE08gMJP.js} +1 -1
  132. package/src/assets/web-panel/assets/{index-B1cX4Rxu.js → index-r2VI1Ikk.js} +1 -1
  133. package/src/assets/web-panel/assets/{index-DmgtY58H.js → index-tqSEHPRT.js} +1 -1
  134. package/src/assets/web-panel/assets/{initDefaultProps-DiBszVdG.js → initDefaultProps-Dd7n7VgI.js} +1 -1
  135. package/src/assets/web-panel/assets/{motion-BGIFFozv.js → motion-BwxouRw1.js} +1 -1
  136. package/src/assets/web-panel/assets/{move-D5W7mp7B.js → move-DObN0PG9.js} +1 -1
  137. package/src/assets/web-panel/assets/{mtc-parser-JFIlxJ7F.js → mtc-parser-B3nOUQc7.js} +1 -1
  138. package/src/assets/web-panel/assets/{omit-CQ3o6LIU.js → omit-o9WU2Nbl.js} +1 -1
  139. package/src/assets/web-panel/assets/{pickAttrs-R8MIlXo3.js → pickAttrs-CL_vvfQ_.js} +1 -1
  140. package/src/assets/web-panel/assets/{placementArrow-sW7ylSky.js → placementArrow-CYrM2tyK.js} +1 -1
  141. package/src/assets/web-panel/assets/{responsiveObserve-Cnl39Vbz.js → responsiveObserve-k_06cQ96.js} +1 -1
  142. package/src/assets/web-panel/assets/{slide-sn8tFd14.js → slide-CPKG0pxS.js} +1 -1
  143. package/src/assets/web-panel/assets/{statusUtils-IKKY_QxZ.js → statusUtils-BDDEeLTw.js} +1 -1
  144. package/src/assets/web-panel/assets/{styleChecker-BNpV4Nqs.js → styleChecker-Cmb7RTh7.js} +1 -1
  145. package/src/assets/web-panel/assets/{useFlexGapSupport-BWyT_eoU.js → useFlexGapSupport-e2IedC4N.js} +1 -1
  146. package/src/assets/web-panel/assets/{useFs-D09p6_U9.js → useFs-CE_gxVnm.js} +1 -1
  147. package/src/assets/web-panel/assets/{usePersonalDataHub-CzW3TkJZ.js → usePersonalDataHub-BkMIIKMz.js} +1 -1
  148. package/src/assets/web-panel/assets/{vnode-3s3WoAKB.js → vnode-DW886XV1.js} +1 -1
  149. package/src/assets/web-panel/assets/{zoom-Cjy_673s.js → zoom-Dwo_adaf.js} +1 -1
  150. package/src/assets/web-panel/index.html +1 -1
  151. package/src/command-help-index.json +3 -3
  152. package/src/commands/agent.js +105 -35
  153. package/src/commands/artifacts.js +363 -33
  154. package/src/commands/cowork.js +202 -36
  155. package/src/commands/session-budget.js +155 -0
  156. package/src/commands/session-location.js +948 -0
  157. package/src/commands/session.js +72 -46
  158. package/src/data/changelog.json +13 -0
  159. package/src/gateways/ws/artifact-protocol.js +77 -13
  160. package/src/gateways/ws/session-protocol.js +391 -24
  161. package/src/gateways/ws/ws-agent-handler.js +191 -14
  162. package/src/gateways/ws/ws-server.js +14 -3
  163. package/src/gateways/ws/ws-session-gateway.js +101 -5
  164. package/src/harness/jsonl-session-store.js +1210 -0
  165. package/src/lib/agent-team/team-runner.js +43 -13
  166. package/src/lib/artifact-access-ledger.js +461 -0
  167. package/src/lib/artifact-cleanup-ledger.js +861 -0
  168. package/src/lib/artifact-deletion-ledger.js +677 -0
  169. package/src/lib/artifact-store.js +256 -51
  170. package/src/lib/command-lifecycle-report.js +8 -4
  171. package/src/lib/cowork-adapter.js +9 -5
  172. package/src/lib/cowork-task-runner.js +20 -0
  173. package/src/lib/cowork-workflow.js +178 -20
  174. package/src/lib/direct-model-usage.js +62 -22
  175. package/src/lib/dynamic-workflow-runtime.js +3184 -111
  176. package/src/lib/execution-location-result-apply.js +339 -0
  177. package/src/lib/execution-location-result-artifact.js +271 -0
  178. package/src/lib/execution-location-result-review.js +253 -0
  179. package/src/lib/execution-location-result-store.js +331 -0
  180. package/src/lib/execution-location-result.js +617 -0
  181. package/src/lib/execution-location-target.js +236 -1
  182. package/src/lib/managed-tool-checkpoint.js +47 -4
  183. package/src/lib/process-execution-broker/workspace-transaction.js +3 -0
  184. package/src/lib/session-budget-production-root.js +376 -0
  185. package/src/lib/session-budget-runtime.js +109 -18
  186. package/src/lib/session-budget-usage.js +63 -0
  187. package/src/lib/session-host-snapshot.js +19 -2
  188. package/src/lib/session-resource-budget.js +766 -105
  189. package/src/lib/sub-agent-context.js +69 -22
  190. package/src/lib/web-ui-server.js +12 -1
  191. package/src/repl/agent-repl.js +237 -16
  192. package/src/runtime/agent-core.js +123 -0
  193. package/src/runtime/headless-runner.js +135 -46
  194. package/src/runtime/headless-stream.js +133 -25
  195. package/src/runtime/policies/agent-policy.js +10 -0
  196. package/src/assets/web-panel/assets/ChatBubbleRenderer-D7tcdDS9.js +0 -1
  197. package/src/assets/web-panel/assets/MarkdownRenderer-SVLOg49H.js +0 -1
  198. package/src/assets/web-panel/assets/MobileProjects-DGbP36-3.js +0 -1
  199. package/src/assets/web-panel/assets/Projects-CF-yD6Cn.js +0 -1
  200. package/src/assets/web-panel/assets/Providers-D-etEhg5.js +0 -1
  201. package/src/assets/web-panel/assets/devWarning-DLv_872g.js +0 -1
  202. package/src/assets/web-panel/assets/index-CdiGCibe.js +0 -1
  203. package/src/assets/web-panel/assets/index-D_0z-gyz.js +0 -1
@@ -59,6 +59,9 @@ import { canonicalJson } from "./scheduler-kernel/contract.js";
59
59
  /** Maximum number of items a single forEach step can expand into. */
60
60
  export const MAX_FAN_OUT = 500;
61
61
 
62
+ /** Maximum declarative choices accepted by one durable stage input gate. */
63
+ export const MAX_STAGE_INPUT_OPTIONS = 32;
64
+
62
65
  /** Absolute ceiling on a single loop step's iterations (infinite-loop guard). */
63
66
  export const MAX_LOOP_ITERATIONS = 100;
64
67
  export const COWORK_WORKFLOW_RUN_RECORD_SCHEMA = "cc-cowork-workflow-run/v1";
@@ -832,6 +835,53 @@ export function validateWorkflow(wf) {
832
835
  if (s.when !== undefined && typeof s.when !== "string") {
833
836
  errors.push(`steps[${i}].when must be a string expression`);
834
837
  }
838
+ if (s.needsInput !== undefined) {
839
+ const input = s.needsInput;
840
+ const inputKeys =
841
+ input && typeof input === "object" && !Array.isArray(input)
842
+ ? Object.keys(input)
843
+ : [];
844
+ if (
845
+ !input ||
846
+ typeof input !== "object" ||
847
+ Array.isArray(input) ||
848
+ inputKeys.some(
849
+ (key) => !["prompt", "options", "multiSelect"].includes(key),
850
+ ) ||
851
+ typeof input.prompt !== "string" ||
852
+ input.prompt.trim() !== input.prompt ||
853
+ input.prompt.length === 0 ||
854
+ input.prompt.length > 4096
855
+ ) {
856
+ errors.push(`steps[${i}].needsInput has an invalid prompt schema`);
857
+ } else {
858
+ if (
859
+ input.options !== undefined &&
860
+ (!Array.isArray(input.options) ||
861
+ input.options.length === 0 ||
862
+ input.options.length > MAX_STAGE_INPUT_OPTIONS ||
863
+ input.options.some(
864
+ (option) =>
865
+ typeof option !== "string" ||
866
+ option.trim() !== option ||
867
+ option.length === 0 ||
868
+ option.length > 512,
869
+ ) ||
870
+ new Set(input.options).size !== input.options.length)
871
+ ) {
872
+ errors.push(`steps[${i}].needsInput.options is invalid`);
873
+ }
874
+ if (
875
+ input.multiSelect !== undefined &&
876
+ typeof input.multiSelect !== "boolean"
877
+ ) {
878
+ errors.push(`steps[${i}].needsInput.multiSelect must be boolean`);
879
+ }
880
+ if (input.multiSelect === true && !Array.isArray(input.options)) {
881
+ errors.push(`steps[${i}].needsInput.multiSelect requires options`);
882
+ }
883
+ }
884
+ }
835
885
  if (s.forEach !== undefined) {
836
886
  const f = s.forEach;
837
887
  const ok =
@@ -1076,6 +1126,69 @@ export function substitutePlaceholders(template, resultsById) {
1076
1126
  );
1077
1127
  }
1078
1128
 
1129
+ function normalizeResolvedStageInput(value, spec) {
1130
+ const answer = snapshotAdmittedCanonicalValue(
1131
+ value,
1132
+ "workflow stage input answer",
1133
+ { maxNodes: 256, maxBytes: 64 * 1024 },
1134
+ );
1135
+ const options = Array.isArray(spec.options) ? spec.options : null;
1136
+ if (spec.multiSelect === true) {
1137
+ if (
1138
+ !Array.isArray(answer) ||
1139
+ answer.length === 0 ||
1140
+ answer.length > MAX_STAGE_INPUT_OPTIONS ||
1141
+ answer.some((item) => typeof item !== "string") ||
1142
+ new Set(answer).size !== answer.length ||
1143
+ answer.some((item) => !options.includes(item))
1144
+ ) {
1145
+ throw runResultError("workflow stage input answer is invalid");
1146
+ }
1147
+ return answer;
1148
+ }
1149
+ if (
1150
+ typeof answer !== "string" ||
1151
+ answer.length === 0 ||
1152
+ answer.length > 64 * 1024 ||
1153
+ (options && !options.includes(answer))
1154
+ ) {
1155
+ throw runResultError("workflow stage input answer is invalid");
1156
+ }
1157
+ return answer;
1158
+ }
1159
+
1160
+ async function resolveStageInputMessage(
1161
+ step,
1162
+ message,
1163
+ resultsById,
1164
+ resolveInput,
1165
+ ) {
1166
+ if (step.needsInput === undefined) return message;
1167
+ if (typeof resolveInput !== "function") {
1168
+ const error = new Error(
1169
+ `workflow step '${step.id}' requires a durable input resolver`,
1170
+ );
1171
+ error.code = "COWORK_WORKFLOW_INPUT_RESOLVER_REQUIRED";
1172
+ throw error;
1173
+ }
1174
+ const spec = step.needsInput;
1175
+ const prompt = substitutePlaceholders(spec.prompt, resultsById);
1176
+ const answer = normalizeResolvedStageInput(
1177
+ await resolveInput(
1178
+ Object.freeze({
1179
+ stepId: step.id,
1180
+ prompt,
1181
+ options: Array.isArray(spec.options)
1182
+ ? Object.freeze([...spec.options])
1183
+ : null,
1184
+ multiSelect: spec.multiSelect === true,
1185
+ }),
1186
+ ),
1187
+ spec,
1188
+ );
1189
+ return `${message}\n\n## Bound user input for stage ${step.id}\n${canonicalJson(answer, "workflowStageInput")}`;
1190
+ }
1191
+
1079
1192
  // ─── Persistence ─────────────────────────────────────────────────────────────
1080
1193
 
1081
1194
  function _storedWorkflowError(message) {
@@ -1600,6 +1713,7 @@ export async function runStepNode(step, ctx) {
1600
1713
  onStepComplete,
1601
1714
  taskSemaphore,
1602
1715
  runTask,
1716
+ resolveInput,
1603
1717
  admitted = false,
1604
1718
  } = ctx;
1605
1719
  const recordId = step.id;
@@ -1620,9 +1734,20 @@ export async function runStepNode(step, ctx) {
1620
1734
  }
1621
1735
  if (!runThis) return single("skipped", "when-condition false");
1622
1736
 
1623
- if (isLoopStep(step)) {
1737
+ const resolvedMessage = await resolveStageInputMessage(
1738
+ step,
1739
+ step.message,
1740
+ resultsById,
1741
+ resolveInput,
1742
+ );
1743
+ const activeStep =
1744
+ resolvedMessage === step.message
1745
+ ? step
1746
+ : { ...step, message: resolvedMessage };
1747
+
1748
+ if (isLoopStep(activeStep)) {
1624
1749
  const o = await runLoopStep({
1625
- step,
1750
+ step: activeStep,
1626
1751
  recordId,
1627
1752
  cwd,
1628
1753
  llmOptions,
@@ -1640,10 +1765,10 @@ export async function runStepNode(step, ctx) {
1640
1765
  };
1641
1766
  }
1642
1767
 
1643
- if (step.forEach !== undefined) {
1768
+ if (activeStep.forEach !== undefined) {
1644
1769
  let items;
1645
1770
  try {
1646
- items = resolveForEachItems(step.forEach, resultsById);
1771
+ items = resolveForEachItems(activeStep.forEach, resultsById);
1647
1772
  } catch (err) {
1648
1773
  return single("failed", err.message);
1649
1774
  }
@@ -1651,10 +1776,10 @@ export async function runStepNode(step, ctx) {
1651
1776
  const children = await Promise.all(
1652
1777
  items.map(async (item, k) => {
1653
1778
  const childId = `${recordId}[${k}]`;
1654
- const withItem = substituteItem(step.message, item);
1779
+ const withItem = substituteItem(activeStep.message, item);
1655
1780
  const msg = substitutePlaceholders(withItem, resultsById);
1656
1781
  const r = await runStepWithRetry({
1657
- step,
1782
+ step: activeStep,
1658
1783
  message: msg,
1659
1784
  cwd,
1660
1785
  llmOptions,
@@ -1687,9 +1812,9 @@ export async function runStepNode(step, ctx) {
1687
1812
  };
1688
1813
  }
1689
1814
 
1690
- const message = substitutePlaceholders(step.message, resultsById);
1815
+ const message = substitutePlaceholders(activeStep.message, resultsById);
1691
1816
  const r = await runStepWithRetry({
1692
- step,
1817
+ step: activeStep,
1693
1818
  message,
1694
1819
  cwd,
1695
1820
  llmOptions,
@@ -1724,6 +1849,7 @@ export async function runPipeline({
1724
1849
  onStepComplete,
1725
1850
  taskSemaphore,
1726
1851
  runTask = _deps.runTask,
1852
+ resolveInput,
1727
1853
  admitted = false,
1728
1854
  }) {
1729
1855
  const limit = Math.max(1, Math.floor(maxParallel) || 1);
@@ -1787,6 +1913,7 @@ export async function runPipeline({
1787
1913
  onStepComplete,
1788
1914
  taskSemaphore,
1789
1915
  runTask,
1916
+ resolveInput,
1790
1917
  admitted,
1791
1918
  });
1792
1919
  } catch (err) {
@@ -1950,6 +2077,7 @@ function normalizeAdmittedRunRecord(
1950
2077
  * @param {object} [options.llmOptions] - Forwarded to each task
1951
2078
  * @param {function} [options.onStepStart]
1952
2079
  * @param {function} [options.onStepComplete]
2080
+ * @param {function} [options.resolveInput] - Durable stage input resolver
1953
2081
  * @param {object} [options.runAdmission] - Secret-free, digest-bound dynamic
1954
2082
  * workflow admission. Production entry points require this even though the
1955
2083
  * low-level executor keeps it optional for existing library callers.
@@ -1973,6 +2101,7 @@ export async function executeWorkflow(options = {}) {
1973
2101
  onStepComplete,
1974
2102
  pipeline,
1975
2103
  runAdmission,
2104
+ resolveInput,
1976
2105
  runTask: requestedRunTask,
1977
2106
  } = options;
1978
2107
 
@@ -2019,6 +2148,16 @@ export async function executeWorkflow(options = {}) {
2019
2148
  "cowork-workflow: runTask is not available (wire runCoworkTask before executing)",
2020
2149
  );
2021
2150
  }
2151
+ if (
2152
+ runtimeWorkflow.steps.some((step) => step.needsInput !== undefined) &&
2153
+ typeof resolveInput !== "function"
2154
+ ) {
2155
+ const error = new Error(
2156
+ "workflow contains needsInput stages but no durable input resolver was provided",
2157
+ );
2158
+ error.code = "COWORK_WORKFLOW_INPUT_RESOLVER_REQUIRED";
2159
+ throw error;
2160
+ }
2022
2161
 
2023
2162
  const taskSemaphore = createWorkflowTaskSemaphore(concurrencyLimit);
2024
2163
  const resultsById = new Map();
@@ -2038,6 +2177,7 @@ export async function executeWorkflow(options = {}) {
2038
2177
  onStepComplete,
2039
2178
  taskSemaphore,
2040
2179
  runTask: runtimeRunTask,
2180
+ resolveInput,
2041
2181
  admitted: verifiedRunAdmission != null,
2042
2182
  }));
2043
2183
  } else {
@@ -2094,23 +2234,33 @@ export async function executeWorkflow(options = {}) {
2094
2234
  preOutcomes.push(outcome);
2095
2235
  continue;
2096
2236
  }
2237
+ const resolvedMessage = await resolveStageInputMessage(
2238
+ step,
2239
+ step.message,
2240
+ resultsById,
2241
+ resolveInput,
2242
+ );
2243
+ const activeStep =
2244
+ resolvedMessage === step.message
2245
+ ? step
2246
+ : { ...step, message: resolvedMessage };
2097
2247
  // loop node — runs its body repeatedly; per-iteration substitution
2098
2248
  // happens inside runLoopStep, so push the raw template.
2099
- if (isLoopStep(step)) {
2249
+ if (isLoopStep(activeStep)) {
2100
2250
  runnable.push({
2101
- step,
2102
- message: step.message,
2103
- recordId: step.id,
2251
+ step: activeStep,
2252
+ message: activeStep.message,
2253
+ recordId: activeStep.id,
2104
2254
  parentId: null,
2105
2255
  isLoop: true,
2106
2256
  });
2107
2257
  continue;
2108
2258
  }
2109
2259
  // forEach-expansion
2110
- if (step.forEach !== undefined) {
2260
+ if (activeStep.forEach !== undefined) {
2111
2261
  let items;
2112
2262
  try {
2113
- items = resolveForEachItems(step.forEach, resultsById);
2263
+ items = resolveForEachItems(activeStep.forEach, resultsById);
2114
2264
  } catch (err) {
2115
2265
  anyFailure = true;
2116
2266
  const outcome = {
@@ -2135,20 +2285,28 @@ export async function executeWorkflow(options = {}) {
2135
2285
  continue;
2136
2286
  }
2137
2287
  for (let k = 0; k < items.length; k++) {
2138
- const childId = `${step.id}[${k}]`;
2139
- const withItem = substituteItem(step.message, items[k]);
2288
+ const childId = `${activeStep.id}[${k}]`;
2289
+ const withItem = substituteItem(activeStep.message, items[k]);
2140
2290
  const msg = substitutePlaceholders(withItem, resultsById);
2141
2291
  runnable.push({
2142
- step,
2292
+ step: activeStep,
2143
2293
  message: msg,
2144
2294
  recordId: childId,
2145
- parentId: step.id,
2295
+ parentId: activeStep.id,
2146
2296
  });
2147
2297
  }
2148
2298
  continue;
2149
2299
  }
2150
- const message = substitutePlaceholders(step.message, resultsById);
2151
- runnable.push({ step, message, recordId: step.id, parentId: null });
2300
+ const message = substitutePlaceholders(
2301
+ activeStep.message,
2302
+ resultsById,
2303
+ );
2304
+ runnable.push({
2305
+ step: activeStep,
2306
+ message,
2307
+ recordId: activeStep.id,
2308
+ parentId: null,
2309
+ });
2152
2310
  }
2153
2311
 
2154
2312
  const promises = runnable.map(
@@ -5,6 +5,13 @@ import {
5
5
  projectRuntimeUsageBoundary,
6
6
  runtimeUsageEventType,
7
7
  } from "./runtime-usage-ledger.js";
8
+ import { sessionBudgetAdmissionError } from "./session-budget-production-root.js";
9
+ import {
10
+ beginSessionBudgetUsage,
11
+ markSessionBudgetUsageUnknown,
12
+ recordSessionBudgetUsage,
13
+ rejectSessionBudgetUsageUnknown,
14
+ } from "./session-budget-usage.js";
8
15
 
9
16
  function asRuntimeLedgerPersistenceError(error) {
10
17
  if (error && (typeof error === "object" || typeof error === "function")) {
@@ -47,36 +54,53 @@ export async function runMeteredDirectModelCall({
47
54
  provider,
48
55
  model,
49
56
  source = "model",
57
+ sessionBudget = null,
50
58
  call,
51
59
  }) {
52
60
  if (typeof call !== "function") {
53
61
  throw new TypeError("metered direct model call requires a callback");
54
62
  }
63
+ const callId = `direct-${randomUUID()}`;
64
+ if (typeof sessionBudget?.consumeTurn === "function") {
65
+ const admission = sessionBudget.consumeTurn({ id: callId });
66
+ if (!admission?.ok) {
67
+ throw sessionBudgetAdmissionError(
68
+ admission?.reason,
69
+ `direct model call ${source}`,
70
+ );
71
+ }
72
+ }
55
73
  if (!sessionId) return call();
56
74
  if (typeof persist !== "function") {
57
75
  throw new TypeError("metered direct model call requires persistence");
58
76
  }
59
- const callId = `direct-${randomUUID()}`;
60
77
  await persistUsageEvent(
61
78
  persist,
62
79
  runtimeUsageEventType("started"),
63
80
  projectRuntimeUsageBoundary({ callId, provider, model, source }, "started"),
64
81
  );
82
+ beginSessionBudgetUsage(
83
+ sessionBudget,
84
+ { callId, provider, model, source },
85
+ `direct model call ${source}`,
86
+ );
65
87
  let result;
66
88
  try {
67
89
  result = await call();
68
90
  } catch (error) {
91
+ const unknown = unknownUsageEvent({
92
+ callId,
93
+ provider,
94
+ model,
95
+ source,
96
+ code: "provider_call_failed",
97
+ });
69
98
  await persistUsageEvent(
70
99
  persist,
71
100
  runtimeUsageEventType("unknown"),
72
- unknownUsageEvent({
73
- callId,
74
- provider,
75
- model,
76
- source,
77
- code: "provider_call_failed",
78
- }),
101
+ unknown,
79
102
  );
103
+ markSessionBudgetUsageUnknown(sessionBudget, unknown);
80
104
  throw error;
81
105
  }
82
106
  if (result?.usage && typeof result.usage === "object") {
@@ -90,32 +114,48 @@ export async function runMeteredDirectModelCall({
90
114
  usage: result.usage,
91
115
  });
92
116
  } catch {
117
+ const unknown = unknownUsageEvent({
118
+ callId,
119
+ provider,
120
+ model,
121
+ source,
122
+ code: "provider_usage_missing",
123
+ });
93
124
  await persistUsageEvent(
94
125
  persist,
95
126
  runtimeUsageEventType("unknown"),
96
- unknownUsageEvent({
97
- callId,
98
- provider,
99
- model,
100
- source,
101
- code: "provider_usage_missing",
102
- }),
127
+ unknown,
103
128
  );
129
+ if (markSessionBudgetUsageUnknown(sessionBudget, unknown)) {
130
+ rejectSessionBudgetUsageUnknown(
131
+ unknown,
132
+ `direct model call ${source}`,
133
+ );
134
+ }
104
135
  return result;
105
136
  }
106
137
  await persistUsageEvent(persist, "token_usage", event);
138
+ recordSessionBudgetUsage(
139
+ sessionBudget,
140
+ event,
141
+ `direct model call ${source} usage settlement`,
142
+ );
107
143
  } else {
144
+ const unknown = unknownUsageEvent({
145
+ callId,
146
+ provider,
147
+ model,
148
+ source,
149
+ code: "provider_usage_missing",
150
+ });
108
151
  await persistUsageEvent(
109
152
  persist,
110
153
  runtimeUsageEventType("unknown"),
111
- unknownUsageEvent({
112
- callId,
113
- provider,
114
- model,
115
- source,
116
- code: "provider_usage_missing",
117
- }),
154
+ unknown,
118
155
  );
156
+ if (markSessionBudgetUsageUnknown(sessionBudget, unknown)) {
157
+ rejectSessionBudgetUsageUnknown(unknown, `direct model call ${source}`);
158
+ }
119
159
  }
120
160
  return result;
121
161
  }