effect-agent 0.1.0-beta.10 → 0.1.0-beta.101

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 (544) hide show
  1. package/dist/Agent-CG_VMrtA.mjs +83 -0
  2. package/dist/Agent-CG_VMrtA.mjs.map +1 -0
  3. package/dist/Agent-CM6JubNX.d.mts +226 -0
  4. package/dist/AgentError-CggcAQ7V.d.mts +101 -0
  5. package/dist/AgentPolicy-BqDoSXO6.d.mts +96 -0
  6. package/dist/AgentRuntime-B1SXMVN7.d.mts +346 -0
  7. package/dist/AgentRuntime-BWOnNc0d.mjs +4690 -0
  8. package/dist/AgentRuntime-BWOnNc0d.mjs.map +1 -0
  9. package/dist/AgentUpdates-DMJ-_xow.d.mts +53 -0
  10. package/dist/ContextCompactor-WwSIG_Z2.d.mts +161 -0
  11. package/dist/ContextWindow-DRQ5Mbm2.d.mts +58 -0
  12. package/dist/DurableAgentRuntime-HOZ3AeSi.mjs +6672 -0
  13. package/dist/DurableAgentRuntime-HOZ3AeSi.mjs.map +1 -0
  14. package/dist/DurableFailpoint-mx3-nsxU.d.mts +41 -0
  15. package/dist/DurableStep-Cry_iol4.d.mts +103 -0
  16. package/dist/EventSource-K7XUzurY.d.mts +51 -0
  17. package/dist/Identifiers-CN2s30fF.d.mts +40 -0
  18. package/dist/InMemory.d.mts +24 -0
  19. package/dist/InMemory.mjs +24 -0
  20. package/dist/InMemory.mjs.map +1 -0
  21. package/dist/MemoryNamespace-BbRW5p71.d.mts +36 -0
  22. package/dist/MemoryReference-B8Q3UJoJ.d.mts +79 -0
  23. package/dist/Messaging-QMYhp297.d.mts +490 -0
  24. package/dist/MessagingHost-CWi_PP3g.mjs +137 -0
  25. package/dist/MessagingHost-CWi_PP3g.mjs.map +1 -0
  26. package/dist/MessagingHost-gAxs5gme.d.mts +246 -0
  27. package/dist/OperationAuthorizer-TzcQtpX5.d.mts +61 -0
  28. package/dist/Output-CjocJzsl.d.mts +25 -0
  29. package/dist/PageCapture-Df8Xwskw.d.mts +583 -0
  30. package/dist/PageScreenshot-BpgZKAxl.d.mts +48 -0
  31. package/dist/PreparedInputAdmission-KLk5rGFI.d.mts +38 -0
  32. package/dist/Receipt-BAHyigAF.d.mts +33 -0
  33. package/dist/Records-Bidb7ByL.d.mts +3803 -0
  34. package/dist/Records-D8167fHn.mjs +844 -0
  35. package/dist/Records-D8167fHn.mjs.map +1 -0
  36. package/dist/RunEvent-DIrzkjLr.d.mts +460 -0
  37. package/dist/RunEventSink-D5aVhISG.d.mts +108 -0
  38. package/dist/RunJournal-srpbEBEy.mjs +909 -0
  39. package/dist/RunJournal-srpbEBEy.mjs.map +1 -0
  40. package/dist/RunOptions-Bruk54SE.d.mts +930 -0
  41. package/dist/RunPolicyUsage-ClZxyR46.d.mts +21 -0
  42. package/dist/Sandbox-CEsDWBLq.d.mts +173 -0
  43. package/dist/Schedule-Cy9up8Uf.d.mts +842 -0
  44. package/dist/Scheduling-CHCsSCGo.mjs +691 -0
  45. package/dist/Scheduling-CHCsSCGo.mjs.map +1 -0
  46. package/dist/Subagent-C2s8PFrd.mjs +1469 -0
  47. package/dist/Subagent-C2s8PFrd.mjs.map +1 -0
  48. package/dist/Subagent-DP0CzO16.d.mts +826 -0
  49. package/dist/SubagentContract-DdT7Cqe6.d.mts +116 -0
  50. package/dist/SubagentHost-CYcxkpRc.d.mts +140 -0
  51. package/dist/Subscription-CHyoQelH.d.mts +921 -0
  52. package/dist/SubscriptionInput-DqrHW-Ja.d.mts +41 -0
  53. package/dist/Thread-DOBQ0QUY.d.mts +96 -0
  54. package/dist/ThreadHistory-tS1KwxHR.d.mts +60 -0
  55. package/dist/ToolBroker-DWs4tZra.d.mts +133 -0
  56. package/dist/ToolExposure-9uF_Yo0T.mjs +10 -0
  57. package/dist/ToolExposure-9uF_Yo0T.mjs.map +1 -0
  58. package/dist/ToolExposure-C93U1sPu.mjs +30 -0
  59. package/dist/ToolExposure-C93U1sPu.mjs.map +1 -0
  60. package/dist/ToolExposure-UCN12eCd.d.mts +39 -0
  61. package/dist/ToolExposure-r2eOWk4F.d.mts +46 -0
  62. package/dist/ToolExposure.d.mts +8 -0
  63. package/dist/ToolExposure.mjs +21 -0
  64. package/dist/ToolExposure.mjs.map +1 -0
  65. package/dist/ToolReconciler-BmVRAHKs.d.mts +80 -0
  66. package/dist/ToolResult-BKdqWRff.d.mts +78 -0
  67. package/dist/Usage-Dx0aknfk.d.mts +121 -0
  68. package/dist/WakeScheduler-EjUF-GhC.d.mts +56 -0
  69. package/dist/Worker--j87JI__.d.mts +228 -0
  70. package/dist/agent-registration-ByeHejH3.mjs +199 -0
  71. package/dist/agent-registration-ByeHejH3.mjs.map +1 -0
  72. package/dist/capabilities/Approval.d.mts +114 -0
  73. package/dist/capabilities/Approval.mjs +226 -0
  74. package/dist/capabilities/Approval.mjs.map +1 -0
  75. package/dist/capabilities/Budget.d.mts +112 -0
  76. package/dist/capabilities/Budget.mjs +346 -0
  77. package/dist/capabilities/Budget.mjs.map +1 -0
  78. package/dist/capabilities/CodeMode.d.mts +157 -0
  79. package/dist/capabilities/CodeMode.mjs +522 -0
  80. package/dist/capabilities/CodeMode.mjs.map +1 -0
  81. package/dist/capabilities/Commands.d.mts +55 -0
  82. package/dist/capabilities/Commands.mjs +57 -0
  83. package/dist/capabilities/Commands.mjs.map +1 -0
  84. package/dist/capabilities/ContextTools.d.mts +321 -0
  85. package/dist/capabilities/ContextTools.mjs +126 -0
  86. package/dist/capabilities/ContextTools.mjs.map +1 -0
  87. package/dist/capabilities/Mcp.d.mts +108 -0
  88. package/dist/capabilities/Mcp.mjs +260 -0
  89. package/dist/capabilities/Mcp.mjs.map +1 -0
  90. package/dist/capabilities/McpClient.d.mts +115 -0
  91. package/dist/capabilities/McpClient.mjs +506 -0
  92. package/dist/capabilities/McpClient.mjs.map +1 -0
  93. package/dist/capabilities/MemoryNotes.d.mts +424 -0
  94. package/dist/capabilities/MemoryNotes.mjs +128 -0
  95. package/dist/capabilities/MemoryNotes.mjs.map +1 -0
  96. package/dist/capabilities/Messaging.d.mts +3 -0
  97. package/dist/capabilities/Messaging.mjs +151 -0
  98. package/dist/capabilities/Messaging.mjs.map +1 -0
  99. package/dist/capabilities/ModelContext.d.mts +89 -0
  100. package/dist/capabilities/ModelContext.mjs +168 -0
  101. package/dist/capabilities/ModelContext.mjs.map +1 -0
  102. package/dist/capabilities/Redaction.d.mts +37 -0
  103. package/dist/capabilities/Redaction.mjs +104 -0
  104. package/dist/capabilities/Redaction.mjs.map +1 -0
  105. package/dist/capabilities/Remembering.d.mts +434 -0
  106. package/dist/capabilities/Remembering.mjs +290 -0
  107. package/dist/capabilities/Remembering.mjs.map +1 -0
  108. package/dist/capabilities/RunHooks.d.mts +82 -0
  109. package/dist/capabilities/RunHooks.mjs +144 -0
  110. package/dist/capabilities/RunHooks.mjs.map +1 -0
  111. package/dist/capabilities/SemanticMemory.d.mts +431 -0
  112. package/dist/capabilities/SemanticMemory.mjs +315 -0
  113. package/dist/capabilities/SemanticMemory.mjs.map +1 -0
  114. package/dist/capabilities/Subagent.d.mts +4 -0
  115. package/dist/capabilities/Subagent.mjs +5 -0
  116. package/dist/capabilities/SubagentReservations.d.mts +186 -0
  117. package/dist/capabilities/SubagentReservations.mjs +479 -0
  118. package/dist/capabilities/SubagentReservations.mjs.map +1 -0
  119. package/dist/capabilities/ToolDiscovery.d.mts +124 -0
  120. package/dist/capabilities/ToolDiscovery.mjs +230 -0
  121. package/dist/capabilities/ToolDiscovery.mjs.map +1 -0
  122. package/dist/capabilities/WebCapture.d.mts +163 -0
  123. package/dist/capabilities/WebCapture.mjs +335 -0
  124. package/dist/capabilities/WebCapture.mjs.map +1 -0
  125. package/dist/capabilities/WebSearch.d.mts +71 -0
  126. package/dist/capabilities/WebSearch.mjs +115 -0
  127. package/dist/capabilities/WebSearch.mjs.map +1 -0
  128. package/dist/compaction-C2OTceKw.mjs +505 -0
  129. package/dist/compaction-C2OTceKw.mjs.map +1 -0
  130. package/dist/core/Agent.d.mts +2 -0
  131. package/dist/core/Agent.mjs +2 -0
  132. package/dist/core/AgentError.d.mts +2 -0
  133. package/dist/core/AgentError.mjs +117 -0
  134. package/dist/core/AgentError.mjs.map +1 -0
  135. package/dist/core/AgentPolicy.d.mts +2 -0
  136. package/dist/core/AgentPolicy.mjs +94 -0
  137. package/dist/core/AgentPolicy.mjs.map +1 -0
  138. package/dist/core/AgentUpdates.d.mts +2 -0
  139. package/dist/core/AgentUpdates.mjs +63 -0
  140. package/dist/core/AgentUpdates.mjs.map +1 -0
  141. package/dist/core/IdGenerator.d.mts +26 -0
  142. package/dist/core/IdGenerator.mjs +27 -0
  143. package/dist/core/IdGenerator.mjs.map +1 -0
  144. package/dist/core/Identifiers.d.mts +2 -0
  145. package/dist/core/Identifiers.mjs +43 -0
  146. package/dist/core/Identifiers.mjs.map +1 -0
  147. package/dist/core/Memory.d.mts +57 -0
  148. package/dist/core/Memory.mjs +203 -0
  149. package/dist/core/Memory.mjs.map +1 -0
  150. package/dist/core/MemoryNamespace.d.mts +2 -0
  151. package/dist/core/MemoryNamespace.mjs +116 -0
  152. package/dist/core/MemoryNamespace.mjs.map +1 -0
  153. package/dist/core/MemoryReference.d.mts +2 -0
  154. package/dist/core/MemoryReference.mjs +109 -0
  155. package/dist/core/MemoryReference.mjs.map +1 -0
  156. package/dist/core/MemoryRevalidation.d.mts +65 -0
  157. package/dist/core/MemoryRevalidation.mjs +126 -0
  158. package/dist/core/MemoryRevalidation.mjs.map +1 -0
  159. package/dist/core/MemoryStore.d.mts +186 -0
  160. package/dist/core/MemoryStore.mjs +243 -0
  161. package/dist/core/MemoryStore.mjs.map +1 -0
  162. package/dist/core/Receipt.d.mts +2 -0
  163. package/dist/core/Receipt.mjs +36 -0
  164. package/dist/core/Receipt.mjs.map +1 -0
  165. package/dist/core/RememberingStore.d.mts +1562 -0
  166. package/dist/core/RememberingStore.mjs +190 -0
  167. package/dist/core/RememberingStore.mjs.map +1 -0
  168. package/dist/core/RunEvent.d.mts +2 -0
  169. package/dist/core/RunEvent.mjs +337 -0
  170. package/dist/core/RunEvent.mjs.map +1 -0
  171. package/dist/core/RunPolicyUsage.d.mts +2 -0
  172. package/dist/core/RunPolicyUsage.mjs +21 -0
  173. package/dist/core/RunPolicyUsage.mjs.map +1 -0
  174. package/dist/core/SemanticMemoryIndex.d.mts +826 -0
  175. package/dist/core/SemanticMemoryIndex.mjs +185 -0
  176. package/dist/core/SemanticMemoryIndex.mjs.map +1 -0
  177. package/dist/core/SemanticMemoryRevalidation.d.mts +45 -0
  178. package/dist/core/SemanticMemoryRevalidation.mjs +191 -0
  179. package/dist/core/SemanticMemoryRevalidation.mjs.map +1 -0
  180. package/dist/core/SubagentContract.d.mts +2 -0
  181. package/dist/core/SubagentContract.mjs +148 -0
  182. package/dist/core/SubagentContract.mjs.map +1 -0
  183. package/dist/core/Thread.d.mts +2 -0
  184. package/dist/core/Thread.mjs +250 -0
  185. package/dist/core/Thread.mjs.map +1 -0
  186. package/dist/core/ToolResult.d.mts +2 -0
  187. package/dist/core/ToolResult.mjs +156 -0
  188. package/dist/core/ToolResult.mjs.map +1 -0
  189. package/dist/core/Usage.d.mts +2 -0
  190. package/dist/core/Usage.mjs +319 -0
  191. package/dist/core/Usage.mjs.map +1 -0
  192. package/dist/core/Worker.d.mts +3 -0
  193. package/dist/core/Worker.mjs +147 -0
  194. package/dist/core/Worker.mjs.map +1 -0
  195. package/dist/durable/ActivityStore.d.mts +116 -0
  196. package/dist/durable/ActivityStore.mjs +131 -0
  197. package/dist/durable/ActivityStore.mjs.map +1 -0
  198. package/dist/durable/Admin.d.mts +2 -0
  199. package/dist/durable/Admin.mjs +330 -0
  200. package/dist/durable/Admin.mjs.map +1 -0
  201. package/dist/durable/AgentRegistration.d.mts +2 -0
  202. package/dist/durable/AgentRegistration.mjs +14 -0
  203. package/dist/durable/AgentRegistration.mjs.map +1 -0
  204. package/dist/durable/Certification.d.mts +110 -0
  205. package/dist/durable/Certification.mjs +159 -0
  206. package/dist/durable/Certification.mjs.map +1 -0
  207. package/dist/durable/CommittedActivity.d.mts +62 -0
  208. package/dist/durable/CommittedActivity.mjs +159 -0
  209. package/dist/durable/CommittedActivity.mjs.map +1 -0
  210. package/dist/durable/Digest.d.mts +2 -0
  211. package/dist/durable/Digest.mjs +50 -0
  212. package/dist/durable/Digest.mjs.map +1 -0
  213. package/dist/durable/DurableAgentRuntime.d.mts +3 -0
  214. package/dist/durable/DurableAgentRuntime.mjs +3 -0
  215. package/dist/durable/DurableFailpoint.d.mts +2 -0
  216. package/dist/durable/DurableFailpoint.mjs +98 -0
  217. package/dist/durable/DurableFailpoint.mjs.map +1 -0
  218. package/dist/durable/DurableFailpointTestControl.d.mts +14 -0
  219. package/dist/durable/DurableFailpointTestControl.mjs +19 -0
  220. package/dist/durable/DurableFailpointTestControl.mjs.map +1 -0
  221. package/dist/durable/EventSource.d.mts +2 -0
  222. package/dist/durable/EventSource.mjs +65 -0
  223. package/dist/durable/EventSource.mjs.map +1 -0
  224. package/dist/durable/GitHubWorkflowSource.d.mts +185 -0
  225. package/dist/durable/GitHubWorkflowSource.mjs +209 -0
  226. package/dist/durable/GitHubWorkflowSource.mjs.map +1 -0
  227. package/dist/durable/MessageDelivery.d.mts +832 -0
  228. package/dist/durable/MessageDelivery.mjs +529 -0
  229. package/dist/durable/MessageDelivery.mjs.map +1 -0
  230. package/dist/durable/MessageDeliveryStoreConformance.d.mts +357 -0
  231. package/dist/durable/MessageDeliveryStoreConformance.mjs +270 -0
  232. package/dist/durable/MessageDeliveryStoreConformance.mjs.map +1 -0
  233. package/dist/durable/OperationAuthorizer.d.mts +2 -0
  234. package/dist/durable/OperationAuthorizer.mjs +70 -0
  235. package/dist/durable/OperationAuthorizer.mjs.map +1 -0
  236. package/dist/durable/PersistentHistory.d.mts +16 -0
  237. package/dist/durable/PersistentHistory.mjs +125 -0
  238. package/dist/durable/PersistentHistory.mjs.map +1 -0
  239. package/dist/durable/PreparedInputAdmission.d.mts +2 -0
  240. package/dist/durable/PreparedInputAdmission.mjs +34 -0
  241. package/dist/durable/PreparedInputAdmission.mjs.map +1 -0
  242. package/dist/durable/Records.d.mts +2 -0
  243. package/dist/durable/Records.mjs +2 -0
  244. package/dist/durable/Recovery.d.mts +2 -0
  245. package/dist/durable/Recovery.mjs +739 -0
  246. package/dist/durable/Recovery.mjs.map +1 -0
  247. package/dist/durable/RunJournal.d.mts +2 -0
  248. package/dist/durable/RunJournal.mjs +2 -0
  249. package/dist/durable/Schedule.d.mts +2 -0
  250. package/dist/durable/Schedule.mjs +382 -0
  251. package/dist/durable/Schedule.mjs.map +1 -0
  252. package/dist/durable/ScheduleStoreConformance.d.mts +17 -0
  253. package/dist/durable/ScheduleStoreConformance.mjs +420 -0
  254. package/dist/durable/ScheduleStoreConformance.mjs.map +1 -0
  255. package/dist/durable/ScheduleTransition.d.mts +24 -0
  256. package/dist/durable/ScheduleTransition.mjs +180 -0
  257. package/dist/durable/ScheduleTransition.mjs.map +1 -0
  258. package/dist/durable/Scheduling.d.mts +54 -0
  259. package/dist/durable/Scheduling.mjs +2 -0
  260. package/dist/durable/SqlMemoryStore.d.mts +29 -0
  261. package/dist/durable/SqlMemoryStore.mjs +436 -0
  262. package/dist/durable/SqlMemoryStore.mjs.map +1 -0
  263. package/dist/durable/SqlMessageDeliveryStore.d.mts +42 -0
  264. package/dist/durable/SqlMessageDeliveryStore.mjs +171 -0
  265. package/dist/durable/SqlMessageDeliveryStore.mjs.map +1 -0
  266. package/dist/durable/SqlStorageV2Upgrade.d.mts +21 -0
  267. package/dist/durable/SqlStorageV2Upgrade.mjs +459 -0
  268. package/dist/durable/SqlStorageV2Upgrade.mjs.map +1 -0
  269. package/dist/durable/SqlSubscriptionStore.d.mts +62 -0
  270. package/dist/durable/SqlSubscriptionStore.mjs +751 -0
  271. package/dist/durable/SqlSubscriptionStore.mjs.map +1 -0
  272. package/dist/durable/SqlThreadNativeReads.d.mts +49 -0
  273. package/dist/durable/SqlThreadNativeReads.mjs +153 -0
  274. package/dist/durable/SqlThreadNativeReads.mjs.map +1 -0
  275. package/dist/durable/SubmissionLedger.d.mts +3 -0
  276. package/dist/durable/SubmissionLedger.mjs +915 -0
  277. package/dist/durable/SubmissionLedger.mjs.map +1 -0
  278. package/dist/durable/SubmissionLedgerConformance.d.mts +29 -0
  279. package/dist/durable/SubmissionLedgerConformance.mjs +1993 -0
  280. package/dist/durable/SubmissionLedgerConformance.mjs.map +1 -0
  281. package/dist/durable/SubmissionStatus.d.mts +2 -0
  282. package/dist/durable/SubmissionStatus.mjs +18 -0
  283. package/dist/durable/SubmissionStatus.mjs.map +1 -0
  284. package/dist/durable/Subscription.d.mts +2 -0
  285. package/dist/durable/Subscription.mjs +360 -0
  286. package/dist/durable/Subscription.mjs.map +1 -0
  287. package/dist/durable/SubscriptionInput.d.mts +2 -0
  288. package/dist/durable/SubscriptionInput.mjs +52 -0
  289. package/dist/durable/SubscriptionInput.mjs.map +1 -0
  290. package/dist/durable/SubscriptionStoreConformance.d.mts +16 -0
  291. package/dist/durable/SubscriptionStoreConformance.mjs +625 -0
  292. package/dist/durable/SubscriptionStoreConformance.mjs.map +1 -0
  293. package/dist/durable/SubscriptionTools.d.mts +273 -0
  294. package/dist/durable/SubscriptionTools.mjs +190 -0
  295. package/dist/durable/SubscriptionTools.mjs.map +1 -0
  296. package/dist/durable/SubscriptionTransition.d.mts +21 -0
  297. package/dist/durable/SubscriptionTransition.mjs +148 -0
  298. package/dist/durable/SubscriptionTransition.mjs.map +1 -0
  299. package/dist/durable/Subscriptions.d.mts +73 -0
  300. package/dist/durable/Subscriptions.mjs +627 -0
  301. package/dist/durable/Subscriptions.mjs.map +1 -0
  302. package/dist/durable/ThreadContextHistory.d.mts +32 -0
  303. package/dist/durable/ThreadContextHistory.mjs +152 -0
  304. package/dist/durable/ThreadContextHistory.mjs.map +1 -0
  305. package/dist/durable/ThreadContextHistoryProjection.d.mts +60 -0
  306. package/dist/durable/ThreadContextHistoryProjection.mjs +149 -0
  307. package/dist/durable/ThreadContextHistoryProjection.mjs.map +1 -0
  308. package/dist/durable/ThreadInvariants.d.mts +76 -0
  309. package/dist/durable/ThreadInvariants.mjs +246 -0
  310. package/dist/durable/ThreadInvariants.mjs.map +1 -0
  311. package/dist/durable/ThreadProjection.d.mts +78 -0
  312. package/dist/durable/ThreadProjection.mjs +158 -0
  313. package/dist/durable/ThreadProjection.mjs.map +1 -0
  314. package/dist/durable/ThreadProjectionMaintenance.d.mts +49 -0
  315. package/dist/durable/ThreadProjectionMaintenance.mjs +33 -0
  316. package/dist/durable/ThreadProjectionMaintenance.mjs.map +1 -0
  317. package/dist/durable/ThreadStore.d.mts +2 -0
  318. package/dist/durable/ThreadStore.mjs +336 -0
  319. package/dist/durable/ThreadStore.mjs.map +1 -0
  320. package/dist/durable/ThreadStoreConformance.d.mts +28 -0
  321. package/dist/durable/ThreadStoreConformance.mjs +503 -0
  322. package/dist/durable/ThreadStoreConformance.mjs.map +1 -0
  323. package/dist/durable/ToolReconciler.d.mts +2 -0
  324. package/dist/durable/ToolReconciler.mjs +85 -0
  325. package/dist/durable/ToolReconciler.mjs.map +1 -0
  326. package/dist/durable/WakeScheduler.d.mts +2 -0
  327. package/dist/durable/WakeScheduler.mjs +85 -0
  328. package/dist/durable/WakeScheduler.mjs.map +1 -0
  329. package/dist/durable/WorkerHost.d.mts +129 -0
  330. package/dist/durable/WorkerHost.mjs +77 -0
  331. package/dist/durable/WorkerHost.mjs.map +1 -0
  332. package/dist/engine/AgentRuntime.d.mts +2 -0
  333. package/dist/engine/AgentRuntime.mjs +2 -0
  334. package/dist/engine/Compaction.d.mts +7 -0
  335. package/dist/engine/Compaction.mjs +16 -0
  336. package/dist/engine/Compaction.mjs.map +1 -0
  337. package/dist/engine/ContextCompactor.d.mts +2 -0
  338. package/dist/engine/ContextCompactor.mjs +119 -0
  339. package/dist/engine/ContextCompactor.mjs.map +1 -0
  340. package/dist/engine/ContextHistory.d.mts +65 -0
  341. package/dist/engine/ContextHistory.mjs +76 -0
  342. package/dist/engine/ContextHistory.mjs.map +1 -0
  343. package/dist/engine/ContextWindow.d.mts +2 -0
  344. package/dist/engine/ContextWindow.mjs +59 -0
  345. package/dist/engine/ContextWindow.mjs.map +1 -0
  346. package/dist/engine/DurableStep.d.mts +2 -0
  347. package/dist/engine/DurableStep.mjs +62 -0
  348. package/dist/engine/DurableStep.mjs.map +1 -0
  349. package/dist/engine/MessagingHost.d.mts +2 -0
  350. package/dist/engine/MessagingHost.mjs +2 -0
  351. package/dist/engine/Output.d.mts +2 -0
  352. package/dist/engine/Output.mjs +8 -0
  353. package/dist/engine/Output.mjs.map +1 -0
  354. package/dist/engine/RunEventSink.d.mts +2 -0
  355. package/dist/engine/RunEventSink.mjs +22 -0
  356. package/dist/engine/RunEventSink.mjs.map +1 -0
  357. package/dist/engine/RunOptions.d.mts +2 -0
  358. package/dist/engine/RunOptions.mjs +122 -0
  359. package/dist/engine/RunOptions.mjs.map +1 -0
  360. package/dist/engine/SubagentHost.d.mts +2 -0
  361. package/dist/engine/SubagentHost.mjs +72 -0
  362. package/dist/engine/SubagentHost.mjs.map +1 -0
  363. package/dist/engine/ThreadHistory.d.mts +2 -0
  364. package/dist/engine/ThreadHistory.mjs +67 -0
  365. package/dist/engine/ThreadHistory.mjs.map +1 -0
  366. package/dist/engine/ToolBroker.d.mts +2 -0
  367. package/dist/engine/ToolBroker.mjs +42 -0
  368. package/dist/engine/ToolBroker.mjs.map +1 -0
  369. package/dist/foreign-diagnostic-DBQ1XHKh.mjs +37 -0
  370. package/dist/foreign-diagnostic-DBQ1XHKh.mjs.map +1 -0
  371. package/dist/index.d.mts +90 -6
  372. package/dist/index.mjs +99 -6
  373. package/dist/output-contract-BC7tjlGw.mjs +84 -0
  374. package/dist/output-contract-BC7tjlGw.mjs.map +1 -0
  375. package/dist/rolldown-runtime-D7D4PA-g.mjs +13 -0
  376. package/dist/sandbox/CodeExecutor.d.mts +194 -0
  377. package/dist/sandbox/CodeExecutor.mjs +278 -0
  378. package/dist/sandbox/CodeExecutor.mjs.map +1 -0
  379. package/dist/sandbox/InteractiveBrowser.d.mts +142 -0
  380. package/dist/sandbox/InteractiveBrowser.mjs +165 -0
  381. package/dist/sandbox/InteractiveBrowser.mjs.map +1 -0
  382. package/dist/sandbox/PageCapture.d.mts +2 -0
  383. package/dist/sandbox/PageCapture.mjs +450 -0
  384. package/dist/sandbox/PageCapture.mjs.map +1 -0
  385. package/dist/sandbox/PageCrawl.d.mts +88 -0
  386. package/dist/sandbox/PageCrawl.mjs +124 -0
  387. package/dist/sandbox/PageCrawl.mjs.map +1 -0
  388. package/dist/sandbox/PageScreenshot.d.mts +2 -0
  389. package/dist/sandbox/PageScreenshot.mjs +53 -0
  390. package/dist/sandbox/PageScreenshot.mjs.map +1 -0
  391. package/dist/sandbox/ProtectedBrowser.d.mts +273 -0
  392. package/dist/sandbox/ProtectedBrowser.mjs +287 -0
  393. package/dist/sandbox/ProtectedBrowser.mjs.map +1 -0
  394. package/dist/sandbox/Sandbox.d.mts +2 -0
  395. package/dist/sandbox/Sandbox.mjs +208 -0
  396. package/dist/sandbox/Sandbox.mjs.map +1 -0
  397. package/dist/utf8-BYfhEkcj.mjs +11 -0
  398. package/dist/utf8-BYfhEkcj.mjs.map +1 -0
  399. package/dist/utf8-DchGZRBd.mjs +23 -0
  400. package/dist/utf8-DchGZRBd.mjs.map +1 -0
  401. package/package.json +1 -40
  402. package/src/InMemory.ts +19 -0
  403. package/src/ToolExposure.ts +2 -0
  404. package/src/capabilities/Approval.ts +352 -0
  405. package/src/capabilities/Budget.ts +536 -0
  406. package/src/capabilities/CodeMode.ts +1090 -0
  407. package/src/capabilities/Commands.ts +86 -0
  408. package/src/capabilities/ContextTools.ts +184 -0
  409. package/src/capabilities/Mcp.ts +427 -0
  410. package/src/capabilities/McpClient.ts +967 -0
  411. package/src/capabilities/MemoryNotes.ts +174 -0
  412. package/src/capabilities/Messaging.ts +261 -0
  413. package/src/capabilities/ModelContext.ts +354 -0
  414. package/src/capabilities/Redaction.ts +157 -0
  415. package/src/capabilities/Remembering.ts +550 -0
  416. package/src/capabilities/RunHooks.ts +280 -0
  417. package/src/capabilities/SemanticMemory.ts +447 -0
  418. package/src/capabilities/Subagent.ts +2277 -0
  419. package/src/capabilities/SubagentReservations.ts +850 -0
  420. package/src/capabilities/ToolDiscovery.ts +369 -0
  421. package/src/capabilities/WebCapture.ts +722 -0
  422. package/src/capabilities/WebSearch.ts +190 -0
  423. package/src/capabilities/internal/subagent-background.ts +1106 -0
  424. package/src/capabilities/internal/subagent-contract.ts +142 -0
  425. package/src/capabilities/internal/subagent-policy.ts +235 -0
  426. package/src/capabilities/internal/subagent-reporting.ts +261 -0
  427. package/src/capabilities/internal/utf8.ts +10 -0
  428. package/src/core/Agent.ts +575 -0
  429. package/src/core/AgentError.ts +152 -0
  430. package/src/core/AgentPolicy.ts +153 -0
  431. package/src/core/AgentUpdates.ts +100 -0
  432. package/src/core/IdGenerator.ts +39 -0
  433. package/src/core/Identifiers.ts +48 -0
  434. package/src/core/Memory.ts +290 -0
  435. package/src/core/MemoryNamespace.ts +196 -0
  436. package/src/core/MemoryReference.ts +121 -0
  437. package/src/core/MemoryRevalidation.ts +185 -0
  438. package/src/core/MemoryStore.ts +368 -0
  439. package/src/core/Messaging.ts +90 -0
  440. package/src/core/Receipt.ts +42 -0
  441. package/src/core/RememberingStore.ts +300 -0
  442. package/src/core/RunEvent.ts +366 -0
  443. package/src/core/RunPolicyUsage.ts +17 -0
  444. package/src/core/SemanticMemoryIndex.ts +250 -0
  445. package/src/core/SemanticMemoryRevalidation.ts +254 -0
  446. package/src/core/SubagentContract.ts +196 -0
  447. package/src/core/Thread.ts +371 -0
  448. package/src/core/ToolExposure.ts +74 -0
  449. package/src/core/ToolResult.ts +190 -0
  450. package/src/core/Usage.ts +529 -0
  451. package/src/core/Worker.ts +173 -0
  452. package/src/core/internal/agent-updates.ts +32 -0
  453. package/src/core/internal/strict-schema.ts +14 -0
  454. package/src/core/internal/utf8.ts +23 -0
  455. package/src/durable/ActivityStore.ts +160 -0
  456. package/src/durable/Admin.ts +505 -0
  457. package/src/durable/AgentRegistration.ts +14 -0
  458. package/src/durable/Certification.ts +210 -0
  459. package/src/durable/CommittedActivity.ts +296 -0
  460. package/src/durable/Digest.ts +93 -0
  461. package/src/durable/DurableAgentRuntime.ts +10911 -0
  462. package/src/durable/DurableFailpoint.ts +107 -0
  463. package/src/durable/DurableFailpointTestControl.ts +39 -0
  464. package/src/durable/EventSource.ts +172 -0
  465. package/src/durable/GitHubWorkflowSource.ts +447 -0
  466. package/src/durable/MessageDelivery.ts +759 -0
  467. package/src/durable/MessageDeliveryStoreConformance.ts +410 -0
  468. package/src/durable/OperationAuthorizer.ts +85 -0
  469. package/src/durable/PersistentHistory.ts +260 -0
  470. package/src/durable/PreparedInputAdmission.ts +44 -0
  471. package/src/durable/Records.ts +1061 -0
  472. package/src/durable/Recovery.ts +1018 -0
  473. package/src/durable/RunJournal.ts +1594 -0
  474. package/src/durable/Schedule.ts +504 -0
  475. package/src/durable/ScheduleStoreConformance.ts +638 -0
  476. package/src/durable/ScheduleTransition.ts +265 -0
  477. package/src/durable/Scheduling.ts +1077 -0
  478. package/src/durable/SqlMemoryStore.ts +778 -0
  479. package/src/durable/SqlMessageDeliveryStore.ts +309 -0
  480. package/src/durable/SqlStorageV2Upgrade.ts +500 -0
  481. package/src/durable/SqlSubscriptionStore.ts +1440 -0
  482. package/src/durable/SqlThreadNativeReads.ts +256 -0
  483. package/src/durable/SubmissionLedger.ts +1202 -0
  484. package/src/durable/SubmissionLedgerConformance.ts +4590 -0
  485. package/src/durable/SubmissionStatus.ts +14 -0
  486. package/src/durable/Subscription.ts +544 -0
  487. package/src/durable/SubscriptionInput.ts +144 -0
  488. package/src/durable/SubscriptionStoreConformance.ts +945 -0
  489. package/src/durable/SubscriptionTools.ts +327 -0
  490. package/src/durable/SubscriptionTransition.ts +302 -0
  491. package/src/durable/Subscriptions.ts +1210 -0
  492. package/src/durable/ThreadContextHistory.ts +227 -0
  493. package/src/durable/ThreadContextHistoryProjection.ts +216 -0
  494. package/src/durable/ThreadInvariants.ts +507 -0
  495. package/src/durable/ThreadProjection.ts +269 -0
  496. package/src/durable/ThreadProjectionMaintenance.ts +67 -0
  497. package/src/durable/ThreadStore.ts +552 -0
  498. package/src/durable/ThreadStoreConformance.ts +1156 -0
  499. package/src/durable/ToolReconciler.ts +109 -0
  500. package/src/durable/WakeScheduler.ts +134 -0
  501. package/src/durable/WorkerHost.ts +171 -0
  502. package/src/durable/internal/agent-registration.ts +589 -0
  503. package/src/durable/internal/agent-updates.ts +302 -0
  504. package/src/durable/internal/foreign-diagnostic.ts +47 -0
  505. package/src/durable/internal/journal-checkpoint.ts +104 -0
  506. package/src/durable/internal/journal-metadata.ts +107 -0
  507. package/src/durable/internal/messaging-host.ts +641 -0
  508. package/src/durable/internal/schedule-time.ts +303 -0
  509. package/src/durable/internal/storage-v2-layout.ts +163 -0
  510. package/src/durable/internal/storage-v2.ts +73 -0
  511. package/src/durable/internal/worker-host.ts +2553 -0
  512. package/src/durable/internal/worker-runtime.ts +9 -0
  513. package/src/engine/AgentRuntime.ts +37 -0
  514. package/src/engine/Compaction.ts +11 -0
  515. package/src/engine/ContextCompactor.ts +277 -0
  516. package/src/engine/ContextHistory.ts +73 -0
  517. package/src/engine/ContextWindow.ts +72 -0
  518. package/src/engine/DurableStep.ts +132 -0
  519. package/src/engine/MessagingHost.ts +110 -0
  520. package/src/engine/Output.ts +2 -0
  521. package/src/engine/RunEventSink.ts +132 -0
  522. package/src/engine/RunOptions.ts +1093 -0
  523. package/src/engine/SubagentHost.ts +181 -0
  524. package/src/engine/ThreadHistory.ts +120 -0
  525. package/src/engine/ToolBroker.ts +157 -0
  526. package/src/engine/ToolExposure.ts +48 -0
  527. package/src/engine/internal/agent-runtime.ts +10402 -0
  528. package/src/engine/internal/bounded-value.ts +315 -0
  529. package/src/engine/internal/compaction.ts +678 -0
  530. package/src/engine/internal/error-diagnostic.ts +39 -0
  531. package/src/engine/internal/output-contract.ts +173 -0
  532. package/src/engine/internal/primitive-delta.ts +80 -0
  533. package/src/engine/internal/provider-result-staging.ts +211 -0
  534. package/src/engine/internal/tool-derivative.ts +106 -0
  535. package/src/engine/internal/tool-exposure.ts +224 -0
  536. package/src/engine/internal/tool-telemetry.ts +484 -0
  537. package/src/index.ts +98 -21
  538. package/src/sandbox/CodeExecutor.ts +352 -0
  539. package/src/sandbox/InteractiveBrowser.ts +257 -0
  540. package/src/sandbox/PageCapture.ts +691 -0
  541. package/src/sandbox/PageCrawl.ts +148 -0
  542. package/src/sandbox/PageScreenshot.ts +81 -0
  543. package/src/sandbox/ProtectedBrowser.ts +436 -0
  544. package/src/sandbox/Sandbox.ts +241 -0
@@ -0,0 +1,2553 @@
1
+ import {
2
+ Cause,
3
+ Clock,
4
+ Context,
5
+ Crypto,
6
+ DateTime,
7
+ Duration,
8
+ Effect,
9
+ Option,
10
+ Schema,
11
+ Stream,
12
+ } from "effect";
13
+
14
+ import type * as Agent from "../../core/Agent.ts";
15
+ import { AgentPolicy } from "../../core/AgentPolicy.ts";
16
+ import { Update, UpdateError } from "../../core/AgentUpdates.ts";
17
+ import { ThreadId, type AgentId, type SubmissionId } from "../../core/Identifiers.ts";
18
+ import { IdempotencyKey, Receipt } from "../../core/Receipt.ts";
19
+ import { SubagentDelegationCaps, SubagentGrant } from "../../core/SubagentContract.ts";
20
+ import {
21
+ WorkerCompletion,
22
+ FrameworkMessage,
23
+ WorkerUpdate,
24
+ WorkerError,
25
+ WorkerHistoryEntry,
26
+ type WorkerContext,
27
+ WorkerRef,
28
+ } from "../../core/Worker.ts";
29
+ import {
30
+ type SubagentHost,
31
+ type WorkerObservation,
32
+ type WorkerReceiptRequest,
33
+ type WorkerRunReport,
34
+ } from "../../engine/SubagentHost.ts";
35
+ import { digestJson } from "../Digest.ts";
36
+ import type {
37
+ DurableAbortFailure,
38
+ DurableAwaitFailure,
39
+ DurableSubmitFailure,
40
+ DurableSubmitOptions,
41
+ } from "../DurableAgentRuntime.ts";
42
+ import {
43
+ DurableRuntimeFailpoint,
44
+ type DurableRuntimeFailpointLocation,
45
+ } from "../DurableFailpoint.ts";
46
+ import {
47
+ MessageDeliveryDriver,
48
+ MessageDeliveryStore,
49
+ prepareMessageDelivery,
50
+ } from "../MessageDelivery.ts";
51
+ import { PreparedInputAdmission } from "../PreparedInputAdmission.ts";
52
+ import {
53
+ BatchId,
54
+ CanonicalBatch,
55
+ CanonicalSequence,
56
+ type Digest,
57
+ type DeploymentId,
58
+ type ProducerId,
59
+ RecordEnvelope,
60
+ RecordId,
61
+ WorkerAdmission,
62
+ WorkerInputRequested,
63
+ WorkerOrigin,
64
+ WorkerOriginRecorded,
65
+ WorkerInputCompleted,
66
+ WorkerReportPrepared,
67
+ WorkerReportRefused,
68
+ WorkerReportingIntent,
69
+ SubtreeBudgetReserved,
70
+ PersistedJson,
71
+ } from "../Records.ts";
72
+ import {
73
+ workerInputRecordId,
74
+ agentUpdateRecordId,
75
+ firstWorkerInputRecordId,
76
+ subagentLineageRecordId,
77
+ workerOriginRecordId,
78
+ workerReportRecordId,
79
+ } from "../RunJournal.ts";
80
+ import {
81
+ type ScheduledInputFailure,
82
+ ScheduledInputRefused,
83
+ ScheduledInputRetryable,
84
+ } from "../Schedule.ts";
85
+ import {
86
+ SubmissionLedger,
87
+ LedgerError,
88
+ AbortCommand,
89
+ type AbortIntent,
90
+ type Principal,
91
+ type Settlement,
92
+ SubmissionLookupById,
93
+ SubmissionLookupByKey,
94
+ type SubmissionSnapshot,
95
+ } from "../SubmissionLedger.ts";
96
+ import type { SubmissionStatus } from "../SubmissionStatus.ts";
97
+ import { PreparedInput } from "../Subscription.ts";
98
+ import {
99
+ ThreadStore,
100
+ getRecord,
101
+ readWorkerState as readNativeWorkerState,
102
+ FencedAppendRequest,
103
+ ThreadExportRequest,
104
+ type ThreadExport,
105
+ MAX_THREAD_EXPORT_RECORDS,
106
+ ThreadRead,
107
+ ThreadTailRequest,
108
+ } from "../ThreadStore.ts";
109
+ import {
110
+ WorkerBudgetAuthorizer,
111
+ WorkerConcurrencyLimit,
112
+ WorkerConcurrencyResolver,
113
+ WorkerHostAuthorizer,
114
+ WorkerHostConfig,
115
+ WorkerPolicyResolver,
116
+ type WorkerPolicyTarget,
117
+ } from "../WorkerHost.ts";
118
+ import {
119
+ definitionDigestsEqual,
120
+ resolveDefinitionBinding,
121
+ type ResolvedBinding,
122
+ } from "./agent-registration.ts";
123
+ import { lastWorkerReportMessageId } from "./agent-updates.ts";
124
+
125
+ const failure = (operation: WorkerError["operation"], reason: WorkerError["reason"]) =>
126
+ WorkerError.make({ operation, reason });
127
+
128
+ const storageFailure = (operation: WorkerError["operation"]) => () => failure(operation, "storage");
129
+
130
+ const decode = <S extends Schema.Top>(
131
+ schema: S,
132
+ value: unknown,
133
+ operation: WorkerError["operation"],
134
+ ) =>
135
+ Schema.decodeUnknownEffect(Schema.toType(schema))(value).pipe(
136
+ Effect.mapError(() => failure(operation, "corrupt")),
137
+ );
138
+
139
+ const sameOrigin = Schema.toEquivalence(WorkerOrigin);
140
+ const sameAdmission = Schema.toEquivalence(WorkerAdmission);
141
+ const sameReporting = Schema.toEquivalence(Schema.UndefinedOr(WorkerReportingIntent));
142
+ const sameJson = Schema.toEquivalence(PersistedJson);
143
+ const sameCaps = Schema.toEquivalence(SubagentDelegationCaps);
144
+ const samePolicy = Schema.toEquivalence(AgentPolicy);
145
+
146
+ const amountCaps = [
147
+ ["turns", "maxTurns"],
148
+ ["toolCalls", "maxToolCalls"],
149
+ ["durationMillis", "maxDurationMillis"],
150
+ ["inputTokens", "maxInputTokens"],
151
+ ["outputTokens", "maxOutputTokens"],
152
+ ["costMicrousd", "maxCostMicrousd"],
153
+ ["resultBytes", "maxResultBytes"],
154
+ ] as const;
155
+
156
+ const sourceCaps = (policy: AgentPolicy): SubagentDelegationCaps =>
157
+ SubagentDelegationCaps.make({
158
+ maxTotalChildInvocations: policy.maxToolCalls,
159
+ maxConcurrentChildren: policy.toolConcurrency,
160
+ maxTurns: policy.maxTurns,
161
+ maxToolCalls: policy.maxToolCalls,
162
+ maxDurationMillis: Math.ceil(Duration.toMillis(policy.maxDuration)),
163
+ maxResultBytes: Math.min(
164
+ Number.MAX_SAFE_INTEGER,
165
+ policy.toolResultBounds.maxBytes * policy.maxToolCalls,
166
+ ),
167
+ ...(policy.tokenBudget === undefined
168
+ ? {}
169
+ : { maxInputTokens: policy.tokenBudget, maxOutputTokens: policy.tokenBudget }),
170
+ ...(policy.costBudgetMicrousd === undefined
171
+ ? {}
172
+ : { maxCostMicrousd: policy.costBudgetMicrousd }),
173
+ });
174
+
175
+ const withinPolicy = (origin: WorkerOrigin, source: AgentPolicy, target: AgentPolicy): boolean => {
176
+ const policy = origin.policy;
177
+ const allocation = origin.budget.allocation;
178
+ const caps = origin.budget.caps;
179
+ const ceilings = sourceCaps(source);
180
+
181
+ for (const [, name] of origin.budgetScope === "worker-run" ? [] : amountCaps) {
182
+ if (caps[name] !== undefined && ceilings[name] !== undefined && caps[name] > ceilings[name])
183
+ return false;
184
+ }
185
+ if (
186
+ origin.budgetScope !== "worker-run" &&
187
+ ((caps.maxTotalChildInvocations !== undefined &&
188
+ caps.maxTotalChildInvocations > source.maxToolCalls) ||
189
+ (caps.maxConcurrentChildren !== undefined &&
190
+ caps.maxConcurrentChildren > source.toolConcurrency))
191
+ )
192
+ return false;
193
+ const tokenCeiling = Math.min(source.tokenBudget ?? Infinity, target.tokenBudget ?? Infinity);
194
+
195
+ const costCeiling = Math.min(
196
+ source.costBudgetMicrousd ?? Infinity,
197
+ target.costBudgetMicrousd ?? Infinity,
198
+ );
199
+
200
+ return (
201
+ policy.maxTurns <= Math.min(allocation.turns, source.maxTurns, target.maxTurns) &&
202
+ policy.maxToolCalls <=
203
+ Math.min(allocation.toolCalls, source.maxToolCalls, target.maxToolCalls) &&
204
+ Duration.toMillis(policy.maxDuration) <=
205
+ Math.min(
206
+ allocation.durationMillis,
207
+ Duration.toMillis(source.maxDuration),
208
+ Duration.toMillis(target.maxDuration),
209
+ ) &&
210
+ policy.toolConcurrency <= Math.min(source.toolConcurrency, target.toolConcurrency) &&
211
+ policy.toolResultBounds.maxBytes <=
212
+ Math.min(source.toolResultBounds.maxBytes, target.toolResultBounds.maxBytes) &&
213
+ (tokenCeiling === Infinity ||
214
+ (policy.tokenBudget !== undefined && policy.tokenBudget <= tokenCeiling)) &&
215
+ (costCeiling === Infinity ||
216
+ (policy.costBudgetMicrousd !== undefined && policy.costBudgetMicrousd <= costCeiling)) &&
217
+ (source.tokenBudget === undefined ||
218
+ (allocation.inputTokens > 0 &&
219
+ allocation.outputTokens > 0 &&
220
+ policy.tokenBudget !== undefined &&
221
+ policy.tokenBudget <= allocation.inputTokens + allocation.outputTokens)) &&
222
+ (source.costBudgetMicrousd === undefined ||
223
+ (policy.costBudgetMicrousd !== undefined &&
224
+ policy.costBudgetMicrousd <= allocation.costMicrousd))
225
+ );
226
+ };
227
+
228
+ export interface WorkerRuntimeOptions {
229
+ readonly bindings: ReadonlyArray<ResolvedBinding>;
230
+ readonly deploymentId: DeploymentId;
231
+ readonly producerId: ProducerId;
232
+ readonly settlementPollInterval: Duration.Duration;
233
+ }
234
+
235
+ /** Admission and cancellation enter the owning runtime, never the raw ledger. */
236
+ export class WorkerInputControl extends Context.Service<
237
+ WorkerInputControl,
238
+ {
239
+ readonly submit: (envelope: PreparedInput) => Effect.Effect<Receipt, DurableSubmitFailure>;
240
+ readonly status: (
241
+ receipt: Receipt,
242
+ ) => Effect.Effect<SubmissionStatus, DurableAwaitFailure | ScheduledInputFailure>;
243
+ readonly abort: (command: AbortCommand) => Effect.Effect<AbortIntent, DurableAbortFailure>;
244
+ }
245
+ >()("@effect-agent/thread/internal/WorkerInputControl") {}
246
+
247
+ /** No in-memory ownership: every mutation is reserved in source canonical history with CAS. */
248
+ export const makeWorkerRuntime = Effect.fn("WorkerHost.make")(function* (
249
+ options: WorkerRuntimeOptions,
250
+ ) {
251
+ const control = yield* WorkerInputControl;
252
+ // A routed read may belong to another owner; capture it before exposing worker operations.
253
+ const admission = yield* Effect.serviceOption(PreparedInputAdmission);
254
+
255
+ const deps = {
256
+ ...options,
257
+ ...control,
258
+ store: yield* ThreadStore,
259
+ ledger: yield* SubmissionLedger,
260
+ deliveries: yield* Effect.serviceOption(MessageDeliveryStore),
261
+ crypto: yield* Crypto.Crypto,
262
+ authorizer: yield* WorkerHostAuthorizer,
263
+ budgetAuthorizer: yield* WorkerBudgetAuthorizer,
264
+ policyResolver: yield* WorkerPolicyResolver,
265
+ concurrencyResolver: yield* WorkerConcurrencyResolver,
266
+ limits: yield* WorkerHostConfig,
267
+ failpoint: yield* DurableRuntimeFailpoint,
268
+ status: Option.getOrUndefined(admission)?.submissionStatus ?? control.status,
269
+ };
270
+
271
+ const withCrypto = <A, E>(effect: Effect.Effect<A, E, Crypto.Crypto>) =>
272
+ Effect.provideService(effect, Crypto.Crypto, deps.crypto);
273
+
274
+ const authorizeBudget = Effect.fn("WorkerHost.authorizeBudget")(function* (
275
+ origin: WorkerOrigin,
276
+ principal: Principal,
277
+ ) {
278
+ if (origin.budgetScope !== "worker-run") return;
279
+ // Independence changes accounting ownership, never delegation generations.
280
+ if (origin.depth !== 1) return yield* failure("start", "denied");
281
+
282
+ yield* deps.budgetAuthorizer.authorize({
283
+ source: origin.source,
284
+ principal,
285
+ worker: origin.worker,
286
+ policy: origin.policy,
287
+ budget: origin.budget,
288
+ });
289
+ });
290
+
291
+ const read = (threadId: ThreadId, operation: WorkerError["operation"]) =>
292
+ deps.store
293
+ .export(ThreadExportRequest.make({ threadId }))
294
+ .pipe(Effect.mapError(storageFailure(operation)));
295
+
296
+ const exactRecord = Effect.fn("WorkerHost.exactRecord")(function* (
297
+ threadId: ThreadId,
298
+ recordId: RecordId,
299
+ operation: WorkerError["operation"],
300
+ ) {
301
+ return yield* getRecord({ threadId, recordId }).pipe(
302
+ Effect.provideService(ThreadStore, deps.store),
303
+ Effect.mapError(storageFailure(operation)),
304
+ );
305
+ });
306
+
307
+ const readIdentity = Effect.fn("WorkerHost.readIdentity")(function* (
308
+ threadId: ThreadId,
309
+ operation: WorkerError["operation"],
310
+ ) {
311
+ const tail = yield* deps.store
312
+ .inspectTail(ThreadTailRequest.make({ threadId }))
313
+ .pipe(Effect.mapError(storageFailure(operation)));
314
+
315
+ const first = yield* deps.store
316
+ .read(ThreadRead.make({ threadId, limit: 1 }))
317
+ .pipe(Stream.runCollect, Effect.mapError(storageFailure(operation)));
318
+
319
+ const worker = yield* exactRecord(threadId, workerOriginRecordId(threadId), operation);
320
+ const attached = yield* exactRecord(threadId, subagentLineageRecordId(threadId), operation);
321
+
322
+ return { ...tail, records: [...first, ...Option.toArray(worker), ...Option.toArray(attached)] };
323
+ });
324
+
325
+ const readWorkerState = Effect.fn("WorkerHost.readWorkerState")(function* (
326
+ threadId: ThreadId,
327
+ operation: WorkerError["operation"],
328
+ sourceSubmissionId?: SubmissionId,
329
+ ) {
330
+ return yield* readNativeWorkerState({
331
+ threadId,
332
+ limit: MAX_THREAD_EXPORT_RECORDS,
333
+ ...(sourceSubmissionId === undefined ? {} : { sourceSubmissionId }),
334
+ }).pipe(
335
+ Effect.provideService(ThreadStore, deps.store),
336
+ Effect.mapError(storageFailure(operation)),
337
+ );
338
+ });
339
+
340
+ const hit = (location: DurableRuntimeFailpointLocation, operation: WorkerError["operation"]) =>
341
+ deps.failpoint.hit(location).pipe(Effect.mapError(storageFailure(operation)));
342
+
343
+ const append = Effect.fn("WorkerHost.append")(
344
+ function* (
345
+ threadId: ThreadId,
346
+ id: string,
347
+ payload:
348
+ | WorkerInputRequested
349
+ | WorkerOriginRecorded
350
+ | WorkerInputCompleted
351
+ | WorkerReportPrepared
352
+ | WorkerReportRefused
353
+ | SubtreeBudgetReserved,
354
+ current: Pick<ThreadExport, "tailSequence" | "tailDigest" | "records">,
355
+ phase: "source" | "origin" | "completion" | "subtree" | "report",
356
+ ) {
357
+ const operation = "start";
358
+ const tail = yield* deps.store.inspectTail(ThreadTailRequest.make({ threadId }));
359
+
360
+ // Never append against a tail newer than the prefix whose capacity was checked.
361
+ if (tail.tailSequence !== current.tailSequence || tail.tailDigest !== current.tailDigest)
362
+ return false;
363
+ yield* hit(`worker:before-${phase}-append`, operation);
364
+
365
+ const result = yield* deps.store
366
+ .append(
367
+ FencedAppendRequest.make({
368
+ threadId,
369
+ producerEpoch: tail.producerEpoch,
370
+ expectedTailSequence: current.tailSequence,
371
+ expectedTailDigest: current.tailDigest,
372
+ batch: CanonicalBatch.make({
373
+ batchId: Schema.decodeSync(BatchId)(id),
374
+ producerId: deps.producerId,
375
+ records: [
376
+ RecordEnvelope.make({
377
+ recordId: Schema.decodeSync(RecordId)(id),
378
+ family: "thread",
379
+ schemaVersion: 1,
380
+ createdAt: DateTime.makeUnsafe(
381
+ payload._tag === "WorkerInputRequested"
382
+ ? payload.admission.createdAtMillis
383
+ : payload._tag === "WorkerOriginRecorded"
384
+ ? payload.origin.createdAtMillis
385
+ : payload._tag === "WorkerInputCompleted"
386
+ ? payload.completedAtMillis
387
+ : yield* Clock.currentTimeMillis,
388
+ ),
389
+ deploymentId: deps.deploymentId,
390
+ payload,
391
+ }),
392
+ ],
393
+ }),
394
+ }),
395
+ )
396
+ .pipe(
397
+ Effect.as(true),
398
+ Effect.catchTag(["AppendConflict", "FenceRejected"], () => Effect.succeed(false)),
399
+ );
400
+
401
+ if (result) yield* hit(`worker:after-${phase}-append`, operation);
402
+
403
+ return result;
404
+ },
405
+ Effect.mapError(storageFailure("start")),
406
+ );
407
+
408
+ const requests = (records: Effect.Success<ReturnType<typeof read>>["records"]) =>
409
+ records.flatMap(({ record }) =>
410
+ record.payload._tag === "WorkerInputRequested" ? [record.payload] : [],
411
+ );
412
+
413
+ const reportIntent = Effect.fn("WorkerHost.reportIntent")(function* (
414
+ source: ResolvedBinding,
415
+ target: ResolvedBinding,
416
+ delegationId: WorkerRef["delegationId"],
417
+ ): Effect.fn.Return<WorkerOrigin["reporting"], WorkerError> {
418
+ const reports = source.reporting?.filter((entry) => entry.delegationId === delegationId) ?? [];
419
+ const report = reports[0];
420
+
421
+ if (report === undefined) return undefined;
422
+ if (
423
+ reports.length !== 1 ||
424
+ !Object.is(report.target, target.definition) ||
425
+ (report.mode !== "standard" && !Object.is(report.input, source.definition.input)) ||
426
+ (report.destination !== undefined && !Object.is(report.destination.target, source.definition))
427
+ )
428
+ return yield* failure("start", "declaration-unavailable");
429
+
430
+ return {
431
+ sourceDigests: source.digests,
432
+ ...(report.mode === undefined ? {} : { mode: report.mode }),
433
+ ...(report.destination === undefined
434
+ ? {}
435
+ : { destinationDelegationId: report.destination.delegationId }),
436
+ };
437
+ });
438
+
439
+ const currentBinding = (agentId: AgentId): ResolvedBinding | undefined => {
440
+ const matches = deps.bindings.filter((entry) => entry.agentId === agentId);
441
+
442
+ return matches.length === 1 ? matches[0] : undefined;
443
+ };
444
+
445
+ const sourceAuthority = Effect.fn("WorkerHost.sourceAuthority")(function* (
446
+ threadId: ThreadId,
447
+ submissionId?: SubmissionId,
448
+ reservations = false,
449
+ ) {
450
+ const current = yield* reservations
451
+ ? readWorkerState(threadId, "start", submissionId)
452
+ : readIdentity(threadId, "start");
453
+
454
+ const created = current.records[0]?.record.payload;
455
+
456
+ if (created?._tag !== "ThreadCreated" || current.records[0]?.sequence !== 1)
457
+ return yield* failure("start", "not-found");
458
+
459
+ const binding = currentBinding(created.agentId);
460
+
461
+ const worker = current.records.find(
462
+ ({ record }) => record.payload._tag === "WorkerOriginRecorded",
463
+ )?.record.payload;
464
+
465
+ const attached = current.records.find(
466
+ ({ record }) => record.payload._tag === "SubagentLineageRecorded",
467
+ )?.record.payload;
468
+
469
+ const nested =
470
+ worker?._tag === "WorkerOriginRecorded" || attached?._tag === "SubagentLineageRecorded";
471
+
472
+ let ownerSubmission: SubmissionSnapshot | undefined;
473
+
474
+ if (nested && submissionId === undefined) return yield* failure("start", "denied");
475
+ if (submissionId !== undefined) {
476
+ const submission = yield* deps.ledger
477
+ .lookup(SubmissionLookupById.make({ submissionId }))
478
+ .pipe(Effect.mapError(storageFailure("start")));
479
+
480
+ if (
481
+ Option.isNone(submission) ||
482
+ submission.value.threadId !== threadId ||
483
+ (nested && submission.value.agentId !== created.agentId)
484
+ )
485
+ return yield* failure("start", "denied");
486
+ ownerSubmission = submission.value;
487
+ if (
488
+ worker?._tag === "WorkerOriginRecorded" &&
489
+ (submission.value.workerAdmission === undefined ||
490
+ !sameOrigin(submission.value.workerAdmission.origin, worker.origin))
491
+ )
492
+ return yield* failure("start", "denied");
493
+ if (
494
+ attached?._tag === "SubagentLineageRecorded" &&
495
+ (submission.value.parentLinkage?.parentSubmissionId !== attached.parentSubmissionId ||
496
+ submission.value.parentLinkage.parentToolCallId !== attached.parentLink.parentToolCallId)
497
+ )
498
+ return yield* failure("start", "denied");
499
+ }
500
+
501
+ const ownerBinding =
502
+ ownerSubmission === undefined ? undefined : currentBinding(ownerSubmission.agentId);
503
+
504
+ const selectedBinding = ownerBinding ?? binding;
505
+
506
+ if (worker?._tag === "WorkerOriginRecorded")
507
+ return {
508
+ current,
509
+ binding: selectedBinding,
510
+ submission: ownerSubmission,
511
+ policyOverride: Option.none<AgentPolicy>(),
512
+ policy: worker.origin.policy,
513
+ budget: worker.origin.budget,
514
+ budgetScope: worker.origin.budgetScope,
515
+ grant: worker.origin.grant,
516
+ depth: worker.origin.depth,
517
+ };
518
+ if (attached?._tag === "SubagentLineageRecorded") {
519
+ if (
520
+ attached.policy === undefined ||
521
+ attached.budget === undefined ||
522
+ attached.grant === undefined
523
+ )
524
+ return yield* failure("start", "denied");
525
+
526
+ return {
527
+ current,
528
+ binding: selectedBinding,
529
+ submission: ownerSubmission,
530
+ policyOverride: Option.none<AgentPolicy>(),
531
+ policy: attached.policy,
532
+ budget: attached.budget,
533
+ budgetScope: undefined,
534
+ grant: attached.grant,
535
+ depth: attached.parentLink.depth,
536
+ };
537
+ }
538
+
539
+ const changedRootAgent =
540
+ ownerSubmission !== undefined && ownerSubmission.agentId !== created.agentId;
541
+
542
+ // A root conversation may admit a new registered Agent after deployment.
543
+ // Its immutable owner input selects authority; child lineage never changes.
544
+ if (selectedBinding === undefined || (changedRootAgent && ownerBinding === undefined))
545
+ return yield* failure("start", "declaration-unavailable");
546
+
547
+ const selected = yield* deps.policyResolver.resolveSource({
548
+ threadId,
549
+ definition: selectedBinding.definition,
550
+ definitions: ownerSubmission?.agentDigests ?? selectedBinding.digests,
551
+ ...(ownerSubmission === undefined ? {} : { submission: ownerSubmission }),
552
+ });
553
+
554
+ if (Option.isSome(selected) && ownerSubmission !== undefined && ownerBinding === undefined)
555
+ return yield* failure("start", "declaration-unavailable");
556
+
557
+ const effectiveBinding =
558
+ Option.isSome(selected) || changedRootAgent || binding === undefined
559
+ ? selectedBinding
560
+ : binding;
561
+
562
+ if (effectiveBinding === undefined) return yield* failure("start", "declaration-unavailable");
563
+
564
+ const policy = Option.isNone(selected)
565
+ ? effectiveBinding.definition.policy
566
+ : yield* decode(AgentPolicy, selected.value, "start");
567
+
568
+ return {
569
+ current,
570
+ binding: effectiveBinding,
571
+ submission: ownerSubmission,
572
+ policyOverride: Option.map(selected, () => policy),
573
+ policy,
574
+ budget: undefined,
575
+ budgetScope: undefined,
576
+ grant: undefined,
577
+ depth: 0,
578
+ };
579
+ });
580
+
581
+ const resolveTargetPolicy = Effect.fn("WorkerHost.resolveTargetPolicy")(function* (
582
+ request: WorkerPolicyTarget,
583
+ ) {
584
+ const selected = yield* deps.policyResolver.resolveTarget(request);
585
+
586
+ if (Option.isNone(selected)) return selected;
587
+ const policy = yield* decode(AgentPolicy, selected.value, "start");
588
+
589
+ if (request._tag === "RetainedWorker" && !samePolicy(policy, request.origin.policy))
590
+ return yield* failure("start", "worker-mismatch");
591
+
592
+ return Option.some(policy);
593
+ });
594
+
595
+ const reserveSubtree = Effect.fn("WorkerHost.reserveSubtree")(function* (
596
+ sourceThreadId: ThreadId,
597
+ requested: SubtreeBudgetReserved,
598
+ ): Effect.fn.Return<void, WorkerError> {
599
+ const payload = yield* decode(SubtreeBudgetReserved, requested, "start");
600
+ const recordId = `subtree:${payload.reservationId}`;
601
+
602
+ for (let attempt = 0; attempt < 16; attempt++) {
603
+ const source = yield* sourceAuthority(sourceThreadId, payload.sourceSubmissionId, true);
604
+
605
+ const previous = source.current.records.find(({ record }) => record.recordId === recordId)
606
+ ?.record.payload;
607
+
608
+ if (previous !== undefined) {
609
+ if (
610
+ previous._tag !== "SubtreeBudgetReserved" ||
611
+ !Schema.toEquivalence(SubtreeBudgetReserved)(previous, payload)
612
+ )
613
+ return yield* failure("start", "idempotency-conflict");
614
+
615
+ return;
616
+ }
617
+ if (payload.depth !== source.depth + 1 || payload.depth > payload.grant.maxDepth)
618
+ return yield* failure("start", "denied");
619
+ const inherited = source.grant;
620
+ const lifetimes = inherited?.childLifetimes;
621
+
622
+ if (
623
+ inherited !== undefined &&
624
+ (payload.depth > inherited.maxDepth ||
625
+ payload.grant.maxDepth > inherited.maxDepth ||
626
+ (lifetimes !== undefined && !lifetimes.includes(payload.lifetime)) ||
627
+ payload.grant.allowedToolNames.some(
628
+ (name) => !inherited.allowedToolNames.includes(name),
629
+ ) ||
630
+ (lifetimes !== undefined &&
631
+ (payload.grant.childLifetimes ?? ["attached", "background"]).some(
632
+ (lifetime) => !lifetimes.includes(lifetime),
633
+ )))
634
+ )
635
+ return yield* failure("start", "denied");
636
+
637
+ const rows = source.current.records.flatMap(({ record }) =>
638
+ record.payload._tag === "SubtreeBudgetReserved" &&
639
+ record.payload.sourceSubmissionId === payload.sourceSubmissionId
640
+ ? [record.payload]
641
+ : [],
642
+ );
643
+
644
+ const caps = payload.budget.caps;
645
+
646
+ if (rows.some((row) => !sameCaps(row.budget.caps, caps)))
647
+ return yield* failure("start", "capacity");
648
+
649
+ const own = {
650
+ turns: source.policy.maxTurns,
651
+ toolCalls: source.policy.maxToolCalls,
652
+ durationMillis: Math.ceil(Duration.toMillis(source.policy.maxDuration)),
653
+ inputTokens: source.policy.tokenBudget ?? source.budget?.allocation.inputTokens ?? 0,
654
+ outputTokens: source.policy.tokenBudget ?? source.budget?.allocation.outputTokens ?? 0,
655
+ costMicrousd:
656
+ source.policy.costBudgetMicrousd ?? source.budget?.allocation.costMicrousd ?? 0,
657
+ resultBytes: source.policy.toolResultBounds.maxBytes,
658
+ };
659
+
660
+ const ceilings = sourceCaps(source.policy);
661
+ const child = payload.policy;
662
+ const allocation = payload.budget.allocation;
663
+
664
+ if (
665
+ child.maxTurns > Math.min(source.policy.maxTurns, allocation.turns) ||
666
+ child.maxToolCalls > Math.min(source.policy.maxToolCalls, allocation.toolCalls) ||
667
+ Duration.toMillis(child.maxDuration) >
668
+ Math.min(Duration.toMillis(source.policy.maxDuration), allocation.durationMillis) ||
669
+ child.toolConcurrency > source.policy.toolConcurrency ||
670
+ child.toolResultBounds.maxBytes > source.policy.toolResultBounds.maxBytes ||
671
+ (source.policy.tokenBudget !== undefined &&
672
+ (child.tokenBudget === undefined ||
673
+ child.tokenBudget > source.policy.tokenBudget ||
674
+ child.tokenBudget > allocation.inputTokens + allocation.outputTokens)) ||
675
+ (source.policy.costBudgetMicrousd !== undefined &&
676
+ (child.costBudgetMicrousd === undefined ||
677
+ child.costBudgetMicrousd >
678
+ Math.min(source.policy.costBudgetMicrousd, allocation.costMicrousd)))
679
+ )
680
+ return yield* failure("start", "capacity");
681
+ for (const [, cap] of amountCaps) {
682
+ if (caps[cap] !== undefined && ceilings[cap] !== undefined && caps[cap] > ceilings[cap])
683
+ return yield* failure("start", "capacity");
684
+ }
685
+ if (
686
+ (caps.maxTotalChildInvocations ?? 0) > source.policy.maxToolCalls ||
687
+ (caps.maxConcurrentChildren ?? 0) > source.policy.toolConcurrency
688
+ )
689
+ return yield* failure("start", "capacity");
690
+ const slots = 1 + (payload.budget.descendantInvocations ?? 0);
691
+
692
+ const chargedSlots = rows.reduce(
693
+ (sum, row) => sum + 1 + (row.budget.descendantInvocations ?? 0),
694
+ slots,
695
+ );
696
+
697
+ const slotLimit = Math.min(
698
+ caps.maxTotalChildInvocations ?? Infinity,
699
+ source.budget === undefined
700
+ ? source.policy.maxToolCalls
701
+ : (source.budget.descendantInvocations ?? 0),
702
+ );
703
+
704
+ if (chargedSlots > slotLimit) return yield* failure("start", "capacity");
705
+ for (const [amount, cap] of amountCaps) {
706
+ // Zero is the encoded absence of an allocation when this dimension is unconfigured.
707
+ // It must not become a new cumulative token or dollar ceiling in a descendant.
708
+ if (
709
+ source.budgetScope === "worker-run" &&
710
+ (amount === "inputTokens" || amount === "outputTokens" || amount === "costMicrousd") &&
711
+ source.budget !== undefined &&
712
+ source.budget.caps[cap] === undefined &&
713
+ source.budget.allocation[amount] === 0 &&
714
+ ceilings[cap] === undefined
715
+ ) {
716
+ const charged = rows.reduce(
717
+ (sum, row) => sum + row.budget.allocation[amount],
718
+ allocation[amount],
719
+ );
720
+
721
+ if (charged > (caps[cap] ?? Infinity)) return yield* failure("start", "capacity");
722
+ continue;
723
+ }
724
+
725
+ const residual =
726
+ source.budget === undefined
727
+ ? (ceilings[cap] ?? Infinity)
728
+ : Math.max(0, source.budget.allocation[amount] - own[amount]);
729
+
730
+ const limit = Math.min(caps[cap] ?? Infinity, residual);
731
+
732
+ const charged = rows.reduce(
733
+ (sum, row) => sum + row.budget.allocation[amount],
734
+ payload.budget.allocation[amount],
735
+ );
736
+
737
+ if (charged > limit) return yield* failure("start", "capacity");
738
+ }
739
+
740
+ // Include unreconciled reservations conservatively; only canonical completion frees an
741
+ // active slot. A worker Thread consumes one slot even when multiple inputs safely join it.
742
+ const completedWorkers = new Set<string>(
743
+ source.current.records.flatMap(({ record }) =>
744
+ record.payload._tag === "WorkerInputCompleted" ? [record.payload.messageId] : [],
745
+ ),
746
+ );
747
+
748
+ const completedAttached = new Set<string>(
749
+ source.current.records.flatMap(({ record }) =>
750
+ record.payload._tag === "SubagentJoined" ? [record.payload.reservationId] : [],
751
+ ),
752
+ );
753
+
754
+ const active = new Set(
755
+ rows
756
+ .filter((row) =>
757
+ row.lifetime === "background"
758
+ ? !completedWorkers.has(row.reservationId)
759
+ : !completedAttached.has(row.reservationId),
760
+ )
761
+ .map((row) => row.childThreadId),
762
+ );
763
+
764
+ if (
765
+ !active.has(payload.childThreadId) &&
766
+ active.size >=
767
+ Math.min(caps.maxConcurrentChildren ?? Infinity, source.policy.toolConcurrency)
768
+ )
769
+ return yield* failure("start", "capacity");
770
+ if (yield* append(sourceThreadId, recordId, payload, source.current, "subtree")) return;
771
+ }
772
+
773
+ return yield* failure("start", "storage");
774
+ });
775
+
776
+ const reservation = Effect.fn("WorkerHost.reserveInput")(function* (
777
+ admission: WorkerAdmission,
778
+ inputDigest: Digest,
779
+ input: PersistedJson,
780
+ principal: Principal,
781
+ retainedFrameworkInput: boolean,
782
+ ): Effect.fn.Return<void, WorkerError> {
783
+ const origin = admission.origin;
784
+ const id = workerInputRecordId(admission.messageId);
785
+
786
+ for (let attempt = 0; attempt < 16; attempt++) {
787
+ const source = yield* sourceAuthority(
788
+ origin.source.threadId,
789
+ admission.sourceSubmissionId,
790
+ true,
791
+ );
792
+
793
+ const current = source.current;
794
+ const rows = requests(current.records);
795
+ const existing = current.records.find(({ record }) => record.recordId === id)?.record.payload;
796
+
797
+ if (existing !== undefined) {
798
+ if (
799
+ existing._tag !== "WorkerInputRequested" ||
800
+ existing.inputDigest !== inputDigest ||
801
+ !sameAdmission(existing.admission, admission)
802
+ )
803
+ return yield* failure("start", "idempotency-conflict");
804
+ }
805
+ const first = current.records[0]?.record.payload;
806
+
807
+ if (first?._tag !== "ThreadCreated") return yield* failure("start", "denied");
808
+
809
+ const own = rows.filter(
810
+ (row) => row.admission.origin.worker.threadId === origin.worker.threadId,
811
+ );
812
+
813
+ const origins = new Map(
814
+ rows.map((row) => [row.admission.origin.worker.threadId, row.admission.origin]),
815
+ );
816
+
817
+ const prior = origins.get(origin.worker.threadId);
818
+
819
+ if (
820
+ prior === undefined &&
821
+ (source.submission?.agentId ?? first.agentId) !== origin.source.agentId
822
+ )
823
+ return yield* failure("start", "denied");
824
+ if (prior !== undefined && !sameOrigin(prior, origin))
825
+ return yield* failure("start", "worker-mismatch");
826
+ if (prior === undefined && admission.messageId !== origin.firstMessageId)
827
+ return yield* failure("start", "not-found");
828
+ const caps = origin.budget.caps;
829
+
830
+ const sourceBinding = source.binding;
831
+
832
+ const targetBinding = currentBinding(origin.worker.targetAgentId);
833
+
834
+ if (sourceBinding === undefined || targetBinding === undefined)
835
+ return yield* failure("start", "declaration-unavailable");
836
+ // Standard reports and updates retain the owner's original input bytes. Their
837
+ // framework message carries the new information independently of the current input codec.
838
+ if (!retainedFrameworkInput)
839
+ yield* Schema.decodeEffect(Schema.toEncoded(targetBinding.definition.input))(input).pipe(
840
+ Effect.mapError(() => failure("start", "corrupt")),
841
+ );
842
+
843
+ const targetRequest = {
844
+ definition: targetBinding.definition,
845
+ definitions: targetBinding.digests,
846
+ source: origin.source,
847
+ };
848
+
849
+ const selected = yield* resolveTargetPolicy(
850
+ admission.messageId === origin.firstMessageId
851
+ ? {
852
+ ...targetRequest,
853
+ _tag: "InitialInput",
854
+ input,
855
+ inputDigest,
856
+ ...(source.submission === undefined ? {} : { sourceSubmission: source.submission }),
857
+ }
858
+ : { ...targetRequest, _tag: "RetainedWorker", origin: prior ?? origin },
859
+ );
860
+
861
+ const independent = origin.budgetScope === "worker-run";
862
+
863
+ const targetPolicy = Option.isSome(selected)
864
+ ? selected.value
865
+ : independent
866
+ ? targetBinding.definition.policy
867
+ : AgentPolicy.resolve(
868
+ targetBinding.definition.policyOverrides ?? targetBinding.definition.policy,
869
+ source.policy,
870
+ );
871
+
872
+ // Captured authority is checked on replay too, before the retained reservation returns.
873
+ // Static callers retain the old idempotent-return behavior.
874
+ if (
875
+ (existing === undefined || Option.isSome(selected)) &&
876
+ !withinPolicy(origin, independent ? targetPolicy : source.policy, targetPolicy)
877
+ )
878
+ return yield* failure("start", "capacity");
879
+ if (existing !== undefined) return;
880
+ const now = yield* Clock.currentTimeMillis;
881
+
882
+ if (now >= origin.expiresAtMillis) return yield* failure("start", "capacity");
883
+ if (
884
+ (prior === undefined && origins.size >= deps.limits.maxWorkersPerSource) ||
885
+ own.filter((row) => row.admission.reportKind === admission.reportKind).length >=
886
+ (admission.reportKind === "update"
887
+ ? (deps.limits.maxUpdateInputsPerWorker ?? 256)
888
+ : deps.limits.maxInputsPerWorker)
889
+ )
890
+ return yield* failure("start", "capacity");
891
+ if (
892
+ prior === undefined &&
893
+ !sameReporting(
894
+ yield* reportIntent(sourceBinding, targetBinding, origin.worker.delegationId),
895
+ origin.reporting,
896
+ )
897
+ )
898
+ return yield* failure("start", "denied");
899
+ if (independent && source.depth !== 0) return yield* failure("start", "denied");
900
+ const ceilings = sourceCaps(source.policy);
901
+
902
+ const conservedRows = rows.filter((row) => row.admission.origin.budgetScope !== "worker-run");
903
+
904
+ const chargedRows =
905
+ source.depth === 0
906
+ ? conservedRows
907
+ : conservedRows.filter(
908
+ (row) => row.admission.sourceSubmissionId === admission.sourceSubmissionId,
909
+ );
910
+
911
+ // Independent origins do not belong to this pool. Preserve the retained conserved
912
+ // origins' cap identity check separately from the current input's charge selection.
913
+ if (
914
+ !independent &&
915
+ conservedRows.some((row) => !sameCaps(row.admission.origin.budget.caps, caps))
916
+ )
917
+ return yield* failure("start", "capacity");
918
+ if (
919
+ !independent &&
920
+ chargedRows.reduce(
921
+ (sum, row) => sum + 1 + (row.admission.origin.budget.descendantInvocations ?? 0),
922
+ 1 + (origin.budget.descendantInvocations ?? 0),
923
+ ) > Math.min(caps.maxTotalChildInvocations ?? Infinity, source.policy.maxToolCalls)
924
+ )
925
+ return yield* failure("start", "capacity");
926
+ // Worker-owned Run usage is already durable in the destination's Run journal. Each
927
+ // Receipt may join an existing Run, so admitting input must never mint an allowance.
928
+ for (const [amount, cap] of independent ? [] : amountCaps) {
929
+ const limit = Math.min(caps[cap] ?? Infinity, ceilings[cap] ?? Infinity);
930
+
931
+ if (
932
+ chargedRows.reduce(
933
+ (sum, row) => sum + row.admission.origin.budget.allocation[amount],
934
+ origin.budget.allocation[amount],
935
+ ) > limit
936
+ )
937
+ return yield* failure("start", "capacity");
938
+ }
939
+
940
+ // Child owners append acknowledgements before ledger finalization. This works through
941
+ // routed canonical storage; source-local delivery rows are never read from a child owner.
942
+ const completed = new Set(
943
+ current.records.flatMap(({ record }) =>
944
+ record.payload._tag === "WorkerInputCompleted" ? [record.payload.messageId] : [],
945
+ ),
946
+ );
947
+
948
+ const pendingRows = rows.filter((row) => !completed.has(row.admission.messageId));
949
+ const activeWorkers = new Set(pendingRows.map((row) => row.admission.origin.worker.threadId));
950
+
951
+ const pendingOwn = pendingRows.filter(
952
+ (row) =>
953
+ row.admission.origin.worker.threadId === origin.worker.threadId &&
954
+ row.admission.reportKind === admission.reportKind,
955
+ ).length;
956
+
957
+ // Resolve inside the source CAS loop: independently delivered starts must compete
958
+ // against one canonical prefix. A conflict repeats both authority and capacity reads.
959
+ const selectedConcurrency = yield* deps.concurrencyResolver.resolve({
960
+ source: origin.source,
961
+ worker: origin.worker,
962
+ principal,
963
+ ...(source.submission === undefined ? {} : { sourceSubmission: source.submission }),
964
+ });
965
+
966
+ const sourceConcurrency = Option.isSome(selectedConcurrency)
967
+ ? (yield* decode(WorkerConcurrencyLimit, selectedConcurrency.value, "start"))
968
+ .maxActiveWorkersPerSource
969
+ : Infinity;
970
+
971
+ if (
972
+ pendingOwn >=
973
+ (admission.reportKind === "update"
974
+ ? (deps.limits.maxPendingUpdateInputsPerWorker ?? 32)
975
+ : deps.limits.maxPendingInputsPerWorker) ||
976
+ (!activeWorkers.has(origin.worker.threadId) &&
977
+ activeWorkers.size >=
978
+ Math.min(
979
+ sourceConcurrency,
980
+ deps.limits.maxActiveWorkersPerSource ?? source.policy.toolConcurrency,
981
+ independent
982
+ ? Infinity
983
+ : Math.min(caps.maxConcurrentChildren ?? Infinity, source.policy.toolConcurrency),
984
+ ))
985
+ )
986
+ return yield* WorkerError.make({ operation: "start", reason: "capacity", retryable: true });
987
+ if (!independent)
988
+ yield* reserveSubtree(
989
+ origin.source.threadId,
990
+ SubtreeBudgetReserved.make({
991
+ reservationId: Schema.decodeSync(SubtreeBudgetReserved.fields.reservationId)(
992
+ admission.messageId,
993
+ ),
994
+ ...(admission.sourceSubmissionId === undefined
995
+ ? {}
996
+ : { sourceSubmissionId: admission.sourceSubmissionId }),
997
+ childThreadId: origin.worker.threadId,
998
+ lifetime: "background",
999
+ depth: origin.depth,
1000
+ policy: origin.policy,
1001
+ grant: origin.grant,
1002
+ budget: origin.budget,
1003
+ }),
1004
+ );
1005
+ if (
1006
+ yield* append(
1007
+ origin.source.threadId,
1008
+ id,
1009
+ WorkerInputRequested.make({ admission, inputDigest }),
1010
+ current,
1011
+ "source",
1012
+ )
1013
+ )
1014
+ return;
1015
+ }
1016
+
1017
+ return yield* failure("start", "storage");
1018
+ });
1019
+
1020
+ const ensureOrigin = Effect.fn("WorkerHost.ensureOrigin")(function* (origin: WorkerOrigin) {
1021
+ for (let attempt = 0; attempt < 16; attempt++) {
1022
+ const current = yield* readIdentity(origin.worker.threadId, "start");
1023
+
1024
+ const existing = current.records.find(
1025
+ ({ record }) => record.payload._tag === "WorkerOriginRecorded",
1026
+ )?.record.payload;
1027
+
1028
+ if (existing?._tag === "WorkerOriginRecorded") {
1029
+ if (!sameOrigin(existing.origin, origin)) return yield* failure("start", "worker-mismatch");
1030
+
1031
+ return;
1032
+ }
1033
+ const first = current.records[0]?.record.payload;
1034
+
1035
+ if (
1036
+ first?._tag !== "ThreadCreated" ||
1037
+ first.agentId !== origin.worker.targetAgentId ||
1038
+ !definitionDigestsEqual(first.definitions, origin.targetDigests) ||
1039
+ current.records.some(({ record }) => record.payload._tag === "SubagentLineageRecorded")
1040
+ )
1041
+ return yield* failure("start", "worker-mismatch");
1042
+ if (
1043
+ yield* append(
1044
+ origin.worker.threadId,
1045
+ workerOriginRecordId(origin.worker.threadId),
1046
+ WorkerOriginRecorded.make({ origin }),
1047
+ current,
1048
+ "origin",
1049
+ )
1050
+ )
1051
+ return;
1052
+ }
1053
+
1054
+ return yield* failure("start", "storage");
1055
+ });
1056
+
1057
+ const validateAdmission = Effect.fn("WorkerHost.validateAdmission")(function* (
1058
+ unvalidated: WorkerAdmission,
1059
+ options: DurableSubmitOptions,
1060
+ agentId: Agent.AnyDefinition["id"],
1061
+ inputDigest: Digest,
1062
+ input: PersistedJson,
1063
+ ) {
1064
+ const admission = yield* decode(WorkerAdmission, unvalidated, "start");
1065
+
1066
+ if (admission.reportKind === "update") {
1067
+ if (!Schema.is(WorkerUpdate)(options.messageAdmission))
1068
+ return yield* failure("start", "denied");
1069
+ yield* validateCompletion(options.messageAdmission, options, agentId, inputDigest);
1070
+ }
1071
+
1072
+ yield* deps.authorizer.authorize({
1073
+ sourceThreadId: admission.origin.source.threadId,
1074
+ ...(admission.sourceSubmissionId === undefined
1075
+ ? {}
1076
+ : { sourceSubmissionId: admission.sourceSubmissionId }),
1077
+ principal: options.principal,
1078
+ operation: "start",
1079
+ access: "send",
1080
+ worker: admission.origin.worker,
1081
+ });
1082
+ yield* authorizeBudget(admission.origin, options.principal);
1083
+ if (
1084
+ admission.origin.worker.threadId !== options.threadId ||
1085
+ admission.origin.worker.targetAgentId !== agentId ||
1086
+ !definitionDigestsEqual(admission.origin.targetDigests, options.definitions) ||
1087
+ options.idempotencyKey !== admission.messageId ||
1088
+ (admission.deliveryPrincipal !== undefined &&
1089
+ admission.deliveryPrincipal !== options.principal)
1090
+ )
1091
+ return yield* failure("start", "worker-mismatch");
1092
+ const retainedFrameworkInput = Schema.is(FrameworkMessage)(options.messageAdmission);
1093
+
1094
+ if (retainedFrameworkInput && admission.reportKind !== "update")
1095
+ yield* validateCompletion(options.messageAdmission, options, agentId, inputDigest);
1096
+ yield* reservation(admission, inputDigest, input, options.principal, retainedFrameworkInput);
1097
+
1098
+ return admission;
1099
+ });
1100
+
1101
+ const prepareUpdate = Effect.fn("WorkerHost.prepareUpdate")(
1102
+ function* (update: Update, submission: SubmissionSnapshot, messageId: IdempotencyKey) {
1103
+ const origin = submission.workerAdmission?.origin;
1104
+ const intent = origin?.reporting;
1105
+
1106
+ if (origin === undefined || intent?.mode !== "standard") return undefined;
1107
+ if (update.threadId !== submission.threadId || update.agentId !== origin.worker.targetAgentId)
1108
+ return yield* failure("followUp", "worker-mismatch");
1109
+
1110
+ const first = Option.getOrUndefined(
1111
+ yield* exactRecord(
1112
+ origin.source.threadId,
1113
+ workerInputRecordId(origin.firstMessageId),
1114
+ "followUp",
1115
+ ),
1116
+ )?.record.payload;
1117
+
1118
+ if (
1119
+ first?._tag !== "WorkerInputRequested" ||
1120
+ first.admission.messageId !== origin.firstMessageId ||
1121
+ !sameOrigin(first.admission.origin, origin)
1122
+ )
1123
+ return yield* failure("followUp", "corrupt");
1124
+
1125
+ const source = yield* sourceAuthority(
1126
+ origin.source.threadId,
1127
+ first.admission.sourceSubmissionId,
1128
+ );
1129
+
1130
+ if (source.binding === undefined || source.submission === undefined)
1131
+ return yield* failure("followUp", "declaration-unavailable");
1132
+
1133
+ const sourceBinding = currentBinding(origin.source.agentId);
1134
+ const targetBinding = currentBinding(origin.worker.targetAgentId);
1135
+
1136
+ const reports =
1137
+ sourceBinding?.reporting?.filter(
1138
+ (entry) => entry.delegationId === origin.worker.delegationId,
1139
+ ) ?? [];
1140
+
1141
+ if (
1142
+ sourceBinding === undefined ||
1143
+ targetBinding === undefined ||
1144
+ reports.length !== 1 ||
1145
+ reports[0]?.mode !== "standard" ||
1146
+ reports[0].target !== targetBinding.definition ||
1147
+ !definitionDigestsEqual(submission.agentDigests, origin.targetDigests)
1148
+ )
1149
+ return yield* failure("followUp", "declaration-unavailable");
1150
+
1151
+ const recorded = source.current.records.find(
1152
+ ({ record }) => record.payload._tag === "WorkerOriginRecorded",
1153
+ )?.record.payload;
1154
+
1155
+ const receivingOrigin =
1156
+ recorded?._tag === "WorkerOriginRecorded" ? recorded.origin : undefined;
1157
+
1158
+ if (source.depth !== 0 && receivingOrigin === undefined)
1159
+ return yield* failure("followUp", "denied");
1160
+ const now = yield* Clock.currentTimeMillis;
1161
+
1162
+ const deadlineAtMillis = Math.min(
1163
+ origin.expiresAtMillis,
1164
+ receivingOrigin?.expiresAtMillis ?? Infinity,
1165
+ );
1166
+
1167
+ if (now >= deadlineAtMillis) return yield* failure("followUp", "denied");
1168
+ const input = source.submission.inputPayload;
1169
+
1170
+ let workerAdmission: WorkerAdmission | undefined;
1171
+ let principal = submission.principal;
1172
+
1173
+ if (receivingOrigin !== undefined) {
1174
+ const retained = source.submission.workerAdmission;
1175
+
1176
+ if (retained === undefined || !sameOrigin(retained.origin, receivingOrigin))
1177
+ return yield* failure("followUp", "denied");
1178
+ principal = source.submission.principal;
1179
+ workerAdmission = {
1180
+ origin: receivingOrigin,
1181
+ reportKind: "update",
1182
+ messageId,
1183
+ parameters: retained.parameters,
1184
+ createdAtMillis: now,
1185
+ ...(retained.sourceSubmissionId === undefined
1186
+ ? {}
1187
+ : { sourceSubmissionId: retained.sourceSubmissionId }),
1188
+ };
1189
+ }
1190
+
1191
+ const sourceSubmissionId =
1192
+ receivingOrigin === undefined
1193
+ ? first.admission.sourceSubmissionId
1194
+ : workerAdmission?.sourceSubmissionId;
1195
+
1196
+ const authorized = yield* deps.authorizer.authorize({
1197
+ sourceThreadId: receivingOrigin?.source.threadId ?? origin.source.threadId,
1198
+ ...(sourceSubmissionId === undefined ? {} : { sourceSubmissionId }),
1199
+ principal,
1200
+ operation: "followUp",
1201
+ access: "send",
1202
+ worker: receivingOrigin?.worker ?? origin.worker,
1203
+ });
1204
+
1205
+ const message = WorkerUpdate.make({
1206
+ _tag: "WorkerUpdate",
1207
+ schemaVersion: 1,
1208
+ worker: origin.worker,
1209
+ update,
1210
+ });
1211
+
1212
+ const envelope: PreparedInput = {
1213
+ schemaVersion: 1,
1214
+ threadId: origin.source.threadId,
1215
+ deliveryPrincipal: authorized,
1216
+ agentId: origin.source.agentId,
1217
+ definitions: intent.sourceDigests,
1218
+ input,
1219
+ inputDigest: yield* withCrypto(digestJson(input)).pipe(
1220
+ Effect.mapError(storageFailure("followUp")),
1221
+ ),
1222
+ admissionKey: messageId,
1223
+ authorization: { policyId: "worker-report", decisionId: messageId },
1224
+ messageAdmission: message,
1225
+ ...(workerAdmission === undefined
1226
+ ? {}
1227
+ : { workerAdmission: { ...workerAdmission, deliveryPrincipal: authorized } }),
1228
+ };
1229
+
1230
+ return {
1231
+ messageId,
1232
+ envelope: yield* Schema.encodeEffect(PreparedInput)(envelope).pipe(
1233
+ Effect.flatMap(Schema.decodeEffect(PersistedJson)),
1234
+ Effect.mapError(storageFailure("followUp")),
1235
+ ),
1236
+ createdAtMillis: now,
1237
+ deadlineAtMillis,
1238
+ };
1239
+ },
1240
+ Effect.mapError((error) =>
1241
+ error.reason === "storage" || error.reason === "corrupt"
1242
+ ? LedgerError.make({ operation: "worker-update", message: error.reason })
1243
+ : UpdateError.make({ reason: error.reason === "denied" ? "denied" : "unavailable" }),
1244
+ ),
1245
+ );
1246
+
1247
+ const reportRun = Effect.fn("WorkerHost.reportRun")(function* (
1248
+ submission: SubmissionSnapshot,
1249
+ history: Effect.Success<ReturnType<typeof read>>,
1250
+ ): Effect.fn.Return<void, WorkerError> {
1251
+ const admission = submission.workerAdmission;
1252
+ const intent = admission?.origin.reporting;
1253
+
1254
+ if (admission === undefined || intent === undefined) return;
1255
+ const origin = admission.origin;
1256
+
1257
+ const member = history.records.find(
1258
+ ({ record }) =>
1259
+ record.payload._tag === "SubmissionSettled" &&
1260
+ record.payload.submissionId === submission.submissionId,
1261
+ )?.record.payload;
1262
+
1263
+ if (member?._tag !== "SubmissionSettled") return yield* failure("inspect", "corrupt");
1264
+ if (member.runId === undefined) return; // No actual Run means no fabricated report identity.
1265
+ const runId = member.runId;
1266
+
1267
+ const host = history.records.find(
1268
+ ({ record }) => record.payload._tag === "SubmissionSettled" && record.payload.runId === runId,
1269
+ )?.record.payload;
1270
+
1271
+ if (host?._tag !== "SubmissionSettled") return yield* failure("inspect", "corrupt");
1272
+
1273
+ const messageId = yield* withCrypto(
1274
+ digestJson(["worker-report", submission.threadId, runId]),
1275
+ ).pipe(
1276
+ Effect.map((value) => Schema.decodeSync(IdempotencyKey)(`report:${value}`)),
1277
+ Effect.mapError(storageFailure("inspect")),
1278
+ );
1279
+
1280
+ const recordId = workerReportRecordId(messageId);
1281
+
1282
+ const prepare = Effect.fn("WorkerHost.prepareReport")(function* (): Effect.fn.Return<
1283
+ WorkerReportPrepared | WorkerReportRefused,
1284
+ WorkerError
1285
+ > {
1286
+ const refused = (reason: WorkerReportRefused["reason"]) =>
1287
+ WorkerReportRefused.make({ runId, messageId, reason });
1288
+
1289
+ const selected = yield* deps.ledger
1290
+ .lookup(SubmissionLookupById.make({ submissionId: host.submissionId }))
1291
+ .pipe(Effect.mapError(storageFailure("inspect")));
1292
+
1293
+ if (
1294
+ Option.isNone(selected) ||
1295
+ selected.value.threadId !== submission.threadId ||
1296
+ selected.value.receiptId !== host.receiptId ||
1297
+ selected.value.workerAdmission === undefined ||
1298
+ !sameOrigin(selected.value.workerAdmission.origin, origin)
1299
+ )
1300
+ return yield* failure("inspect", "corrupt");
1301
+ const hostSubmission = selected.value;
1302
+ const hostAdmission = selected.value.workerAdmission;
1303
+
1304
+ const firstInput = Option.getOrUndefined(
1305
+ yield* exactRecord(
1306
+ origin.source.threadId,
1307
+ workerInputRecordId(origin.firstMessageId),
1308
+ "inspect",
1309
+ ),
1310
+ )?.record.payload;
1311
+
1312
+ if (
1313
+ firstInput?._tag !== "WorkerInputRequested" ||
1314
+ firstInput.admission.messageId !== origin.firstMessageId ||
1315
+ !sameOrigin(firstInput.admission.origin, origin)
1316
+ )
1317
+ return yield* failure("inspect", "corrupt");
1318
+
1319
+ // Reporting stays with the original owner even when a later input came from another
1320
+ // source revision. Per-input parameters still belong to the settled Run.
1321
+ const source = yield* sourceAuthority(
1322
+ origin.source.threadId,
1323
+ firstInput.admission.sourceSubmissionId,
1324
+ );
1325
+
1326
+ if (source.binding === undefined) return refused("declaration-unavailable");
1327
+
1328
+ const sourceBinding = currentBinding(origin.source.agentId);
1329
+ const targetBinding = currentBinding(origin.worker.targetAgentId);
1330
+
1331
+ const reports =
1332
+ sourceBinding?.reporting?.filter(
1333
+ (entry) => entry.delegationId === origin.worker.delegationId,
1334
+ ) ?? [];
1335
+
1336
+ const descriptor = reports[0];
1337
+
1338
+ if (
1339
+ sourceBinding === undefined ||
1340
+ targetBinding === undefined ||
1341
+ descriptor === undefined ||
1342
+ reports.length !== 1 ||
1343
+ !Object.is(descriptor.target, targetBinding.definition) ||
1344
+ (descriptor.mode !== "standard" &&
1345
+ !Object.is(descriptor.input, sourceBinding.definition.input)) ||
1346
+ descriptor.mode !== intent.mode ||
1347
+ descriptor.destination?.delegationId !== intent.destinationDelegationId ||
1348
+ (descriptor.destination !== undefined &&
1349
+ !Object.is(descriptor.destination.target, sourceBinding.definition))
1350
+ )
1351
+ return refused("declaration-unavailable");
1352
+
1353
+ const sourceOriginRecord = source.current.records.find(
1354
+ ({ record }) => record.payload._tag === "WorkerOriginRecorded",
1355
+ )?.record.payload;
1356
+
1357
+ const sourceOrigin =
1358
+ sourceOriginRecord?._tag === "WorkerOriginRecorded" ? sourceOriginRecord.origin : undefined;
1359
+
1360
+ if (source.depth !== 0 && sourceOrigin === undefined) return refused("destination");
1361
+ if (
1362
+ descriptor.mode !== "standard" &&
1363
+ sourceOrigin !== undefined &&
1364
+ (descriptor.destination === undefined ||
1365
+ descriptor.destination.delegationId !== sourceOrigin.worker.delegationId ||
1366
+ descriptor.destination.target.id !== sourceOrigin.worker.targetAgentId)
1367
+ )
1368
+ return refused("destination");
1369
+ if (sourceOrigin === undefined && descriptor.destination !== undefined)
1370
+ return refused("destination");
1371
+ const now = yield* Clock.currentTimeMillis;
1372
+
1373
+ const deadlineAtMillis = Math.min(
1374
+ origin.expiresAtMillis,
1375
+ sourceOrigin?.expiresAtMillis ?? Infinity,
1376
+ );
1377
+
1378
+ if (now >= deadlineAtMillis) return refused("expired");
1379
+
1380
+ const context: WorkerContext = {
1381
+ source: origin.source,
1382
+ policy: source.policy,
1383
+ depth: source.depth,
1384
+ ...(source.grant === undefined ? {} : { grant: source.grant }),
1385
+ };
1386
+
1387
+ const report: WorkerRunReport = {
1388
+ worker: origin.worker,
1389
+ context,
1390
+ observation: {
1391
+ _tag: "Settled",
1392
+ receipt: Receipt.make({
1393
+ threadId: hostSubmission.threadId,
1394
+ submissionId: hostSubmission.submissionId,
1395
+ receiptId: hostSubmission.receiptId,
1396
+ queueSequence: hostSubmission.queueSequence,
1397
+ }),
1398
+ runId,
1399
+ settlementId: host.settlementId,
1400
+ outcome: host.outcome,
1401
+ encodedParameters: hostAdmission.parameters,
1402
+ encodedResult: host.result ?? null,
1403
+ budgetExhausted: host.finishReason === "budget-exhausted",
1404
+ },
1405
+ };
1406
+
1407
+ const projection = yield* Effect.suspend(() => descriptor.prepare(report)).pipe(
1408
+ Effect.timeout(
1409
+ Math.min(deps.limits.reportPreparationTimeoutMillis ?? 5_000, deadlineAtMillis - now),
1410
+ ),
1411
+ Effect.map((value) => ({ _tag: "Prepared" as const, value })),
1412
+ Effect.catchTag("WorkerReportPreparationFailure", (error) =>
1413
+ Effect.succeed(refused(error.stage)),
1414
+ ),
1415
+ Effect.catchTag("TimeoutError", () => Effect.succeed(refused("timeout"))),
1416
+ Effect.catchCauseIf(
1417
+ (cause) => !Cause.hasInterrupts(cause),
1418
+ () => Effect.succeed(refused("defect")),
1419
+ ),
1420
+ );
1421
+
1422
+ if (projection._tag === "WorkerReportRefused") return projection;
1423
+
1424
+ if (descriptor.mode === "standard") {
1425
+ const message = projection.value.message;
1426
+
1427
+ if (source.submission === undefined || !Schema.is(WorkerCompletion)(message))
1428
+ return refused("input");
1429
+ if (
1430
+ !Schema.toEquivalence(WorkerRef)(message.report.worker, origin.worker) ||
1431
+ !Schema.toEquivalence(Receipt)(message.report.receipt, report.observation.receipt) ||
1432
+ message.report.runId !== runId ||
1433
+ message.report.settlementId !== host.settlementId ||
1434
+ message.report.outcome !== host.outcome ||
1435
+ message.budgetExhausted !== report.observation.budgetExhausted
1436
+ )
1437
+ return refused("input");
1438
+ } else if (projection.value.message !== undefined) return refused("input");
1439
+
1440
+ const reportInput =
1441
+ descriptor.mode === "standard"
1442
+ ? source.submission?.inputPayload
1443
+ : projection.value.encodedInput;
1444
+
1445
+ const validated = yield* (
1446
+ descriptor.mode === "standard"
1447
+ ? Schema.decodeUnknownEffect(PersistedJson)(reportInput)
1448
+ : Schema.decodeEffect(Schema.toEncoded(sourceBinding.definition.input))(reportInput).pipe(
1449
+ Effect.flatMap(() => Schema.decodeUnknownEffect(PersistedJson)(reportInput)),
1450
+ )
1451
+ ).pipe(Effect.option);
1452
+
1453
+ if (Option.isNone(validated)) return refused("input");
1454
+ const input = validated.value;
1455
+
1456
+ const inputDigest = yield* withCrypto(digestJson(input)).pipe(
1457
+ Effect.mapError(storageFailure("inspect")),
1458
+ );
1459
+
1460
+ let workerAdmission: WorkerAdmission | undefined;
1461
+ let principal = hostSubmission.principal;
1462
+
1463
+ if (sourceOrigin !== undefined) {
1464
+ const ownerId =
1465
+ descriptor.mode === "standard"
1466
+ ? firstInput.admission.sourceSubmissionId
1467
+ : hostAdmission.sourceSubmissionId;
1468
+
1469
+ if (ownerId === undefined) return refused("destination");
1470
+
1471
+ const sourceSnapshot = yield* deps.ledger
1472
+ .lookup(SubmissionLookupById.make({ submissionId: ownerId }))
1473
+ .pipe(Effect.mapError(storageFailure("inspect")));
1474
+
1475
+ if (
1476
+ Option.isNone(sourceSnapshot) ||
1477
+ sourceSnapshot.value.threadId !== origin.source.threadId ||
1478
+ sourceSnapshot.value.workerAdmission === undefined ||
1479
+ !sameOrigin(sourceSnapshot.value.workerAdmission.origin, sourceOrigin)
1480
+ )
1481
+ return refused("destination");
1482
+
1483
+ const parameters = yield* Schema.decodeUnknownEffect(PersistedJson)(
1484
+ descriptor.mode === "standard"
1485
+ ? sourceSnapshot.value.workerAdmission.parameters
1486
+ : projection.value.encodedParameters,
1487
+ ).pipe(Effect.option);
1488
+
1489
+ if (Option.isNone(parameters)) return refused("destination");
1490
+ principal = sourceSnapshot.value.principal;
1491
+ workerAdmission = {
1492
+ origin: sourceOrigin,
1493
+ messageId,
1494
+ parameters: parameters.value,
1495
+ createdAtMillis: now,
1496
+ ...(sourceSnapshot.value.workerAdmission.sourceSubmissionId === undefined
1497
+ ? {}
1498
+ : { sourceSubmissionId: sourceSnapshot.value.workerAdmission.sourceSubmissionId }),
1499
+ };
1500
+ }
1501
+
1502
+ // Reporting remains owned by the original allocator, even when a later input joins
1503
+ // or starts another Run. Nested reports authorize the enclosing worker's source owner.
1504
+ const authorizationSourceSubmissionId =
1505
+ sourceOrigin === undefined
1506
+ ? firstInput.admission.sourceSubmissionId
1507
+ : workerAdmission?.sourceSubmissionId;
1508
+
1509
+ const authorized = yield* deps.authorizer
1510
+ .authorize({
1511
+ sourceThreadId: sourceOrigin?.source.threadId ?? origin.source.threadId,
1512
+ ...(authorizationSourceSubmissionId === undefined
1513
+ ? {}
1514
+ : { sourceSubmissionId: authorizationSourceSubmissionId }),
1515
+ principal,
1516
+ operation: "followUp",
1517
+ access: "send",
1518
+ worker: sourceOrigin?.worker ?? origin.worker,
1519
+ })
1520
+ .pipe(
1521
+ Effect.map(Option.some),
1522
+ Effect.catchTag("WorkerError", (error) =>
1523
+ error.reason === "storage" || error.reason === "unavailable"
1524
+ ? Effect.fail(error)
1525
+ : Effect.succeed(Option.none<Principal>()),
1526
+ ),
1527
+ );
1528
+
1529
+ if (Option.isNone(authorized)) return refused("denied");
1530
+
1531
+ const envelope: PreparedInput = {
1532
+ schemaVersion: 1,
1533
+ threadId: origin.source.threadId,
1534
+ deliveryPrincipal: authorized.value,
1535
+ agentId: origin.source.agentId,
1536
+ definitions: intent.sourceDigests,
1537
+ input,
1538
+ inputDigest,
1539
+ admissionKey: messageId,
1540
+ authorization: { policyId: "worker-report", decisionId: messageId },
1541
+ ...(projection.value.message === undefined
1542
+ ? {}
1543
+ : { messageAdmission: projection.value.message }),
1544
+ ...(workerAdmission === undefined
1545
+ ? {}
1546
+ : { workerAdmission: { ...workerAdmission, deliveryPrincipal: authorized.value } }),
1547
+ };
1548
+
1549
+ const encoded = yield* Schema.encodeEffect(PreparedInput)(envelope).pipe(
1550
+ Effect.flatMap(Schema.decodeUnknownEffect(PersistedJson)),
1551
+ Effect.mapError(storageFailure("inspect")),
1552
+ );
1553
+
1554
+ return WorkerReportPrepared.make({
1555
+ runId,
1556
+ messageId,
1557
+ envelope: encoded,
1558
+ createdAtMillis: now,
1559
+ deadlineAtMillis,
1560
+ ...(lastWorkerReportMessageId(history.records) === undefined
1561
+ ? {}
1562
+ : { predecessor: lastWorkerReportMessageId(history.records) }),
1563
+ });
1564
+ });
1565
+
1566
+ let decision: WorkerReportPrepared | WorkerReportRefused | undefined;
1567
+
1568
+ for (let attempt = 0; attempt < 16; attempt++) {
1569
+ const current = yield* read(submission.threadId, "inspect");
1570
+
1571
+ const existing = current.records.find(({ record }) => record.recordId === recordId)?.record
1572
+ .payload;
1573
+
1574
+ if (existing !== undefined) {
1575
+ if (
1576
+ (existing._tag !== "WorkerReportPrepared" && existing._tag !== "WorkerReportRefused") ||
1577
+ existing.runId !== runId ||
1578
+ existing.messageId !== messageId
1579
+ )
1580
+ return yield* failure("inspect", "corrupt");
1581
+ decision = existing;
1582
+ break;
1583
+ }
1584
+ decision ??= yield* prepare();
1585
+ if (yield* append(submission.threadId, recordId, decision, current, "report")) break;
1586
+ if (attempt === 15) return yield* failure("inspect", "storage");
1587
+ }
1588
+ if (decision?._tag !== "WorkerReportPrepared") return;
1589
+ if (Option.isNone(deps.deliveries)) return yield* failure("inspect", "unavailable");
1590
+
1591
+ const envelope = yield* Schema.decodeUnknownEffect(PreparedInput)(decision.envelope).pipe(
1592
+ Effect.mapError(() => failure("inspect", "corrupt")),
1593
+ );
1594
+
1595
+ const prepared = yield* withCrypto(
1596
+ prepareMessageDelivery({
1597
+ key: { ownerThreadId: submission.threadId, messageId },
1598
+ envelope,
1599
+ createdAtMillis: decision.createdAtMillis,
1600
+ deadlineAtMillis: decision.deadlineAtMillis,
1601
+ ...(decision.predecessor === undefined ? {} : { predecessor: decision.predecessor }),
1602
+ }),
1603
+ ).pipe(Effect.mapError(storageFailure("inspect")));
1604
+
1605
+ // Until this insertion commits the child ledger stays nonterminal. Afterwards its independent
1606
+ // due index survives both child and source settlement, including Object eviction.
1607
+ yield* hit("worker:before-report-delivery", "inspect");
1608
+ yield* deps.deliveries.value.insert(prepared).pipe(Effect.mapError(storageFailure("inspect")));
1609
+ yield* hit("worker:after-report-delivery", "inspect");
1610
+ });
1611
+
1612
+ const completeInput = Effect.fn("WorkerHost.completeInput")(function* (
1613
+ submission: SubmissionSnapshot,
1614
+ ) {
1615
+ const admission = submission.workerAdmission;
1616
+
1617
+ if (admission === undefined) return;
1618
+ const child = yield* read(submission.threadId, "inspect");
1619
+
1620
+ yield* reportRun(submission, child);
1621
+
1622
+ const settledEnvelope = child.records.find(
1623
+ ({ record }) =>
1624
+ record.payload._tag === "SubmissionSettled" &&
1625
+ record.payload.submissionId === submission.submissionId,
1626
+ )?.record;
1627
+
1628
+ const settled = settledEnvelope?.payload;
1629
+
1630
+ if (
1631
+ settled?._tag !== "SubmissionSettled" ||
1632
+ settled.receiptId !== submission.receiptId ||
1633
+ settledEnvelope === undefined
1634
+ )
1635
+ return yield* failure("inspect", "corrupt");
1636
+
1637
+ const unresolved = new Set<string>();
1638
+
1639
+ for (const { record } of child.records) {
1640
+ const value = record.payload;
1641
+
1642
+ if (
1643
+ (value._tag === "ToolCallPrepared" || value._tag === "ToolCallUnknown") &&
1644
+ value.runId === settled.runId
1645
+ )
1646
+ unresolved.add(value.toolCallId);
1647
+ if (value._tag === "ToolCallSettled" && value.runId === settled.runId)
1648
+ unresolved.delete(value.toolCallId);
1649
+ }
1650
+ if (unresolved.size > 0) return;
1651
+
1652
+ const payload = WorkerInputCompleted.make({
1653
+ effectsResolved: true,
1654
+ messageId: admission.messageId,
1655
+ workerThreadId: submission.threadId,
1656
+ submissionId: submission.submissionId,
1657
+ receiptId: submission.receiptId,
1658
+ settlementId: settled.settlementId,
1659
+ completedAtMillis: DateTime.toEpochMillis(settledEnvelope.createdAt),
1660
+ });
1661
+
1662
+ for (let attempt = 0; attempt < 16; attempt++) {
1663
+ const source = yield* read(admission.origin.source.threadId, "inspect");
1664
+
1665
+ const existing = source.records.findLast(
1666
+ ({ record }) =>
1667
+ record.payload._tag === "WorkerInputCompleted" &&
1668
+ record.payload.messageId === admission.messageId,
1669
+ )?.record.payload;
1670
+
1671
+ if (existing !== undefined) {
1672
+ if (
1673
+ existing._tag !== "WorkerInputCompleted" ||
1674
+ !Schema.toEquivalence(WorkerInputCompleted)(
1675
+ { ...existing, effectsResolved: true },
1676
+ payload,
1677
+ )
1678
+ )
1679
+ return yield* failure("inspect", "corrupt");
1680
+
1681
+ if (existing.effectsResolved) return;
1682
+ }
1683
+ if (
1684
+ yield* append(
1685
+ admission.origin.source.threadId,
1686
+ `worker-effects-resolved:${admission.messageId}`,
1687
+ payload,
1688
+ source,
1689
+ "completion",
1690
+ )
1691
+ )
1692
+ return;
1693
+ }
1694
+
1695
+ return yield* failure("inspect", "storage");
1696
+ });
1697
+
1698
+ const facet = (
1699
+ context: WorkerContext,
1700
+ principal: Principal,
1701
+ sourceSubmissionId?: SubmissionId,
1702
+ ): SubagentHost["Service"] => {
1703
+ const authorize = (
1704
+ operation: WorkerError["operation"],
1705
+ access: "context" | "read" | "send" | "control",
1706
+ worker?: WorkerRef,
1707
+ ) =>
1708
+ deps.authorizer.authorize({
1709
+ sourceThreadId: context.source.threadId,
1710
+ ...(sourceSubmissionId === undefined ? {} : { sourceSubmissionId }),
1711
+ principal,
1712
+ operation,
1713
+ access,
1714
+ ...(worker === undefined ? {} : { worker }),
1715
+ });
1716
+
1717
+ const binding = (target: Agent.AnyDefinition, operation: WorkerError["operation"]) =>
1718
+ resolveDefinitionBinding(deps.bindings, target).pipe(
1719
+ Effect.mapError(() => failure(operation, "declaration-unavailable")),
1720
+ );
1721
+
1722
+ const preparedTarget = Effect.fn("WorkerHost.preparedTarget")(function* (
1723
+ target: Agent.AnyDefinition,
1724
+ encodedInput: unknown,
1725
+ ) {
1726
+ const resolved = yield* binding(target, "start");
1727
+
1728
+ yield* Schema.decodeUnknownEffect(Schema.toEncoded(target.input))(encodedInput).pipe(
1729
+ Effect.mapError(() => failure("start", "corrupt")),
1730
+ );
1731
+ const input = yield* decode(PersistedJson, encodedInput, "start");
1732
+
1733
+ const inputDigest = yield* withCrypto(digestJson(input)).pipe(
1734
+ Effect.mapError(storageFailure("start")),
1735
+ );
1736
+
1737
+ const source = yield* sourceAuthority(context.source.threadId, sourceSubmissionId);
1738
+
1739
+ const policy = yield* resolveTargetPolicy({
1740
+ _tag: "InitialInput",
1741
+ definition: resolved.definition,
1742
+ definitions: resolved.digests,
1743
+ source: context.source,
1744
+ ...(source.submission === undefined ? {} : { sourceSubmission: source.submission }),
1745
+ input,
1746
+ inputDigest,
1747
+ });
1748
+
1749
+ return { resolved, source, policy };
1750
+ });
1751
+
1752
+ const findOrigin = Effect.fn("WorkerHost.findOrigin")(function* (
1753
+ worker: WorkerRef,
1754
+ target: Agent.AnyDefinition,
1755
+ operation: WorkerError["operation"],
1756
+ ) {
1757
+ yield* binding(target, operation);
1758
+
1759
+ if (worker.targetAgentId !== target.id) return yield* failure(operation, "worker-mismatch");
1760
+
1761
+ const first = Option.getOrUndefined(
1762
+ yield* exactRecord(context.source.threadId, firstWorkerInputRecordId(worker), operation),
1763
+ )?.record.payload;
1764
+
1765
+ const origin = first?._tag === "WorkerInputRequested" ? first.admission.origin : undefined;
1766
+
1767
+ if (origin === undefined) return yield* failure(operation, "not-found");
1768
+ if (
1769
+ !Schema.toEquivalence(WorkerRef)(origin.worker, worker) ||
1770
+ first?._tag !== "WorkerInputRequested" ||
1771
+ first.admission.messageId !== origin.firstMessageId ||
1772
+ workerInputRecordId(origin.firstMessageId) !== firstWorkerInputRecordId(worker)
1773
+ )
1774
+ return yield* failure(operation, "worker-mismatch");
1775
+
1776
+ return origin;
1777
+ });
1778
+
1779
+ const receiptInput = Effect.fn("WorkerHost.receiptInput")(function* (
1780
+ request: WorkerReceiptRequest,
1781
+ operation: WorkerError["operation"],
1782
+ ) {
1783
+ const origin = yield* findOrigin(request.worker, request.target, operation);
1784
+ const receipt = request.receipt;
1785
+
1786
+ const snapshot = yield* deps.ledger
1787
+ .lookup(SubmissionLookupById.make({ submissionId: receipt.submissionId }))
1788
+ .pipe(Effect.mapError(storageFailure(operation)));
1789
+
1790
+ if (Option.isNone(snapshot)) return yield* failure(operation, "not-found");
1791
+ const row = snapshot.value;
1792
+
1793
+ if (
1794
+ row.threadId !== request.worker.threadId ||
1795
+ row.threadId !== receipt.threadId ||
1796
+ row.receiptId !== receipt.receiptId ||
1797
+ row.queueSequence !== receipt.queueSequence ||
1798
+ row.workerAdmission === undefined ||
1799
+ !sameOrigin(row.workerAdmission.origin, origin)
1800
+ )
1801
+ return yield* failure(operation, "receipt-mismatch");
1802
+
1803
+ return row.workerAdmission;
1804
+ });
1805
+
1806
+ const observation = Effect.fn("WorkerHost.observation")(function* (
1807
+ request: WorkerReceiptRequest,
1808
+ admission: WorkerAdmission,
1809
+ settlement: Settlement,
1810
+ ): Effect.fn.Return<WorkerObservation, WorkerError> {
1811
+ const history = yield* read(request.worker.threadId, "inspect");
1812
+
1813
+ const record = history.records.find(
1814
+ ({ record }) =>
1815
+ record.payload._tag === "SubmissionSettled" &&
1816
+ record.payload.submissionId === settlement.submissionId,
1817
+ )?.record.payload;
1818
+
1819
+ if (
1820
+ record?._tag !== "SubmissionSettled" ||
1821
+ record.settlementId !== settlement.settlementId ||
1822
+ record.receiptId !== request.receipt.receiptId ||
1823
+ record.outcome !== settlement.outcome
1824
+ )
1825
+ return yield* failure("inspect", "corrupt");
1826
+
1827
+ const input = history.records.find(
1828
+ ({ record }) =>
1829
+ record.payload._tag === "UserInputRecorded" &&
1830
+ record.payload.submissionId === settlement.submissionId,
1831
+ )?.record.payload;
1832
+
1833
+ const inputRunId = input?._tag === "UserInputRecorded" ? input.runId : undefined;
1834
+
1835
+ if (inputRunId !== undefined && record.runId !== undefined && inputRunId !== record.runId)
1836
+ return yield* failure("inspect", "corrupt");
1837
+ const runId = record.runId ?? inputRunId;
1838
+
1839
+ // The host settlement precedes the joined members and carries the Run's actual output.
1840
+ // Both identities come from canonical history; no foreign recovery or finalization is needed.
1841
+ const host =
1842
+ runId === undefined
1843
+ ? undefined
1844
+ : history.records.find(
1845
+ ({ record }) =>
1846
+ record.payload._tag === "SubmissionSettled" && record.payload.runId === runId,
1847
+ )?.record.payload;
1848
+
1849
+ const result = host?._tag === "SubmissionSettled" ? host : record;
1850
+
1851
+ if (result.outcome !== record.outcome) return yield* failure("inspect", "corrupt");
1852
+
1853
+ return {
1854
+ _tag: "Settled",
1855
+ receipt: request.receipt,
1856
+ settlementId: settlement.settlementId,
1857
+ ...(result.runId === undefined ? {} : { runId: result.runId }),
1858
+ outcome: settlement.outcome,
1859
+ encodedParameters: admission.parameters,
1860
+ encodedResult: result.result ?? null,
1861
+ budgetExhausted: result.finishReason === "budget-exhausted",
1862
+ };
1863
+ });
1864
+
1865
+ const send = Effect.fn("WorkerHost.send")(function* (
1866
+ origin: WorkerOrigin,
1867
+ messageId: IdempotencyKey,
1868
+ encodedInput: unknown,
1869
+ encodedParameters: unknown,
1870
+ principal: Principal,
1871
+ operation: "start" | "followUp",
1872
+ ) {
1873
+ if (Option.isNone(deps.deliveries)) return yield* failure(operation, "unavailable");
1874
+ const deliveries = deps.deliveries.value;
1875
+ const input = yield* decode(PersistedJson, encodedInput, operation);
1876
+ const parameters = yield* decode(PersistedJson, encodedParameters, operation);
1877
+
1878
+ const inputDigest = yield* withCrypto(digestJson(input)).pipe(
1879
+ Effect.mapError(storageFailure(operation)),
1880
+ );
1881
+
1882
+ const key = { ownerThreadId: context.source.threadId, messageId };
1883
+ const saved = yield* deliveries.get(key).pipe(Effect.mapError(storageFailure(operation)));
1884
+
1885
+ if (saved !== null) {
1886
+ const metadata = saved.envelope.workerAdmission;
1887
+
1888
+ if (
1889
+ metadata === undefined ||
1890
+ !sameOrigin(metadata.origin, origin) ||
1891
+ !sameJson(metadata.parameters, parameters) ||
1892
+ saved.envelope.inputDigest !== inputDigest ||
1893
+ !sameJson(saved.envelope.input, input)
1894
+ )
1895
+ return yield* failure(operation, "idempotency-conflict");
1896
+ if (saved.receipt !== null) return saved.receipt;
1897
+ } else {
1898
+ const now = yield* Clock.currentTimeMillis;
1899
+
1900
+ if (now >= origin.expiresAtMillis) return yield* failure(operation, "capacity");
1901
+
1902
+ const envelope: PreparedInput = {
1903
+ schemaVersion: 1,
1904
+ threadId: origin.worker.threadId,
1905
+ deliveryPrincipal: principal,
1906
+ agentId: origin.worker.targetAgentId,
1907
+ definitions: origin.targetDigests,
1908
+ input,
1909
+ inputDigest,
1910
+ admissionKey: messageId,
1911
+ authorization: { policyId: "worker-host", decisionId: messageId },
1912
+ workerAdmission: {
1913
+ origin,
1914
+ messageId,
1915
+ parameters,
1916
+ createdAtMillis: now,
1917
+ deliveryPrincipal: principal,
1918
+ ...(sourceSubmissionId === undefined ? {} : { sourceSubmissionId }),
1919
+ },
1920
+ };
1921
+
1922
+ const prepared = yield* withCrypto(
1923
+ prepareMessageDelivery({
1924
+ key,
1925
+ envelope,
1926
+ createdAtMillis: now,
1927
+ deadlineAtMillis: origin.expiresAtMillis,
1928
+ }),
1929
+ ).pipe(Effect.mapError(storageFailure(operation)));
1930
+
1931
+ yield* deliveries
1932
+ .insert(prepared)
1933
+ .pipe(
1934
+ Effect.mapError((error) =>
1935
+ failure(
1936
+ operation,
1937
+ error._tag === "MessageDeliveryError" && error.reason === "capacity"
1938
+ ? "capacity"
1939
+ : "storage",
1940
+ ),
1941
+ ),
1942
+ );
1943
+ }
1944
+
1945
+ // Direct callers and automatic pumps run the same claim/accept/refuse protocol. A
1946
+ // conclusive refusal is retained before it becomes visible to this caller.
1947
+ const processed = yield* MessageDeliveryDriver.pipe(
1948
+ Effect.flatMap((driver) => driver.process(key)),
1949
+ Effect.provide(MessageDeliveryDriver.layer({ batchSize: 1, concurrency: 1 })),
1950
+ Effect.provideService(MessageDeliveryStore, deliveries),
1951
+ Effect.provideService(PreparedInputAdmission, {
1952
+ submit: (prepared) =>
1953
+ deps
1954
+ .submit(prepared)
1955
+ .pipe(
1956
+ Effect.mapError((error) =>
1957
+ error._tag === "AdmissionConflict" || error._tag === "AgentInputError"
1958
+ ? ScheduledInputRefused.make({ code: error._tag })
1959
+ : error._tag === "AdmissionPolicyError" && error.reason === "refused"
1960
+ ? ScheduledInputRefused.make({ code: error.code })
1961
+ : ScheduledInputRetryable.make({ reason: "storage" }),
1962
+ ),
1963
+ ),
1964
+ submissionStatus: (receipt) =>
1965
+ deps
1966
+ .status(receipt)
1967
+ .pipe(Effect.mapError(() => ScheduledInputRetryable.make({ reason: "storage" }))),
1968
+ }),
1969
+ Effect.provideService(Crypto.Crypto, deps.crypto),
1970
+ Effect.mapError(storageFailure(operation)),
1971
+ );
1972
+
1973
+ if (processed.receipt !== null) return processed.receipt;
1974
+ if (processed.status === "refused") {
1975
+ const reason = Schema.decodeUnknownOption(WorkerError.fields.reason)(
1976
+ processed.refusal?.startsWith("worker-")
1977
+ ? processed.refusal.slice("worker-".length)
1978
+ : processed.refusal === "AdmissionConflict"
1979
+ ? "idempotency-conflict"
1980
+ : processed.refusal === "AgentInputError"
1981
+ ? "corrupt"
1982
+ : undefined,
1983
+ );
1984
+
1985
+ return yield* failure(
1986
+ operation,
1987
+ Option.getOrElse(reason, () => "denied"),
1988
+ );
1989
+ }
1990
+
1991
+ // A live claim or a future delivery deadline is not a storage failure. Keep the
1992
+ // receipt-only success contract: retention alone does not mean the child started.
1993
+ return yield* failure(
1994
+ operation,
1995
+ processed.status === "pending" && processed.retry.lastFailure === null
1996
+ ? "delivery-pending"
1997
+ : "storage",
1998
+ );
1999
+ });
2000
+
2001
+ const messageIdFor = (parts: ReadonlyArray<string>) =>
2002
+ withCrypto(digestJson(parts)).pipe(
2003
+ Effect.map((digest) => Schema.decodeSync(IdempotencyKey)(`worker:${digest}`)),
2004
+ Effect.mapError(storageFailure("start")),
2005
+ );
2006
+
2007
+ const summarize = Effect.fn("WorkerHost.summarize")(function* (
2008
+ origin: WorkerOrigin,
2009
+ all: ReadonlyArray<WorkerInputRequested>,
2010
+ operation: "list" | "inspect",
2011
+ ) {
2012
+ yield* authorize(operation, "read", origin.worker);
2013
+ let latestReceipt: Receipt | null = null;
2014
+ let active = false;
2015
+ let starting = false;
2016
+
2017
+ for (const row of all) {
2018
+ if (row.admission.origin.worker.threadId !== origin.worker.threadId) continue;
2019
+
2020
+ const delivery = Option.isNone(deps.deliveries)
2021
+ ? null
2022
+ : yield* deps.deliveries.value
2023
+ .get({
2024
+ ownerThreadId: context.source.threadId,
2025
+ messageId: row.admission.messageId,
2026
+ })
2027
+ .pipe(Effect.mapError(storageFailure(operation)));
2028
+
2029
+ const principal = row.admission.deliveryPrincipal ?? delivery?.envelope.deliveryPrincipal;
2030
+
2031
+ const found =
2032
+ principal === undefined
2033
+ ? Option.none()
2034
+ : yield* deps.ledger
2035
+ .lookup(
2036
+ SubmissionLookupByKey.make({
2037
+ threadId: origin.worker.threadId,
2038
+ principal,
2039
+ idempotencyKey: row.admission.messageId,
2040
+ }),
2041
+ )
2042
+ .pipe(Effect.mapError(storageFailure(operation)));
2043
+
2044
+ if (Option.isNone(found)) {
2045
+ if (delivery?.status !== "refused") starting = true;
2046
+ continue;
2047
+ }
2048
+ active ||= found.value.state !== "settled";
2049
+ if (latestReceipt === null || found.value.queueSequence > latestReceipt.queueSequence) {
2050
+ latestReceipt = {
2051
+ threadId: found.value.threadId,
2052
+ submissionId: found.value.submissionId,
2053
+ receiptId: found.value.receiptId,
2054
+ queueSequence: found.value.queueSequence,
2055
+ };
2056
+ }
2057
+ }
2058
+
2059
+ return {
2060
+ worker: origin.worker,
2061
+ latestReceipt,
2062
+ state: active
2063
+ ? ("active" as const)
2064
+ : starting || latestReceipt === null
2065
+ ? ("starting" as const)
2066
+ : ("idle" as const),
2067
+ };
2068
+ });
2069
+
2070
+ return {
2071
+ context: Effect.gen(function* () {
2072
+ yield* authorize("context", "context");
2073
+ if (context.depth !== 0) return context;
2074
+ const source = yield* sourceAuthority(context.source.threadId, sourceSubmissionId);
2075
+
2076
+ return {
2077
+ ...context,
2078
+ policy: Option.getOrElse(source.policyOverride, () => context.policy),
2079
+ };
2080
+ }),
2081
+ resolveTargetPolicy: Effect.fn("WorkerHost.resolvePreparedTargetPolicy")(function* (request) {
2082
+ yield* authorize("start", "send");
2083
+
2084
+ return (yield* preparedTarget(request.target, request.encodedInput)).policy;
2085
+ }),
2086
+ start: Effect.fn("WorkerHost.start")(function* (request) {
2087
+ const principal = yield* authorize("start", "send");
2088
+
2089
+ if (context.depth !== 0 && sourceSubmissionId === undefined)
2090
+ return yield* failure("start", "denied");
2091
+ const prepared = yield* preparedTarget(request.target, request.encodedInput);
2092
+ const resolved = prepared.resolved;
2093
+ const sourcePolicy = Option.getOrElse(prepared.source.policyOverride, () => context.policy);
2094
+
2095
+ const grant = yield* Schema.decodeUnknownEffect(SubagentGrant)(request.encodedGrant).pipe(
2096
+ Effect.mapError(() => failure("start", "corrupt")),
2097
+ );
2098
+
2099
+ const messageId = yield* messageIdFor([
2100
+ context.source.threadId,
2101
+ request.delegationId,
2102
+ request.idempotencyKey,
2103
+ ]);
2104
+
2105
+ if (Option.isNone(deps.deliveries)) return yield* failure("start", "unavailable");
2106
+
2107
+ const existing = yield* deps.deliveries.value
2108
+ .get({ ownerThreadId: context.source.threadId, messageId })
2109
+ .pipe(Effect.mapError(storageFailure("start")));
2110
+
2111
+ const now = yield* Clock.currentTimeMillis;
2112
+ const previousOrigin = existing?.envelope.workerAdmission?.origin;
2113
+ const sourceBinding = prepared.source.binding;
2114
+
2115
+ if (sourceBinding === undefined) return yield* failure("start", "declaration-unavailable");
2116
+
2117
+ const reporting =
2118
+ previousOrigin === undefined
2119
+ ? yield* reportIntent(sourceBinding, resolved, request.delegationId)
2120
+ : previousOrigin.reporting;
2121
+
2122
+ if (reporting?.mode === "standard" && sourceSubmissionId === undefined)
2123
+ return yield* failure("start", "denied");
2124
+
2125
+ const origin = yield* decode(
2126
+ WorkerOrigin,
2127
+ {
2128
+ worker: {
2129
+ schemaVersion: 1,
2130
+ delegationId: request.delegationId,
2131
+ targetAgentId: request.target.id,
2132
+ threadId: Schema.decodeSync(ThreadId)(messageId),
2133
+ },
2134
+ source: existing?.envelope.workerAdmission?.origin.source ?? context.source,
2135
+ targetDigests: previousOrigin?.targetDigests ?? resolved.digests,
2136
+ policy: request.policy,
2137
+ budget: request.budget,
2138
+ ...(request.budgetScope === undefined ? {} : { budgetScope: request.budgetScope }),
2139
+ grant,
2140
+ depth: context.depth + 1,
2141
+ firstMessageId: messageId,
2142
+ createdAtMillis: existing?.envelope.workerAdmission?.origin.createdAtMillis ?? now,
2143
+ expiresAtMillis:
2144
+ existing?.envelope.workerAdmission?.origin.expiresAtMillis ??
2145
+ now + deps.limits.lifetimeMillis,
2146
+ ...(reporting === undefined ? {} : { reporting }),
2147
+ ...(request.toolCallAllowance === undefined
2148
+ ? {}
2149
+ : { toolCallAllowance: request.toolCallAllowance }),
2150
+ },
2151
+ "start",
2152
+ );
2153
+
2154
+ yield* authorizeBudget(origin, principal);
2155
+
2156
+ const targetPolicy = Option.isSome(prepared.policy)
2157
+ ? prepared.policy.value
2158
+ : origin.budgetScope === "worker-run"
2159
+ ? resolved.definition.policy
2160
+ : AgentPolicy.resolve(
2161
+ resolved.definition.policyOverrides ?? resolved.definition.policy,
2162
+ sourcePolicy,
2163
+ );
2164
+
2165
+ if (
2166
+ !withinPolicy(
2167
+ origin,
2168
+ origin.budgetScope === "worker-run" ? targetPolicy : sourcePolicy,
2169
+ targetPolicy,
2170
+ )
2171
+ )
2172
+ return yield* failure("start", "capacity");
2173
+
2174
+ const receipt = yield* send(
2175
+ origin,
2176
+ messageId,
2177
+ request.encodedInput,
2178
+ request.encodedParameters,
2179
+ principal,
2180
+ "start",
2181
+ );
2182
+
2183
+ return { worker: origin.worker, receipt };
2184
+ }),
2185
+ followUp: Effect.fn("WorkerHost.followUp")(function* (request) {
2186
+ const principal = yield* authorize("followUp", "send", request.worker);
2187
+ const origin = yield* findOrigin(request.worker, request.target, "followUp");
2188
+
2189
+ yield* resolveTargetPolicy({
2190
+ _tag: "RetainedWorker",
2191
+ definition: request.target,
2192
+ definitions: origin.targetDigests,
2193
+ source: origin.source,
2194
+ origin,
2195
+ });
2196
+
2197
+ yield* Schema.decodeUnknownEffect(Schema.toEncoded(request.target.input))(
2198
+ request.encodedInput,
2199
+ ).pipe(Effect.mapError(() => failure("followUp", "corrupt")));
2200
+
2201
+ const messageId = yield* messageIdFor([
2202
+ context.source.threadId,
2203
+ request.worker.threadId,
2204
+ "followUp",
2205
+ request.idempotencyKey,
2206
+ ]);
2207
+
2208
+ return yield* send(
2209
+ origin,
2210
+ messageId,
2211
+ request.encodedInput,
2212
+ request.encodedParameters,
2213
+ principal,
2214
+ "followUp",
2215
+ );
2216
+ }),
2217
+ inspect: Effect.fn("WorkerHost.inspect")(function* (request) {
2218
+ yield* authorize("inspect", "read", request.worker);
2219
+ const admission = yield* receiptInput(request, "inspect");
2220
+
2221
+ const status = yield* deps
2222
+ .status(request.receipt)
2223
+ .pipe(Effect.mapError(storageFailure("inspect")));
2224
+
2225
+ return status._tag === "pending"
2226
+ ? { _tag: "Pending" as const, receipt: request.receipt }
2227
+ : yield* observation(request, admission, status.settlement);
2228
+ }),
2229
+ summary: Effect.fn("WorkerHost.inspectWorker")(function* (request) {
2230
+ yield* authorize("inspect", "read", request.worker);
2231
+ const origin = yield* findOrigin(request.worker, request.target, "inspect");
2232
+ const source = yield* readWorkerState(context.source.threadId, "inspect");
2233
+
2234
+ return yield* summarize(origin, requests(source.records), "inspect");
2235
+ }),
2236
+ observe: (request) =>
2237
+ Stream.unwrap(
2238
+ Effect.gen(function* () {
2239
+ yield* authorize("observe", "read", request.worker);
2240
+ yield* findOrigin(request.worker, request.target, "observe");
2241
+ const after = request.after ?? 0;
2242
+
2243
+ if (!Number.isSafeInteger(after) || after < 0)
2244
+ return yield* failure("observe", "corrupt");
2245
+
2246
+ const tail = yield* deps.store
2247
+ .inspectTail(ThreadTailRequest.make({ threadId: request.worker.threadId }))
2248
+ .pipe(Effect.mapError(storageFailure("observe")));
2249
+
2250
+ return Stream.paginate(after, (cursor) =>
2251
+ Effect.gen(function* () {
2252
+ if (cursor >= tail.tailSequence) return [[], Option.none<number>()] as const;
2253
+ const limit = Math.min(256, tail.tailSequence - cursor);
2254
+
2255
+ const page = yield* deps.store
2256
+ .read(
2257
+ ThreadRead.make({
2258
+ threadId: request.worker.threadId,
2259
+ afterSequence: Schema.decodeSync(CanonicalSequence)(cursor),
2260
+ limit,
2261
+ }),
2262
+ )
2263
+ .pipe(Stream.runCollect, Effect.mapError(storageFailure("observe")));
2264
+
2265
+ if (
2266
+ page.length === 0 ||
2267
+ page.length > limit ||
2268
+ page.some(
2269
+ (entry, index) =>
2270
+ entry.threadId !== request.worker.threadId ||
2271
+ entry.sequence !== cursor + index + 1,
2272
+ )
2273
+ )
2274
+ return yield* failure("observe", "corrupt");
2275
+
2276
+ const entries = yield* Effect.forEach(page, (entry) =>
2277
+ Schema.encodeEffect(RecordEnvelope)(entry.record).pipe(
2278
+ Effect.flatMap((record) =>
2279
+ Schema.decodeEffect(WorkerHistoryEntry)({
2280
+ sequence: entry.sequence,
2281
+ recordId: entry.record.recordId,
2282
+ record,
2283
+ }),
2284
+ ),
2285
+ Effect.mapError(() => failure("observe", "corrupt")),
2286
+ ),
2287
+ );
2288
+
2289
+ const next = cursor + page.length;
2290
+
2291
+ return [
2292
+ entries,
2293
+ next >= tail.tailSequence ? Option.none<number>() : Option.some(next),
2294
+ ] as const;
2295
+ }),
2296
+ );
2297
+ }),
2298
+ ),
2299
+ await: Effect.fn("WorkerHost.await")(function* (request) {
2300
+ yield* authorize("await", "read", request.worker);
2301
+ const admission = yield* receiptInput(request, "await");
2302
+
2303
+ while (true) {
2304
+ const status = yield* deps
2305
+ .status(request.receipt)
2306
+ .pipe(Effect.mapError(storageFailure("await")));
2307
+
2308
+ if (status._tag === "settled")
2309
+ return yield* observation(request, admission, status.settlement);
2310
+ // Poll the same host-routed read used by inspect. Interruption stops only this wait.
2311
+ yield* Effect.sleep(deps.settlementPollInterval);
2312
+ }
2313
+ }),
2314
+ list: Effect.fn("WorkerHost.list")(function* (request) {
2315
+ yield* authorize("list", "read");
2316
+ yield* binding(request.target, "list");
2317
+ if (!Number.isSafeInteger(request.limit) || request.limit < 1 || request.limit > 100)
2318
+ return yield* failure("list", "capacity");
2319
+ const source = yield* readWorkerState(context.source.threadId, "list");
2320
+ const all = requests(source.records);
2321
+
2322
+ const origins = [
2323
+ ...new Map(
2324
+ all.map((row) => [row.admission.origin.worker.threadId, row.admission.origin]),
2325
+ ).values(),
2326
+ ]
2327
+ .filter(
2328
+ (origin) =>
2329
+ origin.worker.delegationId === request.delegationId &&
2330
+ origin.worker.targetAgentId === request.target.id &&
2331
+ (request.after === undefined || origin.worker.threadId > request.after),
2332
+ )
2333
+ .sort((left, right) => left.worker.threadId.localeCompare(right.worker.threadId));
2334
+
2335
+ const selected = origins.slice(0, request.limit);
2336
+
2337
+ const items = yield* Effect.forEach(selected, (origin) => summarize(origin, all, "list"));
2338
+
2339
+ return {
2340
+ items,
2341
+ next:
2342
+ origins.length > selected.length
2343
+ ? (selected[selected.length - 1]?.worker.threadId ?? null)
2344
+ : null,
2345
+ };
2346
+ }),
2347
+ cancel: Effect.fn("WorkerHost.cancel")(function* (request) {
2348
+ const principal = yield* authorize("cancel", "control", request.worker);
2349
+
2350
+ yield* receiptInput(request, "cancel");
2351
+ yield* deps
2352
+ .abort(
2353
+ AbortCommand.make({
2354
+ submissionId: request.receipt.submissionId,
2355
+ author: principal,
2356
+ reason: "Worker owner requested cancellation of this Receipt",
2357
+ }),
2358
+ )
2359
+ .pipe(
2360
+ Effect.mapError((error) =>
2361
+ error._tag === "JoinedToHost" ? error : failure("cancel", "storage"),
2362
+ ),
2363
+ );
2364
+ }),
2365
+ };
2366
+ };
2367
+
2368
+ const validateCompletion = Effect.fn("WorkerHost.validateCompletion")(function* (
2369
+ unvalidated: FrameworkMessage,
2370
+ options: DurableSubmitOptions,
2371
+ agentId: AgentId,
2372
+ inputDigest: Digest,
2373
+ ) {
2374
+ const message = yield* Schema.decodeEffect(FrameworkMessage)(unvalidated).pipe(
2375
+ Effect.mapError(() => failure("followUp", "corrupt")),
2376
+ );
2377
+
2378
+ const childThreadId =
2379
+ message._tag === "WorkerCompletion"
2380
+ ? message.report.worker.threadId
2381
+ : message.worker.threadId;
2382
+
2383
+ const proofId =
2384
+ message._tag === "WorkerCompletion"
2385
+ ? workerReportRecordId(options.idempotencyKey)
2386
+ : yield* withCrypto(
2387
+ agentUpdateRecordId(
2388
+ message.update.threadId,
2389
+ message.update.runId,
2390
+ message.update.updateId,
2391
+ ),
2392
+ ).pipe(Effect.mapError(storageFailure("followUp")));
2393
+
2394
+ const proof = Option.getOrUndefined(yield* exactRecord(childThreadId, proofId, "followUp"))
2395
+ ?.record.payload;
2396
+
2397
+ const frozen =
2398
+ message._tag === "WorkerCompletion"
2399
+ ? proof?._tag === "WorkerReportPrepared" &&
2400
+ proof.runId === message.report.runId &&
2401
+ proof.messageId === options.idempotencyKey
2402
+ ? proof.envelope
2403
+ : undefined
2404
+ : proof?._tag === "AgentUpdateEmitted" &&
2405
+ Schema.toEquivalence(Update)(proof.update, message.update)
2406
+ ? proof.delivery?.envelope
2407
+ : undefined;
2408
+
2409
+ if (frozen === undefined) return yield* failure("followUp", "denied");
2410
+
2411
+ const envelope = yield* Schema.decodeUnknownEffect(PreparedInput)(frozen).pipe(
2412
+ Effect.mapError(() => failure("followUp", "corrupt")),
2413
+ );
2414
+
2415
+ if (
2416
+ !Schema.is(FrameworkMessage)(envelope.messageAdmission) ||
2417
+ !Schema.toEquivalence(FrameworkMessage)(envelope.messageAdmission, message) ||
2418
+ envelope.threadId !== options.threadId ||
2419
+ envelope.agentId !== agentId ||
2420
+ envelope.inputDigest !== inputDigest ||
2421
+ envelope.deliveryPrincipal !== options.principal ||
2422
+ envelope.admissionKey !== options.idempotencyKey ||
2423
+ !definitionDigestsEqual(envelope.definitions, options.definitions) ||
2424
+ !Schema.toEquivalence(Schema.UndefinedOr(WorkerAdmission))(
2425
+ envelope.workerAdmission,
2426
+ options.workerAdmission,
2427
+ )
2428
+ )
2429
+ return yield* failure("followUp", "denied");
2430
+
2431
+ const recorded = Option.getOrUndefined(
2432
+ yield* exactRecord(childThreadId, workerOriginRecordId(childThreadId), "followUp"),
2433
+ )?.record.payload;
2434
+
2435
+ if (
2436
+ recorded?._tag !== "WorkerOriginRecorded" ||
2437
+ recorded.origin.worker.threadId !== childThreadId ||
2438
+ recorded.origin.reporting?.mode !== "standard"
2439
+ )
2440
+ return yield* failure("followUp", "denied");
2441
+ const origin = recorded.origin;
2442
+
2443
+ const first = Option.getOrUndefined(
2444
+ yield* exactRecord(
2445
+ origin.source.threadId,
2446
+ workerInputRecordId(origin.firstMessageId),
2447
+ "followUp",
2448
+ ),
2449
+ )?.record.payload;
2450
+
2451
+ if (
2452
+ first?._tag !== "WorkerInputRequested" ||
2453
+ first.admission.messageId !== origin.firstMessageId ||
2454
+ !sameOrigin(first.admission.origin, origin)
2455
+ )
2456
+ return yield* failure("followUp", "denied");
2457
+ const receiving = envelope.workerAdmission;
2458
+
2459
+ const sourceSubmissionId =
2460
+ receiving === undefined ? first.admission.sourceSubmissionId : receiving.sourceSubmissionId;
2461
+
2462
+ const principal = yield* deps.authorizer.authorize({
2463
+ sourceThreadId: receiving?.origin.source.threadId ?? origin.source.threadId,
2464
+ ...(sourceSubmissionId === undefined ? {} : { sourceSubmissionId }),
2465
+ principal: options.principal,
2466
+ operation: "followUp",
2467
+ access: "send",
2468
+ worker: receiving?.origin.worker ?? origin.worker,
2469
+ });
2470
+
2471
+ if (principal !== options.principal) return yield* failure("followUp", "denied");
2472
+
2473
+ return message;
2474
+ });
2475
+
2476
+ const acquire = Effect.fn("WorkerHost.acquire")(function* (request: {
2477
+ readonly sourceThreadId: ThreadId;
2478
+ readonly principal: Principal;
2479
+ readonly sourceSubmissionId?: SubmissionId;
2480
+ }) {
2481
+ const { sourceThreadId, principal } = request;
2482
+
2483
+ yield* deps.authorizer.authorize({
2484
+ sourceThreadId,
2485
+ ...(request.sourceSubmissionId === undefined
2486
+ ? {}
2487
+ : { sourceSubmissionId: request.sourceSubmissionId }),
2488
+ principal,
2489
+ operation: "context",
2490
+ access: "context",
2491
+ });
2492
+ const current = yield* readIdentity(sourceThreadId, "context");
2493
+ const created = current.records[0]?.record.payload;
2494
+
2495
+ if (created?._tag !== "ThreadCreated") return yield* failure("context", "not-found");
2496
+
2497
+ const selected =
2498
+ request.sourceSubmissionId === undefined
2499
+ ? undefined
2500
+ : yield* sourceAuthority(sourceThreadId, request.sourceSubmissionId);
2501
+
2502
+ const resolved = selected === undefined ? currentBinding(created.agentId) : selected.binding;
2503
+
2504
+ if (resolved === undefined) return yield* failure("context", "declaration-unavailable");
2505
+
2506
+ const origin = current.records.find(
2507
+ ({ record }) => record.payload._tag === "WorkerOriginRecorded",
2508
+ )?.record.payload;
2509
+
2510
+ const attached = current.records.find(
2511
+ ({ record }) => record.payload._tag === "SubagentLineageRecorded",
2512
+ )?.record.payload;
2513
+
2514
+ const retained =
2515
+ origin?._tag === "WorkerOriginRecorded"
2516
+ ? origin.origin
2517
+ : attached?._tag === "SubagentLineageRecorded"
2518
+ ? attached
2519
+ : undefined;
2520
+
2521
+ return facet(
2522
+ {
2523
+ source: {
2524
+ _tag: "programmatic",
2525
+ threadId: sourceThreadId,
2526
+ agentId: selected?.submission?.agentId ?? created.agentId,
2527
+ },
2528
+ policy:
2529
+ retained?.policy ?? selected?.binding?.definition.policy ?? resolved.definition.policy,
2530
+ depth:
2531
+ origin?._tag === "WorkerOriginRecorded"
2532
+ ? origin.origin.depth
2533
+ : attached?._tag === "SubagentLineageRecorded"
2534
+ ? attached.parentLink.depth
2535
+ : 0,
2536
+ ...(retained?.grant === undefined ? {} : { grant: retained.grant }),
2537
+ },
2538
+ principal,
2539
+ request.sourceSubmissionId,
2540
+ );
2541
+ });
2542
+
2543
+ return {
2544
+ facet,
2545
+ prepareUpdate,
2546
+ acquire,
2547
+ validateCompletion,
2548
+ validateAdmission,
2549
+ ensureOrigin,
2550
+ completeInput,
2551
+ reserveSubtree,
2552
+ };
2553
+ });